Line 225... |
Line 225... |
neorv32_uart_print("\nMISA: ");
|
neorv32_uart_print("\nMISA: ");
|
print_hex_word(neorv32_cpu_csr_read(CSR_MISA));
|
print_hex_word(neorv32_cpu_csr_read(CSR_MISA));
|
neorv32_uart_print("\nCONF: ");
|
neorv32_uart_print("\nCONF: ");
|
print_hex_word(SYSINFO_FEATURES);
|
print_hex_word(SYSINFO_FEATURES);
|
neorv32_uart_print("\nIMEM: ");
|
neorv32_uart_print("\nIMEM: ");
|
print_hex_word(SYSINFO_ISPACE_SIZE);
|
print_hex_word(SYSINFO_IMEM_SIZE);
|
neorv32_uart_print(" bytes @ ");
|
neorv32_uart_print(" bytes @ ");
|
print_hex_word(SYSINFO_ISPACE_BASE);
|
print_hex_word(SYSINFO_ISPACE_BASE);
|
neorv32_uart_print("\nDMEM: ");
|
neorv32_uart_print("\nDMEM: ");
|
print_hex_word(SYSINFO_DSPACE_SIZE);
|
print_hex_word(SYSINFO_DMEM_SIZE);
|
neorv32_uart_print(" bytes @ ");
|
neorv32_uart_print(" bytes @ ");
|
print_hex_word(SYSINFO_DSPACE_BASE);
|
print_hex_word(SYSINFO_DSPACE_BASE);
|
|
|
|
|
// ------------------------------------------------
|
// ------------------------------------------------
|
Line 322... |
Line 322... |
neorv32_uart_print("No executable available.");
|
neorv32_uart_print("No executable available.");
|
return;
|
return;
|
}
|
}
|
|
|
// no need to shutdown or reset the used peripherals
|
// no need to shutdown or reset the used peripherals
|
|
// no need to disable interrupt sources
|
// -> this will be done by application's crt0
|
// -> this will be done by application's crt0
|
|
|
// deactivate IRQs and IRQ sources
|
// deactivate global IRQs
|
neorv32_cpu_dint();
|
neorv32_cpu_dint();
|
neorv32_cpu_csr_write(CSR_MIE, 0);
|
|
|
|
neorv32_uart_print("Booting...\n\n");
|
neorv32_uart_print("Booting...\n\n");
|
|
|
// wait for UART to finish transmitting
|
// wait for UART to finish transmitting
|
while ((UART_CT & (1<<UART_CT_TX_BUSY)) != 0);
|
while ((UART_CT & (1<<UART_CT_TX_BUSY)) != 0);
|
|
|
// reset performance counters (to benchmark actual application)
|
// reset performance counters (to benchmark actual application)
|
asm volatile ("csrw mcycle, zero"); // will also clear 'cycle'
|
asm volatile ("csrw mcycle, zero"); // also clears 'cycle'
|
asm volatile ("csrw mcycleh, zero"); // will also clear 'cycleh'
|
asm volatile ("csrw mcycleh, zero"); // also clears 'cycleh'
|
asm volatile ("csrw minstret, zero"); // will also clear 'instret'
|
asm volatile ("csrw minstret, zero"); // also clears 'instret'
|
asm volatile ("csrw minstreth, zero"); // will also clear 'instreth'
|
asm volatile ("csrw minstreth, zero"); // also clears 'instreth'
|
|
|
// start app at instruction space base address
|
// start app at instruction space base address
|
register uint32_t app_base = SYSINFO_ISPACE_BASE;
|
register uint32_t app_base = SYSINFO_ISPACE_BASE;
|
asm volatile ("jalr zero, %0" : : "r" (app_base));
|
asm volatile ("jalr zero, %0" : : "r" (app_base));
|
while (1);
|
while (1);
|
}
|
}
|
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Bootloader trap handler.
|
* Bootloader trap handler. Used for the MTIME tick and to capture any other traps.
|
* Primarily used for the MTIME tick.
|
|
* @warning Since we have no runtime environment, we have to use the interrupt attribute here. Here, and only here!
|
* @warning 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) {
|
void __attribute__((__interrupt__)) bootloader_trap_handler(void) {
|
|
|
// make sure this was caused by MTIME IRQ
|
// make sure this was caused by MTIME IRQ
|
uint32_t cause = neorv32_cpu_csr_read(CSR_MCAUSE);
|
uint32_t cause = neorv32_cpu_csr_read(CSR_MCAUSE);
|
if (cause != TRAP_CODE_MTI) { // raw exception code for MTI
|
if (cause == TRAP_CODE_MTI) { // raw exception code for MTI
|
neorv32_uart_print("\n\nEXCEPTION (");
|
|
print_hex_word(cause);
|
|
neorv32_uart_print(") @ 0x");
|
|
print_hex_word(neorv32_cpu_csr_read(CSR_MEPC));
|
|
system_error(ERROR_SYSTEM);
|
|
while(1); // freeze
|
|
}
|
|
else {
|
|
if (STATUS_LED_EN == 1) {
|
if (STATUS_LED_EN == 1) {
|
// toggle status LED
|
// toggle status LED
|
neorv32_gpio_pin_toggle(STATUS_LED);
|
neorv32_gpio_pin_toggle(STATUS_LED);
|
}
|
}
|
// set time for next IRQ
|
// set time for next IRQ
|
neorv32_mtime_set_timecmp(neorv32_mtime_get_time() + (SYSINFO_CLK/4));
|
neorv32_mtime_set_timecmp(neorv32_mtime_get_time() + (SYSINFO_CLK/4));
|
}
|
}
|
|
|
|
else if (cause == TRAP_CODE_S_ACCESS) { // seems like executable is too large
|
|
system_error(ERROR_SIZE);
|
|
}
|
|
|
|
else {
|
|
neorv32_uart_print("\n\nEXCEPTION (");
|
|
print_hex_word(cause);
|
|
neorv32_uart_print(") @ 0x");
|
|
print_hex_word(neorv32_cpu_csr_read(CSR_MEPC));
|
|
system_error(ERROR_SYSTEM);
|
|
}
|
}
|
}
|
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Get executable stream.
|
* Get executable stream.
|
Line 412... |
Line 415... |
|
|
// image size and checksum
|
// image size and checksum
|
uint32_t size = get_exe_word(src, addr + EXE_OFFSET_SIZE); // size in bytes
|
uint32_t size = get_exe_word(src, addr + EXE_OFFSET_SIZE); // size in bytes
|
uint32_t check = get_exe_word(src, addr + EXE_OFFSET_CHECKSUM); // complement sum checksum
|
uint32_t check = get_exe_word(src, addr + EXE_OFFSET_CHECKSUM); // complement sum checksum
|
|
|
// executable too large?
|
|
uint32_t imem_size = SYSINFO_ISPACE_SIZE;
|
|
if (size > imem_size) {
|
|
system_error(ERROR_SIZE);
|
|
}
|
|
|
|
// transfer program data
|
// transfer program data
|
uint32_t *pnt = (uint32_t*)SYSINFO_ISPACE_BASE;
|
uint32_t *pnt = (uint32_t*)SYSINFO_ISPACE_BASE;
|
uint32_t checksum = 0;
|
uint32_t checksum = 0;
|
uint32_t d = 0, i = 0;
|
uint32_t d = 0, i = 0;
|
addr = addr + EXE_OFFSET_DATA;
|
addr = addr + EXE_OFFSET_DATA;
|
Line 546... |
Line 543... |
*
|
*
|
* @param[in] err_code Error code. See #ERROR_CODES.
|
* @param[in] err_code Error code. See #ERROR_CODES.
|
**************************************************************************/
|
**************************************************************************/
|
void system_error(uint8_t err_code) {
|
void system_error(uint8_t err_code) {
|
|
|
neorv32_uart_print("\a\nBootloader ERR_"); // output error code with annoying bell sound
|
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
|
neorv32_uart_putc('0' + ((char)err_code)); // FIXME err_code should/must be below 10
|
|
|
neorv32_cpu_dint(); // deactivate IRQs
|
neorv32_cpu_dint(); // deactivate IRQs
|
if (STATUS_LED_EN == 1) {
|
if (STATUS_LED_EN == 1) {
|
neorv32_gpio_port_set(1 << STATUS_LED); // permanently light up status LED
|
neorv32_gpio_port_set(1 << STATUS_LED); // permanently light up status LED
|