本文目录
regHeap-Simulation
Verilog HDL
以下内容摘自Verilog_wiki
HDL:Hardware-Description-Language,Verilog HDL是一种硬件描述语言,主要用于集成电路设计。
Verilog能够在多种抽象级别对数字逻辑系统进行描述:既可以在晶体管级、逻辑门级进行描述,也可以在寄存器传输级对电路信号在寄存器之间的传输情况进行描述。除了对电路的逻辑功能进行描述,Verilog代码还能够被用于逻辑仿真、逻辑综合,其中后者可以把寄存器传输级的Verilog代码转换为逻辑门级的网表,从而方便在现场可编程逻辑门阵列上实现硬件电路,或者让硬件厂商制造具体的专用集成电路。设计人员还可以利用Verilog的扩展部分Verilog-AMS进行模拟电路和混合信号集成电路的设计。
Description
本项目源于书籍<CPU自制入门>的例程,是学习Verilog的入门基础项目。
该项目实现了一个32组32位寄存器堆的纯软件实现,并可以通过GTKWave查看仿真波形
寄存器堆框图:
寄存器堆中有作为存储的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查看仿真生成的波形文件
官网:
- Icarus Verilog: http://iverilog.icarus.com
- Icarus Verilog for Windows: http://bleyer.org/icarus/
- GTKWave: http://gtkwave.sourceforge.net/
安装及配置环境过程不再阐述
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
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