OpenCores
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));

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.