纯流水记录安装过程。
Step1. 下载iverilog+gtkwave的安装包。

安装包会自动设置环境变量,安装过程点同意即可。
这一步搞完,iverilog.exe/vvp.exe/gtkwave.exe都可以使用了,但是iverilog-vpi暂时还不可用,下一步需要正确设置gcc编译器。
Step2. 下载mingw64免安装版本。


解压到D盘,然后手动添加环境变量PATH=”D:\mingw64\bin”.
通过命令窗口”gcc -v”确认安装状态,有信息则成功。
3. 建一个sample目录,准备仿真脚本sim.bat如下:
iverilog -o sim.vvp -s adder_tb adder.v adder_tb.v
iverilog-vpi -mingw=D:\mingw64 adder.c
vvp -M. -madder sim.vvp
echo "sim done"
pause
exit
查看波形脚本seewave.bat:
gtkwave wave.vcd
清除脚本clr.bat:
del *.vvp *.vcd *.out *.o *.vpi
准备c代码如下:
// adder.c
#include <vpi_user.h>
static int sum_compiletf(char *user_data)
{
fprintf(stderr, "Yes, you compiled me\n");
return 0;
}
static int sum (char *user_data)
{
vpiHandle systfref, args_iter, argh;
// typedef struct t_vpi_value s_vpi_value
struct t_vpi_value argval;
unsigned int value, value2;
char res[1024];
systfref = vpi_handle(vpiSysTfCall, NULL);
args_iter = vpi_iterate(vpiArgument, systfref); // 迭代所有参数.
argh = vpi_scan(args_iter); // 获取下一个参数
argval.format = vpiIntVal; // 设定格式为int
vpi_get_value(argh, &argval); // 获取参数值
value = argval.value.integer; // 读取获取到的参数值
argh = vpi_scan(args_iter); // 获取下一个参数
argval.format = vpiHexStrVal; // 以hex格式读入
vpi_get_value(argh, &argval);
sscanf(argval.value.str, "%x", &value2); // 将hex str格式读入的值转换为int
argh = vpi_scan(args_iter); // 获取第三个参数
argval.format = vpiHexStrVal; // 设置格式为hex str, verilog读取的时候会自动转换的.
sprintf(res, "%x", value + value2); // 在C里计算两个值的和, 并将其转换为hex格式的字符串
argval.value.str = res;
vpi_put_value(argh, &argval, 0, vpiNoDelay); // 设置第三个参数的值
vpi_put_value(systfref, &argval, 0, vpiNoDelay);
vpi_free_object(args_iter);
return 0;
}
// 注册 $sum
void sum_register() {
s_vpi_systf_data tf_data;
tf_data.type = vpiSysTask; // 类型. 还有一个是SysFunc
tf_data.tfname = "$sum"; // 在verilog中调用的名称
tf_data.calltf = sum; // 被verilog调用时调用的函数
tf_data.compiletf = sum_compiletf; // 被编译时调用的函数
tf_data.sizetf = 0; // 不知道
tf_data.user_data = 0; // 不知道
vpi_register_systf(&tf_data); // 注册
}
// 在这个函数数组里的函数会自动被调用.
void (*vlog_startup_routines[])() = {
sum_register,
0
};
tb代码如下:
// adder_tb.v
`timescale 1ns/1ns
module adder_tb();
reg [3:0] a;
reg [3:0] b;
wire [7:0] c;
reg clk,rst_n;
integer i, n, nf;
adder DUT (
.clk(clk),
.rst_n(rst_n),
.a(a),
.b(b),
.c(c)
);
always begin
#10 clk = 0;
#10 clk = 1;
end
initial begin
$display("=============================");
$display("Tb start at here");
rst_n = 1;
n = 0;
nf = 0;
// $test($random%4,2);
for (i = 0; i < 20; i++)
test($urandom%5'b10000,$urandom%5'b10000);
$display("%d total, %d fail", n, nf);
$finish;
end
task test;
input [3:0] in;
input [3:0] in2;
begin: test
reg [7:0] e;
a = in;
b = in2;
$sum(a,b,e); // HERE
@(posedge clk);
@(negedge clk);
n = n + 1;
if (c == e) begin
$display("It works, %d + %d = %d", in, in2, e);
end else begin
nf = nf + 1;
$display("opps %d + %d ~= %d, expect %d", in, in2, c, e);
end
end
endtask
initial begin
$dumpfile("wave.vcd");
$dumpvars;
end
endmodule
dut代码如下:
//adder.v
module adder(clk, rst_n, a, b, c);
input [3:0] a;
input [3:0] b;
output [7:0] c;
input clk, rst_n;
wire [3:0] a;
wire [3:0] b;
reg [7:0] c;
always @(posedge clk or negedge rst_n) begin
if (rst_n == 1'b0)
c <= 8'b0;
else
c <= a+b;
end
endmodule
最终可以看到的运行结果和波形如下:


附上过程中起到帮助的三则参考链接:
https://www.jb51.net/softjc/696089.html