我正在查看小型C程序的avr-gcc
程序集生成代码。以下应该在堆栈上分配一个100字节的本地数组。
extern void foo(char [], int);
void bar()
{
char t[100];
foo(t,100);
}
当然它通过从堆栈指针中减去100来实现。
据我所知,由于avr是8位机器,更改16位堆栈指针需要2个步骤(更改SPH和SPL)。此外,通过禁用中断来提供一些原子性是个好主意。它由序列
完成in r28,__SP_L__
in r29,__SP_H__ ; get SP
subi r28,100 ; new SP in R29:R28 = OLD -100
sbc r29,__zero_reg__
in __tmp_reg__,__SREG__ ; save status to r0
cli ; disable interrupts
out __SP_H__,r29 ; update SPH
out __SREG__,__tmp_reg__ ; restore status -- why here ?
out __SP_L__,r28 ; update SPL
我还不相信恢复状态指令的位置。
更新SPL后为什么不?
也许有保证在(重新)启用中断后,在下一条指令完成之前不会将中断记入账户?
答案 0 :(得分:5)
看来你是对的。
我找不到一个明确的来源,Electrical Engineering的人显然 1 。
我们得到的最接近的是来自AVR ISA manual sei
指令的声明:
设置SREG(状态寄存器)中的全局中断标志(I)。 SEI之后的指令将在任何待处理中断之前执行。
现在,正如EE网站中所提出的那样,这可能是sei
指令本身的一个特征,也可能是架构本身 2 的一个特征。
如果您查看操作码sei
实际上只是bset 7
,但bset
页面中没有关于待处理中断的注释,尽管bset 7
的行为与{sei
相同1}}。
所以我相信,无论何时使用out
或sei
,在 SREG 中设置 I-bit 都会屏蔽中断一条指令。
有关链接问题的更多信息:AVR sei instruction 3 。
1 链接的问题与您的相同,它包含的实际答案与此假设不同。
2 即它不会计算你如何改变SREG
3 重新连接。