【个人向】Verilog基础:模块代码、Testbench详解与仿真图

文章简介

个人学习总结2 - Verilog最基本模块与Testbench仿真
个人向!!!
参考:数字逻辑基础与Verilog设计(英文原书第3版)McGrawHill Education
参考:机械工业出版社中文翻译版 - 国外电子与电气工程技术丛书
软件:Quartus_II,Vivado,ChatGPT
此文章包括Verilog基本模块代码,Testbench代码,Tb语句讲解,仿真结果与分析!
个人NTU在读,欢迎指正


基本的语法见上一篇文章 :)
状态机电路、Tb及仿真详见下一篇文章,本篇篇幅太长了 :)


目录

文章简介

目录

1. 组合逻辑基础模块

1.1. 4to1MUX多路选择器

1.2. 译码器Decoder(拓展)

拓展 - 7段译码器​编辑

1.3. 编码器Encoder(拓展)

拓展 - 优先级编码器priority

1.4. D锁存器latch

2. 时序逻辑基础模块

2.1. D触发器DFF

2.2. 寄存器register

2.3. 移位寄存器shift register

2.4. !!!计数器counter

2.5. 计数器拓展-2位从0-59计数

X. 由于篇幅太长,10000字了

!状态机FSM



1. 组合逻辑基础模块

1.1. 4to1MUX多路选择器

- 4个输入,使用2bit的选择信号S来决定谁作为输出。
- 第一种写法,使用if / else,这种写法综合出来比较复杂

module test1
(
    input [2:0] w0,  //这里使用3bit的待选输入信号,后面TB看着清晰点
    input [2:0] w1,
    input [2:0] w2,
    input [2:0] w3,
    input [1:0] S,   //选择信号S
    output reg [2:0] Y  //输出Y
);
    always@(*)
    begin
        if(S == 0)   //S等于几就选w几
            Y = w0;
        else if(S == 1)
            Y = w1;
        else if(S == 2)
            Y = w2;
        else
            Y = w3;
    end
endmodule

- 第二种写法,使用case,这种方法综合出来直接是多bit输入的MUX,比较简单

module test1
(
    input [2:0] w0, w1, w2, w3,
    input [1:0] S,
    output reg [2:0] Y
);
    always@(*)
    begin
        case(S)
            0: Y = w0;
            1: Y = w1;
            2: Y = w2;
            3: Y = w3;
        endcase
    end
endmodule

- Testbench如下

`timescale 1ns / 1ps  //时间单位 / 精度
module tb_test1;
    reg [2:0] w0_test, w1_test, w2_test, w3_test;  //将输入声明为reg
    reg [1:0] S;
    wire [2:0] Y;   //输出声明为wire

    // Instantiate the design under test (DUT) 实例化连接
    test1 dut (
        .w0(w0_test),  // Connect w0_test to w0 input of DUT
        .w1(w1_test),
        .w2(w2_test),
        .w3(w3_test),
        .S(S),
        .Y(Y)
    );

    // Test测试
    initial 
    begin
        // Apply initial values to the reg signals
        w0_test = 4;  // Now w0_test is assigned a value
        w1_test = 5;
        w2_test = 6;
        w3_test = 7;
        S = 2'b00; // S = 0, expect Y = w0_test

        // Display header
        $display("S\tw0\tw1\tw2\tw3\tY");
        $monitor("%b\t%b\t%b\t%b\t%b\t%b", S, w0_test, w1_test, w2_test, w3_test, Y);

        // Apply different values for S
        #10 S = 2'b01; // S = 1, expect Y = w1_test
        #10 S = 2'b10; // S = 2, expect Y = w2_test
        #10 S = 2'b11; // S = 3, expect Y = w3_test

        #30 $finish;  //30ns后结束仿真
    end
endmodule

超详细的Testbench解释
1. timescale

- timescale 指令用于指定仿真的时间单位和精度,它是可选的,但通常在testbench和模块文件的顶部添加,以确保仿真时间的一致性和精确度。
- 1ns表示仿真时间的单位为纳秒;1ps表示时间的精度为皮秒。
- 如果改成1ns / 1ns,
2. 模块声明
- 还是用“module”和“endmodule”来声明测试模块,名称通常会加上“_tb”来表示是tb模块。
- 记得直接在名称后面加上“;”分号。
3. 输入输出声明
- Tb中不需要显式地声明输入和输出,测试嘛,实例化连接到原模块模拟一下就行。
- reg:用于表示可以在仿真过程中赋值的信号,通常用于输入信号,表示它们在仿真中可以存储和改变。“_test”这里表示tb中的测试信号,和原模块做区分。
- wire:用于表示通过组合逻辑传输的信号,通常用于输出信号,它的值由模块或其他逻辑驱动。
4. 实例化连接
- 正常的模块调用,把原模块调用到tb里,在tb中模块实例化是必须的,其的目的是将设计单元DUT嵌入到tb中,使其可以进行仿真验证。
5. 测试部分
- 由于是组合逻辑验证,每种情况跑一次就行,所以用了initial。
- 给所有的输入进行赋值,作为一开始的情况,这里直接给S赋值为0,所以一开始就会选择w0_test
- "$display"是Verilog中用于打印消息到仿真输出(控制台)的系统任务,它的作用类似于“printf”函数,在仿真过程中输出文本或变量的值。
- display不写其实不影响tb的仿真,它的意义主要体现在输出格式化调试便捷性上,它用来打印头部或者一些标识性的消息,在tb中用来在仿真开始时打印一行标题,这样你就可以清楚地知道每一列代表的信号是什么。(左图没有display,右图有display)(Tcl控制台截图)

- "S\tw0\tw1\tw2\tw3\tY"是字符串,表示输出的文本格式,"\t"是制表符"Tab",用于在输出中加入空格,使得每个变量名之间有一定的间隔,使输出更加整齐,查看输出结果时,变量名将以表格形式排布。这部分就和python差不多,“ ”内输入什么就打印出什么。
- "$monitor"是Verilog 中用于实时监控信号的系统任务,用来实时监控并输出信号的值,它的行为会随着信号的变化而实时更新,display只执行一次,而monitor会持续监视指定的信号,一旦这些信号的值发生变化,它就会重新输出最新的信号值。
- monitor会一直执行,直到最大仿真时间,或者"$finish"被调用表示结束。(机考题出现&

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值