UVM TB For 64KB RAM

    Hello again, i this blog we will verify 64KB RAM with UVM , Our TB Also Contain Scoreboard So That It Can Check Itself(self checking TB).I assume you know basic UVM.

    Description of Design Signals is shown Below.

////////////////////////////////////////////////////////////////////////////////////////////////////////
// Design of 64KB Ram
// Data input width = 8         -> data_in
// Data output width = 8       -> data_out
// Address width = 16           -> addr
// Address range 0 to 65535
// Synchronous with clk        -> clk , rdn_wr, rst_p
// rdn_wr signal -> when rdn_wr=0 means read rdn_wr=1 means write
// synchronous reset -> rst_p means active high reset
////////////////////////////////////////////////////////////////////////////////////////////////////////

 Major components of our TB is Coverage Collector and Scoreboard. 

Sequence description :

-> write 0 (zero) in all address and read from all addresses.
-> write FF in all address and read from all addresses.
-> first write and read from same location consecutively
-> write in two locations and read from these two location
-> write randomly at any address
-> read randomly from any address
-> reset sequence 
NOTE : you will find these in ram_sequence.sv file 

Test Bench Architecture is shown below.

Design 

////////////////////////////////////////////////////////////////////////////
// design of 64KB Ram
// data input width = 8
// data output width = 8
// address width = 16
// address range 0 to 65535
// synchronous with clk
// rdn_wr signal -> when rdn_wr=0 means read rdn_wr=1 means write
// synchronous reset -> rst_p means active high reset
////////////////////////////////////////////////////////////////////////////
module RAM(clk,
           rst_p,
           data_in,
           data_out,
           addr,
           rdn_wr
           );

    parameter ADDR_WIDTH=16;
    parameter DATA_WIDTH=8;

    input clk;
    input rst_p;
    input rdn_wr;
    input [DATA_WIDTH-1:0]data_in;
    input [ADDR_WIDTH-1:0]addr;

  output reg [DATA_WIDTH-1:0]data_out;

    reg [DATA_WIDTH-1:0] mem[(2**ADDR_WIDTH-1):0];

    always@(posedge clk )
        begin
            if(rst_p==1'b1)
                begin
                    for(int unsigned i=0;i<2**ADDR_WIDTH;i++)
                        begin
                            mem[i]<=0;
                            data_out<=0;
                        end
                end
        end

    always@(addr,data_in,rdn_wr)
        begin
            if(rdn_wr==1'b1)      //write into RAM
                begin
                    mem[addr]=data_in;
                end
            else if (rdn_wr==1'b0// read from RAM
                begin
                    data_out=mem[addr];
                end
            else  
                begin
                    data_out=data_out;
                end
        end
endmodule
            

 

 Interface

interface intf(input bit clk);
    // ------------------- port declaration-------------------------------------
    parameter ADDR_WIDTH=16;
    parameter DATA_WIDTH=8;
    logic [DATA_WIDTH-1:0]data_in;
    logic [DATA_WIDTH-1:0]data_out;
    logic rdn_wr;
    logic rst_p;
    logic [ADDR_WIDTH-1:0]addr;
    //--------------------------------------------------------------------------

    //------------- clocking & modport declaration -----------------------------
  /*  clocking clocking_block_name @(posedge signal_name);
      default input #1step output #1step;
      output //input of DUT
      input  //output of DUT
    endclocking
  */
    //modport modport_name(clocking name_of_block);
    //--------------------------------------------------------------------------
        
endinterface

 

ram_sequence_item


class ram_sequence_item extends uvm_sequence_item;

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

  parameter ADDR_WIDTH=16;
  parameter DATA_WIDTH=8;

  rand logic [DATA_WIDTH-1:0]data_in;
  rand logic rdn_wr;
  rand logic [ADDR_WIDTH-1:0]addr;
  logic rst_p;

  logic [DATA_WIDTH-1:0]data_out;
  
  //---------------- register ram_sequence_item class with factory --------
  `uvm_object_utils_begin(ram_sequence_item) 
     `uvm_field_int( data_in  ,UVM_ALL_ON)
     `uvm_field_int( rdn_wr   ,UVM_ALL_ON)
     `uvm_field_int( rst_p    ,UVM_ALL_ON)
     `uvm_field_int( addr     ,UVM_ALL_ON)
     `uvm_field_int( data_out ,UVM_ALL_ON)
  `uvm_object_utils_end
  //----------------------------------------------------------------------------

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

  function string convert2string();
    return $sformatf("mux_sequence_item",$sformatf("data_in=%0f addr=%0f \
    rdn_wr=%0b rst_p=%0b data_out=%0f",data_in,addr,rdn_wr,rst_p,data_out));
  endfunction
  
endclass:ram_sequence_item


ram_sequencer

class ram_sequencer extends uvm_sequencer#(ram_sequence_item);
  //----------------------------------------------------------------------------
  `uvm_component_utils(ram_sequencer)  
  //----------------------------------------------------------------------------
 
  //----------------------------------------------------------------------------
  function new(string name="",uvm_component parent);  
    super.new(name,parent);
  endfunction
  //----------------------------------------------------------------------------
  
endclass:ram_sequencer


ram_sequence

NOTE: Only Few Sequence is shown here other sequence you will find in link , which is at bottom.

class ram_sequence extends uvm_sequence#(ram_sequence_item);
  //----------------------------------------------------------------------------
  `uvm_object_utils(ram_sequence)            
  //----------------------------------------------------------------------------

  ram_sequence_item txn;

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

  //----------------------------------------------------------------------------
  virtual task body();
    
  endtask:body
  //----------------------------------------------------------------------------
endclass:ram_sequence

/********************************************************************
class name  : reset_sequence
description : ->reset sequence for resetting RAM
*********************************************************************/
class reset_sequence extends ram_sequence;
  //----------------------------------------------------------------------------   
  `uvm_object_utils(reset_sequence)      
  //----------------------------------------------------------------------------
  
  ram_sequence_item txn;
  
  //----------------------------------------------------------------------------
  function new(string name="reset_sequence");
      super.new(name);
  endfunction
  //----------------------------------------------------------------------------
  
  //----------------------------------------------------------------------------
  task body();
    txn=ram_sequence_item::type_id::create("txn");
    start_item(txn);
    txn.rst_p=1;
    txn.data_in=0;
    txn.rdn_wr=0;
    txn.addr=0;
    finish_item(txn);
  endtask:body
  //----------------------------------------------------------------------------
  
endclass:reset_sequence

/********************************************************************
class name  : write_only
description : ->it will only write in RAM , in which data , address 
                are random
              ->you can change iteration to any value  
*********************************************************************/
class write_only extends ram_sequence;
  //----------------------------------------------------------------------------   
  `uvm_object_utils(write_only)      
  //----------------------------------------------------------------------------
  ram_sequence_item txn;
  int unsigned iteration=100;
  //----------------------------------------------------------------------------
  function new(string name="write_only");
      super.new(name);
  endfunction
  //----------------------------------------------------------------------------
  
  //----------------------------------------------------------------------------
  task body();
    repeat(iteration)
    begin
      txn=ram_sequence_item::type_id::create("txn");
      start_item(txn);
      txn.randomize()with{txn.rdn_wr==1;};
      txn.rst_p=0;
      finish_item(txn);
    end
  endtask:body
  //----------------------------------------------------------------------------
  
endclass:write_only


ram_driver


class ram_driver extends uvm_driver #(ram_sequence_item);
  //----------------------------------------------------------------------------
  `uvm_component_utils(ram_driver)
  //----------------------------------------------------------------------------

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

  //--------------------------  virtual interface handle -----------------------  
  virtual interface intf vif;
  //----------------------------------------------------------------------------
  
  //-------------------------  get interface handle 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
  endfunction
  //----------------------------------------------------------------------------
  
  //---------------------------- run task --------------------------------------
  task run_phase(uvm_phase phase);
    ram_sequence_item txn;
    forever begin
      seq_item_port.get_next_item(txn);
      // write driver code here
      @(posedge vif.clk);
      vif.data_in <= txn.data_in;
      vif.rdn_wr  <= txn.rdn_wr;
      vif.rst_p   <= txn.rst_p;
      vif.addr    <= txn.addr;
      #1;
      drv2sb.write(txn);   // send data to scoreboard
      `uvm_info(get_type_name(),txn.convert2string(),UVM_MEDIUM)
     // txn.printf();
      seq_item_port.item_done();    
    end
  endtask
  //----------------------------------------------------------------------------
  
endclass:ram_driver


ram_monitor


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

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

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

  //-------------------- run phase ---------------------------------------------
  task run_phase(uvm_phase phase);
    forever
    begin
      // write monitor code here
      @(negedge vif.clk);
      txn.addr    = vif.addr;
      txn.data_in   = vif.data_in;
      txn.data_out  = vif.data_out;
      txn.rdn_wr    = vif.rdn_wr;
      txn.rst_p     = vif.rst_p
      ap_mon.write(txn);
    end
  endtask
  //-----------------------------------------------------------------------
endclass:ram_monitor


ram_agent


class ram_agent extends uvm_agent;

  //----------------------------------------------------------------------------
  `uvm_component_utils(ram_agent)
  //----------------------------------------------------------------------------

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

  //----------------- class handles --------------------------------------------
  ram_sequencer sequencer_h;
  ram_driver    driver_h;
  ram_monitor   monitor_h;
  //----------------------------------------------------------------------------

  //---------------------- build phase -----------------------------------------
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    driver_h    = ram_driver::type_id::create("driver_h",this);
    sequencer_h = ram_sequencer::type_id::create("sequencer_h",this);
    monitor_h   = ram_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:ram_agent


ram_coverage


class ram_coverage extends uvm_subscriber #(ram_sequence_item);

  //----------------------------------------------------------------------------
  `uvm_component_utils(ram_coverage)
  //----------------------------------------------------------------------------

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

  //----------------------------------------------------------------------------
  ram_sequence_item txn;
  real cov;
  //----------------------------------------------------------------------------
  
  //----------------------------------------------------------------------------
  covergroup dut_cov;
    option.per_instance=1;
    
    ADDR:coverpoint txn.addr { option.auto_bin_max=65535;}
    
    RDN_WR:coverpoint txn.rdn_wr;
    
    ADDR_X_RDN_WR:cross ADDR,RDN_WR;
    
    // ADDR_X_RDN_WR:cross ADDR,RDN_WR {option.cross_auto_bin_max=131072;}
    // option.cross_auto_bin_max gives error in Aldec
    DATA:coverpoint txn.data_in { option.auto_bin_max=255; }
    
  endgroup:dut_cov

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

  //---------------------  write method ----------------------------------------
  function void write(ram_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_LOW)
  endfunction
  //----------------------------------------------------------------------------
  
endclass:ram_coverage

 

 ram_scoreboard

`uvm_analysis_imp_decl( _drv )
`uvm_analysis_imp_decl( _mon )

class ram_scoreboard extends uvm_scoreboard;
  
  `uvm_component_utils(ram_scoreboard)
  
  uvm_analysis_imp_drv #(ram_sequence_item, ram_scoreboard) aport_drv;
  uvm_analysis_imp_mon #(ram_sequence_item, ram_scoreboard) aport_mon;
  
  uvm_tlm_fifo #(ram_sequence_item) expfifo;
  uvm_tlm_fifo #(ram_sequence_item) outfifo;
  
  int VECT_CNT, PASS_CNT, ERROR_CNT;
  parameter ADDR_WIDTH=16;
  parameter DATA_WIDTH=8;
  
  function new(string name="ram_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

  reg [DATA_WIDTH-1:0] mem_test[(2**ADDR_WIDTH-1):0];
  
  reg [ADDR_WIDTH-1:0] t_data_out;
  
  function void write_drv(ram_sequence_item tr);
    `uvm_info("write_drv STIM"tr.convert2string(), UVM_MEDIUM)
    if(tr.rst_p==1) 
      begin
        $display("------------------------------ RESET ------------------");
         `uvm_info("RESET in scoreboard""----- RESET ---------"UVM_MEDIUM)
        for(int unsigned i=0;i<2**ADDR_WIDTH;i++)
          begin
            mem_test[i]=0;
            tr.addr=0;
            tr.data_in=0;
            t_data_out=0;
            tr.rdn_wr=0;
          end
      end
   if(tr.rdn_wr==1)
      begin
        mem_test[tr.addr]=tr.data_in;
      end
   if(tr.rdn_wr==0)
      begin
        t_data_out=mem_test[tr.addr];
      end
    else 
      begin
        t_data_out=t_data_out;
      end
    tr.data_out=t_data_out;
    void'(expfifo.try_put(tr));
  endfunction

  function void write_mon(ram_sequence_item tr);
    `uvm_info("write_mon OUT "tr.convert2string(), UVM_MEDIUM)
  void'(outfifo.try_put(tr));
  endfunction
  
  task run_phase(uvm_phase phase);
  ram_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);
      
     // `uvm_info("[exp]", exp_tr.convert2string(), UVM_MEDIUM)
      
     // `uvm_info("[out]", out_tr.convert2string(), UVM_MEDIUM)
        
      
        if(out_tr.rst_p==1) begin
          $display("RESET Do not compare");
        end
        /*
        else if (out_tr.compare(exp_tr)) begin
      PASS();
         `uvm_info ("PASS ",out_tr.convert2string() , UVM_LOW)
    end
        */
      
        else if(out_tr.data_out==exp_tr.data_out)
          begin
              PASS();
            `uvm_info ("PASS ",out_tr.convert2string() , UVM_LOW)
          end
      
        else begin
          ERROR();
          `uvm_info ("ERROR [ACTUAL_OP]",out_tr.convert2string() , UVM_LOW)
             `uvm_info ("ERROR [EXPECTED_OP]",exp_tr.convert2string() , UVM_LOW)
             `uvm_warning("ERROR",out_tr.convert2string())
    end
      
    end
  endtask

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

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

endclass
 

 

ram_env


class ram_env extends uvm_env;

   //---------------------------------------------------------------------------
   `uvm_component_utils(ram_env)
   //---------------------------------------------------------------------------

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

  //-------------------- class handles -----------------------------------------
  ram_agent      agent_h;
  ram_coverage   coverage_h;
  ram_scoreboard scoreboard_h;
  //----------------------------------------------------------------------------

  //---------------------- build phase -----------------------------------------
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    agent_h      = ram_agent::type_id::create("agent_h",this);
    coverage_h   = ram_coverage::type_id::create("coverage_h",this);
    scoreboard_h = ram_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:ram_env

 

ram_test

NOTE : Only one test is shown here other you will find in link provided.


class ram_test extends uvm_test;

    //--------------------------------------------------------------------------
    `uvm_component_utils(ram_test)
    //--------------------------------------------------------------------------

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

    ram_env env_h;
    int file_h;

    reset_sequence rst_seq;
    write_only write_seq;
    read_only read_seq;
    read_only read_seq1;
    //--------------------------------------------------------------------------
    function void build_phase(uvm_phase phase);
      super.build_phase(phase);
      env_h     = ram_env::type_id::create("env_h",this);
    endfunction
    //--------------------------------------------------------------------------

    //--------------------------------------------------------------------------
    function void end_of_elobartion_phase(uvm_phase phase);
      $display("End of eleboration phase in agent");
      // print topology
      // print();
    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);
      env_h.set_report_verbosity_level_hier(UVM_LOW);  
      print();  //prints topologi
    endfunction
    //--------------------------------------------------------------------------

    //--------------------------------------------------------------------------
    task run_phase(uvm_phase phase);
        phase.raise_objection(this);
            
            rst_seq   = reset_sequence::type_id::create("rst_seq");
           write_seq = write_only::type_id::create("write_seq");
            read_seq  = read_only::type_id::create("resd_seq");
            read_seq1  = read_only::type_id::create("resd_seq1");
       
            rst_seq.start(env_h.agent_h.sequencer_h); 
            read_seq.start(env_h.agent_h.sequencer_h);
            write_seq.start(env_h.agent_h.sequencer_h);
            read_seq.start(env_h.agent_h.sequencer_h);
            #10;
        
          phase.drop_objection(this);
    endtask
    //--------------------------------------------------------------------------

endclass:ram_test


 

 tb_pkg


`ifndef TB_PKG
`define TB_PKG
`include "uvm_macros.svh"
package tb_pkg;
 import uvm_pkg::*;
 `include "ram_sequence_item.sv"        // transaction class
 `include "ram_sequence.sv"             // sequence class
 `include "ram_sequencer.sv"            // sequencer class
 `include "ram_driver.sv"               // driver class
 `include "ram_monitor.sv"
 `include "ram_agent.sv"                // agent class  
 `include "ram_coverage.sv"             // coverage class
 `include "ram_scoreboard.sv" // scoreboard class
 `include "ram_env.sv"                  // environment class

 `include "ram_test.sv"                 // test

endpackage
`endif 

 

 testbench_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);
  //----------------------------------------------------------------------------

  //----------------------------------------------------------------------------
  RAM  DUT (.clk(i_intf.clk),
                    .data_in(i_intf.data_in),
                    .data_out(i_intf.data_out),
                    .rst_p(i_intf.rst_p),
                    .addr(i_intf.addr),
                    .rdn_wr(i_intf.rdn_wr)
                     );
  //----------------------------------------------------------------------------               
  
  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("test_write_read_all0");
// OR use +UVM_TESTNAME="test_name" 
  end
  //----------------------------------------------------------------------------
endmodule
     

 

 Link For Code : https://www.edaplayground

 Thank You for Reading , have a nice day 😊😊.

KeyBoard Shortcut : Windows+v for clipboard history.

Share:
Copyright © VLSI Verification Concepts . Designed by OddThemes