|HOME |ABOUT |ARTICLES |ACK |FEEDBACK |TOC |LINKS |BLOG |JOBS |


Tutorials



PHASE 6 DRIVER

Driver

In this phase we will develop the driver. Driver is defined by extending ovm_driver. Driver takes the transaction from the sequencer using seq_item_port. This transaction will be driven to DUT as per the interface specification. After driving the transaction to DUT, it sends the transaction to scoreboard using ovm_analysis_port.

In driver class, we will also define task for resetting DUT and configuring the DUT. After completing the driver class implementation, we will instantiate it in environment class and connect the sequencer to it. We will also update the test case and run the simulation to check the implementation which we did till now.




1) Define the driver class by extending ovm_driver;

`ifndef GUARD_DRIVER
`define GUARD_DRIVER

class Driver extends ovm_driver #(Packet);

endclass : Driver

2) Create a handle to configuration object. Using this object we can get DUT interfaces and DUT port addresses.

    Configuration cfg;

3) Declare input and memory interfaces

     virtual input_interface.IP   input_intf;
     virtual mem_interface.MEM  mem_intf;

4) Declare ovm_analysis_port which is used to send packets to scoreboard.

     ovm_analysis_port #(Packet) Drvr2Sb_port;

5) Declare component utilities macro.

    `ovm_component_utils(Driver)  

6) Define the constructor method. Pass the parent object to super class.

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

7) In the build method and construct Drvr2Sb_port object.

   function void build();
       super.build();
       Drvr2Sb_port = new("Drvr2Sb_port", this);
   endfunction :  build

8) In the end_of_elaboration() method, get the configuration object using get_config_object and update the virtual interfaces.

  function void end_of_elaboration();
      ovm_object tmp;
      super.end_of_elaboration();
      assert(get_config_object("Configuration",tmp));
      $cast(cfg,tmp);
      this.input_intf = cfg.input_intf;
      this.mem_intf = cfg.mem_intf;
  endfunction : end_of_elaboration

 
9) Define the reset_dut() method which will be used for resetting the DUT.

 virtual task reset_dut();
      ovm_report_info(get_full_name(),"Start of reset_dut() method ",OVM_LOW);
      mem_intf.mem_data      <= 0;
      mem_intf.mem_add       <= 0;
      mem_intf.mem_en        <= 0;
      mem_intf.mem_rd_wr     <= 0;
      input_intf.data_in     <= 0;
      input_intf.data_status <= 0;
      
      input_intf.reset       <= 1;
      repeat (4) @ input_intf.clock;
      input_intf.reset       <= 0;

      ovm_report_info(get_full_name(),"End of reset_dut() method ",OVM_LOW);
 endtask : reset_dut


10) Define the cfg_dut() method which does the configuration due port address.

 virtual task cfg_dut();
      ovm_report_info(get_full_name(),"Start of cfg_dut() method ",OVM_LOW);
      mem_intf.mem_en <= 1;
      @(posedge mem_intf.clock);
      mem_intf.mem_rd_wr <= 1;
      
      @(posedge mem_intf.clock);
      mem_intf.mem_add  <= 8'h0;
      mem_intf.mem_data <= cfg.device0_add;
      ovm_report_info(get_full_name(),
      $psprintf(" Port 0 Address %h ",cfg.device0_add),OVM_LOW);
      
      @(posedge mem_intf.clock);
      mem_intf.mem_add  <= 8'h1;
      mem_intf.mem_data <= cfg.device1_add;
      ovm_report_info(get_full_name(),
      $psprintf(" Port 1 Address %h ",cfg.device1_add),OVM_LOW);
      
      @(posedge mem_intf.clock);
      mem_intf.mem_add  <= 8'h2;
      mem_intf.mem_data <= cfg.device2_add;
      ovm_report_info(get_full_name(),
      $psprintf(" Port 2 Address %h ",cfg.device2_add),OVM_LOW);
      
      @(posedge mem_intf.clock);
      mem_intf.mem_add  <= 8'h3;
      mem_intf.mem_data <= cfg.device3_add;
      ovm_report_info(get_full_name(),
      $psprintf(" Port 3 Address %h ",cfg.device3_add),OVM_LOW);
      
      @(posedge mem_intf.clock);
      mem_intf.mem_en    <=0;
      mem_intf.mem_rd_wr <= 0;
      mem_intf.mem_add   <= 0;
      mem_intf.mem_data  <= 0;

      ovm_report_info(get_full_name(),"End of cfg_dut() method ",OVM_LOW);
 endtask : cfg_dut

11) Define drive() method which will be used to drive the packet to DUT. In this method pack the packet fields using the pack_bytes() method of the transaction and drive the packed data to DUT interface.  

task drive(Packet pkt);
      byte unsigned  bytes[];
      int pkt_len;
      pkt_len = pkt.pack_bytes(bytes);
      ovm_report_info(get_full_name(),"Driving packet ...",OVM_LOW);

      foreach(bytes[i])
      begin
          @(posedge input_intf.clock);
          input_intf.data_status <= 1 ;
          input_intf.data_in <= bytes[i];
      end

      @(posedge input_intf.clock);
      input_intf.data_status <= 0 ;
      input_intf.data_in <= 0;
      repeat(2) @(posedge input_intf.clock);
endtask : drive

12) Now we will use the above 3 defined methods and update the run() method of ovm_driver.
First call the reset_dut() method and then cfg_dut(). After completing the configuration, in a forever loop get the transaction from seq_item_port and send it DUT using drive() method and also to scoreboard using Drvr2SB_port .

 task run();
     Packet pkt;
     @(posedge input_intf.clock);
     reset_dut();
     cfg_dut();
     forever begin
         seq_item_port.get_next_item(pkt);
         Drvr2Sb_port.write(pkt);
         @(posedge input_intf.clock);
         drive(pkt);
         @(posedge input_intf.clock);
         seq_item_port.item_done();
    end
 endtask : run


Driver class source code

`ifndef GUARD_DRIVER
`define GUARD_DRIVER

class Driver extends ovm_driver #(Packet);

    Configuration cfg;
  
    virtual input_interface.IP   input_intf;
    virtual mem_interface.MEM  mem_intf;
    
    ovm_analysis_port #(Packet) Drvr2Sb_port;

    `ovm_component_utils(Driver) 
  
    function new( string name = "" , ovm_component parent = null) ;
        super.new( name , parent );
    endfunction : new
  
    function void build();
        super.build();
        Drvr2Sb_port = new("Drvr2Sb", this);
    endfunction :  build
  
    function void end_of_elaboration();
        ovm_object tmp;
        super.end_of_elaboration();
        assert(get_config_object("Configuration",tmp));
        $cast(cfg,tmp);
        this.input_intf = cfg.input_intf;
        this.mem_intf = cfg.mem_intf;
    endfunction : end_of_elaboration

    task run();
        Packet pkt;
        @(posedge input_intf.clock);
        reset_dut();
        cfg_dut();
        forever begin
            seq_item_port.get_next_item(pkt);
            Drvr2Sb_port.write(pkt);
            @(posedge input_intf.clock);
            drive(pkt);
            @(posedge input_intf.clock);
            seq_item_port.item_done();
        end
    endtask : run
  
    virtual task reset_dut();
        ovm_report_info(get_full_name(),"Start of reset_dut() method ",OVM_LOW);
        mem_intf.mem_data      <= 0;
        mem_intf.mem_add       <= 0;
        mem_intf.mem_en        <= 0;
        mem_intf.mem_rd_wr     <= 0;
        input_intf.data_in     <= 0;
        input_intf.data_status <= 0;
        
        input_intf.reset       <= 1;
        repeat (4) @ input_intf.clock;
            input_intf.reset       <= 0;
  
        ovm_report_info(get_full_name(),"End of reset_dut() method ",OVM_LOW);
    endtask : reset_dut
  
    virtual task cfg_dut();
        ovm_report_info(get_full_name(),"Start of cfg_dut() method ",OVM_LOW);
        mem_intf.mem_en <= 1;
        @(posedge mem_intf.clock);
        mem_intf.mem_rd_wr <= 1;
        
        @(posedge mem_intf.clock);
        mem_intf.mem_add  <= 8'h0;
        mem_intf.mem_data <= cfg.device0_add;
        ovm_report_info(get_full_name(),
        $psprintf(" Port 0 Address %h ",cfg.device0_add),OVM_LOW);
        
        @(posedge mem_intf.clock);
        mem_intf.mem_add  <= 8'h1;
        mem_intf.mem_data <= cfg.device1_add;
        ovm_report_info(get_full_name(),
        $psprintf(" Port 1 Address %h ",cfg.device1_add),OVM_LOW);
        
        @(posedge mem_intf.clock);
        mem_intf.mem_add  <= 8'h2;
        mem_intf.mem_data <= cfg.device2_add;
        ovm_report_info(get_full_name(),
        $psprintf(" Port 2 Address %h ",cfg.device2_add),OVM_LOW);
        
        @(posedge mem_intf.clock);
        mem_intf.mem_add  <= 8'h3;
        mem_intf.mem_data <= cfg.device3_add;
        ovm_report_info(get_full_name(),
        $psprintf(" Port 3 Address %h ",cfg.device3_add),OVM_LOW);
        
        @(posedge mem_intf.clock);
        mem_intf.mem_en    <=0;
        mem_intf.mem_rd_wr <= 0;
        mem_intf.mem_add   <= 0;
        mem_intf.mem_data  <= 0;
  
        ovm_report_info(get_full_name(),"End of cfg_dut() method ",OVM_LOW);
    endtask : cfg_dut
  
   task drive(Packet pkt);
        byte unsigned  bytes[];
        int pkt_len;
        pkt_len = pkt.pack_bytes(bytes);
        ovm_report_info(get_full_name(),"Driving packet ...",OVM_LOW);

        foreach(bytes[i])
        begin
            @(posedge input_intf.clock);
            input_intf.data_status <= 1 ;
            input_intf.data_in <= bytes[i];
        end
  
        @(posedge input_intf.clock);
        input_intf.data_status <= 0 ;
        input_intf.data_in <= 0;
        repeat(2) @(posedge input_intf.clock);
   endtask : drive

endclass : Driver

`endif

Environment Updates

We will take the instance of Sequencer and Driver and connect them in Environment class.

 


1) Declare handles to Driver and Sequencer.

     Sequencer Seqncr;
     Driver Drvr;

2) In build method, construct Seqncr and Drvr object using create() method.

        Drvr   = Driver::type_id::create("Drvr",this);
        Seqncr = Sequencer::type_id::create("Seqncr",this);

2) In connect() method connect the sequencer seq_item_port to drivers seq_item_export.

     Drvr.seq_item_port.connect(Seqncr.seq_item_export);

Environment class code

`ifndef GUARD_ENV
`define GUARD_ENV

class Environment extends ovm_env;

    `ovm_component_utils(Environment)

     Sequencer Seqncr;
     Driver Drvr;

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

    function void build();
        super.build();
        ovm_report_info(get_full_name(),"START of build ",OVM_LOW);

        Drvr   = Driver::type_id::create("Drvr",this);
        Seqncr = Sequencer::type_id::create("Seqncr",this);

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

        Drvr.seq_item_port.connect(Seqncr.seq_item_export);

        ovm_report_info(get_full_name(),"END of connect ",OVM_LOW);
    endfunction


endclass : Environment

`endif

Testcase Updates

We will update the testcase and run the simulation.

1)In the build() method, update the configuration address in the configuration object which in top module.

    function void build();
        super.build();

        cfg.device0_add = 0;
        cfg.device1_add = 1;
        cfg.device2_add = 2;
        cfg.device3_add = 3;

2) In the build() method itself, using set_config_object , configure the configuration object with the one which is in top module.
   with this, the configuration object in Sequencer and Driver will be pointing to the one which in top module.

        set_config_object("t_env.*","Configuration",cfg);

3) In the build method, using set_config_string, configure the default_sequence of the sequencer to use the sequence which we defined.

        set_config_string("*.Seqncr", "default_sequence", "Seq_device0_and_device1");

4) Set the sequencer count value to 2 .

        set_config_int("*.Seqncr", "count",2);

5) Update the run() method to print the Sequencer details.    

     t_env.Seqncr.print();

Testcase code

class test1 extends ovm_test;

    `ovm_component_utils(test1)

     Environment t_env ;

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

    function void build();
        super.build();

        cfg.device0_add = 0;
        cfg.device1_add = 1;
        cfg.device2_add = 2;
        cfg.device3_add = 3;
 
        set_config_object("t_env.*","Configuration",cfg);
        set_config_string("*.Seqncr", "default_sequence", "Seq_device0_and_device1");
        set_config_int("*.Seqncr", "count",2);

    endfunction

    task run ();

       t_env.Seqncr.print();

        #1000;
        global_stop_request();
    endtask : run

endclass : test1


Download the source code

ovm_switch_6.tar
Browse the code in ovm_switch_6.tar

Command to run the simulation

 vcs -sverilog +incdir+$OVM_HOME/src $OVM_HOME/src/ovm_pkg.sv +incdir+. rtl.sv interface.sv top.sv -R +OVM_TESTNAME=test1
 qverilog +incdir+$OVM_HOME/src $OVM_HOME/src/ovm_pkg.sv +incdir+. rtl.sv interface.sv top.sv -R +OVM_TESTNAME=test1


Log report after simulation

OVM_INFO @ 0 [RNTST] Running test test1...
OVM_INFO @ 0: ovm_test_top.t_env [ovm_test_top.t_env] START of build
OVM_INFO @ 0: ovm_test_top.t_env [ovm_test_top.t_env] END of build
OVM_INFO @ 0: ovm_test_top.t_env [ovm_test_top.t_env] START of connect
OVM_INFO @ 0: ovm_test_top.t_env [ovm_test_top.t_env] END of connect
----------------------------------------------------------------------
Name                     Type                Size                Value
----------------------------------------------------------------------
Seqncr                   Sequencer           -               Seqncr@14
--rsp_export             ovm_analysis_export -           rsp_export@16
--seq_item_export        ovm_seq_item_pull_+ -      seq_item_export@40
--default_sequence       string              19    ovm_random_sequence
--count                  integral            32                     -1
--max_random_count       integral            32                   'd10
--sequences              array               5                       -
----[0]                  string              19    ovm_random_sequence
----[1]                  string              23   ovm_exhaustive_sequ+
----[2]                  string              19    ovm_simple_sequence
----[3]                  string              23   Seq_device0_and_dev+
----[4]                  string              19    Seq_constant_length
--max_random_depth       integral            32                    'd4
--num_last_reqs          integral            32                    'd1
--num_last_rsps          integral            32                    'd1
----------------------------------------------------------------------
OVM_INFO @ 30: ovm_test_top.t_env.Drvr [ovm_test_top.t_env.Drvr]
                Start of reset_dut() method
OVM_INFO @ 70: ovm_test_top.t_env.Drvr [ovm_test_top.t_env.Drvr]
                End of reset_dut() method
OVM_INFO @ 70: ovm_test_top.t_env.Drvr [ovm_test_top.t_env.Drvr]
                Start of cfg_dut() method
OVM_INFO @ 110: ovm_test_top.t_env.Drvr [ovm_test_top.t_env.Drvr]  
                Port 0 Address 00
OVM_INFO @ 130: ovm_test_top.t_env.Drvr [ovm_test_top.t_env.Drvr]  
                Port 1 Address 01
OVM_INFO @ 150: ovm_test_top.t_env.Drvr [ovm_test_top.t_env.Drvr]  
                Port 2 Address 02
OVM_INFO @ 170: ovm_test_top.t_env.Drvr [ovm_test_top.t_env.Drvr]  
                Port 3 Address 03
OVM_INFO @ 190: ovm_test_top.t_env.Drvr [ovm_test_top.t_env.Drvr]
                End of cfg_dut() method
OVM_INFO @ 210: ovm_test_top.t_env.Drvr [ovm_test_top.t_env.Drvr]
                Driving packet ...
OVM_INFO @ 590: ovm_test_top.t_env.Drvr [ovm_test_top.t_env.Drvr]
                Driving packet ...
OVM_INFO @ 970: ovm_test_top.t_env.Drvr [ovm_test_top.t_env.Drvr]
                Driving packet ...

--- OVM Report Summary ---

** Report counts by severity
OVM_INFO :   16
OVM_WARNING :    0
OVM_ERROR :    0
OVM_FATAL :    0


Index
Introduction
Specification
Verification Plan
Phase 1 Top
Phase 2 Configuration
Phase 3 Environment N Testcase
Phase 4 Packet
Phase 5 Sequencer N Sequence
Phase 6 Driver
Phase 7 Receiver
Phase 8 Scoreboard

Report a Bug or Comment on This section - Your input is what keeps Testbench.in improving with time!





<< PREVIOUS PAGE

TOP

NEXT PAGE >>

copyright © 2007-2017 :: all rights reserved www.testbench.in::Disclaimer