Question on uvm_driver w.r.t uvm_sequence_item

This is an interview question :
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.

Can someone help with this?

Pseudo code of my understanding :

task run_phase: 

forever begin
seq_item_port.get_next_item(req);

fork
   task_1 ; //drive the lower 32 bits of the data on the interface
   task_2 : //drive the upper 32 bits of the data on the interface
join_none

seq_item_port.item_done();
end

It is not clear to me if this seq_item will still be available once the seq_item_port.item_done() is executed. If it not going to be available, then I think my idea won’t work.
How can we keep info from previous sequence items while also working on the next sequence item?

Thanks.

This is a question on pipelined driver. Here the sequence item is executed in tow stages (lower 32-bit data and higher 32-bit data). So you will need to implement a pipelined driver which can execute two sequence items in parallel but in different stages of execution.

The code looks something like the following:
Class my_driver extends uvm_driver #(my_seq_item);
`uvm_component_utils(my_driver)

 semaphore S1;

task build_phase(uvm_phase phase);
S1 = new(1);

endtask

task run_phase(uvm_phase phase);
wait_for_reset();
fork
drive_data();
drive_data();
join
endtask

task drive_data();
forever begin
S1.get_lock();
seq_item_port.get(req);
send_low_data(req);
S1.release_lock();
send_high_data(req);
seq_item_port.put();
end
endtask

You have to use get() and put() instead of get_next_item() and item_done() pair in order to achieve parallelism.

1 Like

if your task_1 and task_2 consumes time and if you are sending another item immediately i think i will override to the current req in this case it would be better if we copy it to another handle and execute the threads,

if no other items are there means there will be a chance that your sim will exit before you even finish the routines(if time consumed), since it will end the body of sequence and in turn it will end the start method and if no delay given will drop the test objection.
if you want to do pipelined driver then there is article in this website or use fork join_any and use the next item to drive some routine while the other is executing or,

class pipelined_driver extends uvm_driver #(item);
   item req_que [$];
   int max_pipeline_depth = 2;
   `uvm_component_utils(pipelined_driver)
   //////constructor
   task run_phase(uvm_phase phase);
      fork
         get_and_drive();
         drive_transfers();
      join
   endtask : run_phase
   task get_and_drive();
      while(req_que.size() < max_pipeline_depth)begin
         seq_item_port.get_next_item(req);
         $cast(rsp,req.clone());
         rsp.set_id_info(req);
         req_que.push_back(rsp);
         seq_item_port.item_done();
      end
   endtask : get_and_drive
   task drive_transfer();
      item cur_req;
      while(1)begin
         wait(req_que.size() > 0);
         cur_req = req_que.pop_front();
         send_to_dut(cur_req);
         rsp_port.write(cur_req);
      end
   endtask : drive_transfer
endclass : pipelined_driver
1 Like