Line 56... |
Line 56... |
//** external memory base address */
|
//** external memory base address */
|
#define EXT_MEM_BASE (0xF0000000)
|
#define EXT_MEM_BASE (0xF0000000)
|
/**@}*/
|
/**@}*/
|
|
|
|
|
|
/**********************************************************************//**
|
|
* @name UART print macros
|
|
**************************************************************************/
|
|
/**@{*/
|
|
//** for simulation only! */
|
|
#ifdef SUPPRESS_OPTIONAL_UART_PRINT
|
|
//** print standard output to UART0 */
|
|
#define PRINT_STANDARD(...)
|
|
//** print critical output to UART1 */
|
|
#define PRINT_CRITICAL(...) neorv32_uart1_printf(__VA_ARGS__)
|
|
#else
|
|
//** print standard output to UART0 */
|
|
#define PRINT_STANDARD(...) neorv32_uart0_printf(__VA_ARGS__)
|
|
//** print critical output to UART0 */
|
|
#define PRINT_CRITICAL(...) neorv32_uart0_printf(__VA_ARGS__)
|
|
#endif
|
|
/**@}*/
|
|
|
|
|
// Prototypes
|
// Prototypes
|
void sim_irq_trigger(uint32_t sel);
|
void sim_irq_trigger(uint32_t sel);
|
void global_trap_handler(void);
|
void global_trap_handler(void);
|
|
void xirq_trap_handler0(void);
|
|
void xirq_trap_handler1(void);
|
void test_ok(void);
|
void test_ok(void);
|
void test_fail(void);
|
void test_fail(void);
|
|
|
// Global variables (also test initialization of global vars here)
|
// Global variables (also test initialization of global vars here)
|
/// Global counter for failing tests
|
/// Global counter for failing tests
|
Line 71... |
Line 92... |
int cnt_ok = 0;
|
int cnt_ok = 0;
|
/// Global counter for total number of tests
|
/// Global counter for total number of tests
|
int cnt_test = 0;
|
int cnt_test = 0;
|
/// Global numbe rof available HPMs
|
/// Global numbe rof available HPMs
|
uint32_t num_hpm_cnts_global = 0;
|
uint32_t num_hpm_cnts_global = 0;
|
|
/// XIRQ trap handler acknowledge
|
|
uint32_t xirq_trap_handler_ack = 0;
|
|
|
/// Variable to test atomic accessess
|
/// Variable to test atomic accesses
|
uint32_t atomic_access_addr;
|
uint32_t atomic_access_addr;
|
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* High-level CPU/processor test program.
|
* High-level CPU/processor test program.
|
*
|
*
|
* @note Applications has to be compiler with <USER_FLAGS+=-DRUN_CPUTEST>
|
* @note Applications has to be compiler with <USER_FLAGS+=-DRUN_CPUTEST>
|
|
* @warning This test is intended for simulation only.
|
|
* @warning This test requires all optional extensions/modules to be enabled.
|
*
|
*
|
* @return 0 if execution was successful
|
* @return 0 if execution was successful
|
**************************************************************************/
|
**************************************************************************/
|
int main() {
|
int main() {
|
|
|
register uint32_t tmp_a, tmp_b;
|
register uint32_t tmp_a, tmp_b;
|
volatile uint32_t dummy_dst __attribute__((unused));
|
|
uint8_t id;
|
uint8_t id;
|
uint32_t is_simulation = 0;
|
|
|
|
|
|
// init UART at default baud rate, no parity bits, no hw flow control
|
// init UARTs at default baud rate, no parity bits, no hw flow control
|
neorv32_uart_setup(BAUD_RATE, PARITY_NONE, FLOW_CONTROL_NONE);
|
neorv32_uart0_setup(BAUD_RATE, PARITY_NONE, FLOW_CONTROL_NONE);
|
|
UART1_CT = UART0_CT; // copy configuration to initialize UART1
|
|
|
|
#ifdef SUPPRESS_OPTIONAL_UART_PRINT
|
|
neorv32_uart0_disable(); // do not generate any UART0 output
|
|
#endif
|
|
|
// Disable processor_check compilation by default
|
// Disable processor_check compilation by default
|
#ifndef RUN_CHECK
|
#ifndef RUN_CHECK
|
#warning processor_check HAS NOT BEEN COMPILED! Use >>make USER_FLAGS+=-DRUN_CHECK clean_all exe<< to compile it.
|
#warning processor_check HAS NOT BEEN COMPILED! Use >>make USER_FLAGS+=-DRUN_CHECK clean_all exe<< to compile it.
|
|
|
// inform the user if you are actually executing this
|
// inform the user if you are actually executing this
|
neorv32_uart_printf("ERROR! processor_check has not been compiled. Use >>make USER_FLAGS+=-DRUN_CHECK clean_all exe<< to compile it.\n");
|
PRINT_CRITICAL("ERROR! processor_check has not been compiled. Use >>make USER_FLAGS+=-DRUN_CHECK clean_all exe<< to compile it.\n");
|
|
|
return 1;
|
return 1;
|
#endif
|
#endif
|
|
|
// check if this is a simulation (using primary UART0)
|
|
if (UART0_CT & (1 << UART_CT_SIM_MODE)) {
|
|
is_simulation = 1;
|
|
}
|
|
else {
|
|
is_simulation = 0;
|
|
}
|
|
|
|
// ----------------------------------------------
|
// ----------------------------------------------
|
// setup RTE
|
// setup RTE
|
neorv32_rte_setup(); // this will install a full-detailed debug handler for ALL traps
|
neorv32_rte_setup(); // this will install a full-detailed debug handler for ALL traps
|
// ----------------------------------------------
|
// ----------------------------------------------
|
Line 122... |
Line 143... |
// check available hardware extensions and compare with compiler flags
|
// check available hardware extensions and compare with compiler flags
|
neorv32_rte_check_isa(0); // silent = 0 -> show message if isa mismatch
|
neorv32_rte_check_isa(0); // silent = 0 -> show message if isa mismatch
|
|
|
|
|
// intro
|
// intro
|
neorv32_uart_printf("\n<< PROCESSOR CHECK >>\n");
|
PRINT_STANDARD("\n<< PROCESSOR CHECK >>\n");
|
neorv32_uart_printf("build: "__DATE__" "__TIME__"\n");
|
PRINT_STANDARD("build: "__DATE__" "__TIME__"\n");
|
|
|
|
|
// reset performance counter
|
// reset performance counter
|
neorv32_cpu_csr_write(CSR_MCYCLEH, 0);
|
neorv32_cpu_csr_write(CSR_MCYCLEH, 0);
|
neorv32_cpu_csr_write(CSR_MCYCLE, 0);
|
neorv32_cpu_csr_write(CSR_MCYCLE, 0);
|
Line 154... |
Line 175... |
neorv32_rte_print_hw_config();
|
neorv32_rte_print_hw_config();
|
|
|
|
|
// configure RTE
|
// configure RTE
|
// -----------------------------------------------
|
// -----------------------------------------------
|
neorv32_uart_printf("\n\nConfiguring NEORV32 RTE... ");
|
PRINT_STANDARD("\n\nConfiguring NEORV32 RTE... ");
|
|
|
int install_err = 0;
|
int install_err = 0;
|
// initialize ALL provided trap handler (overriding the default debug handlers)
|
// initialize ALL provided trap handler (overriding the default debug handlers)
|
for (id=0; id<NEORV32_RTE_NUM_TRAPS; id++) {
|
for (id=0; id<NEORV32_RTE_NUM_TRAPS; id++) {
|
install_err += neorv32_rte_exception_install(id, global_trap_handler);
|
install_err += neorv32_rte_exception_install(id, global_trap_handler);
|
}
|
}
|
|
|
if (install_err) {
|
if (install_err) {
|
neorv32_uart_printf("RTE install error (%i)!\n", install_err);
|
PRINT_CRITICAL("RTE install error (%i)!\n", install_err);
|
return 1;
|
return 1;
|
}
|
}
|
|
|
// enable interrupt sources
|
// enable interrupt sources
|
neorv32_cpu_irq_enable(CSR_MIE_MSIE); // machine software interrupt
|
neorv32_cpu_irq_enable(CSR_MIE_MSIE); // machine software interrupt
|
neorv32_cpu_irq_enable(CSR_MIE_MTIE); // machine timer interrupt
|
neorv32_cpu_irq_enable(CSR_MIE_MTIE); // machine timer interrupt
|
neorv32_cpu_irq_enable(CSR_MIE_MEIE); // machine external interrupt
|
neorv32_cpu_irq_enable(CSR_MIE_MEIE); // machine external interrupt
|
// enable FAST IRQ sources only where actually needed
|
// enable FAST IRQ sources only where actually needed
|
|
|
// test intro
|
// test intro
|
neorv32_uart_printf("\nStarting tests...\n\n");
|
PRINT_STANDARD("\nStarting tests...\n\n");
|
|
|
// enable global interrupts
|
// enable global interrupts
|
neorv32_cpu_eint();
|
neorv32_cpu_eint();
|
|
|
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Test standard RISC-V performance counter [m]cycle[h]
|
// Test standard RISC-V performance counter [m]cycle[h]
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] [m]instret[h] counter: ", cnt_test);
|
PRINT_STANDARD("[%i] [m]cycle[h] counter: ", cnt_test);
|
|
|
cnt_test++;
|
cnt_test++;
|
|
|
// make sure counter is enabled
|
// make sure counter is enabled
|
asm volatile ("csrci %[addr], %[imm]" : : [addr] "i" (CSR_MCOUNTINHIBIT), [imm] "i" (1<<CSR_MCOUNTINHIBIT_CY));
|
asm volatile ("csrci %[addr], %[imm]" : : [addr] "i" (CSR_MCOUNTINHIBIT), [imm] "i" (1<<CSR_MCOUNTINHIBIT_CY));
|
|
|
// get current cycle counter LOW
|
// prepare overflow
|
tmp_a = neorv32_cpu_csr_read(CSR_MCYCLE);
|
neorv32_cpu_set_mcycle(0x00000000FFFFFFFFULL);
|
tmp_a = neorv32_cpu_csr_read(CSR_MCYCLE) - tmp_a;
|
|
|
// get current cycle counter HIGH
|
|
tmp_a = neorv32_cpu_csr_read(CSR_MCYCLEH);
|
|
|
// make sure cycle counter has incremented and there was no exception during access
|
// make sure cycle counter high has incremented and there was no exception during access
|
if ((tmp_a > 0) && (neorv32_cpu_csr_read(CSR_MCAUSE) == 0)) {
|
if ((tmp_a == 1) && (neorv32_cpu_csr_read(CSR_MCAUSE) == 0)) {
|
test_ok();
|
test_ok();
|
}
|
}
|
else {
|
else {
|
test_fail();
|
test_fail();
|
}
|
}
|
Line 208... |
Line 231... |
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Test standard RISC-V performance counter [m]instret[h]
|
// Test standard RISC-V performance counter [m]instret[h]
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] [m]cycle[h] counter: ", cnt_test);
|
PRINT_STANDARD("[%i] [m]instret[h] counter: ", cnt_test);
|
|
|
cnt_test++;
|
cnt_test++;
|
|
|
// make sure counter is enabled
|
// make sure counter is enabled
|
asm volatile ("csrci %[addr], %[imm]" : : [addr] "i" (CSR_MCOUNTINHIBIT), [imm] "i" (1<<CSR_MCOUNTINHIBIT_IR));
|
asm volatile ("csrci %[addr], %[imm]" : : [addr] "i" (CSR_MCOUNTINHIBIT), [imm] "i" (1<<CSR_MCOUNTINHIBIT_IR));
|
|
|
// get instruction counter LOW
|
// prepare overflow
|
tmp_a = neorv32_cpu_csr_read(CSR_INSTRET);
|
neorv32_cpu_set_minstret(0x00000000FFFFFFFFULL);
|
tmp_a = neorv32_cpu_csr_read(CSR_INSTRET) - tmp_a;
|
|
|
// get instruction counter HIGH
|
// make sure instruction counter has incremented and there was no exception during access
|
tmp_a = neorv32_cpu_csr_read(CSR_INSTRETH);
|
if ((tmp_a > 0) && (neorv32_cpu_csr_read(CSR_MCAUSE) == 0)) {
|
|
if (tmp_a > 1) {
|
// make sure instruction counter high has incremented and there was no exception during access
|
neorv32_uart_printf("INSTRET_diff > 1 (%u)!", tmp_a);
|
if ((tmp_a == 1) && (neorv32_cpu_csr_read(CSR_MCAUSE) == 0)) {
|
test_fail();
|
|
}
|
|
else {
|
|
test_ok();
|
test_ok();
|
}
|
}
|
}
|
|
else {
|
else {
|
test_fail();
|
test_fail();
|
}
|
}
|
|
|
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Test mcountinhibt: inhibit auto-inc of [m]cycle
|
// Test mcountinhibt: inhibit auto-inc of [m]cycle
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] mcountinhibt.cy CSR: ", cnt_test);
|
PRINT_STANDARD("[%i] mcountinhibt.cy CSR: ", cnt_test);
|
|
|
cnt_test++;
|
cnt_test++;
|
|
|
// inhibit [m]cycle CSR
|
// inhibit [m]cycle CSR
|
tmp_a = neorv32_cpu_csr_read(CSR_MCOUNTINHIBIT);
|
tmp_a = neorv32_cpu_csr_read(CSR_MCOUNTINHIBIT);
|
Line 274... |
Line 293... |
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Test mcounteren: do not allow cycle[h] access from user-mode
|
// Test mcounteren: do not allow cycle[h] access from user-mode
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] mcounteren.cy CSR: ", cnt_test);
|
PRINT_STANDARD("[%i] mcounteren.cy CSR: ", cnt_test);
|
|
|
// skip if U-mode is not implemented
|
// skip if U-mode is not implemented
|
if (neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_U_EXT)) {
|
if (neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_U)) {
|
cnt_test++;
|
cnt_test++;
|
|
|
// do not allow user-level code to access cycle[h] CSRs
|
// do not allow user-level code to access cycle[h] CSRs
|
tmp_a = neorv32_cpu_csr_read(CSR_MCOUNTEREN);
|
tmp_a = neorv32_cpu_csr_read(CSR_MCOUNTEREN);
|
tmp_a &= ~(1<<CSR_MCOUNTEREN_CY); // clear access right
|
tmp_a &= ~(1<<CSR_MCOUNTEREN_CY); // clear access right
|
Line 306... |
Line 325... |
else {
|
else {
|
test_fail();
|
test_fail();
|
}
|
}
|
}
|
}
|
else {
|
else {
|
neorv32_uart_printf("skipped (not implemented)\n");
|
PRINT_STANDARD("skipped (n.a.)\n");
|
}
|
}
|
|
|
|
|
// re-allow user-level code to access cycle[h] CSRs
|
// re-allow user-level code to access cycle[h] CSRs
|
tmp_a = neorv32_cpu_csr_read(CSR_MCOUNTEREN);
|
tmp_a = neorv32_cpu_csr_read(CSR_MCOUNTEREN);
|
Line 320... |
Line 339... |
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Test performance counter: setup as many events and counter as feasible
|
// Test performance counter: setup as many events and counter as feasible
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] Initializing HPMs: ", cnt_test);
|
PRINT_STANDARD("[%i] Configuring HPM events: ", cnt_test);
|
|
|
num_hpm_cnts_global = neorv32_cpu_hpm_get_counters();
|
num_hpm_cnts_global = neorv32_cpu_hpm_get_counters();
|
|
|
if (num_hpm_cnts_global != 0) {
|
if (num_hpm_cnts_global != 0) {
|
cnt_test++;
|
cnt_test++;
|
Line 351... |
Line 370... |
else {
|
else {
|
test_fail();
|
test_fail();
|
}
|
}
|
}
|
}
|
else {
|
else {
|
neorv32_uart_printf("skipped (not implemented)\n");
|
PRINT_STANDARD("skipped (n.a.)\n");
|
}
|
}
|
|
|
|
|
//// ----------------------------------------------------------
|
|
//// Bus timeout latency estimation
|
|
//// out of order :P
|
|
//// ----------------------------------------------------------
|
|
//neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
|
//neorv32_uart_printf("[%i] Estimating bus time-out latency: ", cnt_test);
|
|
//cnt_test++;
|
|
//
|
|
//// start timing
|
|
//neorv32_cpu_csr_write(CSR_MCYCLE, 0);
|
|
//
|
|
//// make sure there was a timeout
|
|
//if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_S_ACCESS) {
|
|
// neorv32_uart_printf("~%u cycles ", trap_timestamp32-175); // remove trap handler overhead - empiric value ;)
|
|
// test_ok();
|
|
//}
|
|
//else {
|
|
// test_fail();
|
|
//}
|
|
|
|
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// External memory interface test
|
// External memory interface test
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] External memory access (@ 0x%x): ", cnt_test, (uint32_t)EXT_MEM_BASE);
|
PRINT_STANDARD("[%i] External memory access (@ 0x%x): ", cnt_test, (uint32_t)EXT_MEM_BASE);
|
|
|
if (is_simulation) { // check if this is a simulation
|
|
if (SYSINFO_FEATURES & (1 << SYSINFO_FEATURES_MEM_EXT)) {
|
if (SYSINFO_FEATURES & (1 << SYSINFO_FEATURES_MEM_EXT)) {
|
cnt_test++;
|
cnt_test++;
|
|
|
// create test program in RAM
|
// create test program in RAM
|
static const uint32_t dummy_ext_program[2] __attribute__((aligned(8))) = {
|
static const uint32_t dummy_ext_program[2] __attribute__((aligned(8))) = {
|
Line 416... |
Line 413... |
test_fail();
|
test_fail();
|
}
|
}
|
}
|
}
|
}
|
}
|
else {
|
else {
|
neorv32_uart_printf("skipped (not implemented)\n");
|
PRINT_STANDARD("skipped (n.a.)\n");
|
}
|
}
|
|
|
|
|
|
// ----------------------------------------------------------
|
|
// Test FENCE.I instruction (instruction buffer / i-cache clear & reload)
|
|
// if Zifencei is not implemented FENCE.I should execute as NOP
|
|
// ----------------------------------------------------------
|
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
|
PRINT_STANDARD("[%i] FENCE.I: ", cnt_test);
|
|
|
|
cnt_test++;
|
|
|
|
asm volatile ("fence.i");
|
|
|
|
// make sure there was no exception (and that the cpu did not crash...)
|
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) {
|
|
test_ok();
|
}
|
}
|
else {
|
else {
|
neorv32_uart_printf("skipped (on real HW)\n");
|
test_fail();
|
}
|
}
|
|
|
|
|
//// ----------------------------------------------------------
|
|
//// Test FENCE.I instruction (instruction buffer / i-cache clear & reload)
|
|
//// ----------------------------------------------------------
|
|
//neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
|
//neorv32_uart_printf("[%i] FENCE.I: ", cnt_test);
|
|
//
|
|
//// check if implemented
|
|
//if (neorv32_cpu_csr_read(CSR_MZEXT) & (1 << CSR_MZEXT_ZIFENCEI)) {
|
|
// cnt_test++;
|
|
//
|
|
// asm volatile ("fence.i");
|
|
//
|
|
// // make sure there was no exception (and that the cpu did not crash...)
|
|
// if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) {
|
|
// test_ok();
|
|
// }
|
|
// else {
|
|
// test_fail();
|
|
// }
|
|
//}
|
|
//else {
|
|
// neorv32_uart_printf("skipped (not implemented)\n");
|
|
//}
|
|
|
|
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Illegal CSR access (CSR not implemented)
|
// Illegal CSR access (CSR not implemented)
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] Illegal CSR (0xfff) access: ", cnt_test);
|
PRINT_STANDARD("[%i] Non-existent CSR access: ", cnt_test);
|
|
|
cnt_test++;
|
cnt_test++;
|
|
|
neorv32_cpu_csr_read(0xfff); // CSR 0xfff not implemented
|
tmp_a = neorv32_cpu_csr_read(0xfff); // CSR 0xfff not implemented
|
|
|
|
if (tmp_a != 0) {
|
|
PRINT_CRITICAL("%c[1m<SECURITY FAILURE> %c[0m\n", 27, 27);
|
|
}
|
|
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_I_ILLEGAL) {
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_I_ILLEGAL) {
|
test_ok();
|
test_ok();
|
}
|
}
|
else {
|
else {
|
Line 471... |
Line 463... |
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Write-access to read-only CSR
|
// Write-access to read-only CSR
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] Read-only CSR (time) write access: ", cnt_test);
|
PRINT_STANDARD("[%i] Read-only CSR write access: ", cnt_test);
|
|
|
cnt_test++;
|
cnt_test++;
|
|
|
neorv32_cpu_csr_write(CSR_TIME, 0); // time CSR is read-only
|
neorv32_cpu_csr_write(CSR_TIME, 0); // time CSR is read-only
|
|
|
Line 489... |
Line 481... |
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// No "real" CSR write access (because rs1 = r0)
|
// No "real" CSR write access (because rs1 = r0)
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] Read-only CSR (time) no-write (rs1=0) access: ", cnt_test);
|
PRINT_STANDARD("[%i] Read-only CSR 'no-write' (rs1=0) access: ", cnt_test);
|
|
|
cnt_test++;
|
cnt_test++;
|
|
|
// time CSR is read-only, but no actual write is performed because rs1=r0
|
// time CSR is read-only, but no actual write is performed because rs1=r0
|
// -> should cause no exception
|
// -> should cause no exception
|
Line 509... |
Line 501... |
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Test pending interrupt
|
// Test pending interrupt
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] Pending IRQ test (from MTIME): ", cnt_test);
|
PRINT_STANDARD("[%i] Pending IRQ test (MTIME): ", cnt_test);
|
|
|
if (neorv32_mtime_available()) {
|
|
cnt_test++;
|
cnt_test++;
|
|
|
// disable global interrupts
|
// disable global interrupts
|
neorv32_cpu_dint();
|
neorv32_cpu_dint();
|
|
|
// force MTIME IRQ
|
// prepare MTIME IRQ
|
neorv32_mtime_set_timecmp(0);
|
neorv32_mtime_set_time(0x00000000FFFFFFF8ULL); // prepare overflow
|
|
neorv32_mtime_set_timecmp(0x0000000100000000ULL); // IRQ on overflow
|
|
|
// wait some time for the IRQ to arrive the CPU
|
// wait some time for the IRQ to arrive the CPU
|
asm volatile("nop");
|
asm volatile("nop");
|
asm volatile("nop");
|
asm volatile("nop");
|
|
|
Line 537... |
Line 529... |
test_ok();
|
test_ok();
|
}
|
}
|
else {
|
else {
|
test_fail();
|
test_fail();
|
}
|
}
|
}
|
|
else {
|
|
neorv32_uart_printf("skipped (not implemented)\n");
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Unaligned instruction address
|
// Unaligned instruction address
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] I_ALIGN (instr. alignment) EXC: ", cnt_test);
|
PRINT_STANDARD("[%i] I_ALIGN (instr. alignment) EXC: ", cnt_test);
|
|
|
// skip if C-mode is implemented
|
// skip if C-mode is implemented
|
if ((neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_C_EXT)) == 0) {
|
if ((neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_C)) == 0) {
|
|
|
cnt_test++;
|
cnt_test++;
|
|
|
// call unaligned address
|
// call unaligned address
|
((void (*)(void))ADDR_UNALIGNED)();
|
((void (*)(void))ADDR_UNALIGNED)();
|
|
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_I_MISALIGNED) {
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_I_MISALIGNED) {
|
neorv32_uart_printf("ok\n");
|
PRINT_STANDARD("ok\n");
|
cnt_ok++;
|
cnt_ok++;
|
}
|
}
|
else {
|
else {
|
neorv32_uart_printf("fail\n");
|
PRINT_STANDARD("fail\n");
|
cnt_fail++;
|
cnt_fail++;
|
}
|
}
|
}
|
}
|
else {
|
else {
|
neorv32_uart_printf("skipped (n.a. with C-ext)\n");
|
PRINT_STANDARD("skipped (n.a. with C-ext)\n");
|
}
|
}
|
|
|
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Instruction access fault
|
// Instruction access fault
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] I_ACC (instr. bus access) EXC: ", cnt_test);
|
PRINT_STANDARD("[%i] I_ACC (instr. bus access) EXC: ", cnt_test);
|
cnt_test++;
|
cnt_test++;
|
|
|
// call unreachable aligned address
|
// call unreachable aligned address
|
((void (*)(void))ADDR_UNREACHABLE)();
|
((void (*)(void))ADDR_UNREACHABLE)();
|
|
|
Line 593... |
Line 581... |
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Illegal instruction
|
// Illegal instruction
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] I_ILLEG (illegal instr.) EXC: ", cnt_test);
|
PRINT_STANDARD("[%i] I_ILLEG (illegal instr.) EXC: ", cnt_test);
|
|
|
cnt_test++;
|
cnt_test++;
|
|
|
asm volatile ("csrrw zero, 0xfff, zero"); // = 0xfff01073 : CSR 0xfff not implemented -> illegal instruction
|
asm volatile ("csrrw zero, 0xfff, zero"); // = 0xfff01073 : CSR 0xfff not implemented -> illegal instruction
|
|
|
Line 619... |
Line 607... |
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Illegal compressed instruction
|
// Illegal compressed instruction
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] CI_ILLEG (illegal compr. instr.) EXC: ", cnt_test);
|
PRINT_STANDARD("[%i] CI_ILLEG (illegal compr. instr.) EXC: ", cnt_test);
|
|
|
// skip if C-mode is not implemented
|
// skip if C-mode is not implemented
|
if ((neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_C_EXT)) != 0) {
|
if ((neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_C)) != 0) {
|
|
|
cnt_test++;
|
cnt_test++;
|
|
|
// create test program in RAM
|
// create test program in RAM
|
static const uint32_t dummy_sub_program_ci[2] __attribute__((aligned(8))) = {
|
static const uint32_t dummy_sub_program_ci[2] __attribute__((aligned(8))) = {
|
Line 643... |
Line 631... |
else {
|
else {
|
test_fail();
|
test_fail();
|
}
|
}
|
}
|
}
|
else {
|
else {
|
neorv32_uart_printf("skipped (n.a. with C-ext)\n");
|
PRINT_STANDARD("skipped (n.a. with C-ext)\n");
|
}
|
}
|
|
|
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Breakpoint instruction
|
// Breakpoint instruction
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] BREAK (break instr.) EXC: ", cnt_test);
|
PRINT_STANDARD("[%i] BREAK (break instr.) EXC: ", cnt_test);
|
cnt_test++;
|
cnt_test++;
|
|
|
asm volatile("EBREAK");
|
asm volatile("EBREAK");
|
|
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_BREAKPOINT) {
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_BREAKPOINT) {
|
Line 668... |
Line 656... |
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Unaligned load address
|
// Unaligned load address
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] L_ALIGN (load addr alignment) EXC: ", cnt_test);
|
PRINT_STANDARD("[%i] L_ALIGN (load addr alignment) EXC: ", cnt_test);
|
cnt_test++;
|
cnt_test++;
|
|
|
// load from unaligned address
|
// load from unaligned address
|
asm volatile ("lw zero, %[input_i](zero)" : : [input_i] "i" (ADDR_UNALIGNED));
|
neorv32_cpu_load_unsigned_word(ADDR_UNALIGNED);
|
|
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_L_MISALIGNED) {
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_L_MISALIGNED) {
|
test_ok();
|
test_ok();
|
}
|
}
|
else {
|
else {
|
Line 686... |
Line 674... |
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Load access fault
|
// Load access fault
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] L_ACC (load bus access) EXC: ", cnt_test);
|
PRINT_STANDARD("[%i] L_ACC (load bus access) EXC: ", cnt_test);
|
cnt_test++;
|
cnt_test++;
|
|
|
// load from unreachable aligned address
|
// load from unreachable aligned address
|
dummy_dst = neorv32_cpu_load_unsigned_word(ADDR_UNREACHABLE);
|
neorv32_cpu_load_unsigned_word(ADDR_UNREACHABLE);
|
|
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_L_ACCESS) {
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_L_ACCESS) {
|
test_ok();
|
test_ok();
|
}
|
}
|
else {
|
else {
|
Line 704... |
Line 692... |
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Unaligned store address
|
// Unaligned store address
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] S_ALIGN (store addr alignment) EXC: ", cnt_test);
|
PRINT_STANDARD("[%i] S_ALIGN (store addr alignment) EXC: ", cnt_test);
|
cnt_test++;
|
cnt_test++;
|
|
|
// store to unaligned address
|
// store to unaligned address
|
asm volatile ("sw zero, %[input_i](zero)" : : [input_i] "i" (ADDR_UNALIGNED));
|
asm volatile ("sw zero, %[input_i](zero)" : : [input_i] "i" (ADDR_UNALIGNED));
|
|
|
Line 722... |
Line 710... |
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Store access fault
|
// Store access fault
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] S_ACC (store bus access) EXC: ", cnt_test);
|
PRINT_STANDARD("[%i] S_ACC (store bus access) EXC: ", cnt_test);
|
cnt_test++;
|
cnt_test++;
|
|
|
// store to unreachable aligned address
|
// store to unreachable aligned address
|
neorv32_cpu_store_unsigned_word(ADDR_UNREACHABLE, 0);
|
neorv32_cpu_store_unsigned_word(ADDR_UNREACHABLE, 0);
|
|
|
Line 740... |
Line 728... |
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Environment call from M-mode
|
// Environment call from M-mode
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] ENVCALL (ecall instr.) from M-mode EXC: ", cnt_test);
|
PRINT_STANDARD("[%i] ENVCALL (ecall instr.) from M-mode EXC: ", cnt_test);
|
cnt_test++;
|
cnt_test++;
|
|
|
asm volatile("ECALL");
|
asm volatile("ECALL");
|
|
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_MENV_CALL) {
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_MENV_CALL) {
|
Line 757... |
Line 745... |
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Environment call from U-mode
|
// Environment call from U-mode
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] ENVCALL (ecall instr.) from U-mode EXC: ", cnt_test);
|
PRINT_STANDARD("[%i] ENVCALL (ecall instr.) from U-mode EXC: ", cnt_test);
|
|
|
// skip if U-mode is not implemented
|
// skip if U-mode is not implemented
|
if (neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_U_EXT)) {
|
if (neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_U)) {
|
|
|
cnt_test++;
|
cnt_test++;
|
|
|
// switch to user mode (hart will be back in MACHINE mode when trap handler returns)
|
// switch to user mode (hart will be back in MACHINE mode when trap handler returns)
|
neorv32_cpu_goto_user_mode();
|
neorv32_cpu_goto_user_mode();
|
Line 779... |
Line 767... |
test_fail();
|
test_fail();
|
}
|
}
|
|
|
}
|
}
|
else {
|
else {
|
neorv32_uart_printf("skipped (n.a. without U-ext)\n");
|
PRINT_STANDARD("skipped (n.a. without U-ext)\n");
|
}
|
}
|
|
|
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Machine timer interrupt (MTIME)
|
// Machine timer interrupt (MTIME)
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] MTI (via MTIME): ", cnt_test);
|
PRINT_STANDARD("[%i] MTI (via MTIME): ", cnt_test);
|
|
|
if (neorv32_mtime_available()) {
|
|
cnt_test++;
|
cnt_test++;
|
|
|
// configure MTIME IRQ (and check overflow form low owrd to high word)
|
// configure MTIME IRQ (and check overflow form low owrd to high word)
|
neorv32_mtime_set_timecmp(-1);
|
neorv32_mtime_set_timecmp(-1);
|
neorv32_mtime_set_time(0);
|
neorv32_mtime_set_time(0);
|
Line 816... |
Line 803... |
test_fail();
|
test_fail();
|
}
|
}
|
|
|
// no more mtime interrupts
|
// no more mtime interrupts
|
neorv32_mtime_set_timecmp(-1);
|
neorv32_mtime_set_timecmp(-1);
|
}
|
|
else {
|
|
neorv32_uart_printf("skipped (not implemented)\n");
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Machine software interrupt (MSI) via testbench
|
// Machine software interrupt (MSI) via testbench
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] MSI (via testbench): ", cnt_test);
|
PRINT_STANDARD("[%i] MSI (via testbench): ", cnt_test);
|
|
|
if (is_simulation) { // check if this is a simulation
|
|
cnt_test++;
|
cnt_test++;
|
|
|
// trigger IRQ
|
// trigger IRQ
|
sim_irq_trigger(1 << CSR_MIE_MSIE);
|
sim_irq_trigger(1 << CSR_MIE_MSIE);
|
|
|
Line 844... |
Line 826... |
test_ok();
|
test_ok();
|
}
|
}
|
else {
|
else {
|
test_fail();
|
test_fail();
|
}
|
}
|
}
|
|
else {
|
|
neorv32_uart_printf("skipped (on real HW)\n");
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Machine external interrupt (MEI) via testbench
|
// Machine external interrupt (MEI) via testbench
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] MEI (via testbench): ", cnt_test);
|
PRINT_STANDARD("[%i] MEI (via testbench): ", cnt_test);
|
|
|
if (is_simulation) { // check if this is a simulation
|
|
cnt_test++;
|
cnt_test++;
|
|
|
// trigger IRQ
|
// trigger IRQ
|
sim_irq_trigger(1 << CSR_MIE_MEIE);
|
sim_irq_trigger(1 << CSR_MIE_MEIE);
|
|
|
Line 872... |
Line 849... |
test_ok();
|
test_ok();
|
}
|
}
|
else {
|
else {
|
test_fail();
|
test_fail();
|
}
|
}
|
}
|
|
else {
|
|
neorv32_uart_printf("skipped (on real HW)\n");
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Non-maskable interrupt (NMI) via testbench
|
// Non-maskable interrupt (NMI) via testbench
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] NMI (via testbench): ", cnt_test);
|
PRINT_STANDARD("[%i] NMI (via testbench): ", cnt_test);
|
|
|
if (is_simulation) { // check if this is a simulation
|
|
cnt_test++;
|
cnt_test++;
|
|
|
// trigger IRQ
|
// trigger IRQ
|
sim_irq_trigger(1 << 0);
|
sim_irq_trigger(1 << 0);
|
|
|
Line 900... |
Line 872... |
test_ok();
|
test_ok();
|
}
|
}
|
else {
|
else {
|
test_fail();
|
test_fail();
|
}
|
}
|
}
|
|
else {
|
|
neorv32_uart_printf("skipped (on real HW)\n");
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Fast interrupt channel 0 (WDT)
|
// Fast interrupt channel 0 (WDT)
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
|
if (neorv32_wdt_available()) {
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] FIRQ0 test (via WDT): ", cnt_test);
|
PRINT_STANDARD("[%i] FIRQ0 test (via WDT): ", cnt_test);
|
|
|
if (neorv32_wdt_available()) {
|
|
cnt_test++;
|
cnt_test++;
|
|
|
// enable fast interrupt
|
// enable fast interrupt
|
neorv32_cpu_irq_enable(CSR_MIE_FIRQ0E);
|
neorv32_cpu_irq_enable(CSR_MIE_FIRQ0E);
|
|
|
Line 940... |
Line 908... |
neorv32_wdt_disable();
|
neorv32_wdt_disable();
|
|
|
// disable fast interrupt
|
// disable fast interrupt
|
neorv32_cpu_irq_disable(CSR_MIE_FIRQ0E);
|
neorv32_cpu_irq_disable(CSR_MIE_FIRQ0E);
|
}
|
}
|
else {
|
|
neorv32_uart_printf("skipped (not implemented)\n");
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Fast interrupt channel 1 (CFS)
|
// Fast interrupt channel 1 (CFS)
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_uart_printf("[%i] FIRQ1 test (via CFS): ", cnt_test);
|
PRINT_STANDARD("[%i] FIRQ1 test (via CFS): ", cnt_test);
|
neorv32_uart_printf("skipped (not implemented)\n");
|
PRINT_STANDARD("skipped (n.a.)\n");
|
|
|
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Fast interrupt channel 2 (UART0.RX)
|
// Fast interrupt channel 2 (UART0.RX)
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
|
if (neorv32_uart1_available()) {
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] FIRQ2 test (via UART0.RX): ", cnt_test);
|
PRINT_STANDARD("[%i] FIRQ2 test (via UART0.RX): ", cnt_test);
|
|
|
if (is_simulation) { // check if this is a simulation
|
|
cnt_test++;
|
cnt_test++;
|
|
|
// enable fast interrupt
|
// enable fast interrupt
|
neorv32_cpu_irq_enable(CSR_MIE_FIRQ2E);
|
neorv32_cpu_irq_enable(CSR_MIE_FIRQ2E);
|
|
|
// wait for UART0 to finish transmitting
|
// wait for UART0 to finish transmitting
|
while(neorv32_uart_tx_busy());
|
while(neorv32_uart0_tx_busy());
|
|
|
// backup current UART0 configuration
|
// backup current UART0 configuration
|
tmp_a = UART0_CT;
|
tmp_a = UART0_CT;
|
|
|
// disable UART0 sim_mode if it is enabled
|
// make sure UART is enabled
|
|
UART0_CT |= (1 << UART_CT_EN);
|
|
// make sure sim mode is disabled
|
UART0_CT &= ~(1 << UART_CT_SIM_MODE);
|
UART0_CT &= ~(1 << UART_CT_SIM_MODE);
|
|
|
// trigger UART0 RX IRQ
|
// trigger UART0 RX IRQ
|
// the default test bench connects UART0.TXD_O to UART0_RXD_I
|
neorv32_uart0_putc(0);
|
UART0_DATA = 0; // we need to access the raw HW here, since >UART0_SIM_MODE< might be active
|
|
|
|
// wait for UART0 to finish transmitting
|
// wait for UART0 to finish transmitting
|
while(neorv32_uart_tx_busy());
|
while(neorv32_uart0_tx_busy());
|
|
|
// wait some time for the IRQ to arrive the CPU
|
// wait some time for the IRQ to arrive the CPU
|
asm volatile("nop");
|
asm volatile("nop");
|
asm volatile("nop");
|
asm volatile("nop");
|
|
|
// re-enable UART0 sim_mode if it was enabled
|
// restore original configuration
|
UART0_CT = tmp_a;
|
UART0_CT = tmp_a;
|
|
|
// disable fast interrupt
|
// disable fast interrupt
|
neorv32_cpu_irq_disable(CSR_MIE_FIRQ2E);
|
neorv32_cpu_irq_disable(CSR_MIE_FIRQ2E);
|
|
|
Line 997... |
Line 963... |
}
|
}
|
else {
|
else {
|
test_fail();
|
test_fail();
|
}
|
}
|
}
|
}
|
else {
|
|
neorv32_uart_printf("skipped (on real HW)\n");
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Fast interrupt channel 3 (UART0.TX)
|
// Fast interrupt channel 3 (UART0.TX)
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
|
if (neorv32_uart0_available()) {
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] FIRQ3 test (via UART0.TX): ", cnt_test);
|
PRINT_STANDARD("[%i] FIRQ3 test (via UART0.TX): ", cnt_test);
|
|
|
cnt_test++;
|
cnt_test++;
|
|
|
// UART0 TX interrupt enable
|
// UART0 TX interrupt enable
|
neorv32_cpu_irq_enable(CSR_MIE_FIRQ3E);
|
neorv32_cpu_irq_enable(CSR_MIE_FIRQ3E);
|
|
|
// wait for UART0 to finish transmitting
|
// wait for UART0 to finish transmitting
|
while(neorv32_uart_tx_busy());
|
while(neorv32_uart0_tx_busy());
|
|
|
// backup current UART0 configuration
|
// backup current UART0 configuration
|
tmp_a = UART0_CT;
|
tmp_a = UART0_CT;
|
|
|
// disable UART0 sim_mode if it is enabled
|
// make sure UART is enabled
|
|
UART0_CT |= (1 << UART_CT_EN);
|
|
// make sure sim mode is disabled
|
UART0_CT &= ~(1 << UART_CT_SIM_MODE);
|
UART0_CT &= ~(1 << UART_CT_SIM_MODE);
|
|
|
// trigger UART0 TX IRQ
|
// trigger UART0 TX IRQ
|
UART0_DATA = 0; // we need to access the raw HW here, since >UART0_SIM_MODE< might be active
|
neorv32_uart0_putc(0);
|
|
|
// wait for UART to finish transmitting
|
// wait for UART to finish transmitting
|
while(neorv32_uart_tx_busy());
|
while(neorv32_uart0_tx_busy());
|
|
|
// wait some time for the IRQ to arrive the CPU
|
// wait some time for the IRQ to arrive the CPU
|
asm volatile("nop");
|
asm volatile("nop");
|
asm volatile("nop");
|
asm volatile("nop");
|
|
|
// re-enable UART sim_mode if it was enabled
|
// restore original configuration
|
UART0_CT = tmp_a;
|
UART0_CT = tmp_a;
|
|
|
neorv32_cpu_irq_disable(CSR_MIE_FIRQ3E);
|
neorv32_cpu_irq_disable(CSR_MIE_FIRQ3E);
|
|
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_FIRQ_3) {
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_FIRQ_3) {
|
test_ok();
|
test_ok();
|
}
|
}
|
else {
|
else {
|
test_fail();
|
test_fail();
|
}
|
}
|
|
}
|
|
|
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Fast interrupt channel 4 (UART1.RX)
|
// Fast interrupt channel 4 (UART1.RX)
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
|
if (neorv32_uart1_available()) {
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] FIRQ4 test (via UART1.RX): ", cnt_test);
|
PRINT_STANDARD("[%i] FIRQ4 test (via UART1.RX): ", cnt_test);
|
|
|
if ((neorv32_uart1_available()) && (is_simulation)) { // UART1 available and we are in a simulation
|
|
cnt_test++;
|
cnt_test++;
|
|
|
// UART1 RX interrupt enable
|
// UART1 RX interrupt enable
|
neorv32_cpu_irq_enable(CSR_MIE_FIRQ4E);
|
neorv32_cpu_irq_enable(CSR_MIE_FIRQ4E);
|
|
|
// initialize UART1
|
// backup current UART1 configuration
|
UART1_CT = 0;
|
tmp_a = UART1_CT;
|
tmp_a = UART0_CT; // copy configuration from UART0
|
|
tmp_a &= ~(1 << UART_CT_SIM_MODE); // make sure sim_mode is disabled
|
// make sure UART is enabled
|
UART1_CT = tmp_a;
|
UART1_CT |= (1 << UART_CT_EN);
|
|
// make sure sim mode is disabled
|
|
UART1_CT &= ~(1 << UART_CT_SIM_MODE);
|
|
|
// trigger UART1 RX IRQ
|
// trigger UART1 RX IRQ
|
UART1_DATA = 0;
|
neorv32_uart1_putc(0);
|
|
|
// wait for UART1 to finish transmitting
|
// wait for UART1 to finish transmitting
|
while(neorv32_uart1_tx_busy());
|
while(neorv32_uart1_tx_busy());
|
|
|
// wait some time for the IRQ to arrive the CPU
|
// wait some time for the IRQ to arrive the CPU
|
asm volatile("nop");
|
asm volatile("nop");
|
asm volatile("nop");
|
asm volatile("nop");
|
|
|
// disable UART1
|
// restore original configuration
|
UART1_CT = 0;
|
UART1_CT = tmp_a;
|
|
|
// disable fast interrupt
|
// disable fast interrupt
|
neorv32_cpu_irq_disable(CSR_MIE_FIRQ4E);
|
neorv32_cpu_irq_disable(CSR_MIE_FIRQ4E);
|
|
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_FIRQ_4) {
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_FIRQ_4) {
|
Line 1086... |
Line 1055... |
}
|
}
|
else {
|
else {
|
test_fail();
|
test_fail();
|
}
|
}
|
}
|
}
|
else {
|
|
neorv32_uart_printf("skipped (not implemented)\n");
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Fast interrupt channel 5 (UART1.TX)
|
// Fast interrupt channel 5 (UART1.TX)
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
|
if (neorv32_uart1_available()) {
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] FIRQ5 test (via UART1.TX): ", cnt_test);
|
PRINT_STANDARD("[%i] FIRQ5 test (via UART1.TX): ", cnt_test);
|
|
|
if (neorv32_uart1_available()) {
|
|
cnt_test++;
|
cnt_test++;
|
|
|
// UART1 RX interrupt enable
|
// UART1 RX interrupt enable
|
neorv32_cpu_irq_enable(CSR_MIE_FIRQ5E);
|
neorv32_cpu_irq_enable(CSR_MIE_FIRQ5E);
|
|
|
// initialize UART1
|
// backup current UART1 configuration
|
UART1_CT = 0;
|
tmp_a = UART1_CT;
|
tmp_a = UART0_CT; // copy configuration from UART0
|
|
tmp_a &= ~(1 << UART_CT_SIM_MODE); // make sure sim_mode is disabled
|
// make sure UART is enabled
|
UART1_CT = tmp_a;
|
UART1_CT |= (1 << UART_CT_EN);
|
|
// make sure sim mode is disabled
|
|
UART1_CT &= ~(1 << UART_CT_SIM_MODE);
|
|
|
// trigger UART1 TX IRQ
|
// trigger UART1 TX IRQ
|
UART1_DATA = 0;
|
neorv32_uart1_putc(0);
|
|
|
// wait for UART1 to finish transmitting
|
// wait for UART1 to finish transmitting
|
while(neorv32_uart1_tx_busy());
|
while(neorv32_uart1_tx_busy());
|
|
|
// wait some time for the IRQ to arrive the CPU
|
// wait some time for the IRQ to arrive the CPU
|
asm volatile("nop");
|
asm volatile("nop");
|
asm volatile("nop");
|
asm volatile("nop");
|
|
|
// disable UART1
|
// restore original configuration
|
UART1_CT = 0;
|
UART1_CT = tmp_a;
|
|
|
// disable fast interrupt
|
// disable fast interrupt
|
neorv32_cpu_irq_disable(CSR_MIE_FIRQ5E);
|
neorv32_cpu_irq_disable(CSR_MIE_FIRQ5E);
|
|
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_FIRQ_5) {
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_FIRQ_5) {
|
Line 1132... |
Line 1100... |
}
|
}
|
else {
|
else {
|
test_fail();
|
test_fail();
|
}
|
}
|
}
|
}
|
else {
|
|
neorv32_uart_printf("skipped (not implemented)\n");
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Fast interrupt channel 6 (SPI)
|
// Fast interrupt channel 6 (SPI)
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
|
if (neorv32_spi_available()) {
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] FIRQ6 test (via SPI): ", cnt_test);
|
PRINT_STANDARD("[%i] FIRQ6 test (via SPI): ", cnt_test);
|
|
|
if (neorv32_spi_available()) {
|
|
cnt_test++;
|
cnt_test++;
|
|
|
// enable fast interrupt
|
// enable fast interrupt
|
neorv32_cpu_irq_enable(CSR_MIE_FIRQ6E);
|
neorv32_cpu_irq_enable(CSR_MIE_FIRQ6E);
|
|
|
Line 1173... |
Line 1138... |
neorv32_spi_disable();
|
neorv32_spi_disable();
|
|
|
// disable fast interrupt
|
// disable fast interrupt
|
neorv32_cpu_irq_disable(CSR_MIE_FIRQ6E);
|
neorv32_cpu_irq_disable(CSR_MIE_FIRQ6E);
|
}
|
}
|
else {
|
|
neorv32_uart_printf("skipped (not implemented)\n");
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Fast interrupt channel 7 (TWI)
|
// Fast interrupt channel 7 (TWI)
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
|
if (neorv32_twi_available()) {
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] FIRQ7 test (via TWI): ", cnt_test);
|
PRINT_STANDARD("[%i] FIRQ7 test (via TWI): ", cnt_test);
|
|
|
if (neorv32_twi_available()) {
|
|
cnt_test++;
|
cnt_test++;
|
|
|
// configure TWI, fastest clock, no peripheral clock stretching
|
// configure TWI, fastest clock, no peripheral clock stretching
|
neorv32_twi_setup(CLK_PRSC_2, 0);
|
neorv32_twi_setup(CLK_PRSC_2, 0);
|
|
|
Line 1212... |
Line 1174... |
|
|
// disable TWI
|
// disable TWI
|
neorv32_twi_disable();
|
neorv32_twi_disable();
|
neorv32_cpu_irq_disable(CSR_MIE_FIRQ7E);
|
neorv32_cpu_irq_disable(CSR_MIE_FIRQ7E);
|
}
|
}
|
else {
|
|
neorv32_uart_printf("skipped (not implemented)\n");
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Fast interrupt channel 8 (GPIO)
|
// Fast interrupt channel 8 (XIRQ)
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] FIRQ8 test (via GPIO): ", cnt_test);
|
PRINT_STANDARD("[%i] FIRQ8 test (via XIRQ): ", cnt_test);
|
|
if (neorv32_xirq_available()) {
|
|
|
if (is_simulation) { // check if this is a simulation
|
|
if (neorv32_gpio_available()) {
|
|
cnt_test++;
|
cnt_test++;
|
|
|
// clear output port
|
int xirq_err_cnt = 0;
|
neorv32_gpio_port_set(0);
|
xirq_trap_handler_ack = 0;
|
|
|
neorv32_cpu_irq_enable(CSR_MIE_FIRQ8E);
|
xirq_err_cnt += neorv32_xirq_setup(); // initialize XIRQ
|
|
xirq_err_cnt += neorv32_xirq_install(0, xirq_trap_handler0); // install XIRQ IRQ handler channel 0
|
|
xirq_err_cnt += neorv32_xirq_install(1, xirq_trap_handler1); // install XIRQ IRQ handler channel 1
|
|
|
// configure GPIO.in(31) for pin-change IRQ
|
neorv32_xirq_global_enable(); // enable XIRQ FIRQ
|
neorv32_gpio_pin_change_config(0x80000000);
|
|
|
|
// trigger pin-change IRQ by setting GPIO.out(31)
|
// trigger XIRQ channel 1 and 0
|
// the testbench connects GPIO.out => GPIO.in
|
neorv32_gpio_port_set(3);
|
neorv32_gpio_pin_set(31);
|
|
|
|
// wait some time for the IRQ to arrive the CPU
|
// wait for IRQs to arrive CPU
|
|
asm volatile("nop");
|
asm volatile("nop");
|
asm volatile("nop");
|
asm volatile("nop");
|
asm volatile("nop");
|
|
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_FIRQ_8) {
|
if ((neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_FIRQ_8) && // FIRQ8 IRQ
|
|
(xirq_err_cnt == 0) && // no errors during XIRQ configuration
|
|
(xirq_trap_handler_ack == 4)) { // XIRQ channel handler 0 executed before handler 1
|
test_ok();
|
test_ok();
|
}
|
}
|
else {
|
else {
|
test_fail();
|
test_fail();
|
}
|
}
|
|
|
// disable GPIO pin-change IRQ
|
neorv32_xirq_global_disable();
|
neorv32_gpio_pin_change_config(0);
|
XIRQ_IER = 0;
|
|
XIRQ_IPR = -1;
|
// clear output port
|
|
neorv32_gpio_port_set(0);
|
|
neorv32_cpu_irq_disable(CSR_MIE_FIRQ8E);
|
|
}
|
|
else {
|
|
neorv32_uart_printf("skipped (not implemented)\n");
|
|
}
|
|
}
|
|
else {
|
|
neorv32_uart_printf("skipped (on real HW)\n");
|
|
}
|
}
|
|
|
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Fast interrupt channel 9 (reserved)
|
// Fast interrupt channel 9 (NEOLED)
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_uart_printf("[%i] FIRQ9: ", cnt_test);
|
PRINT_STANDARD("[%i] FIRQ9 (NEOLED): skipped\n", cnt_test);
|
neorv32_uart_printf("skipped (not implemented)\n");
|
|
|
|
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Fast interrupt channel 10..15 (SoC fast IRQ 0..5)
|
// Fast interrupt channel 10 & 11 (SLINK)
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
|
if (neorv32_slink_available()) {
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] FIRQ10..15 (SoC fast IRQ 0..5; via testbench): ", cnt_test);
|
PRINT_STANDARD("[%i] FIRQ10 & 11 (SLINK): ", cnt_test);
|
|
|
if (is_simulation) { // check if this is a simulation
|
|
|
|
cnt_test++;
|
cnt_test++;
|
|
|
// enable SOC FIRQs
|
// enable SLINK
|
for (id=CSR_MIE_FIRQ10E; id<=CSR_MIE_FIRQ15E; id++) {
|
neorv32_slink_enable();
|
neorv32_cpu_irq_enable(id);
|
|
|
// enable SLINK FIRQs
|
|
neorv32_cpu_irq_enable(CSR_MIE_FIRQ10E);
|
|
neorv32_cpu_irq_enable(CSR_MIE_FIRQ11E);
|
|
|
|
tmp_a = 0; // error counter
|
|
|
|
// send single data word via link 0
|
|
if (neorv32_slink_tx0_nonblocking(0xA1B2C3D4)) {
|
|
tmp_a++; // sending failed
|
}
|
}
|
|
|
// trigger all SoC Fast interrupts at once
|
// get single data word from link 0
|
neorv32_cpu_dint(); // do not fire yet!
|
uint32_t slink_rx_data;
|
sim_irq_trigger((1 << CSR_MIE_FIRQ10E) | (1 << CSR_MIE_FIRQ11E) | (1 << CSR_MIE_FIRQ12E) | (1 << CSR_MIE_FIRQ13E) | (1 << CSR_MIE_FIRQ14E) | (1 << CSR_MIE_FIRQ15E));
|
if (neorv32_slink_rx0_nonblocking(&slink_rx_data)) {
|
|
tmp_a++; // receiving failed
|
|
}
|
|
|
// wait some time for the IRQ to arrive the CPU
|
// wait some time for the IRQ to arrive the CPU
|
asm volatile("nop");
|
asm volatile("nop");
|
asm volatile("nop");
|
asm volatile("nop");
|
|
|
// make sure all SoC FIRQs have been triggered
|
tmp_b = neorv32_cpu_csr_read(CSR_MCAUSE);
|
tmp_a = (1 << CSR_MIP_FIRQ10P) | (1 << CSR_MIP_FIRQ11P) | (1 << CSR_MIP_FIRQ12P) | (1 << CSR_MIP_FIRQ13P) | (1 << CSR_MIP_FIRQ14P) | (1 << CSR_MIP_FIRQ15P);
|
if (((tmp_b == TRAP_CODE_FIRQ_10) || (tmp_b == TRAP_CODE_FIRQ_11)) && // right trap code
|
|
(tmp_a == 0) && // local error counter = 0
|
if (neorv32_cpu_csr_read(CSR_MIP) == tmp_a) {
|
(slink_rx_data == 0xA1B2C3D4)) { // correct data read-back
|
neorv32_cpu_eint(); // allow IRQs to fire again
|
|
asm volatile ("nop");
|
|
asm volatile ("nop"); // irq should kick in HERE
|
|
|
|
tmp_a = neorv32_cpu_csr_read(CSR_MCAUSE);
|
|
if ((tmp_a >= TRAP_CODE_FIRQ_8) && (tmp_a <= TRAP_CODE_FIRQ_15)) {
|
|
test_ok();
|
test_ok();
|
}
|
}
|
else {
|
else {
|
test_fail();
|
test_fail();
|
}
|
}
|
}
|
|
|
|
// disable SOC FIRQs
|
// shutdown SLINK
|
for (id=CSR_MIE_FIRQ10E; id<=CSR_MIE_FIRQ15E; id++) {
|
neorv32_slink_disable();
|
neorv32_cpu_irq_disable(id);
|
|
}
|
|
}
|
|
else {
|
|
neorv32_uart_printf("skipped (on real HW)\n");
|
|
}
|
}
|
|
|
neorv32_cpu_eint(); // re-enable IRQs globally
|
|
|
//// ----------------------------------------------------------
|
|
//// Fast interrupt channel 12..15 (reserved)
|
|
//// ----------------------------------------------------------
|
|
//PRINT_STANDARD("[%i] FIRQ12..15: ", cnt_test);
|
|
//PRINT_STANDARD("skipped (n.a.)\n");
|
|
|
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Test WFI ("sleep") instructions, wakeup via MTIME
|
// Test WFI ("sleep") instructions, wakeup via MTIME
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] WFI (sleep instruction) test (wake-up via MTIME): ", cnt_test);
|
PRINT_STANDARD("[%i] WFI (sleep instruction) test (wake-up via MTIME): ", cnt_test);
|
|
|
if (neorv32_mtime_available()) {
|
|
cnt_test++;
|
cnt_test++;
|
|
|
// program wake-up timer
|
// program wake-up timer
|
neorv32_mtime_set_timecmp(neorv32_mtime_get_time() + 1000);
|
neorv32_mtime_set_timecmp(neorv32_mtime_get_time() + 1000);
|
|
|
Line 1349... |
Line 1301... |
test_ok();
|
test_ok();
|
}
|
}
|
|
|
// no more mtime interrupts
|
// no more mtime interrupts
|
neorv32_mtime_set_timecmp(-1);
|
neorv32_mtime_set_timecmp(-1);
|
}
|
|
else {
|
|
neorv32_uart_printf("skipped (not implemented)\n");
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Test invalid CSR access in user mode
|
// Test invalid CSR access in user mode
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] Invalid CSR access (mstatus) from user mode: ", cnt_test);
|
PRINT_STANDARD("[%i] Invalid CSR access (mstatus) from user mode: ", cnt_test);
|
|
|
// skip if U-mode is not implemented
|
// skip if U-mode is not implemented
|
if (neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_U_EXT)) {
|
if (neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_U)) {
|
|
|
cnt_test++;
|
cnt_test++;
|
|
|
// switch to user mode (hart will be back in MACHINE mode when trap handler returns)
|
// switch to user mode (hart will be back in MACHINE mode when trap handler returns)
|
neorv32_cpu_goto_user_mode();
|
neorv32_cpu_goto_user_mode();
|
{
|
{
|
// access to misa not allowed for user-level programs
|
// access to misa not allowed for user-level programs
|
tmp_a = neorv32_cpu_csr_read(CSR_MISA);
|
tmp_a = neorv32_cpu_csr_read(CSR_MISA);
|
}
|
}
|
|
|
|
if (tmp_a != 0) {
|
|
PRINT_CRITICAL("%c[1m<SECURITY FAILURE> %c[0m\n", 27, 27);
|
|
}
|
|
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_I_ILLEGAL) {
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_I_ILLEGAL) {
|
if (tmp_a == 0) { // make sure user-level code CANNOT read machine-level CSR content!
|
|
test_ok();
|
test_ok();
|
}
|
}
|
else {
|
else {
|
test_fail();
|
test_fail();
|
}
|
}
|
}
|
|
else {
|
|
test_fail();
|
|
}
|
|
|
|
}
|
}
|
else {
|
else {
|
neorv32_uart_printf("skipped (n.a. without U-ext)\n");
|
PRINT_STANDARD("skipped (n.a. without U-ext)\n");
|
}
|
}
|
|
|
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Test RTE debug trap handler
|
// Test RTE debug trap handler
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] RTE (runtime env.) debug trap handler: ", cnt_test);
|
PRINT_STANDARD("[%i] RTE debug trap handler: ", cnt_test);
|
|
|
cnt_test++;
|
cnt_test++;
|
|
|
// uninstall custom handler and use default RTE debug handler
|
// uninstall custom handler and use default RTE debug handler
|
neorv32_rte_exception_uninstall(RTE_TRAP_I_ILLEGAL);
|
neorv32_rte_exception_uninstall(RTE_TRAP_I_ILLEGAL);
|
|
|
// trigger illegal instruction exception
|
// trigger illegal instruction exception
|
neorv32_cpu_csr_read(0xfff); // CSR not available
|
neorv32_cpu_csr_read(0xfff); // CSR not available
|
|
|
neorv32_uart_printf(" ");
|
PRINT_STANDARD(" ");
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) != 0) {
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) != 0) {
|
test_ok();
|
test_ok();
|
}
|
}
|
else {
|
else {
|
test_fail();
|
test_fail();
|
neorv32_uart_printf("answer: 0x%x", neorv32_cpu_csr_read(CSR_MCAUSE));
|
PRINT_STANDARD("answer: 0x%x", neorv32_cpu_csr_read(CSR_MCAUSE));
|
}
|
}
|
|
|
// restore original handler
|
// restore original handler
|
neorv32_rte_exception_install(RTE_TRAP_I_ILLEGAL, global_trap_handler);
|
neorv32_rte_exception_install(RTE_TRAP_I_ILLEGAL, global_trap_handler);
|
|
|
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Test physical memory protection
|
// Test physical memory protection
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_uart_printf("[%i] PMP - Physical memory protection: ", cnt_test);
|
PRINT_STANDARD("[%i] PMP - Physical memory protection: ", cnt_test);
|
|
|
// check if PMP is implemented
|
// check if PMP is implemented
|
if (neorv32_cpu_pmp_get_num_regions() != 0) {
|
if (neorv32_cpu_pmp_get_num_regions() != 0) {
|
|
|
// Create PMP protected region
|
// Create PMP protected region
|
// ---------------------------------------------
|
// ---------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
cnt_test++;
|
cnt_test++;
|
|
|
// find out mininmal region size (granulartiy)
|
// find out minimal region size (granularity)
|
tmp_b = neorv32_cpu_pmp_get_granularity();
|
tmp_b = neorv32_cpu_pmp_get_granularity();
|
|
|
tmp_a = SYSINFO_DSPACE_BASE; // base address of protected region
|
tmp_a = SYSINFO_DSPACE_BASE; // base address of protected region
|
neorv32_uart_printf("Creating protected page (NAPOT, [!X,!W,R], %u bytes) @ 0x%x: ", tmp_b, tmp_a);
|
PRINT_STANDARD("Creating protected page (NAPOT, [!X,!W,!R], %u bytes) @ 0x%x: ", tmp_b, tmp_a);
|
|
|
// configure
|
// configure
|
int pmp_return = neorv32_cpu_pmp_configure_region(0, tmp_a, tmp_b, 0b00011001); // NAPOT, read permission, NO write and NO execute permissions
|
int pmp_return = neorv32_cpu_pmp_configure_region(0, tmp_a, tmp_b, 0b00011000); // NAPOT, NO read permission, NO write permission, and NO execute permissions
|
|
|
if ((pmp_return == 0) && (neorv32_cpu_csr_read(CSR_MCAUSE) == 0)) {
|
if ((pmp_return == 0) && (neorv32_cpu_csr_read(CSR_MCAUSE) == 0)) {
|
test_ok();
|
test_ok();
|
}
|
}
|
else {
|
else {
|
test_fail();
|
test_fail();
|
}
|
}
|
|
|
|
|
// ------ EXECUTE: should fail ------
|
// ------ EXECUTE: should fail ------
|
neorv32_uart_printf("[%i] PMP: U-mode [!X,!W,R] execute: ", cnt_test);
|
PRINT_STANDARD("[%i] PMP: U-mode execute: ", cnt_test);
|
cnt_test++;
|
cnt_test++;
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
|
|
// switch to user mode (hart will be back in MACHINE mode when trap handler returns)
|
// switch to user mode (hart will be back in MACHINE mode when trap handler returns)
|
neorv32_cpu_goto_user_mode();
|
neorv32_cpu_goto_user_mode();
|
{
|
{
|
asm volatile ("jalr ra, %[input_i]" : : [input_i] "r" (tmp_a)); // call address to execute -> should fail
|
asm volatile ("jalr ra, %[input_i]" : : [input_i] "r" (tmp_a)); // call address to execute -> should fail
|
}
|
}
|
|
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) {
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) {
|
// switch back to machine mode (if not allready)
|
// switch back to machine mode (if not already)
|
asm volatile ("ecall");
|
asm volatile ("ecall");
|
|
|
test_fail();
|
test_fail();
|
}
|
}
|
else {
|
else {
|
// switch back to machine mode (if not allready)
|
// switch back to machine mode (if not already)
|
asm volatile ("ecall");
|
asm volatile ("ecall");
|
|
|
test_ok();
|
test_ok();
|
}
|
}
|
|
|
|
|
// ------ LOAD: should work ------
|
// ------ LOAD: should fail ------
|
neorv32_uart_printf("[%i] PMP: U-mode [!X,!W,R] read: ", cnt_test);
|
PRINT_STANDARD("[%i] PMP: U-mode read: ", cnt_test);
|
cnt_test++;
|
cnt_test++;
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
|
|
// switch to user mode (hart will be back in MACHINE mode when trap handler returns)
|
// switch to user mode (hart will be back in MACHINE mode when trap handler returns)
|
neorv32_cpu_goto_user_mode();
|
neorv32_cpu_goto_user_mode();
|
{
|
{
|
asm volatile ("lw zero, 0(%[input_i])" : : [input_i] "r" (tmp_a)); // load access -> should work
|
tmp_b = neorv32_cpu_load_unsigned_word(tmp_a); // load access -> should fail
|
}
|
}
|
|
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) {
|
if (tmp_b != 0) {
|
// switch back to machine mode (if not allready)
|
PRINT_CRITICAL("%c[1m<SECURITY FAILURE> %c[0m\n", 27, 27);
|
|
}
|
|
|
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_L_ACCESS) {
|
|
// switch back to machine mode (if not already)
|
asm volatile ("ecall");
|
asm volatile ("ecall");
|
|
|
test_ok();
|
test_ok();
|
}
|
}
|
else {
|
else {
|
// switch back to machine mode (if not allready)
|
// switch back to machine mode (if not already)
|
asm volatile ("ecall");
|
asm volatile ("ecall");
|
|
|
test_fail();
|
test_fail();
|
}
|
}
|
|
|
|
|
// ------ STORE: should fail ------
|
// ------ STORE: should fail ------
|
neorv32_uart_printf("[%i] PMP: U-mode [!X,!W,R] write: ", cnt_test);
|
PRINT_STANDARD("[%i] PMP: U-mode write: ", cnt_test);
|
cnt_test++;
|
cnt_test++;
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
|
|
// switch to user mode (hart will be back in MACHINE mode when trap handler returns)
|
// switch to user mode (hart will be back in MACHINE mode when trap handler returns)
|
neorv32_cpu_goto_user_mode();
|
neorv32_cpu_goto_user_mode();
|
{
|
{
|
asm volatile ("sw zero, 0(%[input_i])" : : [input_i] "r" (tmp_a)); // store access -> should fail
|
neorv32_cpu_store_unsigned_word(tmp_a, 0); // store access -> should fail
|
}
|
}
|
|
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_S_ACCESS) {
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_S_ACCESS) {
|
// switch back to machine mode (if not allready)
|
// switch back to machine mode (if not already)
|
asm volatile ("ecall");
|
asm volatile ("ecall");
|
|
|
test_ok();
|
test_ok();
|
}
|
}
|
else {
|
else {
|
// switch back to machine mode (if not allready)
|
// switch back to machine mode (if not already)
|
asm volatile ("ecall");
|
asm volatile ("ecall");
|
|
|
test_fail();
|
test_fail();
|
}
|
}
|
|
|
|
|
// ------ Lock test - pmpcfg0.0 / pmpaddr0 ------
|
// ------ Lock test - pmpcfg0.0 / pmpaddr0 ------
|
neorv32_uart_printf("[%i] PMP: Entry [mode=off] lock: ", cnt_test);
|
PRINT_STANDARD("[%i] PMP: Entry [mode=off] lock: ", cnt_test);
|
cnt_test++;
|
cnt_test++;
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
|
|
neorv32_cpu_csr_write(CSR_PMPCFG0, 0b10000001); // locked, but entry is deactivated (mode = off)
|
neorv32_cpu_csr_write(CSR_PMPCFG0, 0b10000001); // locked, but entry is deactivated (mode = off)
|
|
|
Line 1546... |
Line 1497... |
test_ok();
|
test_ok();
|
}
|
}
|
|
|
}
|
}
|
else {
|
else {
|
neorv32_uart_printf("skipped (not implemented)\n");
|
PRINT_STANDARD("skipped (n.a.)\n");
|
}
|
}
|
|
|
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Test atomic LR/SC operation - should succeed
|
// Test atomic LR/SC operation - should succeed
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] Atomic access (LR+SC succeeding access): ", cnt_test);
|
PRINT_STANDARD("[%i] Atomic access (LR+SC succeeding access): ", cnt_test);
|
|
|
#ifdef __riscv_atomic
|
#ifdef __riscv_atomic
|
// skip if A-mode is not implemented
|
// skip if A-mode is not implemented
|
if ((neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_A_EXT)) != 0) {
|
if ((neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_A)) != 0) {
|
|
|
cnt_test++;
|
cnt_test++;
|
|
|
neorv32_cpu_store_unsigned_word((uint32_t)&atomic_access_addr, 0x11223344);
|
neorv32_cpu_store_unsigned_word((uint32_t)&atomic_access_addr, 0x11223344);
|
|
|
Line 1580... |
Line 1531... |
else {
|
else {
|
test_fail();
|
test_fail();
|
}
|
}
|
}
|
}
|
else {
|
else {
|
neorv32_uart_printf("skipped (not implemented)\n");
|
PRINT_STANDARD("skipped (n.a.)\n");
|
}
|
}
|
#else
|
#else
|
neorv32_uart_printf("skipped (not implemented)\n");
|
PRINT_STANDARD("skipped (n.a.)\n");
|
#endif
|
#endif
|
|
|
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Test atomic LR/SC operation - should fail
|
// Test atomic LR/SC operation - should fail
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] Atomic access (LR+SC failing access 1): ", cnt_test);
|
PRINT_STANDARD("[%i] Atomic access (LR+SC failing access 1): ", cnt_test);
|
|
|
#ifdef __riscv_atomic
|
#ifdef __riscv_atomic
|
// skip if A-mode is not implemented
|
// skip if A-mode is not implemented
|
if ((neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_A_EXT)) != 0) {
|
if ((neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_A)) != 0) {
|
|
|
cnt_test++;
|
cnt_test++;
|
|
|
neorv32_cpu_store_unsigned_word((uint32_t)&atomic_access_addr, 0xAABBCCDD);
|
neorv32_cpu_store_unsigned_word((uint32_t)&atomic_access_addr, 0xAABBCCDD);
|
|
|
Line 1616... |
Line 1567... |
else {
|
else {
|
test_fail();
|
test_fail();
|
}
|
}
|
}
|
}
|
else {
|
else {
|
neorv32_uart_printf("skipped (not implemented)\n");
|
PRINT_STANDARD("skipped (n.a.)\n");
|
}
|
}
|
#else
|
#else
|
neorv32_uart_printf("skipped (not implemented)\n");
|
PRINT_STANDARD("skipped (n.a.)\n");
|
#endif
|
#endif
|
|
|
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Test atomic LR/SC operation - should fail
|
// Test atomic LR/SC operation - should fail
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_uart_printf("[%i] Atomic access (LR+SC failing access 2): ", cnt_test);
|
PRINT_STANDARD("[%i] Atomic access (LR+SC failing access 2): ", cnt_test);
|
|
|
#ifdef __riscv_atomic
|
#ifdef __riscv_atomic
|
// skip if A-mode is not implemented
|
// skip if A-mode is not implemented
|
if ((neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_A_EXT)) != 0) {
|
if ((neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_A)) != 0) {
|
|
|
cnt_test++;
|
cnt_test++;
|
|
|
neorv32_cpu_store_unsigned_word((uint32_t)&atomic_access_addr, 0x12341234);
|
neorv32_cpu_store_unsigned_word((uint32_t)&atomic_access_addr, 0x12341234);
|
|
|
Line 1652... |
Line 1603... |
else {
|
else {
|
test_fail();
|
test_fail();
|
}
|
}
|
}
|
}
|
else {
|
else {
|
neorv32_uart_printf("skipped (on real HW)\n");
|
PRINT_STANDARD("skipped (on real HW)\n");
|
}
|
}
|
#else
|
#else
|
neorv32_uart_printf("skipped (not implemented)\n");
|
PRINT_STANDARD("skipped (n.a.)\n");
|
#endif
|
#endif
|
|
|
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// HPM reports
|
// HPM reports
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCOUNTINHIBIT, -1); // stop all counters
|
neorv32_cpu_csr_write(CSR_MCOUNTINHIBIT, -1); // stop all counters
|
neorv32_uart_printf("\n\n-- HPM reports LOW (%u HPMs available) --\n", num_hpm_cnts_global);
|
PRINT_STANDARD("\n\n-- HPM reports LOW (%u HPMs available) --\n", num_hpm_cnts_global);
|
neorv32_uart_printf("#IR - Total number of instr.: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_INSTRET)); // = "HPM_0"
|
PRINT_STANDARD("#IR - Instr.: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_INSTRET)); // = "HPM_0"
|
//neorv32_uart_printf("#TM - Current system time: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_TIME)); // = "HPM_1"
|
//PRINT_STANDARD("#TM - Time: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_TIME)); // = "HPM_1"
|
neorv32_uart_printf("#CY - Total number of clk cyc.: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_CYCLE)); // = "HPM_2"
|
PRINT_STANDARD("#CY - CLKs: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_CYCLE)); // = "HPM_2"
|
neorv32_uart_printf("#03 - Retired compr. instr.: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER3));
|
PRINT_STANDARD("#03 - Compr.: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER3));
|
neorv32_uart_printf("#04 - I-fetch wait cyc.: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER4));
|
PRINT_STANDARD("#04 - IF wait: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER4));
|
neorv32_uart_printf("#05 - I-issue wait cyc.: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER5));
|
PRINT_STANDARD("#05 - II wait: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER5));
|
neorv32_uart_printf("#06 - Multi-cyc. ALU wait cyc.: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER6));
|
PRINT_STANDARD("#06 - ALU wait: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER6));
|
neorv32_uart_printf("#07 - Load operations: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER7));
|
PRINT_STANDARD("#07 - Loads: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER7));
|
neorv32_uart_printf("#08 - Store operations: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER8));
|
PRINT_STANDARD("#08 - Stores: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER8));
|
neorv32_uart_printf("#09 - Load/store wait cycles: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER9));
|
PRINT_STANDARD("#09 - MEM wait: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER9));
|
neorv32_uart_printf("#10 - Unconditional jumps: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER10));
|
PRINT_STANDARD("#10 - Jumps: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER10));
|
neorv32_uart_printf("#11 - Cond. branches (total): %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER11));
|
PRINT_STANDARD("#11 - Branches: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER11));
|
neorv32_uart_printf("#12 - Cond. branches (taken): %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER12));
|
PRINT_STANDARD("#12 - Taken: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER12));
|
neorv32_uart_printf("#13 - Entered traps: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER13));
|
PRINT_STANDARD("#13 - Traps: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER13));
|
neorv32_uart_printf("#14 - Illegal operations: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER14));
|
PRINT_STANDARD("#14 - Illegals: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER14));
|
|
|
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Final test reports
|
// Final test reports
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_uart_printf("\n\nTest results:\nOK: %i/%i\nFAILED: %i/%i\n\n", cnt_ok, cnt_test, cnt_fail, cnt_test);
|
PRINT_CRITICAL("\n\nTest results:\nPASS: %i/%i\nFAIL: %i/%i\n\n", cnt_ok, cnt_test, cnt_fail, cnt_test);
|
|
|
// final result
|
// final result
|
if (cnt_fail == 0) {
|
if (cnt_fail == 0) {
|
neorv32_uart_printf("%c[1m[CPU TEST COMPLETED SUCCESSFULLY!]%c[0m\n", 27, 27);
|
PRINT_STANDARD("%c[1m[CPU TEST COMPLETED SUCCESSFULLY!]%c[0m\n", 27, 27);
|
return 0;
|
|
}
|
}
|
else {
|
else {
|
neorv32_uart_printf("%c[1m[CPU TEST FAILED!]%c[0m\n", 27, 27);
|
PRINT_STANDARD("%c[1m[CPU TEST FAILED!]%c[0m\n", 27, 27);
|
return 1;
|
|
}
|
}
|
|
|
|
return (int)cnt_fail; // return error counter for after-main handler
|
}
|
}
|
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Simulation-based function to trigger CPU interrupts (MSI, MEI, FIRQ4..7).
|
* Simulation-based function to trigger CPU interrupts (MSI, MEI, FIRQ4..7).
|
Line 1722... |
Line 1672... |
asm volatile ("csrrs zero, mstatus, %[input_j]" : : [input_j] "r" (mask));
|
asm volatile ("csrrs zero, mstatus, %[input_j]" : : [input_j] "r" (mask));
|
}
|
}
|
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
|
* XIRQ handler channel 0.
|
|
**************************************************************************/
|
|
void xirq_trap_handler0(void) {
|
|
|
|
xirq_trap_handler_ack += 2;
|
|
}
|
|
|
|
|
|
/**********************************************************************//**
|
|
* XIRQ handler channel 1.
|
|
**************************************************************************/
|
|
void xirq_trap_handler1(void) {
|
|
|
|
xirq_trap_handler_ack *= 2;
|
|
}
|
|
|
|
|
|
/**********************************************************************//**
|
* Test results helper function: Shows "[ok]" and increments global cnt_ok
|
* Test results helper function: Shows "[ok]" and increments global cnt_ok
|
**************************************************************************/
|
**************************************************************************/
|
void test_ok(void) {
|
void test_ok(void) {
|
|
|
neorv32_uart_printf("%c[1m[ok]%c[0m\n", 27, 27);
|
PRINT_STANDARD("%c[1m[ok]%c[0m\n", 27, 27);
|
cnt_ok++;
|
cnt_ok++;
|
}
|
}
|
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Test results helper function: Shows "[FAILED]" and increments global cnt_fail
|
* Test results helper function: Shows "[FAIL]" and increments global cnt_fail
|
**************************************************************************/
|
**************************************************************************/
|
void test_fail(void) {
|
void test_fail(void) {
|
|
|
neorv32_uart_printf("%c[1m[FAILED]%c[0m\n", 27, 27);
|
PRINT_CRITICAL("%c[1m[FAIL]%c[0m\n", 27, 27);
|
cnt_fail++;
|
cnt_fail++;
|
}
|
}
|
|
|
No newline at end of file
|
No newline at end of file
|
|
|
|
/**********************************************************************//**
|
|
* "after-main" handler that is executed after the application's
|
|
* main function returns (called by crt0.S start-up code): Output minimal
|
|
* test report to physical UART
|
|
**************************************************************************/
|
|
int __neorv32_crt0_after_main(int32_t return_code) {
|
|
|
|
// make sure sim mode is disabled and UARTs are actually enabled
|
|
UART0_CT |= (1 << UART_CT_EN);
|
|
UART0_CT &= ~(1 << UART_CT_SIM_MODE);
|
|
UART1_CT = UART0_CT;
|
|
|
|
// minimal result report
|
|
PRINT_CRITICAL("%u/%u\n", (uint32_t)return_code, (uint32_t)cnt_test);
|
|
|
|
return 0;
|
|
}
|
|
|
No newline at end of file
|
No newline at end of file
|