A.1 为什么需要强度建模?
一、从实际问题说起
假设你有一个总线,多个设备连接到同一条线上:
┌──────────┐ ┌──────────┐ ┌──────────┐
│ 设备A │ │ 设备B │ │ 设备C │
│ 输出: 1 │ │ 输出: z │ │ 输出: 0 │
└────┬─────┘ └────┬─────┘ └────┬─────┘
│ │ │
└──────────────┼──────────────┘
│
总线信号
如果设备A输出1,设备C输出0,那么总线上的值是什么?
答案取决于驱动强度 ------如果设备A的驱动能力更强,总线为1;如果设备C更强,总线为0;如果两者强度相同,结果为 x(不确定)。
二、强度建模的意义
| 场景 | 需要强度建模的原因 |
|---|---|
| 多驱动源总线 | 判断哪个驱动源"赢" |
| 上拉/下拉电阻 | 电阻的驱动能力比逻辑门弱 |
| 电荷存储节点 | 电容节点可以"记住"电荷 |
| 电源/地 | 最强的驱动源 |
A.2 逻辑值与强度的组合
一、四值逻辑回顾
Verilog 使用四种逻辑值:
| 值 | 含义 |
|---|---|
| 0 | 逻辑0(假) |
| 1 | 逻辑1(真) |
| x | 不确定值 |
| z | 高阻态(浮动) |
二、八种强度等级
除了逻辑值,每个信号还有强度 。Verilog 定义了 8 种强度等级,从最强到最弱:
| 强度等级 | 类型 | 典型来源 | 优先级 |
|---|---|---|---|
| supply | 驱动 | 电源(VDD)、地(VSS) | 最强 ↑ |
| strong | 驱动 | 逻辑门输出、连续赋值 | |
| pull | 驱动 | 上拉/下拉电阻 | |
| large | 存储 | 电容节点(trireg类型) | |
| weak | 驱动 | 弱驱动源 | |
| medium | 存储 | 电容节点(trireg类型) | |
| small | 存储 | 电容节点(trireg类型) | |
| highz | 高阻 | 三态门关闭 | 最弱 ↓ |
记忆口诀 :S upply > S trong > P ull > L arge > W eak > M edium > S mall > Highz
三、强度与逻辑值的组合
每个信号值实际上由强度 + 逻辑值两部分组成:
信号值 = <强度> <逻辑值>
例如:
-
supply1:电源驱动,逻辑值为1(最强) -
strong0:逻辑门输出,逻辑值为0 -
pull1:上拉电阻,逻辑值为1 -
highz:高阻态(没有驱动源)
⚠️ 重要 :
highz没有逻辑值,它表示"没有驱动"。而strong1、pull0等都有明确的逻辑值。
四、强度竞争规则
当多个驱动源连接到同一个线网时,按照以下规则决定最终值:
| 竞争情况 | 结果 | 示例 |
|---|---|---|
| 强度不同 | 强度高的胜出 | strong1 vs pull0 → strong1(1胜出) |
| 强度相同,值相同 | 值不变 | strong1 vs strong1 → strong1 |
| 强度相同,值不同 | 结果为 x |
strong1 vs strong0 → x(不确定) |
示例分析:
// 场景1:不同强度竞争
wire a;
assign (strong1, weak0) a = 1'b1; // 强1驱动
// 结果:a = strong1(1胜出)
// 场景2:相同强度竞争
wire b;
assign (strong1, strong0) b = 1'b1;
assign (strong1, strong0) b = 1'b0;
// 结果:b = x(不确定,因为两个strong驱动冲突)
// 场景3:电源 vs 逻辑门
wire c;
supply1 vdd;
assign c = vdd; // supply1驱动
assign c = 1'b0; // strong0驱动
// 结果:c = supply1(电源强度更高,胜出)
五、在门级原语中指定强度
门级原语(and、or、buf等)和连续赋值都可以指定驱动强度。
语法:
<门类型> ( <强度1>, <强度0> ) <实例名> ( <端口> );
示例:
// 为与门指定强度:输出1时为strong1,输出0时为strong0
and (strong1, strong0) a1(out, in1, in2);
// 为缓冲器指定强度:输出1时为strong1,输出0时为pull0
buf (strong1, pull0) b1(out, in);
// 为连续赋值指定强度
assign (strong1, weak0) out = in1 & in2;
// 为三态门指定强度
bufif1 (strong1, strong0) b1(out, in, enable);
// 电源和地的强度
supply1 vdd; // supply1强度
supply0 gnd; // supply0强度
A.3 高级线网类型
除了最常用的 wire,Verilog 还提供了多种高级线网类型,用于特定的建模场景。
一、线网类型总览
| 线网类型 | 关键字 | 功能 | 适用场景 |
|---|---|---|---|
| 普通连线 | wire |
标准连线 | 最常用,90%的场景 |
| 线与 | wand |
多个驱动源实现与逻辑 | 线与逻辑 |
| 线或 | wor |
多个驱动源实现或逻辑 | 线或逻辑 |
| 三态线网 | tri |
同wire,但允许多驱动源 | 三态总线 |
| 三态线与 | triand |
同wand,但允许多驱动源 | 三态线与 |
| 三态线或 | trior |
同wor,但允许多驱动源 | 三态线或 |
| 电容线网 | trireg |
能存储电荷 | 电荷存储节点 |
| 电源线 | supply0 |
地(逻辑0) | 电源/地建模 |
| 电源线 | supply1 |
电源(逻辑1) | 电源/地建模 |
二、线与(wand)和线或(wor)
线与(wand)
多个驱动源连接到同一线网,结果为所有驱动源的"与"。
wand out;
assign out = a;
assign out = b;
// out = a & b
真值表:
| a | b | wand结果 |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
| 1 | z | 1 |
| 0 | z | 0 |
线与的物理实现:在集电极开路(OC)或漏极开路(OD)电路中,多个输出端直接相连,通过一个上拉电阻拉到高电平。只要有一个输出为0,整条线就被拉低------这就是"线与"。
线或(wor)
多个驱动源连接到同一线网,结果为所有驱动源的"或"。
wor out;
assign out = a;
assign out = b;
// out = a | b
真值表:
| a | b | wor结果 |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 1 |
| 0 | z | 0 |
| 1 | z | 1 |
三、三态线网(tri)
tri 类型在功能上等同于 wire,但它明确表示这是一个三态总线,可以有多个驱动源。
tri [7:0] data_bus; // 8位三态数据总线
// 多个驱动源(不同时有效)
assign data_bus = enable1 ? data1 : 8'bz;
assign data_bus = enable2 ? data2 : 8'bz;
assign data_bus = enable3 ? data3 : 8'bz;
wire vs tri :在功能上完全等价。使用 tri 只是代码风格 上的选择------当你明确知道这是三态总线时,用 tri 让代码意图更清晰。
三态线与(triand)和三态线或(trior) 分别是 wand 和 wor 的三态版本。
四、电容线网(trireg)------ 最重要的高级线网类型
1. trireg 的特殊之处
普通线网(wire)没有驱动源时值为 z,但 trireg 类型的线网可以"记住"最后的驱动值。
trireg (large) cap_node; // 声明一个电容节点
// 当驱动源存在时,cap_node取驱动值
// 当驱动源消失(变为z)时,cap_node保持最后的驱动值
物理意义 :trireg 建模的是有电荷存储能力的节点(如MOS管的栅极电容)。当驱动源断开时,节点上的电荷不会立即消失,而是保持一段时间。
2. trireg 的默认值
| 线网类型 | 默认值(无驱动时) |
|---|---|
wire、tri 等 |
z(高阻) |
trireg |
x(不确定) |
注意 :trireg 的默认值是 x,不是 z!这是因为电容节点在上电时的初始电荷是未知的。
3. trireg 的电荷强度
trireg 可以指定电荷存储强度:
| 强度 | 关键字 | 说明 |
|---|---|---|
| 大电容 | large |
电荷保持时间最长 |
| 中电容 | medium |
中等保持时间 |
| 小电容 | small |
保持时间最短 |
trireg (large) cap1; // 大电容节点(保持时间最长)
trireg (medium) cap2; // 中电容节点
trireg (small) cap3; // 小电容节点
// 如果trireg的强度大于驱动源的强度,驱动源需要更长时间才能改变该节点的值
4. trireg 的应用场景
| 场景 | 说明 |
|---|---|
| 动态MOS电路 | 动态逻辑门利用电容存储电荷 |
| 电荷分享电路 | 电荷在电容之间重新分配 |
| 存储节点建模 | 需要"记住"电荷的节点 |
示例:动态锁存器
module dynamic_latch(q, d, clk);
output q;
input d, clk;
trireg (small) storage; // 电荷存储节点
// 当时钟为高时,数据存入电容节点
// 当时钟为低时,数据保持不变
cmos (storage, d, clk, ~clk);
// 缓冲器输出
buf (q, storage);
endmodule
动态电路的核心:利用电容存储电荷来"记住"数据,不需要静态触发器,因此面积更小、功耗更低。但需要周期性刷新(因为电荷会泄漏),且对噪声敏感。
五、电源线网(supply0 和 supply1)
supply0 和 supply1 是强度最高的驱动源,分别表示地和电源。
supply1 vdd; // 电源(逻辑1,supply强度)
supply0 gnd; // 地(逻辑0,supply强度)
// 使用
assign a = vdd; // a 恒为 supply1(无法被其他驱动源改变)
assign b = gnd; // b 恒为 supply0
特点:
| 特点 | 说明 |
|---|---|
| 强度最高 | supply强度,任何其他驱动源都无法覆盖 |
| 值恒定 | 始终为1(supply1)或0(supply0) |
| 用途 | 建模电源和地网络 |
A.4 强度建模总结
一、强度等级速查表
| 强度 | 级别 | 类型 | 示例 |
|---|---|---|---|
supply |
7(最强) | 驱动 | 电源、地 |
strong |
6 | 驱动 | 逻辑门输出、assign |
pull |
5 | 驱动 | 上拉/下拉电阻 |
large |
4 | 存储 | trireg(大电容) |
weak |
3 | 驱动 | 弱驱动 |
medium |
2 | 存储 | trireg(中电容) |
small |
1 | 存储 | trireg(小电容) |
highz |
0(最弱) | 高阻 | 三态门关闭 |
二、竞争规则速查
| 情况 | 结果 |
|---|---|
| 不同强度 | 强度高的胜出 |
| 相同强度,相同值 | 值不变 |
| 相同强度,不同值 | x(不确定) |
highz vs 任何值 |
任何值胜出(highz不驱动) |
三、线网类型选择指南
| 需求 | 推荐类型 |
|---|---|
| 普通连线 | wire ✅ |
| 多驱动源三态总线 | tri |
| 线与逻辑 | wand |
| 线或逻辑 | wor |
| 电荷存储节点 | trireg |
| 电源/地 | supply0/supply1 |