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文件……那画面太美我不敢看。

避坑指南:Windows用户安装时,记得勾选「Add to PATH」。否则你打开命令行敲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图,把本章的核心逻辑串起来。你一看就明白:

第4章:Verilog基础与Icarus Verilog 知识体系 Verilog模块结构 Icarus Verilog安装 第一个仿真波形 端口定义 · 数据类型 always块 · assign语句 Linux/macOS/Windows iverilog + gtkwave testbench编写 编译 → 仿真 → 波形 目标:从零到第一个仿真波形,建立完整认知
我的建议:学Verilog不要贪多。先把模块结构、always块、赋值语句这三大件搞明白。然后立刻上手跑仿真。看波形比看代码直观多了。你想想看,代码写对了没有,波形上一眼就能看出来。

好了,这一章的内容就到这里。记住,工具只是手段,理解硬件思维才是关键。下次你写Verilog的时候,脑子里要想着「这个代码综合出来是什么电路」,而不是「这个语法对不对」。慢慢来,你会找到感觉的。


公众号:蓝海资料掘金营,微信deep3321