URL
https://opencores.org/ocsvn/neorv32/neorv32/trunk
Subversion Repositories neorv32
Compare Revisions
- This comparison shows the changes necessary to convert path
/neorv32/trunk/sw/example
- from Rev 72 to Rev 73
- ↔ Reverse comparison
Rev 72 → Rev 73
/bitmanip_test/main.c
603,11 → 603,9
* "after-main" handler that is executed after the application's |
* main function returns (called by crt0.S start-up code) |
**************************************************************************/ |
int __neorv32_crt0_after_main(int32_t return_code) { |
void __neorv32_crt0_after_main(int32_t return_code) { |
|
if (return_code) { |
neorv32_uart0_printf("\n<RTE> main function returned with exit code (%i) </RTE>\n", return_code); |
} |
|
return 0; |
} |
/coremark/core_portme.c
81,8 → 81,8
void |
start_time(void) |
{ |
GETMYTIME(&start_time_val); |
neorv32_cpu_csr_write(CSR_MCOUNTINHIBIT, 0); // start all counters |
GETMYTIME(&start_time_val); |
} |
/* Function : stop_time |
This function will be called right after ending the timed portion of the |
103,8 → 103,8
|
Actual value returned may be cpu cycles, milliseconds or any other |
value, as long as it can be converted to seconds by <time_in_secs>. This |
methodology is taken to accomodate any hardware or simulated platform. The |
sample implementation returns millisecs by default, and the resolution is |
methodology is taken to accommodate any hardware or simulated platform. The |
sample implementation returns milliseconds by default, and the resolution is |
controlled by <TIMER_RES_DIVIDER> |
*/ |
CORE_TICKS |
233,24 → 233,24
|
neorv32_uart0_printf("\nNEORV32: All reported numbers only show the integer part.\n\n"); |
|
neorv32_uart0_printf("NEORV32: HPM results\n"); |
neorv32_uart0_printf("NEORV32: HPM results (low words only)\n"); |
if (num_hpm_cnts_global == 0) {neorv32_uart0_printf("no HPMs available\n"); } |
if (num_hpm_cnts_global > 0) {neorv32_uart0_printf("# Retired compr. instructions: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER3)); } |
if (num_hpm_cnts_global > 1) {neorv32_uart0_printf("# I-fetch wait cycles: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER4)); } |
if (num_hpm_cnts_global > 2) {neorv32_uart0_printf("# I-issue wait cycles: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER5)); } |
if (num_hpm_cnts_global > 3) {neorv32_uart0_printf("# Multi-cycle ALU wait cycles: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER6)); } |
if (num_hpm_cnts_global > 4) {neorv32_uart0_printf("# Load operations: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER7)); } |
if (num_hpm_cnts_global > 5) {neorv32_uart0_printf("# Store operations: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER8)); } |
if (num_hpm_cnts_global > 6) {neorv32_uart0_printf("# Load/store wait cycles: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER9)); } |
if (num_hpm_cnts_global > 7) {neorv32_uart0_printf("# Unconditional jumps: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER10)); } |
if (num_hpm_cnts_global > 8) {neorv32_uart0_printf("# Conditional branches (all): %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER11)); } |
if (num_hpm_cnts_global > 9) {neorv32_uart0_printf("# Conditional branches (taken): %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER12)); } |
if (num_hpm_cnts_global > 10) {neorv32_uart0_printf("# Entered traps: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER13)); } |
if (num_hpm_cnts_global > 11) {neorv32_uart0_printf("# Illegal operations: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER14)); } |
if (num_hpm_cnts_global > 0) {neorv32_uart0_printf(" > Retired compr. instructions: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER3)); } |
if (num_hpm_cnts_global > 1) {neorv32_uart0_printf(" > Instr.-fetch wait cycles: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER4)); } |
if (num_hpm_cnts_global > 2) {neorv32_uart0_printf(" > Instr.-issue wait cycles: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER5)); } |
if (num_hpm_cnts_global > 3) {neorv32_uart0_printf(" > Multi-cycle ALU wait cycles: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER6)); } |
if (num_hpm_cnts_global > 4) {neorv32_uart0_printf(" > Load operations: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER7)); } |
if (num_hpm_cnts_global > 5) {neorv32_uart0_printf(" > Store operations: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER8)); } |
if (num_hpm_cnts_global > 6) {neorv32_uart0_printf(" > Load/store wait cycles: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER9)); } |
if (num_hpm_cnts_global > 7) {neorv32_uart0_printf(" > Unconditional jumps: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER10)); } |
if (num_hpm_cnts_global > 8) {neorv32_uart0_printf(" > Conditional branches (all): %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER11)); } |
if (num_hpm_cnts_global > 9) {neorv32_uart0_printf(" > Conditional branches (taken): %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER12)); } |
if (num_hpm_cnts_global > 10) {neorv32_uart0_printf(" > Entered traps: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER13)); } |
if (num_hpm_cnts_global > 11) {neorv32_uart0_printf(" > Illegal operations: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER14)); } |
neorv32_uart0_printf("\n"); |
|
neorv32_uart0_printf("NEORV32: Executed instructions 0x%x_%x\n", (uint32_t)exe_instructions.uint32[1], (uint32_t)exe_instructions.uint32[0]); |
neorv32_uart0_printf("NEORV32: CoreMark core clock cycles 0x%x_%x\n", (uint32_t)exe_time.uint32[1], (uint32_t)exe_time.uint32[0]); |
neorv32_uart0_printf("NEORV32: Executed instructions 0x%x%x\n", (uint32_t)exe_instructions.uint32[1], (uint32_t)exe_instructions.uint32[0]); |
neorv32_uart0_printf("NEORV32: CoreMark core clock cycles 0x%x%x\n", (uint32_t)exe_time.uint32[1], (uint32_t)exe_time.uint32[0]); |
|
uint64_t average_cpi_int = exe_time.uint64 / exe_instructions.uint64; |
neorv32_uart0_printf("NEORV32: Average CPI (integer part only): %u cycles/instruction\n", (uint32_t)average_cpi_int); |
/demo_gptmr/main.c
113,7 → 113,7
**************************************************************************/ |
void gptmr_firq_handler(void) { |
|
neorv32_cpu_csr_write(CSR_MIP, 1<<GPTMR_FIRQ_PENDING); // clear/ack pending FIRQ |
neorv32_cpu_csr_write(CSR_MIP, ~(1<<GPTMR_FIRQ_PENDING)); // clear/ack pending FIRQ |
|
neorv32_uart0_putc('.'); // send tick symbol via UART0 |
neorv32_gpio_pin_toggle(0); // toggle output port bit 0 |
/demo_pmp/main.c
0,0 → 1,177
// ################################################################################################# |
// # << NEORV32 - Physical Memory Protection Example Program >> # |
// # ********************************************************************************************* # |
// # BSD 3-Clause License # |
// # # |
// # Copyright (c) 2022, Stephan Nolting. All rights reserved. # |
// # # |
// # Redistribution and use in source and binary forms, with or without modification, are # |
// # permitted provided that the following conditions are met: # |
// # # |
// # 1. Redistributions of source code must retain the above copyright notice, this list of # |
// # conditions and the following disclaimer. # |
// # # |
// # 2. Redistributions in binary form must reproduce the above copyright notice, this list of # |
// # conditions and the following disclaimer in the documentation and/or other materials # |
// # provided with the distribution. # |
// # # |
// # 3. Neither the name of the copyright holder nor the names of its contributors may be used to # |
// # endorse or promote products derived from this software without specific prior written # |
// # permission. # |
// # # |
// # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS # |
// # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # |
// # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # |
// # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # |
// # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE # |
// # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED # |
// # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # |
// # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # |
// # OF THE POSSIBILITY OF SUCH DAMAGE. # |
// # ********************************************************************************************* # |
// # The NEORV32 Processor - https://github.com/stnolting/neorv32 (c) Stephan Nolting # |
// ################################################################################################# |
|
|
/**********************************************************************//** |
* @file demo_pmp/main.c |
* @author Stephan Nolting |
* @brief Physical memory protection (PMP) example program. |
**************************************************************************/ |
#include <neorv32.h> |
|
|
/**********************************************************************//** |
* @name User configuration |
**************************************************************************/ |
/**@{*/ |
/** UART BAUD rate */ |
#define BAUD_RATE 19200 |
/**@}*/ |
|
|
/**********************************************************************//** |
* Example variable that will be protected by the PMP |
**************************************************************************/ |
uint32_t protected_var[4] = { |
0x11223344, |
0x55667788, |
0x00CAFE00, |
0xDEADC0DE |
}; |
|
|
/**********************************************************************//** |
* Main function |
* |
* @note This program requires the CPU PMP extension (with at least 2 regions) and UART0. |
* |
* @return 0 if execution was successful |
**************************************************************************/ |
int main() { |
|
// initialize NEORV32 run-time environment |
neorv32_rte_setup(); |
|
// setup UART0 at default baud rate, no parity bits, no HW flow control |
neorv32_uart0_setup(BAUD_RATE, PARITY_NONE, FLOW_CONTROL_NONE); |
|
// check if UART0 is implemented |
if (neorv32_uart0_available() == 0) { |
return 1; // UART0 not available, exit |
} |
|
// check if PMP is implemented at all |
if ((neorv32_cpu_csr_read(CSR_MXISA) & (1 << CSR_MXISA_PMP)) == 0) { |
neorv32_uart0_printf("ERROR! PMP CPU extension not implemented!\n"); |
return 1; |
} |
|
|
// intro |
neorv32_uart0_printf("\n<<< NEORV32 Physical Memory Protection (PMP) Example Program >>>\n\n"); |
|
neorv32_uart0_printf("NOTE: This program requires at least 2 PMP regions (PMP_NUM_REGIONS >= 2)\n" |
" and a minimal granularity of 4 bytes (PMP_MIN_GRANULARITY = 4).\n\n"); |
|
neorv32_uart0_printf("NOTE: A 4-word array 'protected_var[4]' is created, which will be probed from\n" |
" **machine-mode**. It provides the following access rights:\n" |
" - NO_EXECUTE\n" |
" - NO_WRITE\n" |
" - READ\n" |
" - LOCKED - also enforce access rights for machine-mode software\n\n"); |
|
|
// show PMP configuration |
neorv32_uart0_printf("PMP hardware configuration:\n"); |
neorv32_uart0_printf("> Number of regions: %u\n", neorv32_cpu_pmp_get_num_regions()); |
neorv32_uart0_printf("> Min. granularity: %u bytes (minimal region size)\n\n", neorv32_cpu_pmp_get_granularity()); |
|
|
// The "protected_var" variable will be protected: No execute and no write access, just allow read access |
|
// create protected region |
int pmp_status; |
uint8_t permissions; |
neorv32_uart0_printf("Creating protected regions (any access within [REGION_BEGIN <= address < REGION_END] will match the PMP rules)...\n"); |
|
// any access in "region_begin <= address < region_end" will match the PMP rule |
uint32_t region_begin = (uint32_t)(&protected_var[0]); |
uint32_t region_end = (uint32_t)(&protected_var[4]) + 4; |
neorv32_uart0_printf("REGION_BEGIN = 0x%x\n", region_begin); |
neorv32_uart0_printf("REGION_END = 0x%x\n", region_end); |
|
// base (region begin) |
permissions = PMP_OFF << PMPCFG_A_LSB; // mode = OFF |
neorv32_uart0_printf("> Region begin (PMP entry 0): Base = 0x%x, Mode = OFF (base of region) ", region_begin); |
pmp_status = neorv32_cpu_pmp_configure_region(0, region_begin, permissions); |
if (pmp_status) { |
neorv32_uart0_printf("[FAILED]\n"); |
} |
else { |
neorv32_uart0_printf("[ok]\n"); |
} |
|
// bound (region end) |
permissions = (PMP_TOR << PMPCFG_A_LSB) | // enable entry as TOR = top of region |
(0 << PMPCFG_X) | // no "execute" permission |
(0 << PMPCFG_W) | // no "write" permission |
(1 << PMPCFG_R) | // set "read" permission |
(1 << PMPCFG_L); // locked: also enforce PMP rule for machine-mode software |
neorv32_uart0_printf("> Region end (PMP entry 1): Base = 0x%x, Mode = TOR (top of region) ", region_end); |
pmp_status = neorv32_cpu_pmp_configure_region(1, region_end, permissions); |
if (pmp_status) { |
neorv32_uart0_printf("[FAILED]\n"); |
} |
else { |
neorv32_uart0_printf("[ok]\n"); |
} |
|
// test access |
neorv32_uart0_printf("\nTesting access to 'protected_var' - invalid accesses will raise an exception, which will be\n" |
"captured by the NEORV32 runtime environment's dummy/debug handlers ('<RTE> ... </RTE>').\n\n"); |
|
neorv32_uart0_printf("Reading protected_var[0] = 0x%x\n", protected_var[0]); |
neorv32_uart0_printf("Reading protected_var[1] = 0x%x\n", protected_var[1]); |
neorv32_uart0_printf("Reading protected_var[2] = 0x%x\n", protected_var[2]); |
neorv32_uart0_printf("Reading protected_var[3] = 0x%x\n\n", protected_var[3]); |
|
neorv32_uart0_printf("Trying to write protected_var[0]... "); |
protected_var[0] = 0; // should fail! |
neorv32_uart0_printf("Trying to write protected_var[1]... "); |
protected_var[1] = 0; // should fail! |
neorv32_uart0_printf("Trying to write protected_var[2]... "); |
protected_var[2] = 0; // should fail! |
neorv32_uart0_printf("Trying to write protected_var[3]... "); |
protected_var[3] = 0; // should fail! |
|
neorv32_uart0_printf("\nReading again protected_var[0] = 0x%x\n", protected_var[0]); |
neorv32_uart0_printf("Reading again protected_var[1] = 0x%x\n", protected_var[1]); |
neorv32_uart0_printf("Reading again protected_var[2] = 0x%x\n", protected_var[2]); |
neorv32_uart0_printf("Reading again protected_var[3] = 0x%x\n\n", protected_var[3]); |
|
|
neorv32_uart0_printf("\nPMP demo program completed.\n"); |
|
return 0; |
} |
/demo_pmp/makefile
0,0 → 1,40
################################################################################################# |
# << NEORV32 - Application Makefile >> # |
# ********************************************************************************************* # |
# Make sure to add the RISC-V GCC compiler's bin folder to your PATH environment variable. # |
# ********************************************************************************************* # |
# BSD 3-Clause License # |
# # |
# Copyright (c) 2021, Stephan Nolting. All rights reserved. # |
# # |
# Redistribution and use in source and binary forms, with or without modification, are # |
# permitted provided that the following conditions are met: # |
# # |
# 1. Redistributions of source code must retain the above copyright notice, this list of # |
# conditions and the following disclaimer. # |
# # |
# 2. Redistributions in binary form must reproduce the above copyright notice, this list of # |
# conditions and the following disclaimer in the documentation and/or other materials # |
# provided with the distribution. # |
# # |
# 3. Neither the name of the copyright holder nor the names of its contributors may be used to # |
# endorse or promote products derived from this software without specific prior written # |
# permission. # |
# # |
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS # |
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # |
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # |
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # |
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE # |
# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED # |
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # |
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # |
# OF THE POSSIBILITY OF SUCH DAMAGE. # |
# ********************************************************************************************* # |
# The NEORV32 Processor - https://github.com/stnolting/neorv32 (c) Stephan Nolting # |
################################################################################################# |
|
# Modify this variable to fit your NEORV32 setup (neorv32 home folder) |
NEORV32_HOME ?= ../../.. |
|
include $(NEORV32_HOME)/sw/common/common.mk |
/demo_slink/main.c
3,7 → 3,7
// # ********************************************************************************************* # |
// # BSD 3-Clause License # |
// # # |
// # Copyright (c) 2021, Stephan Nolting. All rights reserved. # |
// # Copyright (c) 2022, Stephan Nolting. All rights reserved. # |
// # # |
// # Redistribution and use in source and binary forms, with or without modification, are # |
// # permitted provided that the following conditions are met: # |
475,7 → 475,7
**************************************************************************/ |
void slink_rx_firq_handler(void) { |
|
neorv32_cpu_csr_write(CSR_MIP, 1 << SLINK_RX_FIRQ_PENDING); // ACK interrupt |
neorv32_cpu_csr_write(CSR_MIP, ~(1 << SLINK_RX_FIRQ_PENDING)); // ACK interrupt |
neorv32_uart0_printf("\n<SLINK_RX_IRQ>\n"); |
} |
|
485,7 → 485,7
**************************************************************************/ |
void slink_tx_firq_handler(void) { |
|
neorv32_cpu_csr_write(CSR_MIP, 1 << SLINK_TX_FIRQ_PENDING); // ACK interrupt |
neorv32_cpu_csr_write(CSR_MIP, ~(1 << SLINK_TX_FIRQ_PENDING)); // ACK interrupt |
neorv32_uart0_printf("\n<SLINK_TX_IRQ>\n"); |
} |
|
/newlib_demo/main.c
55,7 → 55,7
/**********************************************************************//** |
* Main function: Check some of newlib's core functions. |
* |
* @note This program requires UART. |
* @note This program requires UART0. |
* |
* @return 0 if execution was successful |
**************************************************************************/ |
87,7 → 87,12
|
neorv32_uart0_printf("newlib version %i.%i\n\n", (int32_t)__NEWLIB__, (int32_t)__NEWLIB_MINOR__); |
|
neorv32_uart0_printf("<rand> test... "); |
srand(neorv32_cpu_csr_read(CSR_CYCLE)); // set random seed |
neorv32_uart0_printf("%i, %i, %i, %i ", rand() % 100, rand() % 100, rand() % 100, rand() % 100); |
neorv32_uart0_printf("ok\n"); |
|
|
char *char_buffer; // pointer for dynamic memory allocation |
|
neorv32_uart0_printf("<malloc> test... "); |
131,9 → 136,7
* "after-main" handler that is executed after the application's |
* main function returns (called by crt0.S start-up code) |
**************************************************************************/ |
int __neorv32_crt0_after_main(int32_t return_code) { |
void __neorv32_crt0_after_main(int32_t return_code) { |
|
neorv32_uart0_printf("\n<RTE> main function returned with exit code %i. </RTE>\n", return_code); |
|
return 0; |
neorv32_uart0_printf("\n<RTE> main function returned with exit code %i </RTE>\n", return_code); |
} |
/processor_check/main.c
82,6 → 82,7
|
|
// Prototypes |
void __attribute__((naked)) goto_user_mode(void); |
void sim_irq_trigger(uint32_t sel); |
void global_trap_handler(void); |
void xirq_trap_handler0(void); |
101,10 → 102,16
/// XIRQ trap handler acknowledge |
uint32_t xirq_trap_handler_ack = 0; |
|
/// Variable to test store accesses |
volatile uint32_t store_access_addr[2]; |
|
/// 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. |
* |
162,7 → 169,7
} |
|
|
// reset performance counter |
// reset (performance) counters |
// 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_MINSTRETH, 0); -> done in crt0.S |
177,13 → 184,13
|
// fancy intro |
// ----------------------------------------------- |
// logo |
// show ASCII logo |
neorv32_rte_print_logo(); |
|
// show project credits |
neorv32_rte_print_credits(); |
|
// show full HW config report |
// show full hardware configuration report |
neorv32_rte_print_hw_config(); |
|
|
223,6 → 230,13
|
|
// ---------------------------------------------------------- |
// 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 |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
362,23 → 376,20
tmp_a &= ~(1<<CSR_MCOUNTEREN_CY); // clear access right |
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) |
neorv32_cpu_goto_user_mode(); |
goto_user_mode(); |
{ |
// access to cycle CSR is no longer allowed |
asm volatile (" mv %[result], zero \n" // initialize with zero |
" rdcycle %[result] " // read CSR_CYCLE, is not allowed and should not alter [result] |
asm volatile (" li %[result], 0xcc11aa22 \n" // initialize |
" rdcycleh %[result] " // read CSR_CYCLE, is not allowed and should not alter [result] |
: [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 |
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(); |
} |
else { |
400,7 → 411,7
cnt_test++; |
|
// 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"); |
} |
417,7 → 428,7
// External memory interface test |
// ---------------------------------------------------------- |
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)) { |
cnt_test++; |
456,7 → 467,7
// Illegal CSR access (CSR not implemented) |
// ---------------------------------------------------------- |
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++; |
|
474,7 → 485,7
// Write-access to read-only CSR |
// ---------------------------------------------------------- |
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++; |
|
512,7 → 523,7
// Unaligned instruction address |
// ---------------------------------------------------------- |
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 |
if ((neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_C)) == 0) { |
614,7 → 625,7
// Breakpoint instruction |
// ---------------------------------------------------------- |
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++; |
|
asm volatile("EBREAK"); |
631,14 → 642,17
// Unaligned load address |
// ---------------------------------------------------------- |
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++; |
|
// 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) && |
(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(); |
} |
else { |
650,16 → 664,20
// Load access fault |
// ---------------------------------------------------------- |
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++; |
|
tmp_a = (1 << BUSKEEPER_ERR_FLAG) | (1 << BUSKEEPER_ERR_TYPE); |
|
// 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 |
(NEORV32_BUSKEEPER.CTRL = tmp_a)) { // buskeeper: error flag + timeout error |
(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 |
test_ok(); |
} |
else { |
671,13 → 689,22
// Unaligned store address |
// ---------------------------------------------------------- |
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++; |
|
// 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 |
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(); |
} |
else { |
689,7 → 716,7
// Store access fault |
// ---------------------------------------------------------- |
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++; |
|
tmp_a = (1 << BUSKEEPER_ERR_FLAG) | (0 << BUSKEEPER_ERR_TYPE); |
698,6 → 725,7
neorv32_cpu_store_unsigned_word(ADDR_READONLY, 0); |
|
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 |
test_ok(); |
} |
710,10 → 738,10
// Environment call from M-mode |
// ---------------------------------------------------------- |
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++; |
|
asm volatile("ECALL"); |
asm volatile("ecall"); |
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_MENV_CALL) { |
test_ok(); |
727,14 → 755,14
// Environment call from U-mode |
// ---------------------------------------------------------- |
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++; |
|
// 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) { |
1408,7 → 1436,7
|
|
// ---------------------------------------------------------- |
// 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); |
PRINT_STANDARD("[%i] WFI (sleep instruction, wake-up via MTIME): ", cnt_test); |
1421,9 → 1449,15
// enable mtime interrupt |
neorv32_cpu_irq_enable(CSR_MIE_MTIE); |
|
// put CPU into sleep mode |
asm volatile ("wfi"); |
// 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"); |
} |
|
// no more mtime interrupts |
neorv32_cpu_irq_disable(CSR_MIE_MTIE); |
neorv32_mtime_set_timecmp(-1); |
1445,7 → 1479,7
cnt_test++; |
|
// 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 |
tmp_a = neorv32_cpu_csr_read(CSR_MISA); |
1488,10 → 1522,10
// ---------------------------------------------------------- |
// 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 |
if (neorv32_cpu_pmp_get_num_regions() != 0) { |
// check if PMP is implemented (two regions are required for these tests) |
if (neorv32_cpu_pmp_get_num_regions() > 1) { |
|
// Create PMP protected region |
// --------------------------------------------- |
1498,22 → 1532,19
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
cnt_test++; |
|
// find out minimal region size (granularity) |
tmp_b = neorv32_cpu_pmp_get_granularity(); |
tmp_a = (uint32_t)(&pmp_access_addr); // base address of protected region |
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 |
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 |
|
if ((pmp_return == 0) && (neorv32_cpu_csr_read(CSR_MCAUSE) == 0)) { |
int pmp_res = 0; |
PRINT_STANDARD("Setup region 0 OFF [ -, -, -] @ 0x%x\n", tmp_a); |
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(); |
} |
else { |
if (neorv32_cpu_csr_read(CSR_PMPCFG0) & 0x80) { |
PRINT_CRITICAL("%c[1m<Entry LOCKED!> %c[0m\n", 27, 27); |
} |
test_fail(); |
} |
|
1524,22 → 1555,18
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
|
// 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 |
} |
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) { |
// switch back to machine mode (if not already) |
asm volatile ("ecall"); |
|
test_fail(); |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_I_ACCESS) { |
asm volatile ("ecall"); // switch back to machine mode (if not already) |
test_ok(); |
} |
else { |
// switch back to machine mode (if not already) |
asm volatile ("ecall"); |
|
test_ok(); |
asm volatile ("ecall"); // switch back to machine mode (if not already) |
test_fail(); |
} |
|
|
1549,17 → 1576,15
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
|
// switch to user mode (hart will be back in MACHINE mode when trap handler returns) |
neorv32_cpu_goto_user_mode(); |
tmp_b = 0; |
goto_user_mode(); |
{ |
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) |
asm volatile ("ecall"); |
|
1579,7 → 1604,7
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
|
// 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 |
} |
1774,9 → 1799,27
} |
|
|
|
/**********************************************************************//** |
* Simulation-based function to trigger CPU interrupts (MSI, MEI, FIRQ4..7). |
* 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). |
* |
* @param[in] sel IRQ select mask (bit positions according to #NEORV32_CSR_MIE_enum). |
**************************************************************************/ |
void sim_irq_trigger(uint32_t sel) { |
1793,7 → 1836,7
void global_trap_handler(void) { |
|
// 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 |
register uint32_t mask = (1<<CSR_MSTATUS_MPP_H) | (1<<CSR_MSTATUS_MPP_L); |
1844,7 → 1887,7
* 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) { |
void __neorv32_crt0_after_main(int32_t return_code) { |
|
// make sure sim mode is disabled and UARTs are actually enabled |
NEORV32_UART0.CTRL |= (1 << UART_CTRL_EN); |
1853,6 → 1896,4
|
// minimal result report |
PRINT_CRITICAL("%u/%u\n", (uint32_t)return_code, (uint32_t)cnt_test); |
|
return 0; |
} |