## Arithmetic Operations

April 15, 2013 Coded in ASM for the Microchip PIC16

Arithmetic Operations for PIC microcontroller

``````UDATA
HIBYTE	RES	1
LOBYTE	RES	1
COUNTX	RES	1
MULCND	RES	1
MULPLR	RES	1
BCD	RES	2
ACCaLO	res	1
ACCaHI	res	1
ACCbLO	res	1
ACCbHI	res	1
ACCcLO	res	1
ACCcHI	res	1
ACCdLO	res	1
ACCdHI	res	1
R2	res	1
R1	res	1
R0	res	1
TEMPX	res	1
L_temp	res	1
H_temp	res	1
w_save	res	1
RandHi	res	1
RandLo	res	1
parity	res	1

;*************************************************************************
; Multiplication MULPLR(8 bit) x MULCND(8 bit) -->HIBYTE(msb),LOBYTE(lsb)*
; a) Load the multiplier in the location MULPLR				 *
; b) Load the multiplicant in the location MULCND			 *
; c) Call Mpy8x8						         *
; d) Msb is in the location HIBYTE					 *
; e) Lsb is in the location LOBYTE					 *
;*************************************************************************
Mpy8x8
clrf	HIBYTE
clrf	LOBYTE
clrf	COUNTX
bsf	COUNTX, 3

movf	MULCND, W
LoopX
bcf	STATUS, C
btfsc	MULPLR, 0
rrf	HIBYTE, f
rrf	LOBYTE, f
bcf	STATUS, C
rrf	MULPLR, f
decfsz	COUNTX, f
goto	LoopX
return
;*******************************************************************
;Multiplication: ACCb(16 bits)*ACCa(16 bits) -> ACCb,ACCc (32 bits)*
;(a) Load the 1st operand in location ACCaLO & ACCaHI (16 bits)	   *
;(b) Load the 2nd operand in location ACCbLO & ACCbHI (16 bits)    *
;(c) CALL Mpy_16bit						   *
;(d) The 32 bit result is in location (ACCbHI,ACCbLO,ACCcHI,ACCcLO)*
;*******************************************************************
Mpy_16bit
movlw	.16 		; for 16 shifts
movwf	temp
movf	ACCbHI,W	; move ACCb to ACCd
movwf	ACCdHI
movf	ACCbLO,W
movwf	ACCdLO
clrf	ACCbHI
clrf	ACCbLO
Mloop
rrf	ACCdHI, F	 ;rotate d right
rrf	ACCdLO, F
rrf	ACCbHI, F
rrf	ACCbLO, F
rrf	ACCcHI, F
rrf	ACCcLO, F
decfsz	temp, F 	;loop until all bits checked
goto	Mloop
return

;******************************************************************
;This routine convert the hex value present in the WREG to decimal*
;and store the results in the reg: BCD and BCD+1  		  *
;******************************************************************
BinBCD
clrf	BCD
clrf	BCD+1
Again1
addlw	0x9C	;subtract 100 and check for borrow
btfss	STATUS, C
incf	BCD+1, f
goto	Again1
Again
addlw	0xF6	;subtract 10 and check for borrow
btfss	STATUS, C
goto	SwapBCD
incf	BCD, f
goto	Again

SwapBCD
swapf	BCD, f
iorwf	BCD, f
return

;***************************************************************
;This routine find the square of the number present in the WREG*
;The hex result is stored in WREG and the decimal result is    *
;stored in GPRs BCD and BCD+1                                  *
;***************************************************************
square
movwf	COUNTX
movlw	0x01
movwf	TEMPX
clrw
r_square
incf	TEMPX,F
incf	TEMPX,F
decfsz	COUNTX,F
goto	r_square
movwf	w_save
call	BinBCD
movf	w_save,W
return
;*******************************************************************
;This routine find the square root of a number which is stored in  *
;WREG.The result is stored in WREG.If the number hasn't a finite   *
;square root this function returns an error value EE in WREG       *
;*******************************************************************
square_root
movwf	w_save
movlw	0x01
movwf	TEMPX
movwf	COUNTX
loop
movf	TEMPX,W
subwf	w_save,f
btfsc	STATUS,Z
goto	zero
btfss	STATUS,C
goto	no_root
incf	COUNTX,F
incf	TEMPX,F
incf	TEMPX,F
goto	loop
zero
movf	COUNTX,W
return
no_root
movlw	0XEE
return

;********************************************************************
; Binary To BCD Conversion Routine				    *
; This routine converts a 16 Bit binary Number to a 5 Digit	    *
; BCD Number.							    *
; The 16 bit binary number is input in locations ACCaHI and         *
; ACCaLO with the high byte in ACCaHI.				    *
; The 5 digit BCD number is returned in R0, R1 and R2 with R0	    *
; containing the MSD in its right most nibble.			    *
;********************************************************************
Hex_to_Dec
bcf	STATUS, C
clrf	COUNTX
bsf	COUNTX, 4	;set count to 16
clrf	R0
clrf	R1
clrf	R2
Loop16a
rlf	ACCaLO, f
rlf	ACCaHI, f
rlf	R2, f
rlf	R1, f
rlf	R0, f
decfsz	COUNTX, f
return
movwf	FSR
incf	FSR, f
incf	FSR, f
goto	Loop16a

movf	INDF, w
movwf	TEMPX
btfsc	TEMPX,3;test if result > 7
movwf	INDF
movf	INDF, w
movwf	TEMPX
btfsc	TEMPX, 7	;test if result > 7
movwf	INDF	;save as MSD
return
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Division : ACCb(16 bits) / ACCa(16 bits) -> ACCd(16 bits) with  ;
; Remainder in ACCc (16 bits)					  ;
; (a) Load the Denominator in location ACCaHI & ACCaLO ( 16 bits );
; (b) Load the Numerator in location ACCbHI & ACCbLO ( 16 bits )  ;
; (c) CALL Division						  ;
; (d) The 16 bit result is in location ACCdHI & ACCdLO		  ;
; (e) The 16 bit Remainder is in locations ACCcHI & ACCcLO	  ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Division
clrf	COUNTX
bsf	COUNTX,4 ; set count = 16
clrf	ACCcHI
clrf	ACCcLO
clrf	ACCdLO
clrf	ACCdHI
divLoop
bcf	STATUS,C
rlf	ACCbLO,F
rlf	ACCbHI,F
rlf	ACCcLO,F
rlf	ACCcHI,F
movf	ACCaHI,W
subwf	ACCcHI,W ; check if a>c
btfss	STATUS,Z
goto	notz
movf	ACCaLO,W
subwf	ACCcLO,W ; if msb equal then check lsb
notz
btfss	STATUS,C ; carry set if c>a
goto	nosub	 ; if c < a
subca
movf	ACCaLO,W ; c-a into c
subwf	ACCcLO, F
movf	ACCaHI,W
subwf	ACCcHI, F
bsf	STATUS,C ; shift a 1 into d (result)
nosub
rlf	ACCdLO,F
rlf	ACCdHI,F
decfsz	COUNTX,F
goto	divLoop

return
;*******************************************************************
; Random Number Generator					   *
; This routine generates a 16 Bit Pseudo Sequence Random Generator *
; It is based on Linear shift register feedback. The sequence	   *
; is generated by (Q15 xorwf Q14 xorwf Q12 xorwf Q3 )		   *
; The 16 bit random number is in location RandHi(high byte)	   *
; & RandLo (low byte)						   *
; Before calling this routine, make sure the initial values	   *
; of RandHi & RandLo are NOT ZERO				   *
; A good chiose of initial random number is 0x3045		   *
;*******************************************************************
Random16
rlf	RandHi,W
xorwf	RandHi,W
movwf	w_save
rlf	w_save, F ; carry bit = xorwf(Q15,14)
swapf	RandHi, F
swapf	RandLo,W
movwf	w_save
rlf	w_save, F
xorwf	RandHi,W ; LSB = xorwf(Q12,Q3)
swapf	RandHi, F
andlw	0x01
rlf	RandLo, F
xorwf	RandLo, F
rlf	RandHi, F
return

;**********************************************************************
; BCD To Binary Conversion					      *
; This routine converts a 5 digit BCD number to a 16 bit binary	      *
; number.							      *
; The input 5 digit BCD numbers are asumed to be in locations	      *
; R0, R1 & R2 with R0 containing the MSD in its right most nibble.    *
; The 16 bit binary number is output in registers ACCaHI & ACCaLO     *
; ( high byte & low byte repectively ).				      *
; The method used for conversion is :				      *
; input number X = abcde ( the 5 digit BCD number )		      *
; X = abcde = 10[10[10[10a+b]+c]+d]+e				      *
;**********************************************************************
Dec_to_Hex
clrf	ACCaHI
movf	R0,W
andlw	0x0F
movwf	ACCaLO
call	mpy10a ; result = 10a+b
swapf	R1,W
call	mpy10b ; result = 10[10a+b]
movf	R1,W
call	mpy10b ; result = 10[10[10a+b]+c]
swapf	R2,W
call	mpy10b ; result = 10[10[10[10a+b]+c]+d]
movf	R2,W
andlw	0x0F
btfsc	STATUS,C
incf	ACCaHI, F ; result = 10[10[10[10a+b]+c]+d]+e
return		 ; BCD to binary conversion done

mpy10b
andlw	0x0F
btfsc	STATUS,C
incf	ACCaHI, F
mpy10a
bcf	STATUS,C ; multiply by 2
rlf	ACCaLO,W
movwf	L_temp
rlf	ACCaHI,W ; (H_temp,L_temp) = 2*N
movwf	H_temp
bcf	STATUS,C ; multiply by 2
rlf	ACCaLO, F
rlf	ACCaHI, F
bcf	STATUS,C ; multiply by 2
rlf	ACCaLO, F
rlf	ACCaHI, F
bcf	STATUS,C ; multiply by 2
rlf	ACCaLO, F
rlf	ACCaHI, F ; (H_byte,L_byte) = 8*N
movf	L_temp,W
btfsc	STATUS,C
incf	ACCaHI, F
movf	H_temp,W
return		 ; (H_byte,L_byte) = 10*N
;*********************************************************************************************
;This routine is used to find the parity bit(ODD or EVEN)an 8 bit no:stored in the WREG.     *
;The parity bit is stored in the LSB of parity reg.To find EVEN parity make the EVEN_PARITY  *
;definition TRUE.To find ODD parity make the EVEN_PARITY definition FALSE.  		     *
;*********************************************************************************************
find_parity
movwf	TEMPX
swapf	TEMPX,W
xorwf	TEMPX,W
movwf	parity
rrf	parity, F
rrf	parity, F
xorwf	parity,W
andlw	0x03
movwf	TEMPX
rrf	TEMPX,F
rrf	TEMPX,W
movwf	parity
#if	EVEN_PARITY
xorlw	0x01
movwf	parity
#endif
return

;************************************************************************
; Subtraction : ACCb(16 bits) - ACCa(16 bits) -> ACCb(16 bits)		*
; (a) Load the 1st operand in location ACCaLO & ACCaHI ( 16 bits )	*
; (b) Load the 2nd operand in location ACCbLO & ACCbHI ( 16 bits )	*
; (c) CALL Sub_16bit							*
; (d) The result is in location ACCbLO & ACCbHI ( 16 bits )		*
;************************************************************************
Sub_16bit
call	Neg_16bit
return

;************************************************************************
; Addition : ACCb(16 bits) + ACCa(16 bits) -> ACCb(16 bits)		*
; (a) Load the 1st operand in location ACCaLO & ACCaHI ( 16 bits )	*
; (b) Load the 2nd operand in location ACCbLO & ACCbHI ( 16 bits )	*
; (d) The result is in location ACCbLO & ACCbHI ( 16 bits )		*
;************************************************************************
movf	ACCaLO,W
btfsc	STATUS,C ; add in carry
incf	ACCbHI, F
movf	ACCaHI,W
return
;************************************************************************
; 2's Compliment: negate ACCa ( -ACCa -> ACCa )				*
; (a) Load the operand in location ACCaLO & ACCaHI ( 16 bits )		*
; (b) CALL Neg_16bit							*
; (c) The result is in location ACCaLO & ACCaHI ( 16 bits )		*
;************************************************************************
Neg_16bit
comf	ACCaLO, F ;
incf	ACCaLO, F
btfsc	STATUS,Z
decf	ACCaHI, F
comf	ACCaHI, F
return``````