Startup File startup_<Device>.S
- The Startup File startup_<device>.S contains:
The reset handler which is executed after CPU reset and typically calls the
SystemInit()
function.The setup values for the stack pointer SP and global pointor GP for small data access.
Exception vectors of the Nuclei Processor with weak functions that implement default routines.
Interrupt vectors that are device specific with weak functions that implement default routines.
The processer level start flow is implemented in the startup_<Device>.S. Detail description as below picture:
The IAR version of startup code located in startup_<Device>.c.
- Stage1: Interrupt and Exception initialization
Disable Interrupt
Initialize GP, SP for single core or smp core if existed
Initialize NMI entry and set default NMI handler
Initialize exception entry to early exception entry in
startup_<Device>.S
Initialize vector table entry and set default interrupt handler
Initialize Interrupt mode as ECLIC mode. (ECLIC mode is proposed. Default mode is CLINT mode)
- Stage2: Hardware initialization
Enable FPU if necessary
Enable VPU if necessary
Enable Zc if necessary
- Stage3: Section initialization
Copy section, e.g. data section, text section if necessary.
Clear Block Started by Symbol (BSS) section
Call user defined
SystemInit()
for system clock initialization.Call
__libc_fini_array
and__libc_init_array
functions to do C library initializationCall
_premain_init
function to do initialization steps before main functionInitialize exception entry to exception entry in
intexc_<Device>.S
Enable BPU of Nuclei CPU
Jump Main
The file exists for each supported toolchain and is the only toolchain specific NMSIS file.
To adapt the file to a new device only the interrupt vector table needs to be extended with the device-specific interrupt handlers.
The naming convention for the interrupt handler names are eclic_<interrupt_name>_handler
.
This table needs to be consistent with IRQn_Type
that defines all the IRQ numbers for each interrupt.
The following example shows the extension of the interrupt vector table for the GD32VF103 device family.
1 .section .text.vtable
2
3 .weak eclic_msip_handler
4 .weak eclic_mtip_handler
5 .weak eclic_pmaf_handler
6 /* Adjusted for GD32VF103 interrupt handlers */
7 .weak eclic_wwdgt_handler
8 .weak eclic_lvd_handler
9 .weak eclic_tamper_handler
10 : :
11 : :
12 .weak eclic_can1_ewmc_handler
13 .weak eclic_usbfs_handler
14
15 .globl vector_base
16 .type vector_base, @object
17 vector_base:
18 /* Run in FlashXIP download mode */
19 j _start /* 0: Reserved, Jump to _start when reset for vector table not remapped cases.*/
20 .align LOG_REGBYTES /* Need to align 4 byte for RV32, 8 Byte for RV64 */
21 DECLARE_INT_HANDLER default_intexc_handler /* 1: Reserved */
22 DECLARE_INT_HANDLER default_intexc_handler /* 2: Reserved */
23 DECLARE_INT_HANDLER eclic_msip_handler /* 3: Machine software interrupt */
24 : :
25 : :
26 /* Adjusted for Vendor Defined External Interrupts */
27 DECLARE_INT_HANDLER eclic_wwdgt_handler /* 19: Window watchDog timer interrupt */
28
29 DECLARE_INT_HANDLER eclic_lvd_handler /* 20: LVD through EXTI line detect interrupt */
30 DECLARE_INT_HANDLER eclic_tamper_handler /* 21: tamper through EXTI line detect */
31 : :
32 : :
33 DECLARE_INT_HANDLER eclic_can1_ewmc_handler /* 85: CAN1 EWMC interrupt */
34 DECLARE_INT_HANDLER eclic_usbfs_handler /* 86: USBFS global interrupt */
startup_Device.S Template File
Here provided a riscv-gcc template startup assemble code template file as below. The files for other compilers can slightly differ from this version.
1 /*
2 * Copyright (c) 2019 Nuclei Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Licensed under the Apache License, Version 2.0 (the License); you may
7 * not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
14 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18 /******************************************************************************
19 * \file startup_<Device>.S
20 * \brief NMSIS Nuclei N/NX Class Core based Core Device Startup File for
21 * Device <Device>
22 * \version V2.1.0
23 * \date 19. Dec 2023
24 *
25 ******************************************************************************/
26
27 #include "riscv_encoding.h"
28
29 /* TODO: If BOOT_HARTID is not defined, default value is 0, change it to your desired default boot hartid */
30 #ifndef BOOT_HARTID
31 .equ BOOT_HARTID, 0
32 #endif
33
34 .macro DECLARE_INT_HANDLER INT_HDL_NAME
35 #if defined(__riscv_xlen) && (__riscv_xlen == 32)
36 .word \INT_HDL_NAME
37 #else
38 .dword \INT_HDL_NAME
39 #endif
40 .endm
41
42 .section .text.vtable
43
44 /* TODO: Add your interrupt handler in this vector table */
45 .weak eclic_msip_handler
46 .weak eclic_mtip_handler
47 .weak eclic_inter_core_int_handler
48 .globl vector_base
49 .type vector_base, @object
50 .option push
51 .option norelax
52 vector_base:
53 #ifndef VECTOR_TABLE_REMAPPED
54 j _start /* 0: Reserved, Jump to _start when reset for vector table not remapped cases.*/
55 .align LOG_REGBYTES /* Need to align 4 byte for RV32, 8 Byte for RV64 */
56 #else
57 DECLARE_INT_HANDLER default_intexc_handler /* 0: Reserved, default handler for vector table remapped cases */
58 #endif
59 DECLARE_INT_HANDLER default_intexc_handler /* 1: Reserved */
60 DECLARE_INT_HANDLER default_intexc_handler /* 2: Reserved */
61 DECLARE_INT_HANDLER eclic_msip_handler /* 3: Machine software interrupt */
62
63 DECLARE_INT_HANDLER default_intexc_handler /* 4: Reserved */
64 DECLARE_INT_HANDLER default_intexc_handler /* 5: Reserved */
65 DECLARE_INT_HANDLER default_intexc_handler /* 6: Reserved */
66 DECLARE_INT_HANDLER eclic_mtip_handler /* 7: Machine timer interrupt */
67
68 DECLARE_INT_HANDLER default_intexc_handler /* 8: Reserved */
69 DECLARE_INT_HANDLER default_intexc_handler /* 9: Reserved */
70 DECLARE_INT_HANDLER default_intexc_handler /* 10: Reserved */
71 DECLARE_INT_HANDLER default_intexc_handler /* 11: Reserved */
72
73 DECLARE_INT_HANDLER default_intexc_handler /* 12: Reserved */
74 DECLARE_INT_HANDLER default_intexc_handler /* 13: Reserved */
75 DECLARE_INT_HANDLER default_intexc_handler /* 14: Reserved */
76 DECLARE_INT_HANDLER default_intexc_handler /* 15: Reserved */
77
78 DECLARE_INT_HANDLER eclic_inter_core_int_handler /* 16: Reserved */
79 DECLARE_INT_HANDLER default_intexc_handler /* 17: Reserved */
80 DECLARE_INT_HANDLER default_intexc_handler /* 18: Reserved */
81 DECLARE_INT_HANDLER default_intexc_handler /* 19: Interrupt 19 */
82
83 DECLARE_INT_HANDLER default_intexc_handler /* 20: Interrupt 20 */
84 DECLARE_INT_HANDLER default_intexc_handler /* 21: Interrupt 21 */
85 DECLARE_INT_HANDLER default_intexc_handler /* 22: Interrupt 22 */
86 DECLARE_INT_HANDLER default_intexc_handler /* 23: Interrupt 23 */
87
88 DECLARE_INT_HANDLER default_intexc_handler /* 24: Interrupt 24 */
89 DECLARE_INT_HANDLER default_intexc_handler /* 25: Interrupt 25 */
90 DECLARE_INT_HANDLER default_intexc_handler /* 26: Interrupt 26 */
91 DECLARE_INT_HANDLER default_intexc_handler /* 27: Interrupt 27 */
92
93 DECLARE_INT_HANDLER default_intexc_handler /* 28: Interrupt 28 */
94 DECLARE_INT_HANDLER default_intexc_handler /* 29: Interrupt 29 */
95 DECLARE_INT_HANDLER default_intexc_handler /* 30: Interrupt 30 */
96 DECLARE_INT_HANDLER default_intexc_handler /* 31: Interrupt 31 */
97
98 DECLARE_INT_HANDLER default_intexc_handler /* 32: Interrupt 32 */
99 DECLARE_INT_HANDLER default_intexc_handler /* 33: Interrupt 33 */
100 DECLARE_INT_HANDLER default_intexc_handler /* 34: Interrupt 34 */
101 DECLARE_INT_HANDLER default_intexc_handler /* 35: Interrupt 35 */
102
103 DECLARE_INT_HANDLER default_intexc_handler /* 36: Interrupt 36 */
104 DECLARE_INT_HANDLER default_intexc_handler /* 37: Interrupt 37 */
105 DECLARE_INT_HANDLER default_intexc_handler /* 38: Interrupt 38 */
106 DECLARE_INT_HANDLER default_intexc_handler /* 39: Interrupt 39 */
107
108 DECLARE_INT_HANDLER default_intexc_handler /* 40: Interrupt 40 */
109 DECLARE_INT_HANDLER default_intexc_handler /* 41: Interrupt 41 */
110 DECLARE_INT_HANDLER default_intexc_handler /* 42: Interrupt 42 */
111 DECLARE_INT_HANDLER default_intexc_handler /* 43: Interrupt 43 */
112
113 DECLARE_INT_HANDLER default_intexc_handler /* 44: Interrupt 44 */
114 DECLARE_INT_HANDLER default_intexc_handler /* 45: Interrupt 45 */
115 DECLARE_INT_HANDLER default_intexc_handler /* 46: Interrupt 46 */
116 DECLARE_INT_HANDLER default_intexc_handler /* 47: Interrupt 47 */
117
118 DECLARE_INT_HANDLER default_intexc_handler /* 48: Interrupt 48 */
119 DECLARE_INT_HANDLER default_intexc_handler /* 49: Interrupt 49 */
120 DECLARE_INT_HANDLER default_intexc_handler /* 50: Interrupt 50 */
121 DECLARE_INT_HANDLER default_intexc_handler /* 51: Interrupt 51 */
122
123 DECLARE_INT_HANDLER default_intexc_handler /* 52: Interrupt 52 */
124 DECLARE_INT_HANDLER default_intexc_handler /* 53: Interrupt 53 */
125 DECLARE_INT_HANDLER default_intexc_handler /* 54: Interrupt 54 */
126 DECLARE_INT_HANDLER default_intexc_handler /* 55: Interrupt 55 */
127
128 DECLARE_INT_HANDLER default_intexc_handler /* 56: Interrupt 56 */
129 DECLARE_INT_HANDLER default_intexc_handler /* 57: Interrupt 57 */
130 DECLARE_INT_HANDLER default_intexc_handler /* 58: Interrupt 58 */
131 DECLARE_INT_HANDLER default_intexc_handler /* 59: Interrupt 59 */
132
133 DECLARE_INT_HANDLER default_intexc_handler /* 60: Interrupt 60 */
134 DECLARE_INT_HANDLER default_intexc_handler /* 61: Interrupt 61 */
135 DECLARE_INT_HANDLER default_intexc_handler /* 62: Interrupt 62 */
136 DECLARE_INT_HANDLER default_intexc_handler /* 63: Interrupt 63 */
137
138 .option pop
139
140
141 .section .text.init
142 .globl _start
143 .type _start, @function
144
145 /**
146 * Reset Handler called on controller reset
147 */
148 _start:
149 /* ===== Startup Stage 1 ===== */
150 /* Disable Global Interrupt */
151 csrc CSR_MSTATUS, MSTATUS_MIE
152
153 /* If SMP_CPU_CNT is not defined,
154 * assume that only 1 core is allowed to run,
155 * the core hartid is defined via BOOT_HARTID.
156 * other harts if run to here, just do wfi in __amp_wait
157 */
158 #ifndef SMP_CPU_CNT
159 /* take bit 0-7 for hart id in a local cluster */
160 csrr a0, CSR_MHARTID
161 andi a0, a0, 0xFF
162 /* BOOT_HARTID is configurable in Makefile via BOOT_HARTID variable */
163 li a1, BOOT_HARTID
164 bne a0, a1, __amp_wait
165 #endif
166
167 /* Initialize GP and TP and jump table base when zcmt enabled */
168 .option push
169 .option norelax
170 la gp, __global_pointer$
171 la tp, __tls_base
172 #if defined(__riscv_zcmt)
173 la t0, __jvt_base$
174 csrw CSR_JVT, t0
175 #endif
176 .option pop
177
178 #if defined(SMP_CPU_CNT) && (SMP_CPU_CNT > 1)
179 /* Set correct sp for each cpu
180 * each stack size is __STACK_SIZE
181 * defined in linker script */
182 lui t0, %hi(__STACK_SIZE)
183 addi t0, t0, %lo(__STACK_SIZE)
184 la sp, _sp
185 csrr a0, CSR_MHARTID
186 andi a0, a0, 0xFF
187 li a1, 0
188 1:
189 beq a0, a1, 2f
190 sub sp, sp, t0
191 addi a1, a1, 1
192 j 1b
193 2:
194 #else
195 /* Set correct sp for current cpu */
196 la sp, _sp
197 #endif
198
199 /*
200 * Set the the NMI base mnvec to share
201 * with mtvec by setting CSR_MMISC_CTL
202 * bit 9 NMI_CAUSE_FFF to 1
203 */
204 li t0, MMISC_CTL_NMI_CAUSE_FFF
205 csrs CSR_MMISC_CTL, t0
206
207 /*
208 * Enable Zc feature when compiled zcmp & zcmt
209 */
210 #if defined(__riscv_zcmp) || defined(__riscv_zcmt)
211 li t0, MMISC_CTL_ZC
212 csrs CSR_MMISC_CTL, t0
213 #endif
214
215 /*
216 * Intialize ECLIC vector interrupt
217 * base address mtvt to vector_base
218 */
219 la t0, vector_base
220 csrw CSR_MTVT, t0
221
222 /*
223 * Set ECLIC non-vector entry to be controlled
224 * by mtvt2 CSR register.
225 * Intialize ECLIC non-vector interrupt
226 * base address mtvt2 to irq_entry.
227 */
228 la t0, irq_entry
229 csrw CSR_MTVT2, t0
230 csrs CSR_MTVT2, 0x1
231
232 /*
233 * Set Exception Entry MTVEC to early_exc_entry
234 * Due to settings above, Exception and NMI
235 * will share common entry.
236 * This early_exc_entry is only used during early
237 * boot stage before main
238 */
239 la t0, early_exc_entry
240 csrw CSR_MTVEC, t0
241
242 /* Set the interrupt processing mode to ECLIC mode */
243 li t0, 0x3f
244 csrc CSR_MTVEC, t0
245 csrs CSR_MTVEC, 0x3
246
247 /* ===== Startup Stage 2 ===== */
248
249 /* Enable FPU and Vector Unit if f/d/v exist in march */
250 #if defined(__riscv_flen) && __riscv_flen > 0
251 /* Enable FPU, and set state to initial */
252 li t0, MSTATUS_FS
253 csrc mstatus, t0
254 li t0, MSTATUS_FS_INITIAL
255 csrs mstatus, t0
256 #endif
257
258 #if defined(__riscv_vector)
259 /* Enable Vector, and set state to initial */
260 li t0, MSTATUS_VS
261 csrc mstatus, t0
262 li t0, MSTATUS_VS_INITIAL
263 csrs mstatus, t0
264 #endif
265
266 /* Enable mcycle and minstret counter */
267 csrci CSR_MCOUNTINHIBIT, 0x5
268
269 #if defined(SMP_CPU_CNT) && (SMP_CPU_CNT > 1)
270 csrr a0, CSR_MHARTID
271 li a1, BOOT_HARTID
272 bne a0, a1, __skip_init
273 #endif
274
275 __init_common:
276 /* ===== Startup Stage 3 ===== */
277 /*
278 * Load text section from CODE ROM to CODE RAM
279 * when text LMA is different with VMA
280 */
281 la a0, _text_lma
282 la a1, _text
283 /* If text LMA and VMA are equal
284 * then no need to copy text section */
285 beq a0, a1, 2f
286 la a2, _etext
287 bgeu a1, a2, 2f
288
289 1:
290 /* Load code section if necessary */
291 lw t0, (a0)
292 sw t0, (a1)
293 addi a0, a0, 4
294 addi a1, a1, 4
295 bltu a1, a2, 1b
296 2:
297 /* Load data section */
298 la a0, _data_lma
299 la a1, _data
300 /* If data vma=lma, no need to copy */
301 beq a0, a1, 2f
302 la a2, _edata
303 bgeu a1, a2, 2f
304 1:
305 lw t0, (a0)
306 sw t0, (a1)
307 addi a0, a0, 4
308 addi a1, a1, 4
309 bltu a1, a2, 1b
310 2:
311 /* Clear bss section */
312 la a0, __bss_start
313 la a1, _end
314 bgeu a0, a1, 2f
315 1:
316 sw zero, (a0)
317 addi a0, a0, 4
318 bltu a0, a1, 1b
319 2:
320
321 .globl _start_premain
322 .type _start_premain, @function
323 _start_premain:
324 /*
325 * Call vendor defined SystemInit to
326 * initialize the micro-controller system
327 * SystemInit will just be called by boot cpu
328 */
329 call SystemInit
330
331 /*
332 * Call C/C++ constructor start up code,
333 * __libc_fini is defined in linker script,
334 * so register_fini function will be called
335 * and will run atexit (__libc_fini_array)
336 * to do previous call atexit function
337 */
338 call __libc_init_array
339
340 __skip_init:
341 /* Sync all harts at this function */
342 call __sync_harts
343
344 /* do pre-init steps before main */
345 /* _premain_init will be called by each cpu
346 * please make sure the implementation of __premain_int
347 * considered this
348 */
349 call _premain_init
350
351 /*
352 * When all initialization steps done
353 * set exception entry to correct exception
354 * entry and jump to main.
355 * And set the interrupt processing mode to
356 * ECLIC mode
357 */
358 la t0, exc_entry
359 csrw CSR_MTVEC, t0
360 li t0, 0x3f
361 csrc CSR_MTVEC, t0
362 csrs CSR_MTVEC, 0x3
363
364 /* BPU cold bringup need time, so enable BPU before enter to main */
365 li t0, MMISC_CTL_BPU
366 csrs CSR_MMISC_CTL, t0
367
368 /* ===== Call SMP Main Function ===== */
369 /* argc = argv = 0 */
370 li a0, 0
371 li a1, 0
372 #if defined(SMP_CPU_CNT) && (SMP_CPU_CNT > 1)
373 /* The weak implementation of smp_main is in this file */
374 call smp_main
375 #else
376 #ifdef RTOS_RTTHREAD
377 // Call entry function when using RT-Thread
378 call entry
379 #else
380 call main
381 #endif
382 #endif
383 /* do post-main steps after main
384 * this function will be called by each cpu */
385 call _postmain_fini
386
387 __amp_wait:
388 1:
389 wfi
390 j 1b
391
392 #if defined(SMP_CPU_CNT) && (SMP_CPU_CNT > 1)
393 /*
394 * You can re-implement smp_main function in your code
395 * to do smp boot process and handle multi harts
396 */
397 .weak smp_main
398 .type smp_main, @function
399 smp_main:
400 addi sp, sp, -2*REGBYTES
401 STORE ra, 0*REGBYTES(sp)
402 /* only boot hart goto main, other harts do wfi */
403 csrr t0, CSR_MHARTID
404 li t1, BOOT_HARTID
405 beq t0, t1, 2f
406 1:
407 wfi
408 j 1b
409 2:
410 #ifdef RTOS_RTTHREAD
411 // Call entry function when using RT-Thread
412 call entry
413 #else
414 call main
415 #endif
416 LOAD ra, 0*REGBYTES(sp)
417 addi sp, sp, 2*REGBYTES
418 ret
419 #endif
420
421 /* Early boot exception entry before main */
422 .align 6
423 .global early_exc_entry
424 .type early_exc_entry, @function
425 early_exc_entry:
426 wfi
427 j early_exc_entry