UVM TestBench 举例

DUT为一个可读可写的存储器,RTL代码如下:

//------------------------------------------------------------------------
//				Memory Model RTL - www.verificationguide.com
//------------------------------------------------------------------------
/*
              -----------------
              |               |
    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 [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

首先定义sequence item

class mem_seq_item extends uvm_sequence_item;
  //data and control fields 输入全部加rand
  rand bit [3: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

定义sequence,sequence分为write sequence 和 read sequence,如下:

class mem_sequence extends uvm_sequence#(mem_seq_item);
   
  `uvm_sequence_utils(mem_sequence,mem_sequencer)
   
  //Constructor
  function new(string name = "mem_sequence");
    super.new(name);
  endfunction
   
  virtual task body();
 
    req = mem_seq_item::type_id::create("req");
    wait_for_grant();
    req.randomize();
    send_request(req);
    wait_for_item_done();//可以用`uvm_do(req)代替
 
  endtask
   
endclass

write sequence

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

read sequence 

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

 定义sequencer

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

定义driver

class mem_driver extends uvm_driver #(mem_seq_item);
 
  // Virtual Interface
  virtual mem_if vif;//定义虚接口
 
  `uvm_component_utils(mem_driver)
     
  //uvm_analysis_port #(mem_seq_item) Drvr2Sb_port;
 
  // Constructor
  function new (string name, uvm_component parent);
    super.new(name, parent);
  endfunction : new
 
  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);
    //respond_to_transfer(req);
    drive();
    seq_item_port.item_done();
    end
  endtask : run_phase
 
  // drive
  virtual task drive();
    req.print();
      `DRIV_IF.wr_en <= 0;
      `DRIV_IF.rd_en <= 0;
      @(posedge vif.DRIVER.clk);
      `DRIV_IF.addr <= req.addr;
    if(req.wr_en) begin
        `DRIV_IF.wr_en <= req.wr_en;
        `DRIV_IF.wdata <= req.wdata;
      //$display("\tADDR = %0h \tWDATA = %0h",req.addr,trans.wdata);
        @(posedge vif.DRIVER.clk);
      end
    if(req.rd_en) begin
        `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;
       // $display("\tADDR = %0h \tRDATA = %0h",trans.addr,`DRIV_IF.rdata);
      end
      $display("-----------------------------------------");
  endtask : drive
 
endclass : mem_driver

定义monitor

class mem_monitor extends uvm_monitor;
 
  // Virtual Interface
  virtual mem_if vif;//定义虚接口
 
  uvm_analysis_port #(mem_seq_item) item_collected_port;//分析端口
 
  // Placeholder to capture transaction information.
  mem_seq_item trans_collected;//定义sequence item 句柄
 
  `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
 
  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
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);//将收集的sequence item发送出去
    end
  endtask : run_phase
 
endclass : mem_monitor

定义agent

class mem_agent extends uvm_agent;
  //declaring agent components
  mem_driver    driver;
  mem_sequencer sequencer;
  mem_monitor   monitor;
 
  // UVM automation macros for general components
  `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);
 
    if(get_is_active() == UVM_ACTIVE) begin
      driver = mem_driver::type_id::create("driver", this);
      sequencer = mem_sequencer::type_id::create("sequencer", this);
    end
 
    monitor = mem_monitor::type_id::create("monitor", this);
  endfunction : build_phase
 
  // connect_phase
  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

定义scoreboard

 

class mem_scoreboard extends uvm_scoreboard;
 
  `uvm_component_utils(mem_scoreboard)
  uvm_analysis_imp#(mem_seq_item, mem_scoreboard) item_collected_export;
 
  // new - constructor
  function new (string name, uvm_component parent);
    super.new(name, parent);
  endfunction : new
 
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    item_collected_export = new("item_collected_export", this);
  endfunction: build_phase
   
  // write
  virtual function void write(mem_seq_item pkt);//定义write方法,用于monitor分析port端口的调用
    $display("SCB:: Pkt recived");
    pkt.print();
  endfunction : write
 
  // run phase
  virtual task run_phase(uvm_phase phase);
    --- comparision logic ---   
  endtask : run_phase
endclass : mem_scoreboard

定义environment

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);//连接monitor和scoreboard
  endfunction : connect_phase
 
endclass : mem_model_env

定义test

class mem_model_test extends uvm_test;
 
  `uvm_component_utils(mem_model_test)
 
  mem_model_env env;
  mem_sequence  seq;
 
  function new(string name = "mem_model_test",uvm_component parent=null);
    super.new(name,parent);
  endfunction : new
 
  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
 
    env = mem_model_env::type_id::create("env", this);
    seq = mem_sequence::type_id::create("seq");
  endfunction : build_phase
 
  task run_phase(uvm_phase phase);
phase.raise_objection(this);//在test中启动sequence
  seq.start(env.mem_agnt.sequencer);
    phase.drop_objection(this);
  endtask : run_phase
 
endclass : mem_model_test

定义接口 

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;//对于driver来说,只有读入的数据为input,其余都为output  
  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;//对于monitor来说,全部的数据都为input  
  endclocking
  
  //---------------------------------------
  //driver modport
  //---------------------------------------
  modport DRIVER  (clocking driver_cb,input clk,reset);//driver接口
  
  //---------------------------------------
  //monitor modport  
  //---------------------------------------
  modport MONITOR (clocking monitor_cb,input clk,reset);//monitor接口
  
endinterface

 

定义顶层模块

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
   
  //creatinng instance of interface, inorder to connect DUT and testcase
  mem_if intf(clk,reset);
   
  //DUT instance, interface signals are connected to the DUT ports
  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)
   );
   
  //enabling the wave dump
  initial begin
    uvm_config_db#(virtual mem_if)::set(uvm_root::get(),"*","vif",intf);//配置虚接口
    $dumpfile("dump.vcd"); $dumpvars;
  end
   
  initial begin
    run_test();
  end
endmodule

 

  • 5
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值