regHeap-Simulation

regHeap-Simulation

Verilog HDL

以下内容摘自Verilog_wiki

HDL:Hardware-Description-Language,Verilog HDL是一种硬件描述语言,主要用于集成电路设计。
Verilog能够在多种抽象级别对数字逻辑系统进行描述:既可以在晶体管级、逻辑门级进行描述,也可以在寄存器传输级对电路信号在寄存器之间的传输情况进行描述。除了对电路的逻辑功能进行描述,Verilog代码还能够被用于逻辑仿真、逻辑综合,其中后者可以把寄存器传输级的Verilog代码转换为逻辑门级的网表,从而方便在现场可编程逻辑门阵列上实现硬件电路,或者让硬件厂商制造具体的专用集成电路。设计人员还可以利用Verilog的扩展部分Verilog-AMS进行模拟电路和混合信号集成电路的设计。

Description

本项目源于书籍<CPU自制入门>的例程,是学习Verilog的入门基础项目。
该项目实现了一个32组32位寄存器堆的纯软件实现,并可以通过GTKWave查看仿真波形

寄存器堆框图:

18SWvQ.png

寄存器堆中有作为存储的32个32位寄存器,以及读写寄存器序列用的接口。寄存器堆模块在regfile.v文件中实现,regfile.v引用了regfile.h头文件。

Simulation

Verilog HDL语言同样可以用作电路仿真测试。

Testbench

记述仿真程序的文件称为Testbench。
一个典型的Testbench构造如下:

`timescale 1ns/1ps  //  设定timescale(单位时间:1ns/时间精度:1ps)

module test_bench;  //  定义Testbench模块。无输入输出端口
    reg adder01_in_0;   //  定义接到被测模块输入输出的信号线
    reg adder01_in_1;   //  输入接寄存器型变量
    wire adder01_cut;   //  输出接网络型变量

    adder adder01 (     //  被测模块的实例化
        .in_0 (adder01_in_0),
        .in_1 (adder01_in_1),
        .out  (adder01_out)
    );

    initial begin       //  记述测试用例
        ...
        ...
        ...
    end

endmodule

Waveform output

仿真时的信号变化可以输出到波形文件中,在此使用多数波形软件都支持的VCD格式波形文件输出方法。

VCD文件输出使用¥dumpfile和¥dumpvars两个系统任务实现,e.g如下:

$dumpfile(<filename>)
$dumpvars(<Start time>, <Name of the output-waveform file / signal>)

eg:
initial begin 
    $dumpfile("test.vcd");  //Output waveform to file 'test.vcd'
    $dumpvars(0, test);     //Output module 'test' 's waveform from time 0
end

ToolChains

本例程使用Icarus Verilog(iVerilog)进行仿真
使用GTKWave查看仿真生成的波形文件
官网:

安装及配置环境过程不再阐述

Do it!

我使用VsCode编写代码,内置终端非常好用。
在终端里进入src文件夹,执行以下命令:

iverilog -s regfile_test -o regfile_test.out regfile_test.v regfile.v
vvp regfile_test.out

Testbench执行后的波形文件输出到了regfile.vcd中。
执行:

vvp regfile.out

使用GTKWave查看波形:

gtkwave regfile.vcd

18S4Ds.png

Code

代码在 鱼的Github 上,不过在这里也贴一份啦~

当然,如果你想直接运行,推荐你转至github直接下载zip包~
(不然工程目录结构还有路径的问题可能会搞晕你)

regfile.v

/***** Include Header File *****/
`include "regfile.h"

/***** Module *****/
module regfile (
    /***** Time_clock and Reset *****/
    input wire              clk,        //Clock
    input wire              reset_,     //Asynchronous Reset (Logic 0)

    /***** Access Interface *****/
    input wire [`AddrBus] addr,         //Address
    input wire [`DataBus] d_in,         //Input Data
    input wire             we_,         //Written enable (Logic 0)
    output wire [`DataBus] d_out        //Output Data
);

    /***** Internal signals *****/

    reg [`DataBus]        
        ff [`DATA_D-1:0];   //Register sequence
    //因为这里在显示上出了点bug,所以将上面这一行代码拆成2行了(
    integer                 i;                  //Iterator

    /***** Read Accessory *****/
    assign d_out = ff[addr];

    /***** Write Accessory *****/
    always @(posedge clk or negedge reset_) begin
        if (reset_ == `ENABLE_) begin
            /***** Asynchronous Reset *****/
            for (i = 0; i < `DATA_D; i = i + 1) begin
                ff[i]    <= #1 {`DATA_W{1'b0}};
            end
        end else begin
            /***** Write Accessory *****/
            if (we_ == `ENABLE_) begin
                ff[addr] <= #1 d_in;
            end
        end
    end
endmodule

regfile_test.v

/***** Time scale *****/
`timescale 1ns/1ps

/***** Header File *****/
`include "regfile.h"

/***** Modules *****/
module regfile_test;
    /***** I/O Signals *****/
    //Clock & Reset 
    reg             clk;        //clock
    reg             reset_;     //Reset (Logic 0)
    //Access Interface
    reg [`AddrBus] addr;        //Address
    reg [`DataBus] d_in;        //Input Data
    reg             we_;        //Write Enable (Logic 0)
    wire [`DataBus] d_out;      //Output Data
    /***** Internal Variables *****/
    integer         i;          //Iterator
    /***** Define Simulation loop *****/
    parameter       STEP = 100.0000;     //10 M

    /***** Generate Clock Signal *****/
    always #(STEP/ 2 ) begin
        clk <= ~ clk;
    end

    /***** Instantiate Test_Bench *****/
    regfile regfile (
        /***** Clock & Reset *****/
        .clk        (clk),          //Clock
        .reset_     (reset_),       //Reset (Logic 0)
        /***** Access Interface *****/
        .addr       (addr),         //Address
        .d_in       (d_in),         //Input Data
        .we_        (we_),          //Write Enable (Logic 0)
        .d_out      (d_out)         //Output data    
    );

    /***** Example for test *****/
    initial begin
        # 0 begin 
            clk     <= `HIGH;
            reset_  <= `ENABLE_;
            addr    <= {`ADDR_W{1'b0}};
            d_in    <= {`DATA_W{1'b0}};
            we_     <= `DISABLE_;
        end
        # (STEP *3 / 4)
        # STEP begin
            reset_ <= `DISABLE_;    //Release Reset
        end
        # STEP begin 
            for (i = 0; i < `DATA_D; i = i + 1) begin
                # STEP begin
                    addr    <= i;
                    d_in    <= i;
                    we_     <= `ENABLE_;
                end
                # STEP begin
                    addr    <= {`ADDR_W{1'b0}};
                    d_in    <= {`DATA_W{1'b0}};
                    we_     <= `DISABLE_;
                    if (d_out == i) begin
                        $display ($time, " ff[%d] Read/Write Check OK !", i);
                    end else begin
                        $display ($time, " ff[%d] Read/Write Check NG !", i);
                    end
                end
            end
        end
        # STEP begin
            $finish;
        end
    end

    initial begin
        $dumpfile("regfile.vcd");
        $dumpvars(0, regfile);
    end

endmodule

regfile.h

`ifndef __REGFILE_HEADER__
    `define __REGFILE_HEADER__

    /***** Signal Voltage level *****/
    `define HIGH                1'b1    //High level
    `define LOW                 1'b0    //Low level

    /***** Logic Value *****/
    `define ENABLE_             1'b0    //Low level
    `define DISABLE_            1'b1    //High level

    /***** Data *****/
    `define DATA_W              32      //Data Width
    `define DataBus             31:0    //Data Bus
    `define DATA_D              32      //Data Depth

    /***** Address *****/
    `define ADDR_W              5       //Addr Width
    `define AddrBus             4:0     //Addr Bus

`endif

发表回复