gpt4 book ai didi

c - 从 volatile 指针转储硬件寄存器

转载 作者:行者123 更新时间:2023-12-04 10:08:46 24 4
gpt4 key购买 nike

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

例如,

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

我将 regs 定义为指向

例如,

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

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

例如,

registers_t register_history[5];

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

例如,我正在尝试执行以下操作:

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

有什么方法可以将寄存器复制到内存而无需显式去抖动和保存每个单独的寄存器?

感谢您的帮助。

编辑:

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

因为我知道在 try catch 数据时寄存器不会更改,所以我可以将 ADDR_OF_REGS 转换为 void * 并使用 memcpy。

例如,

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

最佳答案

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

其次,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 快,可以更快,相同或更慢一点,如果你必须使用这个函数,因为你不能处理 64 位寄存器对 32 位寄存器的读取,那么你不能使用 mempcy,所以没有速度比较,这是最好的。

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

关于c - 从 volatile 指针转储硬件寄存器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8857913/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com