3、第一个仿真程序:编写一个简单的Verilog门电路
好,咱们正式开始动手了。
前面两章聊了工具链和基本概念,说实话,光看不练容易犯困。这一章咱们直接写代码、编译、跑仿真、看波形——走完一个完整的流程。你想想看,当你在GTKWave里看到自己写的门电路波形跳起来的那一刻,那种感觉还是挺爽的。
3.1 我们要做什么?
这一章的目标很简单:
- 写一个Verilog描述的与门(AND gate)
- 写一个测试平台(testbench)来驱动它
- 用iverilog编译这两个文件
- 生成VCD波形文件
- 用GTKWave打开波形,验证功能
说白了,就是让一个与门从代码变成看得见的波形。我当年第一次跑通这个流程时,盯着波形看了好几分钟——原来数字电路真的是这样工作的。
核心知识点:Verilog模块结构、testbench写法、iverilog编译命令、VCD文件生成、GTKWave基本操作。
3.2 编写与门模块
先写一个最简单的与门。新建一个文件,命名为 and_gate.v:
module and_gate (
input wire a,
input wire b,
output wire y
);
assign y = a & b;
endmodule
嗯,这里要注意:assign 是连续赋值语句,表示 y 的值随着 a 和 b 的变化实时更新。在项目中我见过有人把 & 写成 &&,前者是按位与,后者是逻辑与——对于单bit信号结果一样,但多bit时就完全不是一回事了。
3.3 编写testbench
光有设计模块还不够,得有个东西给它输入信号、观察输出。这就是testbench的作用。
新建 tb_and_gate.v:
`timescale 1ns / 1ps
module tb_and_gate;
reg a;
reg b;
wire y;
// 实例化被测试模块
and_gate u_and_gate (
.a(a),
.b(b),
.y(y)
);
// 产生激励信号
initial begin
a = 0; b = 0;
#10;
a = 0; b = 1;
#10;
a = 1; b = 0;
#10;
a = 1; b = 1;
#10;
$finish;
end
// 生成VCD波形文件
initial begin
$dumpfile("wave.vcd");
$dumpvars(0, tb_and_gate);
end
endmodule
这里有几个关键点:
`timescale 1ns / 1ps:定义时间单位是1ns,精度是1ps。我习惯这么写,精度够用又不浪费仿真时间。reg和wire:testbench里,驱动输入用reg,观察输出用wire。这是Verilog的规则,别搞反了。#10:延迟10个时间单位,也就是10ns。$dumpfile和$dumpvars:这是生成VCD文件的关键。我曾经忘记加这两行,折腾了半天才发现没波形——嗯,这种低级错误犯过一次就不会再犯了。
小技巧:$dumpvars(0, tb_and_gate) 中的0表示dump所有层次的信号。如果只想看某个模块的信号,可以写成 $dumpvars(1, tb_and_gate.u_and_gate),只dump一层。
3.4 编译与仿真
打开终端,进入文件所在目录,执行:
iverilog -o tb_and_gate.vvp and_gate.v tb_and_gate.v
vvp tb_and_gate.vvp
第一行命令用iverilog编译两个.v文件,输出一个名为 tb_and_gate.vvp 的可执行文件。第二行用vvp运行这个文件,生成 wave.vcd。
如果一切顺利,你会看到终端没有任何报错,目录下多了一个 wave.vcd 文件。这就是我们要的波形文件。
注意:编译时文件顺序有讲究。建议把testbench放在最后,因为iverilog是按顺序解析的,testbench里引用了and_gate模块,所以and_gate要先被编译。
3.5 用GTKWave查看波形
执行:
gtkwave wave.vcd
GTKWave的界面会打开。左侧是信号列表,右侧是波形显示区。操作步骤:
- 在左侧找到
tb_and_gate,展开它 - 找到
u_and_gate,再展开 - 选中
a、b、y三个信号 - 点击左上角的
Insert按钮,或者直接拖拽到右侧波形区
你会看到这样的波形:
- 0ns-10ns:a=0, b=0, y=0
- 10ns-20ns:a=0, b=1, y=0
- 20ns-30ns:a=1, b=0, y=0
- 30ns-40ns:a=1, b=1, y=1
与门的真值表验证通过。y只有在a和b同时为1时才为1,其他情况都是0。
验证结论:与门功能正确,仿真环境搭建成功。
3.6 本章知识体系
下面这张图展示了我们这一章的核心逻辑:
3.7 避坑指南
这一章虽然简单,但有几个坑我当年都踩过:
- 文件找不到:确保终端当前目录和.v文件在同一目录下,或者用路径。
- VCD文件没生成:检查testbench里有没有写
$dumpfile和$dumpvars。我曾经漏写过,仿真跑完了才发现没波形。 - 波形显示不对:检查信号名是否写错,比如把
y写成Y。Verilog是大小写敏感的。 - GTKWave打不开:确认VCD文件确实生成了,用
ls -l wave.vcd看看文件大小,如果为0说明仿真没跑成功。
我的习惯:每次写完testbench,先检查 $dumpfile 和 $dumpvars 这两行有没有写对。这是生成波形的关键,少了它们等于白跑。
3.8 小结
这一章我们走完了从代码到波形的完整流程。你亲手写了一个与门,写了testbench,用iverilog编译,用vvp仿真,最后在GTKWave里看到了波形。说实话,这个流程在后面的29章里会反复出现,所以现在打好基础很重要。
下一章我们会聊更复杂的组合逻辑电路,但核心流程是一样的。嗯,先把这个与门跑通再说。
可可精品资料库