"主题"中讨论的其他器件:C2000-CGT、 C2000WARE
工具/软件:
您好:
根据手册、C2000-CGT 中的 C 编译器不应更改易失性访问的大小( spru514y.pdf、J.3.10限定符中对此进行了说明)、但似乎有一种临界情况、此处实际上并非如此、其中编译器将32位易失性读取拆分为两次16位读取。
此问题的示例、使用"cl2000.exe -c99 -Ooff -v28 -k"编译:
volatile unsigned long value; unsigned long foo_0(unsigned long arg) { return value & arg; } unsigned long foo_1(unsigned long arg) { return value | arg; } unsigned long foo_2(unsigned long arg) { return value ^ arg; }
在 Windows 下使用22.6.0.LTS、22.6.1.LTS 和22.6.2.LTS 进行编译时、上述示例编译为以下汇编指令:
_foo_0: ADDB SP,#2 ; [CPU_ARAU] MOVL *-SP[2],ACC ; [CPU_ALU] |3| MOVW DP,#_value ; [CPU_ARAU] AND AL,@_value ; [CPU_ALU] |3| AND AH,@$BLOCKED(_value)+1 ; [CPU_ALU] |3| SUBB SP,#2 ; [CPU_ARAU] LRETR ; [CPU_ALU] _foo_1: ADDB SP,#2 ; [CPU_ARAU] MOVL *-SP[2],ACC ; [CPU_ALU] |4| MOVW DP,#_value ; [CPU_ARAU] OR AL,@_value ; [CPU_ALU] |4| OR AH,@$BLOCKED(_value)+1 ; [CPU_ALU] |4| SUBB SP,#2 ; [CPU_ARAU] LRETR ; [CPU_ALU] _foo_2: ADDB SP,#2 ; [CPU_ARAU] MOVL *-SP[2],ACC ; [CPU_ALU] |5| MOVW DP,#_value ; [CPU_ARAU] XOR AL,@_value ; [CPU_ALU] |5| XOR AH,@$BLOCKED(_value)+1 ; [CPU_ALU] |5| SUBB SP,#2 ; [CPU_ARAU] LRETR ; [CPU_ALU]
无论选择的优化级别如何、这个问题都存在、即使使用"-Ooff"完全关闭优化、并且当程序从仅支持32位访问的外设读取数据时、这也可能会导致问题。 或者、对于 具有中断的环境中的线程安全、依赖单个易失性32位读取/写入作为原子形式( 据我所知、这两种都是 C2000的预期方法、因为它们也在 C2000Ware 示例和驱动程序中使用)。
针对此问题的可能权变措施似乎是使用 __byte_peripheral_32内在函数读取32位数据、这似乎阻止编译器拆分访问、但它要求用户找到与此问题相关的源代码中的所有位置。
unsigned long foo_fixed(unsigned long arg) { return __byte_peripheral_32(&value) & arg; }
然后编译到:
_foo_fixed: ADDB SP,#2 ; [CPU_ARAU] MOVL *-SP[2],ACC ; [CPU_ALU] |6| MOVL XAR4,#_value ; [CPU_ARAU] |6| MOVL ACC,*+XAR4[0] ; [CPU_ALU] |6| AND AL,*-SP[2] ; [CPU_ALU] |6| AND AH,*-SP[1] ; [CPU_ALU] |6| SUBB SP,#2 ; [CPU_ARAU] LRETR ; [CPU_ALU]
上述例子是我所知唯一涉及这一问题的例子。 如果我尝试对位域或不同运算符进行其他访问、编译器会一次正确加载整个32位字、而不会将它们拆分。