diff --git a/dv/uvm/icache/dv/ibex_icache_core_agent/ibex_icache_core_driver.sv b/dv/uvm/icache/dv/ibex_icache_core_agent/ibex_icache_core_driver.sv index f39ea4a8..22986ee2 100644 --- a/dv/uvm/icache/dv/ibex_icache_core_agent/ibex_icache_core_driver.sv +++ b/dv/uvm/icache/dv/ibex_icache_core_agent/ibex_icache_core_driver.sv @@ -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. diff --git a/dv/uvm/icache/dv/ibex_icache_core_agent/ibex_icache_core_if.sv b/dv/uvm/icache/dv/ibex_icache_core_agent/ibex_icache_core_if.sv index bf208bfd..0e9d4e2f 100644 --- a/dv/uvm/icache/dv/ibex_icache_core_agent/ibex_icache_core_if.sv +++ b/dv/uvm/icache/dv/ibex_icache_core_agent/ibex_icache_core_if.sv @@ -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