How do I implement out of order response of driver?

Are accept_tr, begin_tr, and end_tr connected to each other?
I want to give the sequence different response times depending on the DUT’s response.

For example, for transaction=1, I want to send the response last, after processing the rest of transaction=2 and transaction=3, to see the actual “out-of-order” behaviour, so I added "Delay for

#20000 seq_item_port.put_response(pkt_q[index]);
#20000 end_tr(pkt_q[index]);

But the result always ends up with transaction=1, transaction=2 and transaction=3 in that order, and I don’t know why.


class driver extends uvm_driver#(seq_item);
  seq_item  pkt_q[$];
        
  `uvm_component_utils(driver)
        
  uvm_analysis_port #(seq_item) drv_analysis_port;
        
  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);
    drv_analysis_port = new("drv_analysis_port", this);
        
  endfunction
        
  task run_phase (uvm_phase phase);
    fork
      get_item();
      execute_item();
    join_none
  endtask
        
  virtual task get_item();
    forever begin
      seq_item_port.get_next_item(req);
      accept_tr(req);
        
      pkt_q.push_back(req);
      seq_item_port.item_done(); 
    end 
  endtask
        
  virtual task execute_item();
    forever begin
      int index;
      wait(pkt_q.size() != 0);
      index = $urandom_range(pkt_q.size()-1);
      begin_tr(pkt_q[index]);
        
      if(pkt_q[index].get_transaction_id()==1) begin
        `uvm_info(get_type_name(), $sformatf("delayed pkt_q[%0h]=%0h", index, pkt_q[index]), UVM_LOW)
        #20000 seq_item_port.put_response(pkt_q[index]);
        #20000 end_tr(pkt_q[index]);
      end
      else begin
        seq_item_port.put_response(pkt_q[index]);
        end_tr(pkt_q[index]);
      end
        
      pkt_q.delete(index);
    end
  endtask
       
endclass


In reply to UVM_LOVE:

Your issue is that your execute_item() task will start as soon as the first request is in the queue. You want to fork the execute_item() each time you receive a new sequence_item.

Take a look at this small example: https://www.edaplayground.com/x/LEra

In reply to UVM_LOVE:

As far as I know, the methods accept_tr(), begin_tr(), and end_tr() are part of the UVM Recording Interface for logging transactions. They don’t change how the transactions are processed.