OpenCores
URL https://opencores.org/ocsvn/neorv32/neorv32/trunk

Subversion Repositories neorv32

[/] [neorv32/] [trunk/] [sw/] [example/] [processor_check/] [main.c] - Diff between revs 60 and 61

Go to most recent revision | Show entire file | Details | Blame | View Log

Rev 60 Rev 61
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

powered by: WebSVN 2.1.0

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