I am going through the UVM code on the pipelined driver from cookbook and i dont understand how command phase and data phase execute in parallel? m_bfm.begin_transfer is a blocking call and doesnt not return until the command phase and data phase of the same transaction. The assumption is once end_tr is called the current transaction is done and driver will request for next transaction.
forever begin
seq_item_port.get(req);
accept_tr(req, $time);
void'(begin_tr(req, "pipelined_driver"));'
// This blocking call performs the cmd phase of the request and then returns
// right away before completing the data phase, thus allowing the cmd phase of
// the subsequent request (next loop iteration) to occur in parallel with the
// data phase of the current request, and so implementing the pipeline
m_bfm.begin_transfer(req);
pipeline.push_back(req);
end
endtask: do_pipelined_transfers
// Function to complete the sequence item - driver handshake back to the sequence
// item, decoupled from the point of the originating request
function void end_transfer(mbus_seq_item req);
mbus_seq_item rsp = pipeline.pop_front();
rsp.copy(req);
//seq_item_port.put(rsp); // End of req item
//put_response is a function instead of task:
seq_item_port.put_response(rsp); // End of req item
end_tr(rsp);
endfunction: end_transfer
interface mbus_pipelined_driver_bfm (
input logic MCLK,
input logic MRESETN,
output logic [31:0] MADDR,
output logic [31:0] MWDATA,
output logic MREAD,
output mbus_opcode_e MOPCODE,
input logic MRDY,
input logic [31:0] MRDATA,
input mbus_resp_e MRESP
);
mbus_pipelined_driver proxy;
mbus_seq_item current_tr;
event do_data_phase;
task begin_transfer(mbus_seq_item req);
command_phase(req);
pipeline_lock_get(); // Start of data phase: grab semaphore
current_tr = req;
->do_data_phase;
endtask: begin_transfer
always begin
@do_data_phase;
@(posedge MCLK);
data_phase(current_tr);
proxy.end_transfer(current_tr);
pipeline_lock_put(); // End of data phase: release semaphore
end
task wait_for_reset();
@(posedge MRESETN);
@(posedge MCLK);
endtask
task command_phase(mbus_seq_item req);
MADDR <= req.MADDR;
MREAD <= req.MREAD;
MOPCODE <= req.MOPCODE;
@(posedge MCLK);
while (!MRDY == 1) begin
@(posedge MCLK);
end
if (req.MREAD == 0) begin
MWDATA <= req.MWDATA;
end
endtask: command_phase
task data_phase(mbus_seq_item req);
while (MRDY != 1) begin
@(posedge MCLK);
end
req.MRESP = MRESP;
if (req.MREAD == 1) begin
req.MRDATA = MRDATA;
end
endtask: data_phase
bit pipeline_lock = 0;
task pipeline_lock_get();
while (pipeline_lock) begin
@(posedge MCLK);
end
pipeline_lock = 1;
endtask: pipeline_lock_get
function void pipeline_lock_put();
pipeline_lock = 0;
endfunction: pipeline_lock_put
endinterface: mbus_pipelined_driver_bfm
No, In above code “m_bfm.begin_transfer(req)” blocking only for command phase.
task begin_transfer(mbus_seq_item req);
command_phase(req); // blocking only for command.
pipeline_lock_get(); // directly come out as pipeline_lock = 0. So, non blocking
current_tr = req; // request assignment non blocking.
->do_data_phase; // trigger event for data phase and its non blocking.
endtask: begin_transfer
In begin_transfer once ->do_data_phase event call and task will complete.
However, data_phase will work in background and begin_transfer can able to accept second req item.
And for second request, it can block for next data phase only.
So, we can say that this is one stage pipeline.
The next req gets processed only when the driver signals seq_item_port.put(rsp). That triggers the request for second req. I am not sure how the driver starts the second req as soon as the begin_transfer gets completed.
Thanks got it :) One more question, lets say if the above code is modified for 2 stage pipeline, lets say we have now command,data1, data2 phase. How would that look like?
I have tried to modify original code for 2 stage. ( Please consider in terms of concept )
And if each phase is not depends on each other you can remove pipe_limit + pipe_lock_get/put.
I hope it helps.
I’m not sure if I understand your question right. But in a lot of situations you get more than 1 data back. Consider a burst read. You have a command phase indicating you have burst with 8 data getting back than you are reading according to your bus protocoöl the corresponding data from the bus.