Friday, October 14, 2011

Simple testbench done in System Verilog with OVM

The testbench described here (done in OVM)  has the same functionality or behavior  as a testbenches done without OVM, described in the blog post :  Simple testbench (done in both System Verilog and Verilog HDL) for a Digital design block (Verilog HDL) verification  

Simulate the source code bellow with Cadence tools (using OVM ) with the command:

irun +incdir+<a path to OVM directories>/ovm-2.1.2/src -access +r -gui -ovm +OVM_TESTNAME=test1 top.sv

        

Source code        

Testcase Source code

// the name of the test is test1
        
        
// Define a testcase test1 by extending ovm_test class.

class test1 extends ovm_test;

    `ovm_component_utils(test1)
        
        
////////////////////////////////////////////////////////////////////
// Take the instance of Environment: HINT: it has to be class "Environment"  // defined same where in the code
////////////////////////////////////////////////////////////////////////////

    Environment t_env ;

        
        
//////////////////////////////////////////////////////////////////////////////
// Define the constructor method:
// In this method, construct the environment class object and don't forget to // pass the parent argument(t_env)
//////////////////////////////////////////////////////////////////////////////

    function new (string name="test1", ovm_component parent=null);
       super.new (name, parent);
       t_env = new("t_env",this);
    endfunction : new
        
        
/////////////////////////////////////////////////////////////////////////////
// run() method is the only task which is time consuming.
// After completing the start_of_simulation() phase , this method is called.
/////////////////////////////////////////////////////////////////////////////
    task run ();
     
// the same simple stimulus from testbench of SV without OVM
// except this time we are directly driving interface: intf_tb signal: read
// interface intf_tb is defined in configuration: cfg.
// HINT: it has to be an defined somewhere else  interface: intf_tb and
// configuration: cfg

    cfg.intf_tb.address = 0 ;
cfg.intf_tb.data_in = 0 ;
cfg.intf_tb.read_write = 0 ;
cfg.intf_tb.chip_en = 0 ;

repeat(3) begin
#100
cfg.intf_tb.chip_en = 1 ;
cfg.intf_tb.address = $random ;
cfg.intf_tb.data_in = $random ;
cfg.intf_tb.read_write = 1 ;

#100
cfg.intf_tb.read_write = 0 ;
end
#100
cfg.intf_tb.chip_en = 0 ;
     
    #1000;
        
        
// To terminate this task, we will use global_stop_request()
    global_stop_request();
    endtask : run



endclass : test1

        
        

Environment.sv


`ifndef GUARD_ENV
`define GUARD_ENV

        
        
// Extend ovm_env class to define Environment class
// We will not implement all the ovm_env virtual methods in this phase but will we print messages from these methods

class Environment extends ovm_env;

    `ovm_component_utils(Environment)
        
        
// Define the constructor

    function new(string name , ovm_component parent = null);
       super.new(name, parent);
    endfunction: new

        
        
/////////////////////////////////////////////
// Define build method: just print messages
// Build is the first phase in simulation
//////////////////////////////////////////////

    function void build();
       super.build();
      
       ovm_report_info(get_full_name(),"START of build ",OVM_LOW);
     
       ovm_report_info(get_full_name(),"END of build ",OVM_LOW);
     
    endfunction
   
        
        
//////////////////////////////////////////////
// Define connect method: just print messages
// This method is called automatically after the build() method is called
//////////////////////////////////////////////

    function void connect();
       super.connect();
       ovm_report_info(get_full_name(),"START of connect ",OVM_LOW);
   
       ovm_report_info(get_full_name(),"END of connect ",OVM_LOW);
    endfunction


endclass : Environment

`endif

        
        
Configuration.sv


`ifndef GUARD_CONFIGURATION
`define GUARD_CONFIGURATION


class Configuration extends ovm_object;
        
        
// Declare All the interfaces which are required in this verification
// environment        
// HINT: It has to be defined before interface intf with modport tb

     virtual intf.tb              intf_tb ;


                 
// construct a new object of configuration class and update all the important // fields and return it.

    virtual function ovm_object create(string name="");
       Configuration t = new();


         t.intf_tb     =   this.intf_tb ;

       return t;
    endfunction : create

endclass : Configuration

`endif

Interface ( intf.sv )
`ifndef GUARD_INTERFACE
`define GUARD_INTERFACE
interface intf ( input clk );
logic read_write, chip_en ;
logic[7:0] address, data_in ;
logic[7:0] data_out ;

modport tb (output read_write, chip_en, address, data_in, input data_out);
endinterface :intf
`endif


///////////////////////////////////////////////////////////////////////////////
// top module: integrating Dut and it’s Testbench
// and OVM configuration
///////////////////////////////////////////////////////////////////////////////
`ifndef GUARD_TOP
`define GUARD_TOP
`include "ovm.svh"

module top();
  
  `include "Configuration.sv"
  `include "Environment.sv"
  `include "test.sv"

    bit clk;
   
    initial
       begin
             #20;
             forever #10 clk = ~clk;
     end

    intf      bus_if(clk);  //interface instantiation
   



/////////////////////////////////////////////////////
// Creat Configuration and Strart the run_test//
/////////////////////////////////////////////////////


    Configuration cfg;

initial begin
    cfg = new();

     cfg.intf_tb = bus_if ;
  
    run_test();
end

    memory d (
.address ( bus_if.address ), // connect the verilog
.data_in ( bus_if.data_in ), // using interface hierarchy signal name.
.data_out ( bus_if.data_out ),
.read_write ( bus_if.read_write ),
.chip_en ( bus_if.chip_en )
);

endmodule  : top

`endif







No comments:

Post a Comment