Because blogspot truncates text beyond a certain width, I suggest you copy the include file and paste it in MPLAB or a text editor so you can see all the comments to the right of the code.]
The following include file contains a good number of macros that I've created to make writing code a little easier for the PIC. Also makes the code shorter--albeit only apparently--and easier to read and understand. As in my case, you'll probably find the relational macros (e.g., <, >=, <>0, etc.) the most useful and most used. I'd tear my remaining hair out if I didn't have these macros.
You won't fail to notice that I have four defines each for the btfss and btfsc instructions. I really have a difficult time with these two. The reason is because they force me to think in terms of skipping the next instruction when the test condition is true. I don't know about you but I find it way easier and natural to think of performing the next instruction should the bit test be true. To address this quirk of mine (and in retaliation against what seems to be the defacto assembly way), I've redefined btfsc and btfss as "do next" instructions. "dnx" translates into "do next."
While on the subject of mnemonics, the ones I use for the other macros are as follows:
bit0 = bit is equal to zero
bit1 = bit is equal to one
lt = less than
gt = greater than
eq = equals
not = not
l = literal
lit = literal
f = file register
w = the w register
dest = destination
If you don't like the mnemonics above then by all means change them to something that suits you. Feel free to make up your own macro labels/names.
One very important caveat: Do always keep in mind that these are macros and will be expanded inline (i.e., the macro label will be replaced by the lines of assembly instructions). As such make sure you don't write something like:
dnxgteq reg1, reg2 ; check if reg1 >= reg2 addlf 0xA, reg3 ; do this if it is ; other instructions follow here
This code will fail when reg1 < reg2. The second macro has two lines of assembly and thus when reg1 < reg2 the second line of the macro will be executed along with whatever instructions come after it. The moral is: Never have any (multi-instruction) macros right after a dnx macro.
Now here's the include file that I #include in all my PIC Baseline and Mid-Range asm files.
; ==================================================================================
;
; Defines and Macros
;
; Include this file in all PIC Midrange assembly files
; Edwardson Tan
; April 2007
;
; ==================================================================================
;------------------------------------------------
; do next instruction if bit = 1 (skip next instruction if bit = 0)
#define donextif1 btfsc
#define dnxbit1 btfsc
#define dnxtrue btfsc
#define dnxhigh btfsc
;------------------------------------------------
;------------------------------------------------
; do next instruction if bit = 0 (skip next instruction if bit = 1)
#define donextif0 btfss
#define dnxbit0 btfss
#define dnxfalse btfss
#define dnxlow btfss
;------------------------------------------------
;------------------------------------------------
; copies the contents of one register to another
; same as macro copyregister
movff macro reg1,reg2
movfw reg1
movwf reg2
endm
;------------------------------------------------
;------------------------------------------------
; copies a literal value to a register
; same as macro copyliteral
movlf macro literal, register
movlw literal
movwf register
endm
;------------------------------------------------
;------------------------------------------------
; "sets" a register (opposite of "reset")
; places a literal value of 1 in the register
setf macro register
movlw .1
movwf register
endm
;------------------------------------------------
;------------------------------------------------
; gets the high bits <12:8> of program counter PC and pastes them into PCLATH
; this routine is necessary just prior to doing a table read (retlw)
; with a computed goto, i.e., with a ADDWF PCL,f instruction
getpchigh macro routine_label ; routine_label is the name/label of the subroutine
movlw high routine_label ; "high" is an arithmetic operation that retrieves the high bits of routine_label
movwf PCLATH
endm
;------------------------------------------------
;------------------------------------------------
; mimics the pagesel assembler directive
pageselect macro label ; label is the name/label of the subroutine
movlw high label ; "high" is an arithmetic operation that retrieves the high bits of routine_label
movwf PCLATH
endm
;------------------------------------------------
; ==============================================================================================
; macros that compare two registers
; >, <, >=, <=, =, <>
; ==============================================================================================
;------------------------------------------------
; do next instruction if N1 > N2, skip if not
; N1 and N2 are registers
; in arguments list of macro call, specify N1 first, comma, then N2
dnxgt macro N1,N2
movfw N2
subwf N1,w ; N1 minus N2
donextif1 STATUS,Z ; check if N1 = N2
goto $+3
donextif1 STATUS, C ; note that if C = 0 then subtraction resulted in a negative number
endm ; if N1 >= N2 then C = 1, C = 0 only when N1 < N2
;------------------------------------------------
;------------------------------------------------
; do next instruction if N1 < N2, skip if not
; N1 and N2 are registers
; in arguments list of macro call, specify N1 first, comma, then N2
dnxlt macro N1,N2
movfw N2
subwf N1,w ; N1 minus N2
donextif0 STATUS, C ; note that if C = 0 then subtraction resulted in a negative number
endm ; if N1 >= N2 then C = 1, C = 0 only when N1 < N2
;------------------------------------------------
;------------------------------------------------
; do next instruction if N1 >= N2, skip if not
; N1 and N2 are registers
; in arguments list of macro call, specify N1 first, comma, then N2
dnxgteq macro N1,N2
movfw N2
subwf N1,w ; N1 minus N2
donextif1 STATUS, C ; note that if C = 0 then subtraction resulted in a negative number
endm ; if N1 >= N2 then C = 1, C = 0 only when N1 < N2
;------------------------------------------------
;------------------------------------------------
; do next instruction if N1 <= N2, skip if not
; N1 and N2 are registers
; in arguments list of macro call, specify N1 first, comma, then N2
dnxlteq macro N1,N2
movfw N2
subwf N1,w ; N1 minus N2
donextif0 STATUS,C ; note that if C = 0 then subtraction resulted in a negative number
goto $+3 ; if N1 >= N2 then C = 1, C = 0 only when N1 < N2
donextif0 STATUS,Z
goto $+2
endm
;------------------------------------------------
;------------------------------------------------
; do next instruction if N1 = N2, skip if not
; N1 and N2 are registers
; in arguments list of macro call, specify N1 first, comma, then N2
dnxeq macro N1,N2
movfw N2
subwf N1,w ; N1 minus N2
donextif1 STATUS,Z ; check if N1 = N2
endm
;------------------------------------------------
;------------------------------------------------
; do next instruction if N1 <> N2, skip if not
; N1 and N2 are registers
; in arguments list of macro call, specify N1 first, comma, then N2
dnxnoteq macro N1,N2
movfw N2
subwf N1,w ; N1 minus N2
donextif0 STATUS,Z ; check if N1 = N2
endm
;------------------------------------------------
; ==============================================================================================
; macros that compare a register and a literal
; >, <, >=, <=, =, <>
; ==============================================================================================
;------------------------------------------------
; do next instruction if N > k, skip if not
; N = register, k = literal
; in arguments list of macro call, specify register first, comma, then literal or literal label
dnxgtlit macro N,k
movlw k
subwf N,w ; N minus k
donextif1 STATUS,Z ; check if N = k
goto $+3
donextif1 STATUS, C ; note that if C = 0 then subtraction resulted in a negative number
endm ; if N >= k then C = 1, C = 0 only when N < k
;------------------------------------------------
;------------------------------------------------
; do next instruction if N < k, skip if not
; N = register, k = literal
; in arguments list of macro call, specify register first, comma, then literal or literal label
dnxltlit macro N,k
movlw k
subwf N,w ; N minus k
donextif0 STATUS, C ; note that if C = 0 then subtraction resulted in a negative number
endm ; if N >= k then C = 1, C = 0 only when N < k
;------------------------------------------------
;------------------------------------------------
; do next instruction if N >= k, skip if not
; N= register, k = literal
; in arguments list of macro call, specify N first, comma, then k
dnxgteqlit macro N,k
movlw k
subwf N,w ; N minus k
donextif1 STATUS, C ; note that if C = 0 then subtraction resulted in a negative number
endm ; if N >= k then C = 1, C = 0 only when N < k
;------------------------------------------------
;------------------------------------------------
; do next instruction if N <= k, skip if not
; N = register, k = literal
; in arguments list of macro call, specify N first, comma, then k
dnxlteqlit macro N,k
movlw k
subwf N,w ; N minus k
donextif0 STATUS,C ; note that if C = 0 then subtraction resulted in a negative number
goto $+3 ; if N >= k then C = 1, C = 0 only when N < k
donextif0 STATUS,Z
goto $+2
endm
;------------------------------------------------
;------------------------------------------------
; do next instruction if N = k, skip if not
; N = register, k = literal
; in arguments list of macro call, specify register first, comma, then literal or literal label
dnxeqlit macro N,k
movlw k
subwf N,w ; N minus k
donextif1 STATUS,Z ; check if N = k
endm
;------------------------------------------------
;------------------------------------------------
; do next instruction if N <> k, skip if not
; N = register, k = literal
; in arguments list of macro call, specify register first, comma, then literal or literal label
dnxnoteqlit macro N,k
movlw k
subwf N,w ; N1 minus N2
donextif0 STATUS,Z ; check if N1 = N2
endm
;------------------------------------------------
;------------------------------------------------
; do next instruction if register = 0, skip if not
dnxzero macro register
movf register,w
donextif1 STATUS,Z
endm
;------------------------------------------------
;------------------------------------------------
; do next instruction if register <> 0, skip if not
dnxnotzero macro register
movf register,w
donextif0 STATUS,Z
endm
;------------------------------------------------
; ==============================================================================================
; macros that perform math functions
; ==============================================================================================
;------------------------------------------------
; add literal k to register and put sum in register
; in arguments list of macro call, specify literal first, comma, then register
; NOTE: no provision for results > 255
addlf macro k,register
movlw k
addwf register,f
endm
;------------------------------------------------
;------------------------------------------------
; add literal k to register and put sum in W register
; in arguments list of macro call, specify literal first, comma, then register
; NOTE: no provision for results > 255
addlfw macro k,register
movlw k
addwf register,w
endm
;------------------------------------------------
;------------------------------------------------
; add literal k to register1 and put sum in register3
; this is the general macro for adding literal to a register
; addlf and addlfw can be emulated using this macro but with one additonal instruction
; in arguments list of macro call, specify literal first, comma, reg1, comma, then reg3
; NOTE: no provision for results > 255
addlfdest macro k,reg1,reg3
movlw k
addwf reg1,w
movwf reg3
endm
;------------------------------------------------
;------------------------------------------------
; add register1 to register2 and put sum in register2
; in arguments list of macro call, specify reg1 first, comma, then reg2
; NOTE: no provision for results > 255
addff macro reg1,reg2
movfw reg1
addwf reg2,f
endm
;------------------------------------------------
;------------------------------------------------
; add register1 to register2 and put sum in W register
; in arguments list of macro call, specify reg1 first, comma, then reg2
; NOTE: no provision for results > 255
addffw macro reg1,reg2
movfw reg1
addwf reg2,w
endm
;------------------------------------------------
;------------------------------------------------
; add register1 to register2 and put sum in register3
; this is the general macro for adding two registers
; addff and addffw can be emulated using this macro but with one additonal instruction
; in arguments list of macro call, specify reg1 first, comma, reg2, comma, then reg3
; NOTE: no provision for results > 255
addffdest macro reg1,reg2,reg3
movfw reg1
addwf reg2,w
movwf reg3
endm
;------------------------------------------------
;------------------------------------------------
; subtract literal k from register and put difference in register
; in arguments list of macro call, specify literal first, comma, then register
; NOTE: no provision for negative results
sublf macro k,register
movlw k
subwf register,f
endm
;------------------------------------------------
;------------------------------------------------
; subtract literal k from register and put difference in W register
; in arguments list of macro call, specify literal first, comma, then register
; NOTE: no provision for negative results
sublfw macro k,register
movlw k
subwf register,w
endm
;------------------------------------------------
;------------------------------------------------
; subtract literal k from register1 and put difference in register3
; this is the general macro for subtracting a literal from a register
; sublf and subfw can be emulated using this macro but with one additonal instruction
; in arguments list of macro call, specify literal first, comma, reg1, comma, then reg3
; NOTE: no provision for negative results
sublfdest macro k,reg1,reg3
movlw k
subwf reg1,w
movwf reg3
endm
;------------------------------------------------
;------------------------------------------------
; subtract register1 from register2 and put difference in register2
; in arguments list of macro call, specify reg1 first, comma, then reg2
; NOTE: no provision for negative results
subff macro reg1,reg2
movfw reg1
subwf reg2,f
endm
;------------------------------------------------
;------------------------------------------------
; subtract register1 from register2 and put difference in W register
; in arguments list of macro call, specify reg1 first, comma, then reg2
; NOTE: no provision for negative results
subffw macro reg1,reg2
movfw reg1
subwf reg2,w
endm
;------------------------------------------------
;------------------------------------------------
; subtract register1 from register2 and put difference in register3
; this is the general macro for subtracting a register from another
; subff and subffw can be emulated using this macro but with one additonal instruction
; in arguments list of macro call, specify reg1 first, comma, reg2, comma, then reg3
; NOTE: no provision for negative results
subffdest macro reg1,reg2,reg3
movfw reg1
subwf reg2,w
movwf reg3
endm
;------------------------------------------------
; ------------------------------------------------
; divide content of register by 4 and round off to nearest integer
; to do this just move the "decimal point" to the left two places
; AND the register with b'00111111'. This zeroes bits <7:6> but leaves other bits untouched
; if Carry bit = 1 this means remainder is >= 0.5 so add 1 to register
divby4 macro register
rrf register,f
rrf register,f
movlw b'00111111'
andwf register,f
dnxbit1 STATUS,C
incf register,f
endm
;------------------------------------------------
;------------------------------------------------
; alternature divide by 4 macro
; this also rounds off to nearest integer
; this routine keeps clearing STATUS,C so that the digits that drop off on the right
; don't appear on the left
;divby4 macro register
; bcf STATUS,C
; rrf register,f
; bcf STATUS,C
; rrf register,f
; dnxbit1 STATUS,C
; incf register,f
; endm
;------------------------------------------------
; ------------------------------------------------
; divide content of register by 8 and round off to nearest integer
; to do this just move the "decimal point" to the left three places
; AND the register with b'00011111'. This zeroes bits <7:5> but leaves other bits untouched
; if Carry bit = 1 this means remainder is >= 0.5 so add 1 to register
divby8 macro register
rrf register,f
rrf register,f
rrf register,f
movlw b'00011111'
andwf register,f
dnxbit1 STATUS,C
incf register,f
endm
;------------------------------------------------
;------------------------------------------------
; divide content of register by 16 and round off to nearest integer
; to do this swap nibbles, i.e., bits <7:4> and <3:0> switch places
; AND the register with b10001111'. This zeroes bits <6:4> but leaves other bits untouched
; if bit7 = 1 this means remainder of division >=0.5; hence, add 1 to register
divby16 macro register
swapf register,f
movlw b'10001111'
andwf register,f
dnxbit1 register,7
incf register,f
bcf register,7
endm
;------------------------------------------------
; ==============================================================================================
; macros that perform logic functions
; ==============================================================================================
;------------------------------------------------
; AND literal k with register and put output in register
; in arguments list of macro call, specify literal first, comma, then register
andlf macro k,register
movlw k
andwf register,f
endm
;------------------------------------------------
; ==============================================================================================
; miscellaneous macros
; ==============================================================================================
;------------------------------------------------
; toggles the value of bit of register
toggle macro register,bit
dnxbit1 register,bit
goto $+3
bsf register,bit
goto $+2
bcf register,bit
endm
;------------------------------------------------
No comments:
Post a Comment