handshake - DilipKrishnappa/UVM GitHub Wiki

Driver Sequence Handshake

Introduction

In Universal Verification Methodology (UVM), The method called Driver Sequence Handshake is a mechanism, where we send the transactions from the sequence to the Driver in the order to provide stimulus to the DUT.Since we know that the whole understanding of different type of transactions is imbided into the sequences and Sequencers are being used as the physical component to execute those Sequences. A particular Sequence is directed to run on a Sequencer which in turns further breaks down into a series of transaction items and these transaction items are needs to be transferred to the Driver where these transaction items are converted into cycle based signal/pin level transitions.

The Sequencer get the series of the transaction item/sequence_item through the sequence. This transaction items are needs to be transferred to the Driver where these transaction items are converted into cycle based signal/pin level transitions.

Generally, the Sequence as six function/operation for communicate with the Driver they are

1.create_item() / create req.
2.wait_for_grant().
3.randomize the req.
4.send the req.
5.wait for item done.
6.get response.

The above Sequence can be done with three function/operation for communicate with the Driver they are

  1. start_item(txn);
  2. txn.randomize.
  3. finish_item(txn);

Sequence-Driver-Sequencer communication

Based on the varieties of methods available with sequence and driver, they are two Methods

  1. Using get_next_item and item_done methods in the driver

  2. Using get and put methods in driver

1.Using get_next_item and item_done methods in the driver (1st procedure)

The below Fig.1 show the Transaction Exchange flow between the component Having said that, sending a transaction/sequence_item from a Sequencer to a Driver is a 4 step process which is discussed below.

Untitled Diagram (14)

                                                 Fig.1:Transaction Exchange between Driver Sequencer
  • The Driver class contains the TLM port called uvm_seq_item_pull_port is connected to the uvm_seq_item_pull_Export called sequencer Both are connected in the run phase of UVM_AGENT. The driver can use the TLM function to get the next item from the Sequencer when it is required.

Sequencer side operation:

1.Creating the “transaction item” with the declared handle using factory mechanism.

  1. Calling “start_item(<transaction_item_handle>)“. This call blocks the Sequencer till it grants the Sequence and transaction access to the Driver.

  2. Randomizing the transaction OR randomizing the transaction with in-line constraints. Now the transaction is ready to be used by the Driver.

  3. Calling “finish_item(<transaction_item_handle>)“. This call which is blocking in nature waits till Driver transfer the protocol related transaction data.

  • These are the operational steps from a Sequence which we want to execute using a Sequencer that is connected to a Driver inside an Agent component. Whole of this process is shown in the Figure 1

Driver side operation:

  1. Declaring the “transaction item” with a handle.

  2. Calling the “get_next_item(<transaction_item_handle>)“. Default transaction_handle is “req”. “get_next_item()” blocks the processing until the “req” transaction object is available in the sequencer request FIFO & later “get_next_item” returns with the pointer of the “req” object.

  3. Next, Driver completes its side protocol transfer while working with the virtual interface.

  4. Calling the “item_done()” OR “item_done(rsp)“. It indicates to the sequencer the completion of the process. “item_done” is a non-blocking call & can be processed with an argument or without an argument. If a response is expected by the Sequencer/Sequence then item_done(rsp) is called. It results in Sequencer response FIFO is updated with the “rsp” object handle.

Using get_next_item and item_done methods in the driver (2nd procedure)

Copy of driver_sequence handshake (2)

                         Fig.2: Flow of Transactions between Sequencer,Driver and DUT.
  1. create_item(): Create a sequence item and register in the factory using the create_item function call.
    Example: req = **_seq_item::type_id::create(req);

  2. wait_for_grant() 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() 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. wait_for_item_done()
    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.

Example

Code snippet

Transaction class

  class transaction extends uvm_sequence_item;
  rand bit [3:0] a;
  rand bit [3:0] b;
  bit [4:0] y;

  function new(input string name = "transaction");
  super.new(name);
  endfunction

  `uvm_object_utils_begin(transaction)
  `uvm_field_int(a,UVM_DEFAULT)
  `uvm_field_int(b,UVM_DEFAULT)
  `uvm_field_int(y,UVM_DEFAULT)
  `uvm_object_utils_end

   endclass  

Sequence class

   class sequence1 extends uvm_sequence#(transaction);
   `uvm_object_utils(sequence1)
    transaction trans;

   function new(string name = "sequence1");
   super.new(name);    
   endfunction

   virtual task body();
   begin

   //creating an item 

   trans = transaction::type_id::create("trans");

   `uvm_info("Sequence","Sequence item is created",UVM_NONE)

    wait_for_grant();
    `uvm_info("Sequence","Grant received now randomizing the data",UVM_NONE)
    
    assert(trans.randomize());
    `uvm_info("Sequence",$sformatf("randomised value, a:%0d , b:%0d" ,trans.a,trans.b), UVM_NONE);
    `uvm_info("Sequence","Randmization done and now sent request to driver",UVM_NONE)
    
    send_request(trans);
    `uvm_info("Sequence","Waiting for item done response from driver",UVM_NONE);
   
    wait_for_item_done();
    `uvm_info("Sequence","Ack.recieved from driver,Sequence ended",UVM_NONE)
     
    end
    endtask

    endclass

Driver class

   class driver extends uvm_driver#(transaction);
   `uvm_component_utils(driver)
   transaction trans;

   function new(input string name = "DRV", uvm_component parent);
   super.new(name,parent);
   endfunction

   virtual task run_phase(uvm_phase phase); 
   trans = transaction::type_id::create("trans");
   forever begin
   `uvm_info("Driver", "Waiting for data from sequencer", UVM_NONE);
   
   //get an item from sequencer using get_next method
   //Instead of get_next_item, we can use get(req)
   seq_item_port.get_next_item(req);
   `uvm_info("Driver", $sformatf("Start driving data, a : %0d b:%0d", req.a, req.b), UVM_NONE);

   //call the item_done method to send the request item back to sequencer
   //Instead of item_done, we can use put(req)
   seq_item_port.item_done();     
   `uvm_info("Driver", $sformatf("Finish driving data, a : %0d b:%0d", req.a, req.b), UVM_NONE);
 
   end
   endtask

   endclass

Output

Below figure shows the output of Driver sequence handshake mechanism.

get_next1

                             Figure.2.Output of sequence driver handshake mechanism
  • Initially the driver is waiting for data from the sequence through sequencer using TLM ports.
  • In sequence class the sequence items are created using create method.
  • When the sequencer receives the wait_for_grant call, it sends to sequence block and the data gets randomized.
  • After randomization i.e a=6 and b=15, the request is send to driver through sequencer and it is waiting for item_done response from driver.
  • Then the driver starts driving data i.e a=6 and b=15, after finishes, the driver will wait for the next data from the sequence and at the same time driver will send acknowledgement to sequencer as item done.
  • After these process, then it will create next item.

2. Using get and put methods in driver

Copy of Copy of driver_sequence handshake (2)

                                    Figure.3. get() and put() method  
  1. create_item() Create a sequence item and register in the factory using the create_item function call. Example: req = **_seq_item::type_id::create(req);

  2. wait_for_grant() 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() 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. wait_for_item_done() wait_for_item_done() call from the sequence gets blocked until the driver calls the get method.Once the get method is called, the wait_for_item_done() call from sequence gets unblocked immediately without caring about driving the virtual interface.

  5. get_response() The get_response call is necessary to call that completes the communication. The get_response method is blocked until the driver calls put(RSP).
    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.