(also 18Fmathstest.inc)
;.......;.......;.......;.......;.......;.......;.......;.......;.......;.......;.......;
;****************************************************************************************
; Filename: 18Fmathstest.asm *
; Date: 10/07/2013 *
; Author: Peter G Harrison *
; Company: PGH Consultants *
;****************************************************************************************
; Files required: 18F4520_g.lkr Generic linker script for the PIC18F4520 *
; P18F4520.inc *
; 18Fmathstest.inc Configuration definition *
;****************************************************************************************
;Revision History: *
;****************************************************************************************
;
;****************************************************************************************
processor 18F4520 ; *
list p=18F4520, n=65 ; define processor and pagelength *
#include <P18F4520.inc> ; processor specific variable definitions *
#include <18Fmathstest.inc> ; application specific config definitions *
errorlevel -302,-306 ; suppress message 302 from list file *
;****************************************************************************************
;
;****************************************************************************************
;Define data variables *
;****************************************************************************************
;****************************************************************************************
;ACCESS ram - addressed directly *
;Groups separated to assist in register visibility during debug *
;****************************************************************************************
;
;Maths - 4 byte accumulator registers
group0 udata_acs 0x000
acc1_6 res 1 ;
acc1_5 res 1 ;
acc1_4 res 1 ;
acc1_3 res 1 ;
acc1_2 res 1 ;
acc1_1 res 1 ;
;
group1 udata_acs 0x008
acc2_6 res 1 ;
acc2_5 res 1 ;
acc2_4 res 1 ; main results register
acc2_3 res 1 ;
acc2_2 res 1 ;
acc2_1 res 1 ;
;
group2 udata_acs 0x010
acc3_6 res 1 ;
acc3_5 res 1 ;
acc3_4 res 1 ;
acc3_3 res 1 ;
acc3_2 res 1 ;
acc3_1 res 1 ;
;
group3 udata_acs 0x018
acc4_6 res 1 ;
acc4_5 res 1 ;
acc4_4 res 1 ;
acc4_3 res 1 ;
acc4_2 res 1 ;
acc4_1 res 1 ;
;
group4 udata_acs 0x020
mult_tmp res 1 ; maths temporary store
shft_cnt res 1 ; multiplication and division loop count
;
;=======================================================================================*
;End of data area definition *
;=======================================================================================*
;
;****************************************************************************************
;Baud rate constant calculations *
;****************************************************************************************
;
;Serial I/O base frequency and system clock
xtal_f equ d'7372800' ; OSC freq in Hz (gives exact baud rates)
;
baud_9600 equ (xtal_f/(4*d'9600'))-1
baud_19200 equ (xtal_f/(4*d'19200'))-1
baud_38400 equ (xtal_f/(4*d'38400'))-1
baud_57600 equ (xtal_f/(4*d'57600'))-1
baud_115200 equ (xtal_f/(4*d'115200'))-1
;
;Calculate baudrate when BRGH = 1
#define calc(baudrate) (xtal_f/(4*d'baudrate'))-1
;
;****************************************************************************************
;
;========================================================================================
;Start of Programme *
;========================================================================================
;
RESET_VECTOR CODE 0x000 ; processor reset vector
goto Start ; go to initialisation
;
HPINT_VECTOR CODE 0x008 ; processor interrupt vector
goto hprinth ; go to high priority interrupt handler routines
;
LPINT_VECTOR CODE 0x018 ; processor interrupt vector
goto lprinth ; go to low priority interrupt handler routines
;
;
;****************************************************************************************
;****************************************************************************************
MAIN CODE 0x050 ; allow room for message strings
;
;========================================================================================
;High priority interrupt routines *
;========================================================================================
;
hprinth retfie ; return from interrupt and re-enable
;
;========================================================================================
;Low priority interrupt routines *
;========================================================================================
;
lprinth retfie ; return from interrupt and re-enable
;
;
;========================================================================================
;Main *
;========================================================================================
;
; clr1_4 ; acc1_4, acc1_3, acc1_2, acc1_1 = 0
; clr1_2 ; acc1_2, acc1_1 = 0
; clr2_4 ; acc2_4, acc2_3, acc2_2, acc2_1 = 0
; clr2_2 ; acc2_2, acc2_1 = 0
; clr3_4 ; acc1_4, acc1_3, acc1_2, acc1_1 = 0
; clr3_2 ; acc1_2, acc1_1 = 0
; clr4_4 ; acc2_4, acc2_3, acc2_2, acc2_1 = 0
; clr4_2 ; acc2_2, acc2_1 = 0
;
; sub16 ; 16 bit subtract, acc2 - acc1 -> acc2
; add16 ; 16 bit add, acc2 + acc1 -> acc2
;
; inc2 ; 32 bit increment acc2 + 1 -> acc2
; dec2 ; 32 bit decrement acc2 - 1 -> acc2
;
; sub32 ; 32 bit subtract, acc2 - acc1 -> acc2
; add32 ; 32 bit add, acc2 + acc1 -> acc2
;
; comp1 ; 32 bit 2's complement -acc1 -> acc1
; comp2 ; 32 bit 2's complement -acc2 -> acc2
;
; mul16 ; 16*16 multiply, acc2 x acc1 -> acc2
; div2by1 ; 32/16 divide, acc2/acc1 -> acc2 (R hi, Q lo)
; div32 ; 32/16 divide, acc2/acc1 -> acc2 (R hi, Q lo)
; div48 ; 48/24 divide, acc2/acc1 -> acc2 (R hi, Q lo)
;
; sqrt16 ; 16 bit square root acc2_2:acc2_1 -> acc2_1
; sqrt32 ; 32 bit square root acc2_4:acc2_1 -> acc1_2:1
;
;========================================================================================
;
begin
;========================================================================================
;Maths Routines *
;========================================================================================
;Development basic maths routines
call sub32 ; 32 bit subtract, acc2 - acc1 -> acc2
call add32 ; 32 bit add, acc2 + acc1 -> acc2
call comp1 ; 32 bit 2's complement -acc1 -> acc1
call comp2 ; 32 bit 2's complement -acc2 -> acc2
call mul16 ; 16*16 multiply, acc2 x acc1 -> acc2
call div2by1 ; 32/16 divide, acc2/acc1 -> acc2 (R hi, Q lo)
call sqrt16 ; 16 bit square root acc2_2/1 -> acc2_1
call sqrt32 ; 32 bit square root acc2_4:acc2_1 -> acc1_2/1
call sqrt48 ; 48 bit square root acc2_6:acc2_1 -> acc1_3/2/1
;
;Test routines
call sqrt16test ; test routine for 16 bit square root extraction
call sqrt32test ; test routine for 32 bit square root extraction
call sqrt48test ; test routine for 48 bit square root extraction
goto begin ;
;
;========================================================================================
;Clear accumulators acc1 to to acc4
;========================================================================================
;
clr1_6 clrf acc1_6 ; clear acc1
clrf acc1_5 ;
clr1_4 clrf acc1_4 ;
clrf acc1_3 ;
clr1_2 clrf acc1_2 ;
clrf acc1_1 ;
return
;
clr2_6 clrf acc2_6 ; clear acc2
clrf acc2_5 ;
clr2_4 clrf acc2_4 ;
clrf acc2_3 ;
clr2_2 clrf acc2_2 ;
clrf acc2_1 ;
return
;
clr3_6 clrf acc3_6 ; clear acc3
clrf acc3_5 ;
clr3_4 clrf acc3_4 ;
clrf acc3_3 ;
clr3_2 clrf acc3_2 ;
clrf acc3_1 ;
return
;
clr4_6 clrf acc4_6 ; clear acc4
clrf acc4_5 ;
clr4_4 clrf acc4_4 ;
clrf acc4_3 ;
clr4_2 clrf acc4_2 ;
clrf acc4_1 ;
return
;
;========================================================================================
;Unsigned 16 bit subtract. acc2_2:acc2_1 - acc1_2:acc1_1 -> acc2_2:acc2_1 *
;========================================================================================
;
sub16 movf acc1_1,w ; unsigned 16 bit subtract
subwf acc2_1 ;
movf acc1_2,w ;
subwfb acc2_2 ;
return
;
;========================================================================================
;Unsigned 32 bit subtract. acc2_4:acc2_1 - acc1_4:acc1_1 -> acc2_4:acc2_1 *
;========================================================================================
;
sub32 movf acc1_1,w ; unsigned 32 bit subtract
subwf acc2_1 ;
movf acc1_2,w ;
subwfb acc2_2 ;
movf acc1_3,w ;
subwfb acc2_3 ;
movf acc1_4,w ;
subwfb acc2_4 ;
return
;
;========================================================================================
;Unsigned 48 bit subtract. acc2_6:acc2_1 - acc1_6:acc1_1 -> acc2_6:acc2_1 *
;========================================================================================
;
sub48 movf acc1_1,w ; unsigned 32 bit subtract
subwf acc2_1 ;
movf acc1_2,w ;
subwfb acc2_2 ;
movf acc1_3,w ;
subwfb acc2_3 ;
movf acc1_4,w ;
subwfb acc2_4 ;
movf acc1_5,w ;
subwfb acc2_5 ;
movf acc1_6,w ;
subwfb acc2_6 ;
return
;
;========================================================================================
;Unsigned 16 bit add. acc2_2:acc2_1 + acc1_2:acc1_1 -> acc2_2:acc2_1 *
;========================================================================================
;
add16 movf acc1_1,w ; unsigned 16 bit add
addwf acc2_1 ;
movf acc1_2,w ;
addwfc acc2_2 ;
return
;
;========================================================================================
;Unsigned 32 bit add. acc2_4:acc2_1 + acc1_4:acc1_1 -> acc2_4:acc2_1 *
;========================================================================================
;
add32 movf acc1_1,w ; unsigned 32 bit add
addwf acc2_1 ;
movf acc1_2,w ;
addwfc acc2_2 ;
movf acc1_3,w ;
addwfc acc2_3 ;
movf acc1_4,w ;
addwfc acc2_4 ;
return
;
;========================================================================================
;Unsigned 48 bit add. acc2_6:acc2_1 + acc1_6:acc1_1 -> acc2_6:acc2_1 *
;========================================================================================
;
add48 movf acc1_1,w ; unsigned 32 bit add
addwf acc2_1 ;
movf acc1_2,w ;
addwfc acc2_2 ;
movf acc1_3,w ;
addwfc acc2_3 ;
movf acc1_4,w ;
addwfc acc2_4 ;
movf acc1_5,w ;
addwfc acc2_5 ;
movf acc1_6,w ;
addwfc acc2_6 ;
return
;
;========================================================================================
;2's complement acc1_4:acc1_1 *
;========================================================================================
;
comp1 comf acc1_1 ; complement acc1
comf acc1_2 ;
comf acc1_3 ;
comf acc1_4 ;
incfsz acc1_1,f ;
return ;
incfsz acc1_2,f ;
return ;
incfsz acc1_3,f ;
return ;
incfsz acc1_4,f ;
return
;
;========================================================================================
;2's complement acc1_4:acc1_1 *
;========================================================================================
;
comp2 comf acc2_1 ; complement acc2
comf acc2_2 ;
comf acc2_3 ;
comf acc2_4 ;
incfsz acc2_1,f ;
return ;
incfsz acc2_2,f ;
return ;
incfsz acc2_3,f ;
return ;
incfsz acc2_4,f ;
return
;
;========================================================================================
;Unsigned 32/16 bit division (approx 552 to 712 cycles)
;Inputs: Dividend - acc2_4 -> acc2_1 (32 bits)
; Divisor - acc1_2 -> acc1_1 (16 bits)
;Temporary: Counter - count
;Output: Quotient - acc2_2 -> acc2_1 (32 bits)
; Remainder- acc1_4 -> acc1_3 (16 bits)
;========================================================================================
;
div32 movlw d'32' ; 32-bit divide by 16-bit
movwf shft_cnt
clrf acc1_4 ; clear remainder
clrf acc1_3
;
dvloop bcf STATUS,C ; set quotient bit to 0, shift left dividend & quotient
rlcf acc2_1 ; low byte
rlcf acc2_2
rlcf acc2_3
rlcf acc2_4 ; msb into carry
rlcf acc1_3 ; and then into partial remainder
rlcf acc1_4
;
bc subdiv ; if overflow then remainder > divisor so can subtract
movf acc1_2,w ; compare partial remainder and divisor
subwf acc1_4,w
bnz testgt ; if hi bytes =, check low bytes, else check for >
;
movf acc1_1,w ; high bytes are = so compare low bytes
subwf acc1_3,w
testgt bnc remrlt ; if carry set remainder > divisor, so ok to subtract
;
subdiv movf acc1_1,w ; subtract divisor from partial remainder
subwf acc1_3,f
movf acc1_2,w
subwfb acc1_4,f
bsf acc2_1,0 ; set quotient bit to 1
; ; quotient replaces dividend which is lost
remrlt decfsz shft_cnt
goto dvloop
return
;
;========================================================================================
;Unsigned 32 / 16 bits division *** NOT SURE ABOUT THIS ROUTINE !!!! ******
;Dividend in acc2_ (max val H'FFFE0001' =4,294,836,225)
;Divisor in acc1_ (max value H'FFFF' =65,535)
;Ensure being within range or if a division by zero is going to happen.
;
;Return: quotient in acc2_2:1 (16 bits) and remainder in acc2_4:3 (16 bits)
;Result of acc2_4:acc2_1 / acc1_2:acc1_1 => acc2_2:acc2_1 (quotient)
;affected register: shft_cnt
;Typically 262 cycles
;========================================================================================
;
div2by1 movlw d'16' ;initialize the
movwf shft_cnt ;shift counter
;
divloop bcf STATUS,C ;we ensure that b0
rlcf acc2_1,f ;of acc2_1 is =0
rlcf acc2_2,f ;after the shifting
rlcf acc2_3,f ;to the left of the
rlcf acc2_4,f ;whole dividend
;
;Test carry flag, if = 1, then shift caused overflow so subtract acc1_1 from acc2_3
bc subtrct
movf acc1_2,w ; compare acc1_2
subwf acc2_4,w ; against acc2_4
;
;Test zero flag, if = 0,then acc1_2 != acc2_4. so check if acc1_2 < acc2_4
bnz acc1les
movf acc1_1,w ; acc1_2 = acc2_4; now compare
subwf acc2_3,w ; value of acc1_1 against acc2_3
;
;Test carry flag, if = 1, then DSOR_ < DEND_ , so subtract acc1_2:L from acc2_4:2
acc1les bnc dec_ctr
;
;subtract divisor from MSBs of dividend
subtrct movf acc1_1,w ; acc2_3 = acc2_3 - acc1_1
subwf acc2_3,f ; borrow not used (LSB)
movf acc1_2,w ; acc2_4 = acc2_4 - acc1_2
subwfb acc2_4,f ; borrow used
bsf acc2_1,0 ; flag "divisor was substracted from dividend"
;
dec_ctr decfsz shft_cnt,f
bra divloop
return ; finished
;
;========================================================================================
;Unsigned 48/24 bit division (approx 967 to 1447 cycles)
;Inputs: Dividend - acc2_6 -> acc2_1 (48 bits)
; Divisor - acc1_3 -> acc1_1 (24 bits)
;Temporary: Counter - shft_cnt
;Output: Quotient - acc2_6 -> acc2_1 (48 bits)
; Remainder- acc1_6 -> acc1_4 (24 bits)
;========================================================================================
;
div48 movlw d'48' ; 48-bit divide by 24-bit
movwf shft_cnt
clrf acc1_6 ; Clear remainder
clrf acc1_5
clrf acc1_4
;
divdlp bcf STATUS,C ; Set quotient bit to 0, shift left dividend & quotient
rlcf acc2_1 ; low byte
rlcf acc2_2
rlcf acc2_3
rlcf acc2_4
rlcf acc2_5
rlcf acc2_6 ; most significant bit into carry
rlcf acc1_4 ; and then into partial remainder
rlcf acc1_5
rlcf acc1_6
;
bc subtdiv ; If overflow then remainder must be > divisor
;
;After subtraction, if Z set then check less significant bytes. If Z not set and C
;is set, partial remainder > divisor, so can subtract and set result bit in acc2
;
movf acc1_3,w ; Compare high bytes of partial remainder and divisor
subwf acc1_6,w
bnz test_gt ; bytes not equal, so check if remainder > divisor
;
movf acc1_2,w ; middle bytes of partial remainder and divisor
subwf acc1_5,w
bnz test_gt ; bytes not equal, so check if remainder > divisor
;
movf acc1_1,w ;
subwf acc1_4,w ;
test_gt bnc rmdrlt ; carry set if partial remainder > divisor
;
subtdiv movf acc1_1,w ; Subtract divisor from partial remainder
subwf acc1_4,f
movf acc1_2,w
subwfb acc1_5,f
movf acc1_3,w
subwfb acc1_6,f
bsf acc2_1,0 ; Set quotient bit to 1
; ; Quotient replaces dividend which is lost
rmdrlt decfsz shft_cnt
goto divdlp
return
;
;========================================================================================
;Unsigned 16 * 16 bit multiplication
;acc1_2:acc1_1 * acc2_2:acc2_1 -> acc2_4:acc2_1
;acc1 value remains unchanged.
;affected register: mult_tmp
;28cycles
;========================================================================================
;
mul16 movf acc2_2,w
mulwf acc1_2 ; acc1_2 * acc2_2
movff PRODH,acc2_4 ; into result
movff PRODL,acc2_3
;
movf acc2_1,w
mulwf acc1_1 ; acc1_1 * acc2_1;
movff PRODH,mult_tmp
movff PRODL,acc2_1
;
mulwf acc1_2 ; acc1_2 * acc2_1
movf PRODL,w
addwf mult_tmp,f ; Add cross
movf PRODH,w ; products
addwfc acc2_3,f
clrf WREG
addwfc acc2_4,f
;
movf acc2_2,w
mulwf acc1_1 ; acc1_1 * acc2_2
movf PRODL,w ;
addwf mult_tmp,w ; Add cross
movwf acc2_2
movf PRODH,w ; products
addwfc acc2_3,f
clrf WREG
addwfc acc2_4,f
return
;
;========================================================================================
; Unsigned 24 * 24 bit multiplication
; acc1_3:acc1_1 * acc2_3:acc2_1 -> acc2_6:acc2_1
; 148 cycles, including initial moves and register clearances
;========================================================================================
mul24 movff acc2_3,acc3_6
movff acc2_2,acc3_5
movff acc2_1,acc3_4
movff acc1_3,acc3_3
movff acc1_2,acc3_2
movff acc1_1,acc3_1
;
call clr2_6
call clr1_6
;
movf acc3_6,w
mulwf acc3_1
movff PRODH,acc2_4
movff PRODL,acc2_3
;
movf acc3_3,w
mulwf acc3_4
movff PRODH,acc1_4
movff PRODL,acc1_3
;
call add48
;
movf acc3_2,w
mulwf acc3_6
movff PRODH,acc1_5
movff PRODL,acc1_4
;
mulwf acc3_4
movff PRODH,acc1_3
movff PRODL,acc1_2
;
call add48
;
movf acc3_5,w
mulwf acc3_3
movff PRODH,acc1_5
movff PRODL,acc1_4
;
mulwf acc3_1
movff PRODH,acc1_3
movff PRODL,acc1_2
;
call add48
;
movf acc3_6,w
mulwf acc3_3
movff PRODH,acc1_6
movff PRODL,acc1_5
;
movf acc3_5,w
mulwf acc3_2
movff PRODH,acc1_4
movff PRODL,acc1_3
;
movf acc3_4,w
mulwf acc3_1
movff PRODH,acc1_2
movff PRODL,acc1_1
;
call add48
;
return
;
;========================================================================================
;16 bit square root - sqrt16
;Return with carry set if negative
;
;Inputs: acc2_2 : acc2_1
;Output: acc2_1 returns with the 8 bit result
;
;30 Instructions 104 Cycles best case, 109 average, 122 worst case
;========================================================================================
;
sqrt16 movlw 0xc0 ;Initialize value for mask
movwf acc2_4 ;Mask
movlw 0x40 ;Initial value for the root
clrf STATUS
;
sq1 subwf acc2_2,f ;Subtract the root developed so far
btfss STATUS,C ;If it is larger than acc2_2
goto sq5 ;then go restore the subtraction
;
sq2 iorwf acc2_4,w ;Set the current bit
sq3 bcf STATUS,C ;!!!TEMP DEBUG - see move with no extra bits!!!
rlcf acc2_1,f ;Shift N left one position
rlcf acc2_2,f
rrcf acc2_4,f ;Shift the mask right, and pick up msb of N
btfsc acc2_4,7 ;If msb of N is set, then unconditionally
goto sq6 ;set the next bit (because subtracting the
; ;root is guranteed not to cause a borrow)
;
xorwf acc2_4,w ;Append "01" to the root developed so far
btfss STATUS,C ;If the lsb of mask was shifted into the carry
goto sq1 ;then we're done. Otherwise, loop again.
;
;We are almost done. In the last iteration, we have 7 bits of the root. When
;"01" is appended to it, we will have a 9-bit number that must be subtracted
;from N.
;
subwf acc2_2,f ;
btfss STATUS,C ;If the upper 7 bits cause a borrow, then
goto exitsq ;the appended "01" will as well: We're done.
;
btfsc STATUS,Z ;If the result of the subtraction is zero
btfsc acc2_1,7 ;AND the msb of acc2_1 is set then the LSB of the
; ;root is zero.
xorlw 1 ;Otherwise, it is one.
exitsq movwf acc2_1 ;result to acc2_1
clrf acc2_2 ;
return ;
;
sq6 btfsc STATUS,C ;Need to unconditionally set current bit of root.
goto exitsq ;However, if through iterating, then leave. Note,
;C is set by shifting mask right & the LSB of root
;was set by iorwf at sq2.
;
bcf acc2_4,7 ;Clear the MSB of N that got shifted into the mask.
xorwf acc2_4,w ;Append "01" to the root developed so far.
subwf acc2_2,f ;Subtract
goto sq2 ;Go unconditionally set the current bit.
;
sq5 addwf acc2_2,f ;Restore acc2_2 by reversing the subwf with a ADDWF
goto sq3 ;Don't set the current bit
;
;========================================================================================
; SQRT32
;; Calculates the square root of a 32 bit number using the binary restoring method.
;
; Input: acc2_4:acc2_1
; Mask: acc3_2:acc3_1
; Result: acc1_2:acc1_1
;
; Takes between 395 and 457 cycles (incl. call and return).
; Uses 64 words ROM, 8 bytes RAM including 4 holding the input.
;========================================================================================
;
sqrt32 movlw 0x40 ; Initial value for Result is...
movwf acc1_2 ; ... 01000000 00000000
clrf acc1_1 ;
;
movlw 0xC0 ; Initial value for mask is...
movwf acc3_2 ; ... 11000000 00000000
clrf acc3_1 ; (second '1' is loop counter).
;
compare movf acc1_1,w ; Compare root-so-far with current
subwf acc2_3,f ; ... remainder.
movf acc1_2,w ;
subwfb acc2_4,f ;
bc $+4 ;
goto restore ; result is -ve, so need to restore
;
setcurr movf acc3_1,w ; set the current bit in the result.
iorwf acc1_1,f ;
movf acc3_2,w ;
iorwf acc1_2,f ;
;
shftUp rlcf acc2_1,f ;
rlcf acc2_2,f ;
rlcf acc2_3,f ;
rlcf acc2_4,f ;
;
rrcf acc3_2,f ; Shift mask right for next bit, whilst
rrcf acc3_1,f ; ... shifting in MSB from remainder.
btfsc acc3_2,7 ; If MSB is set, unconditionally set the
goto setnext ; ... next bit.
;
movf acc3_1,w ; Append '01' to root-so-far
xorwf acc1_1,f ;
movf acc3_2,w ;
xorwf acc1_2,f ;
;
bc $+4 ; If second '1' in mask is shifted out,
goto compare ; ... then that was the last normal iteration.
;
movf acc1_1,w ; Last bit Generation.
subwf acc2_3,f ; ... The final subtract is 17-bit (15-bit root
movf acc1_2,w ; ... plus '01'). Subtract 16-bits: if result
subwfb acc2_4,f ; ... generates a carry, last bit is 0.
bc $+4 ;
return
;
movf acc2_3,w ; Clear zero flag if remainder non zero
xorwf acc2_4,w ;
;
movlw 1 ;
bnz $+4 ; If result is 0 AND msb of N is '0', result bit
btfsc acc2_2,7 ; ... is 0, otherwise '1'.
xorwf acc1_1,f ;
return
;
;
setnext bnc $+4 ; If mask has shifted out, leave. final bit
return ; ... has been set by iorwf at in1.
bcf acc3_2,7 ; clear bit shifted in from input.
;
movf acc3_1,w ; Append '01' to root-so-far
xorwf acc1_1,f ;
movf acc3_2,w ;
xorwf acc1_2,f ;
;
movf acc1_1,w ; This subtraction is guaranteed not to
subwf acc2_3,f ; ... cause a borrow, so subtract and
movf acc1_2,w ; ... jump back to insert a '1' in the
subwfb acc2_4,f ; ... root.
goto setcurr ;
;
restore movf acc1_1,w ; A subtract above at Sub_Cmp was -ve, so
addwf acc2_3,f ; ... restore the remainder by adding.
movf acc1_2,w ; The current bit of the root is zero.
addwfc acc2_4,f ;
goto shftUp ;
;
;========================================================================================
; SQRT48
; Calculates the square root of a 48 bit number using the binary restoring method.
; Input: acc2_6:acc2_1
; Mask: acc3_3:acc3_1
; Result: acc1_3:acc1_1
;
; Takes between 810 and 890 cycles (incl. call and return).
; Uses 84 words ROM, 10 bytes RAM including 4 holding the input.
;========================================================================================
;
sqrt48 movlw 0x40 ; Initial value for Result is...
movwf acc1_3 ; ... 01000000 00000000 00000000
clrf acc1_2 ;
clrf acc1_1 ;
;
movlw 0xC0 ; Initial value for mask is...
movwf acc3_3 ; ... 11000000 00000000 00000000
clrf acc3_2 ; (second '1' is loop counter).
clrf acc3_1 ;
;
comp movf acc1_1,w ; Compare root-so-far with current
subwf acc2_4,f ; ... remainder.
movf acc1_2,w ;
subwfb acc2_5,f ;
movf acc1_3,w ;
subwfb acc2_6,f ;
bc $+4 ;
goto undosub ; result is -ve, so need to restore
;
setbit movf acc3_1,w ; set the current bit in the result.
iorwf acc1_1,f ;
movf acc3_2,w ;
iorwf acc1_2,f ;
movf acc3_3,w ;
iorwf acc1_3,f ;
;
upshft rlcf acc2_1,f ;
rlcf acc2_2,f ;
rlcf acc2_3,f ;
rlcf acc2_4,f ;
rlcf acc2_5,f ;
rlcf acc2_6,f ;
;
rrcf acc3_3,f ; Shift mask right for next bit, whilst
rrcf acc3_2,f ; ... shifting in MSB from remainder.
rrcf acc3_1,f ;
btfsc acc3_3,7 ; If MSB is set, unconditionally set the
goto nextset ; ... next bit.
;
movf acc3_1,w ; Append '01' to root-so-far
xorwf acc1_1,f ;
movf acc3_2,w ;
xorwf acc1_2,f ;
movf acc3_3,w ;
xorwf acc1_3,f ;
;
bc $+4 ; If second '1' in mask is shifted out,
goto comp ; ... then that was the last normal iteration.
;
movf acc1_1,w ; Last bit Generation.
subwf acc2_4,f ; ... The final subtract is 15-bit (23-bit root
movf acc1_2,w ; ... plus '01'). Subtract 24-bits: if result
subwfb acc2_5,f ; ... generates a carry, last bit is 0.
movf acc1_3,w ;
subwfb acc2_6,f ;
bc $+4 ;
return
;
movf acc2_4,w ; Clear zero flag if remainder non zero
xorwf acc2_5,w ;
xorwf acc2_6,w ;
;
movlw 1 ;
bnz $+4 ; If result is 0 AND msb of N is '0', result bit
btfsc acc2_3,7 ; ... is 0, otherwise '1'.
xorwf acc1_1,f ;
return
;
;
nextset bnc $+4 ; If mask has shifted out, leave. final bit
return ; ... has been set by iorwf at in1.
bcf acc3_3,7 ; clear bit shifted in from input.
;
movf acc3_1,w ; Append '01' to root-so-far
xorwf acc1_1,f ;
movf acc3_2,w ;
xorwf acc1_2,f ;
movf acc3_3,w ;
xorwf acc1_3,f ;
;
movf acc1_1,w ; This subtraction is guaranteed not to
subwf acc2_4,f ; ... cause a borrow, so subtract and
movf acc1_2,w ; ... jump back to insert a '1' in the
subwfb acc2_5,f ; ... root.
movf acc1_3,w ;
subwfb acc2_6,f ;
goto setbit ;
;
undosub movf acc1_1,w ; A subtract above at Sub_Cmp was -ve, so
addwf acc2_4,f ; ... restore the remainder by adding.
movf acc1_2,w ; The current bit of the root is zero.
addwfc acc2_5,f ;
movf acc1_3,w ;
addwfc acc2_6,f ;
goto upshft ;
;
;========================================================================================
;End of Main Task *
;========================================================================================
;
;========================================================================================
;16 bit square root routine test
;========================================================================================
sqrt16test
clrf acc4_4
clrf acc4_3
clrf acc4_2
clrf acc4_1
;
loop16 incf acc4_1
bnz cont16
incf acc4_2
;
cont16 movff acc4_1,acc2_1
movff acc4_2,acc2_2
call sqrt16
goto loop16
;
;========================================================================================
;32 bit square root routine test
;========================================================================================
;
sqrt32test
clrf acc4_4
clrf acc4_3
clrf acc4_2
clrf acc4_1
;
loop32 incf acc4_1
bnz cont32
incf acc4_2
bnz cont32
incf acc4_3
bnz cont32
incf acc4_4
;
cont32 movff acc4_1,acc2_1
movff acc4_2,acc2_2
movff acc4_3,acc2_3
movff acc4_4,acc2_4
call sqrt32
goto loop32
;
;========================================================================================
;48 bit square root routine test
;========================================================================================
;
sqrt48test
clrf acc4_6
clrf acc4_4
clrf acc4_4
clrf acc4_3
clrf acc4_2
clrf acc4_1
;
loop48 incf acc4_1
bnz cont48
incf acc4_2
bnz cont48
incf acc4_3
bnz cont48
incf acc4_4
bnz cont48
incf acc4_5
bnz cont48
incf acc4_6
;
cont48 movff acc4_1,acc2_1
movff acc4_2,acc2_2
movff acc4_3,acc2_3
movff acc4_4,acc2_4
movff acc4_5,acc2_5
movff acc4_6,acc2_6
call sqrt48
goto loop48
;
;========================================================================================
;Processor initialisation *
;========================================================================================
;
Start ; Start of programme execution
;
;Set up oscllator control register
movlw b'00000000' ;
; | |--------------; SCS0
; | |---------------; SCS1
; | |----------------; IOFS
; | |-----------------; OSTS
; | |------------------; IRCF0
; | |-------------------; IRCF1
; ||--------------------; IRCF2
; |---------------------; IDLEN
movwf OSCCON ; see page 32 of Data Sheet DS39631E
;
;Initialiise I/O ports
;setup PORTA
movlw b'00001111' ; bits 0 - 3 as input, the rest as output
movwf TRISA ; see page 105 of Data Sheet DS39631E
; setup PORTB
movlw b'11111111' ; all inputs
movwf TRISB ; see page 108 of Data Sheet DS39631E
;setup PORTC
movlw b'11000010' ;
; | |--------------; T1OSO
; | |---------------; T1OSI
; | |----------------; RC2
; | |-----------------; RC3
; | |------------------; RC4
; | |-------------------; RC5
; ||--------------------; TX
; |---------------------; RX
movwf TRISC ; see page 111 of Data Sheet DS39631E
; setup PORTD
movlw b'00000000' ; set all as outputs
movwf TRISD ; see page 114 of Data Sheet DS39631E
; setup PORTE
movlw b'00000000' ; set all as outputs
movwf TRISE ; see page 118 of Data Sheet DS39631E
;
;ADC configuration
movlw b'00000000' ;
; | |--------------; ADON
; | |---------------; GO/DONE-
; | |----------------; CHS0
; | |-----------------; CHS1
; | |------------------; CHS2
; | |-------------------; CHS3
; ||--------------------; -
; |---------------------; -
movwf ADCON0 ; see page 223 of Data Sheet DS39631E
;
movlw b'00001011' ;
; | |--------------; PCFQ0
; | |---------------; PCFQ1
; | |----------------; PCFQ2
; | |-----------------; PCFQ3
; | |------------------; VCFG0
; | |-------------------; VCFG1
; ||--------------------; -
; |---------------------; -
movwf ADCON1 ; see page 224 of Data Sheet DS39631E
;
movlw b'10010101' ; right just, 4tad, Fosc/16
; | |--------------; ADCS0
; | |---------------; ADCS1
; | |----------------; ADCS2
; | |-----------------; ACQT0
; | |------------------; ACQT1
; | |-------------------; ACQT2
; ||--------------------; -
; |---------------------; ADFM
movwf ADCON2 ; see page 225 of Data Sheet DS39631E
;
;Comparator module configuration
movlw b'11110101' ; common CVREF, AN0/AN1 inputs, invert both o/p
; | |--------------; CM0
; | |---------------; CM1
; | |----------------; CM2
; | |-----------------; CIS
; | |------------------; C1INV
; | |-------------------; C2INV
; ||--------------------; C1OUT
; |---------------------; C2OUT
movwf CMCON ; See page 233 of Data Sheet DS39631E
;
movlw b'11001000' ; Ref on, high range, set to 50% (current 65uA)
; | |--------------; CRV0
; | |---------------; CRV1
; | |----------------; CRV2
; | |-----------------; CRV3
; | |------------------; CVRSS (0 = high range 1 = low range)
; | |-------------------; CVRR (0 = Vdd - Vss 1 = Vref+ - Vref-)
; ||--------------------; CVROE (0 = reference disconnected from AN2 pin)
; |---------------------; CVREN (1 = reference enabled)
movwf CVRCON ; See page 239 of Data Sheet DS39631E
;
;Serial I/O configuration
movlw h'00' ; 0 for 9600 baud
movwf SPBRGH ; set high byte
;
movlw calc(9600) ; calculate baudrate for 9600 with brgh=1
movwf SPBRG ; and store it
;
movlw b'00001000' ;
; | |--------------; ADBEN
; | |---------------; WUE
; | |----------------; -
; | |-----------------; BRG16
; | |------------------; TXCKP
; | |-------------------; RXDTP
; ||--------------------; RCIDL
; |---------------------; ABDOVF
movwf BAUDCON ; see page 204 of Data Sheet DS39631E
;
movlw b'00100100' ;
; | |--------------; TX9D
; | |---------------; TRMT
; | |----------------; BRGH
; | |-----------------; SENDB
; | |------------------; SYNC
; | |-------------------; TXEN
; ||--------------------; TX9
; |---------------------; CSRC
movwf TXSTA ; see page 202 of Data Sheet DS39631E
;
movlw b'10010000' ;
; | |--------------; RX9D
; | |---------------; OERR
; | |----------------; FERR
; | |-----------------; ADDEN
; | |------------------; CREN
; | |-------------------; SRE
; ||--------------------; RX9
; |---------------------; SPEN
movwf RCSTA ; see page 203 of Data Sheet DS39631E
;
;Timer configuration
movlw b'11000110' ;
; | |--------------; T0PS0
; | |---------------; T0PS1
; | |----------------; T0PS2
; | |-----------------; PSA
; | |------------------; T0SE
; | |-------------------; T0CS
; ||--------------------; T08BIT
; |---------------------; TMR0ON
movwf T0CON ; see page 123 of Data Sheet DS39631E
;
movlw b'10001011' ;
; | |--------------; TMR1ON
; | |---------------; TMR1CS
; | |----------------; T1SYNC-
; | |-----------------; T1OSCEN
; | |------------------; T1CKPS0
; | |-------------------; T1CSPS1
; ||--------------------; T1RUN
; |---------------------; RD16
movwf T1CON ; see page 127 of Data Sheet DS39631E
;
movlw b'00000100' ;
; | |--------------; T2CKPS0
; | |---------------; T2CKPS1
; | |----------------; TMR2ON
; | |-----------------; T2OUTPS0
; | |------------------; T2OUTPS1
; | |-------------------; T2OUTPS2
; ||--------------------; T2OUTPS3
; |---------------------; -
movwf T2CON ; see page 133 of Data Sheet DS39631E
;
movlw b'00000000' ;
; | |--------------; TMR3ON
; | |---------------; TNR3CS
; | |----------------; T3SYNC-
; | |-----------------; T3CCP1
; | |------------------; T3CCPS0
; | |-------------------; T3CCPS1
; ||--------------------; T3CCP2
; |---------------------; RD16
movwf T3CON ; see page 135 of Data Sheet DS39631E
;
;Interrupt configuration
movlw b'01110000' ;
; | |--------------; RBIF
; | |---------------; INT0IF
; | |----------------; TMR0IF
; | |-----------------; RBIE
; | |------------------; INT0IE
; | |-------------------; TMR0IE
; ||--------------------; PEIE
; |---------------------; GIE
movwf INTCON ; see page 93 of Data Sheet DS39631E
;
movlw b'11000000' ;
; | |--------------; RBIP
; | |---------------; -
; | |----------------; TMR0IP
; | |-----------------; -
; | |------------------; INTEDG2
; | |-------------------; INTEDG1
; ||--------------------; INTEDG0
; |---------------------; RBPU-
movwf INTCON2 ; see page 94 of Data Sheet DS39631E
;
movlw b'00000000' ;
; | |--------------; INT1IF
; | |---------------; INT2IF
; | |----------------; -
; | |-----------------; INT1IE
; | |------------------; INT2IE
; | |-------------------; -
; ||--------------------; INT1IP
; |---------------------; INT2IP
movwf INTCON3 ; see page 95 of Data Sheet DS39631E
;
movlw b'00100001' ;
; | |--------------; TMR1IE
; | |---------------; TMR2IE
; | |----------------; CCP1IE
; | |-----------------; SSPIE
; | |------------------; TXIE
; | |-------------------; RCIE
; ||--------------------; ADIE
; |---------------------; PSPIE
movwf PIE1 ; see page 98 of Data Sheet DS39631E
;
movlw b'00000000' ;
; | |--------------; CCP2IE
; | |---------------; TMR3IE
; | |----------------; HLVDIE
; | |-----------------; BCLIE
; | |------------------; EEIE
; | |-------------------; -
; ||--------------------; CMIE
; |---------------------; OSCFIE
movwf PIE2 ; see page 99 of Data Sheet DS39631E
;
clrf PORTC ; clear PORTC
clrf PORTD ; clear PORTD
clrf PORTE ; clear PORTE
;
;Clear all user ram before start of main task.
clr_ram lfsr FSR0,0x000 ; point to beginning of RAM
clr_nxt clrf POSTINC0 ; clear location and inrement pointer
movlw h'6' ; at top of RAM ?
xorwf FSR0H,w ; check it
bnz clr_nxt ; loop till top reached
;
;
;Reset all timers and clear any ourstanding interrupt requests.
clrf PIR1 ; clear interrupt request reg 1
clrf PIR2 ; clear interrupt request reg 2
clrf TMR0 ; reset all timers
clrf TMR1L ;
clrf TMR1H ;
;
;****************************************************************************************
END ; directive 'end of program' *
;****************************************************************************************