From 66f3e2dfc4416ba8d831f4200d525955f6fd518b Mon Sep 17 00:00:00 2001 From: Canberk Topal Date: Fri, 14 Oct 2022 02:37:43 +0100 Subject: [PATCH] [cosim] Cosim integration of internal NMI Signed-off-by: Canberk Topal --- dv/cosim/cosim.h | 7 ++++++ dv/cosim/cosim_dpi.cc | 5 ++++ dv/cosim/cosim_dpi.h | 1 + dv/cosim/cosim_dpi.svh | 1 + dv/cosim/spike_cosim.cc | 25 ++++++++++++++++++- 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 | 12 +++++++-- rtl/ibex_lockstep.sv | 1 + rtl/ibex_top.sv | 2 ++ rtl/ibex_top_tracing.sv | 4 +++ 16 files changed, 64 insertions(+), 3 deletions(-) diff --git a/dv/cosim/cosim.h b/dv/cosim/cosim.h index 1245f6c415..dc0a39e333 100644 --- a/dv/cosim/cosim.h +++ b/dv/cosim/cosim.h @@ -95,6 +95,13 @@ 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. Main difference to consider is that this interrupt is + // synchronous because it comes from the integrity checking logic inside the + // core. + 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..71dca6f34e 100644 --- a/dv/cosim/spike_cosim.cc +++ b/dv/cosim/spike_cosim.cc @@ -200,7 +200,10 @@ 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()->mcause->read() & + 0xFFFFFFE0) || // Internal NMI is a sync trap + processor->get_state() + ->debug_mode) { // (Async-Traps are disabled in debug mode) // Spike encountered a synchronous trap pending_sync_exception = true; @@ -358,6 +361,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 +489,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 af92683cc7..9e47349a77 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 71e43a5910..d33703e07b 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; @@ -1216,6 +1218,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]; @@ -1264,6 +1267,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]; @@ -1293,7 +1297,7 @@ module ibex_core import ibex_pkg::*; #( (rvfi_stage_valid[0] & ~rvfi_wb_done); // Second stage is output stage so simple valid cycle after instruction leaves WB (and so has // retired) - assign rvfi_stage_valid_d[1] = rvfi_wb_done; + assign rvfi_stage_valid_d[1] = rvfi_wb_done && !rvfi_ext_nmi_int; // Signal new instruction in WB cycle after instruction leaves ID/EX (to enter WB) logic rvfi_instr_new_wb_q; @@ -1311,7 +1315,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 @@ -1351,6 +1355,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 @@ -1435,6 +1440,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}}; @@ -1470,6 +1476,7 @@ module ibex_core import ibex_pkg::*; #( rvfi_stage_mem_addr[i] <= rvfi_mem_addr_d; 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] <= '0; rvfi_ext_stage_debug_req[i+1] <= rvfi_ext_stage_debug_req[i]; rvfi_ext_stage_mcycle[i] <= cs_registers_i.mcycle_counter_i.counter_val_o; rvfi_ext_stage_ic_scr_key_valid[i] <= cs_registers_i.cpuctrlsts_ic_scr_key_valid_q; @@ -1512,6 +1519,7 @@ 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] <= 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,