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
11 changes: 8 additions & 3 deletions doc/01_specification/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -193,12 +193,18 @@ identify the versions of RISC-V extensions from these specifications.
Privileged Architecture Extension, version 0.9-draft, 3/15/2022,
https://github.com/riscv/riscv-fast-interrupt/blob/master/clic.pdf

.. [SMRNMI] "Smrnmi" Standard Extension for Resumable Non-Maskable Interrupts
https://github.com/riscv/riscv-isa-manual/releases/download/riscv-isa-release-056b6ff-2023-10-02/riscv-privileged.pdf#chapter.4

Other documents
===============

.. [FPGAreset] Ken Chapman, “Get Smart About Reset: Think Local, Not
Global”, Xilinx WP272 white paper, https://docs.xilinx.com/v/u/en-US/wp272

.. [Ibex] Production-quality open source 32-bit RISC-V CPU core written in SystemVerilog
https://ibex-core.readthedocs.io/en/latest/index.html

CV32E20 core functional requirements
====================================

Expand Down Expand Up @@ -709,9 +715,8 @@ IRQs, but is not yet ratified at the time of specification.
+---------+------------------------------------------------------------+
szbieg marked this conversation as resolved.
Show resolved Hide resolved

.. note::
It should be noted that Ibex had implemented a custom mechanism for NMI
szbieg marked this conversation as resolved.
Show resolved Hide resolved
recovery. A standard RISC-V way of NMI recovery is in draft stage. In
future, the custom mechanism could be reworked to follow the standard.
[Ibex] had implemented a custom mechanism for NMI recovery. In CVE2 this
custom mechanism is reworked to follow the drafted standard [SMRNMI]_.

Coprocessor interface
---------------------
Expand Down
58 changes: 57 additions & 1 deletion doc/03_reference/cs_registers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,13 @@ Ibex implements all the Control and Status Registers (CSRs) listed in the follow
+---------+--------------------+--------+-----------------------------------------------+
| 0x3BF | ``pmpaddr15`` | WARL | PMP Address Register |
+---------+--------------------+--------+-----------------------------------------------+
| . . . . |
| 0x740 | ``mnscratch`` | WARL | Resumable NMI scratch register |
+---------+--------------------+--------+-----------------------------------------------+
| 0x741 | ``mnepc`` | WARL | Resumable NMI program counter |
+---------+--------------------+--------+-----------------------------------------------+
| 0x742 | ``mncause`` | WARL | Resumable NMI cause register |
+---------+--------------------+--------+-----------------------------------------------+
| 0x744 | ``mnstatus`` | WARL | Resumable NMI status register |
+---------+--------------------+--------+-----------------------------------------------+
| 0x757 | ``mseccfgh`` | WARL | Upper 32 bits of ``mseccfg`` |
+---------+--------------------+--------+-----------------------------------------------+
Expand Down Expand Up @@ -310,6 +316,56 @@ Reset Value: ``0x0000_0000``

.. _csr-tselect:

Resumable NMI Machine Exception PC (mnepc)
---------------------------

CSR Address: ``0x741``

Reset Value: ``0x0000_0000``

When an NMI exception is encountered, the current program counter is saved in ``mnepc``, and the core jumps to the exception address.
When an MNRET instruction is executed, the value from ``mnepc`` replaces the current program counter.


Resumable NMI Machine Cause (mncause)
----------------------

CSR Address: ``0x742``

Reset Value: ``0x0000_0000``

+-------+------+------------------------------------------------------------------+
| Bit# | R/W | Description |
+-------+------+------------------------------------------------------------------+
| 31 | R | **Interrupt:** This bit is set when the exception was triggered |
| | | by an interrupt. |
+-------+------+------------------------------------------------------------------+
| 30:0 | WARL | **NMI Cause** |
+-------+------+------------------------------------------------------------------+

The mncause CSR holds the reason for the NMI, with bit MXLEN-1 set to 1, and the NMI cause
encoded in the least-significant bits or zero if NMI causes are not supported.

Resumable NMI Machine Status (mnstatus)
------------------------

CSR Address: ``0x744``

Reset Value: ``0x0000_0000``

+-------+-----+---------------------------------------------------------------------------------+
| Bit# | R/W | Description |
+-------+-----+---------------------------------------------------------------------------------+
| 12:11 | RW | **MNPP:** Machine Previous Privilege mode. |
+-------+-----+---------------------------------------------------------------------------------+
| 3 | RW | **Interrupt Enable (NMIE):** If set to 1'b1, interrupts are globally enabled. |
+-------+-----+---------------------------------------------------------------------------------+

When an RNMI interrupt is detected, The ``mnstatus``.NMIE bit is cleared, masking all interrupts. If you want to enable interrupt handling in your exception handler, set ``mnstatus``.NMIE back to 1'b1 inside your handler code.

Only Machine Mode and User Mode are supported.
Any write to ``mnstatus``.MNPP of an unsupported value will be interpreted as Machine Mode.

Trigger Select Register (tselect)
---------------------------------

Expand Down
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 '"Smrnmi" Standard Extension for Resumable Non-Maskable Interrupts"' in draft of 'The RISC-V Instruction Set Manual <https://github.com/riscv/riscv-isa-manual/releases/download/riscv-isa-release-056b6ff-2023-10-02/riscv-privileged.pdf#chapter.4>'_.


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