URL
https://opencores.org/ocsvn/neorv32/neorv32/trunk
Subversion Repositories neorv32
Compare Revisions
- This comparison shows the changes necessary to convert path
/neorv32/trunk/sw/example
- from Rev 40 to Rev 41
- ↔ Reverse comparison
Rev 40 → Rev 41
/cpu_test/main.c
72,6 → 72,8
int cnt_ok = 0; |
/// Global counter for total number of tests |
int cnt_test = 0; |
/// Global timestamp for traps (stores mcycle.low on trap enter) |
uint32_t trap_timestamp32 = 0; |
|
|
/**********************************************************************//** |
160,6 → 162,10
neorv32_cpu_set_minstret(0); |
neorv32_cpu_set_mcycle(0); |
|
// enable performance counter auto increment |
neorv32_cpu_csr_write(CSR_MCOUNTINHIBIT, 0); |
neorv32_cpu_csr_write(CSR_MCOUNTEREN, 7); // allow access from user-mode code |
|
neorv32_mtime_set_time(0); |
// set CMP of machine system timer MTIME to max to prevent an IRQ |
uint64_t mtime_cmp_max = 0xFFFFFFFFFFFFFFFFUL; |
181,7 → 187,9
// show full HW config report |
neorv32_rte_print_hw_config(); |
|
|
// configure RTE |
// ----------------------------------------------- |
neorv32_uart_printf("\n\nInitializing NEORV32 run-time environment (RTE)... "); |
|
neorv32_rte_setup(); // this will install a full-detailed debug handler for all traps |
295,29 → 303,22
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] Testing [m]instret[h] counters: ", cnt_test); |
|
// check if counters are implemented |
if (neorv32_cpu_csr_read(CSR_MZEXT) & (1<<CPU_MZEXT_ZICNT)) { |
cnt_test++; |
cnt_test++; |
|
// get current cycle counter |
volatile uint64_t cycle_csr_test = neorv32_cpu_get_cycle(); |
// get current cycle counter |
tmp_a = neorv32_cpu_get_cycle(); |
|
// wait some time to have a nice increment |
asm volatile ("nop"); |
asm volatile ("nop"); |
asm volatile ("nop"); |
// wait some time to have a nice increment |
asm volatile ("nop"); |
asm volatile ("nop"); |
|
// make sure cycle counter has incremented and there was no exception during access |
if ((neorv32_cpu_get_cycle() > cycle_csr_test) && |
(neorv32_cpu_csr_read(CSR_MCAUSE) == 0)) { |
test_ok(); |
} |
else { |
test_fail(); |
} |
// make sure cycle counter has incremented and there was no exception during access |
if ((neorv32_cpu_get_cycle() > tmp_a) && |
(neorv32_cpu_csr_read(CSR_MCAUSE) == 0)) { |
test_ok(); |
} |
else { |
neorv32_uart_printf("skipped (not implemented)\n"); |
test_fail(); |
} |
|
|
327,34 → 328,104
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] Testing [m]cycle[h] counters: ", cnt_test); |
|
// check if counters are implemented |
if (neorv32_cpu_csr_read(CSR_MZEXT) & (1<<CPU_MZEXT_ZICNT)) { |
cnt_test++; |
cnt_test++; |
|
// get current instruction counter |
volatile uint64_t instret_csr_test = neorv32_cpu_get_instret(); |
// get current instruction counter |
tmp_a = neorv32_cpu_get_instret(); |
|
// wait some time to have a nice increment |
asm volatile ("nop"); |
asm volatile ("nop"); |
asm volatile ("nop"); |
// wait some time to have a nice increment |
asm volatile ("nop"); |
asm volatile ("nop"); |
|
// make sure instruction counter has incremented and there was no exception during access |
if ((neorv32_cpu_get_instret() > instret_csr_test) && |
(neorv32_cpu_csr_read(CSR_MCAUSE) == 0)) { |
// make sure instruction counter has incremented and there was no exception during access |
if ((neorv32_cpu_get_instret() > tmp_a) && |
(neorv32_cpu_csr_read(CSR_MCAUSE) == 0)) { |
test_ok(); |
} |
else { |
test_fail(); |
} |
|
|
// ---------------------------------------------------------- |
// Test mcountinhibt: inhibit auto-inc of [m]cycle |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] Testing mcountINHIBT.cy CSR: ", cnt_test); |
|
cnt_test++; |
|
// inhibit [m]cycle CSR |
tmp_a = neorv32_cpu_csr_read(CSR_MCOUNTINHIBIT); |
tmp_a |= (1<<CPU_MCOUNTINHIBIT_CY); // inhibit cycle counter auto-increment |
neorv32_cpu_csr_write(CSR_MCOUNTINHIBIT, tmp_a); |
|
// get current cycle counter |
tmp_a = neorv32_cpu_csr_read(CSR_CYCLE); |
|
// wait some time to have a nice "increment" (there should be NO increment at all!) |
asm volatile ("nop"); |
asm volatile ("nop"); |
|
tmp_b = neorv32_cpu_csr_read(CSR_CYCLE); |
|
// make sure instruction counter has NOT incremented and there was no exception during access |
if ((tmp_a == tmp_b) && (neorv32_cpu_csr_read(CSR_MCAUSE) == 0)) { |
test_ok(); |
} |
else { |
test_fail(); |
} |
|
// re-enable [m]cycle CSR |
tmp_a = neorv32_cpu_csr_read(CSR_MCOUNTINHIBIT); |
tmp_a &= ~(1<<CPU_MCOUNTINHIBIT_CY); // clear inhibit of cycle counter auto-increment |
neorv32_cpu_csr_write(CSR_MCOUNTINHIBIT, tmp_a); |
|
|
// ---------------------------------------------------------- |
// Test mcounteren: do not allow cycle[h] access from user-mode |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] Testing mcounterEN.cy CSR: ", cnt_test); |
|
cnt_test++; |
|
// do not allow user-level code to access cycle[h] CSRs |
tmp_a = neorv32_cpu_csr_read(CSR_MCOUNTEREN); |
tmp_a &= ~(1<<CPU_MCOUNTEREN_CY); // clear access right |
neorv32_cpu_csr_write(CSR_MCOUNTEREN, tmp_a); |
|
// switch to user mode (hart will be back in MACHINE mode when trap handler returns) |
neorv32_cpu_goto_user_mode(); |
{ |
// access to cycle CSR is no longer allowed |
tmp_a = neorv32_cpu_csr_read(CSR_CYCLE); |
} |
|
// make sure there was an illegal instruction trap |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_I_ILLEGAL) { |
if (tmp_a == 0) { // make sure user-level code CANNOT read locked CSR content! |
test_ok(); |
} |
else { |
neorv32_uart_printf("SECURITY VIOLATION! "); |
test_fail(); |
} |
} |
else { |
neorv32_uart_printf("skipped (not implemented)\n"); |
test_fail(); |
} |
|
|
// re-allow user-level code to access cycle[h] CSRs |
tmp_a = neorv32_cpu_csr_read(CSR_MCOUNTEREN); |
tmp_a |= (1<<CPU_MCOUNTEREN_CY); // re-allow access right |
neorv32_cpu_csr_write(CSR_MCOUNTEREN, tmp_a); |
|
|
// ---------------------------------------------------------- |
// Bus timeout latency estimation (very unprecise!) |
// Bus timeout latency estimation |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] Estimating bus time-out latency: ", cnt_test); |
364,13 → 435,11
neorv32_cpu_csr_write(CSR_MCYCLE, 0); |
|
// this store access will timeout |
MMR_UNREACHABLE = 0; |
MMR_UNREACHABLE = 0; // trap handler will stor mcycle.low to "trap_timestamp32" |
|
tmp_a = neorv32_cpu_csr_read(CSR_MCYCLE); |
|
// make sure there was a time-out |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_S_ACCESS) { |
neorv32_uart_printf("~%u cycles ", tmp_a/4); // divide by average CPI |
neorv32_uart_printf("~%u cycles ", trap_timestamp32-178); // remove trap handler overhead - empiric value ;) |
test_ok(); |
} |
else { |
560,7 → 629,6
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
asm volatile("nop"); |
asm volatile("nop"); |
|
// no more mtime interrupts |
neorv32_mtime_set_timecmp(-1); |
599,7 → 667,6
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
asm volatile("nop"); |
asm volatile("nop"); |
|
// no more mtime interrupts |
neorv32_mtime_set_timecmp(-1); |
854,7 → 921,6
// switch to user mode (hart will be back in MACHINE mode when trap handler returns) |
neorv32_cpu_goto_user_mode(); |
{ |
// access to misa not allowed for user-level programs |
asm volatile("ECALL"); |
} |
|
886,10 → 952,6
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
asm volatile("nop"); |
asm volatile("nop"); |
asm volatile("nop"); |
asm volatile("nop"); |
asm volatile("nop"); |
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_MTI) { |
test_ok(); |
921,10 → 983,6
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
asm volatile("nop"); |
asm volatile("nop"); |
asm volatile("nop"); |
asm volatile("nop"); |
asm volatile("nop"); |
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_MSI) { |
test_ok(); |
953,10 → 1011,6
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
asm volatile("nop"); |
asm volatile("nop"); |
asm volatile("nop"); |
asm volatile("nop"); |
asm volatile("nop"); |
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_MEI) { |
test_ok(); |
987,10 → 1041,6
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
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_0) { |
test_ok(); |
1030,10 → 1080,6
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
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_1) { |
test_ok(); |
1087,10 → 1133,6
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
asm volatile("nop"); |
asm volatile("nop"); |
asm volatile("nop"); |
asm volatile("nop"); |
asm volatile("nop"); |
|
// wait for UART to finish transmitting |
while(neorv32_uart_tx_busy()); |
1130,10 → 1172,6
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
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_3) { |
test_ok(); |
1170,10 → 1208,6
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
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_3) { |
test_ok(); |
1438,9 → 1472,10
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] Atomic access (LR+SC) test (succeeding access): ", cnt_test); |
|
#ifdef __riscv_atomic |
if ((UART_CT & (1 << UART_CT_SIM_MODE)) != 0) { // check if this is a simulation |
|
// skip if A-mode is implemented |
// skip if A-mode is not implemented |
if ((neorv32_cpu_csr_read(CSR_MISA) & (1<<CPU_MISA_A_EXT)) != 0) { |
|
cnt_test++; |
1463,6 → 1498,9
else { |
neorv32_uart_printf("skipped (on real hardware)\n"); |
} |
#else |
neorv32_uart_printf("skipped (not implemented)\n"); |
#endif |
|
|
// ---------------------------------------------------------- |
1471,9 → 1509,10
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] Atomic access (LR+SC) test (failing access): ", cnt_test); |
|
#ifdef __riscv_atomic |
if ((UART_CT & (1 << UART_CT_SIM_MODE)) != 0) { // check if this is a simulation |
|
// skip if A-mode is implemented |
// skip if A-mode is not implemented |
if ((neorv32_cpu_csr_read(CSR_MISA) & (1<<CPU_MISA_A_EXT)) != 0) { |
|
cnt_test++; |
1495,9 → 1534,44
else { |
neorv32_uart_printf("skipped (on real hardware)\n"); |
} |
#else |
neorv32_uart_printf("skipped (not implemented)\n"); |
#endif |
|
|
// ---------------------------------------------------------- |
// Test AMO atomic operation - should raise illegal instruction exception |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] Atomic AMOSWAP test (should raise illegal CMD exception): ", cnt_test); |
|
#ifdef __riscv_atomic |
// skip if A-mode is not implemented |
if ((neorv32_cpu_csr_read(CSR_MISA) & (1<<CPU_MISA_A_EXT)) != 0) { |
|
cnt_test++; |
|
// AMO operations are not implemented! |
// this should cause an illegal instruction exception |
asm volatile ("amoswap.w x0, x0, (x0)"); |
|
// atomic compare-and-swap |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_I_ILLEGAL) { |
test_ok(); |
} |
else { |
test_fail(); |
} |
} |
else { |
neorv32_uart_printf("skipped (not implemented)\n"); |
} |
#else |
neorv32_uart_printf("skipped (not implemented)\n"); |
#endif |
|
|
// ---------------------------------------------------------- |
// Final test reports |
// ---------------------------------------------------------- |
neorv32_uart_printf("\nExecuted instructions: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_INSTRET)); |
1522,6 → 1596,9
**************************************************************************/ |
void global_trap_handler(void) { |
|
// store time stamp |
trap_timestamp32 = neorv32_cpu_csr_read(CSR_MCYCLE); |
|
// hack: always come back in MACHINE MODE |
register uint32_t mask = (1<<CPU_MSTATUS_MPP_H) | (1<<CPU_MSTATUS_MPP_L); |
asm volatile ("csrrs zero, mstatus, %[input_j]" : : [input_j] "r" (mask)); |