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__ */