create high-level IF ELSE ENDIF with macros in PIC16 assembly
Question
I tried to simulate IF() .... ELIF .... ENDIF in assembly for PIC16F84, but it doesn't seem to work for more than one usage. I tried to use something like this in two places, but it gives some error that a label is duplicated. Shouldn't the parameter from the macro be replaced in the labels too? (name in true_name:)
_f macro name
btfsc EQUAL,0
goto true_name
goto false_name
true_name:
endm
_lse macro name
goto next_name
false_name:
endm
_ndif macro name
goto next_name
next_name:
endm
;; usage example
_f label1
...
_lse label1
...
_ndif
Solution 3
I kinda solved this problem with MPLAB variables, here's an example for testing equality between a register and a literal:
_f_equal_literal macro register,literal,name
movlw literal
subwf register,0
btfss STATUS,2 ;bit indicating result is zero
goto _false#v(name)
endm
_lse macro name
goto _next#v(name)
_false#v(name):
endm
_ndif macro name
_next#v(name):
endm
Notice that I didn't use goto _true#v(name)
and _true#v(name):
label, you'll just have to figure if you need btfss
or btfsc
.
You can have a single _lse
and _ndif
macro, and have multiple macros for _f
statements.
GJ's solution doesn't have a next
label, so the true branch will execute the false branch.
You need to define a variable for each if-else-endif construct. It might even useful if the variable name describes what the if-else-endif is used for.
Example:
variable testing_something=123
_f_equal_literal some_register,some_value,testing_something
...
_lse testing_something
...
_ndif testing_something
OTHER TIPS
I think one can do a bit better. Here's some if-else-endif macros that can be nested five deep. Unfortunately, I was not able to make the definitions of if1, if2.. as nice as I would like since the assembler does not accept "#ifndef if#v(lvl)" so the macros as they stand limit the nesting level to five deep. These symbols count the number of Ifs at a given nesting level so unique labels can be attached. A nonsense example is included.
xIf macro L,R,A
#ifndef lvl
lvl=0
#endif
lvl=lvl+1
#ifndef if1
if1=0
if2=0
if3=0
if4=0
if5=0
#endif
if#v(lvl)=if#v(lvl)+1
movf R,A
xorlw L
bnz _false_#v(lvl)_#v(if#v(lvl))
endm
xElse macro
bra _end_#v(lvl)_#v(if#v(lvl))
_false_#v(lvl)_#v(if#v(lvl)):
endm
xEndIf macro
_end_#v(lvl)_#v(if#v(lvl)):
lvl=lvl-1
endm
xIf 123,STATUS,A
clrf TMR3H,A
xIf 75,STATUS,A
clrf TMR3H,A
xElse
setf TMR3L,A
xEndIf
xElse
setf TMR3H,A
xEndIf
Do not use jumps from one macro to another, it is dangerous.
There is no need to use unique labels. Two ways haw to do this under MPLAB:
1)Case with LOCAL directive
_f macro name
LOCAL true_name
btfsc EQUAL,0
goto true_name
goto name
true_name:
endm
2)Case with $ as current memory address pointer.
_f macro name
btfsc EQUAL,0
goto $+1
goto name
endm