4、Verilog基础与Icarus Verilog:Verilog模块结构、Icarus Verilog安装与使用、第一个仿真波形。
好,咱们今天聊聊Verilog。说实话,很多新手一上来就被各种EDA工具吓住了。其实没必要。我个人习惯,学Verilog的第一步,不是装Vivado或Design Compiler,而是先装一个轻量级的仿真器——Icarus Verilog。为什么?因为它够简单,够快,能让你把精力放在语言本身,而不是折腾工具上。
4.1 Verilog模块结构:芯片设计的最小单元
Verilog里最基本的概念就是「模块」。你可以把它想象成一个黑盒子。这个盒子有输入、有输出,里面装着逻辑。我在项目中遇到过不少新人,上来就写几百行的代码,结果模块的端口定义都是乱的。嗯,这里要养成好习惯:先画框,再填内容。
一个标准的模块长这样:
module counter (
input wire clk, // 时钟
input wire rst_n, // 复位,低有效
output reg [3:0] count // 4位计数器输出
);
// 时序逻辑:每个时钟上升沿触发
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
count <= 4'b0000;
else
count <= count + 1'b1;
end
endmodule
你看,结构其实很清晰:
- module/endmodule:模块的起止标志
- 端口列表:定义输入输出,用input/output/inout声明
- 数据类型:wire(线网)和reg(寄存器)是最常用的
- 逻辑描述:用always块、assign语句来描述行为
rst_n命名,后缀_n表示低有效,这是行业惯例。
4.2 Icarus Verilog安装:别怕,就三步
Icarus Verilog(简称iverilog)是个开源工具。说白了,它就是一个小型的Verilog编译器和仿真器。你想想看,装个Vivado要几十G,而iverilog才几兆。对于学习阶段,它完全够用。
安装方法因系统而异:
| 操作系统 | 安装命令 |
|---|---|
| Ubuntu/Debian | sudo apt-get install iverilog gtkwave |
| CentOS/RHEL | sudo yum install iverilog |
| macOS (Homebrew) | brew install icarus-verilog |
| Windows | 下载安装包,一路Next即可 |
注意,我建议你同时装上gtkwave。这是个波形查看工具,后面看仿真结果全靠它。我曾经见过有人用文本编辑器看vcd文件……那画面太美我不敢看。
iverilog会提示找不到命令。我曾经在这上面浪费了10分钟,后来发现是安装时忘了勾选。
4.3 第一个仿真波形:从代码到波形,走通全流程
好,工具装好了,咱们来跑第一个仿真。我会用一个最简单的例子:一个时钟分频器。为什么选这个?因为它能让你看到波形在动,有成就感。
首先,写一个测试文件(testbench)。测试文件也是个模块,但它没有输入输出,它的任务就是给被测模块(DUT)提供激励。
// tb_divider.v
`timescale 1ns / 1ps
module tb_divider;
reg clk;
reg rst_n;
wire clk_out;
// 实例化被测模块
divider u_divider (
.clk (clk),
.rst_n (rst_n),
.clk_out(clk_out)
);
// 生成时钟:周期20ns,频率50MHz
initial begin
clk = 0;
forever #10 clk = ~clk;
end
// 复位和仿真控制
initial begin
rst_n = 0;
#30;
rst_n = 1;
#500;
$finish;
end
// 保存波形
initial begin
$dumpfile("tb_divider.vcd");
$dumpvars(0, tb_divider);
end
endmodule
然后,写一个简单的分频器模块:
// divider.v
module divider (
input wire clk,
input wire rst_n,
output reg clk_out
);
reg [3:0] cnt;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt <= 0;
clk_out <= 0;
end else if (cnt == 4'd9) begin
cnt <= 0;
clk_out <= ~clk_out;
end else begin
cnt <= cnt + 1'b1;
end
end
endmodule
接下来,用iverilog编译和仿真:
# 编译
iverilog -o tb_divider.vvp divider.v tb_divider.v
# 仿真运行
vvp tb_divider.vvp
# 用gtkwave查看波形
gtkwave tb_divider.vcd
你会看到类似这样的波形:
关键点:clk_out每10个时钟周期翻转一次,实现了5分频(因为高低电平各占5个周期)。这就是你人生中第一个Verilog仿真波形!
为什么会这样?因为cnt从0计数到9,一共10个周期,每计满一次clk_out翻转。所以输入50MHz,输出就是5MHz。嗯,逻辑很简单,但亲手看到波形跳起来的那一刻,感觉还是不一样的。
4.4 知识体系:一张图看懂本章
下面我用一张SVG图,把本章的核心逻辑串起来。你一看就明白:
好了,这一章的内容就到这里。记住,工具只是手段,理解硬件思维才是关键。下次你写Verilog的时候,脑子里要想着「这个代码综合出来是什么电路」,而不是「这个语法对不对」。慢慢来,你会找到感觉的。
公众号:蓝海资料掘金营,微信deep3321