mirror of
https://github.com/stnolting/neorv32.git
synced 2025-04-23 21:57:33 -04:00
updated and optimized RTE - smaller, faster, better ;)
This commit is contained in:
parent
8ade8ad170
commit
11f30c7885
4 changed files with 185 additions and 241 deletions
204
sw/common/crt0.S
204
sw/common/crt0.S
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
/* ************************************************* */
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue