;******************************************************
;******************************************************
;
; Main Project     : VFO
; Project Name     : VFO - Digital Variable Frequency Oscillator
; File Name        : vfo_main.asm
; Version          : A01
; PIC Used         : PIC16F648A
; Assembler        : MPLAB MPASMWIN from Microchip Technology, Inc.
; Initial Date     : May 28, 2011
; Last Update date : May 28, 2011
; Firmware Eng.    : WA7ZVY
; HW Design Eng.   : WA7ZVY
;
;******************************************************
;
; Description of this code:
;
; This code starts execution upon the release of the
; power on reset condition. The code continually
; executes the vfo_main routine.
;
;******************************************************
;
;   Modification History:
;   =-=-=-=-=-=-=-=-=-=-=
;   20110528 pm - Initial creation.
;
;******************************************************

;*****************************************************
;   === Include files ===
;*****************************************************
	LIST   P=16F648A			;List directive to define processor

#include	P16F648A.INC		;Processor specific variable definitions
#include	constants.inc		;Coding constants
#include	micro_bits.inc		;Hardware defined bits
#include	variable_def.inc	;Variable definitions


;*****************************************************
;       === Configuration Word Definitions ===
;*****************************************************
; Defines for PIC16F648A operation in the Digital VFO Board

; '__CONFIG' directive is used to embed configuration data within .asm file.
; The labels following the directive are located in the respective .inc file.
; See respective data sheet for additional information on configuration word.

	__CONFIG	_BODEN_OFF & _BOREN_OFF & _CP_OFF & _DATA_CP_OFF & _PWRTE_OFF & _WDT_OFF & _LVP_OFF & _MCLRE_ON & _INTOSC_OSC_NOCLKOUT

; '__idlocs' sets the four ID locations to the hexadecimal value of expression.
; These are not readable by the cpu, but can be read by the programning hardware.

	__idlocs	0x1234

;**********************************************************************

RESET_VECTOR	ORG	0x0000	; processor reset vector location
;	nop						; for icd debug
	pagesel	vfo_main		;
    goto    vfo_main		; go to beginning of program

;	This code contains goto statements that are located
;	at the beginning of each page of processor memory
;	(except page0).  These goto statements send
;	run-amuck code execution back through the reset
;	vector location in page0 at location 0.  All unused
;	program memory locations are filled with goto 0x0000
;	instructions.
CRASH_VECTOR_PAGE1	ORG	0x0800
	pagesel	RESET_VECTOR
	goto	RESET_VECTOR


;*****************************************************
INTERRUPT_VECTOR	ORG	0x0004	; processor interrupt vector location
    retfie						; return from interrupt (no interrupts from this hardware)

;*****************************************************
DEEPROM	CODE		;Burn into EEPROM the initial default Base Frequency for VFO mode
	de	0x1f			;Location 0x00 has the MSB of the Base Frequency
	de	0xff
	de	0xff
	de	0xfe			;Location 0x03 has the LSB of the Base Frequency

;**********************************************************************

MAIN_CODE	CODE				;vfo_main code space

std_dsply
	addwf	PCL,F
	dt		"FREQ:--.xxx.xxxSTEP:  .xxx.xxx"

base_message
	addwf	PCL,F
	dt		"NEW BASE STORED"

;*****************************************************
;*****************************************************
;
;	Name:		vfo_main
;	
;	Abstract:
;		This is the main entry point for code execution
;		on the digital vfo oscillator board.
;		This routine is the highest level code (ie. it
;		calls other routines which return to it, but
;		it is never called by other routines).
;
;	Callable Routines:  None.
;
;	Called Routines:
		extern	init_hardware, delay_1pt5msec, delay_50msec, delay_250msec
		extern	read_eeprom_location, write_eeprom_location
;
;	Global Variables Used:
;		
;	Local Variables Used:
;	
;	Return Values:	N/A.
; 		
;*****************************************************
;*****************************************************
vfo_main
	pagesel	init_hardware		;Initialize the various hardware functions
	call	init_hardware
	banksel	BANK0
	pagesel	vfo_main


;**********************************
;* Initialize all one time options.
;**********************************
	movlw	0x02			;Step = 100hz.
	movwf	b0_cstep		;Load current step.
	call	hz100			;Load "math" with 100Hz value
	call	math2step		;Transfer "math" to "step"

;***************************
;* Load LCD messages to ram:
;***************************
	movlw	b0_mfreq		;Setup indirection register to point at frequency RAM
	movwf	FSR
	bankisel	b0_mfreq
	clrf	b0_tmp1_lo		;clear a pointer
	nop
idis
	movf	b0_tmp1_lo,W
	call	std_dsply		;On return W has the character pointed to
	movwf	INDF			;Store the character into the frequency RAM
	incf	FSR,F
	incf	b0_tmp1_lo,F
	nop
	movf	b0_tmp1_lo,W
	xorlw	0x1e			;Done printing the FREQ and STEP messages to RAM?
	btfss	STATUS,Z
	goto	idis			;Jump if more to do

;**********************************
;* Get initial state of optical switch.
;**********************************
	movf	PORTA,W			;Read initial settings of vfo dial
	andlw	0x06			;Isolate VFO bits
	movwf	b0_opto_now		;Initialize the opto switch readings
	movwf	b0_opto_prev	;

;**********************
;* Initialize Lcd panel:
;**********************
	movlw	0x03			;Warm up a cold LCD command
							;Not sure we have to do this
	call	inst			; as no "real" code does it but... it is in the spec.
	call	delay_50msec
	movlw	0x03
	call	inst
	call	delay_50msec
	movlw	0x03
	call	inst
	call	delay_50msec
	movlw	0x02			;Set it to 4 bit data bus with 2 line LCD
	call	inst
	call	delay_50msec
	movlw	0x02			;Set it to 4 bit data bus with 2 line LCD
	call	inst
	call	delay_50msec
	movlw	0x08
	call	inst
	call	delay_50msec
	movlw	0x00			;Clear the display and home the cursor
	call	inst
	call	delay_50msec
	movlw	0x01
	call	inst
	call	delay_50msec

;*******************************
;* LCD "DISPLAY ON/OFF" FUNCTION COMMAND:
;* -----------------------------
;* D D D D D D D D
;* 7 6 5 4 3 2 1 0
;*
;* n R E R L L L L
;* c S   W 7 6 5 4
;*
;* 0 0 0 0 1 x x x   (x=1=on, x=0=off)
;*         : : : :
;*         : : : Blink
;*         : : Cursor
;*         : Display
;*         Display On/Off Command Bit
;********************************

	movlw	0x00			;First nibble display command
	call	inst			;Send 1st nibble
	call	delay_50msec	;Long delays for initial commands
	movlw	0x0c			;Display on, cursor off, blink off
	call	inst			;Send 2nd nibble
	call	delay_50msec

	call	zero			;Set frequency to "zero" and also send to Harris DDS
	call	dfreq			;Display the current frequency in LCD
	call	dstep			;Display the current frequency step in LCD


;**************************
;* READ OPTO SWITCH and STORE BASE SWITCH:
;**************************
switch
	btfss	PORTA,0x04		;Check if STORE BASE switch is pushed in (grounded)
	call	storebase		;Store new base frequency if STORE BASE switch is pushed in
	btfss	PORTA,0x02		;Check if VFO button is pushed in (grounded)
	call	bump			;Bump step up if VFO button is pushed in
	movf	PORTA,W			;Read switch input pins
	andlw	0x03			;Isolate the switch bits
	movwf	b0_opto_now		;Store current switch state
	movf	b0_opto_prev,W	;Load old switch data from last read
	xorlw	0x03			;Was previous read a 11
	btfsc	STATUS,Z
	goto	st3				;Yes, then jump
	movf	b0_opto_prev,W	;Reload old switch data from last read
	xorlw	0x02			;Was first read a 10
	btfsc	STATUS,Z
	goto	st2				;Yes, then jump
	movf	b0_opto_prev,W	;Reload old switch data from last read
	xorlw	0x01			;Was first read a 01
	btfsc	STATUS,Z
	goto	st1				;Yes, then jump
							;Otherwise fall through for first read of 00

;****************************
;* Original sw=0.
;* By knowing the values
;* of two sucsessive reads
;* from the VFO Switch we can
;* determine what direction,
;* and if, the switch is
;* being twisted.
;****************************
st0
	movf	b0_opto_now,W	;Save the current read to previous for next time
	movwf	b0_opto_prev
	xorlw	0x01			;Is it an up operation?
	btfsc	STATUS,Z
	goto	up
	movf	b0_opto_now,W
	xorlw	0x02			;Is it a down operation?
	btfsc	STATUS,Z
	goto	dn
	goto	switch			;Otherwise go back to switch routine

;****************
;* Original sw=1.
;****************
st1
	movf	b0_opto_now,W	;Save the current read to previous for next time
	movwf	b0_opto_prev
	xorlw	0x03			;Is it an up operation?
	btfsc	STATUS,Z
	goto	up
	movf	b0_opto_now,W
	xorlw	0x00			;Is it a down operation?
	btfsc	STATUS,Z
	goto	dn
	goto	switch			;Otherwise go back to switch routine

;****************
;* Original sw=2.
;****************
st2
	movf	b0_opto_now,W	;Save the current read to previous for next time
	movwf	b0_opto_prev
	xorlw	0x00			;Is it an up operation?
	btfsc	STATUS,Z
	goto	up
	movf	b0_opto_now,W
	xorlw	0x03			;Is it a down operation?
	btfsc	STATUS,Z
	goto	dn
	goto	switch			;Otherwise go back to switch routine

;****************
;* Original sw=3.
;****************
st3
	movf	b0_opto_now,W	;Save the current read to previous for next time
	movwf	b0_opto_prev
	xorlw	0x02			;Is it an up operation?
	btfsc	STATUS,Z
	goto	up
	movf	b0_opto_now,W
	xorlw	0x01			;Is it a down operation?
	btfsc	STATUS,Z
	goto	dn
	goto	switch			;Otherwise go back to switch routine

;*************************
;* CLICK VFO UP ONE NOTCH.
;*************************
up
	call	step2math		;Put step into math
	call	vfo2scr			;Put vfo into scratch
	call	add32			;Add one "step" to VFO (scr=scr+math)
	call	scr2vfo			;Save it to vfo
	movlw	lcnt			;Load with amount to shift
	movwf	b0_tmp1_lo
	call	shift			;Shift it into the Harris DDS
	call	dfreq			;Update display unit
	goto	switch			;Jump back to switch reading routine


;*************************
;* CLICK VFO Dn ONE NOTCH.
;*************************
dn
	call	step2math		;Put step into math
	call	vfo2scr			;Put vfo into scratch
	call	sub32			;Subtract one "step" from VFO (scr=scr-math)
	call	scr2vfo			;Save it back to vfo
	movlw	lcnt			;Load with amount to shift
	movwf	b0_tmp1_lo
	call	shift			;Shift it into the Harris DDS
	call	dfreq			;Update display unit
	goto	switch			;Jump back to switch reading routine




;********************************************************************
;*                     S U B R O U T I N E S                        *
;********************************************************************

;****************************
;* INSTRUCTION:
;* Use this routine to write
;* command to the LCD.
;****************************
inst
	andlw	0x0f	;Clear control bits to LCD
	call	wrtlcd	;Write to instruction register of LCD port
	iorlw	0x20	;CLK bit (E) on
	call	wrtlcd	;Now write that
	andlw	0x0f	;CLK bit (E) off
	call	wrtlcd	;Write this and data is latched in
	return


;****************************
;* WRITE DATA:
;* Use this routine to write
;* data to the LCD.
;****************************
write
	andlw	0x0f	;Clear control bits field
	iorlw	0x40	;Turn on RS for write commands
	call	wrtlcd	;Send to LCD port
	iorlw	0x20	;CLK bit (E) on
	call	wrtlcd	;Now write that
	andlw	0x4f	;CLK bit (E) off
	call	wrtlcd	;Write this and data is latched in
	return


;********************************
;* WRITE TO LCD DATA PORT:
;* Take data in accumulator and
;* write it to the LCD data port.
;********************************
wrtlcd
	call	delay_1pt5msec	;Delay before? Do it to be safe
	movwf	PORTB			;Write data to the data bus
	bsf		PORTA,0x07		;Set LCD clk high
	nop
	bcf		PORTA,0x07		;Set LCD clk to low, data is now latched
	call	delay_1pt5msec	;Delay between writes to make LCD happy
	return
	

;***********************
;* HOME LCD TO 1ST LINE:
;***********************
home1
	movlw	0x08	;Home to start of first line
	call	inst	;Write to command register
	movlw	0x00	;Send the second nibble
	call	inst	;And write it
	return


;***********************
;* HOME LCD TO 2ND LINE:
;***********************
home2
	movlw	0x0c	;Home to start of second line
	call	inst	;Write to command register
	movlw	0x00	;Load second nibble
	call	inst	;And write it
	return



;********************************
;* WRITE TO HARRIS DATA PORT:
;* Take data in accumulator and
;* write it to the DDS data port.
;********************************
wrtdds
	movwf	PORTB		;Write it to data bus
	bsf		PORTA,0x06	;Set DDS clk high (data is latched)
	nop
	bcf		PORTA,0x06	;Set DDS clk low
	return



;******************
;* Set VFO to zero.
;******************
zero
	; Read the "Stored Base" values to use from the EEPROM
	movlw	0x00			;Location of MSB in EEPROM space
	movwf	arg1_lo
	call	read_eeprom_location	;Value returned in arg1_hi
	banksel	BANK0
	movf	arg1_hi,W
	movwf	b0_vfo4			;Put the value into the msb
	movlw	0x01			;...
	movwf	arg1_lo
	call	read_eeprom_location
	banksel	BANK0
	movf	arg1_hi,W
	movwf	b0_vfo3
	movlw	0x02			;...
	movwf	arg1_lo
	call	read_eeprom_location
	banksel	BANK0
	movf	arg1_hi,W
	movwf	b0_vfo2
	movlw	0x03			;Location of LSB in EEPROM space
	movwf	arg1_lo
	call	read_eeprom_location
	banksel	BANK0
	movf	arg1_hi,W
	movwf	b0_vfo1
	call	vfo2scr			;Save vfo4~1 to scratch
	movlw	lcnt			;Load count to shift
	movwf	b0_tmp1_lo		;
	call	shift			;Shift all data out to Harris
	return



;*************************
;* Copy vfo4~1 to scr4~1:
;* Actual Freq to scratch.
;*************************
vfo2scr
	movf	b0_vfo4,W
	movwf	b0_scr4
	movf	b0_vfo3,W
	movwf	b0_scr3
	movf	b0_vfo2,W
	movwf	b0_scr2
	movf	b0_vfo1,W
	movwf	b0_scr1
	return


;*************************
;* Copy scr4~1 to vfo4~1:
;* Scratch to Actual Freq.
;*************************
scr2vfo
	movf	b0_scr4,W
	movwf	b0_vfo4
	movf	b0_scr3,W
	movwf	b0_vfo3
	movf	b0_scr2,W
	movwf	b0_vfo2
	movf	b0_scr1,W
	movwf	b0_vfo1
	return


;*************************
;* Copy vfo4~1 to math4~1:
;* Actual Freq to scratch.
;*************************
vfo2math
	movf	b0_vfo4,W
	movwf	b0_math4
	movf	b0_vfo3,W
	movwf	b0_math3
	movf	b0_vfo2,W
	movwf	b0_math2
	movf	b0_vfo1,W
	movwf	b0_math1
	return


;*************************
;* Copy math4~1 to vfo4~1:
;* Scratch to Actual Freq.
;*************************
math2vfo
	movf	b0_math4,W
	movwf	b0_vfo4
	movf	b0_math3,W
	movwf	b0_vfo3
	movf	b0_math2,W
	movwf	b0_vfo2
	movf	b0_math1,W
	movwf	b0_vfo1
	return


;*************************
;* Copy math4~1 to scr4~1:
;* Copy math to scratch.
;*************************
math2scr
	movf	b0_math4,W
	movwf	b0_scr4
	movf	b0_math3,W
	movwf	b0_scr3
	movf	b0_math2,W
	movwf	b0_scr2
	movf	b0_math1,W
	movwf	b0_scr1
	return


;*************************
;* Copy scr4~1 to math4~1:
;* Copy scratch to math
;*************************
scr2math
	movf	b0_scr4,W
	movwf	b0_math4
	movf	b0_scr3,W
	movwf	b0_math3
	movf	b0_scr2,W
	movwf	b0_math2
	movf	b0_scr1,W
	movwf	b0_math1
	return


;***************************
;* Copy math4~1 to mathb4~1:
;***************************
math2mathb
	movf	b0_math4,W
	movwf	b0_mathb4
	movf	b0_math3,W
	movwf	b0_mathb3
	movf	b0_math2,W
	movwf	b0_mathb2
	movf	b0_math1,W
	movwf	b0_mathb1
	return


;***************************
;* Copy mathb4~1 to math4~1:
;***************************
mathb2math
	movf	b0_mathb4,W
	movwf	b0_math4
	movf	b0_mathb3,W
	movwf	b0_math3
	movf	b0_mathb2,W
	movwf	b0_math2
	movf	b0_mathb1,W
	movwf	b0_math1
	return


;***************************
;* Copy step4~1 to scr4~1:
;***************************
step2scr
	movf	b0_step4,W
	movwf	b0_scr4
	movf	b0_step3,W
	movwf	b0_scr3
	movf	b0_step2,W
	movwf	b0_scr2
	movf	b0_step1,W
	movwf	b0_scr1
	return


;***************************
;* Copy scr4~1 to step4~1:
;***************************
scr2step
	movf	b0_scr4,W
	movwf	b0_step4
	movf	b0_scr3,W
	movwf	b0_step3
	movf	b0_scr2,W
	movwf	b0_step2
	movf	b0_scr1,W
	movwf	b0_step1
	return


;***************************
;* Copy math4~1 to step4~1:
;***************************
math2step
	movf	b0_math4,W
	movwf	b0_step4
	movf	b0_math3,W
	movwf	b0_step3
	movf	b0_math2,W
	movwf	b0_step2
	movf	b0_math1,W
	movwf	b0_step1
	return


;***************************
;* Copy step4~1 to math4~1:
;***************************
step2math
	movf	b0_step4,W
	movwf	b0_math4
	movf	b0_step3,W
	movwf	b0_math3
	movf	b0_step2,W
	movwf	b0_math2
	movf	b0_step1,W
	movwf	b0_math1
	return


;***********************
;* SUBTRACT 32 BITS:
;* Decrease output freq.
;* A simple 32Bit sub.
;* SCR=SCR-MATH
;***********************
sub32
	movf	b0_math1,W
	subwf	b0_scr1,F
	btfsc	STATUS,C
	goto	sub32_1
	movlw	0x01
	subwf	b0_scr2,F
	btfsc	STATUS,C
	goto	sub32_1
	subwf	b0_scr3,F
	btfsc	STATUS,C
	goto	sub32_1
	subwf	b0_scr4,F
sub32_1
	movf	b0_math2,W
	subwf	b0_scr2,F
	btfsc	STATUS,C
	goto	sub32_2
	movlw	0x01
	subwf	b0_scr3,F
	btfsc	STATUS,C
	goto	sub32_2
	subwf	b0_scr4,F
sub32_2
	movf	b0_math3,W
	subwf	b0_scr3,F
	btfsc	STATUS,C
	goto	sub32_3
	movlw	0x01
	subwf	b0_scr4,F
sub32_3
	movf	b0_math4,W
	subwf	b0_scr4,F

	return
	

;***********************
;* ADD 32 BITS:
;* Increase output freq.
;* A simple 32Bit add.
;* SCR=SCR+MATH
;***********************
add32
	movf	b0_math1,W
	addwf	b0_scr1,F
	btfss	STATUS,C
	goto	add32_1
	movlw	0x01
	addwf	b0_scr2,F
	btfss	STATUS,C
	goto	add32_1
	addwf	b0_scr3,F
	btfss	STATUS,C
	goto	add32_1
	addwf	b0_scr4,F
add32_1
	movf	b0_math2,W
	addwf	b0_scr2,F
	btfss	STATUS,C
	goto	add32_2
	movlw	0x01
	addwf	b0_scr3,F
	btfss	STATUS,C
	goto	add32_2
	addwf	b0_scr4,F
add32_2
	movf	b0_math3,W
	addwf	b0_scr3,F
	btfss	STATUS,C
	goto	add32_3
	movlw	0x01
	addwf	b0_scr4,F
add32_3
	movf	b0_math4,W
	addwf	b0_scr4,F

	return


;****************************************
;* SHIFT 32 BIT DATA:
;* SCR Contains the 32 bit cmd
;* that shall be written to the I/O port.
;* Shift left shifts the 32 long into
;* the HARRIS NCO (or DDS) Chip.
;****************************************
shift
	rlf		b0_scr1,F
	rlf		b0_scr2,F
	rlf		b0_scr3,F
	rlf		b0_scr4,F		;Carry now has bit to send
	movlw	dat1			;Assume the bit to send to DDS is suppose to be a 1
	btfss	STATUS,C
	movlw	dat0			;Oops, carry not set, so send a 0 instead

	call	wrtdds			;Setup data bit to Harris DDS chip
	iorlw	sclk_hi			;Turn on clk bit now
	call	wrtdds			;Write it (clocking in valid data bit)
	andlw	sclk_lo			;Turn off clk bit now
	call	wrtdds			;Write it to Harris DDS
	decf	b0_tmp1_lo,F	;Decrement shift count
	btfss	STATUS,Z
	goto	shift			;Loop until all 32 data bits are sent
							;Data sent, now signal transfer complete

;***********************************
;* TRANSFER:
;* This signals the DDS that
;* a 32 bit command is complete.
;***********************************
xferit
	movlw	xfer			;Load Transfer command
	call	wrtdds			;Write it to DDS port

;****************************
;* Generate Harris DDS wave and return
;****************************
genit
	movlw	dds_on			;Load dds_on
	call	wrtdds			;And write it to the DDS port
	return


;*******************************
;* 32 Bit division routine:    *
;*******************************
;* Divide two 32 Bit integers  *
;* using a kludgy many subtract*
;* Answer is in ans            *
;* Remainder is in scr4~1      *
;* Answer = (scr4~1 / math4~1) *
;*******************************
div32
	clrf	b0_div32_ans	;Clear answer register
	clrf	b0_div32_borrow	;Clear the "borrow happened flag"
divb_1
	movf	b0_math1,W		;Get math1
	subwf	b0_scr1,F		;scr1-math1 -> scr1
	btfsc	STATUS,C		;branch if there was a borrow
	goto	divb_2
	movlw	0x01
	subwf	b0_scr2,F
	btfsc	STATUS,C		;branch if there was a borrow
	goto	divb_2
	subwf	b0_scr3,F
	btfsc	STATUS,C		;branch if there was a borrow
	goto	divb_2
	subwf	b0_scr4,F
	btfsc	STATUS,C		;branch if there was a borrow
	goto	divb_2
	movlw	0x01			;a borrow happened from the most significant, so flag that
	movwf	b0_div32_borrow
divb_2
	movf	b0_math2,W		;Get math2
	subwf	b0_scr2,F		;scr2-math2 -> scr2
	btfsc	STATUS,C		;branch if there was a borrow
	goto	divb_3
	movlw	0x01
	subwf	b0_scr3,F
	btfsc	STATUS,C		;branch if there was a borrow
	goto	divb_3
	subwf	b0_scr4,F
	btfsc	STATUS,C		;branch if there was a borrow
	goto	divb_3
	movlw	0x01			;a borrow happened from the most significant, so flag that
	movwf	b0_div32_borrow
divb_3
	movf	b0_math3,W		;Get math3
	subwf	b0_scr3,F		;scr3-math3 -> scr3
	btfsc	STATUS,C		;branch if there was a borrow
	goto	divb_4
	movlw	0x01
	subwf	b0_scr4,F
	btfsc	STATUS,C		;branch if there was a borrow
	goto	divb_4
	movlw	0x01			;a borrow happened from the most significant, so flag that
	movwf	b0_div32_borrow
divb_4
	movf	b0_math4,W		;Get math4
	subwf	b0_scr4,F		;scr4-math4 -> scr4
	btfsc	STATUS,C		;branch if there was a borrow
	goto	divb_5
	movlw	0x01			;a borrow happened from the most significant, so flag that
	movwf	b0_div32_borrow
	nop
divb_5
	btfsc	b0_div32_borrow,0x00	;Check to see if a borrow previously happened
	goto	fixit			;Since a borrow did happen, we've divided by one too many, go fix it
	incf	b0_div32_ans,F	;Answer
	goto	divb_1			;Keep on dividing (subtracting)

fixit
	movf	b0_math1,W		;scr1 + math1 -> scr1
	addwf	b0_scr1,F
	btfss	STATUS,C		;branch if there was a carry
	goto	fixit_1
	movlw	0x01
	addwf	b0_scr2,F
	btfss	STATUS,C		;branch if there was a carry
	goto	fixit_1
	addwf	b0_scr3,F
	btfss	STATUS,C		;branch if there was a carry
	goto	fixit_1
	addwf	b0_scr4,F
fixit_1
	movf	b0_math2,W		;scr2 + math2 -> scr2
	addwf	b0_scr2,F
	btfss	STATUS,C		;branch if there was a carry
	goto	fixit_2
	movlw	0x01
	addwf	b0_scr3,F
	btfss	STATUS,C		;branch if there was a carry
	goto	fixit_2
	addwf	b0_scr4,F
fixit_2
	movf	b0_math3,W		;scr3 + math3 -> scr3
	addwf	b0_scr3,F
	btfss	STATUS,C		;branch if there was a carry
	goto	fixit_3
	movlw	0x01
	addwf	b0_scr4,F
fixit_3
	movf	b0_math4,W		;scr4 + math4 -> scr4
	addwf	b0_scr4,F

	movf	b0_div32_ans,W	;Get the binary answer
	addlw	0x30			;Convert it to an ASCII "number"
	return					;And return with the answer in W and with scr4~1 having the remainder



;*****************************
;* Change the steps to 10 Mhz.
;*****************************
mhz10
	movlw	mhz10_4		;Load 10 MHz values
	movwf	b0_math4
	movlw	mhz10_3
	movwf	b0_math3
	movlw	mhz10_2
	movwf	b0_math2
	movlw	mhz10_1
	movwf	b0_math1
	return

;****************************
;* Change the steps to 1 MHZ.
;****************************
mhz1
	movlw	mhz_4		;Load 1 MHz values
	movwf	b0_math4
	movlw	mhz_3
	movwf	b0_math3
	movlw	mhz_2
	movwf	b0_math2
	movlw	mhz_1
	movwf	b0_math1
	return

;******************************
;* Change the steps to 100 KHz.
;******************************
khz100
	movlw	k100_4		;Load 100KHz values
	movwf	b0_math4
	movlw	k100_3
	movwf	b0_math3
	movlw	k100_2
	movwf	b0_math2
	movlw	k100_1
	movwf	b0_math1
	return	

;*****************************
;* Change the steps to 10 KHz.
;*****************************
khz10
	movlw	k10_4		;Load 10KHz values
	movwf	b0_math4
	movlw	k10_3
	movwf	b0_math3
	movlw	k10_2
	movwf	b0_math2
	movlw	k10_1
	movwf	b0_math1
	return

;****************************
;* Change the steps to 1 KHz.
;****************************
khz1
	movlw	k1_4			;Load 1KHz values
	movwf	b0_math4
	movlw	k1_3
	movwf	b0_math3
	movlw	k1_2
	movwf	b0_math2
	movlw	k1_1
	movwf	b0_math1
	return

;*********************************
;* Change the steps to 100 cycles.
;*********************************
hz100
	movlw	h100_4		;Load 100Hz values
	movwf	b0_math4
	movlw	h100_3
	movwf	b0_math3
	movlw	h100_2
	movwf	b0_math2
	movlw	h100_1
	movwf	b0_math1
	return

;*******************************
;* Change the step to 10 cycles.
;*******************************
hz10
	movlw	h10_4		;Load 10Hz values
	movwf	b0_math4
	movlw	h10_3
	movwf	b0_math3
	movlw	h10_2
	movwf	b0_math2
	movlw	h10_1
	movwf	b0_math1
	return

;*****************************
;* Change the step to 1 cycle.
;*****************************
hz1
	movlw	h1_4
	movwf	b0_math4
	movlw	h1_3
	movwf	b0_math3
	movlw	h1_2
	movwf	b0_math2
	movlw	h1_1
	movwf	b0_math1
	return



;***************************
;* DISPLAY:
;* Display current frequency
;***************************
dfreq
	movlw	'-'					;Put a dash into the MHz digits just in case we are in vfo mode
	movwf	b0_mfreq+0x05
	movwf	b0_mfreq+0x06
	call	vfo2scr				;Load current vfo frequency into scr4~1
	call	sbase				;Subtract vfo's base freq (5.00MHz typical)
								; scr4~1 has result  (scr=scr-math; where math gets loaded with base freq)
	call	mhz10				;Load 10MHz values to math
	call	div32				;Returns ASCII answer in W (ans=scr/math, remainder in scr)
	btfsc	PORTA,0x03			;Check to see if we are in VFO mode, skip next if we are
	movwf	b0_mfreq+0x05		;Store in 10's of MHz digit
									;SKIP FOR VFO, STORE ONLY IN SIGNAL GENERATOR MODE
	call	mhz1				;Load 1MHz values to math
	call	div32				;Returns ASCII answer in W
	btfsc	PORTA,0x03			;Check to see if we are in VFO mode, skip next if we are
	movwf	b0_mfreq+0x06		;Store in MHz digit
									;SKIP FOR VFO, STORE ONLY IN SIGNAL GENERATOR MODE

	call	khz100
	call	div32	
	movwf	b0_mfreq+0x08		;Store in 100's of KHz digit
	call	khz10
	call	div32
	movwf	b0_mfreq+0x09		;Store in 10's of KHz digit
	call	khz1
	call	div32
	movwf	b0_mfreq+0x0a		;Store in KHz digit
	call	hz100
	call	div32
	movwf	b0_mfreq+0x0c		;Store in 100's of Hz digit
	call	hz10
	call	div32
	movwf	b0_mfreq+0x0d		;Store in 10's of Hz digit
	call	hz1
	call	div32
	movwf	b0_mfreq+0x0e		;Store in Hz digit

;*******************************
;* Print FREQ:xx.xxx.xxx to LCD.
;*******************************
	call	home1			;Put cursor at start of 1st line
	bankisel	b0_mfreq	;Setup indirection access
	movlw	b0_mfreq
	movwf	FSR
ldchar
	movlw	b0_mfreq+0x0f	;Done printing?
	xorwf	FSR,W
	btfsc	STATUS,Z
	goto	efreq
	swapf	INDF,W			;Get the character and put the high nibble in the bottom nibble
	andlw	0x0f			;Mask off
	call	write			;Write high nibble to LCD panel
	movf	INDF,W			;Get the character again
	andlw	0x0f			;Mask off
	call	write			;Write low nibble to LCD panel
	incf	FSR,F
	goto	ldchar			;Loop until done with all characters
efreq
	return

	


;**************************
;* SUBTRACT BASE FREQUENCY.
;* Subtract the zero freq
;* from the scratch regs
;* for display purposes.
;**************************
sbase
	btfsc	PORTA,0x03		;First check to see if we are in VFO mode
	return					;If not in VFO mode, just return, no subtraction needed

							;Load "zero" to math4~1
	movlw	0x00			;Location of MSB in EEPROM space
	movwf	arg1_lo
	call	read_eeprom_location	;Value returned in arg1_hi
	banksel	BANK0
	movf	arg1_hi,W
	movwf	b0_math4			;Put the value into the msb
	movlw	0x01			;...
	movwf	arg1_lo
	call	read_eeprom_location
	banksel	BANK0
	movf	arg1_hi,W
	movwf	b0_math3
	movlw	0x02			;...
	movwf	arg1_lo
	call	read_eeprom_location
	banksel	BANK0
	movf	arg1_hi,W
	movwf	b0_math2
	movlw	0x03			;Location of LSB in EEPROM space
	movwf	arg1_lo
	call	read_eeprom_location
	banksel	BANK0
	movf	arg1_hi,W
	movwf	b0_math1

	call	sub32	;32 bit subtract (scr=scr-math)
	return



;*****************************
;* Store step to memory in ascii.
;*****************************
dstep
	movlw	' '				;Put a space into the MHz digits just in case we are in vfo mode
	movwf	b0_mstep+0x05
	movwf	b0_mstep+0x06

	btfss	PORTA,0x03		;Check to see if we are in Vfo mode
	goto	dstep_1			; jump as we are in Vfo mode

	; Signal generator mode
	call	step2scr		;Load current step to scratch
	call	mhz10			;Load 10MHz to math
	call	div32			;Returns ASCII answer in W (ans=scr/math, remainder in scr)
	movwf	b0_mstep+0x05	;Put ASCII ans to display location
	call	mhz1			;Load 1MHz to math
	call	div32			;Returns ASCII answer in W (ans=scr/math, remainder in scr)
	movwf	b0_mstep+0x06	;Put ASCII ans to display location
	goto	dstep_2

dstep_1
	; Vfo mode
	call	step2scr		;Load current step to scratch
	call	mhz10			;Load 10MHz to math
	call	div32			;Returns ASCII answer in W (ans=scr/math, remainder in scr)
	call	mhz1			;Load 1MHz to math
	call	div32			;Returns ASCII answer in W (ans=scr/math, remainder in scr)

dstep_2
	call	khz100			;Load 100KHz to math
	call	div32			;Returns ASCII answer in W (ans=scr/math, remainder in scr)
	movwf	b0_mstep+0x08	;Put ASCII ans to display location
	call	khz10			;Load 10Khz to math
	call	div32			;Returns ASCII answer in W (ans=scr/math, remainder in scr)
	movwf	b0_mstep+0x09	;Put ASCII ans to display location
	call	khz1			;Load 1Khz to math
	call	div32			;Returns ASCII answer in W (ans=scr/math, remainder in scr)
	movwf	b0_mstep+0x0a	;Put ASCII ans to display location
	call	hz100			;Load 100hz to math
	call	div32			;Returns ASCII answer in W (ans=scr/math, remainder in scr)
	movwf	b0_mstep+0x0c	;Put ASCII ans to display location
	call	hz10			;Load 10hz to math
	call	div32			;Returns ASCII answer in W (ans=scr/math, remainder in scr)
	movwf	b0_mstep+0x0d	;Put ASCII ans to display location
	call	hz1				;Load 1hz to math
	call	div32			;Returns ASCII answer in W (ans=scr/math, remainder in scr)
	movwf	b0_mstep+0x0e	;Put ASCII ans to display location

;****************************
;* Print STEP:xx.xxx.xxx to LCD.
;****************************
	call	home2			;Put cursor at start of line #2
ldc2
	bankisel	b0_mstep	;Setup indirection access
	movlw	b0_mstep
	movwf	FSR

ldc2_1
	movlw	b0_mstep+0x0f	;Done printing?
	xorwf	FSR,W
	btfsc	STATUS,Z
	goto	efq2
	swapf	INDF,W			;Get the character and put the high nibble in the bottom nibble
	andlw	0x0f			;Mask off
	call	write			;Write nibble to LCD panel
	movf	INDF,W			;Get the character again
	andlw	0x0f			;Mask off
	call	write
	incf	FSR,F
	goto	ldc2_1			;Loop until done with all characters
efq2
	return





;**************************
;* BUMP TUNING STEPS.
;* User has pressed the VFO
;* Knob in and this routine
;* responds by changing the
;* current step.
;**************************
bump
	btfsc	PORTA,0x03		;Check to see if we are in vfo mode
	goto	bump_1			;Otherwise go to signal generator mode bumping

	; Vfo mode bumping
	movf	b0_cstep,W		;Load current step
	xorlw	0x00			; Check if this is 1Hz
	btfsc	STATUS,Z		;  Branch if not
	goto	s10				;  It is, so go to 10Hz steps
	movf	b0_cstep,W		;Reload current step
	xorlw	0x01			; Check if this is 10Hz
	btfsc	STATUS,Z		;  Branch if not
	goto	s100			;  It is, so go to 100Hz steps
	movf	b0_cstep,W		;Reload current step
	xorlw	0x02			; Check if this is 100Hz
	btfsc	STATUS,Z		;  Branch if not
	goto	s1k				;  It is, so go to 1KHz steps
	movf	b0_cstep,W		;Reload current step
	xorlw	0x03			; Check if this is 1KHz
	btfsc	STATUS,Z		;  Branch if not
	goto	s10k			;  It is, so go to 10KHz steps
	movf	b0_cstep,W		;Reload current step
	xorlw	0x04			; Check if this is 10KHz
	btfsc	STATUS,Z		;  Branch if not
	goto	s100k			;  It is, so go to 100KHz steps
	movf	b0_cstep,W		;Reload current step
	xorlw	0x05			; Check if this is 100KHz
	btfsc	STATUS,Z		;  Branch if not
	goto	s1				;  It is, so go to 1Hz steps
	return

bump_1
	; Signal generator mode bumping
	movf	b0_cstep,W		;Load current step
	xorlw	0x00			; Check if this is 1Hz
	btfsc	STATUS,Z		;  Branch if not
	goto	s10				;  It is, so go to 10Hz steps
	movf	b0_cstep,W		;Reload current step
	xorlw	0x01			; Check if this is 10Hz
	btfsc	STATUS,Z		;  Branch if not
	goto	s100			;  It is, so go to 100Hz steps
	movf	b0_cstep,W		;Reload current step
	xorlw	0x02			; Check if this is 100Hz
	btfsc	STATUS,Z		;  Branch if not
	goto	s1k				;  It is, so go to 1KHz steps
	movf	b0_cstep,W		;Reload current step
	xorlw	0x03			; Check if this is 1KHz
	btfsc	STATUS,Z		;  Branch if not
	goto	s10k			;  It is, so go to 10KHz steps
	movf	b0_cstep,W		;Reload current step
	xorlw	0x04			; Check if this is 10KHz
	btfsc	STATUS,Z		;  Branch if not
	goto	s100k			;  It is, so go to 100KHz steps
	movf	b0_cstep,W		;Reload current step
	xorlw	0x05			; Check if this is 100KHz
	btfsc	STATUS,Z		;  Branch if not
	goto	s1mhz			;  It is, so go to 1MHz steps
	movf	b0_cstep,W		;Reload current step
	xorlw	0x06			; Check if this is 1MHz
	btfsc	STATUS,Z		; Branch if not
	goto	s10mhz			; It is, so go to 10MHz steps
	movf	b0_cstep,W		;Reload current step
	xorlw	0x07			; Check if this is 10MHz
	btfsc	STATUS,Z		;  Branch if not
	goto	s1				;  It is, so go to 1Hz steps
	return



;**************************
;* STORE BASE
;* User has pressed the STORE BASE
;* Switch in and this routine
;* responds by storing the current
;* vfo frequency as the new base
;* frequency in EEPROM
;**************************
storebase
	btfss	PORTA,0x03		;First check to make sure we are in Signal Generator mode!
	return					; If not, just return!

	call	delay_50msec	;Delay a bit to debounce switch, then check again
	btfsc	PORTA,0x04		; to see that we are still requesting a "store base"
	return

	movlw	0x00			;Setup to write the MSB of the current frequency into the base
	movwf	arg1_lo
	movf	b0_vfo4,W
	movwf	arg1_hi
	call	write_eeprom_location
	banksel	BANK0
	movlw	0x01
	movwf	arg1_lo
	movf	b0_vfo3,W
	movwf	arg1_hi
	call	write_eeprom_location
	banksel	BANK0
	movlw	0x02
	movwf	arg1_lo
	movf	b0_vfo2,W
	movwf	arg1_hi
	call	write_eeprom_location
	banksel	BANK0
	movlw	0x03			;Setup to write the LSB of the current frequency into the base
	movwf	arg1_lo
	movf	b0_vfo1,W
	movwf	arg1_hi
	call	write_eeprom_location
	banksel	BANK0

	;Display the "NEW BASE STORED" message on line 2 (the "STEP:" line) of the LCD
	call	home2			;Put cursor at start of line #2
	clrf	b0_tmp_idx		;clear a pointer
	nop
storebase_1
	movf	b0_tmp_idx,W
	call	base_message	;On return W has the character pointed to
	movwf	b0_tmp1_hi		;save the character for now

	swapf	b0_tmp1_hi,W	;Get the character and put the high nibble in the bottom nibble
	andlw	0x0f			;Mask off
	call	write			;Write nibble to LCD panel
	movf	b0_tmp1_hi,W	;Get the character again
	andlw	0x0f			;Mask off
	call	write
	incf	b0_tmp_idx,F
	movlw	0x0f			;Check to see if we are done
	xorwf	b0_tmp_idx,W
	btfss	STATUS,Z
	goto	storebase_1		;Loop until done with all 15 characters of the message

storebase_2
	btfss	PORTA,0x04		;Now wait around for the switch to be released and debounced
	goto	storebase_2
	call	delay_50msec
	btfss	PORTA,0x04
	goto	storebase_2
	call	delay_50msec
	btfss	PORTA,0x04
	goto	storebase_2

	call	delay_250msec

	;Restore the "STEP:" message line
	call	dstep

	return



;************
;* STEP 1 Hz.
;************
s1
	movlw	0x00
	movwf	b0_cstep
	call	hz1				;Put 1Hz values into math
	call	math2step		;Transfer the 1Hz values to step
	call	dstep			;Display the new step value
	call	delay_250msec	;Delay for switch to stop bouncing
	return


;************
;* STEP 10Hz.
;************
s10
	movlw	0x01
	movwf	b0_cstep
	call	hz10
	call	math2step
	call	dstep
	call	delay_250msec
	return


;*************
;* STEP 100Hz.
;*************
s100
	movlw	0x02
	movwf	b0_cstep
	call	hz100
	call	math2step
	call	dstep
	call	delay_250msec
	return


;************
;* STEP 1KHz.
;************
s1k
	movlw	0x03
	movwf	b0_cstep
	call	khz1
	call	math2step
	call	dstep
	call	delay_250msec
	return


;*************
;* STEP 10KHz.
;*************
s10k
	movlw	0x04
	movwf	b0_cstep
	call	khz10
	call	math2step
	call	dstep
	call	delay_250msec
	return


;**************
;* STEP 100KHz.
;**************
s100k
	movlw	0x05
	movwf	b0_cstep
	call	khz100
	call	math2step
	call	dstep
	call	delay_250msec
	return


;************
;* STEP 1MHz.
;************
s1mhz
	movlw	0x06
	movwf	b0_cstep
	call	mhz1
	call	math2step
	call	dstep
	call	delay_250msec
	return


;************
;* STEP 10MHz.
;************
s10mhz
	movlw	0x07
	movwf	b0_cstep
	call	mhz10
	call	math2step
	call	dstep
	call	delay_250msec
	return




	end
;End of File (vfo_main.asm)
