Sequence items have 64 bit data field and transaction id
Driver drives only 32 bits of the data on the interface. Lower 32 bits are driven first for a given sequence item.
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
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