I've spent a couple hours trying to complete an LED-muxing ISR in gnu assembler, and the "hi8/lo8" operators are giving me no end of pain (as usual). The context is: R30 (ZL) has got the zero-based index of the digit to be displayed, and R31 (ZH) is loaded with 0x10, having been used to manipulate some other hardware. From this state, I want to get the Z register pair pointing to Leds
subi r30, -lo8(Leds) sbci r31, 16 - hi8(Leds)
An exasperated aside: Of what possible benefit is deciding to offer only a "subtract immediate" operation instead of an "add immediate" one? So some designer gets more opportunities to smugly point out that the effect of adding a constant can be gotten by just subtracting the negative of that constant???
Attempting to compile this in AStudio 6.1 gives an error message for each of the above lines, with the helpful description, "garbage at end of line"
So now begins the guessing game. The gnu manual pages provide this one-sentence description of the "lo8" operator:
This modifier allows you to use bits 0 through 7 of an address expression as 8 bit relocatable expression
, but the definition doesn't do much for me beyond making me curious as to what the distinction between "address expressions" and "relocatable expressions" might be (the manual doesn't define these terms, even though there seems to be ample blank space in the top-level "Expressions" section).
Another round of desperate guessing gives:
#define ALPHA (2 << PORT_OPC_gp) ldi r31, ALPHA sts PORTC_PIN0CTRL, r31 .set negLeds,(-Leds) .set highHack, (0xf000 + Leds) .set highHak2, (-highHack) cacheChosenDigit: subi r30, lo8(negLeds) ; sbci r31, hi8((ALPHA << 8) - Leds) ; sbci r31, -hi8(highHack) ; sbci r31, -(hi8(highHack)) sbci r31, hi8(highHak2)
for which the assembler gives the following errors:
Error 1 invalid operand (.bss section) for `-' when setting `negLeds'
Error 2 invalid operand (.bss section) for `-' when setting `highHak2'
The other commented-out variants produced different accusations of "garbage at end of line" or "missing right parenthesis" complaints.
Knowing, though, that the C compiler is able to dereference arrays just fine, working through the same assembler, I fiddled around awhile building some dummy C code and discovered that I hadn't quite guessed the right arrangement of multiple parentheses. This seems to be what the assembler wants, at least for the simple low-byte of the address:
subi r30, lo8(-(Leds))
, but it didn't extend too well to the computation of the high byte. I tried these lines
sbci r31, hi8(0x1000-(Leds)) ; sbci r31, (16+(hi8(-(Leds))))
, and either got accused of "missing ')'" or told "expression too complex". I'm giving up trying to figure out how to coax gnu into doing arithmetic, and just coding it as:
subi r30, lo8(-(Leds)) ldi r31, 0 sbci r31, hi8(-(Leds))
The inability to handle an extra added term seems like a shortcoming in the tools to me, though. Is it that the linker doesn't have a rich enough set of "fixup" operations?