; ; PicMacro12bitCore.inc ; ; Collection of PIC 12 bit core MPASM Macro's ; Terry Rudersdorfer, AScT (VE7TRZ) 15/Nov/2014 ; ; this file is provided as is to the public domain ; ; Inspired by Karl Lunt's Macro Library (May 1999) ; ; I built this as a fun project specifically to use; sav|svc|cmp, _if, select, ; and mSec(s) Macro's ... all of the other Macro's fall in to the nice to have category ; ; there is undoubtably going to be simpler ways to implement some logic but for quick ; prototyping I found these Macro's very useful ... specifically they quickly provided ; constructs to create a State Machine for a simple automation project ; ; Macro Parameters ; ; There are 3 basic parameters; ,, and where: ; L = Literal as 1 or 2 bytes or a bit ; S = Source as 1 or 2 registers or a bit ; D = Destination as 1 or 2 registers or a bit (results returned in D or Status) ; ; There are an additional 4 special parameters; ,,, and where; ; B = Bit Reference, always requires a D or S register ie S,Bs or D,Bd ; Z = Bit Reference, always requires a Register,Bit (cmp16 bit interim Z value) ; A = action _ne, _eq, _gt, or _lt (used in _if tests) ; X = Operation as: logical AND or logical OR (used in _if tests) ; ; Numeric suffixes on Macro Names, L, S and D are defined as: ; 1 = Bit, 8 = Byte, 16 = unsigned Word (data pairs registers are in Low High format) ; ; Suffixes on B (Bit) are s = Source or d = Destination ; ; A suffix of r on the end of a Macro name indicates the Macro uses a Source Register ... ; the numeric suffix identifies the size of the Source and Destination ; ; A special case of Zr,Zb points to a Bit Location to temporarily store the value of the ; Zero Flag required only for 16bit compares; cmp16, cmp16r, tst16 and tst16r ... Zr is the ; register, Zb is the bit number ; ; Macro List ; ; Macro Params Operation Results ;------ ---------------------------- ------------------- ------- ; and8 , L & D -> D ; and8r , S & D -> D ; and16 , L16 & D16 -> D16 ; and16r , S16 & D16 -> D16 ; add8 , L + D -> D ; add8r , S + D -> D ; add16 , L16 + D16 -> D16 ; add16r , S16 + D16 -> D16 ; clr1 , 0 -> D,B ; clr8 0 -> D ; clr16 0 -> D16 ; cmp1 ,, L = D,Bd? -> Z = 1 (L = D) ; cmp1r ,,, S,Bs = D,Bd? -> Z = 1 (S = D) ; cmp8 , L = D? -> Z = 1 (L = D) ; C = 1 (L > D) ; C = 0 (L < D) ; cmp8r , S = D? -> Z = 1 (S = D) ; C = 1 (S > D) ; C = 0 (S < D) ; cmp16 ,,, L16 = D16? -> Z = 1 (L = D) ; C = 1 (L > D) ; C = 0 (L < D) ; cmp16r ,,, S16 = D16? -> Z = 1 (S = D) ; C = 1 (S > D) ; C = 0 (S < D) ; cpl1 , D,B ~ -> D,B ; cplw W ~ -> W ; cpl8 D ~ -> D ; cpl16 D16 ~ -> D16 ; inc8 D + 1 -> D Z = 1 (D = 0) ; inc16 D16 + 1 -> D16 Z = 1 (D = 0) ; ior8 , L & D -> D ; ior8r , S & D -> D ; ior16 , L16 & D16 -> D16 ; ior16r , S16 & D16 -> D16 ; sav1 ,. L -> D,Bd ; sav1r ,,. S,Bs -> D,Bd ; sav8 , L -> D ; sav8r , S -> D ; sav16 , L16 -> D16 ; sav16r , S16 -> D16 ; set1 , 1 -> D,Bd ; sub8 , D - L -> D Z = 1 (D = 0) ; C = 1 (D > 0) ; C = 0 (D < 0) ; sub8r , D - S -> D Z = 1 (D = 0) ; C = 1 (D > 0) ; C = 0 (D < 0) ; sub16 , D16 - L16 -> D16 Z = 1 (D = 0) ; C = 1 (D > 0) ; C = 0 (D < 0) ; sub16r , D16 - S16 -> D16 Z = 1 (D = 0) ; C = 1 (D > 0) ; C = 0 (D < 0) ; svc8 , L ~ + 1 -> D ; svc8r , S ~ + 1 -> D ; svc16 , L16 ~ + 1 -> D16 ; svc16r , S16 ~ + 1 -> D16 ; tcp8 D ~ + 1 -> D ; tcp16 D16 ~ + 1 -> D16 ; xor8 , L xor D -> D ; xor8r , S xor D -> D ; xor16 , L16 xor D16 -> D16 ; xor16r , S16 xor D16 -> D16 ; ; ; Specialty Macros: ; ; Timers: ; ; mSec 1 mSec Delay ; ; mSecs , Ll6 (literal) * 1 mSec Delay (uses D16) ; ; ; Logical: ; ; if, then, else, endif (all are keywords, so macros are prefixed with '_') ; else is optional ; ; tst# and tst#r are tests that can be chained together to form complex if's ; the last tst in any _if must have an Operation = __ ; ; if's can be nested with or without chained tests with like Operators ; (NOTE: while mixing Operators is not recommended, A OR (B and C) will work ; ; if tst and tst and tst then do something endif ; ; if tst or tst or tst then do something else do something else endif ; ; example: test a flag/bit state ; and test a 16 bit register ; and test an 8 bit register ; then ; test a 16 bit register against another 16 bit register ; ; #define SomeFlag r08,0 ; #define TmpZ r08,1 ; #define Reg16x r09 ; and r0A ; #define Reg16y r0B ; and r0C ; #define Reg8x r0D ; #define Reg8y r0E ; ; _if ; tst1 1, SomeFlag, _eq, _and ; tst16 0x1212, Reg16x, TmpZ, _ne, _and ; tst8r Reg8x, Reg8y, _eq, __ ; _then ; _if ; tst16r Reg16x, Reg16z, TmpZ, _eq, __ ; _then ; nop ; nop ; _else ; nop ; _endif ; _endif ; ; _if ; ; _tst1 ,,,, A; 0(!=), 1(=), 2(>), 3(<) ; X; 0(or), 1(and) ; _tst1r ,,,,, A; 0(!=), 1(=), 2(>), 3(<) ; X; 0(or), 1(and) ; _tst8 ,,, A; 0(!=), 1(=), 2(>), 3(<) ; X; 0(or), 1(and) ; _tst8r ,,, A; 0(!=), 1(=), 2(>), 3(<) ; X; 0(or), 1(and) ; _tst16 ,,,,, A; 0(!=), 1(=), 2(>), 3(<) ; X; 0(or), 1(and) ; _tst16r ,,,,, A; 0(!=), 1(=), 2(>), 3(<) ; X; 0(or), 1(and) ; _then ; ; _else ; ; _endif ; ; ; considered adding a select16 however didn't have a use for it in my last project ; ; select, case, endcase, otherwise, endselect ; ; case#, case#r and otherwise can be chained together ; otherwise is optional ; ; example ; select ; movf SomeReg,W ; ; case8 0x11 ; W = 0x11? ; nop ; yes do something ; ; case8r AnotherReg ; W = AnotherReg? ; nop ; yes do somthing else ; ; otherwise ; optional ; nop ; default something ; ; endselect ; ; ; select ; ; case8 L = W? -> do case ; ; case8r S = W? -> do case ; ; endcase ; ; otherwise ; ; endselect ; ; Constants #define mccComplement 0xFF #define mccZero 0x00 #define mccOne 0x01 ; if then else; tst modifiers #define __ 1 ; must always be the last tst in any _if #define _or 0 #define _and 1 #define _ne 0 #define _eq 1 #define _gt 2 #define _lt 3 ; And Literal with D Register and8 macro L,D movlw L andwf D,F endm ; And S Register with D Register and8r macro S,D movf S,W andwf D,F endm ; And 16 bit Literal with 16 bit D Register and16 macro L16,D16 and8 LOW(L16) ,D16 and8 HIGH(L16),D16+1 endm ; And 16 bit S Register with 16 bit D Register and16r macro S16,D16 and8r S16, D16 and8r S16+1,D16+1 endm ; Add Literal to D Register add8 macro L,D movlw L addwf D,F endm ; Add S Register to D Register add8r macro S,D movf S,W addwf D,F endm ; Add 16 bit Literal with 16 bit D Register add16 macro L16,D16 add8 HIGH(L16),D16+1 add8 LOW(L16),D16 _add16 D16 endm ; Add 16 bit S Register to 16 bit D Register add16r macro S16,D16 add8r S16+1,D16+1 add8r S16, D16 _add16 D16 endm _add16 macro D16 local addend bnc addend incf D16+1,F addend endm ; Clear Bd bit in D Register clr1 macro D,Bd bcf D,Bd endm ; Clear D Register clr8 macro D clrf D endm ; Clear 16 bit D Register clr16 macro D16 clrf D16 clrf D16+1 endm ; Compare Literal bit with D Register, Bd bit (Z = 1 when equal) cmp1 macro L,D,Bd clrw if L == 0 cplw endif btfss D,Bd cplw endm ; Compare S Register, Bs bit with D Register, Bd bit (Z = 1 when equal) cmp1r macro S,Bs,D,Bd clrw btfss S,Bs cplw btfss D,Bd cplw endm ; Compare Literal with D Register Z = 1 when D EQ L ; C = 1 when D GT L ; C = 0 when D LT L cmp8 macro L,D movlw L subwf D,W endm ; Compare S Register with D Register Z = 1 when D EQ S ; C = 1 when D GT S ; C = 0 when D LT S cmp8r macro S,D movf S,W subwf D,W endm ; Compare 16 bit Literal with 16 bit D Register Z = 1 when D16 EQ L16 ; C = 1 when D16 GT L16 ; C = 0 when D16 LT L16 cmp16 macro L16,D16,Zr,Zb local _bc cmp8 LOW(L16),D16 sav1r STATUS,Z,Zr,Zb movlw HIGH(L16) bc _bc if HIGH(L16) == mccComplement movlw mccZero else movlw HIGH(L16) + 1 endif _bc subwf (D16)+1,W btfss Zr,Zb iorlw mccOne btfss STATUS,Z iorlw mccOne endm ; Compare 16 bit S Register with 16 bit D Register Z = 1 when D16 EQ S16 ; C = 1 when D16 GT S16 ; C = 0 when D16 LT S16 cmp16r macro S16,D16,Zr,Zb local _bc cmp8r S16,D16 sav1r STATUS,Z,Zr,Zb movf S16+1,W bc _bc incf S16+1,W _bc subwf (D16)+1,W btfss Zr,Zb iorlw mccOne btfss STATUS,Z iorlw mccOne endm ; Complement Bd bit in D Register cpl1 macro D,Bd movf D,W clrf D bsf D,Bd xorwf D,F endm ; Complement W Register cplw macro xorlw mccComplement endm ; Complement D Register cpl8 macro D comf D,F endm ; Compliment 16 bit D Register cpl16 macro D16 cpl8 D16 cpl8 D16+1 endm ; Increment D Register (Z = 1 when Zero) inc8 macro D incf D,F endm ; Increment 16 bit D Register (Z = 1 when Zero) inc16 macro D16 incfsz D16,W decf D16+1,F incf D16+1,F movwf D16 iorwf D16+1,W endm ; Ior Literal with D Register ior8 macro L,D movlw L iorwf D,F endm ; Ior S Register with D Register ior8r macro S,D movf S,W iorwf D,F endm ; Ior 16 bit Literal with 16 bit D Register ior16 macro L16,D16 ior8 LOW(L16) ,D16 ior8 HIGH(L16),D16+1 endm ; Ior 16 bit S Register with 16 bit D Register ior16r macro S16,D16 ior8r S16, D16 ior8r S16+1,D16+1 endm ; Save/Copy Literal bit to D Register, Bd bit sav1 macro L,D,Bd if L == 0 clr1 D,Bd else set1 D,Bd endif endm ; Save/Copy S Register, Bs bit to D Register, Bd bit sav1r macro S,Bs,D,Bd clr1 D,Bd btfsc S,Bs set1 D,Bd endm ; Save/Copy Literal to D Register sav8 macro L,D movlw L movwf D endm ; Save/Copy S Register to D Register sav8r macro S,D movf S,W movwf D endm ; Save/Copy 16 bit Literal to 16 bit D Register sav16 macro L16,D16 sav8 LOW(L16),D16 sav8 HIGH(L16),D16+1 endm ; Save/Copy 16 bit S Register to 16 bit D Register sav16r macro S16,D16 sav8r S16, D16 sav8r S16+1,D16+1 endm ; Set Bd bit in D Register set1 macro D,Bd bsf D,Bd endm ; Subtract Literal from D Register Z = 1 when D EQ L ; C = 1 when D GT L ; C = 0 when D LT L sub8 macro L,D movlw L subwf D,F endm ; Subtract S Register from D Register Z = 1 when D EQ S ; C = 1 when D GT S ; C = 0 when D LT S sub8r macro S,D movf S,W subwf D,F endm ; Subtract 16 bit Literal from 16 bit D Register Z = 1 when D16 EQ L16 ; C = 1 when D16 GT L16 ; C = 0 when D16 LT L16 sub16 macro L16,D16 local _bc sub8 LOW(L16),D16 movlw HIGH(L16) bc _bc if HIGH(L16) == mccComplement movlw mccZero else movlw HIGH(L16) + 1 endif _bc subwf (D16)+1,F movf D16,W iorwf D16+1,W endm ; Subtract 16 bit S Register from 16 bit D Register Z = 1 when D16 EQ S16 ; C = 1 when D16 GT S16 ; C = 0 when D16 LT S16 sub16r macro S16,D16 local _bc sub8r S16,D16 movf S16+1,W bc _bc incf S16+1,W _bc subwf (D16)+1,F movf D16,W iorwf D16+1,W endm ; Save Literal 2's Complimemt result in D Register svc8 macro L,D sav8 L,D tcp8 D endm ; Save S Register 2's Complimemt result in D Register svc8r macro S,D sav8r S,D tcp8 D endm ; Save 16 bit Literal 2's Complimemt result in 16 bit D Register svc16 macro L16,D16 sav16 L16,D16 tcp16 D16 endm ; Save 16 bit S Register 2's Complimemt result in 16 bit D Register svc16r macro S16,D16 sav16r S16,D16 tcp16 D16 endm ; 2's Complement D Register tcp8 macro D cpl8 D inc8 D endm ; 2's Complement 16 Bit D Register tcp16 macro D16 cpl16 D16 inc16 D16 endm ; Xor Literal with D Register xor8 macro L,D movlw L xorwf D,F endm ; Xor S Register with D Register xor8r macro S,D movf S,W xorwf D,F endm ; Xor 16 bit Literal with 16 Bit D Register xor16 macro L16,D16 xor8 LOW(L16) ,D16 xor8 HIGH(L16),D16+1 endm ; Xor 16 bit S Register with 16 Bit D Register xor16r macro S16,D16 xor8r S16, D16 xor8r S16+1,D16+1 endm ; mSec Delay 1 millisecond ; in the 10F206 there are no interrupts so Delays can be very useful ; this 1 milli second delay requires the 10F206 to use the TMR PSA ; Uses TMR0 expects: Osc = 4 MHz ; F0SC / 4 = 1 MHz ; TMR set to use PreScaler ; Prescaler set to 1:8 (PSA = 2 in 10F206) ; #define mccTMR0 0x7D ; FOSC/4 1:8 delay count to match 1 millisecond mSec macro local mcLP clrf TMR0 mcLP movlw mccTMR0 ; check delay value #ifdef _WDT_SET clrwdt #endif subwf TMR0,W bnc mcLP endm ; mSecs Delay 16 bit Literal * millisecond Uses 16 bit D Register mSecs macro L16,D16 local mcLP svc16 L16,D16 mcLP mSec inc16 D16 bnz mcLP endm ; if then else endif (else is optional) ; ; multiple tests can be chained together ; tst# and or tst#r can be combined with AND (X = 1) or OR (X = 0) ; actions include: D != S (A = 0), D = S (A = 1), D > S (A = 2), D < S (A = 3) ; caveat: ; - the last test in an _if MUST always have an Operation of __ ; - if a combination of OR and AND are used, OR tests MUST be done first ; a == 0 OR (b != 0x1000 AND c > 3) can be coded as ; _if ; tst8 a,0x00, _eq,_or ; tst16 b,0x1000,Zr,Zb,_ne,_and ; tst8 c,0x03, _gt,__ ; _then ; ; _else ; ; _endif ; the key to this logic is the _ifs pointer which must keep incrementing to ; ensure labels are not duplicated for multiple instances of _if ; _ifptr also uses last value logic to allow for nesting of if statements variable _ifs =0 ; number of _if instances variable _ifptr =0 ; pointer to current _if instance variable _lastif =0 ; Temporary Storage _if macro _ifs set _ifs+1 ; new if instance _lastif set _ifptr ; temporary storage of last if instance _ifptr set _ifs ; pointer to current if instance _lastptr#v(_ifptr) set _lastif ; last if instance saved to current instance _elseflg#v(_ifptr) set 1 ; special flag to allow optional else endm tst1 macro L,D,Bd,A,X ; Literal bit = Destination bit? cmp1 L,D,Bd _tst A,X endm tst1r macro S,Bs,D,Bd,A,X ; Source bit = Destination bit? cmp1r S,Bs,D,Bd _tst A,X endm tst8 macro L,D,A,X ; Literal Byte = Destination Byte? cmp8 L,D _tst A,X endm tst8r macro S,D,A,X ; Source Byte = Destination Byte? cmp8r S,D _tst A,X endm tst16 macro L16,D16,Zr,Zb,A,X ; Literal Word = Destination Word? (LoHi) cmp16 L16,D16,Zr,Zb _tst A,X endm tst16r macro S16,D16,Zr,Zb,A,X ; Source Word = Destination Word? (LoHi) cmp16r S16,D16,Zr,Zb _tst A,X endm _tst macro A,X if A == _ne ; S <> D if X == _or ; OR bnz _thenx#v(_ifptr) ; OR true -> then, false -> next test else ; AND bz _elsex#v(_ifptr) ; AND true -> next test, false -> else endif ; Logical endif ; Equal if A == _eq ; S = D if X == _or ; OR bz _thenx#v(_ifptr) ; OR true -> then, false -> next test else ; AND bnz _elsex#v(_ifptr) ; AND true -> next test, false -> else endif ; Logical endif ; Equal if A == _gt ; S > D if X == _or ; OR bnc _thenx#v(_ifptr) ; OR true -> then, false -> next test else ; AND bc _elsex#v(_ifptr) ; AND true -> next test, false -> else endif ; Logical endif ; Equal if A == _lt ; S < D if X == _or ; OR bc _thenx#v(_ifptr) ; OR true -> then, false -> next test else ; AND bnc _elsex#v(_ifptr) ; AND true -> next test, false -> else endif ; Logical endif ; Equal endm ; then _then macro _thenx#v(_ifptr) endm ; else (optional) _else macro goto _endifx#v(_ifptr) _elsex#v(_ifptr) _elseflg#v(_ifptr) set 0 ; clear else option flag endm ; endif _endif macro if _elseflg#v(_ifptr) == 1 ; test to see if else was included _elsex#v(_ifptr) ; set the elsex pointer when no else _elseflg#v(_ifptr) set 0 endif _endifx#v(_ifptr) _ifptr set _lastptr#v(_ifptr) ; set pointer to last if instance endm ; select case endcase otherwise endselect (otherwise is optional) ; ; mutiple cases can be chained together variable _sel =0 ; Select instance counter variable _selptr =0 ; current Select instance pointer variable _case =0 ; Case instance counter variable _caseptr=0 ; current Case instance pointer variable _lastsel=0 ; temporary storage ; Select select macro _sel set _sel+1 ; get next instance _lastsel set _selptr ; temporary storage of last instance pointer _selptr set _sel ; set current instance pointer _lastselptr#v(_selptr) set _lastsel ; save last instance pointer endm ; Case compares Literal to W Register case8 macro L _case set _case+1 _caseptr set _case xorlw L bz nextcase#v(_caseptr) xorlw L goto endcasex#v(_caseptr) nextcase#v(_caseptr) xorlw L endm ; Case compares S Register to W Register case8r macro S _case set _case+1 _caseptr set _case xorwf S,W bz nextcase#v(_caseptr) xorwf S,W goto endcasex#v(_caseptr) nextcase#v(_caseptr) xorwf S,W endm ; Endcase endcase macro goto sel#v(_selptr) endcasex#v(_caseptr) endm ; Otherwise (optional) otherwise macro _case set _case+1 _caseptr set _case endm ; EndSelect endselect macro sel#v(_selptr) _selptr set _lastselptr#v(_selptr) endm