iVerilog 和 iVerilog Assistant
由于iverilog是一个非常轻量但是完整的仿真工具,相较于Modelsim这些专业的软件,其使用也是非常简单的。个人使用iverilog工具做科研、开发完全不用担心版权问题。但是iVerilog需要用户自己编写命令行或者是脚本,对于初学者还是不太友好。因此博主做了一个小助手iVerilog Assistant,用于辅助各位朋友使用iVerilog进行仿真。
目前小助手是2022a版本。
🚀使用
安装
用2022a开始,小助手发布的都会用一个7z自解压文件。各位使用的朋友需要注意🎉🎉🎉🎉,重要的话说三遍:
小助手的安装路径和工程路径内不应包含中文和空格!
小助手的安装路径和工程路径内不应包含中文和空格!
小助手的安装路径和工程路径内不应包含中文和空格!
如果在使用过程中出现点没有办法编译或者是仿真的情况,请检查安装路径是否有问题😡😡😡。这里推荐大家解压路径选择C盘根目录,解压完成后将assistant.exe添加一个快捷方式到桌面或者是开始菜单都可以~😀
小助手能正常运行,那么打开的主界面如下图所示。如果不一样那就凉了啊😔
😍😍😍😍在小助手中,双击文件树可以打开相应的文件,双击project可以打开工程路径,双击source、testbech、document同样可以打开相应路径。
配置
要让小助手能够正常工作,首先需要进行必要的配置。
首先设置用户名可以让生成的文件包含尊贵大名。小助手默认的编辑器是notepad,就是系统自带的记事本(因为总得有一个东西要打开代码)。小助手不集成编辑器的原因是每一个人都有自己写代码的习惯,相应的编辑器也有足够丰富的插件支撑快速编码。无论使用任何编辑器,都需要在此处配置路径。小助手内集成一套预编译的iverilog、GTKWave程序,默认参数Internal将使用内部所带的编译器和波形查看器,否则请指定外部编译器(例如自己编译的最新iverilog程序),并且指定的外部仿真器必须包含iverilog、vvp和GTKWave。
创建工程
点击Open/New按钮,选择New Project选项,填上工程名和路径,然后OK就可以了。
添加源代码和测试代码
点击New Files按钮,弹出添加文件对话框。
在该对话框内可以添加三种文件:verilog源代码、verilog测试脚本、说明文档(支持text、markdown、latex)。该对话框包含一个端口编辑器,可以在新建文件的时候就加上一些端口之类的,同时可以指定文件模板。右侧是一个代码预览,可以看看自动生成了什么东西。
此处添加一个名字为“haha.v"的源码文件。
这里有几个设置的参数,对照右边生成的代码就明白了。
此处添加一个叫”test.v"的测试文件**。注意测试文件的模块名程序不允许修改,默认是文件名加"_tb"。另外请不要更改vcd文件的名字,否则会找不到vcd文件弹不出波形!**(高手随意😀)
仿真
仿真之前请先指定【顶层模块】,和【测试代码】
😡😡😡注意,一个工程里面至少需要有一个源代码和一个测试代码!!
点击编译按钮,不出意外可以看到弹出绿字大黑窗(控制台),如果有报错信息,那么需要一条一条耐心修正,不断重新编译。如果编译成功会产生vcd文件,同时也会打印testbench中所有通过 d i s p l a y , display, display,write的内容。
点击仿真按钮,如果选择产生vcd文件,可以看到弹出GTKWave,在GTKWave中可以观察相应信号的波形。
自定义模板
使用的朋友可以自定义模板,包括指定一些注释信息,时间、日期、文件名、作者等。小助手提供的模板编辑器目前支持以下几种MASK,在完成文件添加的时候,MASK会被替换为具有实际意义的文字。
MASK | 说明 | 示例 |
---|---|---|
&file& | 将被替换为此文件名 | led.v |
&author& | 将被替换为作者名(作者名可以设置) | Sun Zhenyu |
&date& | 将被替换为年月日 | 2022 - 02 - 05 |
&port& | 将被替换为端口编辑器生成的端口 | / |
&module_name& | 将被替换为模块名 | led |
&tb_cfg& | 将被替换为testbech配置文件 | / |
建立模板的时候可以在任意位置插入MASK,这意味着,如果MASK对应的字符与实际意义存在冲突(例如&date&在上下文中是女盆友的名字👩),程序将无法按照设想保留这些字符(会被替换为当天时间日期)。
示例程序:二进制转BCD码
选择合适位置新建一个工程。
这里我们需要实现一个二进制转BCD码,博主思来想去辗转反侧决定使用加三法,因此需要建立一个加法器。加法器是一个纯组合逻辑电路,点击新建文件建立一个源码文件add3.v,填写输入和输出端口。
有了加法器,我们需要对加法器进行组合才能输出一个完成转BCD码的操作,因此新建一个文件bin2bcd.v。
注意这里的位宽输入是8位二进制,输出最多BCD码位宽是12位。
添加完源码文件以后,目录树应该是这个样子的。
双击里面的add3.v,填上以下代码。
`timescale 1ns/1ps
/*
@ File : add3.v
@ Author : User
@ Data : 2022-02 -10
@ Version :
@ Brief :
*/
module add3(
input [3:0] in,
output [3:0] out
);
reg [3:0] out;
always @(*) begin
case(in)
4'b0000: out = 4'b0000; // 0
4'b0001: out = 4'b0001; // 1
4'b0010: out = 4'b0010; // 2
4'b0011: out = 4'b0011; // 3
4'b0100: out = 4'b0100; // 4
4'b0101: out = 4'b1000; // 5
4'b0110: out = 4'b1001; //6
4'b0111: out = 4'b1010; //7
4'b1000: out = 4'b1011; //8
4'b1001: out = 4'b1100; //9
default: out = 4'b0000; //others, impossible
endcase
end
endmodule
双击bin2bcd.v,填上以下代码
`timescale 1ns/1ps
/*
@ File : bin2bcd.v
@ Author : User
@ Data : 2022-02-10
@ Version :
@ Brief :
*/
module bin2bcd(
input [7:0] bin,
output [11:0] bcd
);
wire [3:0] add3_inst0_out;
wire [3:0] add3_inst1_out;
wire [3:0] add3_inst2_out;
wire [3:0] add3_inst3_out;
wire [3:0] add3_inst4_out;
wire [3:0] add3_inst5_out;
wire [3:0] add3_inst6_out;
assign bcd[11:8] = {2'b0,add3_inst5_out[3],add3_inst6_out[3]};
assign bcd[7:4] = {add3_inst6_out[2:0],add3_inst4_out[3]};
assign bcd[3:0] = {add3_inst4_out[2:0], bin[0]};
add3 add3_inst0
(
.in({1'b0,bin[7:5]}),
.out(add3_inst0_out)
);
add3 add3_inst1
(
.in({add3_inst0_out[2:0],bin[4]}),
.out(add3_inst1_out)
);
add3 add3_inst2
(
.in({add3_inst1_out[2:0],bin[3]}),
.out(add3_inst2_out)
);
add3 add3_inst3
(
.in({add3_inst2_out[2:0],bin[2]}),
.out(add3_inst3_out)
);
add3 add3_inst4
(
.in({add3_inst3_out[2:0],bin[1]}),
.out(add3_inst4_out)
);
add3 add3_inst5
(
.in({1'b0,add3_inst0_out[3],add3_inst1_out[3],add3_inst2_out[3]}),
.out(add3_inst5_out)
);
add3 add3_inst6
(
.in({add3_inst5_out[2:0],add3_inst3_out[3]}),
.out(add3_inst6_out)
);
endmodule
保存以后接下来新建测试文件。
默认测试文件会生成一些时钟和复位信号,因为我们测试的是纯组合逻辑,在生成的代码中我们把这些东西删掉。
`timescale 1ns/1ps
/*
@ File : test.v
@ Author : User
@ Data : 2022-02-10
@ Version :
@ Brief :
*/
module test_tb();
//************************Do Not Remove************************//
initial begin
$dumpfile("test_tb.vcd");
$dumpvars();
end
//*************************************************************//
reg[8:0] i;
reg [11:0] bcd;
wire [11:0] test_output;
reg [3:0] error_count;
bin2bcd bin2bcd_inst(
.bin(i[7:0]),
.bcd(test_output)
);
initial begin
error_count = 0;
for(i = 0;i <= 255; i = i + 1) begin
bcd[3:0] = i % 10;
bcd[7:4] = (i / 10) % 10;
bcd[11:8] = (i / 100) % 10;
#10;
if(test_output != bcd) begin
error_count = error_count + 1;
$display("integer %d : hdl output [%d %d %d], correct [%d %d %d]\n",
i,
test_output[11:8], test_output[7:4], test_output[3:0],
bcd[11:8], bcd[7:4], bcd[3:0]
);
end
end
if(error_count == 0)
$display("Test pass!\n");
else
$display("%d error occurred while testing hdl module\b");
$finish();
end
endmodule
现在在bin2bcd.v上右键,设置bin2bcd为顶层,在test.v伤右键设置test.v为活动测试代码。
点击编译,如果安装路径、编译器路径设置正常的话就应该能够输出结果。
否则请检查一下安装路径或者是工程路径中是否有空格、中文字符。
点击仿真按钮可以看到弹出GTKWave,说明仿真可以工作。
通过波形我们看到这个bin2bcd是正确的,可以实现二进制转BCD的功能。