SoC 中 SRAM 的读写原理与总线时序
SRAM (Static Random Access Memory) 是 SoC 中最常见的片上存储器:CPU 的一级/二级缓存、紧耦合内存 (TCM)、总线 FIFO、各种硬件加速器的缓冲区,本质上都是 SRAM 或由 SRAM 阵列构成的。本文从 6T 单元开始,逐步讲到总线节点上的读写并发,再讨论电压变化对时序的影响,以及芯片如何控制时序。
1. SRAM 存储单元:6T 结构
一个经典 SRAM 单元由 6 个晶体管组成 (6T):
两个交叉耦合的反相器 (P1/N1 与 P2/N2),构成双稳态锁存器,存储 1 bit
两个存取管 (access transistor) N3、N4,栅极接字线 WL,把存储节点接到位线上
flowchart TB
VDD1["VDD"] --> P1["P1 (PMOS)"]
VDD2["VDD"] --> P2["P2 (PMOS)"]
P1 --> Q["存储节点 Q"]
P2 --> QB["存储节点 QB"]
Q --> N1["N1 (NMOS)"]
QB --> N2["N2 (NMOS)"]
N1 --> GND1["GND"]
N2 --> GND2["GND"]
BL["BL 位线"] --- N3["N3 存取管"]
N3 --- Q
BLB["BLB 位线(反相)"] --- N4["N4 存取管"]
N4 --- QB
WL["WL 字线"] -.->|"栅极"| N3
WL -.->|"栅极"| N4
为什么叫"静态":只要不掉电,交叉耦合反相器的正反馈让 Q/QB 永远稳定在互补的两个电平上,不需要像 DRAM 那样周期性刷新。
假设 Q=1 (VDD)、QB=0 (GND),那么 N1 导通、P2 导通,Q 被 P1 拉高、QB 被 N2 拉低,状态自持。
2. 读操作:预充、放电与灵敏放大
SRAM 的读不是"直接把存储节点的电平送出去",而是通过位线放电 + 灵敏放大完成,分四步:
第一步:预充 (Precharge)。 预充管把两条位线 BL、BLB 都充到 VDD,再断开,位线处于"悬空但带满电荷"的高阻状态。
第二步:字线打开。 WL 拉高,N3/N4 导通,存储节点与位线连通。
第三步:位线差分放电。 假设单元存 Q=1、QB=0:
QB 侧:QB 是 GND,位线 BLB 是 VDD → 电流从 BLB 经 N4、N2 流向地,BLB 电压开始缓慢下降
Q 侧:Q 是 VDD,BL 也是 VDD → 无压差,不放电
位线电容很大 (一条位线挂几百个单元),而单元电流很小,所以 BLB 只是"缓慢下滑",产生一个 ΔV ≈ 100 mV 左右的微小差分。
第四步:灵敏放大 (Sense Amplifier)。 等 ΔV 足够大,灵敏放大器使能信号 SAE 打开,差分放大器把 100 mV 的小信号迅速放大到全摆幅,送到数据总线上。然后位线重新预充,准备下一次访问。
时钟 ___|‾‾‾|___|‾‾‾|___|‾‾‾|___
预充 PC ‾‾‾|_______|‾‾‾‾‾‾‾‾‾|‾‾
WL 字线 ____|‾‾‾‾‾‾‾|__________
BLB (读"0"侧) ~~~~~‾‾‾‾‾‾‾‾\___________ ← 从 VDD 开始缓慢放电
\
ΔV ≈ 100mV
SAE 灵敏放大 ____________|‾‾‾‾|________ ← 检测到 ΔV 后打开
数据输出 ________________|‾‾‾|______ ← 全摆幅输出
两个关键细节:
读是破坏性扰动。 放电电流流过 N4/N2 时,QB 节点电位会被轻微抬高 (read disturb)。如果抬高超过单元的静态噪声容限 SNM (Static Noise Margin),单元会意外翻转——读一次就把数据读坏了。所以单元里下拉管 N1/N2 必须比存取管 N3/N4 强,两者宽长比 (cell ratio, β ratio) 一般取 1.5~2,保证扰动被下拉管"按住"。
自定时 (self-timed)。 SAE 什么时候打开?不是靠设计者定一个固定延迟,而是放一条复本位线 (replica bitline):模拟最坏情况下位线放电的速度。电压低、温度高时,复本位线放电同样变慢,SAE 自动后移——这个时机天然跟踪 PVT (工艺/电压/温度) 变化,这是 SRAM 内部"控制时间"的核心手段。
3. 写操作:强驱动压过锁存器
写操作则相反,要主动破坏锁存器的状态:
写驱动 (write driver) 把 BL 拉到 0、BLB 拉到 1 (假设要写 0 到 Q)
WL 拉高,N3 导通
此时 Q=VDD,P1 正在把 Q 往上拉,而写驱动通过 N3 把 Q 往下拽。写驱动是"大管子",驱动能力远强于单元内部的 PMOS——Q 被强行拉低
Q 一旦跌破反相器 1 的翻转阈值,正反馈立刻接管:QB 被推高 → 又反过来拉低 Q → 翻转完成,锁存器锁住新值
要保证"压得过",存取管必须比单元内的上拉 PMOS 强 (pull-up ratio, γ ratio)。如果写驱动压不过 P1,就会写失败——这就是写裕量 (write margin)。
读和写对单元的要求是对立的:读要求存取管弱 (防止扰动翻转),写要求存取管强 (压过 PMOS)。6T 单元的两个管子尺寸比例就是在这两个约束之间取平衡点。
4. 总线视角:AXI 通道与 SRAM 控制器
在 SoC 里,CPU 不会直接操作 6T 单元,而是通过总线访问 SRAM。最常用的是 AMBA AXI 总线,它有 5 个独立通道:
通道 |
方向 |
作用 |
|---|---|---|
AW |
主 → 从 |
写地址 |
W |
主 → 从 |
写数据 |
B |
从 → 主 |
写响应 |
AR |
主 → 从 |
读地址 |
R |
从 → 主 |
读数据 |
关键点:读通路 (AR/R) 和写通路 (AW/W/B) 是物理上完全独立的导线,没有共享数据总线。所以"节点一边从上游收读数据、一边向下游发写数据"在物理层就没有冲突——这就是全双工。
flowchart LR
M["Master 主设备"]
N["总线节点\n(互连/桥/SRAM控制器)"]
S["SRAM 从设备"]
M -->|"AR: 读地址"| N
N -->|"AR: 读地址"| S
S -->|"R: 读数据"| N
N -->|"R: 读数据"| M
M -->|"AW/W: 写地址+写数据"| N
N -->|"AW/W: 写地址+写数据"| S
S -->|"B: 写响应"| N
N -->|"B: 写响应"| M
每个通道用 VALID/READY 握手:发送方拉高 VALID 表示"我这拍的数据有效",接收方拉高 READY 表示"我能收"。只有 VALID 和 READY 同时为高的那一拍,数据才算被采样。这是数据正确性的第一道防线——数据线电平本身不能说明数据有效,握手信号才能。
注意:SRAM 阵列本身通常是单端口的 (同一时刻要么读要么写),所以控制器的仲裁逻辑会把同时到达的读写请求分时排队。阵列之外的"同时收发"靠的是通道分离 + 控制器内的寄存器缓冲。
5. 总线节点"边读边写":寄存器隔离与流水线
这是最容易困惑的地方:节点 (比如一个总线桥,或者 SRAM 控制器本身) 在同一个时钟周期里,既要从上游采样数据,又要向下游驱动数据,两条数据流为什么不会串?
答案是:节点内部用两级物理独立的寄存器把"收"和"发"隔开——输入寄存器负责从上游捕获,输出寄存器负责向下游驱动,而输出寄存器里放的是上一拍 (甚至更早) 捕获的数据。
flowchart LR
U["上游"] -->|"本拍数据"| IR["输入寄存器\n(捕获上游)"]
IR -->|"上一拍数据"| OR["输出寄存器\n(驱动下游)"]
OR -->|"本拍输出"| D["下游"]
CLK["时钟"] --> IR
CLK --> OR
时序上看:
周期 N-1 N N+1
时钟 ____|‾‾‾‾|____|‾‾‾‾|____|‾‾‾‾|____
上游送出 < A > < B > < C >
输入寄存器 [ A ]→ [ B ]→ [ C ]→ ← 每个上升沿捕获上游
输出寄存器 [ Z ]→ [ A ]→ [ B ]→ ← 每个上升沿更新为"上一拍"的输入
下游看到 < Z > < A > < B >
第 N 拍的时钟沿上,节点同时做了两件事:
输入寄存器把上游的 B 关进去 (读上游)
输出寄存器把上一拍捕获的 A 锁出来驱动下游 (写下游)
下游在第 N 拍看到的是 A——上游第 N-1 拍的数据。上游第 N 拍送出的 B,最早也要第 N+1 拍才会出现在下游。数据经过节点必然"停留"至少一个时钟周期,这就是流水线的一级 (register slice / pipeline cut)。
换句话说,"边读边写"不是同一份数据在同一拍从上游流到下游,而是两拍数据在节点内部接力:拍 N 收 B、发 A;拍 N+1 收 C、发 B。输入寄存器和输出寄存器是两组物理上不同的触发器,时钟沿同时触发时各干各的,数据线互不连接,所以不存在串扰的物理通路。
对比一下:如果节点不做寄存 (纯组合逻辑直连),下游确实会同拍看到上游数据——但那样就完全没有隔离和缓冲了,长路径时序难以收敛,所以真正的总线节点都会插寄存器。
6. 会不会"写错数据"?——数据归属如何保证
针对"先读了上游数据,写的时候会不会把上游数据写出去/写进自己"的疑问,结论分两层:
正常设计下:不会。 有三道防线保证"写的数据一定是自己的数据":
通道分离:读数据走 R 通道、写数据走 W 通道,物理导线不同,读回来的数据根本进不了写数据通路
寄存器隔离:如上一节时序图,下游第 N 拍收到的值最晚在第 N-1 拍的时钟沿之前就锁定了;第 N 拍上游才送来的新数据,不可能在第 N 拍就出现在下游。时序上"读上游"永远晚于"写下游"一拍,写出去的永远是早先已锁存的数据
握手保护:写数据只有在 VALID && READY 同时为高的拍才被打入写数据寄存器;SRAM 阵列的写端口只连接写数据寄存器,读数据寄存器只从阵列接收。两条通路在寄存器层面物理隔离
以 SRAM 控制器为例:第 N 拍,读数据寄存器 (RDR) 里是从阵列读出的数据 (自己存储的数据),经 R 通道发往下游;同时写数据寄存器 (WDR) 捕获上游 W 通道送来的写数据。第 N+1 拍阵列执行写操作时,写端口接的是 WDR——阵列永远不会把 RDR 的内容写进存储单元,除非设计本身连错了线。
真正可能出问题的场景,都是时序违例,而不是设计意图:
保持时间 (hold) 违例 → 寄存器"透明化":如果数据在时钟沿之后的保持窗口内就发生变化 (数据路径太快,或者时钟偏斜太大),寄存器来不及把旧值锁死,新数据会在同一拍穿透。这正好会表现为"刚读到的上游数据在错误的一拍被写下去"。hold 违例在快工艺角 (高电压、低温、快硅) 下最危险,而且降频解决不了 hold 问题,只能插缓冲器修。
跨时钟域 (CDC) 没有同步器 → 亚稳态:如果上游和节点时钟不同源,采样时刻恰好落在数据跳变沿上,触发器进入亚稳态,采到既非 0 也非 1 的中间值,甚至不同触发器采出互相矛盾的值。解决手段是两级触发器同步器或异步 FIFO。
控制信号出错:写使能 (WEN) 或地址译码出错会把数据写进错误的单元。这与数据来源无关,属于功能错误,ECC 可以检测但不能预防。
所以总结:只要 setup/hold 收敛、跨时钟域有同步器,就不会出现"写了上游数据而不是自身数据"——寄存器隔离在时序上把"读上游"和"写下游"严格错开了一拍。
7. 电压变化对时间差的影响
门的传播延迟近似服从 α 幂律模型 (Sakurai-Newton):
C_load · VDD
t_d ∝ ─────────────── ≈ VDD / (VDD - Vth)^α
I_drain
VDD 越高,驱动电流越大,延迟越小;VDD 越低,延迟越大,而且越接近阈值电压 Vth,延迟增长得越陡:
延迟
↑
| *
| *
| *
| *
| *
| *
| *
+─────────────────────────→ VDD
Vth Vnom
对 SRAM 读周期的影响尤其明显:读电流 ∝ (VDD−Vth)^α,低压下位线放电变慢,从字线打开到 SAE 使能的时间差显著拉长——只不过自定时的复本位线会自动跟着变慢,把 SAE 时机同步后移,抵消了大部分影响。这正是自定时设计在低压场景下的价值。
标准 PVT 工艺角如下:
工艺角 |
工艺 |
电压 |
温度 |
最坏影响 |
|---|---|---|---|---|
SS |
慢 |
-10% |
高温 |
setup 违例 (数据来得太晚) |
FF |
快 |
+10% |
低温 |
hold 违例 (数据来得太早) |
TT |
典型 |
标称 |
25°C |
参考基准 |
注意温度效应在现代深亚微米工艺里是高温更慢。
另外要区分静态和动态:
静态电压设定 (DVFS 档位) 决定整个芯片的平均速度
动态电压跌落 (IR drop / di/dt 噪声):大量单元同时翻转瞬间把电源拉低几十到上百 mV,局部电路瞬时变慢,可能造成本来收敛的 setup 路径在那一瞬间违例。这就是芯片要留电压裕量和时序裕量的原因
8. 芯片如何控制时序
芯片控制"时间"的机制可以分成五层:
第一层:同步设计 + 静态时序分析 (STA)。 所有时序都以时钟沿为基准,STA 工具用 SDC 约束检查每一条寄存器到寄存器的路径是否满足 setup/hold,并按工艺角留裕量 (OCV/AOCV/POCV 补偿片上变异)。收敛的标准不是"仿真过了",而是"所有角都过了"。
第二层:时钟网络。 PLL (锁相环) 从外部晶振倍频出芯片主时钟,分频器产生各模块时钟,时钟树综合 (CTS) 把时钟均衡地送到每个触发器——skew (时钟到达不同触发器的时间差) 直接影响 hold 裕量。所以 hold 违例的修法是调整时钟树/插缓冲,而不是降频。
第三层:SRAM 内部自定时。 前面说的复本位线:SAE、预充、字线脉冲都由内部模拟路径产生,天然跟踪 PVT,不需要外部精确计时。
第四层:DVFS (动态电压频率调节)。 电压决定速度上限,频率决定工作节奏,两者必须协调:
flowchart LR
A["当前工作点 (V, f)"] -->|"升频: 先升电压"| B["V↑ (PMIC/LDO)"]
B -->|"电压稳定后"| C["f↑ (PLL)"]
C --> D["新工作点 (V', f')"]
A -->|"降频: 先降频率"| E["f↓"]
E -->|"频率稳定后"| F["V↓"]
F --> D
原则是:升频时电压先行 (频率永远不能超过当前电压支撑的上限),降频时频率先行 (电压永远不能低于当前频率所需)。顺序反了就会在过渡期出现 setup 违例。
第五层:AVS (自适应电压调节)。 用片内环形振荡器、canary 电路甚至 Razor 触发器实时监测硅片的实际速度,把电压动态调到"刚好能满足时序"的最低值,省电且抗老化。低压下电压裕量小,这种闭环调节比固定档位更有效。
9. 总结
SRAM 读 = 预充 → 字线开 → 位线差分放电 → 灵敏放大;写 = 写驱动强压锁存器翻转。β ratio 保读稳定,γ ratio 保写成功
总线节点"边读边写"靠通道分离 (全双工) + 寄存器隔离 (流水线):本拍写的永远是上一拍已锁存的数据,读上游和写下游在时序上天然错开一拍
"写错数据"正常不会发生;唯一接近的失效模式是 hold 违例导致寄存器同拍穿透,以及 CDC 亚稳态——都是时序问题,不是设计问题
电压下降 → 延迟按 (VDD−Vth)^α 规律拉长,SRAM 读放电时间显著变长;自定时复本位线自动补偿
芯片靠 STA 收敛 + PLL/时钟树 + SRAM 自定时 + DVFS (升压先于升频、降频先于降压) + AVS 闭环,五层机制共同控制时序
参考资料
Neil Weste, David Harris, CMOS VLSI Design: A Circuits and Systems Perspective (第 4 版),第 12 章 (Array Subsystems)
Jan Rabaey, Digital Integrated Circuits: A Design Perspective,第 12 章
Sakurai & Newton, Alpha-Power Law MOSFET Model and its Applications to CMOS Inverter Delay and Other Formulas, IEEE JSSC 1990
ARM, AMBA AXI and ACE Protocol Specification
Seevinck et al., Static-Noise Margin Analysis of MOS SRAM Cells, IEEE JSSC 1987