UVM Driver

 UVM Driver 


Driver is written by extending uvm_driver.

uvm_driver is inherited from uvm_component, Methods and TLM port (seq_item_port) are defined for communication between sequencer and driver.

The uvm_driver is a parameterised class and it is parameterised with the type of the request sequence_item and the type of the response sequence_item. 

UVM_Driver Methods,

 get_next_item 
This method blocks until a REQ sequence_item is available in the sequencer.

 try_next_item 
This is a non-blocking variant of the get_next_item() method. It will return a null pointer if there is no REQ sequence_item available in the sequencer.

 item_done 
The non-blocking item_done() method completes the driver-sequencer handshake and it should be called after a get_next_item() or a successful try_next_item() call.

 put 
The put() method is non-blocking and is used to place a RSP sequence_item in the sequencer.


 Writing Driver : 

1. Driver is written by extending the UVM_DRIVER

class mem_driver extends uvm_driver #(mem_seq_item);

  `uvm_component_utils(mem_driver)

  // Constructor
  function new (string name, uvm_component parent);
    super.new(name, parent);
  endfunction : new

endclass : mem_driver

2. Declare the virtual interface, 

  // Virtual Interface
  virtual mem_if vif;

3. Get the interface handle using get config_db, 

if(!uvm_config_db#(virtual mem_if)::get(this, "", "vif", vif))
       `uvm_fatal("NO_VIF",{"virtual interface must be set for: ",get_full_name(),".vif"});

4. Will place the get config_db in the build_phase, 

  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
     if(!uvm_config_db#(virtual mem_if)::get(this, "", "vif", vif))
       `uvm_fatal("NO_VIF",{"virtual interface must be set for: ",get_full_name(),".vif"});
  endfunction: build_phase

5. Add driving logic. get the seq_item and drive to DUT signals, 

  // run phase
  virtual task run_phase(uvm_phase phase);
    forever begin
    seq_item_port.get_next_item(req);
     ......
     .. driving logic ..
     ......
    seq_item_port.item_done();
    end
  endtask : run_phase

 Complete driver code, 

class mem_driver extends uvm_driver #(mem_seq_item);

  // Virtual Interface
  virtual mem_if vif;

  `uvm_component_utils(mem_driver)
    
  //uvm_analysis_port #(mem_seq_item) Drvr2Sb_port;

  // Constructor
  function new (string name, uvm_component parent);
    super.new(name, parent);
  endfunction : new

  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
     if(!uvm_config_db#(virtual mem_if)::get(this, "", "vif", vif))
       `uvm_fatal("NO_VIF",{"virtual interface must be set for: ",get_full_name(),".vif"});
  endfunction: build_phase

  // run phase
  virtual task run_phase(uvm_phase phase);
    forever begin
    seq_item_port.get_next_item(req);
    //respond_to_transfer(req);
    drive();
    seq_item_port.item_done();
    end
  endtask : run_phase

  // drive 
  virtual task drive();
    req.print();
      `DRIV_IF.wr_en <= 0;
      `DRIV_IF.rd_en <= 0;
      @(posedge vif.DRIVER.clk);
      `DRIV_IF.addr <= req.addr;
    if(req.wr_en) begin
        `DRIV_IF.wr_en <= req.wr_en;
        `DRIV_IF.wdata <= req.wdata;
      //$display("\tADDR = %0h \tWDATA = %0h",req.addr,trans.wdata);
        @(posedge vif.DRIVER.clk);
      end
    if(req.rd_en) begin
        `DRIV_IF.rd_en <= req.rd_en;
        @(posedge vif.DRIVER.clk);
        `DRIV_IF.rd_en <= 0;
        @(posedge vif.DRIVER.clk);
        req.rdata = `DRIV_IF.rdata;
       // $display("\tADDR = %0h \tRDATA = %0h",trans.addr,`DRIV_IF.rdata);
      end
      $display("-----------------------------------------");
  endtask : drive

endclass : mem_driver