3、DDR控制器设计:控制器架构与调度策略

好,咱们今天聊聊DDR控制器。说实话,这是整个存储系统里最核心的模块之一。我当年刚接触DDR设计时,总觉得控制器不就是发发命令嘛,有什么难的?后来被现实狠狠教育了一顿——控制器设计不好,再好的DDR颗粒也白搭。

3.1 控制器架构:调度器、命令队列、数据路径

DDR控制器的架构,说白了就三大块:调度器、命令队列、数据路径。这三者配合得好,DDR带宽才能跑满。

调度器是大脑。它决定下一个该发什么命令。我个人习惯把调度器分成两层:高层调度和底层调度。高层管策略,比如优先级、QoS;底层管时序,比如tRCD、tCL这些参数。

命令队列是缓冲区。DDR颗粒很慢,但CPU很快。命令队列就是用来解耦的。我见过不少新手把队列设计得太浅,结果CPU一忙就丢命令。嗯,这里要注意:队列深度至少得覆盖DDR的延迟,一般16~32个entry比较稳妥。

数据路径是高速公路。数据怎么从DDR颗粒到CPU,中间经过哪些缓冲、哪些纠错,都得设计好。我在项目中遇到过数据路径上时序没对齐,结果读出来的数据全是错的——查了三天才发现是时钟域同步出了问题。

核心要点:调度器决定发什么,命令队列存什么,数据路径传什么。三者缺一不可。

3.2 地址映射与Bank管理

地址映射,听起来高大上,其实就一件事:把CPU发来的地址,翻译成DDR颗粒能懂的地址。DDR颗粒的地址包括:Bank、Row、Column。

为什么要有Bank管理?因为DDR颗粒内部有多个Bank,每个Bank独立工作。你想想看,如果所有请求都打到一个Bank上,那其他Bank就闲着,带宽浪费了。我建议把连续的地址映射到不同的Bank上,这样能提高并行度。

举个例子:

// 地址映射示例
// CPU地址: 0x12345678
// 映射规则: Bank = addr[13:12], Row = addr[31:14], Column = addr[11:0]

bank = (addr >> 12) & 0x3;
row  = (addr >> 14) & 0x3FFFF;
col  = addr & 0xFFF;

我曾经在一个项目里,因为地址映射没做好,导致所有请求都集中在Bank0上。结果DDR带宽利用率只有30%。后来改了映射规则,把Bank位放在地址的高位,利用率直接飙到85%。

小技巧:地址映射时,尽量让Bank位在地址的中间位置。这样既能保证Bank切换频繁,又不会让Row切换太频繁。

3.3 读写调度策略:FCFS与FR-FCFS

调度策略,说白了就是排队规则。最简单的就是FCFS(First Come First Serve),谁先来谁先走。但DDR不是这么玩的——你想想看,如果先来的请求要读Bank0,后来的请求要读Bank1,但Bank0正在预充电,Bank1已经准备好了。这时候先服务谁?

FCFS:按到达顺序服务。公平,但效率低。我刚开始做DDR时就用FCFS,结果带宽利用率不到50%。

FR-FCFS:先服务Row命中的请求,再服务Row未命中的请求。说白了,就是优先服务那些已经打开行的请求。这样能减少预充电和激活的开销。

FR-FCFS的调度逻辑大致如下:

// FR-FCFS调度伪代码
while (1) {
    // 先检查有没有Row命中的请求
    for (每个请求) {
        if (请求的Row == 当前打开的Row) {
            服务该请求;
            break;
        }
    }
    // 如果没有Row命中的请求,再服务最早的请求
    if (没有服务任何请求) {
        服务最早的请求;
    }
}

我在项目中做过对比测试:FCFS的带宽利用率约55%,FR-FCFS能到75%以上。当然,FR-FCFS也有代价——它可能导致某些请求被饿死。比如一直有Row命中的请求,那Row未命中的请求就永远排不上队。

避坑指南:我曾经在一个视频处理芯片里用了纯FR-FCFS,结果某些帧的延迟特别大。后来加了超时机制——如果一个请求等待超过一定时间,就强制服务它。这样既保证了带宽,又控制了延迟。

3.4 实际设计中的权衡

设计DDR控制器,其实就是做权衡。我总结了几点:

  • 带宽 vs 延迟:FR-FCFS带宽高,但延迟可能不稳定。FCFS延迟稳定,但带宽低。
  • 队列深度 vs 面积:队列越深,能缓冲的请求越多,但芯片面积也越大。
  • Bank数量 vs 复杂度:Bank越多,并行度越高,但地址映射和调度逻辑也更复杂。

我个人建议:先根据应用场景确定需求。如果是服务器,带宽优先,用FR-FCFS;如果是手机,延迟敏感,用FCFS加超时机制。

策略 带宽利用率 延迟稳定性 适用场景
FCFS ~55% 延迟敏感应用
FR-FCFS ~75% 带宽敏感应用
FR-FCFS + 超时 ~70% 通用场景

好了,这一章就到这里。下一章咱们聊聊DDR的时序参数,那些tRCD、tCL、tRP到底怎么配。嗯,那才是真正考验功力的地方。

本章总结:DDR控制器设计,核心是调度器、命令队列、数据路径的配合。地址映射要合理,Bank管理要高效。调度策略上,FR-FCFS是主流,但别忘了加超时机制。记住,没有完美的方案,只有适合的方案。