简单的UVM项目完整代码

目录

1.项目介绍

2.组件代码实现与功能介绍 

3.运行结果与讨论 


参考书:UVM实战(张强)

1.项目介绍

DUT:待测设计算是一个非常简单的RTL,主要功能为实现输入信号的打拍输出,可以理解为实现打拍功能,通过valid信号控制打拍后的数据是否给到输出。

这个项目是做的第一个项目,主要是通过这个项目去理解UVM中的各个组件,phase机制以及对白皮书中除寄存器模型外的各种机制进行实验并加进一步加深理解。在此项目的基础上,做更难的项目时就可以更加得心应手。

项目文件:

d9831e12fa3f4c538ec94f5180ca6d5f.png

项目架构:借用一下apb_watchdog中的图

ece113e67c124caca5d6eb919851a83c.png

2.组件代码实现与功能介绍 

interface 接口文件

interface my_if(input clk,input rstn);
    logic [31:0] tx_d;//输入
    logic [31:0] rx_d;//输出
    logic [31:0] addr_i;
    logic [31:0] addr_o;
    logic valid_i;
    logic valid_o;
   
    clocking cb @(posedge clk);
      output tx_d;
      output valid_i;
      output addr_i;
      input  rx_d;
      input  valid_o;
      input addr_o;
    endclocking 

endinterface

clocking块中的input是指DUT对测试平台的输入,output是指测试平台对DUT的输入。所以如果在测试平台中需要监测interface中的某些信号,只能监测类型为input的信号,而output类型的信号更多是跟随DUT进行变化的。

tb_top 

`include "uvm_macros.svh"
import uvm_pkg::*;

module tb_top;
 reg clk;
 reg rstn;
 
  if if0(clk,rstn);

  test u_test( //interface与待测DUT之间的连接
      .clk(clk),
      .rstn(rstn),
      .tx_d(if0.tx_d),
      .addr_i(if0.addr_i),
      .valid_i(if0.valid_i),
      .rx_d(if0.rx_d),
      .addr_o(if0.addr_o),
      .valid_o(if0.valid_o)
  );

  initial begin//复位信号定义
      rstn=1;
      #50;
      rstn=0;
      #50;
      rstn=1;
  end
 
  initial begin//时钟频率定义
      clk=0;
      forever #20 clk<=~clk;
  end

  initial begin
    $fsdbDumpfile("test.fsdb");//波形文件
    $fsdbDumpvars(0,tb_top);//生成层次
  end

  initial begin
    run_test();//必须要有的UVM_TESTNAME相关的
  end
  initial begin
    uvm_config_db#(virtual if)::set(null,"test_top.u_env.*","if0",if0);//派发接口
  end

//  initial begin
//      static real clk_half_period=100.0;
//      if(uvm_config_db#(real)::get(uvm_root::get(),"uvm_test_top","clk_half_period",clk_half_period))
//          `uvm_info("tb_top",$sformatf("clk half period is %0f",clk_half_period),UVM_LOW)
//      end

endmodule 

transaction transaction是一个抽象的概念。一般来说,物理协议中的数据交换都是以帧或者包为单位的,通常在一帧或者一个包中要定义好各项参数,每个包的大小不一样。很少会有协议是以bit或者byte为单位来进行数据交换的。以以太网为例,每个包的大小至少是64byte。这个包中要包括源地址、目的地址、包的类型、整个包的CRC校验数据等。transaction就是用于模拟这种实际情况,一笔transaction就是一个包。在不同的验证平台中,会有不同的transaction。(来源: 白皮书)

在这个项目中,采用数组方式发送数据,因此要求scoreboard中数据比对方式为数组比对。一般来说,除了定义每帧中的各个参数之外,还需要对比对数据进行注册,例如,如果要比对的是data和addr,那么应该对这些参数进行注册,即field automation机制。只有经过field automation机制注册的参数才能调用compare和copy等函数进行数据的处理,否则就要自定义compare函数,往往效果不好。

代码 field automation可以把参数都加上,不用的添加注释即可。

class transaction extends uvm_sequence_item;
    rand bit [31:0] data;//数据打包
    rand bit [31:0] addr;
    rand bit [31:0] pload[];//数组

    //`uvm_object_utils(transaction)
    `uvm_object_utils_begin(transaction)
        `uvm_field_int(addr,UVM_ALL_ON)
        `uvm_field_array_int(pload,UVM_ALL_ON)
       // `uvm_field_int(data,UVM_ALL_ON)
    `uvm_object_utils_end

    function new(string name="my_transaction");
     	super.new(name);
    endfunction

endclass

driver 组件driver实现的功能为将transaction转换成interface级别,使transaction中随机出的、自己定义的数据能够驱动进入DUT,通过检查结果确定DUT相关功能是否完备。

//typedef class A;//callback相关
class driver extends uvm_driver#(transaction);
    //uvm_analysis_port #(transaction) ap;
    virtual if if0;
    int delay ; // when rstn become to high , begin to send data after the number clocks
    int pre_num;
//    `uvm_component_utils(driver)
    `uvm_register_cb(mydriver,A);

    `uvm_component_utils_begin(driver)
    `uvm_field_int(pre_num,UVM_ALL_ON)
    `uvm_component_utils_end

    function new(string name="driver",uvm_component parent=null);
        super.new(name,parent);
	//ap=new("ap",this);
        ini_delay=10;
        pre_num=3;
//	`uvm_info("my_driver","new is called",UVM_LOW);
    endfunction

    virtual function void build_phase(uvm_phase phase);
    	super.build_phase(phase);
	    `uvm_info("driver","build_phase enter...",UVM_LOW);
      `uvm_info("driver",$sformatf("pre_num value is %0d",pre_num),UVM_LOW);
//      set_report_max_quit_count(5);
        if(!uvm_config_db#(virtual if)::get(this,"","if0",if0))
	    `uvm_fatal("driver",{"virtual interface must be set for ",get_full_name()," if0!!!"})
        uvm_config_db#(int)::get(this,"","ini_delay",ini_delay);
        `uvm_info("driver","build_phase exiting...",UVM_LOW)
      //uvm_config_db test
       // void'(uvm_config_db#(int)::get(uvm_root::get(),"uvm_test_top.u_my_env.scb","pre_num",pre_num));
       // $display("uvm_config_db test driver pre_num value is %0d",pre_num);
      // uvm_config_db#(int)::set(uvm_root::get(),"uvm_test_top.env.scb","pre_num",100);
    endfunction

    /** uvm_phase order test */
    virtual function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    `uvm_info("driver","connect_phase enter...",UVM_LOW)
    `uvm_info("driver","connect_phase exiting...",UVM_LOW)
    endfunction

    task main_phase(uvm_phase phase);
        super.main_phase(phase);
//        phase.raise_objection(this);
        `uvm_info("driver","main_phase enter...",UVM_LOW)
//        $display("driver main phase begin time %0t",$time);
    	if0.cb.tx_d <=0;
    	if0.cb.valid_i <=0;
    	if0.cb.addr_i <=0;
    	@(posedge if0.rstn);
    	repeat(ini_delay) @(posedge if0.clk);
    	while(1)begin
    	    @(posedge if0.clk);
    	    seq_item_port.get_next_item(req);
          $display("---------driver--------");//对数据通路的理解
          req.print; //yes
          `uvm_do_callbacks(my_driver, A, pre_tran(this,req))
    	    if(req==null);
    	    else begin
                if(req.delay==0);
                else repeat(req.delay) @(posedge if0.clk); 
//		ap.write(req);
		foreach(req.pload[i]) begin
		     if0.cb.addr_i<= req.addr+i*4;
	         if0.cb.tx_d <= req.pload[i];
		     if0.cb.valid_i <= 1'b1;
           $display("@%0t:driver if0.cb.tx_d is %0h",$time,if0.tx_d);
	       @(posedge if0.clk);
	        end

      //callback
//      `uvm_info("driver","Enter callback driver_pkg...",UVM_LOW)
//      `uvm_do_callbacks(driver,A,driver_pkg(if0,req));
//      `uvm_info("driver","Enter callback driver_pkg...",UVM_LOW)
          if0.cb.valid_i <=0;
	        seq_item_port.item_done();
	    end
	end
//  phase.drop_objection(this);
  $display("driver main phase end time %0t",$time);
  `uvm_info("driver","main_phase exiting...",UVM_LOW)
    endtask
    
    task post_main_phase(uvm_phase phase);
        super.post_main_phase(phase);
        `uvm_info("driver","post_main_phase enter...",UVM_LOW)
//        $display("driver post_main_phase begin time %0t",$time);
          `uvm_do_callbacks(driver, A, pre_tran(this,req))
        #1000;
        $display("driver post_main_phase end time %0t",$time);
    endtask
//
//    task run_phase(uvm_phase phase);
//        super.run_phase(phase);
//        `uvm_info("driver","run_phase enter...",UVM_LOW)
//        #100;
//        `uvm_info("driver","run_phase exiting...",UVM_LOW)
//    endtask




endclass
//class A extends uvm_callback;
//    virtual task pre_tran(driver drv, ref my_transaction tr);
//    endtask
//endclass
//
//typedef uvm_callbacks#(driver, A) A_pool;    

callback相关的代码甭管。main_phase中,首先将相应数据赋值0,然后等待复位信号拉起,将transaction中相应数据给到接口,进而驱动进入DUT内部。

sequencer

class sequencer extends uvm_sequencer #(transaction);
    uvm_analysis_port #(transaction) ap;

    function new(string name,uvm_component parent);
	    super.new(name,parent);
    endfunction

    virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    `uvm_info("sequencer","build_phase enter...",UVM_LOW)
	      ap=new("ap",this);
        `uvm_info("sequencer","build_phase exiting...",UVM_LOW)
    endfunction
    `uvm_component_utils(sequencer)

     /** uvm_phase order test */

endclass

sequencer的实现非常简单, 只要声明一下就可以,这里根据之前的框图,sequencer根据seq_item_port/export与driver进行通信,并通过ap端口向scoreboard发送正确数据。

monitor

class monitor extends uvm_monitor;
    virtual if if0;
    uvm_analysis_port#(transaction) ap;

  
    `uvm_component_utils(monitor)
    function new(string name="monitor",uvm_component parent=null);
	super.new(name,parent);
    endfunction

    virtual function void build_phase(uvm_phase phase);
      	super.build_phase(phase);
        `uvm_info("monitor","build_phase enter...",UVM_LOW)
      	ap=new("ap",this);
      	if(!uvm_config_db#(virtual if)::get(this,"","if0",if0))
      	    `uvm_fatal("monitor","virtual interface must be set for if0!!!")
            `uvm_info("monitor","build_phase exiting...",UVM_LOW)
            //nonlinear line
            //uvm_config_db#(int)::set(uvm_root::get(),"uvm_test_top.u_my_env.agt.drv","pre_num",100);
    endfunction

     /** uvm_phase order test */
    virtual function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    `uvm_info("monitor","connect_phase enter...",UVM_LOW)
    `uvm_info("monitor","connect_phase exiting...",UVM_LOW)
    endfunction


    task main_phase(uvm_phase phase);
    	transaction tr;
        `uvm_info("monitor","main_phase enter...",UVM_LOW)
        $display("monitor main phase begin time %0t",$time);
    	while(1)begin
         @(posedge if0.clk);
         // $display("monitor after repeat time is %0t",$time);
    	    if(if0.valid_o==1'b1) begin
    	          tr=new("tr");
    	    	  tr.data=if0.rx_d;
    		      tr.addr=if0.addr_o;
                  $display("@%0t:if0.rx_d %0h",$time,if0.rx_d);
                  tr.print;//理解数据通路,检查monitor处数据,可删除
    	          ap.write(tr);
	          end
	    end
      `uvm_info("monitor","main_phase exiting",UVM_LOW)
      $display("monitor main phase end time %0t",$time);
  endtask



endclass

这里,需要等valid_o为1时才进行interface级别到transaction级别的转换,因为RTL代码说明只有valid_o为1时,打拍后的输入数据才能给到rx_d,否则就直接将输入数据给到输出数据。到这里,整体架构就已经非常清晰了,driver将sequencer通过seq_item_port传输过来的transaction拆成interface级别,因为在top层中,已经实现了interface和DUT的连接,所以这里通过driver直接将相应数据驱动进入DUT,然后由monitor监测DUT的输出,将输出的interface级转为transaction级别,给到scoreboard进行比对,如整体框架图所示,monitor收集到的关于DUT的输出是需要进行比对的数据。如果将整体架构比作一个人的话,transaction级才是其中的血液,不是interface级。

agent

class agent extends uvm_agent;
    sequencer sqr;
    driver drv;
    monitor mon;

    //uvm_analysis_port #(transaction) drv_ap;
    uvm_analysis_port #(transaction) sqr_ap;
    uvm_analysis_port #(transaction) mon_ap;

    function new(string name,uvm_component parent);
    	super.new(name,parent);
    endfunction	

    `uvm_component_utils(agent)

    function void build_phase(uvm_phase phase);
    	super.build_phase(phase);
      `uvm_info("agent","build_phase enter...",UVM_LOW)
    	if(is_active==UVM_ACTIVE) begin
    	    sqr=sequencer::type_id::create("sqr",this);
    	    drv=driver::type_id::create("drv",this);
    	end
    	    mon = monitor::type_id::create("mon",this);
      `uvm_info("agent","build_phase exiting...",UVM_LOW)
    endfunction

    function void connect_phase(uvm_phase phase);
    	super.connect_phase(phase);
      `uvm_info("agent","connect_phase enter...",UVM_LOW)
    	if(is_active==UVM_ACTIVE) begin
    	    drv.seq_item_port.connect(sqr.seq_item_export);
    	    //drv_ap=drv.ap;
    	    sqr_ap=sqr.ap;
    	    mon_ap=mon.ap;
      `uvm_info("agent","connect_phase exiting...",UVM_LOW)
    	end
    endfunction

endclass

agent中包含driver,monitor,sequencer,并进行这三个组件的例化工作。其中定义了sqr_ap和mon_ap,原因是组件之间的连接关系最好不要跨层次。mon中的数据需要给到scoreboard,如果直接连接就相当于跨了层次,agent和scoreboard是同一等级,所以先进行mon_ap与monitor中ap的连接,然后由mon_ap去连接scoreboard的相应端口,保证规范性。

scoreboard

class scoreboard extends uvm_scoreboard;
    uvm_blocking_get_port #(transaction) exp_port;
    uvm_blocking_get_port #(transaction) act_port;
    transaction queue[$];
    transaction dut_final;
    int start;
    int pre_num;
    `uvm_component_utils(scoreboard)

    function new (string name="scoreboard",uvm_component parent);
    	super.new(name,parent);
	    start=0;
    endfunction

    function void build_phase(uvm_phase phase);
	    super.build_phase(phase);
      /** uvm_phase order test */
      `uvm_info("scoreboard","build_phase enter...",UVM_LOW)
	    exp_port = new("exp_port",this);
	    act_port = new("act_port",this);
      //nonlinear line
      //uvm_config_db#(int)::set(uvm_root::get(),"uvm_test_top.u_my_env.agt.drv","pre_num",100);
     // uvm_config_db#(int)::set(null,"uvm_test_top.u_my_env.agt.drv","pre_num",90);
     //$display("$$$$$$$$$$ nonlinear line test pre_num is %0d",pre_num);


      `uvm_info("scoreboard","build_phase exiting...",UVM_LOW)
    endfunction

     /** uvm_phase order test */
    virtual function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    `uvm_info("scoreboard","connect_phase enter...",UVM_LOW)
    `uvm_info("scoreboard","connect_phase exiting...",UVM_LOW)
    endfunction


    task main_phase(uvm_phase phase);
      	transaction tr_golden,tr_dut,tr_tmp;
      	bit result;
	      super.main_phase(phase);
        fork
	    while(1)begin
	    	exp_port.get(tr_golden); // golden port
//        $display("tr_golden is");
//        tr_golden.print;
	    	queue.push_back(tr_golden);
        $display("tr_golden is");
        tr_golden.print;
        $display("queue is");
        queue[$].print;
	    end
	    while(1) begin
	    	act_port.get(tr_dut);
       // $display("tr_dut print at %0t",$time);
       // tr_dut.print; //data not in `uvm_object_utils_begin `uvm_object_utils_end, so print nothing
	    	if(queue.size>0 || start!==0) begin
	    	    if(start==0)tr_tmp=queue.pop_front();
	    	    if(start!==tr_tmp.pload.size) begin
	             	if(start==0)begin
                        dut_final=new;
	    		        dut_final.pload=new[tr_tmp.pload.size];
	    		        dut_final.pload[start]=tr_dut.data;
	    		        dut_final.addr=tr_dut.addr;
	    	        end
	    	   	  else begin
	    	   	      dut_final.pload[start]=tr_dut.data;
	    	   	  end
	    	  	start++;
	         end
           //
           $display("tr_dut_final print");
           dut_final.print;
	    	    if(start==tr_tmp.pload.size) begin
	    		    start=0;
	    	            //result = tr_dut.compare(tr_tmp);
	    	       result = dut_final.compare(tr_tmp);
	    		    if(result) begin
	    		        `uvm_info("my_scoreboard","compare match",UVM_LOW)
                  $display("print tr_tmp dut_final");
                  tr_tmp.print;
	    		        dut_final.print;
	    		    end
	    	      else begin
	    	            `uvm_error("scoreboard",$sformatf("compare mismatched at time %0t",$time))
	    	            $display("DUT is");tr_dut.print; 
	    	            $display("DUT is");dut_final.print; 
	    	            $display("GOLDEN is");tr_tmp.print; 
	    	        end
	                end
	    	end
	    	else begin
	    	    `uvm_error("scoreboard",$sformatf("received dut, but golden is null at time %0t",$time))
	    	end
	    end
           join
    endtask

    function void check_phase(uvm_phase phase);
    	transaction tr;
    	if(queue.size>0) `uvm_error("scoreboard",$sformatf("the golden queue not empty , still have %0d transaction",exp_queue.size))
    	while(queue.size>0) begin
    	    tr=queue.pop_back;
    	    `uvm_error("scoreboard","no compared golden")
    	     tr.print;
    	end
        endfunction
endclass

scoreboard的实现当时属实困惑了,尤其是涉及到数组的数据重新打包整合。要理解scoreboard的代码实现方式,必须理解TLM1.0通信中的阻塞端口和非阻塞端口。以DUT端口为例,act_port声明为blocking_get类型的阻塞端口,阻塞端口意味着如果此端口没有get到来自通信端口的transaction,那么就会阻塞在这里,不会执行接下来的代码。而一旦执行了(exp_queue.size>0 || start!==0) 这段代码,就意味着blocking_get口一定是收到了monitor发送过来的transaction,这时如果exp_queue=0,则可以直接打印错误信息receive DUT,but golden is null。这意味着收到了来自monitor的信息,但是没有收到来自sequencer的数据,说明sequence->sequencer->FIFO->scoreboard这条数据通路发生了错误,错误原因有可能出现在各个通信节点,我之前的错误是env中关于接口与接口的连接出现了问题,这里可能会发生的错误对于刚接触的来说是多种多样的。start为数据整合打包的索引,数组之间的比对是不能够错位的.

env

/** TLM test */
//`include "A.sv"
//`include "B.sv"
//`include "B_no_export.sv"
//`include "A_export.sv"
//`include "C_export.sv"
//`include "A_get.sv"
//`include "B_get.sv"
//`include "A_transport.sv"
//`include "B_transport.sv"
//`include "A_nonblocking.sv"
//`include "B_nonblocking.sv"
//`include "A_analysis.sv"
//`include "B_analysis.sv"
//`include "C_analysis.sv"
class my_env extends uvm_env;
    agent agt;
    scoreboard scb;
    int delay;

    /** TLM test */
//    A A_inst;
//    B B_inst;
//    B_no_export Bne;
//    A_export Aex;
//    C_export C_inst;
//    A_get A_g;
//    B_get B_g;
//    A_transport A_trans;
//    B_transport B_trans;
//    A_nonblocking A_non;
//    B_nonblocking B_non;
//   A_analysis A_ana;
//   B_analysis B_ana;
//   C_analysis C_ana;


    //uvm_tlm_analysis_fifo #(transaction) drv_scb_fifo;
    uvm_tlm_analysis_fifo #(transaction) sqr_scb_fifo;
    uvm_tlm_analysis_fifo #(transaction) mon_scb_fifo;

    `uvm_component_utils(env)
     function new(string name,uvm_component parent);
	      super.new(name,parent);
    endfunction

    virtual function void build_phase(uvm_phase phase);
	    super.build_phase(phase);
      `uvm_info("environment","build_phase enter...",UVM_LOW)
        //drv_scb_fifo=new("drv_scb_fifo",this);
        sqr_scb_fifo=new("sqr_scb_fifo",this);
        mon_scb_fifo=new("mon_scb_fifo",this);
	      agt = agent::type_id::create("agt",this);
        scb = scoreboard::type_id::create("scb",this);
	      agt.is_active=UVM_ACTIVE;
        `uvm_info("environment","build_phase exiting...",UVM_LOW)

        //uvm_config_db test
        //uvm_config_db#(int)::set(uvm_root::get(),"uvm_test_top.u_my_env.agt.drv","pre_num",100);//or replace uvm_root::get to null

// a middle value
        uvm_config_db#(int)::get(this,"","a",delay);
        $display("@%0t: delay value is %0d",$time,delay);
        assert(delay==11) $display("@%0t:delay is 10",$time);
        else $error("delay!=11");

        $display("Enter TLM test field....");
//        A_inst = A::type_id::create("A_inst",this);
//        C_inst = C_export::type_id::create("C_inst",this);
//        B_inst = B::type_id::create("B_inst",this);
//        Bne    = B_no_export::type_id::create("Bne",this);
//        Aex    = A_export   ::type_id::create("Aex",this);
//          A_g  = A_get::type_id::create("A_g",this);
//          B_g  = B_get::type_id::create("B_g",this);
//       A_trans = A_transport::type_id::create("A_trans",this); 
//       B_trans = B_transport::type_id::create("B_trans",this); 
//        A_non = A_nonblocking::type_id::create("A_non",this);
//        B_non = B_nonblocking::type_id::create("B_non",this);
//        A_ana = A_analysis::type_id::create("A_ana",this);
//        B_ana = B_analysis::type_id::create("B_ana",this);
//        C_ana = C_analysis::type_id::create("C_ana",this);
        

    endfunction

    virtual function void connect_phase(uvm_phase phase);
	      super.connect_phase(phase);
        `uvm_info("environment","connect_phase enter...",UVM_LOW)
	      //agt.drv_ap.connect(drv_scb_fifo.analysis_export);
	      agt.sqr_ap.connect(sqr_scb_fifo.analysis_export);
	      agt.mon_ap.connect(mon_scb_fifo.analysis_export);
	      scb.exp_port.connect(sqr_scb_fifo.blocking_get_export);
	      scb.act_port.connect(mon_scb_fifo.blocking_get_export);

//        $display("TLM connect begin...A_port connect C_export");
//        A_inst.A_port.connect(B_inst.B_export);
//        A_inst.A_port.connect(Bne.B_imp);
//        A_inst.A_port.connect(C_inst.C_export);
//        Aex.A_export.connect(Bne.B_imp);
//        A_g.A_port.connect(B_g.B_export);
//        A_trans.A_transport.connect(B_trans.B_imp);
//        A_non.A_port.connect(B_non.B_imp);
//        A_ana.A_ap.connect(B_ana.B_imp);
//        A_ana.A_ap.connect(C_ana.C_imp);
//        `uvm_info("environment","connect_phase exitiing...",UVM_LOW)
    endfunction

    task main_phase(uvm_phase phase);
        super.main_phase(phase);
        `uvm_info("environment","main phase enter...",UVM_LOW)
          #1000;
        `uvm_info("environment","main phase exiting...",UVM_LOW)
    endtask

    //function void report_phase(uvm_phase phase);
    //  bit                             check_error;
    //  uvm_report_server               svr;
    // 
    //  svr = uvm_report_server::get_server();
    // 
    //  if(svr.get_severity_count(UVM_FATAL) + svr.get_severity_count(UVM_ERROR) != 0) begin
    //    check_error = 1;
    //    `uvm_info(get_type_name(), "SIMULATION FAIL", UVM_NONE)
    //  end
    //  if(check_error == 0) begin
    //    `uvm_info(get_type_name, "   Simulation PASSED!  ", UVM_NONE)
    //  end else begin
    //    `uvm_info(get_type_name, "   Simulation FAILED!  ", UVM_NONE)    
    //  end
    //  $display("\n\n");
    // 
    //endfunction : report_phase

endclass

env中主要实现对FIFO的连接工作,mon_ap与FIFO的连接,FIFO与scoreboard的连接。sqr_ap与FIFO的连接,FIFO与scoreboard的连接。并例化agent和scoreboard,如框架图所示。

sequence 

class sequence extends uvm_sequence #(transaction);
    transaction m_trans;
    transaction d_trans;

    `uvm_object_utils(sequence)
    `uvm_declare_p_sequencer(sequencer)
    function new(string name="my_sequence");
      	super.new(name);
    endfunction

//reload    
    virtual function void test();
    $display("********my_sequence virtual type********");
    endfunction
    
    function void test_00();
        $display("my_sequence not virtual type test_00");
    endfunction
//end


    

    virtual task pre_body();
    //time test
    `uvm_info("pre_body","task pre_body enter...",UVM_LOW)
    $display("begin_time is %0t",$time);
    #10;
    $display("end_time is %0t",$time);
//        uvm_phase phase;
//        super.pre_body();
//`ifdef UVM_12
//        phase=get_starting_phase();
//`else 
//        phase=starting_phase;
//`endif
//	if(phase!=null) begin
//            phase.phase_done.set_drain_time(this,1000);
//	    phase.raise_objection(this);
//	end
    endtask

//    virtual task body();
     virtual task body();
    `uvm_info("my_sequence","body is called",UVM_LOW)
     	repeat(1)begin
//	    `uvm_do(m_trans)
	    `uvm_create(m_trans)
      m_trans.randomize();
	    `uvm_send(m_trans)
            p_sequencer.ap.write(m_trans);

	 //   `uvm_create(m_trans)
   //         m_trans.randomize() with {m_trans.addr==8;
	 //                             m_trans.pload.size==3;
   //                                   foreach(m_trans.pload[i])m_trans.pload[i]==i+10;
	 // 		     };
	 //    p_sequencer.ap.write(m_trans);
	 //   `uvm_send(m_trans)

	//    `uvm_do_with(m_trans,{m_trans.addr==8;
	//                          m_trans.pload.size==3;
        //                          foreach(m_trans.pload[i])m_trans.pload[i]==i+10;
	//                         }
	//	          )
        end
    endtask

    virtual task post_body();
//        uvm_phase phase;
//        super.post_body();
//`ifdef UVM_12
//        phase=get_starting_phase();
//`else 
//        phase=starting_phase;
//`endif
//	if(phase!=null) begin
//	    phase.drop_objection(this);
//	end
    endtask
endclass

endclass

sequence中采用p_sequencer调用sequencer中的ap端口进行transaction的发送。

test 

import uvm_pkg::*;
import env_pkg::*;
`include "sequence.sv"
//`include "normal_sequence.sv"
 
class my_callback extends A;
    virtual task pre_tran(my_driver drv, ref my_transaction tr);
    `uvm_info("my_callback","this is pre_tran task",UVM_LOW)
    endtask

    function new(string name="my_callback");
        super.new(name);
    endfunction

    `uvm_object_utils(my_callback)
endclass

class base_test extends uvm_test;
    env u_env;
    sequence seq0;
//    normal_sequence nseq;
//    sequence1 seq1;
    

    `uvm_component_utils(base_test)
    function new(string name, uvm_component parent);
	    super.new(name,parent);
    endfunction

//    function void print_test(sequence seq0);
//        seq0.test();
//        seq0.test_00();
//    endfunction



    function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        /** uvm_phase order test */
        `uvm_info("test","build_phase enter...",UVM_LOW)
          uvm_default_printer.knobs.begin_elements=10;
          uvm_default_printer.knobs.end_elements=10;

          //uvm_config_db test
          uvm_config_db#(int)::set(null,"uvm_test_top.u_my_env.agt.drv","pre_num",90);
          uvm_config_db#(real)::set(this,"","clk_half_period",200.0);



//         seq0 = new("seq0");
	       u_env=env::type_id::create("u_env",this);
//         //factory.set_type_override_by_type(sequence::get_type(),normal_sequence::get_type());
           seq0=sequence::type_id::create("seq0");
//         nseq = normal_sequence::type_id::create("nseq",this);

//         print_test(seq0);
//         print_test(nseq);

        //factory.set_type_override_by_type(normal_sequence::get_type(),adnormal_sequence::get_type());

         //factory.set_type_override_by_type(sequence::get_type(),adnormal_sequence::get_type());
         seq0=sequence::type_id::create("seq0");
//         $display("method no.2 uvm_sequence_base start");
//         uvm_config_db#(uvm_sequence_base)::set(this,"u_env.agt.sqr.main_phase","default_sequence",seq0);
//         $display("method no.3");
//        uvm_config_db#(uvm_object_wrapper)::set(this,
//						"u_env.agt.sqr.main_phase",
//						"default_sequence",
//						sequence::type_id::get());



         //uvm test



        /** uvm_error count 5 quit */
//        set_report_max_quit_count(5);
        `uvm_info("test","build_phase exiting...",UVM_LOW)
    endfunction

     /** uvm_phase order test */
    virtual function void connect_phase(uvm_phase phase);

/** callback */
    my_callback my_cb;

    super.connect_phase(phase);
    `uvm_info("test","connect_phase enter...",UVM_LOW)
//        set_report_max_quit_count(5);
        u_my_env.set_report_severity_action(UVM_WARNING, UVM_DISPLAY| UVM_STOP);
        my_cb = my_callback::type_id::create("my_cb");
        A_pool::add(u_my_env.agt.drv, my_cb);
        uvm_top.print_topology();
        check_config_usage();
        print_config(0);
//       seq0.print_override_info("my_sequence");

    `uvm_info("test","connect_phase exiting...",UVM_LOW)
    endfunction



    task main_phase(uvm_phase phase);
        `uvm_info("test","main_phase enter...",UVM_LOW)
        $display("test main_phase begin time %0t",$time);
        set_report_max_quit_count(5);
        phase.raise_objection(this);
//         seq0=sequence::type_id::create("seq0");
//	    seq1=sequence1::type_id::create("seq1");
/** first */
	      seq0.start(u_my_env.agt.sqr);

	  repeat(25)@(posedge tb_top.u_test.clk);
//	seq1.start(u_env.agt.sqr);
       phase.phase_done.set_drain_time(this,200);
//      #200;
        `uvm_info("test","main_phase exiting...",UVM_LOW)
        $display("test main phase end time %0t",$time);
        phase.drop_objection(this);

    endtask

//    task run_phase(uvm_phase phase);
//        super.run_phase(phase);
//        phase.raise_objection(this);
//        `uvm_info("test","run_phase enter...",UVM_LOW)
//        #10000;
//        `uvm_info("test","run_phase exiting...",UVM_LOW)
//       phase.drop_objection(this); 
//    endtask 

//    task post_shutdown_phase(uvm_phase phase);
//        super.post_shutdown_phase(phase);
//        phase.raise_objection(this);
//
//        `uvm_info("test","post_shutdown_phase enter...",UVM_LOW)
//        #1000;
//        phase.drop_objection(this);
//        `uvm_info("test","post_shutdown_phase exiting...",UVM_LOW)
//    endtask

//    task shutdown_phase(uvm_phase phase);
//        super.shutdown_phase(phase);
//        phase.raise_objection(this);
//
//        `uvm_info("test","shutdown_phase enter...",UVM_LOW)
//        #100000;
//        phase.drop_objection(this);
//        `uvm_info("test","shutdown_phase exiting...",UVM_LOW)
//    endtask
//
//    virtual function void extract_phase(uvm_phase phase);
//    super.extract_phase(phase);
//    phase.raise_objection(this);
//    `uvm_info("test","extract phase enter...",UVM_LOW)
//    phase.drop_objection(this);
//    endfunction
 

    function void report_phase(uvm_phase phase);
        uvm_report_server server;
        int err_num;
        super.report_phase(phase);

        server=uvm_report_server::get_server();
        err_num=server.get_severity_count(UVM_ERROR);
        if(err_num!=0) $display("base_test FAILED");
        else $display("base_test PASSED");
    endfunction
endclass

主要在test中控制系统整体运行时间。

env_pkg

package env_pkg;
import uvm_pkg::*;

`include "transaction.sv"
`include "monitor.sv"
`include "sequencer.sv"
`include "driver.sv"
`include "agent.sv"
`include "scoreboard.sv"
`include "env.sv"
`include "callbacks.sv"
endpackage

对于文件包一般有两个写法,其一是将env组件待运行文件按照例化顺序打包执行;其二是与白皮书的编写方式类似,将所有待执行文件包括test,sequence等按照例化顺序在tb_top中依次排列,平台开始运行后,所有tb_top中的`include都会被执行,这时只要使用+incdir+将`include文件的搜索路径写清楚就可以了。

3.运行结果与讨论 

因为RTL非常简单,所以不必提取验证点,比对输入输出数据就行。

这里选择将待执行文件打包。base_test为随机出一个transaction,transaction中添加约束限制数组随机数组的数量,并在各个节点处增加打印信息。Makefile脚本如下,vcs -后面接的参数一搜就有,涉及到文件路径省略掉了。

TEST_NAME=base_test

compile :
	vcs -省略(有文件路径) -top tb_top ./if.sv ./test.v ./env_pkg.sv  ./tb_top.sv ./test/*.sv 

sim:
	./simv +UVM_TESTNAME=${TEST_NAME} -l simv.log 

test中运行结果。运行结果显示,driver处添加的打印信息率先将随机得到的transaction打印出来,数组中共有8笔数据,并打印transaction拆分成interface级后的数据。紧接着tr_golden被打印,这是因为golden数据的传输中间不经过任何逻辑,因此到达scoreboard的时间一定是快于DUT数据达到scoreboard的时间。并且打印了存储golden数据的队列,没有问题。而后monitor开始不断的拿到DUT的输出数据。transaction不能print出数据是因为data并没有加入field autommation中。从打印结果可以清晰的观察到dut_final不停的将DUT输出的数据加入进来,然后两者比对通过。

---------driver--------
---------------------------------------------------------------------------------------
Name                           Type            Size  Value                             
---------------------------------------------------------------------------------------
m_trans                        transaction     -     @852                              
  addr                         integral        32    'h2f0                             
  pload                        da(integral)    8     -                                 
    [0]                        integral        32    'h282a5b45                        
    [1]                        integral        32    'ha91a7e04                        
    [2]                        integral        32    'h8c366963                        
    [3]                        integral        32    'h48290a3f                        
    [4]                        integral        32    'h5ff1bded                        
    [5]                        integral        32    'ha39adc79                        
    [6]                        integral        32    'h42a33ffa                        
    [7]                        integral        32    'h5dd378b6                        
  begin_time                   time            64    500000                            
  depth                        int             32    'd2                               
  parent sequence (name)       string          4     seq0                              
  parent sequence (full name)  string          34    uvm_test_top.u_env.agt.sqr.seq0
  sequencer                    string          29    uvm_test_top.u_env.agt.sqr     
---------------------------------------------------------------------------------------
UVM_INFO ./test/base_test.sv(8) @ 500000: reporter [my_callback] this is pre_tran task
UVM_INFO driver.sv(75) @ 500000: uvm_test_top.u_env.agt.drv [driver] Enter callback driver_pkg...
callback driver_pkg
driver if0.cb.tx_d is 0
callback driver_pkg
driver if0.cb.tx_d is 282a5b45
callback driver_pkg
driver if0.cb.tx_d is a91a7e04
callback driver_pkg
driver if0.cb.tx_d is 8c366963
callback driver_pkg
driver if0.cb.tx_d is 48290a3f
callback driver_pkg
driver if0.cb.tx_d is 5ff1bded
callback driver_pkg
driver if0.cb.tx_d is a39adc79
callback driver_pkg
driver if0.cb.tx_d is 42a33ffa
UVM_INFO my_driver.sv(77) @ 820000: uvm_test_top.u_env.agt.drv [driver] Enter callback driver_pkg...
tr_golden is
---------------------------------------------------------------------------------------
Name                           Type            Size  Value                             
---------------------------------------------------------------------------------------
m_trans                        transaction     -     @852                              
  addr                         integral        32    'h2f0                             
  pload                        da(integral)    8     -                                 
    [0]                        integral        32    'h282a5b45                        
    [1]                        integral        32    'ha91a7e04                        
    [2]                        integral        32    'h8c366963                        
    [3]                        integral        32    'h48290a3f                        
    [4]                        integral        32    'h5ff1bded                        
    [5]                        integral        32    'ha39adc79                        
    [6]                        integral        32    'h42a33ffa                        
    [7]                        integral        32    'h5dd378b6                        
  begin_time                   time            64    500000                            
  end_time                     time            64    820000                            
  depth                        int             32    'd2                               
  parent sequence (name)       string          4     seq0                              
  parent sequence (full name)  string          34    uvm_test_top.u_env.agt.sqr.seq0
  sequencer                    string          29    uvm_test_top.u_env.agt.sqr     
---------------------------------------------------------------------------------------
queue is
---------------------------------------------------------------------------------------
Name                           Type            Size  Value                             
---------------------------------------------------------------------------------------
m_trans                        transaction     -     @852                              
  addr                         integral        32    'h2f0                             
  pload                        da(integral)    8     -                                 
    [0]                        integral        32    'h282a5b45                        
    [1]                        integral        32    'ha91a7e04                        
    [2]                        integral        32    'h8c366963                        
    [3]                        integral        32    'h48290a3f                        
    [4]                        integral        32    'h5ff1bded                        
    [5]                        integral        32    'ha39adc79                        
    [6]                        integral        32    'h42a33ffa                        
    [7]                        integral        32    'h5dd378b6                        
  begin_time                   time            64    500000                            
  end_time                     time            64    820000                            
  depth                        int             32    'd2                               
  parent sequence (name)       string          4     seq0                              
  parent sequence (full name)  string          34    uvm_test_top.u_env.agt.sqr.seq0
  sequencer                    string          29    uvm_test_top.u_env.agt.sqr     
---------------------------------------------------------------------------------------
@860000:if0.rx_d 282a5b45
------------------------------------
Name     Type            Size  Value
------------------------------------
tr       transaction  -     @857 
  addr   integral        32    'h2f0
  pload  da(integral)    0     -    
------------------------------------
dut_final print
------------------------------------------------
Name            Type            Size  Value     
------------------------------------------------
transaction  transaction        -      @861      
  addr          integral        32    'h2f0     
  pload         da(integral)    8     -         
    [0]         integral        32    'h282a5b45
    [1]         integral        32    'h0       
    [2]         integral        32    'h0       
    [3]         integral        32    'h0       
    [4]         integral        32    'h0       
    [5]         integral        32    'h0       
    [6]         integral        32    'h0       
    [7]         integral        32    'h0       
------------------------------------------------
@900000:if0.rx_d a91a7e04
------------------------------------
Name     Type            Size  Value
------------------------------------
tr       transaction     -     @865 
  addr   integral        32    'h2f4
  pload  da(integral)    0     -    
------------------------------------
dut_final print
------------------------------------------------
Name            Type            Size  Value     
------------------------------------------------
transaction  transaction        -     @861      
  addr          integral        32    'h2f0     
  pload         da(integral)    8     -         
    [0]         integral        32    'h282a5b45
    [1]         integral        32    'ha91a7e04
    [2]         integral        32    'h0       
    [3]         integral        32    'h0       
    [4]         integral        32    'h0       
    [5]         integral        32    'h0       
    [6]         integral        32    'h0       
    [7]         integral        32    'h0       
------------------------------------------------
@940000:if0.rx_d 8c366963
------------------------------------
Name     Type            Size  Value
------------------------------------
tr       transaction     -     @869 
  addr   integral        32    'h2f8
  pload  da(integral)    0     -    
------------------------------------
dut_final print
------------------------------------------------
Name            Type            Size  Value     
------------------------------------------------
transaction  transaction        -     @861      
  addr          integral        32    'h2f0     
  pload         da(integral)    8     -         
    [0]         integral        32    'h282a5b45
    [1]         integral        32    'ha91a7e04
    [2]         integral        32    'h8c366963
    [3]         integral        32    'h0       
    [4]         integral        32    'h0       
    [5]         integral        32    'h0       
    [6]         integral        32    'h0       
    [7]         integral        32    'h0       
------------------------------------------------
@980000:if0.rx_d 48290a3f
------------------------------------
Name     Type            Size  Value
------------------------------------
tr       transaction     -     @873 
  addr   integral        32    'h2fc
  pload  da(integral)    0     -    
------------------------------------
dut_final print
------------------------------------------------
Name            Type            Size  Value     
------------------------------------------------
transaction  transaction        -     @861      
  addr          integral        32    'h2f0     
  pload         da(integral)    8     -         
    [0]         integral        32    'h282a5b45
    [1]         integral        32    'ha91a7e04
    [2]         integral        32    'h8c366963
    [3]         integral        32    'h48290a3f
    [4]         integral        32    'h0       
    [5]         integral        32    'h0       
    [6]         integral        32    'h0       
    [7]         integral        32    'h0       
------------------------------------------------
UVM_INFO my_env.sv(112) @ 1000000: uvm_test_top.u_env [environment] main phase exiting...
@1020000:if0.rx_d 5ff1bded
------------------------------------
Name     Type            Size  Value
------------------------------------
tr       transaction     -     @877 
  addr   integral        32    'h300
  pload  da(integral)    0     -    
------------------------------------
dut_final print
------------------------------------------------
Name            Type            Size  Value     
------------------------------------------------
transaction  transaction        -     @861      
  addr          integral        32    'h2f0     
  pload         da(integral)    8     -         
    [0]         integral        32    'h282a5b45
    [1]         integral        32    'ha91a7e04
    [2]         integral        32    'h8c366963
    [3]         integral        32    'h48290a3f
    [4]         integral        32    'h5ff1bded
    [5]         integral        32    'h0       
    [6]         integral        32    'h0       
    [7]         integral        32    'h0       
------------------------------------------------
@1060000:if0.rx_d a39adc79
------------------------------------
Name     Type            Size  Value
------------------------------------
tr       transaction     -     @881 
  addr   integral        32    'h304
  pload  da(integral)    0     -    
------------------------------------
dut_final print
------------------------------------------------
Name            Type            Size  Value     
------------------------------------------------
transaction  transaction        -     @861      
  addr          integral        32    'h2f0     
  pload         da(integral)    8     -         
    [0]         integral        32    'h282a5b45
    [1]         integral        32    'ha91a7e04
    [2]         integral        32    'h8c366963
    [3]         integral        32    'h48290a3f
    [4]         integral        32    'h5ff1bded
    [5]         integral        32    'ha39adc79
    [6]         integral        32    'h0       
    [7]         integral        32    'h0       
------------------------------------------------
@1100000:if0.rx_d 42a33ffa
------------------------------------
Name     Type            Size  Value
------------------------------------
tr       transaction     -     @885 
  addr   integral        32    'h308
  pload  da(integral)    0     -    
------------------------------------
dut_final print
------------------------------------------------
Name            Type            Size  Value     
------------------------------------------------
transaction  transaction        -     @861      
  addr          integral        32    'h2f0     
  pload         da(integral)    8     -         
    [0]         integral        32    'h282a5b45
    [1]         integral        32    'ha91a7e04
    [2]         integral        32    'h8c366963
    [3]         integral        32    'h48290a3f
    [4]         integral        32    'h5ff1bded
    [5]         integral        32    'ha39adc79
    [6]         integral        32    'h42a33ffa
    [7]         integral        32    'h0       
------------------------------------------------
@1140000:if0.rx_d 5dd378b6
------------------------------------
Name     Type            Size  Value
------------------------------------
tr       transaction     -     @889 
  addr   integral        32    'h30c
  pload  da(integral)    0     -    
------------------------------------
dut_final print
------------------------------------------------
Name            Type            Size  Value     
------------------------------------------------
transaction  transaction        -     @861      
  addr          integral        32    'h2f0     
  pload         da(integral)    8     -         
    [0]         integral        32    'h282a5b45
    [1]         integral        32    'ha91a7e04
    [2]         integral        32    'h8c366963
    [3]         integral        32    'h48290a3f
    [4]         integral        32    'h5ff1bded
    [5]         integral        32    'ha39adc79
    [6]         integral        32    'h42a33ffa
    [7]         integral        32    'h5dd378b6
------------------------------------------------
UVM_INFO scoreboard.sv(79) @ 1140000: uvm_test_top.u_env.scb [scoreboard] compare match
print tr_tmp dut_final
---------------------------------------------------------------------------------------
Name                           Type            Size  Value                             
---------------------------------------------------------------------------------------
m_trans                        transaction     -     @852                              
  addr                         integral        32    'h2f0                             
  pload                        da(integral)    8     -                                 
    [0]                        integral        32    'h282a5b45                        
    [1]                        integral        32    'ha91a7e04                        
    [2]                        integral        32    'h8c366963                        
    [3]                        integral        32    'h48290a3f                        
    [4]                        integral        32    'h5ff1bded                        
    [5]                        integral        32    'ha39adc79                        
    [6]                        integral        32    'h42a33ffa                        
    [7]                        integral        32    'h5dd378b6                        
  begin_time                   time            64    500000                            
  end_time                     time            64    820000                            
  depth                        int             32    'd2                               
  parent sequence (name)       string          4     seq0                              
  parent sequence (full name)  string          34    uvm_test_top.u_env.agt.sqr.seq0
  sequencer                    string          29    uvm_test_top.u_env.agt.sqr     
---------------------------------------------------------------------------------------
------------------------------------------------
Name            Type            Size  Value     
------------------------------------------------
transaction  transaction        -     @861      
  addr          integral        32    'h2f0     
  pload         da(integral)    8     -         
    [0]         integral        32    'h282a5b45
    [1]         integral        32    'ha91a7e04
    [2]         integral        32    'h8c366963
    [3]         integral        32    'h48290a3f
    [4]         integral        32    'h5ff1bded
    [5]         integral        32    'ha39adc79
    [6]         integral        32    'h42a33ffa
    [7]         integral        32    'h5dd378b6
------------------------------------------------
UVM_INFO ./test/base_test.sv(123) @ 1820000: uvm_test_top [test] main_phase exiting...
test main phase end time 1820000
UVM_INFO agent.sv(44) @ 2000000: uvm_test_top.u_env.agt [agent] main phase exiting...
UVM_INFO driver.sv(89) @ 2200000: uvm_test_top.u_env.agt.drv [driver] post_main_phase enter...
UVM_INFO ./test/base_test.sv(8) @ 2200000: reporter [my_callback] this is pre_tran task
base_test PASSED

--- UVM Report Summary ---

Quit count :     0 of     5
** Report counts by severity
UVM_INFO :   46
UVM_WARNING :    0
UVM_ERROR :    0
UVM_FATAL :    0

 

 

 

 

  • 25
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值