OpenCores
URL https://opencores.org/ocsvn/neorv32/neorv32/trunk

Subversion Repositories neorv32

[/] [neorv32/] [trunk/] [sw/] [bootloader/] [bootloader.c] - Blame information for rev 65

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 zero_gravi
// #################################################################################################
2
// # << NEORV32 - Bootloader >>                                                                    #
3
// # ********************************************************************************************* #
4
// # BSD 3-Clause License                                                                          #
5
// #                                                                                               #
6 55 zero_gravi
// # Copyright (c) 2021, Stephan Nolting. All rights reserved.                                     #
7 2 zero_gravi
// #                                                                                               #
8
// # Redistribution and use in source and binary forms, with or without modification, are          #
9
// # permitted provided that the following conditions are met:                                     #
10
// #                                                                                               #
11
// # 1. Redistributions of source code must retain the above copyright notice, this list of        #
12
// #    conditions and the following disclaimer.                                                   #
13
// #                                                                                               #
14
// # 2. Redistributions in binary form must reproduce the above copyright notice, this list of     #
15
// #    conditions and the following disclaimer in the documentation and/or other materials        #
16
// #    provided with the distribution.                                                            #
17
// #                                                                                               #
18
// # 3. Neither the name of the copyright holder nor the names of its contributors may be used to  #
19
// #    endorse or promote products derived from this software without specific prior written      #
20
// #    permission.                                                                                #
21
// #                                                                                               #
22
// # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS   #
23
// # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF               #
24
// # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE    #
25
// # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,     #
26
// # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE #
27
// # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED    #
28
// # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING     #
29
// # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED  #
30
// # OF THE POSSIBILITY OF SUCH DAMAGE.                                                            #
31
// # ********************************************************************************************* #
32 61 zero_gravi
// # The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32       (c) Stephan Nolting #
33 2 zero_gravi
// #################################################################################################
34
 
35
 
36
/**********************************************************************//**
37
 * @file bootloader.c
38
 * @author Stephan Nolting
39 61 zero_gravi
 * @brief NEORV32 bootloader.
40 2 zero_gravi
 **************************************************************************/
41
 
42
// Libraries
43
#include <stdint.h>
44
#include <neorv32.h>
45
 
46
 
47
/**********************************************************************//**
48 61 zero_gravi
 * @name Bootloader configuration (override via console to customize)
49
 * default values are used if not explicitly customized
50 2 zero_gravi
 **************************************************************************/
51
/**@{*/
52 61 zero_gravi
 
53
/* ---- UART interface configuration ---- */
54
 
55
/** Set to 0 to disable UART interface */
56
#ifndef UART_EN
57
  #define UART_EN 1
58
#endif
59
 
60
/** UART BAUD rate for serial interface */
61
#ifndef UART_BAUD
62
  #define UART_BAUD 19200
63
#endif
64
 
65
/* ---- Status LED ---- */
66
 
67
/** Set to 0 to disable bootloader status LED (heart beat) at GPIO.gpio_o(STATUS_LED_PIN) */
68
#ifndef STATUS_LED_EN
69
  #define STATUS_LED_EN 1
70
#endif
71
 
72
/** GPIO output pin for high-active bootloader status LED (heart beat) */
73
#ifndef STATUS_LED_PIN
74
  #define STATUS_LED_PIN 0
75
#endif
76
 
77
/* ---- Boot configuration ---- */
78
 
79 63 zero_gravi
/** Set to 1 to enable automatic (after reset) only boot from external SPI flash at address SPI_BOOT_BASE_ADDR */
80 61 zero_gravi
#ifndef AUTO_BOOT_SPI_EN
81
  #define AUTO_BOOT_SPI_EN 0
82
#endif
83
 
84 63 zero_gravi
/** Set to 1 to enable boot only via on-chip debugger (keep CPU in halt loop until OCD takes over control) */
85 61 zero_gravi
#ifndef AUTO_BOOT_OCD_EN
86
  #define AUTO_BOOT_OCD_EN 0
87
#endif
88
 
89 63 zero_gravi
/** Set to 1 to enable simple UART executable upload (no console, no SPI flash) */
90
#ifndef AUTO_BOOT_SIMPLE_UART_EN
91
  #define AUTO_BOOT_SIMPLE_UART_EN 0
92
#endif
93
 
94 61 zero_gravi
/** Time until the auto-boot sequence starts (in seconds); 0 = disabled */
95
#ifndef AUTO_BOOT_TIMEOUT
96
  #define AUTO_BOOT_TIMEOUT 8
97
#endif
98
 
99
/* ---- SPI configuration ---- */
100
 
101 63 zero_gravi
/** Enable SPI module (default) including SPI flash boot options */
102
#ifndef SPI_EN
103
  #define SPI_EN 1
104
#endif
105
 
106 61 zero_gravi
/** SPI flash chip select (low-active) at SPI.spi_csn_o(SPI_FLASH_CS) */
107
#ifndef SPI_FLASH_CS
108
  #define SPI_FLASH_CS 0
109
#endif
110
 
111
/** SPI flash sector size in bytes */
112
#ifndef SPI_FLASH_SECTOR_SIZE
113
  #define SPI_FLASH_SECTOR_SIZE 65536 // default = 64kB
114
#endif
115
 
116 64 zero_gravi
/** SPI flash clock pre-scaler; see #NEORV32_SPI_CTRL_enum */
117 61 zero_gravi
#ifndef SPI_FLASH_CLK_PRSC
118
  #define SPI_FLASH_CLK_PRSC CLK_PRSC_8
119
#endif
120
 
121
/** SPI flash boot base address */
122
#ifndef SPI_BOOT_BASE_ADDR
123
  #define SPI_BOOT_BASE_ADDR 0x08000000
124
#endif
125 2 zero_gravi
/**@}*/
126
 
127
 
128
/**********************************************************************//**
129
  Executable stream source select
130
 **************************************************************************/
131
enum EXE_STREAM_SOURCE {
132
  EXE_STREAM_UART  = 0, /**< Get executable via UART */
133
  EXE_STREAM_FLASH = 1  /**< Get executable via SPI flash */
134
};
135
 
136
 
137
/**********************************************************************//**
138
 * Error codes
139
 **************************************************************************/
140
enum ERROR_CODES {
141
  ERROR_SIGNATURE = 0, /**< 0: Wrong signature in executable */
142
  ERROR_SIZE      = 1, /**< 1: Insufficient instruction memory capacity */
143
  ERROR_CHECKSUM  = 2, /**< 2: Checksum error in executable */
144 61 zero_gravi
  ERROR_FLASH     = 3  /**< 3: SPI flash access error */
145 2 zero_gravi
};
146
 
147
 
148
/**********************************************************************//**
149
 * SPI flash commands
150
 **************************************************************************/
151
enum SPI_FLASH_CMD {
152
  SPI_FLASH_CMD_PAGE_PROGRAM = 0x02, /**< Program page */
153
  SPI_FLASH_CMD_READ         = 0x03, /**< Read data */
154
  SPI_FLASH_CMD_READ_STATUS  = 0x05, /**< Get status register */
155
  SPI_FLASH_CMD_WRITE_ENABLE = 0x06, /**< Allow write access */
156
  SPI_FLASH_CMD_READ_ID      = 0x9E, /**< Read manufacturer ID */
157
  SPI_FLASH_CMD_SECTOR_ERASE = 0xD8  /**< Erase complete sector */
158
};
159
 
160
 
161
/**********************************************************************//**
162
 * NEORV32 executable
163
 **************************************************************************/
164
enum NEORV32_EXECUTABLE {
165
  EXE_OFFSET_SIGNATURE =  0, /**< Offset in bytes from start to signature (32-bit) */
166
  EXE_OFFSET_SIZE      =  4, /**< Offset in bytes from start to size (32-bit) */
167
  EXE_OFFSET_CHECKSUM  =  8, /**< Offset in bytes from start to checksum (32-bit) */
168
  EXE_OFFSET_DATA      = 12, /**< Offset in bytes from start to data (32-bit) */
169
};
170
 
171
 
172
/**********************************************************************//**
173
 * Valid executable identification signature.
174
 **************************************************************************/
175
#define EXE_SIGNATURE 0x4788CAFE
176
 
177
 
178
/**********************************************************************//**
179 61 zero_gravi
 * Helper macros
180 2 zero_gravi
 **************************************************************************/
181
/**@{*/
182 61 zero_gravi
/** Actual define-to-string helper */
183 2 zero_gravi
#define xstr(a) str(a)
184 61 zero_gravi
/** Internal helper macro */
185 2 zero_gravi
#define str(a) #a
186 61 zero_gravi
/** Print to UART 0 */
187
#if (UART_EN != 0)
188
  #define PRINT_TEXT(...) neorv32_uart0_print(__VA_ARGS__)
189
  #define PRINT_XNUM(a) print_hex_word(a)
190
  #define PRINT_GETC(a) neorv32_uart0_getc()
191
  #define PRINT_PUTC(a) neorv32_uart0_putc(a)
192
#else
193
  #define PRINT_TEXT(...)
194
  #define PRINT_XNUM(a)
195
  #define PRINT_GETC(a) 0
196
  #define PRINT_PUTC(a)
197
#endif
198 2 zero_gravi
/**@}*/
199
 
200
 
201 22 zero_gravi
/**********************************************************************//**
202
 * This global variable keeps the size of the available executable in bytes.
203
 * If =0 no executable is available (yet).
204
 **************************************************************************/
205 47 zero_gravi
volatile uint32_t exe_available = 0;
206 22 zero_gravi
 
207
 
208 47 zero_gravi
/**********************************************************************//**
209 61 zero_gravi
 * Only set during executable fetch (required for capturing STORE BUS-TIMOUT exception).
210 47 zero_gravi
 **************************************************************************/
211
volatile uint32_t getting_exe = 0;
212
 
213
 
214 2 zero_gravi
// Function prototypes
215 22 zero_gravi
void __attribute__((__interrupt__)) bootloader_trap_handler(void);
216 2 zero_gravi
void print_help(void);
217
void start_app(void);
218
void get_exe(int src);
219
void save_exe(void);
220
uint32_t get_exe_word(int src, uint32_t addr);
221
void system_error(uint8_t err_code);
222
void print_hex_word(uint32_t num);
223
 
224 37 zero_gravi
// SPI flash driver functions
225 2 zero_gravi
uint8_t spi_flash_read_byte(uint32_t addr);
226
void spi_flash_write_byte(uint32_t addr, uint8_t wdata);
227
void spi_flash_write_word(uint32_t addr, uint32_t wdata);
228
void spi_flash_erase_sector(uint32_t addr);
229
uint8_t spi_flash_read_1st_id(void);
230 37 zero_gravi
void spi_flash_write_wait(void);
231 4 zero_gravi
void spi_flash_write_enable(void);
232
void spi_flash_write_addr(uint32_t addr);
233 2 zero_gravi
 
234
 
235
/**********************************************************************//**
236 61 zero_gravi
 * Sanity check: Base ISA only!
237
 **************************************************************************/
238
#if defined __riscv_atomic || defined __riscv_a || __riscv_b || __riscv_compressed || defined __riscv_c || defined __riscv_mul || defined __riscv_m
239
  #warning In order to allow the bootloader to run on *any* CPU configuration it should be compiled using the base ISA only.
240
#endif
241
 
242
 
243
/**********************************************************************//**
244 2 zero_gravi
 * Bootloader main.
245
 **************************************************************************/
246
int main(void) {
247
 
248 61 zero_gravi
  // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
249
  // AUTO BOOT: OCD
250
  // Stay in endless loop until the on-chip debugger
251
  // takes over CPU control
252
  // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
253
#if (AUTO_BOOT_OCD_EN != 0)
254 63 zero_gravi
  #warning Custom boot configuration: Boot via on-chip debugger.
255 61 zero_gravi
  while(1) {
256
    asm volatile ("nop");
257
  }
258
  return 0; // should never be reached
259 39 zero_gravi
#endif
260
 
261
 
262 61 zero_gravi
  // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
263 63 zero_gravi
  // AUTO BOOT: Simple UART boot
264
  // Upload executable via simple UART interface, no console, no flash options
265
  // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
266
#if (AUTO_BOOT_SIMPLE_UART_EN != 0)
267
  #warning Custom boot configuration: Auto boot via simple UART interface.
268
 
269
  // setup UART0 (primary UART, no parity bit, no hardware flow control)
270
  neorv32_uart0_setup(UART_BAUD, PARITY_NONE, FLOW_CONTROL_NONE);
271
 
272
  PRINT_TEXT("\nNEORV32 bootloader\nUART executable upload\n");
273
  get_exe(EXE_STREAM_UART);
274
  PRINT_TEXT("\n");
275
  start_app();
276
 
277
  return 0; // bootloader should never return
278
#endif
279
 
280
 
281
  // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
282
  // AUTO BOOT: SPI flash only
283 61 zero_gravi
  // Bootloader will directly boot and execute image from SPI flash
284
  // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
285
#if (AUTO_BOOT_SPI_EN != 0)
286 63 zero_gravi
  #warning Custom boot configuration: Auto boot from external SPI flash.
287 39 zero_gravi
 
288 63 zero_gravi
  // setup UART0 (primary UART, no parity bit, no hardware flow control)
289
  neorv32_uart0_setup(UART_BAUD, PARITY_NONE, FLOW_CONTROL_NONE);
290
  // SPI setup
291 65 zero_gravi
  neorv32_spi_setup(SPI_FLASH_CLK_PRSC, 0, 0, 0);
292 63 zero_gravi
 
293 61 zero_gravi
  PRINT_TEXT("\nNEORV32 bootloader\nLoading from SPI flash at ");
294
  PRINT_XNUM((uint32_t)SPI_BOOT_BASE_ADDR);
295
  PRINT_TEXT("...\n");
296 2 zero_gravi
 
297 61 zero_gravi
  get_exe(EXE_STREAM_FLASH);
298
  PRINT_TEXT("\n");
299
  start_app();
300 2 zero_gravi
 
301 61 zero_gravi
  return 0; // bootloader should never return
302 56 zero_gravi
#endif
303 39 zero_gravi
 
304 2 zero_gravi
 
305 61 zero_gravi
  // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
306
  // AUTO BOOT: Default
307
  // User UART to upload new executable and optionally store it to SPI flash
308
  // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
309 2 zero_gravi
 
310 61 zero_gravi
  exe_available = 0; // global variable for executable size; 0 means there is no exe available
311
  getting_exe   = 0; // we are not trying to get an executable yet
312
 
313
 
314 60 zero_gravi
  // configure trap handler (bare-metal, no neorv32 rte available)
315 47 zero_gravi
  neorv32_cpu_csr_write(CSR_MTVEC, (uint32_t)(&bootloader_trap_handler));
316
 
317 63 zero_gravi
#if (SPI_EN != 0)
318 61 zero_gravi
  // setup SPI for 8-bit, clock-mode 0
319 65 zero_gravi
  neorv32_spi_setup(SPI_FLASH_CLK_PRSC, 0, 0, 0);
320 63 zero_gravi
#endif
321 2 zero_gravi
 
322 61 zero_gravi
#if (STATUS_LED_EN != 0)
323
  if (neorv32_gpio_available()) {
324
    // activate status LED, clear all others
325
    neorv32_gpio_port_set(1 << STATUS_LED_PIN);
326
  }
327
#endif
328 2 zero_gravi
 
329 61 zero_gravi
#if (UART_EN != 0)
330
  // setup UART0 (primary UART, no parity bit, no hardware flow control)
331
  neorv32_uart0_setup(UART_BAUD, PARITY_NONE, FLOW_CONTROL_NONE);
332
#endif
333 2 zero_gravi
 
334 61 zero_gravi
  // Configure machine system timer interrupt for ~2Hz
335
  if (neorv32_mtime_available()) {
336 65 zero_gravi
    neorv32_mtime_set_timecmp(neorv32_cpu_get_systime() + (NEORV32_SYSINFO.CLK/4));
337 61 zero_gravi
    // active timer IRQ
338
    neorv32_cpu_csr_write(CSR_MIE, 1 << CSR_MIE_MTIE); // activate MTIME IRQ source only!
339
    neorv32_cpu_eint(); // enable global interrupts
340
  }
341 2 zero_gravi
 
342 39 zero_gravi
 
343 2 zero_gravi
  // ------------------------------------------------
344
  // Show bootloader intro and system info
345
  // ------------------------------------------------
346 61 zero_gravi
  PRINT_TEXT("\n\n\n<< NEORV32 Bootloader >>\n\n"
347 2 zero_gravi
                     "BLDV: "__DATE__"\nHWV:  ");
348 61 zero_gravi
  PRINT_XNUM(neorv32_cpu_csr_read(CSR_MIMPID));
349
  PRINT_TEXT("\nCLK:  ");
350 64 zero_gravi
  PRINT_XNUM(NEORV32_SYSINFO.CLK);
351 61 zero_gravi
  PRINT_TEXT("\nMISA: ");
352
  PRINT_XNUM(neorv32_cpu_csr_read(CSR_MISA));
353 64 zero_gravi
  PRINT_TEXT("\nCPU:  ");
354
  PRINT_XNUM(NEORV32_SYSINFO.CPU);
355
  PRINT_TEXT("\nSOC:  ");
356
  PRINT_XNUM(NEORV32_SYSINFO.SOC);
357 61 zero_gravi
  PRINT_TEXT("\nIMEM: ");
358 64 zero_gravi
  PRINT_XNUM(NEORV32_SYSINFO.IMEM_SIZE);
359 61 zero_gravi
  PRINT_TEXT(" bytes @");
360 64 zero_gravi
  PRINT_XNUM(NEORV32_SYSINFO.ISPACE_BASE);
361 61 zero_gravi
  PRINT_TEXT("\nDMEM: ");
362 64 zero_gravi
  PRINT_XNUM(NEORV32_SYSINFO.DMEM_SIZE);
363 61 zero_gravi
  PRINT_TEXT(" bytes @");
364 64 zero_gravi
  PRINT_XNUM(NEORV32_SYSINFO.DSPACE_BASE);
365 2 zero_gravi
 
366
 
367
  // ------------------------------------------------
368
  // Auto boot sequence
369
  // ------------------------------------------------
370 63 zero_gravi
#if (SPI_EN != 0)
371
#if (AUTO_BOOT_TIMEOUT != 0)
372 61 zero_gravi
  if (neorv32_mtime_available()) {
373 2 zero_gravi
 
374 61 zero_gravi
    PRINT_TEXT("\n\nAutoboot in "xstr(AUTO_BOOT_TIMEOUT)"s. Press key to abort.\n");
375 65 zero_gravi
    uint64_t timeout_time = neorv32_cpu_get_systime() + (uint64_t)(AUTO_BOOT_TIMEOUT * NEORV32_SYSINFO.CLK);
376 13 zero_gravi
 
377 61 zero_gravi
    while(1){
378 2 zero_gravi
 
379 61 zero_gravi
      if (neorv32_uart0_available()) { // wait for any key to be pressed
380
        if (neorv32_uart0_char_received()) {
381
          break;
382
        }
383
      }
384
 
385 65 zero_gravi
      if (neorv32_cpu_get_systime() >= timeout_time) { // timeout? start auto boot sequence
386 61 zero_gravi
        get_exe(EXE_STREAM_FLASH); // try booting from flash
387
        PRINT_TEXT("\n");
388
        start_app();
389
        while(1);
390
      }
391
 
392 2 zero_gravi
    }
393 61 zero_gravi
    PRINT_TEXT("Aborted.\n\n");
394 2 zero_gravi
  }
395 24 zero_gravi
#else
396 61 zero_gravi
  PRINT_TEXT("Aborted.\n\n");
397 24 zero_gravi
#endif
398 63 zero_gravi
#else
399
  PRINT_TEXT("\n\n");
400
#endif
401 24 zero_gravi
 
402 2 zero_gravi
  print_help();
403
 
404
 
405
  // ------------------------------------------------
406
  // Bootloader console
407
  // ------------------------------------------------
408
  while (1) {
409
 
410 61 zero_gravi
    PRINT_TEXT("\nCMD:> ");
411
    char c = PRINT_GETC();
412
    PRINT_PUTC(c); // echo
413
    PRINT_TEXT("\n");
414 2 zero_gravi
 
415 61 zero_gravi
    if (c == 'r') { // restart bootloader
416 22 zero_gravi
      asm volatile ("li t0, %[input_i]; jr t0" :  : [input_i] "i" (BOOTLOADER_BASE_ADDRESS)); // jump to beginning of boot ROM
417 2 zero_gravi
    }
418
    else if (c == 'h') { // help menu
419
      print_help();
420
    }
421
    else if (c == 'u') { // get executable via UART
422
      get_exe(EXE_STREAM_UART);
423
    }
424 63 zero_gravi
#if (SPI_EN != 0)
425 24 zero_gravi
    else if (c == 's') { // program flash from memory (IMEM)
426 2 zero_gravi
      save_exe();
427
    }
428
    else if (c == 'l') { // get executable from flash
429
      get_exe(EXE_STREAM_FLASH);
430
    }
431 63 zero_gravi
#endif
432 61 zero_gravi
    else if (c == 'e') { // start application program  // executable available?
433
      if (exe_available == 0) {
434
        PRINT_TEXT("No executable available.");
435
      }
436
      else {
437
        start_app();
438
      }
439 2 zero_gravi
    }
440
    else { // unknown command
441 61 zero_gravi
      PRINT_TEXT("Invalid CMD");
442 2 zero_gravi
    }
443
  }
444
 
445 60 zero_gravi
  return 1; // bootloader should never return
446 2 zero_gravi
}
447
 
448
 
449
/**********************************************************************//**
450
 * Print help menu.
451
 **************************************************************************/
452
void print_help(void) {
453
 
454 61 zero_gravi
  PRINT_TEXT("Available CMDs:\n"
455 2 zero_gravi
                     " h: Help\n"
456
                     " r: Restart\n"
457
                     " u: Upload\n"
458 63 zero_gravi
#if (SPI_EN != 0)
459 2 zero_gravi
                     " s: Store to flash\n"
460
                     " l: Load from flash\n"
461 63 zero_gravi
#endif
462 2 zero_gravi
                     " e: Execute");
463
}
464
 
465
 
466
/**********************************************************************//**
467
 * Start application program at the beginning of instruction space.
468
 **************************************************************************/
469
void start_app(void) {
470
 
471 23 zero_gravi
  // deactivate global IRQs
472 2 zero_gravi
  neorv32_cpu_dint();
473
 
474 61 zero_gravi
  PRINT_TEXT("Booting...\n\n");
475 2 zero_gravi
 
476
  // wait for UART to finish transmitting
477 61 zero_gravi
  while (neorv32_uart0_tx_busy());
478 2 zero_gravi
 
479
  // start app at instruction space base address
480 64 zero_gravi
  register uint32_t app_base = NEORV32_SYSINFO.ISPACE_BASE;
481 14 zero_gravi
  asm volatile ("jalr zero, %0" : : "r" (app_base));
482
  while (1);
483 2 zero_gravi
}
484
 
485
 
486
/**********************************************************************//**
487 23 zero_gravi
 * Bootloader trap handler. Used for the MTIME tick and to capture any other traps.
488 61 zero_gravi
 *
489
 * @warning Adapt exception PC only for sync exceptions!
490
 *
491
 * @note Since we have no runtime environment, we have to use the interrupt attribute here. Here and only here!
492 2 zero_gravi
 **************************************************************************/
493 22 zero_gravi
void __attribute__((__interrupt__)) bootloader_trap_handler(void) {
494 2 zero_gravi
 
495 47 zero_gravi
  uint32_t cause = neorv32_cpu_csr_read(CSR_MCAUSE);
496
 
497 61 zero_gravi
  // Machine timer interrupt
498 23 zero_gravi
  if (cause == TRAP_CODE_MTI) { // raw exception code for MTI
499 56 zero_gravi
#if (STATUS_LED_EN != 0)
500 61 zero_gravi
    if (neorv32_gpio_available()) {
501
      neorv32_gpio_pin_toggle(STATUS_LED_PIN); // toggle status LED
502
    }
503 56 zero_gravi
#endif
504 2 zero_gravi
    // set time for next IRQ
505 61 zero_gravi
    if (neorv32_mtime_available()) {
506 65 zero_gravi
      neorv32_mtime_set_timecmp(neorv32_cpu_get_systime() + (NEORV32_SYSINFO.CLK/4));
507 61 zero_gravi
    }
508 2 zero_gravi
  }
509 61 zero_gravi
 
510
  // Bus store access error during get_exe
511
  else if ((cause == TRAP_CODE_S_ACCESS) && (getting_exe)) {
512
    system_error(ERROR_SIZE); // -> seems like executable is too large
513
  }
514
 
515
  // Anything else (that was not expected); output exception notifier and try to resume
516 23 zero_gravi
  else {
517 61 zero_gravi
    uint32_t epc = neorv32_cpu_csr_read(CSR_MEPC);
518
#if (UART_EN != 0)
519
    if (neorv32_uart0_available()) {
520
      PRINT_TEXT("\n[EXC ");
521
      PRINT_XNUM(cause); // MCAUSE
522
      PRINT_PUTC(' ');
523
      PRINT_XNUM(epc); // MEPC
524
      PRINT_PUTC(' ');
525
      PRINT_XNUM(neorv32_cpu_csr_read(CSR_MTVAL)); // MTVAL
526
      PRINT_TEXT("]\n");
527 47 zero_gravi
    }
528 61 zero_gravi
#endif
529
    neorv32_cpu_csr_write(CSR_MEPC, epc + 4); // advance to next instruction
530 23 zero_gravi
  }
531 2 zero_gravi
}
532
 
533
 
534
/**********************************************************************//**
535
 * Get executable stream.
536
 *
537
 * @param src Source of executable stream data. See #EXE_STREAM_SOURCE.
538
 **************************************************************************/
539
void get_exe(int src) {
540
 
541 47 zero_gravi
  getting_exe = 1; // to inform trap handler we were trying to get an executable
542
 
543 2 zero_gravi
  // flash image base address
544 61 zero_gravi
  uint32_t addr = (uint32_t)SPI_BOOT_BASE_ADDR;
545 2 zero_gravi
 
546
  // get image from flash?
547
  if (src == EXE_STREAM_UART) {
548 61 zero_gravi
    PRINT_TEXT("Awaiting neorv32_exe.bin... ");
549 2 zero_gravi
  }
550 63 zero_gravi
#if (SPI_EN != 0)
551 2 zero_gravi
  else {
552 61 zero_gravi
    PRINT_TEXT("Loading... ");
553 2 zero_gravi
 
554 61 zero_gravi
    // flash checks
555
    if ((neorv32_spi_available() == 0) ||    // check if SPI is available at all
556
        (spi_flash_read_1st_id() == 0x00)) { // check if flash ready (or available at all)
557 57 zero_gravi
      system_error(ERROR_FLASH);
558
    }
559 2 zero_gravi
  }
560 63 zero_gravi
#endif
561 2 zero_gravi
 
562
  // check if valid image
563
  uint32_t signature = get_exe_word(src, addr + EXE_OFFSET_SIGNATURE);
564
  if (signature != EXE_SIGNATURE) { // signature
565
    system_error(ERROR_SIGNATURE);
566
  }
567
 
568
  // image size and checksum
569
  uint32_t size  = get_exe_word(src, addr + EXE_OFFSET_SIZE); // size in bytes
570
  uint32_t check = get_exe_word(src, addr + EXE_OFFSET_CHECKSUM); // complement sum checksum
571
 
572
  // transfer program data
573 64 zero_gravi
  uint32_t *pnt = (uint32_t*)NEORV32_SYSINFO.ISPACE_BASE;
574 2 zero_gravi
  uint32_t checksum = 0;
575
  uint32_t d = 0, i = 0;
576
  addr = addr + EXE_OFFSET_DATA;
577
  while (i < (size/4)) { // in words
578
    d = get_exe_word(src, addr);
579
    checksum += d;
580
    pnt[i++] = d;
581
    addr += 4;
582
  }
583
 
584
  // error during transfer?
585
  if ((checksum + check) != 0) {
586
    system_error(ERROR_CHECKSUM);
587
  }
588
  else {
589 61 zero_gravi
    PRINT_TEXT("OK");
590 22 zero_gravi
    exe_available = size; // store exe size
591 2 zero_gravi
  }
592 47 zero_gravi
 
593
  getting_exe = 0; // to inform trap handler we are done getting an executable
594 2 zero_gravi
}
595
 
596
 
597
/**********************************************************************//**
598
 * Store content of instruction memory to SPI flash.
599
 **************************************************************************/
600
void save_exe(void) {
601
 
602 63 zero_gravi
#if (SPI_EN != 0)
603 2 zero_gravi
  // size of last uploaded executable
604 22 zero_gravi
  uint32_t size = exe_available;
605 2 zero_gravi
 
606
  if (size == 0) {
607 61 zero_gravi
    PRINT_TEXT("No executable available.");
608 2 zero_gravi
    return;
609
  }
610
 
611 61 zero_gravi
  uint32_t addr = (uint32_t)SPI_BOOT_BASE_ADDR;
612 2 zero_gravi
 
613
  // info and prompt
614 61 zero_gravi
  PRINT_TEXT("Write ");
615
  PRINT_XNUM(size);
616
  PRINT_TEXT(" bytes to SPI flash @ ");
617
  PRINT_XNUM(addr);
618
  PRINT_TEXT("? (y/n) ");
619 2 zero_gravi
 
620 61 zero_gravi
  char c = PRINT_GETC();
621
  PRINT_PUTC(c);
622 2 zero_gravi
  if (c != 'y') {
623
    return;
624
  }
625
 
626
  // check if flash ready (or available at all)
627
  if (spi_flash_read_1st_id() == 0x00) { // manufacturer ID
628
    system_error(ERROR_FLASH);
629
  }
630
 
631 61 zero_gravi
  PRINT_TEXT("\nFlashing... ");
632 2 zero_gravi
 
633
  // clear memory before writing
634 61 zero_gravi
  uint32_t num_sectors = (size / (SPI_FLASH_SECTOR_SIZE)) + 1; // clear at least 1 sector
635
  uint32_t sector = (uint32_t)SPI_BOOT_BASE_ADDR;
636 2 zero_gravi
  while (num_sectors--) {
637
    spi_flash_erase_sector(sector);
638
    sector += SPI_FLASH_SECTOR_SIZE;
639
  }
640
 
641
  // write EXE signature
642
  spi_flash_write_word(addr + EXE_OFFSET_SIGNATURE, EXE_SIGNATURE);
643
 
644
  // write size
645
  spi_flash_write_word(addr + EXE_OFFSET_SIZE, size);
646
 
647
  // store data from instruction memory and update checksum
648
  uint32_t checksum = 0;
649 64 zero_gravi
  uint32_t *pnt = (uint32_t*)NEORV32_SYSINFO.ISPACE_BASE;
650 2 zero_gravi
  addr = addr + EXE_OFFSET_DATA;
651
  uint32_t i = 0;
652
  while (i < (size/4)) { // in words
653
    uint32_t d = (uint32_t)*pnt++;
654
    checksum += d;
655
    spi_flash_write_word(addr, d);
656
    addr += 4;
657
    i++;
658
  }
659
 
660
  // write checksum (sum complement)
661
  checksum = (~checksum) + 1;
662 61 zero_gravi
  spi_flash_write_word((uint32_t)SPI_BOOT_BASE_ADDR + EXE_OFFSET_CHECKSUM, checksum);
663 2 zero_gravi
 
664 61 zero_gravi
  PRINT_TEXT("OK");
665 63 zero_gravi
#endif
666 2 zero_gravi
}
667
 
668
 
669
/**********************************************************************//**
670
 * Get word from executable stream
671
 *
672
 * @param src Source of executable stream data. See #EXE_STREAM_SOURCE.
673
 * @param addr Address when accessing SPI flash.
674
 * @return 32-bit data word from stream.
675
 **************************************************************************/
676
uint32_t get_exe_word(int src, uint32_t addr) {
677
 
678
  union {
679
    uint32_t uint32;
680
    uint8_t  uint8[sizeof(uint32_t)];
681
  } data;
682
 
683
  uint32_t i;
684
  for (i=0; i<4; i++) {
685
    if (src == EXE_STREAM_UART) {
686 61 zero_gravi
      data.uint8[i] = (uint8_t)PRINT_GETC();
687 2 zero_gravi
    }
688 63 zero_gravi
#if (SPI_EN != 0)
689 2 zero_gravi
    else {
690 60 zero_gravi
      data.uint8[i] = spi_flash_read_byte(addr + i);
691 2 zero_gravi
    }
692 63 zero_gravi
#endif
693 2 zero_gravi
  }
694
 
695
  return data.uint32;
696
}
697
 
698
 
699
/**********************************************************************//**
700
 * Output system error ID and stall.
701
 *
702
 * @param[in] err_code Error code. See #ERROR_CODES.
703
 **************************************************************************/
704
void system_error(uint8_t err_code) {
705
 
706 61 zero_gravi
  PRINT_TEXT("\a\nERROR_"); // output error code with annoying bell sound
707
  PRINT_PUTC('0' + ((char)err_code));
708 2 zero_gravi
 
709
  neorv32_cpu_dint(); // deactivate IRQs
710 61 zero_gravi
#if (STATUS_LED_EN != 0)
711
  if (neorv32_gpio_available()) {
712
    neorv32_gpio_port_set(1 << STATUS_LED_PIN); // permanently light up status LED
713 22 zero_gravi
  }
714 61 zero_gravi
#endif
715 2 zero_gravi
 
716
  while(1); // freeze
717
}
718
 
719
 
720
/**********************************************************************//**
721
 * Print 32-bit number as 8-digit hexadecimal value (with "0x" suffix).
722
 *
723
 * @param[in] num Number to print as hexadecimal.
724
 **************************************************************************/
725
void print_hex_word(uint32_t num) {
726
 
727 61 zero_gravi
#if (UART_EN != 0)
728 56 zero_gravi
  static const char hex_symbols[16] = "0123456789abcdef";
729 2 zero_gravi
 
730 61 zero_gravi
  PRINT_TEXT("0x");
731 2 zero_gravi
 
732
  int i;
733
  for (i=0; i<8; i++) {
734
    uint32_t index = (num >> (28 - 4*i)) & 0xF;
735 61 zero_gravi
    PRINT_PUTC(hex_symbols[index]);
736 2 zero_gravi
  }
737 61 zero_gravi
#endif
738 2 zero_gravi
}
739
 
740
 
741
 
742
// -------------------------------------------------------------------------------------
743 37 zero_gravi
// SPI flash driver functions
744 2 zero_gravi
// -------------------------------------------------------------------------------------
745
 
746
/**********************************************************************//**
747
 * Read byte from SPI flash.
748
 *
749
 * @param[in] addr Flash read address.
750
 * @return Read byte from SPI flash.
751
 **************************************************************************/
752
uint8_t spi_flash_read_byte(uint32_t addr) {
753
 
754 63 zero_gravi
#if (SPI_EN != 0)
755 2 zero_gravi
  neorv32_spi_cs_en(SPI_FLASH_CS);
756
 
757
  neorv32_spi_trans(SPI_FLASH_CMD_READ);
758 4 zero_gravi
  spi_flash_write_addr(addr);
759 2 zero_gravi
  uint8_t rdata = (uint8_t)neorv32_spi_trans(0);
760
 
761
  neorv32_spi_cs_dis(SPI_FLASH_CS);
762
 
763
  return rdata;
764 63 zero_gravi
#else
765
  return 0;
766
#endif
767 2 zero_gravi
}
768
 
769
 
770
/**********************************************************************//**
771
 * Write byte to SPI flash.
772
 *
773
 * @param[in] addr SPI flash read address.
774
 * @param[in] wdata SPI flash read data.
775
 **************************************************************************/
776
void spi_flash_write_byte(uint32_t addr, uint8_t wdata) {
777
 
778 63 zero_gravi
#if (SPI_EN != 0)
779 4 zero_gravi
  spi_flash_write_enable(); // allow write-access
780 2 zero_gravi
 
781
  neorv32_spi_cs_en(SPI_FLASH_CS);
782
 
783
  neorv32_spi_trans(SPI_FLASH_CMD_PAGE_PROGRAM);
784 4 zero_gravi
  spi_flash_write_addr(addr);
785 2 zero_gravi
  neorv32_spi_trans(wdata);
786
 
787
  neorv32_spi_cs_dis(SPI_FLASH_CS);
788
 
789 37 zero_gravi
  spi_flash_write_wait(); // wait for write operation to finish
790 63 zero_gravi
#endif
791 2 zero_gravi
}
792
 
793
 
794
/**********************************************************************//**
795
 * Write word to SPI flash.
796
 *
797
 * @param addr SPI flash write address.
798
 * @param wdata SPI flash write data.
799
 **************************************************************************/
800
void spi_flash_write_word(uint32_t addr, uint32_t wdata) {
801
 
802 63 zero_gravi
#if (SPI_EN != 0)
803 2 zero_gravi
  union {
804
    uint32_t uint32;
805
    uint8_t  uint8[sizeof(uint32_t)];
806
  } data;
807
 
808
  data.uint32 = wdata;
809
 
810 39 zero_gravi
  int i;
811 2 zero_gravi
  for (i=0; i<4; i++) {
812 60 zero_gravi
    spi_flash_write_byte(addr + i, data.uint8[i]);
813 2 zero_gravi
  }
814 63 zero_gravi
#endif
815 2 zero_gravi
}
816
 
817
 
818
/**********************************************************************//**
819
 * Erase sector (64kB) at base adress.
820
 *
821
 * @param[in] addr Base address of sector to erase.
822
 **************************************************************************/
823
void spi_flash_erase_sector(uint32_t addr) {
824
 
825 63 zero_gravi
#if (SPI_EN != 0)
826 4 zero_gravi
  spi_flash_write_enable(); // allow write-access
827 2 zero_gravi
 
828
  neorv32_spi_cs_en(SPI_FLASH_CS);
829
 
830
  neorv32_spi_trans(SPI_FLASH_CMD_SECTOR_ERASE);
831 4 zero_gravi
  spi_flash_write_addr(addr);
832 2 zero_gravi
 
833
  neorv32_spi_cs_dis(SPI_FLASH_CS);
834
 
835 37 zero_gravi
  spi_flash_write_wait(); // wait for write operation to finish
836 63 zero_gravi
#endif
837 2 zero_gravi
}
838
 
839
 
840
/**********************************************************************//**
841 37 zero_gravi
 * Read first byte of ID (manufacturer ID), should be != 0x00.
842 2 zero_gravi
 *
843 37 zero_gravi
 * @note The first bit of the manufacturer ID is used to detect if a Flash is connected at all.
844
 *
845
 * @return First byte of ID.
846 2 zero_gravi
 **************************************************************************/
847 37 zero_gravi
uint8_t spi_flash_read_1st_id(void) {
848 2 zero_gravi
 
849 63 zero_gravi
#if (SPI_EN != 0)
850 2 zero_gravi
  neorv32_spi_cs_en(SPI_FLASH_CS);
851
 
852 37 zero_gravi
  neorv32_spi_trans(SPI_FLASH_CMD_READ_ID);
853
  uint8_t id = (uint8_t)neorv32_spi_trans(0);
854 2 zero_gravi
 
855
  neorv32_spi_cs_dis(SPI_FLASH_CS);
856
 
857 37 zero_gravi
  return id;
858 63 zero_gravi
#else
859
  return 0;
860
#endif
861 2 zero_gravi
}
862
 
863
 
864
/**********************************************************************//**
865 63 zero_gravi
 * Wait for flash write operation to finish.
866 2 zero_gravi
 **************************************************************************/
867 37 zero_gravi
void spi_flash_write_wait(void) {
868 2 zero_gravi
 
869 63 zero_gravi
#if (SPI_EN != 0)
870 37 zero_gravi
  while(1) {
871 2 zero_gravi
 
872 37 zero_gravi
    neorv32_spi_cs_en(SPI_FLASH_CS);
873 2 zero_gravi
 
874 37 zero_gravi
    neorv32_spi_trans(SPI_FLASH_CMD_READ_STATUS);
875
    uint8_t status = (uint8_t)neorv32_spi_trans(0);
876 2 zero_gravi
 
877 37 zero_gravi
    neorv32_spi_cs_dis(SPI_FLASH_CS);
878
 
879
    if ((status & 0x01) == 0) { // write in progress flag cleared?
880
      break;
881
    }
882
  }
883 63 zero_gravi
#endif
884 2 zero_gravi
}
885
 
886
 
887
/**********************************************************************//**
888 4 zero_gravi
 * Enable flash write access.
889 2 zero_gravi
 **************************************************************************/
890 4 zero_gravi
void spi_flash_write_enable(void) {
891 2 zero_gravi
 
892 63 zero_gravi
#if (SPI_EN != 0)
893 2 zero_gravi
  neorv32_spi_cs_en(SPI_FLASH_CS);
894 4 zero_gravi
  neorv32_spi_trans(SPI_FLASH_CMD_WRITE_ENABLE);
895
  neorv32_spi_cs_dis(SPI_FLASH_CS);
896 63 zero_gravi
#endif
897 4 zero_gravi
}
898 2 zero_gravi
 
899
 
900 4 zero_gravi
/**********************************************************************//**
901
 * Send address word to flash.
902
 *
903
 * @param[in] addr Address word.
904
 **************************************************************************/
905
void spi_flash_write_addr(uint32_t addr) {
906
 
907 63 zero_gravi
#if (SPI_EN != 0)
908 4 zero_gravi
  union {
909
    uint32_t uint32;
910
    uint8_t  uint8[sizeof(uint32_t)];
911
  } address;
912
 
913
  address.uint32 = addr;
914
 
915 39 zero_gravi
  int i;
916
  for (i=2; i>=0; i--) {
917
    neorv32_spi_trans(address.uint8[i]);
918
  }
919 63 zero_gravi
#endif
920 2 zero_gravi
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.