diff --git a/dv/uvm/icache/dv/env/ibex_icache_env.core b/dv/uvm/icache/dv/env/ibex_icache_env.core index cff52c65..ac29f9e8 100644 --- a/dv/uvm/icache/dv/env/ibex_icache_env.core +++ b/dv/uvm/icache/dv/env/ibex_icache_env.core @@ -9,7 +9,7 @@ filesets: depend: - lowrisc:dv:dv_lib - lowrisc:dv:ibex_icache_core_agent - - lowrisc:dv:ibex_mem_intf_agent + - lowrisc:dv:ibex_icache_mem_agent files: - ibex_icache_env_pkg.sv - ibex_icache_env_cfg.sv: {is_include_file: true} @@ -19,7 +19,6 @@ filesets: - ibex_icache_env.sv: {is_include_file: true} - seq_lib/ibex_icache_vseq_list.sv: {is_include_file: true} - seq_lib/ibex_icache_base_vseq.sv: {is_include_file: true} - - seq_lib/ibex_icache_common_vseq.sv: {is_include_file: true} - seq_lib/ibex_icache_sanity_vseq.sv: {is_include_file: true} file_type: systemVerilogSource diff --git a/dv/uvm/icache/dv/env/ibex_icache_env.sv b/dv/uvm/icache/dv/env/ibex_icache_env.sv index 17dc8c08..9f108dba 100644 --- a/dv/uvm/icache/dv/env/ibex_icache_env.sv +++ b/dv/uvm/icache/dv/env/ibex_icache_env.sv @@ -10,31 +10,32 @@ class ibex_icache_env extends dv_base_env #( ); `uvm_component_utils(ibex_icache_env) - ibex_icache_core_agent m_ibex_icache_core_agent; - ibex_mem_intf_slave_agent m_ibex_mem_intf_slave_agent; + ibex_icache_core_agent core_agent; + ibex_icache_mem_agent mem_agent; `uvm_component_new function void build_phase(uvm_phase phase); super.build_phase(phase); // create components - m_ibex_icache_core_agent = ibex_icache_core_agent::type_id::create("m_ibex_icache_core_agent", this); - uvm_config_db#(ibex_icache_core_agent_cfg)::set(this, "m_ibex_icache_core_agent*", "cfg", cfg.m_ibex_icache_core_agent_cfg); - // create components - m_ibex_mem_intf_slave_agent = ibex_mem_intf_slave_agent::type_id::create("m_ibex_mem_intf_slave_agent", this); + core_agent = ibex_icache_core_agent::type_id::create("core_agent", this); + uvm_config_db#(ibex_icache_core_agent_cfg)::set(this, "core_agent*", "cfg", cfg.core_agent_cfg); + + mem_agent = ibex_icache_mem_agent::type_id::create("mem_agent", this); + uvm_config_db#(ibex_icache_mem_agent_cfg)::set(this, "mem_agent*", "cfg", cfg.mem_agent_cfg); endfunction function void connect_phase(uvm_phase phase); super.connect_phase(phase); if (cfg.en_scb) begin - m_ibex_icache_core_agent.monitor.analysis_port.connect(scoreboard.core_fifo.analysis_export); - m_ibex_mem_intf_slave_agent.monitor.addr_ph_port.connect(scoreboard.mem_fifo.analysis_export); + core_agent.monitor.analysis_port.connect(scoreboard.core_fifo.analysis_export); + mem_agent.monitor.analysis_port.connect(scoreboard.mem_fifo.analysis_export); end - if (cfg.is_active && cfg.m_ibex_icache_core_agent_cfg.is_active) begin - virtual_sequencer.core_sequencer_h = m_ibex_icache_core_agent.sequencer; + if (cfg.is_active && cfg.core_agent_cfg.is_active) begin + virtual_sequencer.core_sequencer_h = core_agent.sequencer; end - if (cfg.is_active && m_ibex_mem_intf_slave_agent.get_is_active()) begin - virtual_sequencer.mem_sequencer_h = m_ibex_mem_intf_slave_agent.sequencer; + if (cfg.is_active && cfg.mem_agent_cfg.is_active) begin + virtual_sequencer.mem_sequencer_h = mem_agent.sequencer; end endfunction diff --git a/dv/uvm/icache/dv/env/ibex_icache_env_cfg.sv b/dv/uvm/icache/dv/env/ibex_icache_env_cfg.sv index 25c8cd60..c5315531 100644 --- a/dv/uvm/icache/dv/env/ibex_icache_env_cfg.sv +++ b/dv/uvm/icache/dv/env/ibex_icache_env_cfg.sv @@ -5,19 +5,19 @@ class ibex_icache_env_cfg extends dv_base_env_cfg; // ext component cfgs - rand ibex_icache_core_agent_cfg m_ibex_icache_core_agent_cfg; + rand ibex_icache_core_agent_cfg core_agent_cfg; + rand ibex_icache_mem_agent_cfg mem_agent_cfg; `uvm_object_utils_begin(ibex_icache_env_cfg) - `uvm_field_object(m_ibex_icache_core_agent_cfg, UVM_DEFAULT) + `uvm_field_object(core_agent_cfg, UVM_DEFAULT) + `uvm_field_object(mem_agent_cfg, UVM_DEFAULT) `uvm_object_utils_end `uvm_object_new - virtual function void initialize(bit [TL_AW-1:0] csr_base_addr = '1); - // create ibex_icache agent config obj - m_ibex_icache_core_agent_cfg = ibex_icache_core_agent_cfg::type_id::create("m_ibex_icache_core_agent_cfg"); - // create ibex_mem_intf_slave agent config obj + core_agent_cfg = ibex_icache_core_agent_cfg::type_id::create("core_agent_cfg"); + mem_agent_cfg = ibex_icache_mem_agent_cfg::type_id::create ("mem_agent_cfg"); endfunction endclass diff --git a/dv/uvm/icache/dv/env/ibex_icache_env_cov.sv b/dv/uvm/icache/dv/env/ibex_icache_env_cov.sv index 1ba11079..4089988a 100644 --- a/dv/uvm/icache/dv/env/ibex_icache_env_cov.sv +++ b/dv/uvm/icache/dv/env/ibex_icache_env_cov.sv @@ -8,7 +8,8 @@ * Covergroups may also be wrapped inside helper classes if needed. */ -class ibex_icache_env_cov extends dv_base_env_cov #(.CFG_T(ibex_icache_env_cfg)); +class ibex_icache_env_cov extends dv_base_env_cov #(.CFG_T (ibex_icache_env_cfg)); + `uvm_component_utils(ibex_icache_env_cov) // the base class provides the following handles for use: diff --git a/dv/uvm/icache/dv/env/ibex_icache_env_pkg.sv b/dv/uvm/icache/dv/env/ibex_icache_env_pkg.sv index 2974c197..1bc056ab 100644 --- a/dv/uvm/icache/dv/env/ibex_icache_env_pkg.sv +++ b/dv/uvm/icache/dv/env/ibex_icache_env_pkg.sv @@ -8,7 +8,7 @@ package ibex_icache_env_pkg; import top_pkg::*; import dv_utils_pkg::*; import ibex_icache_core_agent_pkg::*; - import ibex_mem_intf_agent_pkg::*; + import ibex_icache_mem_agent_pkg::*; import dv_lib_pkg::*; // macro includes @@ -18,7 +18,6 @@ package ibex_icache_env_pkg; // parameters // types - typedef dv_base_reg_block ibex_icache_reg_block; // functions diff --git a/dv/uvm/icache/dv/env/ibex_icache_scoreboard.sv b/dv/uvm/icache/dv/env/ibex_icache_scoreboard.sv index 26e881d1..5646fcb0 100644 --- a/dv/uvm/icache/dv/env/ibex_icache_scoreboard.sv +++ b/dv/uvm/icache/dv/env/ibex_icache_scoreboard.sv @@ -2,17 +2,16 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 -class ibex_icache_scoreboard extends dv_base_scoreboard #( - .CFG_T(ibex_icache_env_cfg), - .COV_T(ibex_icache_env_cov) - ); +class ibex_icache_scoreboard + extends dv_base_scoreboard #(.CFG_T(ibex_icache_env_cfg), .COV_T(ibex_icache_env_cov)); + `uvm_component_utils(ibex_icache_scoreboard) // local variables // TLM agent fifos - uvm_tlm_analysis_fifo #(ibex_icache_core_item) core_fifo; - uvm_tlm_analysis_fifo #(ibex_mem_intf_seq_item) mem_fifo; + uvm_tlm_analysis_fifo #(ibex_icache_core_item) core_fifo; + uvm_tlm_analysis_fifo #(ibex_icache_mem_resp_item) mem_fifo; `uvm_component_new @@ -29,12 +28,12 @@ class ibex_icache_scoreboard extends dv_base_scoreboard #( task run_phase(uvm_phase phase); super.run_phase(phase); fork - process_ibex_icache_fifo(); - process_ibex_mem_intf_slave_fifo(); + process_core_fifo(); + process_mem_fifo(); join_none endtask - virtual task process_ibex_icache_fifo(); + virtual task process_core_fifo(); ibex_icache_core_item item; forever begin core_fifo.get(item); @@ -42,8 +41,8 @@ class ibex_icache_scoreboard extends dv_base_scoreboard #( end endtask - virtual task process_ibex_mem_intf_slave_fifo(); - ibex_mem_intf_seq_item item; + virtual task process_mem_fifo(); + ibex_icache_mem_resp_item item; forever begin mem_fifo.get(item); `uvm_info(`gfn, $sformatf("received ibex_mem_intf_seq item:\n%0s", item.sprint()), UVM_HIGH) diff --git a/dv/uvm/icache/dv/env/ibex_icache_virtual_sequencer.sv b/dv/uvm/icache/dv/env/ibex_icache_virtual_sequencer.sv index 40bdd2ad..32a1e8ec 100644 --- a/dv/uvm/icache/dv/env/ibex_icache_virtual_sequencer.sv +++ b/dv/uvm/icache/dv/env/ibex_icache_virtual_sequencer.sv @@ -2,14 +2,12 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 -class ibex_icache_virtual_sequencer extends dv_base_virtual_sequencer #( - .CFG_T(ibex_icache_env_cfg), - .COV_T(ibex_icache_env_cov) - ); +class ibex_icache_virtual_sequencer + extends dv_base_virtual_sequencer #(.CFG_T(ibex_icache_env_cfg), .COV_T(ibex_icache_env_cov)); `uvm_component_utils(ibex_icache_virtual_sequencer) - ibex_icache_core_sequencer core_sequencer_h; - ibex_mem_intf_slave_sequencer mem_sequencer_h; + ibex_icache_core_sequencer core_sequencer_h; + ibex_icache_mem_sequencer mem_sequencer_h; `uvm_component_new diff --git a/dv/uvm/icache/dv/env/seq_lib/ibex_icache_base_vseq.sv b/dv/uvm/icache/dv/env/seq_lib/ibex_icache_base_vseq.sv index 09182e4c..3d6b30fd 100644 --- a/dv/uvm/icache/dv/env/seq_lib/ibex_icache_base_vseq.sv +++ b/dv/uvm/icache/dv/env/seq_lib/ibex_icache_base_vseq.sv @@ -2,7 +2,8 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 -class ibex_icache_base_vseq extends dv_base_vseq #( +class ibex_icache_base_vseq + extends dv_base_vseq #( .CFG_T (ibex_icache_env_cfg), .COV_T (ibex_icache_env_cov), .VIRTUAL_SEQUENCER_T (ibex_icache_virtual_sequencer) diff --git a/dv/uvm/icache/dv/env/seq_lib/ibex_icache_common_vseq.sv b/dv/uvm/icache/dv/env/seq_lib/ibex_icache_common_vseq.sv deleted file mode 100644 index 030f0a94..00000000 --- a/dv/uvm/icache/dv/env/seq_lib/ibex_icache_common_vseq.sv +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright lowRISC contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -class ibex_icache_common_vseq extends ibex_icache_base_vseq; - `uvm_object_utils(ibex_icache_common_vseq) - - constraint num_trans_c { - num_trans inside {[1:2]}; - } - `uvm_object_new - - virtual task body(); - // TODO: implement the body of the common virtual sequence - endtask : body - - -endclass diff --git a/dv/uvm/icache/dv/env/seq_lib/ibex_icache_sanity_vseq.sv b/dv/uvm/icache/dv/env/seq_lib/ibex_icache_sanity_vseq.sv index 6c0dbaf5..0764e376 100644 --- a/dv/uvm/icache/dv/env/seq_lib/ibex_icache_sanity_vseq.sv +++ b/dv/uvm/icache/dv/env/seq_lib/ibex_icache_sanity_vseq.sv @@ -5,18 +5,29 @@ // Basic sanity test class ibex_icache_sanity_vseq extends ibex_icache_base_vseq; - `uvm_object_utils(ibex_icache_sanity_vseq) + `uvm_object_utils(ibex_icache_sanity_vseq) `uvm_object_new - // A sanity sequence for the core agent + // A sanity sequence for the core agent and a basic slave sequence for the memory agent ibex_icache_core_sanity_seq core_seq; + ibex_icache_mem_resp_seq mem_seq; task body(); - // TODO: This currently just drives the core sequence (which clearly isn't going to work!) - `uvm_create_on(core_seq, p_sequencer.core_sequencer_h) - `DV_CHECK_RANDOMIZE_FATAL(core_seq) - core_seq.start(p_sequencer.core_sequencer_h); + // Start the core and memory sequences. We use fork/join_any so that we don't wait for the + // memory sequence (which is reactive so will never finish). + fork + begin + `uvm_create_on(core_seq, p_sequencer.core_sequencer_h) + `DV_CHECK_RANDOMIZE_FATAL(core_seq) + core_seq.start(p_sequencer.core_sequencer_h); + end + begin + `uvm_create_on(mem_seq, p_sequencer.mem_sequencer_h) + `DV_CHECK_RANDOMIZE_FATAL(mem_seq) + mem_seq.start(p_sequencer.mem_sequencer_h); + end + join_any endtask : body endclass : ibex_icache_sanity_vseq diff --git a/dv/uvm/icache/dv/env/seq_lib/ibex_icache_vseq_list.sv b/dv/uvm/icache/dv/env/seq_lib/ibex_icache_vseq_list.sv index 4a8ece41..ea3a00bf 100644 --- a/dv/uvm/icache/dv/env/seq_lib/ibex_icache_vseq_list.sv +++ b/dv/uvm/icache/dv/env/seq_lib/ibex_icache_vseq_list.sv @@ -4,4 +4,3 @@ `include "ibex_icache_base_vseq.sv" `include "ibex_icache_sanity_vseq.sv" -`include "ibex_icache_common_vseq.sv" diff --git a/dv/uvm/icache/dv/ibex_icache_mem_agent/README.md b/dv/uvm/icache/dv/ibex_icache_mem_agent/README.md new file mode 100644 index 00000000..03e57792 --- /dev/null +++ b/dv/uvm/icache/dv/ibex_icache_mem_agent/README.md @@ -0,0 +1,22 @@ +# ICache Memory UVM Agent + +The ICache memory UVM agent models the instruction memory bus downstream of the ICache. +This also includes the PMP machinery. + +The basic idea is that instruction memory is modelled with a single 32-bit *seed*. +A simple hash function takes this seed and calculates 32 bits of memory for each (aligned) base address. +The seed also determines a memory region which should result in PMP errors and another memory region that should result in memory errors. + +The agent exposes a slave interface to the core using the usual UVM architecture for a reactive slave, but it looks a little complicated because we need to spot PMP errors immediately (rather than on the next clock edge). +The entire dance is as follows: + + 1. The monitor spots a new request (either because of a posedge on the `req` line or a change in the `addr` line). + 1. It generates an `ibex_icache_mem_req_item` with `is_grant` field false and writes it to the sequencer's request port. + 1. This request gets picked up by the sequence (in `ibex_icache_mem_resp_seq.sv`). + 1. The sequence checks for a PMP error using its internal memory model and generates a sequence item (of type `ibex_icache_mem_resp_item`) with `is_grant` field false. + 1. This sequence item is picked up by the driver, which uses it to drive the PMP line appropriately. + 1. If the PMP response didn't squash the request, it will get granted at some point when the `grant` line goes high. At this point, the monitor will spot the request being granted and create another `ibex_icache_mem_req_item`, writing it to the sequencer's request port. This time, the `is_grant` field is true. + 1. This request in turn gets picked up by the sequence (in `ibex_icache_mem_resp_seq.sv`). + 1. The sequence uses its memory model to decide the data to be fetched and whether the response should have an error. The results get written into a sequence item with `is_grant` field true. + 1. When the driver picks up this sequence item, it adds it to a response queue. + 1. Responses get popped from the response queue in order. Each causes a delay of zero or more cycles and then the response is finally driven onto the bus with `rvalid`, `rdata` and `err`. diff --git a/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_agent.core b/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_agent.core new file mode 100644 index 00000000..24153eac --- /dev/null +++ b/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_agent.core @@ -0,0 +1,32 @@ +CAPI=2: +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "lowrisc:dv:ibex_icache_mem_agent:0.1" +description: "IBEX_ICACHE DV UVM agent" +filesets: + files_dv: + depend: + - lowrisc:dv:dv_utils + - lowrisc:dv:dv_lib + files: + - ibex_icache_mem_if.sv + - ibex_icache_mem_agent_pkg.sv + - ibex_icache_mem_req_item.sv: {is_include_file: true} + - ibex_icache_mem_resp_item.sv: {is_include_file: true} + - ibex_icache_mem_agent_cfg.sv: {is_include_file: true} + - ibex_icache_mem_agent_cov.sv: {is_include_file: true} + - ibex_icache_mem_driver.sv: {is_include_file: true} + - ibex_icache_mem_monitor.sv: {is_include_file: true} + - ibex_icache_mem_agent.sv: {is_include_file: true} + - ibex_icache_mem_sequencer.sv: {is_include_file: true} + - ibex_icache_mem_model.sv: {is_include_file: true} + - seq_lib/ibex_icache_mem_base_seq.sv: {is_include_file: true} + - seq_lib/ibex_icache_mem_resp_seq.sv: {is_include_file: true} + - seq_lib/ibex_icache_mem_seq_list.sv: {is_include_file: true} + file_type: systemVerilogSource + +targets: + default: + filesets: + - files_dv diff --git a/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_agent.sv b/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_agent.sv new file mode 100644 index 00000000..2addb58b --- /dev/null +++ b/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_agent.sv @@ -0,0 +1,32 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +class ibex_icache_mem_agent extends dv_base_agent #( + .CFG_T (ibex_icache_mem_agent_cfg), + .DRIVER_T (ibex_icache_mem_driver), + .SEQUENCER_T (ibex_icache_mem_sequencer), + .MONITOR_T (ibex_icache_mem_monitor), + .COV_T (ibex_icache_mem_agent_cov) +); + + `uvm_component_utils(ibex_icache_mem_agent) + `uvm_component_new + + function void build_phase(uvm_phase phase); + super.build_phase(phase); + // get ibex_icache_mem_if handle + if (!uvm_config_db#(virtual ibex_icache_mem_if)::get(this, "", "vif", cfg.vif)) begin + `uvm_fatal(`gfn, "failed to get ibex_icache_mem_if handle from uvm_config_db") + end + endfunction + + function void connect_phase(uvm_phase phase); + super.connect_phase(phase); + if (cfg.is_active) begin + // Pass snooped requests from the monitor to the sequencer + monitor.request_port.connect(sequencer.request_fifo.analysis_export); + end + endfunction + +endclass diff --git a/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_agent_cfg.sv b/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_agent_cfg.sv new file mode 100644 index 00000000..5ef36847 --- /dev/null +++ b/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_agent_cfg.sv @@ -0,0 +1,19 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +class ibex_icache_mem_agent_cfg extends dv_base_agent_cfg; + + // Knobs + bit disable_pmp_errs = 0; + bit disable_mem_errs = 0; + + // interface handle used by driver, monitor & the sequencer, via cfg handle + virtual ibex_icache_mem_if vif; + + `uvm_object_param_utils_begin(ibex_icache_mem_agent_cfg) + `uvm_object_utils_end + + `uvm_object_new + +endclass diff --git a/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_agent_cov.sv b/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_agent_cov.sv new file mode 100644 index 00000000..44bfa7fb --- /dev/null +++ b/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_agent_cov.sv @@ -0,0 +1,20 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +class ibex_icache_mem_agent_cov + extends dv_base_agent_cov #(.CFG_T (ibex_icache_mem_agent_cfg)); + + `uvm_component_utils(ibex_icache_mem_agent_cov) + + // the base class provides the following handles for use: + // ibex_icache_mem_agent_cfg: cfg + + // covergroups + + function new(string name, uvm_component parent); + super.new(name, parent); + // instantiate all covergroups here + endfunction : new + +endclass diff --git a/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_agent_pkg.sv b/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_agent_pkg.sv new file mode 100644 index 00000000..a2a1eefd --- /dev/null +++ b/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_agent_pkg.sv @@ -0,0 +1,29 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +package ibex_icache_mem_agent_pkg; + // dep packages + import uvm_pkg::*; + import dv_utils_pkg::*; + import dv_lib_pkg::*; + + // macro includes + `include "uvm_macros.svh" + `include "dv_macros.svh" + + // parameters + + // package sources + `include "ibex_icache_mem_req_item.sv" + `include "ibex_icache_mem_resp_item.sv" + `include "ibex_icache_mem_model.sv" + `include "ibex_icache_mem_agent_cfg.sv" + `include "ibex_icache_mem_agent_cov.sv" + `include "ibex_icache_mem_driver.sv" + `include "ibex_icache_mem_monitor.sv" + `include "ibex_icache_mem_sequencer.sv" + `include "ibex_icache_mem_agent.sv" + `include "ibex_icache_mem_seq_list.sv" + +endpackage: ibex_icache_mem_agent_pkg diff --git a/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_driver.sv b/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_driver.sv new file mode 100644 index 00000000..076b51ae --- /dev/null +++ b/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_driver.sv @@ -0,0 +1,136 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// Drive the memory <-> icache interface +// +// There are 3 different signals getting driven here: +// +// (1) GNT: This toggles randomly, completely ignoring any other signals. +// (2) PMP_ERR: This can be set as a result of taking a bad request. +// (3) RDATA: This gets set with response data some time after granting a request. + +class ibex_icache_mem_driver + extends dv_base_driver #(.ITEM_T (ibex_icache_mem_resp_item), + .CFG_T (ibex_icache_mem_agent_cfg)); + + int unsigned min_grant_delay = 0; + int unsigned max_grant_delay = 10; + + mailbox #(ibex_icache_mem_resp_item) rdata_queue; + bit pmp_driven; + + `uvm_component_utils(ibex_icache_mem_driver) + `uvm_component_new + + function void build_phase(uvm_phase phase); + super.build_phase(phase); + rdata_queue = new("rdata_queue"); + pmp_driven = 1'b0; + endfunction + + virtual task reset_signals(); + cfg.vif.reset(); + endtask + + virtual task get_and_drive(); + // None of these processes terminate + fork + drive_grant(); + take_requests(); + drive_responses(); + join + endtask + + // Drive the grant line. This toggles independently of any other signal on the bus. + task automatic drive_grant(); + int gnt_delay; + + forever begin + // Pick a number of cycles for the grant line to be low + `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(gnt_delay, + gnt_delay dist { + min_grant_delay :/ 3, + [min_grant_delay+1 : max_grant_delay-1] :/ 1, + max_grant_delay :/ 1 + };) + repeat(gnt_delay) @(cfg.vif.driver_cb); + + // Set the grant line high for a cycle then go around again. Note that the grant line will be + // high for two consecutive cycles if gnt_delay is 0. + cfg.vif.driver_cb.gnt <= 1'b1; + @(cfg.vif.driver_cb); + cfg.vif.driver_cb.gnt <= 1'b0; + end + endtask + + // Take requests from the sequencer. + task automatic take_requests(); + forever begin + seq_item_port.get_next_item(req); + `uvm_info(`gfn, $sformatf("rcvd item:\n%0s", req.sprint()), UVM_HIGH) + + // Is this a request or a grant? + if (!req.is_grant) begin + // If a request, we'll deal with it immediately, spawning a process that drives the PMP line + // until the request goes away. + fork + drive_pmp(req.err); + join_none + 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()); + rsp.set_id_info(req); + rdata_queue.put(rsp); + end + + seq_item_port.item_done(); + end + endtask + + // Drive the rdata/valid/err response lines + task automatic drive_responses(); + int unsigned delay; + ibex_icache_mem_resp_item item; + + forever begin + rdata_queue.get(item); + cfg.vif.wait_clks(item.delay); + cfg.vif.send_response(item.err, item.rdata); + end + endtask + + // Drive the PMP line. + // + // This task gets spawned by take_requests each time a new address comes in. The driver should + // have at most one instance running at once. + // + // If err is false, there is nothing to do. If err is true, it sets the PMP error flag and then + // waits until either req is de-asserted or the address changes, at which point it clears the flag + // and exits. + task automatic drive_pmp(bit err); + + // This is a simple check to make sure that only one instance of the drive_pmp task is running + // at a time. If not, you'll have multiple drivers for the cfg.vif.pmp_err signal, which is + // probably going to be very confusing. The logic in the monitor's collect_requests() task is + // supposed to be in sync with this code so that this can't happen, but it can't hurt to make + // sure. + if (pmp_driven) begin + `uvm_error(`gfn, "drive_pmp is not re-entrant: bug in monitor?") + return; + end + + if (! err) + return; + + pmp_driven = 1'b1; + cfg.vif.pmp_err <= 1'b1; + + // Wait for an address change or req to de-assert + @(negedge cfg.vif.req or cfg.vif.addr); + + cfg.vif.pmp_err <= 1'b0; + pmp_driven = 1'b0; + endtask + +endclass diff --git a/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_if.sv b/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_if.sv new file mode 100644 index 00000000..8fe15956 --- /dev/null +++ b/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_if.sv @@ -0,0 +1,72 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +interface ibex_icache_mem_if (input clk); + + // Requests + logic req; + logic gnt; + logic [31:0] addr; + + // PMP errors + logic pmp_err; + + // Response + logic rvalid; + logic [31:0] rdata; + logic err; + + // Clocking block used by the driver + default clocking driver_cb @(posedge clk); + default output negedge; + + output gnt; + + output pmp_err; + output rvalid; + output rdata; + output err; + endclocking + + // Clocking block used by the monitor + clocking monitor_cb @(posedge clk); + input req; + input gnt; + input addr; + + input pmp_err; + + input rvalid; + input rdata; + input err; + endclocking + + + // Reset all the signals from the memory bus to the cache (the other direction is controlled by + // the DUT). + task automatic reset(); + driver_cb.rvalid <= 1'b0; + driver_cb.pmp_err <= 1'b0; + driver_cb.gnt <= 1'b0; + endtask + + // Wait for num_clks posedges on the clk signal + task automatic wait_clks(int num_clks); + repeat (num_clks) @(driver_cb); + endtask + + // Drive a response with the given rdata and possible error signals for a single cycle + task automatic send_response(logic rsp_err, logic [31:0] rsp_rdata); + driver_cb.rvalid <= 1'b1; + driver_cb.err <= rsp_err; + driver_cb.rdata <= rsp_rdata; + + @(driver_cb); + + driver_cb.rvalid <= 1'b0; + driver_cb.err <= 'X; + driver_cb.rdata <= 'X; + endtask + +endinterface diff --git a/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_model.sv b/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_model.sv new file mode 100644 index 00000000..8d096c15 --- /dev/null +++ b/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_model.sv @@ -0,0 +1,131 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// A simple "memory model" governed by a single seed +// +// We pick a contiguous PMP range that covers ~1/8 of the address space. Set +// +// pmp_lo = seed ^ 32'hdeadbeef +// pmp_hi = pmp_lo + min(32'd1 << (32 - 3), (~32'd0) - pmp_lo) +// +// then the disallowed PMP range will be [pmp_lo, pmp_hi]. +// +// We'd like errors to be sparsely distributed in the address space, with 1/128 chance of any given +// address causing an error. We should probably do something more sensible, but for now let's XOR +// the address with something else (32'hf00dbeef) and pass it to the PMP calculation. +// +// For the memory content hash function, we use the first example from [1] (explicitly +// public-domain), except that we have 30+32 = 62 bits of input, which we just XOR together +// (aligning LSBs). +// +// [1] https://burtleburtle.net/bob/hash/integer.html + +class ibex_icache_mem_model #(parameter int unsigned BusWidth = 32) + extends uvm_object; + + protected bit [31:0] seed = 32'd0; + protected bit no_pmp_errs = 0; + protected bit no_mem_errs = 0; + + function new(string name="", bit disable_pmp_errs=0, bit disable_mem_errs=0); + no_pmp_errs = disable_pmp_errs; + no_mem_errs = disable_mem_errs; + endfunction + + `uvm_object_utils_begin(ibex_icache_mem_model) + `uvm_field_int (seed, UVM_DEFAULT | UVM_HEX) + `uvm_field_int (no_pmp_errs, UVM_DEFAULT) + `uvm_field_int (no_mem_errs, UVM_DEFAULT) + `uvm_object_utils_end + + function void set_seed(bit [31:0] new_seed); + seed = new_seed; + endfunction + + // Return true if reading from BusWidth bits from address should give an error + function automatic logic is_error(logic [31:0] address); + logic [31:0] rng_lo, rng_hi, rng_w0, rng_w1; + rng_lo = seed ^ 32'hdeadbeef; + rng_w0 = 32'd1 << (32 - 3); + rng_w1 = (~32'd0) - rng_lo; + rng_hi = rng_lo + ((rng_w0 < rng_w1) ? rng_w0 : rng_w1); + + return ranges_overlap(address, address + BusWidth / 8, rng_lo, rng_hi); + endfunction + + // Return true iff [lo0, hi0) and [lo1, hi1) have nonempty intersection + function automatic logic ranges_overlap(logic [31:0] lo0, logic [31:0] hi0, + logic [31:0] lo1, logic [31:0] hi1); + return (lo0 < hi1) && (lo1 < hi0); + endfunction + + // Return true if reading BusWidth bits from address should give a PMP error + function automatic logic is_pmp_error(logic [31:0] address); + return (! no_pmp_errs) && is_error(address ^ 32'h12344321); + endfunction + + // Return true if reading BusWidth bits from address should give a memory error + function automatic logic is_mem_error(logic [31:0] address); + return (! no_mem_errs) && is_error(address ^ 32'hf00dbeef); + endfunction + + // Return true if reading BusWidth bits from address should give some sort of error + function automatic logic is_either_error(logic [31:0] address); + return is_pmp_error(address) || is_mem_error(address); + endfunction + + // Return BusWidth bits of data from reading at address. + function automatic logic [BusWidth-1:0] read_data(logic [31:0] address); + logic [BusWidth-1:0] acc, word_data; + int word_count, lo_idx, lo_bit; + logic [29:0] word_addr; + + // The number of 32-bit words we have to read is the number of words in BusWidth, plus one if + // the address is not word-aligned. + word_count = ((BusWidth + 31) / 32) + ((address & 32'd3) ? 1 : 0); + + // The word address of the first word we're going to read. + word_addr = address >> 2; + + // The accumulator that we'll fill with bits of data + acc = 0; + + // The bottom bit that should be written to this iteration + lo_bit = 0; + + for (int i = 0; i < word_count; i++) begin + // Note that the address sum might wrap (if we read off the top of memory), but that's not + // really a problem. + word_data = 0; + word_data[31:0] = read_word(word_addr + i[29:0]); + + // The bottom valid byte in word_data is normally 0, but is positive if i is zero (the bottom) + // word and the read was misaligned. In that case, it equals i & 3. + lo_idx = (i > 0) ? 0 : (i & 3); + + // We don't bother tracking the top valid byte: our left shifts will just push anything extra + // off the top anyway. + acc = acc | (((word_data >> lo_idx) << lo_idx) << lo_bit); + + lo_bit = lo_bit + 32; + end + + return acc; + endfunction + + // Read 32 bits of data from reading at word_address. + function automatic logic [31:0] read_word(logic [29:0] address); + return hash({2'b0, address} ^ seed); + endfunction + + // A 32-bit to 32-bit hash function (see notes at top of file) + function automatic logic [31:0] hash(logic [31:0] in); + in = (in ^ 32'd61) ^ (in >> 16); + in = in + (in << 3); + in = in ^ (in >> 4); + in = in * 32'h27d4eb2d; + return in ^ (in >> 15); + endfunction + +endclass diff --git a/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_monitor.sv b/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_monitor.sv new file mode 100644 index 00000000..56a26188 --- /dev/null +++ b/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_monitor.sv @@ -0,0 +1,92 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +class ibex_icache_mem_monitor + extends dv_base_monitor #(.ITEM_T (ibex_icache_mem_resp_item), + .CFG_T (ibex_icache_mem_agent_cfg), + .COV_T (ibex_icache_mem_agent_cov)); + + `uvm_component_utils(ibex_icache_mem_monitor) + `uvm_component_new + + // the base class provides the following handles for use: + // ibex_icache_mem_agent_cfg: cfg + // ibex_icache_mem_agent_cov: cov + // uvm_analysis_port #(ibex_icache_resp_item): analysis_port + + // Incoming requests. This gets hooked up to the sequencer to service requests + uvm_analysis_port #(ibex_icache_mem_req_item) request_port; + + function automatic void build_phase(uvm_phase phase); + super.build_phase(phase); + request_port = new("request_port", this); + endfunction + + task run_phase(uvm_phase phase); + super.run_phase(phase); + endtask + + // Collect transactions forever. Forked in dv_base_moditor::run_phase + protected task automatic collect_trans(uvm_phase phase); + fork + collect_requests(); + collect_grants(); + join + endtask + + // The collect_requests monitor is in charge of spotting changes to instr_addr_o when the req + // line is high + // + // This must collect the "I have a new address request" immediately, rather than at the next clock + // edge, to make sure that a PMP error can be signalled in the same cycle. + // + // Note that it's possible the underlying memory seed will change after the request has been seen. + // We don't try to spot this, and instead report the error state based on the seed when the + // request appeared. + task automatic collect_requests(); + forever begin + // Wait for either a posedge on req or any change to the address + @(posedge cfg.vif.req or cfg.vif.addr); + + // If the req line is high, pass the "new address" request to the driver + if (cfg.vif.req) + new_request(cfg.vif.addr); + end + endtask + + // The collect_grants monitor is in charge of spotting granted requests which haven't been + // squashed by a PMP error, passing them back to the driver ("Hey, you granted this. Time to + // service it!") + task automatic collect_grants(); + logic pending_req = 1'b0; + + forever begin + if (cfg.vif.monitor_cb.req & cfg.vif.monitor_cb.gnt & !cfg.vif.monitor_cb.pmp_err) + new_grant(cfg.vif.monitor_cb.addr); + + @(cfg.vif.monitor_cb); + end + endtask + + // This is called immediately when an address is requested and is used to drive the PMP response + function automatic void new_request(logic [31:0] addr); + ibex_icache_mem_req_item item = new("item"); + + item.is_grant = 1'b0; + item.address = addr; + item.seed = '0; + request_port.write(item); + endfunction + + // This is called on a clock edge when an request is granted + function automatic void new_grant(logic [31:0] addr); + ibex_icache_mem_req_item item = new("item"); + + item.is_grant = 1'b1; + item.address = addr; + `DV_CHECK_RANDOMIZE_FATAL(item) + request_port.write(item); + endfunction + +endclass diff --git a/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_req_item.sv b/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_req_item.sv new file mode 100644 index 00000000..87c5e452 --- /dev/null +++ b/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_req_item.sv @@ -0,0 +1,37 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// An item that represents a memory request from the icache and a possible update to the backing +// memory. +// +// When a request first comes in (via a posedge on the req line), it immediately generates a +// req_item with is_grant = 0. This is used by the driver to decide whether to generate a PMP error. +// +// Assuming that the request wasn't squashed by a PMP error, it will be granted on some later clock +// edge. At that point, another req_item is generated with is_grant = 1. This is added to a queue in +// the driver and will be serviced at some later point. This item may also have a seed update. + +class ibex_icache_mem_req_item extends uvm_sequence_item; + + bit is_grant; + logic [31:0] address; + + rand bit [31:0] seed; + + // Change the memory seed roughly one time in 500 reads + constraint c_seed_dist { + seed dist { + 32'd0 :/ 499, + [1:32'hffffffff] :/ 1 + }; + } + + `uvm_object_utils_begin(ibex_icache_mem_req_item) + `uvm_field_int (is_grant, UVM_DEFAULT) + `uvm_field_int (address, UVM_DEFAULT | UVM_HEX) + `uvm_field_int (seed, UVM_DEFAULT | UVM_HEX) + `uvm_object_utils_end + + `uvm_object_new +endclass diff --git a/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_resp_item.sv b/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_resp_item.sv new file mode 100644 index 00000000..06a24cf3 --- /dev/null +++ b/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_resp_item.sv @@ -0,0 +1,50 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// An item that represents a memory response to the icache + +class ibex_icache_mem_resp_item + extends uvm_sequence_item; + + int unsigned min_response_delay = 0; + int unsigned mid_response_delay = 5; + int unsigned max_response_delay = 50; + + // True if this is a granted request. Otherwise, this is the first time we've seen an address (and + // we might need to drive the PMP line). + bit is_grant; + + // If true, drive either a PMP error (if !is_grant) or respond later with a memory error. + bit err; + + // Only has an effect if is_grant. The number of cycles to wait between reading this from the + // queue and responding with it. + rand int unsigned delay; + + // Only has an effect if is_grant. The memory data to reply with (will be 'X if err is set) + logic [31:0] rdata; + + constraint c_delay_dist { + delay dist { + min_response_delay :/ 5, + [min_response_delay+1:mid_response_delay] :/ 5, + [mid_response_delay+1:max_response_delay] :/ 1 + }; + } + + // The delay field has no effect for requests (i.e. if is_grant is false). Force it to zero rather + // than leave mysterious numbers in the logs. + constraint c_no_delay_for_req { + (!is_grant) -> delay == 0; + } + + `uvm_object_utils_begin(ibex_icache_mem_resp_item) + `uvm_field_int (is_grant, UVM_DEFAULT) + `uvm_field_int (err, UVM_DEFAULT) + `uvm_field_int (delay, UVM_DEFAULT) + `uvm_field_int (rdata, UVM_DEFAULT | UVM_HEX) + `uvm_object_utils_end + + `uvm_object_new +endclass diff --git a/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_sequencer.sv b/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_sequencer.sv new file mode 100644 index 00000000..73647259 --- /dev/null +++ b/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_sequencer.sv @@ -0,0 +1,21 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// A sequencer class for the icache memory agent. + +class ibex_icache_mem_sequencer + extends dv_base_sequencer #(.ITEM_T (ibex_icache_mem_resp_item), + .CFG_T (ibex_icache_mem_agent_cfg)); + + `uvm_component_utils(ibex_icache_mem_sequencer) + `uvm_component_new + + uvm_tlm_analysis_fifo #(ibex_icache_mem_req_item) request_fifo; + + function void build_phase(uvm_phase phase); + super.build_phase(phase); + request_fifo = new("request_fifo", this); + endfunction + +endclass diff --git a/dv/uvm/icache/dv/ibex_icache_mem_agent/seq_lib/ibex_icache_mem_base_seq.sv b/dv/uvm/icache/dv/ibex_icache_mem_agent/seq_lib/ibex_icache_mem_base_seq.sv new file mode 100644 index 00000000..5c1eafca --- /dev/null +++ b/dv/uvm/icache/dv/ibex_icache_mem_agent/seq_lib/ibex_icache_mem_base_seq.sv @@ -0,0 +1,17 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +class ibex_icache_mem_base_seq + extends dv_base_seq #(.REQ (ibex_icache_mem_resp_item), + .CFG_T (ibex_icache_mem_agent_cfg), + .SEQUENCER_T (ibex_icache_mem_sequencer)); + `uvm_object_utils(ibex_icache_mem_base_seq) + + `uvm_object_new + + virtual task body(); + `uvm_fatal(`gtn, "Need to override this when you extend from this class!") + endtask + +endclass diff --git a/dv/uvm/icache/dv/ibex_icache_mem_agent/seq_lib/ibex_icache_mem_resp_seq.sv b/dv/uvm/icache/dv/ibex_icache_mem_agent/seq_lib/ibex_icache_mem_resp_seq.sv new file mode 100644 index 00000000..56458c22 --- /dev/null +++ b/dv/uvm/icache/dv/ibex_icache_mem_agent/seq_lib/ibex_icache_mem_resp_seq.sv @@ -0,0 +1,59 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// Slave response sequence + +class ibex_icache_mem_resp_seq extends ibex_icache_mem_base_seq; + + ibex_icache_mem_model #(.BusWidth (32)) mem_model; + + `uvm_object_utils(ibex_icache_mem_resp_seq) + `uvm_object_new + + task pre_start(); + super.pre_start(); + mem_model = new("mem_model", cfg.disable_pmp_errs, cfg.disable_mem_errs); + endtask + + task body(); + ibex_icache_mem_req_item req_item = new("req_item"); + ibex_icache_mem_resp_item resp_item = new("resp_item"); + + forever begin + // Wait for a transaction request. + p_sequencer.request_fifo.get(req_item); + + if (!req_item.is_grant) begin + // If this is a request (not a grant), check the memory model for a PMP error at this + // address. The other fields are ignored. + resp_item.is_grant = 1'b0; + resp_item.err = mem_model.is_pmp_error(req_item.address); + resp_item.rdata = 'X; + `uvm_info(`gfn, + $sformatf("Seen request at address 0x%08h (PMP error? %0d)", + req_item.address, resp_item.err), + UVM_LOW) + + end else begin + // If this is a grant, take any new seed then check the memory model for a (non-PMP) error + // at this address. On success, look up the memory data too. + + if (req_item.seed != 32'd0) begin + `uvm_info(`gfn, $sformatf("New memory seed: 0x%08h", req_item.seed), UVM_HIGH) + mem_model.set_seed(req_item.seed); + end + + resp_item.is_grant = 1'b1; + resp_item.err = mem_model.is_mem_error(req_item.address); + resp_item.rdata = resp_item.err ? 'X : mem_model.read_data(req_item.address); + end + + // Use the response item as an entry in the sequence, randomising any delay + start_item(resp_item); + `DV_CHECK_RANDOMIZE_FATAL(resp_item) + finish_item(resp_item); + end + endtask + +endclass diff --git a/dv/uvm/icache/dv/ibex_icache_mem_agent/seq_lib/ibex_icache_mem_seq_list.sv b/dv/uvm/icache/dv/ibex_icache_mem_agent/seq_lib/ibex_icache_mem_seq_list.sv new file mode 100644 index 00000000..bfdf6012 --- /dev/null +++ b/dv/uvm/icache/dv/ibex_icache_mem_agent/seq_lib/ibex_icache_mem_seq_list.sv @@ -0,0 +1,6 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +`include "ibex_icache_mem_base_seq.sv" +`include "ibex_icache_mem_resp_seq.sv" diff --git a/dv/uvm/icache/dv/ibex_icache_sim_cfg.hjson b/dv/uvm/icache/dv/ibex_icache_sim_cfg.hjson index 5face15c..90b722fb 100644 --- a/dv/uvm/icache/dv/ibex_icache_sim_cfg.hjson +++ b/dv/uvm/icache/dv/ibex_icache_sim_cfg.hjson @@ -42,7 +42,7 @@ { name: ibex_icache_sanity uvm_test_seq: ibex_icache_sanity_vseq - run_opts: ["+test_timeout_ns=10000"] + run_opts: ["+test_timeout_ns=1000000"] } // TODO: add more tests here diff --git a/dv/uvm/icache/dv/tb/tb.sv b/dv/uvm/icache/dv/tb/tb.sv index dc15e309..c85bcd2b 100644 --- a/dv/uvm/icache/dv/tb/tb.sv +++ b/dv/uvm/icache/dv/tb/tb.sv @@ -17,8 +17,9 @@ module tb; // interfaces clk_rst_if clk_rst_if(.clk(clk), .rst_n(rst_n)); + ibex_icache_core_if core_if (.clk(clk)); - ibex_mem_intf ibex_mem_intf(); + ibex_icache_mem_if mem_if (.clk(clk)); // dut ibex_icache dut ( @@ -37,17 +38,24 @@ module tb; .err_plus2_o (core_if.err_plus2), .icache_enable_i (core_if.enable), .icache_inval_i (core_if.invalidate), - .busy_o (core_if.busy) + .busy_o (core_if.busy), - // TODO: add remaining IOs and hook them + // Connect icache <-> instruction bus interface + .instr_req_o (mem_if.req), + .instr_gnt_i (mem_if.gnt), + .instr_addr_o (mem_if.addr), + .instr_rdata_i (mem_if.rdata), + .instr_err_i (mem_if.err), + .instr_pmp_err_i (mem_if.pmp_err), + .instr_rvalid_i (mem_if.rvalid) ); initial begin // drive clk and rst_n from clk_if clk_rst_if.set_active(); uvm_config_db#(virtual clk_rst_if)::set(null, "*.env", "clk_rst_vif", clk_rst_if); - uvm_config_db#(virtual ibex_icache_core_if)::set(null, "*.env.m_ibex_icache_core_agent*", "vif", core_if); - uvm_config_db#(virtual ibex_mem_intf)::set(null, "*.env.m_ibex_mem_intf_slave_agent*", "vif", ibex_mem_intf); + uvm_config_db#(virtual ibex_icache_core_if)::set(null, "*.env.core_agent*", "vif", core_if); + uvm_config_db#(virtual ibex_icache_mem_if)::set(null, "*.env.mem_agent*", "vif", mem_if); $timeformat(-12, 0, " ps", 12); run_test(); end