Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/smrnmi #149

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
10 changes: 6 additions & 4 deletions doc/03_reference/exception_interrupts.rst
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,13 @@ In Debug Mode, all interrupts including the NMI are ignored independent of ``mst
Recoverable Non-Maskable Interrupt
----------------------------------

To support recovering from an NMI happening during a trap handling routine, Ibex features additional CSRs for backing up ``mstatus``.MPP, ``mstatus``.MPIE, ``mepc`` and ``mcause``.
These CSRs are not accessible by software running on the core.
The base machine-level architecture supports only unresumable non-maskable interrupts (UNMIs), where the NMI jumps to a handler in machine mode, overwriting the current ``mepc`` and ``mcause``
register values. If the hart had been executing machine-mode code in a trap handler, the previous values in ``mepc`` and ``mcause`` would not be recoverable and so execution is not generally resumable.

These CSRs are nonstandard.
For more information, see `the corresponding proposal <https://github.com/riscv/riscv-isa-manual/issues/261>`_.
To support recovering from an NMI (RNMI) happening during a trap handling routine, CVE2 supports the Smrnmi extension. The extension adds four new CSRs (``mnepc``, ``mncause``, ``mnstatus``, and ``mnscratch``) to hold the
interrupted state, and one new instruction, MNRET, to resume from the RNMI handler.

For more information, see chapter 4 in draft of 'The RISC-V Instruction Set Manual <https://github.com/riscv/riscv-isa-manual/releases>'_.
szbieg marked this conversation as resolved.
Show resolved Hide resolved


Exceptions
Expand Down
21 changes: 16 additions & 5 deletions rtl/cve2_controller.sv
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ module cve2_controller #(
input logic illegal_insn_i, // decoder has an invalid instr
input logic ecall_insn_i, // decoder has ECALL instr
input logic mret_insn_i, // decoder has MRET instr
input logic mnret_insn_i, // decoder has MNRET instr
input logic dret_insn_i, // decoder has DRET instr
input logic wfi_insn_i, // decoder has WFI instr
input logic ebrk_insn_i, // decoder has EBREAK instr
Expand Down Expand Up @@ -81,6 +82,7 @@ module cve2_controller #(
output logic csr_save_if_o,
output logic csr_save_id_o,
output logic csr_restore_mret_id_o,
output logic csr_restore_mnret_id_o,
output logic csr_restore_dret_id_o,
output logic csr_save_cause_o,
output logic [31:0] csr_mtval_o,
Expand Down Expand Up @@ -146,6 +148,7 @@ module cve2_controller #(

logic ecall_insn;
logic mret_insn;
logic mnret_insn;
logic dret_insn;
logic wfi_insn;
logic ebrk_insn;
Expand Down Expand Up @@ -176,6 +179,7 @@ module cve2_controller #(
// Decoder doesn't take instr_valid into account, factor it in here.
assign ecall_insn = ecall_insn_i & instr_valid_i;
assign mret_insn = mret_insn_i & instr_valid_i;
assign mnret_insn = mnret_insn_i & instr_valid_i;
assign dret_insn = dret_insn_i & instr_valid_i;
assign wfi_insn = wfi_insn_i & instr_valid_i;
assign ebrk_insn = ebrk_insn_i & instr_valid_i;
Expand All @@ -189,7 +193,7 @@ module cve2_controller #(
// Some instructions can only be executed in M-Mode
assign illegal_umode = (priv_mode_i != PRIV_LVL_M) &
// MRET must be in M-Mode. TW means trap WFI to M-Mode.
(mret_insn | (csr_mstatus_tw_i & wfi_insn));
(mret_insn | mnret_insn | (csr_mstatus_tw_i & wfi_insn));

// This is recorded in the illegal_insn_q flop to help timing. Specifically
// it is needed to break the path from cve2_cs_registers/illegal_csr_insn_o
Expand Down Expand Up @@ -218,7 +222,7 @@ module cve2_controller #(
assign special_req_flush_only = wfi_insn | csr_pipe_flush;

// These special requests cause a change in PC
assign special_req_pc_change = mret_insn | dret_insn | exc_req_d | exc_req_lsu;
assign special_req_pc_change = mret_insn | mnret_insn | dret_insn | exc_req_d | exc_req_lsu;

// generic special request signal, applies to all instructions
assign special_req = special_req_pc_change | special_req_flush_only;
Expand Down Expand Up @@ -326,6 +330,7 @@ module cve2_controller #(
csr_save_if_o = 1'b0;
csr_save_id_o = 1'b0;
csr_restore_mret_id_o = 1'b0;
csr_restore_mnret_id_o = 1'b0;
csr_restore_dret_id_o = 1'b0;
csr_save_cause_o = 1'b0;
csr_mtval_o = '0;
Expand Down Expand Up @@ -660,10 +665,16 @@ module cve2_controller #(
endcase
end else begin
// special instructions and pipeline flushes
if (mret_insn) begin
pc_mux_o = PC_ERET;
if (mret_insn | mnret_insn) begin
pc_set_o = 1'b1;
csr_restore_mret_id_o = 1'b1;
if(mret_insn) begin
csr_restore_mret_id_o = 1'b1;
pc_mux_o = PC_ERET;
end
if(mnret_insn) begin
csr_restore_mnret_id_o = 1'b1;
pc_mux_o = PC_NRET;
end
if (nmi_mode_q) begin
nmi_mode_d = 1'b0; // exit NMI mode
end
Expand Down
7 changes: 6 additions & 1 deletion rtl/cve2_core.sv
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ module cve2_core import cve2_pkg::*; #(
logic nmi_mode;
irqs_t irqs;
logic csr_mstatus_mie;
logic [31:0] csr_mepc, csr_depc;
logic [31:0] csr_mepc, csr_mnepc, csr_depc;

// PMP signals
logic [33:0] csr_pmp_addr [PMPNumRegions];
Expand All @@ -235,6 +235,7 @@ module cve2_core import cve2_pkg::*; #(
logic csr_save_if;
logic csr_save_id;
logic csr_restore_mret_id;
logic csr_restore_mnret_id;
logic csr_restore_dret_id;
logic csr_save_cause;
logic csr_mtvec_init;
Expand Down Expand Up @@ -329,6 +330,7 @@ module cve2_core import cve2_pkg::*; #(

// CSRs
.csr_mepc_i (csr_mepc), // exception return address
.csr_mnepc_i (csr_mnepc), // NMI return address
.csr_depc_i (csr_depc), // debug return address
.csr_mtvec_i (csr_mtvec), // trap-vector base address
.csr_mtvec_init_o(csr_mtvec_init),
Expand Down Expand Up @@ -417,6 +419,7 @@ module cve2_core import cve2_pkg::*; #(
.csr_save_if_o (csr_save_if), // control signal to save PC
.csr_save_id_o (csr_save_id), // control signal to save PC
.csr_restore_mret_id_o(csr_restore_mret_id), // restore mstatus upon MRET
.csr_restore_mnret_id_o(csr_restore_mnret_id), // restore mstatus upon MNRET
.csr_restore_dret_id_o(csr_restore_dret_id), // restore mstatus upon MRET
.csr_save_cause_o (csr_save_cause),
.csr_mtval_o (csr_mtval),
Expand Down Expand Up @@ -712,6 +715,7 @@ module cve2_core import cve2_pkg::*; #(
.csr_mstatus_mie_o(csr_mstatus_mie),
.csr_mstatus_tw_o (csr_mstatus_tw),
.csr_mepc_o (csr_mepc),
.csr_mnepc_o (csr_mnepc),

// PMP
.csr_pmp_cfg_o (csr_pmp_cfg),
Expand All @@ -734,6 +738,7 @@ module cve2_core import cve2_pkg::*; #(
.csr_save_if_i (csr_save_if),
.csr_save_id_i (csr_save_id),
.csr_restore_mret_i(csr_restore_mret_id),
.csr_restore_mnret_i(csr_restore_mnret_id),
.csr_restore_dret_i(csr_restore_dret_id),
.csr_save_cause_i (csr_save_cause),
.csr_mcause_i (exc_cause),
Expand Down
Loading
Loading