Lately, with AtMegas with much more flash memory, we can lay down calling reused routines to save few bytes in the code. The lots of kBytes of flash allows us to sometimes repeat small routines here and there, without thinking about the code size, at least, gaining in little extra speed. Then I started to use macros with more frequency to have a clean readable code.
For example, instead of using
I created a simple small macro;
It make things a little bit easier, and cleaner to read.
Also, the infamous PUSH ZL, PUSH ZH became PUSHZ, the same for POPZ, it makes always the order correct. Yeah, I already fall in the pop the registers reversed...
The "MOVI" macro makes success here, a kind of LDI for low registers (R0-R15), obviously it is very simple,
Of course I got some misses with the relative jump instructions without label, such BRNE PC-4 now need to observe if there is a macro within the jump, more instructions to jump.
Okay, now the problem.
Using code labels in macros, make me confused.
Lets consider two different macros:
; Macro LDIF RegisterPairName, CodeLabel
; MACRO __TEXT Var1, CodeLabel, Var2
Ldi R18, @0
.if (@1 != 0)
Ldi R19, @2
;Do Something else in the macro that may or may not use Z register.
;If new value of Z register is to be set above or not, will depend
;about the "CodeLabel" (@2) received, if any Label is specified,
;then it should change Z. Otherwise, if Z is not to be changed, a
;simple numeric zero is supplied in place and becomes @2.
Now consider this code example:
Table1: .db 0x25,0x14,0xF2,0x4D
Label19: LDS R16,0x150
__TEXT 14, Table1, 55
__TEXT 55, Table2, 29
Table2: .db 0x59,0xC2,0x25,0x99
The macro will fail at the second __TEXT, where the macro receives (or not receives) the "Table2" reference.
The first __TEXT works fine, since "Table1" was already referenced by the assembler.
This only fails in the ".IF", it does not fail at the LDI R30,low(Table2*2).
I mean, the .IF works fine if the label referenced is BEFORE the call to the macro, in the code.
Does not work if the label is after the call to the macro.
I don't understand how it works with the LDIF and fails with the .IF
Of course, at the moment is called, its contents will be evaluated and part or all its contents will be inserted into the code, it should know the Table2 address, if not, how it does correctly the LDI R30,low(Table2*2) ?
The problem is with the .IF, it can not do future references.
The AVRasm2 complains as;
" error: Illegal use of undefined or forward referenced symbol 'Table2' in conditional"
The same happens as:
.equ FOO1 = 10
.equ FOO2 = 11
being MACROCALL =
The AVRASM2 manual, #IF, says:
" The preprocessor recognizes the special operator defined(name)that returns 1 if name is #defined and 0 otherwise."
Long time ago I wrote a Macro Assembler for Z80 into the IBM MVS using Compiled REXX2 language. So, I have a decent idea how an assembler works.
Forward Reference Values, as FOO1, FOO2, or Table1, Tabl2, you insert this "value name or label name" into a list of undefined values, you use the Index Entry as the temporary value for the assembler code being produced, make another entry in a second list of "Values to be updated" at the second pass. Once you finished the first pass, you already have all the FOO1, FOO2, Table1 and Table2 values of code addresses, to be more precise, you have the real numbers. Then you scan the list of "Values to be updated", cross with "Undefined Values", and replace the values into the code. Badabim, badabum. So, I understand that when the conditional .IF doesn't have yet the value of address of a forward reference, it can not decide if the instructions enclosed in the .IF are to be included or not into the code, or at least evaluated. In the Z80 assembler I created, I included into the code the .IF enclosed instructions as if the .IF was valid, and created a flag for it. The last thing the assembler would do, is check the conditional .IF flags. If the .IF enclosed instructions were not to be included, the third pass would remove the instructions and recalculate all the addresses, replacing all the references. Of course the third pass would only run if there was any FLAG lifted, if not, only two passes would be enough. But it was working marvelous. AVRASM2 does not do that. It does at the LDIF because it is just a matter of update a number, not delete instructions, it would give more headaches for the AVRASM2 developer. Well, it is very low cost... $0.00 !
Well, may be there a simpler solution for me.
How can I identify if a parameter is present inside the macro?
Suppose I want to send Var1, Var2, but don't want to send Label to the macro.
How can I identify inside the macro, that @2 is present or missing?
I tried to use space, nothing, comma comma, etc, no deal.