sometimes,自己写了块RTL,想快速地输入激励看一下结果;根据UVM的套路一步步的搭建看来是太费劲了;本文就给出了一种简单方法,可以快速简单的给出激励;
1 RTL
本文的DUT如下,file名字test_md.v
其实现的功能很简单,通过一组BUS读写寄存器;
module test_md(
input clk ,
input rst_n,
input rd ,
input wr ,
input [1:0] addr ,
input [31:0] wdata,
output reg ack ,
output reg [31:0] rdata
);
reg [31:0] cfg_test0;
reg [31:0] cfg_test1;
reg [31:0] cfg_test2;
reg [31:0] cfg_test3;
always@(posedge clk or negedge rst_n) begin
if(rst_n==1'b0) begin
cfg_test0<=32'b0;
cfg_test1<=32'b0;
cfg_test2<=32'b0;
cfg_test3<=32'b0;
end
else if(wr) begin
if(addr==2'd0) cfg_test0<=wdata;
if(addr==2'd1) cfg_test1<=wdata;
if(addr==2'd2) cfg_test2<=wdata;
if(addr==2'd3) cfg_test3<=wdata;
end
end
always@(posedge clk or negedge rst_n) begin
if(rst_n==1'b0)
cfg_test0<=32'b0;
else if(rd) begin
case(addr)
2'd0: rdata<=cfg_test0;
2'd1: rdata<=cfg_test1;
2'd2: rdata<=cfg_test2;
2'd3: rdata<=cfg_test3;
endcase
end
end
always@(posedge clk or negedge rst_n) begin
if(rst_n==1'b0)
ack<=1'b0;
else
ack<=wr | rd;
end
endmodule
2 TB and CASE
这里TB和CASE用一个文件实现,名字为top_tb.sv
代码如下:
`timescale 1ns/1ps //part 1
`include "test_md.v" //part 2
interface acc_if(input clk); //part 3
bit rd ;
bit wr ;
bit [1:0] addr ;
bit [31:0] wdata;
bit [31:0] rdata;
bit ack ;
endinterface
class acc_drv; //part 4
virtual acc_if vif;
function new(virtual acc_if cc_if);
this.vif=cc_if;
endfunction
extern task init();
extern task write(bit[1:0] addr,bit[31:0] wdata);
extern task read (bit[1:0] addr,output bit[31:0] rdata);
endclass;
task acc_drv::init();
vif.wr =0;
vif.rd =0;
vif.addr =0;
vif.wdata=0;
endtask
task acc_drv::write(bit[1:0] addr, bit[31:0] wdata);
repeat(1)@(vif.clk);
vif.wr =1;
vif.addr =addr;
vif.wdata =wdata;
repeat(1)@(vif.clk);
vif.wr =0;
vif.addr =0;
endtask
task acc_drv::read(bit[1:0] addr, output bit[31:0] rdata);
repeat(1)@(vif.clk);
vif.rd =1;
vif.addr =addr;
repeat(1)@(vif.clk);
vif.rd =0;
vif.addr =0;
rdata =vif.rdata;
endtask
module top_tb; //part 5
bit clk;
bit rst_n;
bit [31:0] rdata;
acc_if u_acc_if(clk);
test_md U_TEST_MD(
.clk (clk ),
.rst_n (rst_n ),
.rd (u_acc_if.rd ),
.wr (u_acc_if.wr ),
.addr (u_acc_if.addr ),
.wdata (u_acc_if.wdata ),
.ack (u_acc_if.ack ),
.rdata (u_acc_if.rdata )
);
initial begin
clk=0;
forever #5 clk=~clk;
end
initial begin
rst_n=0;
#30 rst_n=1'b1;
end
initial begin
acc_drv bus;
bus=new(u_acc_if);
bus.init();
wait(rst_n);
bus.write(2'b0,32'hA);
bus.read(2'b0,rdata);
if(rdata==32'hA) begin
$display("compare ok!!");
end
else begin
$display("compare failed!!");
end
#400 $finish();
end
initial begin
$fsdbDumpfile("top_tb.fsdb");
$fsdbDumpvars;
end
endmodule
分为5个大部分:
- timescale
- include RTL
- interface定义
- class定义,主要定义驱动class及其task与function:
- 注意要声明一个virtual interface,类型和part 3一致;
- new函数中对virtual interface赋值;
- module定义,这里将class和interface例化,并完成主要功能
- 声明clk,rst_n和其他变量;
- 例化一个interface实体;
- 例化DUT,并和interface实体相连;
- clk和rst的产生;
- 生成class句柄,new时候将实体interface赋值给virtual interface
- 使用class中的task驱动DUT
- 比较结果,finish
- dump波形
3 makefile
case := top_tb
file := $(addsuffix .sv,$(case))
comp:
vcs -sverilog -debug_access -kdb $(file) -f "xxx.f" -l comp.log +lint=TFIPC-L
sim:
./simv -l sim.log
run: comp sim
verdi:
verdi -dbdir simv.daidir -ssf top_tb.fsdb
clean:
rm -r *.log *fsdb* *.key csrc verdiLog simv.daidir simv *.rc *.conf
将test_md.v,top_tb.sv和makefile这3个file放在一个路径;执行下面命令即可完成simulation
> make run
4 结束语
SV在RTL验证中功能不是死板的,可以很灵活地完成各种想要验证的内容;