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
- from Rev 60 to Rev 61
- ↔ Reverse comparison
Rev 60 → Rev 61
/bootloader/bootloader.c
1,22 → 1,6
// ################################################################################################# |
// # << NEORV32 - Bootloader >> # |
// # ********************************************************************************************* # |
// # In order to run the bootloader on *any* CPU configuration, the bootloader should be compiled # |
// # using the base ISA (rv32i/rv32e) only. # |
// # ********************************************************************************************* # |
// # Boot from (internal) instruction memory, UART or SPI Flash. # |
// # Bootloader executables (neorv32_exe.bin) are LITTLE-ENDIAN! # |
// # # |
// # The bootloader uses the primary UART (UART0) for user console interface. # |
// # # |
// # UART configuration: 8 data bits, NO parity bit, 1 stop bit, 19200 baud (19200-8N1) # |
// # Boot Flash: 8-bit SPI, 24-bit addresses (like Micron N25Q032A) @ neorv32.spi_csn_o(0) # |
// # neorv32.gpio_o(0) is used as high-active status LED (can be disabled via #STATUS_LED_EN). # |
// # # |
// # Auto boot sequence (can be disabled via #AUTOBOOT_EN) after timeout (via #AUTOBOOT_TIMEOUT): # |
// # -> Try booting from SPI flash at spi_csn_o(0). # |
// # -> Permanently light up status led and stall CPU if SPI flash booting attempt fails. # |
// # ********************************************************************************************* # |
// # BSD 3-Clause License # |
// # # |
// # Copyright (c) 2021, Stephan Nolting. All rights reserved. # |
45,7 → 29,7
// # 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 # |
// # The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 (c) Stephan Nolting # |
// ################################################################################################# |
|
|
52,7 → 36,7
/**********************************************************************//** |
* @file bootloader.c |
* @author Stephan Nolting |
* @brief Default NEORV32 bootloader. |
* @brief NEORV32 bootloader. |
**************************************************************************/ |
|
// Libraries |
61,31 → 45,73
|
|
/**********************************************************************//** |
* @name User configuration |
* @name Bootloader configuration (override via console to customize) |
* default values are used if not explicitly customized |
**************************************************************************/ |
/**@{*/ |
/** UART BAUD rate */ |
#define BAUD_RATE (19200) |
/** Enable auto-boot sequence if != 0 */ |
#define AUTOBOOT_EN (1) |
/** Time until the auto-boot sequence starts (in seconds) */ |
#define AUTOBOOT_TIMEOUT (8) |
/** Set to 0 to disable bootloader status LED */ |
#define STATUS_LED_EN (1) |
/** Set to 1 to enable SPI direct boot (disables the entire user console!) */ |
#define SPI_DIRECT_BOOT_EN (0) |
/** Bootloader status LED at GPIO output port */ |
#define STATUS_LED (0) |
/** SPI flash boot image base address (warning! address might wrap-around!) */ |
#define SPI_FLASH_BOOT_ADR (0x00800000) |
/** SPI flash chip select line at spi_csn_o */ |
#define SPI_FLASH_CS (0) |
/** Default SPI flash clock prescaler */ |
#define SPI_FLASH_CLK_PRSC (CLK_PRSC_8) |
/** SPI flash sector size in bytes (default = 64kb) */ |
#define SPI_FLASH_SECTOR_SIZE (64*1024) |
/** ASCII char to start fast executable upload process (for use with automatic upload scripts) */ |
#define FAST_UPLOAD_CMD ('#') |
|
/* ---- UART interface configuration ---- */ |
|
/** Set to 0 to disable UART interface */ |
#ifndef UART_EN |
#define UART_EN 1 |
#endif |
|
/** UART BAUD rate for serial interface */ |
#ifndef UART_BAUD |
#define UART_BAUD 19200 |
#endif |
|
/* ---- Status LED ---- */ |
|
/** Set to 0 to disable bootloader status LED (heart beat) at GPIO.gpio_o(STATUS_LED_PIN) */ |
#ifndef STATUS_LED_EN |
#define STATUS_LED_EN 1 |
#endif |
|
/** GPIO output pin for high-active bootloader status LED (heart beat) */ |
#ifndef STATUS_LED_PIN |
#define STATUS_LED_PIN 0 |
#endif |
|
/* ---- Boot configuration ---- */ |
|
/** Set to 1 to enable automatic (after reset) boot from external SPI flash at address SPI_BOOT_BASE_ADDR */ |
#ifndef AUTO_BOOT_SPI_EN |
#define AUTO_BOOT_SPI_EN 0 |
#endif |
|
/** Set to 1 to enable boot via on-chip debugger (keep CPU in halt loop until OCD takes over control) */ |
#ifndef AUTO_BOOT_OCD_EN |
#define AUTO_BOOT_OCD_EN 0 |
#endif |
|
/** Time until the auto-boot sequence starts (in seconds); 0 = disabled */ |
#ifndef AUTO_BOOT_TIMEOUT |
#define AUTO_BOOT_TIMEOUT 8 |
#endif |
|
/* ---- SPI configuration ---- */ |
|
/** SPI flash chip select (low-active) at SPI.spi_csn_o(SPI_FLASH_CS) */ |
#ifndef SPI_FLASH_CS |
#define SPI_FLASH_CS 0 |
#endif |
|
/** SPI flash sector size in bytes */ |
#ifndef SPI_FLASH_SECTOR_SIZE |
#define SPI_FLASH_SECTOR_SIZE 65536 // default = 64kB |
#endif |
|
/** SPI flash clock pre-scaler; see #NEORV32_TWI_CT_enum */ |
#ifndef SPI_FLASH_CLK_PRSC |
#define SPI_FLASH_CLK_PRSC CLK_PRSC_8 |
#endif |
|
/** SPI flash boot base address */ |
#ifndef SPI_BOOT_BASE_ADDR |
#define SPI_BOOT_BASE_ADDR 0x08000000 |
#endif |
/**@}*/ |
|
|
105,9 → 131,7
ERROR_SIGNATURE = 0, /**< 0: Wrong signature in executable */ |
ERROR_SIZE = 1, /**< 1: Insufficient instruction memory capacity */ |
ERROR_CHECKSUM = 2, /**< 2: Checksum error in executable */ |
ERROR_FLASH = 3, /**< 3: SPI flash access error */ |
ERROR_ROM = 4, /**< 4: Instruction memory is marked as read-only */ |
ERROR_SYSTEM = 5 /**< 5: System exception */ |
ERROR_FLASH = 3 /**< 3: SPI flash access error */ |
}; |
|
|
142,13 → 166,25
|
|
/**********************************************************************//** |
* String output helper macros. |
* Helper macros |
**************************************************************************/ |
/**@{*/ |
/* Actual define-to-string helper */ |
/** Actual define-to-string helper */ |
#define xstr(a) str(a) |
/* Internal helper macro */ |
/** Internal helper macro */ |
#define str(a) #a |
/** Print to UART 0 */ |
#if (UART_EN != 0) |
#define PRINT_TEXT(...) neorv32_uart0_print(__VA_ARGS__) |
#define PRINT_XNUM(a) print_hex_word(a) |
#define PRINT_GETC(a) neorv32_uart0_getc() |
#define PRINT_PUTC(a) neorv32_uart0_putc(a) |
#else |
#define PRINT_TEXT(...) |
#define PRINT_XNUM(a) |
#define PRINT_GETC(a) 0 |
#define PRINT_PUTC(a) |
#endif |
/**@}*/ |
|
|
160,7 → 196,7
|
|
/**********************************************************************//** |
* Only set during executable fetch (required for cpaturing STORE-BUS-TIMOUT exception). |
* Only set during executable fetch (required for capturing STORE BUS-TIMOUT exception). |
**************************************************************************/ |
volatile uint32_t getting_exe = 0; |
|
167,7 → 203,6
|
// Function prototypes |
void __attribute__((__interrupt__)) bootloader_trap_handler(void); |
void fast_upload(int src); |
void print_help(void); |
void start_app(void); |
void get_exe(int src); |
188,121 → 223,140
|
|
/**********************************************************************//** |
* Sanity check: Base ISA only! |
**************************************************************************/ |
#if defined __riscv_atomic || defined __riscv_a || __riscv_b || __riscv_compressed || defined __riscv_c || defined __riscv_mul || defined __riscv_m |
#warning In order to allow the bootloader to run on *any* CPU configuration it should be compiled using the base ISA only. |
#endif |
|
|
/**********************************************************************//** |
* Bootloader main. |
**************************************************************************/ |
int main(void) { |
|
// check ISA |
#if defined __riscv_atomic || defined __riscv_a || __riscv_b || __riscv_compressed || defined __riscv_c || defined __riscv_mul || defined __riscv_m |
#warning In order to allow the bootloader to run on *ANY* CPU configuration it should be compiled using the base ISA (rv32i/e) only. |
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// AUTO BOOT: OCD |
// Stay in endless loop until the on-chip debugger |
// takes over CPU control |
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
#if (AUTO_BOOT_OCD_EN != 0) |
#warning Boot configuration: Boot via on-chip debugger. |
while(1) { |
asm volatile ("nop"); |
} |
return 0; // should never be reached |
#endif |
|
exe_available = 0; // global variable for executable size; 0 means there is no exe available |
getting_exe = 0; // we are not trying to get an executable yet |
|
// ------------------------------------------------ |
// Minimal processor hardware initialization |
// - all IO devices are reset and disabled by the crt0 code |
// ------------------------------------------------ |
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// AUTO BOOT: SPI flash |
// Bootloader will directly boot and execute image from SPI flash |
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
#if (AUTO_BOOT_SPI_EN != 0) |
#warning Boot configuration: Auto boot from external SPI flash. |
|
// get clock speed (in Hz) |
uint32_t clock_speed = SYSINFO_CLK; |
PRINT_TEXT("\nNEORV32 bootloader\nLoading from SPI flash at "); |
PRINT_XNUM((uint32_t)SPI_BOOT_BASE_ADDR); |
PRINT_TEXT("...\n"); |
|
// init SPI for 8-bit, clock-mode 0 |
if (clock_speed < 40000000) { |
neorv32_spi_setup(SPI_FLASH_CLK_PRSC, 0, 0); |
} |
else { |
neorv32_spi_setup(CLK_PRSC_128, 0, 0); |
} |
get_exe(EXE_STREAM_FLASH); |
PRINT_TEXT("\n"); |
start_app(); |
|
#if (STATUS_LED_EN != 0) |
// activate status LED, clear all others |
neorv32_gpio_port_set(1 << STATUS_LED); |
return 0; // bootloader should never return |
#endif |
|
// init UART (no parity bit, no hardware flow control) |
neorv32_uart_setup(BAUD_RATE, PARITY_NONE, FLOW_CONTROL_NONE); |
|
// Configure machine system timer interrupt for ~2Hz |
neorv32_mtime_set_timecmp(neorv32_mtime_get_time() + (clock_speed/4)); |
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// AUTO BOOT: Default |
// User UART to upload new executable and optionally store it to SPI flash |
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
|
exe_available = 0; // global variable for executable size; 0 means there is no exe available |
getting_exe = 0; // we are not trying to get an executable yet |
|
|
// configure trap handler (bare-metal, no neorv32 rte available) |
neorv32_cpu_csr_write(CSR_MTVEC, (uint32_t)(&bootloader_trap_handler)); |
|
// active timer IRQ |
neorv32_cpu_csr_write(CSR_MIE, 1 << CSR_MIE_MTIE); // activate MTIME IRQ source |
neorv32_cpu_eint(); // enable global interrupts |
// setup SPI for 8-bit, clock-mode 0 |
neorv32_spi_setup(SPI_FLASH_CLK_PRSC, 0, 0); |
|
#if (STATUS_LED_EN != 0) |
if (neorv32_gpio_available()) { |
// activate status LED, clear all others |
neorv32_gpio_port_set(1 << STATUS_LED_PIN); |
} |
#endif |
|
// ------------------------------------------------ |
// Fast boot mode: Direct SPI boot |
// Bootloader will directly boot and execute image from SPI memory. |
// No user UART console is available in this mode! |
// ------------------------------------------------ |
#if (SPI_DIRECT_BOOT_EN != 0) |
#warning Compiling bootloader in 'SPI direct boot mode'. Bootloader will directly boot from SPI memory. No user UART console will be available. |
#if (UART_EN != 0) |
// setup UART0 (primary UART, no parity bit, no hardware flow control) |
neorv32_uart0_setup(UART_BAUD, PARITY_NONE, FLOW_CONTROL_NONE); |
#endif |
|
neorv32_uart_print("\nNEORV32 bootloader\nAccessing SPI flash at "); |
print_hex_word((uint32_t)SPI_FLASH_BOOT_ADR); |
neorv32_uart_print("\n"); |
// Configure machine system timer interrupt for ~2Hz |
if (neorv32_mtime_available()) { |
neorv32_mtime_set_timecmp(neorv32_mtime_get_time() + (SYSINFO_CLK/4)); |
// active timer IRQ |
neorv32_cpu_csr_write(CSR_MIE, 1 << CSR_MIE_MTIE); // activate MTIME IRQ source only! |
neorv32_cpu_eint(); // enable global interrupts |
} |
|
get_exe(EXE_STREAM_FLASH); |
neorv32_uart_print("\n"); |
start_app(); |
|
return 1; // bootloader should never return |
#endif |
|
|
// ------------------------------------------------ |
// Show bootloader intro and system info |
// ------------------------------------------------ |
neorv32_uart_print("\n\n\n\n<< NEORV32 Bootloader >>\n\n" |
PRINT_TEXT("\n\n\n<< NEORV32 Bootloader >>\n\n" |
"BLDV: "__DATE__"\nHWV: "); |
print_hex_word(neorv32_cpu_csr_read(CSR_MIMPID)); |
neorv32_uart_print("\nCLK: "); |
print_hex_word(SYSINFO_CLK); |
neorv32_uart_print("\nUSER: "); |
print_hex_word(SYSINFO_USER_CODE); |
neorv32_uart_print("\nMISA: "); |
print_hex_word(neorv32_cpu_csr_read(CSR_MISA)); |
neorv32_uart_print("\nZEXT: "); |
print_hex_word(neorv32_cpu_csr_read(CSR_MZEXT)); |
neorv32_uart_print("\nPROC: "); |
print_hex_word(SYSINFO_FEATURES); |
neorv32_uart_print("\nIMEM: "); |
print_hex_word(SYSINFO_IMEM_SIZE); |
neorv32_uart_print(" bytes @ "); |
print_hex_word(SYSINFO_ISPACE_BASE); |
neorv32_uart_print("\nDMEM: "); |
print_hex_word(SYSINFO_DMEM_SIZE); |
neorv32_uart_print(" bytes @ "); |
print_hex_word(SYSINFO_DSPACE_BASE); |
PRINT_XNUM(neorv32_cpu_csr_read(CSR_MIMPID)); |
PRINT_TEXT("\nCLK: "); |
PRINT_XNUM(SYSINFO_CLK); |
PRINT_TEXT("\nMISA: "); |
PRINT_XNUM(neorv32_cpu_csr_read(CSR_MISA)); |
PRINT_TEXT("\nZEXT: "); |
PRINT_XNUM(neorv32_cpu_csr_read(CSR_MZEXT)); |
PRINT_TEXT("\nPROC: "); |
PRINT_XNUM(SYSINFO_FEATURES); |
PRINT_TEXT("\nIMEM: "); |
PRINT_XNUM(SYSINFO_IMEM_SIZE); |
PRINT_TEXT(" bytes @"); |
PRINT_XNUM(SYSINFO_ISPACE_BASE); |
PRINT_TEXT("\nDMEM: "); |
PRINT_XNUM(SYSINFO_DMEM_SIZE); |
PRINT_TEXT(" bytes @"); |
PRINT_XNUM(SYSINFO_DSPACE_BASE); |
|
|
// ------------------------------------------------ |
// Auto boot sequence |
// ------------------------------------------------ |
#if (AUTOBOOT_EN != 0) |
neorv32_uart_print("\n\nAutoboot in "xstr(AUTOBOOT_TIMEOUT)"s. Press key to abort.\n"); |
# if (AUTO_BOOT_TIMEOUT != 0) |
if (neorv32_mtime_available()) { |
|
uint64_t timeout_time = neorv32_mtime_get_time() + (uint64_t)(AUTOBOOT_TIMEOUT * clock_speed); |
PRINT_TEXT("\n\nAutoboot in "xstr(AUTO_BOOT_TIMEOUT)"s. Press key to abort.\n"); |
uint64_t timeout_time = neorv32_mtime_get_time() + (uint64_t)(AUTO_BOOT_TIMEOUT * SYSINFO_CLK); |
|
while (neorv32_uart_char_received() == 0) { // wait for any key to be pressed |
while(1){ |
|
if (neorv32_mtime_get_time() >= timeout_time) { // timeout? start auto boot sequence |
fast_upload(EXE_STREAM_FLASH); // try booting from flash |
if (neorv32_uart0_available()) { // wait for any key to be pressed |
if (neorv32_uart0_char_received()) { |
break; |
} |
} |
|
if (neorv32_mtime_get_time() >= timeout_time) { // timeout? start auto boot sequence |
get_exe(EXE_STREAM_FLASH); // try booting from flash |
PRINT_TEXT("\n"); |
start_app(); |
while(1); |
} |
|
} |
PRINT_TEXT("Aborted.\n\n"); |
} |
neorv32_uart_print("Aborted.\n\n"); |
|
// fast executable upload? |
if (neorv32_uart_char_received_get() == FAST_UPLOAD_CMD) { |
fast_upload(EXE_STREAM_UART); |
} |
#else |
neorv32_uart_print("\n\n"); |
PRINT_TEXT("Aborted.\n\n"); |
#endif |
|
print_help(); |
313,15 → 367,12
// ------------------------------------------------ |
while (1) { |
|
neorv32_uart_print("\nCMD:> "); |
char c = neorv32_uart_getc(); |
neorv32_uart_putc(c); // echo |
neorv32_uart_print("\n"); |
PRINT_TEXT("\nCMD:> "); |
char c = PRINT_GETC(); |
PRINT_PUTC(c); // echo |
PRINT_TEXT("\n"); |
|
if (c == FAST_UPLOAD_CMD) { // fast executable upload |
fast_upload(EXE_STREAM_UART); |
} |
else if (c == 'r') { // restart bootloader |
if (c == 'r') { // restart bootloader |
asm volatile ("li t0, %[input_i]; jr t0" : : [input_i] "i" (BOOTLOADER_BASE_ADDRESS)); // jump to beginning of boot ROM |
} |
else if (c == 'h') { // help menu |
336,11 → 387,16
else if (c == 'l') { // get executable from flash |
get_exe(EXE_STREAM_FLASH); |
} |
else if (c == 'e') { // start application program |
start_app(); |
else if (c == 'e') { // start application program // executable available? |
if (exe_available == 0) { |
PRINT_TEXT("No executable available."); |
} |
else { |
start_app(); |
} |
} |
else { // unknown command |
neorv32_uart_print("Invalid CMD"); |
PRINT_TEXT("Invalid CMD"); |
} |
} |
|
349,25 → 405,11
|
|
/**********************************************************************//** |
* Get executable stream and execute it. |
* |
* @param src Source of executable stream data. See #EXE_STREAM_SOURCE. |
**************************************************************************/ |
void fast_upload(int src) { |
|
get_exe(src); |
neorv32_uart_print("\n"); |
start_app(); |
while(1); |
} |
|
|
/**********************************************************************//** |
* Print help menu. |
**************************************************************************/ |
void print_help(void) { |
|
neorv32_uart_print("Available CMDs:\n" |
PRINT_TEXT("Available CMDs:\n" |
" h: Help\n" |
" r: Restart\n" |
" u: Upload\n" |
382,23 → 424,13
**************************************************************************/ |
void start_app(void) { |
|
// executable available? |
if (exe_available == 0) { |
neorv32_uart_print("No executable available."); |
return; |
} |
|
// no need to shut down/reset the used peripherals |
// no need to disable interrupt sources |
// -> crt0 will do a clean CPU/processor reset/setup |
|
// deactivate global IRQs |
neorv32_cpu_dint(); |
|
neorv32_uart_print("Booting...\n\n"); |
PRINT_TEXT("Booting...\n\n"); |
|
// wait for UART to finish transmitting |
while (neorv32_uart_tx_busy()); |
while (neorv32_uart0_tx_busy()); |
|
// start app at instruction space base address |
register uint32_t app_base = SYSINFO_ISPACE_BASE; |
409,35 → 441,48
|
/**********************************************************************//** |
* Bootloader trap handler. Used for the MTIME tick and to capture any other traps. |
* @warning Since we have no runtime environment, we have to use the interrupt attribute here. Here and only here! |
* |
* @warning Adapt exception PC only for sync exceptions! |
* |
* @note Since we have no runtime environment, we have to use the interrupt attribute here. Here and only here! |
**************************************************************************/ |
void __attribute__((__interrupt__)) bootloader_trap_handler(void) { |
|
uint32_t cause = neorv32_cpu_csr_read(CSR_MCAUSE); |
|
// make sure this was caused by MTIME IRQ |
// Machine timer interrupt |
if (cause == TRAP_CODE_MTI) { // raw exception code for MTI |
#if (STATUS_LED_EN != 0) |
// toggle status LED |
neorv32_gpio_pin_toggle(STATUS_LED); |
if (neorv32_gpio_available()) { |
neorv32_gpio_pin_toggle(STATUS_LED_PIN); // toggle status LED |
} |
#endif |
// set time for next IRQ |
neorv32_mtime_set_timecmp(neorv32_mtime_get_time() + (SYSINFO_CLK/4)); |
if (neorv32_mtime_available()) { |
neorv32_mtime_set_timecmp(neorv32_mtime_get_time() + (SYSINFO_CLK/4)); |
} |
} |
|
// Bus store access error during get_exe |
else if ((cause == TRAP_CODE_S_ACCESS) && (getting_exe)) { |
system_error(ERROR_SIZE); // -> seems like executable is too large |
} |
|
// Anything else (that was not expected); output exception notifier and try to resume |
else { |
// store bus access error during get_exe |
// -> seems like executable is too large |
if ((cause == TRAP_CODE_S_ACCESS) && (getting_exe)) { |
system_error(ERROR_SIZE); |
uint32_t epc = neorv32_cpu_csr_read(CSR_MEPC); |
#if (UART_EN != 0) |
if (neorv32_uart0_available()) { |
PRINT_TEXT("\n[EXC "); |
PRINT_XNUM(cause); // MCAUSE |
PRINT_PUTC(' '); |
PRINT_XNUM(epc); // MEPC |
PRINT_PUTC(' '); |
PRINT_XNUM(neorv32_cpu_csr_read(CSR_MTVAL)); // MTVAL |
PRINT_TEXT("]\n"); |
} |
// unknown error |
else { |
neorv32_uart_print("\n\nEXCEPTION mcause="); |
print_hex_word(cause); |
neorv32_uart_print(" @ pc="); |
print_hex_word(neorv32_cpu_csr_read(CSR_MEPC)); |
system_error(ERROR_SYSTEM); |
} |
#endif |
neorv32_cpu_csr_write(CSR_MEPC, epc + 4); // advance to next instruction |
} |
} |
|
451,31 → 496,21
|
getting_exe = 1; // to inform trap handler we were trying to get an executable |
|
// is MEM implemented and read-only? |
if ((SYSINFO_FEATURES & (1 << SYSINFO_FEATURES_MEM_INT_IMEM_ROM)) && |
(SYSINFO_FEATURES & (1 << SYSINFO_FEATURES_MEM_INT_IMEM))) { |
system_error(ERROR_ROM); |
} |
|
// flash image base address |
uint32_t addr = SPI_FLASH_BOOT_ADR; |
uint32_t addr = (uint32_t)SPI_BOOT_BASE_ADDR; |
|
// get image from flash? |
if (src == EXE_STREAM_UART) { |
neorv32_uart_print("Awaiting neorv32_exe.bin... "); |
PRINT_TEXT("Awaiting neorv32_exe.bin... "); |
} |
else { |
neorv32_uart_print("Loading... "); |
PRINT_TEXT("Loading... "); |
|
// check if SPI is available at all |
if (neorv32_spi_available() == 0) { |
// flash checks |
if ((neorv32_spi_available() == 0) || // check if SPI is available at all |
(spi_flash_read_1st_id() == 0x00)) { // check if flash ready (or available at all) |
system_error(ERROR_FLASH); |
} |
|
// check if flash ready (or available at all) |
if (spi_flash_read_1st_id() == 0x00) { // manufacturer ID |
system_error(ERROR_FLASH); |
} |
} |
|
// check if valid image |
505,7 → 540,7
system_error(ERROR_CHECKSUM); |
} |
else { |
neorv32_uart_print("OK"); |
PRINT_TEXT("OK"); |
exe_available = size; // store exe size |
} |
|
522,21 → 557,21
uint32_t size = exe_available; |
|
if (size == 0) { |
neorv32_uart_print("No executable available."); |
PRINT_TEXT("No executable available."); |
return; |
} |
|
uint32_t addr = SPI_FLASH_BOOT_ADR; |
uint32_t addr = (uint32_t)SPI_BOOT_BASE_ADDR; |
|
// info and prompt |
neorv32_uart_print("Write 0x"); |
print_hex_word(size); |
neorv32_uart_print(" bytes to SPI flash @ 0x"); |
print_hex_word(addr); |
neorv32_uart_print("? (y/n) "); |
PRINT_TEXT("Write "); |
PRINT_XNUM(size); |
PRINT_TEXT(" bytes to SPI flash @ "); |
PRINT_XNUM(addr); |
PRINT_TEXT("? (y/n) "); |
|
char c = neorv32_uart_getc(); |
neorv32_uart_putc(c); |
char c = PRINT_GETC(); |
PRINT_PUTC(c); |
if (c != 'y') { |
return; |
} |
546,11 → 581,11
system_error(ERROR_FLASH); |
} |
|
neorv32_uart_print("\nFlashing... "); |
PRINT_TEXT("\nFlashing... "); |
|
// clear memory before writing |
uint32_t num_sectors = (size / SPI_FLASH_SECTOR_SIZE) + 1; // clear at least 1 sector |
uint32_t sector = SPI_FLASH_BOOT_ADR; |
uint32_t num_sectors = (size / (SPI_FLASH_SECTOR_SIZE)) + 1; // clear at least 1 sector |
uint32_t sector = (uint32_t)SPI_BOOT_BASE_ADDR; |
while (num_sectors--) { |
spi_flash_erase_sector(sector); |
sector += SPI_FLASH_SECTOR_SIZE; |
577,9 → 612,9
|
// write checksum (sum complement) |
checksum = (~checksum) + 1; |
spi_flash_write_word(SPI_FLASH_BOOT_ADR + EXE_OFFSET_CHECKSUM, checksum); |
spi_flash_write_word((uint32_t)SPI_BOOT_BASE_ADDR + EXE_OFFSET_CHECKSUM, checksum); |
|
neorv32_uart_print("OK"); |
PRINT_TEXT("OK"); |
} |
|
|
600,7 → 635,7
uint32_t i; |
for (i=0; i<4; i++) { |
if (src == EXE_STREAM_UART) { |
data.uint8[i] = (uint8_t)neorv32_uart_getc(); |
data.uint8[i] = (uint8_t)PRINT_GETC(); |
} |
else { |
data.uint8[i] = spi_flash_read_byte(addr + i); |
618,13 → 653,15
**************************************************************************/ |
void system_error(uint8_t err_code) { |
|
neorv32_uart_print("\a\nERROR_"); // output error code with annoying bell sound |
neorv32_uart_putc('0' + ((char)err_code)); // FIXME err_code should/must be below 10 |
PRINT_TEXT("\a\nERROR_"); // output error code with annoying bell sound |
PRINT_PUTC('0' + ((char)err_code)); |
|
neorv32_cpu_dint(); // deactivate IRQs |
if (STATUS_LED_EN == 1) { |
neorv32_gpio_port_set(1 << STATUS_LED); // permanently light up status LED |
#if (STATUS_LED_EN != 0) |
if (neorv32_gpio_available()) { |
neorv32_gpio_port_set(1 << STATUS_LED_PIN); // permanently light up status LED |
} |
#endif |
|
while(1); // freeze |
} |
637,15 → 674,17
**************************************************************************/ |
void print_hex_word(uint32_t num) { |
|
#if (UART_EN != 0) |
static const char hex_symbols[16] = "0123456789abcdef"; |
|
neorv32_uart_print("0x"); |
PRINT_TEXT("0x"); |
|
int i; |
for (i=0; i<8; i++) { |
uint32_t index = (num >> (28 - 4*i)) & 0xF; |
neorv32_uart_putc(hex_symbols[index]); |
PRINT_PUTC(hex_symbols[index]); |
} |
#endif |
} |
|
|
/common/crt0.S
44,85 → 44,75
|
nop |
|
// ********************************************************* |
// Clear integer register file (lower half, assume E extension) |
// ********************************************************* |
__crt0_reg_file_clear: |
//addi x0, x0, 0 // hardwired to zero |
addi x1, x0, 0 |
addi x2, x0, 0 |
addi x3, x0, 0 |
addi x4, x0, 0 |
addi x5, x0, 0 |
addi x6, x0, 0 |
addi x7, x0, 0 |
//addi x8, x0, 0 |
//addi x9, x0, 0 |
//addi x10, x0, 0 |
//addi x11, x0, 0 |
//addi x12, x0, 0 |
//addi x13, x0, 0 |
addi x14, x0, 0 |
addi x15, x0, 0 |
|
|
// ********************************************************* |
// ************************************************************************************************ |
// Setup pointers using linker script symbols |
// ********************************************************* |
// ************************************************************************************************ |
__crt0_pointer_init: |
.option push |
.option norelax |
la sp, __crt0_stack_begin |
andi sp, sp, 0xfffffffc // make sure this is aligned |
addi fp, sp, 0 // frame pointer = stack pointer |
la gp, __global_pointer$ // global pointer |
.option pop |
.option push |
.option norelax |
|
la sp, __crt0_stack_begin // stack pointer |
la gp, __global_pointer$ // global pointer |
|
// ********************************************************* |
// Setup CPU core CSRs (some of them DO NOT have a dedicated reset and need to be explicitly initialized) |
// ********************************************************* |
.option pop |
|
|
// ************************************************************************************************ |
// Setup CPU core CSRs (some of them DO NOT have a dedicated |
// reset and need to be explicitly initialized) |
// ************************************************************************************************ |
__crt0_cpu_csr_init: |
|
// set address of first-level exception handler |
la x10, __crt0_dummy_trap_handler |
csrw mtvec, x10 |
csrw mepc, x10 |
csrw mtval, zero |
csrw mcause, zero |
la x10, __crt0_dummy_trap_handler // configure early trap handler |
csrw mtvec, x10 |
csrw mepc, x10 // just to init mepc |
|
// no global IRQ enable (is also done by hardware) |
csrw mstatus, zero |
csrw mstatus, zero // disable global IRQ |
|
// absolutely no interrupts, thanks |
csrw mie, zero |
csrw mie, zero // absolutely no interrupts sources, thanks |
|
// no access from less-privileged modes to counter CSRs |
csrw mcounteren, zero |
csrw mcounteren, zero // no access from less-privileged modes to counter CSRs |
|
// stop all counters except for [m]cycle[h] and [m]instret[h] |
li x11, ~5 |
csrw 0x320, x11 // mcountinhibit (literal address for lagacy toolchain compatibility) |
li x11, ~5 // stop all counters except for [m]cycle[h] and [m]instret[h] |
csrw 0x320, x11 // = mcountinhibit (literal address for lagacy toolchain compatibility) |
|
// clear cycle counters |
csrw mcycle, zero |
csrw mcycleh, zero |
|
// clear instruction counters |
csrw minstret, zero |
csrw mcycle, zero // reset cycle counters |
csrw mcycleh, zero |
csrw minstret, zero // reset instruction counters |
csrw minstreth, zero |
|
#if defined(__riscv_flen) && (__riscv_flen != 0) |
// clear floating-point CSR (rounding mode & exception flags) |
csrw fcsr, zero |
#if defined(__riscv_flen) |
csrw fcsr, zero // reset floating-point CSR |
#endif |
|
|
// ********************************************************* |
// Clear integer register file (upper half, if no E extension) |
// ********************************************************* |
// ************************************************************************************************ |
// Initialize integer register file (lower half) |
// ************************************************************************************************ |
__crt0_reg_file_clear: |
//addi x0, x0, 0 // hardwired to zero |
addi x1, x0, 0 |
//addi x2, x0, 0 // stack pointer sp |
//addi x3, x0, 0 // gloabl pointer gp |
addi x4, x0, 0 |
addi x5, x0, 0 |
addi x6, x0, 0 |
addi x7, x0, 0 |
//addi x8, x0, 0 // initialized within crt0 |
//addi x9, x0, 0 // initialized within crt0 |
//addi x10, x0, 0 // initialized within crt0 |
//addi x11, x0, 0 // initialized within crt0 |
//addi x12, x0, 0 // initialized within crt0 |
//addi x13, x0, 0 // initialized within crt0 |
addi x14, x0, 0 |
addi x15, x0, 0 |
|
|
// ************************************************************************************************ |
// Initialize integer register file (upper half, if no E extension) |
// ************************************************************************************************ |
#ifndef __riscv_32e |
// DO NOT DO THIS if compiling bootloader (to save some program space) |
// do not do this if compiling bootloader (to save some program space) |
#ifndef make_bootloader |
addi x16, x0, 0 |
addi x17, x0, 0 |
144,14 → 134,14
#endif |
|
|
// ********************************************************* |
// ************************************************************************************************ |
// Reset/deactivate IO/peripheral devices |
// Devices, that are not implemented, will cause a store access fault |
// which is captured but actually ignored due to the dummy handler. |
// ********************************************************* |
// Devices, that are not implemented, will cause a store bus access fault |
// which is captured (but actually ignored) by the dummy trap handler. |
// ************************************************************************************************ |
__crt0_reset_io: |
la x8, __ctr0_io_space_begin // start of processor-internal IO region |
la x9, __ctr0_io_space_end // end of processor-internal IO region |
la x8, __ctr0_io_space_begin // start of processor-internal IO region |
la x9, __ctr0_io_space_end // end of processor-internal IO region |
|
__crt0_reset_io_loop: |
sw zero, 0(x8) |
159,29 → 149,29
bne x8, x9, __crt0_reset_io_loop |
|
|
// ********************************************************* |
// ************************************************************************************************ |
// Clear .bss section (byte-wise) using linker script symbols |
// ********************************************************* |
// ************************************************************************************************ |
__crt0_clear_bss: |
la x11, __crt0_bss_start |
la x12, __crt0_bss_end |
la x11, __crt0_bss_start |
la x12, __crt0_bss_end |
|
__crt0_clear_bss_loop: |
bge x11, x12, __crt0_clear_bss_loop_end |
bge x11, x12, __crt0_clear_bss_loop_end |
sb zero, 0(x11) |
addi x11, x11, 1 |
addi x11, x11, 1 |
j __crt0_clear_bss_loop |
|
__crt0_clear_bss_loop_end: |
|
|
// ********************************************************* |
// ************************************************************************************************ |
// Copy initialized .data section from ROM to RAM (byte-wise) using linker script symbols |
// ********************************************************* |
// ************************************************************************************************ |
__crt0_copy_data: |
la x11, __crt0_copy_data_src_begin // start of data area (copy source) |
la x12, __crt0_copy_data_dst_begin // start of data area (copy destination) |
la x13, __crt0_copy_data_dst_end // last address of destination data area |
la x11, __crt0_copy_data_src_begin // start of data area (copy source) |
la x12, __crt0_copy_data_dst_begin // start of data area (copy destination) |
la x13, __crt0_copy_data_dst_end // last address of destination data area |
|
__crt0_copy_data_loop: |
bge x12, x13, __crt0_copy_data_loop_end |
194,69 → 184,75
__crt0_copy_data_loop_end: |
|
|
// ********************************************************* |
// Call main function |
// ********************************************************* |
// ************************************************************************************************ |
// Setup arguments and call main function |
// ************************************************************************************************ |
__crt0_main_entry: |
addi x10, zero, 0 // a0 = argc = 0 |
addi x11, zero, 0 // a1 = argv = 0 |
jal ra, main // call actual app's main function, this "should" not return |
|
// setup arguments for calling main |
addi x10, zero, 0 // argc = 0 |
addi x11, zero, 0 // argv = 0 |
|
// call actual app's main function |
jal ra, main |
// ************************************************************************************************ |
// call "after main" handler (if there is any) if main really returns |
// ************************************************************************************************ |
__crt0_main_aftermath: |
csrw mscratch, a0 // copy main's return code in mscratch for debugger |
|
#ifndef make_bootloader // after_main handler not supported for bootloader |
.weak __neorv32_crt0_after_main |
la ra, __neorv32_crt0_after_main |
beqz ra, __crt0_main_aftermath_end // check if an aftermath handler has been specified |
jalr ra // execute handler, main's return code in a0 |
#endif |
|
// ********************************************************* |
// Go to endless sleep mode if main returns |
// ********************************************************* |
__crt0_this_is_the_end: |
csrrci zero, mstatus, 8 // mstatus: disable global IRQs (MIE) |
__crt0_this_is_the_end_my_friend: |
wfi |
j __crt0_this_is_the_end_my_friend |
|
// ************************************************************************************************ |
// go to endless sleep mode |
// ************************************************************************************************ |
__crt0_main_aftermath_end: |
csrci mstatus, 8 // mstatus: disable global IRQs (mstatus.mie) |
__crt0_main_aftermath_end_loop: |
wfi // try to go to sleep mode |
j __crt0_main_aftermath_end_loop // endless loop |
|
// ********************************************************* |
// dummy trap handler (for exceptions & IRQs) |
// tries to move on to next instruction |
// ********************************************************* |
.global __crt0_dummy_trap_handler |
|
// ************************************************************************************************ |
// dummy trap handler (for exceptions & IRQs during very early boot stage) |
// does nothing but tries to move on to next instruction |
// ************************************************************************************************ |
.balign 4 |
__crt0_dummy_trap_handler: |
|
addi sp, sp, -8 |
sw x8, 0(sp) |
sw x9, 4(sp) |
addi sp, sp, -8 |
sw x8, 0(sp) |
sw x9, 4(sp) |
|
csrr x8, mcause |
blt x8, zero, __crt0_dummy_trap_handler_irq // skip mepc modification if interrupt |
csrr x8, mcause |
blt x8, zero, __crt0_dummy_trap_handler_irq // skip mepc modification if interrupt |
|
csrr x8, mepc |
csrr x8, mepc |
|
// is compressed instruction? |
__crt0_dummy_trap_handler_exc_c_check: |
lh x9, 0(x8) // get compressed instruction or lower 16 bits of uncompressed instruction that caused exception |
andi x9, x9, 3 // mask: isolate lowest 2 opcode bits (= 11 for uncompressed instructions) |
__crt0_dummy_trap_handler_exc_c_check: // is compressed instruction? |
lh x9, 0(x8) // get compressed instruction or lower 16 bits of uncompressed instruction that caused exception |
andi x9, x9, 3 // mask: isolate lowest 2 opcode bits (= 11 for uncompressed instructions) |
|
addi x8, x8, +2 // only this for compressed instructions |
csrw mepc, x8 // set return address when compressed instruction |
addi x8, x8, +2 // only this for compressed instructions |
csrw mepc, x8 // set return address when compressed instruction |
|
addi x8, zero, 3 |
bne x8, x9, __crt0_dummy_trap_handler_irq // jump if compressed instruction |
|
// is uncompressed instruction |
__crt0_dummy_trap_handler_exc_uncrompressed: |
csrr x8, mepc |
addi x8, x8, +2 // add another 2 (making +4) for uncompressed instructions |
addi x8, zero, 3 |
bne x8, x9, __crt0_dummy_trap_handler_irq // jump if compressed instruction |
|
__crt0_dummy_trap_handler_exc_uncrompressed: // is uncompressed instruction! |
csrr x8, mepc |
addi x8, x8, +2 // add another 2 (making +4) for uncompressed instructions |
csrw mepc, x8 |
|
__crt0_dummy_trap_handler_irq: |
lw x8, 0(sp) |
lw x9, 4(sp) |
addi sp, sp, +8 |
|
lw x8, 0(sp) |
lw x9, 4(sp) |
addi sp, sp, +8 |
|
mret |
|
.cfi_endproc |
/common/neorv32.ld
36,7 → 36,7
/* Copyright (C) 2014-2020 Free Software Foundation, Inc. |
Copying and distribution of this script, with or without modification, |
are permitted in any medium without royalty provided the copyright |
notice and this notice are preserved. */ |
notice and this notice are preserved. */ |
|
/* modified for the NEORV32 processor by Stephan Nolting */ |
|
46,20 → 46,25
ENTRY(_start) |
SEARCH_DIR("/opt/riscv/riscv32-unknown-elf/lib"); SEARCH_DIR("=/opt/riscv/riscv64-unknown-linux-gnu/lib"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib"); |
|
/* ************************************************************************* */ |
/* NEORV32 memory configuration. */ |
/* Make sure this is sync with your processor/memory hardware configuration! */ |
/* ************************************************************************* */ |
/* "rom" : instruction memory (IMEM) / bootloader ROM */ |
/* "ram" : data memory (DMEM) */ |
/* "iodev" : peripheral/IO devices (not used here; passed to crt0) */ |
/* ************************************************************************* */ |
/* ************************************************************************** */ |
/* NEORV32 memory section configuration. */ |
/* ************************************************************************** */ |
/* "ram" : data memory (int/ext DMEM) - make sure this is sync with the HW! */ |
/* "rom" : instruction memory (int/ext IMEM or bootloader ROM) */ |
/* "iodev" : peripheral/IO devices */ |
/* ************************************************************************** */ |
MEMORY |
{ |
/* "rom" section: first value of ORIGIN/LENGTH => bootloader ROM; second value of ORIGIN/LENGTH => instruction memory */ |
/* section base addresses and sizes have to be a multiple of 4-bytes */ |
/* ram section: first value of LENGTH => data memory used by bootloader (fixed!); second value of LENGTH => *physical* size of data memory */ |
/* adapt the right-most value to match the *total physical data memory size* of your setup */ |
|
rom (rx) : ORIGIN = DEFINED(make_bootloader) ? 0xFFFF0000 : 0x00000000, LENGTH = DEFINED(make_bootloader) ? 4*1024 : 16*1024 |
ram (rwx) : ORIGIN = 0x80000000, LENGTH = 8*1024 |
ram (rwx) : ORIGIN = 0x80000000, LENGTH = DEFINED(make_bootloader) ? 512 : 8*1024 |
|
/* rom and iodev sections should NOT be modified by the user at all! */ |
/* rom section: first value of ORIGIN/LENGTH => bootloader ROM; second value of ORIGIN/LENGTH => maximum *logical* size of instruction memory */ |
|
rom (rx) : ORIGIN = DEFINED(make_bootloader) ? 0xFFFF0000 : 0x00000000, LENGTH = DEFINED(make_bootloader) ? 32K : 2048M |
iodev (rw) : ORIGIN = 0xFFFFFE00, LENGTH = 512 |
|
} |
67,9 → 72,6
|
SECTIONS |
{ |
/* stack pointer init: last 32-bit entry in data memory */ |
__crt0_stack_begin = (ORIGIN(ram) + LENGTH(ram)) - 4; |
|
/* start section on WORD boundary */ |
. = ALIGN(4); |
|
291,7 → 293,8
/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } |
|
|
/* Provide further symbols for neorv32 crt0 */ |
/* Provide symbols for neorv32 crt0 start-up code */ |
PROVIDE(__crt0_stack_begin = (ORIGIN(ram) + LENGTH(ram)) - 4); |
PROVIDE(__crt0_bss_start = __bss_start); |
PROVIDE(__crt0_bss_end = __BSS_END__); |
PROVIDE(__crt0_copy_data_src_begin = __etext + SIZEOF(.rodata)); |
/example/demo_gpio_irq/makefile
File deleted
/example/demo_gpio_irq/main.c
File deleted
/example/demo_nco/makefile
File deleted
/example/demo_nco/main.c
File deleted
/example/blink_led/main.c
79,7 → 79,7
// check if GPIO unit is implemented at all |
if (neorv32_gpio_available() == 0) { |
neorv32_uart_print("Error! No GPIO unit synthesized!\n"); |
return 0; // nope, no GPIO unit synthesized |
return 1; // nope, no GPIO unit synthesized |
} |
|
// capture all exceptions and give debug info via UART |
86,9 → 86,6
// this is not required, but keeps us safe |
neorv32_rte_setup(); |
|
// check available hardware extensions and compare with compiler flags |
neorv32_rte_check_isa(0); // silent = 0 -> show message if isa mismatch |
|
// say hello |
neorv32_uart_print("Blinking LED demo program\n"); |
|
/example/demo_xirq/main.c
0,0 → 1,196
// ################################################################################################# |
// # << NEORV32 - External Interrupt Controller (XIRQ) Demo Program >> # |
// # ********************************************************************************************* # |
// # 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 # |
// ################################################################################################# |
|
|
/**********************************************************************//** |
* @file demo_xirq/main.c |
* @author Stephan Nolting |
* @brief External interrupt controller (XIRQ) demo program. |
**************************************************************************/ |
|
#include <neorv32.h> |
|
|
/**********************************************************************//** |
* @name User configuration |
**************************************************************************/ |
/**@{*/ |
/** UART BAUD rate */ |
#define BAUD_RATE 19200 |
/**@}*/ |
|
// prototypes |
void xirq_handler_ch0(void); |
void xirq_handler_ch1(void); |
void xirq_handler_ch2(void); |
void xirq_handler_ch3(void); |
|
|
/**********************************************************************//** |
* Main function |
* |
* @note This program requires the WDT and the UART to be synthesized. |
* |
* @return 0 if execution was successful |
**************************************************************************/ |
int main() { |
|
// initialize the neorv32 runtime environment |
// this will take care of handling all CPU traps (interrupts and exceptions) |
neorv32_rte_setup(); |
|
// setup UART0 at default baud rate, no parity bits, ho hw flow control |
neorv32_uart0_setup(BAUD_RATE, PARITY_NONE, FLOW_CONTROL_NONE); |
|
// check if XIRQ unit is implemented at all |
if (neorv32_xirq_available() == 0) { |
neorv32_uart0_printf("XIRQ not synthesized!\n"); |
return 1; |
} |
|
|
// intro |
neorv32_uart0_printf("External interrupt controller (XIRQ) demo program\n\n"); |
|
int err_cnt = 0; |
|
|
// initialize XIRQ controller |
// this will disable all XIRQ channels and will also clear any pending external interrupts |
// (details: this will register the XIRQ's second-level interrupt handler in the NEORV32 RTE) |
err_cnt = neorv32_xirq_setup(); |
|
// check if setup went fine |
if (err_cnt) { |
neorv32_uart0_printf("Error during XIRQ setup!\n"); |
return 1; |
} |
|
|
// install handler functions for XIRQ channel 0,1,2,3. note that these functions are "normal" functions! |
// (details: these are "third-level" interrupt handler) |
err_cnt = 0; |
err_cnt += neorv32_xirq_install(0, xirq_handler_ch0); // handler function for channel 0 |
err_cnt += neorv32_xirq_install(1, xirq_handler_ch1); // handler function for channel 1 |
err_cnt += neorv32_xirq_install(2, xirq_handler_ch2); // handler function for channel 2 |
err_cnt += neorv32_xirq_install(3, xirq_handler_ch3); // handler function for channel 3 |
|
// check if installation went fine |
if (err_cnt) { |
neorv32_uart0_printf("Error during XIRQ install!\n"); |
return 1; |
} |
|
|
// allow XIRQ to trigger CPU interrupt |
neorv32_xirq_global_enable(); |
|
|
// enable global interrupts |
neorv32_cpu_eint(); |
|
|
// now we are ready to got! |
// the code below assumes the XIRQ inputs are connected to the processor's GPIO output port |
// so we can trigger the IRQs from software; if you have connected the XIRQs to buttons you |
// can remove the code below (note the trigger configuration using the XIRQ generics!) |
{ |
// trigger XIRQs 3:0 at once |
// assumes xirq_i <= gpio.output(31:0) |
|
// due to the prioritization this will execute |
// -> xirq_handler_ch0 |
// -> xirq_handler_ch1 |
// -> xirq_handler_ch2 |
// -> xirq_handler_ch3 |
neorv32_gpio_port_set(0xF); // set output pins 3:0 -> trigger XIRQ 3:0 |
neorv32_gpio_port_set(0x0); |
} |
|
|
// wait for interrupts |
while(1); |
|
|
// just as an example: to disable certain XIRQ interrupt channels, we can |
// uninstall the according handler. this will also clear a pending interrupt for that channel |
neorv32_xirq_uninstall(0); // disable XIRQ channel 0 and remove associated handler |
neorv32_xirq_uninstall(1); // disable XIRQ channel 1 and remove associated handler |
neorv32_xirq_uninstall(2); // disable XIRQ channel 2 and remove associated handler |
neorv32_xirq_uninstall(3); // disable XIRQ channel 3 and remove associated handler |
|
|
return 0; |
} |
|
|
/**********************************************************************//** |
* XIRQ handler channel 0. |
* |
* @warning This function has to be of type "void xyz(void)" and must not use any interrupt attributes! |
**************************************************************************/ |
void xirq_handler_ch0(void) { |
|
neorv32_uart0_printf("XIRQ interrupt from channel %i\n", 0); |
} |
|
/**********************************************************************//** |
* XIRQ handler channel 1. |
* |
* @warning This function has to be of type "void xyz(void)" and must not use any interrupt attributes! |
**************************************************************************/ |
void xirq_handler_ch1(void) { |
|
neorv32_uart0_printf("XIRQ interrupt from channel %i\n", 1); |
} |
|
/**********************************************************************//** |
* XIRQ handler channel 2. |
* |
* @warning This function has to be of type "void xyz(void)" and must not use any interrupt attributes! |
**************************************************************************/ |
void xirq_handler_ch2(void) { |
|
neorv32_uart0_printf("XIRQ interrupt from channel %i\n", 2); |
} |
|
/**********************************************************************//** |
* XIRQ handler channel 3. |
* |
* @warning This function has to be of type "void xyz(void)" and must not use any interrupt attributes! |
**************************************************************************/ |
void xirq_handler_ch3(void) { |
|
neorv32_uart0_printf("XIRQ interrupt from channel %i\n", 3); |
} |
/example/demo_xirq/makefile
0,0 → 1,338
################################################################################################# |
# << 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 # |
################################################################################################# |
|
|
# ***************************************************************************** |
# USER CONFIGURATION |
# ***************************************************************************** |
# User's application sources (*.c, *.cpp, *.s, *.S); add additional files here |
APP_SRC ?= $(wildcard ./*.c) $(wildcard ./*.s) $(wildcard ./*.cpp) $(wildcard ./*.S) |
|
# User's application include folders (don't forget the '-I' before each entry) |
APP_INC ?= -I . |
# User's application include folders - for assembly files only (don't forget the '-I' before each entry) |
ASM_INC ?= -I . |
|
# Optimization |
EFFORT ?= -Os |
|
# Compiler toolchain |
RISCV_TOOLCHAIN ?= riscv32-unknown-elf |
|
# CPU architecture and ABI |
MARCH ?= -march=rv32i |
MABI ?= -mabi=ilp32 |
|
# User flags for additional configuration (will be added to compiler flags) |
USER_FLAGS ?= |
|
# Serial port for executable upload via bootloer |
COM_PORT ?= /dev/ttyUSB0 |
|
# Relative or absolute path to the NEORV32 home folder |
NEORV32_HOME ?= ../../.. |
# ***************************************************************************** |
|
|
|
# ----------------------------------------------------------------------------- |
# NEORV32 framework |
# ----------------------------------------------------------------------------- |
# Path to NEORV32 linker script and startup file |
NEORV32_COM_PATH = $(NEORV32_HOME)/sw/common |
# Path to main NEORV32 library include files |
NEORV32_INC_PATH = $(NEORV32_HOME)/sw/lib/include |
# Path to main NEORV32 library source files |
NEORV32_SRC_PATH = $(NEORV32_HOME)/sw/lib/source |
# Path to NEORV32 executable generator |
NEORV32_EXG_PATH = $(NEORV32_HOME)/sw/image_gen |
# Path to NEORV32 core rtl folder |
NEORV32_RTL_PATH = $(NEORV32_HOME)/rtl/core |
# Marker file to check for NEORV32 home folder |
NEORV32_HOME_MARKER = $(NEORV32_INC_PATH)/neorv32.h |
|
# Core libraries (peripheral and CPU drivers) |
CORE_SRC = $(wildcard $(NEORV32_SRC_PATH)/*.c) |
# Application start-up code |
CORE_SRC += $(NEORV32_COM_PATH)/crt0.S |
|
# Linker script |
LD_SCRIPT = $(NEORV32_COM_PATH)/neorv32.ld |
|
# Main output files |
APP_EXE = neorv32_exe.bin |
APP_ASM = main.asm |
APP_IMG = neorv32_application_image.vhd |
BOOT_IMG = neorv32_bootloader_image.vhd |
|
|
# ----------------------------------------------------------------------------- |
# Sources and objects |
# ----------------------------------------------------------------------------- |
# Define all sources |
SRC = $(APP_SRC) |
SRC += $(CORE_SRC) |
|
# Define all object files |
OBJ = $(SRC:%=%.o) |
|
|
# ----------------------------------------------------------------------------- |
# Tools and flags |
# ----------------------------------------------------------------------------- |
# Compiler tools |
CC = $(RISCV_TOOLCHAIN)-gcc |
OBJDUMP = $(RISCV_TOOLCHAIN)-objdump |
OBJCOPY = $(RISCV_TOOLCHAIN)-objcopy |
SIZE = $(RISCV_TOOLCHAIN)-size |
|
# Host native compiler |
CC_X86 = g++ -Wall -O -g |
|
# NEORV32 executable image generator |
IMAGE_GEN = $(NEORV32_EXG_PATH)/image_gen |
|
# Compiler & linker flags |
CC_OPTS = $(MARCH) $(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles -mno-fdiv |
CC_OPTS += -Wl,--gc-sections -lm -lc -lgcc -lc |
# This accelerates instruction fetch after branches when C extension is enabled (irrelevant when C extension is disabled) |
CC_OPTS += -falign-functions=4 -falign-labels=4 -falign-loops=4 -falign-jumps=4 |
CC_OPTS += $(USER_FLAGS) |
|
|
# ----------------------------------------------------------------------------- |
# Application output definitions |
# ----------------------------------------------------------------------------- |
.PHONY: check info help elf_info clean clean_all bootloader |
.DEFAULT_GOAL := help |
|
# 'compile' is still here for compatibility |
exe: $(APP_ASM) $(APP_EXE) |
compile: $(APP_ASM) $(APP_EXE) |
install: $(APP_ASM) $(APP_IMG) |
all: $(APP_ASM) $(APP_EXE) $(APP_IMG) |
|
# Check if making bootloader |
# Use different base address and legth for instruction memory/"rom" (BOOTMEM instead of IMEM) |
# Also define "make_bootloader" for crt0.S |
target bootloader: CC_OPTS += -Wl,--defsym=make_bootloader=1 -Dmake_bootloader |
|
|
# ----------------------------------------------------------------------------- |
# Image generator targets |
# ----------------------------------------------------------------------------- |
# install/compile tools |
$(IMAGE_GEN): $(NEORV32_EXG_PATH)/image_gen.cpp |
@echo Compiling $(IMAGE_GEN) |
@$(CC_X86) $< -o $(IMAGE_GEN) |
|
|
# ----------------------------------------------------------------------------- |
# General targets: Assemble, compile, link, dump |
# ----------------------------------------------------------------------------- |
# Compile app *.s sources (assembly) |
%.s.o: %.s |
@$(CC) -c $(CC_OPTS) -I $(NEORV32_INC_PATH) $(ASM_INC) $< -o $@ |
|
# Compile app *.S sources (assembly + C pre-processor) |
%.S.o: %.S |
@$(CC) -c $(CC_OPTS) -I $(NEORV32_INC_PATH) $(ASM_INC) $< -o $@ |
|
# Compile app *.c sources |
%.c.o: %.c |
@$(CC) -c $(CC_OPTS) -I $(NEORV32_INC_PATH) $(APP_INC) $< -o $@ |
|
# Compile app *.cpp sources |
%.cpp.o: %.cpp |
@$(CC) -c $(CC_OPTS) -I $(NEORV32_INC_PATH) $(APP_INC) $< -o $@ |
|
# Link object files and show memory utilization |
main.elf: $(OBJ) |
@$(CC) $(CC_OPTS) -T $(LD_SCRIPT) $(OBJ) -o $@ -lm |
@echo "Memory utilization:" |
@$(SIZE) main.elf |
|
# Assembly listing file (for debugging) |
$(APP_ASM): main.elf |
@$(OBJDUMP) -d -S -z $< > $@ |
|
# Generate final executable from .text + .rodata + .data (in THIS order!) |
main.bin: main.elf $(APP_ASM) |
@$(OBJCOPY) -I elf32-little $< -j .text -O binary text.bin |
@$(OBJCOPY) -I elf32-little $< -j .rodata -O binary rodata.bin |
@$(OBJCOPY) -I elf32-little $< -j .data -O binary data.bin |
@cat text.bin rodata.bin data.bin > $@ |
@rm -f text.bin rodata.bin data.bin |
|
|
# ----------------------------------------------------------------------------- |
# Application targets: Generate binary executable, install (as VHDL file) |
# ----------------------------------------------------------------------------- |
# Generate NEORV32 executable image for upload via bootloader |
$(APP_EXE): main.bin $(IMAGE_GEN) |
@set -e |
@$(IMAGE_GEN) -app_bin $< $@ $(shell basename $(CURDIR)) |
@echo "Executable ($(APP_EXE)) size in bytes:" |
@wc -c < $(APP_EXE) |
|
# Generate NEORV32 executable VHDL boot image |
$(APP_IMG): main.bin $(IMAGE_GEN) |
@set -e |
@$(IMAGE_GEN) -app_img $< $@ $(shell basename $(CURDIR)) |
@echo "Installing application image to $(NEORV32_RTL_PATH)/$(APP_IMG)" |
@cp $(APP_IMG) $(NEORV32_RTL_PATH)/. |
|
|
# ----------------------------------------------------------------------------- |
# Bootloader targets |
# ----------------------------------------------------------------------------- |
# Create and install bootloader VHDL init image |
$(BOOT_IMG): main.bin $(IMAGE_GEN) |
@set -e |
@$(IMAGE_GEN) -bld_img $< $(BOOT_IMG) $(shell basename $(CURDIR)) |
@echo "Installing bootloader image to $(NEORV32_RTL_PATH)/$(BOOT_IMG)" |
@cp $(BOOT_IMG) $(NEORV32_RTL_PATH)/. |
|
# Just an alias that |
bootloader: $(BOOT_IMG) |
|
|
# ----------------------------------------------------------------------------- |
# Check toolchain |
# ----------------------------------------------------------------------------- |
check: $(IMAGE_GEN) |
@echo "---------------- Check: NEORV32_HOME folder ----------------" |
ifneq ($(shell [ -e $(NEORV32_HOME_MARKER) ] && echo 1 || echo 0 ), 1) |
$(error NEORV32_HOME folder not found!) |
endif |
@echo "NEORV32_HOME: $(NEORV32_HOME)" |
@echo "---------------- Check: $(CC) ----------------" |
@$(CC) -v |
@echo "---------------- Check: $(OBJDUMP) ----------------" |
@$(OBJDUMP) -V |
@echo "---------------- Check: $(OBJCOPY) ----------------" |
@$(OBJCOPY) -V |
@echo "---------------- Check: $(SIZE) ----------------" |
@$(SIZE) -V |
@echo "---------------- Check: NEORV32 image_gen ----------------" |
@$(IMAGE_GEN) -help |
@echo "---------------- Check: Native GCC ----------------" |
@$(CC_X86) -v |
@echo |
@echo "Toolchain check OK" |
|
|
# ----------------------------------------------------------------------------- |
# Upload executable via serial port to bootloader |
# ----------------------------------------------------------------------------- |
upload: $(APP_EXE) |
@sh $(NEORV32_EXG_PATH)/uart_upload.sh $(COM_PORT) $(APP_EXE) |
|
|
# ----------------------------------------------------------------------------- |
# Show configuration |
# ----------------------------------------------------------------------------- |
info: |
@echo "---------------- Info: Project ----------------" |
@echo "Project folder: $(shell basename $(CURDIR))" |
@echo "Source files: $(APP_SRC)" |
@echo "Include folder(s): $(APP_INC)" |
@echo "ASM include folder(s): $(ASM_INC)" |
@echo "---------------- Info: NEORV32 ----------------" |
@echo "NEORV32 home folder (NEORV32_HOME): $(NEORV32_HOME)" |
@echo "IMAGE_GEN: $(IMAGE_GEN)" |
@echo "Core source files:" |
@echo "$(CORE_SRC)" |
@echo "Core include folder:" |
@echo "$(NEORV32_INC_PATH)" |
@echo "---------------- Info: Objects ----------------" |
@echo "Project object files:" |
@echo "$(OBJ)" |
@echo "---------------- Info: RISC-V CPU ----------------" |
@echo "MARCH: $(MARCH)" |
@echo "MABI: $(MABI)" |
@echo "---------------- Info: Toolchain ----------------" |
@echo "Toolchain: $(RISCV_TOLLCHAIN)" |
@echo "CC: $(CC)" |
@echo "OBJDUMP: $(OBJDUMP)" |
@echo "OBJCOPY: $(OBJCOPY)" |
@echo "SIZE: $(SIZE)" |
@echo "---------------- Info: Compiler Libraries ----------------" |
@echo "LIBGCC:" |
@$(CC) -print-libgcc-file-name |
@echo "SEARCH-DIRS:" |
@$(CC) -print-search-dirs |
@echo "---------------- Info: Flags ----------------" |
@echo "USER_FLAGS: $(USER_FLAGS)" |
@echo "CC_OPTS: $(CC_OPTS)" |
@echo "---------------- Info: Host Native GCC Flags ----------------" |
@echo "CC_X86: $(CC_X86)" |
|
|
# ----------------------------------------------------------------------------- |
# Show final ELF details (just for debugging) |
# ----------------------------------------------------------------------------- |
elf_info: main.elf |
@$(OBJDUMP) -x main.elf |
|
|
# ----------------------------------------------------------------------------- |
# Help |
# ----------------------------------------------------------------------------- |
help: |
@echo "<<< NEORV32 Application Makefile >>>" |
@echo "Make sure to add the bin folder of RISC-V GCC to your PATH variable." |
@echo "Targets:" |
@echo " help - show this text" |
@echo " check - check toolchain" |
@echo " info - show makefile/toolchain configuration" |
@echo " exe - compile and generate <neorv32_exe.bin> executable for upload via bootloader" |
@echo " install - compile, generate and install VHDL IMEM boot image (for application)" |
@echo " all - compile and generate <neorv32_exe.bin> executable for upload via bootloader and generate and install VHDL IMEM boot image (for application)" |
@echo " clean - clean up project" |
@echo " clean_all - clean up project, core libraries and image generator" |
@echo " bootloader - compile, generate and install VHDL BOOTROM boot image (for bootloader only!)" |
@echo " upload - upload <neorv32_exe.bin> executable via serial port <COM_PORT> to bootloader" |
|
|
# ----------------------------------------------------------------------------- |
# Clean up |
# ----------------------------------------------------------------------------- |
clean: |
@rm -f *.elf *.o *.bin *.out *.asm *.vhd |
|
clean_all: clean |
@rm -f $(OBJ) $(IMAGE_GEN) |
/example/hex_viewer/main.c
210,7 → 210,7
char terminal_buffer[16]; |
uint32_t mem_address, rdata, wdata, status; |
|
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) { |
|
// enter memory address |
neorv32_uart_printf("Enter memory address (8 hex chars): 0x"); |
/example/processor_check/check.sh
33,6 → 33,7
clean_all \ |
USER_FLAGS+=-DRUN_CHECK \ |
USER_FLAGS+=-DUART0_SIM_MODE \ |
USER_FLAGS+=-DUART1_SIM_MODE \ |
MARCH=-march=rv32imac \ |
info \ |
all |
/example/processor_check/main.c
58,9 → 58,30
/**@}*/ |
|
|
/**********************************************************************//** |
* @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 |
void sim_irq_trigger(uint32_t sel); |
void global_trap_handler(void); |
void xirq_trap_handler0(void); |
void xirq_trap_handler1(void); |
void test_ok(void); |
void test_fail(void); |
|
71,10 → 92,12
int cnt_ok = 0; |
/// Global counter for total number of tests |
int cnt_test = 0; |
/// Global numbe rof available HPMs |
/// Global number of available HPMs |
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; |
|
|
82,6 → 105,8
* High-level CPU/processor test program. |
* |
* @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 |
**************************************************************************/ |
88,31 → 113,27
int main() { |
|
register uint32_t tmp_a, tmp_b; |
volatile uint32_t dummy_dst __attribute__((unused)); |
uint8_t id; |
uint32_t is_simulation = 0; |
|
|
// init UART at default baud rate, no parity bits, no hw flow control |
neorv32_uart_setup(BAUD_RATE, PARITY_NONE, FLOW_CONTROL_NONE); |
// init UARTs at default baud rate, no parity bits, no hw flow control |
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 |
#ifndef RUN_CHECK |
#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 |
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; |
#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 |
124,8 → 145,8
|
|
// intro |
neorv32_uart_printf("\n<< PROCESSOR CHECK >>\n"); |
neorv32_uart_printf("build: "__DATE__" "__TIME__"\n"); |
PRINT_STANDARD("\n<< PROCESSOR CHECK >>\n"); |
PRINT_STANDARD("build: "__DATE__" "__TIME__"\n"); |
|
|
// reset performance counter |
156,7 → 177,7
|
// configure RTE |
// ----------------------------------------------- |
neorv32_uart_printf("\n\nConfiguring NEORV32 RTE... "); |
PRINT_STANDARD("\n\nConfiguring NEORV32 RTE... "); |
|
int install_err = 0; |
// initialize ALL provided trap handler (overriding the default debug handlers) |
165,18 → 186,18
} |
|
if (install_err) { |
neorv32_uart_printf("RTE install error (%i)!\n", install_err); |
PRINT_CRITICAL("RTE install error (%i)!\n", install_err); |
return 1; |
} |
|
// enable interrupt sources |
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_MEIE); // machine external 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_MEIE); // machine external interrupt |
// enable FAST IRQ sources only where actually needed |
|
// test intro |
neorv32_uart_printf("\nStarting tests...\n\n"); |
PRINT_STANDARD("\nStarting tests...\n\n"); |
|
// enable global interrupts |
neorv32_cpu_eint(); |
186,7 → 207,7
// Test standard RISC-V performance counter [m]cycle[h] |
// ---------------------------------------------------------- |
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++; |
|
193,12 → 214,14
// make sure counter is enabled |
asm volatile ("csrci %[addr], %[imm]" : : [addr] "i" (CSR_MCOUNTINHIBIT), [imm] "i" (1<<CSR_MCOUNTINHIBIT_CY)); |
|
// get current cycle counter LOW |
tmp_a = neorv32_cpu_csr_read(CSR_MCYCLE); |
tmp_a = neorv32_cpu_csr_read(CSR_MCYCLE) - tmp_a; |
// prepare overflow |
neorv32_cpu_set_mcycle(0x00000000FFFFFFFFULL); |
|
// make sure cycle counter has incremented and there was no exception during access |
if ((tmp_a > 0) && (neorv32_cpu_csr_read(CSR_MCAUSE) == 0)) { |
// get current cycle counter HIGH |
tmp_a = neorv32_cpu_csr_read(CSR_MCYCLEH); |
|
// make sure cycle counter high has incremented and there was no exception during access |
if ((tmp_a == 1) && (neorv32_cpu_csr_read(CSR_MCAUSE) == 0)) { |
test_ok(); |
} |
else { |
210,7 → 233,7
// Test standard RISC-V performance counter [m]instret[h] |
// ---------------------------------------------------------- |
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++; |
|
217,19 → 240,15
// make sure counter is enabled |
asm volatile ("csrci %[addr], %[imm]" : : [addr] "i" (CSR_MCOUNTINHIBIT), [imm] "i" (1<<CSR_MCOUNTINHIBIT_IR)); |
|
// get instruction counter LOW |
tmp_a = neorv32_cpu_csr_read(CSR_INSTRET); |
tmp_a = neorv32_cpu_csr_read(CSR_INSTRET) - tmp_a; |
// prepare overflow |
neorv32_cpu_set_minstret(0x00000000FFFFFFFFULL); |
|
// make sure instruction counter 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_uart_printf("INSTRET_diff > 1 (%u)!", tmp_a); |
test_fail(); |
} |
else { |
test_ok(); |
} |
// get instruction counter HIGH |
tmp_a = neorv32_cpu_csr_read(CSR_INSTRETH); |
|
// make sure instruction counter high has incremented and there was no exception during access |
if ((tmp_a == 1) && (neorv32_cpu_csr_read(CSR_MCAUSE) == 0)) { |
test_ok(); |
} |
else { |
test_fail(); |
240,7 → 259,7
// Test mcountinhibt: inhibit auto-inc of [m]cycle |
// ---------------------------------------------------------- |
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++; |
|
276,10 → 295,10
// Test mcounteren: do not allow cycle[h] access from user-mode |
// ---------------------------------------------------------- |
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 |
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++; |
|
// do not allow user-level code to access cycle[h] CSRs |
308,7 → 327,7
} |
} |
else { |
neorv32_uart_printf("skipped (not implemented)\n"); |
PRINT_STANDARD("skipped (n.a.)\n"); |
} |
|
|
322,7 → 341,7
// Test performance counter: setup as many events and counter as feasible |
// ---------------------------------------------------------- |
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(); |
|
353,114 → 372,87
} |
} |
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 |
// ---------------------------------------------------------- |
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)) { |
cnt_test++; |
if (SYSINFO_FEATURES & (1 << SYSINFO_FEATURES_MEM_EXT)) { |
cnt_test++; |
|
// create test program in RAM |
static const uint32_t dummy_ext_program[2] __attribute__((aligned(8))) = { |
0x3407D073, // csrwi mscratch, 15 |
0x00008067 // ret (32-bit) |
}; |
// create test program in RAM |
static const uint32_t dummy_ext_program[2] __attribute__((aligned(8))) = { |
0x3407D073, // csrwi mscratch, 15 |
0x00008067 // ret (32-bit) |
}; |
|
// copy to external memory |
if (memcpy((void*)EXT_MEM_BASE, (void*)&dummy_ext_program, (size_t)sizeof(dummy_ext_program)) == NULL) { |
test_fail(); |
} |
else { |
// copy to external memory |
if (memcpy((void*)EXT_MEM_BASE, (void*)&dummy_ext_program, (size_t)sizeof(dummy_ext_program)) == NULL) { |
test_fail(); |
} |
else { |
|
// execute program |
tmp_a = (uint32_t)EXT_MEM_BASE; // call the dummy sub program |
asm volatile ("jalr ra, %[input_i]" : : [input_i] "r" (tmp_a)); |
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) { // make sure there was no exception |
if (neorv32_cpu_csr_read(CSR_MSCRATCH) == 15) { // make sure the program was executed in the right way |
test_ok(); |
} |
else { |
test_fail(); |
} |
// execute program |
tmp_a = (uint32_t)EXT_MEM_BASE; // call the dummy sub program |
asm volatile ("jalr ra, %[input_i]" : : [input_i] "r" (tmp_a)); |
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) { // make sure there was no exception |
if (neorv32_cpu_csr_read(CSR_MSCRATCH) == 15) { // make sure the program was executed in the right way |
test_ok(); |
} |
else { |
test_fail(); |
} |
} |
else { |
test_fail(); |
} |
} |
else { |
neorv32_uart_printf("skipped (not implemented)\n"); |
} |
} |
else { |
neorv32_uart_printf("skipped (on real HW)\n"); |
PRINT_STANDARD("skipped (n.a.)\n"); |
} |
|
|
//// ---------------------------------------------------------- |
//// 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"); |
//} |
// ---------------------------------------------------------- |
// 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 { |
test_fail(); |
} |
|
|
// ---------------------------------------------------------- |
// Illegal CSR access (CSR not implemented) |
// ---------------------------------------------------------- |
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++; |
|
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) { |
test_ok(); |
} |
473,7 → 465,7
// Write-access to read-only CSR |
// ---------------------------------------------------------- |
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++; |
|
491,7 → 483,7
// No "real" CSR write access (because rs1 = r0) |
// ---------------------------------------------------------- |
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++; |
|
511,37 → 503,33
// Test pending interrupt |
// ---------------------------------------------------------- |
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 |
neorv32_cpu_dint(); |
// disable global interrupts |
neorv32_cpu_dint(); |
|
// force MTIME IRQ |
neorv32_mtime_set_timecmp(0); |
// prepare MTIME IRQ |
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 |
asm volatile("nop"); |
asm volatile("nop"); |
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
asm volatile("nop"); |
|
// no more mtime interrupts |
neorv32_mtime_set_timecmp(-1); |
// no more mtime interrupts |
neorv32_mtime_set_timecmp(-1); |
|
// re-enable global interrupts |
neorv32_cpu_eint(); |
// re-enable global interrupts |
neorv32_cpu_eint(); |
|
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_MTI) { |
test_ok(); |
} |
else { |
test_fail(); |
} |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_MTI) { |
test_ok(); |
} |
else { |
neorv32_uart_printf("skipped (not implemented)\n"); |
test_fail(); |
} |
|
|
549,10 → 537,10
// Unaligned instruction address |
// ---------------------------------------------------------- |
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 |
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++; |
|
560,16 → 548,16
((void (*)(void))ADDR_UNALIGNED)(); |
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_I_MISALIGNED) { |
neorv32_uart_printf("ok\n"); |
PRINT_STANDARD("ok\n"); |
cnt_ok++; |
} |
else { |
neorv32_uart_printf("fail\n"); |
PRINT_STANDARD("fail\n"); |
cnt_fail++; |
} |
} |
else { |
neorv32_uart_printf("skipped (n.a. with C-ext)\n"); |
PRINT_STANDARD("skipped (n.a. with C-ext)\n"); |
} |
|
|
577,7 → 565,7
// Instruction access fault |
// ---------------------------------------------------------- |
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++; |
|
// call unreachable aligned address |
595,7 → 583,7
// Illegal instruction |
// ---------------------------------------------------------- |
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++; |
|
621,10 → 609,10
// Illegal compressed instruction |
// ---------------------------------------------------------- |
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 |
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++; |
|
645,7 → 633,7
} |
} |
else { |
neorv32_uart_printf("skipped (n.a. with C-ext)\n"); |
PRINT_STANDARD("skipped (n.a. with C-ext)\n"); |
} |
|
|
653,7 → 641,7
// Breakpoint instruction |
// ---------------------------------------------------------- |
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++; |
|
asm volatile("EBREAK"); |
670,11 → 658,11
// Unaligned load address |
// ---------------------------------------------------------- |
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++; |
|
// 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) { |
test_ok(); |
688,11 → 676,11
// Load access fault |
// ---------------------------------------------------------- |
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++; |
|
// 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) { |
test_ok(); |
706,7 → 694,7
// Unaligned store address |
// ---------------------------------------------------------- |
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++; |
|
// store to unaligned address |
724,7 → 712,7
// Store access fault |
// ---------------------------------------------------------- |
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++; |
|
// store to unreachable aligned address |
742,7 → 730,7
// Environment call from M-mode |
// ---------------------------------------------------------- |
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++; |
|
asm volatile("ECALL"); |
759,10 → 747,10
// Environment call from U-mode |
// ---------------------------------------------------------- |
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 |
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++; |
|
781,7 → 769,7
|
} |
else { |
neorv32_uart_printf("skipped (n.a. without U-ext)\n"); |
PRINT_STANDARD("skipped (n.a. without U-ext)\n"); |
} |
|
|
789,66 → 777,56
// Machine timer interrupt (MTIME) |
// ---------------------------------------------------------- |
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) |
neorv32_mtime_set_timecmp(-1); |
neorv32_mtime_set_time(0); |
// configure MTIME IRQ (and check overflow form low owrd to high word) |
neorv32_mtime_set_timecmp(-1); |
neorv32_mtime_set_time(0); |
|
neorv32_cpu_csr_write(CSR_MIP, 0); // clear all pending IRQs |
neorv32_cpu_csr_write(CSR_MIP, 0); // clear all pending IRQs |
|
neorv32_mtime_set_timecmp(0x0000000100000000ULL); |
neorv32_mtime_set_time( 0x00000000FFFFFFFEULL); |
neorv32_mtime_set_timecmp(0x0000000100000000ULL); |
neorv32_mtime_set_time( 0x00000000FFFFFFFEULL); |
|
// wait some time for the IRQ to trigger and arrive the CPU |
asm volatile("nop"); |
asm volatile("nop"); |
asm volatile("nop"); |
asm volatile("nop"); |
// wait some time for the IRQ to trigger and arrive the CPU |
asm volatile("nop"); |
asm volatile("nop"); |
asm volatile("nop"); |
asm volatile("nop"); |
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_MTI) { |
test_ok(); |
} |
else { |
test_fail(); |
} |
|
// no more mtime interrupts |
neorv32_mtime_set_timecmp(-1); |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_MTI) { |
test_ok(); |
} |
else { |
neorv32_uart_printf("skipped (not implemented)\n"); |
test_fail(); |
} |
|
// no more mtime interrupts |
neorv32_mtime_set_timecmp(-1); |
|
|
// ---------------------------------------------------------- |
// Machine software interrupt (MSI) via testbench |
// ---------------------------------------------------------- |
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 |
sim_irq_trigger(1 << CSR_MIE_MSIE); |
// trigger IRQ |
sim_irq_trigger(1 << CSR_MIE_MSIE); |
|
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
asm volatile("nop"); |
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
asm volatile("nop"); |
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_MSI) { |
test_ok(); |
} |
else { |
test_fail(); |
} |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_MSI) { |
test_ok(); |
} |
else { |
neorv32_uart_printf("skipped (on real HW)\n"); |
test_fail(); |
} |
|
|
856,27 → 834,22
// Machine external interrupt (MEI) via testbench |
// ---------------------------------------------------------- |
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 |
sim_irq_trigger(1 << CSR_MIE_MEIE); |
// trigger IRQ |
sim_irq_trigger(1 << CSR_MIE_MEIE); |
|
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
asm volatile("nop"); |
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
asm volatile("nop"); |
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_MEI) { |
test_ok(); |
} |
else { |
test_fail(); |
} |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_MEI) { |
test_ok(); |
} |
else { |
neorv32_uart_printf("skipped (on real HW)\n"); |
test_fail(); |
} |
|
|
884,27 → 857,22
// Non-maskable interrupt (NMI) via testbench |
// ---------------------------------------------------------- |
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 |
sim_irq_trigger(1 << 0); |
// trigger IRQ |
sim_irq_trigger(1 << 0); |
|
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
asm volatile("nop"); |
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
asm volatile("nop"); |
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_NMI) { |
test_ok(); |
} |
else { |
test_fail(); |
} |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_NMI) { |
test_ok(); |
} |
else { |
neorv32_uart_printf("skipped (on real HW)\n"); |
test_fail(); |
} |
|
|
911,10 → 879,10
// ---------------------------------------------------------- |
// Fast interrupt channel 0 (WDT) |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] FIRQ0 test (via WDT): ", cnt_test); |
if (neorv32_wdt_available()) { |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
PRINT_STANDARD("[%i] FIRQ0 test (via WDT): ", cnt_test); |
|
if (neorv32_wdt_available()) { |
cnt_test++; |
|
// enable fast interrupt |
942,25 → 910,22
// disable fast interrupt |
neorv32_cpu_irq_disable(CSR_MIE_FIRQ0E); |
} |
else { |
neorv32_uart_printf("skipped (not implemented)\n"); |
} |
|
|
// ---------------------------------------------------------- |
// Fast interrupt channel 1 (CFS) |
// ---------------------------------------------------------- |
neorv32_uart_printf("[%i] FIRQ1 test (via CFS): ", cnt_test); |
neorv32_uart_printf("skipped (not implemented)\n"); |
PRINT_STANDARD("[%i] FIRQ1 test (via CFS): ", cnt_test); |
PRINT_STANDARD("skipped (n.a.)\n"); |
|
|
// ---------------------------------------------------------- |
// Fast interrupt channel 2 (UART0.RX) |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] FIRQ2 test (via UART0.RX): ", cnt_test); |
if (neorv32_uart1_available()) { |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
PRINT_STANDARD("[%i] FIRQ2 test (via UART0.RX): ", cnt_test); |
|
if (is_simulation) { // check if this is a simulation |
cnt_test++; |
|
// enable fast interrupt |
967,26 → 932,27
neorv32_cpu_irq_enable(CSR_MIE_FIRQ2E); |
|
// wait for UART0 to finish transmitting |
while(neorv32_uart_tx_busy()); |
while(neorv32_uart0_tx_busy()); |
|
// backup current UART0 configuration |
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); |
|
// trigger UART0 RX IRQ |
// the default test bench connects UART0.TXD_O to UART0_RXD_I |
UART0_DATA = 0; // we need to access the raw HW here, since >UART0_SIM_MODE< might be active |
neorv32_uart0_putc(0); |
|
// 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 |
asm volatile("nop"); |
asm volatile("nop"); |
|
// re-enable UART0 sim_mode if it was enabled |
// restore original configuration |
UART0_CT = tmp_a; |
|
// disable fast interrupt |
999,74 → 965,77
test_fail(); |
} |
} |
else { |
neorv32_uart_printf("skipped (on real HW)\n"); |
} |
|
|
// ---------------------------------------------------------- |
// Fast interrupt channel 3 (UART0.TX) |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] FIRQ3 test (via UART0.TX): ", cnt_test); |
if (neorv32_uart0_available()) { |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
PRINT_STANDARD("[%i] FIRQ3 test (via UART0.TX): ", cnt_test); |
|
cnt_test++; |
cnt_test++; |
|
// UART0 TX interrupt enable |
neorv32_cpu_irq_enable(CSR_MIE_FIRQ3E); |
// UART0 TX interrupt enable |
neorv32_cpu_irq_enable(CSR_MIE_FIRQ3E); |
|
// wait for UART0 to finish transmitting |
while(neorv32_uart_tx_busy()); |
// wait for UART0 to finish transmitting |
while(neorv32_uart0_tx_busy()); |
|
// backup current UART0 configuration |
tmp_a = UART0_CT; |
// backup current UART0 configuration |
tmp_a = UART0_CT; |
|
// disable UART0 sim_mode if it is enabled |
UART0_CT &= ~(1 << UART_CT_SIM_MODE); |
// make sure UART is enabled |
UART0_CT |= (1 << UART_CT_EN); |
// make sure sim mode is disabled |
UART0_CT &= ~(1 << UART_CT_SIM_MODE); |
|
// trigger UART0 TX IRQ |
UART0_DATA = 0; // we need to access the raw HW here, since >UART0_SIM_MODE< might be active |
// trigger UART0 TX IRQ |
neorv32_uart0_putc(0); |
|
// wait for UART to finish transmitting |
while(neorv32_uart_tx_busy()); |
// wait for UART to finish transmitting |
while(neorv32_uart0_tx_busy()); |
|
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
asm volatile("nop"); |
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
asm volatile("nop"); |
|
// re-enable UART sim_mode if it was enabled |
UART0_CT = tmp_a; |
// restore original configuration |
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) { |
test_ok(); |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_FIRQ_3) { |
test_ok(); |
} |
else { |
test_fail(); |
} |
} |
else { |
test_fail(); |
} |
|
|
// ---------------------------------------------------------- |
// Fast interrupt channel 4 (UART1.RX) |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] FIRQ4 test (via UART1.RX): ", cnt_test); |
if (neorv32_uart1_available()) { |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
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++; |
|
// UART1 RX interrupt enable |
neorv32_cpu_irq_enable(CSR_MIE_FIRQ4E); |
|
// initialize UART1 |
UART1_CT = 0; |
tmp_a = UART0_CT; // copy configuration from UART0 |
tmp_a &= ~(1 << UART_CT_SIM_MODE); // make sure sim_mode is disabled |
UART1_CT = tmp_a; |
// backup current UART1 configuration |
tmp_a = UART1_CT; |
|
// make sure UART is enabled |
UART1_CT |= (1 << UART_CT_EN); |
// make sure sim mode is disabled |
UART1_CT &= ~(1 << UART_CT_SIM_MODE); |
|
// trigger UART1 RX IRQ |
UART1_DATA = 0; |
neorv32_uart1_putc(0); |
|
// wait for UART1 to finish transmitting |
while(neorv32_uart1_tx_busy()); |
1075,8 → 1044,8
asm volatile("nop"); |
asm volatile("nop"); |
|
// disable UART1 |
UART1_CT = 0; |
// restore original configuration |
UART1_CT = tmp_a; |
|
// disable fast interrupt |
neorv32_cpu_irq_disable(CSR_MIE_FIRQ4E); |
1088,31 → 1057,30
test_fail(); |
} |
} |
else { |
neorv32_uart_printf("skipped (not implemented)\n"); |
} |
|
|
// ---------------------------------------------------------- |
// Fast interrupt channel 5 (UART1.TX) |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] FIRQ5 test (via UART1.TX): ", cnt_test); |
if (neorv32_uart1_available()) { |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
PRINT_STANDARD("[%i] FIRQ5 test (via UART1.TX): ", cnt_test); |
|
if (neorv32_uart1_available()) { |
cnt_test++; |
|
// UART1 RX interrupt enable |
neorv32_cpu_irq_enable(CSR_MIE_FIRQ5E); |
|
// initialize UART1 |
UART1_CT = 0; |
tmp_a = UART0_CT; // copy configuration from UART0 |
tmp_a &= ~(1 << UART_CT_SIM_MODE); // make sure sim_mode is disabled |
UART1_CT = tmp_a; |
// backup current UART1 configuration |
tmp_a = UART1_CT; |
|
// make sure UART is enabled |
UART1_CT |= (1 << UART_CT_EN); |
// make sure sim mode is disabled |
UART1_CT &= ~(1 << UART_CT_SIM_MODE); |
|
// trigger UART1 TX IRQ |
UART1_DATA = 0; |
neorv32_uart1_putc(0); |
|
// wait for UART1 to finish transmitting |
while(neorv32_uart1_tx_busy()); |
1121,8 → 1089,8
asm volatile("nop"); |
asm volatile("nop"); |
|
// disable UART1 |
UART1_CT = 0; |
// restore original configuration |
UART1_CT = tmp_a; |
|
// disable fast interrupt |
neorv32_cpu_irq_disable(CSR_MIE_FIRQ5E); |
1134,18 → 1102,15
test_fail(); |
} |
} |
else { |
neorv32_uart_printf("skipped (not implemented)\n"); |
} |
|
|
// ---------------------------------------------------------- |
// Fast interrupt channel 6 (SPI) |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] FIRQ6 test (via SPI): ", cnt_test); |
if (neorv32_spi_available()) { |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
PRINT_STANDARD("[%i] FIRQ6 test (via SPI): ", cnt_test); |
|
if (neorv32_spi_available()) { |
cnt_test++; |
|
// enable fast interrupt |
1175,18 → 1140,15
// disable fast interrupt |
neorv32_cpu_irq_disable(CSR_MIE_FIRQ6E); |
} |
else { |
neorv32_uart_printf("skipped (not implemented)\n"); |
} |
|
|
// ---------------------------------------------------------- |
// Fast interrupt channel 7 (TWI) |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] FIRQ7 test (via TWI): ", cnt_test); |
if (neorv32_twi_available()) { |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
PRINT_STANDARD("[%i] FIRQ7 test (via TWI): ", cnt_test); |
|
if (neorv32_twi_available()) { |
cnt_test++; |
|
// configure TWI, fastest clock, no peripheral clock stretching |
1214,157 → 1176,143
neorv32_twi_disable(); |
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_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 |
neorv32_gpio_port_set(0); |
int xirq_err_cnt = 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_gpio_pin_change_config(0x80000000); |
neorv32_xirq_global_enable(); // enable XIRQ FIRQ |
|
// trigger pin-change IRQ by setting GPIO.out(31) |
// the testbench connects GPIO.out => GPIO.in |
neorv32_gpio_pin_set(31); |
// trigger XIRQ channel 1 and 0 |
neorv32_gpio_port_set(3); |
|
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
asm volatile("nop"); |
// wait for IRQs to arrive CPU |
asm volatile("nop"); |
asm volatile("nop"); |
asm volatile("nop"); |
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_FIRQ_8) { |
test_ok(); |
} |
else { |
test_fail(); |
} |
|
// disable GPIO pin-change IRQ |
neorv32_gpio_pin_change_config(0); |
|
// clear output port |
neorv32_gpio_port_set(0); |
neorv32_cpu_irq_disable(CSR_MIE_FIRQ8E); |
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(); |
} |
else { |
neorv32_uart_printf("skipped (not implemented)\n"); |
test_fail(); |
} |
|
neorv32_xirq_global_disable(); |
XIRQ_IER = 0; |
XIRQ_IPR = -1; |
} |
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); |
neorv32_uart_printf("skipped (not implemented)\n"); |
PRINT_STANDARD("[%i] FIRQ9 (NEOLED): skipped\n", cnt_test); |
|
|
// ---------------------------------------------------------- |
// Fast interrupt channel 10..15 (SoC fast IRQ 0..5) |
// Fast interrupt channel 10 & 11 (SLINK) |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] FIRQ10..15 (SoC fast IRQ 0..5; via testbench): ", cnt_test); |
if (neorv32_slink_available()) { |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
PRINT_STANDARD("[%i] FIRQ10 & 11 (SLINK): ", cnt_test); |
|
if (is_simulation) { // check if this is a simulation |
|
cnt_test++; |
|
// enable SOC FIRQs |
for (id=CSR_MIE_FIRQ10E; id<=CSR_MIE_FIRQ15E; id++) { |
neorv32_cpu_irq_enable(id); |
// enable SLINK |
neorv32_slink_enable(); |
|
// 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 |
neorv32_cpu_dint(); // do not fire yet! |
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)); |
// get single data word from link 0 |
uint32_t slink_rx_data; |
if (neorv32_slink_rx0_nonblocking(&slink_rx_data)) { |
tmp_a++; // receiving failed |
} |
|
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
asm volatile("nop"); |
|
// make sure all SoC FIRQs have been triggered |
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 (neorv32_cpu_csr_read(CSR_MIP) == tmp_a) { |
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(); |
} |
else { |
test_fail(); |
} |
tmp_b = neorv32_cpu_csr_read(CSR_MCAUSE); |
if (((tmp_b == TRAP_CODE_FIRQ_10) || (tmp_b == TRAP_CODE_FIRQ_11)) && // right trap code |
(tmp_a == 0) && // local error counter = 0 |
(slink_rx_data == 0xA1B2C3D4)) { // correct data read-back |
test_ok(); |
} |
else { |
test_fail(); |
} |
|
// disable SOC FIRQs |
for (id=CSR_MIE_FIRQ10E; id<=CSR_MIE_FIRQ15E; id++) { |
neorv32_cpu_irq_disable(id); |
} |
// shutdown SLINK |
neorv32_slink_disable(); |
} |
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 |
// ---------------------------------------------------------- |
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 |
neorv32_mtime_set_timecmp(neorv32_mtime_get_time() + 1000); |
// program wake-up timer |
neorv32_mtime_set_timecmp(neorv32_mtime_get_time() + 1000); |
|
// put CPU into sleep mode |
asm volatile ("wfi"); |
// put CPU into sleep mode |
asm volatile ("wfi"); |
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) != TRAP_CODE_MTI) { |
test_fail(); |
} |
else { |
test_ok(); |
} |
|
// no more mtime interrupts |
neorv32_mtime_set_timecmp(-1); |
if (neorv32_cpu_csr_read(CSR_MCAUSE) != TRAP_CODE_MTI) { |
test_fail(); |
} |
else { |
neorv32_uart_printf("skipped (not implemented)\n"); |
test_ok(); |
} |
|
// no more mtime interrupts |
neorv32_mtime_set_timecmp(-1); |
|
|
// ---------------------------------------------------------- |
// Test invalid CSR access in user mode |
// ---------------------------------------------------------- |
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 |
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++; |
|
1375,13 → 1323,12
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 (tmp_a == 0) { // make sure user-level code CANNOT read machine-level CSR content! |
test_ok(); |
} |
else { |
test_fail(); |
} |
test_ok(); |
} |
else { |
test_fail(); |
1389,7 → 1336,7
|
} |
else { |
neorv32_uart_printf("skipped (n.a. without U-ext)\n"); |
PRINT_STANDARD("skipped (n.a. without U-ext)\n"); |
} |
|
|
1397,7 → 1344,7
// Test RTE debug trap handler |
// ---------------------------------------------------------- |
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++; |
|
1407,13 → 1354,13
// trigger illegal instruction exception |
neorv32_cpu_csr_read(0xfff); // CSR not available |
|
neorv32_uart_printf(" "); |
PRINT_STANDARD(" "); |
if (neorv32_cpu_csr_read(CSR_MCAUSE) != 0) { |
test_ok(); |
} |
else { |
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 |
1423,7 → 1370,7
// ---------------------------------------------------------- |
// 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 |
if (neorv32_cpu_pmp_get_num_regions() != 0) { |
1433,14 → 1380,14
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
cnt_test++; |
|
// find out mininmal region size (granulartiy) |
// find out minimal region size (granularity) |
tmp_b = neorv32_cpu_pmp_get_granularity(); |
|
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 |
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)) { |
test_ok(); |
1451,7 → 1398,7
|
|
// ------ 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++; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
|
1462,13 → 1409,13
} |
|
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"); |
|
test_fail(); |
} |
else { |
// switch back to machine mode (if not allready) |
// switch back to machine mode (if not already) |
asm volatile ("ecall"); |
|
test_ok(); |
1475,8 → 1422,8
} |
|
|
// ------ LOAD: should work ------ |
neorv32_uart_printf("[%i] PMP: U-mode [!X,!W,R] read: ", cnt_test); |
// ------ LOAD: should fail ------ |
PRINT_STANDARD("[%i] PMP: U-mode read: ", cnt_test); |
cnt_test++; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
|
1483,17 → 1430,21
// switch to user mode (hart will be back in MACHINE mode when trap handler returns) |
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) { |
// switch back to machine mode (if not allready) |
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) { |
// switch back to machine mode (if not already) |
asm volatile ("ecall"); |
|
test_ok(); |
} |
else { |
// switch back to machine mode (if not allready) |
// switch back to machine mode (if not already) |
asm volatile ("ecall"); |
|
test_fail(); |
1501,7 → 1452,7
|
|
// ------ 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++; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
|
1508,17 → 1459,17
// switch to user mode (hart will be back in MACHINE mode when trap handler returns) |
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) { |
// switch back to machine mode (if not allready) |
// switch back to machine mode (if not already) |
asm volatile ("ecall"); |
|
test_ok(); |
} |
else { |
// switch back to machine mode (if not allready) |
// switch back to machine mode (if not already) |
asm volatile ("ecall"); |
|
test_fail(); |
1526,7 → 1477,7
|
|
// ------ 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++; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
|
1548,7 → 1499,7
|
} |
else { |
neorv32_uart_printf("skipped (not implemented)\n"); |
PRINT_STANDARD("skipped (n.a.)\n"); |
} |
|
|
1556,11 → 1507,11
// Test atomic LR/SC operation - should succeed |
// ---------------------------------------------------------- |
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 |
// 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++; |
|
1582,10 → 1533,10
} |
} |
else { |
neorv32_uart_printf("skipped (not implemented)\n"); |
PRINT_STANDARD("skipped (n.a.)\n"); |
} |
#else |
neorv32_uart_printf("skipped (not implemented)\n"); |
PRINT_STANDARD("skipped (n.a.)\n"); |
#endif |
|
|
1593,11 → 1544,11
// Test atomic LR/SC operation - should fail |
// ---------------------------------------------------------- |
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 |
// 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++; |
|
1618,10 → 1569,10
} |
} |
else { |
neorv32_uart_printf("skipped (not implemented)\n"); |
PRINT_STANDARD("skipped (n.a.)\n"); |
} |
#else |
neorv32_uart_printf("skipped (not implemented)\n"); |
PRINT_STANDARD("skipped (n.a.)\n"); |
#endif |
|
|
1629,11 → 1580,11
// Test atomic LR/SC operation - should fail |
// ---------------------------------------------------------- |
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 |
// 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++; |
|
1654,10 → 1605,10
} |
} |
else { |
neorv32_uart_printf("skipped (on real HW)\n"); |
PRINT_STANDARD("skipped (on real HW)\n"); |
} |
#else |
neorv32_uart_printf("skipped (not implemented)\n"); |
PRINT_STANDARD("skipped (n.a.)\n"); |
#endif |
|
|
1665,39 → 1616,38
// HPM reports |
// ---------------------------------------------------------- |
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); |
neorv32_uart_printf("#IR - Total number of 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" |
neorv32_uart_printf("#CY - Total number of clk cyc.: %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)); |
neorv32_uart_printf("#04 - I-fetch wait cyc.: %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)); |
neorv32_uart_printf("#06 - Multi-cyc. ALU wait cyc.: %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)); |
neorv32_uart_printf("#08 - Store operations: %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)); |
neorv32_uart_printf("#10 - Unconditional 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)); |
neorv32_uart_printf("#12 - Cond. branches (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)); |
neorv32_uart_printf("#14 - Illegal operations: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER14)); |
PRINT_STANDARD("\n\n-- HPM reports LOW (%u HPMs available) --\n", num_hpm_cnts_global); |
PRINT_STANDARD("#IR - Instr.: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_INSTRET)); // = "HPM_0" |
//PRINT_STANDARD("#TM - Time: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_TIME)); // = "HPM_1" |
PRINT_STANDARD("#CY - CLKs: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_CYCLE)); // = "HPM_2" |
PRINT_STANDARD("#03 - Compr.: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER3)); |
PRINT_STANDARD("#04 - IF wait: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER4)); |
PRINT_STANDARD("#05 - II wait: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER5)); |
PRINT_STANDARD("#06 - ALU wait: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER6)); |
PRINT_STANDARD("#07 - Loads: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER7)); |
PRINT_STANDARD("#08 - Stores: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER8)); |
PRINT_STANDARD("#09 - MEM wait: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER9)); |
PRINT_STANDARD("#10 - Jumps: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER10)); |
PRINT_STANDARD("#11 - Branches: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER11)); |
PRINT_STANDARD("#12 - Taken: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER12)); |
PRINT_STANDARD("#13 - Traps: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER13)); |
PRINT_STANDARD("#14 - Illegals: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER14)); |
|
|
// ---------------------------------------------------------- |
// 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 |
if (cnt_fail == 0) { |
neorv32_uart_printf("%c[1m[CPU TEST COMPLETED SUCCESSFULLY!]%c[0m\n", 27, 27); |
return 0; |
PRINT_STANDARD("%c[1m[CPU TEST COMPLETED SUCCESSFULLY!]%c[0m\n", 27, 27); |
} |
else { |
neorv32_uart_printf("%c[1m[CPU TEST FAILED!]%c[0m\n", 27, 27); |
return 1; |
PRINT_STANDARD("%c[1m[CPU TEST FAILED!]%c[0m\n", 27, 27); |
} |
|
return (int)cnt_fail; // return error counter for after-main handler |
} |
|
|
1724,20 → 1674,57
|
|
/**********************************************************************//** |
* 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 |
**************************************************************************/ |
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++; |
} |
|
|
/**********************************************************************//** |
* 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) { |
|
neorv32_uart_printf("%c[1m[FAILED]%c[0m\n", 27, 27); |
PRINT_CRITICAL("%c[1m[FAIL]%c[0m\n", 27, 27); |
cnt_fail++; |
} |
|
|
/**********************************************************************//** |
* "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; |
} |
/image_gen/image_gen.cpp
58,7 → 58,7
|
FILE *input, *output; |
unsigned char buffer[4]; |
char tmp_string[512]; |
char tmp_string[1024]; |
uint32_t tmp = 0, size = 0, checksum = 0; |
unsigned int i = 0; |
int option = 0; |
89,7 → 89,13
return 3; |
} |
|
// get input file size |
fseek(input, 0L, SEEK_END); |
unsigned int input_size = (unsigned int)ftell(input); |
rewind(input); |
unsigned int input_words = input_size / 4; |
|
|
// ------------------------------------------------------------ |
// Get size of application (in bytes) |
// ------------------------------------------------------------ |
174,14 → 180,17
// header |
sprintf(tmp_string, "-- The NEORV32 RISC-V Processor, https://github.com/stnolting/neorv32\n" |
"-- Auto-generated memory init file (for APPLICATION) from source file <%s/%s>\n" |
"-- Size: %lu bytes\n" |
"\n" |
"library ieee;\n" |
"use ieee.std_logic_1164.all;\n" |
"\n" |
"library neorv32;\n" |
"use neorv32.neorv32_package.all;\n" |
"\n" |
"package neorv32_application_image is\n" |
"\n" |
" type application_init_image_t is array (0 to %lu) of std_ulogic_vector(31 downto 0);\n" |
" constant application_init_image : application_init_image_t := (\n", argv[4], argv[2], raw_exe_size/4); |
" constant application_init_image : mem32_t := (\n", argv[4], argv[2], raw_exe_size); |
fputs(tmp_string, output); |
|
// data |
190,12 → 199,33
buffer[2] = 0; |
buffer[3] = 0; |
i = 0; |
while(fread(&buffer, sizeof(unsigned char), 4, input) != 0) { |
|
while (i < (input_words-1)) { |
if (fread(&buffer, sizeof(unsigned char), 4, input) != 0) { |
tmp = (uint32_t)(buffer[0] << 0); |
tmp |= (uint32_t)(buffer[1] << 8); |
tmp |= (uint32_t)(buffer[2] << 16); |
tmp |= (uint32_t)(buffer[3] << 24); |
sprintf(tmp_string, " %08d => x\"%08x\",\n", i, (unsigned int)tmp); |
fputs(tmp_string, output); |
buffer[0] = 0; |
buffer[1] = 0; |
buffer[2] = 0; |
buffer[3] = 0; |
i++; |
} |
else { |
printf("Unexpected input file end!\n"); |
break; |
} |
} |
|
if (fread(&buffer, sizeof(unsigned char), 4, input) != 0) { |
tmp = (uint32_t)(buffer[0] << 0); |
tmp |= (uint32_t)(buffer[1] << 8); |
tmp |= (uint32_t)(buffer[2] << 16); |
tmp |= (uint32_t)(buffer[3] << 24); |
sprintf(tmp_string, " %08d => x\"%08x\",\n", i, tmp); |
sprintf(tmp_string, " %08d => x\"%08x\"\n", i, (unsigned int)tmp); |
fputs(tmp_string, output); |
buffer[0] = 0; |
buffer[1] = 0; |
203,10 → 233,10
buffer[3] = 0; |
i++; |
} |
else { |
printf("Unexpected input file end!\n"); |
} |
|
sprintf(tmp_string, " others => x\"00000000\"\n"); |
fputs(tmp_string, output); |
|
// end |
sprintf(tmp_string, " );\n" |
"\n" |
223,28 → 253,52
// header |
sprintf(tmp_string, "-- The NEORV32 RISC-V Processor, https://github.com/stnolting/neorv32\n" |
"-- Auto-generated memory init file (for BOOTLOADER) from source file <%s/%s>\n" |
"-- Size: %lu bytes\n" |
"\n" |
"library ieee;\n" |
"use ieee.std_logic_1164.all;\n" |
"\n" |
"library neorv32;\n" |
"use neorv32.neorv32_package.all;\n" |
"\n" |
"package neorv32_bootloader_image is\n" |
"\n" |
" type bootloader_init_image_t is array (0 to %lu) of std_ulogic_vector(31 downto 0);\n" |
" constant bootloader_init_image : bootloader_init_image_t := (\n", argv[4], argv[2], raw_exe_size/4); |
" constant bootloader_init_image : mem32_t := (\n", argv[4], argv[2], raw_exe_size); |
fputs(tmp_string, output); |
|
// data |
// data |
buffer[0] = 0; |
buffer[1] = 0; |
buffer[2] = 0; |
buffer[3] = 0; |
i = 0; |
while(fread(&buffer, sizeof(unsigned char), 4, input) != 0) { |
|
while (i < (input_words-1)) { |
if (fread(&buffer, sizeof(unsigned char), 4, input) != 0) { |
tmp = (uint32_t)(buffer[0] << 0); |
tmp |= (uint32_t)(buffer[1] << 8); |
tmp |= (uint32_t)(buffer[2] << 16); |
tmp |= (uint32_t)(buffer[3] << 24); |
sprintf(tmp_string, " %08d => x\"%08x\",\n", i, (unsigned int)tmp); |
fputs(tmp_string, output); |
buffer[0] = 0; |
buffer[1] = 0; |
buffer[2] = 0; |
buffer[3] = 0; |
i++; |
} |
else { |
printf("Unexpected input file end!\n"); |
break; |
} |
} |
|
if (fread(&buffer, sizeof(unsigned char), 4, input) != 0) { |
tmp = (uint32_t)(buffer[0] << 0); |
tmp |= (uint32_t)(buffer[1] << 8); |
tmp |= (uint32_t)(buffer[2] << 16); |
tmp |= (uint32_t)(buffer[3] << 24); |
sprintf(tmp_string, " %08d => x\"%08x\",\n", i, tmp); |
sprintf(tmp_string, " %08d => x\"%08x\"\n", i, (unsigned int)tmp); |
fputs(tmp_string, output); |
buffer[0] = 0; |
buffer[1] = 0; |
252,10 → 306,10
buffer[3] = 0; |
i++; |
} |
else { |
printf("Unexpected input file end!\n"); |
} |
|
sprintf(tmp_string, " others => x\"00000000\"\n"); |
fputs(tmp_string, output); |
|
// end |
sprintf(tmp_string, " );\n" |
"\n" |
/lib/include/neorv32_nco.h
File deleted
/lib/include/neorv32.h
43,6 → 43,11
#ifndef neorv32_h |
#define neorv32_h |
|
#ifdef __cplusplus |
extern "C" { |
#endif |
|
|
// Standard libraries |
#include <stdint.h> |
#include <inttypes.h> |
53,9 → 58,9
* Available CPU Control and Status Registers (CSRs) |
**************************************************************************/ |
enum NEORV32_CSR_enum { |
CSR_FFLAGS = 0x001, /**< 0x001 - fflags (r/w): Floating-point accrued exception flags */ |
CSR_FRM = 0x002, /**< 0x002 - frm (r/w): Floating-point dynamic rounding mode */ |
CSR_FCSR = 0x003, /**< 0x003 - fcsr (r/w): Floating-point control/staturs register (frm + fflags) */ |
CSR_FFLAGS = 0x001, /**< 0x001 - fflags (r/w): Floating-point accrued exception flags */ |
CSR_FRM = 0x002, /**< 0x002 - frm (r/w): Floating-point dynamic rounding mode */ |
CSR_FCSR = 0x003, /**< 0x003 - fcsr (r/w): Floating-point control/staturs register (frm + fflags) */ |
|
CSR_MSTATUS = 0x300, /**< 0x300 - mstatus (r/w): Machine status register */ |
CSR_MISA = 0x301, /**< 0x301 - misa (r/-): CPU ISA and extensions (read-only in NEORV32) */ |
183,8 → 188,8
CSR_PMPADDR62 = 0x3ee, /**< 0x3ee - pmpaddr62 (r/w): Physical memory protection address register 62 */ |
CSR_PMPADDR63 = 0x3ef, /**< 0x3ef - pmpaddr63 (r/w): Physical memory protection address register 63 */ |
|
CSR_MCYCLE = 0xb00, /**< 0xb00 - mcycle (r/w): Machine cycle counter low word */ |
CSR_MINSTRET = 0xb02, /**< 0xb02 - minstret (r/w): Machine instructions-retired counter low word */ |
CSR_MCYCLE = 0xb00, /**< 0xb00 - mcycle (r/w): Machine cycle counter low word */ |
CSR_MINSTRET = 0xb02, /**< 0xb02 - minstret (r/w): Machine instructions-retired counter low word */ |
|
CSR_MHPMCOUNTER3 = 0xb03, /**< 0xb03 - mhpmcounter3 (r/w): Machine hardware performance monitor 3 counter low word */ |
CSR_MHPMCOUNTER4 = 0xb04, /**< 0xb04 - mhpmcounter4 (r/w): Machine hardware performance monitor 4 counter low word */ |
216,8 → 221,8
CSR_MHPMCOUNTER30 = 0xb1e, /**< 0xb1e - mhpmcounter30 (r/w): Machine hardware performance monitor 30 counter low word */ |
CSR_MHPMCOUNTER31 = 0xb1f, /**< 0xb1f - mhpmcounter31 (r/w): Machine hardware performance monitor 31 counter low word */ |
|
CSR_MCYCLEH = 0xb80, /**< 0xb80 - mcycleh (r/w): Machine cycle counter high word */ |
CSR_MINSTRETH = 0xb82, /**< 0xb82 - minstreth (r/w): Machine instructions-retired counter high word */ |
CSR_MCYCLEH = 0xb80, /**< 0xb80 - mcycleh (r/w): Machine cycle counter high word */ |
CSR_MINSTRETH = 0xb82, /**< 0xb82 - minstreth (r/w): Machine instructions-retired counter high word */ |
|
CSR_MHPMCOUNTER3H = 0xb83, /**< 0xb83 - mhpmcounter3h (r/w): Machine hardware performance monitor 3 counter high word */ |
CSR_MHPMCOUNTER4H = 0xb84, /**< 0xb84 - mhpmcounter4h (r/w): Machine hardware performance monitor 4 counter high word */ |
249,74 → 254,14
CSR_MHPMCOUNTER30H = 0xb9e, /**< 0xb9e - mhpmcounter30h (r/w): Machine hardware performance monitor 30 counter high word */ |
CSR_MHPMCOUNTER31H = 0xb9f, /**< 0xb9f - mhpmcounter31h (r/w): Machine hardware performance monitor 31 counter high word */ |
|
CSR_CYCLE = 0xc00, /**< 0xc00 - cycle (r/-): Cycle counter low word (from MCYCLE) */ |
CSR_TIME = 0xc01, /**< 0xc01 - time (r/-): Timer low word (from MTIME.TIME_LO) */ |
CSR_INSTRET = 0xc02, /**< 0xc02 - instret (r/-): Instructions-retired counter low word (from MINSTRET) */ |
CSR_CYCLE = 0xc00, /**< 0xc00 - cycle (r/-): Cycle counter low word (from MCYCLE) */ |
CSR_TIME = 0xc01, /**< 0xc01 - time (r/-): Timer low word (from MTIME.TIME_LO) */ |
CSR_INSTRET = 0xc02, /**< 0xc02 - instret (r/-): Instructions-retired counter low word (from MINSTRET) */ |
|
CSR_HPMCOUNTER3 = 0xc03, /**< 0xc03 - hpmcounter3 (r/w): Hardware performance monitor 3 counter low word */ |
CSR_HPMCOUNTER4 = 0xc04, /**< 0xc04 - hpmcounter4 (r/w): Hardware performance monitor 4 counter low word */ |
CSR_HPMCOUNTER5 = 0xc05, /**< 0xc05 - hpmcounter5 (r/w): Hardware performance monitor 5 counter low word */ |
CSR_HPMCOUNTER6 = 0xc06, /**< 0xc06 - hpmcounter6 (r/w): Hardware performance monitor 6 counter low word */ |
CSR_HPMCOUNTER7 = 0xc07, /**< 0xc07 - hpmcounter7 (r/w): Hardware performance monitor 7 counter low word */ |
CSR_HPMCOUNTER8 = 0xc08, /**< 0xc08 - hpmcounter8 (r/w): Hardware performance monitor 8 counter low word */ |
CSR_HPMCOUNTER9 = 0xc09, /**< 0xc09 - hpmcounter9 (r/w): Hardware performance monitor 9 counter low word */ |
CSR_HPMCOUNTER10 = 0xc0a, /**< 0xc0a - hpmcounter10 (r/w): Hardware performance monitor 10 counter low word */ |
CSR_HPMCOUNTER11 = 0xc0b, /**< 0xc0b - hpmcounter11 (r/w): Hardware performance monitor 11 counter low word */ |
CSR_HPMCOUNTER12 = 0xc0c, /**< 0xc0c - hpmcounter12 (r/w): Hardware performance monitor 12 counter low word */ |
CSR_HPMCOUNTER13 = 0xc0d, /**< 0xc0d - hpmcounter13 (r/w): Hardware performance monitor 13 counter low word */ |
CSR_HPMCOUNTER14 = 0xc0e, /**< 0xc0e - hpmcounter14 (r/w): Hardware performance monitor 14 counter low word */ |
CSR_HPMCOUNTER15 = 0xc0f, /**< 0xc0f - hpmcounter15 (r/w): Hardware performance monitor 15 counter low word */ |
CSR_HPMCOUNTER16 = 0xc10, /**< 0xc10 - hpmcounter16 (r/w): Hardware performance monitor 16 counter low word */ |
CSR_HPMCOUNTER17 = 0xc11, /**< 0xc11 - hpmcounter17 (r/w): Hardware performance monitor 17 counter low word */ |
CSR_HPMCOUNTER18 = 0xc12, /**< 0xc12 - hpmcounter18 (r/w): Hardware performance monitor 18 counter low word */ |
CSR_HPMCOUNTER19 = 0xc13, /**< 0xc13 - hpmcounter19 (r/w): Hardware performance monitor 19 counter low word */ |
CSR_HPMCOUNTER20 = 0xc14, /**< 0xc14 - hpmcounter20 (r/w): Hardware performance monitor 20 counter low word */ |
CSR_HPMCOUNTER21 = 0xc15, /**< 0xc15 - hpmcounter21 (r/w): Hardware performance monitor 21 counter low word */ |
CSR_HPMCOUNTER22 = 0xc16, /**< 0xc16 - hpmcounter22 (r/w): Hardware performance monitor 22 counter low word */ |
CSR_HPMCOUNTER23 = 0xc17, /**< 0xc17 - hpmcounter23 (r/w): Hardware performance monitor 23 counter low word */ |
CSR_HPMCOUNTER24 = 0xc18, /**< 0xc18 - hpmcounter24 (r/w): Hardware performance monitor 24 counter low word */ |
CSR_HPMCOUNTER25 = 0xc19, /**< 0xc19 - hpmcounter25 (r/w): Hardware performance monitor 25 counter low word */ |
CSR_HPMCOUNTER26 = 0xc1a, /**< 0xc1a - hpmcounter26 (r/w): Hardware performance monitor 26 counter low word */ |
CSR_HPMCOUNTER27 = 0xc1b, /**< 0xc1b - hpmcounter27 (r/w): Hardware performance monitor 27 counter low word */ |
CSR_HPMCOUNTER28 = 0xc1c, /**< 0xc1c - hpmcounter28 (r/w): Hardware performance monitor 28 counter low word */ |
CSR_HPMCOUNTER29 = 0xc1d, /**< 0xc1d - hpmcounter29 (r/w): Hardware performance monitor 29 counter low word */ |
CSR_HPMCOUNTER30 = 0xc1e, /**< 0xc1e - hpmcounter30 (r/w): Hardware performance monitor 30 counter low word */ |
CSR_HPMCOUNTER31 = 0xc1f, /**< 0xc1f - hpmcounter31 (r/w): Hardware performance monitor 31 counter low word */ |
CSR_CYCLEH = 0xc80, /**< 0xc80 - cycleh (r/-): Cycle counter high word (from MCYCLEH) */ |
CSR_TIMEH = 0xc81, /**< 0xc81 - timeh (r/-): Timer high word (from MTIME.TIME_HI) */ |
CSR_INSTRETH = 0xc82, /**< 0xc82 - instreth (r/-): Instructions-retired counter high word (from MINSTRETH) */ |
|
CSR_CYCLEH = 0xc80, /**< 0xc80 - cycleh (r/-): Cycle counter high word (from MCYCLEH) */ |
CSR_TIMEH = 0xc81, /**< 0xc81 - timeh (r/-): Timer high word (from MTIME.TIME_HI) */ |
CSR_INSTRETH = 0xc82, /**< 0xc82 - instreth (r/-): Instructions-retired counter high word (from MINSTRETH) */ |
|
CSR_HPMCOUNTER3H = 0xc83, /**< 0xc83 - hpmcounter3h (r/w): Hardware performance monitor 3 counter high word */ |
CSR_HPMCOUNTER4H = 0xc84, /**< 0xc84 - hpmcounter4h (r/w): Hardware performance monitor 4 counter high word */ |
CSR_HPMCOUNTER5H = 0xc85, /**< 0xc85 - hpmcounter5h (r/w): Hardware performance monitor 5 counter high word */ |
CSR_HPMCOUNTER6H = 0xc86, /**< 0xc86 - hpmcounter6h (r/w): Hardware performance monitor 6 counter high word */ |
CSR_HPMCOUNTER7H = 0xc87, /**< 0xc87 - hpmcounter7h (r/w): Hardware performance monitor 7 counter high word */ |
CSR_HPMCOUNTER8H = 0xc88, /**< 0xc88 - hpmcounter8h (r/w): Hardware performance monitor 8 counter high word */ |
CSR_HPMCOUNTER9H = 0xc89, /**< 0xc89 - hpmcounter9h (r/w): Hardware performance monitor 9 counter high word */ |
CSR_HPMCOUNTER10H = 0xc8a, /**< 0xc8a - hpmcounter10h (r/w): Hardware performance monitor 10 counter high word */ |
CSR_HPMCOUNTER11H = 0xc8b, /**< 0xc8b - hpmcounter11h (r/w): Hardware performance monitor 11 counter high word */ |
CSR_HPMCOUNTER12H = 0xc8c, /**< 0xc8c - hpmcounter12h (r/w): Hardware performance monitor 12 counter high word */ |
CSR_HPMCOUNTER13H = 0xc8d, /**< 0xc8d - hpmcounter13h (r/w): Hardware performance monitor 13 counter high word */ |
CSR_HPMCOUNTER14H = 0xc8e, /**< 0xc8e - hpmcounter14h (r/w): Hardware performance monitor 14 counter high word */ |
CSR_HPMCOUNTER15H = 0xc8f, /**< 0xc8f - hpmcounter15h (r/w): Hardware performance monitor 15 counter high word */ |
CSR_HPMCOUNTER16H = 0xc90, /**< 0xc90 - hpmcounter16h (r/w): Hardware performance monitor 16 counter high word */ |
CSR_HPMCOUNTER17H = 0xc91, /**< 0xc91 - hpmcounter17h (r/w): Hardware performance monitor 17 counter high word */ |
CSR_HPMCOUNTER18H = 0xc92, /**< 0xc92 - hpmcounter18h (r/w): Hardware performance monitor 18 counter high word */ |
CSR_HPMCOUNTER19H = 0xc93, /**< 0xc93 - hpmcounter19h (r/w): Hardware performance monitor 19 counter high word */ |
CSR_HPMCOUNTER20H = 0xc94, /**< 0xc94 - hpmcounter20h (r/w): Hardware performance monitor 20 counter high word */ |
CSR_HPMCOUNTER21H = 0xc95, /**< 0xc95 - hpmcounter21h (r/w): Hardware performance monitor 21 counter high word */ |
CSR_HPMCOUNTER22H = 0xc96, /**< 0xc96 - hpmcounter22h (r/w): Hardware performance monitor 22 counter high word */ |
CSR_HPMCOUNTER23H = 0xc97, /**< 0xc97 - hpmcounter23h (r/w): Hardware performance monitor 23 counter high word */ |
CSR_HPMCOUNTER24H = 0xc98, /**< 0xc98 - hpmcounter24h (r/w): Hardware performance monitor 24 counter high word */ |
CSR_HPMCOUNTER25H = 0xc99, /**< 0xc99 - hpmcounter25h (r/w): Hardware performance monitor 25 counter high word */ |
CSR_HPMCOUNTER26H = 0xc9a, /**< 0xc9a - hpmcounter26h (r/w): Hardware performance monitor 26 counter high word */ |
CSR_HPMCOUNTER27H = 0xc9b, /**< 0xc9b - hpmcounter27h (r/w): Hardware performance monitor 27 counter high word */ |
CSR_HPMCOUNTER28H = 0xc9c, /**< 0xc9c - hpmcounter28h (r/w): Hardware performance monitor 28 counter high word */ |
CSR_HPMCOUNTER29H = 0xc9d, /**< 0xc9d - hpmcounter29h (r/w): Hardware performance monitor 29 counter high word */ |
CSR_HPMCOUNTER30H = 0xc9e, /**< 0xc9e - hpmcounter30h (r/w): Hardware performance monitor 30 counter high word */ |
CSR_HPMCOUNTER31H = 0xc9f, /**< 0xc9f - hpmcounter31h (r/w): Hardware performance monitor 31 counter high word */ |
|
CSR_MVENDORID = 0xf11, /**< 0xf11 - mvendorid (r/-): Vendor ID */ |
CSR_MARCHID = 0xf12, /**< 0xf12 - marchid (r/-): Architecture ID */ |
CSR_MIMPID = 0xf13, /**< 0xf13 - mimpid (r/-): Implementation ID/version */ |
341,39 → 286,9
* CPU <b>mcounteren</b> CSR (r/w): Machine counter enable (RISC-V spec.) |
**************************************************************************/ |
enum NEORV32_CSR_MCOUNTEREN_enum { |
CSR_MCOUNTEREN_CY = 0, /**< CPU mcounteren CSR (0): CY - Allow access to cycle[h] CSRs from U-mode when set (r/w) */ |
CSR_MCOUNTEREN_TM = 1, /**< CPU mcounteren CSR (1): TM - Allow access to time[h] CSRs from U-mode when set (r/w) */ |
CSR_MCOUNTEREN_IR = 2, /**< CPU mcounteren CSR (2): IR - Allow access to instret[h] CSRs from U-mode when set (r/w) */ |
|
CSR_MCOUNTEREN_HPM3 = 3, /**< CPU mcounteren CSR (3): HPM3 - Allow access to hpmcnt3[h] CSRs from U-mode when set (r/w) */ |
CSR_MCOUNTEREN_HPM4 = 4, /**< CPU mcounteren CSR (4): HPM4 - Allow access to hpmcnt4[h] CSRs from U-mode when set (r/w) */ |
CSR_MCOUNTEREN_HPM5 = 5, /**< CPU mcounteren CSR (5): HPM5 - Allow access to hpmcnt5[h] CSRs from U-mode when set (r/w) */ |
CSR_MCOUNTEREN_HPM6 = 6, /**< CPU mcounteren CSR (6): HPM6 - Allow access to hpmcnt6[h] CSRs from U-mode when set (r/w) */ |
CSR_MCOUNTEREN_HPM7 = 7, /**< CPU mcounteren CSR (7): HPM7 - Allow access to hpmcnt7[h] CSRs from U-mode when set (r/w) */ |
CSR_MCOUNTEREN_HPM8 = 8, /**< CPU mcounteren CSR (8): HPM8 - Allow access to hpmcnt8[h] CSRs from U-mode when set (r/w) */ |
CSR_MCOUNTEREN_HPM9 = 9, /**< CPU mcounteren CSR (9): HPM9 - Allow access to hpmcnt9[h] CSRs from U-mode when set (r/w) */ |
CSR_MCOUNTEREN_HPM10 = 10, /**< CPU mcounteren CSR (10): HPM10 - Allow access to hpmcnt10[h] CSRs from U-mode when set (r/w) */ |
CSR_MCOUNTEREN_HPM11 = 11, /**< CPU mcounteren CSR (11): HPM11 - Allow access to hpmcnt11[h] CSRs from U-mode when set (r/w) */ |
CSR_MCOUNTEREN_HPM12 = 12, /**< CPU mcounteren CSR (12): HPM12 - Allow access to hpmcnt12[h] CSRs from U-mode when set (r/w) */ |
CSR_MCOUNTEREN_HPM13 = 13, /**< CPU mcounteren CSR (13): HPM13 - Allow access to hpmcnt13[h] CSRs from U-mode when set (r/w) */ |
CSR_MCOUNTEREN_HPM14 = 14, /**< CPU mcounteren CSR (14): HPM14 - Allow access to hpmcnt14[h] CSRs from U-mode when set (r/w) */ |
CSR_MCOUNTEREN_HPM15 = 15, /**< CPU mcounteren CSR (15): HPM15 - Allow access to hpmcnt15[h] CSRs from U-mode when set (r/w) */ |
CSR_MCOUNTEREN_HPM16 = 16, /**< CPU mcounteren CSR (16): HPM16 - Allow access to hpmcnt16[h] CSRs from U-mode when set (r/w) */ |
CSR_MCOUNTEREN_HPM17 = 17, /**< CPU mcounteren CSR (17): HPM17 - Allow access to hpmcnt17[h] CSRs from U-mode when set (r/w) */ |
CSR_MCOUNTEREN_HPM18 = 18, /**< CPU mcounteren CSR (18): HPM18 - Allow access to hpmcnt18[h] CSRs from U-mode when set (r/w) */ |
CSR_MCOUNTEREN_HPM19 = 19, /**< CPU mcounteren CSR (19): HPM19 - Allow access to hpmcnt19[h] CSRs from U-mode when set (r/w) */ |
CSR_MCOUNTEREN_HPM20 = 20, /**< CPU mcounteren CSR (20): HPM20 - Allow access to hpmcnt20[h] CSRs from U-mode when set (r/w) */ |
CSR_MCOUNTEREN_HPM21 = 21, /**< CPU mcounteren CSR (21): HPM21 - Allow access to hpmcnt21[h] CSRs from U-mode when set (r/w) */ |
CSR_MCOUNTEREN_HPM22 = 22, /**< CPU mcounteren CSR (22): HPM22 - Allow access to hpmcnt22[h] CSRs from U-mode when set (r/w) */ |
CSR_MCOUNTEREN_HPM23 = 23, /**< CPU mcounteren CSR (23): HPM23 - Allow access to hpmcnt23[h] CSRs from U-mode when set (r/w) */ |
CSR_MCOUNTEREN_HPM24 = 24, /**< CPU mcounteren CSR (24): HPM24 - Allow access to hpmcnt24[h] CSRs from U-mode when set (r/w) */ |
CSR_MCOUNTEREN_HPM25 = 25, /**< CPU mcounteren CSR (25): HPM25 - Allow access to hpmcnt25[h] CSRs from U-mode when set (r/w) */ |
CSR_MCOUNTEREN_HPM26 = 26, /**< CPU mcounteren CSR (26): HPM26 - Allow access to hpmcnt26[h] CSRs from U-mode when set (r/w) */ |
CSR_MCOUNTEREN_HPM27 = 27, /**< CPU mcounteren CSR (27): HPM27 - Allow access to hpmcnt27[h] CSRs from U-mode when set (r/w) */ |
CSR_MCOUNTEREN_HPM28 = 28, /**< CPU mcounteren CSR (28): HPM28 - Allow access to hpmcnt28[h] CSRs from U-mode when set (r/w) */ |
CSR_MCOUNTEREN_HPM29 = 29, /**< CPU mcounteren CSR (29): HPM29 - Allow access to hpmcnt29[h] CSRs from U-mode when set (r/w) */ |
CSR_MCOUNTEREN_HPM30 = 30, /**< CPU mcounteren CSR (30): HPM30 - Allow access to hpmcnt30[h] CSRs from U-mode when set (r/w) */ |
CSR_MCOUNTEREN_HPM31 = 31 /**< CPU mcounteren CSR (31): HPM31 - Allow access to hpmcnt31[h] CSRs from U-mode when set (r/w) */ |
CSR_MCOUNTEREN_CY = 0, /**< CPU mcounteren CSR (0): CY - Allow access to cycle[h] CSRs from U-mode when set (r/w) */ |
CSR_MCOUNTEREN_TM = 1, /**< CPU mcounteren CSR (1): TM - Allow access to time[h] CSRs from U-mode when set (r/w) */ |
CSR_MCOUNTEREN_IR = 2 /**< CPU mcounteren CSR (2): IR - Allow access to instret[h] CSRs from U-mode when set (r/w) */ |
}; |
|
|
459,7 → 374,6
CSR_MIP_FIRQ5P = 21, /**< CPU mip CSR (21): FIRQ5P - Fast interrupt channel 5 pending (r/-) */ |
CSR_MIP_FIRQ6P = 22, /**< CPU mip CSR (22): FIRQ6P - Fast interrupt channel 6 pending (r/-) */ |
CSR_MIP_FIRQ7P = 23, /**< CPU mip CSR (23): FIRQ7P - Fast interrupt channel 7 pending (r/-) */ |
|
CSR_MIP_FIRQ8P = 24, /**< CPU mip CSR (24): FIRQ8P - Fast interrupt channel 8 pending (r/-) */ |
CSR_MIP_FIRQ9P = 25, /**< CPU mip CSR (25): FIRQ9P - Fast interrupt channel 9 pending (r/-) */ |
CSR_MIP_FIRQ10P = 26, /**< CPU mip CSR (26): FIRQ10P - Fast interrupt channel 10 pending (r/-) */ |
475,18 → 389,18
* CPU <b>misa</b> CSR (r/-): Machine instruction set extensions (RISC-V spec.) |
**************************************************************************/ |
enum NEORV32_CSR_MISA_enum { |
CSR_MISA_A_EXT = 0, /**< CPU misa CSR (0): A: Atomic instructions CPU extension available (r/-)*/ |
CSR_MISA_B_EXT = 1, /**< CPU misa CSR (1): B: Bit manipulation CPU extension available (r/-)*/ |
CSR_MISA_C_EXT = 2, /**< CPU misa CSR (2): C: Compressed instructions CPU extension available (r/-)*/ |
CSR_MISA_D_EXT = 3, /**< CPU misa CSR (3): D: Double-precision floating-point extension available (r/-)*/ |
CSR_MISA_E_EXT = 4, /**< CPU misa CSR (4): E: Embedded CPU extension available (r/-) */ |
CSR_MISA_F_EXT = 5, /**< CPU misa CSR (5): F: Single-precision floating-point extension available (r/-)*/ |
CSR_MISA_I_EXT = 8, /**< CPU misa CSR (8): I: Base integer ISA CPU extension available (r/-) */ |
CSR_MISA_M_EXT = 12, /**< CPU misa CSR (12): M: Multiplier/divider CPU extension available (r/-)*/ |
CSR_MISA_U_EXT = 20, /**< CPU misa CSR (20): U: User mode CPU extension available (r/-)*/ |
CSR_MISA_X_EXT = 23, /**< CPU misa CSR (23): X: Non-standard CPU extension available (r/-) */ |
CSR_MISA_MXL_LO_EXT = 30, /**< CPU misa CSR (30): MXL.lo: CPU data width (r/-) */ |
CSR_MISA_MXL_HI_EXT = 31 /**< CPU misa CSR (31): MXL.Hi: CPU data width (r/-) */ |
CSR_MISA_A = 0, /**< CPU misa CSR (0): A: Atomic instructions CPU extension available (r/-)*/ |
CSR_MISA_B = 1, /**< CPU misa CSR (1): B: Bit manipulation CPU extension available (r/-)*/ |
CSR_MISA_C = 2, /**< CPU misa CSR (2): C: Compressed instructions CPU extension available (r/-)*/ |
CSR_MISA_D = 3, /**< CPU misa CSR (3): D: Double-precision floating-point extension available (r/-)*/ |
CSR_MISA_E = 4, /**< CPU misa CSR (4): E: Embedded CPU extension available (r/-) */ |
CSR_MISA_F = 5, /**< CPU misa CSR (5): F: Single-precision floating-point extension available (r/-)*/ |
CSR_MISA_I = 8, /**< CPU misa CSR (8): I: Base integer ISA CPU extension available (r/-) */ |
CSR_MISA_M = 12, /**< CPU misa CSR (12): M: Multiplier/divider CPU extension available (r/-)*/ |
CSR_MISA_U = 20, /**< CPU misa CSR (20): U: User mode CPU extension available (r/-)*/ |
CSR_MISA_X = 23, /**< CPU misa CSR (23): X: Non-standard CPU extension available (r/-) */ |
CSR_MISA_MXL_LO = 30, /**< CPU misa CSR (30): MXL.lo: CPU data width (r/-) */ |
CSR_MISA_MXL_HI = 31 /**< CPU misa CSR (31): MXL.Hi: CPU data width (r/-) */ |
}; |
|
|
496,9 → 410,8
enum NEORV32_CSR_MZEXT_enum { |
CSR_MZEXT_ZICSR = 0, /**< CPU mzext CSR (0): Zicsr extension (I sub-extension) available when set (r/-) */ |
CSR_MZEXT_ZIFENCEI = 1, /**< CPU mzext CSR (1): Zifencei extension (I sub-extension) available when set (r/-) */ |
//CSR_MZEXT_ZBB = 2, /**< CPU mzext CSR (2): Zbb extension (B sub-extension) available when set (r/-) */ |
//CSR_MZEXT_ZBS = 3, /**< CPU mzext CSR (3): Zbs extension (B sub-extension) available when set (r/-) */ |
//CSR_MZEXT_ZBA = 4, /**< CPU mzext CSR (4): Zba extension (B sub-extension) available when set (r/-) */ |
CSR_MZEXT_ZMMUL = 2, /**< CPU mzext CSR (2): Zmmul extension (M sub-extension) available when set (r/-) */ |
|
CSR_MZEXT_ZFINX = 5, /**< CPU mzext CSR (5): Zfinx extension (F sub-/alternative-extension) available when set (r/-) */ |
CSR_MZEXT_ZXSCNT = 6, /**< CPU mzext CSR (6): Custom extension - Small CPU counters: "cycle" & "instret" CSRs have less than 64-bit when set (r/-) */ |
CSR_MZEXT_ZXNOCNT = 7, /**< CPU mzext CSR (7): Custom extension - NO CPU counters: "cycle" & "instret" CSRs are NOT available at all when set (r/-) */ |
715,7 → 628,7
**************************************************************************/ |
/**@{*/ |
/** PWM base address */ |
#define PWM_BASE (0XFFFFFF80UL) // /**< PWM base address */ |
#define PWM_BASE (0xFFFFFE80UL) // /**< PWM base address */ |
/** PWM address space size in bytes */ |
#define PWM_SIZE (16*4) // /**< PWM address space size in bytes */ |
|
763,68 → 676,93
|
|
/**********************************************************************//** |
* @name IO Device: General Purpose Input/Output Port Unit (GPIO) |
* @name IO Device: Stream link interface (SLINK) |
**************************************************************************/ |
/**@{*/ |
/** GPIO base address */ |
#define GPIO_BASE (0xFFFFFF80UL) // /**< GPIO base address */ |
/** GPIO address space size in bytes */ |
#define GPIO_SIZE (2*4) // /**< GPIO address space size in bytes */ |
/** SLINK base address */ |
#define SLINK_BASE (0xFFFFFEC0UL) // /**< SLINK base address */ |
/** SLINK address space size in bytes */ |
#define SLINK_SIZE (16*4) // /**< SLINK address space size in bytes */ |
|
/** read access: GPIO parallel input port 32-bit (r/-), write_access: pin-change IRQ for each input pin (-/w) */ |
#define GPIO_INPUT (*(IO_REG32 (GPIO_BASE + 0))) |
/** GPIO parallel output port 32-bit (r/w) */ |
#define GPIO_OUTPUT (*(IO_REG32 (GPIO_BASE + 4))) |
/**@}*/ |
/** SLINK control register (r/w) */ |
#define SLINK_CT (*(IO_REG32 (SLINK_BASE + 0))) // r/w: control register |
/** stream link 0 (r/w) */ |
#define SLINK_CH0 (*(IO_REG32 (SLINK_BASE + 32 + 0))) // r/w: link 0 |
/** stream link 1 (r/w) */ |
#define SLINK_CH1 (*(IO_REG32 (SLINK_BASE + 32 + 4))) // r/w: link 1 |
/** stream link 2 (r/w) */ |
#define SLINK_CH2 (*(IO_REG32 (SLINK_BASE + 32 + 8))) // r/w: link 2 |
/** stream link 3 (r/w) */ |
#define SLINK_CH3 (*(IO_REG32 (SLINK_BASE + 32 + 12))) // r/w: link 3 |
/** stream link 4 (r/w) */ |
#define SLINK_CH4 (*(IO_REG32 (SLINK_BASE + 32 + 16))) // r/w: link 4 |
/** stream link 5 (r/w) */ |
#define SLINK_CH5 (*(IO_REG32 (SLINK_BASE + 32 + 20))) // r/w: link 5 |
/** stream link 6 (r/w) */ |
#define SLINK_CH6 (*(IO_REG32 (SLINK_BASE + 32 + 24))) // r/w: link 6 |
/** stream link 7 (r/w) */ |
#define SLINK_CH7 (*(IO_REG32 (SLINK_BASE + 32 + 28))) // r/w: link 7 |
|
/** SLINK control register bits */ |
enum NEORV32_SLINK_CT_enum { |
SLINK_CT_RX0_AVAIL = 0, /**< SLINK control register(0) (r/-): RX link 0 data available */ |
SLINK_CT_RX1_AVAIL = 1, /**< SLINK control register(1) (r/-): RX link 1 data available */ |
SLINK_CT_RX2_AVAIL = 2, /**< SLINK control register(2) (r/-): RX link 2 data available */ |
SLINK_CT_RX3_AVAIL = 3, /**< SLINK control register(3) (r/-): RX link 3 data available */ |
SLINK_CT_RX4_AVAIL = 4, /**< SLINK control register(4) (r/-): RX link 4 data available */ |
SLINK_CT_RX5_AVAIL = 5, /**< SLINK control register(5) (r/-): RX link 5 data available */ |
SLINK_CT_RX6_AVAIL = 6, /**< SLINK control register(6) (r/-): RX link 6 data available */ |
SLINK_CT_RX7_AVAIL = 7, /**< SLINK control register(7) (r/-): RX link 7 data available */ |
|
/**********************************************************************//** |
* @name IO Device: True Random Number Generator (TRNG) |
**************************************************************************/ |
/**@{*/ |
/** TRNG base address */ |
#define TRNG_BASE (0xFFFFFF88UL) // /**< TRNG base address */ |
/** TRNG address space size in bytes */ |
#define TRNG_SIZE (1*4) // /**< TRNG address space size in bytes */ |
SLINK_CT_TX0_FREE = 8, /**< SLINK control register(8) (r/-): RT link 0 ready to send */ |
SLINK_CT_TX1_FREE = 9, /**< SLINK control register(9) (r/-): RT link 1 ready to send */ |
SLINK_CT_TX2_FREE = 10, /**< SLINK control register(10) (r/-): RT link 2 ready to send */ |
SLINK_CT_TX3_FREE = 11, /**< SLINK control register(11) (r/-): RT link 3 ready to send */ |
SLINK_CT_TX4_FREE = 12, /**< SLINK control register(12) (r/-): RT link 4 ready to send */ |
SLINK_CT_TX5_FREE = 13, /**< SLINK control register(13) (r/-): RT link 5 ready to send */ |
SLINK_CT_TX6_FREE = 14, /**< SLINK control register(14) (r/-): RT link 6 ready to send */ |
SLINK_CT_TX7_FREE = 15, /**< SLINK control register(15) (r/-): RT link 7 ready to send */ |
|
/** TRNG control/data register (r/w) */ |
#define TRNG_CT (*(IO_REG32 (TRNG_BASE + 0))) |
SLINK_CT_RX_NUM0 = 16, /**< SLINK control register(16) (r/-): number of implemented RX links -1 bit 0 */ |
SLINK_CT_RX_NUM1 = 17, /**< SLINK control register(17) (r/-): number of implemented RX links -1 bit 1 */ |
SLINK_CT_RX_NUM2 = 18, /**< SLINK control register(18) (r/-): number of implemented RX links -1 bit 2 */ |
|
/** TRNG control/data register bits */ |
enum NEORV32_TRNG_CT_enum { |
TRNG_CT_DATA_LSB = 0, /**< TRNG data/control register(0) (r/-): Random data byte LSB */ |
TRNG_CT_DATA_MSB = 7, /**< TRNG data/control register(7) (r/-): Random data byte MSB */ |
SLINK_CT_TX_NUM0 = 19, /**< SLINK control register(19) (r/-): number of implemented TX links -1bit 0 */ |
SLINK_CT_TX_NUM1 = 20, /**< SLINK control register(20) (r/-): number of implemented TX links -1bit 1 */ |
SLINK_CT_TX_NUM2 = 21, /**< SLINK control register(21) (r/-): number of implemented TX links -1bit 2 */ |
|
TRNG_CT_EN = 30, /**< TRNG data/control register(30) (r/w): TRNG enable */ |
TRNG_CT_VALID = 31 /**< TRNG data/control register(31) (r/-): Random data output valid */ |
SLINK_CT_RX_FIFO_S0 = 22, /**< SLINK control register(22) (r/-): log2(RX FIFO size) bit 0 */ |
SLINK_CT_RX_FIFO_S1 = 23, /**< SLINK control register(23) (r/-): log2(RX FIFO size) bit 1 */ |
SLINK_CT_RX_FIFO_S2 = 24, /**< SLINK control register(24) (r/-): log2(RX FIFO size) bit 2 */ |
SLINK_CT_RX_FIFO_S3 = 25, /**< SLINK control register(25) (r/-): log2(RX FIFO size) bit 3 */ |
|
SLINK_CT_TX_FIFO_S0 = 26, /**< SLINK control register(26) (r/-): log2(TX FIFO size) bit 0 */ |
SLINK_CT_TX_FIFO_S1 = 27, /**< SLINK control register(27) (r/-): log2(TX FIFO size) bit 1 */ |
SLINK_CT_TX_FIFO_S2 = 28, /**< SLINK control register(28) (r/-): log2(TX FIFO size) bit 2 */ |
SLINK_CT_TX_FIFO_S3 = 29, /**< SLINK control register(29) (r/-): log2(TX FIFO size) bit 3 */ |
|
SLINK_CT_EN = 31 /**< SLINK control register(31) (r/w): SLINK controller enable */ |
}; |
/**@}*/ |
|
|
/**********************************************************************//** |
* @name IO Device: Watchdog Timer (WDT) |
* @name IO Device: External Interrupt Controller (XIRQ) |
**************************************************************************/ |
/**@{*/ |
/** WDT base address */ |
#define WDT_BASE (0xFFFFFF8CUL) // /**< WDT base address */ |
/** WDT address space size in bytes */ |
#define WDT_SIZE (1*4) // /**< WDT address space size in bytes */ |
/** XIRQ base address */ |
#define XIRQ_BASE (0xFFFFFF80UL) // /**< XIRQ base address */ |
/** XIRQ address space size in bytes */ |
#define XIRQ_SIZE (4*4) // /**< XIRQ address space size in bytes */ |
|
/** Watchdog control register (r/w) */ |
#define WDT_CT (*(IO_REG32 (WDT_BASE + 0))) |
|
/** WTD control register bits */ |
enum NEORV32_WDT_CT_enum { |
WDT_CT_EN = 0, /**< WDT control register(0) (r/w): Watchdog enable */ |
WDT_CT_CLK_SEL0 = 1, /**< WDT control register(1) (r/w): Clock prescaler select bit 0 */ |
WDT_CT_CLK_SEL1 = 2, /**< WDT control register(2) (r/w): Clock prescaler select bit 1 */ |
WDT_CT_CLK_SEL2 = 3, /**< WDT control register(3) (r/w): Clock prescaler select bit 2 */ |
WDT_CT_MODE = 4, /**< WDT control register(4) (r/w): Watchdog mode: 0=timeout causes interrupt, 1=timeout causes processor reset */ |
WDT_CT_RCAUSE = 5, /**< WDT control register(5) (r/-): Cause of last system reset: 0=external reset, 1=watchdog */ |
WDT_CT_RESET = 6, /**< WDT control register(6) (-/w): Reset WDT counter when set, auto-clears */ |
WDT_CT_FORCE = 7, /**< WDT control register(7) (-/w): Force WDT action, auto-clears */ |
WDT_CT_LOCK = 8 /**< WDT control register(8) (r/w): Lock write access to control register, clears on reset (HW or WDT) only */ |
}; |
/** XIRQ IRQ input enable register (r/w) */ |
#define XIRQ_IER (*(IO_REG32 (XIRQ_BASE + 0))) |
/** XIRQ pending IRQ register /ack/clear (r/w) */ |
#define XIRQ_IPR (*(IO_REG32 (XIRQ_BASE + 4))) |
/** EXTIRW (time compare register) low word (r/w) */ |
#define XIRQ_SCR (*(IO_REG32 (XIRQ_BASE + 8))) |
// reserved |
//#define XIRQ_reserved (*(IO_REG32 (XIRQ_BASE + 12))) |
/**@}*/ |
|
|
1010,67 → 948,81
|
|
/**********************************************************************//** |
* @name IO Device: Numerically-Controlled Oscillator (NCO) |
* @name IO Device: True Random Number Generator (TRNG) |
**************************************************************************/ |
/**@{*/ |
/** NCO base address */ |
#define NCO_BASE (0xFFFFFFC0UL) // /**< NCO base address */ |
/** NCO address space size in bytes */ |
#define NCO_SIZE (4*4) // /**< NCO address space size in bytes */ |
/** TRNG base address */ |
#define TRNG_BASE (0xFFFFFFB8UL) // /**< TRNG base address */ |
/** TRNG address space size in bytes */ |
#define TRNG_SIZE (1*4) // /**< TRNG address space size in bytes */ |
|
/** NCO control register (r/w) */ |
#define NCO_CT (*(IO_REG32 (NCO_BASE + 0))) // r/w: control register |
/** NCO channel 0 tuning word (r/w) */ |
#define NCO_TUNE_CH0 (*(IO_REG32 (NCO_BASE + 4))) // r/w: tuning word channel 0 |
/** NCO channel 1 tuning word (r/w) */ |
#define NCO_TUNE_CH1 (*(IO_REG32 (NCO_BASE + 8))) // r/w: tuning word channel 1 |
/** NCO channel 2 tuning word (r/w) */ |
#define NCO_TUNE_CH2 (*(IO_REG32 (NCO_BASE + 12))) // r/w: tuning word channel 2 |
/** TRNG control/data register (r/w) */ |
#define TRNG_CT (*(IO_REG32 (TRNG_BASE + 0))) |
|
/** NCO control register bits */ |
enum NEORV32_NCO_CT_enum { |
NCO_CT_EN = 0, /**< NCO control register(0) (r/w): NCO global enable */ |
// channel 0 |
NCO_CT_CH0_MODE = 1, /**< NCO control register(1) - channel 0 (r/w): Output mode (0=fixed 50% duty cycle; 1=pulse mode) */ |
NCO_CT_CH0_IDLE_POL = 2, /**< NCO control register(2) - channel 0 (r/w): Output idle polarity (0=low, 1=high) */ |
NCO_CT_CH0_OE = 3, /**< NCO control register(3) - channel 0 (r/w): Enable processor output pin */ |
NCO_CT_CH0_OUTPUT = 4, /**< NCO control register(4) - channel 0 (r/-): Current channel output state */ |
NCO_CT_CH0_PRSC0 = 5, /**< NCO control register(5) - channel 0 (r/w): Clock prescaler select bit 0 */ |
NCO_CT_CH0_PRSC1 = 6, /**< NCO control register(6) - channel 0 (r/w): Clock prescaler select bit 1 */ |
NCO_CT_CH0_PRSC2 = 7, /**< NCO control register(7) - channel 0 (r/w): Clock prescaler select bit 2 */ |
NCO_CT_CH0_PULSE0 = 8, /**< NCO control register(8) - channel 0 (r/w): Pulse-mode: Pulse length select bit 0 */ |
NCO_CT_CH0_PULSE1 = 9, /**< NCO control register(9) - channel 0 (r/w): Pulse-mode: Pulse length select bit 1 */ |
NCO_CT_CH0_PULSE2 = 10, /**< NCO control register(10) - channel 0 (r/w): Pulse-mode: Pulse length select bit 2 */ |
// channel 1 |
NCO_CT_CH1_MODE = 11, /**< NCO control register(11) - channel 1 (r/w): Output mode (0=fixed 50% duty cycle; 1=pulse mode) */ |
NCO_CT_CH1_IDLE_POL = 12, /**< NCO control register(12) - channel 1 (r/w): Output idle polarity (0=low, 1=high) */ |
NCO_CT_CH1_OE = 13, /**< NCO control register(13) - channel 1 (r/w): Enable processor output pin */ |
NCO_CT_CH1_OUTPUT = 14, /**< NCO control register(14) - channel 1 (r/-): Current channel output state */ |
NCO_CT_CH1_PRSC0 = 15, /**< NCO control register(15) - channel 1 (r/w): Clock prescaler select bit 0 */ |
NCO_CT_CH1_PRSC1 = 16, /**< NCO control register(16) - channel 1 (r/w): Clock prescaler select bit 1 */ |
NCO_CT_CH1_PRSC2 = 17, /**< NCO control register(17) - channel 1 (r/w): Clock prescaler select bit 2 */ |
NCO_CT_CH1_PULSE0 = 18, /**< NCO control register(18) - channel 1 (r/w): Pulse-mode: Pulse length select bit 0 */ |
NCO_CT_CH1_PULSE1 = 19, /**< NCO control register(19) - channel 1 (r/w): Pulse-mode: Pulse length select bit 1 */ |
NCO_CT_CH1_PULSE2 = 20, /**< NCO control register(20) - channel 1 (r/w): Pulse-mode: Pulse length select bit 2 */ |
// channel 2 |
NCO_CT_CH2_MODE = 21, /**< NCO control register(21) - channel 2 (r/w): Output mode (0=fixed 50% duty cycle; 1=pulse mode) */ |
NCO_CT_CH2_IDLE_POL = 22, /**< NCO control register(22) - channel 2 (r/w): Output idle polarity (0=low, 1=high) */ |
NCO_CT_CH2_OE = 23, /**< NCO control register(23) - channel 2 (r/w): Enable processor output pin */ |
NCO_CT_CH2_OUTPUT = 24, /**< NCO control register(24) - channel 2 (r/-): Current channel output state */ |
NCO_CT_CH2_PRSC0 = 25, /**< NCO control register(25) - channel 2 (r/w): Clock prescaler select bit 0 */ |
NCO_CT_CH2_PRSC1 = 26, /**< NCO control register(26) - channel 2 (r/w): Clock prescaler select bit 1 */ |
NCO_CT_CH2_PRSC2 = 27, /**< NCO control register(27) - channel 2 (r/w): Clock prescaler select bit 2 */ |
NCO_CT_CH2_PULSE0 = 28, /**< NCO control register(28) - channel 2 (r/w): Pulse-mode: Pulse length select bit 0 */ |
NCO_CT_CH2_PULSE1 = 29, /**< NCO control register(29) - channel 2 (r/w): Pulse-mode: Pulse length select bit 1 */ |
NCO_CT_CH2_PULSE2 = 20 /**< NCO control register(30) - channel 2 (r/w): Pulse-mode: Pulse length select bit 2 */ |
/** TRNG control/data register bits */ |
enum NEORV32_TRNG_CT_enum { |
TRNG_CT_DATA_LSB = 0, /**< TRNG data/control register(0) (r/-): Random data byte LSB */ |
TRNG_CT_DATA_MSB = 7, /**< TRNG data/control register(7) (r/-): Random data byte MSB */ |
|
TRNG_CT_EN = 30, /**< TRNG data/control register(30) (r/w): TRNG enable */ |
TRNG_CT_VALID = 31 /**< TRNG data/control register(31) (r/-): Random data output valid */ |
}; |
/**@}*/ |
|
/** Size of one "channel entry" in control register in bits */ |
#define NCO_CHX_WIDTH 10 // Size of one "channel entry" in control register in bits |
|
/**********************************************************************//** |
* @name IO Device: Watchdog Timer (WDT) |
**************************************************************************/ |
/**@{*/ |
/** WDT base address */ |
#define WDT_BASE (0xFFFFFFBCUL) // /**< WDT base address */ |
/** WDT address space size in bytes */ |
#define WDT_SIZE (1*4) // /**< WDT address space size in bytes */ |
|
/** Watchdog control register (r/w) */ |
#define WDT_CT (*(IO_REG32 (WDT_BASE + 0))) |
|
/** WTD control register bits */ |
enum NEORV32_WDT_CT_enum { |
WDT_CT_EN = 0, /**< WDT control register(0) (r/w): Watchdog enable */ |
WDT_CT_CLK_SEL0 = 1, /**< WDT control register(1) (r/w): Clock prescaler select bit 0 */ |
WDT_CT_CLK_SEL1 = 2, /**< WDT control register(2) (r/w): Clock prescaler select bit 1 */ |
WDT_CT_CLK_SEL2 = 3, /**< WDT control register(3) (r/w): Clock prescaler select bit 2 */ |
WDT_CT_MODE = 4, /**< WDT control register(4) (r/w): Watchdog mode: 0=timeout causes interrupt, 1=timeout causes processor reset */ |
WDT_CT_RCAUSE = 5, /**< WDT control register(5) (r/-): Cause of last system reset: 0=external reset, 1=watchdog */ |
WDT_CT_RESET = 6, /**< WDT control register(6) (-/w): Reset WDT counter when set, auto-clears */ |
WDT_CT_FORCE = 7, /**< WDT control register(7) (-/w): Force WDT action, auto-clears */ |
WDT_CT_LOCK = 8 /**< WDT control register(8) (r/w): Lock write access to control register, clears on reset (HW or WDT) only */ |
}; |
/**@}*/ |
|
|
/**********************************************************************//** |
* @name IO Device: General Purpose Input/Output Port Unit (GPIO) |
**************************************************************************/ |
/**@{*/ |
/** GPIO base address */ |
#define GPIO_BASE (0xFFFFFFC0UL) // /**< GPIO base address */ |
/** GPIO address space size in bytes */ |
#define GPIO_SIZE (4*4) // /**< GPIO address space size in bytes */ |
|
/** GPIO parallel input port lower 32-bit (r/-) */ |
#define GPIO_INPUT_LO (*(IO_REG32 (GPIO_BASE + 0))) |
/** GPIO parallel input port upper 32-bit (r/-) */ |
#define GPIO_INPUT_HI (*(IO_REG32 (GPIO_BASE + 4))) |
/** GPIO parallel output port lower 32-bit (r/w) */ |
#define GPIO_OUTPUT_LO (*(IO_REG32 (GPIO_BASE + 8))) |
/** GPIO parallel output port upper 32-bit (r/w) */ |
#define GPIO_OUTPUT_HI (*(IO_REG32 (GPIO_BASE + 12))) |
|
/** GPIO parallel input 64-bit access (r/-) */ |
#define GPIO_INPUT (*(IO_REG64 (&GPIO_INPUT_LO))) |
/** GPIO parallel output 64-bit access (r/w) */ |
#define GPIO_OUTPUT (*(IO_REG64 (&GPIO_OUTPUT_LO))) |
/**@}*/ |
|
|
/**********************************************************************//** |
* @name IO Device: Smart LED Hardware Interface (NEOLED) |
**************************************************************************/ |
/**@{*/ |
1153,13 → 1105,12
* SYSINFO_FEATURES (r/-): Implemented processor devices/features |
**************************************************************************/ |
enum NEORV32_SYSINFO_FEATURES_enum { |
SYSINFO_FEATURES_BOOTLOADER = 0, /**< SYSINFO_FEATURES (0) (r/-): Bootloader implemented when 1 (via BOOTLOADER_EN generic) */ |
SYSINFO_FEATURES_BOOTLOADER = 0, /**< SYSINFO_FEATURES (0) (r/-): Bootloader implemented when 1 (via INT_BOOTLOADER_EN generic) */ |
SYSINFO_FEATURES_MEM_EXT = 1, /**< SYSINFO_FEATURES (1) (r/-): External bus interface implemented when 1 (via MEM_EXT_EN generic) */ |
SYSINFO_FEATURES_MEM_INT_IMEM = 2, /**< SYSINFO_FEATURES (2) (r/-): Processor-internal instruction memory implemented when 1 (via MEM_INT_IMEM_EN generic) */ |
SYSINFO_FEATURES_MEM_INT_IMEM_ROM = 3, /**< SYSINFO_FEATURES (3) (r/-): Processor-internal instruction memory implemented as ROM when 1 (via MEM_INT_IMEM_ROM generic) */ |
SYSINFO_FEATURES_MEM_INT_DMEM = 4, /**< SYSINFO_FEATURES (4) (r/-): Processor-internal data memory implemented when 1 (via MEM_INT_DMEM_EN generic) */ |
SYSINFO_FEATURES_MEM_EXT_ENDIAN = 5, /**< SYSINFO_FEATURES (5) (r/-): External bus interface uses BIG-endian byte-order when 1 (via package.xbus_big_endian_c constant) */ |
SYSINFO_FEATURES_ICACHE = 6, /**< SYSINFO_FEATURES (6) (r/-): Processor-internal instruction cache implemented when 1 (via ICACHE_EN generic) */ |
SYSINFO_FEATURES_MEM_INT_DMEM = 3, /**< SYSINFO_FEATURES (3) (r/-): Processor-internal data memory implemented when 1 (via MEM_INT_DMEM_EN generic) */ |
SYSINFO_FEATURES_MEM_EXT_ENDIAN = 4, /**< SYSINFO_FEATURES (4) (r/-): External bus interface uses BIG-endian byte-order when 1 (via package.xbus_big_endian_c constant) */ |
SYSINFO_FEATURES_ICACHE = 5, /**< SYSINFO_FEATURES (5) (r/-): Processor-internal instruction cache implemented when 1 (via ICACHE_EN generic) */ |
|
SYSINFO_FEATURES_OCD = 14, /**< SYSINFO_FEATURES (14) (r/-): On-chip debugger implemented when 1 (via ON_CHIP_DEBUGGER_EN generic) */ |
SYSINFO_FEATURES_HW_RESET = 15, /**< SYSINFO_FEATURES (15) (r/-): Dedicated hardware reset of core registers implemented when 1 (via package's dedicated_reset_c constant) */ |
1173,9 → 1124,10
SYSINFO_FEATURES_IO_WDT = 22, /**< SYSINFO_FEATURES (22) (r/-): Watchdog timer implemented when 1 (via IO_WDT_EN generic) */ |
SYSINFO_FEATURES_IO_CFS = 23, /**< SYSINFO_FEATURES (23) (r/-): Custom functions subsystem implemented when 1 (via IO_CFS_EN generic) */ |
SYSINFO_FEATURES_IO_TRNG = 24, /**< SYSINFO_FEATURES (24) (r/-): True random number generator implemented when 1 (via IO_TRNG_EN generic) */ |
SYSINFO_FEATURES_IO_NCO = 25, /**< SYSINFO_FEATURES (25) (r/-): Numerically-controlled oscillator implemented when 1 (via IO_NCO_EN generic) */ |
SYSINFO_FEATURES_IO_SLINK = 25, /**< SYSINFO_FEATURES (25) (r/-): Stream link interface implemented when 1 (via SLINK_NUM_RX & SLINK_NUM_TX generics) */ |
SYSINFO_FEATURES_IO_UART1 = 26, /**< SYSINFO_FEATURES (26) (r/-): Secondary universal asynchronous receiver/transmitter 1 implemented when 1 (via IO_UART1_EN generic) */ |
SYSINFO_FEATURES_IO_NEOLED = 27 /**< SYSINFO_FEATURES (27) (r/-): NeoPixel-compatible smart LED interface implemented when 1 (via IO_NEOLED_EN generic) */ |
SYSINFO_FEATURES_IO_NEOLED = 27, /**< SYSINFO_FEATURES (27) (r/-): NeoPixel-compatible smart LED interface implemented when 1 (via IO_NEOLED_EN generic) */ |
SYSINFO_FEATURES_IO_XIRQ = 28 /**< SYSINFO_FEATURES (28) (r/-): External interrupt controller implemented when 1 (via XIRQ_NUM_IO generic) */ |
}; |
|
/**********************************************************************//** |
1220,13 → 1172,19
#include "neorv32_cfs.h" |
#include "neorv32_gpio.h" |
#include "neorv32_mtime.h" |
#include "neorv32_nco.h" |
#include "neorv32_neoled.h" |
#include "neorv32_pwm.h" |
#include "neorv32_slink.h" |
#include "neorv32_spi.h" |
#include "neorv32_trng.h" |
#include "neorv32_twi.h" |
#include "neorv32_uart.h" |
#include "neorv32_wdt.h" |
#include "neorv32_xirq.h" |
|
|
#ifdef __cplusplus |
} |
#endif |
|
#endif // neorv32_h |
/lib/include/neorv32_cpu.h
61,6 → 61,15
|
|
/**********************************************************************//** |
* Prototype for "after-main handler". This function is called if main() returns. |
* |
* @param[in] return_code Return value of main() function. |
* @return Return value is irrelevant (there is no one left to check for it...). |
**************************************************************************/ |
extern int __neorv32_crt0_after_main(int32_t return_code); |
|
|
/**********************************************************************//** |
* Store unsigned word to address space. |
* |
* @note An unaligned access address will raise an alignment exception. |
/lib/include/neorv32_gpio.h
45,13 → 45,13
#define neorv32_gpio_h |
|
// prototypes |
int neorv32_gpio_available(void); |
void neorv32_gpio_pin_set(uint8_t p); |
void neorv32_gpio_pin_clr(uint8_t p); |
void neorv32_gpio_pin_toggle(uint8_t p); |
uint32_t neorv32_gpio_pin_get(uint8_t p); |
void neorv32_gpio_port_set(uint32_t d); |
uint32_t neorv32_gpio_port_get(void); |
void neorv32_gpio_pin_change_config(uint32_t pin_sel); |
int neorv32_gpio_available(void); |
void neorv32_gpio_pin_set(int pin); |
void neorv32_gpio_pin_clr(int pin); |
void neorv32_gpio_pin_toggle(int pin); |
uint32_t neorv32_gpio_pin_get(int pin); |
|
void neorv32_gpio_port_set(uint64_t d); |
uint64_t neorv32_gpio_port_get(void); |
|
#endif // neorv32_gpio_h |
/lib/include/neorv32_intrinsics.h
148,19 → 148,19
|
//** Construct custom R3-type instruction (4 registers, funct3, opcode) */ |
#define CUSTOM_INSTR_R3_TYPE(rs3, rs2, rs1, funct3, rd, opcode) \ |
asm volatile (".word "STR(CMD_WORD_R3_TYPE(GET_REG_ADDR(rs3), GET_REG_ADDR(rs2), GET_REG_ADDR(rs1), funct3, GET_REG_ADDR(rd), opcode))"\n"); |
asm volatile (".word " STR(CMD_WORD_R3_TYPE(GET_REG_ADDR(rs3), GET_REG_ADDR(rs2), GET_REG_ADDR(rs1), funct3, GET_REG_ADDR(rd), opcode))"\n"); |
|
//** Construct custom R2-type instruction (3 registers, funct3, funct7, opcode) */ |
#define CUSTOM_INSTR_R2_TYPE(funct7, rs2, rs1, funct3, rd, opcode) \ |
asm volatile (".word "STR(CMD_WORD_R2_TYPE(funct7, GET_REG_ADDR(rs2), GET_REG_ADDR(rs1), funct3, GET_REG_ADDR(rd), opcode))"\n"); |
asm volatile (".word " STR(CMD_WORD_R2_TYPE(funct7, GET_REG_ADDR(rs2), GET_REG_ADDR(rs1), funct3, GET_REG_ADDR(rd), opcode))"\n"); |
|
//** Construct custom R1-type instruction (2 registers, funct3, funct7, funct5, opcode) */ |
#define CUSTOM_INSTR_R1_TYPE(funct7, funct5, rs1, funct3, rd, opcode) \ |
asm volatile (".word "STR(CMD_WORD_R2_TYPE(funct7, funct5, GET_REG_ADDR(rs1), funct3, GET_REG_ADDR(rd), opcode))"\n"); |
asm volatile (".word " STR(CMD_WORD_R2_TYPE(funct7, funct5, GET_REG_ADDR(rs1), funct3, GET_REG_ADDR(rd), opcode))"\n"); |
|
//** Construct custom I-type instruction (2 registers, funct3, imm12, opcode) */ |
#define CUSTOM_INSTR_I_TYPE(imm12, rs1, funct3, rd, opcode) \ |
asm volatile (".word "STR(CMD_WORD_I_TYPE(imm12, GET_REG_ADDR(rs1), funct3, GET_REG_ADDR(rd), opcode))"\n"); |
asm volatile (".word " STR(CMD_WORD_I_TYPE(imm12, GET_REG_ADDR(rs1), funct3, GET_REG_ADDR(rd), opcode))"\n"); |
/**@}*/ |
|
#endif // neorv32_intrinsics_h |
/lib/include/neorv32_pwm.h
48,6 → 48,7
int neorv32_pwm_available(void); |
void neorv32_pwm_setup(uint8_t prsc); |
void neorv32_pwm_disable(void); |
void neorv32_pwm_enable(void); |
int neorv32_pmw_get_num_channels(void); |
void neorv32_pwm_set(uint8_t channel, uint8_t duty); |
uint8_t neorv32_pwm_get(uint8_t channel); |
/lib/include/neorv32_slink.h
0,0 → 1,265
// ################################################################################################# |
// # << NEORV32: neorv32_slink.h - Stream Link Interface HW Driver >> # |
// # ********************************************************************************************* # |
// # 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 # |
// ################################################################################################# |
|
|
/**********************************************************************//** |
* @file neorv32_slink.h |
* @author Stephan Nolting |
* @brief Stream Link Interface HW driver header file. |
**************************************************************************/ |
|
#ifndef neorv32_slink_h |
#define neorv32_slink_h |
|
// prototypes |
int neorv32_slink_available(void); |
void neorv32_slink_enable(void); |
void neorv32_slink_disable(void); |
int neorv32_slink_get_rx_num(void); |
int neorv32_slink_get_tx_num(void); |
int neorv32_slink_get_rx_depth(void); |
int neorv32_slink_get_tx_depth(void); |
// non-blocking transmit |
int neorv32_slink_tx0_nonblocking(uint32_t tx_data); |
int neorv32_slink_tx1_nonblocking(uint32_t tx_data); |
int neorv32_slink_tx2_nonblocking(uint32_t tx_data); |
int neorv32_slink_tx3_nonblocking(uint32_t tx_data); |
int neorv32_slink_tx4_nonblocking(uint32_t tx_data); |
int neorv32_slink_tx5_nonblocking(uint32_t tx_data); |
int neorv32_slink_tx6_nonblocking(uint32_t tx_data); |
int neorv32_slink_tx7_nonblocking(uint32_t tx_data); |
// non-blocking receive |
int neorv32_slink_rx0_nonblocking(uint32_t *rx_data); |
int neorv32_slink_rx1_nonblocking(uint32_t *rx_data); |
int neorv32_slink_rx2_nonblocking(uint32_t *rx_data); |
int neorv32_slink_rx3_nonblocking(uint32_t *rx_data); |
int neorv32_slink_rx4_nonblocking(uint32_t *rx_data); |
int neorv32_slink_rx5_nonblocking(uint32_t *rx_data); |
int neorv32_slink_rx6_nonblocking(uint32_t *rx_data); |
int neorv32_slink_rx7_nonblocking(uint32_t *rx_data); |
|
|
/**********************************************************************//** |
* Write data to TX stream link 0 (blocking!) |
* |
* @warning This function will raise an exception when the bus access times out! |
* |
* @param[in] tx_data Data to send to link. |
**************************************************************************/ |
inline void __attribute__ ((always_inline)) neorv32_slink_tx0_blocking(uint32_t tx_data) { |
SLINK_CH0 = tx_data; |
} |
|
|
/**********************************************************************//** |
* Write data to TX stream link 1 (blocking!) |
* |
* @warning This function will raise an exception when the bus access times out! |
* |
* @param[in] tx_data Data to send to link. |
**************************************************************************/ |
inline void __attribute__ ((always_inline)) neorv32_slink_tx1_blocking(uint32_t tx_data) { |
SLINK_CH1 = tx_data; |
} |
|
|
/**********************************************************************//** |
* Write data to TX stream link 2 (blocking!) |
* |
* @warning This function will raise an exception when the bus access times out! |
* |
* @param[in] tx_data Data to send to link. |
**************************************************************************/ |
inline void __attribute__ ((always_inline)) neorv32_slink_tx2_blocking(uint32_t tx_data) { |
SLINK_CH2 = tx_data; |
} |
|
|
/**********************************************************************//** |
* Write data to TX stream link 3 (blocking!) |
* |
* @warning This function will raise an exception when the bus access times out! |
* |
* @param[in] tx_data Data to send to link. |
**************************************************************************/ |
inline void __attribute__ ((always_inline)) neorv32_slink_tx3_blocking(uint32_t tx_data) { |
SLINK_CH3 = tx_data; |
} |
|
|
/**********************************************************************//** |
* Write data to TX stream link 4 (blocking!) |
* |
* @warning This function will raise an exception when the bus access times out! |
* |
* @param[in] tx_data Data to send to link. |
**************************************************************************/ |
inline void __attribute__ ((always_inline)) neorv32_slink_tx4_blocking(uint32_t tx_data) { |
SLINK_CH4 = tx_data; |
} |
|
|
/**********************************************************************//** |
* Write data to TX stream link 5 (blocking!) |
* |
* @warning This function will raise an exception when the bus access times out! |
* |
* @param[in] tx_data Data to send to link. |
**************************************************************************/ |
inline void __attribute__ ((always_inline)) neorv32_slink_tx5_blocking(uint32_t tx_data) { |
SLINK_CH5 = tx_data; |
} |
|
|
/**********************************************************************//** |
* Write data to TX stream link 6 (blocking!) |
* |
* @warning This function will raise an exception when the bus access times out! |
* |
* @param[in] tx_data Data to send to link. |
**************************************************************************/ |
inline void __attribute__ ((always_inline)) neorv32_slink_tx6_blocking(uint32_t tx_data) { |
SLINK_CH6 = tx_data; |
} |
|
|
/**********************************************************************//** |
* Write data to TX stream link 7 (blocking!) |
* |
* @warning This function will raise an exception when the bus access times out! |
* |
* @param[in] tx_data Data to send to link. |
**************************************************************************/ |
inline void __attribute__ ((always_inline)) neorv32_slink_tx7_blocking(uint32_t tx_data) { |
SLINK_CH7 = tx_data; |
} |
|
|
/**********************************************************************//** |
* Read data from RX stream link 0 (blocking!) |
* |
* @warning This function will raise an exception when the bus access times out! |
* |
* @param[in,out] rx_data Pointer to return read data. |
**************************************************************************/ |
inline void __attribute__ ((always_inline)) neorv32_slink_rx0_blocking(uint32_t *rx_data) { |
*rx_data = SLINK_CH0; |
} |
|
|
/**********************************************************************//** |
* Read data from RX stream link 1 (blocking!) |
* |
* @warning This function will raise an exception when the bus access times out! |
* |
* @param[in,out] rx_data Pointer to return read data. |
**************************************************************************/ |
inline void __attribute__ ((always_inline)) neorv32_slink_rx1_blocking(uint32_t *rx_data) { |
*rx_data = SLINK_CH1; |
} |
|
|
/**********************************************************************//** |
* Read data from RX stream link 2 (blocking!) |
* |
* @warning This function will raise an exception when the bus access times out! |
* |
* @param[in,out] rx_data Pointer to return read data. |
**************************************************************************/ |
inline void __attribute__ ((always_inline)) neorv32_slink_rx2_blocking(uint32_t *rx_data) { |
*rx_data = SLINK_CH2; |
} |
|
|
/**********************************************************************//** |
* Read data from RX stream link 3 (blocking!) |
* |
* @warning This function will raise an exception when the bus access times out! |
* |
* @param[in,out] rx_data Pointer to return read data. |
**************************************************************************/ |
inline void __attribute__ ((always_inline)) neorv32_slink_rx3_blocking(uint32_t *rx_data) { |
*rx_data = SLINK_CH3; |
} |
|
|
/**********************************************************************//** |
* Read data from RX stream link 4 (blocking!) |
* |
* @warning This function will raise an exception when the bus access times out! |
* |
* @param[in,out] rx_data Pointer to return read data. |
**************************************************************************/ |
inline void __attribute__ ((always_inline)) neorv32_slink_rx4_blocking(uint32_t *rx_data) { |
*rx_data = SLINK_CH4; |
} |
|
|
/**********************************************************************//** |
* Read data from RX stream link 5 (blocking!) |
* |
* @warning This function will raise an exception when the bus access times out! |
* |
* @param[in,out] rx_data Pointer to return read data. |
**************************************************************************/ |
inline void __attribute__ ((always_inline)) neorv32_slink_rx5_blocking(uint32_t *rx_data) { |
*rx_data = SLINK_CH5; |
} |
|
|
/**********************************************************************//** |
* Read data from RX stream link 6 (blocking!) |
* |
* @warning This function will raise an exception when the bus access times out! |
* |
* @param[in,out] rx_data Pointer to return read data. |
**************************************************************************/ |
inline void __attribute__ ((always_inline)) neorv32_slink_rx6_blocking(uint32_t *rx_data) { |
*rx_data = SLINK_CH6; |
} |
|
|
/**********************************************************************//** |
* Read data from RX stream link 7 (blocking!) |
* |
* @warning This function will raise an exception when the bus access times out! |
* |
* @param[in,out] rx_data Pointer to return read data. |
**************************************************************************/ |
inline void __attribute__ ((always_inline)) neorv32_slink_rx7_blocking(uint32_t *rx_data) { |
*rx_data = SLINK_CH7; |
} |
|
|
#endif // neorv32_slink_h |
/lib/include/neorv32_spi.h
48,6 → 48,7
int neorv32_spi_available(void); |
void neorv32_spi_setup(uint8_t prsc, uint8_t clk_polarity, uint8_t data_size); |
void neorv32_spi_disable(void); |
void neorv32_spi_enable(void); |
void neorv32_spi_cs_en(uint8_t cs); |
void neorv32_spi_cs_dis(uint8_t cs); |
uint32_t neorv32_spi_trans(uint32_t tx_data); |
/lib/include/neorv32_twi.h
48,6 → 48,7
int neorv32_twi_available(void); |
void neorv32_twi_setup(uint8_t prsc, uint8_t ckst_en); |
void neorv32_twi_disable(void); |
void neorv32_twi_enable(void); |
void neorv32_twi_mack_enable(void); |
int neorv32_twi_busy(void); |
int neorv32_twi_start_trans(uint8_t a); |
/lib/include/neorv32_uart.h
53,6 → 53,7
int neorv32_uart_available(void); |
void neorv32_uart_setup(uint32_t baudrate, uint8_t parity, uint8_t flow_con); |
void neorv32_uart_disable(void); |
void neorv32_uart_enable(void); |
void neorv32_uart_putc(char c); |
int neorv32_uart_tx_busy(void); |
char neorv32_uart_getc(void); |
67,6 → 68,7
int neorv32_uart0_available(void); |
void neorv32_uart0_setup(uint32_t baudrate, uint8_t parity, uint8_t flow_con); |
void neorv32_uart0_disable(void); |
void neorv32_uart0_enable(void); |
void neorv32_uart0_putc(char c); |
int neorv32_uart0_tx_busy(void); |
char neorv32_uart0_getc(void); |
81,6 → 83,7
int neorv32_uart1_available(void); |
void neorv32_uart1_setup(uint32_t baudrate, uint8_t parity, uint8_t flow_con); |
void neorv32_uart1_disable(void); |
void neorv32_uart1_enable(void); |
void neorv32_uart1_putc(char c); |
int neorv32_uart1_tx_busy(void); |
char neorv32_uart1_getc(void); |
/lib/include/neorv32_xirq.h
0,0 → 1,70
// ################################################################################################# |
// # << NEORV32: neorv32_xirq.h - External Interrupt controller HW Driver >> # |
// # ********************************************************************************************* # |
// # 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 # |
// ################################################################################################# |
|
|
/**********************************************************************//** |
* @file neorv32_xirq.h |
* @author Stephan Nolting |
* @brief SExternal Interrupt controller HW driver header file. |
**************************************************************************/ |
|
#ifndef neorv32_xirq_h |
#define neorv32_xirq_h |
|
|
/**********************************************************************//** |
* @name XIRQ fast interrupt channel |
**************************************************************************/ |
/**@{*/ |
/** XIRQ MIE FIRQ bit */ |
#define XIRQ_FIRQ_ENABLE CSR_MIE_FIRQ8E // MIE FIRQ bit |
/** XIRQ MIP FIRQ bit */ |
#define XIRQ_FIRQ_PENDING CSR_MIP_FIRQ8P // MIP FIRQ bit |
/** XIRQ RTE IRQ ID */ |
#define XIRQ_RTE_ID RTE_TRAP_FIRQ_8 // RTE IRQ ID |
/**@}*/ |
|
|
// prototypes |
int neorv32_xirq_available(void); |
int neorv32_xirq_setup(void); |
void neorv32_xirq_global_enable(void); |
void neorv32_xirq_global_disable(void); |
int neorv32_xirq_get_num(void); |
|
int neorv32_xirq_install(uint8_t ch, void (*handler)(void)); |
int neorv32_xirq_uninstall(uint8_t ch); |
|
|
#endif // neorv32_xirq_h |
/lib/source/neorv32_nco.c
File deleted
/lib/source/neorv32_cpu.c
685,7 → 685,7
} |
|
// inhibt auto-update |
asm volatile ("csrwi %[addr], %[imm]" : : [addr] "i" (CSR_MCOUNTINHIBIT), [imm] "i" (1<<CSR_MCOUNTEREN_HPM3)); |
asm volatile ("csrwi %[addr], %[imm]" : : [addr] "i" (CSR_MCOUNTINHIBIT), [imm] "i" (1<<CSR_MCOUNTINHIBIT_HPM3)); |
|
neorv32_cpu_csr_write(CSR_MHPMCOUNTER3, 0xffffffff); |
neorv32_cpu_csr_write(CSR_MHPMCOUNTER3H, 0xffffffff); |
/lib/source/neorv32_gpio.c
64,12 → 64,18
/**********************************************************************//** |
* Set single pin of GPIO's output port. |
* |
* @param[in] pin Output pin number to be set (0..31). |
* @param[in] pin Output pin number to be set (0..63). |
**************************************************************************/ |
void neorv32_gpio_pin_set(uint8_t pin) { |
void neorv32_gpio_pin_set(int pin) { |
|
pin &= 0x1f; |
GPIO_OUTPUT = GPIO_OUTPUT | (uint32_t)(1 << pin); |
uint32_t mask = (uint32_t)(1 << (pin & 0x1f)); |
|
if (pin < 32) { |
GPIO_OUTPUT_LO |= mask; |
} |
else { |
GPIO_OUTPUT_HI |= mask; |
} |
} |
|
|
76,12 → 82,18
/**********************************************************************//** |
* Clear single pin of GPIO's output port. |
* |
* @param[in] pin Output pin number to be cleared (0..31). |
* @param[in] pin Output pin number to be cleared (0..63). |
**************************************************************************/ |
void neorv32_gpio_pin_clr(uint8_t pin) { |
void neorv32_gpio_pin_clr(int pin) { |
|
pin &= 0x1f; |
GPIO_OUTPUT = GPIO_OUTPUT & ~((uint32_t)(1 << pin)); |
uint32_t mask = (uint32_t)(1 << (pin & 0x1f)); |
|
if (pin < 32) { |
GPIO_OUTPUT_LO &= ~mask; |
} |
else { |
GPIO_OUTPUT_HI &= ~mask; |
} |
} |
|
|
88,12 → 100,18
/**********************************************************************//** |
* Toggle single pin of GPIO's output port. |
* |
* @param[in] pin Output pin number to be toggled (0..31). |
* @param[in] pin Output pin number to be toggled (0..63). |
**************************************************************************/ |
void neorv32_gpio_pin_toggle(uint8_t pin) { |
void neorv32_gpio_pin_toggle(int pin) { |
|
pin &= 0x1f; |
GPIO_OUTPUT = GPIO_OUTPUT ^ (uint32_t)(1 << pin); |
uint32_t mask = (uint32_t)(1 << (pin & 0x1f)); |
|
if (pin < 32) { |
GPIO_OUTPUT_LO ^= mask; |
} |
else { |
GPIO_OUTPUT_HI ^= mask; |
} |
} |
|
|
100,13 → 118,19
/**********************************************************************//** |
* Get single pin of GPIO's input port. |
* |
* @param[in] pin Input pin to be read (0..31). |
* @return uint32_t: =0 if pin is low, !=0 if pin is high. |
* @param[in] pin Input pin to be read (0..63). |
* @return =0 if pin is low, !=0 if pin is high. |
**************************************************************************/ |
uint32_t neorv32_gpio_pin_get(uint8_t pin) { |
uint32_t neorv32_gpio_pin_get(int pin) { |
|
pin &= 0x1f; |
return GPIO_INPUT & (uint32_t)(1 << pin); |
uint32_t mask = (uint32_t)(1 << (pin & 0x1f)); |
|
if (pin < 32) { |
return GPIO_INPUT_LO & mask; |
} |
else { |
return GPIO_INPUT_HI & mask; |
} |
} |
|
|
113,9 → 137,9
/**********************************************************************//** |
* Set complete GPIO output port. |
* |
* @param[in] port_data New output port value (32-bit). |
* @param[in] port_data New output port value (64-bit). |
**************************************************************************/ |
void neorv32_gpio_port_set(uint32_t port_data) { |
void neorv32_gpio_port_set(uint64_t port_data) { |
|
GPIO_OUTPUT = port_data; |
} |
124,23 → 148,10
/**********************************************************************//** |
* Get complete GPIO input port. |
* |
* @return Current input port state (32-bit). |
* @return Current input port state (64-bit). |
**************************************************************************/ |
uint32_t neorv32_gpio_port_get(void) { |
uint64_t neorv32_gpio_port_get(void) { |
|
return GPIO_INPUT; |
} |
|
|
/**********************************************************************//** |
* Configure pin-change IRQ mask for input pins. |
* |
* @note The pin-change IRQ will trigger on any transition (rising and falling edge) for any enabled input pin. |
* |
* @param[in] pin_sel Mask to select which input pins can cause a pin-change IRQ (32-bit), 1 = pin enabled. |
**************************************************************************/ |
void neorv32_gpio_pin_change_config(uint32_t pin_sel) { |
|
GPIO_INPUT = pin_sel; |
} |
|
/lib/source/neorv32_pwm.c
90,6 → 90,15
|
|
/**********************************************************************//** |
* Enable pulse width modulation controller. |
**************************************************************************/ |
void neorv32_pwm_enable(void) { |
|
PWM_CT |= ((uint32_t)(1 << PWM_CT_EN)); |
} |
|
|
/**********************************************************************//** |
* Get number of implemented channels. |
* @warning This function will override all duty cycle configuration registers. |
* |
/lib/source/neorv32_rte.c
63,11 → 63,6
**************************************************************************/ |
void neorv32_rte_setup(void) { |
|
// check if CSR system is available at all |
if (neorv32_cpu_csr_read(CSR_MISA) == 0) { |
neorv32_uart_print("<RTE> WARNING! CPU CSR system not available! </RTE>"); |
} |
|
// configure trap handler base address |
uint32_t mtvec_base = (uint32_t)(&__neorv32_rte_core); |
neorv32_cpu_csr_write(CSR_MTVEC, mtvec_base); |
137,7 → 132,7
register uint32_t rte_mcause = neorv32_cpu_csr_read(CSR_MCAUSE); |
|
// compute return address |
if ((rte_mcause & 0x80000000) == 0) { // modify pc only if exception |
if (((int32_t)rte_mcause) >= 0) { // modify pc only if exception (MSB cleared) |
|
// get low half word of faulting instruction |
register uint32_t rte_trap_inst; |
203,6 → 198,10
**************************************************************************/ |
static void __neorv32_rte_debug_exc_handler(void) { |
|
if (neorv32_uart0_available() == 0) { |
return; // handler cannot output anything if UART0 is not implemented |
} |
|
char tmp; |
|
// intro |
266,6 → 265,10
**************************************************************************/ |
void neorv32_rte_print_hw_config(void) { |
|
if (neorv32_uart0_available() == 0) { |
return; // cannot output anything if UART0 is not implemented |
} |
|
uint32_t tmp; |
int i; |
char c; |
273,50 → 276,57
neorv32_uart_printf("\n\n<<< Processor Configuration Overview >>>\n"); |
|
// Processor - general stuff |
neorv32_uart_printf("\n=== << General >> ===\n"); |
neorv32_uart_printf("Clock: %u Hz\n", SYSINFO_CLK); |
neorv32_uart_printf("User ID: 0x%x\n", SYSINFO_USER_CODE); |
neorv32_uart_printf("Full HW reset: "); __neorv32_rte_print_true_false(SYSINFO_FEATURES & (1 << SYSINFO_FEATURES_HW_RESET)); |
neorv32_uart_printf("On-chip debug: "); __neorv32_rte_print_true_false(SYSINFO_FEATURES & (1 << SYSINFO_FEATURES_OCD)); |
neorv32_uart0_printf("\n=== << General >> ===\n" |
"Clock: %u Hz\n" |
"User ID: 0x%x\n", SYSINFO_CLK, SYSINFO_USER_CODE); |
neorv32_uart0_printf("Full HW reset: "); __neorv32_rte_print_true_false(SYSINFO_FEATURES & (1 << SYSINFO_FEATURES_HW_RESET)); |
neorv32_uart0_printf("Boot Config.: Boot "); |
if (SYSINFO_FEATURES & (1 << SYSINFO_FEATURES_BOOTLOADER)) { |
neorv32_uart0_printf("via Bootloader\n"); |
} |
else { |
neorv32_uart0_printf("from memory (@ 0x%x)\n", SYSINFO_ISPACE_BASE); |
} |
neorv32_uart0_printf("On-chip debug: "); __neorv32_rte_print_true_false(SYSINFO_FEATURES & (1 << SYSINFO_FEATURES_OCD)); |
|
|
// CPU configuration |
neorv32_uart_printf("\n=== << CPU >> ===\n"); |
neorv32_uart0_printf("\n=== << CPU >> ===\n"); |
|
// ID |
neorv32_uart_printf("Hart ID: 0x%x\n", neorv32_cpu_csr_read(CSR_MHARTID)); |
neorv32_uart_printf("Vendor ID: 0x%x\n", neorv32_cpu_csr_read(CSR_MVENDORID)); |
neorv32_uart0_printf("Hart ID: 0x%x\n" |
"Vendor ID: 0x%x\n", neorv32_cpu_csr_read(CSR_MHARTID), neorv32_cpu_csr_read(CSR_MVENDORID)); |
|
tmp = neorv32_cpu_csr_read(CSR_MARCHID); |
neorv32_uart_printf("Architecture ID: 0x%x", tmp); |
neorv32_uart0_printf("Architecture ID: 0x%x", tmp); |
if (tmp == NEORV32_ARCHID) { |
neorv32_uart_printf(" (NEORV32)"); |
neorv32_uart0_printf(" (NEORV32)"); |
} |
|
// hardware version |
neorv32_uart_printf("\nImplementation ID: 0x%x (", neorv32_cpu_csr_read(CSR_MIMPID)); |
neorv32_uart0_printf("\nImplementation ID: 0x%x (", neorv32_cpu_csr_read(CSR_MIMPID)); |
neorv32_rte_print_hw_version(); |
neorv32_uart_putc(')'); |
neorv32_uart0_putc(')'); |
|
// CPU architecture and endianness |
neorv32_uart_printf("\nArchitecture: "); |
neorv32_uart0_printf("\nArchitecture: "); |
tmp = neorv32_cpu_csr_read(CSR_MISA); |
tmp = (tmp >> 30) & 0x03; |
if (tmp == 1) { |
neorv32_uart_printf("rv32-little"); |
neorv32_uart0_printf("rv32-little"); |
} |
else { |
neorv32_uart_printf("unknown"); |
neorv32_uart0_printf("unknown"); |
} |
|
// CPU extensions |
neorv32_uart_printf("\nExtensions: "); |
neorv32_uart0_printf("\nISA extensions: "); |
tmp = neorv32_cpu_csr_read(CSR_MISA); |
for (i=0; i<26; i++) { |
if (tmp & (1 << i)) { |
c = (char)('A' + i); |
neorv32_uart_putc(c); |
neorv32_uart_putc(' '); |
neorv32_uart0_putc(c); |
neorv32_uart0_putc(' '); |
} |
} |
|
323,68 → 333,67
// Z* CPU extensions (from custom "mzext" CSR) |
tmp = neorv32_cpu_csr_read(CSR_MZEXT); |
if (tmp & (1<<CSR_MZEXT_ZICSR)) { |
neorv32_uart_printf("Zicsr "); |
neorv32_uart0_printf("Zicsr "); |
} |
if (tmp & (1<<CSR_MZEXT_ZIFENCEI)) { |
neorv32_uart_printf("Zifencei "); |
neorv32_uart0_printf("Zifencei "); |
} |
if (tmp & (1<<CSR_MZEXT_ZMMUL)) { |
neorv32_uart0_printf("Zmmul "); |
} |
|
if (tmp & (1<<CSR_MZEXT_ZFINX)) { |
neorv32_uart_printf("Zfinx "); |
neorv32_uart0_printf("Zfinx "); |
} |
if (tmp & (1<<CSR_MZEXT_ZXNOCNT)) { |
neorv32_uart_printf("Zxnocnt(!) "); |
neorv32_uart0_printf("Zxnocnt(!) "); |
} |
if (tmp & (1<<CSR_MZEXT_ZXSCNT)) { |
neorv32_uart_printf("Zxscnt(!) "); |
neorv32_uart0_printf("Zxscnt(!) "); |
} |
if (tmp & (1<<CSR_MZEXT_DEBUGMODE)) { |
neorv32_uart_printf("Debug-Mode "); |
neorv32_uart0_printf("Debug-Mode "); |
} |
|
// check physical memory protection |
neorv32_uart_printf("\nPMP: "); |
neorv32_uart0_printf("\nPMP: "); |
uint32_t pmp_num_regions = neorv32_cpu_pmp_get_num_regions(); |
if (pmp_num_regions != 0) { |
neorv32_uart_printf("%u regions, %u bytes minimal granularity\n", pmp_num_regions, neorv32_cpu_pmp_get_granularity()); |
neorv32_uart0_printf("%u regions, %u bytes minimal granularity\n", pmp_num_regions, neorv32_cpu_pmp_get_granularity()); |
} |
else { |
neorv32_uart_printf("not implemented\n"); |
neorv32_uart0_printf("not implemented\n"); |
} |
|
// check hardware performance monitors |
neorv32_uart_printf("HPM Counters: %u counters, %u-bit wide\n", neorv32_cpu_hpm_get_counters(), neorv32_cpu_hpm_get_size()); |
neorv32_uart0_printf("HPM Counters: %u counters, %u-bit wide\n", neorv32_cpu_hpm_get_counters(), neorv32_cpu_hpm_get_size()); |
|
|
// Memory configuration |
neorv32_uart_printf("\n=== << Memory Configuration >> ===\n"); |
neorv32_uart0_printf("\n=== << Memory Configuration >> ===\n"); |
|
neorv32_uart_printf("Instr. base address: 0x%x\n", SYSINFO_ISPACE_BASE); |
neorv32_uart0_printf("Instr. base address: 0x%x\n", SYSINFO_ISPACE_BASE); |
|
// IMEM |
neorv32_uart_printf("Internal IMEM: "); |
neorv32_uart0_printf("Internal IMEM: "); |
if (SYSINFO_FEATURES & (1 << SYSINFO_FEATURES_MEM_INT_IMEM)) { |
neorv32_uart_printf("yes, %u bytes", SYSINFO_IMEM_SIZE); |
if (SYSINFO_FEATURES & (1 << SYSINFO_FEATURES_MEM_INT_IMEM_ROM)) { |
neorv32_uart_printf(", read-only (ROM)"); |
} |
neorv32_uart0_printf("yes, %u bytes\n", SYSINFO_IMEM_SIZE); |
} |
else { |
neorv32_uart_printf("no"); |
neorv32_uart0_printf("no\n"); |
} |
neorv32_uart_printf("\n"); |
|
// DMEM |
neorv32_uart_printf("Data base address: 0x%x\n", SYSINFO_DSPACE_BASE); |
neorv32_uart_printf("Internal DMEM: "); |
if (SYSINFO_FEATURES & (1 << SYSINFO_FEATURES_MEM_INT_DMEM)) { neorv32_uart_printf("yes, %u bytes\n", SYSINFO_DMEM_SIZE); } |
else { neorv32_uart_printf("no\n"); } |
neorv32_uart0_printf("Data base address: 0x%x\n", SYSINFO_DSPACE_BASE); |
neorv32_uart0_printf("Internal DMEM: "); |
if (SYSINFO_FEATURES & (1 << SYSINFO_FEATURES_MEM_INT_DMEM)) { neorv32_uart0_printf("yes, %u bytes\n", SYSINFO_DMEM_SIZE); } |
else { neorv32_uart0_printf("no\n"); } |
|
// i-cache |
neorv32_uart_printf("Internal i-cache: "); |
neorv32_uart0_printf("Internal i-cache: "); |
__neorv32_rte_print_true_false(SYSINFO_FEATURES & (1 << SYSINFO_FEATURES_ICACHE)); |
if (SYSINFO_FEATURES & (1 << SYSINFO_FEATURES_ICACHE)) { |
neorv32_uart_printf("- "); |
neorv32_uart0_printf("- "); |
|
uint32_t ic_block_size = (SYSINFO_CACHE >> SYSINFO_CACHE_IC_BLOCK_SIZE_0) & 0x0F; |
if (ic_block_size) { |
405,71 → 414,45
uint32_t ic_associativity = (SYSINFO_CACHE >> SYSINFO_CACHE_IC_ASSOCIATIVITY_0) & 0x0F; |
ic_associativity = 1 << ic_associativity; |
|
neorv32_uart_printf("%u bytes: %u set(s), %u block(s) per set, %u bytes per block", ic_associativity*ic_num_blocks*ic_block_size, ic_associativity, ic_num_blocks, ic_block_size); |
neorv32_uart0_printf("%u bytes: %u set(s), %u block(s) per set, %u bytes per block", ic_associativity*ic_num_blocks*ic_block_size, ic_associativity, ic_num_blocks, ic_block_size); |
if (ic_associativity == 1) { |
neorv32_uart_printf(" (direct-mapped)\n"); |
neorv32_uart0_printf(" (direct-mapped)\n"); |
} |
else if (((SYSINFO_CACHE >> SYSINFO_CACHE_IC_REPLACEMENT_0) & 0x0F) == 1) { |
neorv32_uart_printf(" (LRU replacement policy)\n"); |
neorv32_uart0_printf(" (LRU replacement policy)\n"); |
} |
else { |
neorv32_uart_printf("\n"); |
neorv32_uart0_printf("\n"); |
} |
} |
|
neorv32_uart_printf("Bootloader: "); |
__neorv32_rte_print_true_false(SYSINFO_FEATURES & (1 << SYSINFO_FEATURES_BOOTLOADER)); |
|
neorv32_uart_printf("Ext. bus interface: "); |
neorv32_uart0_printf("Ext. bus interface: "); |
__neorv32_rte_print_true_false(SYSINFO_FEATURES & (1 << SYSINFO_FEATURES_MEM_EXT)); |
neorv32_uart_printf("Ext. bus Endianness: "); |
neorv32_uart0_printf("Ext. bus Endianness: "); |
if (SYSINFO_FEATURES & (1 << SYSINFO_FEATURES_MEM_EXT_ENDIAN)) { |
neorv32_uart_printf("big\n"); |
neorv32_uart0_printf("big\n"); |
} |
else { |
neorv32_uart_printf("little\n"); |
neorv32_uart0_printf("little\n"); |
} |
|
// peripherals |
neorv32_uart_printf("\n=== << Peripherals >> ===\n"); |
neorv32_uart0_printf("\n=== << Peripherals >> ===\n"); |
|
tmp = SYSINFO_FEATURES; |
|
neorv32_uart_printf("GPIO - "); |
__neorv32_rte_print_true_false(tmp & (1 << SYSINFO_FEATURES_IO_GPIO)); |
|
neorv32_uart_printf("MTIME - "); |
__neorv32_rte_print_true_false(tmp & (1 << SYSINFO_FEATURES_IO_MTIME)); |
|
neorv32_uart_printf("UART0 - "); |
__neorv32_rte_print_true_false(tmp & (1 << SYSINFO_FEATURES_IO_UART0)); |
|
neorv32_uart_printf("UART1 - "); |
__neorv32_rte_print_true_false(tmp & (1 << SYSINFO_FEATURES_IO_UART1)); |
|
neorv32_uart_printf("SPI - "); |
__neorv32_rte_print_true_false(tmp & (1 << SYSINFO_FEATURES_IO_SPI)); |
|
neorv32_uart_printf("TWI - "); |
__neorv32_rte_print_true_false(tmp & (1 << SYSINFO_FEATURES_IO_TWI)); |
|
neorv32_uart_printf("PWM - "); |
__neorv32_rte_print_true_false(tmp & (1 << SYSINFO_FEATURES_IO_PWM)); |
|
neorv32_uart_printf("WDT - "); |
__neorv32_rte_print_true_false(tmp & (1 << SYSINFO_FEATURES_IO_WDT)); |
|
neorv32_uart_printf("TRNG - "); |
__neorv32_rte_print_true_false(tmp & (1 << SYSINFO_FEATURES_IO_TRNG)); |
|
neorv32_uart_printf("CFS - "); |
__neorv32_rte_print_true_false(tmp & (1 << SYSINFO_FEATURES_IO_CFS)); |
|
neorv32_uart_printf("NCO - "); |
__neorv32_rte_print_true_false(tmp & (1 << SYSINFO_FEATURES_IO_NCO)); |
|
neorv32_uart_printf("NEOLED - "); |
__neorv32_rte_print_true_false(tmp & (1 << SYSINFO_FEATURES_IO_NEOLED)); |
neorv32_uart0_printf("GPIO - "); __neorv32_rte_print_true_false(tmp & (1 << SYSINFO_FEATURES_IO_GPIO)); |
neorv32_uart0_printf("MTIME - "); __neorv32_rte_print_true_false(tmp & (1 << SYSINFO_FEATURES_IO_MTIME)); |
neorv32_uart0_printf("UART0 - "); __neorv32_rte_print_true_false(tmp & (1 << SYSINFO_FEATURES_IO_UART0)); |
neorv32_uart0_printf("UART1 - "); __neorv32_rte_print_true_false(tmp & (1 << SYSINFO_FEATURES_IO_UART1)); |
neorv32_uart0_printf("SPI - "); __neorv32_rte_print_true_false(tmp & (1 << SYSINFO_FEATURES_IO_SPI)); |
neorv32_uart0_printf("TWI - "); __neorv32_rte_print_true_false(tmp & (1 << SYSINFO_FEATURES_IO_TWI)); |
neorv32_uart0_printf("PWM - "); __neorv32_rte_print_true_false(tmp & (1 << SYSINFO_FEATURES_IO_PWM)); |
neorv32_uart0_printf("WDT - "); __neorv32_rte_print_true_false(tmp & (1 << SYSINFO_FEATURES_IO_WDT)); |
neorv32_uart0_printf("TRNG - "); __neorv32_rte_print_true_false(tmp & (1 << SYSINFO_FEATURES_IO_TRNG)); |
neorv32_uart0_printf("CFS - "); __neorv32_rte_print_true_false(tmp & (1 << SYSINFO_FEATURES_IO_CFS)); |
neorv32_uart0_printf("SLINK - "); __neorv32_rte_print_true_false(tmp & (1 << SYSINFO_FEATURES_IO_SLINK)); |
neorv32_uart0_printf("NEOLED - "); __neorv32_rte_print_true_false(tmp & (1 << SYSINFO_FEATURES_IO_NEOLED)); |
neorv32_uart0_printf("XIRQ - "); __neorv32_rte_print_true_false(tmp & (1 << SYSINFO_FEATURES_IO_XIRQ)); |
} |
|
|
482,10 → 465,10
static void __neorv32_rte_print_true_false(int state) { |
|
if (state) { |
neorv32_uart_print("yes\n"); |
neorv32_uart0_print("yes\n"); |
} |
else { |
neorv32_uart_print("no\n"); |
neorv32_uart0_print("no\n"); |
} |
} |
|
500,12 → 483,12
|
static const char hex_symbols[16] = "0123456789ABCDEF"; |
|
neorv32_uart_print("0x"); |
neorv32_uart0_print("0x"); |
|
int i; |
for (i=0; i<8; i++) { |
uint32_t index = (num >> (28 - 4*i)) & 0xF; |
neorv32_uart_putc(hex_symbols[index]); |
neorv32_uart0_putc(hex_symbols[index]); |
} |
} |
|
518,6 → 501,10
uint32_t i; |
char tmp, cnt; |
|
if (neorv32_uart0_available() == 0) { |
return; // cannot output anything if UART0 is not implemented |
} |
|
for (i=0; i<4; i++) { |
|
tmp = (char)(neorv32_cpu_csr_read(CSR_MIMPID) >> (24 - 8*i)); |
530,11 → 517,11
} |
|
if (cnt) { |
neorv32_uart_putc('0' + cnt); |
neorv32_uart0_putc('0' + cnt); |
} |
neorv32_uart_putc('0' + tmp); |
neorv32_uart0_putc('0' + tmp); |
if (i < 3) { |
neorv32_uart_putc('.'); |
neorv32_uart0_putc('.'); |
} |
} |
} |
545,10 → 532,14
**************************************************************************/ |
void neorv32_rte_print_credits(void) { |
|
neorv32_uart_print("The NEORV32 Processor Project\n" |
"Copyright 2021, Stephan Nolting\n" |
"BSD 3-Clause License\n" |
"https://github.com/stnolting/neorv32\n\n"); |
if (neorv32_uart0_available() == 0) { |
return; // cannot output anything if UART0 is not implemented |
} |
|
neorv32_uart0_print("The NEORV32 RISC-V Processor\n" |
"(c) Stephan Nolting\n" |
"BSD 3-Clause License\n" |
"https://github.com/stnolting/neorv32\n\n"); |
} |
|
|
575,22 → 566,26
int u,v,w; |
uint32_t tmp; |
|
if (neorv32_uart0_available() == 0) { |
return; // cannot output anything if UART0 is not implemented |
} |
|
for (u=0; u<11; u++) { |
neorv32_uart_print("\n"); |
neorv32_uart0_print("\n"); |
for (v=0; v<4; v++) { |
tmp = logo_data_c[u][v]; |
for (w=0; w<32; w++){ |
if (tmp & 0x80000000UL) { // check MSB |
neorv32_uart_putc('#'); |
if (((int32_t)tmp) < 0) { // check MSB |
neorv32_uart0_putc('#'); |
} |
else { |
neorv32_uart_putc(' '); |
neorv32_uart0_putc(' '); |
} |
tmp <<= 1; |
} |
} |
} |
neorv32_uart_print("\n"); |
neorv32_uart0_print("\n"); |
} |
|
|
599,6 → 594,10
**************************************************************************/ |
void neorv32_rte_print_license(void) { |
|
if (neorv32_uart0_available() == 0) { |
return; // cannot output anything if UART0 is not implemented |
} |
|
neorv32_uart_print( |
"\n" |
"BSD 3-Clause License\n" |
644,41 → 643,41
uint32_t misa_cc = 0; |
|
#if defined __riscv_atomic || defined __riscv_a |
misa_cc |= 1 << CSR_MISA_A_EXT; |
misa_cc |= 1 << CSR_MISA_A; |
#endif |
|
#ifdef __riscv_b |
misa_cc |= 1 << CSR_MISA_B_EXT; |
misa_cc |= 1 << CSR_MISA_B; |
#endif |
|
#if defined __riscv_compressed || defined __riscv_c |
misa_cc |= 1 << CSR_MISA_C_EXT; |
misa_cc |= 1 << CSR_MISA_C; |
#endif |
|
#if (__riscv_flen == 64) || defined __riscv_d |
misa_cc |= 1 << CSR_MISA_D_EXT; |
misa_cc |= 1 << CSR_MISA_D; |
#endif |
|
#ifdef __riscv_32e |
misa_cc |= 1 << CSR_MISA_E_EXT; |
misa_cc |= 1 << CSR_MISA_E; |
#else |
misa_cc |= 1 << CSR_MISA_I_EXT; |
misa_cc |= 1 << CSR_MISA_I; |
#endif |
|
#if (__riscv_flen == 32) || defined __riscv_f |
misa_cc |= 1 << CSR_MISA_F_EXT; |
misa_cc |= 1 << CSR_MISA_F; |
#endif |
|
#if defined __riscv_mul || defined __riscv_m |
misa_cc |= 1 << CSR_MISA_M_EXT; |
misa_cc |= 1 << CSR_MISA_M; |
#endif |
|
#if (__riscv_xlen == 32) |
misa_cc |= 1 << CSR_MISA_MXL_LO_EXT; |
misa_cc |= 1 << CSR_MISA_MXL_LO; |
#elif (__riscv_xlen == 64) |
misa_cc |= 2 << CSR_MISA_MXL_LO_EXT; |
misa_cc |= 2 << CSR_MISA_MXL_LO; |
#else |
misa_cc |= 3 << CSR_MISA_MXL_LO_EXT; |
misa_cc |= 3 << CSR_MISA_MXL_LO; |
#endif |
|
return misa_cc; |
704,7 → 703,7
return 0; |
} |
else { |
if (silent == 0) { |
if ((silent == 0) || (neorv32_uart0_available() == 0)) { |
neorv32_uart_printf("\nWARNING! SW_ISA (features required) vs HW_ISA (features available) mismatch!\n" |
"SW_ISA = 0x%x (compiler flags)\n" |
"HW_ISA = 0x%x (misa csr)\n\n", misa_sw, misa_hw); |
/lib/source/neorv32_slink.c
0,0 → 1,401
// ################################################################################################# |
// # << NEORV32: neorv32_slink.c - Stream Link Interface HW Driver >> # |
// # ********************************************************************************************* # |
// # 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 # |
// ################################################################################################# |
|
|
/**********************************************************************//** |
* @file neorv32_slink.h |
* @author Stephan Nolting |
* @brief Stream Link Interface HW driver source file. |
**************************************************************************/ |
|
#include "neorv32.h" |
#include "neorv32_slink.h" |
|
|
/**********************************************************************//** |
* Check if stream link interface was synthesized. |
* |
* @return 0 if SLINK was not synthesized, 1 if SLINK is available. |
**************************************************************************/ |
int neorv32_slink_available(void) { |
|
if (SYSINFO_FEATURES & (1 << SYSINFO_FEATURES_IO_SLINK)) { |
return 1; |
} |
else { |
return 0; |
} |
} |
|
|
/**********************************************************************//** |
* Activate stream link interface. |
**************************************************************************/ |
void neorv32_slink_enable(void) { |
|
SLINK_CT |= (uint32_t)(1 << SLINK_CT_EN); |
} |
|
|
/**********************************************************************//** |
* Deactivate stream link interface. |
* |
* @note This will also clear all link FIFOs. |
**************************************************************************/ |
void neorv32_slink_disable(void) { |
|
SLINK_CT &= ~(uint32_t)(1 << SLINK_CT_EN); |
} |
|
|
/**********************************************************************//** |
* Get number of implemented RX links |
* |
* @return Number of implemented RX link (0..8). |
**************************************************************************/ |
int neorv32_slink_get_rx_num(void) { |
|
if (neorv32_slink_available()) { |
return (int)(((SLINK_CT >> SLINK_CT_RX_NUM0) & 0x07) + 1); |
} |
else { |
return 0; |
} |
} |
|
|
/**********************************************************************//** |
* Get number of implemented TX links |
* |
* @return Number of implemented TX link (0..8). |
**************************************************************************/ |
int neorv32_slink_get_tx_num(void) { |
|
if (neorv32_slink_available()) { |
return (int)(((SLINK_CT >> SLINK_CT_TX_NUM0) & 0x07) + 1); |
} |
else { |
return 0; |
} |
} |
|
|
/**********************************************************************//** |
* Get FIFO depth of RX links |
* |
* @return FIFO depth of RX links (1..32768); 0 if no RX links implemented. |
**************************************************************************/ |
int neorv32_slink_get_rx_depth(void) { |
|
if (neorv32_slink_available()) { |
uint32_t tmp = (SLINK_CT >> SLINK_CT_RX_FIFO_S0) & 0x0f; |
return (int)(1 << tmp); |
} |
else { |
return 0; |
} |
} |
|
|
/**********************************************************************//** |
* Get FIFO depth of TX links |
* |
* @return FIFO depth of TX links (1..32768); 0 if no TX links implemented. |
**************************************************************************/ |
int neorv32_slink_get_tx_depth(void) { |
|
if (neorv32_slink_available()) { |
uint32_t tmp = (SLINK_CT >> SLINK_CT_TX_FIFO_S0) & 0x0f; |
return (int)(1 << tmp); |
} |
else { |
return 0; |
} |
} |
|
|
/**********************************************************************//** |
* Write data to TX stream link 0 (non-blocking) |
* |
* @param[in] tx_data Data to send to link. |
* @return 0 if data was send, 1 if link is still busy. |
**************************************************************************/ |
int neorv32_slink_tx0_nonblocking(uint32_t tx_data) { |
|
if (SLINK_CT & (1 << SLINK_CT_TX0_FREE)) { |
SLINK_CH0 = tx_data; |
return 0; |
} |
return 1; |
} |
|
|
/**********************************************************************//** |
* Write data to TX stream link 1 (non-blocking) |
* |
* @param[in] tx_data Data to send to link. |
* @return 0 if data was send, 1 if link is still busy. |
**************************************************************************/ |
int neorv32_slink_tx1_nonblocking(uint32_t tx_data) { |
|
if (SLINK_CT & (1 << SLINK_CT_TX1_FREE)) { |
SLINK_CH1 = tx_data; |
return 0; |
} |
return 1; |
} |
|
|
/**********************************************************************//** |
* Write data to TX stream link 2 (non-blocking) |
* |
* @param[in] tx_data Data to send to link. |
* @return 0 if data was send, 1 if link is still busy. |
**************************************************************************/ |
int neorv32_slink_tx2_nonblocking(uint32_t tx_data) { |
|
if (SLINK_CT & (1 << SLINK_CT_TX2_FREE)) { |
SLINK_CH2 = tx_data; |
return 0; |
} |
return 1; |
} |
|
|
/**********************************************************************//** |
* Write data to TX stream link 3 (non-blocking) |
* |
* @param[in] tx_data Data to send to link. |
* @return 0 if data was send, 1 if link is still busy. |
**************************************************************************/ |
int neorv32_slink_tx3_nonblocking(uint32_t tx_data) { |
|
if (SLINK_CT & (1 << SLINK_CT_TX3_FREE)) { |
SLINK_CH3 = tx_data; |
return 0; |
} |
return 1; |
} |
|
|
/**********************************************************************//** |
* Write data to TX stream link 4 (non-blocking) |
* |
* @param[in] tx_data Data to send to link. |
* @return 0 if data was send, 1 if link is still busy. |
**************************************************************************/ |
int neorv32_slink_tx4_nonblocking(uint32_t tx_data) { |
|
if (SLINK_CT & (1 << SLINK_CT_TX4_FREE)) { |
SLINK_CH4 = tx_data; |
return 0; |
} |
return 1; |
} |
|
|
/**********************************************************************//** |
* Write data to TX stream link 5 (non-blocking) |
* |
* @param[in] tx_data Data to send to link. |
* @return 0 if data was send, 1 if link is still busy. |
**************************************************************************/ |
int neorv32_slink_tx5_nonblocking(uint32_t tx_data) { |
|
if (SLINK_CT & (1 << SLINK_CT_TX5_FREE)) { |
SLINK_CH5 = tx_data; |
return 0; |
} |
return 1; |
} |
|
|
/**********************************************************************//** |
* Write data to TX stream link 6 (non-blocking) |
* |
* @param[in] tx_data Data to send to link. |
* @return 0 if data was send, 1 if link is still busy. |
**************************************************************************/ |
int neorv32_slink_tx6_nonblocking(uint32_t tx_data) { |
|
if (SLINK_CT & (1 << SLINK_CT_TX6_FREE)) { |
SLINK_CH6 = tx_data; |
return 0; |
} |
return 1; |
} |
|
|
/**********************************************************************//** |
* Write data to TX stream link 7 (non-blocking) |
* |
* @param[in] tx_data Data to send to link. |
* @return 0 if data was send, 1 if link is still busy. |
**************************************************************************/ |
int neorv32_slink_tx7_nonblocking(uint32_t tx_data) { |
|
if (SLINK_CT & (1 << SLINK_CT_TX7_FREE)) { |
SLINK_CH7 = tx_data; |
return 0; |
} |
return 1; |
} |
|
|
/**********************************************************************//** |
* Read data from RX stream link 0 (non-blocking) |
* |
* @param[in,out] rx_data Pointer to return read data. Only valid if function return value = 0. |
* @return 0 if data was received, 1 if there is no data to fetch. |
**************************************************************************/ |
int neorv32_slink_rx0_nonblocking(uint32_t *rx_data) { |
|
if (SLINK_CT & (1 << SLINK_CT_RX0_AVAIL)) { |
*rx_data = SLINK_CH0; |
return 0; |
} |
return 1; |
} |
|
|
/**********************************************************************//** |
* Read data from RX stream link 1 (non-blocking) |
* |
* @param[in,out] rx_data Pointer to return read data. Only valid if function return value = 0. |
* @return 0 if data was received, 1 if there is no data to fetch. |
**************************************************************************/ |
int neorv32_slink_rx1_nonblocking(uint32_t *rx_data) { |
|
if (SLINK_CT & (1 << SLINK_CT_RX1_AVAIL)) { |
*rx_data = SLINK_CH1; |
return 0; |
} |
return 1; |
} |
|
|
/**********************************************************************//** |
* Read data from RX stream link 2 (non-blocking) |
* |
* @param[in,out] rx_data Pointer to return read data. Only valid if function return value = 0. |
* @return 0 if data was received, 1 if there is no data to fetch. |
**************************************************************************/ |
int neorv32_slink_rx2_nonblocking(uint32_t *rx_data) { |
|
if (SLINK_CT & (1 << SLINK_CT_RX2_AVAIL)) { |
*rx_data = SLINK_CH2; |
return 0; |
} |
return 1; |
} |
|
|
/**********************************************************************//** |
* Read data from RX stream link 3 (non-blocking) |
* |
* @param[in,out] rx_data Pointer to return read data. Only valid if function return value = 0. |
* @return 0 if data was received, 1 if there is no data to fetch. |
**************************************************************************/ |
int neorv32_slink_rx3_nonblocking(uint32_t *rx_data) { |
|
if (SLINK_CT & (1 << SLINK_CT_RX3_AVAIL)) { |
*rx_data = SLINK_CH3; |
return 0; |
} |
return 1; |
} |
|
|
/**********************************************************************//** |
* Read data from RX stream link 4 (non-blocking) |
* |
* @param[in,out] rx_data Pointer to return read data. Only valid if function return value = 0. |
* @return 0 if data was received, 1 if there is no data to fetch. |
**************************************************************************/ |
int neorv32_slink_rx4_nonblocking(uint32_t *rx_data) { |
|
if (SLINK_CT & (1 << SLINK_CT_RX4_AVAIL)) { |
*rx_data = SLINK_CH4; |
return 0; |
} |
return 1; |
} |
|
|
/**********************************************************************//** |
* Read data from RX stream link 5 (non-blocking) |
* |
* @param[in,out] rx_data Pointer to return read data. Only valid if function return value = 0. |
* @return 0 if data was received, 1 if there is no data to fetch. |
**************************************************************************/ |
int neorv32_slink_rx5_nonblocking(uint32_t *rx_data) { |
|
if (SLINK_CT & (1 << SLINK_CT_RX5_AVAIL)) { |
*rx_data = SLINK_CH5; |
return 0; |
} |
return 1; |
} |
|
|
/**********************************************************************//** |
* Read data from RX stream link 6 (non-blocking) |
* |
* @param[in,out] rx_data Pointer to return read data. Only valid if function return value = 0. |
* @return 0 if data was received, 1 if there is no data to fetch. |
**************************************************************************/ |
int neorv32_slink_rx6_nonblocking(uint32_t *rx_data) { |
|
if (SLINK_CT & (1 << SLINK_CT_RX6_AVAIL)) { |
*rx_data = SLINK_CH6; |
return 0; |
} |
return 1; |
} |
|
|
/**********************************************************************//** |
* Read data from RX stream link 7 (non-blocking) |
* |
* @param[in,out] rx_data Pointer to return read data. Only valid if function return value = 0. |
* @return 0 if data was received, 1 if there is no data to fetch. |
**************************************************************************/ |
int neorv32_slink_rx7_nonblocking(uint32_t *rx_data) { |
|
if (SLINK_CT & (1 << SLINK_CT_RX7_AVAIL)) { |
*rx_data = SLINK_CH7; |
return 0; |
} |
return 1; |
} |
/lib/source/neorv32_spi.c
98,6 → 98,15
|
|
/**********************************************************************//** |
* Enable SPI controller. |
**************************************************************************/ |
void neorv32_spi_enable(void) { |
|
SPI_CT |= ((uint32_t)(1 << SPI_CT_EN)); |
} |
|
|
/**********************************************************************//** |
* Activate SPI chip select signal. |
* |
* @note The chip select output lines are LOW when activated. |
/lib/source/neorv32_twi.c
94,6 → 94,15
|
|
/**********************************************************************//** |
* Enable TWI controller. |
**************************************************************************/ |
void neorv32_twi_enable(void) { |
|
TWI_CT |= (uint32_t)(1 << TWI_CT_EN); |
} |
|
|
/**********************************************************************//** |
* Activate sending ACKs by controller (MACK). |
**************************************************************************/ |
void neorv32_twi_mack_enable(void) { |
/lib/source/neorv32_uart.c
46,6 → 46,7
#include "neorv32.h" |
#include "neorv32_uart.h" |
#include <string.h> |
#include <stdarg.h> |
|
/// \cond |
// Private functions |
94,6 → 95,13
|
|
/**********************************************************************//** |
* Enable UART0. |
* @warning This functions maps to UART0 (primary UART). |
**************************************************************************/ |
void neorv32_uart_enable(void) { neorv32_uart0_enable(); } |
|
|
/**********************************************************************//** |
* Send single char via UART0. |
* |
* @warning This functions maps to UART0 (primary UART). |
310,6 → 318,15
|
|
/**********************************************************************//** |
* Enable UART0. |
**************************************************************************/ |
void neorv32_uart0_enable(void) { |
|
UART0_CT = ((uint32_t)(1 << UART_CT_EN)); |
} |
|
|
/**********************************************************************//** |
* Send single char via UART0. |
* |
* @note This function is blocking. |
318,13 → 335,9
**************************************************************************/ |
void neorv32_uart0_putc(char c) { |
|
#if defined UART0_SIM_MODE || defined UART_SIM_MODE |
UART0_DATA = ((uint32_t)c) << UART_DATA_LSB; |
#else |
// wait for previous transfer to finish |
while ((UART0_CT & (1<<UART_CT_TX_BUSY)) != 0); |
UART0_DATA = ((uint32_t)c) << UART_DATA_LSB; |
#endif |
} |
|
|
665,6 → 678,15
|
|
/**********************************************************************//** |
* Enable UART1. |
**************************************************************************/ |
void neorv32_uart1_enable(void) { |
|
UART1_CT |= ((uint32_t)(1 << UART_CT_EN)); |
} |
|
|
/**********************************************************************//** |
* Send single char via UART1. |
* |
* @note This function is blocking. |
673,13 → 695,9
**************************************************************************/ |
void neorv32_uart1_putc(char c) { |
|
#ifdef UART1_SIM_MODE |
UART1_DATA = ((uint32_t)c) << UART_DATA_LSB; |
#else |
// wait for previous transfer to finish |
while ((UART1_CT & (1<<UART_CT_TX_BUSY)) != 0); |
UART1_DATA = ((uint32_t)c) << UART_DATA_LSB; |
#endif |
} |
|
|
/lib/source/neorv32_wdt.c
64,9 → 64,9
/**********************************************************************//** |
* Configure and enable watchdog timer. The WDT control register bits are listed in #NEORV32_WDT_CT_enum. |
* |
* @param[in] prsc Clock prescaler to selet timeout interval. See #NEORV32_CLOCK_PRSC_enum. |
* @param[in] prsc Clock prescaler to select timeout interval. See #NEORV32_CLOCK_PRSC_enum. |
* @param[in] mode Trigger system reset on timeout when 1, trigger interrupt on timeout when 0. |
* @param[in] lock Control register will be locked when 1 (unitl next reset). |
* @param[in] lock Control register will be locked when 1 (until next reset). |
**************************************************************************/ |
void neorv32_wdt_setup(uint8_t prsc, uint8_t mode, uint8_t lock) { |
|
91,7 → 91,7
/**********************************************************************//** |
* Disable watchdog timer. |
* |
* @return Returns 0 if WDT is really deativated, -1 otherwise. |
* @return Returns 0 if WDT is really deactivated, -1 otherwise. |
**************************************************************************/ |
int neorv32_wdt_disable(void) { |
|
/lib/source/neorv32_xirq.c
0,0 → 1,219
// ################################################################################################# |
// # << NEORV32: neorv32_xirq.c - External Interrupt controller HW Driver >> # |
// # ********************************************************************************************* # |
// # 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 # |
// ################################################################################################# |
|
|
/**********************************************************************//** |
* @file neorv32_xirq.h |
* @author Stephan Nolting |
* @brief External Interrupt controller HW driver source file. |
**************************************************************************/ |
|
#include "neorv32.h" |
#include "neorv32_xirq.h" |
|
|
/**********************************************************************//** |
* The >private< trap vector look-up table of the XIRQ. |
**************************************************************************/ |
static uint32_t __neorv32_xirq_vector_lut[32] __attribute__((unused)); // trap handler vector table |
|
// private functions |
static void __attribute__((aligned(16))) __attribute__((unused)) __neorv32_xirq_core(void); |
static void __attribute__((unused)) __neorv32_xirq_dummy_handler(void); |
|
|
/**********************************************************************//** |
* Check if external interrupt controller was synthesized. |
* |
* @return 0 if XIRQ was not synthesized, 1 if EXTIRQ is available. |
**************************************************************************/ |
int neorv32_xirq_available(void) { |
|
if (SYSINFO_FEATURES & (1 << SYSINFO_FEATURES_IO_XIRQ)) { |
return 1; |
} |
else { |
return 0; |
} |
} |
|
|
/**********************************************************************//** |
* Initialize XIRQ controller. |
* |
* @note All interrupt channels will be deactivated, all pending IRQs will be deleted and all |
* handler addresses will be deleted. |
* @return 0 if success, 1 if error. |
**************************************************************************/ |
int neorv32_xirq_setup(void) { |
|
XIRQ_IER = 0; // disable all input channels |
XIRQ_IPR = 0xffffffff; // clear/ack all pending IRQs |
|
int i; |
for (i=0; i<32; i++) { |
__neorv32_xirq_vector_lut[i] = (uint32_t)(&__neorv32_xirq_dummy_handler); |
} |
|
// register XIRQ handler in RTE |
return neorv32_rte_exception_install(XIRQ_RTE_ID, __neorv32_xirq_core); |
} |
|
|
/**********************************************************************//** |
* Globally enable XIRQ interrupts (via according FIRQ channel). |
**************************************************************************/ |
void neorv32_xirq_global_enable(void) { |
|
// enable XIRQ fast interrupt channel |
neorv32_cpu_irq_enable(XIRQ_FIRQ_ENABLE); |
} |
|
|
/**********************************************************************//** |
* Globally disable XIRQ interrupts (via according FIRQ channel). |
**************************************************************************/ |
void neorv32_xirq_global_disable(void) { |
|
// enable XIRQ fast interrupt channel |
neorv32_cpu_irq_disable(XIRQ_FIRQ_ENABLE); |
} |
|
|
/**********************************************************************//** |
* Get number of implemented XIRQ channels |
* |
* @return Number of implemented channels (0..32). |
**************************************************************************/ |
int neorv32_xirq_get_num(void) { |
|
uint32_t enable; |
int i, cnt; |
|
if (neorv32_xirq_available()) { |
|
neorv32_cpu_irq_disable(XIRQ_FIRQ_ENABLE); // make sure XIRQ cannot fire |
XIRQ_IER = 0xffffffff; // try to set all enable flags |
enable = XIRQ_IER; // read back actually set flags |
|
// count set bits in enable |
cnt = 0; |
for (i=0; i<32; i++) { |
if (enable & 1) { |
cnt++; |
} |
enable >>= 1; |
} |
return cnt; |
} |
else { |
return 0; |
} |
} |
|
|
/**********************************************************************//** |
* Install exception handler function for XIRQ channel. |
* |
* @note This will also activate the according XIRQ channel and clear a pending IRQ at this channel. |
* |
* @param[in] ch XIRQ interrupt channel (0..31). |
* @param[in] handler The actual handler function for the specified exception (function MUST be of type "void function(void);"). |
* @return 0 if success, 1 if error. |
**************************************************************************/ |
int neorv32_xirq_install(uint8_t ch, void (*handler)(void)) { |
|
// channel valid? |
if (ch < 32) { |
__neorv32_xirq_vector_lut[ch] = (uint32_t)handler; // install handler |
uint32_t mask = 1 << ch; |
XIRQ_IPR = mask; // clear if pending |
XIRQ_IER |= mask; // enable channel |
return 0; |
} |
return 1; |
} |
|
|
/**********************************************************************//** |
* Uninstall exception handler function for XIRQ channel. |
* |
* @note This will also deactivate the according XIRQ channel and clear pending state. |
* |
* @param[in] ch XIRQ interrupt channel (0..31). |
* @return 0 if success, 1 if error. |
**************************************************************************/ |
int neorv32_xirq_uninstall(uint8_t ch) { |
|
// channel valid? |
if (ch < 32) { |
__neorv32_xirq_vector_lut[ch] = (uint32_t)(&__neorv32_xirq_dummy_handler); // override using dummy handler |
uint32_t mask = 1 << ch; |
XIRQ_IER &= ~mask; // disable channel |
XIRQ_IPR = mask; // clear if pending |
return 0; |
} |
return 1; |
} |
|
|
/**********************************************************************//** |
* This is the actual second-level IRQ handler for the XIRQ. It will call the previously installed handler |
* if an XIRQ fires. |
* |
* @note This function must no be used by the user. |
**************************************************************************/ |
static void __attribute__((aligned(16))) __attribute__((unused)) __neorv32_xirq_core(void) { |
|
register uint32_t src = XIRQ_SCR; // get IRQ source (with highest priority) |
src &= 0x1f; |
|
XIRQ_IPR = (uint32_t)(1 << src); // acknowledge pending interrupt |
|
// execute handler |
register uint32_t xirq_handler = __neorv32_xirq_vector_lut[src]; |
void (*handler_pnt)(void); |
handler_pnt = (void*)xirq_handler; |
(*handler_pnt)(); |
} |
|
|
/**********************************************************************//** |
* XIRQ dummy handler. |
**************************************************************************/ |
static void __attribute__((unused)) __neorv32_xirq_dummy_handler(void) { |
|
asm volatile ("nop"); |
} |
|
/ocd-firmware/park_loop.S
99,4 → 99,5
addi s0, zero, SREG_EXECUTE_ACK |
sw s0, DBMEM_SREG_BASE(zero) // ACK that execution is about to start |
csrr s0, dscratch0 // restore s0 from dscratch0 |
fence.i // synchronize i-cache & prefetch with memory (program buffer) |
jalr zero, zero, %lo(DBMEM_PBUF_BASE) // jump to beginning of program buffer |