Tutorials

Learn More

UVM Sequence, Sequencer and driver interface

We discussed sequece_item, sequence, sequencer, and driver independently. In this section, we will discuss how they talk with each other and provide sequence items from sequence to driver via the sequencer. Before you start reading this section, make sure you are aware of all methods used in sequencer and driver. (Refer: UVM Sequencer and UVM Driver).

Sequencer-Driver Connections

UVM sequencer and driver connections

The sequencer and driver communicate with each other using a bidirectional TLM interface to transfer REQ and RSP sequence items.

The driver has uvm_seq_item_pull_port which is connected with uvm_seq_item_pull_export of the associated sequencer. This TLM interface provides a facility to use implemented API to retrieve REQ items and turn RSP items.

Note: 

  1. Both uvm_seq_item_pull_port and uvm_seq_item_pull_export are parameterized classes with REQ and RSP sequence items.
  2. The TLM connection between driver and sequencer is one-to-one. It means neither multiple sequencers are connected to a single driver nor multiple drivers connected to a single sequencer.

Connections: The driver and sequencers are connected in the connect_phase of the UVM agent.

<driver_inst>.seq_item_port.connect(<sequencer_inst>.seq_item_export);

Where,

The seq_item_port and seq_item_export are an instance handle for uvm_seq_item_pull_port and uvm_seq_item_pull_export respectively.

Sequence-Driver-Sequencer communication Approaches

Based on the varieties of methods available with sequence and driver, all combinations are explained further.

Approach A: Using get_next_item and item_done methods in the driver

Approach B: Using get and put methods in driver

A. Using get_next_item and item_done methods in the driver

Without RSP packet

get_next_item and item_done methods driver without RSP block diagram
  1. Create a sequence item and register in the factory using the create_item function call. 
  2. The wait_for_grant issues request to the sequencer and wait for the grant from the sequencer. It returns when the sequencer has granted the sequence. 
  3. Randomize the sequence item and send it to the sequencer using send_request call. There should not be any simulation time delay between wait_for_grant and send_request method call. The sequencer forwards the sequence item to the driver with the help of REQ FIFO. This unblocks the get_next_item() call and the driver receives the sequence item.
  4. The wait_for_item_done() call from sequence gets blocked until the driver responds back.
  5. In the meantime, the driver drives the sequence item to the DUT using a virtual interface handle. Once it is completed, the item_done method is called. This unblocks the wait_for_item_done method from the sequence.
  6. If a response has to be sent from the driver to the sequence, item_done(RSP) is called with the RSP item as an argument. The RSP item is communicated to the sequence by a sequencer with help of RSP FIFO. It is important to call the get_response method to get the response. This step is optional and not required if the RSP item is not sent by the DUT.
// Driver Code
class driver extends uvm_driver#(seq_item);
  `uvm_component_utils(driver)
  
  function new(string name = "driver", uvm_component parent = null);
    super.new(name, parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
  endfunction
  
  task run_phase (uvm_phase phase);
    forever begin
      seq_item_port.get_next_item(req);
      `uvm_info(get_type_name(), "After get_next_item call", UVM_LOW);
      #50; // Driving delay. Assuming time taken to drive RTL signals
      seq_item_port.item_done();
      `uvm_info(get_type_name(), "After item_done call", UVM_LOW);
    end
  endtask
endclass

// Sequence Code
class base_seq extends uvm_sequence #(seq_item);
  seq_item req;
  `uvm_object_utils(base_seq)
  
  function new (string name = "base_seq");
    super.new(name);
  endfunction

  task body();
    `uvm_info(get_type_name(), "Base seq: Inside Body", UVM_LOW);
    //req = seq_item::type_id::create("req");
    // or
    $cast(req, create_item(seq_item::get_type(), m_sequencer, "req"));
    wait_for_grant();
    assert(req.randomize());
    send_request(req);
    `uvm_info(get_type_name(), "Before wait_for_item_done", UVM_LOW);
    wait_for_item_done();
    `uvm_info(get_type_name(), "After wait_for_item_done", UVM_LOW);
  endtask
endclass

Output:

UVM_INFO testbench.sv(21) @ 0: uvm_test_top.env_o.agt.seqr@@bseq [base_seq] Base seq: Inside Body
UVM_INFO testbench.sv(28) @ 0: uvm_test_top.env_o.agt.seqr@@bseq [base_seq] Before wait_for_item_done
UVM_INFO driver.sv(15) @ 0: uvm_test_top.env_o.agt.drv [driver] After get_next_item call
UVM_INFO driver.sv(19) @ 50: uvm_test_top.env_o.agt.drv [driver] After item_done call
UVM_INFO testbench.sv(30) @ 50: uvm_test_top.env_o.agt.seqr@@bseq [base_seq] After wait_for_item_done

With RSP packet

When the driver sends the RSP item to the sequence.

get_next_item and item_done methods driver with RSP block diagram
// Driver Code
class driver extends uvm_driver#(seq_item);
  `uvm_component_utils(driver)
  
  function new(string name = "driver", uvm_component parent = null);
    super.new(name, parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
  endfunction
  
  task run_phase (uvm_phase phase);
    forever begin
      seq_item_port.get_next_item(req);
      `uvm_info(get_type_name(), "After get_next_item call", UVM_LOW);
      #50; // Driving delay. Assuming time taken to drive RTL signals
      req.rsp_b = 1;
      seq_item_port.item_done(req);
      `uvm_info(get_type_name(), "After item_done call", UVM_LOW);
    end
  endtask
endclass

// Sequence Code
class base_seq extends uvm_sequence #(seq_item);
  seq_item req;
  `uvm_object_utils(base_seq)
  
  function new (string name = "base_seq");
    super.new(name);
  endfunction

  task body();
    `uvm_info(get_type_name(), "Base seq: Inside Body", UVM_LOW);
    //req = seq_item::type_id::create("req");
    // or
    $cast(req, create_item(seq_item::get_type(), m_sequencer, "req"));
    wait_for_grant();
    assert(req.randomize());
    send_request(req);
    `uvm_info(get_type_name(), "Before wait_for_item_done", UVM_LOW);
    wait_for_item_done();
    `uvm_info(get_type_name(), "After wait_for_item_done", UVM_LOW);
    get_response(req);
    `uvm_info(get_type_name(), $sformatf("After get_response: rsp_b = %0d", req.rsp_b), UVM_LOW);
  endtask
endclass

Output:

UVM_INFO testbench.sv(21) @ 0: uvm_test_top.env_o.agt.seqr@@bseq [base_seq] Base seq: Inside Body
UVM_INFO testbench.sv(28) @ 0: uvm_test_top.env_o.agt.seqr@@bseq [base_seq] Before wait_for_item_done
UVM_INFO driver.sv(15) @ 0: uvm_test_top.env_o.agt.drv [driver] After get_next_item call
UVM_INFO driver.sv(20) @ 50: uvm_test_top.env_o.agt.drv [driver] After item_done call
UVM_INFO testbench.sv(30) @ 50: uvm_test_top.env_o.agt.seqr@@bseq [base_seq] After wait_for_item_done
UVM_INFO testbench.sv(32) @ 50: uvm_test_top.env_o.agt.seqr@@bseq [base_seq] After get_response: rsp_b = 1

B. Using get and put methods in driver

get and put methods in driver block diagram
  1. Create a sequence item and register in the factory using the create_item function call.
  2. The wait_for_grant issues the request to the sequencer and wait for the grant from the sequencer. It returns when the sequencer has granted the sequence.
  3. Randomize the sequence item and send it to the sequencer using send_request call. There should not be any simulation time delay between wait_for_grant and send_request method call. The sequencer forwards the sequence item to the driver with the help of REQ FIFO. This unblocks the get() call and the driver receives the sequence item.
  4. The wait_for_item_done() call from the sequence gets blocked until the driver calls the get method.
  5. Once the get method is called, the wait_for_item_done() call from sequence gets unblocked immediately without caring about driving the virtual interface.
  6. The get_response call is necessary to call that completes the communication. The get_response method is blocked until the driver calls put(RSP).
  7. In the meantime, the driver drives the sequence item to the DUT using a virtual interface handle. Once it is completed, the put(RSP) method is called. This unblocks the get_response method from the sequence. The RSP item is communicated to the sequence by a sequencer with help of RSP FIFO.
// Driver Code
class driver extends uvm_driver#(seq_item);
  `uvm_component_utils(driver)
  
  function new(string name = "driver", uvm_component parent = null);
    super.new(name, parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
  endfunction
  
  task run_phase (uvm_phase phase);
    forever begin
      seq_item_port.get(req);
      `uvm_info(get_type_name(), "After get call", UVM_LOW);
      #50; // Driving delay. Assuming time taken to drive RTL signals
      req.rsp_b = 1;
      seq_item_port.put(req);
      `uvm_info(get_type_name(), "After put call", UVM_LOW);
    end
  endtask
endclass

// Sequence Code
class base_seq extends uvm_sequence #(seq_item);
  seq_item req;
  `uvm_object_utils(base_seq)
  
  function new (string name = "base_seq");
    super.new(name);
  endfunction

  task body();
    `uvm_info(get_type_name(), "Base seq: Inside Body", UVM_LOW);
    //req = seq_item::type_id::create("req");
    // or
    $cast(req, create_item(seq_item::get_type(), m_sequencer, "req"));
    wait_for_grant();
    assert(req.randomize());
    send_request(req);
    `uvm_info(get_type_name(), "Before wait_for_item_done call", UVM_LOW);
    wait_for_item_done();
    `uvm_info(get_type_name(), "After wait_for_item_done call", UVM_LOW);
    get_response(req);
    `uvm_info(get_type_name(), $sformatf("After get_response: rsp_b = %0d", req.rsp_b), UVM_LOW);
  endtask
endclass

Output:

UVM_INFO testbench.sv(21) @ 0: uvm_test_top.env_o.agt.seqr@@bseq [base_seq] Base seq: Inside Body
UVM_INFO testbench.sv(28) @ 0: uvm_test_top.env_o.agt.seqr@@bseq [base_seq] Before wait_for_item_done call
UVM_INFO driver.sv(15) @ 0: uvm_test_top.env_o.agt.drv [driver] After get call
UVM_INFO testbench.sv(30) @ 0: uvm_test_top.env_o.agt.seqr@@bseq [base_seq] After wait_for_item_done call
UVM_INFO driver.sv(20) @ 50: uvm_test_top.env_o.agt.drv [driver] After put call
UVM_INFO testbench.sv(32) @ 50: uvm_test_top.env_o.agt.seqr@@bseq [base_seq] After get_response: rsp_b = 1