;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