Pipelined access of sequence from cookbook

I am looking at the UVM cookbook and i see the example with pipelined_item_done has 2 sequences one with unpipelined and another with pipelined. I see both the sequences have command and data phase separately. How is the first one non-pipelined and second one pipelined? Can any one help?


class mbus_unpipelined_seq extends uvm_sequence #(mbus_seq_item);

`uvm_object_utils(mbus_unpipelined_seq)

logic[31:0] addr[10]; // To save addresses
logic[31:0] data[10]; // To save data

int error_count;

function new(string name = "mbus_unpipelined_seq");
  super.new(name);
endfunction

task body;

  mbus_seq_item req = mbus_seq_item::type_id::create("req");
  error_count = 0;

  for(int i=0; i<10; i++) begin
    start_item(req);
    assert(req.randomize() with {MREAD == 0; MOPCODE == SINGLE; MADDR inside {[32'h0010_0000:32'h001F_FFFC]};});
    addr[i] = req.MADDR;
    data[i] = req.MWDATA;
    finish_item(req);
    req.wait_trigger("DATA_DONE"); // I think this should be "CMD_DONE"
  end

  foreach(addr[i]) begin
    start_item(req);
    req.MADDR = addr[i];
    req.MREAD = 1;
    finish_item(req);
    req.wait_trigger("DATA_DONE");
    if(req.MRDATA != data[i]) begin
      error_count++;
      `uvm_error("body", $sformatf("@%0h Expected data:%0h Actual data:%0h", addr[i], data[i], req.MRDATA))
    end
  end
endtask: body

endclass: mbus_unpipelined_seq

class mbus_pipelined_seq extends uvm_sequence #(mbus_seq_item);

`uvm_object_utils(mbus_pipelined_seq)

logic[31:0] addr[10]; // To save addresses
int count; // To ensure that the sequence does not complete too early

function new(string name = "mbus_pipelined_seq");
  super.new(name);
endfunction

task body;
  mbus_seq_item req = mbus_seq_item::type_id::create("req");
  use_response_handler(1);
  count = 0;

  for (int i=0; i<10; i++) begin
    start_item(req);
    assert(req.randomize() with {MREAD == 0; MOPCODE == SINGLE; MADDR inside {[32'h0010_0000:32'h001F_FFFC]};});
    addr[i] = req.MADDR;
    finish_item(req);
    `uvm_info("", $sformatf("write (i = %0d) of %h at %h", i, req.MWDATA, req.MADDR), UVM_MEDIUM);
  end

  foreach (addr[i]) begin
    start_item(req);
    req.MADDR = addr[i];
    req.MREAD = 1;
    finish_item(req);
    `uvm_info("", $sformatf("read (i = %0d) of %h at %h", i, req.MRDATA, req.MADDR), UVM_MEDIUM);
  end
  // Do not end the sequence until the last req item is complete
  wait(count == 20);
endtask: body

// This response_handler function is enabled to keep the sequence response FIFO empty
function void response_handler(uvm_sequence_item response);
  count++;
endfunction: response_handler

endclass: mbus_pipelined_seq

In reply to rag123:

Because we are waiting for a trigger in the non-pipelined sequence.

In reply to hsam:

We want to use the same driver for piplined and non-pipelined access. In the non-pipelined access we see the trigger imediately after the command phase has completed.

the only difference between pipleined and unpipelined is that in case unpipelined, there exists

req.wait_trigger("DATA_DONE");

And what?

Using events in the transaction is bad idea

  1. when running regression your simulation will become slow
  2. who and how is controlling the “DATA_DONE” event? is it driver controlling or req?
  3. why not use simple response here?
  4. If you want really unpiplined case, use some interface signal in driver. Like it is done in real hardware. Much easy.

Thanks

In reply to rag123:

@rag123
You have an old version of the pipelined example.
Ther eis a newer one which does not have events in the sequences. The synchronization of the transactions is done in the driver. This is the right place, because this component controls any timimg.

The example you are showing is a little bit tricky, but it works.