Line 49... |
Line 49... |
|
|
// private functions
|
// private functions
|
static void __attribute__((__interrupt__)) __neorv32_rte_core(void) __attribute__((aligned(16))) __attribute__((unused));
|
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_debug_exc_handler(void) __attribute__((unused));
|
static void __neorv32_rte_print_true_false(int state) __attribute__((unused));
|
static void __neorv32_rte_print_true_false(int state) __attribute__((unused));
|
|
static void __neorv32_rte_print_hex_word(uint32_t num);
|
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Setup NEORV32 runtime environment.
|
* Setup NEORV32 runtime environment.
|
*
|
*
|
Line 62... |
Line 63... |
**************************************************************************/
|
**************************************************************************/
|
void neorv32_rte_setup(void) {
|
void neorv32_rte_setup(void) {
|
|
|
// check if CSR system is available at all
|
// check if CSR system is available at all
|
if (neorv32_cpu_csr_read(CSR_MISA) == 0) {
|
if (neorv32_cpu_csr_read(CSR_MISA) == 0) {
|
neorv32_uart_printf("<RTE> WARNING! CPU CSR system not available! </RTE>");
|
neorv32_uart_print("<RTE> WARNING! CPU CSR system not available! </RTE>");
|
}
|
}
|
|
|
// configure trap handler base address
|
// configure trap handler base address
|
uint32_t mtvec_base = (uint32_t)(&__neorv32_rte_core);
|
uint32_t mtvec_base = (uint32_t)(&__neorv32_rte_core);
|
neorv32_cpu_csr_write(CSR_MTVEC, mtvec_base);
|
neorv32_cpu_csr_write(CSR_MTVEC, mtvec_base);
|
Line 135... |
Line 136... |
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* This is the core of the NEORV32 RTE.
|
* This is the core of the NEORV32 RTE.
|
*
|
*
|
* @note This function must no be explicitly used by the user.
|
* @note This function must no be explicitly used by the user.
|
|
* @note The RTE core uses mscratch CSR to store the trap-causing mepc for further (user-defined) processing.
|
|
*
|
* @warning When using the the RTE, this function is the ONLY function that can use the 'interrupt' attribute!
|
* @warning When using the the RTE, this function is the ONLY function that can use the 'interrupt' attribute!
|
**************************************************************************/
|
**************************************************************************/
|
static void __attribute__((__interrupt__)) __attribute__((aligned(16))) __neorv32_rte_core(void) {
|
static void __attribute__((__interrupt__)) __attribute__((aligned(16))) __neorv32_rte_core(void) {
|
|
|
register uint32_t rte_mepc = neorv32_cpu_csr_read(CSR_MEPC);
|
register uint32_t rte_mepc = neorv32_cpu_csr_read(CSR_MEPC);
|
|
neorv32_cpu_csr_write(CSR_MSCRATCH, rte_mepc); // store for later
|
register uint32_t rte_mcause = neorv32_cpu_csr_read(CSR_MCAUSE);
|
register uint32_t rte_mcause = neorv32_cpu_csr_read(CSR_MCAUSE);
|
|
|
// compute return address
|
// compute return address
|
if ((rte_mcause & 0x80000000) == 0) { // modify pc only if exception
|
if ((rte_mcause & 0x80000000) == 0) { // modify pc only if exception
|
|
|
Line 196... |
Line 200... |
* @note This function is used by neorv32_rte_exception_uninstall(void) only.
|
* @note This function is used by neorv32_rte_exception_uninstall(void) only.
|
**************************************************************************/
|
**************************************************************************/
|
static void __neorv32_rte_debug_exc_handler(void) {
|
static void __neorv32_rte_debug_exc_handler(void) {
|
|
|
// intro
|
// intro
|
neorv32_uart_printf("<RTE> ");
|
neorv32_uart_print("<RTE> ");
|
|
|
// cause
|
// cause
|
register uint32_t trap_cause = neorv32_cpu_csr_read(CSR_MCAUSE);
|
register uint32_t trap_cause = neorv32_cpu_csr_read(CSR_MCAUSE);
|
switch (trap_cause) {
|
switch (trap_cause) {
|
case TRAP_CODE_I_MISALIGNED: neorv32_uart_printf("Instruction address misaligned"); break;
|
case TRAP_CODE_I_MISALIGNED: neorv32_uart_print("Instruction address misaligned"); break;
|
case TRAP_CODE_I_ACCESS: neorv32_uart_printf("Instruction access fault"); break;
|
case TRAP_CODE_I_ACCESS: neorv32_uart_print("Instruction access fault"); break;
|
case TRAP_CODE_I_ILLEGAL: neorv32_uart_printf("Illegal instruction"); break;
|
case TRAP_CODE_I_ILLEGAL: neorv32_uart_print("Illegal instruction"); break;
|
case TRAP_CODE_BREAKPOINT: neorv32_uart_printf("Breakpoint"); break;
|
case TRAP_CODE_BREAKPOINT: neorv32_uart_print("Breakpoint"); break;
|
case TRAP_CODE_L_MISALIGNED: neorv32_uart_printf("Load address misaligned"); break;
|
case TRAP_CODE_L_MISALIGNED: neorv32_uart_print("Load address misaligned"); break;
|
case TRAP_CODE_L_ACCESS: neorv32_uart_printf("Load access fault"); break;
|
case TRAP_CODE_L_ACCESS: neorv32_uart_print("Load access fault"); break;
|
case TRAP_CODE_S_MISALIGNED: neorv32_uart_printf("Store address misaligned"); break;
|
case TRAP_CODE_S_MISALIGNED: neorv32_uart_print("Store address misaligned"); break;
|
case TRAP_CODE_S_ACCESS: neorv32_uart_printf("Store access fault"); break;
|
case TRAP_CODE_S_ACCESS: neorv32_uart_print("Store access fault"); break;
|
case TRAP_CODE_MENV_CALL: neorv32_uart_printf("Environment call"); break;
|
case TRAP_CODE_MENV_CALL: neorv32_uart_print("Environment call"); break;
|
case TRAP_CODE_MSI: neorv32_uart_printf("Machine software interrupt"); break;
|
case TRAP_CODE_MSI: neorv32_uart_print("Machine software interrupt"); break;
|
case TRAP_CODE_MTI: neorv32_uart_printf("Machine timer interrupt"); break;
|
case TRAP_CODE_MTI: neorv32_uart_print("Machine timer interrupt"); break;
|
case TRAP_CODE_MEI: neorv32_uart_printf("Machine external interrupt"); break;
|
case TRAP_CODE_MEI: neorv32_uart_print("Machine external interrupt"); break;
|
case TRAP_CODE_FIRQ_0: neorv32_uart_printf("Fast interrupt 0"); break;
|
case TRAP_CODE_FIRQ_0: neorv32_uart_print("Fast interrupt 0"); break;
|
case TRAP_CODE_FIRQ_1: neorv32_uart_printf("Fast interrupt 1"); break;
|
case TRAP_CODE_FIRQ_1: neorv32_uart_print("Fast interrupt 1"); break;
|
case TRAP_CODE_FIRQ_2: neorv32_uart_printf("Fast interrupt 2"); break;
|
case TRAP_CODE_FIRQ_2: neorv32_uart_print("Fast interrupt 2"); break;
|
case TRAP_CODE_FIRQ_3: neorv32_uart_printf("Fast interrupt 3"); break;
|
case TRAP_CODE_FIRQ_3: neorv32_uart_print("Fast interrupt 3"); break;
|
default: neorv32_uart_printf("Unknown (0x%x)", trap_cause); break;
|
default: neorv32_uart_print("Unknown trap cause: "); __neorv32_rte_print_hex_word(trap_cause); break;
|
}
|
}
|
|
|
// address
|
// instruction address
|
register uint32_t trap_addr = neorv32_cpu_csr_read(CSR_MEPC);
|
neorv32_uart_print(" @ ");
|
register uint32_t trap_inst;
|
__neorv32_rte_print_hex_word(neorv32_cpu_csr_read(CSR_MSCRATCH)); // rte core stores actual mepc to mscratch
|
asm volatile ("lh %[result], 0(%[input_i])" : [result] "=r" (trap_inst) : [input_i] "r" (trap_addr));
|
|
|
// additional info
|
// modify return address only if exception (NOT for interrupts)
|
neorv32_uart_print(", MTVAL=");
|
if ((trap_cause & 0x80000000) == 0) { // is exception?
|
__neorv32_rte_print_hex_word(neorv32_cpu_csr_read(CSR_MTVAL));
|
if ((trap_inst & 3) == 3) { // is uncompressed instruction?
|
neorv32_uart_print(" </RTE>");
|
trap_addr -= 4;
|
|
}
|
|
else {
|
|
trap_addr -= 2;
|
|
}
|
|
}
|
|
neorv32_uart_printf(" @ 0x%x, MTVAL=0x%x </RTE>", trap_addr, neorv32_cpu_csr_read(CSR_MTVAL));
|
|
}
|
}
|
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* NEORV32 runtime environment: Print hardware configuration information via UART
|
* NEORV32 runtime environment: Print hardware configuration information via UART
|
Line 298... |
Line 295... |
}
|
}
|
}
|
}
|
|
|
// Z* CPU extensions (from custom CSR "mzext")
|
// Z* CPU extensions (from custom CSR "mzext")
|
tmp = neorv32_cpu_csr_read(CSR_MZEXT);
|
tmp = neorv32_cpu_csr_read(CSR_MZEXT);
|
if (tmp & (1<<0)) {
|
if (tmp & (1<<CPU_MZEXT_ZICSR)) {
|
neorv32_uart_printf("Zicsr ");
|
neorv32_uart_printf("Zicsr ");
|
}
|
}
|
if (tmp & (1<<1)) {
|
if (tmp & (1<<CPU_MZEXT_ZIFENCEI)) {
|
neorv32_uart_printf("Zifencei ");
|
neorv32_uart_printf("Zifencei ");
|
}
|
}
|
|
if (tmp & (1<<CPU_MZEXT_PMP)) {
|
|
neorv32_uart_printf("PMP ");
|
|
}
|
|
|
|
|
// Misc
|
// Misc
|
neorv32_uart_printf("\n\n\n-- Processor --\n");
|
neorv32_uart_printf("\n\n\n-- Processor --\n");
|
neorv32_uart_printf("Clock: %u Hz\n", SYSINFO_CLK);
|
neorv32_uart_printf("Clock: %u Hz\n", SYSINFO_CLK);
|
Line 376... |
Line 376... |
* @param[in] state Print TRUE when !=0, print FALSE when 0
|
* @param[in] state Print TRUE when !=0, print FALSE when 0
|
**************************************************************************/
|
**************************************************************************/
|
static void __neorv32_rte_print_true_false(int state) {
|
static void __neorv32_rte_print_true_false(int state) {
|
|
|
if (state) {
|
if (state) {
|
neorv32_uart_printf("True\n");
|
neorv32_uart_print("True\n");
|
}
|
}
|
else {
|
else {
|
neorv32_uart_printf("False\n");
|
neorv32_uart_print("False\n");
|
|
}
|
|
}
|
|
|
|
|
|
/**********************************************************************//**
|
|
* NEORV32 runtime environment: Private function to print 32-bit number
|
|
* as 8-digit hexadecimal value (with "0x" suffix).
|
|
*
|
|
* @param[in] num Number to print as hexadecimal.
|
|
**************************************************************************/
|
|
void __neorv32_rte_print_hex_word(uint32_t num) {
|
|
|
|
static const char hex_symbols[16] = "0123456789ABCDEF";
|
|
|
|
neorv32_uart_print("0x");
|
|
|
|
int i;
|
|
for (i=0; i<8; i++) {
|
|
uint32_t index = (num >> (28 - 4*i)) & 0xF;
|
|
neorv32_uart_putc(hex_symbols[index]);
|
}
|
}
|
}
|
}
|
|
|
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* NEORV32 runtime environment: Function to show the processor version in human-readable format.
|
* NEORV32 runtime environment: Function to show the processor version in human-readable format.
|
**************************************************************************/
|
**************************************************************************/
|
void neorv32_rte_print_hw_version(void) {
|
void neorv32_rte_print_hw_version(void) {
|
|
|
uint32_t i;
|
uint32_t i;
|
char tmp, cnt;
|
char tmp, cnt;
|
uint32_t version = neorv32_cpu_csr_read(CSR_MIMPID);
|
|
|
|
for (i=0; i<4; i++) {
|
for (i=0; i<4; i++) {
|
|
|
tmp = (char)(version >> (24 - 8*i));
|
tmp = (char)(neorv32_cpu_csr_read(CSR_MIMPID) >> (24 - 8*i));
|
|
|
// serial division
|
// serial division
|
cnt = 0;
|
cnt = 0;
|
while (tmp >= 10) {
|
while (tmp >= 10) {
|
tmp = tmp - 10;
|
tmp = tmp - 10;
|