2024. 8. 13. 00:59ㆍSystem Verilog
Cadence사의 Xcelium은 xmvlog, xmelab, xmsim을 xrun이라는 커맨드를 통해 한번에 실행할 수 있다.
vivado로 Xcelium처럼 한번에 실행하는 Command는 찾지 못했다.
#!/bin/bash
./:del
xvlog -f file.f -sv
xelab tb
xsim tb -t log_wave.tcl -wdb dump.wdb -view dump.wdb -gui
xvlog는 xrun -c 에 해당하며, Compile만 수행한다. -f은 filelist를 물려 돌리는 option, -sv는 systemverilog compile시 사용한다. -sv 옵션을 사용하지 않으면 일반 verilog로 인식해 문법 오류가 날 수 있다,
xvlog와 xelab은 일반적인 시뮬레이터와 비슷하게 쓸 수 있었지만, xsim은 살짝 달랐다.
xcelium에서는 -input option을 통해 tcl로 simulation을 실행하는 도중 명령을 추가로 내릴 수 있는데, vivado에서도 유사하게 사용할 수 있다.
차이점은 simulation dump 파일이다.
Cadence사의 simVison에서 사용하는 *.shm이나, Synopsys사의 Verdi에서 사용하는 *.fsdb처럼 $shm_open 또는 $fsdbdumpfile과 같이 *.wdb를 dump받을 수 있는 task가 없는 듯 했다. (아직 찾지 못함)
따라서 $dumpfile, $dumpvars를 이용해 dump를 만든 뒤 -wdb 옵션을 통해 wdb 파일을 만들어 줘야 한다.
-wdb를 사용하지 않으면 work.lib.wdb라는 기본 파일이 만들어진다.
그리고, tcl을 통해서 어떤 signal을 wdb에 dump받을지 정해줘야 한다. option은 다음과 같다.
• All signals in the design (excluding those of alternate top modules):
log_wave -r /
• All signals in a scope: /tb:
log_wave /tb/*
• Those objects having names that start with a and end in b and have digits in between:
log_wave [get_objects -regexp {^a[0-9]+b$}]
• All objects in the current scope and all child scopes, recursively:
log_wave -r *
• The objects in the current scope:
log_wave *
• Only the ports of the scope /tb/UUT, use the command:
log_wave [get_objects -filter {type == in_port || type == out_port || type == inout_port || type == port} /tb/UUT/*]
• Only the internal signals of the scope /tb/UUT, use the command:
log_wave [get_objects -filter {type == signal} /tb/UUT/*]
이 때 주의할 점은 $dump를 받지 않으면 dump를 찾을 수 없다며 오류가 나는데, $dumpfiles를 통해 만들어진 vcd를 기반으로 wdb를 만들어 주는 듯하다. 확실하진 않다.
-view 와 -gui는 같이 쓰는것을 권장한다 하며, -view는 *.wdb를 지정한다. 여러개의 wdb가 있으면 wdb개수만큼 해당 옵션을 넣어줘야한다.
Vivado Design Suite Tcl Command Reference Guide 에 사용하는 방법이 자세히 나와있다.
위 3개의 command를 쭉 실행하면 다음과 같이 친숙한 vivado의 simulator화면이 켜진다.
해당 코드는 RISC-V의 register file을 test하기 위해 작성한 것이다.
module riscv_rf #(parameter WD = 32)(
input i_clk ,
input i_rstn ,
input [WD-1 : 0] i_data ,
input [4 : 0] i_RD ,
input [4 : 0] i_RS1 , //register source1
input [4 : 0] i_RS2 , //register source2
input i_wen ,
output [WD-1 : 0] o_RS1_data ,
output [WD-1 : 0] o_RS2_data
);
localparam stack_address = 1024;
reg [WD-1 : 0] r_x [0 : 32-1];
integer i,j;
always @(posedge i_clk, negedge i_rstn) begin
if(!i_rstn)begin
for(i=0; i<32; i=i+1)begin
if(i!=2)
r_x[i] <= #0.1 32'b0;
else
r_x[i] <= #0.1 stack_address; //r_x[2]= stack pointer
end
end
else if(i_wen)begin
r_x[i_RD] <= #0.1 i_data;
end
else begin
for(j=0; j<32; j=j+1)begin
r_x[j] <= #0.1 r_x[j];
end
end
end
assign o_RS1_data = r_x[i_RS1];
assign o_RS2_data = r_x[i_RS2];
endmodule
일반적으로 하드웨어 설계할 때 권장되는 방식은 아니지만, 32개의 register를 하나하나 다 치기 귀찮아서 for문과 memory를 사용하였다.
module tb;
reg clk, rstn, wen1, wen2;
reg [31:0] data;
reg [4:0] RD1, RD2, RS1, RS2;
wire [31:0] RS1_data, RS2_data;
riscv_rf u_riscv_rf(
.i_clk ( clk ),
.i_rstn ( rstn ),
.i_data ( data ),
.i_RD ( RD1 ),
.i_RS1 ( RS1 ),
.i_RS2 ( RS2 ),
.i_wen ( wen1 ),
.o_RS1_data ( RS1_data ),
.o_RS2_data ( RS2_data )
);
always #5 clk = !clk;
task write();
for(int i = 0; i < 32; i++)begin
RD1 = i;
data= 32'h 10000000 + i;
wen1 = 1'b1;
#15;
end
endtask
task read();
for(int i = 0; i < 15; i++)begin
RS1 = i;
RS2 = i + 16;
#15;
end
endtask
initial begin
$dumpfile("dump.vcd");
$dumpvars(0, tb);
end
initial begin
clk = 0;
rstn = 0;
wen1 = 0;
wen2 = 0;
data = 0;
RD1 = 0;
RD2 = 0;
RS1 = 0;
RS2 = 0;
#10 rstn = 1'b1;
write();
#100;
read();
$finish();
end
endmodule
'System Verilog' 카테고리의 다른 글
ERROR: [XSIM 43-3409] Failed to compile generated C file xsim.dir/work.top/obj/xsim_22.c. 에러 고치기 (0) | 2024.09.02 |
---|---|
Vivado CLI로 UVM 사용하기 (0) | 2024.05.27 |