【发布时间】:2021-08-13 19:02:17
【问题描述】:
假设我在 Zynq-7000 SoC 上运行以下 C++ 代码
struct ControlReg
{
uint32_t reset_bit : 1;
};
struct ConfigReg
{
uint32_t even_channel_value : 16;
uint32_t odd_channel_value : 16;
};
struct PeripheralRegs
{
volatile ControlReg control_reg;
volatile uint32_t status_reg_01[2];
volatile uint32_t status_reg_02[2];
volatile ConfigReg config_reg_01[8];
volatile ConfigReg config_reg_02[8];
volatile uint32_t status_reg_03[2];
};
PeripheralRegs *regs;
regs = new (reinterpret_cast<void *>(0x43C20000)) PeripheralRegs;
uint16_t value = 6573;
regs->config_reg_01[0].odd_channel_value = value;
regs->config_reg_01[0].even_channel_value = value;
我在调试器中单步执行了这段代码,我发现config_reg_01[0]
尽管尝试将6573 值写入其中,但仍包含全零。谁能告诉我为什么会发生这种行为?奇怪的是,如果我将一些值写入status_reg_01[0],我会在调试器的“内存监视器”中的适当地址看到这个值。
编辑:
我已经部分找到了这种行为发生的原因。它在某种程度上与代码优化有关。该结论基于以下观察:如果我在 ARM v7 g++ 编译器设置中将代码优化级别从 O2 切换到 O0,问题就会消失。我的第二个观察结果是,如果我使用代码优化级别 O2 并进行了以下修改:
struct ControlReg
{
volatile uint32_t reset_bit : 1;
};
struct ConfigReg
{
volatile uint32_t even_channel_value : 16;
volatile uint32_t odd_channel_value : 16;
};
在优化级别 O0 的情况下会发生相同的正确行为。
谁能向我解释为什么应用于位域项的volatile 关键字对代码优化有如此巨大的影响。
【问题讨论】:
-
似乎硬件阻止您写入 config_reg_01 寄存器。也许还有另一个寄存器可以让你解锁那个寄存器。
-
确保相关时钟已启用。详情请查看芯片参考手册。
-
@doron 你认为这个问题可能是由“PeripheralRegs”结构到内存的错误映射引起的吗?有什么方法可以排除这个假设吗?
-
没有文档,我不知道
标签: c++ memory struct volatile bit-fields