System Configuration Files system_<Device>.c and system_<Device>.h
The System Configuration Files system_<device>.c and system_<device>.h provides as a minimum the functions described under System Device Configuration.
These functions are device specific and need adaptations. In addition, the file might have configuration settings for the device such as XTAL frequency or PLL prescaler settings, necessary system initialization, vendor customized interrupt, exception and nmi handling code, refer to System Device Configuration for more details.
For devices with external memory BUS the system_<Device>.c
also configures the BUS system.
The silicon vendor might expose other functions (i.e. for power configuration) in the system_<Device>.c
file.
In case of additional features the function prototypes need to be added to the system_<Device>.h
header file.
system_Device.c Template File
Here we provided system_Device.c
template file as below:
1 /*
2 * Copyright (c) 2009-2018 Arm Limited. All rights reserved.
3 * Copyright (c) 2019 Nuclei Limited. All rights reserved.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Licensed under the Apache License, Version 2.0 (the License); you may
8 * not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19 /******************************************************************************
20 * @file system_<Device>.c
21 * @brief NMSIS Nuclei N/NX Device Peripheral Access Layer Source File for
22 * Device <Device>
23 * @version V2.0.0
24 * @date 30. Dec 2022
25 ******************************************************************************/
26
27 #include <stdint.h>
28 #include "<Device>.h"
29 #include <stdio.h>
30
31 /*----------------------------------------------------------------------------
32 Define clocks
33 *----------------------------------------------------------------------------*/
34 /* ToDo: add here your necessary defines for device initialization
35 following is an example for different system frequencies */
36 #ifndef SYSTEM_CLOCK
37 #define SYSTEM_CLOCK (80000000UL)
38 #endif
39
40 /**
41 * \defgroup NMSIS_Core_SystemConfig System Device Configuration
42 * \brief Functions for system and clock setup available in system_<device>.c.
43 * \details
44 * Nuclei provides a template file **system_Device.c** that must be adapted by
45 * the silicon vendor to match their actual device. As a <b>minimum requirement</b>,
46 * this file must provide:
47 * - A device-specific system configuration function, \ref SystemInit.
48 * - Global c library \ref _premain_init and \ref _postmain_fini functions called right before calling main function.
49 * - A global variable that contains the system frequency, \ref SystemCoreClock.
50 * - A global eclic configuration initialization, \ref ECLIC_Init.
51 * - A global exception and trap configuration initialization, \ref Trap_Init and \ref Exception_Init.
52 * - Vendor customized interrupt, exception and nmi handling code, see \ref NMSIS_Core_IntExcNMI_Handling
53 *
54 * The file configures the device and, typically, initializes the oscillator (PLL) that is part
55 * of the microcontroller device. This file might export other functions or variables that provide
56 * a more flexible configuration of the microcontroller system.
57 *
58 * And this file also provided common interrupt, exception and NMI exception handling framework template,
59 * Silicon vendor can customize these template code as they want.
60 *
61 * \note Please pay special attention to the static variable \c SystemCoreClock. This variable might be
62 * used throughout the whole system initialization and runtime to calculate frequency/time related values.
63 * Thus one must assure that the variable always reflects the actual system clock speed.
64 *
65 * \attention
66 * Be aware that a value stored to \c SystemCoreClock during low level initialization (i.e. \c SystemInit()) might get
67 * overwritten by C libray startup code and/or .bss section initialization.
68 * Thus its highly recommended to call \ref SystemCoreClockUpdate at the beginning of the user \c main() routine.
69 *
70 * @{
71 */
72 #if defined(__TEE_PRESENT) && (__TEE_PRESENT == 1)
73
74 typedef void (*fnptr)(void);
75
76 /* for the following variables, see intexc_evalsoc.S and intexc_evalsoc_s.S */
77 /** default entry for s-mode non-vector irq entry */
78 extern fnptr irq_entry_s;
79 /** default entry for s-mode exception entry */
80 extern fnptr exc_entry_s;
81 /** default eclic interrupt or exception interrupt handler */
82 extern void default_intexc_handler(void);
83
84 /** eclic s-mode software interrupt handler in eclic mode */
85 extern void eclic_ssip_handler(void) __WEAK;
86 /** eclic s-mode time interrupt handler in eclic mode */
87 extern void eclic_stip_handler(void) __WEAK;
88
89 /* default s-mode exception handler, which user can modify it at your need */
90 static void system_default_exception_handler_s(unsigned long scause, unsigned long sp);
91
92 #ifndef __ICCRISCV__
93 #define __SMODE_VECTOR_ATTR __attribute__((section (".text.vtable_s"), aligned(512)))
94 #else
95 #define __SMODE_VECTOR_ATTR __attribute__((section (".sintvec"), aligned(512)))
96 #endif
97 // TODO: change the aligned(512) to match stvt alignment requirement according to your eclic max interrupt number
98 // TODO: place your interrupt handler into this vector table, important if your vector table is in flash
99 /**
100 * \var unsigned long vector_table_s[SOC_INT_MAX]
101 * \brief vector interrupt storing ISRs for supervisor mode
102 * \details
103 * vector_table_s is hold by stvt register, the address must align according
104 * to actual interrupt numbers as below, now align to 512 bytes considering we put up to 128 interrupts here
105 * alignment must comply to table below if you increase or decrease vector interrupt number
106 * interrupt number alignment
107 * 0 to 16 64-byte
108 * 17 to 32 128-byte
109 * 33 to 64 256-byte
110 * 65 to 128 512-byte
111 * 129 to 256 1KB
112 * 257 to 512 2KB
113 * 513 to 1024 4KB
114 */
115 const unsigned long vector_table_s[SOC_INT_MAX] __SMODE_VECTOR_ATTR =
116 {
117 (unsigned long)(default_intexc_handler), /* 0: Reserved */
118 (unsigned long)(default_intexc_handler), /* 1: Reserved */
119 (unsigned long)(default_intexc_handler), /* 2: Reserved */
120
121 (unsigned long)(eclic_ssip_handler), /* 3: supervisor software interrupt in eclic mode */
122
123 (unsigned long)(default_intexc_handler), /* 4: Reserved */
124 (unsigned long)(default_intexc_handler), /* 5: Reserved */
125 (unsigned long)(default_intexc_handler), /* 6: Reserved */
126
127 (unsigned long)(eclic_stip_handler), /* 7: supervisor timer interrupt in eclic mode */
128
129 (unsigned long)(default_intexc_handler), /* 8: Reserved */
130 (unsigned long)(default_intexc_handler), /* 9: Reserved */
131 (unsigned long)(default_intexc_handler), /* 10: Reserved */
132 (unsigned long)(default_intexc_handler), /* 11: Reserved */
133
134 (unsigned long)(default_intexc_handler), /* 12: Reserved */
135 (unsigned long)(default_intexc_handler), /* 13: Reserved */
136 (unsigned long)(default_intexc_handler), /* 14: Reserved */
137 (unsigned long)(default_intexc_handler), /* 15: Reserved */
138
139 (unsigned long)(default_intexc_handler), /* 16: Reserved */
140 (unsigned long)(default_intexc_handler), /* 17: Reserved */
141 (unsigned long)(default_intexc_handler), /* 18: Reserved */
142 (unsigned long)(default_intexc_handler), /* 19: Interrupt 19 */
143
144 (unsigned long)(default_intexc_handler), /* 20: Interrupt 20 */
145 (unsigned long)(default_intexc_handler), /* 21: Interrupt 21 */
146 (unsigned long)(default_intexc_handler), /* 22: Interrupt 22 */
147 (unsigned long)(default_intexc_handler), /* 23: Interrupt 23 */
148
149 (unsigned long)(default_intexc_handler), /* 24: Interrupt 24 */
150 (unsigned long)(default_intexc_handler), /* 25: Interrupt 25 */
151 (unsigned long)(default_intexc_handler), /* 26: Interrupt 26 */
152 (unsigned long)(default_intexc_handler), /* 27: Interrupt 27 */
153
154 (unsigned long)(default_intexc_handler), /* 28: Interrupt 28 */
155 (unsigned long)(default_intexc_handler), /* 29: Interrupt 29 */
156 (unsigned long)(default_intexc_handler), /* 30: Interrupt 30 */
157 (unsigned long)(default_intexc_handler), /* 31: Interrupt 31 */
158
159 (unsigned long)(default_intexc_handler), /* 32: Interrupt 32 */
160 (unsigned long)(default_intexc_handler), /* 33: Interrupt 33 */
161 (unsigned long)(default_intexc_handler), /* 34: Interrupt 34 */
162 (unsigned long)(default_intexc_handler), /* 35: Interrupt 35 */
163
164 (unsigned long)(default_intexc_handler), /* 36: Interrupt 36 */
165 (unsigned long)(default_intexc_handler), /* 37: Interrupt 37 */
166 (unsigned long)(default_intexc_handler), /* 38: Interrupt 38 */
167 (unsigned long)(default_intexc_handler), /* 39: Interrupt 39 */
168
169 (unsigned long)(default_intexc_handler), /* 40: Interrupt 40 */
170 (unsigned long)(default_intexc_handler), /* 41: Interrupt 41 */
171 (unsigned long)(default_intexc_handler), /* 42: Interrupt 42 */
172 (unsigned long)(default_intexc_handler), /* 43: Interrupt 43 */
173
174 (unsigned long)(default_intexc_handler), /* 44: Interrupt 44 */
175 (unsigned long)(default_intexc_handler), /* 45: Interrupt 45 */
176 (unsigned long)(default_intexc_handler), /* 46: Interrupt 46 */
177 (unsigned long)(default_intexc_handler), /* 47: Interrupt 47 */
178
179 (unsigned long)(default_intexc_handler), /* 48: Interrupt 48 */
180 (unsigned long)(default_intexc_handler), /* 49: Interrupt 49 */
181 (unsigned long)(default_intexc_handler), /* 50: Interrupt 50 */
182 (unsigned long)(default_intexc_handler), /* 51: Interrupt 51 */
183
184 (unsigned long)(default_intexc_handler), /* 52: Interrupt 52 */
185 (unsigned long)(default_intexc_handler), /* 53: Interrupt 53 */
186 (unsigned long)(default_intexc_handler), /* 54: Interrupt 54 */
187 (unsigned long)(default_intexc_handler), /* 55: Interrupt 55 */
188
189 (unsigned long)(default_intexc_handler), /* 56: Interrupt 56 */
190 (unsigned long)(default_intexc_handler), /* 57: Interrupt 57 */
191 (unsigned long)(default_intexc_handler), /* 58: Interrupt 58 */
192 (unsigned long)(default_intexc_handler), /* 59: Interrupt 59 */
193
194 (unsigned long)(default_intexc_handler), /* 60: Interrupt 60 */
195 (unsigned long)(default_intexc_handler), /* 61: Interrupt 61 */
196 (unsigned long)(default_intexc_handler), /* 62: Interrupt 62 */
197 (unsigned long)(default_intexc_handler), /* 63: Interrupt 63 */
198 };
199 #endif
200 /*----------------------------------------------------------------------------
201 System Core Clock Variable
202 *----------------------------------------------------------------------------*/
203 /* ToDo: initialize SystemCoreClock with the system core clock frequency value
204 achieved after system intitialization.
205 This means system core clock frequency after call to SystemInit() */
206 /**
207 * \brief Variable to hold the system core clock value
208 * \details
209 * Holds the system core clock, which is the system clock frequency supplied to the SysTick
210 * timer and the processor core clock. This variable can be used by debuggers to query the
211 * frequency of the debug timer or to configure the trace clock speed.
212 *
213 * \attention
214 * Compilers must be configured to avoid removing this variable in case the application
215 * program is not using it. Debugging systems require the variable to be physically
216 * present in memory so that it can be examined to configure the debugger.
217 */
218 volatile uint32_t SystemCoreClock = SYSTEM_CLOCK; /* System Clock Frequency (Core Clock) */
219
220 /*----------------------------------------------------------------------------
221 Clock functions
222 *----------------------------------------------------------------------------*/
223
224 /**
225 * \brief Function to update the variable \ref SystemCoreClock
226 * \details
227 * Updates the variable \ref SystemCoreClock and must be called whenever the core clock is changed
228 * during program execution. The function evaluates the clock register settings and calculates
229 * the current core clock.
230 */
231 void SystemCoreClockUpdate(void) /* Get Core Clock Frequency */
232 {
233 /* ToDo: add code to calculate the system frequency based upon the current
234 * register settings.
235 * Note: This function can be used to retrieve the system core clock frequeny
236 * after user changed register settings.
237 */
238 SystemCoreClock = SYSTEM_CLOCK;
239 }
240
241 /**
242 * \brief Function to Initialize the system.
243 * \details
244 * Initializes the microcontroller system. Typically, this function configures the
245 * oscillator (PLL) that is part of the microcontroller device. For systems
246 * with a variable clock speed, it updates the variable \ref SystemCoreClock.
247 * SystemInit is called from the file <b>startup<i>_device</i></b>.
248 */
249 void SystemInit(void)
250 {
251 /* ToDo: add code to initialize the system
252 * Warn: do not use global variables because this function is called before
253 * reaching pre-main. RW section maybe overwritten afterwards.
254 */
255 SystemCoreClock = SYSTEM_CLOCK;
256 }
257
258 /**
259 * \defgroup NMSIS_Core_IntExcNMI_Handling Interrupt and Exception and NMI Handling
260 * \brief Functions for interrupt, exception and nmi handle available in system_<device>.c.
261 * \details
262 * Nuclei provide a template for interrupt, exception and NMI handling. Silicon Vendor could adapat according
263 * to their requirement. Silicon vendor could implement interface for different exception code and
264 * replace current implementation.
265 *
266 * @{
267 */
268 /** \brief Max exception handler number, don't include the NMI(0xFFF) one */
269 #define MAX_SYSTEM_EXCEPTION_NUM 26
270 /**
271 * \brief Store the exception handlers for each exception ID
272 * \note
273 * - This SystemExceptionHandlers are used to store all the handlers for all
274 * the exception codes Nuclei N/NX core provided.
275 * - Exception code 0 - 25, totally 26 exceptions are mapped to SystemExceptionHandlers[0:25]
276 * - Exception for NMI is also re-routed to exception handling(exception code 0xFFF) in startup code configuration, the handler itself is mapped to SystemExceptionHandlers[MAX_SYSTEM_EXCEPTION_NUM]
277 */
278 static unsigned long SystemExceptionHandlers[MAX_SYSTEM_EXCEPTION_NUM + 1];
279
280 /**
281 * \brief Store the exception handlers for each exception ID in supervisor mode
282 * \note
283 * - This SystemExceptionHandlers_S are used to store all the handlers for all
284 * the exception codes Nuclei N/NX core provided.
285 * - Exception code 0 - 11, totally 12 exceptions are mapped to SystemExceptionHandlers_S[0:11]
286 * - The NMI (Non-maskable-interrupt) cannot be trapped to the supervisor-mode or user-mode for any configuration
287 */
288 #if defined(__TEE_PRESENT) && (__TEE_PRESENT == 1)
289 static unsigned long SystemExceptionHandlers_S[MAX_SYSTEM_EXCEPTION_NUM];
290 #endif
291 /**
292 * \brief Exception Handler Function Typedef
293 * \note
294 * This typedef is only used internal in this system_<Device>.c file.
295 * It is used to do type conversion for registered exception handler before calling it.
296 */
297 typedef void (*EXC_HANDLER)(unsigned long cause, unsigned long sp);
298
299 /**
300 * \brief System Default Exception Handler
301 * \details
302 * This function provides a default exception and NMI handler for all exception ids.
303 * By default, It will just print some information for debug, Vendor can customize it according to its requirements.
304 * \param [in] mcause code indicating the reason that caused the trap in machine mode
305 * \param [in] sp stack pointer
306 */
307 static void system_default_exception_handler(unsigned long mcause, unsigned long sp)
308 {
309 /* TODO: Uncomment this if you have implement printf function */
310 printf("MCAUSE : 0x%lx\r\n", mcause);
311 printf("MDCAUSE: 0x%lx\r\n", __RV_CSR_READ(CSR_MDCAUSE));
312 printf("MEPC : 0x%lx\r\n", __RV_CSR_READ(CSR_MEPC));
313 printf("MTVAL : 0x%lx\r\n", __RV_CSR_READ(CSR_MTVAL));
314 printf("HARTID : %u\r\n", (unsigned int)__get_hart_id());
315 Exception_DumpFrame(sp, PRV_M);
316 #if defined(SIMULATION_MODE)
317 // directly exit if in SIMULATION
318 extern void simulation_exit(int status);
319 simulation_exit(1);
320 #else
321 while (1);
322 #endif
323 }
324
325 /**
326 * \brief Initialize all the default core exception handlers
327 * \details
328 * The core exception handler for each exception id will be initialized to \ref system_default_exception_handler.
329 * \note
330 * Called in \ref _init function, used to initialize default exception handlers for all exception IDs
331 * SystemExceptionHandlers contains NMI, but SystemExceptionHandlers_S not, because NMI can't be delegated to S-mode.
332 */
333 static void Exception_Init(void)
334 {
335 for (int i = 0; i < MAX_SYSTEM_EXCEPTION_NUM; i++) {
336 SystemExceptionHandlers[i] = (unsigned long)system_default_exception_handler;
337 #if defined(__TEE_PRESENT) && (__TEE_PRESENT == 1)
338 SystemExceptionHandlers_S[i] = (unsigned long)system_default_exception_handler_s;
339 #endif
340 }
341 SystemExceptionHandlers[MAX_SYSTEM_EXCEPTION_NUM] = (unsigned long)system_default_exception_handler;
342 }
343
344 /**
345 * \brief Dump Exception Frame
346 * \details
347 * This function provided feature to dump exception frame stored in stack.
348 * \param [in] sp stackpoint
349 * \param [in] mode privileged mode to decide whether to dump msubm CSR
350 */
351 void Exception_DumpFrame(unsigned long sp, uint8_t mode)
352 {
353 EXC_Frame_Type *exc_frame = (EXC_Frame_Type *)sp;
354
355 #ifndef __riscv_32e
356 printf("ra: 0x%lx, tp: 0x%lx, t0: 0x%lx, t1: 0x%lx, t2: 0x%lx, t3: 0x%lx, t4: 0x%lx, t5: 0x%lx, t6: 0x%lx\n" \
357 "a0: 0x%lx, a1: 0x%lx, a2: 0x%lx, a3: 0x%lx, a4: 0x%lx, a5: 0x%lx, a6: 0x%lx, a7: 0x%lx\n" \
358 "cause: 0x%lx, epc: 0x%lx\n", exc_frame->ra, exc_frame->tp, exc_frame->t0, \
359 exc_frame->t1, exc_frame->t2, exc_frame->t3, exc_frame->t4, exc_frame->t5, exc_frame->t6, \
360 exc_frame->a0, exc_frame->a1, exc_frame->a2, exc_frame->a3, exc_frame->a4, exc_frame->a5, \
361 exc_frame->a6, exc_frame->a7, exc_frame->cause, exc_frame->epc);
362 #else
363 printf("ra: 0x%lx, tp: 0x%lx, t0: 0x%lx, t1: 0x%lx, t2: 0x%lx\n" \
364 "a0: 0x%lx, a1: 0x%lx, a2: 0x%lx, a3: 0x%lx, a4: 0x%lx, a5: 0x%lx\n" \
365 "cause: 0x%lx, epc: 0x%lx\n", exc_frame->ra, exc_frame->tp, exc_frame->t0, \
366 exc_frame->t1, exc_frame->t2, exc_frame->a0, exc_frame->a1, exc_frame->a2, exc_frame->a3, \
367 exc_frame->a4, exc_frame->a5, exc_frame->cause, exc_frame->epc);
368 #endif
369
370 if (PRV_M == mode) {
371 /* msubm is exclusive to machine mode */
372 printf("msubm: 0x%lx\n", exc_frame->msubm);
373 }
374 }
375
376 /**
377 * \brief Register an exception handler for exception code EXCn
378 * \details
379 * - For EXCn < \ref MAX_SYSTEM_EXCEPTION_NUM, it will be registered into SystemExceptionHandlers[EXCn-1].
380 * - For EXCn == NMI_EXCn, it will be registered into SystemExceptionHandlers[MAX_SYSTEM_EXCEPTION_NUM].
381 * \param [in] EXCn See \ref EXCn_Type
382 * \param [in] exc_handler The exception handler for this exception code EXCn
383 */
384 void Exception_Register_EXC(uint32_t EXCn, unsigned long exc_handler)
385 {
386 if (EXCn < MAX_SYSTEM_EXCEPTION_NUM) {
387 SystemExceptionHandlers[EXCn] = exc_handler;
388 } else if (EXCn == NMI_EXCn) {
389 SystemExceptionHandlers[MAX_SYSTEM_EXCEPTION_NUM] = exc_handler;
390 }
391 }
392
393 /**
394 * \brief Get current exception handler for exception code EXCn
395 * \details
396 * - For EXCn < \ref MAX_SYSTEM_EXCEPTION_NUM, it will return SystemExceptionHandlers[EXCn-1].
397 * - For EXCn == NMI_EXCn, it will return SystemExceptionHandlers[MAX_SYSTEM_EXCEPTION_NUM].
398 * \param [in] EXCn See \ref EXCn_Type
399 * \return Current exception handler for exception code EXCn, if not found, return 0.
400 */
401 unsigned long Exception_Get_EXC(uint32_t EXCn)
402 {
403 if (EXCn < MAX_SYSTEM_EXCEPTION_NUM) {
404 return SystemExceptionHandlers[EXCn];
405 } else if (EXCn == NMI_EXCn) {
406 return SystemExceptionHandlers[MAX_SYSTEM_EXCEPTION_NUM];
407 } else {
408 return 0;
409 }
410 }
411
412 /**
413 * \brief Common NMI and Exception handler entry
414 * \details
415 * This function provided a command entry for NMI and exception. Silicon Vendor could modify
416 * this template implementation according to requirement.
417 * \param [in] mcause code indicating the reason that caused the trap in machine mode
418 * \param [in] sp stack pointer
419 * \remarks
420 * - RISCV provided common entry for all types of exception. This is proposed code template
421 * for exception entry function, Silicon Vendor could modify the implementation.
422 * - For the core_exception_handler template, we provided exception register function \ref Exception_Register_EXC
423 * which can help developer to register your exception handler for specific exception number.
424 */
425 uint32_t core_exception_handler(unsigned long mcause, unsigned long sp)
426 {
427 uint32_t EXCn = (uint32_t)(mcause & 0X00000fff);
428 EXC_HANDLER exc_handler;
429
430 if (EXCn < MAX_SYSTEM_EXCEPTION_NUM) {
431 exc_handler = (EXC_HANDLER)SystemExceptionHandlers[EXCn];
432 } else if (EXCn == NMI_EXCn) {
433 exc_handler = (EXC_HANDLER)SystemExceptionHandlers[MAX_SYSTEM_EXCEPTION_NUM];
434 } else {
435 exc_handler = (EXC_HANDLER)system_default_exception_handler;
436 }
437 if (exc_handler != NULL) {
438 exc_handler(mcause, sp);
439 }
440 return 0;
441 }
442
443 #if defined(__TEE_PRESENT) && (__TEE_PRESENT == 1)
444 /**
445 * \brief Supervisor mode system Default Exception Handler
446 * \details
447 * This function provided a default supervisor mode exception and NMI handling code for all exception ids.
448 * By default, It will just print some information for debug, Vendor can customize it according to its requirements.
449 * \param [in] scause code indicating the reason that caused the trap in supervisor mode
450 * \param [in] sp stack pointer
451 */
452 static void system_default_exception_handler_s(unsigned long scause, unsigned long sp)
453 {
454 /* TODO: Uncomment this if you have implement printf function */
455 printf("SCAUSE : 0x%lx\r\n", scause);
456 printf("SDCAUSE: 0x%lx\r\n", __RV_CSR_READ(CSR_SDCAUSE));
457 printf("SEPC : 0x%lx\r\n", __RV_CSR_READ(CSR_SEPC));
458 printf("STVAL : 0x%lx\r\n", __RV_CSR_READ(CSR_STVAL));
459 Exception_DumpFrame(sp, PRV_S);
460 #if defined(SIMULATION_MODE)
461 // directly exit if in SIMULATION
462 extern void simulation_exit(int status);
463 simulation_exit(1);
464 #else
465 while (1);
466 #endif
467 }
468
469 /**
470 * \brief Register an exception handler for exception code EXCn of supervisor mode
471 * \details
472 * -For EXCn < \ref MAX_SYSTEM_EXCEPTION_NUM, it will be registered into SystemExceptionHandlers_S[EXCn-1].
473 * -For EXCn == NMI_EXCn, The NMI (Non-maskable-interrupt) cannot be trapped to the supervisor-mode or user-mode for any
474 * configuration, so NMI won't be registered into SystemExceptionHandlers_S.
475 * \param [in] EXCn See \ref EXCn_Type
476 * \param [in] exc_handler The exception handler for this exception code EXCn
477 */
478 void Exception_Register_EXC_S(uint32_t EXCn, unsigned long exc_handler)
479 {
480 if (EXCn < MAX_SYSTEM_EXCEPTION_NUM) {
481 SystemExceptionHandlers_S[EXCn] = exc_handler;
482 }
483 }
484
485 /**
486 * \brief Get current exception handler for exception code EXCn of supervisor mode
487 * \details
488 * - For EXCn < \ref MAX_SYSTEM_EXCEPTION_NUM, it will return SystemExceptionHandlers_S[EXCn-1].
489 * \param [in] EXCn See \ref EXCn_Type
490 * \return Current exception handler for exception code EXCn, if not found, return 0.
491 */
492 unsigned long Exception_Get_EXC_S(uint32_t EXCn)
493 {
494 if (EXCn < MAX_SYSTEM_EXCEPTION_NUM) {
495 return SystemExceptionHandlers[EXCn];
496 } else {
497 return 0;
498 }
499 }
500
501 /**
502 * \brief common Exception handler entry of supervisor mode
503 * \details
504 * This function provided a supervisor mode common entry for exception. Silicon Vendor could modify
505 * this template implementation according to requirement.
506 * \param [in] scause code indicating the reason that caused the trap in supervisor mode
507 * \param [in] sp stack pointer
508 * \remarks
509 * - RISCV provided supervisor mode common entry for all types of exception. This is proposed code template
510 * for exception entry function, Silicon Vendor could modify the implementation.
511 * - For the core_exception_handler_s template, we provided exception register function \ref Exception_Register_EXC_S
512 * which can help developer to register your exception handler for specific exception number.
513 */
514 uint32_t core_exception_handler_s(unsigned long scause, unsigned long sp)
515 {
516 uint32_t EXCn = (uint32_t)(scause & 0X00000fff);
517 EXC_HANDLER exc_handler;
518
519 if (EXCn < MAX_SYSTEM_EXCEPTION_NUM) {
520 exc_handler = (EXC_HANDLER)SystemExceptionHandlers_S[EXCn];
521 } else {
522 exc_handler = (EXC_HANDLER)system_default_exception_handler_s;
523 }
524 if (exc_handler != NULL) {
525 exc_handler(scause, sp);
526 }
527 return 0;
528 }
529 #endif
530
531 /** @} */ /* End of Doxygen Group NMSIS_Core_ExceptionAndNMI */
532
533 /** Banner Print for Nuclei SDK */
534 void SystemBannerPrint(void)
535 {
536 #if defined(NUCLEI_BANNER) && (NUCLEI_BANNER == 1)
537 printf("Nuclei SDK Build Time: %s, %s\r\n", __DATE__, __TIME__);
538 #ifdef DOWNLOAD_MODE_STRING
539 printf("Download Mode: %s\r\n", DOWNLOAD_MODE_STRING);
540 #endif
541 printf("CPU Frequency %u Hz\r\n", (unsigned int)SystemCoreClock);
542 printf("CPU HartID: %u\r\n", (unsigned int)__get_hart_id());
543 #endif
544 }
545
546 /**
547 * \brief initialize eclic config
548 * \details
549 * ECLIC needs be initialized after boot up,
550 * Vendor could also change the initialization
551 * configuration.
552 */
553 void ECLIC_Init(void)
554 {
555 /* Global Configuration about MTH and NLBits.
556 * TODO: Please adapt it according to your system requirement.
557 * This function is called in _init function */
558 ECLIC_SetMth(0);
559 ECLIC_SetCfgNlbits(__ECLIC_INTCTLBITS);
560
561 #if defined(__TEE_PRESENT) && (__TEE_PRESENT == 1)
562 /* Global Configuration about STH */
563 ECLIC_SetSth(0);
564 #endif
565 }
566
567 /**
568 * \brief Initialize a specific IRQ and register the handler
569 * \details
570 * This function set vector mode, trigger mode and polarity, interrupt level and priority,
571 * assign handler for specific IRQn.
572 * \param [in] IRQn NMI interrupt handler address
573 * \param [in] shv \ref ECLIC_NON_VECTOR_INTERRUPT means non-vector mode, and \ref ECLIC_VECTOR_INTERRUPT is vector mode
574 * \param [in] trig_mode see \ref ECLIC_TRIGGER_Type
575 * \param [in] lvl interupt level
576 * \param [in] priority interrupt priority
577 * \param [in] handler interrupt handler, if NULL, handler will not be installed
578 * \return -1 means invalid input parameter. 0 means successful.
579 * \remarks
580 * - This function use to configure specific eclic interrupt and register its interrupt handler and enable its interrupt.
581 * - If the vector table is placed in read-only section(FLASHXIP mode), handler could not be installed
582 */
583 int32_t ECLIC_Register_IRQ(IRQn_Type IRQn, uint8_t shv, ECLIC_TRIGGER_Type trig_mode, uint8_t lvl, uint8_t priority, void* handler)
584 {
585 if ((IRQn > SOC_INT_MAX) || (shv > ECLIC_VECTOR_INTERRUPT) \
586 || (trig_mode > ECLIC_NEGTIVE_EDGE_TRIGGER)) {
587 return -1;
588 }
589
590 /* set interrupt vector mode */
591 ECLIC_SetShvIRQ(IRQn, shv);
592 /* set interrupt trigger mode and polarity */
593 ECLIC_SetTrigIRQ(IRQn, trig_mode);
594 /* set interrupt level */
595 ECLIC_SetLevelIRQ(IRQn, lvl);
596 /* set interrupt priority */
597 ECLIC_SetPriorityIRQ(IRQn, priority);
598 if (handler != NULL) {
599 /* set interrupt handler entry to vector table */
600 ECLIC_SetVector(IRQn, (rv_csr_t)handler);
601 }
602 /* enable interrupt */
603 ECLIC_EnableIRQ(IRQn);
604 return 0;
605 }
606
607 #if defined(__TEE_PRESENT) && (__TEE_PRESENT == 1)
608 /**
609 * \brief Initialize a specific IRQ and register the handler for supervisor mode
610 * \details
611 * This function set vector mode, trigger mode and polarity, interrupt level and priority,
612 * assign handler for specific IRQn.
613 * \param [in] IRQn NMI interrupt handler address
614 * \param [in] shv \ref ECLIC_NON_VECTOR_INTERRUPT means non-vector mode, and \ref ECLIC_VECTOR_INTERRUPT is vector mode
615 * \param [in] trig_mode see \ref ECLIC_TRIGGER_Type
616 * \param [in] lvl interupt level
617 * \param [in] priority interrupt priority
618 * \param [in] handler interrupt handler, if NULL, handler will not be installed
619 * \return -1 means invalid input parameter. 0 means successful.
620 * \remarks
621 * - This function use to configure specific eclic S-mode interrupt and register its interrupt handler and enable its interrupt.
622 * - If the vector table is placed in read-only section (FLASHXIP mode), handler could not be installed.
623 */
624 int32_t ECLIC_Register_IRQ_S(IRQn_Type IRQn, uint8_t shv, ECLIC_TRIGGER_Type trig_mode, uint8_t lvl, uint8_t priority, void* handler)
625 {
626 if ((IRQn > SOC_INT_MAX) || (shv > ECLIC_VECTOR_INTERRUPT) \
627 || (trig_mode > ECLIC_NEGTIVE_EDGE_TRIGGER)) {
628 return -1;
629 }
630
631 /* set interrupt vector mode */
632 ECLIC_SetShvIRQ_S(IRQn, shv);
633 /* set interrupt trigger mode and polarity */
634 ECLIC_SetTrigIRQ_S(IRQn, trig_mode);
635 /* set interrupt level */
636 ECLIC_SetLevelIRQ_S(IRQn, lvl);
637 /* set interrupt priority */
638 ECLIC_SetPriorityIRQ_S(IRQn, priority);
639 if (handler != NULL) {
640 /* set interrupt handler entry to vector table */
641 ECLIC_SetVector_S(IRQn, (rv_csr_t)handler);
642 }
643 /* enable interrupt */
644 ECLIC_EnableIRQ_S(IRQn);
645 return 0;
646 }
647 #endif
648
649 #define FALLBACK_DEFAULT_ECLIC_BASE 0x0C000000UL
650 #define FALLBACK_DEFAULT_SYSTIMER_BASE 0x02000000UL
651
652 /** Nuclei RISC-V CPU IRegion Information Variable used to store probed info */
653 volatile IRegion_Info_Type SystemIRegionInfo;
654 /**
655 * \brief Get Nuclei Internal Region Information
656 * \details
657 * This function is used to get nuclei cpu internal region
658 * information, such as iregion base, eclic base, smp base,
659 * timer base and idu base, and fallback to old evalsoc
660 * timer and eclic base if no iregion feature found
661 */
662 static void _get_iregion_info(IRegion_Info_Type *iregion)
663 {
664 unsigned long mcfg_info;
665 if (iregion == NULL) {
666 return;
667 }
668 mcfg_info = __RV_CSR_READ(CSR_MCFG_INFO);
669 if (mcfg_info & MCFG_INFO_IREGION_EXIST) { // IRegion Info present
670 iregion->iregion_base = (__RV_CSR_READ(CSR_MIRGB_INFO) >> 10) << 10;
671 iregion->eclic_base = iregion->iregion_base + IREGION_ECLIC_OFS;
672 iregion->systimer_base = iregion->iregion_base + IREGION_TIMER_OFS;
673 iregion->smp_base = iregion->iregion_base + IREGION_SMP_OFS;
674 iregion->idu_base = iregion->iregion_base + IREGION_IDU_OFS;
675 } else {
676 iregion->eclic_base = FALLBACK_DEFAULT_ECLIC_BASE;
677 iregion->systimer_base = FALLBACK_DEFAULT_SYSTIMER_BASE;
678 }
679 }
680
681 #define CLINT_MSIP(base, hartid) (*(volatile uint32_t *)((uintptr_t)((base) + ((hartid) * 4))))
682 #define SMP_CTRLREG(base, ofs) (*(volatile uint32_t *)((uintptr_t)((base) + (ofs))))
683
684 void __sync_harts(void) __attribute__((section(".text.init")));
685 /**
686 * \brief Synchronize all harts
687 * \details
688 * This function is used to synchronize all the harts,
689 * especially to wait the boot hart finish initialization of
690 * data section, bss section and c runtines initialization
691 * This function must be placed in .text.init section, since
692 * section initialization is not ready, global variable
693 * and static variable should be avoid to use in this function,
694 * and avoid to call other functions
695 */
696 void __sync_harts(void)
697 {
698 // Only do synchronize when SMP_CPU_CNT is defined and number > 0
699 #if defined(SMP_CPU_CNT) && (SMP_CPU_CNT > 1)
700 unsigned long hartid = __get_hart_id();
701 unsigned long tmr_hartid = __get_hart_index();
702 unsigned long clint_base, irgb_base, smp_base;
703 unsigned long mcfg_info;
704
705 mcfg_info = __RV_CSR_READ(CSR_MCFG_INFO);
706 if (mcfg_info & MCFG_INFO_IREGION_EXIST) { // IRegion Info present
707 // clint base = system timer base + 0x1000
708 irgb_base = (__RV_CSR_READ(CSR_MIRGB_INFO) >> 10) << 10;
709 clint_base = irgb_base + IREGION_TIMER_OFS + 0x1000;
710 smp_base = irgb_base + IREGION_SMP_OFS;
711 } else {
712 clint_base = FALLBACK_DEFAULT_SYSTIMER_BASE + 0x1000;
713 smp_base = (__RV_CSR_READ(CSR_MSMPCFG_INFO) >> 4) << 4;
714 }
715 // Enable SMP and L2, disable cluster local memory
716 SMP_CTRLREG(smp_base, 0xc) = 0xFFFFFFFF;
717 SMP_CTRLREG(smp_base, 0x10) = 0x1;
718 SMP_CTRLREG(smp_base, 0xd8) = 0x0;
719 __SMP_RWMB();
720
721 // pre-condition: interrupt must be disabled, this is done before calling this function
722 // BOOT_HARTID is defined <Device.h>
723 if (hartid == BOOT_HARTID) { // boot hart
724 // clear msip pending
725 for (int i = 0; i < SMP_CPU_CNT; i ++) {
726 CLINT_MSIP(clint_base, i) = 0;
727 }
728 __SMP_RWMB();
729 } else {
730 // Set machine software interrupt pending to 1
731 CLINT_MSIP(clint_base, tmr_hartid) = 1;
732 __SMP_RWMB();
733 // wait for pending bit cleared by boot hart
734 while (CLINT_MSIP(clint_base, tmr_hartid) == 1);
735 }
736 #endif
737 }
738
739 /**
740 * \brief do the init for trap(interrupt and exception) entry for supervisor mode
741 * \details
742 * This function provide initialization of CSR_STVT CSR_STVT2 and CSR_STVEC.
743 */
744 static void Trap_Init(void)
745 {
746 #if defined(__TEE_PRESENT) && (__TEE_PRESENT == 1)
747 /*
748 * Intialize ECLIC supervisor mode vector interrupt
749 * base address stvt to vector_table_s
750 */
751 __RV_CSR_WRITE(CSR_STVT, (unsigned long)&vector_table_s);
752 /*
753 * Set ECLIC supervisor mode non-vector entry to be controlled
754 * by stvt2 CSR register.
755 * Intialize supervisor mode ECLIC non-vector interrupt
756 * base address stvt2 to irq_entry_s.
757 */
758 __RV_CSR_WRITE(CSR_STVT2, (unsigned long)&irq_entry_s);
759 __RV_CSR_SET(CSR_STVT2, 0x01);
760 /*
761 * Set supervisor exception entry stvec to exc_entry_s */
762 __RV_CSR_WRITE(CSR_STVEC, (unsigned long)&exc_entry_s);
763 #endif
764 }
765
766 /**
767 * \brief early init function before main
768 * \details
769 * This function is executed right before main function.
770 * For RISC-V gnu toolchain, _init function might not be called
771 * by __libc_init_array function, so we defined a new function
772 * to do initialization.
773 */
774 void _premain_init(void)
775 {
776 // TODO to make it possible for configurable boot hartid
777 unsigned long hartid = __get_hart_id();
778
779 // BOOT_HARTID is defined <Device.h>
780 if (hartid == BOOT_HARTID) { // only done in boot hart
781 // IREGION INFO MUST BE SET BEFORE ANY PREMAIN INIT STEPS
782 _get_iregion_info((IRegion_Info_Type *)(&SystemIRegionInfo));
783 }
784 /* TODO: Add your own initialization code here, called before main */
785 // This code located in RUNMODE_CONTROL ifdef endif block just for internal usage
786 // No need to use in your code
787 #ifdef RUNMODE_CONTROL
788 #if defined(RUNMODE_ILM_EN) && RUNMODE_ILM_EN == 0
789 // Only disable ilm when it is present
790 if (__RV_CSR_READ(CSR_MCFG_INFO) & MCFG_INFO_ILM) {
791 __RV_CSR_CLEAR(CSR_MILM_CTL, MILM_CTL_ILM_EN);
792 }
793 #endif
794 #if defined(RUNMODE_DLM_EN) && RUNMODE_DLM_EN == 0
795 // Only disable dlm when it is present
796 if (__RV_CSR_READ(CSR_MCFG_INFO) & MCFG_INFO_DLM) {
797 __RV_CSR_CLEAR(CSR_MDLM_CTL, MDLM_CTL_DLM_EN);
798 }
799 #endif
800 #endif
801
802 /* __ICACHE_PRESENT and __DCACHE_PRESENT are defined in demosoc.h */
803 // For our internal cpu testing, they want to set demosoc __ICACHE_PRESENT/__DCACHE_PRESENT to be 1
804 // __CCM_PRESENT is still default to 0 in demosoc.h, since it is used in core_feature_eclic.h to register interrupt, if set to 1, it might cause exception
805 // but in the cpu, icache or dcache might not exist due to cpu configuration, so here
806 // we need to check whether icache/dcache really exist, if yes, then turn on it
807 #if defined(__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1)
808 if (ICachePresent()) { // Check whether icache real present or not
809 EnableICache();
810 }
811 #endif
812 #if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1)
813 if (DCachePresent()) { // Check whether dcache real present or not
814 EnableDCache();
815 }
816 #endif
817
818 /* Do fence and fence.i to make sure previous ilm/dlm/icache/dcache control done */
819 __RWMB();
820 __FENCE_I();
821
822 if (hartid == BOOT_HARTID) { // only required for boot hartid
823 // TODO implement get_cpu_freq function to get real cpu clock freq in HZ or directly give the real cpu HZ
824 SystemCoreClock = get_cpu_freq();
825 uart_init(SOC_DEBUG_UART, 115200);
826 /* Display banner after UART initialized */
827 SystemBannerPrint();
828 /* Initialize exception default handlers */
829 Exception_Init();
830 /* ECLIC initialization, mainly MTH and NLBIT */
831 ECLIC_Init();
832 Trap_Init();
833 // TODO: internal usage for Nuclei
834 #ifdef RUNMODE_CONTROL
835 printf("Current RUNMODE=%s, ilm:%d, dlm %d, icache %d, dcache %d, ccm %d\n", \
836 RUNMODE_STRING, RUNMODE_ILM_EN, RUNMODE_DLM_EN, \
837 RUNMODE_IC_EN, RUNMODE_DC_EN, RUNMODE_CCM_EN);
838 printf("CSR: MILM_CTL 0x%x, MDLM_CTL 0x%x, MCACHE_CTL 0x%x\n", \
839 __RV_CSR_READ(CSR_MILM_CTL), __RV_CSR_READ(CSR_MDLM_CTL), \
840 __RV_CSR_READ(CSR_MCACHE_CTL));
841 #endif
842 }
843 }
844
845 /**
846 * \brief finish function after main
847 * \param [in] status status code return from main
848 * \details
849 * This function is executed right after main function.
850 * For RISC-V gnu toolchain, _fini function might not be called
851 * by __libc_fini_array function, so we defined a new function
852 * to do initialization
853 */
854 void _postmain_fini(int status)
855 {
856 /* TODO: Add your own finishing code here, called after main */
857 extern void simulation_exit(int status);
858 simulation_exit(status);
859 }
860
861 /**
862 * \brief _init function called in __libc_init_array()
863 * \details
864 * This `__libc_init_array()` function is called during startup code,
865 * user need to implement this function, otherwise when link it will
866 * error init.c:(.text.__libc_init_array+0x26): undefined reference to `_init'
867 * \note
868 * Please use \ref _premain_init function now
869 */
870 void _init(void)
871 {
872 /* Don't put any code here, please use _premain_init now */
873 }
874
875 /**
876 * \brief _fini function called in __libc_fini_array()
877 * \details
878 * This `__libc_fini_array()` function is called when exit main.
879 * user need to implement this function, otherwise when link it will
880 * error fini.c:(.text.__libc_fini_array+0x28): undefined reference to `_fini'
881 * \note
882 * Please use \ref _postmain_fini function now
883 */
884 void _fini(void)
885 {
886 /* Don't put any code here, please use _postmain_fini now */
887 }
888
889 /** @} */ /* End of Doxygen Group NMSIS_Core_SystemConfig */
system_Device.h Template File
Here we provided system_Device.h
template file as below:
1 /*
2 * Copyright (c) 2009-2018 Arm Limited. All rights reserved.
3 * Copyright (c) 2019 Nuclei Limited. All rights reserved.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Licensed under the Apache License, Version 2.0 (the License); you may
8 * not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19 /*******************************************************************************
20 * @file system_<Device>.h
21 * @brief NMSIS Nuclei N/NX Device Peripheral Access Layer Header File for
22 * Device <Device>
23 * @version V2.0.0
24 * @date 30. Dec 2022
25 ******************************************************************************/
26
27 #ifndef __SYSTEM_<Device>_H__ /* TODO: replace '<Device>' with your device name */
28 #define __SYSTEM_<Device>_H__
29
30 #ifdef __cplusplus
31 extern "C" {
32 #endif
33
34 #include <stdint.h>
35
36 extern volatile uint32_t SystemCoreClock; /*!< System Clock Frequency (Core Clock) */
37
38 typedef struct EXC_Frame {
39 unsigned long ra; /* ra: x1, return address for jump */
40 unsigned long tp; /* tp: x4, thread pointer */
41 unsigned long t0; /* t0: x5, temporary register 0 */
42 unsigned long t1; /* t1: x6, temporary register 1 */
43 unsigned long t2; /* t2: x7, temporary register 2 */
44 unsigned long a0; /* a0: x10, return value or function argument 0 */
45 unsigned long a1; /* a1: x11, return value or function argument 1 */
46 unsigned long a2; /* a2: x12, function argument 2 */
47 unsigned long a3; /* a3: x13, function argument 3 */
48 unsigned long a4; /* a4: x14, function argument 4 */
49 unsigned long a5; /* a5: x15, function argument 5 */
50 unsigned long cause; /* cause: machine/supervisor mode cause csr register */
51 unsigned long epc; /* epc: machine/ supervisor mode exception program counter csr register */
52 unsigned long msubm; /* msubm: machine sub-mode csr register, nuclei customized, exclusive to machine mode */
53 #ifndef __riscv_32e
54 unsigned long a6; /* a6: x16, function argument 6 */
55 unsigned long a7; /* a7: x17, function argument 7 */
56 unsigned long t3; /* t3: x28, temporary register 3 */
57 unsigned long t4; /* t4: x29, temporary register 4 */
58 unsigned long t5; /* t5: x30, temporary register 5 */
59 unsigned long t6; /* t6: x31, temporary register 6 */
60 #endif
61 } EXC_Frame_Type;
62
63 /**
64 * \brief Setup the microcontroller system.
65 * \details
66 * Initialize the System and update the SystemCoreClock variable.
67 */
68 extern void SystemInit(void);
69
70 /**
71 * \brief Update SystemCoreClock variable.
72 * \details
73 * Updates the SystemCoreClock with current core Clock retrieved from cpu registers.
74 */
75 extern void SystemCoreClockUpdate(void);
76
77 /**
78 * \brief Dump Exception Frame
79 */
80 void Exception_DumpFrame(unsigned long sp, uint8_t mode);
81
82 /**
83 * \brief Register an exception handler for exception code EXCn
84 */
85 extern void Exception_Register_EXC(uint32_t EXCn, unsigned long exc_handler);
86
87 /**
88 * \brief Get current exception handler for exception code EXCn
89 */
90 extern unsigned long Exception_Get_EXC(uint32_t EXCn);
91
92 /**
93 * \brief Initialize eclic config
94 */
95 extern void ECLIC_Init(void);
96
97 /**
98 * \brief Initialize a specific IRQ and register the handler
99 * \details
100 * This function set vector mode, trigger mode and polarity, interrupt level and priority,
101 * assign handler for specific IRQn.
102 */
103 extern int32_t ECLIC_Register_IRQ(IRQn_Type IRQn, uint8_t shv, ECLIC_TRIGGER_Type trig_mode, uint8_t lvl, uint8_t priority, void* handler);
104
105 #if defined(__TEE_PRESENT) && (__TEE_PRESENT == 1)
106 /**
107 * \brief Register an exception handler for exception code EXCn of supervisor mode
108 */
109 extern void Exception_Register_EXC_S(uint32_t EXCn, unsigned long exc_handler);
110
111 /**
112 * \brief Get current exception handler for exception code EXCn of supervisor mode
113 */
114 extern unsigned long Exception_Get_EXC_S(uint32_t EXCn);
115
116 /**
117 * \brief Initialize a specific IRQ and register the handler of supervisor mode
118 * \details
119 * This function set vector mode, trigger mode and polarity, interrupt level and priority,
120 * assign handler for specific IRQn.
121 */
122 extern int32_t ECLIC_Register_IRQ_S(IRQn_Type IRQn, uint8_t shv, ECLIC_TRIGGER_Type trig_mode, uint8_t lvl, uint8_t priority, void* handler);
123
124 #endif
125
126 #ifdef __cplusplus
127 }
128 #endif
129
130 #endif /* __SYSTEM_<Device>_H__ */