mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-22 04:47:25 -04:00
Add clocking blocks to the ibex_icache_core_agent
Since this agent doesn't currently do any monitoring (will be addressed in a later patch), the monitor_cb clocking block doesn't do very much at the moment. The driver_cb clocking block *is* used, though. The input lines are just those needed to drive things correctly (ready is needed to do ready/valid signalling properly; err is needed to abort instruction fetches and do a branch after an error). I've marked the output signals as negedge: this doesn't really make any difference to simulation results, since the design samples everything on posedge, but makes it rather easier to read dumped waves.
This commit is contained in:
parent
bce473b1dc
commit
5a188342e7
2 changed files with 75 additions and 31 deletions
|
@ -6,9 +6,14 @@ class ibex_icache_core_driver extends dv_base_driver #(ibex_icache_core_item, ib
|
|||
`uvm_component_utils(ibex_icache_core_driver)
|
||||
`uvm_component_new
|
||||
|
||||
// The current state of the enable pin: this is toggled by sequence items, but the current state
|
||||
// is stored on the driver.
|
||||
bit enable;
|
||||
|
||||
// reset signals
|
||||
virtual task automatic reset_signals();
|
||||
cfg.vif.reset();
|
||||
enable = 1'b0;
|
||||
endtask
|
||||
|
||||
// drive trans received from sequencer
|
||||
|
@ -34,11 +39,15 @@ class ibex_icache_core_driver extends dv_base_driver #(ibex_icache_core_item, ib
|
|||
// (enable/disable, invalidate, read instructions).
|
||||
virtual task automatic drive_branch_trans(ibex_icache_core_item req);
|
||||
// Make sure that req is enabled (has no effect unless this is the first transaction)
|
||||
cfg.vif.req <= 1'b1;
|
||||
cfg.vif.driver_cb.req <= 1'b1;
|
||||
|
||||
// Toggle the enable state if necessary and drive its pin
|
||||
if (req.toggle_enable)
|
||||
enable = ~enable;
|
||||
cfg.vif.driver_cb.enable <= enable;
|
||||
|
||||
fork
|
||||
cfg.vif.branch_to(req.branch_addr);
|
||||
if (req.toggle_enable) toggle_enable();
|
||||
if (req.invalidate) invalidate();
|
||||
read_insns(req.num_insns);
|
||||
join
|
||||
|
@ -62,25 +71,24 @@ class ibex_icache_core_driver extends dv_base_driver #(ibex_icache_core_item, ib
|
|||
[100:200] :/ 2,
|
||||
[1000:1200] :/ 1 };)
|
||||
|
||||
// Toggle the enable state if necessary and drive its pin
|
||||
if (req.toggle_enable)
|
||||
enable = ~enable;
|
||||
cfg.vif.driver_cb.enable <= enable;
|
||||
|
||||
fork
|
||||
if (req_low_cycles > 0) lower_req(req_low_cycles);
|
||||
if (req.toggle_enable) toggle_enable();
|
||||
if (req.invalidate) invalidate();
|
||||
join
|
||||
read_insns(req.num_insns);
|
||||
endtask
|
||||
|
||||
// Toggle whether the cache is enabled
|
||||
virtual task automatic toggle_enable();
|
||||
cfg.vif.enable <= ~cfg.vif.enable;
|
||||
endtask
|
||||
|
||||
// Read up to num_insns instructions from the cache, stopping early on an error
|
||||
virtual task automatic read_insns(int num_insns);
|
||||
for (int i = 0; i < num_insns; i++) begin
|
||||
read_insn();
|
||||
// Spot any error and exit early
|
||||
if (cfg.vif.err)
|
||||
if (cfg.vif.driver_cb.err)
|
||||
break;
|
||||
end
|
||||
endtask
|
||||
|
@ -91,7 +99,7 @@ class ibex_icache_core_driver extends dv_base_driver #(ibex_icache_core_item, ib
|
|||
|
||||
// Maybe (1 time in 10) wait for a valid signal before even considering asserting ready.
|
||||
if ($urandom_range(9) == 0)
|
||||
wait (cfg.vif.valid);
|
||||
wait (cfg.vif.driver_cb.valid);
|
||||
|
||||
// Then pick how long we wait before asserting that we are ready.
|
||||
//
|
||||
|
@ -99,21 +107,21 @@ class ibex_icache_core_driver extends dv_base_driver #(ibex_icache_core_item, ib
|
|||
cfg.vif.wait_clks($urandom_range(3));
|
||||
|
||||
// Assert ready and then wait until valid
|
||||
cfg.vif.ready <= 1'b1;
|
||||
cfg.vif.driver_cb.ready <= 1'b1;
|
||||
while (1'b1) begin
|
||||
@(posedge cfg.vif.clk);
|
||||
if (cfg.vif.valid)
|
||||
@(cfg.vif.driver_cb);
|
||||
if (cfg.vif.driver_cb.valid)
|
||||
break;
|
||||
end
|
||||
|
||||
cfg.vif.ready <= 1'b0;
|
||||
cfg.vif.driver_cb.ready <= 1'b0;
|
||||
endtask
|
||||
|
||||
// Lower the req line for the given number of cycles
|
||||
virtual task automatic lower_req(int unsigned num_cycles);
|
||||
cfg.vif.req <= 1'b0;
|
||||
repeat (num_cycles) @(posedge cfg.vif.clk);
|
||||
cfg.vif.req <= 1'b1;
|
||||
cfg.vif.driver_cb.req <= 1'b0;
|
||||
repeat (num_cycles) @(cfg.vif.driver_cb);
|
||||
cfg.vif.driver_cb.req <= 1'b1;
|
||||
endtask
|
||||
|
||||
// Raise the invalidate line for a randomly chosen number of cycles > 0.
|
||||
|
|
|
@ -27,16 +27,52 @@ interface ibex_icache_core_if (input clk);
|
|||
// itself)
|
||||
logic busy;
|
||||
|
||||
// A clocking block for test code that drives the interface
|
||||
clocking driver_cb @(posedge clk);
|
||||
|
||||
// Drive signals on the following negedge: this isn't needed by the design, but makes it
|
||||
// slightly easier to read dumped waves.
|
||||
default output negedge;
|
||||
|
||||
output req;
|
||||
|
||||
output branch;
|
||||
output branch_addr;
|
||||
|
||||
output ready;
|
||||
input valid;
|
||||
input err;
|
||||
|
||||
output enable;
|
||||
output invalidate;
|
||||
endclocking
|
||||
|
||||
// A clocking block for test code that needs to monitor the interface
|
||||
clocking monitor_cb @(posedge clk);
|
||||
input req;
|
||||
input branch;
|
||||
input branch_addr;
|
||||
input ready;
|
||||
input valid;
|
||||
input rdata;
|
||||
input addr;
|
||||
input err;
|
||||
input err_plus2;
|
||||
input enable;
|
||||
input invalidate;
|
||||
input busy;
|
||||
endclocking
|
||||
|
||||
// Drive the branch pin for a single cycle, redirecting the cache to the given instruction
|
||||
// address.
|
||||
task automatic branch_to(logic [31:0] addr);
|
||||
branch <= 1'b1;
|
||||
branch_addr <= addr;
|
||||
driver_cb.branch <= 1'b1;
|
||||
driver_cb.branch_addr <= addr;
|
||||
|
||||
@(posedge clk);
|
||||
@(driver_cb);
|
||||
|
||||
branch <= 1'b0;
|
||||
branch_addr <= 'X;
|
||||
driver_cb.branch <= 1'b0;
|
||||
driver_cb.branch_addr <= 'X;
|
||||
endtask
|
||||
|
||||
// Raise a pulse on the invalidate line for the given number of cycles.
|
||||
|
@ -44,24 +80,24 @@ interface ibex_icache_core_if (input clk);
|
|||
// A one-cycle pulse will start an invalidation, but testing might want a longer pulse (which the
|
||||
// cache should support)
|
||||
task automatic invalidate_pulse(int num_cycles);
|
||||
invalidate <= 1'b1;
|
||||
repeat (num_cycles) @(posedge clk);
|
||||
invalidate <= 1'b0;
|
||||
driver_cb.invalidate <= 1'b1;
|
||||
wait_clks(num_cycles);
|
||||
driver_cb.invalidate <= 1'b0;
|
||||
endtask
|
||||
|
||||
// A task that waits for num_clks posedges on the clk signal
|
||||
task automatic wait_clks(int num_clks);
|
||||
repeat (num_clks) @(posedge clk);
|
||||
repeat (num_clks) @(driver_cb);
|
||||
endtask
|
||||
|
||||
// Reset all the signals from the core to the cache (the other direction is controlled by the
|
||||
// DUT)
|
||||
task automatic reset();
|
||||
req <= 1'b0;
|
||||
branch <= 1'b0;
|
||||
ready <= 1'b0;
|
||||
enable <= 1'b0;
|
||||
invalidate <= 1'b0;
|
||||
driver_cb.req <= 1'b0;
|
||||
driver_cb.branch <= 1'b0;
|
||||
driver_cb.ready <= 1'b0;
|
||||
driver_cb.enable <= 1'b0;
|
||||
driver_cb.invalidate <= 1'b0;
|
||||
endtask
|
||||
|
||||
endinterface
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue