Line 147... |
Line 147... |
void get_exe(int src);
|
void get_exe(int src);
|
void save_exe(void);
|
void save_exe(void);
|
uint32_t get_exe_word(int src, uint32_t addr);
|
uint32_t get_exe_word(int src, uint32_t addr);
|
void system_error(uint8_t err_code);
|
void system_error(uint8_t err_code);
|
void print_hex_word(uint32_t num);
|
void print_hex_word(uint32_t num);
|
void print_proc_version(void);
|
|
|
|
// SPI flash access
|
// SPI flash access
|
uint8_t spi_flash_read_byte(uint32_t addr);
|
uint8_t spi_flash_read_byte(uint32_t addr);
|
void spi_flash_write_byte(uint32_t addr, uint8_t wdata);
|
void spi_flash_write_byte(uint32_t addr, uint8_t wdata);
|
void spi_flash_write_word(uint32_t addr, uint32_t wdata);
|
void spi_flash_write_word(uint32_t addr, uint32_t wdata);
|
Line 170... |
Line 169... |
// ------------------------------------------------
|
// ------------------------------------------------
|
// Processor hardware initialization
|
// Processor hardware initialization
|
// ------------------------------------------------
|
// ------------------------------------------------
|
|
|
// reset system time
|
// reset system time
|
neorv32_mtime_set_time(0);
|
MTIME_LO = 0;
|
|
MTIME_HI = 0;
|
|
|
// deactivate unused IO devices
|
// deactivate unused IO devices
|
|
neorv32_wdt_disable();
|
neorv32_clic_disable();
|
neorv32_clic_disable();
|
neorv32_pwm_disable();
|
neorv32_pwm_disable();
|
neorv32_spi_disable();
|
neorv32_spi_disable();
|
neorv32_trng_disable();
|
neorv32_trng_disable();
|
neorv32_twi_disable();
|
neorv32_twi_disable();
|
neorv32_wdt_disable();
|
|
|
|
// get clock speed (in Hz)
|
// get clock speed (in Hz)
|
uint32_t clock_speed = neorv32_cpu_csr_read(CSR_MCLOCK);
|
uint32_t clock_speed = SYSINFO_CLK;
|
|
|
// init SPI for 8-bit, clock-mode 0, MSB-first, no interrupt
|
// init SPI for 8-bit, clock-mode 0, MSB-first, no interrupt
|
if (clock_speed < 40000000) {
|
if (clock_speed < 40000000) {
|
neorv32_spi_setup(SPI_FLASH_CLK_PRSC, 0, 0, 0, 0);
|
neorv32_spi_setup(SPI_FLASH_CLK_PRSC, 0, 0, 0, 0);
|
}
|
}
|
Line 216... |
Line 216... |
// ------------------------------------------------
|
// ------------------------------------------------
|
// Show bootloader intro and system info
|
// Show bootloader intro and system info
|
// ------------------------------------------------
|
// ------------------------------------------------
|
neorv32_uart_print("\n\n\n\n<< NEORV32 Bootloader >>\n\n"
|
neorv32_uart_print("\n\n\n\n<< NEORV32 Bootloader >>\n\n"
|
"BLDV: "__DATE__"\nHWV: ");
|
"BLDV: "__DATE__"\nHWV: ");
|
print_proc_version();
|
neorv32_rte_print_hw_version();
|
neorv32_uart_print("\nCLK: ");
|
neorv32_uart_print("\nCLK: ");
|
print_hex_word(neorv32_cpu_csr_read(CSR_MCLOCK));
|
print_hex_word(SYSINFO_CLK);
|
neorv32_uart_print(" Hz\nMHID: ");
|
neorv32_uart_print(" Hz\nUSER: ");
|
print_hex_word(neorv32_cpu_csr_read(CSR_MHARTID));
|
print_hex_word(SYSINFO_USER_CODE);
|
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(neorv32_cpu_csr_read(CSR_MFEATURES));
|
print_hex_word(SYSINFO_FEATURES);
|
neorv32_uart_print("\nIMEM: ");
|
neorv32_uart_print("\nIMEM: ");
|
print_hex_word(neorv32_cpu_csr_read(CSR_MISPACESIZE));
|
print_hex_word(SYSINFO_ISPACE_SIZE);
|
neorv32_uart_print(" bytes @ ");
|
neorv32_uart_print(" bytes @ ");
|
print_hex_word(neorv32_cpu_csr_read(CSR_MISPACEBASE));
|
print_hex_word(SYSINFO_ISPACE_BASE);
|
neorv32_uart_print("\nDMEM: ");
|
neorv32_uart_print("\nDMEM: ");
|
print_hex_word(neorv32_cpu_csr_read(CSR_MDSPACESIZE));
|
print_hex_word(SYSINFO_DSPACE_SIZE);
|
neorv32_uart_print(" bytes @ ");
|
neorv32_uart_print(" bytes @ ");
|
print_hex_word(neorv32_cpu_csr_read(CSR_MDSPACEBASE));
|
print_hex_word(SYSINFO_DSPACE_BASE);
|
|
|
|
|
// ------------------------------------------------
|
// ------------------------------------------------
|
// Auto boot sequence
|
// Auto boot sequence
|
// ------------------------------------------------
|
// ------------------------------------------------
|
Line 264... |
Line 264... |
char c = neorv32_uart_getc();
|
char c = neorv32_uart_getc();
|
neorv32_uart_putc(c); // echo
|
neorv32_uart_putc(c); // echo
|
neorv32_uart_print("\n");
|
neorv32_uart_print("\n");
|
|
|
if (c == 'r') { // restart bootloader
|
if (c == 'r') { // restart bootloader
|
break;
|
neorv32_cpu_dint(); // disable global interrupts
|
|
// jump to beginning of boot ROM
|
|
asm volatile ("li t0, %[input_i]; jr t0" : : [input_i] "i" (BOOTLOADER_BASE_ADDRESS));
|
|
while(1); // just for the compiler
|
}
|
}
|
else if (c == 'h') { // help menu
|
else if (c == 'h') { // help menu
|
print_help();
|
print_help();
|
}
|
}
|
else if (c == 'u') { // get executable via UART
|
else if (c == 'u') { // get executable via UART
|
Line 289... |
Line 292... |
else { // unknown command
|
else { // unknown command
|
neorv32_uart_print("Invalid CMD");
|
neorv32_uart_print("Invalid CMD");
|
}
|
}
|
}
|
}
|
|
|
return 0; // bootloader will restart when returning
|
return 0; // bootloader should never return
|
}
|
}
|
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Print help menu.
|
* Print help menu.
|
Line 331... |
Line 334... |
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)
|
|
asm volatile ("csrrw zero, mcycle, zero"); // will also clear 'cycle'
|
|
asm volatile ("csrrw zero, mcycleh, zero"); // will also clear 'cycleh'
|
|
asm volatile ("csrrw zero, minstret, zero"); // will also clear 'instret'
|
|
asm volatile ("csrrw zero, minstreth, zero"); // will also clear 'instreth'
|
|
|
// start app at instruction space base address
|
// start app at instruction space base address
|
while (1) {
|
while (1) {
|
register uint32_t app_base = neorv32_cpu_csr_read(CSR_MISPACEBASE);
|
register uint32_t app_base = SYSINFO_ISPACE_BASE;
|
asm volatile ("jalr zero, %0" : : "r" (app_base));
|
asm volatile ("jalr zero, %0" : : "r" (app_base));
|
}
|
}
|
}
|
}
|
|
|
|
|
Line 347... |
Line 356... |
**************************************************************************/
|
**************************************************************************/
|
void __attribute__((__interrupt__)) mtime_irq_handler(void) {
|
void __attribute__((__interrupt__)) mtime_irq_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 != 0x80000007) { // raw exception code for MTI
|
if (cause != EXCCODE_MTI) { // raw exception code for MTI
|
neorv32_uart_print("\n\nEXCEPTION: ");
|
neorv32_uart_print("\n\nEXCEPTION: ");
|
print_hex_word(cause);
|
print_hex_word(cause);
|
neorv32_uart_print(" @ 0x");
|
neorv32_uart_print(" @ 0x");
|
print_hex_word(neorv32_cpu_csr_read(CSR_MEPC));
|
print_hex_word(neorv32_cpu_csr_read(CSR_MEPC));
|
system_error(ERROR_SYSTEM);
|
system_error(ERROR_SYSTEM);
|
Line 359... |
Line 368... |
}
|
}
|
else {
|
else {
|
// 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() + (neorv32_cpu_csr_read(CSR_MCLOCK)/4));
|
neorv32_mtime_set_timecmp(neorv32_mtime_get_time() + (SYSINFO_CLK/4));
|
}
|
}
|
}
|
}
|
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
Line 372... |
Line 381... |
* @param src Source of executable stream data. See #EXE_STREAM_SOURCE.
|
* @param src Source of executable stream data. See #EXE_STREAM_SOURCE.
|
**************************************************************************/
|
**************************************************************************/
|
void get_exe(int src) {
|
void get_exe(int src) {
|
|
|
// is instruction memory (actually, the IMEM) read-only?
|
// is instruction memory (actually, the IMEM) read-only?
|
if (neorv32_cpu_csr_read(CSR_MFEATURES) & (1 << CPU_MFEATURES_MEM_INT_IMEM_ROM)) {
|
if (SYSINFO_FEATURES & (1 << SYSINFO_FEATURES_MEM_INT_IMEM_ROM)) {
|
system_error(ERROR_ROM);
|
system_error(ERROR_ROM);
|
}
|
}
|
|
|
// flash image base address
|
// flash image base address
|
uint32_t addr = SPI_FLASH_BOOT_ADR;
|
uint32_t addr = SPI_FLASH_BOOT_ADR;
|
Line 403... |
Line 412... |
// 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?
|
// executable too large?
|
uint32_t imem_size = neorv32_cpu_csr_read(CSR_MISPACESIZE);
|
uint32_t imem_size = SYSINFO_ISPACE_SIZE;
|
if (size > imem_size) {
|
if (size > imem_size) {
|
system_error(ERROR_SIZE);
|
system_error(ERROR_SIZE);
|
}
|
}
|
|
|
// transfer program data
|
// transfer program data
|
uint32_t *pnt = (uint32_t*)neorv32_cpu_csr_read(CSR_MISPACEBASE);
|
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;
|
while (i < (size/4)) { // in words
|
while (i < (size/4)) { // in words
|
d = get_exe_word(src, addr);
|
d = get_exe_word(src, addr);
|
Line 495... |
Line 504... |
// write size
|
// write size
|
spi_flash_write_word(addr + EXE_OFFSET_SIZE, size);
|
spi_flash_write_word(addr + EXE_OFFSET_SIZE, size);
|
|
|
// store data from instruction memory and update checksum
|
// store data from instruction memory and update checksum
|
uint32_t checksum = 0;
|
uint32_t checksum = 0;
|
uint32_t *pnt = (uint32_t*)neorv32_cpu_csr_read(CSR_MISPACEBASE);
|
uint32_t *pnt = (uint32_t*)SYSINFO_ISPACE_BASE;
|
addr = addr + EXE_OFFSET_DATA;
|
addr = addr + EXE_OFFSET_DATA;
|
uint32_t i = 0;
|
uint32_t i = 0;
|
while (i < (size/4)) { // in words
|
while (i < (size/4)) { // in words
|
uint32_t d = (uint32_t)*pnt++;
|
uint32_t d = (uint32_t)*pnt++;
|
checksum += d;
|
checksum += d;
|
Line 586... |
Line 595... |
neorv32_uart_putc(hex_symbols[index]);
|
neorv32_uart_putc(hex_symbols[index]);
|
}
|
}
|
}
|
}
|
|
|
|
|
/**********************************************************************//**
|
|
* Print processor version. Deciaml format: "Dd.Dd.Dd.Dd".
|
|
**************************************************************************/
|
|
void print_proc_version(void) {
|
|
|
|
uint32_t i;
|
|
char tmp, cnt;
|
|
uint32_t version = neorv32_cpu_csr_read(CSR_MIMPID);
|
|
|
|
for (i=0; i<4; i++) {
|
|
|
|
tmp = (char)(version >> (24 - 8*i));
|
|
|
|
// serial division
|
|
cnt = 0;
|
|
while (tmp >= 10) {
|
|
tmp = tmp - 10;
|
|
cnt++;
|
|
}
|
|
|
|
if (cnt) {
|
|
neorv32_uart_putc('0' + cnt);
|
|
}
|
|
neorv32_uart_putc('0' + tmp);
|
|
if (i < 3) {
|
|
neorv32_uart_putc('.');
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------
|
// SPI flash functions
|
// SPI flash functions
|
// -------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------
|
|
|