我正在使用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 "然后是dword" LDR r1,[r0]"而不是" LDRB"操作码?
更新:我想访问的目的地是SOC上的设备寄存器。它有4个字段,我们使用表示该寄存器的结构。访问像byte0
这样的reg.byte0 = 3
字段通常会生成字节访问汇编代码。我想知道这种c代码reg.byte0=3
是否可以汇编为字访问(32位,LDR
)代码。
真的很抱歉我的英语很差!
更新:这个例子只是对现实世界的简化。 linux驱动程序中也使用了volatile
和内存屏障。只是忘了添加例子。它是我工作的ARM11。
1)似乎memcpy
对我不好,因为不同的寄存器有各种字段,我不能写所有的access-inline-function
2)使用union
似乎有效,并且在完成测试时我会更新结果。
UPDATE2:只测试union
,它仍无法在我的平台上运行。
我认为更好的方法是使用显式字访问,不要混淆编译器。
UPDATE3:似乎其他人发布完全相同的问题,并且已经解决了。 Force GCC to access structs with words
谢谢你们!
答案 0 :(得分:0)
你可以使用内联汇编:
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
但不能修改汇编指令。