今年FPGA大赛我们团队选了国产高云FPGA做AI加速器,但发现AXI-Lite寄存器配置接口和DMA搬运之间配合不好,CPU配置寄存器的时候DMA就停了,整体吞吐率上不去。评委说我们的设计瓶颈在控制通路而不是计算通路。想请教各位,寄存器配置和DMA搬运到底怎么协同设计?是用乒乓寄存器还是双缓冲?中断和轮询怎么选?有没有具体的架构参考?
2026年了,FPGA大赛用国产高云FPGA做AI加速,AXI-Lite寄存器配置和DMA搬运怎么协同设计才能不成为性能瓶颈?
4 个回答

先别急着上乒乓寄存器,把问题拆开看:AXI-Lite是配置通路,DMA是数据通路,两者物理上本来就不该互相阻塞。你们现在CPU配寄存器时DMA停了,大概率是DMA描述符里的地址或长度直接依赖配置寄存器更新,导致CPU写AXI-Lite时DMA在等。常见做法是给配置寄存器加影子副本,CPU先写影子区,写完一个控制位后由硬件一次性锁存到工作寄存器,DMA只读工作区,这样配置过程完全不打断搬运。如果高云IP里没有现成影子寄存器,自己用两级触发器在AXI-Lite写通道后面串一下也行,关键是让DMA永远看不到半更新的配置。先把这个做出来,中断和轮询后面再说。

既然评委直接点名控制通路是瓶颈,我建议你把配置流程和搬运流程彻底并行化,而不是只加个缓冲。我做过类似的高云方案,给你一条主线:先用描述符链把DMA做成自驱模式,CPU只负责往链尾追加描述符,DMA搬完当前段自动取下一条,这样CPU配置一次后续完全不用管。然后配置寄存器走影子寄存器+软件预写机制,CPU提前把下一轮算子的系数、偏移、量化参数全部写到影子区,等当前描述符搬完、DMA进入链尾空闲时,硬件自动把影子区一次性锁存到工作寄存器,同时触发下一段搬运。这样配置和搬运在时间上完全重叠,CPU写AXI-Lite的延迟被隐藏,DMA永远不会因为等配置而停。中断这块,别每个描述符都中断一次,用聚合中断:DMA搬完一整轮(比如8个描述符)才拉一次中断,CPU在中断里只做两件事——补描述符和预写下一轮影子寄存器。轮询更简单,但高云的中断控制器一般支持边沿触发,聚合后开销很小,我建议用中断。乒乓缓冲在这个架构里其实已经内嵌了,描述符链天然支持双缓冲,你只需要保证描述符池深度大于2,比如4个或8个,就能让CPU预写和DMA搬运错开。工程上容易踩的坑是:影子寄存器锁存时机没对齐描述符边界,导致搬运中途配置变了,所以一定要在描述符链的空闲状态(即DMA读完最后一段且还没取下一段)时锁存,这个时序可以用高云的时序约束或逻辑分析仪抓一下。最后说轮询,除非你的CPU非常闲且中断延迟不可控,否则不建议,因为轮询会让CPU空转,反而增加功耗和延迟。你先按这个思路改,重点抓影子锁存时机和描述符链深度,吞吐率应该能明显上来。

换个角度想,你这个问题其实和PCIE驱动里DMA和MMIO的协同很像,核心原则就是让配置通路永远不要出现在数据通路的临界路径上。高云FPGA的AXI-Lite带宽本来就有限,如果CPU每次配寄存器都要等DMA停,那计算阵列再快也没用。我建议你做一个更激进的架构:把配置分成静态和动态两类。静态配置(比如算子类型、数据位宽、量化模式)只在启动时写一次,用普通AXI-Lite寄存器就行;动态配置(比如每轮迭代的系数、偏移量)走一个独立的配置FIFO,CPU往FIFO里写,DMA侧有一个小状态机在描述符边界自动从FIFO读取并更新影子寄存器。这样CPU写配置的动作变成纯粹的写FIFO,完全不和DMA互锁,吞吐率瓶颈就转移到FIFO深度和DMA描述符预取深度。风险点是高云的低端型号可能没有现成配置FIFO IP,需要自己用BRAM搭,但逻辑不复杂。另外,我见过有团队用轮询反而比中断好,因为高云的中断响应有固定几十个周期的延迟,而轮询如果放在主循环里且CPU任务很轻,延迟反而可控。你最好先测一下你们CPU中断响应时间,如果超过100个周期,那聚合中断也救不回来,不如改成轮询+描述符链深度翻倍。最后问一句,你们高云用的是GW2A还是GW5A?不同系列的DMA控制器对描述符链的支持深度不一样,这会影响你影子寄存器的设计。

其实你这个问题,往深了说不是寄存器怎么配、DMA怎么搬的问题,而是你愿不愿意让控制通路和数据通路彻底各过各的日子。我之前在做高云Arora系列的时候踩过类似的坑,当时也是CPU一写配置DMA就卡住,后来发现根本原因是我把配置寄存器和DMA描述符的基地址绑在了一个更新流程里,等于CPU每次写配置都隐性地改了DMA的搬运参数,DMA当然要等。后来我干脆把配置分成两套:一套是启动前写死的静态参数,比如数据位宽、算子模式,这些直接写普通寄存器,写完整个加速器才使能;另一套是每轮迭代才变的动态系数,这些不走寄存器了,走一个专用的配置FIFO,CPU往FIFO里扔数据,DMA侧有个小状态机在描述符边界处自动从FIFO取数更新影子寄存器。这样CPU写配置的动作变成了纯粹的写FIFO,跟DMA数据搬运完全解耦,DMA永远等不到配置。这个做法的风险是如果你用的是高云的低端型号,可能没有现成的FIFO IP,得自己用Block RAM拼一个,但逻辑不复杂。还有个容易被忽略的点:影子寄存器更新之后,DMA取用新配置的时机要设计好,我建议放在描述符链的链尾空闲时刻,而不是当前描述符搬完的瞬间,这样能多留出几个周期的余量,防止配置更新和DMA启动撞在同一拍上。你们现在如果只是想让评委看到控制通路不阻塞,这个方案基本够了。你们用的是高云哪个系列?Arora还是GW2A?不同系列的DMA控制器对描述符链的支持深度不一样,这会影响你影子寄存器锁存时机的实现方式。
发表回答
登录后可在本页底部提交回答