目标
- 完成一个verilog文件的仿真。
- 书写一个sim_main.cpp文件,能够对该verilog文件进行测试。
目标Verilog文件
- 我们首先拿到一个目标verilog文件。
- 这个verilog文件的test bench已经写好了,命名为tb。
- 这个tb有两个input,这两个input由verilator的test bench控制,它们分别是
clock
和reset
。 - 因为有clock pulse才能进行仿真,所以我们需要书写一个
sim_main.cpp
(可以换名字)来对clock
进行控制。
// Following code segment is generated from /home/ziyue/researchlib/Micro_Eletronic/STSearch/tests/b11/src/b11.v:1
module b11(x_in, stbi, clock, reset, x_out);
input [5:0] x_in;
input stbi;
input clock;
input reset;
output [5:0] x_out;
reg [5:0] cont = 6'b0;
reg signed [8:0] cont1 = 9'b0;
reg signed [8:0] cont1_inv = 9'b0;
reg [5:0] r_in = 6'b0;
reg [3:0] stato = 4'b0;
reg [5:0] x_out = 6'b0;
always @(*) begin
cont1_inv = (9'sb000000000 - cont1); $display(";A 0"); //(= cont1_inv (bv-sub 0b000000000 cont1 ))) ;0
end
// Following code segment is generated from /home/ziyue/researchlib/Micro_Eletronic/STSearch/tests/b11/src/b11.v:28
always @(posedge clock) begin
if ((reset == 1'b1)) begin
$display("target");
stato = 4'b0000; $display(";A 3"); //(= stato 0b0000)) ;3
r_in = 6'b000000; $display(";A 4"); //(= r_in 0b000000)) ;4
cont = 6'b000000; $display(";A 5"); //(= cont 0b000000)) ;5
cont1 = 9'b000000000; $display(";A 6"); //(= cont1 0b000000000)) ;6
x_out <= 6'b000000; $display(";A 7"); //(= x_out 0b000000)) ;7
end
else begin
case (stato)
4'b0000 :
begin
$display(";A 8"); //(= stato 0b0000)) ;8
cont = 6'b000000; $display(";A 9"); //(= cont 0b000000)) ;9
r_in = x_in; $display(";A 10"); //(= r_in x_in )) ;10
x_out <= #1 6'b000000; $display(";A 11"); //(= x_out 0b000000)) ;11
stato = 4'b0001; $display(";A 12"); //(= stato 0b0001)) ;12
end
4'b0001 :
begin
$display(";A 13"); //(= stato 0b0001)) ;13
r_in = x_in; $display(";A 14"); //(= r_in x_in )) ;14
if ((stbi == 1'b1)) begin
$display(";A 15"); //(= (bv-comp stbi 0b1) 0b1)) ;15
stato = 4'b0001; $display(";A 17"); //(= stato 0b0001)) ;17
end
else begin
$display(";A 16"); //(= (bv-comp stbi 0b1) 0b0)) ;16
stato = 4'b0010; $display(";A 18"); //(= stato 0b0010)) ;18
end
end
4'b0010 :
begin
$display(";A 19"); //(= stato 0b0010)) ;19
if (((r_in == 6'b000000) || (r_in == 6'b111111))) begin
$display(";A 20"); //(= (bv-or (bv-comp r_in 0b000000) (bv-comp r_in 0b111111)) 0b1)) ;20
if ((cont < 6'b011001)) begin
$display(";A 22"); //(= (bool-to-bv (bv-lt cont 0b011001)) 0b1)) ;22
cont = (cont + 6'b000001); $display(";A 24"); //(= cont (bv-add cont 0b000001))) ;24
end
else begin
$display(";A 23"); //(= (bool-to-bv (bv-lt cont 0b011001)) 0b0)) ;23
cont = 6'b000000; $display(";A 25"); //(= cont 0b000000)) ;25
end
cont1 = {3'b000, r_in}; $display(";A 26"); //(= cont1 (bv-concat 0b000 r_in ))) ;26
stato = 4'b1000; $display(";A 27"); //(= stato 0b1000)) ;27
end
else begin
$display(";A 21"); //(= (bv-or (bv-comp r_in 0b000000) (bv-comp r_in 0b111111)) 0b0)) ;21
if ((r_in <= 6'b011010)) begin
$display(";A 28"); //(= (bool-to-bv (bv-le r_in 0b011010)) 0b1)) ;28
stato = 4'b0011; $display(";A 30"); //(= stato 0b0011)) ;30
end
else begin
$display(";A 29"); //(= (bool-to-bv (bv-le r_in 0b011010)) 0b0)) ;29
stato = 4'b0001; $display(";A 31"); //(= stato 0b0001)) ;31
end
end
end
4'b0011 :
begin
$display(";A 32"); //(= stato 0b0011)) ;32
if ((r_in[0] == 1'b1)) begin
$display(";A 33"); //(= (bv-comp (bv-extract 0 0 r_in ) 0b1) 0b1)) ;33
cont1 = {2'b00, cont, 1'b0}; $display(";A 35"); //(= cont1 (bv-concat 0b00 cont 0b0))) ;35
end
else begin
$display(";A 34"); //(= (bv-comp (bv-extract 0 0 r_in ) 0b1) 0b0)) ;34
cont1 = {3'b000, cont}; $display(";A 36"); //(= cont1 (bv-concat 0b000 cont ))) ;36
end
stato = 4'b0100; $display(";A 37"); //(= stato 0b0100)) ;37
end
4'b0100 :
begin
$display(";A 38"); //(= stato 0b0100)) ;38
if ((r_in[1] == 1'b1)) begin
$display(";A 39"); //(= (bv-comp (bv-extract 1 1 r_in ) 0b1) 0b1)) ;39
cont1 = ({3'b000, r_in} + cont1); $display(";A 41"); //(= cont1 (bv-add (bv-concat 0b000 r_in ) cont1 ))) ;41
stato = 4'b0101; $display(";A 42"); //(= stato 0b0101)) ;42
end
else begin
$display(";A 40"); //(= (bv-comp (bv-extract 1 1 r_in ) 0b1) 0b0)) ;40
cont1 = ({3'b000, r_in} - cont1); $display(";A 43"); //(= cont1 (bv-sub (bv-concat 0b000 r_in ) cont1 ))) ;43
stato = 4'b0110; $display(";A 44"); //(= stato 0b0110)) ;44
end
end
4'b0101 :
begin
$display(";A 45"); //(= stato 0b0101)) ;45
if ((cont1 > 9'sb000011010)) begin
$display(";A 46"); //(= (bool-to-bv (bv-sgt cont1 0b000011010)) 0b1)) ;46
cont1 = (cont1 - 9'b000011010); $display(";A 48"); //(= cont1 (bv-sub cont1 0b000011010))) ;48
stato = 4'b0101; $display(";A 49"); //(= stato 0b0101)) ;49
end
else begin
$display(";A 47"); //(= (bool-to-bv (bv-sgt cont1 0b000011010)) 0b0)) ;47
stato = 4'b0111; $display(";A 50"); //(= stato 0b0111)) ;50
end
end
4'b0110 :
begin
$display(";A 51"); //(= stato 0b0110)) ;51
if ((cont1 > 9'sb000111111)) begin
$display(";A 52"); //(= (bool-to-bv (bv-sgt cont1 0b000111111)) 0b1)) ;52
cont1 = (cont1 + 9'b000011010); $display(";A 54"); //(= cont1 (bv-add cont1 0b000011010))) ;54
stato = 4'b0110; $display(";A 55"); //(= stato 0b0110)) ;55
end
else begin
$display(";A 53"); //(= (bool-to-bv (bv-sgt cont1 0b000111111)) 0b0)) ;53
stato = 4'b0111; $display(";A 56"); //(= stato 0b0111)) ;56
end
end
4'b0111 :
begin
$display(";A 57"); //(= stato 0b0111)) ;57
if ((r_in[3:2] == 2'b00)) begin
$display(";A 58"); //(= (bv-comp (bv-extract 3 2 r_in ) 0b00) 0b1)) ;58
cont1 = (cont1 - 9'b000010101); $display(";A 60"); //(= cont1 (bv-sub cont1 0b000010101))) ;60
end
else begin
$display(";A 59"); //(= (bv-comp (bv-extract 3 2 r_in ) 0b00) 0b0)) ;59
if ((r_in[3:2] == 2'b01)) begin
$display(";A 61"); //(= (bv-comp (bv-extract 3 2 r_in ) 0b01) 0b1)) ;61
cont1 = (cont1 - 9'b000101010); $display(";A 63"); //(= cont1 (bv-sub cont1 0b000101010))) ;63
end
else begin
$display(";A 62"); //(= (bv-comp (bv-extract 3 2 r_in ) 0b01) 0b0)) ;62
if ((r_in[3:2] == 2'b10)) begin
$display(";A 64"); //(= (bv-comp (bv-extract 3 2 r_in ) 0b10) 0b1)) ;64
cont1 = (cont1 + 9'b000000111); $display(";A 66"); //(= cont1 (bv-add cont1 0b000000111))) ;66
end
else begin
$display(";A 65"); //(= (bv-comp (bv-extract 3 2 r_in ) 0b10) 0b0)) ;65
cont1 = (cont1 + 9'b000011100); $display(";A 67"); //(= cont1 (bv-add cont1 0b000011100))) ;67
end
end
end
stato = 4'b1000; $display(";A 68"); //(= stato 0b1000)) ;68
end
4'b1000 :
begin
$display(";A 69"); //(= stato 0b1000)) ;69
if ((cont1 < 9'sb000000000)) begin
$display(";A 70"); //(= (bool-to-bv (bv-slt cont1 0b000000000)) 0b1)) ;70
x_out <= #1 cont1_inv[5:0]; $display(";A 72"); //(= x_out (bv-extract 5 0 cont1_inv ))) ;72
end
else begin
$display(";A 71"); //(= (bool-to-bv (bv-slt cont1 0b000000000)) 0b0)) ;71
x_out <= #1 cont1[5:0]; $display(";A 73"); //(= x_out (bv-extract 5 0 cont1 ))) ;73
end
stato = 4'b0001; $display(";A 74"); //(= stato 0b0001)) ;74
end
default :
begin
$display(";A 75"); //(= stato 0b0000)) ;75
end
endcase
end
$display(";F cont = %b;cont1 = %b;cont1_inv = %b;r_in = %b;stato = %b;x_out = %b;clock = %b;reset = %b;stbi = %b;x_in = %b;",cont,cont1,cont1_inv,r_in,stato,x_out,clock,reset,stbi,x_in);
end
endmodule
module tb(input reset, input clock);
// Generated top module signals
reg [5:0] x_in = 6'b0;
reg stbi = 1'b0;
//reg reset;
wire [5:0] x_out;
// Generated top module instance
b11 _conc_top_inst(
.x_in ( x_in ),
.stbi ( stbi ),
.clock ( clock ),
.reset ( reset ),
.x_out ( x_out ));
// Generated internal use signals
reg [31:0] _conc_pc;
reg [6:0] _conc_opcode;
reg [6:0] _conc_ram[0:3];
// Generated program counter
always @(posedge clock) begin
_conc_opcode = _conc_ram[_conc_pc];
stbi <= _conc_opcode[6];
x_in <= _conc_opcode[5:0];
_conc_pc = _conc_pc + 32'b1;
$display(";_C %d", _conc_pc);
end
// Generated initial block
initial begin
//reset = 1'b0;
_conc_pc = 32'b0;
$readmemb("data.mem", _conc_ram);
//reset = 1'b1;
end
endmodule
- 这个tb的含义是,打开
data.mem
文件,把里面的测试串传入进去。 _conc_ram[0:3]
指的是我们会导入4个测试串。- 下面是
data.mem
的内容。
0101001
0000111
1101100
0101011
- 注意底下这个回车是不可省略的!
1. 我们来查看一下文件夹结构
.
.
├── b11.v
├── data.mem
├── sim_main.cpp
└── src
└── b11.v
1 directory, 4 files
2. 首先我们要对b11.v文件编译,把它变为cpp文件
-
首先执行:
verilator --cc b11.v --exe sim_main.cpp
-
这个语句的含义是通过verilator把b11.v转化为cpp文件,并且指定test bench的名字为sim_main。
3. sim_main.cpp文件
- 执行完过后我们生成了一个
obj_dir
文件,我们现在书写sim_main.cpp
文件。
#include "Vb11.h"
#include "verilated.h"
vluint64_t sim_time = 0; // 用于计数时钟边沿
int main(int argc, char **argv, char **env) {
Verilated::commandArgs(argc, argv);
Vb11* top = new Vb11;
while (sim_time <= 10)
{
top->clock ^= 1;
if(sim_time < 3){
top->reset = 1;
}else{
top->reset = 0;
}
printf("clock = %d reset = %d sim_time = %d\n", top->clock,top->reset,sim_time);
top->eval();
sim_time++;
}
exit(0);
}
- 我们要把这个文件拖进
obj_dir
中。 - 现在的文件结构如下图所示:
.
├── b11.v
├── data.mem
├── obj_dir
│ ├── data.mem
│ ├── sim_main.cpp
│ ├── Vb11_classes.mk
│ ├── Vb11.cpp
│ ├── Vb11.h
│ ├── Vb11.mk
│ ├── Vb11__Syms.cpp
│ ├── Vb11__Syms.h
│ ├── Vb11__ver.d
│ └── Vb11__verFiles.dat
├── sim_main.cpp
└── src
└── b11.v
- 同理,我们也得把
data.mem
拖进去。
4. 我们编译出可执行文件
cd obj_dir
make -j8 -f Vb11.mk Vb11
- make后面参数的含义可以自己查。
- 最后我们进行仿真:
./Vb11
clock = 1 reset = 1 sim_time = 0
;A 0
clock = 0 reset = 1 sim_time = 1
clock = 1 reset = 1 sim_time = 2
target
;A 3
;A 4
;A 5
;A 6
;A 7
;F cont = 000000;cont1 = 000000000;cont1_inv = 000000000;r_in = 000000;stato = 0000;x_out = 000000;clock = 1;reset = 1;stbi = 0;x_in = 000000;
;_C 1
clock = 0 reset = 0 sim_time = 3
clock = 1 reset = 0 sim_time = 4
;A 8
;A 9
;A 10
;A 11
;A 12
;F cont = 000000;cont1 = 000000000;cont1_inv = 000000000;r_in = 101001;stato = 0001;x_out = 000000;clock = 1;reset = 0;stbi = 0;x_in = 101001;
;_C 2
clock = 0 reset = 0 sim_time = 5
clock = 1 reset = 0 sim_time = 6
;A 13
;A 14
;A 16
;A 18
;F cont = 000000;cont1 = 000000000;cont1_inv = 000000000;r_in = 000111;stato = 0010;x_out = 000000;clock = 1;reset = 0;stbi = 0;x_in = 000111;
;_C 3
clock = 0 reset = 0 sim_time = 7
clock = 1 reset = 0 sim_time = 8
;A 19
;A 21
;A 28
;A 30
;F cont = 000000;cont1 = 000000000;cont1_inv = 000000000;r_in = 000111;stato = 0011;x_out = 000000;clock = 1;reset = 0;stbi = 1;x_in = 101100;
;_C 4
clock = 0 reset = 0 sim_time = 9
clock = 1 reset = 0 sim_time = 10
;A 32
;A 33
;A 35
;A 37
;F cont = 000000;cont1 = 000000000;cont1_inv = 000000000;r_in = 000111;stato = 0100;x_out = 000000;clock = 1;reset = 0;stbi = 0;x_in = 101011;
;_C 5
- 我们观察到,只有处于上升沿的clock才能触发迭代,所以我们需要迭代(x+1)*2次,例如我们想迭代4个cycle,那么我们的while循环需要重复10次。