IC芯片验证 - 手把手教你搭建UVM验证环境

这是一个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

IC芯片验证 - 手把手教你搭建UVM验证环境_第1张图片

IC芯片验证 - 手把手教你搭建UVM验证环境_第2张图片

IC芯片验证 - 手把手教你搭建UVM验证环境_第3张图片

目录结构

IC芯片验证 - 手把手教你搭建UVM验证环境_第4张图片

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;
}

你可能感兴趣的:(IC设计验证,芯片,uvm,ic验证,systemverilog)