updated and optimized RTE - smaller, faster, better ;)

This commit is contained in:
stnolting 2020-07-23 21:41:55 +02:00
parent 8ade8ad170
commit 11f30c7885
4 changed files with 185 additions and 241 deletions

View file

@ -43,11 +43,11 @@
// IO region
.set IO_BEGIN, 0xFFFFFF80 // start of processor-internal IO region
.equ IO_BEGIN, 0xFFFFFF80 // start of processor-internal IO region
// SYSINFO
.set SYSINFO_DSPACE_BASE, 0xFFFFFFF4
.set SYSINFO_DSPACE_SIZE, 0xFFFFFFFC
.equ SYSINFO_DSPACE_BASE, 0xFFFFFFF4
.equ SYSINFO_DSPACE_SIZE, 0xFFFFFFFC
_start:
@ -58,9 +58,8 @@ _start:
// Clear register file
// *********************************************************
__crt0_reg_file_clear:
addi x0, x0, 0 // hardwired to zero
//addi x0, x0, 0 // hardwired to zero
addi x1, x0, 0
__crt0_reg_file_init:
addi x2, x1, 0
addi x3, x2, 0
addi x4, x3, 0
@ -78,7 +77,7 @@ __crt0_reg_file_init:
// the following registers do not exist in rv32e
// "__RISCV_EMBEDDED_CPU__" is automatically defined by the makefiles when
// compiling for a rv32e architecture
// compiling for a rv32e* architecture
#ifndef __RISCV_EMBEDDED_CPU__
addi x16, x15, 0
addi x17, x16, 0
@ -100,7 +99,7 @@ __crt0_reg_file_init:
// *********************************************************
// TEST AREA / DANGER ZONE / IDEA-LAB
// TEST AREA / DANGER ZONE
// *********************************************************
__crt0_tests:
nop
@ -128,22 +127,12 @@ __crt0_global_pointer_init:
// *********************************************************
// Init exception vector table (2x16 4-byte entries) with dummy handlers
// Init trap handler base address
// *********************************************************
__crt0_neorv32_rte_init:
la x11, __crt0_neorv32_rte
__crt0_neorv32_trap_init:
la x11, __crt0_dummy_trap_handler
csrw mtvec, x11 // set address of first-level exception handler
lw x11, SYSINFO_DSPACE_BASE(zero) // data memory space base address
la x12, __crt0_neorv32_rte_dummy_hanlder
li x13, 2*16 // number of entries (16xEXC, 16xIRQ)
__crt0_neorv32_rte_init_loop:
sw x12, 0(x11) // set dummy handler
add x11, x11, 4
add x13, x13, -1
bne zero, x13, __crt0_neorv32_rte_init_loop
// *********************************************************
// Reset/deactivate IO/peripheral devices
@ -216,167 +205,44 @@ __crt0_this_is_the_end_end:
// *********************************************************
// NEORV32 runtime environment: First-level exception/interrupt handler
// dummy trap handler (for exceptions & IRQs)
// tries to move on to next instruction
// *********************************************************
.align 4
__crt0_neorv32_rte:
.balign 4
__crt0_dummy_trap_handler:
// --------------------------------------------
// full context save
// --------------------------------------------
#ifndef __RISCV_EMBEDDED_CPU__
addi sp, sp, -120
#else
addi sp, sp, -56
#endif
addi sp, sp, -8
sw x8, 0(sp)
sw x9, 4(sp)
sw ra,0(sp)
sw gp,4(sp)
sw tp,8(sp)
sw t0,12(sp)
sw t1,16(sp)
sw t2,20(sp)
sw s0,24(sp)
sw s1,28(sp)
sw a0,32(sp)
sw a1,36(sp)
sw a2,40(sp)
sw a3,44(sp)
sw a4,48(sp)
sw a5,52(sp)
#ifndef __RISCV_EMBEDDED_CPU__
sw a6,56(sp)
sw a7,60(sp)
sw s2,64(sp)
sw s3,68(sp)
sw s4,72(sp)
sw s5,76(sp)
sw s6,80(sp)
sw s7,84(sp)
sw s8,88(sp)
sw s9,92(sp)
sw s10,96(sp)
sw s11,100(sp)
sw t3,104(sp)
sw t4,108(sp)
sw t5,112(sp)
sw t6,116(sp)
#endif
csrr x8, mcause
blt x8, zero, __crt0_dummy_trap_handler_irq // skip mepc modification if interrupt
__crt0_dummy_trap_handler_compute_return:
csrr x8, mepc
// --------------------------------------------
// get cause and prepare jump into vector table
// --------------------------------------------
csrr t0, mcause // get cause code
// is compressed instruction?
lh x9, 0(x8) // get compressed instruction or lower 16 bits of uncompressed instruction that caused exception
andi x9, zero, 3 // mask: isolate lowest 2 opcode bits (= 11 for uncompressed instructions)
andi t1, t0, 0x0f // isolate cause ID
slli t1, t1, 2 // make address offset
lw ra, SYSINFO_DSPACE_BASE(zero) // data memory space base address
add t1, t1, ra // get vetor table entry address (EXC vectors)
addi x8, x8, +2 // only this for compressed instructions
csrw mepc, x8 // set return address when compressed instruction
csrr ra, mepc // get return address
blt t0, zero, __crt0_neorv32_rte_is_irq // branch if this is an INTERRUPT
// --------------------------------------------
// compute return address for EXCEPTIONS only
// --------------------------------------------
__crt0_neorv32_rte_is_exc:
// check if faulting instruction is compressed and adjust return address
lh t0, 0(ra) // get compressed instruction or lower 16 bits of uncompressed instruction that caused exception
addi t2, zero, 3 // mask
and t0, t0, t2 // isolate lowest 2 opcode bits (= 11 for uncompressed instructions)
addi ra, ra, +2 // only this for compressed instructions
bne t0, t2, __crt0_neorv32_rte_execute // jump if compressed instruction
addi x8, zero, 3
bne x8, x9, __crt0_dummy_trap_handler_irq // jump if compressed instruction
addi ra, ra, +2 // add another 2 (making +4) for uncompressed instructions
j __crt0_neorv32_rte_execute
// is uncompressed instruction
csrr x8, mepc
addi x8, x8, +2 // add another 2 (making +4) for uncompressed instructions
csrw mepc, x8
__crt0_dummy_trap_handler_irq:
// --------------------------------------------
// vector table offset for INTERRUPTS only
// --------------------------------------------
__crt0_neorv32_rte_is_irq:
addi t1, t1, 16*4
lw x9, 0(sp)
lw x8, 4(sp)
addi sp, sp, +8
// --------------------------------------------
// call handler from vector table
// --------------------------------------------
__crt0_neorv32_rte_execute:
lw t0, 0(t1) // get base address of second-level handler
// push ra
addi sp, sp, -4
sw ra, 0(sp)
jalr ra, t0 // call second-level handler
// pop ra
lw ra, 0(sp)
addi sp, sp, +4
csrw mepc, ra
// --------------------------------------------
// full context restore
// --------------------------------------------
lw ra,0(sp)
lw gp,4(sp)
lw tp,8(sp)
lw t0,12(sp)
lw t1,16(sp)
lw t2,20(sp)
lw s0,24(sp)
lw s1,28(sp)
lw a0,32(sp)
lw a1,36(sp)
lw a2,40(sp)
lw a3,44(sp)
lw a4,48(sp)
lw a5,52(sp)
#ifndef __RISCV_EMBEDDED_CPU__
lw a6,56(sp)
lw a7,60(sp)
lw s2,64(sp)
lw s3,68(sp)
lw s4,72(sp)
lw s5,76(sp)
lw s6,80(sp)
lw s7,84(sp)
lw s8,88(sp)
lw s9,92(sp)
lw s10,96(sp)
lw s11,100(sp)
lw t3,104(sp)
lw t4,108(sp)
lw t5,112(sp)
lw t6,116(sp)
#endif
#ifndef __RISCV_EMBEDDED_CPU__
addi sp, sp, +120
#else
addi sp, sp, +56
#endif
// --------------------------------------------
// this is the ONLY place where MRET should be used!
// --------------------------------------------
mret
// *********************************************************
// Dummy exception handler: just move on to next instruction
// *********************************************************
__crt0_neorv32_rte_dummy_hanlder:
ret
.cfi_endproc
.end

View file

@ -53,9 +53,8 @@ SEARCH_DIR("=/opt/riscv/riscv64-unknown-linux-gnu/lib"); SEARCH_DIR("=/usr/local
/* ************************************************* */
MEMORY
{
rom (rx) : ORIGIN = 0x00000000, LENGTH = 16*1024
ram (rwx) : ORIGIN = 0x80000000 + 2*16*4, LENGTH = 8*1024
/* DO NOT REMOVE THE " + 2*16*4"!! */
rom (rx) : ORIGIN = 0x00000000, LENGTH = 16*1024
ram (rwx) : ORIGIN = 0x80000000, LENGTH = 8*1024
}
/* ************************************************* */

View file

@ -42,10 +42,32 @@
#ifndef neorv32_rte_h
#define neorv32_rte_h
/**********************************************************************//**
* RTE trap IDs.
**************************************************************************/
enum NEORV32_RTE_TRAP_enum {
RTE_TRAP_I_MISALIGNED = 0, /**< Instruction address misaligned */
RTE_TRAP_I_ACCESS = 1, /**< Instruction (bus) access fault */
RTE_TRAP_I_ILLEGAL = 2, /**< Illegal instruction */
RTE_TRAP_BREAKPOINT = 3, /**< Breakpoint (EBREAK instruction) */
RTE_TRAP_L_MISALIGNED = 4, /**< Load address misaligned */
RTE_TRAP_L_ACCESS = 5, /**< Load (bus) access fault */
RTE_TRAP_S_MISALIGNED = 6, /**< Store address misaligned */
RTE_TRAP_S_ACCESS = 7, /**< Store (bus) access fault */
RTE_TRAP_MENV_CALL = 8, /**< Environment call from machine mode (ECALL instruction) */
RTE_TRAP_MSI = 9, /**< Machine software interrupt */
RTE_TRAP_MTI = 10, /**< Machine timer interrupt */
RTE_TRAP_MEI = 11, /**< Machine external interrupt */
RTE_TRAP_FIRQ_0 = 12, /**< Fast interrupt channel 0 */
RTE_TRAP_FIRQ_1 = 13, /**< Fast interrupt channel 1 */
RTE_TRAP_FIRQ_2 = 14, /**< Fast interrupt channel 2 */
RTE_TRAP_FIRQ_3 = 15 /**< Fast interrupt channel 3 */
};
// prototypes
void neorv32_rte_enable_debug_mode(void);
int neorv32_rte_exception_install(uint8_t exc_id, void (*handler)(void));
int neorv32_rte_exception_uninstall(uint8_t exc_id);
void neorv32_rte_setup(void);
int neorv32_rte_exception_install(uint8_t id, void (*handler)(void));
int neorv32_rte_exception_uninstall(uint8_t id);
void neorv32_rte_print_hw_config(void);
void neorv32_rte_print_hw_version(void);

View file

@ -43,29 +43,29 @@
#include "neorv32_rte.h"
// Privates
static void __neorv32_rte_dummy_exc_handler(void) __attribute__((unused));
static uint32_t __neorv32_rte_vector_lut[16] __attribute__((unused)); // trap handler vector table
static void __attribute__((__interrupt__)) __neorv32_rte_core(void) __attribute__((aligned(16))) __attribute__((unused));
static void __neorv32_rte_debug_exc_handler(void) __attribute__((unused));
static void __neorv32_rte_print_true_false(int state) __attribute__((unused));
/**********************************************************************//**
* Setup NEORV32 runtime environment in debug mode.
* Setup NEORV32 runtime environment.
*
* @note This function installs a debug handler for ALL exception and interrupt sources, which
* gives detailed information about the exception/interrupt. Call this function before you
* install custom handler functions via neorv32_rte_exception_install(uint8_t exc_id, void (*handler)(void)),
* since this function will override all installed exception handlers.
*
* @warning This function should be used for debugging only, since it only shows the uninitialize exception/interrupt, but
* does not resolve the cause. Hence, it cannot guarantee to resume normal application execution after showing the debug messages.
* gives detailed information about the exception/interrupt. Actual handler can be installed afterwards
* via neorv32_rte_exception_install(uint8_t id, void (*handler)(void)).
**************************************************************************/
void neorv32_rte_enable_debug_mode(void) {
void neorv32_rte_setup(void) {
uint8_t id;
// configure trap handler base address
uint32_t mtvec_base = (uint32_t)(&__neorv32_rte_core);
neorv32_cpu_csr_write(CSR_MTVEC, mtvec_base);
// install debug handler for all sources
for (id=0; id<32; id++) {
neorv32_rte_exception_install(id, __neorv32_rte_debug_exc_handler);
uint8_t id;
for (id = 0; id < (sizeof(__neorv32_rte_vector_lut)/sizeof(__neorv32_rte_vector_lut[0])); id++) {
neorv32_rte_exception_uninstall(id); // this will configure the debug handler
}
}
@ -74,28 +74,32 @@ void neorv32_rte_enable_debug_mode(void) {
* Install exception handler function to NEORV32 runtime environment.
*
* @note This function automatically activates the according CSR.mie bits when installing handlers for
* the MTIME (MTI), CLIC (MEI) or machine software interrupt (MSI). The global interrupt enable bit mstatus.mie has
* the MTIME (MTI), CLIC (MEI), machine software interrupt (MSI) or a fast IRQ. The global interrupt enable bit mstatus.mie has
* to be set by the user via neorv32_cpu_eint(void).
*
* @param[in] exc_id Identifier (type) of the targeted exception. See #NEORV32_EXCEPTION_IDS_enum.
* @param[in] handler The actual handler function for the specified exception (function must be of type "void function(void);").
* return 0 if success, 1 if error (invalid exc_id or targeted exception not supported).
* @param[in] id Identifier (type) of the targeted exception. See #NEORV32_RTE_TRAP_enum.
* @param[in] handler The actual handler function for the specified exception (function MUST be of type "void function(void);").
* return 0 if success, 1 if error (invalid id or targeted exception not supported).
**************************************************************************/
int neorv32_rte_exception_install(uint8_t exc_id, void (*handler)(void)) {
int neorv32_rte_exception_install(uint8_t id, void (*handler)(void)) {
// id valid?
if ((exc_id == EXCID_I_MISALIGNED) || (exc_id == EXCID_I_ACCESS) || (exc_id == EXCID_I_ILLEGAL) ||
(exc_id == EXCID_BREAKPOINT) || (exc_id == EXCID_L_MISALIGNED) || (exc_id == EXCID_L_ACCESS) ||
(exc_id == EXCID_S_MISALIGNED) || (exc_id == EXCID_S_ACCESS) || (exc_id == EXCID_MENV_CALL) ||
(exc_id == EXCID_MSI) || (exc_id == EXCID_MTI) || (exc_id == EXCID_MEI)) {
if ((id == RTE_TRAP_I_MISALIGNED) || (id == RTE_TRAP_I_ACCESS) || (id == RTE_TRAP_I_ILLEGAL) ||
(id == RTE_TRAP_BREAKPOINT) || (id == RTE_TRAP_L_MISALIGNED) || (id == RTE_TRAP_L_ACCESS) ||
(id == RTE_TRAP_S_MISALIGNED) || (id == RTE_TRAP_S_ACCESS) || (id == RTE_TRAP_MENV_CALL) ||
(id == RTE_TRAP_MSI) || (id == RTE_TRAP_MTI) || (id == RTE_TRAP_MEI) ||
(id == RTE_TRAP_FIRQ_0) || (id == RTE_TRAP_FIRQ_1) || (id == RTE_TRAP_FIRQ_2) || (id == RTE_TRAP_FIRQ_3)) {
if (exc_id == EXCID_MSI) { neorv32_cpu_irq_enable(CPU_MIE_MSIE); } // activate software interrupt
if (exc_id == EXCID_MTI) { neorv32_cpu_irq_enable(CPU_MIE_MTIE); } // activate timer interrupt
if (exc_id == EXCID_MEI) { neorv32_cpu_irq_enable(CPU_MIE_MEIE); } // activate external interrupt
uint32_t vt_base = SYSINFO_DSPACE_BASE; // base address of vector table
vt_base = vt_base + (((uint32_t)exc_id) << 2);
(*(IO_REG32 (vt_base))) = (uint32_t)handler;
if (id == RTE_TRAP_MSI) { neorv32_cpu_irq_enable(CPU_MIE_MSIE); } // activate software interrupt
if (id == RTE_TRAP_MTI) { neorv32_cpu_irq_enable(CPU_MIE_MTIE); } // activate timer interrupt
if (id == RTE_TRAP_MEI) { neorv32_cpu_irq_enable(CPU_MIE_MEIE); } // activate external interrupt
if (id == RTE_TRAP_FIRQ_0) { neorv32_cpu_irq_enable(CPU_MIE_FIRQ0E); } // activate fast interrupt channel 0
if (id == RTE_TRAP_FIRQ_1) { neorv32_cpu_irq_enable(CPU_MIE_FIRQ1E); } // activate fast interrupt channel 1
if (id == RTE_TRAP_FIRQ_2) { neorv32_cpu_irq_enable(CPU_MIE_FIRQ2E); } // activate fast interrupt channel 2
if (id == RTE_TRAP_FIRQ_3) { neorv32_cpu_irq_enable(CPU_MIE_FIRQ3E); } // activate fast interrupt channel 3
__neorv32_rte_vector_lut[id] = (uint32_t)handler; // install handler
return 0;
}
@ -105,30 +109,33 @@ int neorv32_rte_exception_install(uint8_t exc_id, void (*handler)(void)) {
/**********************************************************************//**
* Uninstall exception handler function from NEORV32 runtime environment, which was
* previously installed via neorv32_rte_exception_install(uint8_t exc_id, void (*handler)(void)).
* previously installed via neorv32_rte_exception_install(uint8_t id, void (*handler)(void)).
*
* @note This function automatically clears the according CSR.mie bits when uninstalling handlers for
* the MTIME (MTI), CLIC (MEI) or machine software interrupt (MSI). The global interrupt enable bit mstatus.mie has
* the MTIME (MTI), CLIC (MEI), machine software interrupt (MSI) or fast IRQs. The global interrupt enable bit mstatus.mie has
* to be cleared by the user via neorv32_cpu_dint(void).
*
* @param[in] exc_id Identifier (type) of the targeted exception. See #NEORV32_EXCEPTION_IDS_enum.
* return 0 if success, 1 if error (invalid exc_id or targeted exception not supported).
* @param[in] id Identifier (type) of the targeted exception. See #NEORV32_RTE_TRAP_enum.
* return 0 if success, 1 if error (invalid id or targeted exception not supported).
**************************************************************************/
int neorv32_rte_exception_uninstall(uint8_t exc_id) {
int neorv32_rte_exception_uninstall(uint8_t id) {
// id valid?
if ((exc_id == EXCID_I_MISALIGNED) || (exc_id == EXCID_I_ACCESS) || (exc_id == EXCID_I_ILLEGAL) ||
(exc_id == EXCID_BREAKPOINT) || (exc_id == EXCID_L_MISALIGNED) || (exc_id == EXCID_L_ACCESS) ||
(exc_id == EXCID_S_MISALIGNED) || (exc_id == EXCID_S_ACCESS) || (exc_id == EXCID_MENV_CALL) ||
(exc_id == EXCID_MSI) || (exc_id == EXCID_MTI) || (exc_id == EXCID_MEI)) {
if ((id == RTE_TRAP_I_MISALIGNED) || (id == RTE_TRAP_I_ACCESS) || (id == RTE_TRAP_I_ILLEGAL) ||
(id == RTE_TRAP_BREAKPOINT) || (id == RTE_TRAP_L_MISALIGNED) || (id == RTE_TRAP_L_ACCESS) ||
(id == RTE_TRAP_S_MISALIGNED) || (id == RTE_TRAP_S_ACCESS) || (id == RTE_TRAP_MENV_CALL) ||
(id == RTE_TRAP_MSI) || (id == RTE_TRAP_MTI) || (id == RTE_TRAP_MEI) ||
(id == RTE_TRAP_FIRQ_0) || (id == RTE_TRAP_FIRQ_1) || (id == RTE_TRAP_FIRQ_2) || (id == RTE_TRAP_FIRQ_3)) {
if (exc_id == EXCID_MSI) { neorv32_cpu_irq_disable(CPU_MIE_MSIE); } // deactivate software interrupt
if (exc_id == EXCID_MTI) { neorv32_cpu_irq_disable(CPU_MIE_MTIE); } // deactivate timer interrupt
if (exc_id == EXCID_MEI) { neorv32_cpu_irq_disable(CPU_MIE_MEIE); } // deactivate external interrupt
if (id == RTE_TRAP_MSI) { neorv32_cpu_irq_disable(CPU_MIE_MSIE); } // deactivate software interrupt
if (id == RTE_TRAP_MTI) { neorv32_cpu_irq_disable(CPU_MIE_MTIE); } // deactivate timer interrupt
if (id == RTE_TRAP_MEI) { neorv32_cpu_irq_disable(CPU_MIE_MEIE); } // deactivate external interrupt
if (id == RTE_TRAP_FIRQ_0) { neorv32_cpu_irq_disable(CPU_MIE_FIRQ0E); } // deactivate fast interrupt channel 0
if (id == RTE_TRAP_FIRQ_1) { neorv32_cpu_irq_disable(CPU_MIE_FIRQ1E); } // deactivate fast interrupt channel 1
if (id == RTE_TRAP_FIRQ_2) { neorv32_cpu_irq_disable(CPU_MIE_FIRQ2E); } // deactivate fast interrupt channel 2
if (id == RTE_TRAP_FIRQ_3) { neorv32_cpu_irq_disable(CPU_MIE_FIRQ3E); } // deactivate fast interrupt channel 3
uint32_t vt_base = SYSINFO_DSPACE_BASE; // base address of vector table
vt_base = vt_base + (((uint32_t)exc_id) << 2);
(*(IO_REG32 (vt_base))) = (uint32_t)(&__neorv32_rte_dummy_exc_handler); // use dummy handler in case the exception is triggered
__neorv32_rte_vector_lut[id] = (uint32_t)(&__neorv32_rte_debug_exc_handler); // use dummy handler in case the exception is accidently triggered
return 0;
}
@ -137,18 +144,66 @@ int neorv32_rte_exception_uninstall(uint8_t exc_id) {
/**********************************************************************//**
* NEORV32 runtime environment: Dummy exception handler (does nothing).
* @note This function is used by neorv32_rte_exception_uninstall(uint8_t exc_id) only.
* This is the core of the NEORV32 RTE.
*
* @note This function must no be explicitly used by the user.
* @warning When using the the RTE, this function is the ONLY function that can use the 'interrupt' attribute!
**************************************************************************/
static void __neorv32_rte_dummy_exc_handler(void) {
static void __attribute__((__interrupt__)) __attribute__((aligned(16))) __neorv32_rte_core(void) {
asm volatile("nop");
register uint32_t rte_mepc = neorv32_cpu_csr_read(CSR_MEPC);
register uint32_t rte_mcause = neorv32_cpu_csr_read(CSR_MCAUSE);
// compute return address
if ((rte_mcause & 0x80000000) == 0) { // modify pc only if exception
// get low half word of faulting instruction
register uint32_t rte_trap_inst;
asm volatile ("lh %[result], 0(%[input_i])" : [result] "=r" (rte_trap_inst) : [input_i] "r" (rte_mepc));
if ((rte_trap_inst & 3) == 3) { // faulting instruction is uncompressed instruction
rte_mepc += 4;
}
else { // faulting instruction is compressed instruction
rte_mepc += 2;
}
// store new return address
neorv32_cpu_csr_write(CSR_MEPC, rte_mepc);
}
// find according trap handler
register uint32_t rte_handler = (uint32_t)(&__neorv32_rte_debug_exc_handler);
switch (rte_mcause) {
case TRAP_CODE_I_MISALIGNED: rte_handler = __neorv32_rte_vector_lut[RTE_TRAP_I_MISALIGNED]; break;
case TRAP_CODE_I_ACCESS: rte_handler = __neorv32_rte_vector_lut[RTE_TRAP_I_ACCESS]; break;
case TRAP_CODE_I_ILLEGAL: rte_handler = __neorv32_rte_vector_lut[RTE_TRAP_I_ILLEGAL]; break;
case TRAP_CODE_BREAKPOINT: rte_handler = __neorv32_rte_vector_lut[RTE_TRAP_BREAKPOINT]; break;
case TRAP_CODE_L_MISALIGNED: rte_handler = __neorv32_rte_vector_lut[RTE_TRAP_L_MISALIGNED]; break;
case TRAP_CODE_L_ACCESS: rte_handler = __neorv32_rte_vector_lut[RTE_TRAP_L_ACCESS]; break;
case TRAP_CODE_S_MISALIGNED: rte_handler = __neorv32_rte_vector_lut[RTE_TRAP_S_MISALIGNED]; break;
case TRAP_CODE_S_ACCESS: rte_handler = __neorv32_rte_vector_lut[RTE_TRAP_S_ACCESS]; break;
case TRAP_CODE_MENV_CALL: rte_handler = __neorv32_rte_vector_lut[RTE_TRAP_MENV_CALL]; break;
case TRAP_CODE_MSI: rte_handler = __neorv32_rte_vector_lut[RTE_TRAP_MSI]; break;
case TRAP_CODE_MTI: rte_handler = __neorv32_rte_vector_lut[RTE_TRAP_MTI]; break;
case TRAP_CODE_MEI: rte_handler = __neorv32_rte_vector_lut[RTE_TRAP_MEI]; break;
case TRAP_CODE_FIRQ_0: rte_handler = __neorv32_rte_vector_lut[RTE_TRAP_FIRQ_0]; break;
case TRAP_CODE_FIRQ_1: rte_handler = __neorv32_rte_vector_lut[RTE_TRAP_FIRQ_1]; break;
case TRAP_CODE_FIRQ_2: rte_handler = __neorv32_rte_vector_lut[RTE_TRAP_FIRQ_2]; break;
case TRAP_CODE_FIRQ_3: rte_handler = __neorv32_rte_vector_lut[RTE_TRAP_FIRQ_3]; break;
default: break;
}
// execute handler
void (*handler_pnt)(void);
handler_pnt = (void*)rte_handler;
(*handler_pnt)();
}
/**********************************************************************//**
* NEORV32 runtime environment: Debug exception handler, printing various exception/interrupt information via UART.
* @note This function is used by neorv32_rte_enable_debug_mode(void) only.
* @note This function is used by neorv32_rte_exception_uninstall(void) only.
**************************************************************************/
static void __neorv32_rte_debug_exc_handler(void) {
@ -179,29 +234,34 @@ static void __neorv32_rte_debug_exc_handler(void) {
neorv32_uart_printf("Cause: ");
switch (trap_cause) {
case 0x00000000: neorv32_uart_printf("Instruction address misaligned"); break;
case 0x00000001: neorv32_uart_printf("Instruction access fault"); break;
case 0x00000002: neorv32_uart_printf("Illegal instruction"); break;
case 0x00000003: neorv32_uart_printf("Breakpoint (EBREAK)"); break;
case 0x00000004: neorv32_uart_printf("Load address misaligned"); break;
case 0x00000005: neorv32_uart_printf("Load access fault"); break;
case 0x00000006: neorv32_uart_printf("Store address misaligned"); break;
case 0x00000007: neorv32_uart_printf("Store access fault"); break;
case 0x0000000B: neorv32_uart_printf("Environment call (ECALL)"); break;
case 0x80000003: neorv32_uart_printf("Machine software interrupt"); break;
case 0x80000007: neorv32_uart_printf("Machine timer interrupt (via MTIME)"); break;
case 0x8000000B: neorv32_uart_printf("Machine external interrupt (via CLIC)"); break;
default: neorv32_uart_printf("Unknown (0x%x)", trap_cause); break;
case TRAP_CODE_I_MISALIGNED: neorv32_uart_printf("Instruction address misaligned"); break;
case TRAP_CODE_I_ACCESS: neorv32_uart_printf("Instruction access fault"); break;
case TRAP_CODE_I_ILLEGAL: neorv32_uart_printf("Illegal instruction"); break;
case TRAP_CODE_BREAKPOINT: neorv32_uart_printf("Breakpoint (EBREAK)"); break;
case TRAP_CODE_L_MISALIGNED: neorv32_uart_printf("Load address misaligned"); break;
case TRAP_CODE_L_ACCESS: neorv32_uart_printf("Load access fault"); break;
case TRAP_CODE_S_MISALIGNED: neorv32_uart_printf("Store address misaligned"); break;
case TRAP_CODE_S_ACCESS: neorv32_uart_printf("Store access fault"); break;
case TRAP_CODE_MENV_CALL: neorv32_uart_printf("Environment call from M-mode"); break;
case TRAP_CODE_MSI: neorv32_uart_printf("Machine software interrupt"); break;
case TRAP_CODE_MTI: neorv32_uart_printf("Machine timer interrupt"); break;
case TRAP_CODE_MEI: neorv32_uart_printf("Machine external interrupt"); break;
case TRAP_CODE_FIRQ_0: neorv32_uart_printf("Fast interrupt channel 0"); break;
case TRAP_CODE_FIRQ_1: neorv32_uart_printf("Fast interrupt channel 1"); break;
case TRAP_CODE_FIRQ_2: neorv32_uart_printf("Fast interrupt channel 2"); break;
case TRAP_CODE_FIRQ_3: neorv32_uart_printf("Fast interrupt channel 3"); break;
default: neorv32_uart_printf("Unknown (0x%x)", trap_cause); break;
}
// fault address
neorv32_uart_printf("\nFaulting instruction (low): 0x%x\n", trap_inst);
neorv32_uart_printf("MTVAL: 0x%x\n", neorv32_cpu_csr_read(CSR_MTVAL));
neorv32_uart_printf("\nFaulting instruction (low half word): 0x%x", trap_inst);
if ((trap_inst & 3) != 3) {
neorv32_uart_printf("(decompressed)\n");
neorv32_uart_printf(" (decompressed)\n");
}
neorv32_uart_printf("\nMTVAL: 0x%x\n", neorv32_cpu_csr_read(CSR_MTVAL));
neorv32_uart_printf("Trying to resume application @ 0x%x...", neorv32_cpu_csr_read(CSR_MEPC));
neorv32_uart_printf("\n<</NEORV32 Runtime Environment >>\n\n");
@ -313,9 +373,6 @@ void neorv32_rte_print_hw_config(void) {
neorv32_uart_printf("WDT: ");
__neorv32_rte_print_true_false(tmp & (1 << SYSINFO_FEATURES_IO_WDT));
neorv32_uart_printf("CLIC: ");
__neorv32_rte_print_true_false(tmp & (1 << SYSINFO_FEATURES_IO_CLIC));
neorv32_uart_printf("TRNG: ");
__neorv32_rte_print_true_false(tmp & (1 << SYSINFO_FEATURES_IO_TRNG));