SRAM 基础与功耗模型:6T单元结构,读写操作,静态功耗与动态功耗分解
各位同学,今天我们聊聊片上存储的基石——SRAM。说实话,SRAM 这东西,你看着它简单,就六个管子,但里面门道特别多。我做了十几年芯片,每次流片回来,最怕的就是 SRAM 出问题。为什么?因为它占的面积大,功耗占比高,而且一旦出 bug,基本就是全盘重来。
这一节,我们就把 SRAM 的底裤扒干净。从 6T 单元怎么干活,到读写操作到底发生了什么,再到功耗是怎么拆解的。你把这些搞明白了,后面讲低功耗 SRAM 设计,你才能听懂我在说什么。
6T SRAM 单元结构
先看最基本的单元。6T,顾名思义,六个晶体管。两个交叉耦合的反相器,加上两个访问管。我画个图给你看。
核心要点:6T 单元的本质是「两个反相器首尾相接,形成正反馈锁存」。只要不断电,数据就能一直保持。这是 SRAM 和 DRAM 最大的区别——不需要刷新。
你看这个结构。左边反相器输出 Q,右边反相器输出 Q#。Q 和 Q# 永远是反的。M5 和 M6 是访问管,栅极连在一起,叫字线(WL)。源漏分别连位线(BL/BL#)和内部节点。
我个人习惯,在设计 SRAM 宏单元时,会特别关注 M5/M6 的尺寸。为什么?因为访问管太强,写操作容易,但读操作可能破坏数据;访问管太弱,读操作稳定,但写不进去。这是个 trade-off,后面我们会细讲。
读操作:小心别把数据读没了
读操作,说白了就是把存储节点的电压,通过位线传出去。但这里有个坑——读干扰。
读操作的过程是这样的:
- 先把 BL 和 BL# 预充电到 VDD。
- 然后拉高 WL,M5/M6 导通。
- 假设 Q 存的是 0,Q# 存的是 1。那么 BL 会通过 M5 和 M1 放电,BL# 保持高电平。
- 灵敏放大器检测 BL 和 BL# 的电压差,放大输出。
我曾经踩过的坑:有一次设计一个 512Kb 的 SRAM,读操作总是出错。查了三天,发现是 M5 的尺寸偏大,导致读操作时 Q 节点电压被抬升太多,超过了反相器的翻转阈值,数据直接翻掉了。这就是典型的「读破坏」问题。
为什么会发生读破坏?你想想看,读操作时,BL 是 VDD,Q 是 0。M5 导通后,电流从 BL 流向 Q,Q 节点的电压会被抬升。如果这个抬升超过了反相器 M3/M4 的翻转阈值,数据就丢了。
所以,设计时有个经验法则:访问管的驱动能力,不能超过下拉管 M1/M3 的驱动能力。通常,M1/M3 的宽长比是 M5/M6 的 1.5 到 2 倍。
写操作:强推才能写进去
写操作和读操作正好相反。你要强行把位线上的电压,灌进存储节点,覆盖原来的数据。
写操作的过程:
- 把 BL 和 BL# 驱动到目标值。比如你要写 1,就把 BL 拉到 VDD,BL# 拉到 GND。
- 拉高 WL,M5/M6 导通。
- BL 通过 M5 给 Q 充电,BL# 通过 M6 给 Q# 放电。
- 当 Q 和 Q# 的电压超过反相器阈值,正反馈启动,数据被锁住。
写操作的关键是「能写进去」。如果访问管太弱,或者上拉管 M2/M4 太强,你可能推不动。我见过一个案例,为了省功耗把访问管做得特别小,结果写操作需要很长时间,时序直接崩了。
| 操作 | BL/BL# 状态 | 关键约束 | 常见问题 |
|---|---|---|---|
| 读 | 预充电到 VDD | 访问管 < 下拉管 | 读破坏 |
| 写 | 强制驱动到目标值 | 访问管 > 上拉管 | 写失败 |
| 保持 | 高阻态 | 正反馈稳定 | 漏电导致数据丢失 |
你看这个表,读和写对管子尺寸的要求是矛盾的。读要求访问管弱,写要求访问管强。怎么办?
嗯,这就是 SRAM 设计的核心矛盾之一。实际工程中,我们通常优先保证读稳定性,因为读操作更频繁。写操作可以通过加宽位线驱动、或者用写辅助电路来解决。
静态功耗:漏电是头号敌人
SRAM 的静态功耗,说白了就是漏电。管子关断时,电流还是会偷偷流过去。在先进工艺下,漏电功耗甚至能占到总功耗的 50% 以上。
静态功耗主要来自三个地方:
- 亚阈值漏电:晶体管关不断,Vgs 接近阈值电压时,沟道里还是有电流。这是最主要的漏电来源。
- 栅极漏电:栅氧化层太薄,电子直接隧穿过去。28nm 以下工艺特别明显。
- 结漏电:源漏和衬底之间的 PN 结反向漏电。温度越高,漏电越大。
我建议:在做低功耗 SRAM 设计时,先把静态功耗拆开看。用 SPICE 仿真跑一下,看看哪个漏电占比最大。很多时候,你花大力气优化了亚阈值漏电,结果栅极漏电才是大头,白忙活一场。
静态功耗的公式很简单:
P_static = VDD × I_leakage
其中 I_leakage = I_subthreshold + I_gate + I_junction
降低静态功耗的手段,无非就是降压、用高阈值管、或者电源门控。但这些方法都有代价,后面章节我们会详细讲。
动态功耗:读写一次烧多少钱
动态功耗,就是每次读写操作时,给电容充放电消耗的能量。SRAM 的动态功耗主要来自位线充放电。
动态功耗的公式:
P_dynamic = α × C_load × VDD² × f
其中:
α 是翻转活动因子(0~1)
C_load 是负载电容
f 是工作频率
你看,VDD 是平方项。所以降压对降低动态功耗效果最明显。但降压会牺牲速度,这是个 trade-off。
SRAM 的动态功耗可以进一步分解:
| 功耗分量 | 来源 | 占比(典型) | 优化方向 |
|---|---|---|---|
| 位线充放电 | 读/写时 BL/BL# 的电压摆幅 | 60-70% | 减小位线摆幅、分块 |
| 字线驱动 | WL 的充放电 | 15-20% | 减小字线长度、分层 |
| 灵敏放大器 | 放大器的偏置和切换 | 5-10% | 电流模式、快速关断 |
| 控制逻辑 | 译码器、时序控制 | 5-10% | 门控时钟、简化逻辑 |
我在项目中遇到过一个问题:一个 4MB 的 SRAM,动态功耗超标 30%。一分析,发现位线摆幅是满摆幅(0 到 VDD)。后来改成差分小摆幅读,只摆 200mV,功耗直接降了 40%。
功耗模型:把账算清楚
做低功耗设计,不能光凭感觉。你得有个模型,把每一笔功耗算清楚。
一个完整的 SRAM 功耗模型包含:
- 静态部分:所有单元的漏电总和,加上外围电路的静态电流。
- 动态部分:每次读/写操作消耗的能量,乘以操作频率。
- 唤醒部分:如果用了电源门控,从休眠到唤醒的额外功耗。
我习惯用这个公式估算总功耗:
P_total = P_static + P_dynamic + P_wakeup
P_static = N_cells × I_cell_leak × VDD + I_peri_leak × VDD
P_dynamic = (E_read × N_read + E_write × N_write) × f
P_wakeup = E_wakeup × f_wakeup
嗯,这里要注意,E_read 和 E_write 不是常数。它们和工艺角、温度、电压都有关系。我一般会在 TT、FF、SS 三个工艺角下分别提取,然后取最差情况做设计。