mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-24 13:57:19 -04:00
Handle a seed change that clears a PMP error in icache memory driver
When the existing code in drive_pmp() decided that an error needed signalling, it waited until the request was dropped, or the address changed, before clearing the PMP error. This is fine, unless the memory seed is changed (by magical means!) under our feet. The monitor spots a new request, but the driver needs to know to clear the PMP error. This patch forcibly tells the driver to drop the existing item if a new one comes in.
This commit is contained in:
parent
608ad2dfbc
commit
a56f14e060
1 changed files with 24 additions and 16 deletions
|
@ -18,7 +18,7 @@ class ibex_icache_mem_driver
|
|||
int unsigned max_grant_delay = 10;
|
||||
|
||||
mailbox #(ibex_icache_mem_resp_item) rdata_queue;
|
||||
mailbox #(bit [31:0]) pmp_queue;
|
||||
mailbox #(bit [32:0]) req_queue;
|
||||
|
||||
`uvm_component_utils(ibex_icache_mem_driver)
|
||||
`uvm_component_new
|
||||
|
@ -26,7 +26,7 @@ class ibex_icache_mem_driver
|
|||
function void build_phase(uvm_phase phase);
|
||||
super.build_phase(phase);
|
||||
rdata_queue = new("rdata_queue");
|
||||
pmp_queue = new("pmp_queue");
|
||||
req_queue = new("req_queue");
|
||||
endfunction
|
||||
|
||||
virtual task reset_signals();
|
||||
|
@ -73,11 +73,8 @@ class ibex_icache_mem_driver
|
|||
|
||||
// Is this a request or a grant?
|
||||
if (!req.is_grant) begin
|
||||
// If a request causes a PMP error, we push the address onto pmp_queue (which will be
|
||||
// handled by drive_pmp).
|
||||
if (req.err) begin
|
||||
pmp_queue.put(req.address);
|
||||
end
|
||||
// Push the address onto req_queue (which will be handled by drive_pmp).
|
||||
req_queue.put({req.err, req.address});
|
||||
end else begin
|
||||
// If a grant, we take a copy and add it to the response queue (handled by drive_responses)
|
||||
$cast(rsp, req.clone());
|
||||
|
@ -112,22 +109,33 @@ class ibex_icache_mem_driver
|
|||
// driver clears the address and exits. The idea is that if stuff gets out of sync for a delta
|
||||
// cycle or two, drive_pmp can discard items to catch up.
|
||||
task automatic drive_pmp();
|
||||
bit err;
|
||||
bit [31:0] address;
|
||||
bit [32:0] data;
|
||||
|
||||
forever begin
|
||||
pmp_queue.get(address);
|
||||
req_queue.get(data);
|
||||
{err, address} = data;
|
||||
|
||||
// The address we just got means "The req line should be high and the address should be this
|
||||
// one. Squash the request with a PMP error".
|
||||
//
|
||||
// If err is false, this is a request which shouldn't trigger a PMP error.
|
||||
if (!err) continue;
|
||||
|
||||
// Otherwise, the address is the address that we expect to see on the interface.
|
||||
// If the req line is low, or the address doesn't match, skip this item.
|
||||
if ((!cfg.vif.req) || (cfg.vif.addr != address)) continue;
|
||||
|
||||
cfg.vif.pmp_err <= 1'b1;
|
||||
|
||||
// Wait for an address change or req to de-assert
|
||||
@(negedge cfg.vif.req or cfg.vif.addr);
|
||||
|
||||
// Fork into two processes. The first waits for something else to appear in the queue. The
|
||||
// second drives the line until it thinks the request is finished. The driver is stopped if we
|
||||
// see a new request come in.
|
||||
fork
|
||||
req_queue.peek(data);
|
||||
begin
|
||||
cfg.vif.pmp_err <= 1'b1;
|
||||
// Wait for an address change or req to de-assert
|
||||
@(negedge cfg.vif.req or cfg.vif.addr);
|
||||
end
|
||||
join_any
|
||||
disable fork;
|
||||
cfg.vif.pmp_err <= 1'b0;
|
||||
end
|
||||
endtask
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue