[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 <ctopal@lowrisc.org>
This commit is contained in:
Canberk Topal 2022-10-14 02:37:43 +01:00 committed by Greg Chadwick
parent 12ae6b2478
commit 715292ce55
16 changed files with 68 additions and 2 deletions

View file

@ -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

View file

@ -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);

View file

@ -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,

View file

@ -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,

View file

@ -211,7 +211,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;
@ -376,6 +377,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) {
@ -529,6 +536,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;

View file

@ -109,6 +109,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;

View file

@ -121,6 +121,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);

View file

@ -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;

View file

@ -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)

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -139,6 +139,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],
@ -1235,9 +1236,11 @@ 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;
logic captured_nmi_int;
logic captured_debug_req;
logic captured_valid;
@ -1245,6 +1248,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+1];
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];
@ -1293,6 +1297,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];
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];
@ -1380,6 +1385,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.controller_i.irq_nm_int & ~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
@ -1387,13 +1393,16 @@ module ibex_core import ibex_pkg::*; #(
captured_valid <= 1'b0;
captured_mip <= '0;
captured_nmi <= 1'b0;
captured_nmi_int <= 1'b0;
captured_debug_req <= 1'b0;
end else begin
// Capture when ID stage has emptied out and something occurs that will cause a trap and we
// haven't yet captured
if (~instr_valid_id & (new_debug_req | new_irq | new_nmi) & ~captured_valid) begin
if (~instr_valid_id & (new_debug_req | new_irq | new_nmi | new_nmi_int) &
~captured_valid) begin
captured_valid <= 1'b1;
captured_nmi <= irq_nm_i;
captured_nmi_int <= id_stage_i.controller_i.irq_nm_int;
captured_mip <= cs_registers_i.mip;
captured_debug_req <= debug_req_i;
end
@ -1415,12 +1424,16 @@ module ibex_core import ibex_pkg::*; #(
if (!rst_ni) begin
rvfi_ext_stage_mip[0] <= '0;
rvfi_ext_stage_nmi[0] <= '0;
rvfi_ext_stage_nmi_int[0] <= '0;
rvfi_ext_stage_debug_req[0] <= '0;
end else if (if_stage_i.instr_valid_id_d & if_stage_i.instr_new_id_d) begin
rvfi_ext_stage_mip[0] <= instr_valid_id | ~captured_valid ? cs_registers_i.mip :
captured_mip;
rvfi_ext_stage_nmi[0] <= instr_valid_id | ~captured_valid ? irq_nm_i :
captured_nmi;
rvfi_ext_stage_nmi_int[0] <=
instr_valid_id | ~captured_valid ? id_stage_i.controller_i.irq_nm_int :
captured_nmi_int;
rvfi_ext_stage_debug_req[0] <= instr_valid_id | ~captured_valid ? debug_req_i :
captured_debug_req;
end
@ -1454,6 +1467,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+1] <= '0;
rvfi_ext_stage_debug_req[i+1] <= '0;
rvfi_ext_stage_mcycle[i] <= '0;
rvfi_ext_stage_mhpmcounters[i] <= '{10{'0}};
@ -1489,6 +1503,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+1] <= rvfi_ext_stage_nmi_int[i];
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;
@ -1531,6 +1546,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+1] <= rvfi_ext_stage_nmi_int[i];
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];

View file

@ -429,6 +429,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 (),

View file

@ -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],
@ -387,6 +388,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,

View file

@ -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,