【发布时间】:2017-09-09 01:04:50
【问题描述】:
我在 ARMv7 平台上工作,遇到了寄存器访问问题。 设备模块中的寄存器对访问有很强的WORD要求:
typedef unsigned char u8;
struct reg {
u8 byte0; u8 byte1; u8 byte2; u8 byte3;
};
当尝试这样的c代码时:reg.byte0 = 0x3,通常gcc会生成类似LDRB r1, [r0]的汇编代码,这个字节操作会导致我平台的未定义行为。
它有一个选项,以便 gcc 将生成代码“读取 reg,掩码 byte0”,然后生成一个双字“LDR r1,[r0]”而不是“LDRB”操作码?
更新:我想访问的目的地是 SOC 上的设备寄存器。它有 4 个字段,我们使用一个表示该寄存器的结构。访问byte0 字段如reg.byte0 = 3 通常会生成字节访问汇编代码。我想知道这种c 代码reg.byte0=3 是否可以组装成字访问(32 位,LDR)代码。
真的很抱歉我的英语不好!
更新:该示例只是对现实世界的简化。并且volatile 和内存屏障 也用于linux 驱动程序。只是忘记添加示例。这是我正在研究的ARM11。
1) 似乎memcpy 对我不好,因为不同的寄存器有不同的字段,我不能写所有的访问内联函数
2) 使用union 似乎很有效,我会在完成测试时更新结果。
UPDATE2:只需测试union,它仍然无法在我的平台上运行。
我认为更好的方法是使用显式字访问并且不要混淆编译器。
UPDATE3:似乎其他人发布了完全相同的问题,并且已经解决。 Force GCC to access structs with words
谢谢你们!
【问题讨论】:
-
什么是
u8?使用标准的固定宽度类型。而LDR使用一个字(即 32 位)访问。下降将是 64 位访问,即LDRD。不清楚你的问题是什么。如果您想要 32 位访问,请使用 32 位变量。对于 64 位访问,请使用 64 位整数类型。 -
抱歉声明不清楚:我的意思是 word 访问(32 位),
u8代表unsigned char。 -
我相信如果你希望它只作为一个单词被访问,你需要将它声明为
volatile int(或者其他一些类似单词的类型,可能是无符号的)。然后,您可以使用辅助函数来加载/存储字节。 -
在 x86_64 上,如果您删除
volatile int x; struct A { char a,b,c,d; }; void f(){ union { int i; struct A a; } e; e.i=x; e.a.b=3; x=e.i; }中的volatile,差异会非常明显。使用 -O3 进行编译时,将提供不带 volatile 的字节访问和带 volatile 的字访问。 -
如果有可用的标准类型,请不要使用自制类型!这就是
stdint.h的用途!请注意,((un)signed) char通常不保证为 8 位宽。