AVRasm2 MACROS headaches...

Go To Last Post
6 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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  

 

LDI ZL,low(CodeLabel*2)

LDI ZH,high(CodeLabel*2)

 

I created a simple small macro;

 

LDIF Z,CodeLabel

 

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,  

 

MOVI R5,0x44  

makes

LDI R15,@1  

MOV @0,R15

 

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    __LDIF

    ldi    @0L,low(@1*2)
    ldi    @0H,high(@1*2)
.endm

 

 

; MACRO __TEXT  Var1, CodeLabel, Var2

.macro    __TEXT

    Ldi  R18, @0

   .if (@1 != 0)

      Ldi  R30,low(@1*2)

      Ldi  R31,high(@1*2)

   .endif

    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.

.endm

 

 

Now consider this code example:

 

 

Table1:    .db 0x25,0x14,0xF2,0x4D

 

Label19:   LDS    R16,0x150

           __LDIF Z,Table1

           __LDIF Y,Table2

           __TEXT 14, Table1, 55

           __TEXT 55, Table2, 29

           Ret

 

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

MACROCALL

.equ FOO2 = 11

 

being  MACROCALL =

 

.macro   MACROCALL

  .if FOO1...

works!

 

.macro  MACROCALL

  .if FOO2...

doesn't work!

 

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.

 

 

Wagner Lipnharski
Orlando Florida USA

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

MOVI R5,0x44  

makes

LDI R15,@1  

MOV @0,R15

How does that work? You can only LDI to R16..R31 can't you?

 

(BTW most programmers who start "macroising" C to make it a higher level language eventually give in and just use C which is little more than an advanced macro assembler! ;-)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

MOVI R5,0x44  

makes

LDI R15,@1  

MOV @0,R15

How does that work? You can only LDI to R16..R31 can't you?

 

(BTW most programmers who start "macroising" C to make it a higher level language eventually give in and just use C which is little more than an advanced macro assembler! ;-)

 

Sorry.... R16 !!!

Wagner Lipnharski
Orlando Florida USA

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

wagnerlip wrote:
The first __TEXT works fine, since "Table1" was already referenced by the assembler.

Surely this is because it is a "one pass assembler" ? If you can only refer to something that has already been "seen" then don't you just move table2 to before the invocation?

 

One (rather radical) solution to this would be to switch assemblers - use GNU avr-as rather than Atmel Asm2. However be warned that you will be learning a whole new macro language.

 

An alternative might be to look at the use of C preprocessor to write macros as Asm2 runs the code through a preprocessor before it starts. Having said that the pre-pro is not THAT advanced in what it can support.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think some smart assembler programmer should write a bunch of macros for the 16 register tinys like the tiny104, and maybe old c nuts like me could then be able to use a tiny104 in a project. Good idea or stupid?

 

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

bobgardner wrote:
I think some smart assembler programmer should write a bunch of macros for the 16 register tinys like the tiny104, and maybe old c nuts like me could then be able to use a tiny104 in a project. Good idea or stupid?

As I've replied before when you brought this up:  Choose a C toolchain with support for the brain-dead models.  No macros necessary.

 

This thread:  https://www.avrfreaks.net/comment...

 

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.