|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 uvm_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 uvm_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 uvm_driver;

`ifndef GUARD_DRIVER
`define GUARD_DRIVER

class Driver extends uvm_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 uvm_analysis_port which is used to send packets to scoreboard.

     uvm_analysis_port #(Packet) Drvr2Sb_port;

5) Declare component utilities macro.

    `uvm_component_utils(Driver)  

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

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

7) In the build method and construct Drvr2Sb_port object.

   virtual 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.

  virtual function void end_of_elaboration();
      uvm_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();
      uvm_report_info(get_full_name(),"Start of reset_dut() method ",UVM_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;

      uvm_report_info(get_full_name(),"End of reset_dut() method ",UVM_LOW);
 endtask : reset_dut


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

 virtual task cfg_dut();
        uvm_report_info(get_full_name(),"Start of cfg_dut() method ",UVM_LOW);
        mem_intf.cb.mem_en <= 1;
        @(mem_intf.cb);
        mem_intf.cb.mem_rd_wr <= 1;

        foreach (cfg.device_add[i])  begin

            @(mem_intf.cb);
            mem_intf.cb.mem_add  <= i;
            mem_intf.cb.mem_data <= cfg.device_add[i];
            uvm_report_info(get_full_name(),$psprintf(" Port %0d Address %h ",i,cfg.device_add[i]),UVM_LOW);
        
        end
        
        @(mem_intf.cb);
        mem_intf.cb.mem_en    <=0;
        mem_intf.cb.mem_rd_wr <= 0;
        mem_intf.cb.mem_add   <= 0;
        mem_intf.cb.mem_data  <= 0;
  
        uvm_report_info(get_full_name(),"End of cfg_dut() method ",UVM_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.  

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

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

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

12) Now we will use the above 3 defined methods and update the run() method of uvm_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 .

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


Driver class source code

`ifndef GUARD_DRIVER
`define GUARD_DRIVER

class Driver extends uvm_driver #(Packet);

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

    `uvm_component_utils(Driver) 
  
    function new( string name = "" , uvm_component parent = null) ;
        super.new( name , parent );
    endfunction : new
  
    virtual function void build();
        super.build();
        Drvr2Sb_port = new("Drvr2Sb", this);
    endfunction :  build
  
    virtual function void end_of_elaboration();
        uvm_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

    virtual task run();
        Packet pkt;
        @(input_intf.cb);
        reset_dut();
        cfg_dut();
        forever begin
            seq_item_port.get_next_item(pkt);
            Drvr2Sb_port.write(pkt);
            @(input_intf.cb);
            drive(pkt);
            @(input_intf.cb);
            seq_item_port.item_done();
        end
    endtask : run
  
    virtual task reset_dut();
        uvm_report_info(get_full_name(),"Start of reset_dut() method ",UVM_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;
  
        uvm_report_info(get_full_name(),"End of reset_dut() method ",UVM_LOW);
    endtask : reset_dut
  
    virtual task cfg_dut();
        uvm_report_info(get_full_name(),"Start of cfg_dut() method ",UVM_LOW);
        mem_intf.cb.mem_en <= 1;
        @(mem_intf.cb);
        mem_intf.cb.mem_rd_wr <= 1;

        foreach (cfg.device_add[i])  begin

            @(mem_intf.cb);
            mem_intf.cb.mem_add  <= i;
            mem_intf.cb.mem_data <= cfg.device_add[i];
            uvm_report_info(get_full_name(),$psprintf(" Port %0d Address %h ",i,cfg.device_add[i]),UVM_LOW);
        
        end
        
        @(mem_intf.cb);
        mem_intf.cb.mem_en    <=0;
        mem_intf.cb.mem_rd_wr <= 0;
        mem_intf.cb.mem_add   <= 0;
        mem_intf.cb.mem_data  <= 0;
  
        uvm_report_info(get_full_name(),"End of cfg_dut() method ",UVM_LOW);
   endtask : cfg_dut
  
   virtual task drive(Packet pkt);
        byte unsigned  bytes[];
        int pkt_len;
        pkt_len = pkt.pack_bytes(bytes);
        uvm_report_info(get_full_name(),"Driving packet ...",UVM_LOW);

        foreach(bytes[i])
        begin
            @(input_intf.cb);
            input_intf.data_status <= 1 ;
            input_intf.data_in <= bytes[i];
        end
  
        @(input_intf.cb);
        input_intf.data_status <= 0 ;
        input_intf.data_in <= 0;
        repeat(2) @(input_intf.cb);
   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 uvm_env;

    `uvm_component_utils(Environment)

     Sequencer Seqncr;
     Driver Drvr;

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

    virtual function void build();
        super.build();
        uvm_report_info(get_full_name(),"START of build ",UVM_LOW);

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

        uvm_report_info(get_full_name(),"END of build ",UVM_LOW);
    endfunction
    
    virtual function void connect();
        super.connect();
        uvm_report_info(get_full_name(),"START of connect ",UVM_LOW);

        Drvr.seq_item_port.connect(Seqncr.seq_item_export);

        uvm_report_info(get_full_name(),"END of connect ",UVM_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.

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

        cfg.device_add[0] = 0;
        cfg.device_add[1] = 1;
        cfg.device_add[2] = 2;
        cfg.device_add[3] = 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 uvm_test;

    `uvm_component_utils(test1)

     Environment t_env ;

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

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

        cfg.device_add[0] = 0;
        cfg.device_add[1] = 1;
        cfg.device_add[2] = 2;
        cfg.device_add[3] = 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

    virtual task run ();

       t_env.Seqncr.print();

        #3000ns;
        global_stop_request();
    endtask : run

endclass : test1


Download the source code

uvm_switch_6.tar
Browse the code in uvm_switch_6.tar

Command to run the simulation

VCS Users : make vcs
Questa Users: make questa


Log report after simulation

UVM_INFO @ 0 [RNTST] Running test test1...
UVM_INFO @ 0: uvm_test_top.t_env [uvm_test_top.t_env] START of build
UVM_INFO @ 0: uvm_test_top.t_env [uvm_test_top.t_env] END of build
UVM_INFO @ 0: uvm_test_top.t_env [uvm_test_top.t_env] START of connect
UVM_INFO @ 0: uvm_test_top.t_env [uvm_test_top.t_env] END of connect
----------------------------------------------------------------------
Name                     Type                Size                Value
----------------------------------------------------------------------
Seqncr                   Sequencer           -               Seqncr@14
--rsp_export             uvm_analysis_export -           rsp_export@16
--seq_item_export        uvm_seq_item_pull_+ -      seq_item_export@40
--default_sequence       string              19    uvm_random_sequence
--count                  integral            32                     -1
--max_random_count       integral            32                   'd10
--sequences              array               5                       -
----[0]                  string              19    uvm_random_sequence
----[1]                  string              23   uvm_exhaustive_sequ+
----[2]                  string              19    uvm_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
----------------------------------------------------------------------
UVM_INFO @ 30: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]
                Start of reset_dut() method
UVM_INFO @ 70: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]
                End of reset_dut() method
UVM_INFO @ 70: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]
                Start of cfg_dut() method
UVM_INFO @ 110: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]  
                Port 0 Address 00
UVM_INFO @ 130: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]  
                Port 1 Address 01
UVM_INFO @ 150: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]  
                Port 2 Address 02
UVM_INFO @ 170: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]  
                Port 3 Address 03
UVM_INFO @ 190: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]
                End of cfg_dut() method
UVM_INFO @ 210: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]
                Driving packet ...
UVM_INFO @ 590: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]
                Driving packet ...
UVM_INFO @ 970: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]
                Driving packet ...

--- UVM Report Summary ---

** Report counts by severity
UVM_INFO :   16
UVM_WARNING :    0
UVM_ERROR :    0
UVM_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