;******************************************************
;******************************************************
;
; Main Project     : FT301D
; Project Name     : FT301D - Replacement Digital Display
; File Name        : utilities.asm
; Version          : A03
; PIC Used         : PIC16F887
; Assembler        : MPLAB MPASMWIN from Microchip Technology, Inc.
; Initial Date     : May 1, 2011
; Last Update date : May 1, 2011
; Firmware Eng.    : WA7ZVY
; HW Design Eng.   : WA7ZVY
;
;******************************************************
;
; Description of this code:
;
; These routines provide various utility functions.
;
;******************************************************
;
;	Function List (in top-2-bottom order):
;		long binary_to_decimal(long binary_word)
;		long divide_by_n(long dividend, long divisor)
;		long divide32_by_n16(long dividend, long divisor)
;		void delay_100msec(char delay_time)
;
;
;******************************************************
;
;   Modification History:
;   =-=-=-=-=-=-=-=-=-=-=
;   20110501 pm - Initial creation.
;
;******************************************************
;******************************************************
;
;******************************************************
;   === Include files ===
;******************************************************
	LIST   P=16F887				;List directive to define processor

#include	P16F887.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
;				modulus
;	
;	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_100msec
;	
;	Abstract:	this routine sits around and delays for
;					delay_time * 100 milliseconds.
;
;	Callable Routines:
		global	delay_100msec
;
;	Called Routines:  None.
;
;	Global Variables Used:
;		arg1_lo contains the number of 100 millisecond intervals to delay
;
;	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 up counter byte 2
;		b0_tmp2_hi contains count up counter byte 3
;		b0_tmp3_lo contains count down counter for the number
;			of 100 millisecond intervals to delay
;
;	Return Values:
;
;		
;*****************************************************
;*****************************************************

delay_100msec
	banksel	BANK0
	movf	arg1_lo,W
	movwf	b0_tmp3_lo
	movlw	0xcf
	movwf	b0_tmp1_lo
	movlw	0xcf
	movwf	b0_tmp1_hi
	movlw	0xcf
	movwf	b0_tmp2_lo
	movlw	0xff
	movwf	b0_tmp2_hi
d100ms_1						;8.00MHz clock/4  =  500ns/cpu cycle
	incfsz	b0_tmp1_lo,F		;1 cycle
	goto	d100ms_1			;2 cycles
	movlw	0xdc
	movwf	b0_tmp1_lo
	incfsz	b0_tmp1_hi,F		;1 cycle
	goto	d100ms_1			;2 cycles
	movlw	0xdc
	movwf	b0_tmp1_hi
	incfsz	b0_tmp2_lo,F		;1 cycle
	goto	d100ms_1			;2 cycles
	movlw	0xdc
	movwf	b0_tmp2_lo
	incfsz	b0_tmp2_hi,F		;1 cycle
	goto	d100ms_1			;2 cycles
	movlw	0xff
	movwf	b0_tmp2_hi
	decfsz	b0_tmp3_lo,F		;1 cycle
	goto	d100ms_1			;2 cycles

	return



;*****************************************************
;*****************************************************
;
;	Name:		load_message
;	
;	Abstract:	this routine loads a message into the
;				LED digit memories and segment memories.
;
;	Callable Routines:
		global	load_message
;
;	Called Routines:
		extern	message_table, convert_to_segments
;
;	Global Variables Used:
;		arg1_lo contains the low byte of the address of
;			the message to load
;
;	Local Variables Used:
;		b0_digit0, b0_digit1, b0_digit2, b0_digit3,
;		b0_digit4, b0_digit5
;		b0_tmp1_lo
;
;	Return Values:  None
;
;		
;*****************************************************
;*****************************************************

load_message
	banksel	BANK0
	pagesel	message_table

	movf	arg1_lo,W
	call	message_table		;On return W has the character
	movwf	b0_digit5
	incf	arg1_lo,F
	movf	arg1_lo,W
	call	message_table		;On return W has the character
	movwf	b0_digit4
	incf	arg1_lo,F
	movf	arg1_lo,W
	call	message_table		;On return W has the character
	movwf	b0_digit3
	incf	arg1_lo,F
	movf	arg1_lo,W
	call	message_table		;On return W has the character
	movwf	b0_digit2
	incf	arg1_lo,F
	movf	arg1_lo,W
	call	message_table		;On return W has the character
	movwf	b0_digit1
	incf	arg1_lo,F
	movf	arg1_lo,W
	call	message_table		;On return W has the character
	movwf	b0_digit0

	pagesel	convert_to_segments
	call	convert_to_segments

	return



	end
;End of File (utilities.asm)
