Showing posts with label SYSTEM VERILOG v.s. VERILOG HDL: WHAT IS DIFFERENT AND WHAT ARE SYSTEM VERILOG ADVANTAGES (IF ANY)?. Show all posts
Showing posts with label SYSTEM VERILOG v.s. VERILOG HDL: WHAT IS DIFFERENT AND WHAT ARE SYSTEM VERILOG ADVANTAGES (IF ANY)?. Show all posts

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







Simple testbench (done in both System Verilog and Verilog HDL) for a Digital design block (Verilog HDL) verification

Lets assume that we have  to verify a basic memory design block done in behavior Verilog HDL (memory.v ) .

memory.v  is done here in Verilog HDL and NOT in System Verilog for legacy reasons:
  • it is certain that we can synthesise Verilog HDL RTL design and gate level design that is result of synthesis will also be in Verilog HDL.


/////////////////
/// DUT
///////////////
module memory(
address,
data_in,
data_out,
read_write,
chip_en
);

input [7:0] address, data_in;
output[7:0] data_out;
input read_write, chip_en;

reg [7:0] data_out ;
reg [7:0] mem [0:255];

always @ (address or data_in or read_write or chip_en)
if (read_write == 1 && chip_en == 1) begin
 mem[address] = data_in;
end

always @ (read_write or chip_en or address)
if (read_write == 0 && chip_en)
 data_out = mem[address];
else
 data_out = 0;

endmodule
    
Here is a simple testbench enviroment first done in Verilog HDL and in System Verilog.

Testbench enviroment done in Verilog HDL

////////////////////////////
// Testbench
////////////////////////////
module Testbench(
                             address,
            data_in,
            data_out,
            read_write,
            chip_en
           );

output [7:0] address, data_in;
input  [7:0] data_out;
output       read_write, chip_en;

reg [7:0] address, data_in;
reg       read_write, chip_en;

initial
     begin
        address           = 0 ;
        data_in             = 0 ;
        read_write = 0 ;
        chip_en            = 0 ;

        repeat(3)
            begin
              
               #100  
               chip_en            = 1 ;
               address           = $random ;
               data_in             = $random  ;  
               read_write  =  1’b1 ;
              
               #100
                read_write  =  1’b0 ;
             end

#100
chip_en            = 0 ;

#100
        $finish;

     end // initial

  endmodule

        
        
///////////////////////////////////////////////////////////////////////////////
// top module: integrating Dut and it’s Testbench
///////////////////////////////////////////////////////////////////////////////

module top();
       wire [7:0] address, data_in;
  wire [7:0] data_out;
  wire       read_write, chip_en;

       memory D (
                    .address    ( address    ),
        .data_in    ( data_in    ),
         .data_out   ( data_out   ),
         .read_write ( read_write ),
         .chip_en    ( chip_en    )
               );

     Testbench tb (
                         .address    ( address    ),
               .data_in    ( data_in    ),
               .data_out   ( data_out   ),
               .read_write ( read_write ),
               .chip_en    ( chip_en     )
           );
           
endmodule


Testbench enviroment done in System Verilog

Simulate with Cadence tools  with the command:

irun -access +r -gui  top.sv




////////////////////////////////////////////////////////////////////////////////////////////////
// Interface: for communication between Dut and it’s Testbench
////////////////////////////////////////////////////////////////////////////////////////////////

`ifndef GUARD_INTERFACE
`define GUARD_INTERFACE
interface intf ();
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

///////////////////////////
// Testbench
////////////////////////////
module Testbench(intf tb_if);
initial
begin
tb_if.address = 0 ;
tb_if.data_in = 0 ;
tb_if.read_write = 0 ;
tb_if.chip_en = 0 ;


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


#100
tb_if.read_write = 0 ;
end


#100
tb_if.chip_en = 0 ;


#1000
$finish;
end
endmodule


///////////////////////////////////////////////////////////////////////////////
// top module ( top.sv ): integrating Dut and it’s Testbench
////////////////////////////////////////////////////////////////////////////
        
        
`ifndef GUARD_TOP
`define GUARD_TOP
 
module top();
 
intf bus_if(); //interface instantiation
Testbench tb (
.tb_if( bus_if )
        ) ; // Pass the modport into the module
memory d (
.address ( bus_if.address ), // connect the verilog
.data_in ( bus_if.data_in ), // RTL port 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