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:

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)