;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+
file: /Techref/member/RF-AMY-K22a/mathsdefs_h.htm, 34KB, , updated: 2014/4/9 16:37, local time: 2024/10/18 09:36,
owner: RF-AMY-K22a,
3.135.211.217:LOG IN ©2024 PLEASE DON'T RIP! THIS SITE CLOSES OCT 28, 2024 SO LONG AND THANKS FOR ALL THE FISH!
|
©2024 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions? <A HREF="http://ecomorder.com/techref/member/RF-AMY-K22a/mathsdefs_h.htm"> Roger Froud's 16 and 32 bit maths function macros for PIC18F458</A> |
Did you find what you needed? |