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

Subversion Repositories neorv32

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

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

Rev 71 Rev 73
Line 80... Line 80...
#endif
#endif
/**@}*/
/**@}*/
 
 
 
 
// Prototypes
// Prototypes
 
void __attribute__((naked)) goto_user_mode(void);
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_handler0(void);
void xirq_trap_handler1(void);
void xirq_trap_handler1(void);
void test_ok(void);
void test_ok(void);
Line 99... Line 100...
/// Global number of available HPMs
/// Global number of available HPMs
uint32_t num_hpm_cnts_global = 0;
uint32_t num_hpm_cnts_global = 0;
/// XIRQ trap handler acknowledge
/// XIRQ trap handler acknowledge
uint32_t xirq_trap_handler_ack = 0;
uint32_t xirq_trap_handler_ack = 0;
 
 
 
/// Variable to test store accesses
 
volatile uint32_t store_access_addr[2];
 
 
/// Variable to test atomic accesses
/// Variable to test atomic accesses
uint32_t atomic_access_addr;
volatile uint32_t atomic_access_addr;
 
 
 
/// Variable to test PMP
 
volatile uint32_t pmp_access_addr;
 
 
 
 
/**********************************************************************//**
/**********************************************************************//**
 * High-level CPU/processor test program.
 * High-level CPU/processor test program.
 *
 *
Line 160... Line 167...
  else {
  else {
    PRINT_STANDARD("no\n");
    PRINT_STANDARD("no\n");
  }
  }
 
 
 
 
  // reset performance counter
  // reset (performance) counters
  // neorv32_cpu_csr_write(CSR_MCYCLEH, 0);   -> done in crt0.S
  // neorv32_cpu_csr_write(CSR_MCYCLEH, 0);   -> done in crt0.S
  // neorv32_cpu_csr_write(CSR_MCYCLE, 0);    -> done in crt0.S
  // neorv32_cpu_csr_write(CSR_MCYCLE, 0);    -> done in crt0.S
  // neorv32_cpu_csr_write(CSR_MINSTRETH, 0); -> done in crt0.S
  // neorv32_cpu_csr_write(CSR_MINSTRETH, 0); -> done in crt0.S
  // neorv32_cpu_csr_write(CSR_MINSTRET, 0);  -> done in crt0.S
  // neorv32_cpu_csr_write(CSR_MINSTRET, 0);  -> done in crt0.S
  neorv32_cpu_csr_write(CSR_MCOUNTINHIBIT, 0); // enable performance counter auto increment (ALL counters)
  neorv32_cpu_csr_write(CSR_MCOUNTINHIBIT, 0); // enable performance counter auto increment (ALL counters)
Line 175... Line 182...
  neorv32_mtime_set_time(0);
  neorv32_mtime_set_time(0);
 
 
 
 
  // fancy intro
  // fancy intro
  // -----------------------------------------------
  // -----------------------------------------------
  // logo
  // show ASCII logo
  neorv32_rte_print_logo();
  neorv32_rte_print_logo();
 
 
  // show project credits
  // show project credits
  neorv32_rte_print_credits();
  neorv32_rte_print_credits();
 
 
  // show full HW config report
  // show full hardware configuration report
  neorv32_rte_print_hw_config();
  neorv32_rte_print_hw_config();
 
 
 
 
  // configure RTE
  // configure RTE
  // -----------------------------------------------
  // -----------------------------------------------
Line 221... Line 228...
  // Run CPU and SoC tests
  // Run CPU and SoC tests
  // **********************************************************************************************
  // **********************************************************************************************
 
 
 
 
  // ----------------------------------------------------------
  // ----------------------------------------------------------
 
  // Test fence instructions (just make sure CPU does not crash)
 
  // ----------------------------------------------------------
 
  asm volatile ("fence");
 
  asm volatile ("fence.i");
 
 
 
 
 
  // ----------------------------------------------------------
  // 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);
  PRINT_STANDARD("[%i] Setup HPM events: ", cnt_test);
  PRINT_STANDARD("[%i] Setup HPM events: ", cnt_test);
 
 
Line 360... Line 374...
  // 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
  neorv32_cpu_csr_write(CSR_MCOUNTEREN, tmp_a);
  neorv32_cpu_csr_write(CSR_MCOUNTEREN, tmp_a);
 
 
  neorv32_cpu_csr_write(CSR_CYCLE, 1); // make sure CSR is != 0 for this test
  neorv32_cpu_csr_write(CSR_CYCLEH, 1); // make sure CSR is != 0 for this 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();
  goto_user_mode();
  {
  {
    // access to cycle CSR is no longer allowed
    // access to cycle CSR is no longer allowed
    asm volatile (" mv      %[result], zero  \n" // initialize with zero
    asm volatile (" li       %[result], 0xcc11aa22  \n" // initialize
                  " rdcycle %[result]          " // read CSR_CYCLE, is not allowed and should not alter [result]
                  " rdcycleh %[result]                " // read CSR_CYCLE, is not allowed and should not alter [result]
                  : [result] "=r" (tmp_a) : );
                  : [result] "=r" (tmp_a) : );
  }
  }
 
 
  if (tmp_a != 0) {
 
    PRINT_CRITICAL("%c[1m<SECURITY FAILURE> %c[0m\n", 27, 27);
 
  }
 
 
 
  // make sure there was an illegal instruction trap
  // make sure there was an illegal instruction trap
  if ((neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_I_ILLEGAL) && (tmp_a == 0)) {
  if ((neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_I_ILLEGAL) &&
 
      (tmp_a == 0xcc11aa22)) { // destination register not altered
    test_ok();
    test_ok();
  }
  }
  else {
  else {
    test_fail();
    test_fail();
  }
  }
Line 398... Line 409...
  PRINT_STANDARD("[%i] MRET in U-mode: ", cnt_test);
  PRINT_STANDARD("[%i] MRET in U-mode: ", cnt_test);
 
 
  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();
  goto_user_mode();
  {
  {
    asm volatile ("mret");
    asm volatile ("mret");
  }
  }
 
 
  if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_I_ILLEGAL) {
  if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_I_ILLEGAL) {
Line 415... Line 426...
 
 
  // ----------------------------------------------------------
  // ----------------------------------------------------------
  // External memory interface test
  // External memory interface test
  // ----------------------------------------------------------
  // ----------------------------------------------------------
  neorv32_cpu_csr_write(CSR_MCAUSE, 0);
  neorv32_cpu_csr_write(CSR_MCAUSE, 0);
  PRINT_STANDARD("[%i] External memory access (@ 0x%x): ", cnt_test, (uint32_t)EXT_MEM_BASE);
  PRINT_STANDARD("[%i] Ext. memory access (@ 0x%x): ", cnt_test, (uint32_t)EXT_MEM_BASE);
 
 
  if (NEORV32_SYSINFO.SOC & (1 << SYSINFO_SOC_MEM_EXT)) {
  if (NEORV32_SYSINFO.SOC & (1 << SYSINFO_SOC_MEM_EXT)) {
    cnt_test++;
    cnt_test++;
 
 
    // create test program in RAM
    // create test program in RAM
Line 454... Line 465...
 
 
  // ----------------------------------------------------------
  // ----------------------------------------------------------
  // 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);
  PRINT_STANDARD("[%i] Non-existent CSR access: ", cnt_test);
  PRINT_STANDARD("[%i] Non-existent CSR: ", cnt_test);
 
 
  cnt_test++;
  cnt_test++;
 
 
  tmp_a = neorv32_cpu_csr_read(0xfff); // CSR 0xfff not implemented
  tmp_a = neorv32_cpu_csr_read(0xfff); // CSR 0xfff not implemented
 
 
Line 472... Line 483...
 
 
  // ----------------------------------------------------------
  // ----------------------------------------------------------
  // 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);
  PRINT_STANDARD("[%i] Read-only CSR write access: ", cnt_test);
  PRINT_STANDARD("[%i] Read-only CSR write: ", 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 510... Line 521...
 
 
  // ----------------------------------------------------------
  // ----------------------------------------------------------
  // Unaligned instruction address
  // Unaligned instruction address
  // ----------------------------------------------------------
  // ----------------------------------------------------------
  neorv32_cpu_csr_write(CSR_MCAUSE, 0);
  neorv32_cpu_csr_write(CSR_MCAUSE, 0);
  PRINT_STANDARD("[%i] I_ALIGN (instr. alignment) EXC: ", cnt_test);
  PRINT_STANDARD("[%i] I_ALIGN (instr. align) 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)) == 0) {
  if ((neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_C)) == 0) {
 
 
    cnt_test++;
    cnt_test++;
Line 612... Line 623...
 
 
  // ----------------------------------------------------------
  // ----------------------------------------------------------
  // Breakpoint instruction
  // Breakpoint instruction
  // ----------------------------------------------------------
  // ----------------------------------------------------------
  neorv32_cpu_csr_write(CSR_MCAUSE, 0);
  neorv32_cpu_csr_write(CSR_MCAUSE, 0);
  PRINT_STANDARD("[%i] BREAK (break instr.) EXC: ", cnt_test);
  PRINT_STANDARD("[%i] BREAK 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 629... Line 640...
 
 
  // ----------------------------------------------------------
  // ----------------------------------------------------------
  // Unaligned load address
  // Unaligned load address
  // ----------------------------------------------------------
  // ----------------------------------------------------------
  neorv32_cpu_csr_write(CSR_MCAUSE, 0);
  neorv32_cpu_csr_write(CSR_MCAUSE, 0);
  PRINT_STANDARD("[%i] L_ALIGN (load addr alignment) EXC: ", cnt_test);
  PRINT_STANDARD("[%i] L_ALIGN (load align) EXC: ", cnt_test);
  cnt_test++;
  cnt_test++;
 
 
  // load from unaligned address
  // load from unaligned address
  neorv32_cpu_load_unsigned_word(ADDR_UNALIGNED_1);
  asm volatile ("li %[da], 0xcafe1230 \n" // initialize destination register with known value
 
                "lw %[da], 0(%[ad])     " // must not update destination register to to exception
 
                : [da] "=r" (tmp_b) : [ad] "r" (ADDR_UNALIGNED_1));
 
 
  if ((neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_L_MISALIGNED) &&
  if ((neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_L_MISALIGNED) &&
      (neorv32_cpu_csr_read(CSR_MTVAL) == ADDR_UNALIGNED_1)) {
      (neorv32_cpu_csr_read(CSR_MTVAL) == ADDR_UNALIGNED_1) &&
 
      (tmp_b == 0xcafe1230)) { // make sure dest. reg is not updated
    test_ok();
    test_ok();
  }
  }
  else {
  else {
    test_fail();
    test_fail();
  }
  }
Line 648... Line 662...
 
 
  // ----------------------------------------------------------
  // ----------------------------------------------------------
  // Load access fault
  // Load access fault
  // ----------------------------------------------------------
  // ----------------------------------------------------------
  neorv32_cpu_csr_write(CSR_MCAUSE, 0);
  neorv32_cpu_csr_write(CSR_MCAUSE, 0);
  PRINT_STANDARD("[%i] L_ACC (load bus access) EXC: ", cnt_test);
  PRINT_STANDARD("[%i] L_ACC (load access) EXC: ", cnt_test);
  cnt_test++;
  cnt_test++;
 
 
  tmp_a = (1 << BUSKEEPER_ERR_FLAG) | (1 << BUSKEEPER_ERR_TYPE);
  tmp_a = (1 << BUSKEEPER_ERR_FLAG) | (1 << BUSKEEPER_ERR_TYPE);
 
 
  // load from unreachable aligned address
  // load from unreachable aligned address
  neorv32_cpu_load_unsigned_word(ADDR_UNREACHABLE);
  asm volatile ("li %[da], 0xcafe1230 \n" // initialize destination register with known value
 
                "lw %[da], 0(%[ad])     " // must not update destination register to to exception
 
                : [da] "=r" (tmp_b) : [ad] "r" (ADDR_UNREACHABLE));
 
 
  if ((neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_L_ACCESS) && // load bus access error exception
  if ((neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_L_ACCESS) && // load bus access error exception
 
      (neorv32_cpu_csr_read(CSR_MTVAL) == ADDR_UNREACHABLE) &&
 
      (tmp_b == 0xcafe1230) && // make sure dest. reg is not updated
     (NEORV32_BUSKEEPER.CTRL = tmp_a)) { // buskeeper: error flag + timeout error
     (NEORV32_BUSKEEPER.CTRL = tmp_a)) { // buskeeper: error flag + timeout error
    test_ok();
    test_ok();
  }
  }
  else {
  else {
    test_fail();
    test_fail();
Line 669... Line 687...
 
 
  // ----------------------------------------------------------
  // ----------------------------------------------------------
  // Unaligned store address
  // Unaligned store address
  // ----------------------------------------------------------
  // ----------------------------------------------------------
  neorv32_cpu_csr_write(CSR_MCAUSE, 0);
  neorv32_cpu_csr_write(CSR_MCAUSE, 0);
  PRINT_STANDARD("[%i] S_ALIGN (store addr alignment) EXC: ", cnt_test);
  PRINT_STANDARD("[%i] S_ALIGN (store align) EXC: ", cnt_test);
  cnt_test++;
  cnt_test++;
 
 
 
  // initialize test variable
 
  store_access_addr[0] = 0x11223344;
 
  store_access_addr[1] = 0x55667788;
 
  tmp_a = (uint32_t)(&store_access_addr[0]);
 
  tmp_a += 2; // make word-unaligned
 
 
  // store to unaligned address
  // store to unaligned address
  neorv32_cpu_store_unsigned_word(ADDR_UNALIGNED_2, 0);
  neorv32_cpu_store_unsigned_word(tmp_a, 0);
 
 
  if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_S_MISALIGNED) {
  if ((neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_S_MISALIGNED) &&
 
      (neorv32_cpu_csr_read(CSR_MTVAL) == tmp_a) &&
 
      (store_access_addr[0] == 0x11223344) &&
 
      (store_access_addr[1] == 0x55667788)) { // make sure memory was not altered
    test_ok();
    test_ok();
  }
  }
  else {
  else {
    test_fail();
    test_fail();
  }
  }
Line 687... Line 714...
 
 
  // ----------------------------------------------------------
  // ----------------------------------------------------------
  // Store access fault
  // Store access fault
  // ----------------------------------------------------------
  // ----------------------------------------------------------
  neorv32_cpu_csr_write(CSR_MCAUSE, 0);
  neorv32_cpu_csr_write(CSR_MCAUSE, 0);
  PRINT_STANDARD("[%i] S_ACC (store bus access) EXC: ", cnt_test);
  PRINT_STANDARD("[%i] S_ACC (store access) EXC: ", cnt_test);
  cnt_test++;
  cnt_test++;
 
 
  tmp_a = (1 << BUSKEEPER_ERR_FLAG) | (0 << BUSKEEPER_ERR_TYPE);
  tmp_a = (1 << BUSKEEPER_ERR_FLAG) | (0 << BUSKEEPER_ERR_TYPE);
 
 
  // store to unreachable aligned address
  // store to unreachable aligned address
  neorv32_cpu_store_unsigned_word(ADDR_READONLY, 0);
  neorv32_cpu_store_unsigned_word(ADDR_READONLY, 0);
 
 
  if ((neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_S_ACCESS) && // store bus access error exception
  if ((neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_S_ACCESS) && // store bus access error exception
 
      (neorv32_cpu_csr_read(CSR_MTVAL) == ADDR_READONLY) &&
      (NEORV32_BUSKEEPER.CTRL == tmp_a)) { // buskeeper: error flag + device error
      (NEORV32_BUSKEEPER.CTRL == tmp_a)) { // buskeeper: error flag + device error
    test_ok();
    test_ok();
  }
  }
  else {
  else {
    test_fail();
    test_fail();
Line 708... Line 736...
 
 
  // ----------------------------------------------------------
  // ----------------------------------------------------------
  // Environment call from M-mode
  // Environment call from M-mode
  // ----------------------------------------------------------
  // ----------------------------------------------------------
  neorv32_cpu_csr_write(CSR_MCAUSE, 0);
  neorv32_cpu_csr_write(CSR_MCAUSE, 0);
  PRINT_STANDARD("[%i] ENVCALL (ecall instr.) from M-mode EXC: ", cnt_test);
  PRINT_STANDARD("[%i] ENVCALL 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) {
    test_ok();
    test_ok();
  }
  }
  else {
  else {
Line 725... Line 753...
 
 
  // ----------------------------------------------------------
  // ----------------------------------------------------------
  // Environment call from U-mode
  // Environment call from U-mode
  // ----------------------------------------------------------
  // ----------------------------------------------------------
  neorv32_cpu_csr_write(CSR_MCAUSE, 0);
  neorv32_cpu_csr_write(CSR_MCAUSE, 0);
  PRINT_STANDARD("[%i] ENVCALL (ecall instr.) from U-mode EXC: ", cnt_test);
  PRINT_STANDARD("[%i] ENVCALL U-mode EXC: ", cnt_test);
 
 
  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();
  goto_user_mode();
  {
  {
    asm volatile("ECALL");
    asm volatile("ecall");
  }
  }
 
 
  if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_UENV_CALL) {
  if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_UENV_CALL) {
    test_ok();
    test_ok();
  }
  }
Line 1406... Line 1434...
//PRINT_STANDARD("[%i] FIRQ13..15: ", cnt_test);
//PRINT_STANDARD("[%i] FIRQ13..15: ", cnt_test);
//PRINT_STANDARD("skipped (n.a.)\n");
//PRINT_STANDARD("skipped (n.a.)\n");
 
 
 
 
  // ----------------------------------------------------------
  // ----------------------------------------------------------
  // Test WFI ("sleep") instructions, wakeup via MTIME
  // Test WFI ("sleep") instruction (executed in user mode), wakeup via MTIME
  // ----------------------------------------------------------
  // ----------------------------------------------------------
  neorv32_cpu_csr_write(CSR_MCAUSE, 0);
  neorv32_cpu_csr_write(CSR_MCAUSE, 0);
  PRINT_STANDARD("[%i] WFI (sleep instruction, wake-up via MTIME): ", cnt_test);
  PRINT_STANDARD("[%i] WFI (sleep instruction, wake-up via MTIME): ", cnt_test);
 
 
  cnt_test++;
  cnt_test++;
Line 1419... Line 1447...
  neorv32_mtime_set_timecmp(neorv32_mtime_get_time() + 500);
  neorv32_mtime_set_timecmp(neorv32_mtime_get_time() + 500);
 
 
  // enable mtime interrupt
  // enable mtime interrupt
  neorv32_cpu_irq_enable(CSR_MIE_MTIE);
  neorv32_cpu_irq_enable(CSR_MIE_MTIE);
 
 
  // put CPU into sleep mode
  // clear mstatus.TW to allow execution of WFI also in user-mode
 
  neorv32_cpu_csr_write(CSR_MSTATUS, neorv32_cpu_csr_read(CSR_MSTATUS) & ~(1<<CSR_MSTATUS_TW));
 
 
 
  // put CPU into sleep mode (from user mode)
 
  goto_user_mode();
 
  {
  asm volatile ("wfi");
  asm volatile ("wfi");
 
  }
 
 
  // no more mtime interrupts
  // no more mtime interrupts
  neorv32_cpu_irq_disable(CSR_MIE_MTIE);
  neorv32_cpu_irq_disable(CSR_MIE_MTIE);
  neorv32_mtime_set_timecmp(-1);
  neorv32_mtime_set_timecmp(-1);
 
 
Line 1443... Line 1477...
  PRINT_STANDARD("[%i] Invalid CSR access (mstatus) from user mode: ", cnt_test);
  PRINT_STANDARD("[%i] Invalid CSR access (mstatus) from user mode: ", cnt_test);
 
 
  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();
  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);
  }
  }
 
 
Line 1486... Line 1520...
 
 
 
 
  // ----------------------------------------------------------
  // ----------------------------------------------------------
  // Test physical memory protection
  // Test physical memory protection
  // ----------------------------------------------------------
  // ----------------------------------------------------------
  PRINT_STANDARD("[%i] PMP - Physical memory protection: ", cnt_test);
  PRINT_STANDARD("[%i] PMP:\n", cnt_test);
 
 
  // check if PMP is implemented
  // check if PMP is implemented (two regions are required for these tests)
  if (neorv32_cpu_pmp_get_num_regions() != 0)  {
  if (neorv32_cpu_pmp_get_num_regions() > 1)  {
 
 
    // 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 minimal region size (granularity)
    tmp_a = (uint32_t)(&pmp_access_addr); // base address of protected region
    tmp_b = neorv32_cpu_pmp_get_granularity();
    tmp_b = PMP_TOR << PMPCFG_A_LSB; // enable region, but absolutely no access rights
 
 
    tmp_a = NEORV32_SYSINFO.DSPACE_BASE; // base address of protected region
 
    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, PMPCFG_MODE_NAPOT << PMPCFG_A_LSB); // NAPOT, NO read/write/execute permissions
    int pmp_res = 0;
 
    PRINT_STANDARD("Setup region 0 OFF [ -, -, -] @ 0x%x\n", tmp_a);
    if ((pmp_return == 0) && (neorv32_cpu_csr_read(CSR_MCAUSE) == 0)) {
    pmp_res += neorv32_cpu_pmp_configure_region(0, tmp_a, 0);
 
    PRINT_STANDARD("Setup region 1 TOR [!X,!W,!R] @ 0x%x ", tmp_a+4);
 
    pmp_res += neorv32_cpu_pmp_configure_region(1, tmp_a+4, tmp_b);
 
    if ((pmp_res == 0) && (neorv32_cpu_csr_read(CSR_MCAUSE) == 0)) {
      test_ok();
      test_ok();
    }
    }
    else {
    else {
      if (neorv32_cpu_csr_read(CSR_PMPCFG0) & 0x80) {
 
      PRINT_CRITICAL("%c[1m<Entry LOCKED!> %c[0m\n", 27, 27);
 
      }
 
      test_fail();
      test_fail();
    }
    }
 
 
 
 
    // ------ EXECUTE: should fail ------
    // ------ EXECUTE: should fail ------
    PRINT_STANDARD("[%i] PMP: U-mode 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();
    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) == TRAP_CODE_I_ACCESS) {
      // switch back to machine mode (if not already)
      asm volatile ("ecall"); // switch back to machine mode (if not already)
      asm volatile ("ecall");
      test_ok();
 
 
      test_fail();
 
    }
    }
    else {
    else {
      // switch back to machine mode (if not already)
      asm volatile ("ecall"); // switch back to machine mode (if not already)
      asm volatile ("ecall");
      test_fail();
 
 
      test_ok();
 
    }
    }
 
 
 
 
    // ------ LOAD: should fail ------
    // ------ LOAD: should fail ------
    PRINT_STANDARD("[%i] PMP: U-mode 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();
    goto_user_mode();
    tmp_b = 0;
 
    {
    {
      tmp_b = neorv32_cpu_load_unsigned_word(tmp_a); // load access -> should fail
      asm volatile ("li %[da], 0xcafe0000 \n" // initialize destination register with known value
    }
                    "lw %[da], 0(%[ad])     " // must not update destination register to to exception
 
                    : [da] "=r" (tmp_b) : [ad] "r" (tmp_a));
    if (tmp_b != 0) {
 
      PRINT_CRITICAL("%c[1m<SECURITY FAILURE> %c[0m\n", 27, 27);
 
    }
    }
 
 
    if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_L_ACCESS) {
    if ((neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_L_ACCESS) &&
 
        (tmp_b == 0xcafe0000)) { // destination register not altered
      // switch back to machine mode (if not already)
      // switch back to machine mode (if not already)
      asm volatile ("ecall");
      asm volatile ("ecall");
 
 
      test_ok();
      test_ok();
    }
    }
Line 1577... Line 1602...
    PRINT_STANDARD("[%i] PMP: U-mode 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();
    goto_user_mode();
    {
    {
      neorv32_cpu_store_unsigned_word(tmp_a, 0); // 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) {
Line 1772... Line 1797...
 
 
  return (int)cnt_fail; // return error counter for after-main handler
  return (int)cnt_fail; // return error counter for after-main handler
}
}
 
 
 
 
 
 
 
/**********************************************************************//**
 
 * Switch from privilege mode MACHINE to privilege mode USER.
 
 *
 
 * @warning This function requires the U extension to be implemented.
 
 **************************************************************************/
 
void __attribute__((naked)) goto_user_mode(void) {
 
 
 
  // make sure to use NO registers in here! -> naked
 
 
 
  asm volatile ("csrw mepc, ra           \n" // move return address to mepc so we can return using "mret". also, we can now use ra as temp register
 
                "li ra, %[input_imm]     \n" // bit mask to clear the two MPP bits
 
                "csrrc zero, mstatus, ra \n" // clear MPP bits -> MPP=u-mode
 
                "mret                    \n" // return and switch to user mode
 
                :  : [input_imm] "i" ((1<<CSR_MSTATUS_MPP_H) | (1<<CSR_MSTATUS_MPP_L)));
 
}
 
 
 
 
/**********************************************************************//**
/**********************************************************************//**
 * Simulation-based function to trigger CPU interrupts (MSI, MEI, FIRQ4..7).
 * Simulation-based function to trigger CPU interrupts (MSI, MEI).
 *
 *
 * @param[in] sel IRQ select mask (bit positions according to #NEORV32_CSR_MIE_enum).
 * @param[in] sel IRQ select mask (bit positions according to #NEORV32_CSR_MIE_enum).
 **************************************************************************/
 **************************************************************************/
void sim_irq_trigger(uint32_t sel) {
void sim_irq_trigger(uint32_t sel) {
 
 
Line 1791... Line 1834...
 * Trap handler for ALL exceptions/interrupts.
 * Trap handler for ALL exceptions/interrupts.
 **************************************************************************/
 **************************************************************************/
void global_trap_handler(void) {
void global_trap_handler(void) {
 
 
  // clear all pending FIRQs
  // clear all pending FIRQs
  neorv32_cpu_csr_write(CSR_MIP, -1);
  neorv32_cpu_csr_write(CSR_MIP, 0);
 
 
  // hack: always come back in MACHINE MODE
  // hack: always come back in MACHINE MODE
  register uint32_t mask = (1<<CSR_MSTATUS_MPP_H) | (1<<CSR_MSTATUS_MPP_L);
  register uint32_t mask = (1<<CSR_MSTATUS_MPP_H) | (1<<CSR_MSTATUS_MPP_L);
  asm volatile ("csrrs zero, mstatus, %[input_j]" :  : [input_j] "r" (mask));
  asm volatile ("csrrs zero, mstatus, %[input_j]" :  : [input_j] "r" (mask));
}
}
Line 1842... Line 1885...
/**********************************************************************//**
/**********************************************************************//**
 * "after-main" handler that is executed after the application's
 * "after-main" handler that is executed after the application's
 * main function returns (called by crt0.S start-up code): Output minimal
 * main function returns (called by crt0.S start-up code): Output minimal
 * test report to physical UART
 * test report to physical UART
 **************************************************************************/
 **************************************************************************/
int __neorv32_crt0_after_main(int32_t return_code) {
void __neorv32_crt0_after_main(int32_t return_code) {
 
 
  // make sure sim mode is disabled and UARTs are actually enabled
  // make sure sim mode is disabled and UARTs are actually enabled
  NEORV32_UART0.CTRL |=  (1 << UART_CTRL_EN);
  NEORV32_UART0.CTRL |=  (1 << UART_CTRL_EN);
  NEORV32_UART0.CTRL &= ~(1 << UART_CTRL_SIM_MODE);
  NEORV32_UART0.CTRL &= ~(1 << UART_CTRL_SIM_MODE);
  NEORV32_UART1.CTRL = NEORV32_UART0.CTRL;
  NEORV32_UART1.CTRL = NEORV32_UART0.CTRL;
 
 
  // minimal result report
  // minimal result report
  PRINT_CRITICAL("%u/%u\n", (uint32_t)return_code, (uint32_t)cnt_test);
  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.