第四章 存储控制器顶层架构设计
存储控制器的顶层架构,说白了就是决定怎么把各个功能模块拼起来。我做了这么多年芯片设计,发现很多新手容易一上来就写代码,结果写到一半发现接口对不上、时钟域乱套,最后只能推倒重来。嗯,这节课我们就聊聊顶层架构该怎么搭。
4.1 控制器模块划分
我个人习惯把存储控制器分成三个层次:PHY接口层、命令调度层、数据通路层。这三层各司其职,互不干扰。
4.1.1 PHY接口层
PHY接口层是离物理层最近的一层。它负责处理DDR PHY的初始化、训练、以及时序校准。我在项目中遇到过一个问题:PHY的延迟校准没做好,导致数据采样点偏移,跑起来偶尔出错。后来花了整整两天才定位到问题。
这一层主要包含:
- PHY初始化状态机
- 延迟锁定环(DLL)控制
- 写数据输出和读数据采样
- ODT(片上端接)控制
4.1.2 命令调度层
命令调度层是存储控制器的「大脑」。它接收来自总线接口的请求,然后决定先执行哪个命令。你想想看,如果同时来了读和写请求,先处理哪个?这里就有讲究了。
我一般把命令调度层分成:
- 命令队列(Command Queue)
- 仲裁器(Arbiter)
- 刷新控制器(Refresh Controller)
- 时序参数检查器(Timing Checker)
仲裁策略我建议用优先级+轮询的方式。为什么?因为纯优先级会导致低优先级请求饿死,纯轮询又无法保证紧急请求的响应。折中一下,效果最好。
4.1.3 数据通路层
数据通路层负责数据的搬移和缓冲。说白了就是数据从总线到DDR颗粒之间的「高速公路」。
这一层的关键模块:
- 写数据缓冲(Write Data Buffer)
- 读数据缓冲(Read Data Buffer)
- ECC校验模块(如果支持ECC)
- 数据掩码处理(Data Mask)
4.2 AXI/AHB总线接口设计
总线接口是存储控制器和SoC其他模块通信的桥梁。现在主流的总线协议是AXI和AHB。我个人更推荐AXI,因为它支持乱序传输和突发传输,性能更好。
AXI接口的关键信号:
| 信号组 | 方向 | 说明 |
|---|---|---|
| AW通道 | Master→Slave | 写地址通道 |
| W通道 | Master→Slave | 写数据通道 |
| B通道 | Slave→Master | 写响应通道 |
| AR通道 | Master→Slave | 读地址通道 |
| R通道 | Slave→Master | 读数据通道 |
设计AXI接口时,我最常踩的坑是握手信号的时序。AXI的VALID和READY信号必须满足一定的依赖关系,否则会死锁。我曾经在一个项目中,因为READY信号拉高的时机不对,导致总线卡死,整个系统都跑不动。
下面是一个简单的AXI写地址通道的Verilog代码示例:
// AXI写地址通道示例
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
aw_ready <= 1'b0;
aw_addr_reg <= 32'b0;
end else begin
// 当VALID有效且READY为高时,握手成功
if (aw_valid && aw_ready) begin
aw_addr_reg <= aw_addr;
aw_ready <= 1'b0; // 拉低READY,等待下一个请求
end else begin
aw_ready <= 1'b1; // 准备好接收地址
end
end
end
4.3 时钟域与复位策略
时钟域和复位策略,是存储控制器设计中最容易出问题的地方。我见过太多因为时钟域没处理好导致的亚稳态问题。
4.3.1 时钟域划分
存储控制器通常有多个时钟域:
- 总线时钟域(比如200MHz的AXI时钟)
- 控制器核心时钟域(比如400MHz的DDR时钟)
- PHY时钟域(比如800MHz的DDR PHY时钟)
不同时钟域之间传输数据,必须用异步FIFO或者双触发器同步。我习惯用异步FIFO来处理大批量数据的跨时钟域传输,用双触发器来处理控制信号的跨时钟域传输。
4.3.2 复位策略
复位策略有两种:同步复位和异步复位。我个人更推荐异步复位、同步释放的方式。为什么?因为异步复位可以保证复位信号立即生效,而同步释放可以避免复位释放时的亚稳态问题。
下面是一个异步复位、同步释放的Verilog实现:
// 异步复位、同步释放
reg rst_sync1, rst_sync2;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
rst_sync1 <= 1'b0;
rst_sync2 <= 1'b0;
end else begin
rst_sync1 <= 1'b1;
rst_sync2 <= rst_sync1;
end
end
// 使用rst_sync2作为内部复位信号
always @(posedge clk or negedge rst_sync2) begin
if (!rst_sync2) begin
// 复位逻辑
end else begin
// 正常工作逻辑
end
end
4.4 架构图展示
下面我用一张SVG图来展示存储控制器的顶层架构。这张图把三个层次、总线接口、时钟域和复位策略都画出来了。
这张图里,我特意把时钟域和复位域的边界标出来了。你想想看,如果数据从总线接口直接穿到PHY接口层,中间没有经过同步处理,那亚稳态问题就来了。所以每一层之间都要做跨时钟域处理。
好了,这节课的内容就到这里。存储控制器的顶层架构,说白了就是三个层次加总线接口,再加上时钟域和复位的处理。把这些想清楚了,后面的RTL设计就水到渠成了。