Hi all I have a question regarding driving sequence items in a certain way. The details are provided below. Please let me know if I am doing anything wrong with my code

Implement a uvm driver with following conditions

  1. Sequence items have 64 bit data field and transaction id
  2. Driver drives only 32 bits of the data on the interface. Lower 32 bits are driven first for a given sequence item.
  3. Upper 32 bits may or may not immediately follow the lower 32 bits. For a given sequence item, lower 32 bits will be driven first, then d-words from other sequence items may be driven, and upper 32 bits will be driven after that. This flow is randomized.

class driver extends uvm_driver#(trans);

`uvm_component_utils(driver)
virtual interface vif;
trans tr;
int idx[$];
int data[$];
semaphore s;
function new(string name ="", uvm_component parent);
super.new();
s = new(1);
endfunction

virtual task run_phase(uvm_phase phase);
forever begin
    @(posedge clk);
    fork
      begin
        #5;
        s.get(1);
        if(data.size() != 0)
        begin
          vif.payload <= data.pop_front();
          vif.tid <= idx.pop_front();
      	end
        s.put(1);
      end
      begin
            s.get(1);
            seq_item_port.get_next_item(item);
            vif.payload <= tr.data[31:0];
            vif.tid<= tr.tid;
            data.push_back(tr.data[63:32]);
            idx.push_back(tr.tid);
            seq_item_port.item_done();
            s.put(1);
      end
    join
end
endtask
endclass:driver

In reply to rohandbz:

Your requirements are ambiguous. How is “d-words from other sequence items” defined? Also, if the flow is ‘randomized’, how do you verify that it is correct? Randomized behavior from a protocol standpoint isn’t verifiable.

If you were to send the lower 32-bits, followed by the upper 32-bits, this would be correct behavior as the requirements use the term ‘may be driven’.

Is there a limit of how many transactions should be queued? Is the sequence waiting for a completion of the transaction, or just that the transaction was received by the driver?

I would create a single queue of data/transaction id. Have a thread that when a new transaction is received, insert the lower 32 bits in a random location of the queue. Insert the upper 32 bits in a random location higher than the lower 32 bits.

Have a second thread that pops data from the queue and sends it on the bus.

Some pseudo-code:


class driver extends uvm_driver#(trans);
  `uvm_component_utils(driver)
  virtual interface vif;
  trans tr;
  int data_q[$];
  int tx_id_q[$];
  semaphore s;

  function new(string name ="", uvm_component parent);
    super.new();
    s = new(1);
  endfunction

  task get_and_queue();
    REQ item;
    int idx;
    forever begin
      seq_item_port.get_next_item(item);
      s.get();
      idx = $urandom_range(data_q.size(),0);
      data_q.insert(idx, item.data[31:0];
      tx_id_q.insert(idx, item.id);
      idx = $urandom_range(data_q.size(), idx+1); 
      data_q.insert(idx, item.data[63:32];
      tx_id_q.insert(idx, item.id);
      seq_item_port.item_done();
      s.put();
    end
  endtask

  task pop_and_drive();
    int data;
    int tr_id;
    forever begin
      @(posedge vif.clk);
      s.get();
      if (data_q.size()) begin
        data = data_q.pop_front();
        tr_id = tr_id_q.pop_front();
        vif.payload = data;
        vif.tr_id = tr_id;
      end
      s.put();
    end
  endtask
 
  virtual task run_phase(uvm_phase phase);
    fork
      get_and_queue();
      pop_and_drive();
    join
  endtask
endclass:driver