UVM TB For Adder

     Hello , this time we will verify simple 4bit Adder using UVM. In design of Adder threre are two inputs in1 and in2 both are of 4bits, a reset signal and a clock, output is of 5 bits.Thing is Adder should produce output at rising edge of clock. for example if in1=2 and in2=2 are changing value at rising edge of clk then output should be 4 at same time.

     UVM Test Bench involve Scoreboard , Coverage Collector , Driver , Monitor and Similar Basic Components.

    Test Becnh Architecture is shown below. 

NOTE : For viewing coverage report download files from edaplayground and open coverage_data.html file. Link is given at bottom.

 

Design

module adder( clk,
        in1,
        in2,
        out,
        rst
      );
  parameter N=4;
  
  input clk;
  input rst;
  
  input [N-1:0] in1;
  input [N-1:0] in2;
  
  output [N:0] out;
  reg [N:0] temp; 
  
  assign out=(rst==1)?temp:(in1+in2);
  
  always @(posedge clk or posedge rst)
      if(rst==1)
        begin
          temp=0;
        end
    
endmodule
 

 

 adder_sequence_item

 

class adder_sequence_item extends uvm_sequence_item;

  //------------ i/p || o/p field declaration----------------------------------
  parameter N=4;
   
  rand logic [N-1:0]in1;  //i/p
  rand logic [N-1:0]in2;

  logic [N:0]out;        //o/p
  logic rst;
  
  //---------------- register adder_sequence_item class with factory ----------
  `uvm_object_utils_begin(adder_sequence_item) 
     `uvm_field_int( in1 ,UVM_ALL_ON)
     `uvm_field_int( in2 ,UVM_ALL_ON)
     `uvm_field_int( out ,UVM_ALL_ON)
     `uvm_field_int( rst ,UVM_ALL_ON)
  `uvm_object_utils_end
  //----------------------------------------------------------------------------

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

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

endclass:adder_sequence_item

 

adder_sequences

 


/***************************************************
** class name  : adder_sequence
** description : generate random inputs i.e, in1 
                 and in2
***************************************************/
class adder_sequence extends uvm_sequence#(adder_sequence_item);
  //----------------------------------------------------------------------------
  `uvm_object_utils(adder_sequence)            
  //----------------------------------------------------------------------------

  adder_sequence_item txn;
  longint loop_count=20;

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

  //----------------------------------------------------------------------------
  virtual task body();
    repeat(loop_count)
      begin
        txn=adder_sequence_item::type_id::create("txn");
        start_item(txn);
        assert(txn.randomize());
        txn.rst=0;
        finish_item(txn);
      end  
  endtask:body
  //----------------------------------------------------------------------------
endclass:adder_sequence

/***************************************************
** class name  : adder_add_zero_in1
** description : add value 0 , in1 reamains 0 
***************************************************/
class adder_add_zero_in1 extends adder_sequence;
  //----------------------------------------------------------------------------   
  `uvm_object_utils(adder_add_zero_in1)      
  //----------------------------------------------------------------------------
  
  adder_sequence_item txn;
  longint loop_count=30;
  
  //----------------------------------------------------------------------------
  function new(string name="adder_add_zero_in1");
      super.new(name);
  endfunction
  //----------------------------------------------------------------------------
  
  //----------------------------------------------------------------------------
  task body();
    repeat(loop_count)
      begin
        txn=adder_sequence_item::type_id::create("txn");
        start_item(txn);
        assert(txn.randomize()with{txn.in1==0;});
         txn.rst=0;
        finish_item(txn);
      end
  endtask:body
  //----------------------------------------------------------------------------
  
endclass

/***************************************************
** class name  : adder_add_zero_in2
** description : add 0 , in2 remains 0
***************************************************/
class adder_add_zero_in2 extends adder_sequence;
  //----------------------------------------------------------------------------   
  `uvm_object_utils(adder_add_zero_in2)      
  //----------------------------------------------------------------------------
  
  adder_sequence_item txn;
  longint loop_count=30;
  
  //----------------------------------------------------------------------------
  function new(string name="adder_add_zero_in2");
      super.new(name);
  endfunction
  //----------------------------------------------------------------------------
  
  //----------------------------------------------------------------------------
  task body();
    repeat(loop_count)
      begin
        txn=adder_sequence_item::type_id::create("txn");
        start_item(txn);
        assert(txn.randomize()with{txn.in2==0;});
         txn.rst=0;
        finish_item(txn);
      end
  endtask:body
  //----------------------------------------------------------------------------
  
endclass


/***************************************************
** class name  : add_F
** description : in1 and in2 are F(4'b1111)
***************************************************/
class add_F extends adder_sequence;
  //----------------------------------------------------------------------------   
  `uvm_object_utils(add_F)      
  //----------------------------------------------------------------------------
  
  adder_sequence_item txn;
  longint loop_count=30;
  
  //----------------------------------------------------------------------------
  function new(string name="add_F");
      super.new(name);
  endfunction
  //----------------------------------------------------------------------------
  
  //----------------------------------------------------------------------------
  task body();
    repeat(loop_count)
      begin
        txn=adder_sequence_item::type_id::create("txn");
        start_item(txn);
        assert(txn.randomize()with{txn.in1=='b1111txn.in2=='b1111;});
         txn.rst=0;
        finish_item(txn);
      end
  endtask:body
  //----------------------------------------------------------------------------
  
endclass



class reset extends adder_sequence;
  //----------------------------------------------------------------------------   
  `uvm_object_utils(reset)      
  //----------------------------------------------------------------------------
  
  adder_sequence_item txn;
  
  //----------------------------------------------------------------------------
  function new(string name="reset");
      super.new(name);
  endfunction
  //----------------------------------------------------------------------------
  
  //----------------------------------------------------------------------------
  task body();
      begin
        txn=adder_sequence_item::type_id::create("txn");
        start_item(txn);
        txn.rst=1;
        txn.in1=0;
        txn.in2=0;
        #3;
        finish_item(txn);
      end
  endtask:body
  //----------------------------------------------------------------------------
  
endclass

 

 adder_sequencer

 

class adder_sequencer extends uvm_sequencer#(adder_sequence_item);
  //----------------------------------------------------------------------------
  `uvm_component_utils(adder_sequencer)  
  //----------------------------------------------------------------------------

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

 adder_driver

 


class adder_driver extends uvm_driver #(adder_sequence_item);
  //----------------------------------------------------------------------------
  `uvm_component_utils(adder_driver)
  //----------------------------------------------------------------------------
  uvm_analysis_port #(adder_sequence_item) drv2sb;

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

  //--------------------------  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(get_type_name(),"unable to get interface");
    end
  endfunction
  //----------------------------------------------------------------------------
  
  //---------------------------- run task --------------------------------------
  task run_phase(uvm_phase phase);
    adder_sequence_item txn;
    forever begin
      seq_item_port.get_next_item(txn);
      @(posedge vif.clk);  // or vif.Clk_Blk.clk
      vif.in1 <= txn.in1;
      vif.in2 <= txn.in2;
      vif.rst <= txn.rst;
      drv2sb.write(txn);
      seq_item_port.item_done();    
    end
  endtask
  //----------------------------------------------------------------------------
  
endclass:adder_driver

 

interface

interface intf(input bit clk);
    // ------------------- port declaration-------------------------------------
    parameter N=4;

    logic [N-1:0] in1;
    logic [N-1:0] in2;
    logic [N:0]   out;
    logic rst;
    //--------------------------------------------------------------------------

  property p1;
    disable iff(rst==1)
    @(posedge clk) (out==in1+in2);
  endproperty
  
  ASSERT:assert property(p1) $display("------------ PASS -------------");
     else $display("------------ FAIL -------------");
endinterface

adder_monitor

 


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

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

  //------------------------ analysis port -------------------------------------
  uvm_analysis_port#(adder_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=adder_sequence_item::type_id::create("txn",this);
  endfunction
  //----------------------------------------------------------------------------

  //-------------------- run phase ---------------------------------------------
  task run_phase(uvm_phase phase);
    forever
    begin
      @(negedge vif.clk);
      
      txn.in1 = vif.in1;
      txn.in2 = vif.in2;
      txn.out = vif.out;
      txn.rst = vif.rst;
      ap_mon.write(txn);
    end
  endtask
  //----------------------------------------------------------------------------

endclass:adder_monitor

adder_agent

 


class adder_agent extends uvm_agent;

  //----------------------------------------------------------------------------
  `uvm_component_utils(adder_agent)
  //----------------------------------------------------------------------------

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

  //----------------- class handles --------------------------------------------
  adder_sequencer sequencer_h;
  adder_driver    driver_h;
  adder_monitor   monitor_h;
  //----------------------------------------------------------------------------

  //---------------------- build phase -----------------------------------------
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    driver_h    = adder_driver::type_id::create("driver_h",this);
    sequencer_h = adder_sequencer::type_id::create("sequencer_h",this);
    monitor_h   = adder_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:adder_agent

adder_coverage

 


class adder_coverage extends uvm_subscriber #(adder_sequence_item);

  //----------------------------------------------------------------------------
  `uvm_component_utils(adder_coverage)
  //----------------------------------------------------------------------------

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

  //----------------------------------------------------------------------------
  adder_sequence_item txn;
  real cov;
  //----------------------------------------------------------------------------
  
  //----------------------------------------------------------------------------
  covergroup dut_cov;
    option.per_instance=1;
// or coverpoint txn.in1;
// coverpoint txn.in2; it work as well. 
    IN1:coverpoint txn.in1 { 
      bins name1_1[]={[0:3]};
      bins name2_1[]={[4:7]};
      bins name3_1[]={[8:11]};
      bins name4_1[]={[11:15]};
    }
    IN2:coverpoint txn.in2 { 
      bins name1_2[]={[0:3]};
      bins name2_2[]={[4:7]};
      bins name3_2[]={[8:11]};
      bins name4_2[]={[11:15]};
    }
  endgroup:dut_cov

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

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

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


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

adder_scoreboard


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

`uvm_analysis_imp_decl( _drv )
`uvm_analysis_imp_decl( _mon )

class adder_scoreboard extends uvm_scoreboard;
  
  `uvm_component_utils(adder_scoreboard)
  
  uvm_analysis_imp_drv #(adder_sequence_item, adder_scoreboard) aport_drv;
  uvm_analysis_imp_mon #(adder_sequence_item, adder_scoreboard) aport_mon;
  
  uvm_tlm_fifo #(adder_sequence_item) expfifo;
  uvm_tlm_fifo #(adder_sequence_item) outfifo;
  
  int VECT_CNT, PASS_CNT, ERROR_CNT;
  reg [5:0]t_out,past_out;
  reg [4:0]t_in1,t_in2;


  function new(string name="adder_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(adder_sequence_item tr);
    `uvm_info("write_drv STIM"tr.input2string(), UVM_MEDIUM)
    if(tr.rst==1) 
      begin 
        t_out=0;
      end
    else 
      begin
      t_in1=tr.in1;
      t_in2=tr.in2;
      t_out=t_in1+t_in2;
      end
     tr.out = t_out;
    void'(expfifo.try_put(tr));
  endfunction

  function void write_mon(adder_sequence_item tr);
    `uvm_info("write_mon OUT "tr.convert2string(), UVM_MEDIUM)
    void'(outfifo.try_put(tr));
  endfunction
  
  task run_phase(uvm_phase phase);
  adder_sequence_item exp_tr, out_tr;
  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);
        
        if (out_tr.out == exp_tr.outbegin
            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 PASS();
  VECT_CNT++;
  PASS_CNT++;
  endfunction

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

endclass
 

 adder_env

 


class adder_env extends uvm_env;

   //---------------------------------------------------------------------------
   `uvm_component_utils(adder_env)
   //---------------------------------------------------------------------------

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

  //-------------------- class handles -----------------------------------------
  adder_agent      agent_h;
  adder_coverage   coverage_h;
  adder_scoreboard scoreboard_h;
  //----------------------------------------------------------------------------

  //---------------------- build phase -----------------------------------------
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    agent_h      = adder_agent::type_id::create("agent_h",this);
    coverage_h   = adder_coverage::type_id::create("coverage_h",this);
    scoreboard_h = adder_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:adder_env

adder_test

 


class adder_test extends uvm_test;

    //--------------------------------------------------------------------------
    `uvm_component_utils(adder_test)
    //--------------------------------------------------------------------------

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

    adder_env env_h;
    int file_h;


    adder_sequence seq;
    adder_add_zero_in1 seq1_1;
    adder_add_zero_in1 seq1_2;

    adder_add_zero_in2 seq2_1;
    adder_add_zero_in2 seq2_2;

    add_F seq3_1;
    add_F seq3_2;
  
    reset rst;

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

      seq=adder_sequence::type_id::create("seq");
      seq1_1=adder_add_zero_in1::type_id::create("seq1_1");
      seq1_2=adder_add_zero_in1::type_id::create("seq1_2");
      seq2_1=adder_add_zero_in2::type_id::create("seq2_1");
      seq2_2=adder_add_zero_in2::type_id::create("seq2_2");
      seq3_1=add_F::type_id::create("seq3_1");
      seq3_2=add_F::type_id::create("seq3_2");
      rst=reset::type_id::create("rst");
    endfunction
    //--------------------------------------------------------------------------

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

    //--------------------------------------------------------------------------
    function void start_of_simulation_phase(uvm_phase phase);
      //super.start_of_simulation_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);
      env_h.set_report_verbosity_level_hier(UVM_MEDIUM);
      seq.loop_count=100; // change value from here
    endfunction
    //--------------------------------------------------------------------------

    //--------------------------------------------------------------------------
    task run_phase(uvm_phase phase);
        phase.raise_objection(this);
           // seq.start(env_h.agent_h.sequencer_h);
            rst.start(env_h.agent_h.sequencer_h);
            seq.start(env_h.agent_h.sequencer_h);
            seq3_1.start(env_h.agent_h.sequencer_h);
            seq1_1.start(env_h.agent_h.sequencer_h);
            seq2_1.start(env_h.agent_h.sequencer_h);
            
            #10;
        phase.drop_objection(this);
    endtask
    //--------------------------------------------------------------------------

endclass:adder_test

tb_pkg


`ifndef TB_PKG
`define TB_PKG
`include "uvm_macros.svh"
package tb_pkg;
 import uvm_pkg::*;
 `include "adder_sequence_item.sv"        // transaction class
 `include "adder_sequence.sv"             // sequence class
 `include "adder_sequencer.sv"            // sequencer class
 `include "adder_driver.sv"               // driver class
 `include "adder_monitor.sv"
 `include "adder_agent.sv"                // agent class  
 `include "adder_coverage.sv"             // coverage class
 `include "adder_scoreboard.sv"           // scoreboard class
 `include "adder_env.sv"                  // environment class

 `include "adder_test.sv"                 // test

endpackage
`endif 

tb_top


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

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

  //----------------------------------------------------------------------------
  adder DUT(.in1(i_intf.in1),
            .in2(i_intf.in2),
            .out(i_intf.out),
            .clk(i_intf.clk),
            .rst(i_intf.rst)
            );
  //----------------------------------------------------------------------------               
  
  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("adder_test");
  end
  //----------------------------------------------------------------------------
endmodule

 

Link for Code : https://www.edaplayground 

Thank you for reading , have a nice day 😊😊👍.

 

Share:
Copyright © VLSI Verification Concepts . Designed by OddThemes