;******************************************************
;******************************************************
;
; Main Project     : VFO
; Project Name     : VFO - Digital Variable Frequency Oscillator
; File Name        : utilities.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:
;
; These routines provide various utility functions.
;
;******************************************************
;
;   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


UTILITIES_CODE	CODE				;utilities code space

;*****************************************************
;*****************************************************
;
;	Name:		binary_to_decimal
;	
;	Abstract:	converts a binary word to a four nibble
;					decimal word.
;
;	Callable Routines:
		global	binary_to_decimal
;
;	Called Routines:
;		extern	modulusd10
;
;	Global Variables Used:
;		arg1_wrd contains binary value to convert to decimal (value is NOT preserved)
;
;	Local Variables Used:
;		b0_tmp1_wrd
;		
;	Return Values:
;		arg2_wrd contains four digits of decimal
;
;*****************************************************
;*****************************************************

binary_to_decimal
	banksel	BANK0
	clrf	b0_tmp1_hi		;clear a temporary result holding register
	clrf	b0_tmp1_lo

	clrf	arg2_hi			;clear the high word before calling the modulusd10
	clrf	arg2_lo
	pagesel	modulusd10
	call	modulusd10		;result returned in arg3, modulus returned in arg4
	movf	arg4_hi,W		;move the result back into arg1 for doing the next nibble
	movwf	arg1_hi
	movf	arg4_lo,W
	movwf	arg1_lo
	movf	arg3_lo,W		;get the modulus, only the lowest nibble is non-zero
	movwf	b0_tmp1_lo		;and save it
	clrf	arg2_hi
	clrf	arg2_lo
	call	modulusd10
	movf	arg4_hi,W		;move the result back into arg1 for doing the next nibble
	movwf	arg1_hi
	movf	arg4_lo,W
	movwf	arg1_lo
	swapf	arg3_lo,W		;move the modulus to the next higher nibble and put it in W
	iorwf	b0_tmp1_lo,F	;and merge it into the holding register
	clrf	arg2_hi
	clrf	arg2_lo
	call	modulusd10
	movf	arg4_hi,W		;move the result back into arg1 for doing the next nibble
	movwf	arg1_hi
	movf	arg4_lo,W
	movwf	arg1_lo
	movf	arg3_lo,W		;get the modulus, only the lowest nibble is non-zero
	movwf	b0_tmp1_hi		;and save it
	clrf	arg2_hi
	clrf	arg2_lo
	call	modulusd10
	swapf	arg3_lo,W		;move the modulus to the next higher nibble and put it in W
	iorwf	b0_tmp1_hi,F	;and merge it into the holding register
	movf	b0_tmp1_lo,W	;now put the binary_to_decimal result into the returning register
	movwf	arg2_lo
	movf	b0_tmp1_hi,W
	movwf	arg2_hi
	return




;*****************************************************
;*****************************************************
;
;	Name:		divide32bd10
;				and
;				modulusd10
;	
;	Abstract:	Divides a 32 bit binary number by decimal 10
;
;	Callable Routines:
		global	divide32bd10
		global	modulusd10
;
;	Called Routines:  None
;
;	Global Variables Used:
;		arg1_wrd contains the low word dividend (value is NOT preserved)
;		arg2_wrd contains the high word dividend (value is NOT preserved)
;
;	Local Variables Used:
;		b0_tmp5_lo contains a working register
;		b0_tmp5_hi contains a bit counter for doing the 32 bits worth of dividing
;
;	Return Values:
;		arg3_lo contains the modulus
;		arg4_wrd contains the low word result
;		arg5_wrd contains the high word result
;		
;*****************************************************
;*****************************************************

divide32bd10
modulusd10
	banksel	BANK0
	clrf	arg4_lo			;Clear the result registers
	clrf	arg4_hi
	clrf	arg5_lo
	clrf	arg5_hi
	clrf	b0_tmp5_lo		;Clear the working register
	movlw	0x20			;A counter for 32 bits of "division"
	movwf	b0_tmp5_hi

d32bd10_1
	rlf		arg1_lo,F
	rlf		arg1_hi,F
	rlf		arg2_lo,F
	rlf		arg2_hi,F		;Carry flag now has the most significant bit of the dividend word
	rlf		b0_tmp5_lo,F
	movlw	0x0a			;"Divide by 10."
	subwf	b0_tmp5_lo,W
	btfsc	STATUS,C
	goto	d32bd10_result_was_positive
	rlf		arg4_lo,F		;The subtraction was negative, so shift a zero into the result
	rlf		arg4_hi,F
	rlf		arg5_lo,F
	rlf		arg5_hi,F
	decfsz	b0_tmp5_hi,F	;Decrement the counter and check for done with 32 bits
	goto	d32bd10_1		;Loop to do another bits worth
	goto	d32bd10_done_with_division
d32bd10_result_was_positive
	bsf		STATUS,C		;The subtraction was positive, so rotate a one into the result
	rlf		arg4_lo,F
	rlf		arg4_hi,F
	rlf		arg5_lo,F
	rlf		arg5_hi,F
	movlw	0x0a
	subwf	b0_tmp5_lo,F	;So do the subtraction again, but this time keep the result
	decfsz	b0_tmp5_hi,F	;Decrement the counter and check for done with 32 bits
	goto	d32bd10_1		;Loop to get another bits worth
d32bd10_done_with_division
	movf	b0_tmp5_lo,W	;Get the left over, its the modulus
	movwf	arg3_lo

	return




;*****************************************************
;*****************************************************
;
;	Name:		delay_1pt5msec
;	
;	Abstract:	This routine sits around and delays for
;					1.5 milliseconds.
;
;	Callable Routines:
		global	delay_1pt5msec
;
;	Called Routines:  None.
;
;	Global Variables Used:  None.
;
;	Local Variables Used:
;		b0_tmp1_lo contains count up counter byte 0
;
;	Return Values:
;
;		
;*****************************************************
;*****************************************************

delay_1pt5msec					;4.00MHz clock/4  = 1000ns/cpu cycle
	clrf	b0_tmp1_lo
d1pt5ms_1
	nop							;1 cycle
	nop							;1 cycle
	nop							;1 cycle
	incfsz	b0_tmp1_lo,F		;1 cycle
	goto	d1pt5ms_1			;2 cycles / => 256 loops x 6 cycles each = 1.536msec
	return




;*****************************************************
;*****************************************************
;
;	Name:		delay_50msec
;	
;	Abstract:	This routine sits around and delays 50msec
;
;	Callable Routines:
		global	delay_50msec
;
;	Called Routines:  None.
;
;	Global Variables Used:
;		Selectively: arg1_lo contains number of 50msec delays to do
;
;	Local Variables Used:
;		b0_tmp1_lo contains count up counter byte 0
;		b0_tmp1_hi contains count up counter byte 1
;		b0_tmp2_lo contains count down counter for the number
;			of 50 millisecond intervals to delay
;
;	Return Values:
;
;		
;*****************************************************
;*****************************************************

delay_50msec					;Assumes a 4.00MHz clock/4  = 1000ns/cpu cycle
	banksel	BANK0

;	movf	arg1_lo,W			;Uncomment when coding 50msec*arg1_lo delays
	movlw	0x01				;Uncomment when coding a forced number of 50msec delays

	movwf	b0_tmp2_lo
	movlw	0x00
	movwf	b0_tmp1_lo
	movlw	0xea
	movwf	b0_tmp1_hi
d50ms_1
	incfsz	b0_tmp1_lo,F		;1 cycle
	goto	d50ms_1				;2 cycles
	incfsz	b0_tmp1_hi,F		;1 cycle
	goto	d50ms_1				;2 cycles
	decfsz	b0_tmp2_lo,F		;1 cycle
	goto	d50ms_1				;2 cycles

	return




;*****************************************************
;*****************************************************
;
;	Name:		delay_250msec
;	
;	Abstract:	This routine sits around and delays 250msec
;
;	Callable Routines:
		global	delay_250msec
;
;	Called Routines:  None.
;
;	Global Variables Used:  None.
;
;
;	Local Variables Used:
;		b0_tempw	Used to Save and Restore W Register
;
;	Return Values:  None.
;
;		
;*****************************************************
;*****************************************************

delay_250msec
	movwf	b0_tempw	;Save the current value in W
	call	delay_50msec
	call	delay_50msec
	call	delay_50msec
	call	delay_50msec
	call	delay_50msec
	movf	b0_tempw,W	;Restore the original W value
	return



	end
;End of File (utilities.asm)
