UVM实战验证全加器

uvm验证全加器

初学uvm验证方法学,试着验证了32位全加器,适合初学者做参考。

DUT代码

// adder32.sv 32位全加器
module adder32_sv(
  input         clk     ,
  input         rst_n     ,
  input         enable  ,
  input  [31:0] a       ,
  input  [31:0] b       ,
  input         cin     ,
  output [31:0] s     ,
  output        cout  
);

  reg [31:0] s  = 32'h00000000 ;
  reg        cout = 1'h0  ;

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        s  = 32'h00000000  ;
        cout=  1'h0          ;
      end
    else if(enable) begin 
        {cout,s} <= a + b + cin;              
      end
    else
      begin               
        s  <= s  ;
        cout <= cout ;
      end                                   
  end    
endmodul

顶层文件top.sv

//top.sv
`ifndef TB_SV
`define TB_SV
`timescale 1ns/1ns

`include "interface.sv"
`include "test.sv"
module top;
 
`include "uvm_macros.svh"
import uvm_pkg::*;
  
 bit clk;
 
// Interface to connect the ALU agent with the DUT
slv_if    my_if(clk);
 
// DUT connections
adder32_sv  u_adder32 (
      .clk(clk),
      .rst_n(my_if.rst_n),
      .enable(my_if.enable),
      .a(my_if.a),
      .b(my_if.b),
      .cin(my_if.cin),
      .cout(my_if.cout),
      .s(my_if.s)
    );

 initial  begin
         my_if.cin    = 1'b0         ;
         my_if.a      = 32'h00000000 ;
         my_if.b      = 32'h00000000 ;
         my_if.enable       = 1'b1         ;
         my_if.rst_n        = 1'b0         ;
    #100 my_if.rst_n        = 1'b1         ;
  end

// Clock generator
initial begin
    clk = 0;
    forever begin
      #50 clk = ~clk;
    end
end
 
// Set the interface to the DUT to be used by UVM TB.
initial begin
    uvm_config_db#(virtual slv_if)::set(null,"uvm_test_top.my_env.i_agt.drv","my_if",my_if);
    uvm_config_db#(virtual slv_if)::set(null,"uvm_test_top.my_env.o_agt.mon","my_if",my_if);   
    run_test();
end
 
endmodule
`endif

测试案例test.sv

`ifndef   TEST_SV
`define   TEST_SV

`include "env.sv"

class my_test extends uvm_test;

`uvm_component_utils(my_test)

   env  my_env;

  extern function new(string name="my_test",uvm_component parent=null);
  extern virtual function void build_phase(uvm_phase phase);
  extern virtual function void start_of_simulation_phase(uvm_phase phase);


 endclass

function my_test::new (string name="my_test",uvm_component parent=null);
  super.new(name,parent);
endfunction

function void my_test::build_phase(uvm_phase phase);
   super.build_phase(phase);
   my_env = env::type_id::create("my_env",this);
   uvm_config_db#(uvm_object_wrapper)::set(this,"my_env.i_agt.seqr.main_phase","default_sequence",my_sequence::get_type());
endfunction

function void my_test::start_of_simulation_phase(uvm_phase phase);
  super.start_of_simulation_phase(phase);
  uvm_top.print_topology(uvm_default_table_printer);
  factory.print();
endfunction

`endif

env.sv

`ifndef ENV_SV
`define ENV_SV

`include "agent.sv"
`include "scoreboard.sv"
`include "modle.sv"


class env extends uvm_env;
  agent       i_agt ;              //my_driver functional
  agent       o_agt ;              //my_monitor functional
  model       mdl   ;
  scoreboard  scb   ;
  
  uvm_tlm_analysis_fifo  #(transaction) agt_scb_fifo;   //my_monitor
  uvm_tlm_analysis_fifo  #(transaction) agt_mdl_fifo;   //my_driver
  uvm_tlm_analysis_fifo  #(transaction) mdl_scb_fifo;   //my_model

  extern function new (string name,uvm_component parent);
  extern virtual function void build_phase(uvm_phase phase);
  extern virtual function void connect_phase(uvm_phase phase);
 `uvm_component_utils(env)

endclass

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

function void env::build_phase(uvm_phase phase);
super.build_phase(phase);
  i_agt = agent::type_id::create("i_agt",this);
  o_agt = agent::type_id::create("o_agt",this);
  i_agt.is_active = UVM_ACTIVE;
  o_agt.is_active = UVM_PASSIVE;
  mdl = model::type_id::create("mdl",this);
  scb = scoreboard::type_id::create("scb",this);
  agt_scb_fifo = new("agt_scb_fifo",this);
  agt_mdl_fifo = new("agt_mdl_fifo",this);
  mdl_scb_fifo = new(" mdl_scb_fifo",this);
endfunction

function void env::connect_phase(uvm_phase phase);
  super.connect_phase(phase);
  i_agt.ap.connect(agt_mdl_fifo.analysis_export);
  mdl.port.connect(agt_mdl_fifo.blocking_get_export);
  mdl.ap.connect(mdl_scb_fifo.analysis_export);
  scb.exp_port.connect(mdl_scb_fifo.blocking_get_export);
  o_agt.ap.connect(agt_scb_fifo.analysis_export);
  scb.act_port.connect(agt_scb_fifo.blocking_get_export);

endfunction


`endif

agent.sv

`ifndef AGENT_SV
`define AGENT_SV

`include "transaction.sv"
`include "driver.sv"
`include "monitor.sv"
`include "sequence.sv"


typedef uvm_sequencer #(transaction) sequencer ;

class agent extends uvm_agent;

  `uvm_component_utils(agent)

   sequencer   seqr;
   driver      drv;
   monitor     mon;

   uvm_analysis_port #(transaction) ap;

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

  virtual function  void build_phase(uvm_phase phase);
    super.build_phase(phase);
     if(is_active == UVM_ACTIVE) begin
      seqr = sequencer::type_id::create("seqr", this);
      drv = driver::type_id::create("drv", this);
    end
    else begin
       mon = monitor::type_id::create("mon", this);
    end
  endfunction

  virtual function void connect_phase(uvm_phase phase);
   super.connect_phase(phase);
   if(is_active == UVM_ACTIVE) begin 
      drv.seq_item_port.connect(seqr.seq_item_export);
     this.ap = drv.ap;
    end
    else begin
      this.ap=mon.ap;
    end
  endfunction

endclass

`endif

modle.sv

`ifndef MODEL_SV
`define MODEL_SV

class model extends uvm_component;
  uvm_blocking_get_port #(transaction)  port;   //from my_driver
  uvm_analysis_port  #(transaction)   ap;       //to scoreboard
  extern function new (string name,uvm_component parent);
  extern virtual function void build_phase(uvm_phase phase);
  extern virtual task  main_phase(uvm_phase phase);
  extern virtual task one_pkt(ref transaction pkt,ref transaction pkt2);

`uvm_component_utils(model)

endclass

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

function void model::build_phase(uvm_phase phase);
  super.build_phase(phase);
  port=new("port",this);
  ap=new("ap",this);
endfunction

task model::main_phase(uvm_phase phase);
  transaction tr,tr2;
  super.main_phase(phase);
  while(1) begin
    tr2=new();
    port.get(tr);
    #100;
    `uvm_info("MOL_MAIN_PHASE", tr.sprint(), UVM_MEDIUM)
    one_pkt(tr2,tr);
    ap.write(tr2);
    `uvm_info("MOL_MAIN_PHASE", tr2.sprint(), UVM_MEDIUM)

  end
endtask

task model::one_pkt(ref transaction pkt,ref transaction pkt2);
  bit [32:0] sum_total;
  begin
    sum_total=pkt2.a+pkt2.b+pkt2.cin;
    pkt.s=sum_total[31:0];
    pkt.cout=sum_total[32];
  end
endtask

`endif

scoreboard.sv

`ifndef SCOREBOARD_SV
`define SCOREBOARD_SV

class scoreboard extends uvm_scoreboard;
int pre_number=0;
transaction expect_queue[$];
uvm_blocking_get_port #(transaction) exp_port;//from my_reference
uvm_blocking_get_port #(transaction) act_port;//from my_monitor

`uvm_component_utils(scoreboard)

extern function new (string name,uvm_component parent);
extern virtual function void build_phase(uvm_phase phase);
extern virtual task  main_phase(uvm_phase phase);

endclass

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

function void scoreboard::build_phase(uvm_phase phase);
  super.build_phase(phase);
  exp_port=new("exp_port",this);
  act_port=new("act_port",this);
endfunction

task scoreboard::main_phase(uvm_phase phase);
  transaction get_expect,get_actual,tmp_tran;
  bit result;
  super.main_phase(phase);
fork
  while (1)
  begin
      exp_port.get(get_expect);
      expect_queue.push_back(get_expect);
  end
  while (1) begin                   
    act_port.get(get_actual);
    if(expect_queue.size>0)begin
      tmp_tran=expect_queue.pop_front();
      result=get_actual.compare(tmp_tran);
      if(result)  begin
        pre_number=pre_number+1;
        $display("compare SUCCESSFULLy:%0d",pre_number);
      end
    
      else begin
        $display("compare FAILED");
        $display("the expect pkt is");  
        tmp_tran.print();
        $display("the actual pkt is");  
        get_actual.print();
      end
    end
    else  begin
      //$display("ERROR::Received from DUT,while Expect Queue is empty");
      get_actual.print();
     end
  end
join

endtask                
                        
`endif

monitor.sv

`ifndef MONITOR__SV
`define MONITOR__SV

`include "interface.sv"

class monitor extends uvm_monitor;
  virtual slv_if vif;
  uvm_analysis_port #(transaction) ap; //  to scoreboard
  extern function new (string name,uvm_component parent);
  extern virtual function void build_phase(uvm_phase phase);
  extern virtual task  main_phase(uvm_phase phase);
  extern virtual task  receive_one_pkt(ref transaction get_pkt);
`uvm_component_utils(monitor)

endclass

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

function  void monitor::build_phase(uvm_phase phase);
  super.build_phase(phase);
  if(!uvm_config_db#(virtual slv_if)::get(this,"","my_if",vif))
  `uvm_fatal("monitor","Error in Getting interface");
  ap=new("ap",this);
endfunction

task monitor::main_phase(uvm_phase phase);
  transaction tr;
  super.main_phase(phase);
  while(1) begin
    tr=new();
    receive_one_pkt(tr);
    ap.write(tr);
  end
endtask

task monitor::receive_one_pkt(ref transaction get_pkt);
  @( negedge vif.mon_cb.enable);
    get_pkt.cout=vif.mon_cb.cout;
    get_pkt.s=vif.mon_cb.s;
endtask
           
`endif

driver.sv

`ifndef DRIVER_SV
`define DRIVER_SV

`include "transaction.sv"
`include "interface.sv"
`include "uvm_macros.svh"

class driver extends uvm_driver #(transaction);
 
  virtual slv_if vif;
  uvm_analysis_port #(transaction) ap; //to modle
  `uvm_component_utils(driver)

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

  function  void build_phase(uvm_phase phase);
    super.build_phase(phase);
    if(!uvm_config_db#(virtual slv_if)::get(this,"","my_if",vif))
    `uvm_fatal("driver","Error in Getting interface");
    ap=new("ap",this);

  endfunction

  virtual task run_phase(uvm_phase phase);
  super.run_phase(phase);
    forever begin
      seq_item_port.get_next_item(req);
      `uvm_info("DRV_RUN_PHASE", req.sprint(), UVM_MEDIUM)
      drive_one_pkt(req);
      ap.write(req);
      #100;
      seq_item_port.item_done();
    end
  endtask

task drive_one_pkt(transaction req);
    @vif.drv_cb;
    @vif.drv_cb;
    begin
        vif.drv_cb.enable<=1'b1;
        vif.drv_cb.cin<=req.cin;
        vif.drv_cb.a<=req.a;
        vif.drv_cb.b<=req.b;
    end
    @vif.drv_cb;
    @vif.drv_cb;
    vif.drv_cb.enable<=1'b0;

endtask

endclass
`endif

sequence.sv

`ifndef SEQUENCE_SV
`define SEQUENCE_SV

class my_sequence extends uvm_sequence #(transaction);

  `uvm_object_utils(my_sequence)

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

  virtual task body();
   if(starting_phase != null)
     starting_phase.raise_objection(this);
     repeat(10) begin
       `uvm_do(req);
       
       `uvm_info("SEQUENCE", req.sprint(), UVM_MEDIUM)

     end
       #100
     
   if(starting_phase != null)
     starting_phase.drop_objection(this);
   endtask

 endclass

 `endif

transaction.sv

`ifndef TRANSACTION_SV
`define TRANSACTION_SV

class transaction extends uvm_sequence_item;
    
  rand bit [31:0] a;
  rand bit [31:0] b;
  rand bit        cin;
  bit      [31:0] s;
  bit             cout;
   `uvm_object_utils_begin(transaction)
    `uvm_field_int(a, UVM_ALL_ON)
    `uvm_field_int(b, UVM_ALL_ON)
    `uvm_field_int(cin, UVM_ALL_ON)
    `uvm_field_int(cout, UVM_ALL_ON)
    `uvm_field_int(s, UVM_ALL_ON)
  `uvm_object_utils_end

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

endclass

`endif

transaction是整个验证平台各个组件之间通信所传输的事物。

interface.sv

interface是验证平台和DUT之间进行通信的接口

`ifndef INTERFACE__SV
`define INTERFACE__SV

interface slv_if(input bit clk);
    logic             rst_n   ;
    logic             cin        ; 
    logic [31:0]      a          ; 
    logic [31:0]      b        ;
    logic             enable ; 
    wire              cout;
    wire  [31:0]       s;
      
clocking drv_cb @(posedge clk);
    output enable,cin,a,b;
endclocking

clocking mon_cb @(posedge clk);
    input cout,s,enable;      
endclocking

endinterface

`endif

需要Makefile脚本文件的可以私信问哦

你可能感兴趣的:(uvm验证学习笔记)