;PIC Microcontoller Basic Math Method ;Mainly Maths Macros for PIC18F458 (16bit & some 32bit) ;By Roger Froud ;Overview... ;This approach to handling 16bit maths is borrowed from Microchips ;Embedded Control Handbook where it is flirted with but not generalised ;or published in any useful form. ;The aim is to provide the user with 16bit pseudo registers in RAM ;that behave very much like an extended native 16bit instuction set. ;You can create your own 16 bit variables by reserving 2 consecutive bytes ;and then freely mix them with the 16bit macros. ;This allows you to have as many 16bit files as you need while allowing ;easy manipulation of their values using the macros. ;The only downside of this approach is that it exposes a nasty bug in MPLAB ;that has been made worse post V7.11. Up to V7.11 the assembler often shows ;errors listed against the wrong line numbers. It does single step correctly ;through the macros though. By V7.31, the assembler not only gives the wrong ;line numbers but MPLAB no longer shows the correct lines while stepping ;through the macros. The code still works fine but you don't see the ;lines that are being executed. Microchip have acknowledged this problem ;so perhaps they will at last get both these problems sorted out. ;These macros have been tested and published here in good faith but ;no liability can be accepted for any inaccuracies. ;Please feel free to correct, improve or add to these for the greater good. ;Caution:- ;Do not assume that the W register or status registers are preserved ;unless specifically mentioned. ;Don't forget that these routines use memory pairs which can be ;corrupted if you use these macros in interrupt routines as well ;as in the main body of the code. You are responsible for storing ;their contents. Beware High & Low level interrupts that may need to ;store their own copies. The code routines are shown below are complete ;to show what resources would be used if you used all of the macros. ;Typically you will only have definitions for ACCaLO & ACCaHI ;If you forget to allocate memory for them, the assembler will complain ;so you could just use the macros and let the assembler tell you ;what definitions you need to include. ;The pseudo registers are normally stored in Access RAM so that they ;are readily available without Bank switching. ;Beware changing macro names as some are used in other macros ;16 Bit Pseudo register definitions. LS & MS explicitly defined ;so they can be accessed by macros ;ACCaLO RES 1 ;LS of accumulator 'a' ;ACCaHI RES 1 ;MS ;ACCbLO RES 1 ;LS of accumulator 'b' ;ACCbHI RES 1 ;MS ;ACCcLO RES 1 ;LS of accumulator 'c' ;ACCcHI RES 1 ;MS ;ACCdLO RES 1 ;LS of accumulator 'd' ;ACCdHI RES 1 ;MS ;M_TEMP RES 1 ;Temp counter for 16bit/16bit maths routines ;The following are only required for 16bit x 16bit multiplication ;RES0 RES 1 ;LS Destination for multiply result ;RES1 RES 1 ;RES2 RES 1 ;RES3 RES 1 ;MS ;Beware! 2 sets of temp stores required as low priority interrupt can be interrupted by a high priority one! ;These can be defined in other banks as their data is stored using movff instructions that include the full address ;W_TEMP_L RES 1 ; variable used for context saving durng interrupts ;W_TEMP_H RES 1 ; variable used for context saving durng interrupts ;NB:- STATUS_TEMP etc in another bank to save acces bank space ;M_TEMP_L RES 1 ;Counter for some maths routines (check if you are using it by leaving it out) ;M_TEMP_H RES 1 ;Counter for some maths routines (check if you are using it by leaving it out) ;ACCaLO_TEMP_L RES 1 ; for context saving LS of accumulator 'A' ;ACCaHI_TEMP_L RES 1 ; for context saving MS ;ACCbLO_TEMP_L RES 1 ; for context saving LS of accumulator 'b' ;ACCbHI_TEMP_L RES 1 ; for context saving MS ;ACCcLO_TEMP_L RES 1 ; for context saving LS of accumulator 'c' ;ACCcHI_TEMP_L RES 1 ; for context saving MS ;ACCdLO_TEMP_L RES 1 ; for context saving LS of accumulator 'd' ;ACCdHI_TEMP_L RES 1 ; for context saving MS ;The following are only required for 16bit x 16bit multiplication ;RES0_L RES 1 ;LS Destination for multiply result ;RES1_L RES 1 ;RES2_L RES 1 ;RES3_L RES 1 ;MS ;ACCaLO_TEMP_H RES 1 ; for context saving LS of accumulator 'A' ;ACCaHI_TEMP_H RES 1 ; for context saving MS ;ACCbLO_TEMP_H RES 1 ; for context saving LS of accumulator 'b' ;ACCbHI_TEMP_H RES 1 ; for context saving MS ;ACCcLO_TEMP_H RES 1 ; for context saving LS of accumulator 'b' ;ACCcHI_TEMP_H RES 1 ; for context saving MS ;ACCdLO_TEMP_H RES 1 ; for context saving LS of accumulator 'b' ;ACCdHI_TEMP_H RES 1 ; for context saving MS ;The following are only required for 16bit x 16bit multiplication ;RES0_H RES 1 ;LS Destination for multiply result ;RES1_H RES 1 ;RES2_H RES 1 ;RES3_H RES 1 ;MS ;Use same style definition for High priority interrupt but change the _L to _H for variables ;LOWINT MOVWF W_TEMP_L ;Copy W register else it will be corrupted ; MOVFF STATUS,STATUS_TEMP_L ;save status ; MOVFF BSR,BSR_TEMP_L ;Save BSR register ; ;Leave out any or all of the following if macros ; ;are not used in the interrupt routine. Just check the ; ;macros to see what they use. ; MOVFF ACCaLO,ACCaLO_TEMP_L ;Save my pseudo registers for 16 bit macros ; MOVFF ACCaHI,ACCaHI_TEMP_L ;Save my pseudo registers for 16 bit macros ; MOVFF ACCbLO,ACCbLO_TEMP_L ;Save my pseudo registers for 16 bit macros ; MOVFF ACCbHI,ACCbHI_TEMP_L ;Save my pseudo registers for 16 bit macros ; MOVFF ACCcLO,ACCaLO_TEMP_L ;Save my pseudo registers for 16 bit macros ; MOVFF ACCcHI,ACCaHI_TEMP_L ;Save my pseudo registers for 16 bit macros ; MOVFF ACCdLO,ACCbLO_TEMP_L ;Save my pseudo registers for 16 bit macros ; MOVFF ACCdHI,ACCbHI_TEMP_L ;Save my pseudo registers for 16 bit macros ; MOVFF M_TEMP,M_TEMP_L ;Save counter ; MOVFF RES0,RES0_L ;Save 32bit result of 16 x 16 bit multiply ; MOVFF RES1,RES1_L ; MOVFF RES2,RES2_L ; MOVFF RES3,RES3_L ; ; body of low priority interrupt ; ; MOVFF RES3_L,RES3 ; MOVFF RES2_L,RES2 ; MOVFF RES1_L,RES1 ; MOVFF RES0_L,RES0 ; MOVFF M_TEMP_L,M_TEMP ;Restore counter ; MOVFF ACCdHI_TEMP_L,ACCbHI ;Restore my pseudo registers for 16 bit macros ; MOVFF ACCdLO_TEMP_L,ACCbLO ; MOVFF ACCcHI_TEMP_L,ACCbHI ;Restore my pseudo registers for 16 bit macros ; MOVFF ACCcLO_TEMP_L,ACCbLO ; MOVFF ACCbHI_TEMP_L,ACCbHI ;Restore my pseudo registers for 16 bit macros ; MOVFF ACCbLO_TEMP_L,ACCbLO ; MOVFF ACCaHI_TEMP_L,ACCaHI ;Restore my pseudo registers for 16 bit macros ; MOVFF ACCaLO_TEMP_L,ACCaLO ; MOVFF BSR_TEMP_L,BSR ;Restore BSR register ; MOVF W_TEMP_L,W ;Restore W reg. ; MOVFF STATUS_TEMP_L,STATUS ;Restore status reg. ; RETFIE ;back to interrupted program ;16 bit pseudo-register macro definitions ;Test accumulator and set Z flag if zero & c flag if MS bit set ;Corrupts W reg. TSTA MACRO TSTF16 ACCaLO ENDM ;Test accumulator and set Z flag if zero & c flag if MS bit set ;Corrupts W reg. TSTB MACRO TSTF16 ACCbLO ENDM ;Test 16 bit file and set Z flag if zero ;Corrupts W reg. TSTF16 MACRO ADDRESS BCF STATUS,C BTFSC ADDRESS+1,7 ;Set carry if MS bit=1 BSF STATUS,C ;None of the following changes Carry MOVF ADDRESS,W ;get LS IORWF ADDRESS+1,W ;Z flag set if both zero ENDM TSTW MACRO IORLW 0 ENDM ;Make accumulator +ve if -ve (assuming signed numbers of course) ABSA MACRO ABSF16 ACCaLO ENDM ;Make 16bit file +ve if -ve (assuming signed numbers of course) ABSF16 MACRO ADDRESS LOCAL PLUSNOW BTFSS ADDRESS+1,7 ;MS byte GOTO PLUSNOW NEGF16 ADDRESS PLUSNOW ENDM ;Moves 16bit file in LS/MS format to Accumulator A MOVFA MACRO ADDRESS MOVF16 ADDRESS,ACCaLO ENDM ;Moves Accumulator A to Accumulator B MOVAB MACRO MOVF16 ACCaLO,ACCbLO ENDM ;Moves 16bit file in LS/MS format from Accumulator A MOVAF MACRO ADDRESS MOVF16 ACCaLO,ADDRESS ENDM ;moves 16bit file in LS/MS format to Accumulator B MOVFB MACRO ADDRESS MOVF16 ADDRESS,ACCbLO ;Move LS ENDM ;moves 16bit file in LS/MS format from Accumulator B MOVBF MACRO ADDRESS MOVF16 ACCbLO,ADDRESS ENDM ;moves 16bit file in LS/MS format to Accumulator C MOVFC MACRO ADDRESS MOVF16 ADDRESS,ACCcLO ENDM ;moves 16bit file in LS/MS format from Accumulator C MOVCF MACRO ADDRESS MOVF16 ACCcLO,ADDRESS ENDM ;moves 16bit file in LS/MS format to Accumulator D MOVFD MACRO ADDRESS MOVF16 ADDRESS,ACCdLO ENDM ;moves 16bit file in LS/MS format from Accumulator D MOVDF MACRO ADDRESS MOVF16 ACCdLO,ADDRESS ENDM ;Moves 16 bit literal to accumulator A MOVLAA MACRO VALUE MOVLW LOW VALUE MOVWF ACCaLO MOVLW HIGH VALUE MOVWF ACCaHI ENDM ;Moves 16 bit literal to accumulator B MOVLAB MACRO VALUE MOVLW LOW VALUE MOVWF ACCbLO MOVLW HIGH VALUE MOVWF ACCbHI ENDM ;Moves 16 bit literal to accumulator C MOVLAC MACRO VALUE MOVLW LOW VALUE MOVWF ACCcLO MOVLW HIGH VALUE MOVWF ACCcHI ENDM ;Moves 16 bit literal to accumulator D MOVLAD MACRO VALUE MOVLW LOW VALUE MOVWF ACCdLO MOVLW HIGH VALUE MOVWF ACCdHI ENDM ;Moves 8 bit literal to file (corrupts W) MOVLF MACRO VALUE,ADDRESS MOVLW VALUE MOVWF ADDRESS ENDM ;Make file absolute ABSF MACRO ADDRESS BTFSC ADDRESS,7 ;-ve? NEGF ADDRESS ;Make -ve into +ve ENDM ;Moves 16 bit literal to file ;NB:-Done MS first to writes to 16bit timers work correctly. ;You can't use this for reading 16 bit timers, you must reverse the order! MOVLF16 MACRO VALUE,ADDRESS MOVLW HIGH VALUE MOVWF ADDRESS+1 ;MS MOVLW LOW VALUE MOVWF ADDRESS ;LS ENDM ;Moves 16 bit file to file. Uses MOVFF so it is page independant ;NB:-Done MS first to writes to 16bit timers work correctly. ;You can't use this for reading 16 bit timers, you must reverse the order! MOVF16 MACRO ADDRESS,ADDRESS1 MOVFF ADDRESS+1,ADDRESS1+1 ;MS MOVFF ADDRESS,ADDRESS1 ;LS ENDM ;Add 16 bit file to accumulator A ADDFA MACRO ADDRESS ;a+f->a MOVF ADDRESS,W ADDWF ACCaLO,F MOVF ADDRESS+1,W ADDWFC ACCaHI,F ENDM ;Add accumulator A to 16 bit file ADDAF MACRO ADDRESS ;f+a->f MOVF ACCaLO,W ADDWF ADDRESS,F ;Save LS back to file MOVF ACCaHI,W ADDWFC ADDRESS+1,F ENDM ;Add 16 bit file to accumulator B ADDFB MACRO ADDRESS ;b+f->b MOVF ADDRESS,W ADDWF ACCbLO,F MOVF ADDRESS+1,W ADDWFC ACCbHI,F ENDM ;Add literal to accumulator 'A' ADDLA MACRO VALUE ;a+l->a MOVLW LOW VALUE ADDWF ACCaLO,F MOVLW HIGH VALUE ADDWFC ACCaHI,F ENDM ;Add literal to file' ADDLF16 MACRO VALUE,ADDRESS ;f+l->f MOVLW LOW VALUE ADDWF ADDRESS,F MOVLW HIGH VALUE ADDWFC ADDRESS+1,F ENDM ;Subtract 16 bit file from 'A' result in 'A' SUBFA MACRO ADDRESS ;See AN526 MOVF ADDRESS,W SUBWF ACCaLO,F MOVF ADDRESS+1,W SUBWFB ACCaHI,F ENDM ;Subtract 16 bit file ADDRESS from 16 bit file ADDRESS1. result in ADDRESS1 SUBF16 MACRO ADDRESS,ADDRESS1 ;See AN526 MOVF ADDRESS,W SUBWF ADDRESS1,F MOVF ADDRESS+1,W SUBWFB ADDRESS1+1,F ENDM ;Subtract 16 bit literal from 'A' result in 'A' SUBLA MACRO VALUE ;a-l->a MOVLW LOW VALUE SUBWF ACCaLO,F MOVLW HIGH VALUE SUBWFB ACCaHI,F ENDM ;Subtract 16 bit file from 'B' result in 'B' SUBFB MACRO ADDRESS ;See AN526 MOVF ADDRESS,W SUBWF ACCbLO,F MOVF ADDRESS+1,W SUBWFB ACCbHI,F ENDM ;Subtract 16 bit literal from 'B' result in 'B' SUBLB MACRO VALUE ;b-l->b MOVLW LOW VALUE SUBWF ACCbLO,F MOVLW HIGH VALUE SUBWFB ACCbHI,F ENDM ;Subtract 16 bit literal from 'f' result in 'f' SUBLF16 MACRO VALUE,ADDRESS ;f-l->f MOVLW LOW VALUE SUBWF ADDRESS,F MOVLW HIGH VALUE SUBWFB ADDRESS+1,F ENDM ;Unsigned Compare of 16 bit file with 'A' (A-f) ;Set carry & zero flags to reflect unsigned 16bit result ;so we can use BLT macros etc the same as for signed compare CMPFAU MACRO ADDRESS ;See signed compare below LOCAL NOCHK LOCAL LSCHK MOVF ADDRESS+1,W ;ms SUBWF ACCaHI,W ;check if File > A BZ LSCHK ;continue if File=A GOTO NOCHK ;ms result tells all LSCHK MOVF ADDRESS,W ;ms same so LS tells all SUBWF ACCaLO,W ;carry set if A > File NOCHK ENDM ;Unsigned Compare of 16 bit file with Literal (L-f) ;Set carry & zero flags to reflect unsigned 16bit result ;so we can use BLT macros etc the same as for signed compare CMPFLU MACRO VALUE,ADDRESS ;See signed compare below LOCAL NOCHK LOCAL LSCHK MOVF ADDRESS+1,W ;ms SUBLW HIGH VALUE ;check if File > L BZ LSCHK ;continue if File=L GOTO NOCHK ;ms result tells all LSCHK MOVF ADDRESS,W ;ms same so LS tells all SUBLW LOW VALUE ;carry set if L > File NOCHK ENDM ;Compare signed 16 bit file with 'A' (A-f) ;Using biased (inverted sign) method to set carry & zero flags ;to reflect signed 16bit result CMPFA MACRO ADDRESS ;See AN526 LOCAL NOCHK LOCAL LSCHK ;first invert sign bit of accumulator BTG ACCaHI,7 ;inverts bit ;Now do unsigned compare on biased values MOVF ADDRESS+1,W ;ms XORLW H'80' ;invert sign of file SUBWF ACCaHI,W ;check if file > a (both numbers are biased) BZ LSCHK ;continue if file=a GOTO NOCHK ;ms result tells all LSCHK MOVF ADDRESS,W ;ms same so LS tells all SUBWF ACCaLO,W ;carry set if a > file NOCHK ;Z and C bits now set but we must repair accumulator sign without ;corrupting the Z flag BTG ACCaHI,7 ;inverts bit ENDM ;Compare signed 16 bit accumulator with literal (A-L) ;Using biased (inverted sign) method to set carry & zero flags ;to reflect signed 16bit result CMPLA MACRO VALUE LOCAL NOCHK LOCAL LSCHK ;first invert sign bit of accumulator BTG ACCaHI,7 ;inverts bit ;Now do unsigned compare on biased values MOVLW HIGH VALUE ;ms XORLW H'80' ;invert sign of value SUBWF ACCaHI,W ;check if value > a (both numbers are biased) BZ LSCHK ;continue if file=a GOTO NOCHK ;ms result tells all LSCHK MOVLW LOW VALUE ;ms same so LS tells all SUBWF ACCaLO,W ;carry set if a > value NOCHK ;Z and C bits now set but we must repair accumulator sign without corrupting the Z flag BTG ACCaHI,7 ;inverts bit ENDM ;Compare unsigned 16 bit accumulator with literal (A-L) ;carry & zero flags reflect unsigned 16bit result CMPLAU MACRO VALUE LOCAL NOCHK LOCAL LSCHK MOVLW HIGH VALUE ;ms SUBWF ACCaHI,W ;check if value > a (both numbers are biased) BZ LSCHK ;continue if file=a GOTO NOCHK ;ms result tells all LSCHK MOVLW LOW VALUE ;ms same so LS tells all SUBWF ACCaLO,W ;carry set if a > value NOCHK ENDM ;Compare signed 16 bit file with 16 bit file (f2-f1) ;Using biased (inverted sign) method to set carry & zero flags ;to reflect signed 16bit result CMPFF16 MACRO ADDRESS1,ADDRESS2 ;See AN526 LOCAL NOCHK LOCAL LSCHK ;first invert sign bit of accumulator BTG ADDRESS2+1,7 ;inverts bit ;Now do unsigned compare on biased values MOVF ADDRESS1+1,W ;ms XORLW H'80' ;invert sign of file SUBWF ADDRESS2+1,W ;check if file > file (both numbers are biased) BZ LSCHK ;continue if file=file GOTO NOCHK ;ms result tells all LSCHK MOVF ADDRESS1,W ;ms same so LS tells all SUBWF ADDRESS2,W ;carry set if a > file NOCHK ;Z and C bits now set but we must repair accumulator sign without ;corrupting the Z flag BTG ADDRESS2+1,7 ;inverts bit ENDM ;Unsigned compare 16 bit file with 16 bit file (f2-f1) ;carry & zero flags reflect unsigned 16bit result CMPFFU16 MACRO ADDRESS1,ADDRESS2 ;See AN526 LOCAL NOCHK LOCAL LSCHK MOVF ADDRESS1+1,W ;ms SUBWF ADDRESS2+1,W ;check if file > file BZ LSCHK ;continue if file=file GOTO NOCHK ;ms result tells all LSCHK MOVF ADDRESS1,W ;ms same so LS tells all SUBWF ADDRESS2,W ;carry set if a > file NOCHK ENDM ;Compare unsigned 16 bit file with literal (F-L) ;carry & zero flags reflect unsigned 16bit result CMPLFU16 MACRO VALUE,ADDRESS LOCAL NOCHK LOCAL LSCHK MOVLW HIGH VALUE ;ms SUBWF ADDRESS+1,W ;check if file > l BZ LSCHK ;continue if file=l GOTO NOCHK ;ms result tells all LSCHK MOVLW LOW VALUE ;ms same so LS tells all SUBWF ADDRESS,W ;carry set if l > value NOCHK ENDM ;Compare signed 16 bit file with literal (F-L) ;Using biased (inverted sign) method to set carry & zero flags ;to reflect signed 16bit result CMPLF16 MACRO VALUE,ADDRESS LOCAL NOCHK LOCAL LSCHK ;first invert sign bit of accumulator BTG ACCaHI,7 ;inverts bit ;Now do unsigned compare on biased values MOVLW HIGH VALUE ;ms XORLW H'80' ;invert sign of file SUBWF ADDRESS+1,W ;check if file > a (both numbers are biased) BZ LSCHK ;continue if file=a GOTO NOCHK ;ms result tells all LSCHK MOVLW LOW VALUE ;ms same so LS tells all SUBWF ADDRESS,W ;carry set if a > value NOCHK ;Z and C bits now set but we must repair file sign without corrupting the Z flag BTG ADDRESS+1,7 ;inverts bit ENDM ;Branch if > BGT MACRO ADDRESS LOCAL ONE BTFSC STATUS,Z GOTO ONE ;Equal so not > BTFSC STATUS,C ;Take branch if Carry clear GOTO ADDRESS ONE ENDM ;Branch if < BLT MACRO ADDRESS LOCAL ONE BTFSC STATUS,Z GOTO ONE ;Equal so not < BTFSS STATUS,C ;Take branch if carry set GOTO ADDRESS ONE ENDM ;Branch if >= BGE MACRO ADDRESS LOCAL ONE BTFSC STATUS,C ;Take branch if carry clear GOTO ONE BTFSC STATUS,Z ;Take branch if not zero ONE GOTO ADDRESS ENDM ;Branch if <= BLE MACRO ADDRESS LOCAL ONE BTFSS STATUS,C ;Take branch if carry set GOTO ONE BTFSC STATUS,Z ;Take branch if not zero ONE GOTO ADDRESS ENDM ;Negate accumulator A NEGA MACRO ;2's comp. NEGF16 ACCaLO ENDM ;Negate accumulator B NEGB MACRO ;2's comp. NEGF16 ACCbLO ENDM ;Negate 16 bit file NEGF16 MACRO ADDRESS ;See AN526 P5-14 2's comp. COMF ADDRESS,F ;LS INCF ADDRESS,F BTFSC STATUS,Z DECF ADDRESS+1,F ;MS COMF ADDRESS+1,F ENDM ;Clip 'A' to signed 15bits so that 2 of these added together ;can never exceed 16bits signed. The result can then be clipped itself CLIPA15 MACRO LOCAL CLIPPLU LOCAL SATDAT BTFSS ACCaHI,7 ;Test if -ve (ms bit set) GOTO CLIPPLU ;This way if -ve BTFSC ACCaHI,6 GOTO SATDAT MOVLAA H'C000' GOTO SATDAT ;----------------------- ;This way to clip plus CLIPPLU BTFSS ACCaHI,6 GOTO SATDAT MOVLAA H'3FFF' SATDAT ENDM ;Clip 'A' to signed 14bits to limit swings in control system CLIPA14 MACRO LOCAL CLIPPLU LOCAL SATDAT LOCAL NEGCLIP LOCAL POSCLIP BTFSS ACCaHI,7 ;Test if -ve (ms bit set) GOTO CLIPPLU ;This way if -ve BTFSS ACCaHI,6 GOTO NEGCLIP BTFSC ACCaHI,5 GOTO SATDAT NEGCLIP MOVLAA H'E000' GOTO SATDAT ;----------------------- ;This way to clip plus CLIPPLU BTFSC ACCaHI,6 GOTO POSCLIP BTFSS ACCaHI,5 GOTO SATDAT POSCLIP MOVLAA H'1FFF' SATDAT ENDM ;Clip A to the value in F ie if A>F then A=F CLIPAF MACRO ADDRESS LOCAL NOCLIP NOP CMPFA ADDRESS ;Is it > clip value? BLT NOCLIP NOP MOVFA ADDRESS ;Use clip value NOCLIP ENDM ;Clip A to the Literal value ie if A>L then A=L CLIPAL MACRO VALUE LOCAL NOCLIP NOP CMPLA VALUE ;Is it > clip value? BLT NOCLIP NOP MOVLAA VALUE ;Use clip value NOCLIP ENDM ;Clip F to A CLIPFA MACRO ADDRESS LOCAL NOCLIP CMPFA ADDRESS ;Is it < clip value? BGE NOCLIP MOVAF ADDRESS ;Use clip value NOCLIP ENDM ;Increment 16 bit file and test if zero INCF16 MACRO ADDRESS INCF ADDRESS,F BTFSC STATUS,Z INCF ADDRESS+1,F TSTF16 ADDRESS ENDM ;Increment accumulator 'A' and test if zero INCA MACRO INCF16 ACCaLO ENDM ;Increment accumulator 'B' and test if zero INCB MACRO INCF16 ACCbLO ENDM ;Decrement accumulator 'A' and test if zero DECA MACRO DECF16 ACCaLO ENDM ;Decrement accumulator 'B' and test if zero DECB MACRO DECF16 ACCbLO ENDM ;The following are Used for timers in interrupt routine which ;are then polled outside ;Decrement 16 bit file and test if zero DECF16 MACRO ADDRESS LOCAL NBORROW TSTFSZ ADDRESS ;LS GOTO NBORROW DECF ADDRESS+1,F ;MS NBORROW DECF ADDRESS,F ;LS TSTF16 ADDRESS ENDM ;Decrement A to zero if not already zero DECATZ MACRO DECFTZ16 ACCaLO ENDM ;Decrement B to zero if not already zero DECBTZ MACRO DECFTZ16 ACCbLO ENDM ;Decrement 8 bit file if not already zero ;Sets Z bit to suit DECFTZ MACRO ADDRESS TSTFSZ ADDRESS ;Aready zero DECF ADDRESS,F TSTF ADDRESS ENDM ;Decrement 16 bit file if not already zero DECFTZ16 MACRO ADDRESS LOCAL ZEXIT TSTF16 ADDRESS BTFSC STATUS,Z GOTO ZEXIT ;This way if not zero so decrement it DECF16 ADDRESS ZEXIT ENDM ;XOR 16 bit file with accumulator 'A', result in 'A' XORFA MACRO ADDRESS MOVF ADDRESS,W XORWF ACCaLO,F MOVF ADDRESS+1,W XORWF ACCaHI,F TSTA ;use previous macro ENDM ;XOR literal with accumulator 'A', result in 'A' XORLA MACRO VALUE MOVLW LOW VALUE XORWF ACCaLO,F MOVLW HIGH VALUE XORWF ACCaHI,F TSTA ;use previous macro ENDM ;clears the 16bit file in LS/MS format CLRF16 MACRO ADDRESS CLRF ADDRESS ;Clear LS CLRF ADDRESS+1 ;MS ENDM ;clears the accumulator 'A' CLRA MACRO CLRF16 ACCaLO ;Clear LS/MS ENDM ;Sets the accumulator 'A' SETA MACRO SETF16 ACCaLO ;Clear LS/MS ENDM ;Set 16bit file SETF16 MACRO ADDRESS SETF ADDRESS SETF ADDRESS+1 ENDM ;clears the accumulator 'B' CLRB MACRO CLRF16 ACCbLO ;Clear LS/MS ENDM ;Sets the accumulator 'B' SETB MACRO SETF16 ACCaLO ;Clear LS/MS ENDM ;clears the accumulator 'C' CLRAC MACRO CLRF16 ACCcLO ;Clear LS/MS ENDM ;clears the accumulator 'B' CLRD MACRO CLRF16 ACCdLO ;Clear LS/MS ENDM ;clears the 24bit file in LS/MS format CLRF24 MACRO ADDRESS CLRF ADDRESS ;Clear LS CLRF ADDRESS+1 CLRF ADDRESS+2 ;MS ENDM ;Shift 16 bit file left one bit LSLF16 MACRO ADDRESS CLRC ;so it won't corrupt LS bit RLCF ADDRESS,F ;LS setting carry as appropriate RLCF ADDRESS+1,F ;MS with any carry from LS byte ENDM ;Shift 16bit accumulator left 1 bit LSLA MACRO ;See LSLF16 for comments LSLF16 ACCaLO ENDM ;Shift 16bit accumulator left 1 bit LSLB MACRO ;See LSLF16 for comments LSLF16 ACCbLO ENDM ;Shift 16 bit file right one bit LSRF16 MACRO ADDRESS CLRC ;so it won't corrupt MS bit RRCF ADDRESS+1,F ;MS setting carry as appropriate RRCF ADDRESS,F ;LS with any carry from MS byte ENDM ;Logical Shift 16bit accumulator right 1 bit LSRA MACRO ;See LSLF16 for comments LSRF16 ACCaLO ENDM ;Logical Shift 16bit accumulator right 1 bit LSRB MACRO ;See LSLF16 for comments LSRF16 ACCbLO ENDM ;Logical Shift 32bits right where 'B' holds MS and 'A' holds LS part LSRBA MACRO RLCF ACCbHI,W ;Get Sign bit into carry without corrupting file RRCF ACCbHI,F RRCF ACCbLO,F RRCF ACCaHI,F RRCF ACCaLO,F ENDM ;Logical shift right 32bit number by 8 bits through 'B' and 'A' ;where 'B' holds MS and 'A' holds LS LSRBA8 MACRO MOVFF ACCaHI,ACCaLO MOVFF ACCbLO,ACCaHI MOVFF ACCbHI,ACCbLO CLRF ACCbHI ENDM ;Arithmetic shift right 32bit number by 8 bits through 'B' and 'A' ;where 'B' holds MS and 'A' holds LS ASRBA8 MACRO MOVFF ACCaHI,ACCaLO MOVFF ACCbLO,ACCaHI MOVFF ACCbHI,ACCbLO CLRF ACCbHI BTFSC ADDRESS+1,7 ;If original MS bit is set SETF ACCbHI ;Then new MS is all 1's ENDM ;Increment 32bits in 'B' MS and 'A' LS INCBA MACRO INCF ACCaLO,F BTFSC STATUS,Z INCF ACCaHI,F BTFSC STATUS,Z INCF ACCbLO,F BTFSC STATUS,Z INCF ACCbHI,F ENDM ;Arithmetic Shift 16 bit file right one bit ;Same as logical shift except MS bit is copied into new MS bit ASRF16 MACRO ADDRESS CLRC BTFSC ADDRESS+1,7 ;If MS bit is set SETC ;Then set carry ready for copying RRCF ADDRESS+1,F ;MS setting carry as appropriate RRCF ADDRESS,F ;LS with any carry from MS byte ENDM ;Arithmetic Shift 16bit accumulator right 1 bit ;Same as logical shift except MS bit is copied into new MS bit ASRA MACRO ASRF16 ACCaLO ENDM ;Add source file to destination file (corrupts W reg) ADDFF MACRO ADDRSRC,ADDRDEST MOVF ADDRSRC,W ADDWF ADDRDEST,F ENDM ;Add source file to destination file with carry (corrupts W reg) ADDFFC MACRO ADDRSRC,ADDRDEST MOVF ADDRSRC,W ADDWFC ADDRDEST,F ENDM ;Add literal to designated file (corrupts W reg) ADDLF MACRO ADDRESS,VALUE MOVLW VALUE ADDWF ADDRESS,F ENDM ;Add literal with carry to designated file (corrupts W reg) ADDLFC MACRO ADDRESS,VALUE MOVLW VALUE ADDWFC ADDRESS,F ENDM ;Double precision unsigned 16x16 bit multiplication of accumulator x file ;with LS result in accumulator 'a' ;and MS result in accumulator 'b' ;NB:-Uses RES0:RES3 so don't use it in interrupt routine as well as ;in main loop without saving RES0:RES3 context MULFA MACRO ADDRESS MULFA16 ADDRESS ;Unsigned multiply MOVF32 RES0,ACCaLO ;Get result in accumulator pair 'ab' ENDM ;Double precision Signed 16x16 bit multiplication of accumulator x file ;with LS result in accumulator 'a' ;and MS result in accumulator 'b' ;NB:-Uses RES0:RES3 so don't use it in interrupt routine as well as ;in main loop without saving RES0:RES3 context MULFAS MACRO ADDRESS MULFA16S ADDRESS ;Signed multiply MOVF32 RES0,ACCaLO ;Get result in accumulator pair 'ab' ENDM ;Unsigned multiply accumulator 'a' by file, answer in RES0:RES3 ;Copied from PIC18FXX8 manual P76 ;NB:-Uses RES0:RES3 so don't use it in interrupt routine as well as ;in main loop without saving RES0:RES3 context MULFA16 MACRO ADDRESS MOVF ACCaLO,W MULWF ADDRESS MOVFF PRODH,RES1 MOVFF PRODL,RES0 MOVF ACCaHI,W MULWF ADDRESS+1 MOVFF PRODH,RES3 MOVFF PRODL,RES2 MOVF ACCaLO,W MULWF ADDRESS+1 MOVF PRODL,W ADDWF RES1 MOVF PRODH,W ADDWFC RES2 CLRF WREG ADDWFC RES3 MOVF ACCaHI,W MULWF ADDRESS MOVF PRODL,W ADDWF RES1 MOVF PRODH,W ADDWFC RES2 CLRF WREG ADDWFC RES3 ENDM ;Signed multiply accumulator 'a' by file, answer in RES0:RES3 MULFA16S MACRO ADDRESS LOCAL SIGN_ARG1 LOCAL CONT_CODE MULFA16 ADDRESS ;Unsigned multiply ;Now handle signs BTFSS ADDRESS+1,7 BRA SIGN_ARG1 MOVF ACCaLO,W SUBWF RES2 MOVF ACCaHI,W SUBWFB RES3 SIGN_ARG1 BTFSS ACCaHI,7 BRA CONT_CODE MOVF ADDRESS,W SUBWF RES2 MOVF ADDRESS+1,W SUBWFB RES3 CONT_CODE ENDM ;Double Precision unsigned 16/16 division ACCb/ACCa->ACCb with remainder in ACCc ;Source modified from AN526 P5-36 ;Beware, make sure that ACCb > ACCa ;Beware,don't use Div routine in interrupt routines as it uses M_TEMP unless you save it ;Uses register 'd' DIVBA MACRO LOCAL DLOOP LOCAL NOCHK LOCAL NOGO ;First move 16 bit register b to register d ; INTERRUPTS_OFF ;Make sure it doesn't change between reading MS & LS halves! MOVFF ACCbHI,ACCdHI ;MS MOVFF ACCbLO,ACCdLO ;LS ; INTERRUPTS_ON ;And clear register b CLRF ACCbHI CLRF ACCbLO ;Also clear register c CLRF ACCcHI CLRF ACCcLO ;And setup loop counter MOVLW .16 MOVWF M_TEMP DLOOP BCF STATUS,C RLCF ACCdLO,F RLCF ACCdHI,F RLCF ACCcLO,F RLCF ACCcHI,F MOVF ACCaHI,W SUBWF ACCcHI,W ;Check if a>c BTFSS STATUS,Z ;carry set if c>a GOTO NOCHK MOVF ACCaLO,W SUBWF ACCcLO,W ;If msb equal then check lsb NOCHK BTFSS STATUS,C GOTO NOGO MOVF ACCaLO,W ;C-A into C SUBWF ACCcLO,F BTFSS STATUS,C DECF ACCcHI,F MOVF ACCaHI,W SUBWF ACCcHI,F BSF STATUS,C ;Shift a 1 into b (result) NOGO RLCF ACCbLO,F RLCF ACCbHI,F DECFSZ M_TEMP,F ;Loop until all bits checked GOTO DLOOP ENDM ;32/16 bit division ;(ACCa,ACCb)/ACCc-> (ACCa,ACCb) rem ACCd ;Move ab pair into ef pair & clear ab pair & d ;Setup loop counter to 32 ;Shift d & ef left one bit (ef ms into d ls) ;Check if c>d ;If yes then d-c->d & shift a 1 into lsb of ab (result) ;Else shift a 0 into lsb of ab (result) ;Repeat for all bits ;Double Precision unsigned 32/16 division (ACCa,ACCb)/ACCc->(ACCa,ACCb) with remainder in (ACCe,ACCf) ;Source modified from above DIVBA ;Beware, make sure that ACCb > ACCa ;Beware,don't use Div routine in interrupt routines as it uses M_TEMP unless you save it DIVABC MACRO LOCAL DLOOP LOCAL NOCHK LOCAL NOGO ;First move 32 bit register ab to register gh ; INTERRUPTS_OFF ;Make sure it doesn't change between reading each byte! MOVF16 ACCaLO,ACCgLO ;Done as 2 lots so explicit use of Acc h makes sure it exists! MOVF16 ACCbLO,ACChLO ; INTERRUPTS_ON CLRAB ;Clear 32bit register pair ab that will hold the answer CLREF ;Also clear 32 bit register pair EF ;And setup loop counter MOVLW d'32' MOVWF M_TEMP DLOOP LSLGH ;Logical shift left GH pair RLFEFC ;into EF with carry NOP NOP ;if EF > C CLRC ;Following MOVF does not affect C flag MOVF ACCfHI,W ;F register contains overflow from E register so will always be bigger than C if non zero BNZ SUBIT MOVF ACCfLO,W BNZ SUBIT MOVF ACCcHI,W SUBWF ACCeHI,W BTFSS STATUS,Z GOTO NOCHK MOVF ACCcLO,W SUBWF ACCeLO,W NOCHK BTFSS STATUS,C GOTO NOGO ;Shift a 0 into b (result) SUBIT MOVF ACCcLO,W ;EF-C into EF SUBWF ACCeLO,F MOVF ACCcHI,W SUBWFB ACCeHI,F CLRF WREG SUBWFB ACCfLO,F CLRF WREG SUBWFB ACCfHI,F BSF STATUS,C ;Shift a 1 into b (result) NOGO RLCF ACCaLO,F ;Shift 1 or 0 into result RLCF ACCaHI,F RLCF ACCbLO,F RLCF ACCbHI,F DECFSZ M_TEMP,F ;Loop until all bits checked GOTO DLOOP ENDM ;Start of 32Bit maths definitions ;When using register pairs eg A & B then A is LS and B is MS MOVF32 MACRO ADDRESS,ADDRESS1 MOVFF ADDRESS,ADDRESS1 MOVFF ADDRESS+1,ADDRESS1+1 MOVFF ADDRESS+2,ADDRESS1+2 MOVFF ADDRESS+3,ADDRESS1+3 ENDM ;Move 16bit file into 32bit file & sign extend MOVF16E32 MACRO ADDRESS,ADDRESS1 LOCAL PLUS MOVFF ADDRESS,ADDRESS1 MOVFF ADDRESS+1,ADDRESS1+1 CLRF ADDRESS1+2 CLRF ADDRESS1+3 BTFSS ADDRESS+1,7 ;Original sign GOTO PLUS SETF ADDRESS1+2 SETF ADDRESS1+3 PLUS ENDM ;Move 32bit pair AB to File MOVABF MOVABF MACRO ADDRESS MOVF32 ACCaLO,ADDRESS ENDM ;Move File to 32bit pair AB MOVFAB MACRO ADDRESS MOVF32 ADDRESS,ACCaLO ENDM ;Move 16 bit File to 32bit pair AB & sign extend MOVF16EAB MACRO ADDRESS MOVF16E32 ADDRESS,ACCaLO ENDM ;Move 16 bit File to 32bit pair CD & sign extend MOVF16ECD MACRO ADDRESS MOVF16E32 ADDRESS,ACCcLO ENDM ;Move File to 32bit pair CD MOVFCD MACRO ADDRESS MOVF32 ADDRESS,ACCcLO ENDM ;Move 32bit pair CD to File MOVCDF MACRO ADDRESS MOVF32 ACCcLO,ADDRESS ENDM ;Move 32bit pair AB to CD MOVABCD MACRO MOVF32 ACCaLO,ACCcLO ENDM ;Move 32bit pair CD to AB MOVCDAB MACRO MOVF32 ACCcLO,ACCaLO ENDM ;clears the 32bit file in LS/MS format CLRF32 MACRO ADDRESS CLRF ADDRESS ;Clear LS CLRF ADDRESS+1 CLRF ADDRESS+2 CLRF ADDRESS+3 ;MS ENDM ;Clear 32 bit register pair AB CLRAB MACRO CLRF32 ACCaLO ENDM ;Clear 32 bit register pair CD CLRCD MACRO CLRF32 ACCcLO ENDM ;Clear 32 bit register pair EF CLREF MACRO CLRF32 ACCeLO ENDM ;Add CD to AB ADDCDAB MACRO ;ab+cd->ab ADDFAB ACCcLO ENDM ;Add 32 bit file to accumulator pair AB ADDFAB MACRO ADDRESS ;ab+f->ab MOVF ADDRESS,W ADDWF ACCaLO,F MOVF ADDRESS+1,W ADDWFC ACCaHI,F MOVF ADDRESS+2,W ADDWFC ACCbLO,F MOVF ADDRESS+3,W ADDWFC ACCbHI,F ENDM ;Add accumulator pair AB to 32 bit file ADDABF MACRO ADDRESS ;f+ab->f MOVF ACCaLO,W ADDWF ADDRESS,F MOVF ACCaHI,W ADDWFC ADDRESS+1,F MOVF ACCbLO,W ADDWFC ADDRESS+2,F MOVF ACCbHI,W ADDWFC ADDRESS+3,F ENDM ;Subtract 32 bit file from 'AB' result in 'AB' SUBFAB MACRO ADDRESS MOVF ADDRESS,W SUBWF ACCaLO,F MOVF ADDRESS+1,W SUBWFB ACCaHI,F MOVF ADDRESS+2,W SUBWFB ACCbLO,F MOVF ADDRESS+3,W SUBWFB ACCbHI,F ENDM ;Subtract 'AB' from 32 bit file result in file SUBABF MACRO ADDRESS MOVF ACCaLO,W SUBWF ADDRESS,F MOVF ACCaHI,W SUBWFB ADDRESS+1,F MOVF ACCbLO,W SUBWFB ADDRESS+2,F MOVF ACCbHI,W SUBWFB ADDRESS+3,F ENDM ;Unsigned compare 32 bit file with 32 bit file (f2-f1) ;carry & zero flags reflect unsigned 32bit result CMPFFU32 MACRO ADDRESS1,ADDRESS2 ;See AN526 LOCAL NOCHK LOCAL LSCHK MOVF ADDRESS1+3,W ;ms SUBWF ADDRESS2+3,W ;check if file > file BZ LSCHK1 ;continue if file=file GOTO NOCHK ;ms result tells all LSCHK1 MOVF ADDRESS1+2,W ;ms same so test next ms SUBWF ADDRESS2+2,W ;carry set if a > file BZ LSCHK2 ;continue if file=file GOTO NOCHK ;next ms result tells all LSCHK2 MOVF ADDRESS1+1,W ;ms same so test next ms SUBWF ADDRESS2+1,W ;carry set if a > file BZ LSCHK3 ;continue if file=file GOTO NOCHK ;next ms result tells all LSCHK3 MOVF ADDRESS1,W ;ms same so test next ms SUBWF ADDRESS2,W ;carry set if a > file NOCHK ENDM ;Negate 32 bit register pair AB NEGAB MACRO NEGF32 ACCaLO ENDM ;Negate 32 bit file NEGF32 MACRO ADDRESS ;Invert then add 1 COMF ADDRESS,F ;LS COMF ADDRESS+1,F COMF ADDRESS+2,F COMF ADDRESS+3,F CLRF WREG SETC ADDWFC ADDRESS,F ;LS ADDWFC ADDRESS+1,F ADDWFC ADDRESS+2,F ADDWFC ADDRESS+3,F ENDM ;Shift 32 bit file left one bit LSLF32 MACRO ADDRESS CLRC ;so it won't corrupt LS bit RLCF ADDRESS,F ;LS setting carry as appropriate RLCF ADDRESS+1,F ;carry from LS byte RLCF ADDRESS+2,F RLCF ADDRESS+3,F ENDM ;Rotate 32 bit file left one bit through carry RLF32C MACRO ADDRESS RLCF ADDRESS,F ;Using carry from caller RLCF ADDRESS+1,F ;carry from LS byte RLCF ADDRESS+2,F RLCF ADDRESS+3,F ENDM ;Rotate 32bit register pair EF left through carry RLFEFC MACRO RLF32C ACCeLO ENDM ;Logical Shift 32bit register pair AB one bit right. LSRAB MACRO LSRF32 ACCaLO ENDM ;Logical Shift 32 bit file right one bit LSRF32 MACRO ADDRESS CLRC ;so it won't corrupt MS bit RRCF ADDRESS+3,F ;MS setting carry as appropriate RRCF ADDRESS+2,F RRCF ADDRESS+1,F RRCF ADDRESS,F ;LS with any carry from MS byte ENDM ;Arithmetic Shift 32 bit file right one bit ASRF32 MACRO ADDRESS CLRC BTFSC ADDRESS+3,7 ;If MS bit is set SETC ;Then set carry ready for copying RRCF ADDRESS+3,F ;MS setting carry as appropriate RRCF ADDRESS+2,F RRCF ADDRESS+1,F RRCF ADDRESS,F ;LS with any carry from MS byte ENDM ;Arithmetic Shift accumulator pair AB one bit right ASRAB MACRO ASRF32 ACCbLO ENDM ;Logical Shift accumulator pair AB one bit left LSLAB MACRO LSLF32 ACCaLO ENDM ;Logical Shift accumulator pair CD one bit left LSLCD MACRO LSLF32 ACCcLO ENDM ;Logical Shift accumulator pair EF one bit left LSLEF MACRO LSLF32 ACCeLO ENDM ;Logical Shift accumulator pair GH one bit left LSLGH MACRO LSLF32 ACCgLO ENDM ;Save 8 bit file to Indirection pointer 2 POST2F8 MACRO ADDRESS MOVF ADDRESS,W MOVWF POSTINC2 ;Save to Capture buffer & increment pointer ENDM ;Save 16 bit file to Indirection pointer 2 POST2F16 MACRO ADDRESS MOVF ADDRESS,W MOVWF POSTINC2 ;Save to Capture buffer & increment pointer MOVF ADDRESS+1,W MOVWF POSTINC2 ;Save to Capture buffer & increment pointer ENDM ;Save 32 bit file to Indirection pointer 2 POST2F32 MACRO ADDRESS MOVF ADDRESS,W MOVWF POSTINC2 ;Save to Capture buffer & increment pointer MOVF ADDRESS+1,W MOVWF POSTINC2 ;Save to Capture buffer & increment pointer MOVF ADDRESS+2,W MOVWF POSTINC2 ;Save to Capture buffer & increment pointer MOVF ADDRESS+3,W MOVWF POSTINC2 ;Save to Capture buffer & increment pointer ENDM ;Odds & ends for PIC18F458 ;Select databank given REGBANK MACRO BANKNUMBER MOVLB BANKNUMBER ;BSR=0 for bank 0 etc ENDM ;Extend instruction set with more convenient op-codes SAVEMAX8 MACRO ADDRESS CPFSGT ADDRESS MOVWF ADDRESS ;Save as its bigger ENDM SAVEMIN8 MACRO ADDRESS CPFSLT ADDRESS MOVWF ADDRESS ;Save as its smaller ENDM ;Clear carry CLRC MACRO BCF STATUS,C ENDM ;Set Carry SETC MACRO BSF STATUS,C ENDM ;Logical shift left file LSLF MACRO ADDRESS CLRC ;So it won't corrupt LS bit RLCF ADDRESS,F ENDM ;Logical shift right file LSRF MACRO ADDRESS CLRC ;So it won't corrupt MS bit RRCF ADDRESS,F ENDM ;Sets Z and N flag but does not change file TSTF MACRO ADDRESS MOVF ADDRESS,F ENDM