从易失性指针转储硬件寄存器

时间:2012-01-13 22:07:59

标签: c arm

假设我有一个映射到硬件寄存器集的结构,可以随时更改。

如,

typedef struct
{
    int  register1;
    char register2;
    ... (varying sizes, etc) ...
    int  registerX;
} registers_t;

我将regs定义为指向

基础的易失性指针

如,

#define regs (* (volatile registers_t *) ADDR_OF_REGS)

我正在尝试在特定时间转储reg并将其保存到存储寄存器历史记录的数组中。

如,

registers_t register_history[5];

据我所知,memcpy不能/不允许将volatile *转换为const *,因为它是未定义的行为。

例如,我正在尝试做以下事情:

memcpy(&register_history[0], regs, sizeof(registers_t));

有没有办法将寄存器复制到存储器而无需明确地去除和保存每个寄存器?

感谢您的帮助。

修改

由于我在发布之后8小时没有足够的声誉回答我的问题,问题,我现在就在这里发布答案:

因为我知道在我尝试捕获数据时寄存器不会改变,所以我可以将ADDR_OF_REGS转换为void *并使用memcpy。

如,

memcpy(&register_history[0], (void *)ADDR_OF_REGS, sizeof(registers_t));

1 个答案:

答案 0 :(得分:0)

在编译域中使用结构是有风险的业务。指向内存/寄存器等是一个“编译域”。

第二,memcpy只是按顺序读取寄存器并按顺序复制它们,尝试用结构和memcpy来做这件事是没有魔力的,你不能自己做。例如,如果它们是32位寄存器并且对齐,则可以比memcpy做得更好....只需自己动手。

复制8个32位寄存器,例如:

.globl myregcopy
myregcopy:
  push {r4,r5}
  ldmia r0!,{r2-r5}
  stmia r1!,{r2-r5}
  ldmia r0!,{r2-r5}
  stmia r1!,{r2-r5}
  pop {r4,r5}
  bx lr

调用它
myregcopy(base_add_of_registers,base_add_of_destination_ram);
memcpy将齿轮从字节转换为半字到单词然后巡航经常使用每个指令四个字然后在停止之前向下移回到半字和字节(根据需要,但检查代码在那里)所以你将执行memcpy而不会必须处理这些编译器问题。

如果您的内核具有64位总线,您必须向硬件人员验证,四字ldm或stm或ldrd / strd可以/将导致64位转换而不是32位事务。如果寄存器硬件没有声明寄存器可以成对访问64位事务,则可能只能解码两个寄存器中的一个,并且总线上有32位垃圾。所以你需要知道这是一个32位总线或64位总线的核心,如果I / O硬件或你正在捕获的任何东西,正确处理事务。如果它没有将代码改为这样:

.globl wordcopy
wordcopy:
  ldr r3,[r0],#4
  str r3,[r0],#4
  subs r2,r2,#1
  bne wordcopy
  bx lr

调用
wordcopy(regbase,destmembase,numregs);

不一定比memcpy更快,可能更快,相同或稍慢,如果你必须使用这个功能,因为你不能处理针对32位寄存器的64位寄存器读取,那么你不能使用mempcy所以没有速度比较,这很好。

无论您对寄存器不会改变的假设仍然负责。这也是一个冒险的假设,因为你不知道这个副本要花多长时间,除非你采取一些额外的措施。即使这样,复制时间也会有所不同。