UVM简单测试平台

一:验证平台代码

DUT是一个简单的存储器。就六个信号,时钟信号clk,复位信号reset(高有效),读使能信号rd_en,写使能信号wr_en,写数据信号wdata,读数据信号rdata。
对于写操作:
address, wr_en和wdata 在同一时钟进行驱动。
对于读操作:
address和rd_en在同一时钟进行驱动,系统在下一时钟出现反应。

/*
              -----------------
              |               |
    addr ---->|               |
              |               |------> rdata
              | Memory Model  |
   wdata ---->|               |
              |               | 
              -----------------
                   ^     ^
                   |     |
                wr_en  rd_en

-------------------------------------------------------------------------- */
module memory
  #( parameter ADDR_WIDTH = 2,
     parameter DATA_WIDTH = 8 ) (
    input clk,
    input reset,
    
    //control signals
    input [ADDR_WIDTH-1:0]  addr,
    input                   wr_en,
    input                   rd_en,
    
    //data signals
    input  		[DATA_WIDTH-1:0] wdata,
    output reg	[DATA_WIDTH-1:0] rdata
  ); 
  
  // reg [DATA_WIDTH-1:0] rdata;
  
  //Memory
  reg [DATA_WIDTH-1:0] mem [2**ADDR_WIDTH];

  //Reset 
  always @(posedge reset) 
    for(int i=0;i<2**ADDR_WIDTH;i++) mem[i]=8'hFF;
   
  // Write data to Memory
  always @(posedge clk) 
    if (wr_en)    mem[addr] <= wdata;

  // Read data from memory
  always @(posedge clk)
    if (rd_en) rdata <= mem[addr];

endmodule

利用uvm平台搭建这个mem的验证平台。
验证平台结构图如下:

在这里插入图片描述
首先定义验证平台的interface。

`ifndef INTERFACE_SV
`define INTERFACE_SV
interface mem_if(input logic clk,reset);
  
  //---------------------------------------
  //declaring the signals
  //---------------------------------------
  logic [1:0] addr;
  logic wr_en;
  logic rd_en;
  logic [7:0] wdata;
  logic [7:0] rdata;
  
  //---------------------------------------
  //driver clocking block
  //---------------------------------------
  clocking driver_cb @(posedge clk);
    default input #1 output #1;//采样在时钟前,驱动时候在时钟上升沿后。
    output addr;
    output wr_en;
    output rd_en;
    output wdata;
    input  rdata;  
  endclocking
  
  //---------------------------------------
  //monitor clocking block
  //---------------------------------------
  clocking monitor_cb @(posedge clk);
    default input #1 output #1;
    input addr;
    input wr_en;
    input rd_en;
    input wdata;
    input rdata;  
  endclocking
  
  //---------------------------------------
  //driver modport
  //---------------------------------------
  modport DRIVER  (clocking driver_cb,input clk,reset);
  
  //---------------------------------------
  //monitor modport  
  //---------------------------------------
  modport MONITOR (clocking monitor_cb,input clk,reset);
  
endinterface
`endif

1,产生seq_item。

`ifndef SEQ_ITEM_SV
`define SEQ_ITEM_SV
import uvm_pkg::*;
`include "uvm_macros.svh"
class mem_seq_item extends uvm_sequence_item;
  //---------------------------------------
  //data and control fields
  //---------------------------------------
  rand bit [1:0] addr;
  rand bit       wr_en;
  rand bit       rd_en;
  rand bit [7:0] wdata;
       bit [7:0] rdata;
  
  //---------------------------------------
  //Utility and Field macros
  //---------------------------------------
  `uvm_object_utils_begin(mem_seq_item)
    `uvm_field_int(addr,UVM_ALL_ON)
    `uvm_field_int(wr_en,UVM_ALL_ON)
    `uvm_field_int(rd_en,UVM_ALL_ON)
    `uvm_field_int(wdata,UVM_ALL_ON)
  `uvm_object_utils_end
  
  //---------------------------------------
  //Constructor
  //---------------------------------------
  function new(string name = "mem_seq_item");
    super.new(name);
  endfunction
  
  //---------------------------------------
  //constaint, to generate any one among write and read
  //---------------------------------------
  constraint wr_rd_c { wr_en != rd_en; }; 
  
endclass
`endif

seq_item类继承与uvm_sequence_item,在这个类中定义产生的sequence的类型,并且利用域的自动化(方便后边调用比较,拷贝函数),并且做了简单的随机会约束。
2,定义sequence类,此类继承与uvm_sequence。


//=========================================================================
// mem_sequence - random stimulus 
//=========================================================================
`include "seq_item.sv"
import uvm_pkg::*;
`include "uvm_macros.svh"
class mem_sequence extends uvm_sequence#(mem_seq_item);
  
  `uvm_object_utils(mem_sequence)
  
  //--------------------------------------- 
  //Constructor
  //---------------------------------------
  function new(string name = "mem_sequence");
    super.new(name);
  endfunction
  
  //`uvm_declare_p_sequencer(mem_sequencer)
  
  //---------------------------------------
  // create, randomize and send the item to driver
  //---------------------------------------
  virtual task body();
   repeat(2) begin
    req = mem_seq_item::type_id::create("req");
    wait_for_grant();
    req.randomize();
    send_request(req);
    wait_for_item_done();
   end 
  endtask
endclass
//=========================================================================

//=========================================================================
// write_sequence - "write" type
//=========================================================================
class write_sequence extends uvm_sequence#(mem_seq_item);
  
  `uvm_object_utils(write_sequence)
   
  //--------------------------------------- 
  //Constructor
  //---------------------------------------
  function new(string name = "write_sequence");
    super.new(name);
  endfunction
  
  virtual task body();
    `uvm_do_with(req,{req.wr_en==1;})
  endtask
endclass
//=========================================================================

//=========================================================================
// read_sequence - "read" type
//=========================================================================
class read_sequence extends uvm_sequence#(mem_seq_item);
  
  `uvm_object_utils(read_sequence)
   
  //--------------------------------------- 
  //Constructor
  //---------------------------------------
  function new(string name = "read_sequence");
    super.new(name);
  endfunction
  
  virtual task body();
    `uvm_do_with(req,{req.rd_en==1;})
  endtask
endclass
//=========================================================================

//=========================================================================
// write_read_sequence - "write" followed by "read" 
//=========================================================================
class write_read_sequence extends uvm_sequence#(mem_seq_item);
  
  `uvm_object_utils(write_read_sequence)
   
  //--------------------------------------- 
  //Constructor
  //---------------------------------------
  function new(string name = "write_read_sequence");
    super.new(name);
  endfunction
  
  virtual task body();
    `uvm_do_with(req,{req.wr_en==1;})
    `uvm_do_with(req,{req.rd_en==1;})
  endtask
endclass
//=========================================================================


//=========================================================================
// wr_rd_sequence - "write" followed by "read" (sequence's inside sequences)
//=========================================================================
class wr_rd_sequence extends uvm_sequence#(mem_seq_item);
  
  //--------------------------------------- 
  //Declaring sequences
  //---------------------------------------
  write_sequence wr_seq;
  read_sequence  rd_seq;
  
  `uvm_object_utils(wr_rd_sequence)
   
  //--------------------------------------- 
  //Constructor
  //---------------------------------------
  function new(string name = "wr_rd_sequence");
    super.new(name);
  endfunction
  
  virtual task body();
  repeat(4)
    `uvm_do(wr_seq)
  repeat(4)
    `uvm_do(rd_seq)
  endtask
endclass
//=========================================================================

本案例产生了4个不同的sequence。产生sequence可以用两种不同的方法,第一个是利用
req = mem_seq_item::type_id::create(“req”);
wait_for_grant();
req.randomize();
send_request(req);
wait_for_item_done();
这种发生产生一个sequence并且交给sequencer发送出去。第二种方法就是利用sequence宏,`uvm_do和``uvm_do_with。直接产生。
其中sequence中的body函数会自动执行,需要在test中使用start,或者使用config机制,设置set.default_srqunence.。比如:
uvm_config_db#(uvm_object_wrapper)::set(this,“xxxx”,“default_sequence”,“xxxx”)
3,sequencer。一般来说sequence不需要做任何改动。

import uvm_pkg::*;
`include "seq_item.sv"
`include "uvm_macros.svh"
class mem_sequencer extends uvm_sequencer#(mem_seq_item);

  `uvm_component_utils(mem_sequencer); 

  //---------------------------------------
  //constructor
  //---------------------------------------
  function new(string name, uvm_component parent);
    super.new(name,parent);
  endfunction
  
endclass

4,driver。sequencer将sequence发送传输到driver并且由driver发送到interface。driver和sequencer使用TLM通信使用端口进行传输数据。因为item不输入compontent类型不能使用端口。其中driver通过config机制get到interface。

import uvm_pkg::*;
`include "uvm_macros.svh"
`define DRIV_IF vif.DRIVER.driver_cb
`include "seq_item.sv"
class mem_driver extends uvm_driver #(mem_seq_item);

  //--------------------------------------- 
  // Virtual Interface
  //--------------------------------------- 
  virtual mem_if vif;
  `uvm_component_utils(mem_driver)
    
  //--------------------------------------- 
  // Constructor
  //--------------------------------------- 
  function new (string name, uvm_component parent);
    super.new(name, parent);
  endfunction : new

  //--------------------------------------- 
  // build phase
  //---------------------------------------
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
     if(!uvm_config_db#(virtual mem_if)::get(this, "", "vif", vif))
       `uvm_fatal("NO_VIF",{"virtual interface must be set for: ",get_full_name(),".vif"});
  endfunction: build_phase

  //---------------------------------------  
  // run phase
  //---------------------------------------  
  virtual task run_phase(uvm_phase phase);
    forever begin
      seq_item_port.get_next_item(req);
      drive();
      seq_item_port.item_done();
    end
  endtask : run_phase
  
  //---------------------------------------
  // drive - transaction level to signal level
  // drives the value's from seq_item to interface signals
  //---------------------------------------
  virtual task drive();
    `DRIV_IF.wr_en <= 0;
    `DRIV_IF.rd_en <= 0;
    @(posedge vif.DRIVER.clk);
    
    `DRIV_IF.addr <= req.addr;
    
    if(req.wr_en) begin // write operation
      `DRIV_IF.wr_en <= req.wr_en;
      `DRIV_IF.wdata <= req.wdata;
      @(posedge vif.DRIVER.clk);
    end
    else if(req.rd_en) begin //read operation
      `DRIV_IF.rd_en <= req.rd_en;
      @(posedge vif.DRIVER.clk);
      `DRIV_IF.rd_en <= 0;
      @(posedge vif.DRIVER.clk);
      req.rdata = `DRIV_IF.rdata;
    end
    
  endtask : drive
endclass : mem_driver

在run_phase中通过
seq_item_port.get_next_item(req);
drive();
seq_item_port.item_done(); 一直从sequencer中获取sequence发送出去。
5,monitor。监视器通过接口获取interface中的数据,并将信号转换为事务级别。

import uvm_pkg::*;
`include "uvm_macros.svh"
`include "seq_item.sv"
class mem_monitor extends uvm_monitor;

  //---------------------------------------
  // Virtual Interface
  //---------------------------------------
  virtual mem_if vif;

  //---------------------------------------
  // analysis port, to send the transaction to scoreboard
  //---------------------------------------
  uvm_analysis_port #(mem_seq_item) item_collected_port;
  
  //---------------------------------------
  // The following property holds the transaction information currently
  // begin captured (by the collect_address_phase and data_phase methods).
  //---------------------------------------
  mem_seq_item trans_collected;

  `uvm_component_utils(mem_monitor)

  //---------------------------------------
  // new - constructor
  //---------------------------------------
  function new (string name, uvm_component parent);
    super.new(name, parent);
    trans_collected = new();
    item_collected_port = new("item_collected_port", this);
  endfunction : new

  //---------------------------------------
  // build_phase - getting the interface handle
  //---------------------------------------
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    if(!uvm_config_db#(virtual mem_if)::get(this, "", "vif", vif))
       `uvm_fatal("NOVIF",{"virtual interface must be set for: ",get_full_name(),".vif"});
  endfunction: build_phase
  
  //---------------------------------------
  // run_phase - convert the signal level activity to transaction level.
  // i.e, sample the values on interface signal ans assigns to transaction class fields
  //---------------------------------------
  virtual task run_phase(uvm_phase phase);
    forever begin
      @(posedge vif.MONITOR.clk);
      wait(vif.monitor_cb.wr_en || vif.monitor_cb.rd_en);
        trans_collected.addr = vif.monitor_cb.addr;
      if(vif.monitor_cb.wr_en) begin
        trans_collected.wr_en = vif.monitor_cb.wr_en;
        trans_collected.wdata = vif.monitor_cb.wdata;
        trans_collected.rd_en = 0;
        @(posedge vif.MONITOR.clk);
      end
      if(vif.monitor_cb.rd_en) begin
        trans_collected.rd_en = vif.monitor_cb.rd_en;
        trans_collected.wr_en = 0;
        @(posedge vif.MONITOR.clk);
        @(posedge vif.MONITOR.clk);
        trans_collected.rdata = vif.monitor_cb.rdata;
      end
	  item_collected_port.write(trans_collected);
      end 
  endtask : run_phase

endclass : mem_monitor

其中声明uvm_analysis_port #(mem_seq_item) item_collected_port;设置一个广播的port方便在scoreboard中接收monitor中获取的数据。run_phase中监视接口中的数据并且通过import中的write函数写入到scoreboard的队列中。
6,agent,将driver,sequencer和monitor包在一起。在agent中需要实例化driver,sequencer和monitor并且完成sequencer和driver之间的端口连接(此端口是uvm类中自己定义的,只需要连接即可)

`include "seq_item.sv"
`include "sequencer.sv"
`include "sequence.sv"
`include "driver.sv"
`include "monitor.sv"

class mem_agent extends uvm_agent;

  //---------------------------------------
  // component instances
  //---------------------------------------
  mem_driver    driver;
  mem_sequencer sequencer;
  mem_monitor   monitor;

  `uvm_component_utils(mem_agent)
  
  //---------------------------------------
  // constructor
  //---------------------------------------
  function new (string name, uvm_component parent);
    super.new(name, parent);
  endfunction : new

  //---------------------------------------
  // build_phase
  //---------------------------------------
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    
    monitor = mem_monitor::type_id::create("monitor", this);

    //creating driver and sequencer only for ACTIVE agent
    if(get_is_active() == UVM_ACTIVE) begin
      driver    = mem_driver::type_id::create("driver", this);
      sequencer = mem_sequencer::type_id::create("sequencer", this);
    end
  endfunction : build_phase
  
  //---------------------------------------  
  // connect_phase - connecting the driver and sequencer port
  //---------------------------------------
  function void connect_phase(uvm_phase phase);
    if(get_is_active() == UVM_ACTIVE) begin
      driver.seq_item_port.connect(sequencer.seq_item_export);
    end
  endfunction : connect_phase

endclass : mem_agent

7,scoreboard。scoreboard继承uvm_scoreboard。在scoreboard中需要声明import接收monitor中写入的事务,并且需要定义write函数。

import uvm_pkg::*;
`include "uvm_macros.svh"
`include "seq_item.sv"
class mem_scoreboard extends uvm_scoreboard;
  
  //---------------------------------------
  // declaring pkt_qu to store the pkt's recived from monitor
  //---------------------------------------
  mem_seq_item pkt_qu[$];
  
  //---------------------------------------
  // sc_mem 
  //---------------------------------------
  bit [7:0] sc_mem [4];

  //---------------------------------------
  //port to recive packets from monitor
  //---------------------------------------
  uvm_analysis_imp#(mem_seq_item, mem_scoreboard) item_collected_export;
  `uvm_component_utils(mem_scoreboard)

  //---------------------------------------
  // new - constructor
  //---------------------------------------
  function new (string name, uvm_component parent);
    super.new(name, parent);
  endfunction : new
  //---------------------------------------
  // build_phase - create port and initialize local memory
  //---------------------------------------
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
      item_collected_export = new("item_collected_export", this);
      foreach(sc_mem[i]) sc_mem[i] = 8'hFF;
  endfunction: build_phase
  
  //---------------------------------------
  // write task - recives the pkt from monitor and pushes into queue
  //---------------------------------------
  virtual function void write(mem_seq_item pkt);
    //pkt.print();
    pkt_qu.push_back(pkt);
  endfunction : write

  //---------------------------------------
  // run_phase - compare's the read data with the expected data(stored in local memory)
  // local memory will be updated on the write operation.
  //---------------------------------------
  virtual task run_phase(uvm_phase phase);
    mem_seq_item mem_pkt;
    
    forever begin
      wait(pkt_qu.size() > 0);
      mem_pkt = pkt_qu.pop_front();
      
      if(mem_pkt.wr_en) begin
        sc_mem[mem_pkt.addr] = mem_pkt.wdata;
        `uvm_info(get_type_name(),$sformatf("------ :: WRITE DATA       :: ------"),UVM_LOW)
        `uvm_info(get_type_name(),$sformatf("Addr: %0h",mem_pkt.addr),UVM_LOW)
        `uvm_info(get_type_name(),$sformatf("Data: %0h",mem_pkt.wdata),UVM_LOW)
        `uvm_info(get_type_name(),"------------------------------------",UVM_LOW)        
      end
      else if(mem_pkt.rd_en) begin
        if(sc_mem[mem_pkt.addr] == mem_pkt.rdata) begin
          `uvm_info(get_type_name(),$sformatf("------ :: READ DATA Match :: ------"),UVM_LOW)
          `uvm_info(get_type_name(),$sformatf("Addr: %0h",mem_pkt.addr),UVM_LOW)
          `uvm_info(get_type_name(),$sformatf("Expected Data: %0h Actual Data: %0h",sc_mem[mem_pkt.addr],mem_pkt.rdata),UVM_LOW)
          `uvm_info(get_type_name(),"------------------------------------",UVM_LOW)
        end
        else begin
          `uvm_error(get_type_name(),"------ :: READ DATA MisMatch :: ------")
          `uvm_info(get_type_name(),$sformatf("Addr: %0h",mem_pkt.addr),UVM_LOW)
          `uvm_info(get_type_name(),$sformatf("Expected Data: %0h Actual Data: %0h",sc_mem[mem_pkt.addr],mem_pkt.rdata),UVM_LOW)
          `uvm_info(get_type_name(),"------------------------------------",UVM_LOW)
        end
      end
    end
  endtask : run_phase
endclass : mem_scoreboard

因为本例比较简单,所以没有chacker,直接在scoreboard中创建参考模型,然后做数据比对。如果数据比对错误,会产生uvm_error在test中会产生错误。
8,environment。将上面的agent和scoreboard包在一起。其中在env中需要创建agent和scoreboard对象,并且实现scoreboard中的import和angent中的monitor的port连接。

import uvm_pkg::*;
`include "uvm_macros.svh"
`include "agent.sv"
`include "scoreboard.sv"

class mem_model_env extends uvm_env;
  
  //---------------------------------------
  // agent and scoreboard instance
  //---------------------------------------
  mem_agent      mem_agnt;
  mem_scoreboard mem_scb;
  
  `uvm_component_utils(mem_model_env)
  
  //--------------------------------------- 
  // constructor
  //---------------------------------------
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction : new

  //---------------------------------------
  // build_phase - crate the components
  //---------------------------------------
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);

    mem_agnt = mem_agent::type_id::create("mem_agnt", this);
    mem_scb  = mem_scoreboard::type_id::create("mem_scb", this);
  endfunction : build_phase
  
  //---------------------------------------
  // connect_phase - connecting monitor and scoreboard port
  //---------------------------------------
  function void connect_phase(uvm_phase phase);
    mem_agnt.monitor.item_collected_port.connect(mem_scb.item_collected_export);
  endfunction : connect_phase

endclass : mem_model_env

9,test。test类继承uvm_test.在test类中需要创建env对象。

`ifndef TEST_SV
`define TEST_SV
`include "env.sv"
class mem_model_base_test extends uvm_test;

  `uvm_component_utils(mem_model_base_test)
  
  //---------------------------------------
  // env instance 
  //--------------------------------------- 
  mem_model_env env;

  //---------------------------------------
  // constructor
  //---------------------------------------
  function new(string name = "mem_model_base_test",uvm_component parent=null);
    super.new(name,parent);
  endfunction : new

  //---------------------------------------
  // build_phase
  //---------------------------------------
  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);

    // Create the env
    env = mem_model_env::type_id::create("env", this);
  endfunction : build_phase
  
  //---------------------------------------
  // end_of_elobaration phase
  //---------------------------------------  
  virtual function void end_of_elaboration();
    //print's the topology
    print();
  endfunction

  //---------------------------------------
  // end_of_elobaration phase
  //---------------------------------------   
 function void report_phase(uvm_phase phase);
   uvm_report_server svr;
   super.report_phase(phase);
   
   svr = uvm_report_server::get_server();
   if(svr.get_severity_count(UVM_FATAL)+svr.get_severity_count(UVM_ERROR)>0) begin
     `uvm_info(get_type_name(), "---------------------------------------", UVM_NONE)
     `uvm_info(get_type_name(), "----            TEST FAIL          ----", UVM_NONE)
     `uvm_info(get_type_name(), "---------------------------------------", UVM_NONE)
    end
    else begin
     `uvm_info(get_type_name(), "---------------------------------------", UVM_NONE)
     `uvm_info(get_type_name(), "----           TEST PASS           ----", UVM_NONE)
     `uvm_info(get_type_name(), "---------------------------------------", UVM_NONE)
    end
  endfunction 

endclass : mem_model_base_test
`endif

并且在report_phase产生报告。
10,创建一个测试类继承test类分别创建出不同的测试任务。

import uvm_pkg::*;
`include "uvm_macros.svh"
`include "seq_item.sv"
`include "test.sv"
class mem_wr_rd_test extends mem_model_base_test;

  `uvm_component_utils(mem_wr_rd_test)
  
  //---------------------------------------
  // sequence instance 
  //--------------------------------------- 
  wr_rd_sequence seq;
  //定义sequence的种类方便调用不同的测试
  //换用不同的sequence可以实现不同的测试激励
  //---------------------------------------
  // constructor
  //---------------------------------------
  function new(string name = "mem_wr_rd_test",uvm_component parent=null);
    super.new(name,parent);
  endfunction : new

  //---------------------------------------
  // build_phase
  //---------------------------------------
  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);

    // Create the sequence
    seq = wr_rd_sequence::type_id::create("seq");
  endfunction : build_phase
  
  //---------------------------------------
  // run_phase - starting the test
  //---------------------------------------
  task run_phase(uvm_phase phase);
    
    phase.raise_objection(this);
    seq.start(env.mem_agnt.sequencer);//启动sequence
    phase.drop_objection(this);
    
    //set a drain-time for the environment if desired
    phase.phase_done.set_drain_time(this, 50);
  endtask : run_phase
  
endclass : mem_wr_rd_test

注:在test中要开启sequence,seq.start(env.mem_agnt.sequencer);并且把objection挂起,防止仿真的结束。(在任意一个run_pgase中挂起都行)
11,top顶层,在top中产生所用的clk,例化dut,利用config_db设置interface,方便driver和monitor调用。并且调用run_test(“mem_wr_rd_test”);函数。系统会自动的调用上诉的test。也可以通过使用脚本参数指定仿真的test。
vsim -novopt -classdebug +UVM_TESTNAME=mem_wr_rd_test work.tbench_top

//including interfcae and testcase files
`include "interface.sv"
`include "test.sv"
`include "wr_rd_test.sv"
//---------------------------------------------------------------

module tbench_top;

  //---------------------------------------
  //clock and reset signal declaration
  //---------------------------------------
  bit clk;
  bit reset;
  
  //---------------------------------------
  //clock generation
  //---------------------------------------
  always #5 clk = ~clk;
  
  //---------------------------------------
  //reset Generation
  //---------------------------------------
  initial begin
    reset = 1;
    #5 reset =0;
  end
  
  //---------------------------------------
  //interface instance
  //---------------------------------------
  mem_if intf(clk,reset);
  
  //---------------------------------------
  //DUT instance
  //---------------------------------------
  memory DUT (
    .clk(intf.clk),
    .reset(intf.reset),
    .addr(intf.addr),
    .wr_en(intf.wr_en),
    .rd_en(intf.rd_en),
    .wdata(intf.wdata),
    .rdata(intf.rdata)
   );
  
  //---------------------------------------
  //passing the interface handle to lower heirarchy using set method 
  //and enabling the wave dump
  //---------------------------------------
  initial begin 
    uvm_config_db#(virtual mem_if)::set(uvm_root::get(),"*","vif",intf);
    //enable wave dump
    $dumpfile("dump.vcd"); 
    $dumpvars;
  end
  
  //---------------------------------------
  //calling test
  //---------------------------------------
  initial begin 
    run_test("mem_wr_rd_test");
  end
  
endmodule

二,仿真
通过questasim,运行do脚本仿真结果如下:
在这里插入图片描述

  • 4
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
UVM(Universal Verification Methodology)是一种基于SystemVerilog的验证方法学,用于构建可重用、可扩展的验证环境。以下是一个简单UVM平台的实现示例。 1. 创建一个Testbench模块,该模块包含了UVM框架的主要组件,例如Env、Agent、Driver、Monitor和Scoreboard。 ``` `include "uvm_macros.svh" module tb_top; // UVM Components `uvm_component_name(tb_env) tb_env env; `uvm_component_name(tb_agent) tb_agent agent; `uvm_component_name(tb_driver) tb_driver driver; `uvm_component_name(tb_monitor) tb_monitor monitor; `uvm_component_name(tb_scoreboard) tb_scoreboard scoreboard; // Constructor function new(string name, uvm_component parent); super.new(name, parent); endfunction // Build Phase function void build_phase(uvm_phase phase); super.build_phase(phase); // Create UVM Components env = tb_env::type_id::create("env", this); agent = tb_agent::type_id::create("agent", this); driver = tb_driver::type_id::create("driver", this); monitor = tb_monitor::type_id::create("monitor", this); scoreboard = tb_scoreboard::type_id::create("scoreboard", this); // Connect UVM Components agent.monitor_port.connect(monitor.analysis_export); driver.seq_item_port.connect(agent.seq_item_export); scoreboard.analysis_export.connect(agent.scoreboard_export); endfunction // Run Phase task run_phase(uvm_phase phase); super.run_phase(phase); endtask endmodule ``` 2. 创建一个Env模块,该模块包含了被测设备的接口和其他环境组件。 ``` `include "uvm_macros.svh" class tb_env extends uvm_env; // UVM Components `uvm_component_name(tb_env_driver) tb_env_driver driver; `uvm_component_name(tb_env_monitor) tb_env_monitor monitor; // Constructor function new(string name, uvm_component parent); super.new(name, parent); endfunction // Build Phase function void build_phase(uvm_phase phase); super.build_phase(phase); // Create UVM Components driver = tb_env_driver::type_id::create("driver", this); monitor = tb_env_monitor::type_id::create("monitor", this); // Connect UVM Components driver.clock = env_clk; driver.reset = env_reset; monitor.clock = env_clk; monitor.reset = env_reset; endfunction endclass class tb_env_driver extends uvm_driver #(tb_env_packet); // Interface uvm_blocking_put_port #(tb_env_packet) put_port; // Constructor function new(string name, uvm_component parent); super.new(name, parent); endfunction // Run Phase virtual task run_phase(uvm_phase phase); tb_env_packet packet; forever begin // Generate Packet packet = new; packet.data = $random; // Send Packet put_port.put(packet); // Delay #10; end endtask endclass class tb_env_monitor extends uvm_monitor #(tb_env_packet); // Interface uvm_analysis_port #(tb_env_packet) analysis_port; // Constructor function new(string name, uvm_component parent); super.new(name, parent); endfunction // Run Phase virtual task run_phase(uvm_phase phase); tb_env_packet packet; forever begin // Wait for Packet @(posedge env_clk); packet = get_packet(); // Send Packet to Analysis analysis_port.write(packet); end endtask // Private Methods function tb_env_packet get_packet(); tb_env_packet packet; packet = new; packet.data = env_data; return packet; endfunction endclass ``` 3. 创建一个Agent模块,该模块包含了一个Driver和一个Monitor。 ``` `include "uvm_macros.svh" class tb_agent extends uvm_agent; // UVM Components `uvm_component_name(tb_agent_driver) tb_agent_driver driver; `uvm_component_name(tb_agent_monitor) tb_agent_monitor monitor; // Constructor function new(string name, uvm_component parent); super.new(name, parent); endfunction // Build Phase function void build_phase(uvm_phase phase); super.build_phase(phase); // Create UVM Components driver = tb_agent_driver::type_id::create("driver", this); monitor = tb_agent_monitor::type_id::create("monitor", this); // Connect UVM Components monitor.agent = this; driver.monitor_port.connect(monitor.analysis_export); endfunction endclass class tb_agent_driver extends uvm_driver #(tb_agent_sequence_item); // Interface uvm_blocking_put_port #(tb_agent_sequence_item) seq_item_port; // Constructor function new(string name, uvm_component parent); super.new(name, parent); endfunction // Run Phase virtual task run_phase(uvm_phase phase); tb_agent_sequence_item seq_item; forever begin // Get Sequence Item seq_item_port.get(seq_item); // Drive Sequence Item drive_sequence_item(seq_item); // Delay #10; end endtask // Private Methods function void drive_sequence_item(tb_agent_sequence_item seq_item); // Drive Sequence Item endfunction endclass class tb_agent_monitor extends uvm_monitor #(tb_agent_sequence_item); // Interface uvm_analysis_port #(tb_agent_sequence_item) analysis_port; // Agent tb_agent agent; // Constructor function new(string name, uvm_component parent); super.new(name, parent); endfunction // Run Phase virtual task run_phase(uvm_phase phase); tb_agent_sequence_item seq_item; forever begin // Wait for Sequence Item @(posedge agent.clock); seq_item = get_sequence_item(); // Send Sequence Item to Analysis analysis_port.write(seq_item); end endtask // Private Methods function tb_agent_sequence_item get_sequence_item(); tb_agent_sequence_item seq_item; seq_item = new; return seq_item; endfunction endclass ``` 4. 创建一个Scoreboard模块,该模块用于比对Agent的输出和Env的输出。 ``` `include "uvm_macros.svh" class tb_scoreboard extends uvm_scoreboard; // UVM Components `uvm_component_name(tb_scoreboard_driver) tb_scoreboard_driver driver; // Constructor function new(string name, uvm_component parent); super.new(name, parent); endfunction // Build Phase function void build_phase(uvm_phase phase); super.build_phase(phase); // Create UVM Components driver = tb_scoreboard_driver::type_id::create("driver", this); // Connect UVM Components driver.agent = agent; endfunction endclass class tb_scoreboard_driver extends uvm_driver #(tb_scoreboard_sequence_item); // Agent tb_agent agent; // Constructor function new(string name, uvm_component parent); super.new(name, parent); endfunction // Run Phase virtual task run_phase(uvm_phase phase); tb_scoreboard_sequence_item exp_seq_item; tb_agent_sequence_item act_seq_item; forever begin // Get Expected Sequence Item exp_seq_item = get_expected_sequence_item(); // Get Actual Sequence Item act_seq_item = get_actual_sequence_item(); // Compare Sequence Items compare_sequence_items(exp_seq_item, act_seq_item); // Delay #10; end endtask // Private Methods function tb_scoreboard_sequence_item get_expected_sequence_item(); tb_scoreboard_sequence_item seq_item; seq_item = new; return seq_item; endfunction function tb_agent_sequence_item get_actual_sequence_item(); tb_agent_sequence_item seq_item; seq_item = new; return seq_item; endfunction function void compare_sequence_items(tb_scoreboard_sequence_item exp_seq_item, tb_agent_sequence_item act_seq_item); // Compare Sequence Items endfunction endclass ``` 5. 创建一个Sequence模块,该模块用于生成测试序列。 ``` `include "uvm_macros.svh" class tb_sequence extends uvm_sequence #(tb_agent_sequence_item); // Constructor function new(string name); super.new(name); endfunction // Body virtual task body(); tb_agent_sequence_item seq_item; forever begin // Generate Sequence Item seq_item = new; // Send Sequence Item seq_item_port.put(seq_item); // Delay #10; end endtask endclass ``` 6. 最后,在顶层模块中实例化Testbench模块和Sequence模块,并运行UVM测试。 ``` module top; // Testbench tb_top tb; // Sequence tb_sequence seq; // Clock logic clk; // Reset logic reset; // Constructor initial begin // Create Testbench tb = new; // Create Sequence seq = tb_sequence::type_id::create("seq"); // Set Clock clk = 0; forever begin #5 clk = ~clk; end // Set Reset reset = 1; #10 reset = 0; // Run UVM Test run_test(); end endmodule module env; // Clock logic clk; // Reset logic reset; // Data logic [31:0] data; // Constructor initial begin // Set Clock clk = 0; forever begin #5 clk = ~clk; end // Set Reset reset = 1; #10 reset = 0; // Run Testbench top.tb.env_clk = clk; top.tb.env_reset = reset; run_test(); end endmodule ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值