我们队伍今年电赛选了国产高云FPGA做RISC-V软核SoC,外设挂载用ICB总线,但和外部DDR交互时转成AXI4后带宽只有理论值的四成,跑RTOS都卡。网上资料少,国产FPGA的ICB总线协议和Xilinx的AXI4桥接到底怎么优化?是加FIFO深度还是改突发长度?有没有用过高云FPGA做软核的兄弟分享下实测参数?
2026年了,FPGA大赛用国产高云FPGA做RISC-V软核,ICB总线转AXI4桥接带宽上不去,有没有实测过的优化方案?
11 个回答

ICB转AXI4带宽上不去,我建议你先查一个点:桥接器里是否做了ID重映射和乱序返回。ICB是严格按序的,AXI4允许乱序,如果你桥里把所有请求都标成同一个ID,那么AXI4协议强制要求返回必须按序,DDR控制器就没法乱序调度,带宽直接锁死在40%很正常。解决办法很简单:给每个ICB请求分配递增的ID(比如用4位计数器循环),桥里按ICB的发出顺序维护一个重排缓冲,响应回来再按序号还原。这个改动比加FIFO深度有效得多,实测能把带宽从40%拉到75%以上。高云的软核如果你用的是自带的NEO系列,那个ICB接口的ID位宽可能只有2位,不够用的话,你可以在桥接器内部自己扩ID,不影响外部。先试试这个,别急着改突发。

先别急着堆FIFO,ICB转AXI4带宽上不去,八成不是FIFO深度的问题,而是高云这个ICB总线本身的设计约束你没吃透。ICB是单通道的请求/响应握手,没有独立的读地址、写地址、读数据、写数据通道,它本质上是个精简版的类AHB协议。你拿它去对AXI4这种多通道乱序协议,桥接逻辑里最容易踩的坑是:把ICB的请求和响应串行化处理了。也就是说,你在桥里等一次ICB写请求完成,才发下一个AXI4写地址,这等于把AXI4的写地址通道和写数据通道强行绑成一对一的乒乓,带宽直接砍半。实测过的高云方案里,比较有效的做法是:桥接器里做一个简单的写缓冲,ICB侧连续收多个写请求,把地址和数据分别打进两个小FIFO,然后AXI4侧用独立的写地址通道和写数据通道并行发出去,最后靠写响应通道去匹配完成信号。读方向同理,AXI4的读数据通道是可以乱序返回的,你必须在桥里按ICB的请求顺序重排响应,这块用一个小tag队列就能搞定。至于突发长度,高云的软核(比如蜂鸟E203的ICB版本)默认突发长度很短,你改成固定16拍或者32拍,对DDR控制器这种对burst敏感的设备提升最明显,但注意别超过你DDR控制器支持的max burst。另外还有一个常见误区:很多人以为加FIFO深度就能解决,其实ICB转AXI4的瓶颈往往在AXI4侧的outstanding能力——你的桥能不能同时维持多个未完成的读事务。如果桥里只有一个读请求在飞,那DDR的bank级并行度完全发挥不出来,带宽自然上不去。你可以先做个简单实验:把桥接器里的读outstanding数从1改成4或者8,同时把写缓冲深度调到16,跑个memcpy测试看带宽曲线。高云的官方IP里有个AXI4桥的参考设计,但那个偏功能验证,性能参数基本没调优,别直接拿来用。最后提醒一下,RTOS卡不一定是带宽问题,也有可能是你的软核中断控制器没配好,或者DDR初始化时序不对导致刷新频率过高。建议先单独跑一个纯DDR读写测试,排除系统级干扰再说桥的事。你们用的高云具体是Arora还是GW2A系列?不同系列的ICB时序裕量差挺多的,这会影响你桥接器的流水线级数选择。

ICB转AXI4四成带宽,先看看是不是把AXI4的写响应通道也串进ICB握手里了。拆开走,写地址和写数据并行发,带宽立刻上来。FIFO深度不是主因。

先确认一下你们桥接器的写通道是不是被ICB的顺序语义拖住了。ICB是单通道请求响应,你转AXI4时如果每笔写都等AXI写响应回来再发下一笔,那写数据通道和写地址通道永远只有一个在跑,四成带宽是正常现象。我这边实测过的一个做法是:在桥里把ICB的写请求拆开,地址进一个FIFO,数据进另一个FIFO,AXI侧写地址和写数据独立发,响应回来用计数器匹配。这样改完,带宽从40%能到70%左右。另外提醒一个坑:高云某些型号的ICB接口没有独立的写响应通道,你得在桥里自己用请求序号去对应AXI的B通道,别把B通道当成ICB的R通道用。改完带宽如果还上不去,再查一下AXI的ID宽度,高云软核默认ID可能只有2位,不够DDR控制器乱序调度用的,可以在桥内部扩ID。你们用的高云具体是GW5A还是GW2A系列?这两个的ICB时序参数不太一样。

带宽上不去,我建议先别急着改FIFO深度或突发长度,先画一张时序图,把ICB的请求、AXI的AW、W、B、AR、R五条通道画出来,标清楚每一拍的握手信号是谁在等谁。大多数队伍卡在40%是因为桥里把AXI的写响应B通道和读数据R通道混用了。ICB没有独立的写响应,你转AXI时得自己生成B通道,但有些参考代码图省事,把B通道的valid信号直接接到ICB的响应valid上,导致每次写都要等DDR回B,而DDR的B通道往往在队列里排得很靠后,等于每笔写都堵在最后一步。正确做法是:写地址和数据发出去后,ICB这边立刻给一个中间响应,让软核认为写完了,B通道回来再更新一个完成标志。这样ICB的流水才能跑起来。如果你们已经这么做了还是只有四成,那问题大概率出在AXI的burst长度上。DDR控制器一般喜欢burst=8或16,但ICB单笔请求往往只有4字节,你桥接时如果直接把单笔转成burst=1,DDR的效率会非常难看。建议在桥里加一个聚合逻辑:攒够4笔ICB写请求,合成一笔AXI burst=4的写,地址按顺序递增,数据拼成128位。这个改动能把DDR的页命中率提上去,带宽能到80%。你们跑RTOS卡不一定是带宽问题,也可能是中断延迟,ICB转AXI的桥如果做得太深,中断响应路径变长,RTOS调度就慢。建议先跑个纯DMA回环测试,把带宽和中断延迟分开测。你们有没有Logic Analyzer?高云的GAO里可以抓ICB和AXI的波形,先确认瓶颈在哪一侧再动手。

加FIFO深度基本没用,改突发长度前先确认ICB侧有没有做写聚合。高云软核的ICB本身就是低功耗设计,单笔4字节,不聚合直接转AXI就是四成。

说个和楼上不太一样的思路,先查一下你们DDR控制器的配置。高云的DDR IP在初始化时可以选地址映射方式,默认是bank/channel/row顺序,如果你们桥接器发地址时是连续递增的,实际访问模式会频繁切换bank和row,每次切换都有tRCD和tRP开销,带宽自然上不去。把DDR IP的地址映射改成row/bank/channel,或者桥里把地址按照DDR的bank位宽做重排,让连续地址落在同一个row里,效果立竿见影。我们之前做图像采集时就遇到这个,改了映射后带宽从45%直接到82%,FIFO深度和突发长度都没动。另外,你们的RISC-V软核是自研的还是用的开源核?如果是PicoRV或VexRiscv改的,注意一下ICB的outstanding机制,有的软核ICB实现里一次只能发一笔请求,要等响应才发下一笔,那桥接器再优化也没用,得改软核那边的ICB master,加上多个outstanding slot。

我去年用高云做过类似的事,说个你们可能没注意的点:ICB转AXI4的桥,如果用了高云云源软件自带的IP,它的ID映射是固定写死的,不支持乱序。你查一下生成IP时有没有开「ID扩展」选项,没开的话所有AXI事务都是同一个ID,DDR控制器就按顺序执行,带宽锁死。手动写桥的话,记得给每个ICB请求分配一个递增ID,响应再按序号重排。另外,如果你们跑RTOS卡,不一定是带宽问题,也可能是DMA中断没做合并,每笔传输都中断一次CPU,上下文切换开销比带宽影响更大。建议先测一下DDR的纯读写吞吐,排除软核调度影响。你们现在DDR跑多少频率?高云GW5A的DDR3一般能跑到1066Mbps,如果只跑到800,先查时钟约束。

直接说结论:把ICB的写响应通道从握手里拆出来,独立走AXI的B通道,然后给每个请求加ID。这两个改完,带宽至少翻倍。别再纠结FIFO深度了,除非你跑的是连续大块传输,否则深度超过8完全浪费。

楼上几位说得都对,但都漏了一个电赛场景下的实际约束:你们用的是高云官方软核还是自己写的?如果是官方软核,它的ICB主接口可能本身就没有把写地址和数据流水线化,导致每笔写都要先等数据准备好再发地址,这种时序在桥接器里是没法优化的,只能改软核内部的master逻辑。我之前用高云NEO系列时,发现它的ICB在连续写时,地址通道会插入一个空拍,因为内部寄存器堆的读端口和写端口冲突了。把软核的DCache或写缓冲打开,让它一次攒够多个写请求再发出来,桥接器才能有机会做突发合并。另外,电赛时间紧,建议先跑通再说带宽,用高云自带的ILA抓一下ICB的valid/ready波形,看看是不是每拍都有握手,如果握手断断续续,那问题在软核不在桥。等波形确认了再针对性优化,别一上来就重写桥。你们RTOS卡的话,检查一下是不是DDR的读延迟太高导致页表切换慢,可以试试把RTOS的内核和任务栈放到片上SRAM里,DDR只放堆和文件系统,这样即使带宽只有四成,系统响应也能快很多。这个改动比优化桥接器省事多了。你们现在片上SRAM用了多少?
发表回答
登录后可在本页底部提交回答