From 488f535ab2823365713e27c7401e4f8483a42602 Mon Sep 17 00:00:00 2001 From: Canberk Topal Date: Tue, 20 Sep 2022 12:23:03 +0100 Subject: [PATCH 1/8] [ibex,dv] Switch to new sequence for memory errors Signed-off-by: Canberk Topal --- .../core_ibex/tests/core_ibex_new_seq_lib.sv | 8 +- dv/uvm/core_ibex/tests/core_ibex_test_lib.sv | 104 ++++-------------- 2 files changed, 23 insertions(+), 89 deletions(-) diff --git a/dv/uvm/core_ibex/tests/core_ibex_new_seq_lib.sv b/dv/uvm/core_ibex/tests/core_ibex_new_seq_lib.sv index 6b372ea5d3..066697a550 100644 --- a/dv/uvm/core_ibex/tests/core_ibex_new_seq_lib.sv +++ b/dv/uvm/core_ibex/tests/core_ibex_new_seq_lib.sv @@ -72,6 +72,7 @@ class core_base_new_seq #(type REQ = uvm_sequence_item) extends uvm_sequence #(R `DV_CHECK_FATAL(iteration_cnt != 0) `uvm_info(`gfn, $sformatf("Number of stimulus iterations = %0d", iteration_cnt), UVM_LOW) for (int i = 0; i <= iteration_cnt; i++) begin + `uvm_info(`gfn, $sformatf("Running %0d/%0d", i, iteration_cnt), UVM_LOW) drive_stimulus(); end end @@ -198,7 +199,7 @@ class debug_new_seq extends core_base_new_seq#(irq_seq_item); endclass -class memory_error_seq extends core_base_new_seq#(irq_seq_item); +class memory_error_seq extends core_base_new_seq#(ibex_mem_intf_seq_item); core_ibex_vseq vseq; rand bit choose_side; bit start_seq = 0; // Use this bit to start any unique sequence once @@ -210,7 +211,6 @@ class memory_error_seq extends core_base_new_seq#(irq_seq_item); function new (string name = ""); super.new(name); - vseq = core_ibex_vseq::type_id::create("vseq"); endfunction virtual task send_req(); @@ -233,10 +233,6 @@ class memory_error_seq extends core_base_new_seq#(irq_seq_item); // DO nothing end endcase - if(!start_seq) begin - vseq.start(p_sequencer); - start_seq = 1; - end endtask endclass: memory_error_seq diff --git a/dv/uvm/core_ibex/tests/core_ibex_test_lib.sv b/dv/uvm/core_ibex/tests/core_ibex_test_lib.sv index d4dc0a1311..4941f7880f 100644 --- a/dv/uvm/core_ibex/tests/core_ibex_test_lib.sv +++ b/dv/uvm/core_ibex/tests/core_ibex_test_lib.sv @@ -1167,93 +1167,31 @@ class core_ibex_mem_error_test extends core_ibex_directed_test; `uvm_component_utils(core_ibex_mem_error_test) `uvm_component_new - int err_delay; - - // check memory error inputs and verify that core jumps to correct exception handler virtual task check_stimulus(); - forever begin - while (!vseq.data_intf_seq.get_error_synch()) begin - clk_vif.wait_clks(1); + memory_error_seq memory_error_seq_h; + memory_error_seq_h = memory_error_seq::type_id::create("memory_error_seq_h", this); + + `uvm_info(`gfn, "Running core_ibex_mem_error_test", UVM_LOW) + memory_error_seq_h.vseq = vseq; + memory_error_seq_h.iteration_modes = InfiniteRuns; + memory_error_seq_h.stimulus_delay_cycles_min = 800; // Interval between injected errors + memory_error_seq_h.stimulus_delay_cycles_max = 5000; + fork + begin + forever begin + memory_error_seq_h.start(env.vseqr); + // Wait until we are out of IRQ handler to the inject errors + wait_ret("mret", 20000); + end end - vseq.data_intf_seq.inject_error(); - `uvm_info(`gfn, "Injected dmem error", UVM_LOW) - // Dmem interface error could be either a load or store operation - check_dmem_fault(); - // Random delay before injecting instruction fetch fault - `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(err_delay, err_delay inside { [50:200] };) - clk_vif.wait_clks(err_delay); - inject_imem_error(); - check_imem_fault(); - // Random delay before injecting this series of errors again - `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(err_delay, err_delay inside { [250:750] };) - clk_vif.wait_clks(err_delay); - end - endtask - - virtual task inject_imem_error(); - while (!vseq.instr_intf_seq.get_error_synch()) begin - clk_vif.wait_clks(1); - end - `uvm_info(`gfn, "Injecting imem fault", UVM_LOW) - vseq.instr_intf_seq.inject_error(); - endtask - - virtual task check_dmem_fault(); - bit[ibex_mem_intf_agent_pkg::DATA_WIDTH-1:0] mcause; - core_status_t mem_status; - ibex_pkg::exc_cause_t exc_type; - // Don't impose a timeout period for dmem check, since dmem errors injected by the sequence are - // not guaranteed to be reflected in RTL state until the next memory instruction is executed, - // and the frequency of which is not controllable by the testbench - check_next_core_status(HANDLING_EXCEPTION, "Core did not jump to exception handler"); - check_priv_mode(PRIV_LVL_M); - // Next write of CORE_STATUS will be the load/store fault type - wait_for_mem_txn(cfg.signature_addr, CORE_STATUS); - mem_status = core_status_t'(signature_data_q.pop_front()); - if (mem_status == LOAD_FAULT_EXCEPTION) begin - exc_type = ExcCauseLoadAccessFault; - end else if (mem_status == STORE_FAULT_EXCEPTION) begin - exc_type = ExcCauseStoreAccessFault; - end - check_mcause(1'b0, exc_type.lower_cause); - wait (dut_vif.dut_cb.mret === 1'b1); - `uvm_info(`gfn, "exiting mem fault checker", UVM_LOW) - endtask - - virtual task check_imem_fault(); - bit latched_imem_err = 1'b0; - core_status_t mem_status; - ibex_pkg::exc_cause_t exc_type; - // Need to account for case where imem_error is asserted during an instruction fetch that gets - // killed - due to jumps and control flow changes - do begin - fork - begin - fork : imem_fork - begin - check_next_core_status(HANDLING_EXCEPTION, "Core did not jump to exception handler"); - check_priv_mode(PRIV_LVL_M); - latched_imem_err = 1'b1; - `uvm_info(`gfn, $sformatf("latched_imem_err: 0x%0x", latched_imem_err), UVM_LOW) - end - begin - clk_vif.wait_clks(5000); - end - join_any - disable fork; + begin + forever begin + wait_for_core_status(HANDLING_IRQ); + // Do not allow error injection while we are handling IRQ + memory_error_seq_h.stop(); end - join - if (latched_imem_err === 1'b0) begin - cur_run_phase.drop_objection(this); - inject_imem_error(); end - end while (latched_imem_err === 1'b0); - check_next_core_status(INSTR_FAULT_EXCEPTION, - "Core did not register correct memory fault type", 5000); - exc_type = ExcCauseInstrAccessFault; - check_mcause(1'b0, exc_type.lower_cause); - wait (dut_vif.dut_cb.mret === 1'b1); - `uvm_info(`gfn, "exiting mem fault checker", UVM_LOW) + join_none endtask endclass From 653b97e9e3863c5d878d5508fe9ebf8057b5d0e4 Mon Sep 17 00:00:00 2001 From: Canberk Topal Date: Sun, 16 Oct 2022 03:30:03 +0100 Subject: [PATCH 2/8] [dv] Don't inject mem errors at test_control_addr This will prevent seeing mismatches right at the end of our test. Before this change, mem_error_test could inject error at the store instruction in which we finish up the test, resulting with mismatches with Spike and Ibex on the instructions after finishing. Also do the same prevention for signature_addr as well, since we also don't want to corrupt that memory transaction too. Signed-off-by: Canberk Topal --- .../ibex_mem_intf_agent/ibex_mem_intf_response_seq_lib.sv | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dv/uvm/core_ibex/common/ibex_mem_intf_agent/ibex_mem_intf_response_seq_lib.sv b/dv/uvm/core_ibex/common/ibex_mem_intf_agent/ibex_mem_intf_response_seq_lib.sv index d5f5a0dc0a..0e4276fabb 100644 --- a/dv/uvm/core_ibex/common/ibex_mem_intf_agent/ibex_mem_intf_response_seq_lib.sv +++ b/dv/uvm/core_ibex/common/ibex_mem_intf_agent/ibex_mem_intf_response_seq_lib.sv @@ -60,6 +60,11 @@ class ibex_mem_intf_response_seq extends uvm_sequence #(ibex_mem_intf_seq_item); enable_error = 1'b0; error_synch = 1'b1; aligned_addr = {req.addr[DATA_WIDTH-1:2], 2'b0}; + // Do not inject any error to the handshake test_control_addr + // TODO: Parametrize this. Until then, this needs to be changed manually. + if (aligned_addr inside {32'h8ffffff8, 32'h8ffffffc}) begin + req.error = 1'b0; + end if (req.error) begin `DV_CHECK_STD_RANDOMIZE_FATAL(rand_data) req.data = rand_data; From 2fb358842ee2da61c665d3e567aee05b74af00d4 Mon Sep 17 00:00:00 2001 From: Canberk Topal Date: Thu, 20 Oct 2022 17:45:43 +0100 Subject: [PATCH 3/8] Fix-up new_seq_lib to start after stopping Signed-off-by: Canberk Topal --- dv/uvm/core_ibex/tests/core_ibex_new_seq_lib.sv | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dv/uvm/core_ibex/tests/core_ibex_new_seq_lib.sv b/dv/uvm/core_ibex/tests/core_ibex_new_seq_lib.sv index 066697a550..a4bec9ddce 100644 --- a/dv/uvm/core_ibex/tests/core_ibex_new_seq_lib.sv +++ b/dv/uvm/core_ibex/tests/core_ibex_new_seq_lib.sv @@ -63,6 +63,8 @@ class core_base_new_seq #(type REQ = uvm_sequence_item) extends uvm_sequence #(R `uvm_info(`gfn, $sformatf("Running the \"%s\" schedule for stimulus generation", iteration_modes.name()), UVM_LOW) + stop_seq = 1'b0; + seq_finished = 1'b0; case (iteration_modes) SingleRun: begin drive_stimulus(); From f22983e9fbef3ddd866d0d557864e55c1d309852 Mon Sep 17 00:00:00 2001 From: Canberk Topal Date: Tue, 20 Sep 2022 12:37:14 +0100 Subject: [PATCH 4/8] [ibex,dv] Add new test for memory integrity errors This test picks between inserting an integrity error or a bus error to the response in the case of a memory request from Ibex. Introduces a control knob `enable_mem_intg_err` which can control the rate of having integrity errors per request. This commit also disables checking for double fault alerts in the scoreboard because they're expected to be seen while simulating and they don't cause infinite loop problems because every time a memory response is requested the error causing part is just randomized. That means Ibex trying to execute same instruction again would have a chance to succeed this time. Signed-off-by: Canberk Topal --- .../ibex_mem_intf_response_seq_lib.sv | 11 ++++++- dv/uvm/core_ibex/env/core_ibex_env_cfg.sv | 3 ++ .../riscv_dv_extension/testlist.yaml | 21 ++++++++++++ dv/uvm/core_ibex/tb/core_ibex_tb_top.sv | 3 +- .../core_ibex/tests/core_ibex_new_seq_lib.sv | 33 ++++++++++++++++--- dv/uvm/core_ibex/tests/core_ibex_test_lib.sv | 1 + 6 files changed, 66 insertions(+), 6 deletions(-) diff --git a/dv/uvm/core_ibex/common/ibex_mem_intf_agent/ibex_mem_intf_response_seq_lib.sv b/dv/uvm/core_ibex/common/ibex_mem_intf_agent/ibex_mem_intf_response_seq_lib.sv index 0e4276fabb..deacdf73a2 100644 --- a/dv/uvm/core_ibex/common/ibex_mem_intf_agent/ibex_mem_intf_response_seq_lib.sv +++ b/dv/uvm/core_ibex/common/ibex_mem_intf_agent/ibex_mem_intf_response_seq_lib.sv @@ -10,6 +10,7 @@ class ibex_mem_intf_response_seq extends uvm_sequence #(ibex_mem_intf_seq_item); ibex_mem_intf_seq_item item; mem_model m_mem; + bit enable_intg_error = 1'b0; bit enable_error = 1'b0; // Used to ensure that whenever inject_error() is called, the very next transaction will inject an // error, and that enable_error will not be flipped back to 0 immediately @@ -64,6 +65,7 @@ class ibex_mem_intf_response_seq extends uvm_sequence #(ibex_mem_intf_seq_item); // TODO: Parametrize this. Until then, this needs to be changed manually. if (aligned_addr inside {32'h8ffffff8, 32'h8ffffffc}) begin req.error = 1'b0; + enable_intg_error = 1'b0; end if (req.error) begin `DV_CHECK_STD_RANDOMIZE_FATAL(rand_data) @@ -90,7 +92,10 @@ class ibex_mem_intf_response_seq extends uvm_sequence #(ibex_mem_intf_seq_item); // If data_was_uninitialized is true then we want to force bad integrity bits: invert the // correct ones, which we know will break things for the codes we use. - if (data_was_uninitialized) req.intg = ~req.intg; + if (data_was_uninitialized || enable_intg_error) begin + req.intg = ~req.intg; + enable_intg_error = 1'b0; + end `uvm_info(get_full_name(), $sformatf("Response transfer:\n%0s", req.sprint()), UVM_HIGH) start_item(req); @@ -111,6 +116,10 @@ class ibex_mem_intf_response_seq extends uvm_sequence #(ibex_mem_intf_seq_item); this.enable_error = 1'b1; endfunction + virtual function void inject_intg_error(); + this.enable_intg_error = 1'b1; + endfunction + virtual function bit get_error_synch(); return this.error_synch; endfunction diff --git a/dv/uvm/core_ibex/env/core_ibex_env_cfg.sv b/dv/uvm/core_ibex/env/core_ibex_env_cfg.sv index a717c8a7c7..fba3b1bb49 100644 --- a/dv/uvm/core_ibex/env/core_ibex_env_cfg.sv +++ b/dv/uvm/core_ibex/env/core_ibex_env_cfg.sv @@ -7,6 +7,7 @@ class core_ibex_env_cfg extends uvm_object; virtual clk_rst_if ibex_clk_vif; virtual core_ibex_dut_probe_if ibex_dut_vif; + bit enable_mem_intg_err; bit enable_irq_single_seq; bit enable_irq_multiple_seq; bit enable_irq_nmi_seq; @@ -31,6 +32,7 @@ class core_ibex_env_cfg extends uvm_object; `uvm_object_utils_begin(core_ibex_env_cfg) `uvm_field_int(enable_double_fault_detector, UVM_DEFAULT) `uvm_field_int(is_double_fault_detected_fatal, UVM_DEFAULT) + `uvm_field_int(enable_mem_intg_err, UVM_DEFAULT) `uvm_field_int(enable_irq_single_seq, UVM_DEFAULT) `uvm_field_int(enable_irq_multiple_seq, UVM_DEFAULT) `uvm_field_int(enable_irq_nmi_seq, UVM_DEFAULT) @@ -48,6 +50,7 @@ class core_ibex_env_cfg extends uvm_object; super.new(name); void'($value$plusargs("enable_double_fault_detector=%0d", enable_double_fault_detector)); void'($value$plusargs("is_double_fault_detected_fatal=%0d", is_double_fault_detected_fatal)); + void'($value$plusargs("enable_mem_intg_err=%0d", enable_mem_intg_err)); void'($value$plusargs("enable_irq_single_seq=%0d", enable_irq_single_seq)); void'($value$plusargs("enable_irq_multiple_seq=%0d", enable_irq_multiple_seq)); void'($value$plusargs("enable_irq_nmi_seq=%0d", enable_irq_nmi_seq)); diff --git a/dv/uvm/core_ibex/riscv_dv_extension/testlist.yaml b/dv/uvm/core_ibex/riscv_dv_extension/testlist.yaml index 4d126337b5..792d196141 100644 --- a/dv/uvm/core_ibex/riscv_dv_extension/testlist.yaml +++ b/dv/uvm/core_ibex/riscv_dv_extension/testlist.yaml @@ -549,6 +549,27 @@ +suppress_pmp_setup=1 rtl_test: core_ibex_mem_error_test sim_opts: > + +enable_mem_intg_err=0 + +enable_double_fault_detector=0 + +require_signature_addr=1 + compare_opts: + compare_final_value_only: 1 + +- test: riscv_mem_intg_error_test + description: > + Normal random instruction test, but randomly insert memory load/store integrity errors + iterations: 15 + gen_test: riscv_rand_instr_test + gen_opts: > + +require_signature_addr=1 + +instr_cnt=10000 + +randomize_csr=1 + +enable_unaligned_load_store=1 + +suppress_pmp_setup=1 + rtl_test: core_ibex_mem_error_test + sim_opts: > + +enable_mem_intg_err=1 + +enable_double_fault_detector=0 +require_signature_addr=1 compare_opts: compare_final_value_only: 1 diff --git a/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv b/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv index 3962609ca0..580deefdef 100644 --- a/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv +++ b/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv @@ -158,8 +158,9 @@ module core_ibex_tb_top; ); // We should never see any alerts triggered in normal testing - `ASSERT(NoAlertsTriggered, + `ASSERT(NoAlertsTriggered_A, !dut_if.alert_minor && !dut_if.alert_major_internal && !dut_if.alert_major_bus, clk, !rst_n) + `DV_ASSERT_CTRL("NoAlertsTriggered", core_ibex_tb_top.NoAlertsTriggered_A) // Data load/store vif connection assign data_mem_vif.reset = ~rst_n; diff --git a/dv/uvm/core_ibex/tests/core_ibex_new_seq_lib.sv b/dv/uvm/core_ibex/tests/core_ibex_new_seq_lib.sv index a4bec9ddce..ed14ad0dcd 100644 --- a/dv/uvm/core_ibex/tests/core_ibex_new_seq_lib.sv +++ b/dv/uvm/core_ibex/tests/core_ibex_new_seq_lib.sv @@ -207,6 +207,13 @@ class memory_error_seq extends core_base_new_seq#(ibex_mem_intf_seq_item); bit start_seq = 0; // Use this bit to start any unique sequence once rand error_type_e err_type = PickErr; + rand bit inject_intg_err; + // CONTROL_KNOB: Configure the rate between seeing an integrity error versus seeing a bus error. + int unsigned intg_err_pct = 50; + constraint inject_intg_err_c { + inject_intg_err dist {1 :/ intg_err_pct, + 0 :/ 100 - intg_err_pct}; + } `uvm_object_utils(memory_error_seq) `uvm_declare_p_sequencer(core_ibex_vseqr) @@ -216,14 +223,18 @@ class memory_error_seq extends core_base_new_seq#(ibex_mem_intf_seq_item); endfunction virtual task send_req(); - case (err_type) - IsideErr: begin + `DV_CHECK_MEMBER_RANDOMIZE_FATAL(inject_intg_err) + // If we expect to see only bus errors, we can enable this assertion. Otherwise + // integrity errors would cause alerts to trigger. + `DV_ASSERT_CTRL_REQ("NoAlertsTriggered", intg_err_pct == 0) + case ({err_type, inject_intg_err}) + {IsideErr, 1'b0}: begin vseq.instr_intf_seq.inject_error(); end - DsideErr: begin + {DsideErr, 1'b0}: begin vseq.data_intf_seq.inject_error(); end - PickErr: begin + {PickErr, 1'b0}: begin `DV_CHECK_STD_RANDOMIZE_FATAL(choose_side) if (choose_side) begin vseq.instr_intf_seq.inject_error(); @@ -231,6 +242,20 @@ class memory_error_seq extends core_base_new_seq#(ibex_mem_intf_seq_item); vseq.data_intf_seq.inject_error(); end end + {IsideErr, 1'b1}: begin + vseq.instr_intf_seq.inject_intg_error(); + end + {DsideErr, 1'b1}: begin + vseq.data_intf_seq.inject_intg_error(); + end + {PickErr, 1'b1}: begin + `DV_CHECK_STD_RANDOMIZE_FATAL(choose_side) + if (choose_side) begin + vseq.instr_intf_seq.inject_intg_error(); + end else begin + vseq.data_intf_seq.inject_intg_error(); + end + end default: begin // DO nothing end diff --git a/dv/uvm/core_ibex/tests/core_ibex_test_lib.sv b/dv/uvm/core_ibex/tests/core_ibex_test_lib.sv index 4941f7880f..c9e98e11d2 100644 --- a/dv/uvm/core_ibex/tests/core_ibex_test_lib.sv +++ b/dv/uvm/core_ibex/tests/core_ibex_test_lib.sv @@ -1176,6 +1176,7 @@ class core_ibex_mem_error_test extends core_ibex_directed_test; memory_error_seq_h.iteration_modes = InfiniteRuns; memory_error_seq_h.stimulus_delay_cycles_min = 800; // Interval between injected errors memory_error_seq_h.stimulus_delay_cycles_max = 5000; + memory_error_seq_h.intg_err_pct = cfg.enable_mem_intg_err ? 75 : 0; fork begin forever begin From 5d423a67bfd7da096ee3ecb186a043ead6965d14 Mon Sep 17 00:00:00 2001 From: Canberk Topal Date: Fri, 14 Oct 2022 02:37:43 +0100 Subject: [PATCH 5/8] [cosim] Cosim integration of internal NMI This commit is mainly an extension to cosim environment to drive the newly introduced state variable `nmi_int` in Spike. This commit - Extends RVFI interface by a single bit (ext_nmi_int) - Configures cosim to set nmi_int inside Spike Signed-off-by: Canberk Topal --- dv/cosim/cosim.h | 6 +++++ dv/cosim/cosim_dpi.cc | 5 ++++ dv/cosim/cosim_dpi.h | 1 + dv/cosim/cosim_dpi.svh | 1 + dv/cosim/spike_cosim.cc | 23 ++++++++++++++++++- dv/cosim/spike_cosim.h | 1 + .../ibex_cosim_agent/ibex_cosim_scoreboard.sv | 1 + .../ibex_cosim_agent/ibex_rvfi_monitor.sv | 1 + .../ibex_cosim_agent/ibex_rvfi_seq_item.sv | 2 ++ dv/uvm/core_ibex/env/core_ibex_rvfi_if.sv | 2 ++ dv/uvm/core_ibex/tb/core_ibex_tb_top.sv | 1 + .../ibex_simple_system_cosim_checker.sv | 1 + rtl/ibex_core.sv | 10 +++++++- rtl/ibex_lockstep.sv | 1 + rtl/ibex_top.sv | 2 ++ rtl/ibex_top_tracing.sv | 4 ++++ 16 files changed, 60 insertions(+), 2 deletions(-) diff --git a/dv/cosim/cosim.h b/dv/cosim/cosim.h index 1245f6c415..cbb0b01ba9 100644 --- a/dv/cosim/cosim.h +++ b/dv/cosim/cosim.h @@ -95,6 +95,12 @@ class Cosim { // When an NMI is due to be taken that will occur at the next call of `step`. virtual void set_nmi(bool nmi) = 0; + // Set the state of the internal NMI (non-maskable interrupt) line. + // Behaviour wise this is almost as same as external NMI case explained at + // set_nmi method. Difference is that this one is a response from Ibex rather + // than an input. + virtual void set_nmi_int(bool nmi_int) = 0; + // Set the debug request. // // When set to true the core will enter debug mode at the next step diff --git a/dv/cosim/cosim_dpi.cc b/dv/cosim/cosim_dpi.cc index 2d628f0c83..f2fe48c1cb 100644 --- a/dv/cosim/cosim_dpi.cc +++ b/dv/cosim/cosim_dpi.cc @@ -28,6 +28,11 @@ void riscv_cosim_set_nmi(Cosim *cosim, svBit nmi) { cosim->set_nmi(nmi); } +void riscv_cosim_set_nmi_int(Cosim *cosim, svBit nmi_int) { + assert(cosim); + + cosim->set_nmi_int(nmi_int); +} void riscv_cosim_set_debug_req(Cosim *cosim, svBit debug_req) { assert(cosim); diff --git a/dv/cosim/cosim_dpi.h b/dv/cosim/cosim_dpi.h index df7600bfd3..29a7e25c3a 100644 --- a/dv/cosim/cosim_dpi.h +++ b/dv/cosim/cosim_dpi.h @@ -17,6 +17,7 @@ int riscv_cosim_step(Cosim *cosim, const svBitVecVal *write_reg, svBit sync_trap); void riscv_cosim_set_mip(Cosim *cosim, const svBitVecVal *mip); void riscv_cosim_set_nmi(Cosim *cosim, svBit nmi); +void riscv_cosim_set_nmi_int(Cosim *cosim, svBit nmi_int); void riscv_cosim_set_debug_req(Cosim *cosim, svBit debug_req); void riscv_cosim_set_mcycle(Cosim *cosim, svBitVecVal *mcycle); void riscv_cosim_set_csr(Cosim *cosim, const int csr_id, diff --git a/dv/cosim/cosim_dpi.svh b/dv/cosim/cosim_dpi.svh index 6a6f1a5814..44361cb557 100644 --- a/dv/cosim/cosim_dpi.svh +++ b/dv/cosim/cosim_dpi.svh @@ -14,6 +14,7 @@ import "DPI-C" function int riscv_cosim_step(chandle cosim_handle, bit [4:0] wri bit [31:0] write_reg_data, bit [31:0] pc, bit sync_trap); import "DPI-C" function void riscv_cosim_set_mip(chandle cosim_handle, bit [31:0] mip); import "DPI-C" function void riscv_cosim_set_nmi(chandle cosim_handle, bit nmi); +import "DPI-C" function void riscv_cosim_set_nmi_int(chandle cosim_handle, bit nmi_int); import "DPI-C" function void riscv_cosim_set_debug_req(chandle cosim_handle, bit debug_req); import "DPI-C" function void riscv_cosim_set_mcycle(chandle cosim_handle, bit [63:0] mcycle); import "DPI-C" function void riscv_cosim_set_csr(chandle cosim_handle, int csr_id, diff --git a/dv/cosim/spike_cosim.cc b/dv/cosim/spike_cosim.cc index a5509c52fb..7711498a34 100644 --- a/dv/cosim/spike_cosim.cc +++ b/dv/cosim/spike_cosim.cc @@ -200,7 +200,8 @@ bool SpikeCosim::step(uint32_t write_reg, uint32_t write_reg_data, if (processor->get_state()->last_inst_pc == PC_INVALID) { if (!(processor->get_state()->mcause->read() & 0x80000000) || - processor->get_state()->debug_mode) { // (Async-Traps are disabled in debug mode) + processor->get_state() + ->debug_mode) { // (Async-Traps are disabled in debug mode) // Spike encountered a synchronous trap pending_sync_exception = true; @@ -358,6 +359,12 @@ bool SpikeCosim::check_sync_trap(uint32_t write_reg, return false; } + // If we see an internal NMI, that means we receive an extra memory intf item. + // Deleting that is necessary since next Load/Store would fail otherwise. + if (processor->get_state()->mcause->read() == 0xFFFFFFE0) { + pending_dside_accesses.erase(pending_dside_accesses.begin()); + } + // Errors may have been generated outside of step() (e.g. in // check_mem_access()), return false if there are any. if (errors.size() != 0) { @@ -480,6 +487,20 @@ void SpikeCosim::set_nmi(bool nmi) { } } +void SpikeCosim::set_nmi_int(bool nmi_int) { + if (nmi_int && !nmi_mode && !processor->get_state()->debug_mode) { + processor->get_state()->nmi_int = true; + nmi_mode = true; + + // When NMI is set it is guaranteed NMI trap will be taken at the next step + // so save CSR state for recoverable NMI to mstack now. + mstack.mpp = get_field(processor->get_csr(CSR_MSTATUS), MSTATUS_MPP); + mstack.mpie = get_field(processor->get_csr(CSR_MSTATUS), MSTATUS_MPIE); + mstack.epc = processor->get_csr(CSR_MEPC); + mstack.cause = processor->get_csr(CSR_MCAUSE); + } +} + void SpikeCosim::set_debug_req(bool debug_req) { processor->halt_request = debug_req ? processor_t::HR_REGULAR : processor_t::HR_NONE; diff --git a/dv/cosim/spike_cosim.h b/dv/cosim/spike_cosim.h index 53f03f999f..76f8066a4f 100644 --- a/dv/cosim/spike_cosim.h +++ b/dv/cosim/spike_cosim.h @@ -102,6 +102,7 @@ class SpikeCosim : public simif_t, public Cosim { uint32_t initial_spike_pc); void set_mip(uint32_t mip) override; void set_nmi(bool nmi) override; + void set_nmi_int(bool nmi_int) override; void set_debug_req(bool debug_req) override; void set_mcycle(uint64_t mcycle) override; void set_csr(const int csr_num, const uint32_t new_val) override; diff --git a/dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_cosim_scoreboard.sv b/dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_cosim_scoreboard.sv index dd45ba040c..8ff2be4936 100644 --- a/dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_cosim_scoreboard.sv +++ b/dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_cosim_scoreboard.sv @@ -122,6 +122,7 @@ class ibex_cosim_scoreboard extends uvm_scoreboard; end riscv_cosim_set_nmi(cosim_handle, rvfi_instr.nmi); + riscv_cosim_set_nmi_int(cosim_handle, rvfi_instr.nmi_int); riscv_cosim_set_mip(cosim_handle, rvfi_instr.mip); riscv_cosim_set_debug_req(cosim_handle, rvfi_instr.debug_req); riscv_cosim_set_mcycle(cosim_handle, rvfi_instr.mcycle); diff --git a/dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_rvfi_monitor.sv b/dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_rvfi_monitor.sv index 76fa36f9f4..83c99afeb4 100644 --- a/dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_rvfi_monitor.sv +++ b/dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_rvfi_monitor.sv @@ -38,6 +38,7 @@ class ibex_rvfi_monitor extends uvm_monitor; trans_collected.order = vif.monitor_cb.order; trans_collected.mip = vif.monitor_cb.ext_mip; trans_collected.nmi = vif.monitor_cb.ext_nmi; + trans_collected.nmi_int = vif.monitor_cb.ext_nmi_int; trans_collected.debug_req = vif.monitor_cb.ext_debug_req; trans_collected.mcycle = vif.monitor_cb.ext_mcycle; trans_collected.ic_scr_key_valid = vif.monitor_cb.ext_ic_scr_key_valid; diff --git a/dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_rvfi_seq_item.sv b/dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_rvfi_seq_item.sv index 9532ee346a..5356023248 100644 --- a/dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_rvfi_seq_item.sv +++ b/dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_rvfi_seq_item.sv @@ -10,6 +10,7 @@ class ibex_rvfi_seq_item extends uvm_sequence_item; bit [63:0] order; bit [31:0] mip; bit nmi; + bit nmi_int; bit debug_req; bit [63:0] mcycle; @@ -25,6 +26,7 @@ class ibex_rvfi_seq_item extends uvm_sequence_item; `uvm_field_int (order, UVM_DEFAULT) `uvm_field_int (mip, UVM_DEFAULT) `uvm_field_int (nmi, UVM_DEFAULT) + `uvm_field_int (nmi_int, UVM_DEFAULT) `uvm_field_int (debug_req, UVM_DEFAULT) `uvm_field_int (mcycle, UVM_DEFAULT) `uvm_field_sarray_int (mhpmcounters, UVM_DEFAULT) diff --git a/dv/uvm/core_ibex/env/core_ibex_rvfi_if.sv b/dv/uvm/core_ibex/env/core_ibex_rvfi_if.sv index 7e58df4379..c6ec6ea621 100644 --- a/dv/uvm/core_ibex/env/core_ibex_rvfi_if.sv +++ b/dv/uvm/core_ibex/env/core_ibex_rvfi_if.sv @@ -28,6 +28,7 @@ interface core_ibex_rvfi_if(input logic clk); logic [31:0] mem_wdata; logic [31:0] ext_mip; logic ext_nmi; + logic ext_nmi_int; logic [31:0] ext_debug_req; logic [63:0] ext_mcycle; @@ -61,6 +62,7 @@ interface core_ibex_rvfi_if(input logic clk); input mem_wdata; input ext_mip; input ext_nmi; + input ext_nmi_int; input ext_debug_req; input ext_mcycle; input ext_mhpmcounters; diff --git a/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv b/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv index 580deefdef..360b3ec22f 100644 --- a/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv +++ b/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv @@ -192,6 +192,7 @@ module core_ibex_tb_top; assign rvfi_if.mem_wdata = dut.rvfi_mem_wdata; assign rvfi_if.ext_mip = dut.rvfi_ext_mip; assign rvfi_if.ext_nmi = dut.rvfi_ext_nmi; + assign rvfi_if.ext_nmi_int = dut.rvfi_ext_nmi_int; assign rvfi_if.ext_debug_req = dut.rvfi_ext_debug_req; assign rvfi_if.ext_mcycle = dut.rvfi_ext_mcycle; assign rvfi_if.ext_mhpmcounters = dut.rvfi_ext_mhpmcounters; diff --git a/dv/verilator/simple_system_cosim/ibex_simple_system_cosim_checker.sv b/dv/verilator/simple_system_cosim/ibex_simple_system_cosim_checker.sv index b65834b1e9..362f548b06 100644 --- a/dv/verilator/simple_system_cosim/ibex_simple_system_cosim_checker.sv +++ b/dv/verilator/simple_system_cosim/ibex_simple_system_cosim_checker.sv @@ -43,6 +43,7 @@ module ibex_simple_system_cosim_checker #( always @(posedge clk_i) begin if (u_top.rvfi_valid) begin riscv_cosim_set_nmi(cosim_handle, u_top.rvfi_ext_nmi); + riscv_cosim_set_nmi_int(cosim_handle, u_top.rvfi_ext_nmi_int); riscv_cosim_set_mip(cosim_handle, u_top.rvfi_ext_mip); riscv_cosim_set_debug_req(cosim_handle, u_top.rvfi_ext_debug_req); riscv_cosim_set_mcycle(cosim_handle, u_top.rvfi_ext_mcycle); diff --git a/rtl/ibex_core.sv b/rtl/ibex_core.sv index 895aad651a..092c6fe805 100644 --- a/rtl/ibex_core.sv +++ b/rtl/ibex_core.sv @@ -138,6 +138,7 @@ module ibex_core import ibex_pkg::*; #( output logic [31:0] rvfi_mem_wdata, output logic [31:0] rvfi_ext_mip, output logic rvfi_ext_nmi, + output logic rvfi_ext_nmi_int, output logic rvfi_ext_debug_req, output logic [63:0] rvfi_ext_mcycle, output logic [31:0] rvfi_ext_mhpmcounters [10], @@ -1204,6 +1205,7 @@ module ibex_core import ibex_pkg::*; #( logic new_debug_req; logic new_nmi; + logic new_nmi_int; logic new_irq; ibex_pkg::irqs_t captured_mip; logic captured_nmi; @@ -1214,6 +1216,7 @@ module ibex_core import ibex_pkg::*; #( // debug_req and MIP captured at IF -> ID transition so one extra stage ibex_pkg::irqs_t rvfi_ext_stage_mip [RVFI_STAGES+1]; logic rvfi_ext_stage_nmi [RVFI_STAGES+1]; + logic rvfi_ext_stage_nmi_int [RVFI_STAGES]; logic rvfi_ext_stage_debug_req [RVFI_STAGES+1]; logic [63:0] rvfi_ext_stage_mcycle [RVFI_STAGES]; logic [31:0] rvfi_ext_stage_mhpmcounters [RVFI_STAGES][10]; @@ -1262,6 +1265,7 @@ module ibex_core import ibex_pkg::*; #( end assign rvfi_ext_nmi = rvfi_ext_stage_nmi [RVFI_STAGES]; + assign rvfi_ext_nmi_int = rvfi_ext_stage_nmi_int [RVFI_STAGES-1]; assign rvfi_ext_debug_req = rvfi_ext_stage_debug_req [RVFI_STAGES]; assign rvfi_ext_mcycle = rvfi_ext_stage_mcycle [RVFI_STAGES-1]; assign rvfi_ext_mhpmcounters = rvfi_ext_stage_mhpmcounters [RVFI_STAGES-1]; @@ -1309,7 +1313,7 @@ module ibex_core import ibex_pkg::*; #( end assign rvfi_trap_id = id_stage_i.controller_i.id_exception_o; - assign rvfi_trap_wb = id_stage_i.controller_i.exc_req_lsu; + assign rvfi_trap_wb = id_stage_i.controller_i.exc_req_lsu | new_nmi_int; // WB is instantly done in the tracking pipeline when a trap is progress through the pipeline assign rvfi_wb_done = instr_done_wb | (rvfi_stage_valid[0] & rvfi_stage_trap[0]); end else begin : gen_rvfi_no_wb_stage @@ -1349,6 +1353,7 @@ module ibex_core import ibex_pkg::*; #( // appropriately. assign new_debug_req = (debug_req_i & ~debug_mode); assign new_nmi = irq_nm_i & ~nmi_mode & ~debug_mode; + assign new_nmi_int = id_stage_i.mem_resp_intg_err & ~nmi_mode & ~debug_mode; assign new_irq = irq_pending_o & csr_mstatus_mie & ~nmi_mode & ~debug_mode; always_ff @(posedge clk_i or negedge rst_ni) begin @@ -1423,6 +1428,7 @@ module ibex_core import ibex_pkg::*; #( rvfi_stage_mem_addr[i] <= '0; rvfi_ext_stage_mip[i+1] <= '0; rvfi_ext_stage_nmi[i+1] <= '0; + rvfi_ext_stage_nmi_int[i] <= '0; rvfi_ext_stage_debug_req[i+1] <= '0; rvfi_ext_stage_mcycle[i] <= '0; rvfi_ext_stage_mhpmcounters[i] <= '{10{'0}}; @@ -1500,6 +1506,8 @@ module ibex_core import ibex_pkg::*; #( rvfi_ext_stage_mip[i+1] <= rvfi_ext_stage_mip[i]; rvfi_ext_stage_nmi[i+1] <= rvfi_ext_stage_nmi[i]; + rvfi_ext_stage_nmi_int[i] <= rvfi_ext_stage_nmi_int[i-1]; + rvfi_ext_stage_nmi_int[i-1] <= new_nmi_int; rvfi_ext_stage_debug_req[i+1] <= rvfi_ext_stage_debug_req[i]; rvfi_ext_stage_mcycle[i] <= rvfi_ext_stage_mcycle[i-1]; rvfi_ext_stage_ic_scr_key_valid[i] <= rvfi_ext_stage_ic_scr_key_valid[i-1]; diff --git a/rtl/ibex_lockstep.sv b/rtl/ibex_lockstep.sv index e6ab5fd0c7..f70172bba9 100644 --- a/rtl/ibex_lockstep.sv +++ b/rtl/ibex_lockstep.sv @@ -425,6 +425,7 @@ module ibex_lockstep import ibex_pkg::*; #( .rvfi_mem_wdata (), .rvfi_ext_mip (), .rvfi_ext_nmi (), + .rvfi_ext_nmi_int (), .rvfi_ext_debug_req (), .rvfi_ext_mcycle (), .rvfi_ext_mhpmcounters (), diff --git a/rtl/ibex_top.sv b/rtl/ibex_top.sv index e951eb76bf..8b29aa06fd 100644 --- a/rtl/ibex_top.sv +++ b/rtl/ibex_top.sv @@ -118,6 +118,7 @@ module ibex_top import ibex_pkg::*; #( output logic [31:0] rvfi_mem_wdata, output logic [31:0] rvfi_ext_mip, output logic rvfi_ext_nmi, + output logic rvfi_ext_nmi_int, output logic rvfi_ext_debug_req, output logic [63:0] rvfi_ext_mcycle, output logic [31:0] rvfi_ext_mhpmcounters [10], @@ -366,6 +367,7 @@ module ibex_top import ibex_pkg::*; #( .rvfi_mem_wdata, .rvfi_ext_mip, .rvfi_ext_nmi, + .rvfi_ext_nmi_int, .rvfi_ext_debug_req, .rvfi_ext_mcycle, .rvfi_ext_mhpmcounters, diff --git a/rtl/ibex_top_tracing.sv b/rtl/ibex_top_tracing.sv index b830bc14f0..ca866ae741 100644 --- a/rtl/ibex_top_tracing.sv +++ b/rtl/ibex_top_tracing.sv @@ -121,6 +121,7 @@ module ibex_top_tracing import ibex_pkg::*; #( logic [31:0] rvfi_mem_wdata; logic [31:0] rvfi_ext_mip; logic rvfi_ext_nmi; + logic rvfi_ext_nmi_int; logic rvfi_ext_debug_req; logic [63:0] rvfi_ext_mcycle; @@ -134,6 +135,7 @@ module ibex_top_tracing import ibex_pkg::*; #( logic [31:0] unused_rvfi_ext_mip; logic unused_rvfi_ext_nmi; + logic unused_rvfi_ext_nmi_int; logic unused_rvfi_ext_debug_req; logic [63:0] unused_rvfi_ext_mcycle; logic unused_rvfi_ext_ic_scr_key_valid; @@ -142,6 +144,7 @@ module ibex_top_tracing import ibex_pkg::*; #( // them. assign unused_rvfi_ext_mip = rvfi_ext_mip; assign unused_rvfi_ext_nmi = rvfi_ext_nmi; + assign unused_rvfi_ext_nmi_int = rvfi_ext_nmi_int; assign unused_rvfi_ext_debug_req = rvfi_ext_debug_req; assign unused_rvfi_ext_mcycle = rvfi_ext_mcycle; assign unused_perf_regs = rvfi_ext_mhpmcounters; @@ -242,6 +245,7 @@ module ibex_top_tracing import ibex_pkg::*; #( .rvfi_mem_wdata, .rvfi_ext_mip, .rvfi_ext_nmi, + .rvfi_ext_nmi_int, .rvfi_ext_debug_req, .rvfi_ext_mcycle, .rvfi_ext_mhpmcounters, From d2995a3679af08197c958605f6b3554468330ef1 Mon Sep 17 00:00:00 2001 From: Canberk Topal Date: Fri, 14 Oct 2022 03:08:41 +0100 Subject: [PATCH 6/8] Update COSIM_VERSION to latest ibex_cosim hash Signed-off-by: Canberk Topal --- ci/vars.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/vars.yml b/ci/vars.yml index b5cfb2976e..0cc5bbefd4 100644 --- a/ci/vars.yml +++ b/ci/vars.yml @@ -7,7 +7,7 @@ # end up as float otherwise). variables: VERILATOR_VERSION: "v4.104" - IBEX_COSIM_VERSION: "0dc2de5d" + IBEX_COSIM_VERSION: "6272327d" RISCV_TOOLCHAIN_TAR_VERSION: "20220210-1" RISCV_TOOLCHAIN_TAR_VARIANT: "lowrisc-toolchain-gcc-rv32imcb" RISCV_COMPLIANCE_GIT_VERSION: "844c6660ef3f0d9b96957991109dfd80cc4938e2" From d257dd8bd11ab9b7f297a9fcdc7e5693a0a5b588 Mon Sep 17 00:00:00 2001 From: Canberk Topal Date: Thu, 20 Oct 2022 17:41:52 +0100 Subject: [PATCH 7/8] Fixup RVFI connection for pc_wdata Signed-off-by: Canberk Topal --- dv/uvm/core_ibex/tb/core_ibex_tb_top.sv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv b/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv index 360b3ec22f..6d39534816 100644 --- a/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv +++ b/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv @@ -185,7 +185,7 @@ module core_ibex_tb_top; assign rvfi_if.rd_addr = dut.rvfi_rd_addr; assign rvfi_if.rd_wdata = dut.rvfi_rd_wdata; assign rvfi_if.pc_rdata = dut.rvfi_pc_rdata; - assign rvfi_if_pc_wdata = dut.rvfi_pc_wdata; + assign rvfi_if.pc_wdata = dut.rvfi_pc_wdata; assign rvfi_if.mem_addr = dut.rvfi_mem_addr; assign rvfi_if.mem_rmask = dut.rvfi_mem_rmask; assign rvfi_if.mem_rdata = dut.rvfi_mem_rdata; From 66d8d0fc0b087fa48f74cf8e0d343b582e2ad8e9 Mon Sep 17 00:00:00 2001 From: Canberk Topal Date: Thu, 20 Oct 2022 17:58:49 +0100 Subject: [PATCH 8/8] [rtl] Remove data_intg_err gating register writes Signed-off-by: Canberk Topal --- rtl/ibex_load_store_unit.sv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtl/ibex_load_store_unit.sv b/rtl/ibex_load_store_unit.sv index 6dc86a901d..1c1a329f6e 100644 --- a/rtl/ibex_load_store_unit.sv +++ b/rtl/ibex_load_store_unit.sv @@ -508,7 +508,7 @@ module ibex_load_store_unit #( assign data_or_pmp_err = lsu_err_q | data_bus_err_i | pmp_err_q; assign lsu_resp_valid_o = (data_rvalid_i | pmp_err_q) & (ls_fsm_cs == IDLE); assign lsu_rdata_valid_o = - (ls_fsm_cs == IDLE) & data_rvalid_i & ~data_or_pmp_err & ~data_we_q & ~data_intg_err; + (ls_fsm_cs == IDLE) & data_rvalid_i & ~data_or_pmp_err & ~data_we_q; // output to register file assign lsu_rdata_o = data_rdata_ext;