C99“;原子的;装入裸金属便携式图书馆
我正在为裸金属嵌入式应用程序开发一个便携式库 假设我有一个定时器ISR,它增加一个计数器,在主循环中,这个计数器的读取肯定不是原子负载 我试图确保负载一致性(即,我没有读取垃圾,因为负载被中断,值被更改),而不必禁用中断。只要读取的值正确,读取计数器后值是否发生变化并不重要。这能奏效吗C99“;原子的;装入裸金属便携式图书馆,c,atomic,c99,isr,C,Atomic,C99,Isr,我正在为裸金属嵌入式应用程序开发一个便携式库 假设我有一个定时器ISR,它增加一个计数器,在主循环中,这个计数器的读取肯定不是原子负载 我试图确保负载一致性(即,我没有读取垃圾,因为负载被中断,值被更改),而不必禁用中断。只要读取的值正确,读取计数器后值是否发生变化并不重要。这能奏效吗 uint32_t read(volatile uint32_t *var){ uint32_t value; do { value = *var; } while(value != *var);
uint32_t read(volatile uint32_t *var){
uint32_t value;
do { value = *var; } while(value != *var);
return value;
}
您是否在任何
uint32\t
大于单个汇编指令字读/写大小的系统上运行?如果不是,IO到内存应该是单个指令,因此是原子的(假设总线也是字大小的…),当编译器将其分解为多个较小的读/写时,您会遇到麻烦。否则,我总是不得不求助于DI/EI。您可以让用户配置您的库,以便在原子指令或最小32位字长可用以防止中断旋转时,它具有信息。如果您有这些保证,就不需要验证代码
不过,要回答这个问题,在必须拆分读/写操作的系统上,您的代码是不安全的。假设您在“do”部分正确读取了值,但在“while”部分检查期间该值被拆分。此外,在极端情况下,这是一个无限循环。为了完全安全,您需要重试计数和错误条件来防止这种情况。循环的情况肯定是极端的,但我希望它只是以防万一。这当然会延长运行时间
让我们举一个失败的例子——在一台一次读取8位值的机器上使用16位数字,以便更容易理解:
另一种失败的情况是,*var恰好以与代码运行相同的频率更改,这可能导致在每次验证失败时出现无限循环。或者,即使它最终爆发了,这也将是一个很难跟踪的性能缺陷。很可能没有任何一种可移植的解决方案来解决这个问题,尤其是因为很多纯C平台都是纯C的,并且使用一次性编译器,也就是说,没有像gcc或clang这样符合主流和现代标准的。因此,如果你真正的目标是根深蒂固的C语言,那么它完全是特定于平台的,不可移植的——以至于“C99”支持已经失败了。对于可移植C代码,您所能期望的最好的是ANSIC支持——指的是ANSI发布的第一个非草案C标准。不幸的是,这仍然是主要供应商可以侥幸逃脱的共同点。我的意思是:Zilog以某种方式逃脱了惩罚,即使他们现在只是Littelfuse的一个部门,以前是Littelfuse收购的IXYS半导体的一个部门 例如,以下是一些编译器,其中只有一种特定于平台的方法:
- Zilog eZ8使用“最近”的Zilog C编译器(任何20年或更短的版本都可以):8位值读修改写是原子的。编译器生成与单词对齐的单词指令(如
、LDWX
、INCW
)的16位操作也是原子操作。如果读-修改-写操作符合3条或更少的指令,则应使用DECW
asm(“\tATM”)代码>。否则,您需要禁用中断:
asm(“\tPUSHF\n\tDI”)代码>,然后重新启用它们:
asm(“\tPOPF”)代码>
- Zilog ZNEO是一个具有32位寄存器的16位平台,对寄存器的读-修改-写访问是原子的,但通常通过寄存器进行内存读-修改-写往返,并接受3条指令-因此使用
预先结束R-M-W操作asm(“\tATM”)
- Zilog Z80和eZ80需要将代码包装在
和asm(“\tDI”)
中,尽管这仅在知道代码运行时总是启用中断时有效。如果它们可能未启用,则会出现问题,因为Z80不允许读取asm(“\tEI”)
-中断启用触发器的状态。因此,您需要将其状态的“阴影”保存在某个位置,并使用该值有条件地启用中断。不幸的是,eZ80没有提供允许访问IFF1
(eZ80使用IEF1
术语而不是IEFn
)的中断控制器寄存器,因此这种架构监督从古老的Z80延续到了“现代”Z80IFFn
MYLIB\u BEGIN\u ATOMIC(vector)
和MYLIB\u END\u ATOMIC(vector)
,这些宏将用于包装需要访问给定中断向量的原子代码(或者如果涉及所有中断向量,则为-1
)。当然,将MYLIB
替换为特定于库的“名称空间”前缀
在“现代”Zilog平台上启用特定于平台的优化,例如ATM
vsDI