
;---------------------------------------------------------------------------;
;			   BCD MATH ROUTINES				    ;
;		    Copyright (c) 1992, Robert Cobb			    ;
;									    ;
;   The following routines are offered to the public domain to help promote ;
;   the Parallax, Inc. development tools as well as the PIC (r) series of   ;
;   microcontrollers from Microchip Technology, Inc.			    ;
;---------------------------------------------------------------------------;


                DEVICE  PIC16C54,RC_OSC,WDT_OFF,PROTECT_OFF

		RESET	startup 	;Jump to startup on reset or power on


		org	8		;Start at beginning of RAM 
					;(can be 7 on PIC16C54 and '56)

bcd_num 	ds	1		;Place to hold the BCD number
count		ds	1		;Place to hold the binary number

accum		ds	1		;Used for math in bin2bcd routine


		org	0

;***************************************************************************
;  Test code for BCD routines
;***************************************************************************


startup
		clr	count		;Start with zero

		mov	FSR, #bcd_num	;Point FSR to where the BCD number
					;is to be stored
:loop		mov	W, count	;Load W with the number to convert

		call	bin2bcd 	;Call conversion routine

		call	inc_bcd 	;Increment the BCD number

		call	dec_bcd 	;Decrement the BCD number

		inc	count		;Go to next number

		jmp	:loop		;Loop through all numbers

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



;---------------------------------------------------------------------------
; Converts a binary number to BCD format (fast)
; Called with binary number in W and pointer to BCD number in FSR
; If the binary number is greater than 99, Z is set to 1, and the BCD number
; is set to 00h

bin2bcd
		mov	accum, W	;Save binary value
		clr	INDIRECT	;Start with 00h in result
		cja	accum, #99,:ov	;Overflow if greater than 99

		sub	accum, #10 * 8	;Divide by 10 using weighted subtract
		rl	INDIRECT	;Rotate bit into result
		sb	INDIRECT.0	;Skip value restore if no underflow
		add	accum, W	;Underflow, restore value

		sub	accum, #10 * 4	;
		rl	INDIRECT	;
		sb	INDIRECT.0	;
		add	accum, W	;
					;
		sub	accum, #10 * 2	;\
		rl	INDIRECT	;  \
		sb	INDIRECT.0	;  / Do all four bits of divide
		add	accum, W	;/
					;
		sub	accum, #10	;
		rl	INDIRECT	;
		sb	INDIRECT.0	;
		add	accum, W	;

		swap	INDIRECT	;Move result of divide to ten's place
		or	INDIRECT, accum ;Add one's place (remainder)

                clz                     ;Indicate valid BCD conversion
		ret			;Return with Z=0

:ov		stz			;Overflow, return 00 in bcd and Z set
		ret


;------------------------------------------------------------
; Increment number in BCD format
; On overflow, Z is set to 1 and BCD number is set to 00h
; If no overflow, Z is cleared to 0
;
; Called with pointer to BCD number in FSR
;

inc_bcd
		add	INDIRECT, #07h	;Test for overflow of one's place
		mov	W, #06h 	;Set up for possible sub
                sb      DC
		sub	INDIRECT, W	;If no DC, sub 06h to inc by 1

		mov	W, #60h 	;Test for overflow of ten's place
		add	INDIRECT, W	;C will be set if INDIRECT = A0h
		sc			;Leave value alone if overflow
		sub	INDIRECT, W	;No overflow - restore value

		ret			;Z will be set if overflow to zero


;------------------------------------------------------------
; Decrement number in BCD format
; On underflow, Z is set to 1 and BCD number is set to 99h
; Else, Z is cleared to zero
;
; Called with pointer to BCD number in FSR
;

dec_bcd
		sub	INDIRECT, #1	;Sub 1 to set C and DC flags
		mov	W, #06h 	;Set up for one's underflow
		sc			;If C set, possible one's underflow
		mov	W, #66h 	;Set up for ten's underflow
		sb	DC		;Leave alone if no underflow
		sub	INDIRECT, W	;Else, sub either 06h or 66h depending
					;on a one's or ten's underflow
		mov	W, #99h 	;Test for underflow
		mov	W, INDIRECT - W ;Z flag set if equal to 99 (underflow)
		ret



