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