Line 1... |
Line 1... |
// #################################################################################################
|
// #################################################################################################
|
// # << NEORV32 - Bootloader >> #
|
// # << NEORV32 - Bootloader >> #
|
// # ********************************************************************************************* #
|
// # ********************************************************************************************* #
|
// # BSD 3-Clause License #
|
// # BSD 3-Clause License #
|
// # #
|
// # #
|
// # Copyright (c) 2021, Stephan Nolting. All rights reserved. #
|
// # Copyright (c) 2022, Stephan Nolting. All rights reserved. #
|
// # #
|
// # #
|
// # Redistribution and use in source and binary forms, with or without modification, are #
|
// # Redistribution and use in source and binary forms, with or without modification, are #
|
// # permitted provided that the following conditions are met: #
|
// # permitted provided that the following conditions are met: #
|
// # #
|
// # #
|
// # 1. Redistributions of source code must retain the above copyright notice, this list of #
|
// # 1. Redistributions of source code must retain the above copyright notice, this list of #
|
Line 142... |
Line 142... |
ERROR_SIZE = 1, /**< 1: Insufficient instruction memory capacity */
|
ERROR_SIZE = 1, /**< 1: Insufficient instruction memory capacity */
|
ERROR_CHECKSUM = 2, /**< 2: Checksum error in executable */
|
ERROR_CHECKSUM = 2, /**< 2: Checksum error in executable */
|
ERROR_FLASH = 3 /**< 3: SPI flash access error */
|
ERROR_FLASH = 3 /**< 3: SPI flash access error */
|
};
|
};
|
|
|
|
/**********************************************************************//**
|
|
* Error messages
|
|
**************************************************************************/
|
|
const char error_message[4][24] = {
|
|
"exe signature fail",
|
|
"exceeding IMEM capacity",
|
|
"checksum fail",
|
|
"SPI flash access failed"
|
|
};
|
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* SPI flash commands
|
* SPI flash commands
|
**************************************************************************/
|
**************************************************************************/
|
enum SPI_FLASH_CMD {
|
enum SPI_FLASH_CMD {
|
Line 168... |
Line 178... |
EXE_OFFSET_DATA = 12, /**< Offset in bytes from start to data (32-bit) */
|
EXE_OFFSET_DATA = 12, /**< Offset in bytes from start to data (32-bit) */
|
};
|
};
|
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Valid executable identification signature.
|
* Valid executable identification signature
|
**************************************************************************/
|
**************************************************************************/
|
#define EXE_SIGNATURE 0x4788CAFE
|
#define EXE_SIGNATURE 0x4788CAFE
|
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
Line 329... |
Line 339... |
#if (UART_EN != 0)
|
#if (UART_EN != 0)
|
// setup UART0 (primary UART, no parity bit, no hardware flow control)
|
// setup UART0 (primary UART, no parity bit, no hardware flow control)
|
neorv32_uart0_setup(UART_BAUD, PARITY_NONE, FLOW_CONTROL_NONE);
|
neorv32_uart0_setup(UART_BAUD, PARITY_NONE, FLOW_CONTROL_NONE);
|
#endif
|
#endif
|
|
|
// Configure machine system timer interrupt for ~2Hz
|
// Configure machine system timer interrupt
|
if (neorv32_mtime_available()) {
|
if (neorv32_mtime_available()) {
|
neorv32_mtime_set_timecmp(neorv32_cpu_get_systime() + (NEORV32_SYSINFO.CLK/4));
|
neorv32_mtime_set_timecmp(0 + (NEORV32_SYSINFO.CLK/4));
|
// active timer IRQ
|
// active timer IRQ
|
neorv32_cpu_csr_write(CSR_MIE, 1 << CSR_MIE_MTIE); // activate MTIME IRQ source only!
|
neorv32_cpu_csr_write(CSR_MIE, 1 << CSR_MIE_MTIE); // activate MTIME IRQ source only!
|
neorv32_cpu_eint(); // enable global interrupts
|
neorv32_cpu_eint(); // enable global interrupts
|
}
|
}
|
|
|
Line 346... |
Line 356... |
PRINT_TEXT("\n\n\n<< NEORV32 Bootloader >>\n\n"
|
PRINT_TEXT("\n\n\n<< NEORV32 Bootloader >>\n\n"
|
"BLDV: "__DATE__"\nHWV: ");
|
"BLDV: "__DATE__"\nHWV: ");
|
PRINT_XNUM(neorv32_cpu_csr_read(CSR_MIMPID));
|
PRINT_XNUM(neorv32_cpu_csr_read(CSR_MIMPID));
|
PRINT_TEXT("\nCLK: ");
|
PRINT_TEXT("\nCLK: ");
|
PRINT_XNUM(NEORV32_SYSINFO.CLK);
|
PRINT_XNUM(NEORV32_SYSINFO.CLK);
|
PRINT_TEXT("\nMISA: ");
|
PRINT_TEXT("\nISA: ");
|
PRINT_XNUM(neorv32_cpu_csr_read(CSR_MISA));
|
PRINT_XNUM(neorv32_cpu_csr_read(CSR_MISA));
|
PRINT_TEXT("\nCPU: ");
|
PRINT_TEXT(" + ");
|
PRINT_XNUM(NEORV32_SYSINFO.CPU);
|
PRINT_XNUM(neorv32_cpu_csr_read(CSR_MXISA));
|
PRINT_TEXT("\nSOC: ");
|
PRINT_TEXT("\nSOC: ");
|
PRINT_XNUM(NEORV32_SYSINFO.SOC);
|
PRINT_XNUM(NEORV32_SYSINFO.SOC);
|
PRINT_TEXT("\nIMEM: ");
|
PRINT_TEXT("\nIMEM: ");
|
PRINT_XNUM(NEORV32_SYSINFO.IMEM_SIZE);
|
PRINT_XNUM(NEORV32_SYSINFO.IMEM_SIZE); PRINT_TEXT(" bytes @");
|
PRINT_TEXT(" bytes @");
|
|
PRINT_XNUM(NEORV32_SYSINFO.ISPACE_BASE);
|
PRINT_XNUM(NEORV32_SYSINFO.ISPACE_BASE);
|
PRINT_TEXT("\nDMEM: ");
|
PRINT_TEXT("\nDMEM: ");
|
PRINT_XNUM(NEORV32_SYSINFO.DMEM_SIZE);
|
PRINT_XNUM(NEORV32_SYSINFO.DMEM_SIZE);
|
PRINT_TEXT(" bytes @");
|
PRINT_TEXT(" bytes @");
|
PRINT_XNUM(NEORV32_SYSINFO.DSPACE_BASE);
|
PRINT_XNUM(NEORV32_SYSINFO.DSPACE_BASE);
|
Line 369... |
Line 378... |
// ------------------------------------------------
|
// ------------------------------------------------
|
#if (SPI_EN != 0)
|
#if (SPI_EN != 0)
|
#if (AUTO_BOOT_TIMEOUT != 0)
|
#if (AUTO_BOOT_TIMEOUT != 0)
|
if (neorv32_mtime_available()) {
|
if (neorv32_mtime_available()) {
|
|
|
PRINT_TEXT("\n\nAutoboot in "xstr(AUTO_BOOT_TIMEOUT)"s. Press key to abort.\n");
|
PRINT_TEXT("\n\nAutoboot in "xstr(AUTO_BOOT_TIMEOUT)"s. Press any key to abort.\n");
|
uint64_t timeout_time = neorv32_cpu_get_systime() + (uint64_t)(AUTO_BOOT_TIMEOUT * NEORV32_SYSINFO.CLK);
|
uint64_t timeout_time = neorv32_mtime_get_time() + (uint64_t)(AUTO_BOOT_TIMEOUT * NEORV32_SYSINFO.CLK);
|
|
|
while(1){
|
while(1){
|
|
|
if (neorv32_uart0_available()) { // wait for any key to be pressed
|
if (neorv32_uart0_available()) { // wait for any key to be pressed
|
if (neorv32_uart0_char_received()) {
|
if (neorv32_uart0_char_received()) {
|
break;
|
break;
|
}
|
}
|
}
|
}
|
|
|
if (neorv32_cpu_get_systime() >= timeout_time) { // timeout? start auto boot sequence
|
if (neorv32_mtime_get_time() >= timeout_time) { // timeout? start auto boot sequence
|
get_exe(EXE_STREAM_FLASH); // try booting from flash
|
get_exe(EXE_STREAM_FLASH); // try booting from flash
|
PRINT_TEXT("\n");
|
PRINT_TEXT("\n");
|
start_app();
|
start_app();
|
while(1);
|
while(1);
|
}
|
}
|
Line 436... |
Line 445... |
}
|
}
|
else {
|
else {
|
start_app();
|
start_app();
|
}
|
}
|
}
|
}
|
|
else if (c == '?') {
|
|
PRINT_TEXT("(c) by Stephan Nolting\nhttps://github.com/stnolting/neorv32");
|
|
}
|
else { // unknown command
|
else { // unknown command
|
PRINT_TEXT("Invalid CMD");
|
PRINT_TEXT("Invalid CMD");
|
}
|
}
|
}
|
}
|
|
|
Line 502... |
Line 514... |
neorv32_gpio_pin_toggle(STATUS_LED_PIN); // toggle status LED
|
neorv32_gpio_pin_toggle(STATUS_LED_PIN); // toggle status LED
|
}
|
}
|
#endif
|
#endif
|
// set time for next IRQ
|
// set time for next IRQ
|
if (neorv32_mtime_available()) {
|
if (neorv32_mtime_available()) {
|
neorv32_mtime_set_timecmp(neorv32_cpu_get_systime() + (NEORV32_SYSINFO.CLK/4));
|
neorv32_mtime_set_timecmp(neorv32_mtime_get_timecmp() + (NEORV32_SYSINFO.CLK/4));
|
}
|
}
|
}
|
}
|
|
|
// Bus store access error during get_exe
|
// Bus store access error during get_exe
|
else if ((cause == TRAP_CODE_S_ACCESS) && (getting_exe)) {
|
else if ((cause == TRAP_CODE_S_ACCESS) && (getting_exe)) {
|
Line 516... |
Line 528... |
// Anything else (that was not expected); output exception notifier and try to resume
|
// Anything else (that was not expected); output exception notifier and try to resume
|
else {
|
else {
|
register uint32_t epc = neorv32_cpu_csr_read(CSR_MEPC);
|
register uint32_t epc = neorv32_cpu_csr_read(CSR_MEPC);
|
#if (UART_EN != 0)
|
#if (UART_EN != 0)
|
if (neorv32_uart0_available()) {
|
if (neorv32_uart0_available()) {
|
PRINT_TEXT("\n[ERR ");
|
PRINT_TEXT("\n[ERROR - Unexpected exception! mcause=");
|
PRINT_XNUM(cause); // MCAUSE
|
PRINT_XNUM(cause); // MCAUSE
|
PRINT_PUTC(' ');
|
PRINT_TEXT(" mepc=");
|
PRINT_XNUM(epc); // MEPC
|
PRINT_XNUM(epc); // MEPC
|
PRINT_PUTC(' ');
|
PRINT_TEXT(" mtval=");
|
PRINT_XNUM(neorv32_cpu_csr_read(CSR_MTVAL)); // MTVAL
|
PRINT_XNUM(neorv32_cpu_csr_read(CSR_MTVAL)); // MTVAL
|
PRINT_TEXT("]\n");
|
PRINT_TEXT("] trying to resume...\n");
|
}
|
}
|
#endif
|
#endif
|
neorv32_cpu_csr_write(CSR_MEPC, epc + 4); // advance to next instruction
|
neorv32_cpu_csr_write(CSR_MEPC, epc + 4); // advance to next instruction
|
}
|
}
|
}
|
}
|
Line 697... |
Line 709... |
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Output system error ID and stall.
|
* Output system error ID and stall.
|
*
|
*
|
* @param[in] err_code Error code. See #ERROR_CODES.
|
* @param[in] err_code Error code. See #ERROR_CODES and #error_message.
|
**************************************************************************/
|
**************************************************************************/
|
void system_error(uint8_t err_code) {
|
void system_error(uint8_t err_code) {
|
|
|
PRINT_TEXT("\a\nERROR_"); // output error code with annoying bell sound
|
PRINT_TEXT("\a\nERROR_"); // output error code with annoying bell sound
|
PRINT_PUTC('0' + ((char)err_code));
|
PRINT_PUTC('0' + ((char)err_code));
|
|
PRINT_PUTC(':');
|
|
PRINT_PUTC(' ');
|
|
PRINT_TEXT(error_message[err_code]);
|
|
|
neorv32_cpu_dint(); // deactivate IRQs
|
neorv32_cpu_dint(); // deactivate IRQs
|
#if (STATUS_LED_EN != 0)
|
#if (STATUS_LED_EN != 0)
|
if (neorv32_gpio_available()) {
|
if (neorv32_gpio_available()) {
|
neorv32_gpio_port_set(1 << STATUS_LED_PIN); // permanently light up status LED
|
neorv32_gpio_port_set(1 << STATUS_LED_PIN); // permanently light up status LED
|