3、Verilog-AMS基础:语言结构、数据类型、模拟行为建模入门

各位同学,欢迎来到第三章。从这一章开始,我们正式进入Verilog-AMS的世界。

说实话,很多做数字验证的朋友一听到“模拟”两个字就头大。我当年也一样。但后来发现,Verilog-AMS其实没那么可怕。它就是在Verilog的基础上,加了一些描述模拟信号的能力。说白了,就是让数字工程师也能看懂模拟电路在干什么。

3.1 语言结构:从数字到模拟的桥梁

Verilog-AMS的模块结构和Verilog很像。但有个关键区别——它多了naturediscipline这两个概念。

什么是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搭建完整的验证平台。

记住,模拟验证的核心不是精确建模,而是足够精确。你不需要把每个晶体管都建出来,只需要让行为匹配到验证需要的精度就行。这个度怎么把握?多做几个项目,你自然就懂了。