0

我正在开发一个在 Xilinx 的 QEMU 构建下运行的程序。这个问题被标记为,但我实际上是针对 QEMU 中的 Zynq MP,特别是 Cortex-R5。

我的背景是微控制器和 Cortex-M,所以这是一个很大的飞跃,并且有很多我不习惯的特性(MPU、AXI、额外缓存)。我正在编写一个驱动程序,该驱动程序正在访问其中一个硬外设(在低功耗域中)中的外设寄存器。我编写了一个函数,reginsert以简化访问这些寄存器中的位。

void reginsert(uint32_t base, uint32_t offset,
               uint32_t mask, uint32_t data)
{
    uint32_t volatile * reg = (uint32_t volatile *)(base + offset);
    uint32_t regdata;
    /* This section actually happens in a critical section for atomicity, 
     * but I've trimmed that out for brevity */
    regdata = *reg;
    *reg = (regdata & ~mask) | data;
    /* End of critical section */
}

根本不是一个非常令人兴奋的功能。对我来说,这也很简单。

我这样调用函数:

/* Magic number provided by Xilinx, I don't actually plan to keep it as such a
 * magical number, but for now while trying things to debug. */
reginsert(XPAR_PSU_UART_0_BASEADDR, XUARTPS_CR_OFFSET, 0x3C, 0);

附加信息:

#define XPART_PSU_UART_0_BASEADDR 0xFF000000
#define XUARTPS_CR_OFFSET         0x00000000

在逐步执行代码时,我发现该函数正确地计算了寄存器的地址,0xFF000000当查看reg. 我还可以看到,单步执行寄存器r3加载了正确地址的程序集。

当执行达到:

regdata = *reg;

拆解有:

ldr r3, [r3]

我进去0x00000000r3。如果我使用内存视图,我可以看到它0xFF000000的值为0x00000114. 如果我查看变量视图,我可以看到它*reg具有相同的值 ( 0x00000114)。如果我进入屏蔽本地副本的行,然后写回,我最终会得到以下指令:

str r2, [r3]   ; r3 has been reloaded with the register address,
               ; and r2 contains the read-modify-write data.

跳过这一点,我看到0x00000000应该写入的值(尽管不是正确的值),但该值实际上并没有改变(通过内存或变量视图)。在这些视图中的任何一个中,我都可以手动更改值并正确写入。

我不知道在这个 QEMU 版本中对 Zynq MP 的总线架构进行了多么彻底的仿真,但是芯片具有用于调试访问和处理器访问的单独内存端口,并且不通过 CPU 访问内存,所以有一个以不同方式映射事物的可能性。但是,Xilinx 演示代码确实可以适当地执行相同的操作。

所以,总结一下我的尝试:

  1. 验证反汇编应该从寄存器位置加载/存储。
  2. 逐步执行指令以验证 CPU 寄存器是否具有访问外设寄存器的正确值。
  3. 通过调试器直接访问内存和变量。
  4. 使用 Xilinx 代码验证 QEMU 模拟外设。
  5. 检查 MPU 设置(区域设置为非共享且无访问限制)

我不知道我还应该尝试什么,我基本上被难住了。看起来 QEMU,至少通过 gdb 接口,正确地模拟了外围寄存器,所以我认为 CPU 读/写相当简单。我感谢任何帮助、指示、提示等。有很多事情对我来说是新的,包括使用 QEMU 作为开发平台。

4

0 回答 0