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
 74typedef 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 */
 78extern fnptr irq_entry_s;
 79/** default entry for s-mode exception entry */
 80extern fnptr exc_entry_s;
 81/** default eclic interrupt or exception interrupt handler */
 82extern void default_intexc_handler(void);
 83
 84/** eclic s-mode software interrupt handler in eclic mode */
 85extern void eclic_ssip_handler(void) __WEAK;
 86/** eclic s-mode time interrupt handler in eclic mode */
 87extern void eclic_stip_handler(void) __WEAK;
 88
 89/* default s-mode exception handler, which user can modify it at your need */
 90static 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 */
115const 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 */
218volatile 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 */
231void 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 */
249void 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 */
278static 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)
289static 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 */
297typedef 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 */
307static 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 */
333static 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 */
351void 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 */
384void 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 */
401unsigned 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 */
425uint32_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 */
452static 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 */
478void 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 */
492unsigned 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 */
514uint32_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 */
534void 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 */
553void 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 */
583int32_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 */
624int32_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 */
653volatile 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 */
662static 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
684void __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 */
696void __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 */
744static 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 */
774void _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 */
854void _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 */
870void _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 */
884void _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
 31extern "C" {
 32#endif
 33
 34#include <stdint.h>
 35
 36extern volatile uint32_t SystemCoreClock;     /*!< System Clock Frequency (Core Clock) */
 37
 38typedef 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 */
 68extern 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 */
 75extern void SystemCoreClockUpdate(void);
 76
 77/**
 78 * \brief Dump Exception Frame
 79 */
 80void Exception_DumpFrame(unsigned long sp, uint8_t mode);
 81
 82/**
 83 * \brief Register an exception handler for exception code EXCn
 84 */
 85extern void Exception_Register_EXC(uint32_t EXCn, unsigned long exc_handler);
 86
 87/**
 88 * \brief Get current exception handler for exception code EXCn
 89 */
 90extern unsigned long Exception_Get_EXC(uint32_t EXCn);
 91
 92/**
 93 * \brief Initialize eclic config
 94 */
 95extern 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 */
103extern 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 */
109extern 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 */
114extern 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 */
122extern 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__ */