use*_*847 6 c gcc avr interrupt
我有一个非常简单的中断服务程序(ISR)为atmega328编写,并使用AVR工作室使用avrgcc(使用-Os)编译.
ISR (TIMER0_OVF_vect) {
txofcnt++; //count overflows and store in uint16_t
}
Run Code Online (Sandbox Code Playgroud)
如果你注意到生成的程序集(如下),它使用r24,r25来获取增加易失性uint16_t txofcnt的作业,但它也是push-write-pop r1,r28,r29而没有读取它们.它还有一个额外的r0推/弹,而不会在它们之间使用它.
我不知道为什么r1被推,清除然后最终poped.但是为什么gcc觉得需要将EIMSK和GPIOR0加载到寄存器中然后不使用它们.如果你能告诉我GPIOR0的用途是什么,那么数据表说它存在但没有描述.
00000258 <__vector_16>:
ISR (TIMER0_OVF_vect) {
258: 1f 92 push r1
25a: 0f 92 push r0
25c: 00 90 5f 00 lds r0, 0x005F
260: 0f 92 push r0
262: 11 24 eor r1, r1
264: 8f 93 push r24
266: 9f 93 push r25
268: cf 93 push r28
26a: df 93 push r29
26c: cd b7 in r28, 0x3d ; 61 reads register EIMSK
26e: de b7 in r29, 0x3e ; 62 reads register GPIOR0
txofcnt++;
270: 80 91 0a 01 lds r24, 0x010A
274: 90 91 0b 01 lds r25, 0x010B
278: 01 96 adiw r24, 0x01 ; 1
27a: 90 93 0b 01 sts 0x010B, r25
27e: 80 93 0a 01 sts 0x010A, r24
}
282: df 91 pop r29
284: cf 91 pop r28
286: 9f 91 pop r25
288: 8f 91 pop r24
28a: 0f 90 pop r0
28c: 00 92 5f 00 sts 0x005F, r0
290: 0f 90 pop r0
292: 1f 90 pop r1
294: 18 95 reti
Run Code Online (Sandbox Code Playgroud)
https://gcc.gnu.org/wiki/avr-gcc有一些关于 AVR 的 GCC 寄存器用法的文档
\n\n与您的问题相关的一些段落:
\n\n\n\n\n固定寄存器
\n\n固定寄存器是不会由 GCC 寄存器分配器分配的寄存器。寄存器 R0 和 R1 是固定的,并在打印汇编指令时隐式使用\n:
\n\n\n
\n\n- \n
罗0
\n\n用作暂存寄存器,使用后无需恢复。它必须在中断服务程序(ISR)的序言和尾声中保存和恢复。在内联汇编器中,您可以使用 \n
__tmp_reg__作为暂存寄存器。- \n
R1
\n\n始终包含零。在insn期间,内容可能被破坏,例如,通过使用R0/R1作为隐式输出寄存器的MUL指令。如果insn破坏了R1,则insn必须随后将R1恢复为零。该寄存器必须保存在 ISR 序言中,并且必须\n 然后设置为零,因为 R1 可能包含非零的值。\n ISR 结尾会恢复该值。在内联汇编器中,您可以使用 \n
\n\n__zero_reg__作为零寄存器。...
调用使用的寄存器
\n\n调用使用或调用破坏的通用寄存器 (GPR) 是可能被函数调用破坏(破坏)的寄存器。
\n\n\n
\n\n- \n
R18\xe2\x80\x93R27、R30、R31
\n\n这些探地雷达被呼叫破坏了。普通函数可以使用它们而无需恢复内容。中断服务例程 (ISR) 必须保存和恢复它们使用的每个寄存器。
\n\n...
调用保存的寄存器
\n\n\n
\n- \n
R2\xe2\x80\x93R17、R28、R29
\n\n其余的 GPR 是调用保存的,即使用此类寄存器的函数必须恢复其原始内容。即使寄存器用于传递函数参数,这也适用。
以下是我对编译器为何在 ISR 序言/尾声中执行一些明显不必要的寄存器保存/恢复的猜测:
\n\nr0并r1被保存/恢复,因为编译器生成或调用的代码将做出上面概述的假设。由于它们不被 GCC 的寄存器分配器跟踪,因此序言必须确保它们被保存(并且在r1这种情况下初始化为 0)。
r28和r29用于保存堆栈指针(0x3d/SPL和0x3e/ SPH)。我猜测(我想强调这是一个猜测)编译器编写者假设中断处理程序交换堆栈可能很常见,这确保了 ISR 可以恢复正在使用的堆栈当中断发生时。编译器可以假设这些寄存器不会被调用的函数更改,因为它们是“调用保存”寄存器。
另外,您应该注意,显然“额外”的压入和弹出r0是将状态寄存器保存SREG在堆栈上。即使在这些指令和指令r0之间没有使用,请记住该寄存器是一个暂存寄存器,不会被寄存器分配器跟踪,因此编译器不会假设它在加载到其中后不会发生变化。pushpopr0r0SREG
附带说明一下,0x3d和的读取0x3e是SPL和SPH堆栈指针寄存器,而不是EIMSK和GPIOR0寄存器。有关使用/指令而不是加载或存储指令时寄存器寻址有何不同的详细信息,请参阅此处参考手册第 625 页寄存器摘要表的注释 4 。INOUT
对于以下方面的奖励积分GPIOR0:
\n\n8.5.1 通用 I/O 寄存器
\n\nATmega48A/PA/88A/PA/168A/PA/328/P 包含三个通用 I/O 寄存器。这些寄存器可用于存储任何信息,并且对于存储全局变量和状态标志特别有用。地址范围 0x00 - 0x1F 内的通用 I/O 寄存器可使用 SBI、CBI、SBIS 和 SBIC 指令直接进行位访问。
\n