4、前端接口层(AXI/SRAM):AXI协议到DDR命令的转换

前端接口层,说白了就是DDR控制器和外部主设备(比如CPU、GPU、DMA)之间的“翻译官”。我个人习惯把这一层叫做“协议适配层”,因为它要干的事情很纯粹——把AXI或者SRAM接口上的读写请求,翻译成DDR控制器内部能理解的命令。

你想想看,AXI协议是burst-based的,一次传输可以发很多笔数据。但DDR颗粒呢?它一次只能读写一个column地址的数据。这中间的粒度差异,就是前端接口层要解决的核心问题。

AXI协议到DDR命令的转换

AXI协议有五个独立的通道:读地址、读数据、写地址、写数据、写响应。DDR控制器内部呢?通常只有一组命令接口(ACTIVATE、READ、WRITE、PRECHARGE等)和一组数据接口。

转换过程大致是这样的:

  • 地址解析:把AXI的burst地址拆解成DDR的Bank、Row、Column三级地址
  • 长度转换:AXI的burst长度(1~256)映射到DDR的BL8/BL16/BL32
  • 属性映射:AXI的QoS、Cache属性、Lock属性等,转换成DDR控制器的优先级和调度策略

核心要点:AXI的地址是连续的线性地址,DDR的地址是三维的(Bank+Row+Column)。转换时要注意地址对齐——如果AXI burst的起始地址没有对齐到DDR的column边界,那就得拆成多个DDR命令。

我在项目中遇到过一个问题:某个SoC的DDR带宽利用率一直上不去,查了半天发现是AXI burst地址没有64B对齐,导致每次DDR访问都要多做一个column切换。嗯,这个坑踩过一次就记住了。

写地址通道与写数据通道的合并

AXI协议里,写地址和写数据是分开的通道。但DDR控制器执行写操作时,必须同时知道“写到哪里”和“写什么数据”。所以前端接口层需要把这两个通道的信息合并起来。

合并策略通常有两种:

  1. 立即合并:写地址到达后,等待对应的写数据到达,然后一起提交给后端调度器
  2. 延迟合并:写地址先进入地址队列,写数据进入数据队列,等到调度时再匹配

我个人更推荐第二种。为什么呢?因为AXI的写数据和写地址可能不是同时到达的——写地址可能早到,写数据可能晚到(或者反过来)。如果采用立即合并,就会阻塞后续的读请求。

经验之谈:我曾经在一个高性能存储控制器项目里,采用了“写地址先入队,写数据后匹配”的策略。地址队列深度设了16,数据队列深度设了32。这样即使写数据延迟到达,也不会阻塞读请求的地址解析。

合并时还要注意一个细节:写数据的字节使能(WSTRB)。DDR的写操作是按字节使能来写的,但AXI的WSTRB可能不是连续的。比如只写第2~5字节,那DDR就得先读后写(Read-Modify-Write)。这个逻辑也要在前端接口层处理好。

读地址与读数据的返回路径

读操作相对简单一些。读地址通道把请求发出去,读数据通道把数据返回。但这里有一个关键点:读数据的返回顺序必须和读地址的发出顺序一致

AXI协议要求读数据通道保持顺序——先发出的读地址,对应的读数据必须先返回。但DDR控制器内部可能有多个Bank并行处理,读数据的返回顺序可能被打乱。所以前端接口层需要做重排序(Reordering)。

重排序的实现方式:

  • 每个读请求分配一个ID(Transaction ID)
  • 读数据返回时,根据ID找到对应的读请求
  • 按照读请求的发出顺序,把数据重新排列后输出

注意:重排序的buffer深度要足够大。如果buffer满了,读数据就无法返回,会造成读通道的stall。我建议buffer深度至少是outstanding交易数的两倍。

Outstanding交易管理

Outstanding交易,说白了就是“发出去但还没回来的请求”。AXI协议允许主设备连续发出多个读/写请求,而不需要等待前一个完成。这个特性对DDR控制器来说,既是机遇也是挑战。

机遇在于:outstanding交易可以隐藏DDR的访问延迟。比如DDR的读延迟是20ns,如果连续发出4个读请求,那么第2~4个请求的延迟就被隐藏了。

挑战在于:outstanding交易太多,会撑爆控制器的内部buffer。而且如果读请求和写请求混在一起,还要处理读写冲突。

我一般这样管理outstanding交易:

参数 建议值 说明
最大outstanding读 8~16 取决于DDR的Bank数量和page命中率
最大outstanding写 4~8 写操作通常不需要太多outstanding
读写混合outstanding 16~32 要考虑读写比例和优先级

我曾经在一个项目里把outstanding读设到了32,结果DDR控制器的内部buffer爆了,导致数据丢失。后来改成16,配合合理的调度策略,性能反而更好了。所以outstanding不是越大越好,要结合硬件资源来权衡。

核心逻辑框架图

下面这张图展示了前端接口层的核心逻辑:AXI请求进来后,经过地址解析、通道合并、outstanding管理,最终转换成DDR命令发送给后端。

AXI请求 地址解析 Bank/Row/Column 通道合并 地址+数据匹配 Outstanding管理 ID分配/重排序 DDR命令 读/写分离 合并后请求 调度就绪

这张图里,AXI请求进来后分两条路:读请求走地址解析,写请求走通道合并。最终都汇聚到outstanding管理模块,统一调度后输出DDR命令。我个人觉得这个架构比较清晰,适合初学者理解。

小技巧:实际项目中,前端接口层通常还会加一个“写合并”模块。如果多个写请求写的是同一个DDR地址,可以把它们合并成一个写命令,减少DDR的访问次数。这个优化在视频处理场景下特别有效。

好了,前端接口层的内容就讲到这里。记住一句话:前端接口层是DDR控制器的“门面”,它做得好不好,直接决定了整个DDR子系统的性能和兼容性


公众号:蓝海资料掘金营,微信deep3321