Comments or questions:
atferrariweb-nospam @fibertel.com.ar
(Please take out -nospam and the space)
PIC micros
I have included basic math routines for the 18F family and macros for the 16F family which I use continuously.
Here you have the routines for the 18F family.
;ROUT MATHS.ASM (18F family)
;------------------------------------------------------------------------------
ADD_1616U ;unsigned 16-bit values addition
;To call the routine:
;values in NROA_H:NROA_L & NROB_H:NROB_L
;Result of NROA + NROB => NROA
;W adds low byte of NROB to low byte of NROA.
;Result in low byte of NROA.
MOVF NROB_L,W ;LSB - Carry is NOT applied
ADDWF NROA_L,F
;W adds (high byte of NROB plus C) to high byte of NROA.
;Result in high byte of NROA.
MOVF NROB_H,W ;MSB - Carry IS applied
ADDWFC NROA_H,F
RETURN ;result in NROA_H:NROA_L
;------------------------------------------------------------------------------
SUB_1616U ;unsigned 16-bit values substraction
;To call the routine:
;values in NROA_H:NROA_L & NROB_H:NROB_L
;Result of NROA - NROB => NROA
;W substracts low byte of NROB from low byte of NROA.
;Result in low byte of NROA.
MOVF NROB_L,W ;LSB - Borrow is NOT applied
SUBWF NROA_L,F
;W substracts (high byte of NROB + Borrow) from high byte of NROA.
;Result in high byte of NROA.
MOVF NROB_H,W
SUBWFB NROA_H,F ;MSB - Borrow IS applied
RETURN ;result in NROA_H:NROA_L
;------------------------------------------------------------------------------
MUL_1616U ;unsigned 16-bit values multiplication
;Straight from the manual for the 18F452. Nothing original from my side.
;To call the routine:
;multiplicands in NROA_H:NROA_L and NROB_H:NROB_L.
;Maximum value => H'FFFF' * H'FFFF' =H'FFFE0001'
;Result of NROA * NROB => RES_3:RES_0 (32 bits)
MOVF NROA_L,W
MULWF NROB_L ;NROA_L*NROB_L => PRODH:PRODL
MOVFF PRODH,RES_1
MOVFF PRODL,RES_0
MOVF NROA_H,W
MULWF NROB_H ;NROA_H*NROB_H => PRODH:PRODL
MOVFF PRODH,RES_3
MOVFF PRODL,RES_2
MOVF NROA_L,W
MULWF NROB_H ;NROA_L*NROB_H => PRODH:PRODL
MOVF PRODL,W
ADDWF RES_1,F ;add cross
MOVF PRODH,W ;products
ADDWFC RES_2,F
CLRF WREG
ADDWFC RES_3,F
MOVF NROA_H,W
MULWF NROB_L ;NROA_H*NROB_L => PRODH:PRODL
MOVF PRODL,W
ADDWF RES_1,F ;add cross
MOVF PRODH,W ;products
ADDWFC RES_2,F
CLRF WREG
ADDWFC RES_3,F
RETURN ;result in RES_3:RES_0
;-------------------------------------------------------------------------------
DIV_3216U_ATFN ;unsigned 32/16 bits values division
;To call the routine:
;dividend in DEND_3:0 (max val H'FFFE0001' =4.294.836.225) (32 bits).
;divisor in DSOR_H:L (max value H'FFFF' =65.535) (16 bits).
;User to ensure being within range or if a division by zero is going to happen.
;The routine gives:
;quotient in DEND_1:0 (16 bits)
;reminder in DEND_3:2 (16 bits)
;Result of DEND_3:DEND_0 / DSOR_1:DSOR_0 => DEND_1:DEND_0 (quotient)
;Remainder in DEND_3:DEND_2
MOVLW 16 ;initialize the
MOVWF CNTR_SHIFTS ;shiftings counter
DIV_3216U_ATFN_LOOP
BCF STATUS,C ;we ensure that b0
RLCF DEND_0,F ;of DEND_0 is =0
RLCF DEND_1,F ;after the shifting
RLCF DEND_2,F ;to the left of the
RLCF DEND_3,F ;whole dividend
;We test C. If =1, shifting caused an o'flow! Substract DSOR_H:L from DEND_3:2
BC DIV_3216U_ATFN_SUBST_DSOR
MOVF DSOR_H,W ;compare DSOR_H
SUBWF DEND_3,W ;against DEND_3
;We test Z. If =0, DSOR_H != DEND_3. Chech if DSOR_H < DEND_3
BNZ DIV_3216U_CHKIF_DSOR_LOW_DEND
MOVF DSOR_L,W ;DSOR_H = DEND_3; now compare
SUBWF DEND_2,W ;value of DSOR_L against DEND_2
DIV_3216U_CHKIF_DSOR_LOW_DEND
;We test C. If =1, DSOR_ < DEND_ - Substract DSOR_H:L from DEND_3:2
BNC DIV_3216U_ATFN_DECR_CNTR_SH
DIV_3216U_ATFN_SUBST_DSOR ;substract DSOR from MSBs of dividend
MOVF DSOR_L,W ;DEND_2 = DEND_2 - DSOR_L
SUBWF DEND_2,F ;Borrow not used (LSB)
MOVF DSOR_H,W ;DEND_3 = DEND_3 - DSOR_H
SUBWFB DEND_3,F ;Borrow used
BSF DEND_0,0 ;flag "divisor was substracted from dividend"
DIV_3216U_ATFN_DECR_CNTR_SH
DECFSZ CNTR_SHIFTS,F
BRA DIV_3216U_ATFN_LOOP
RETURN ;job done!
;------------------------------------------------------------------------------
DIV_3216U_KEN ;unsigned 32/16-bit values division (KENYAN)
;Agustin T. Ferrari Nicolay - Buenos Aires - April 2007
;Algorithm implemented:
;Given DEND and DSOR, initialize QUOT =0 and INDEX_DSOR =0.
;Duplicate DSOR repeatedly. Increase PNTR_DSOR every time DSOR is doubled
;Repeat doubling to get a DSOR equal to, or the closest below DEND.
;Substract the highest DSOR from DEND setting b0 of QUOT.
;Shift QUOT to left and decrement PNTR_DSOR.
;Succesively try to substract from the resulting remainder above, every DSOR
;value, down in the list.
;For every possible substraction, keep setting b0 of QUOT and shifting it
;to left. If not possible, just shift QUOT to the left. In any case, always
;decrement PNTR_DSOR.
;Once finished (PNTR_DSOR again =0), the remainder is the result of the last
;substraction. QUOT in the corresponding register.
;------------------------------------------------------------------------------
;To call the routine:
;dividend in DEND_3:0 (max val H'FFFE 0001' = H'FFFF' * H'FFFF' =4.294.836.225)
;divisor in DSOR_1:0 (max value H'FFFF' =65.535) - DSOR_3:2 used internally in
;the routine
;User to ensure being within range or if a division by zero is attempted.
;The routine gives:
;Result of DEND_3:DEND_0 / DSOR_1:DSOR_0 => QUOT_H:QUOT_L.
;Remainder in DEND_3:0
CLRF DSOR_3 ;clear them
CLRF DSOR_2 ;as a precaution
CLRF QUOT_H
CLRF QUOT_L
CLRF PNTR_DSOR
DIV_3216U_KEN_INC_DSOR_LOOP
BCF STATUS,C ;ensure b0 of
RLCF DSOR_0,F ;DSOR_0 is clear
RLCF DSOR_1,F ;after the shifting
RLCF DSOR_2,F ;to the right to get
RLCF DSOR_3,F ;DSOR =DSOR*2
INCF PNTR_DSOR,F ;we go for a new value (double of previous DSOR)
;the following is to check if DSOR exceeded DEND (if so, stop doubling DSOR)
MOVF DSOR_3,W ;we test DSOR_3 against DEND_3
SUBWF DEND_3,W ;to see if they are equal
BNZ CHKIF_DSOR3_GT_DEND3;they are not - check if DSOR > DEND
MOVF DSOR_2,W ;we test DSOR_2 against DEND_2
SUBWF DEND_2,W ;to see if they are equal
BNZ CHKIF_DSOR2_GT_DEND2;they are not - check if DSOR > DEND
MOVF DSOR_1,W ;we test DSOR_1 against DEND_1
SUBWF DEND_1,W ;to see if they are equal
BNZ CHKIF_DSOR1_GT_DEND1;they are not - check if DSOR > DEND
MOVF DSOR_0,W ;we test DSOR_0 against DEND_0
SUBWF DEND_0,W ;to see if DSOR >DEND - If so, start substraction
BC DIV_3216U_KEN_INC_DSOR_LOOP;otherwise, go for next doubling of DSOR
DIV_3216U_KEN_SUBST_DSOR_LOOP
TSTFSZ PNTR_DSOR
BRA DIV_3216U_KEN_DECR_PNTR
RETURN
DIV_3216U_KEN_DECR_PNTR
DECF PNTR_DSOR ;we look down in the list of double DSOR values
BCF STATUS,C ;ensure b0 of QUOT_L is clear after shifting
RLCF QUOT_L,F ;shift QUOT to the left to have it ready
RLCF QUOT_H,F ;for next substraction
BCF STATUS,C ;ensure b7 of DSOR_3 is clear after shifting
RRCF DSOR_3,F ;shift DSOR
RRCF DSOR_2,F ;to the right
RRCF DSOR_1,F ;to get
RRCF DSOR_0,F ;DSOR =DSOR/2
;the following is to check if DSOR <DEND (if so, substract DSOR from DEND)
MOVF DSOR_3,W ;we test DSOR_3 against DEND_3
SUBWF DEND_3,W ;to see if they are equal
BNZ CHKIF_DSOR3_LT_DEND3
MOVF DSOR_2,W ;we test DSOR_2 against DEND_2
SUBWF DEND_2,W ;to see if they are equal
BNZ CHKIF_DSOR2_LT_DEND2
MOVF DSOR_1,W ;we test DSOR_1 against DEND_1
SUBWF DEND_1,W ;to see if they are equal
BNZ CHKIF_DSOR3_LT_DEND3
MOVF DSOR_0,W ;we test DSOR_0 against DEND_0
SUBWF DEND_0,W ;to see if DSOR may be susbtracted from DEND
BNC DIV_3216U_KEN_SUBST_DSOR_LOOP;DSOR >DEND - get next double DSOR value
DIV_3216U_KEN_SUBST_DSOR ;substract DSOR_3:0 from DEND_3:0
MOVF DSOR_0,W ;LSB, borrow
SUBWF DEND_0,F ;is NOT used
MOVF DSOR_1,W ;borrow
SUBWFB DEND_1,F ;IS used
MOVF DSOR_2,W ;borrow
SUBWFB DEND_2,F ;IS used
MOVF DSOR_3,W ;borrow
SUBWFB DEND_3,F ;IS used
BSF QUOT_L,0 ;flag "a valid substraction from dividend occurred"
BRA DIV_3216U_KEN_SUBST_DSOR_LOOP
CHKIF_DSOR3_GT_DEND3
BNC DIV_3216U_KEN_SUBST_DSOR_LOOP
BRA DIV_3216U_KEN_INC_DSOR_LOOP
CHKIF_DSOR2_GT_DEND2
BNC DIV_3216U_KEN_SUBST_DSOR_LOOP
BRA DIV_3216U_KEN_INC_DSOR_LOOP
CHKIF_DSOR1_GT_DEND1
BNC DIV_3216U_KEN_SUBST_DSOR_LOOP
BRA DIV_3216U_KEN_INC_DSOR_LOOP
CHKIF_DSOR3_LT_DEND3
BC DIV_3216U_KEN_SUBST_DSOR
BRA DIV_3216U_KEN_SUBST_DSOR_LOOP
CHKIF_DSOR2_LT_DEND2
BC DIV_3216U_KEN_SUBST_DSOR
BRA DIV_3216U_KEN_SUBST_DSOR_LOOP
CHKIF_DSOR1_LT_DEND1
BC DIV_3216U_KEN_SUBST_DSOR
BRA DIV_3216U_KEN_SUBST_DSOR_LOOP
;------------------------------------------------------------------------------
Macros to skip next line if a condition is met - Used with the 16FXXX series.
These macros are implemented to skip (or not) the next line of code, that is, immediately after the macro, based on the result of a certain check.
The check could be made:
for a file in a certain condition
after a comparison between files
after a comparison between a file and a value.
Example:
-------------------------- ;previous code
-------------------------- ;previous code
-------------------------- ;previous code
INCF COUNTER,F ;previous code
SKIP8_F_HIG_V COUNTER,D'238' ;this is the MACRO to check COUNTER against 238
GOTO DISPLAY_FULL ;this line is to be skipped if F is higher than V (COUNTER > 238)
MOVLW D'108' ;if the above line is skipped your PC will land here.
-------------------------- ;further code
-------------------------- ;further code
-------------------------- ;further code
SKIP8 : macros for single values or files (registers).
SKIP16: macros for 16-bit values or pair of registers (high & low)
;-----------------------------------------------------------------
SKIP8_F_ZERO MACRO FILE ;skip next line if file=0
MOVF FILE,F ;F copies to itself
BTFSS STATUS,Z ;if Z=1 it's F=0 - skip next line!
ENDM
SKIP8_F_255 MACRO FILE ;skip next line if file =255
INCF FILE,W ;value is incremented (but file unchanged)
BTFSS STATUS,Z ;if Z=1 it wrapped from 255 to 0 - skip!
ENDM
SKIP8_F_EQU_V MACRO FILE,VALUE ;skip next line if file =value
MOVLW VALUE ;W=VALUE which is substracted from
SUBWF FILE,W ;file (but not changing it)
BTFSS STATUS,Z ;if Z=1 it's F=V - skip next line!
ENDM
SKIP8_F_DIF_V MACRO FILE,VALUE ;skip next line if file is different from value
MOVLW VALUE ;W=VALUE which is substracted from
SUBWF FILE,W ;file (but not changing it)
BTFSC STATUS,Z ;if Z=0 F not =V - skip next line!
ENDM
SKIP8_F_HIG_V MACRO FILE,VALUE ;skip next line if file is higher than value
MOVLW VALUE ;W=VALUE which is substracted from
SUBWF FILE,W ;file (but not changing it)
BTFSC STATUS,Z ;if Z=0, C could be =0 or =1 - check C!
BCF STATUS,C ;Z=1 thus C always =1 - force C=0
BTFSS STATUS,C ;if C=1 skip next line!
ENDM
SKIP8_F_LOW_V MACRO FILE,VALUE ;skip next line if file is lower than value
MOVLW VALUE ;W=VALUE which is substracted from
SUBWF FILE,W ;file (but not changing it)
BTFSC STATUS,C ;if C=0 F<V - skip next line!
ENDM
;-------------------------------
SKIP8_V_HIG_F MACRO VALUE,FILE ;skip next line if value higher than file
MOVF FILE,W ;W=FILE which is substracted
SUBLW VALUE ;from VALUE
BTFSC STATUS,Z ;if Z=0, need to check C!
BCF STATUS,C ;Z=1 (and also C=1) - force C=0!
BTFSS STATUS,C ;if C=1 skip next line!
ENDM
SKIP8_V_LOW_F MACRO VALUE,FILE ;skip next line if value is lower than file
MOVF FILE,W ;W=FILE which is substracted
SUBLW VALUE ;from VALUE
BTFSC STATUS,C ;if C=0, V<F - skip next line!
ENDM
;-------------------------------
SKIP8_F1_EQU_F2 MACRO F1,F2 ;skip next line if file1 = file2
MOVF F2,W ;F2 to W - substracted from
SUBWF F1,W ;F1 but (but not changing it)
BTFSS STATUS,Z ;if Z=1, F1=F2 - skip next line!
ENDM
SKIP8_F1_DIF_F2 MACRO F1,F2 ;skip next line if file1 different from file2
MOVF F2,W ;F2 to W - substracted from
SUBWF F1,W ;F1 (but not changing it)
BTFSC STATUS,Z ;if Z=0, F1 not =F2 - skip next line!
ENDM
;-------------------------------
SKIP16_F_ZERO MACRO F_H,F_L ;skip if file = 00000000 00000000
MOVF F_H,W ;W=F_H
IORWF F_L,W ;W=W.OR.F_L will be zero if both=0
BTFSS STATUS,Z ;if Z=1 (both=0) - skip next line!
ENDM
SKIP16_F_65535 MACRO F_H,F_L ;skip if file is = 11111111 11111111
MOVF F_H,W ;W=F_H
ANDWF F_L,W ;W.AND.F_L =255 if F_H and F_L =255
XORLW 255 ;W.XOR.255 =0, only if W was =255
BTFSS STATUS,Z ;if Z=1,W was =255 - skip next line!
ENDM
SKIP16_F_EQU_V MACRO F_H,F_L,V_H,V_L ;skip if file = value
MOVF F_H,W ;W=F_H
XORLW V_H ;W.XOR.V_H - if both equal, Z=1
BTFSS STATUS,Z ;if Z=1, F_H=V_H - check F_L!
GOTO $+4 ;Z=0 - EQU condition not met - leave!
MOVF F_L,W ;W=F_L
XORLW V_L ;W.XOR.V_L - if both equal, Z=1
BTFSS STATUS,Z ;if Z=1, F_L=V_L - skip next line!
ENDM
SKIP16_F_DIF_V MACRO F_H,F_L,V_H,V_L ;skip if file is different from value
MOVLW V_H ;W=V_H - subtracts value from
SUBWF F_H,W ;F_H (but not changing it)
BTFSS STATUS,Z ;if Z=1, F_H=V_H - check F_L
GOTO $ + 5 ;Z=0 - skip the line!
MOVLW V_L ;W=V_L - subtracts value from
SUBWF F_L,W ;F_L (but not changing it)
BTFSC STATUS,Z ;if Z=0, F not =V - skip next line!
ENDM
SKIP16_F_HIG_V MACRO F_H,F_L,V_H,V_L ;skip if file higher than value
MOVLW V_H ;W=V_H - subtracts value from
SUBWF F_H,W ;F_H (but not changing it)
BTFSS STATUS,C ;if C=1, F_H=>V_H
GOTO $ + 8 ;C=0, F<V - don't skip the line!
BTFSS STATUS,Z ;if Z=1 F_H=V_H - Check F_L
GOTO $ + 7 ;Z=0, F_H>V_H - skip the line!
MOVLW V_L ;W=V_L - subtracts value from
SUBWF F_L,W ;F_L (but not changing it)
BTFSS STATUS,C ;if C=1, F_L=>V_L - Check Z
GOTO $ + 2 ;C=0, F<V - don't skip the line
BTFSC STATUS,Z ;if Z=0, F_L>V_L - skip next line!
ENDM
SKIP16_F_LOW_V MACRO F_H,F_L,V_H,V_L ;skip if file lower than value
MOVLW V_H ;W=V_H - subtracts value from
SUBWF F_H,W ;F_H (but not changing it)
BTFSS STATUS,C ;if C=1, F_H=>V_H - check Z
GOTO $ + 7 ;C=0, F<V - skip the line!
BTFSS STATUS,Z ;if Z=1 F_H=V_H - Check F_L
GOTO $ + 4 ;Z=0, F_H>V_H - don't skip the line!
MOVLW V_L ;W=V_L - subtracts value from
SUBWF F_L,W ;F_L (but not changing it)
BTFSC STATUS,C ;if C=0, F_L<V_L - skip next line!
ENDM
;-----------------------------------
SKIP16_F1_EQU_F2 MACRO F1_H,F1_L,F2_H,F2_L ;skip if file1 = file 2
MOVF F1_H,W ;W=F1_H
XORWF F2_H,W ;W.XOR.F2_H - if both equal, Z=1
BTFSS STATUS,Z ;if Z=1, F1_H=F2_H - check F2_H!
GOTO $+4 ;Z=0 - EQU condition not met - leave!
MOVF F1_L,W ;W=F1_L
XORWF F2_L,W ;W.XOR.F2_L - if both equal, Z=1
BTFSS STATUS,Z ;if Z=1, F1_L=F2_L - skip next line!
ENDM
SKIP16_F1_DIF_F2 MACRO F1_H,F1_L,F2_H,F2_L ;skip if file1 different from file 2
MOVF F1_H,W ;W=F1_H
XORWF F2_H,W ;W.XOR.F2_H - if both diff, Z=0
BTFSS STATUS,Z ;if Z=1, F1_H=F2_H - check F2_H
GOTO $ + 5 ;Z=0, F1 not =F2 - skip the line!
MOVF F1_L,W ;W=F1_L
XORWF F2_L,W ;W.XOR.F2_L - if both diff, Z=0
BTFSC STATUS,Z ;if Z=0, F1_L not =F2_L - skip next line!
ENDM
SKIP16_F1_HIG_F2 MACRO F1_H,F1_L,F2_H,F2_L ;skip if file1 higher than file 2
MOVF F2_H,W ;W=F2_H - substracted from
SUBWF F1_H,W ;F1_H (but not changing it)
BTFSS STATUS,C ;if C=1, F1_H=>F2_H - check Z
GOTO $ + 8 ;C=0 F1_H<F2_H - don't skip the line!
BTFSS STATUS,Z ;if Z=1 F1_H=F2_H - check F1_L
GOTO $ + 7 ;Z=0, F1_H>F2_H - skip the line!
MOVF F2_L,W ;W=F2_L - substracted from
SUBWF F1_L,W ;F1_L (but not changing it)
BTFSS STATUS,C ;if C=1, F1_L=>F2_L - check Z
GOTO $ + 2 ;C=0 F1_L<F2_L - don't skip the line!
BTFSC STATUS,Z ;if Z=0, F1_L>F2_L - skip next line!
ENDM
SKIP16_F1_LOW_F2 MACRO F1_H,F1_L,F2_H,F2_L ;skip if file1 lower than file 2
MOVF F2_H,W ;W=F2_H - substracted from
SUBWF F1_H,W ;F1_H (but not changing it)
BTFSS STATUS,C ;if C=1, F1_H=>F2_H - check Z
GOTO $ + 7 ;C=0, F1_H<F2_H - skip the line!
BTFSS STATUS,Z ;if Z=1 F1_H=F2_H - Check F1_L
GOTO $ + 4 ;Z=0, F1_H>V_H - don't skip the line!
MOVF F2_L,W ;W=F2_L - substracted from
SUBWF F1_L,W ;F1_L (but not changing it)
BTFSC STATUS,C ;if C=0, F_L<V_L - skip next line!
ENDM
Comments or questions: atferrariweb-nospam @fibertel.com.ar (Please take out -nospam and the space)