我正在 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 将生成代码“read reg,mask byte0”,然后生成双字“LDR r1,[r0]”而不是“LDRB”操作码?
更新:我想要访问的目的地是 SOC 上的设备寄存器。它有 4 个字段,我们使用一个结构体来表示该寄存器。像 reg.byte0 = 3
这样访问 byte0
字段通常会生成字节访问汇编代码。我想知道这种c代码reg.byte0=3
是否可以汇编成字访问(32位,LDR
)代码。
真的很抱歉我的英语不好!
更新:该示例只是现实世界的简化。 volatile
和内存屏障也用于linux驱动程序。只是忘记添加示例。我正在研究ARM11。
1)似乎memcpy对我来说不太好,因为不同的寄存器有不同的字段,我无法编写所有的access-inline-function
2)使用union
似乎有效,我将在完成测试时更新结果。
更新2:仅测试union
,它仍然无法在我的平台上工作。
我认为更好的方法是使用显式的字访问并且不要混淆编译器。
UPDATE3:似乎其他人发布了完全相同的问题,并且已解决。 Force GCC to access structs with words
谢谢你们!
最佳答案
您可以使用内联汇编:
static inline u8 read_reg_b0(const struct reg *rp) __attribute__((always_inline)) {
struct reg r;
u32 tmp;
__asm__("ldr %0, %1" : "=r" (tmp) : "m" (*rp));
memcpy(&r, &tmp, 4);
return r.b0;
}
static inline void write_reg_b0(struct reg *rp, u8 b0) __attribute__((always_inline)) {
struct reg r;
u32 tmp;
__asm__("ldr %0, %1" : "=r" (tmp) : "m" (*rp));
memcpy(&r, &tmp, 4);
r.b0 = b0;
memcpy(&tmp, &r, 4);
__asm__("str %1, %0" : "=m" (*rp) : "r" (tmp));
}
GCC 将优化掉 memcpy
但无法修改汇编指令。
关于gcc 总是可以生成对寄存器的字访问吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43383271/