Commit e85a2855 authored by Dimitris Lampridis's avatar Dimitris Lampridis

hdl/sim: Protect CIWBMasterAccessor against multiple requests

When performing reads/writes from multiple threads, CIWBMasterAccessor does not provide any
protection, leading to data from one request being delivered to another.

By replacing the data queues with SV mailboxes, we ensure that only one thread can access the
mailbox at any given time. Furthermore, we add a SV event in wb_cycle_t, which is used to notify
the readm()/writem() tasks that their transfer is complete, to avoid getting the result of the
wrong transfer.
parent 17140a58
......@@ -72,8 +72,8 @@ interface IWishboneMaster
WAIT_ACK
} xf_state;
wb_cycle_t request_queue[$];
wb_cycle_t result_queue[$];
mailbox #(wb_cycle_t) request_queue;
mailbox #(wb_cycle_t) result_queue;
struct {
int gen_random_throttling;
......@@ -283,35 +283,29 @@ class CIWBMasterAccessor extends CWishboneAccessor;
endfunction // poll
task get(ref wb_cycle_t xfer);
while(!result_queue.size())
@(posedge clk_i);
xfer = result_queue.pop_front();
result_queue.get(xfer);
endtask // get
task put(ref wb_cycle_t xfer);
request_queue.push_back(xfer);
request_queue.put(xfer);
endtask // put
function int idle();
return (request_queue.size() == 0) && (xf_state == IDLE);
return (request_queue.num() == 0) && (xf_state == IDLE);
endfunction // idle
endclass // CIWBMasterAccessor
CIWBMasterAccessor theAccessor;
initial
theAccessor = new;
function automatic CIWBMasterAccessor get_accessor();
return theAccessor;
endfunction // get_accessor
always@(posedge clk_i)
if (!rst_n_i) begin
request_queue = {};
result_queue = {};
request_queue = new();
result_queue = new();
xf_state = IDLE;
cyc <= 0;
dat_o <= 0;
......@@ -322,30 +316,38 @@ endclass // CIWBMasterAccessor
end
initial begin
theAccessor = new;
request_queue = new();
result_queue = new();
settings.gen_random_throttling = 0;
settings.throttle_prob = 0.1;
settings.addr_gran = WORD;
end
initial forever begin
@(posedge clk_i);
if (request_queue.size() > 0) begin
forever begin
wb_cycle_t c;
c = request_queue.pop_front();
@(posedge clk_i);
case(c.ctype)
PIPELINED:
pipelined_cycle(c);
CLASSIC:
classic_cycle(c);
endcase
if (request_queue.try_get(c)) begin
result_queue.push_back(c);
end
case (c.ctype)
PIPELINED:
pipelined_cycle(c);
CLASSIC:
classic_cycle(c);
endcase
// Notify any waiting thread that the transfer is complete
->c.done;
result_queue.put(c);
end // if (request_queue.try_get(c))
end // forever begin
end
end // initial begin
endinterface // IWishboneMaster
......@@ -66,8 +66,11 @@ virtual class CWishboneAccessor extends CBusAccessor;
end
// $display("DS: %d", cycle.data.size());
put(cycle);
// wait for the transfer completion notification to avoid getting the result of the wrong transfer
// in case multiple threads are calling readm()/writem() in parallel.
@cycle.done;
get(cycle);
result = cycle.result;
......@@ -91,6 +94,9 @@ virtual class CWishboneAccessor extends CBusAccessor;
end
put(cycle);
// wait for the transfer completion notification to avoid getting the result of the wrong transfer
// in case multiple threads are calling readm()/writem() in parallel.
@cycle.done;
get(cycle);
for(i=0;i < addr.size(); i++)
......
......@@ -42,6 +42,7 @@ typedef struct {
wb_cycle_type_t ctype;
wb_xfer_t data[$];
wb_cycle_result_t result;
event done;
} wb_cycle_t;
typedef enum
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment