UVM Driver
Table of Contents
-
- A driver is written by extending the 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 parameterized class and it is parameterized 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 an RSP sequence_item in the sequencer.
Writing Driver :
1. A 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;the interface handle using get config_db,
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
The uvm driver example
below is the complete drive code.
`define DRIV_IF vif.DRIVER.driver_cb
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