; ------------------------------------------------------------------------------- ; ENGR 2210 SECTION 01 PIC ASSEMBLER MACROS ; ------------------------------------------------------------------------------- ; Created by Bradley A. Minch 9/2004 to facilitate reasonably structured ; programming in PIC assembler. These macros were inspired and informed ; both by Karl Lunt's PIC macros, described in an atricle in the July 1999 ; Nuts & Volts magazine, and by Myke Predko's structured programming macros, ; which are described on pp. 542-546 of the second edition of Programming and ; Customizing PICmicro Microcontrollers. These macros provide facilities for ; for-next loops, repeat-until loops, select satatements, and if statements. ; ------------------------------------------------------------------------------- ; FOR-NEXT LOOP MACROS ; ------------------------------------------------------------------------------- ; Macros: for, forf, forlf, forfl, next, nextl, nextf, exitfor, escfor ; ------------------------------------------------------------------------------- ; The for-next group of macros provides an iterated looping structure in which ; an index variable takes on a succession of values from the specified starting ; value to the specified ending value. The loop begins with one of the four for ; macros. These each take three arguments: the register to use as an index ; variable, the initial value of the index, and the final value of the index. ; The only difference between the for macros is whether the initial values and ; final values are literals (i.e., constants) or contained in registers (i.e., ; variables). Before the first loop iteration, the index register is set to the ; specified initial value. At the top of the loop, the current value of the ; index is compared to the specified ending value; if the index exceeds the ; ending value, the loop terminates. The loop ends with one of the three next ; macros. They each take the index register as an argument. Two of them take ; a second argument, which specifies the step size. The index is incremented ; by the specified step size at the bottom of the loop. Any one of the for ; macros can be used with any one of the next macros. In the present version, ; the index variable can only count up. An example of the basic form of the for ; loop is as follows: ; ; for i, 1, 10 ; . ; . ; . ; next i ; ; In this case, the body of the loop would be executed ten times with the index ; variable, i, taking on each integer value between 1 and 10 on each succesive ; iteration of the loop. For loops may be nested to any depth. The macros ; exitfor and escfor respectively exit the innermost and outermost for loop in ; a nested for-loop structure. Both the for and next macros make use of the W ; register. ; ------------------------------------------------------------------------------- variable _forcount = 0 variable _forstackptr = 0 ; ------------------------------------------------------------------------------- ; FOR (START OF A FOR-NEXT LOOP) ; ------------------------------------------------------------------------------- ; Syntax: for index, begl, endl ; ------------------------------------------------------------------------------- ; Arguments: index the register to be used as the loop index variable ; begl a literal value used as the initial value of the index ; endl a literal value used as the final value of the index ; ------------------------------------------------------------------------------- ; The body of the loop executes until the value of the index exceeds the endl ; literal value, at which point the loop terminates with the statement following ; the next that terminates the loop. This test is performed at the top of the ; loop. This macro destroys the contents of the W register. You can terminate ; a for loop with next, nextl, or nextf. ; ------------------------------------------------------------------------------- for macro index,begl,endl movlw begl movwf index,BANKED _for#v(_forcount) movf index,W,BANKED sublw endl btfss STATUS,C,ACCESS goto _next#v(_forcount) variable _forstack#v(_forstackptr) = _forcount _forstackptr ++ _forcount ++ endm ; ------------------------------------------------------------------------------- ; FORF (START OF A FORF-NEXT LOOP) ; ------------------------------------------------------------------------------- ; Syntax: forf index, begf, endf ; ------------------------------------------------------------------------------- ; Arguments: index the register to be used as the loop index variable ; begf a register whose value is used to initialize the index ; endf a register whose value is used as the final index ; ------------------------------------------------------------------------------- ; The body of the loop executes until the value of the index exceeds the endl ; literal value, at which point the loop terminates with the statement following ; the next that terminates the loop. This test is performed at the top of the ; loop. This macro destroys the contents of the W register. You can terminate ; a forf loop with next, nextl, or nextf. ; ------------------------------------------------------------------------------- forf macro index,begf,endf movf begf,W,BANKED movwf index,BANKED _for#v(_forcount) movf index,W,BANKED subwf endf,W,BANKED btfss STATUS,C,ACCESS goto _next#v(_forcount) variable _forstack#v(_forstackptr) = _forcount _forstackptr ++ _forcount ++ endm ; ------------------------------------------------------------------------------- ; FORLF (START OF A FORLF-NEXT LOOP) ; ------------------------------------------------------------------------------- ; Syntax: forlf index, begl, endf ; ------------------------------------------------------------------------------- ; Arguments: index the register to be used as the loop index variable ; begl a literal value used as the initial value of the index ; endf a register whose value is used as the final index ; ------------------------------------------------------------------------------- ; The body of the loop executes until the value of the index exceeds the endl ; literal value, at which point the loop terminates with the statement following ; the next that terminates the loop. This test is performed at the top of the ; loop. This macro destroys the contents of the W register. You can terminate ; a forlf loop with next, nextl, or nextf. ; ------------------------------------------------------------------------------- forlf macro index,begl,endf movlw begl movwf index,BANKED _for#v(_forcount) movf index,W,BANKED subwf endf,W,BANKED btfss STATUS,C,ACCESS goto _next#v(_forcount) variable _forstack#v(_forstackptr) = _forcount _forstackptr ++ _forcount ++ endm ; ------------------------------------------------------------------------------- ; FORFL (START OF A FORFL-NEXT LOOP) ; ------------------------------------------------------------------------------- ; Syntax: forfl index, begf, endl ; ------------------------------------------------------------------------------- ; Arguments: index the register to be used as the loop index variable ; begf a register whose value is used to initialize the index ; endl a literal value used as the final value of the index ; ------------------------------------------------------------------------------- ; The body of the loop executes until the value of the index exceeds the endl ; literal value, at which point the loop terminates with the statement following ; the next that terminates the loop. This test is performed at the top of the ; loop. This macro destroys the contents of the W register. You can terminate ; a forfl loop with next, nextl, or nextf. ; ------------------------------------------------------------------------------- forfl macro index,begf,endl movf begf,W,BANKED movwf index,BANKED _for#v(_forcount) movf index,W,BANKED sublw endl btfss STATUS,C,ACCESS goto _next#v(_forcount) variable _forstack#v(_forstackptr) = _forcount _forstackptr ++ _forcount ++ endm ; ------------------------------------------------------------------------------- ; NEXT (END OF A FOR-NEXT LOOP) ; ------------------------------------------------------------------------------- ; Syntax: next index ; ------------------------------------------------------------------------------- ; Arguments: index the register being used as the loop index variable ; ------------------------------------------------------------------------------- ; The next macro increments the index and jumps back to the test at the top of ; the for loop. This macro can be used with for, forf, forlf, and forfl. ; ------------------------------------------------------------------------------- next macro index _forstackptr -- incf index,F,BANKED goto _for#v(_forstack#v(_forstackptr)) _next#v(_forstack#v(_forstackptr)) endm ; ------------------------------------------------------------------------------- ; NEXTL (END OF A FOR-NEXTL LOOP) ; ------------------------------------------------------------------------------- ; Syntax: nextl index, stepl ; ------------------------------------------------------------------------------- ; Arguments: index the register being used as the loop index variable ; stepl a literal value used as the step size ; ------------------------------------------------------------------------------- ; The next macro adds stepl to the index and jumps back to the test at the ; top of the for loop. This macro alters the contents of the W register. ; This macro can be used with for, forf, forlf, and forfl. ; ------------------------------------------------------------------------------- nextl macro index,stepl _forstackptr -- movf index,W,BANKED addlw stepl movwf index,BANKED goto _for#v(_forstack#v(_forstackptr)) _next#v(_forstack#v(_forstackptr)) endm ; ------------------------------------------------------------------------------- ; NEXTF (END OF A FOR-NEXTF LOOP) ; ------------------------------------------------------------------------------- ; Syntax: nextf index, stepf ; ------------------------------------------------------------------------------- ; Arguments: index the register being used as the loop index variable ; stepf a register whose value is used as the step size ; ------------------------------------------------------------------------------- ; The next macro adds the value contained in stepf to the index and jumps back ; to the test at the top of the for loop. This macro alters the contents of ; the W register. This macro can be used with for, forf, forlf, and forfl. ; ------------------------------------------------------------------------------- nextf macro index,stepf _forstackptr -- movf index,W,BANKED addwf stepf,W,BANKED movwf index,BANKED goto _for#v(_forstack#v(_forstackptr)) _next#v(_forstack#v(_forstackptr)) endm ; ------------------------------------------------------------------------------- ; EXITFOR (TERMINATE EXECUTION OF THE INNERMOST FOR-NEXT LOOP) ; ------------------------------------------------------------------------------- ; Syntax: exitfor ; ------------------------------------------------------------------------------- ; The exitfor macro terminates the execution of the innermost for-next loop in ; a nested for-loop structure. ; ------------------------------------------------------------------------------- exitfor macro goto _next#v(_forstack#v(_forstackptr - 1)) endm ; ------------------------------------------------------------------------------- ; ESCFOR (TERMINATE EXECUTION OF THE OUTERMOST FOR-NEXT LOOP) ; ------------------------------------------------------------------------------- ; Syntax: escfor ; ------------------------------------------------------------------------------- ; The escfor macro terminates the execution of the outermost for-next loop in ; a nested for-loop structure. In the context of a single for-next loop, this ; macro behaves in the same manner as does exitfor. ; ------------------------------------------------------------------------------- escfor macro goto _next#v(_forstack0) endm ; ------------------------------------------------------------------------------- ; REPEAT-UNTIL LOOP MACROS ; ------------------------------------------------------------------------------- ; Macros: repeat, forever, until, untilf, untilset, untilclr, ; exitrepeat, escrepeat ; ------------------------------------------------------------------------------- ; The repeat-until loop provides a mechanism for repeatedly executing the ; instructions comprising the body of the loop until a specified condition ; holds. The condition is tested at the bottom of the loop, so the body ; of the loop is always executed at least once. An example of the basic ; strucutre of a repeat-until loop is as follows: ; ; repeat ; . ; . ; . ; untilset reg, b, a ; ; In this example, the instructions between the repeat and untilset macros ; would be executed until bit b of register reg is set. Repeat-until loops ; may be nested to any depth. The macros exitrepeat and escrepeat respectively ; exit the innermost and outermost loop in a nested repeat-until loop structure. ; ------------------------------------------------------------------------------- variable _rptcount = 0 variable _rptstackptr = 0 ; ------------------------------------------------------------------------------- ; REPEAT (START OF A REPEAT-UNTIL LOOP) ; ------------------------------------------------------------------------------- ; Syntax: repeat ; ------------------------------------------------------------------------------- ; The body of the loop executes repeatedly until the condition specified at ; the close of the loop holds. The test occurs at the bottom of the loop, so ; even if the condition holds before the execution of the loop begins, the ; body of the loop will be executed. The repeat macro can be used with any of ; the forever, untilset, untilclr, untileq, untilne, untilcs, and untilcc ; macros. It does not alter the contents of the W register. ; ------------------------------------------------------------------------------- repeat macro _repeat#v(_rptcount) variable _rptstack#v(_rptstackptr) = _rptcount _rptstackptr ++ _rptcount ++ endm ; ------------------------------------------------------------------------------- ; FOREVER (END OF A REPEAT-FOREVER LOOP) ; ------------------------------------------------------------------------------- ; Syntax: forever ; ------------------------------------------------------------------------------- ; The forever macro creates an infinite loop by unconditionally jumping back ; to the top of the loop. The body of the loop is executed endlessly until ; an exitrepeat or escrepeat statement is executed. ; ------------------------------------------------------------------------------- forever macro _rptstackptr -- goto _repeat#v(_rptstack#v(_rptstackptr)) _endrepeat#v(_rptstack#v(_rptstackptr)) endm ; ------------------------------------------------------------------------------- ; UNTIL (END OF A REPEAT-UNTIL LOOP) ; ------------------------------------------------------------------------------- ; Syntax: until var, relop, lit ; ------------------------------------------------------------------------------- ; Arguments: var the register to be tested against a literal ; relop the relational operator to use for the test, which ; must be one of ==, !=, <, <=, >, >= ; lit the literal to test the contents of register var against ; ------------------------------------------------------------------------------- ; This macro performs a comparison between the contents of register var and a ; literal. If the specified relation holds, the loop terminates. This macro ; makes use of the W register. ; ------------------------------------------------------------------------------- ; This macro borrows heavily from Myke Predko's structured programming macros, ; which are described on pp. 542-546 of the second edition of Programming and ; Customizing PICmicro Microcontrollers. ; ------------------------------------------------------------------------------- until macro var,relop,lit _rptstackptr -- if (1 relop 1) ; See if relop is == movf var,W,BANKED sublw lit btfss STATUS,Z,ACCESS else if (1 relop 0) ; See if relop is !=, >, or >= if (0 relop 1) ; See if relop is != movf var,W,BANKED sublw lit btfsc STATUS,Z,ACCESS else if (1 relop 1) ; See if relop is >= movlw lit subwf var,W,BANKED btfss STATUS,C,ACCESS else ; Relop must be > movf var,W,BANKED sublw lit btfsc STATUS,C,ACCESS endif endif else if (0 relop 1) ; See if relop is < or <= if (1 relop 1) ; See if relop is <= movf var,W,BANKED sublw lit btfss STATUS,C,ACCESS else ; Relop must be < movlw lit subwf var,W,BANKED btfsc STATUS,C,ACCESS endif else error "Illegal relational operator in until statement." endif endif endif goto _repeat#v(_rptstack#v(_rptstackptr)) _endrepeat#v(_rptstack#v(_rptstackptr)) endm ; ------------------------------------------------------------------------------- ; UNTILF (END OF A REPEAT-UNTILF LOOP) ; ------------------------------------------------------------------------------- ; Syntax: untilf var1, relop, var2 ; ------------------------------------------------------------------------------- ; Arguments: var1 the first register whose contents are to be tested ; against those of a second register ; relop the relational operator to use for the test, which ; must be one of ==, !=, <, <=, >, >= ; var2 a second register ; ------------------------------------------------------------------------------- ; This macro performs a comparison between the contents of register var1 and ; those of register var2. If the specified relation holds, the loop terminates. ; This macro makes use of the W register. ; ------------------------------------------------------------------------------- ; This macro borrows heavily from Myke Predko's structured programming macros, ; which are described on pp. 542-546 of the second edition of Programming and ; Customizing PICmicro Microcontrollers. ; ------------------------------------------------------------------------------- untilf macro var1,relop,var2 _rptstackptr -- if (1 relop 1) ; See if relop is == movf var1,W,BANKED subwf var2,W,BANKED btfss STATUS,Z,ACCESS else if (1 relop 0) ; See if relop is !=, >, or >= if (0 relop 1) ; See if relop is != movf var1,W,BANKED subwf var2,W,BANKED btfsc STATUS,Z,ACCESS else if (1 relop 1) ; See if relop is >= movf var2,W,BANKED subwf var1,W,BANKED btfss STATUS,C,ACCESS else ; Relop must be > movf var1,W,BANKED subwf var2,W,BANKED btfsc STATUS,C,ACCESS endif endif else if (0 relop 1) ; See if relop is < or <= if (1 relop 1) ; See if relop is <= movf var1,W,BANKED subwf var2,W,BANKED btfss STATUS,C,ACCESS else ; Relop must be < movf var2,W,BANKED subwf var1,W,BANKED btfsc STATUS,C,ACCESS endif else error "Illegal relational operator in untilf statement." endif endif endif goto _repeat#v(_rptstack#v(_rptstackptr)) _endrepeat#v(_rptstack#v(_rptstackptr)) endm ; ------------------------------------------------------------------------------- ; UNTILSET (END OF A REPEAT-UNTILSET LOOP) ; ------------------------------------------------------------------------------- ; Syntax: untilset reg, bit, a ; ------------------------------------------------------------------------------- ; Arguments: reg the register containing the bit to be tested ; bit a literal value between 0 and 7 specifying the bit ; position to be tested ; a if a is 0, the access bank is selected. if a is 1, ; the BSR specifies the bank used to select reg. ; ------------------------------------------------------------------------------- ; The untilset macro tests the specified bit of register reg and terminates ; loop execution if it is set. ; ------------------------------------------------------------------------------- untilset macro reg,bit,a _rptstackptr -- btfss reg,bit,a goto _repeat#v(_rptstack#v(_rptstackptr)) _endrepeat#v(_rptstack#v(_rptstackptr)) endm ; ------------------------------------------------------------------------------- ; UNTILCLR (END OF A REPEAT-UNTILCLR LOOP) ; ------------------------------------------------------------------------------- ; Syntax: untilclr reg, bit, a ; ------------------------------------------------------------------------------- ; Arguments: reg the register containing the bit to be tested ; bit a literal value between 0 and 7 specifying the bit ; position to be tested ; a if a is 0, the access bank is selected. if a is 1, ; the BSR specifies the bank used to select reg. ; ------------------------------------------------------------------------------- ; The untilclr macro tests the specified bit of register reg and terminates ; loop execution if it is clear. ; ------------------------------------------------------------------------------- untilclr macro reg,bit,a _rptstackptr -- btfsc reg,bit,a goto _repeat#v(_rptstack#v(_rptstackptr)) _endrepeat#v(_rptstack#v(_rptstackptr)) endm ; ------------------------------------------------------------------------------- ; EXITREPEAT (TERMINATE EXECUTION OF THE INNERMOST REPEAT-UNTIL LOOP) ; ------------------------------------------------------------------------------- ; Syntax: exitrepeat ; ------------------------------------------------------------------------------- ; The exitrepeat macro terminates the execution of the innermost loop in a ; nested repeat-until loop structure. ; ------------------------------------------------------------------------------- exitrepeat macro goto _endrepeat#v(_rptstack#v(_rptstackptr - 1)) endm ; ------------------------------------------------------------------------------- ; ESCREPEAT (TERMINATE EXECUTION OF THE OUTERMOST REPEAT-UNTIL LOOP) ; ------------------------------------------------------------------------------- ; Syntax: escrepeat ; ------------------------------------------------------------------------------- ; The escrepeat macro terminates the execution of the outermost loop in a ; nested repeat-until loop structure. In the context of a single repeat-until ; loop, this macro behaves in the same manner as does exitrepeat. ; ------------------------------------------------------------------------------- escrepeat macro goto _endrepeat#v(_rptstack0) endm ; ------------------------------------------------------------------------------- ; SELECT STATEMENT MACROS ; ------------------------------------------------------------------------------- ; Macros: select, selectf, case, casef, caseset, caseclr, default, break, ends ; ------------------------------------------------------------------------------- ; This group of macros allows a program to selectively execute sequences of ; instructions based on the value of a variable and/or based on the bit values ; in certain registers. An example of a select statement is as follows: ; ; select ; case 1 ; . ; . ; . ; break ; case 4 ; casef foo ; . ; . ; . ; break ; caseset reg, 0, a ; . ; . ; . ; break ; default ; . ; . ; . ; ends ; ; In this case, the first group of instructions is executed if the value ; of the W register is 1. The second group of instructions is executed if ; the value of the W register is 4 or if it matches the value of register ; foo. The third group of instructions is executed if bit 0 of register ; reg is set. The fourth group of instructions is executed in the event ; that none of the specified cases held. The default block is optional. ; The break macro terminates the execution of the select statement; if no ; break macro exists at the end of a block of instructions, execution ; continues in the next block. The contents of the W register are preserved ; by the case macros. Select statements may be nested to any depth. ; ------------------------------------------------------------------------------- variable _selcount = 0 variable _selstackptr = 0 variable _casecount = 0 ; ------------------------------------------------------------------------------- ; SELECT (START OF A SELECT STATEMENT) ; ------------------------------------------------------------------------------- ; Syntax: select ; ------------------------------------------------------------------------------- ; This macro begins a select statement. The W register is used as ; the selection variable. ; ------------------------------------------------------------------------------- select macro variable _casestack#v(_selstackptr) = _casecount variable _selstack#v(_selstackptr) = _selcount _selstackptr ++ _casecount = 0 _select#v(_selstack#v(_selstackptr - 1)) goto _case#v(_selstack#v(_selstackptr - 1))_#v(_casecount) _selcount ++ endm ; ------------------------------------------------------------------------------- ; SELECTF (START OF A SELECT STATEMENT) ; ------------------------------------------------------------------------------- ; Syntax: selectf var ; ------------------------------------------------------------------------------- ; Arguments: var the register whose value will be tested in each case ; ------------------------------------------------------------------------------- ; This macro begins a selectf statement. It begins by moving the contents of ; var into the W register. ; ------------------------------------------------------------------------------- selectf macro var variable _casestack#v(_selstackptr) = _casecount variable _selstack#v(_selstackptr) = _selcount _selstackptr ++ _casecount = 0 _select#v(_selstack#v(_selstackptr - 1)) movf var,W,BANKED goto _case#v(_selstack#v(_selstackptr - 1))_#v(_casecount) _selcount ++ endm ; ------------------------------------------------------------------------------- ; CASE (START OF A CASE IN A SELECT STATEMENT) ; ------------------------------------------------------------------------------- ; Syntax: case val ; ------------------------------------------------------------------------------- ; Arguments: val a literal value to be compared with the contents of ; the W register ; ------------------------------------------------------------------------------- ; This macro compares the value containted in the W register with val; if they ; match, the instructions following the case macro are executed. Otherwise, ; the next case is tested. This macro preserves the value of the W register. ; ------------------------------------------------------------------------------- case macro val goto _casebypass#v(_selstack#v(_selstackptr - 1))_#v(_casecount) _case#v(_selstack#v(_selstackptr - 1))_#v(_casecount) xorlw val btfsc STATUS,Z,ACCESS goto _casematch#v(_selstack#v(_selstackptr - 1))_#v(_casecount) xorlw val goto _case#v(_selstack#v(_selstackptr - 1))_#v(_casecount + 1) _casematch#v(_selstack#v(_selstackptr - 1))_#v(_casecount) xorlw val _casebypass#v(_selstack#v(_selstackptr - 1))_#v(_casecount) _casecount ++ endm ; ------------------------------------------------------------------------------- ; CASEF (START OF A CASE IN A SELECT STATEMENT) ; ------------------------------------------------------------------------------- ; Syntax: casef var ; ------------------------------------------------------------------------------- ; Arguments: var a register whose value is to be compared with that of ; the W register ; ------------------------------------------------------------------------------- ; This macro compares the value containted in the W register with that in ; register var; if they match, the instructions following the case macro are ; executed. Otherwise, the next case is tested. This macro preserves the ; value of the W register. ; ------------------------------------------------------------------------------- casef macro var goto _casebypass#v(_selstack#v(_selstackptr - 1))_#v(_casecount) _case#v(_selstack#v(_selstackptr - 1))_#v(_casecount) xorwf var,W,BANKED btfsc STATUS,Z,ACCESS goto _casematch#v(_selstack#v(_selstackptr - 1))_#v(_casecount) xorwf var,W,BANKED goto _case#v(_selstack#v(_selstackptr - 1))_#v(_casecount + 1) _casematch#v(_selstack#v(_selstackptr - 1))_#v(_casecount) xorwf var,W,BANKED _casebypass#v(_selstack#v(_selstackptr - 1))_#v(_casecount) _casecount ++ endm ; ------------------------------------------------------------------------------- ; CASESET (START OF A CASE IN A SELECT STATEMENT) ; ------------------------------------------------------------------------------- ; Syntax: caseset reg, bit, a ; ------------------------------------------------------------------------------- ; Arguments: reg the register containing the bit to be tested ; bit a literal value between 0 and 7 specifying the bit ; position to be tested ; a if a is 0, the access bank is selected. if a is 1, ; the BSR specifies the bank used to select reg. ; ------------------------------------------------------------------------------- ; This macro tests the specified bit in register reg; if it is set, the ; instructions following the case macro are executed. Otherwise, the next ; case is tested. This macro does not change the value of the W register. ; ------------------------------------------------------------------------------- caseset macro reg,bit,a goto _casebypass#v(_selstack#v(_selstackptr - 1))_#v(_casecount) _case#v(_selstack#v(_selstackptr - 1))_#v(_casecount) btfss reg,bit,a goto _case#v(_selstack#v(_selstackptr - 1))_#v(_casecount + 1) _casebypass#v(_selstack#v(_selstackptr - 1))_#v(_casecount) _casecount ++ endm ; ------------------------------------------------------------------------------- ; CASECLR (START OF A CASE IN A SELECT STATEMENT) ; ------------------------------------------------------------------------------- ; Syntax: caseclr reg, bit, a ; ------------------------------------------------------------------------------- ; Arguments: reg the register containing the bit to be tested ; bit a literal value between 0 and 7 specifying the bit ; position to be tested ; a if a is 0, the access bank is selected. if a is 1, ; the BSR specifies the bank used to select reg. ; ------------------------------------------------------------------------------- ; This macro tests the specified bit in register reg; if it is clear, the ; instructions following the case macro are executed. Otherwise, the next ; case is tested. This macro does not change the value of the W register. ; ------------------------------------------------------------------------------- caseclr macro reg,bit,a goto _casebypass#v(_selstack#v(_selstackptr - 1))_#v(_casecount) _case#v(_selstack#v(_selstackptr - 1))_#v(_casecount) btfsc reg,bit,a goto _case#v(_selstack#v(_selstackptr - 1))_#v(_casecount + 1) _casebypass#v(_selstack#v(_selstackptr - 1))_#v(_casecount) _casecount ++ endm ; ------------------------------------------------------------------------------- ; DEFAULT (START OF A DEFAULT CASE IN A SELECT STATEMENT) ; ------------------------------------------------------------------------------- ; Syntax: default ; ------------------------------------------------------------------------------- ; This macro begins the sequence of instructions that is executed if none ; of the other cases held. The default block is optional. ; ------------------------------------------------------------------------------- default macro _case#v(_selstack#v(_selstackptr - 1))_#v(_casecount) _casecount ++ endm ; ------------------------------------------------------------------------------- ; BREAK (TERMINATES EXECUTION OF A SELECT STATEMENT) ; ------------------------------------------------------------------------------- ; Syntax: break ; ------------------------------------------------------------------------------- ; This macro terminates the execution of a select statement. ; ------------------------------------------------------------------------------- break macro goto _endselect#v(_selstack#v(_selstackptr - 1)) endm ; ------------------------------------------------------------------------------- ; ENDS (END OF A SELECT STATEMENT) ; ------------------------------------------------------------------------------- ; Syntax: ends ; ------------------------------------------------------------------------------- ; This macro marks the end of a select statement. ; ------------------------------------------------------------------------------- ends macro _selstackptr -- _case#v(_selstack#v(_selstackptr))_#v(_casecount) _endselect#v(_selstack#v(_selstackptr)) _casecount = _casestack#v(_selstackptr) endm ; ------------------------------------------------------------------------------- ; IF STATEMENT MACROS ; ------------------------------------------------------------------------------- ; Macros: ifl, iff, ifset, ifclr, ; andif, andiff, andifset, andifclr, ; orif, oriff, orifset, orifclr, ; elsif, elsiff, elsifset, elsifclr, ; otherwise, endi ; ------------------------------------------------------------------------------- ; This set of macros allows the selective exectution of groups of instructions ; based on the values of one or more bits. An example of an if statement is ; as follows: ; ; ifset foo, 0, a ; . ; . ; . ; elsifclr bar, 5, a ; andifset foo, 1, a ; . ; . ; . ; elsifset foo, 2, a ; orifset foo, 3, a ; . ; . ; . ; otherwise ; . ; . ; . ; endi ; ; In this example, the first group of instructions is executed if bit 0 of ; register foo is set. The second group of instructions is executed if bit ; 5 of register bar is clear and bit 1 of register foo is set. The third ; group is executed if either of bit 2 or bit 3 of register foo is set. ; Otherwise, the fourth group of instructions is executed. The elsif and ; otherwise blocks are optional. If statements can be nested to any depth. ; ------------------------------------------------------------------------------- variable _ifcount = 0 variable _ifstackptr = 0 variable _ifclausecount = 0 ; ------------------------------------------------------------------------------- ; IFL (START OF AN IF CLAUSE IN AN IF STATEMENT) ; ------------------------------------------------------------------------------- ; Syntax: ifl var, relop, lit ; ------------------------------------------------------------------------------- ; Arguments: var the register to be tested against a literal ; relop the relational operator to use for the test, which ; must be one of ==, !=, <, <=, >, >= ; lit the literal to test the contents of register var against ; ------------------------------------------------------------------------------- ; This macro performs a comparison between the contents of register var and a ; literal. If the specified relation holds, the block of statements following ; the ifl are executed. This macro makes use of the W register. ; ------------------------------------------------------------------------------- ; This macro borrows heavily from Myke Predko's structured programming macros, ; which are described on pp. 542-546 of the second edition of Programming and ; Customizing PICmicro Microcontrollers. ; ------------------------------------------------------------------------------- ifl macro var,relop,lit variable _ifclausestack#v(_ifstackptr) = _ifclausecount variable _ifstack#v(_ifstackptr) = _ifcount _ifstackptr ++ _ifclausecount = 0 _if#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount) if (1 relop 1) ; See if relop is == movf var,W,BANKED sublw lit btfss STATUS,Z,ACCESS else if (1 relop 0) ; See if relop is !=, >, or >= if (0 relop 1) ; See if relop is != movf var,W,BANKED sublw lit btfsc STATUS,Z,ACCESS else if (1 relop 1) ; See if relop is >= movlw lit subwf var,W,BANKED btfss STATUS,C,ACCESS else ; Relop must be > movf var,W,BANKED sublw lit btfsc STATUS,C,ACCESS endif endif else if (0 relop 1) ; See if relop is < or <= if (1 relop 1) ; See if relop is <= movf var,W,BANKED sublw lit btfss STATUS,C,ACCESS else ; Relop must be < movlw lit subwf var,W,BANKED btfsc STATUS,C,ACCESS endif else error "Illegal relational operator in ifl statement." endif endif endif goto _if#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount + 1) _ifcount ++ _ifclausecount ++ endm ; ------------------------------------------------------------------------------- ; IFF (START OF AN IF CLAUSE IN AN IF STATEMENT) ; ------------------------------------------------------------------------------- ; Syntax: iff var1, relop, var2 ; ------------------------------------------------------------------------------- ; Arguments: var1 the first register whose contents are to be tested ; against those of a second register ; relop the relational operator to use for the test, which ; must be one of ==, !=, <, <=, >, >= ; var2 a second register ; ------------------------------------------------------------------------------- ; This macro performs a comparison between the contents of register var1 and ; those of register var2. If the specified relation holds, the block of ; statements following the iff are executed. This macro makes use of the W ; register. ; ------------------------------------------------------------------------------- ; This macro borrows heavily from Myke Predko's structured programming macros, ; which are described on pp. 542-546 of the second edition of Programming and ; Customizing PICmicro Microcontrollers. ; ------------------------------------------------------------------------------- iff macro var1,relop,var2 variable _ifclausestack#v(_ifstackptr) = _ifclausecount variable _ifstack#v(_ifstackptr) = _ifcount _ifstackptr ++ _ifclausecount = 0 _if#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount) if (1 relop 1) ; See if relop is == movf var1,W,BANKED subwf var2,W,BANKED btfss STATUS,Z,ACCESS else if (1 relop 0) ; See if relop is !=, >, or >= if (0 relop 1) ; See if relop is != movf var1,W,BANKED subwf var2,W,BANKED btfsc STATUS,Z,ACCESS else if (1 relop 1) ; See if relop is >= movf var2,W,BANKED subwf var1,W,BANKED btfss STATUS,C,ACCESS else ; Relop must be > movf var1,W,BANKED subwf var2,W,BANKED btfsc STATUS,C,ACCESS endif endif else if (0 relop 1) ; See if relop is < or <= if (1 relop 1) ; See if relop is <= movf var1,W,BANKED subwf var2,W,BANKED btfss STATUS,C,ACCESS else ; Relop must be < movf var2,W,BANKED subwf var1,W,BANKED btfsc STATUS,C,ACCESS endif else error "Illegal relational operator in iff statement." endif endif endif goto _if#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount + 1) _ifcount ++ _ifclausecount ++ endm ; ------------------------------------------------------------------------------- ; IFSET (START OF AN IF CLAUSE IN AN IF STATEMENT) ; ------------------------------------------------------------------------------- ; Syntax: ifset reg, bit, a ; ------------------------------------------------------------------------------- ; Arguments: reg the register containing the bit to be tested ; bit a literal value between 0 and 7 specifying the bit ; position to be tested ; a if a is 0, the access bank is selected. if a is 1, ; the BSR specifies the bank used to select reg. ; ------------------------------------------------------------------------------- ; This macro tests the specified bit in register reg; if it is set, the ; instructions following the ifset macro are executed. Otherwise, the next ; case is tested. ; ------------------------------------------------------------------------------- ifset macro reg,bit,a variable _ifclausestack#v(_ifstackptr) = _ifclausecount variable _ifstack#v(_ifstackptr) = _ifcount _ifstackptr ++ _ifclausecount = 0 _if#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount) btfss reg,bit,a goto _if#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount + 1) _ifcount ++ _ifclausecount ++ endm ; ------------------------------------------------------------------------------- ; IFCLR (START OF AN IF CLAUSE IN AN IF STATEMENT) ; ------------------------------------------------------------------------------- ; Syntax: ifclr reg, bit, a ; ------------------------------------------------------------------------------- ; Arguments: reg the register containing the bit to be tested ; bit a literal value between 0 and 7 specifying the bit ; position to be tested ; a if a is 0, the access bank is selected. if a is 1, ; the BSR specifies the bank used to select reg. ; ------------------------------------------------------------------------------- ; This macro tests the specified bit in register reg; if it is clear, the ; instructions following the ifclr macro are executed. Otherwise, the next ; case is tested. ; ------------------------------------------------------------------------------- ifclr macro reg,bit,a variable _ifclausestack#v(_ifstackptr) = _ifclausecount variable _ifstack#v(_ifstackptr) = _ifcount _ifstackptr ++ _ifclausecount = 0 _if#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount) btfsc reg,bit,a goto _if#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount + 1) _ifcount ++ _ifclausecount ++ endm ; ------------------------------------------------------------------------------- ; ANDIF (CONTINUATION OF AN IF/ELSIF CLAUSE IN AN IF STATEMENT) ; ------------------------------------------------------------------------------- ; Syntax: andif var, relop, lit ; ------------------------------------------------------------------------------- ; Arguments: var the register to be tested against a literal ; relop the relational operator to use for the test, which ; must be one of ==, !=, <, <=, >, >= ; lit the literal to test the contents of register var against ; ------------------------------------------------------------------------------- ; This macro performs a comparison between the contents of register var and a ; literal. If the specified relation holds, the block of statements following ; the ifl are executed. This macro makes use of the W register. ; ------------------------------------------------------------------------------- ; This macro borrows heavily from Myke Predko's structured programming macros, ; which are described on pp. 542-546 of the second edition of Programming and ; Customizing PICmicro Microcontrollers. ; ------------------------------------------------------------------------------- andif macro var,relop,lit if (1 relop 1) ; See if relop is == movf var,W,BANKED sublw lit btfss STATUS,Z,ACCESS else if (1 relop 0) ; See if relop is !=, >, or >= if (0 relop 1) ; See if relop is != movf var,W,BANKED sublw lit btfsc STATUS,Z,ACCESS else if (1 relop 1) ; See if relop is >= movlw lit subwf var,W,BANKED btfss STATUS,C,ACCESS else ; Relop must be > movf var,W,BANKED sublw lit btfsc STATUS,C,ACCESS endif endif else if (0 relop 1) ; See if relop is < or <= if (1 relop 1) ; See if relop is <= movf var,W,BANKED sublw lit btfss STATUS,C,ACCESS else ; Relop must be < movlw lit subwf var,W,BANKED btfsc STATUS,C,ACCESS endif else error "Illegal relational operator in andif statement." endif endif endif goto _if#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount) endm ; ------------------------------------------------------------------------------- ; ANDIFF (CONTINUATION OF AN IF/ELSIF CLAUSE IN AN IF STATEMENT) ; ------------------------------------------------------------------------------- ; Syntax: andiff var1, relop, var2 ; ------------------------------------------------------------------------------- ; Arguments: var1 the first register whose contents are to be tested ; against those of a second register ; relop the relational operator to use for the test, which ; must be one of ==, !=, <, <=, >, >= ; var2 a second register ; ------------------------------------------------------------------------------- ; This macro performs a comparison between the contents of register var1 and ; those of register var2. If the specified relation holds, the block of ; statements following the iff are executed. This macro makes use of the W ; register. ; ------------------------------------------------------------------------------- ; This macro borrows heavily from Myke Predko's structured programming macros, ; which are described on pp. 542-546 of the second edition of Programming and ; Customizing PICmicro Microcontrollers. ; ------------------------------------------------------------------------------- andiff macro var1,relop,var2 if (1 relop 1) ; See if relop is == movf var1,W,BANKED subwf var2,W,BANKED btfss STATUS,Z,ACCESS else if (1 relop 0) ; See if relop is !=, >, or >= if (0 relop 1) ; See if relop is != movf var1,W,BANKED subwf var2,W,BANKED btfsc STATUS,Z,ACCESS else if (1 relop 1) ; See if relop is >= movf var2,W,BANKED subwf var1,W,BANKED btfss STATUS,C,ACCESS else ; Relop must be > movf var1,W,BANKED subwf var2,W,BANKED btfsc STATUS,C,ACCESS endif endif else if (0 relop 1) ; See if relop is < or <= if (1 relop 1) ; See if relop is <= movf var1,W,BANKED subwf var2,W,BANKED btfss STATUS,C,ACCESS else ; Relop must be < movf var2,W,BANKED subwf var1,W,BANKED btfsc STATUS,C,ACCESS endif else error "Illegal relational operator in andiff statement." endif endif endif goto _if#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount) endm ; ------------------------------------------------------------------------------- ; ANDIFSET (CONTINUATION OF AN IF/ELSIF CLAUSE IN AN IF STATEMENT) ; ------------------------------------------------------------------------------- ; Syntax: andifset reg, bit, a ; ------------------------------------------------------------------------------- ; Arguments: reg the register containing the bit to be tested ; bit a literal value between 0 and 7 specifying the bit ; position to be tested ; a if a is 0, the access bank is selected. if a is 1, ; the BSR specifies the bank used to select reg. ; ------------------------------------------------------------------------------- andifset macro reg,bit,a btfss reg,bit,a goto _if#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount) endm ; ------------------------------------------------------------------------------- ; ANDIFCLR (CONTINUATION OF AN IF/ELSIF CLAUSE IN AN IF STATEMENT) ; ------------------------------------------------------------------------------- ; Syntax: andifclr reg, bit, a ; ------------------------------------------------------------------------------- ; Arguments: reg the register containing the bit to be tested ; bit a literal value between 0 and 7 specifying the bit ; position to be tested ; a if a is 0, the access bank is selected. if a is 1, ; the BSR specifies the bank used to select reg. ; ------------------------------------------------------------------------------- andifclr macro reg,bit,a btfsc reg,bit,a goto _if#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount) endm ; ------------------------------------------------------------------------------- ; ORIF (CONTINUATION OF AN IF/ELSIF CLAUSE IN AN IF STATEMENT) ; ------------------------------------------------------------------------------- ; Syntax: orif var, relop, lit ; ------------------------------------------------------------------------------- ; Arguments: var the register to be tested against a literal ; relop the relational operator to use for the test, which ; must be one of ==, !=, <, <=, >, >= ; lit the literal to test the contents of register var against ; ------------------------------------------------------------------------------- ; This macro performs a comparison between the contents of register var and a ; literal. If the specified relation holds, the block of statements following ; the ifl are executed. This macro makes use of the W register. ; ------------------------------------------------------------------------------- ; This macro borrows heavily from Myke Predko's structured programming macros, ; which are described on pp. 542-546 of the second edition of Programming and ; Customizing PICmicro Microcontrollers. ; ------------------------------------------------------------------------------- orif macro var,relop,lit goto _ifbypass#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount) _if#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount) if (1 relop 1) ; See if relop is == movf var,W,BANKED sublw lit btfss STATUS,Z,ACCESS else if (1 relop 0) ; See if relop is !=, >, or >= if (0 relop 1) ; See if relop is != movf var,W,BANKED sublw lit btfsc STATUS,Z,ACCESS else if (1 relop 1) ; See if relop is >= movlw lit subwf var,W,BANKED btfss STATUS,C,ACCESS else ; Relop must be > movf var,W,BANKED sublw lit btfsc STATUS,C,ACCESS endif endif else if (0 relop 1) ; See if relop is < or <= if (1 relop 1) ; See if relop is <= movf var,W,BANKED sublw lit btfss STATUS,C,ACCESS else ; Relop must be < movlw lit subwf var,W,BANKED btfsc STATUS,C,ACCESS endif else error "Illegal relational operator in orif statement." endif endif endif goto _if#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount + 1) _ifbypass#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount) _ifclausecount ++ endm ; ------------------------------------------------------------------------------- ; ORIFF (CONTINUATION OF AN IF/ELSIF CLAUSE IN AN IF STATEMENT) ; ------------------------------------------------------------------------------- ; Syntax: oriff var1, relop, var2 ; ------------------------------------------------------------------------------- ; Arguments: var1 the first register whose contents are to be tested ; against those of a second register ; relop the relational operator to use for the test, which ; must be one of ==, !=, <, <=, >, >= ; var2 a second register ; ------------------------------------------------------------------------------- ; This macro performs a comparison between the contents of register var1 and ; those of register var2. If the specified relation holds, the block of ; statements following the iff are executed. This macro makes use of the W ; register. ; ------------------------------------------------------------------------------- ; This macro borrows heavily from Myke Predko's structured programming macros, ; which are described on pp. 542-546 of the second edition of Programming and ; Customizing PICmicro Microcontrollers. ; ------------------------------------------------------------------------------- oriff macro var1,relop,var2 goto _ifbypass#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount) _if#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount) if (1 relop 1) ; See if relop is == movf var1,W,BANKED subwf var2,W,BANKED btfss STATUS,Z,ACCESS else if (1 relop 0) ; See if relop is !=, >, or >= if (0 relop 1) ; See if relop is != movf var1,W,BANKED subwf var2,W,BANKED btfsc STATUS,Z,ACCESS else if (1 relop 1) ; See if relop is >= movf var2,W,BANKED subwf var1,W,BANKED btfss STATUS,C,ACCESS else ; Relop must be > movf var1,W,BANKED subwf var2,W,BANKED btfsc STATUS,C,ACCESS endif endif else if (0 relop 1) ; See if relop is < or <= if (1 relop 1) ; See if relop is <= movf var1,W,BANKED subwf var2,W,BANKED btfss STATUS,C,ACCESS else ; Relop must be < movf var2,W,BANKED subwf var1,W,BANKED btfsc STATUS,C,ACCESS endif else error "Illegal relational operator in oriff statement." endif endif endif goto _if#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount + 1) _ifbypass#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount) _ifclausecount ++ endm ; ------------------------------------------------------------------------------- ; ORIFSET (CONTINUATION OF AN IF/ELSIF CLAUSE IN AN IF STATEMENT) ; ------------------------------------------------------------------------------- ; Syntax: orifset reg, bit, a ; ------------------------------------------------------------------------------- ; Arguments: reg the register containing the bit to be tested ; bit a literal value between 0 and 7 specifying the bit ; position to be tested ; ------------------------------------------------------------------------------- orifset macro reg,bit,a goto _ifbypass#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount) _if#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount) btfss reg,bit,a goto _if#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount + 1) _ifbypass#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount) _ifclausecount ++ endm ; ------------------------------------------------------------------------------- ; ORIFCLR (CONTINUATION OF AN IF/ELSIF CLAUSE IN AN IF STATEMENT) ; ------------------------------------------------------------------------------- ; Syntax: orifclr reg, bit, a ; ------------------------------------------------------------------------------- ; Arguments: reg the register containing the bit to be tested ; bit a literal value between 0 and 7 specifying the bit ; position to be tested ; a if a is 0, the access bank is selected. if a is 1, ; the BSR specifies the bank used to select reg. ; ------------------------------------------------------------------------------- orifclr macro reg,bit,a goto _ifbypass#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount) _if#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount) btfsc reg,bit,a goto _if#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount + 1) _ifbypass#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount) _ifclausecount ++ endm ; ------------------------------------------------------------------------------- ; ELSIF (START OF AN ELSIF CLAUSE IN AN IF STATEMENT) ; ------------------------------------------------------------------------------- ; Syntax: elsif var, relop, lit ; ------------------------------------------------------------------------------- ; Arguments: var the register to be tested against a literal ; relop the relational operator to use for the test, which ; must be one of ==, !=, <, <=, >, >= ; lit the literal to test the contents of register var against ; ------------------------------------------------------------------------------- ; This macro performs a comparison between the contents of register var and a ; literal. If the specified relation holds, the block of statements following ; the ifl are executed. This macro makes use of the W register. ; ------------------------------------------------------------------------------- ; This macro borrows heavily from Myke Predko's structured programming macros, ; which are described on pp. 542-546 of the second edition of Programming and ; Customizing PICmicro Microcontrollers. ; ------------------------------------------------------------------------------- elsif macro var,relop,lit goto _endif#v(_ifstack#v(_ifstackptr - 1)) _if#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount) if (1 relop 1) ; See if relop is == movf var,W,BANKED sublw lit btfss STATUS,Z,ACCESS else if (1 relop 0) ; See if relop is !=, >, or >= if (0 relop 1) ; See if relop is != movf var,W,BANKED sublw lit btfsc STATUS,Z,ACCESS else if (1 relop 1) ; See if relop is >= movlw lit subwf var,W,BANKED btfss STATUS,C,ACCESS else ; Relop must be > movf var,W,BANKED sublw lit btfsc STATUS,C,ACCESS endif endif else if (0 relop 1) ; See if relop is < or <= if (1 relop 1) ; See if relop is <= movf var,W,BANKED sublw lit btfss STATUS,C,ACCESS else ; Relop must be < movlw lit subwf var,W,BANKED btfsc STATUS,C,ACCESS endif else error "Illegal relational operator in elsif statement." endif endif endif goto _if#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount + 1) _ifclausecount ++ endm ; ------------------------------------------------------------------------------- ; ELSIFF (START OF AN IF/ELSIF CLAUSE IN AN IF STATEMENT) ; ------------------------------------------------------------------------------- ; Syntax: elsiff var1, relop, var2 ; ------------------------------------------------------------------------------- ; Arguments: var1 the first register whose contents are to be tested ; against those of a second register ; relop the relational operator to use for the test, which ; must be one of ==, !=, <, <=, >, >= ; var2 a second register ; ------------------------------------------------------------------------------- ; This macro performs a comparison between the contents of register var1 and ; those of register var2. If the specified relation holds, the block of ; statements following the iff are executed. This macro makes use of the W ; register. ; ------------------------------------------------------------------------------- ; This macro borrows heavily from Myke Predko's structured programming macros, ; which are described on pp. 542-546 of the second edition of Programming and ; Customizing PICmicro Microcontrollers. ; ------------------------------------------------------------------------------- elsiff macro var1,relop,var2 goto _endif#v(_ifstack#v(_ifstackptr - 1)) _if#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount) if (1 relop 1) ; See if relop is == movf var1,W,BANKED subwf var2,W,BANKED btfss STATUS,Z,ACCESS else if (1 relop 0) ; See if relop is !=, >, or >= if (0 relop 1) ; See if relop is != movf var1,W,BANKED subwf var2,W,BANKED btfsc STATUS,Z,ACCESS else if (1 relop 1) ; See if relop is >= movf var2,W,BANKED subwf var1,W,BANKED btfss STATUS,C,ACCESS else ; Relop must be > movf var1,W,BANKED subwf var2,W,BANKED btfsc STATUS,C,ACCESS endif endif else if (0 relop 1) ; See if relop is < or <= if (1 relop 1) ; See if relop is <= movf var1,W,BANKED subwf var2,W,BANKED btfss STATUS,C,ACCESS else ; Relop must be < movf var2,W,BANKED subwf var1,W,BANKED btfsc STATUS,C,ACCESS endif else error "Illegal relational operator in elsiff statement." endif endif endif goto _if#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount + 1) _ifclausecount ++ endm ; ------------------------------------------------------------------------------- ; ELSIFSET (START OF AN ELSIF CLAUSE IN AN IF STATEMENT) ; ------------------------------------------------------------------------------- ; Syntax: elsifset reg, bit, a ; ------------------------------------------------------------------------------- ; Arguments: reg the register containing the bit to be tested ; bit a literal value between 0 and 7 specifying the bit ; position to be tested ; a if a is 0, the access bank is selected. if a is 1, ; the BSR specifies the bank used to select reg. ; ------------------------------------------------------------------------------- ; This macro tests the specified bit in register reg; if it is set, the ; instructions following the elsifset macro are executed. Otherwise, the ; next case is tested. ; ------------------------------------------------------------------------------- elsifset macro reg,bit,a goto _endif#v(_ifstack#v(_ifstackptr - 1)) _if#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount) btfss reg,bit,a goto _if#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount + 1) _ifclausecount ++ endm ; ------------------------------------------------------------------------------- ; ELSIFCLR (START OF AN ELSIF CLAUSE IN AN IF STATEMENT) ; ------------------------------------------------------------------------------- ; Syntax: elsifclr reg, bit, a ; ------------------------------------------------------------------------------- ; Arguments: reg the register containing the bit to be tested ; bit a literal value between 0 and 7 specifying the bit ; position to be tested ; a if a is 0, the access bank is selected. if a is 1, ; the BSR specifies the bank used to select reg. ; ------------------------------------------------------------------------------- ; This macro tests the specified bit in register reg; if it is clear, the ; instructions following the elsifset macro are executed. Otherwise, the ; next case is tested. ; ------------------------------------------------------------------------------- elsifclr macro reg,bit,a goto _endif#v(_ifstack#v(_ifstackptr - 1)) _if#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount) btfsc reg,bit,a goto _if#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount + 1) _ifclausecount ++ endm ; ------------------------------------------------------------------------------- ; OTHERWISE (START OF AN OTHERWISE CLAUSE IN AN IF STATEMENT) ; ------------------------------------------------------------------------------- ; Syntax: OTHERWISE ; ------------------------------------------------------------------------------- ; This macro begins the sequence of instructions that is executed if none ; of the other conditions held. The otherwise block is optional. Note that ; this would normally be called 'else', but that was taken by MPASM for ; conditional assembly structures. ; ------------------------------------------------------------------------------- otherwise macro goto _endif#v(_ifstack#v(_ifstackptr - 1)) _if#v(_ifstack#v(_ifstackptr - 1))_#v(_ifclausecount) _ifclausecount ++ endm ; ------------------------------------------------------------------------------- ; ENDI (END OF AN IF STATEMENT) ; ------------------------------------------------------------------------------- ; Syntax: endi ; ------------------------------------------------------------------------------- ; This macro marks the end of an if statement. ; ------------------------------------------------------------------------------- endi macro _ifstackptr -- _if#v(_ifstack#v(_ifstackptr))_#v(_ifclausecount) _endif#v(_ifstack#v(_ifstackptr)) _ifclausecount = _ifclausestack#v(_ifstackptr) endm