Converting avra macros to gas macros

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

Avra first substitutes the actual argument string(s) into the %0, %1, etc strings of the macro
definition, then evaluates the resulting strings. I can't see a simple way of achieving the same thing in gas.

If I have

r0 = 0
r1 = 1
etc

.macro add16 Rd, Rs
add \Rd, \Rs
adc (\Rd+1), (\Rs+1)
.endm

and then write

add16 r0, r2

then gas objects to the expression(s).

How can I achieve the desired (\Rn+1) values in the macro expansion?

I would really like to retain the standard assembler syntax i.e avoid the need to write source code of the form add16(r0, r2) if it is at all possible.

Thanks,

Roger

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

This is my first idea on it:

.macro add16 Rd, Rs
.set .L\@, \Rd + 1
.set .L\@, \Rs + 1
add \Rd, \Rs
adc .L\@, .L\@
.endm

add16 0, 2

Fairly ugly, agreed.

Upon researching the gas documentation, I got another
hint which leads to:

.macro xpand op, arg1, arg2
\op     \arg1, \arg2
.endm

.macro add16 Rd, Rs
add \Rd, \Rs
xpand adc, "(\Rd+1)", "(\Rs+1)"
.endm

add16 0, 2

It does the right thing, but always gives two warnings:

foo.S:0: Warning: unknown escape '\R' in string; ignored
foo.S:0: Warning: unknown escape '\R' in string; ignored

Perhaps you can convince it to not spit out these warnings. :)

In AVR gas, a number can be used already at any place where a register
argument is expected (as it is clear from the opcode and operand that
this is a register). If you need source code compatibility to the "r"
notation, put the following preprocessor macros somewhere into a
central header file:

#define r0 0
#define r1 1
#define r2 2
#define r3 3
#define r4 4
#define r5 5
#define r6 6
#define r7 7
#define r8 8
#define r9 9
#define r10 10
#define r11 11
#define r12 12
#define r13 13
#define r14 14
#define r15 15
#define r16 16
#define r17 17
#define r18 18
#define r19 19
#define r20 20
#define r21 21
#define r22 22
#define r23 23
#define r24 24
#define r25 25
#define r26 26
#define r27 27
#define r28 28
#define r29 29
#define r30 30
#define r31 31

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

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

Very cunning, thanks Jorg. I'll look at it further, in the morning.

Roger

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

That first idea is very clever - it will be years before I know gas well enough to come up with an idea like that so quickly.

To be able to write source code such as

        ld16 r2, y              (i)
        ld16 r2, y+             (ii)
        st16 -y, r2   etc       (iii)

my macro needs to determine which pointer is used, and whether it is a simple indirection (i),
or an auto-increment/decrement (ii)(iii). The avra string substitution - evaluation again makes this easy;
I have some defines which include:

        .def r0lo=r0            ;low byte of a multi-byte value in rn:r0 is r0
        .def r1lo=r1            ;low byte of a multi-byte value in rn:r1 is r1
        .def r2lo=r2            ;low byte of a multi-byte value in rn:r2 is r2
            etc

        .def r0b1=r1            ;byte1 of a multi-byte value in rn:r0 is r1
        .def r1b1=r2            ;byte1 of a multi-byte value in rn:r1 is r2
        .def r2b1=r3            ;byte1 of a multi-byte value in rn:r2 is r3
            etc

        .def r0b2=r2            ;byte2 of a multi-byte value in rn:r0 is r2
        .def r1b2=r3            ;byte2 of a multi-byte value in rn:r1 is r3
        .def r2b2=r4            ;byte2 of a multi-byte value in rn:r2 is r4
            etc

        .define aa 1
        .define x1 -1
        .define y1 -1
        .define z1 -1
        .define x2 -1
        .define y2 -1
        .define z2 -1
        .define aax1 1
        .define aay1 1
        .define aaz1 1
        .define aax 1
        .define aay 1
        .define aaz 1
so that I then write my macro as

        .MACRO ld16
        .if (aa@11-2)           ; only ld16 Rd, x (or y, or z) has a non-zero result
          ld @0lo, @1+
          ld @0hi, @1
          ld @0lo, -@1          ; restore pointer without affecting SREG

        .else                   ; now separate x+ and -x (or y, or z)

          .if (aa@12-2)         ; only ld16 Rd, x+ (or y+, or z+) has a non-zero result
            ld @0lo, @1
            ld @0hi, @1
          .else                 ; assume only remaining possibility is ld16 Rd, -x (or -y, or -z)
            ld @0hi, @1
            ld @0lo, @1
          .endif
        .endif
        .ENDMACRO

Yes, it's inefficient for the simple indirection, because it generates an additional instruction,
but I consider the benefit for general coding to outweigh that. If I wanted to, I could further seperate the pointer register into x or (y or z), and then use an (ldd @0hi, @1+1) for the second instruction. The st16 macro is essentially identical.

The code that is emitted for the three examples above is:

        ld16 r2, y  -->         ld r2lo, y+
                                ld r2hi, y+
                                ld r2lo, -y

        ld16 r2, y+  -->        ld r2lo, y+
                                ld r2hi, y+

        st16 -y, r2  -->        st -y, r2hi
                                st -y, r2lo

I find this difficult in gas.

Edit: Correction: Note that the emitted code uses the r2hi/r2lo notation, rather than the explicit r3/r2 notation that I showed originally.