我正在开发一个在Xilinx的QEMU版本下运行的程序。这个问题被标记为zynq,但我实际上是针对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
,在查看{{1}的值时,我可以在Xilinx SDK调试器(基于gdb)中看到这一点。 }}。我还可以看到,逐步通过程序集,寄存器reg
加载了正确的地址。
执行到达时:
r3
反汇编有:
regdata = *reg;
我在ldr r3, [r3]
获得0x00000000
。如果我使用内存视图,我可以看到r3
的值为0xFF000000
。如果我查看变量视图,我可以看到0x00000114
具有相同的值(*reg
)。如果我走到掩盖本地副本然后写回的行,我最终会得到指令:
0x00000114
单步过去,我看到str r2, [r3] ; r3 has been reloaded with the register address,
; and r2 contains the read-modify-write data.
的值(虽然不是正确的值)应该已经写好,但是值实际上并没有改变(通过内存或变量视图)。在这些视图中,我可以手动更改值并正确写入。
我不知道Zynq MP的总线架构在这个QEMU版本中的仿真程度有多彻底,但硅片有独立的内存端口用于调试访问和处理器访问,并且不通过CPU访问内存,因此有可能以不同的方式映射事物。但是,Xilinx演示代码可以正确执行相同的操作。
所以,我已尝试过的摘要:
我不知道还应该尝试什么,而且我基本上都难过了。似乎QEMU,至少通过gdb接口,正确模拟外设寄存器,所以我认为CPU读/写相当简单。我感谢任何帮助,指示,提示等。对我来说,这是很多新事物,包括使用QEMU作为开发平台。