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

implement vectored mtvec #691

Merged
merged 4 commits into from
Sep 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ mimpid = 0x01040312 -> Version 01.04.03.12 -> v1.4.3.12

| Date (*dd.mm.yyyy*) | Version | Comment |
|:-------------------:|:-------:|:--------|
| 23.09.2023 | 1.8.9.4 | :sparkles: added vectored trap handling mode of `mtvec` for reduced latency from IRQ to ISR; [#691](https://github.com/stnolting/neorv32/pull/691)
| 22.09.2023 | 1.8.9.3 | :lock: **watchdog**: add reset password and optional "strict" mode for increased safety; [#692](https://github.com/stnolting/neorv32/pull/692) |
| 15.09.2023 | 1.8.9.2 | :warning: rework CFU CSRs; minor rtl edits; [#690](https://github.com/stnolting/neorv32/pull/690) |
| 11.09.2023 | 1.8.9.1 | minor rtl edits and updates; [#684](https://github.com/stnolting/neorv32/pull/684) |
Expand Down
10 changes: 6 additions & 4 deletions docs/datasheet/cpu_csr.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -279,19 +279,21 @@ Machine-mode software can discover available `Z*` _sub-extensions_ (like `Zicsr`
| Address | `0x305`
| Reset value | `0x00000000`
| ISA | `Zicsr`
| Description | The `mtvec` CSR contain the address of the primary trap handler, which gets executed whenever an
interrupt is triggered or an exception is raised.
| Description | The `mtvec` CSR holds the trap vector configuration.
|=======================

.`mtvec` CSR bits
[cols="^1,^1,<10"]
[options="header",grid="rows"]
|=======================
| Bit | R/W | Function
| 1:0 | r/- | **MODE**: always zero (= DIRECT mode); BASE defines entry for _all_ traps
| 31:2 | r/w | **BASE**: 4-byte aligned base address of trap base handler
| 1:0 | r/w | **MODE**: mode configuration, `00` = DIRECT, `01` = VECTORED. (Others will fall back to DIRECT mode.)
| 31:2 | r/w | **BASE**: in DIRECT mode = 4-byte aligned base address of trap base handler, _all_ traps set `pc` = `BASE`; in VECTORED mode = 128-byte aligned base address of trap vector table, interrupts cause a jump to `pc` = `BASE` + 4 * `mcause` and exceptions to `pc` = `BASE`.
|=======================

.Interrupt Latency
[TIP]
The vectored `mtvec` mode is useful for reducing the time between interrupt request (IRQ) and servicing it (ISR). As software does not need to determine the interrupt cause the reduction in latency can be 5 to 10 times and as low as _26_ cycles.

{empty} +
[discrete]
Expand Down
14 changes: 11 additions & 3 deletions rtl/core/neorv32_cpu_control.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -656,7 +656,11 @@ begin
elsif (debug_ctrl.running = '1') and (CPU_EXTENSION_RISCV_Sdext = true) then -- any other trap INSIDE debug mode
execute_engine.next_pc <= CPU_DEBUG_EXC_ADDR; -- debug mode enter: start at "parking loop" <exception_entry>
else -- normal start of trap
execute_engine.next_pc <= csr.mtvec(XLEN-1 downto 2) & "00";
if (csr.mtvec(1 downto 0) = "01") and (trap_ctrl.cause(6) = '1') then -- vectored mode + interrupt
execute_engine.next_pc <= csr.mtvec(XLEN-1 downto 7) & trap_ctrl.cause(4 downto 0) & "00"; -- pc = mtvec + 4 * mcause
else
execute_engine.next_pc <= csr.mtvec(XLEN-1 downto 2) & "00"; -- pc = mtvec
end if;
end if;
when TRAP_EXIT => -- leaving trap environment
if (debug_ctrl.running = '1') and (CPU_EXTENSION_RISCV_Sdext = true) then -- debug mode exit
Expand Down Expand Up @@ -1672,7 +1676,11 @@ begin
csr.mie_firq <= csr.wdata(31 downto 16);

when csr_mtvec_c => -- machine trap-handler base address
csr.mtvec <= csr.wdata(XLEN-1 downto 2) & "00"; -- mtvec.MODE=0 (direct)
if (csr.wdata(1 downto 0) = "01") then
csr.mtvec <= csr.wdata(XLEN-1 downto 7) & "00000" & "01"; -- mtvec.MODE=1 (vectored)
else
csr.mtvec <= csr.wdata(XLEN-1 downto 2) & "00"; -- mtvec.MODE=0 (direct)
end if;

when csr_mcounteren_c => -- machine counter access enable
if (CPU_EXTENSION_RISCV_U = true) then
Expand Down Expand Up @@ -1933,7 +1941,7 @@ begin
csr_rdata(31 downto 16) <= csr.mie_firq;

when csr_mtvec_c => -- machine trap-handler base address
csr_rdata <= csr.mtvec(XLEN-1 downto 2) & "00"; -- mtvec.MODE=0 (direct)
csr_rdata <= csr.mtvec;

when csr_mcounteren_c => -- machine counter enable register
if (CPU_EXTENSION_RISCV_U = true) then
Expand Down
2 changes: 1 addition & 1 deletion rtl/core/neorv32_package.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ package neorv32_package is

-- Architecture Constants -----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01080903"; -- hardware version
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01080904"; -- hardware version
constant archid_c : natural := 19; -- official RISC-V architecture ID
constant XLEN : natural := 32; -- native data path width, do not change!

Expand Down
2 changes: 1 addition & 1 deletion sim/neorv32_tb.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ begin
if ci_mode then
-- No need to send the full expectation in one big chunk
check_uart(net, uart1_rx_handle, nul & nul);
check_uart(net, uart1_rx_handle, "0/55" & cr & lf);
check_uart(net, uart1_rx_handle, "0/56" & cr & lf);
end if;

-- Wait until all expected data has been received
Expand Down
103 changes: 103 additions & 0 deletions sw/example/processor_check/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@
// Prototypes
void sim_irq_trigger(uint32_t sel);
void global_trap_handler(void);
void vectored_irq_table(void) __attribute__((naked, aligned(128)));
void vectored_global_handler(void) __attribute__((interrupt("machine")));
void vectored_mei_handler(void) __attribute__((interrupt("machine")));
void xirq_trap_handler0(void);
void xirq_trap_handler1(void);
void test_ok(void);
Expand All @@ -101,6 +104,8 @@ int cnt_ok = 0;
int cnt_test = 0;
/// Global number of available HPMs
uint32_t num_hpm_cnts_global = 0;
/// Vectored MEI trap handler acknowledge
volatile int vectored_mei_handler_ack = 0;
/// XIRQ trap handler acknowledge
uint32_t xirq_trap_handler_ack = 0;
/// DMA source & destination data
Expand Down Expand Up @@ -1037,6 +1042,49 @@ int main() {
}


// ----------------------------------------------------------
// Test vectored interrupt via testbench external interrupt
// ----------------------------------------------------------
neorv32_cpu_csr_write(CSR_MCAUSE, mcause_never_c);
PRINT_STANDARD("[%i] Vectored IRQ (sim) ", cnt_test);

if (neorv32_cpu_csr_read(CSR_MXISA) & (1 << CSR_MXISA_IS_SIM)) {
cnt_test++;

// back-up RTE
uint32_t mtvec_bak = neorv32_cpu_csr_read(CSR_MTVEC);

// install vector table and enable vector mode (mtvec[1:0] = 0b01)
neorv32_cpu_csr_write(CSR_MTVEC, (uint32_t)&vectored_irq_table | 0x1);

// enable interrupt
neorv32_cpu_csr_write(CSR_MIE, 1 << CSR_MIE_MEIE);

// trigger IRQ
sim_irq_trigger(1 << CSR_MIE_MEIE);

// wait some time for the IRQ to arrive the CPU
asm volatile ("nop");
asm volatile ("nop");

neorv32_cpu_csr_write(CSR_MIE, 0);
sim_irq_trigger(0);

if (vectored_mei_handler_ack == 1) {
test_ok();
}
else {
test_fail();
}

// restore RTE
neorv32_cpu_csr_write(CSR_MTVEC, mtvec_bak);
}
else {
PRINT_STANDARD("[n.a.]\n");
}


// ----------------------------------------------------------
// Fast interrupt channel 0 (WDT)
// ----------------------------------------------------------
Expand Down Expand Up @@ -2120,6 +2168,61 @@ void global_trap_handler(void) {
}


/**********************************************************************//**
* Vectored mtvec mode jump table.
**************************************************************************/
void vectored_irq_table(void) {
asm volatile(
".org vectored_irq_table + 0*4 \n"
"jal zero, %[glb] \n" // 0
".org vectored_irq_table + 3*4 \n"
"jal zero, %[glb] \n" // 3
".org vectored_irq_table + 7*4 \n"
"jal zero, %[glb] \n" // 7
".org vectored_irq_table + 11*4 \n"
"jal zero, %[mei] \n" // 11
".org vectored_irq_table + 16*4 \n"
"jal zero, %[glb] \n"
"jal zero, %[glb] \n"
"jal zero, %[glb] \n"
"jal zero, %[glb] \n"
"jal zero, %[glb] \n"
"jal zero, %[glb] \n"
"jal zero, %[glb] \n"
"jal zero, %[glb] \n"
"jal zero, %[glb] \n"
"jal zero, %[glb] \n"
"jal zero, %[glb] \n"
"jal zero, %[glb] \n"
"jal zero, %[glb] \n"
"jal zero, %[glb] \n"
"jal zero, %[glb] \n"
"jal zero, %[glb] "
: : [glb] "i" ((uint32_t)&vectored_global_handler), [mei] "i" ((uint32_t)&vectored_mei_handler)
);
}


/**********************************************************************//**
* Vectored trap handler for ALL exceptions/interrupts.
**************************************************************************/
void vectored_global_handler(void) {

// Call the default trap handler, cannot be put into the vector table directly
// as all function in the table must have the gcc attribute "interrupt".
global_trap_handler();
}


/**********************************************************************//**
* Machine external interrupt handler.
**************************************************************************/
void vectored_mei_handler(void) {

vectored_mei_handler_ack = 1; // successfully called
}


/**********************************************************************//**
* XIRQ handler channel 0.
**************************************************************************/
Expand Down