Still struggling with AVR assembly. This time avr-gcc
seems to completely ignore my directive to permanently bind a local variable to a register. Here's an example — this is of course just an illustration, not the final code:
// C code:
ISR(USART1_RX_vect)
{
register uint8_t c asm("r3") = UDR1;
tty1::buffer[tty1::ptr.head] = c;
}
// Generated assembly:
000000d8 <__vector_20>:
d8: 1f 92 push r1
da: 0f 92 push r0
dc: 0f b6 in r0, SREG ; 63
de: 0f 92 push r0
e0: 11 24 eor r1, r1
e2: 8f 93 push r24
e4: ef 93 push r30
e6: ff 93 push r31
e8: 80 91 73 00 lds r24, UDR1 ; 0x800073 <__EEPROM_REGION_LENGTH__+0x7f0073>
ec: e0 91 01 01 lds r30, 0x0101 ; 0x800101 <tty<drv::uart1>::ptr>
f0: e2 95 swap r30
f2: ef 70 andi r30, 0x0F ; 15
f4: f0 e0 ldi r31, 0x00 ; 0
f6: ee 5f subi r30, 0xFE ; 254
f8: fe 4f sbci r31, 0xFE ; 254
fa: 80 83 st Z, r24
fc: ff 91 pop r31
fe: ef 91 pop r30
100: 8f 91 pop r24
102: 0f 90 pop r0
104: 0f be out SREG, r0 ; 63
106: 0f 90 pop r0
108: 1f 90 pop r1
10a: 18 95 reti
- Give me r3
, please.
- Sure thing! here's r24
.
I can ask any register between r2
and r7
that compiler just takes whatever it wants! And it has nothing to do with UDR1
, it does that with whatever I assign c
. What's the point of that directive if it does nothing at all? How am I supposed to control the register the compiler selects?
To the question «Why the heck am I wanting to assign variable to a register?» I reply «Because the generated code is sub-optimal for an interrupt and I want a fine control over the generated assembly.» So far it's been a trouble for me.
Still using avr-gcc
version 7.1.0...
Remove the declaration from the Interrupt Service Routine (ISR) to the global scope. GCC allows global and local permanent bindings. Yours is in the ISR scope, which is but useless in your case.
I will try my best to give a more detailed explanation.
See the code: https://godbolt.org/g/HsjvCa and https://godbolt.org/g/ZGjvRE with optimisations on.
Local bindings do not change any general register use rules.
If you bind registers - you can't call any functions compiled without header files with register bindings (global scope). In the local scope call to any function invalidates the local bindings.