Grab Transactions inside UVM_Sequencer Run Phase

1.1k views Asked by At

I want to grab the transactions inside my uvm_sequencer's run_phase to check if the transactions are crossing 4KB boundary. In case they cross the 4KB boundary I want to split that transaction into multiple transactions and then send it to the driver. When the response is received from the driver, all the split transactions response should be merged back into the original transaction and returned back to the sequence which generated the original transaction. Is there a way to do this? And is uvm_sequencer the right place to do this job? Any help would be greatly appreciated.

Edit:

Tudor's solution does work. I added a few edits to his code (translation_sequence) as below:

up_sequencer.get_next_item(req);
$cast(up_trans, req.clone());
// do the splitting.
start_item(up_trans);
finish_item(up_trans);
up_sequencer.item_done();
get_response(rsp);
rsp.set_sequence_id(req.get_sequence_id());
up_sequencer.put_response(rsp);
1

There are 1 answers

2
Tudor Timi On BEST ANSWER

You can't do this in the sequencer, because sending an item is performed in 2 steps: start_item(...) and finish_item(...). If it were only one method, you could have done there.

The way to go, IMO, is to implement a layering scheme. Your upper layer is the one where you start your sequences, where you don't care about the length of the transaction. Your second layer is the one where the maximum length is 4K. The flow of transactions would be:

your sequence -> upper sequencer -> translation sequence -> bus sequencer -> driver

This means that in your agent, you'll need two sequencers, where only one is connected to the driver. A translation sequence might look like this:

class translation_sequence extends uvm_sequence #(some_trans);
  uvm_sequencer #(some_trans) up_sequencer;

  task body();
    while (1) begin
      some_trans up_trans;
      up_sequencer.get_next_item(up_trans);

      if (up_trans.size <= 4096) begin
        `uvm_info("SPLIT", "No need to split", UVM_LOW);
        start_item(up_trans);
        finish_item(up_trans);
      end
      else begin
        // implement the splitting
        int unsigned size = up_trans.size;

        while (1) begin
          req = new();
          req.size = size > 4096 ? 4096 : size;
          start_item(req);
          finish_item(req);

          if (size < 4096)
            break;
          else
            size -= 4096;
        end
      end

      up_sequencer.item_done();
    end
  endtask
endclass

Notice that it has a pointer to the upper level sequencer and it gets items from it and signals their completion. In the agent you need to start this sequence, also giving it a pointer to the upper sequencer:

class some_agent extends uvm_agent;
  //...

  // start the translation sequence
  task run_phase(uvm_phase phase);
    translation_sequence seq = new();
    seq.up_sequencer = sequencer;
    seq.start(bus_sequencer);
  endtask
endclass

If you want to read more on layering, have a look at this article on Verification Horizons.