3、Verilog-AMS基础:语言结构、数据类型、模拟行为建模入门
各位同学,欢迎来到第三章。从这一章开始,我们正式进入Verilog-AMS的世界。
说实话,很多做数字验证的朋友一听到“模拟”两个字就头大。我当年也一样。但后来发现,Verilog-AMS其实没那么可怕。它就是在Verilog的基础上,加了一些描述模拟信号的能力。说白了,就是让数字工程师也能看懂模拟电路在干什么。
3.1 语言结构:从数字到模拟的桥梁
Verilog-AMS的模块结构和Verilog很像。但有个关键区别——它多了nature和discipline这两个概念。
什么是discipline?你可以把它理解成“信号的类型标签”。比如,电信号有电压、电流,机械信号有力、位移。Verilog-AMS用discipline来区分这些物理量。
看个最简单的例子:
// 定义一个电压域的discipline
nature voltage
access = V;
units = "V";
endnature
nature current
access = I;
units = "A";
endnature
discipline electrical
potential voltage;
flow current;
enddiscipline
嗯,这里要注意:access关键字定义了访问函数。比如V(net)就是读取节点电压,I(net)就是读取流入节点的电流。我个人习惯把discipline定义放在一个单独的文件里,方便复用。
核心概念:Verilog-AMS的模块可以同时包含数字信号(wire/reg)和模拟信号(electrical)。模拟端口用inout声明,但类型是electrical。
3.2 数据类型:不只是0和1
数字世界里,信号只有0、1、X、Z。但模拟世界里,电压可以是1.23V,电流可以是0.456mA。Verilog-AMS引入了real类型来处理这些连续值。
常用的数据类型有:
| 类型 | 说明 | 我踩过的坑 |
|---|---|---|
real |
双精度浮点数,模拟信号的核心 | 别拿real做逻辑判断,精度问题会让你怀疑人生 |
integer |
32位整数,和Verilog一样 | 模拟模块里少用,除非是计数器 |
electrical |
模拟节点类型,包含电压和电流 | 记得用V()和I()访问 |
wreal |
实数线网,用于数字-模拟接口 | 这个类型很实用,后面会细讲 |
为什么会引入wreal?你想想看,如果数字模块的输出要连到模拟模块的输入,直接用real类型会出问题——它没有驱动强度概念。wreal就是为了解决这个问题的。它像wire一样可以多驱动,但传递的是实数值。
个人经验:我在做ADC验证时,经常用wreal来连接数字控制信号和模拟比较器。这样既保留了模拟精度,又避免了复杂的discipline转换。
3.3 模拟行为建模入门
好了,重头戏来了。模拟行为建模,说白了就是用数学公式描述电路的行为。
Verilog-AMS提供了两种建模方式:
- 结构级建模:用晶体管、电阻、电容等基本元件搭电路
- 行为级建模:用数学表达式描述输入输出关系
对于验证来说,行为级建模更常用。因为速度快,而且容易控制。
看一个简单的电阻模型:
module resistor (p, n);
inout p, n;
electrical p, n;
parameter real R = 1000; // 默认1kΩ
analog begin
V(p,n) <+ R * I(p,n);
end
endmodule
这里的关键是analog begin...end块。它和always块不同:
analog块里的语句是连续执行的,不是事件触发的- 赋值用
<+操作符,表示“贡献” - 多个贡献语句会自动叠加
我曾经犯过一个低级错误:在analog块里用了=赋值。结果仿真器报了一大堆错误。记住,模拟域用<+,数字域用=。
3.4 常用模拟行为模型
实际项目中,我们经常需要快速搭建这些模型:
3.4.1 理想运放
module opamp_ideal (out, inp, inn);
inout out, inp, inn;
electrical out, inp, inn;
parameter real gain = 1e5;
analog begin
V(out) <+ gain * (V(inp) - V(inn));
end
endmodule
这个模型很简单,但够用。如果你需要更真实的模型,可以加上压摆率限制、输出摆幅等。
3.4.2 一阶低通滤波器
module lpf_1st (out, in);
inout out, in;
electrical out, in;
parameter real fc = 1e6; // 截止频率1MHz
parameter real R = 1e3;
real wc;
analog begin
wc = 2 * `M_PI * fc;
// 使用拉普拉斯算子
V(out) <+ laplace_nd(V(in), {0, wc}, {1, wc});
end
endmodule
避坑指南:我曾经在滤波器模型里直接用微分方程,结果仿真步长太小,跑了一天没出结果。后来改用拉普拉斯算子,速度快了100倍。记住,能用频域就别用时域。
3.5 混合信号接口处理
这是验证中最容易出问题的地方。数字信号和模拟信号怎么交互?
Verilog-AMS提供了$bound_step()函数来控制仿真步长。当数字信号跳变时,模拟求解器需要知道这个事件。
module comparator (out, inp, inn);
input inp, inn;
output out;
electrical inp, inn;
reg out;
real vdiff;
analog begin
vdiff = V(inp) - V(inn);
// 告诉求解器:电压差过零时,步长要小
$bound_step(1e-9);
end
always @(cross(vdiff, 0))
out = (vdiff > 0) ? 1'b1 : 1'b0;
endmodule
看到cross()函数了吗?它检测模拟信号穿越某个阈值的事件。这是连接数字和模拟世界的桥梁。
我的习惯:在混合信号接口处,我都会加一个$bound_step()。虽然会稍微慢一点,但能避免很多莫名其妙的收敛问题。
3.6 本章小结
这一章我们覆盖了:
- Verilog-AMS的语言结构:module、discipline、nature
- 数据类型:real、electrical、wreal
- 模拟行为建模:analog块、贡献操作符<+
- 常用模型:运放、滤波器
- 混合信号接口:cross()、$bound_step()
说实话,这些内容只是冰山一角。但掌握了这些,你已经可以开始写简单的混合信号验证环境了。下一章我们会深入讨论如何用Verilog-AMS搭建完整的验证平台。
记住,模拟验证的核心不是精确建模,而是足够精确。你不需要把每个晶体管都建出来,只需要让行为匹配到验证需要的精度就行。这个度怎么把握?多做几个项目,你自然就懂了。