Data items are obtained from the Sequencer and the driver drives them onto the interface conforming to a bus protocol. All driver classes should be extended from uvm_driver, either directly or indirectly. In order to create a driver, follow the steps outlined below :

  • Derive a driver from uvm_driver base class
  • Declare a virtual interface handle (to connect with DUT) and retrieve the interface object from database
  • Obtain the next data item from sequencer
  • Execute the item during run_phase() or other parallel run-time phases detailed in Phases.


Now lets look at an example of a driver.

class my_driver extends uvm_driver #(my_data);
  `uvm_component_utils (my_driver)
   virtual  dut_if   vif;
   function new (string name, uvm_component parent); (name, parent);
   virtual function void build_phase (uvm_phase phase);
      super.build_phase (phase);
      if (! uvm_config_db #(virtual dut_if) :: get (this, "", "vif", vif)) begin
         `uvm_fatal (get_type_name (), "Didn't get handle to virtual interface dut_if")
   task run_phase (uvm_phase phase);
      super.run_phase (phase);
      forever begin
         `uvm_info (get_type_name (), $sformatf ("Waiting for data from sequencer"), UVM_MEDIUM)
         seq_item_port.get_next_item (data_obj);
         drive_item (data_obj);
         seq_item_port.item_done ();
   virtual task drive_item (my_data data_obj);
      // Drive based on bus protocol

Note the following from example shown above :

  • Driver is extended from uvm_driver
  • A virtual interface handle vif is declared and assigned later in the build_phase().
  • Real interface object is retrieved from the database directly into a local variable using uvm_config_db::get() method
  • Get the next data item from sequencer using seq_item_port.get_next_item() in run_phase
  • Call drive task to send data in accordance with a bus protocol
  • Indicate to the sequencer that the data item has been driven using seq_item_port.item_done()

Other Details

The base driver class contains a uvm_seq_item_pull_port through which it can request for new transactions from the export connected to it. The ports are typically connected to the exports of a sequencer component in the parent class where the two are instantiated.The RSP port needs connecting only if the driver will use it to write responses to the analysis export in the sequencer.

class uvm_driver #(type REQ = uvm_sequence_item, type RSP = REQ) extends uvm_component;

The driver's port and the sequencer's export are connected during the connect_phase() of an environment/agent class.

virtual function void connect_phase ();
   m_drv0.seq_item_port.connect (m_seqr0.seq_item_export);

Refer to Class Definitions to know about method declarations.

Was this article helpful ?