// Driver parameterised with the same sequence_item for request & response
// response defaults to request
class my_driver extends uvm_driver #(my_sequence_item);
  my_interface vif;
  .....
  task run_phase(uvm_phase phase);
    my_sequence_item req_item;
    forever
    begin
      seq_item_port.get_next_item(req_item); // Blocking call returning the next transaction
      @(posedge vif.clk);
      vif.addr = req_item.address; // vif is the drivers Virtual Interface
      //
      // etc
      //
      // End of bus cycle
      if(req_item.read_or_write == READ)
      begin // Assign response data to the req_item fields
        req_item.rdata = vif.rdata;
      end
      req_item.resp = vif.error; // Assign response to the req_item response field
      seq_item_port.item_done(); // Signal to the sequence that the driver has finished with the item
    end
  endtask: run
endclass: my_driver


// Sequencer parameterised with the same sequence item for request & response
class my_sequencer extends uvm_sequencer #(my_sequence_item);
.....
endclass: my_sequencer


// Agent containing a driver and a sequencer
class my_agent extends uvm_agent;
  my_driver    m_driver;
  my_sequencer m_sequencer;
  my_interface vif;
  my_agent_cfg m_cfg;
  .....
  // Sequencer-Driver connection:
  function void connect_phase(uvm_phase phase);
    if(m_cfg.active == UVM_ACTIVE) // The agent is actively driving stimulus
    begin
      m_driver.seq_item_port.connect(m_sequencer.seq_item_export); // TLM connection
      m_driver.vif = vif; // Virtual interface assignment
    end
  endfunction: connect_phase
endclass: my_agent