这是一个UVM的demo项目:
做一个包含绝大部分组件的uvm(sequencer, driver, monitor, agent, scoreboard, model), 验证一个同向放大器的dut, 主要验证点是
(1)放大倍数设定是否正确(过一个时钟后采集结果比较, 在sequence里直接比较)
(2) 放大值是否计算正确(和调用c++的dll 计算的预期结果, 在scoreboard里比较)
(3) 断言覆盖率
(4) 功能覆盖率
教学视频
IC验证 - 手把手教你搭建UVM芯片验证环境(含代码)_哔哩哔哩_bilibili
代码下载
IC验证-uvm验证demo代码-其它文档类资源-CSDN下载
PPT下载
https://blog.csdn.net/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;
super.report();
server = get_report_server();
err_num = server.get_severity_count(UVM_ERROR);
if(err_num != 0)
`uvm_info(get_type_name(), $sformatf("err_num:%0d TEST CASE FAILED",err_num), UVM_LOW)
else
`uvm_info(get_type_name(), $sformatf("TEST CASE PASSED"), UVM_LOW)
endfunction
`endif // UE_BASE_TEST_SV
ue_driver.sv
`ifndef UE_DRIVER_SV
`define UE_DRIVER_SV
//---------------------------------------
// svh
//---------------------------------------
class ue_driver extends uvm_driver #(ue_transaction);
bit show_info;
ue_config cfg;
virtual ue_interface vif;
`uvm_component_utils(ue_driver)
extern function new(string name ="ue_driver",uvm_component parent = null);
extern function void build();
extern task run();
extern protected task _reset_listener();
extern protected task _get_and_drive();
extern protected task _drive_transfer(ue_transaction t);
extern protected task _do_idle();
extern protected task _set_scaler(ue_transaction t);
extern protected task _wr_base_number(ue_transaction t);
endclass : ue_driver
//---------------------------------------
// sv
//---------------------------------------
function ue_driver::new(string name ="ue_driver",uvm_component parent = null);
super.new(name, parent);
`uvm_info(get_type_name(), $sformatf("created"), UVM_LOW)
endfunction : new
function void ue_driver::build();
super.build();
if(!uvm_config_db#(ue_config)::get(this,"","cfg", cfg)) begin
cfg = ue_config::type_id::create("cfg");
end
show_info = cfg.show_info_drv;
`uvm_info(get_type_name(), "built", UVM_LOW)
endfunction : build
task ue_driver::run();
super.run();
vif.wr_en_i = 1'b0;
vif.set_scaler_i = 1'b0;
vif.wr_data_i = 1'b0;
vif.rd_val_o = 1'b0;
vif.rd_data_o = 1'b0;
vif.scaler_o = 1'b0;
while(!vif.rstn)
@(posedge vif.clk);
`uvm_info(get_type_name(), "start run()", UVM_LOW)
fork
ue_driver::_get_and_drive();
ue_driver::_reset_listener();
join
`uvm_info(get_type_name(), "end run()", UVM_LOW)
endtask : run
task ue_driver::_reset_listener();
forever begin
@(negedge vif.rstn);
vif.wr_en_i = 0;
vif.set_scaler_i =0 ;
vif.wr_data_i = 0;
if(show_info)
`uvm_info(get_type_name(), "_reset_listener done", UVM_LOW)
end
endtask
task ue_driver::_drive_transfer(ue_transaction t);
if(show_info)
t.print_info("ue_driver _drive_transfer");
case (t.ttype)
ue_transaction::IDLE:_do_idle();
ue_transaction::SET_SCALER:_set_scaler(t);
ue_transaction::WR_BASE_NUMBER:_wr_base_number(t);
default:`uvm_error("ERRTYPE", "_drive_transfer mode err")
endcase
endtask
task ue_driver::_do_idle();
@(vif.cb_drv);
vif.cb_drv.wr_en_i <= 1'b0;
vif.cb_drv.wr_data_i<= 1'b0;
endtask
task ue_driver::_set_scaler(ue_transaction t);
@(vif.cb_drv);
vif.cb_drv.wr_en_i <= 1'b1;
vif.cb_drv.set_scaler_i<= 1'b1;
vif.cb_drv.wr_data_i <= t.wr_scaler;
@(vif.cb_drv);//dut收到信号
@(vif.cb_drv);
t.rd_scaler = vif.cb_drv.scaler_o;
endtask
task ue_driver::_wr_base_number(ue_transaction t);
@(vif.cb_drv);
vif.cb_drv.wr_en_i <= 1'b1;
vif.cb_drv.set_scaler_i <= 1'b0;
vif.cb_drv.wr_data_i <= {t.no,t.base_number};
t.rd_scaler = vif.cb_drv.scaler_o;
repeat(t.idle_cycles) _do_idle();
endtask
task ue_driver::_get_and_drive();
forever begin
seq_item_port.get_next_item(req);
this._drive_transfer(req);
void'($cast(rsp, req.clone()));
rsp.set_sequence_id(req.get_sequence_id());
seq_item_port.item_done(rsp);
end
endtask
`endif // UE_DRIVER_SV
ue_env.sv
`ifndef UE_ENV_SV
`define UE_ENV_SV
//---------------------------------------
// svh
//---------------------------------------
class ue_env extends uvm_env;
ue_config cfg;
ue_agent i_agt;
ue_agent o_agt;
ue_ref_model mdl;
ue_scoreboard scb;
uvm_tlm_analysis_fifo #(ue_transaction) iagt_mdl_fifo;
uvm_tlm_analysis_fifo #(ue_transaction) oagt_scb_fifo;
uvm_tlm_analysis_fifo #(ue_transaction) mdl_scb_fifo;
`uvm_component_utils(ue_env)
extern function new (string name = "ue_env", uvm_component parent =null);
extern function void build();
extern function void connect();
extern function void report();
endclass : ue_env
//---------------------------------------
// sv
//---------------------------------------
function ue_env::new(string name ="ue_env",uvm_component parent = null);
super.new(name, parent);
`uvm_info(get_type_name(), $sformatf("created"), UVM_LOW)
endfunction : new
function void ue_env::build();
super.build();
if(!uvm_config_db#(ue_config)::get(this,"","cfg", cfg)) begin
cfg = ue_config::type_id::create("cfg");
end
i_agt = ue_agent::type_id::create("i_agt",this);
i_agt.is_active=cfg.i_agt_is_active;
o_agt = ue_agent::type_id::create("o_agt",this);
o_agt.is_active=cfg.o_agt_is_active;
mdl = ue_ref_model::type_id::create("mdl",this);
scb = ue_scoreboard::type_id::create("scb",this);
iagt_mdl_fifo = new("iagt_mdl_fifo",this);
oagt_scb_fifo = new("oagt_scb_fifo",this);
mdl_scb_fifo = new("mdl_scb_fifo",this);
`uvm_info(get_type_name(), $sformatf("built"), UVM_LOW)
endfunction :build
function void ue_env::connect();
super.connect();
i_agt.mon.ap.connect(iagt_mdl_fifo.analysis_export);
mdl.gp.connect(iagt_mdl_fifo.blocking_get_export);
o_agt.mon.ap.connect(oagt_scb_fifo.analysis_export);
scb.act_gp.connect(oagt_scb_fifo.blocking_get_export);
mdl.ap.connect(mdl_scb_fifo.analysis_export);
scb.exp_gp.connect(mdl_scb_fifo.blocking_get_export);
`uvm_info(get_type_name(), "connected", UVM_LOW)
endfunction :connect
function void ue_env::report();
super.report();
if(i_agt.mon.sent_item_num == o_agt.mon.sent_item_num)
`uvm_info(get_type_name(), "sent_item_num check ok", UVM_LOW)
else
`uvm_error("ENV_ERROR", "sent_item_num check error")
endfunction:report
`endif // UE_ENV_SV
ue_monitor.sv
`ifndef UE_MONITOR_SV
`define UE_MONITOR_SV
//---------------------------------------
// svh
//---------------------------------------
class ue_monitor extends uvm_monitor;
bit show_info;
ue_config cfg;
bit monitor_input;
int sent_item_num;
virtual ue_interface vif;
uvm_analysis_port #(ue_transaction) ap;
protected ue_transaction trans_collected; //内部使用的指针
`uvm_component_utils(ue_monitor)
extern function new(string name ="ue_monitor",uvm_component parent = null);
extern function void build();
extern task run();
extern protected task _collect_transfer(ue_transaction t);
extern function void report();
endclass
//---------------------------------------
// sv
//---------------------------------------
function ue_monitor::new(string name="ue_monitor",uvm_component parent = null);
super.new(name, parent);
`uvm_info(get_type_name(), $sformatf("created"), UVM_LOW)
endfunction : new
function void ue_monitor::build();
ap = new("ap",this);
if(!uvm_config_db#(ue_config)::get(this,"","cfg", cfg)) begin
cfg = ue_config::type_id::create("cfg");
end
show_info = cfg.show_info_mon;
sent_item_num = 0;
`uvm_info(get_type_name(), $sformatf("built"), UVM_LOW)
endfunction
task ue_monitor::run();
super.run();
`uvm_info(get_type_name(), "start run()", UVM_LOW)
fork
while(1) begin
@(vif.cb_mon);
trans_collected = ue_transaction::type_id::create("trans_collected");
this._collect_transfer(trans_collected);//收集vif的资料赋值给 trans_collected
if(monitor_input && trans_collected.ttype==ue_transaction::WR_BASE_NUMBER) begin
ap.write(trans_collected);
sent_item_num+=1;
if(show_info)
trans_collected.print_info("mon input");
end
else if(trans_collected.rd_valid) begin
ap.write(trans_collected);
sent_item_num+=1;
if(show_info)
trans_collected.print_info("mon output");
end
end
join
`uvm_info(get_type_name(), "end run()", UVM_LOW)
endtask
function void ue_monitor::report();
super.report();
`uvm_info(get_type_name(), $sformatf("sent_item_num:%d",sent_item_num), UVM_LOW)
endfunction:report
task ue_monitor::_collect_transfer(ue_transaction t);
@(vif.cb_mon);
if(monitor_input)begin //i_agent
if(vif.cb_mon.wr_en_i && !vif.cb_mon.set_scaler_i) begin
t.ttype = ue_transaction::WR_BASE_NUMBER;
t.no = vif.cb_mon.wr_data_i[15:8];
t.base_number = vif.cb_mon.wr_data_i[7:0];
t.rd_scaler = vif.cb_mon.scaler_o;
end
else if(vif.cb_mon.wr_en_i && vif.cb_mon.set_scaler_i) begin
t.ttype = ue_transaction::SET_SCALER;
t.no = 0;
t.base_number = 0;
t.wr_scaler = vif.cb_mon.wr_data_i;
t.rd_scaler = vif.cb_mon.scaler_o;
end
else begin
t.ttype = ue_transaction::IDLE;
end
end
else begin //o_agent
t.rd_valid = vif.cb_mon.rd_val_o;
t.no = vif.cb_mon.rd_data_o[31:24];
t.rd_data = vif.cb_mon.rd_data_o[23:0];
end
endtask
`endif // UE_MONITOR_SV
ue_ref_model.sv
`ifndef UE_REF_MODEL_SV
`define UE_REF_MODEL_SV
//---------------------------------------
// svh
//---------------------------------------
import "DPI-C" context function int amplifier(input int base_number,int scaler);
export "DPI-C" dpi_info=function dpi_info;
export "DPI-C" dpi_fatal=function dpi_fatal;
function void dpi_info(string s);
`uvm_info("dpi_info", s, UVM_LOW)
endfunction: dpi_info
function void dpi_fatal(string s);
`uvm_fatal("dpi_fatal", s)
endfunction: dpi_fatal
class ue_ref_model extends uvm_component;
ue_config cfg;
bit show_info;
uvm_blocking_get_port #(ue_transaction) gp;
uvm_analysis_port #(ue_transaction) ap;
protected ue_transaction tr;
protected ue_transaction new_tr;
int res;
`uvm_component_utils(ue_ref_model)
extern function new(string name ="ue_ref_model",uvm_component parent = null);
extern function void build();
extern task run();
endclass : ue_ref_model
//--------------------------------------------------------------------------------------------------------
// sv
//--------------------------------------------------------------------------------------------------------
function ue_ref_model::new(string name ="ue_ref_model",uvm_component parent = null);
super.new(name, parent);
`uvm_info(get_type_name(), $sformatf("created, show_info:%0d",show_info), UVM_LOW)
endfunction : new
function void ue_ref_model::build();
super.build();
if(!uvm_config_db#(ue_config)::get(this,"","cfg", cfg)) begin
cfg = ue_config::type_id::create("cfg");
end
show_info = cfg.show_info_mdl;
gp = new("gp", this);
ap = new("ap", this);
if(show_info)
`uvm_info(get_type_name(), "built", UVM_LOW)
endfunction
task ue_ref_model::run();
if(show_info)
`uvm_info(get_type_name(), " start run()", UVM_LOW)
super.run();
while(1) begin
new_tr = new("new_tr");
tr=new("tr");
gp.get(tr);
if(show_info)
tr.print_info("ref_model tr");
new_tr.copy(tr);
//res=tr.base_number*tr.rd_scaler;
res=amplifier(tr.base_number,tr.rd_scaler);
new_tr.rd_data=res;
ap.write(new_tr);
if(show_info)
new_tr.print_info("ref_model new_tr");
end
`uvm_info(get_type_name(), "end run()", UVM_LOW)
endtask
`endif // UE_REF_MODEL_SV
ue_scoreboard.sv
`ifndef UE_SCOREBOARD_SV
`define UE_SCOREBOARD_SV
//---------------------------------------
// svh
//---------------------------------------
class ue_scoreboard extends uvm_scoreboard;
ue_config cfg;
bit show_info;
uvm_blocking_get_port #(ue_transaction) exp_gp;
uvm_blocking_get_port #(ue_transaction) act_gp;
ue_transaction tran_exp,tran_act;
int success_num;
int failure_num;
`uvm_component_utils(ue_scoreboard)
extern function new (string name = "ue_scoreboard", uvm_component parent =null);
extern function void build();
extern task run();
extern function void report();
endclass : ue_scoreboard
//---------------------------------------
// sv
//---------------------------------------
function ue_scoreboard::new(string name ="ue_scoreboard",uvm_component parent = null);
super.new(name, parent);
`uvm_info(get_type_name(), $sformatf("created"), UVM_LOW)
endfunction : new
function void ue_scoreboard::build();
super.build();
if(!uvm_config_db#(ue_config)::get(this,"","cfg", cfg)) begin
cfg = ue_config::type_id::create("cfg");
end
show_info = cfg.show_info_scb;
exp_gp=new("exp_gp",this);
act_gp=new("act_gp",this);
success_num=0;
failure_num=0;
`uvm_info(get_type_name(), "built", UVM_LOW)
endfunction :build
task ue_scoreboard::run();
super.run();
fork
while(1)begin
exp_gp.get(tran_exp);
act_gp.get(tran_act);
if(tran_exp.no!=tran_act.no)
`uvm_info(get_type_name(), $sformatf("no is different,exp:%0d act:%0d",tran_exp.no,tran_act.no), UVM_LOW)
else begin
if(tran_exp.rd_data==tran_act.rd_data) begin
success_num+=1;
if(show_info) begin
`uvm_info(get_type_name(), $sformatf("compare successfully scaler:%0d base_number:%0d rd_data:%0d",tran_act.rd_scaler,tran_act.base_number,tran_act.rd_data), UVM_LOW)
tran_act.print_info(get_type_name());
end
end
else begin
failure_num+=1;
`uvm_error("SCORE_ERROR", $sformatf("compare failed,scaler:%0d,base_number:%0d,exp_res:%0d,act_res:%0d",tran_exp.rd_scaler,tran_exp.base_number,tran_exp.rd_data,tran_act.rd_data))
end
end
end
join
endtask
function void ue_scoreboard::report();
super.report();
if(show_info)
`uvm_info(get_type_name(), $sformatf("report"), UVM_LOW)
`uvm_info(get_type_name(), $sformatf("success_num:%0d",success_num), UVM_LOW)
`uvm_info(get_type_name(), $sformatf("failure_num:%0d",failure_num), UVM_LOW)
// `uvm_info(get_type_name(), $sformatf("failure_base_numbers:%0s",failure_base_numbers), UVM_LOW)
endfunction :report
`endif // UE_SCOREBOARD_SV
ue_sequencer.sv
`ifndef UE_SEQUENCER_SV
`define UE_SEQUENCER_SV
class ue_sequencer extends uvm_sequencer #(ue_transaction);
`uvm_component_utils(ue_sequencer)
extern function new(string name ="ue_sequencer",uvm_component parent = null);
extern function void build();
endclass
//--------------------------------------------------------------------------------------------------------
// sv
//--------------------------------------------------------------------------------------------------------
function ue_sequencer::new(string name ="ue_sequencer",uvm_component parent = null);
super.new(name, parent);
`uvm_info(get_type_name(), $sformatf("created"), UVM_LOW)
endfunction : new
function void ue_sequencer::build();
super.build();
`uvm_info(get_type_name(), "built", UVM_LOW)
endfunction : build
`endif // UE_SEQUENCER_SV
ue_interface.sv
`ifndef UE_INTERFACE_SV
`define UE_INTERFACE_SV
import uvm_pkg::*;
`include "uvm_macros.svh"
`include "param_def.v"
`timescale 1ps/1ps
interface ue_interface (input clk,input rstn);
logic wr_en_i; // input valid
logic set_scaler_i; // is_input_scaler
logic [`WR_DATA_WIDTH-1:0] wr_data_i; // input data: 16 bit scaler or (8 bit no + 8 bit base_number)
logic rd_val_o; // rd_data valid
logic [`RD_DATA_WIDTH-1:0] rd_data_o; //
logic [`SCALER_WIDTH-1:0] scaler_o; //current scaler
bit start_report ;
//---------------------------------------
// clocking
//---------------------------------------
// https://blog.csdn.net/wonder_coole/article/details/82597125
clocking cb_drv @(posedge clk);
default input #1ps output #1ps;
output wr_en_i,set_scaler_i, wr_data_i;
input rd_val_o, rd_data_o,scaler_o;
endclocking : cb_drv
clocking cb_mon @(posedge clk);
default input #1ps output #1ps;
input wr_en_i,set_scaler_i,wr_data_i, rd_val_o,rd_data_o, scaler_o;
endclocking : cb_mon
// cg option https://xueying.blog.csdn.net/article/details/105309727
covergroup cg_wr_command(string comment ="") @(posedge clk iff rstn);
//type total bins: 8-2(ignore_bins)-4(type_option.weight = 0)=2
//instance total bins : 8-2(ignore_bins)=6
// type_option.weight = 0;
// option.goal =100;
// option.auto_bin_max = 100; //default 64
// option.at_least =10;
// option.goal =100;
// option.cross_num_print_missing=1;//多个实例的时候 分开计算
// option.comment=comment; //多个实例的时候
wr_en: coverpoint wr_en_i{
//http://blog.sina.com.cn/s/blog_5391b49c0102vte0.html
type_option.weight = 0;
bins unsel = {0};
bins sel = {1};
}
set_scaler: coverpoint set_scaler_i{
type_option.weight = 0;
bins unsel = {0};
bins sel = {1};
}
cmd: cross wr_en,set_scaler{
bins cmd_set_scaler = binsof(wr_en.sel) && binsof(set_scaler.sel);
bins cmd_write = binsof(wr_en.sel) && binsof(set_scaler.unsel);
ignore_bins ignore0 = binsof(wr_en.unsel) && binsof(set_scaler.sel);
ignore_bins ignore1 = binsof(wr_en.unsel) && binsof(set_scaler.unsel);
// ignore_bins others = default; //采样到的时候, 仿真会停止
// ignore_bins others = binsof(default) && binsof(default);
}
endgroup
covergroup cg_wr_timing_group(string comment ="") @(posedge clk iff (rstn && !set_scaler_i));
//type total bins: 8
//instance total bins : 8-6(option.weight = 0)=2
option.comment=comment;
coverpoint wr_en_i{
bins burst_1 = ( 0 => 1 => 0);
bins burst_2 = ( 0 => 1[*2] => 0);
bins burst_3 = ( 0 => 1[*3] => 0);
bins burst_4 = ( 0 => 1[*4] => 0);
bins burst_5 = ( 0 => 1[*5] => 0);
}
endgroup: cg_wr_timing_group
covergroup cg_scaler_range_group(int low,high,string comment ="") @(posedge clk iff (rstn && wr_en_i && set_scaler_i));
//type total bins: 1
//instance total bins : 1
option.comment=comment;
option.cross_num_print_missing=1;
coverpoint wr_data_i {
bins range[] ={[low:high]};
}
endgroup: cg_scaler_range_group
covergroup cg_base_number_range_group(int low,high,string comment ="") @(posedge clk iff (rstn && wr_en_i && !set_scaler_i));
//type total bins: 1
//instance total bins : 1
option.comment=comment;
option.cross_num_print_missing=1;
coverpoint wr_data_i[7:0] {
bins range[] ={[low:high]};
}
endgroup: cg_base_number_range_group
covergroup cg_scaler_bits_wide_group(string comment ="") @(posedge clk iff (rstn && wr_en_i && set_scaler_i));
//type total bins: 2
//instance total bins : 2
coverpoint wr_data_i {
wildcard bins highest_bit_wide0={16'b1xxx_xxxx_xxxx_xxxx};
wildcard bins highest_bit_wide1={16'b0zzz_zzzz_zzzz_zzzz};
illegal_bins others = default;
}
endgroup: cg_scaler_bits_wide_group
covergroup cg_base_number_bits_wide_group(string comment ="") @(posedge clk iff (rstn && wr_en_i && !set_scaler_i));
//type total bins: 2
//instance total bins : 2
coverpoint wr_data_i {
wildcard bins highest_bit_wide0={16'b????_????_1???_????};
wildcard bins highest_bit_wide1={16'bxxxx_xxxx_0xxx_xxxx};
illegal_bins others = default;
}
endgroup: cg_base_number_bits_wide_group
initial begin
automatic cg_wr_command cg_0= new();
automatic cg_wr_timing_group cg_1= new();
automatic cg_scaler_range_group cg_2= new(1,10);
automatic cg_base_number_range_group cg_3= new(121,130);
automatic cg_scaler_bits_wide_group cg_4= new();
automatic cg_base_number_bits_wide_group cg_5= new();
wait(rstn==0);
cg_0.stop();
wait(rstn==1);
cg_0.start();
cg_0.sample();
cg_0.set_inst_name("cg_0");
wait(start_report)begin
string s;
s={s,"cg_wr_command "};
s={s,$sformatf("coverage:%0d\n",cg_0.get_inst_coverage())};
s={s,"cg_wr_timing_group "};
s={s,$sformatf("coverage:%0d\n",cg_1.get_inst_coverage())};
s={s,"cg_scaler_range_group "};
s={s,$sformatf("coverage:%0d\n",cg_2.get_inst_coverage())};
s={s,"cg_base_number_range_group "};
s={s,$sformatf("coverage:%0d\n",cg_3.get_inst_coverage())};
s={s,"cg_scaler_bits_wide_group "};
s={s,$sformatf("coverage:%0d\n",cg_4.get_inst_coverage())};
s={s,"cg_base_number_bits_wide_group "};
s={s,$sformatf("coverage:%0d\n",cg_5.get_inst_coverage())};
s={s,$sformatf("total coverage:%0d\n",$get_coverage())};
//监测并 动态修改约束,提高覆盖率,或停止仿真
$display("%0s",s);
end
end
//--------------------------------------------------------------------------------------------------------
// property
//--------------------------------------------------------------------------------------------------------
property pro_wr_en_wr_data;
@(posedge clk) disable iff (!rstn)
wr_en_i |-> not $isunknown(wr_data_i) ;
endproperty: pro_wr_en_wr_data
assert property(pro_wr_en_wr_data) else `uvm_error("ASSERT", "wr_data_i is unknown while wr_en_i is high")
cover property(pro_wr_en_wr_data) ;
property pro_set_scaler;
@(posedge clk) disable iff (!rstn)
(wr_en_i && set_scaler_i) |-> (wr_data_i!=0) |=> not $isunknown(scaler_o);
endproperty: pro_set_scaler
assert property(pro_set_scaler) else `uvm_error("ASSERT", "set zero scaler")
cover property(pro_set_scaler) ;
property pro_wr_en_wr_scaler_rd_val;
@(posedge clk) disable iff (!rstn)
(wr_en_i && !set_scaler_i) |=> (##1 rd_val_o or $rose(rd_val_o)) ;
endproperty: pro_wr_en_wr_scaler_rd_val
assert property(pro_wr_en_wr_scaler_rd_val) else `uvm_error("ASSERT", "rd_val_o is still invalid after (wr_en_i && !wr_scaler_i)")
cover property(pro_wr_en_wr_scaler_rd_val) ;
property pro_wr_scaler_i_scaler_o;
logic [15:0] data;
@(posedge clk) disable iff (!rstn)
(wr_en_i && set_scaler_i , data = wr_data_i) |=> (data == scaler_o) ;
endproperty: pro_wr_scaler_i_scaler_o
assert property(pro_wr_scaler_i_scaler_o) else `uvm_error("ASSERT", "set scaler fail");
cover property(pro_wr_scaler_i_scaler_o) ;
property pro_rd_val_rd_data_o;
@(posedge clk) disable iff (!rstn)
rd_val_o |-> !$isunknown(rd_data_o) ;
endproperty: pro_rd_val_rd_data_o
assert property(pro_rd_val_rd_data_o) else `uvm_error("ASSERT", "rd_data_o is unknown while rd_valid")
cover property(pro_rd_val_rd_data_o) ;
// initial begin
// forever begin
// wait(rstn==0);
// $assertoff();
// wait(rstn==1);
// $asserton();
// end
// end
endinterface
`endif // UE_INTERFACE_SV
ue_base_sequense.sv
`ifndef UE_BASE_SEQUENCE
`define UE_BASE_SEQUENCE
class ue_base_sequense extends uvm_sequence #(ue_transaction);
ue_transaction m_trans;
`uvm_object_utils(ue_base_sequense)
extern function new(string name="ue_base_sequense");
extern function int get_rand_number_except(int min_thre,int max_thre,int except_num);
extern function int get_rand_number(int min_thre,int max_thre);
endclass
function ue_base_sequense::new(string name="ue_base_sequense");
super.new(name);
endfunction : new
function int ue_base_sequense::get_rand_number_except(int min_thre,int max_thre,int except_num);
int val=get_rand_number( min_thre, max_thre);
while(val==except_num)
val=get_rand_number( min_thre, max_thre);
return val;
endfunction
function int ue_base_sequense::get_rand_number(int min_thre,int max_thre);
int val;
void'(std::randomize(val) with { val inside {[min_thre:max_thre]};});
return val;
endfunction
`endif // UE_BASE_SEQUENCE
ue_base_sequense_lib.sv
`ifndef UE_BASE_SEQ_LIB
`define UE_BASE_SEQ_LIB
//--------------------------------------------------------------------------------------------------------
// set_scaler
//--------------------------------------------------------------------------------------------------------
class subseq_set_scaler extends ue_base_sequense;
rand bit [`SCALER_WIDTH-1:0] scaler;
`uvm_object_utils(subseq_set_scaler)
function new(string name="subseq_set_scaler");
super.new(name);
endfunction : new
virtual task body();
`uvm_do_with(req, {no==0;base_number==0;wr_scaler == local::scaler;ttype==ue_transaction::SET_SCALER;idle_cycles==0;})
get_response(rsp);
if(scaler!=rsp.rd_scaler)
`uvm_error("SET_SCALER_ERR", $sformatf("ue_set_scaler_idle_sequence err, exp:%0d act:%0d",scaler,rsp.rd_scaler))
// else
// `uvm_info(get_type_name(),$sformatf("ue_set_scaler_idle_sequence success"), UVM_LOW)
endtask : body
endclass : subseq_set_scaler
class subseq_wr_base_number extends ue_base_sequense;
rand logic [ 7:0] base_number;
rand int idle_cycles;
rand int no;
`uvm_object_utils(subseq_wr_base_number)
function new(string name="");
super.new(name);
endfunction : new
virtual task body();
`uvm_do_with(req, {no==local::no;base_number== local::base_number;ttype==ue_transaction::WR_BASE_NUMBER;idle_cycles==local::idle_cycles;})
get_response(rsp);
endtask : body
endclass : subseq_wr_base_number
class subseq_idle extends ue_base_sequense;
rand int idle_cycles;
`uvm_object_utils(subseq_idle)
function new(string name="subseq_idle");
super.new(name);
`uvm_info(get_type_name(), $sformatf("created"), UVM_LOW)
endfunction : new
virtual task body();
`uvm_do_with(req, {no==0;ttype==ue_transaction::IDLE;idle_cycles==local::idle_cycles;})
get_response(rsp);
endtask : body
endclass : subseq_idle
`endif // UE_BASE_SEQ_LIB
ue_config.sv
`ifndef UE_CONFIG_SV
`define UE_CONFIG_SV
class ue_config extends uvm_object;
uvm_active_passive_enum i_agt_is_active = UVM_ACTIVE;
uvm_active_passive_enum o_agt_is_active = UVM_PASSIVE;
//debug 资讯
bit show_info_drv =0;
bit show_info_mon =0;
bit show_info_mdl =0;
bit show_info_scb =0;
`uvm_object_utils(ue_config)
endclass : ue_config
`endif // UE_CONFIG_SV
ue_transaction.sv
`ifndef UE_TRANS
`define UE_TRANS
`include "param_def.v"
class ue_transaction extends uvm_sequence_item;
typedef enum{IDLE,SET_SCALER,WR_BASE_NUMBER} trans_type;
rand trans_type ttype;
randc bit [`NO_WIDTH-1:0] no;
randc bit [`BASE_NUMBER_WIDTH-1:0] base_number;
randc bit [`SCALER_WIDTH-1:0] wr_scaler;
rand int idle_cycles;
bit [`SCALER_WIDTH-1:0] rd_scaler;
bit rd_valid;
bit [`RD_DATA_WIDTH-1:0] rd_data;
constraint cstr {
soft idle_cycles inside {[0:2]};
soft idle_cycles dist {[0:50],[1:25],[2:30]}; //destination 1:50/105 2:25/105 3:30/105
soft wr_scaler inside {[32:55]}; //0-200
// soft wr_scaler inside {[$:12],[20:$]}; //0-50 60-255
// 两个都是硬约束,取交集,如果无解就求解失败,所有值都是默认值0 ,为避免求解失败尽量用soft
soft base_number inside {[0:30],[50:80]}; //软约束
// soft (!wr_en)-> base_number ==0;//以后面的为准 0 50-100
}
`uvm_object_utils_begin(ue_transaction)
`uvm_field_enum (trans_type,ttype , UVM_ALL_ON)
`uvm_field_int (no, UVM_ALL_ON)
`uvm_field_int (base_number, UVM_ALL_ON)
`uvm_field_int (wr_scaler, UVM_ALL_ON)
`uvm_field_int (rd_scaler, UVM_ALL_ON)
`uvm_field_int (rd_valid, UVM_ALL_ON)
`uvm_field_int (rd_data, UVM_ALL_ON)
`uvm_field_int (idle_cycles, UVM_ALL_ON)
`uvm_object_utils_end
function new(string name = "ue_trans_inst");
super.new(name);
`uvm_info(get_type_name(), "obj created", UVM_FULL)
endfunction
function void print_info(string stage);
string s;
s={s,$sformatf("\n=========%s==============\n",stage)};
s={s,$sformatf("no:%0d\t",no)};
s={s,$sformatf("trans_type:%s\t",ttype)};
s={s,$sformatf("base_number:%d\t",base_number)};
s={s,$sformatf("wr_scaler:%d\t",wr_scaler)};
s={s,$sformatf("rd_scaler:%d\t",rd_scaler)};
s={s,$sformatf("rd_data:%d\t",rd_data)};
s={s,$sformatf("idle_cycles:%d\n",idle_cycles)};
s={s,"=======================================================\n"};
$display("%s",s);
endfunction:print_info
endclass
`endif // UE_TRANS
ue_case0_test.sv
`ifndef UE_CASE0_TEST_SV
`define UE_CASE0_TEST_SV
//--------------------------------------------------------------------------------------------------------
// sequence svh
//--------------------------------------------------------------------------------------------------------
class ue_case0_sequence extends ue_base_sequense;
randc bit [15:0] wr_scaler;
randc bit [ 7:0] base_number;
bit [ 7:0] no;
int idle_cycles;
int bug_base_number;
int bug_scaler;
subseq_set_scaler seq_scaler;
subseq_wr_base_number seq_base_number;
subseq_idle seq_idle;
randc int burst_num;
`uvm_object_utils(ue_case0_sequence)
extern function new(string name="ue_case0_sequence");
extern task body();
endclass : ue_case0_sequence
//--------------------------------------------------------------------------------------------------------
// sv
//--------------------------------------------------------------------------------------------------------
function ue_case0_sequence::new(string name="ue_case0_sequence");
super.new(name);
`uvm_info(get_type_name(), $sformatf("created"), UVM_FULL)
endfunction : new
task ue_case0_sequence::body();
if(starting_phase != null) begin
starting_phase.raise_objection(this);
end
bug_base_number=123;
bug_scaler=5;
`uvm_do_with(seq_idle,{idle_cycles == 10;})
wr_scaler=16'hffff;
// 写法:1
// `uvm_create(seq_scaler)
// seq_scaler.scaler=wr_scaler;
// `uvm_send(seq_scaler)
// 写法:2
// `uvm_create(seq_scaler)
// `uvm_rand_send_with(seq_scaler, {scaler == local::wr_scaler;})
// 写法:3
`uvm_do_with(seq_scaler, {scaler == local::wr_scaler;})
no=1;
base_number=0;
`uvm_do_with(seq_base_number, {no == local::no;base_number == local::base_number;idle_cycles == 0;})
//连续写入
repeat(20) begin
wr_scaler=get_rand_number_except(1,10,bug_scaler);
`uvm_do_with(seq_scaler, {scaler == local::wr_scaler;})
`uvm_do_with(seq_idle, {idle_cycles == 1;})
burst_num=get_rand_number(1,5);
$display("burst_num %0d", burst_num);
repeat(burst_num) begin //连续写入次数
no+=1;
base_number = get_rand_number_except(121,130,bug_base_number);
`uvm_do_with(seq_base_number, {no == local::no;base_number == local::base_number;idle_cycles == 0;})
end
`uvm_do_with(seq_idle, {idle_cycles == 1;})
end
repeat(10)
`uvm_do_with(seq_idle, {idle_cycles == 1;})
if(starting_phase != null)
starting_phase.drop_objection(this);
endtask : body
//--------------------------------------------------------------------------------------------------------
// test
//--------------------------------------------------------------------------------------------------------
class ue_case0_test extends ue_base_test;
`uvm_component_utils(ue_case0_test)
function new(string name="ue_case0_test", uvm_component parent = null);
super.new(name,parent);
endfunction : new
function void build();
super.build();
uvm_config_db#(uvm_object_wrapper)::set(this,"env.i_agt.sqr.main_phase","default_sequence", ue_case0_sequence::type_id::get());
endfunction
endclass : ue_case0_test
`endif // UE_CASE0_TEST_SV
ue_case1_test.sv
`ifndef UE_case1_TEST_SV
`define UE_case1_TEST_SV
//--------------------------------------------------------------------------------------------------------
// sequence svh
//--------------------------------------------------------------------------------------------------------
class ue_case1_sequence extends ue_base_sequense;
bit [15:0] wr_scaler;
bit [ 7:0] base_number;
bit [ 7:0] no;
int idle_cycles;
int bug_base_number;
int bug_scaler;
subseq_set_scaler seq_scaler;
subseq_wr_base_number seq_base_number;
subseq_idle seq_idle;
`uvm_object_utils(ue_case1_sequence)
extern function new(string name="ue_case1_sequence");
extern task body();
endclass : ue_case1_sequence
//--------------------------------------------------------------------------------------------------------
// sv
//--------------------------------------------------------------------------------------------------------
function ue_case1_sequence::new(string name="ue_case1_sequence");
super.new(name);
`uvm_info(get_type_name(), $sformatf("created"), UVM_FULL)
endfunction : new
task ue_case1_sequence::body();
if(starting_phase != null) begin
starting_phase.raise_objection(this);
end
bug_base_number=123;
bug_scaler=5;
`uvm_do_with(seq_idle,{idle_cycles == 10;})
`uvm_do_with(seq_scaler, {scaler == 7;})
no=1;
// 测试bug
`uvm_do_with(seq_base_number, {no == local::no;base_number == bug_base_number;idle_cycles == 0;})
`uvm_do_with(seq_scaler, {scaler == bug_scaler;})
`uvm_do_with(seq_idle, {idle_cycles == 10;})
if(starting_phase != null)
starting_phase.drop_objection(this);
endtask : body
//--------------------------------------------------------------------------------------------------------
// test
//--------------------------------------------------------------------------------------------------------
class ue_case1_test extends ue_base_test;
`uvm_component_utils(ue_case1_test)
function new(string name="ue_case1_test", uvm_component parent = null);
super.new(name,parent);
endfunction : new
function void build();
super.build();
uvm_config_db#(uvm_object_wrapper)::set(this,"env.i_agt.sqr.main_phase","default_sequence", ue_case1_sequence::type_id::get());
endfunction
endclass : ue_case1_test
`endif // UE_case1_TEST_SV
ue_case2_test.sv
`ifndef UE_case2_TEST_SV
`define UE_case2_TEST_SV
//--------------------------------------------------------------------------------------------------------
// sequence svh
//--------------------------------------------------------------------------------------------------------
class ue_case2_sequence extends ue_base_sequense;
bit [15:0] wr_scaler;
bit [ 7:0] base_number;
bit [ 7:0] no;
int idle_cycles;
int bug_base_number;
int bug_scaler;
subseq_set_scaler seq_scaler;
subseq_wr_base_number seq_base_number;
subseq_idle seq_idle;
`uvm_object_utils(ue_case2_sequence)
extern function new(string name="ue_case2_sequence");
extern task body();
endclass : ue_case2_sequence
//--------------------------------------------------------------------------------------------------------
// sv
//--------------------------------------------------------------------------------------------------------
function ue_case2_sequence::new(string name="ue_case2_sequence");
super.new(name);
`uvm_info(get_type_name(), $sformatf("created"), UVM_FULL)
endfunction : new
task ue_case2_sequence::body();
if(starting_phase != null) begin
starting_phase.raise_objection(this);
end
repeat (100000) begin
`uvm_do(req)
get_response(rsp);
end
repeat(10)
`uvm_do_with(seq_idle, {idle_cycles == 1;})
if(starting_phase != null)
starting_phase.drop_objection(this);
endtask : body
//--------------------------------------------------------------------------------------------------------
// test
//--------------------------------------------------------------------------------------------------------
class ue_case2_test extends ue_base_test;
`uvm_component_utils(ue_case2_test)
function new(string name="ue_case2_test", uvm_component parent = null);
super.new(name,parent);
endfunction : new
function void build();
super.build();
uvm_config_db#(uvm_object_wrapper)::set(this,"env.i_agt.sqr.main_phase","default_sequence", ue_case2_sequence::type_id::get());
endfunction
endclass : ue_case2_test
`endif // UE_case2_TEST_SV
complist.f
$DUT_SRC/amplifier.v
$UVM_SRC/ue_pkg.svh
$TB_SRC/ue_tb.sv
ue_sim.do
#======================================#
# TCL script for a mini regression #
#======================================#
onbreak resume
onerror resume
# set environment variables
setenv UVM_SRC ./src/uvm
setenv TB_SRC ./src/tb
setenv DUT_SRC src/dut
setenv COMP_LIST complist.f
setenv RESULT_DIR result
setenv TB_NAME ue_tb
setenv LOG_DIR log
set timetag [clock format [clock seconds] -format "%Y%b%d-%H_%M"]
#clean the environment and remove trash files.....
set delfiles [glob work *.log *.ucdb sim.list]
file delete -force {*}$delfiles
#compile the design and dut with a filelist
vlib work
#complie cpp files
#方法1调用cpp档案
#vlog ./src/uvm/cpp/my_fun_c.c
#vlog ./src/uvm/cpp/cpp_amplifier.cpp
#方法2调用dll
vlog ./src/uvm/cpp/my_fun_dll.c
echo prepare simrun folder
file mkdir $env(RESULT_DIR)/regr_ucdb_${timetag}
file mkdir $env(LOG_DIR)
vlog -sv -cover bst -timescale=1ns/1ps -l $env(LOG_DIR)/comp_${timetag}.log +incdir+$env(DUT_SRC) -f $env(COMP_LIST)
#simulate with specific testname sequentially
set TestSets { {ue_case0_test 1} \
{ue_case1_test 0} \
{ue_case2_test 0}
}
foreach testset $TestSets {
set testname [lindex $testset 0]
set LoopNum [lindex $testset 1]
for {set loop 0} {$loop < $LoopNum} {incr loop} {
set seed [expr int(rand() * 100)]
echo seed:${seed}
vsim -onfinish stop -cvgperinstance -cvgmergeinstances -sv_seed $seed +UVM_TESTNAME=${testname} -l $env(RESULT_DIR)/regr_ucdb_${timetag}/run_${testname}_${seed}.log work.$env(TB_NAME)
run -all
coverage save $env(RESULT_DIR)/regr_ucdb_${timetag}/${testname}_${seed}.ucdb
quit -sim
}
}
#echo merge the ucdb per test
vcover merge -testassociated $env(RESULT_DIR)/regr_ucdb_${timetag}/regr_${timetag}.ucdb {*}[glob $env(RESULT_DIR)/regr_ucdb_${timetag}/*.ucdb]
echo ending.....
quit -f
ue_pkg.svh
.
import uvm_pkg::*;
`include "uvm_macros.svh"
`include "./interface/ue_interface.sv"
`include "./obj/ue_transaction.sv"
`include "./obj/ue_config.sv"
`include "./obj/sequence/ue_base_sequense.sv"
`include "./obj/sequence/ue_base_sequense_lib.sv"
`include "./compoment/ue_driver.sv"
`include "./compoment/ue_monitor.sv"
`include "./compoment/ue_sequencer.sv"
`include "./compoment/ue_agent.sv"
`include "./compoment/ue_ref_model.sv"
`include "./compoment/ue_scoreboard.sv"
`include "./compoment/ue_env.sv"
`include "./compoment/ue_base_test.sv"
`include "./test_case/ue_case0_test.sv"
`include "./test_case/ue_case1_test.sv"
`include "./test_case/ue_case2_test.sv"
my_fun_c.c
#include
int cal(int base_number, int scaler){
printf("calculated by c\n");
return base_number*scaler;
}
int amplifier(int base_number, int scaler) {
// 直接用c写算法
// return cal(base_number,scaler);
//调用cpp档案
return amplifier_by_cpp(base_number,scaler);
}
cpp_amplifier.cpp
#include
#ifdef __cplusplus
extern "C" {
#endif
class c_cpp{
public:
c_cpp(){};
~c_cpp(){};
int calculate(int base_number, int scaler);
};
int amplifier_by_cpp(int base_number, int scaler);
#ifdef __cplusplus
}
#endif
int c_cpp::calculate(int base_number, int scaler){
using namespace std;
cout<<"calculated by cpp"<
my_fun_dll.c
#include
#include
#include
extern void dpi_info(char* s);
extern void dpi_fatal(char* s);
int amplifier(int base_number, int scaler) {
int(*p_get_res)(int, int) = NULL;
int res;
HMODULE h_my_fun = LoadLibraryA("my_fun.dll");
if (h_my_fun == NULL) {
dpi_fatal("load dll fail");
}
dpi_info("load dll success");
p_get_res = (int(*)(int, int))GetProcAddress(h_my_fun, "get_res");
void(*p_get_info)(char*,int,int, int, int) = NULL;
res = p_get_res(base_number, scaler);
p_get_info = (void(*)(char*,int,int, int, int))GetProcAddress(h_my_fun, "get_info");
char mm[256];
p_get_info(mm, 256, base_number, scaler, res);
dpi_info(mm);
return res;
}