这是一个UVM的demo项目:
做一个包含绝大部分组件的uvm(sequencer, driver, monitor, agent, scoreboard, model), 验证一个同向放大器的dut, 主要验证点是
(1)放大倍数设定是否正确(过一个时钟后采集结果比较, 在sequence里直接比较)
(2) 放大值是否计算正确(和调用c++的dll 计算的预期结果, 在scoreboard里比较)
(3) 断言覆盖率
(4) 功能覆盖率
教学视频
IC验证 - 手把手教你搭建UVM芯片验证环境(含代码)_哔哩哔哩_bilibili
代码下载
IC验证-uvm验证demo代码-其它文档类资源-优快云下载
PPT下载
https://blog.youkuaiyun.com/howard789/article/details/123237280



目录结构

param_def.v
`define NO_WIDTH 8
`define BASE_NUMBER_WIDTH 8
`define SCALER_WIDTH 16
`define WR_DATA_WIDTH 16
`define RES_WIDTH 24
`define RD_DATA_WIDTH 32
amplifier.v
`include "param_def.v"
module amplifier
(
clk_i,
rstn_i,
wr_en_i,
set_scaler_i,
wr_data_i,
rd_val_o,
rd_data_o,
scaler_o
);
input clk_i;
input rstn_i;
input wr_en_i; //
input set_scaler_i; //是否是修改scaler
input [`WR_DATA_WIDTH-1:0] wr_data_i; //输入序号8位 输入数字8位 ,或 sacaler 16位
output reg rd_val_o; //data_o有效
output reg [`RD_DATA_WIDTH-1:0] rd_data_o; //输出资料包括 序号[31:24], 基本数字[23:16], 放大后的数字[15:0]其中第15位是正负号
output [`SCALER_WIDTH-1:0] scaler_o; //當前的scaler
//=============================================================================
//**************************** Main Code *******************************
//=============================================================================
reg [`SCALER_WIDTH-1:0] scaler; //max 65,535
assign scaler_o = scaler;
reg flag;
reg [`NO_WIDTH-1:0] no_r;
reg [`RES_WIDTH-1:0] res_r;
always @ (posedge clk_i or negedge rstn_i) begin
if(rstn_i == 1'b0) begin
no_r <= 1'b0;
res_r <= 1'b0;
scaler <= 1'b0;
flag <= 1'b0;
end
//bug start 1
else if(wr_en_i && set_scaler_i && wr_data_i == 16'd5) begin
scaler <= 16'd55;
no_r <= 1'b0;
res_r <= 1'b0;
flag <= 1'b0;
end
// bug end 1
else if(wr_en_i && set_scaler_i) begin
scaler <= wr_data_i;
no_r <= 1'b0;
res_r <= 1'b0;
flag <= 1'b0;
end
//bug start 2
else if(wr_en_i && !set_scaler_i && wr_data_i[ 7:0]== 8'd123) begin
scaler <= scaler;
no_r <= wr_data_i[15:8];
res_r <= wr_data_i[ 7:0] * 100;
flag <= 1'b1;
end
// bug end 2
else if(wr_en_i && !set_scaler_i) begin
scaler <= scaler;
no_r <= wr_data_i[15:8];
res_r <= wr_data_i[ 7:0] * scaler;
flag <= 1'b1;
end
else begin
scaler <= scaler;
no_r <= 1'b0;
res_r <= 1'b0;
flag <= 1'b0;
end
end
always @ (posedge clk_i or negedge rstn_i) begin
if(rstn_i == 1'b0) begin
rd_val_o <= 1'b0;
rd_data_o <= 1'b0;
end
else if(flag) begin
rd_val_o <= 1'b1;
rd_data_o <= {no_r,res_r};
end
else begin
rd_val_o <= 1'b0;
rd_data_o <= 1'b0;
end
end
endmodule
basic_tb.sv
`timescale 1ps/1ps
`include "../dut/param_def.v"
parameter T = 2;
module ref_tb;
bit clk,rstn;
initial begin
fork
begin
forever #(T/2) clk = !clk;
end
begin
rstn <= 1'b0;
#T;
rstn <= 1'b1;
end
join_none
end
logic wr_en_i;
logic set_scaler_i;
logic [`WR_DATA_WIDTH-1:0] wr_data_i;
logic rd_val_o;
logic [`RD_DATA_WIDTH-1:0] rd_data_o;
logic [`SCALER_WIDTH-1:0] scaler_o;
initial begin
wait(!rstn);
#T;
wr_en_i =1'b0;
set_scaler_i =1'b0;
wr_data_i = 16'd0;
#(T*2);
// 设定scaler 100
wr_en_i =1'b1;
set_scaler_i =1'b1;
wr_data_i = 16'd100;
$display("input scaler %d ",set_scaler_i);
#T;
//查看是否设定成功
$display("rd_val_o %d ",rd_val_o);
$display("rd_data_o %d ",rd_data_o);
$display("scaler_o %d ",scaler_o);
#T;
//输入base_number
wr_en_i =1'b1;
set_scaler_i =1'b0;
wr_data_i ={8'd5,8'd25};
$display("input no %d ",wr_data_i[15:8]);
$display("input base number %d ",wr_data_i[ 7:0]);
#T;
//查看结果
$display("rd_val_o %d ",rd_val_o);
$display("rd_data_o no %d ",rd_data_o[31:24]);
$display("rd_data_o res %d ",rd_data_o[23:0]);
$display("scaler_o %d ",scaler_o);
#T;
//查看结果
$display("rd_val_o %d ",rd_val_o);
$display("rd_data_o no %d ",rd_data_o[31:24]);
$display("rd_data_o res %d ",rd_data_o[23:0]);
$display("scaler_o %d ",scaler_o);
end
amplifier amplifier_inst
(
.clk_i(clk),
.rstn_i(rstn),
.wr_en_i(wr_en_i),
.set_scaler_i(set_scaler_i),
.wr_data_i(wr_data_i),
.rd_val_o(rd_val_o),
.rd_data_o(rd_data_o),
.scaler_o(scaler_o)
);
endmodule
ue_tb.sv
`timescale 1ns/1ps
import uvm_pkg::*;
`include "uvm_macros.svh"
// `include "../uvm/ue_pkg.svh"
module ue_tb;
parameter T = 2;
bit clk,rstn;
string s;
int res;
initial begin
fork
begin
forever #(T/2) clk = !clk;
end
begin
rstn <= 1'b0;
#T;
rstn <= 1'b1;
end
join_none
end
// ue_interface intf(clk, rstn);
ue_interface intf(.*);
amplifier amplifier_inst
(
.clk_i(clk),
.rstn_i(rstn),
.wr_en_i(intf.wr_en_i),
.set_scaler_i(intf.set_scaler_i),
.wr_data_i(intf.wr_data_i),
.rd_val_o(intf.rd_val_o),
.rd_data_o(intf.rd_data_o),
.scaler_o(intf.scaler_o)
);
initial begin
uvm_config_db#(virtual ue_interface)::set(uvm_root::get(), "uvm_test_top.env.i_agt", "vif", intf);
uvm_config_db#(virtual ue_interface)::set(uvm_root::get(), "uvm_test_top.env.o_agt", "vif", intf);
end
initial begin
// run_test("ue_case0_test");
// run_test("ue_case1_test");
// run_test("ue_case2_test");
run_test();
end
endmodule
ue_agent.sv
`ifndef UE_AGENT_SV
`define UE_AGENT_SV
//---------------------------------------
// svh
//---------------------------------------
class ue_agent extends uvm_agent;
uvm_active_passive_enum is_active;
ue_driver drv;
ue_sequencer sqr;
ue_monitor mon;
ue_config cfg;
virtual ue_interface vif;
`uvm_component_utils(ue_agent)
extern function new(string name = "ue_agent",uvm_component parent = null);
extern function void build();
extern function void connect();
extern function void report();
endclass
//---------------------------------------
// sv
//---------------------------------------
function ue_agent::new(string name = "ue_agent" ,uvm_component parent = null);
super.new(name, parent);
`uvm_info(get_type_name(), $sformatf("created, is_active: %s" ,is_active), UVM_LOW)
endfunction : new
function void ue_agent::build();
super.build();
if(!uvm_config_db#(ue_config)::get(this,"","cfg", cfg)) begin
cfg = ue_config::type_id::create("cfg");
end
`uvm_info(get_type_name(), $sformatf("start to build, is_active: %s",is_active), UVM_LOW)
if(!uvm_config_db#(virtual ue_interface)::get(this,"","vif", vif)) begin
`uvm_fatal("GETVIF","cannot get vif handle from config DB")
end
vif.start_report=0;
mon = ue_monitor::type_id::create("mon",this);
mon.vif=vif;
if(is_active==UVM_ACTIVE) begin
sqr = ue_sequencer::type_id::create("sqr",this);
drv = ue_driver::type_id::create("drv",this);
drv.vif = vif;
mon.monitor_input=1'b1;
end
else
mon.monitor_input=1'b0;
`uvm_info(get_type_name(), "built", UVM_LOW)
endfunction:build
function void ue_agent::connect();
if(is_active==UVM_ACTIVE) begin
drv.seq_item_port.connect(sqr.seq_item_export);
end
`uvm_info(get_type_name(), "connected", UVM_LOW)
endfunction:connect
function void ue_agent::report();
super.report();
vif.start_report=1;
endfunction:report
`endif // UE_AGENT_SV
ue_base_test.sv
`ifndef UE_BASE_TEST_SV
`define UE_BASE_TEST_SV
//--------------------------------------------------------------------------------------------------------
// svh
//--------------------------------------------------------------------------------------------------------
class ue_base_test extends uvm_test;
ue_env env;
`uvm_component_utils(ue_base_test)
extern function new(string name="ue_base_test",uvm_component parent = null);
extern function void build();
extern function void report();
endclass
//--------------------------------------------------------------------------------------------------------
// sv
//--------------------------------------------------------------------------------------------------------
function ue_base_test::new(string name ="ue_base_test",uvm_component parent = null);
super.new(name, parent);
`uvm_info(get_type_name(), $sformatf("created"), UVM_LOW)
endfunction : new
function void ue_base_test::build();
super.build();
env = ue_env::type_id::create("env",this);
`uvm_info(get_type_name(), "built", UVM_LOW)
endfunction
function void ue_base_test::report();
uvm_report_server server;
int err_num;

这是一个使用UVM组件库构建的模拟器验证环境,包括 sequencer, driver, monitor, agent 和 scoreboard。主要验证点是放大倍数设置、放大值计算、断言覆盖率和功能覆盖率。通过创建不同类型的序列(如设置增益、写入基数值),模拟器接收并处理这些请求,然后在scoreboard中与预期结果进行比较,确保正确性。此外,还包含了覆盖率组和断言,以评估和验证设计的行为。
最低0.47元/天 解锁文章
4899

被折叠的 条评论
为什么被折叠?



