Rework RTE trap handler look-up-table (#1295)
Some checks failed
Documentation / SW Framework (push) Has been cancelled
Documentation / Datasheet (push) Has been cancelled
Processor / processor simulation (push) Has been cancelled
Documentation / Deploy to Releases and Pages (push) Has been cancelled

This commit is contained in:
stnolting 2025-06-22 21:11:25 +02:00 committed by GitHub
commit 2eae568b01
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 100 additions and 128 deletions

View file

@ -126,7 +126,6 @@ void __attribute__((constructor)) neorv32_constructor() {
int main() {
uint32_t tmp_a, tmp_b;
uint8_t id;
// disable machine-mode interrupts
neorv32_cpu_csr_clr(CSR_MSTATUS, 1 << CSR_MSTATUS_MIE);
@ -145,10 +144,38 @@ int main() {
// -----------------------------------------------
neorv32_rte_setup(); // this will install a full-detailed debug handler for ALL traps
int install_err = 0;
// initialize ALL provided trap handler (overriding the default debug handlers)
for (id=0; id<NEORV32_RTE_NUM_TRAPS; id++) {
install_err += neorv32_rte_handler_install(id, global_trap_handler);
}
// synchronous exceptions
install_err += neorv32_rte_handler_install(RTE_TRAP_I_ACCESS, global_trap_handler);
install_err += neorv32_rte_handler_install(RTE_TRAP_I_ILLEGAL, global_trap_handler);
install_err += neorv32_rte_handler_install(RTE_TRAP_I_MISALIGNED, global_trap_handler);
install_err += neorv32_rte_handler_install(RTE_TRAP_BREAKPOINT, global_trap_handler);
install_err += neorv32_rte_handler_install(RTE_TRAP_L_MISALIGNED, global_trap_handler);
install_err += neorv32_rte_handler_install(RTE_TRAP_L_ACCESS, global_trap_handler);
install_err += neorv32_rte_handler_install(RTE_TRAP_S_MISALIGNED, global_trap_handler);
install_err += neorv32_rte_handler_install(RTE_TRAP_S_ACCESS, global_trap_handler);
install_err += neorv32_rte_handler_install(RTE_TRAP_UENV_CALL, global_trap_handler);
install_err += neorv32_rte_handler_install(RTE_TRAP_MENV_CALL, global_trap_handler);
install_err += neorv32_rte_handler_install(RTE_TRAP_DOUBLE_TRAP, global_trap_handler);
// asynchronous exceptions (interrupts)
install_err += neorv32_rte_handler_install(RTE_TRAP_MSI, global_trap_handler);
install_err += neorv32_rte_handler_install(RTE_TRAP_MTI, global_trap_handler);
install_err += neorv32_rte_handler_install(RTE_TRAP_MEI, global_trap_handler);
install_err += neorv32_rte_handler_install(RTE_TRAP_FIRQ_0, global_trap_handler);
install_err += neorv32_rte_handler_install(RTE_TRAP_FIRQ_1, global_trap_handler);
install_err += neorv32_rte_handler_install(RTE_TRAP_FIRQ_2, global_trap_handler);
install_err += neorv32_rte_handler_install(RTE_TRAP_FIRQ_3, global_trap_handler);
install_err += neorv32_rte_handler_install(RTE_TRAP_FIRQ_4, global_trap_handler);
install_err += neorv32_rte_handler_install(RTE_TRAP_FIRQ_5, global_trap_handler);
install_err += neorv32_rte_handler_install(RTE_TRAP_FIRQ_6, global_trap_handler);
install_err += neorv32_rte_handler_install(RTE_TRAP_FIRQ_7, global_trap_handler);
install_err += neorv32_rte_handler_install(RTE_TRAP_FIRQ_8, global_trap_handler);
install_err += neorv32_rte_handler_install(RTE_TRAP_FIRQ_9, global_trap_handler);
install_err += neorv32_rte_handler_install(RTE_TRAP_FIRQ_10, global_trap_handler);
install_err += neorv32_rte_handler_install(RTE_TRAP_FIRQ_11, global_trap_handler);
install_err += neorv32_rte_handler_install(RTE_TRAP_FIRQ_12, global_trap_handler);
install_err += neorv32_rte_handler_install(RTE_TRAP_FIRQ_13, global_trap_handler);
install_err += neorv32_rte_handler_install(RTE_TRAP_FIRQ_14, global_trap_handler);
install_err += neorv32_rte_handler_install(RTE_TRAP_FIRQ_15, global_trap_handler);
if (install_err) {
PRINT_CRITICAL("RTE fail!\n");
return 1;

View file

@ -1,13 +1,9 @@
# Application makefile.
# Use this makefile to configure all relevant CPU / compiler options.
# Processor-check program makefile
# Override the default CPU ISA
# Maximum ISA configuration (but without C)
override MARCH = rv32ima_zba_zbb_zbs_zbkb_zbkc_zbkx_zknd_zkne_zknh_zksh_zksed_zicsr_zfinx_zifencei_zicond
# Override the default RISC-V GCC prefix
#RISCV_PREFIX ?= riscv-none-elf-
# Override default optimization goal
# Optimization goal
EFFORT = -Os
# Add extended debug symbols
@ -23,15 +19,11 @@ override USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=32k
override USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
# Adjust maximum heap size
override USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=3096
override USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=3k
# Simulation arguments
override GHDL_RUN_FLAGS ?= --stop-time=15ms
# Additional sources
#APP_SRC += $(wildcard ./*.c)
#APP_INC += -I .
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..

View file

@ -20,43 +20,41 @@
* NEORV32 runtime environment trap IDs.
**************************************************************************/
/**@{*/
/**< Trap ID enumeration */
enum NEORV32_RTE_TRAP_enum {
// --- synchronous exceptions ---
RTE_TRAP_I_ACCESS = 0, /**< Instruction access fault */
RTE_TRAP_I_ILLEGAL = 1, /**< Illegal instruction */
RTE_TRAP_I_MISALIGNED = 2, /**< Instruction address misaligned */
RTE_TRAP_BREAKPOINT = 3, /**< Breakpoint (EBREAK instruction) */
RTE_TRAP_L_MISALIGNED = 4, /**< Load address misaligned */
RTE_TRAP_L_ACCESS = 5, /**< Load access fault */
RTE_TRAP_S_MISALIGNED = 6, /**< Store address misaligned */
RTE_TRAP_S_ACCESS = 7, /**< Store access fault */
RTE_TRAP_UENV_CALL = 8, /**< Environment call from user mode (ECALL instruction) */
RTE_TRAP_MENV_CALL = 9, /**< Environment call from machine mode (ECALL instruction) */
RTE_TRAP_DOUBLE_TRAP = 10,/**< Double-trap */
// --- asynchronous exceptions ---
RTE_TRAP_MSI = 11, /**< Machine software interrupt */
RTE_TRAP_MTI = 12, /**< Machine timer interrupt */
RTE_TRAP_MEI = 13, /**< Machine external interrupt */
RTE_TRAP_FIRQ_0 = 14, /**< Fast interrupt channel 0 */
RTE_TRAP_FIRQ_1 = 15, /**< Fast interrupt channel 1 */
RTE_TRAP_FIRQ_2 = 16, /**< Fast interrupt channel 2 */
RTE_TRAP_FIRQ_3 = 17, /**< Fast interrupt channel 3 */
RTE_TRAP_FIRQ_4 = 18, /**< Fast interrupt channel 4 */
RTE_TRAP_FIRQ_5 = 19, /**< Fast interrupt channel 5 */
RTE_TRAP_FIRQ_6 = 20, /**< Fast interrupt channel 6 */
RTE_TRAP_FIRQ_7 = 21, /**< Fast interrupt channel 7 */
RTE_TRAP_FIRQ_8 = 22, /**< Fast interrupt channel 8 */
RTE_TRAP_FIRQ_9 = 23, /**< Fast interrupt channel 9 */
RTE_TRAP_FIRQ_10 = 24, /**< Fast interrupt channel 10 */
RTE_TRAP_FIRQ_11 = 25, /**< Fast interrupt channel 11 */
RTE_TRAP_FIRQ_12 = 26, /**< Fast interrupt channel 12 */
RTE_TRAP_FIRQ_13 = 27, /**< Fast interrupt channel 13 */
RTE_TRAP_FIRQ_14 = 28, /**< Fast interrupt channel 14 */
RTE_TRAP_FIRQ_15 = 29 /**< Fast interrupt channel 15 */
};
/**< Total number of trap IDs */
#define NEORV32_RTE_NUM_TRAPS 30
/**< Synchronous exceptions */
#define RTE_TRAP_I_ACCESS TRAP_CODE_I_MISALIGNED /**< Instruction access fault */
#define RTE_TRAP_I_ILLEGAL TRAP_CODE_I_ACCESS /**< Illegal instruction */
#define RTE_TRAP_I_MISALIGNED TRAP_CODE_I_ILLEGAL /**< Instruction address misaligned */
#define RTE_TRAP_BREAKPOINT TRAP_CODE_BREAKPOINT /**< Breakpoint (EBREAK instruction) */
#define RTE_TRAP_L_MISALIGNED TRAP_CODE_L_MISALIGNED /**< Load address misaligned */
#define RTE_TRAP_L_ACCESS TRAP_CODE_L_ACCESS /**< Load access fault */
#define RTE_TRAP_S_MISALIGNED TRAP_CODE_S_MISALIGNED /**< Store address misaligned */
#define RTE_TRAP_S_ACCESS TRAP_CODE_S_ACCESS /**< Store access fault */
#define RTE_TRAP_UENV_CALL TRAP_CODE_UENV_CALL /**< Environment call from user mode (ECALL instruction) */
#define RTE_TRAP_MENV_CALL TRAP_CODE_MENV_CALL /**< Environment call from machine mode (ECALL instruction) */
#define RTE_TRAP_DOUBLE_TRAP TRAP_CODE_DOUBLE_TRAP /**< Double-trap */
/**< Asynchronous exceptions */
#define RTE_TRAP_MSI TRAP_CODE_MSI /**< Machine software interrupt */
#define RTE_TRAP_MTI TRAP_CODE_MTI /**< Machine timer interrupt */
#define RTE_TRAP_MEI TRAP_CODE_MEI /**< Machine external interrupt */
#define RTE_TRAP_FIRQ_0 TRAP_CODE_FIRQ_0 /**< Fast interrupt channel 0 */
#define RTE_TRAP_FIRQ_1 TRAP_CODE_FIRQ_1 /**< Fast interrupt channel 1 */
#define RTE_TRAP_FIRQ_2 TRAP_CODE_FIRQ_2 /**< Fast interrupt channel 2 */
#define RTE_TRAP_FIRQ_3 TRAP_CODE_FIRQ_3 /**< Fast interrupt channel 3 */
#define RTE_TRAP_FIRQ_4 TRAP_CODE_FIRQ_4 /**< Fast interrupt channel 4 */
#define RTE_TRAP_FIRQ_5 TRAP_CODE_FIRQ_5 /**< Fast interrupt channel 5 */
#define RTE_TRAP_FIRQ_6 TRAP_CODE_FIRQ_6 /**< Fast interrupt channel 6 */
#define RTE_TRAP_FIRQ_7 TRAP_CODE_FIRQ_7 /**< Fast interrupt channel 7 */
#define RTE_TRAP_FIRQ_8 TRAP_CODE_FIRQ_8 /**< Fast interrupt channel 8 */
#define RTE_TRAP_FIRQ_9 TRAP_CODE_FIRQ_9 /**< Fast interrupt channel 9 */
#define RTE_TRAP_FIRQ_10 TRAP_CODE_FIRQ_10 /**< Fast interrupt channel 10 */
#define RTE_TRAP_FIRQ_11 TRAP_CODE_FIRQ_11 /**< Fast interrupt channel 11 */
#define RTE_TRAP_FIRQ_12 TRAP_CODE_FIRQ_12 /**< Fast interrupt channel 12 */
#define RTE_TRAP_FIRQ_13 TRAP_CODE_FIRQ_13 /**< Fast interrupt channel 13 */
#define RTE_TRAP_FIRQ_14 TRAP_CODE_FIRQ_14 /**< Fast interrupt channel 14 */
#define RTE_TRAP_FIRQ_15 TRAP_CODE_FIRQ_15 /**< Fast interrupt channel 15 */
/**< Total number of trap codes */
#define NEORV32_RTE_NUM_TRAPS (2*32)
/**@}*/
/**********************************************************************//**
@ -65,7 +63,7 @@ enum NEORV32_RTE_TRAP_enum {
/**@{*/
void neorv32_rte_setup(void);
void neorv32_rte_core(void);
int neorv32_rte_handler_install(int id, void (*handler)(void));
int neorv32_rte_handler_install(uint32_t code, void (*handler)(void));
void neorv32_rte_debug_handler(void);
uint32_t neorv32_rte_context_get(int x);
void neorv32_rte_context_put(int x, uint32_t data);

View file

@ -13,21 +13,13 @@
#include <neorv32.h>
// ------------------------------------------------------------------------------------------------
// RTE private variables and functions
// ------------------------------------------------------------------------------------------------
// private trap vector look-up table (for all cores!)
static volatile uint32_t __neorv32_rte_vector_lut[NEORV32_RTE_NUM_TRAPS];
static volatile uint32_t __attribute__((aligned(4))) __neorv32_rte_vector_lut[2][32];
// private helper functions
static void __neorv32_rte_print_hex(uint32_t num, int digits);
// ------------------------------------------------------------------------------------------------
// RTE core functions
// ------------------------------------------------------------------------------------------------
/**********************************************************************//**
* NEORV32 runtime environment (RTE):
* Setup RTE.
@ -43,8 +35,8 @@ void neorv32_rte_setup(void) {
// clear mstatus, set previous privilege level to machine-mode
neorv32_cpu_csr_write(CSR_MSTATUS, (1<<CSR_MSTATUS_MPP_H) | (1<<CSR_MSTATUS_MPP_L));
// configure trap handler base address
neorv32_cpu_csr_write(CSR_MTVEC, (uint32_t)(&neorv32_rte_core));
// configure trap handler base address (direct mode)
neorv32_cpu_csr_write(CSR_MTVEC, (uint32_t)(&neorv32_rte_core) & 0xfffffffcU);
// disable all IRQ channels
neorv32_cpu_csr_write(CSR_MIE, 0);
@ -52,12 +44,12 @@ void neorv32_rte_setup(void) {
// install debug handler for all trap sources (executed only on core 0)
if (neorv32_cpu_csr_read(CSR_MHARTID) == 0) {
int index;
for (index = 0; index < ((int)NEORV32_RTE_NUM_TRAPS); index++) {
__neorv32_rte_vector_lut[index] = (uint32_t)(&neorv32_rte_debug_handler);
for (index = 0; index < 32; index++) {
__neorv32_rte_vector_lut[0][index] = (uint32_t)(&neorv32_rte_debug_handler);
__neorv32_rte_vector_lut[1][index] = (uint32_t)(&neorv32_rte_debug_handler);
}
asm volatile ("fence"); // flush handler table to main memory
}
asm volatile ("fence"); // flush handler table to main memory
}
@ -68,24 +60,22 @@ void neorv32_rte_setup(void) {
* @note Trap handler installation applies to both cores. Hence, both
* cores will execute the same handler for the same trap.
*
* @param[in] id Identifier (type) of the targeted trap
* @param[in] code Identifier (type) of the targeted trap
* See #NEORV32_RTE_TRAP_enum.
*
* @param[in] handler The actual handler function for the specified trap
* (function MUST be of type "void function(void);").
* (function must be of type "void function(void);").
*
* @return 0 if success, -1 if invalid trap ID.
* @return 0 if success, -1 if invalid trap code.
**************************************************************************/
int neorv32_rte_handler_install(int id, void (*handler)(void)) {
int neorv32_rte_handler_install(uint32_t code, void (*handler)(void)) {
// check if invalid trap ID
if ((uint32_t)id < NEORV32_RTE_NUM_TRAPS) {
__neorv32_rte_vector_lut[id] = (uint32_t)handler; // install handler
asm volatile ("fence"); // flush updated handler table to main memory
return 0;
if (code & (~0x8000001fU)) { // invalid trap code
return -1;
}
else {
return -1;
__neorv32_rte_vector_lut[code >> 31][code] = (uint32_t)handler;
return 0;
}
}
@ -150,41 +140,10 @@ void __attribute__((__naked__,aligned(4))) neorv32_rte_core(void) {
// reload trap table from main memory
asm volatile ("fence");
// find according trap handler base address
// get trap handler base address
uint32_t mcause = neorv32_cpu_csr_read(CSR_MCAUSE);
uint32_t handler_base = 0;
switch (neorv32_cpu_csr_read(CSR_MCAUSE)) {
case TRAP_CODE_I_ACCESS: handler_base = __neorv32_rte_vector_lut[RTE_TRAP_I_ACCESS]; break;
case TRAP_CODE_I_ILLEGAL: handler_base = __neorv32_rte_vector_lut[RTE_TRAP_I_ILLEGAL]; break;
case TRAP_CODE_I_MISALIGNED: handler_base = __neorv32_rte_vector_lut[RTE_TRAP_I_MISALIGNED]; break;
case TRAP_CODE_BREAKPOINT: handler_base = __neorv32_rte_vector_lut[RTE_TRAP_BREAKPOINT]; break;
case TRAP_CODE_L_MISALIGNED: handler_base = __neorv32_rte_vector_lut[RTE_TRAP_L_MISALIGNED]; break;
case TRAP_CODE_L_ACCESS: handler_base = __neorv32_rte_vector_lut[RTE_TRAP_L_ACCESS]; break;
case TRAP_CODE_S_MISALIGNED: handler_base = __neorv32_rte_vector_lut[RTE_TRAP_S_MISALIGNED]; break;
case TRAP_CODE_S_ACCESS: handler_base = __neorv32_rte_vector_lut[RTE_TRAP_S_ACCESS]; break;
case TRAP_CODE_UENV_CALL: handler_base = __neorv32_rte_vector_lut[RTE_TRAP_UENV_CALL]; break;
case TRAP_CODE_MENV_CALL: handler_base = __neorv32_rte_vector_lut[RTE_TRAP_MENV_CALL]; break;
case TRAP_CODE_DOUBLE_TRAP: handler_base = __neorv32_rte_vector_lut[RTE_TRAP_DOUBLE_TRAP]; break;
case TRAP_CODE_MSI: handler_base = __neorv32_rte_vector_lut[RTE_TRAP_MSI]; break;
case TRAP_CODE_MTI: handler_base = __neorv32_rte_vector_lut[RTE_TRAP_MTI]; break;
case TRAP_CODE_MEI: handler_base = __neorv32_rte_vector_lut[RTE_TRAP_MEI]; break;
case TRAP_CODE_FIRQ_0: handler_base = __neorv32_rte_vector_lut[RTE_TRAP_FIRQ_0]; break;
case TRAP_CODE_FIRQ_1: handler_base = __neorv32_rte_vector_lut[RTE_TRAP_FIRQ_1]; break;
case TRAP_CODE_FIRQ_2: handler_base = __neorv32_rte_vector_lut[RTE_TRAP_FIRQ_2]; break;
case TRAP_CODE_FIRQ_3: handler_base = __neorv32_rte_vector_lut[RTE_TRAP_FIRQ_3]; break;
case TRAP_CODE_FIRQ_4: handler_base = __neorv32_rte_vector_lut[RTE_TRAP_FIRQ_4]; break;
case TRAP_CODE_FIRQ_5: handler_base = __neorv32_rte_vector_lut[RTE_TRAP_FIRQ_5]; break;
case TRAP_CODE_FIRQ_6: handler_base = __neorv32_rte_vector_lut[RTE_TRAP_FIRQ_6]; break;
case TRAP_CODE_FIRQ_7: handler_base = __neorv32_rte_vector_lut[RTE_TRAP_FIRQ_7]; break;
case TRAP_CODE_FIRQ_8: handler_base = __neorv32_rte_vector_lut[RTE_TRAP_FIRQ_8]; break;
case TRAP_CODE_FIRQ_9: handler_base = __neorv32_rte_vector_lut[RTE_TRAP_FIRQ_9]; break;
case TRAP_CODE_FIRQ_10: handler_base = __neorv32_rte_vector_lut[RTE_TRAP_FIRQ_10]; break;
case TRAP_CODE_FIRQ_11: handler_base = __neorv32_rte_vector_lut[RTE_TRAP_FIRQ_11]; break;
case TRAP_CODE_FIRQ_12: handler_base = __neorv32_rte_vector_lut[RTE_TRAP_FIRQ_12]; break;
case TRAP_CODE_FIRQ_13: handler_base = __neorv32_rte_vector_lut[RTE_TRAP_FIRQ_13]; break;
case TRAP_CODE_FIRQ_14: handler_base = __neorv32_rte_vector_lut[RTE_TRAP_FIRQ_14]; break;
case TRAP_CODE_FIRQ_15: handler_base = __neorv32_rte_vector_lut[RTE_TRAP_FIRQ_15]; break;
default: handler_base = (uint32_t)(&neorv32_rte_debug_handler); break;
}
handler_base = __neorv32_rte_vector_lut[mcause >> 31][mcause & 31];
// call handler
if (handler_base != 0) {
@ -195,21 +154,20 @@ void __attribute__((__naked__,aligned(4))) neorv32_rte_core(void) {
// compute return address (for exceptions only)
// do not alter return address if instruction access exception (fatal?)
uint32_t cause = neorv32_cpu_csr_read(CSR_MCAUSE);
if (((cause >> 31) == 0) && (cause != TRAP_CODE_I_ACCESS)) {
if (((mcause >> 31) == 0) && (mcause != TRAP_CODE_I_ACCESS)) {
uint32_t rte_mepc = neorv32_cpu_csr_read(CSR_MEPC);
rte_mepc += 4; // default: faulting instruction is uncompressed
uint32_t mepc = neorv32_cpu_csr_read(CSR_MEPC);
mepc += 4; // default: faulting instruction is uncompressed
#ifdef __riscv_c
// adjust return address if compressed instruction
if (neorv32_cpu_csr_read(CSR_MISA) & (1 << CSR_MISA_C)) { // C extension implemented?
if ((neorv32_cpu_csr_read(CSR_MTINST) & 3) != 3) { // faulting instruction is compressed instruction
rte_mepc -= 2;
}
if ((neorv32_cpu_csr_read(CSR_MTINST) & 3) != 3) { // faulting instruction is compressed instruction
mepc -= 2;
}
#endif
// update return address
neorv32_cpu_csr_write(CSR_MEPC, rte_mepc);
neorv32_cpu_csr_write(CSR_MEPC, mepc);
}
// restore context
@ -404,10 +362,6 @@ void neorv32_rte_debug_handler(void) {
}
// ------------------------------------------------------------------------------------------------
// Private helper functions
// ------------------------------------------------------------------------------------------------
/**********************************************************************//**
* NEORV32 runtime environment (RTE):
* Private function to print the lowest 0 to 8 hex characters of a
@ -417,7 +371,7 @@ void neorv32_rte_debug_handler(void) {
*
* @param[in] digits Number of hexadecimal digits to print (0..8).
**************************************************************************/
void __neorv32_rte_print_hex(uint32_t num, int digits) {
static void __neorv32_rte_print_hex(uint32_t num, int digits) {
int i = 0;
const char hex_symbols[] = "0123456789ABCDEF";
@ -432,3 +386,4 @@ void __neorv32_rte_print_hex(uint32_t num, int digits) {
}
}
}