最近在紫光同创的FPGA上移植RISC-V软核,把UART和GPIO外设挂在AXI总线上,结果CPU一访问外设就死机,用ILA抓波形发现地址总线上数据完全对不上。查了手册也没找到具体例子,怀疑是地址译码逻辑或者总线对齐的问题。有没有大佬遇到过类似情况?能不能分享下地址映射和总线互联的排查思路,比如从哪几个方向入手定位问题?
2026年了,FPGA工程师用国产紫光FPGA做RISC-V软核,UART和GPIO挂到AXI总线上老是地址映射错乱,有没有排查套路?
5 个回答

先把外设基地址和RISC-V软核的地址总线位宽对齐这件事单独拎出来查。紫光同创的PDS里,AXI互联IP的地址映射表是独立配置的,很多人习惯在软核里把外设地址定义成32位,但互联IP的地址段掩码是按高位地址做的,比如只用了高4位做译码,那低28位就得全部对齐到0。你可以先用ILA抓AWADDR,对比一下CPU发出的地址和互联IP实际收到的地址,如果低几位被截断或者移位,基本就是位宽不匹配。另外,检查一下软核的AHB-to-AXI桥,有的桥默认会做地址对齐,比如把非对齐访问强制对齐到4字节边界,这会直接导致UART寄存器偏移量错乱。先只挂UART,用最简单的寄存器读写测试,把地址打印出来和ILA对比,一步步缩小范围。你现在用的软核是自研的还是开源的?这个影响挺大的,因为不同核的地址转换逻辑差很多。

个人感觉这类问题八成出在互联IP的地址映射表配置上,而不是软核本身。紫光的AXI互联IP在PDS里配的时候,每个从端口的地址段是独立设置的,它默认的起始地址可能和你在软核里定义的基地址差一个偏移,比如你定义UART基地址0x10000000,但互联里配成0x00000000加一个窗口,那CPU访问0x10000000时,互联会把地址直接透传给从设备,但UART的译码逻辑是按0x00000000来的,自然就对不上。我遇到过类似情况,最后是打开互联IP的地址映射表,把每个从端口的起始地址和大小重新填一遍,并且确保地址段之间没有重叠。另外,RISC-V软核的地址总线如果是64位的,但互联IP配成32位通道,那高位地址会被直接丢弃,也会导致错乱。建议你先把GPIO和UART都从总线上摘掉,用ILA直接抓软核发出的AWADDR,单独看一个地址写进去,确认软核侧地址是干净的,然后再接上互联IP,一级一级排查。你PDS是2023还是2024版本?不同版本互联IP的默认参数有差异,这个也值得确认下。

这条线我建议你按「先验证软核地址源、再验证互联译码、最后验证外设侧对齐」的顺序走,但每一步都有坑。先说软核侧,很多RISC-V软核在SoC集成时,会有一个系统地址映射寄存器组,比如基地址重映射或者MMU的页表转换,如果你没关掉或者没配好,CPU发出的虚拟地址和AXI上的物理地址会差一个固定偏移。紫光的软核例程里一般默认不开MMU,但有些人移植时会把Linux的启动代码搬过来,不小心开了Sv32模式,那地址就全乱了。你ILA抓到的AWADDR和CPU里打印的地址对不上,先确认是不是这个原因,最简单的方法是把软核的bootloader里所有和CSR相关的初始化全注释掉,只留最简单的跳转。再说互联IP,紫光的AXI互联IP在PDS里配的时候,有一个「Address Region」设置,它默认是4K对齐的,如果你的外设地址段小且位置不在4K边界上,互联会把地址做对齐处理,比如把0x10000010对齐到0x10000000,那UART的寄存器偏移就全错了。这个坑我踩过,解决方法是把地址段大小扩大到一个4K页,并且把基地址放在页边界上。最后是外设侧,UART和GPIO的地址译码如果用的是case语句且没做地址掩码,比如只判断高12位,但你把寄存器偏移放在低8位,那高位地址变化时外设也会响应错误。建议你先写一个最简单的测试模块,只挂一个寄存器,地址固定在0x10000000,CPU直接写0x55,ILA抓AWADDR和WSTRB,如果这个都对,再逐步加外设。另外,紫光的PDS里有一个AXI Debugger工具,可以直接在硬件上做读写测试,比你自己写testbench快很多,你可以试试。你现在外设是挂在同一个互联上还是分成了两个从端口?如果共用一个从端口且地址相邻,那互联的默认地址译码优先级也可能出问题。

先别急着怀疑软核,八成是互联IP地址段没配干净。PDS里那个AXI互联的Address Region默认4K对齐,你UART基地址如果低12位不是0,它会把地址整形掉。拿ILA抓AWADDR,对比CPU打印的地址,差在低几位就是对齐问题,直接改基地址到4K边界最省事。

个人感觉这种问题最坑的是软核和互联各自有一套地址理解,两边都看着对,合起来就错。我上次调紫光RISC-V,CPU访问0x20000000的GPIO,ILA抓出来AWADDR是0x20000004,差了4个字节,查半天发现是AHB-to-AXI桥默认做了非对齐访问拆分,把单次写拆成两次对齐写,地址就偏了。你先把软核的CSR初始化全关掉,尤其是MMU和任何重映射寄存器,然后只挂UART一个外设,基地址设成4K对齐,用ILA同时抓AWADDR和ARADDR,跟CPU里打印的地址逐位对比。如果高位错,查互联IP的地址掩码是不是只用了高几位;如果低位错,查桥的对齐逻辑。另外确认下软核地址总线位宽和AXI通道位宽一致,64位核配32位互联会把高位丢掉。你现在软核是自研还是开源的?自研的话还得查下地址译码那级有没有移位。
发表回答
登录后可在本页底部提交回答