UVM : Multiplier UVM TB

      Hello , welcome back. so in this blog post we will verify 8-bit unsigned multiplier using UVM self check TestBench.
 
     Our design has two 8-bit ports in1 and in2, 16-bit output port out.Multiplication tack place on every posedge of clock clk.
 
    TestBench Architecture
design.sv
module mul(in1,
           in2,
           clk,
           out
           );
    
   parameter N=8;

   input [N-1:0]  in1,in2;
   input              clk;
   output [(2*N)-1:0] out;
   reg[(2*N)-1:0]     temp;

   assign out=temp;
  
   always@(posedge clk)
        begin
           temp=in1*in2;
        end

endmodule
 
interface


interface intf(input bit clk);
    // ------------------- port declaration-------------------------------------
    logic [7:0]in1;
    logic [7:0]in2;
    logic [15:0]out;

endinterface

 
mul_sequence_item
class mul_sequence_item extends uvm_sequence_item;

  //------------ i/p || o/p field declaration-----------------

  rand logic [7:0]in1;  //i/p
  rand logic [7:0]in2;

  logic  [15:0]out; //o/p

  //---------------- register mul_sequence_item class with factory --------
  `uvm_object_utils_begin(mul_sequence_item) 
     `uvm_field_int( in1 ,UVM_ALL_ON)
     `uvm_field_int( in2 ,UVM_ALL_ON)
     `uvm_field_int( out ,UVM_ALL_ON)
  `uvm_object_utils_end
  //----------------------------------------------------------------------------

  //----------------------------------------------------------------------------
  function new(string name="mul_sequence_item");
    super.new(name);
  endfunction
  //----------------------------------------------------------------------------

  //----------------------------------------------------------------------------
  // write DUT inputs here for printing
  function string input2string();
    return($sformatf("in1=%h  in2=%h", in1,in2 ));
  endfunction
  
  // write DUT outputs here for printing
  function string output2string();
    return($sformatf("out=%h ",out));
  endfunction
    
  function string convert2string();
    return($sformatf({input2string(), "  ", output2string()}));
  endfunction
  //----------------------------------------------------------------------------

endclass:mul_sequence_item

 
mul_sequence

/***************************************************
** class name  : mul_sequence
** description : send random data to DUT
***************************************************/
class mul_sequence extends uvm_sequence#(mul_sequence_item);
  //----------------------------------------------------------------------------
  `uvm_object_utils(mul_sequence)            
  //----------------------------------------------------------------------------

  mul_sequence_item txn;
  int loop_count=30;

  //----------------------------------------------------------------------------
  function new(string name="mul_sequence");  
    super.new(name);
  endfunction
  //----------------------------------------------------------------------------

  //----------------------------------------------------------------------------
  virtual task body();
    for(int i=0;i<loop_count;i++) begin
      txn=mul_sequence_item::type_id::create("txn");
      start_item(txn);
      txn.randomize();
      finish_item(txn);
    end
  endtask:body
  //----------------------------------------------------------------------------
endclass:mul_sequence



/***************************************************
** class name  : mul_sequence_short
** description : vlaue of in1 and in2 is < 16
***************************************************/
class mul_sequence_short extends uvm_sequence#(mul_sequence_short);
  //----------------------------------------------------------------------------
  `uvm_object_utils(mul_sequence_short)            
  //----------------------------------------------------------------------------

  mul_sequence_item txn;
  int loop_count=30;

  //----------------------------------------------------------------------------
  function new(string name="mul_sequence_short");  
    super.new(name);
  endfunction
  //----------------------------------------------------------------------------

  //----------------------------------------------------------------------------
  virtual task body();
    for(int i=0;i<loop_count;i++) begin
      txn=mul_sequence_item::type_id::create("txn");
      start_item(txn);
      txn.randomize()with{txn.in1<16;txn.in2<16;};
      finish_item(txn);
    end
  endtask:body
  //----------------------------------------------------------------------------
endclass


/***************************************************
** class name  : mul_sequence_high
** description : vlaue of in1 and in2 is > 128
***************************************************/
class mul_sequence_high extends uvm_sequence#(mul_sequence_high);
  //----------------------------------------------------------------------------
  `uvm_object_utils(mul_sequence_high)            
  //----------------------------------------------------------------------------

  mul_sequence_item txn;
  int loop_count=30;

  //----------------------------------------------------------------------------
  function new(string name="mul_sequence_high");  
    super.new(name);
  endfunction
  //----------------------------------------------------------------------------

  //----------------------------------------------------------------------------
  virtual task body();
    for(int i=0;i<loop_count;i++) begin
      txn=mul_sequence_item::type_id::create("txn");
      start_item(txn);
      txn.randomize()with{txn.in1>128;txn.in2>128;};
      finish_item(txn);
    end
  endtask:body
  //----------------------------------------------------------------------------
endclass

/***************************************************
** class name  : in1_0_seq
** description : send data to DUT in which in1==0
***************************************************/
class in1_0_seq extends mul_sequence;
  //----------------------------------------------------------------------------   
  `uvm_object_utils(in1_0_seq)      
  //----------------------------------------------------------------------------
  
  mul_sequence_item txn;
  int loop_count=30;
  
  //----------------------------------------------------------------------------
  function new(string name="in1_0_seq");
      super.new(name);
  endfunction
  //----------------------------------------------------------------------------
  
  //----------------------------------------------------------------------------
  task body();
    for(int i=0;i<loop_count;i++) begin
      txn=mul_sequence_item::type_id::create("txn");
      start_item(txn);
      txn.randomize()with{txn.in1==0;};
      finish_item(txn);
    end
  endtask:body
  //----------------------------------------------------------------------------
  
endclass
 
mul_sequencer
class mul_sequencer extends uvm_sequencer#(mul_sequence_item);
  //----------------------------------------------------------------------------
  `uvm_component_utils(mul_sequencer)  
  //----------------------------------------------------------------------------

  //----------------------------------------------------------------------------
  function new(string name="mul_sequencer",uvm_component parent);  
    super.new(name,parent);
  endfunction
  //----------------------------------------------------------------------------
  
endclass:mul_sequencer

 
mul_driver

class mul_driver extends uvm_driver #(mul_sequence_item);
  //----------------------------------------------------------------------------
  `uvm_component_utils(mul_driver)
  //----------------------------------------------------------------------------

  //----------------------------------------------------------------------------
  function new(string name="mul_driver",uvm_component parent);
    super.new(name,parent);
  endfunction
  //---------------------------------------------------------------------------- 

  uvm_analysis_port #(mul_sequence_item) drv2sb;
  bit flag;
  
  //--------------------------  virtual interface handel -----------------------  
  virtual interface intf vif;
  //----------------------------------------------------------------------------
  
  //-------------------------  get interface handel from top -------------------
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    if(!(uvm_config_db#(virtual intf)::get(this,"","vif",vif))) begin
      `uvm_fatal("driver","unable to get interface");
    end
    drv2sb=new("drv2sb",this);
  endfunction
  //----------------------------------------------------------------------------
  
  //---------------------------- run task --------------------------------------
  task run_phase(uvm_phase phase);
    mul_sequence_item txn;
    forever begin
      seq_item_port.get_next_item(txn);
      @(posedge vif.clk);
      vif.in1 <= txn.in1;
      vif.in2 <= txn.in2;
      flag=$isunknown(txn.in1);
      if(flag==1) begin
        $display("   UNKNOW VALUE DETECTED   ");
        seq_item_port.item_done();
      end
      else begin
        drv2sb.write(txn);
        `uvm_info(get_type_name(),txn.convert2string(),UVM_MEDIUM)      
        seq_item_port.item_done();
      end
    end
  endtask
  //----------------------------------------------------------------------------
  
endclass:mul_driver

 
mul_monitor
class mul_monitor extends uvm_monitor;
  //----------------------------------------------------------------------------
  `uvm_component_utils(mul_monitor)
  //----------------------------------------------------------------------------

  //------------------- constructor --------------------------------------------
  function new(string name="mul_monitor",uvm_component parent);
    super.new(name,parent);
  endfunction
  //----------------------------------------------------------------------------
  
  //---------------- sequence_item class ---------------------------------------
  mul_sequence_item  txn;
  //----------------------------------------------------------------------------
  bit flag,flag1;
  //------------------------ virtual interface handle---------------------------  
  virtual interface intf vif;
  //----------------------------------------------------------------------------

  //------------------------ analysis port -------------------------------------
  uvm_analysis_port#(mul_sequence_item) ap_mon;
  //----------------------------------------------------------------------------
  
  //------------------- build phase --------------------------------------------
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    if(!(uvm_config_db#(virtual intf)::get(this,"","vif",vif)))
    begin
      `uvm_fatal("monitor","unable to get interface")
    end
    
    ap_mon=new("ap_mon",this);
    txn=mul_sequence_item::type_id::create("txn",this);
  endfunction
  //----------------------------------------------------------------------------

  //-------------------- run phase ---------------------------------------------
  task run_phase(uvm_phase phase);
    forever
    begin
      @(posedge vif.clk);
      txn.in1 = vif.in1;
      txn.in2 = vif.in2;
      txn.out = vif.out;
      flag=$isunknown(txn.in1);
      flag=$isunknown(txn.out);
      `uvm_info(get_type_name(),txn.convert2string(),UVM_MEDIUM)      
    ap_mon.write(txn);
    end
  endtask
  //----------------------------------------------------------------------------

endclass:mul_monitor

 
mul_agent

class mul_agent extends uvm_agent;

  //----------------------------------------------------------------------------
  `uvm_component_utils(mul_agent)
  //----------------------------------------------------------------------------

  //----------------------------------------------------------------------------
  function new(string name="mul_agent",uvm_component parent);
    super.new(name,parent);
  endfunction
  //----------------------------------------------------------------------------

  //----------------- class handles --------------------------------------------
  mul_sequencer sequencer_h;
  mul_driver    driver_h;
  mul_monitor   monitor_h;
  //----------------------------------------------------------------------------

  //---------------------- build phase -----------------------------------------
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    driver_h    = mul_driver::type_id::create("driver_h",this);
    sequencer_h = mul_sequencer::type_id::create("sequencer_h",this);
    monitor_h   = mul_monitor::type_id::create("monitor_h",this);
  endfunction
  //----------------------------------------------------------------------------

  //----------------------- connect phase --------------------------------------
  function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    driver_h.seq_item_port.connect(sequencer_h.seq_item_export);
  endfunction
  //----------------------------------------------------------------------------

endclass:mul_agent

 
mul_coverage

class mul_coverage extends uvm_subscriber #(mul_sequence_item);

  //----------------------------------------------------------------------------
  `uvm_component_utils(mul_coverage)
  //----------------------------------------------------------------------------

  //----------------------------------------------------------------------------
  function new(string name="mul_coverage",uvm_component parent);
    super.new(name,parent);
    dut_cov=new();
  endfunction
  //----------------------------------------------------------------------------

  //----------------------------------------------------------------------------
  mul_sequence_item txn;
  real cov;
  //----------------------------------------------------------------------------
  
  //----------------------------------------------------------------------------
  covergroup dut_cov;
    option.per_instance= 1;
    option.comment     = "dut_cov";
    option.name        = "dut_cov";
    option.auto_bin_max= 256;

    IN1:coverpoint txn.in1;
    IN2:coverpoint txn.in2;
  
  endgroup:dut_cov;

  //----------------------------------------------------------------------------

  //---------------------  write method ----------------------------------------
  function void write(mul_sequence_item t);
    txn=t;
    dut_cov.sample();
  endfunction
  //----------------------------------------------------------------------------

  //----------------------------------------------------------------------------
  function void extract_phase(uvm_phase phase);
    cov=dut_cov.get_coverage();
  endfunction
  //----------------------------------------------------------------------------


  //----------------------------------------------------------------------------
  function void report_phase(uvm_phase phase);
    `uvm_info(get_type_name(),$sformatf("Coverage is %f",cov),UVM_LOW)
  endfunction
  //----------------------------------------------------------------------------
  
endclass:mul_coverage

 
mul_scoreboard

/***************************************************
  analysis_port from driver
  analysis_port from monitor
***************************************************/

`uvm_analysis_imp_decl( _drv )
`uvm_analysis_imp_decl( _mon )

class mul_scoreboard extends uvm_scoreboard;
  
  `uvm_component_utils(mul_scoreboard)
  
  uvm_analysis_imp_drv #(mul_sequence_item, mul_scoreboard) aport_drv;
  uvm_analysis_imp_mon #(mul_sequence_item, mul_scoreboard) aport_mon;
  
  uvm_tlm_fifo #(mul_sequence_item) expfifo;
  uvm_tlm_fifo #(mul_sequence_item) outfifo;
  
  int q1[$];
  int q2[$];
  int i;
  int VECT_CNT, PASS_CNT, ERROR_CNT;
  logic [15:0]t_out;
  
  function new(string name="mul_scoreboard",uvm_component parent);
    super.new(name,parent);
  endfunction
    
  function void build_phase(uvm_phase phase);
  super.build_phase(phase);
  aport_drv = new("aport_drv"this);
  aport_mon = new("aport_mon"this);
  expfifo= new("expfifo",this);
  outfifo= new("outfifo",this);
  endfunction


  function void write_drv(mul_sequence_item tr);
    `uvm_info("write_drv STIM"tr.convert2string(), UVM_MEDIUM)
    //write scoreboard code here
    t_out  = tr.in1*tr.in2;
    tr.out = t_out;
    q1.push_back(t_out);
    void'(expfifo.try_put(tr));
  endfunction

  function void write_mon(mul_sequence_item tr);
    `uvm_info("write_mon OUT "tr.convert2string(), UVM_MEDIUM)
    q2.push_back(tr.out);
    void'(outfifo.try_put(tr));
  endfunction
  
  task run_phase(uvm_phase phase);
  mul_sequence_item exp_tr, out_tr;
    i=0;
  forever begin
      `uvm_info("scoreboard run task","WAITING for expected output"UVM_DEBUG)
      expfifo.get(exp_tr);
      `uvm_info("scoreboard run task","WAITING for actual output"UVM_DEBUG)
      outfifo.get(out_tr);
  //      $display("i = %0d",i);
  //      $display("q1 = %h",q1[i]);
  //      $display("q2 = %h",q2[i]);
      
        i++;
    /*  if (out_tr.out===exp_tr.out) begin
            PASS();
           `uvm_info ("PASS ",out_tr.convert2string() , UVM_MEDIUM)
    end
      
        else begin
     ERROR();
          `uvm_info ("ERROR [ACTUAL_OP]",out_tr.convert2string() , UVM_MEDIUM)
          `uvm_info ("ERROR [EXPECTED_OP]",exp_tr.convert2string() , UVM_MEDIUM)
          `uvm_warning("ERROR",exp_tr.convert2string())
  end */
    end  
  endtask
  
  
  function void check_phase(uvm_phase phase);
    super.check_phase(phase);
    $display("INSIDE CHECK PHASE ");
    foreach(q1[i])
      begin
        if(q1[i]==q2[i+2]) begin
            //$display("q1=%h q2=%h : i=%d",q1[i],q2[i+2],i);
            PASS();
          `uvm_info ("PASS ",$sformatf("q1=%h q2=%h : PASS",q1[i],q2[i+2]) , UVM_LOW)
        end
        else begin
          //$display("FAIL");
          ERROR();
          `uvm_warning("ERROR",$sformatf("q1=%h q2=%h : ERROR",q1[i],q2[i+2]))
        end
        if(i==(q1.size()-2)) begin
          $display("BREAKING LOOP");
          break;
        end
      end
  endfunction
  
  
  function void report_phase(uvm_phase phase);
        super.report_phase(phase);
        if (VECT_CNT && !ERROR_CNT)
            `uvm_info("PASSED",$sformatf("*** TEST PASSED - %0d vectors ran, %0d vectors passed***",
            VECT_CNT, PASS_CNT), UVM_LOW)

        else
            `uvm_info("FAILED",$sformatf("*** TEST FAILED - %0d vectors ran, %0d vectors passed, %0d vectors failed ***",
            VECT_CNT, PASS_CNT, ERROR_CNT), UVM_LOW)
  endfunction

  function void PASS();
  VECT_CNT++;
  PASS_CNT++;
  endfunction

  function void ERROR();
    VECT_CNT++;
    ERROR_CNT++;
  endfunction

endclass

 
mul_env

class mul_env extends uvm_env;

   //---------------------------------------------------------------------------
   `uvm_component_utils(mul_env)
   //---------------------------------------------------------------------------

  //----------------------------------------------------------------------------
  function new(string name="mul_env",uvm_component parent);
    super.new(name,parent);
  endfunction
  //----------------------------------------------------------------------------

  //-------------------- class handles -----------------------------------------
  mul_agent    agent_h;
  mul_coverage coverage_h;
  mul_scoreboard scoreboard_h;
  //----------------------------------------------------------------------------

  //---------------------- build phase -----------------------------------------
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    agent_h    = mul_agent::type_id::create("agent_h",this);
    coverage_h = mul_coverage::type_id::create("coverage_h",this);
    scoreboard_h = mul_scoreboard::type_id::create("scoreboard_h",this);
  endfunction
  //----------------------------------------------------------------------------

  //-------------------------- connect phase -----------------------------------
  function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    agent_h.monitor_h.ap_mon.connect(coverage_h.analysis_export);
    
    agent_h.monitor_h.ap_mon.connect(scoreboard_h.aport_mon);
    agent_h.driver_h.drv2sb.connect(scoreboard_h.aport_drv);
  endfunction
  //----------------------------------------------------------------------------
endclass:mul_env

 
mul_test

class mul_test extends uvm_test;

    //--------------------------------------------------------------------------
    `uvm_component_utils(mul_test)
    //--------------------------------------------------------------------------

    //--------------------------------------------------------------------------
    function new(string name="mul_test",uvm_component parent);
      super.new(name,parent);
    endfunction
    //--------------------------------------------------------------------------

    mul_env env_h;
    int file_h;

    //--------------------------------------------------------------------------
    function void build_phase(uvm_phase phase);
      super.build_phase(phase);
      env_h = mul_env::type_id::create("env_h",this);
    endfunction
    //--------------------------------------------------------------------------

    //--------------------------------------------------------------------------
    function void end_of_elobartion_phase(uvm_phase phase);
      //factory.print();
      $display("End of eleboration phase in agent");
    endfunction
    //--------------------------------------------------------------------------

    //--------------------------------------------------------------------------
    function void start_of_simulation_phase(uvm_phase phase);
      $display("start_of_simulation_phase");
      file_h=$fopen("LOG_FILE.log","w");
      set_report_default_file_hier(file_h);
      set_report_severity_action_hier(UVM_INFO,UVM_DISPLAY+UVM_LOG);
      set_report_verbosity_level_hier(UVM_LOW);
    endfunction
    //--------------------------------------------------------------------------

    //--------------------------------------------------------------------------
    task run_phase(uvm_phase phase);
        mul_sequence seq1,seq2;
        in1_0_seq seq3;
        mul_sequence_short seq4;
        mul_sequence_high seq5;
        phase.raise_objection(this);
            
          seq1= mul_sequence::type_id::create("seq1");
            seq2= mul_sequence::type_id::create("seq2");
            seq3= in1_0_seq::type_id::create("seq3");
          seq4=mul_sequence_short::type_id::create("seq4");
          seq5=mul_sequence_high::type_id::create("seq5");
          
          seq1.loop_count=100;
          seq2.loop_count=100;
          seq4.loop_count=200;
          seq5.loop_count=200;
            seq1.start(env_h.agent_h.sequencer_h);
            seq2.start(env_h.agent_h.sequencer_h);
            seq3.start(env_h.agent_h.sequencer_h);
            seq4.start(env_h.agent_h.sequencer_h);
           seq5.start(env_h.agent_h.sequencer_h);
            #10;
        phase.drop_objection(this);
    endtask
    //--------------------------------------------------------------------------

endclass:mul_test
 
tb_pkg

`ifndef TB_PKG
`define TB_PKG
`include "uvm_macros.svh"
package tb_pkg;
    
 import uvm_pkg::*;
 `include "mul_sequence_item.sv"        // transaction class
 `include "mul_sequence.sv"             // sequence class
 `include "mul_sequencer.sv"            // sequencer class
 `include "mul_driver.sv"               // driver class
 `include "mul_monitor.sv"
 `include "mul_agent.sv"                // agent class  
 `include "mul_coverage.sv"             // coverage class
 `include "mul_scoreboard.sv"
 `include "mul_env.sv"                  // environment class
 `include "mul_test.sv"                 // test1

endpackage
`endif 

 
tb_top

`include "interface.sv"
`include "tb_pkg.sv"
module top;
  import uvm_pkg::*;
  import tb_pkg::*;
  
  bit clk; 

  //----------------------------------------------------------------------------
  intf i_intf(clk);
  //----------------------------------------------------------------------------

  //----------------------------------------------------------------------------
  mul DUT(.in1(i_intf.in1),
          .in2(i_intf.in2),
          .clk(i_intf.clk),
          .out(i_intf.out)
          );
  //----------------------------------------------------------------------------               
  always #5 clk=~clk;

  initial begin
    clk<=0;
  end
  
  //----------------------------------------------------------------------------
  initial begin
    $dumpfile("dumpfile.vcd");
    $dumpvars;
  end
  //----------------------------------------------------------------------------

  //----------------------------------------------------------------------------
  initial begin
    uvm_config_db#(virtual intf)::set(uvm_root::get(),"","vif",i_intf);
  end
  //----------------------------------------------------------------------------

  //----------------------------------------------------------------------------
  initial begin
    run_test("mul_test");
  end
  //----------------------------------------------------------------------------
endmodule
 
Output Result  :

UVM_INFO /home/runner/mul_coverage.sv(50) @ 6305: uvm_test_top.env_h.
     coverage_h [mul_coverage] Coverage is 85.937500
UVM_INFO /home/runner/mul_scoreboard.sv(109) @ 6305: uvm_test_top.env_h.
     scoreboard_h [PASSED] *** TEST PASSED - 629 vectors ran,629 vectors passed***
 
 
For cross verify scoreboard you can change something in design and see whether it is working properly or not.
 
Thank You, for reading. have a nice Day 🙂🙂😇. 
 
Share:
Copyright © VLSI Verification Concepts . Designed by OddThemes