avr-gcc 问题:忽略永久 variable/register 绑定。为什么?
avr-gcc woes: ignores permanent variable/register binding. Why?
仍在为 AVR 组装而苦苦挣扎。这次avr-gcc
似乎完全无视我对permanently bind a local variable to a register的指令。这是一个例子——这当然只是一个例子,不是最终代码:
// 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
- 请给我r3
。
- 当然可以!这是 r24
。
我可以询问 r2
和 r7
之间的任何寄存器,编译器只需要它想要的任何东西!它与 UDR1
无关,它与我分配的任何内容 c
一样。如果它什么都不做,那条指令有什么意义呢?我应该如何控制编译器选择的寄存器?
对于问题 «为什么我要将变量分配给寄存器?» 我回答 «因为生成的代码对于一个中断,我想对生成的程序集进行精细控制。» 到目前为止,这对我来说是个麻烦。
仍在使用 avr-gcc
版本 7.1.0...
从中断服务例程 (ISR) 中删除对全局范围的声明。 GCC 允许全局和本地永久绑定。你的在 ISR 范围内,但对你来说没用。
我会尽力给出更详细的解释。
本地范围
- 从绑定中注册不再是寄存器,而是作为存储位置。
- 相同的优化规则适用于任何其他自动变量。
- ISR 必须恢复所有寄存器(绑定在全局范围内的寄存器除外)- 因此不会产生副作用 - 即使寄存器绑定在本地范围内也是如此。
见代码:
https://godbolt.org/g/HsjvCa and https://godbolt.org/g/ZGjvRE 开启优化。
本地绑定不会更改任何通用寄存器使用规则。
如果您绑定寄存器 - 您将无法调用任何没有使用寄存器绑定(全局范围)的头文件编译的函数。在本地范围内调用任何函数都会使本地绑定无效。
仍在为 AVR 组装而苦苦挣扎。这次avr-gcc
似乎完全无视我对permanently bind a local variable to a register的指令。这是一个例子——这当然只是一个例子,不是最终代码:
// 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
- 请给我r3
。
- 当然可以!这是 r24
。
我可以询问 r2
和 r7
之间的任何寄存器,编译器只需要它想要的任何东西!它与 UDR1
无关,它与我分配的任何内容 c
一样。如果它什么都不做,那条指令有什么意义呢?我应该如何控制编译器选择的寄存器?
对于问题 «为什么我要将变量分配给寄存器?» 我回答 «因为生成的代码对于一个中断,我想对生成的程序集进行精细控制。» 到目前为止,这对我来说是个麻烦。
仍在使用 avr-gcc
版本 7.1.0...
从中断服务例程 (ISR) 中删除对全局范围的声明。 GCC 允许全局和本地永久绑定。你的在 ISR 范围内,但对你来说没用。
我会尽力给出更详细的解释。
本地范围
- 从绑定中注册不再是寄存器,而是作为存储位置。
- 相同的优化规则适用于任何其他自动变量。
- ISR 必须恢复所有寄存器(绑定在全局范围内的寄存器除外)- 因此不会产生副作用 - 即使寄存器绑定在本地范围内也是如此。
见代码: https://godbolt.org/g/HsjvCa and https://godbolt.org/g/ZGjvRE 开启优化。
本地绑定不会更改任何通用寄存器使用规则。
如果您绑定寄存器 - 您将无法调用任何没有使用寄存器绑定(全局范围)的头文件编译的函数。在本地范围内调用任何函数都会使本地绑定无效。