NMSIS-Core  Version 1.4.0
NMSIS-Core support for Nuclei processor-based devices
System Device Configuration

Functions for system and clock setup available in system_<device>.c. More...

Modules

 Interrupt and Exception and NMI Handling
 Functions for interrupt, exception and nmi handle available in system_<device>.c.
 

Macros

#define CLINT_MSIP(base, hartid)   (*(volatile uint32_t *)((uintptr_t)((base) + ((hartid) * 4))))
 
#define SMP_CTRLREG(base, ofs)   (*(volatile uint32_t *)((uintptr_t)((base) + (ofs))))
 

Functions

void exc_entry_s (void)
 
void irq_entry_s (void)
 default entry for s-mode non-vector irq entry More...
 
void default_intexc_handler (void)
 default entry for s-mode exception entry More...
 
void SystemCoreClockUpdate (void)
 Function to update the variable SystemCoreClock. More...
 
void SystemInit (void)
 Function to Initialize the system. More...
 
void SystemBannerPrint (void)
 Banner Print for Nuclei SDK. More...
 
void irq_entry (void)
 
void exc_entry (void)
 
void ECLIC_Interrupt_Init (void)
 Do ECLIC Interrupt configuration. More...
 
void CLINT_Interrupt_Init (void)
 Do CLINT Interrupt configuration. More...
 
void PLIC_Interrupt_Init (void)
 Do PLIC Interrupt configuration. More...
 
void Interrupt_Init (void)
 initialize interrupt controller More...
 
int32_t ECLIC_Register_IRQ (IRQn_Type IRQn, uint8_t shv, ECLIC_TRIGGER_Type trig_mode, uint8_t lvl, uint8_t priority, void *handler)
 Initialize a specific IRQ and register the handler. More...
 
int32_t Core_Register_IRQ (uint32_t irqn, void *handler)
 Register a m-mode riscv core interrupt and register the handler. More...
 
int32_t Core_Register_IRQ_S (uint32_t irqn, void *handler)
 Register a riscv s-mode core interrupt and register the handler. More...
 
int32_t PLIC_Register_IRQ (uint32_t source, uint8_t priority, void *handler)
 Register a m-mode specific plic interrupt and register the handler. More...
 
int32_t PLIC_Register_IRQ_S (uint32_t source, uint8_t priority, void *handler)
 Register a s-mode specific plic interrupt and register the handler. More...
 
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)
 Initialize a specific IRQ and register the handler for supervisor mode. More...
 
void __sync_harts (void)
 Synchronize all harts. More...
 
static void Trap_Init (void)
 do the init for trap More...
 
void _premain_init (void)
 early init function before main More...
 
void _postmain_fini (int status)
 finish function after main More...
 
void _init (void)
 _init function called in __libc_init_array() More...
 
void _fini (void)
 _fini function called in __libc_fini_array() More...
 

Variables

volatile uint32_t SystemCoreClock = SYSTEM_CLOCK
 Variable to hold the system core clock value. More...
 
unsigned long vector_base []
 
volatile unsigned long CpuIRegionBase = 0xFFFFFFFF
 Nuclei RISC-V CPU IRegion Base Address Probed, you should avoid to use it in your application code, please use __IREGION_BASEADDR if you want. More...
 

Detailed Description

Functions for system and clock setup available in system_<device>.c.

Nuclei provides a template file system_Device.c that must be adapted by the silicon vendor to match their actual device. As a minimum requirement, this file must provide:

The file configures the device and, typically, initializes the oscillator (PLL) that is part of the microcontroller device. This file might export other functions or variables that provide a more flexible configuration of the microcontroller system.

And this file also provided common interrupt, exception and NMI exception handling framework template, Silicon vendor can customize these template code as they want.

Note
Please pay special attention to the static variable SystemCoreClock. This variable might be used throughout the whole system initialization and runtime to calculate frequency/time related values. Thus one must assure that the variable always reflects the actual system clock speed.
Attention
Be aware that a value stored to SystemCoreClock during low level initialization (i.e. SystemInit()) might get overwritten by C libray startup code and/or .bss section initialization. Thus its highly recommended to call SystemCoreClockUpdate at the beginning of the user main() routine.

Macro Definition Documentation

◆ CLINT_MSIP

#define CLINT_MSIP (   base,
  hartid 
)    (*(volatile uint32_t *)((uintptr_t)((base) + ((hartid) * 4))))

Definition at line 1244 of file system_Device.c.

◆ SMP_CTRLREG

#define SMP_CTRLREG (   base,
  ofs 
)    (*(volatile uint32_t *)((uintptr_t)((base) + (ofs))))

Definition at line 1245 of file system_Device.c.

Function Documentation

◆ __sync_harts()

void __sync_harts ( void  )

Synchronize all harts.

This function is used to synchronize all the harts, especially to wait the boot hart finish initialization of data section, bss section and c runtines initialization This function must be placed in .text.init section, since section initialization is not ready, global variable and static variable should be avoid to use in this function, and avoid to call other functions

Definition at line 1247 of file system_Device.c.

1260 {
1261 // Only do synchronize when SMP_CPU_CNT is defined and number > 0
1262 // TODO: If you don't need to support SMP, you can directly remove code in it
1263 #if defined(SMP_CPU_CNT) && (SMP_CPU_CNT > 1)
1264  unsigned long hartid = __get_hart_id();
1265  unsigned long tmr_hartid = __get_hart_index();
1266  unsigned long clint_base, irgb_base, smp_base;
1267  unsigned long mcfg_info;
1268 
1269  // NOTE: we should avoid to use global variable such as CpuIRegionBase before smp cpu are configured
1270  mcfg_info = __RV_CSR_READ(CSR_MCFG_INFO);
1271  // Assume IREGION feature present
1272  if (mcfg_info & MCFG_INFO_IREGION_EXIST) { // IRegion Info present
1273  // clint base = system timer base + 0x1000
1274  irgb_base = (__RV_CSR_READ(CSR_MIRGB_INFO) >> 10) << 10;
1275  clint_base = irgb_base + IREGION_TIMER_OFS + 0x1000;
1276  smp_base = irgb_base + IREGION_SMP_OFS;
1277  } else {
1278  // Should not enter to here if iregion feature present
1279  while(1);
1280  }
1281  // Enable SMP
1282  SMP_CTRLREG(smp_base, 0xc) = 0xFFFFFFFF;
1283  // Enaable L2, disable cluster local memory
1284  if (SMP_CTRLREG(smp_base, 0x4) & 0x1) {
1285  SMP_CTRLREG(smp_base, 0x10) = 0x1;
1286  SMP_CTRLREG(smp_base, 0xd8) = 0x0;
1287  }
1288  __SMP_RWMB();
1289 
1290  // pre-condition: interrupt must be disabled, this is done before calling this function
1291  // BOOT_HARTID is defined <Device.h>
1292  if (hartid == BOOT_HARTID) { // boot hart
1293  // clear msip pending
1294  for (int i = 0; i < SMP_CPU_CNT; i ++) {
1295  CLINT_MSIP(clint_base, i) = 0;
1296  }
1297  __SMP_RWMB();
1298  } else {
1299  // Set machine software interrupt pending to 1
1300  CLINT_MSIP(clint_base, tmr_hartid) = 1;
1301  __SMP_RWMB();
1302  // wait for pending bit cleared by boot hart
1303  while (CLINT_MSIP(clint_base, tmr_hartid) == 1);
1304  }
1305 #endif
1306 }
#define __SMP_RWMB()
SMP Read & Write Memory barrier.
#define MCFG_INFO_IREGION_EXIST
#define IREGION_TIMER_OFS
#define IREGION_SMP_OFS
#define __RV_CSR_READ(csr)
CSR operation Macro for csrr instruction.
__STATIC_FORCEINLINE unsigned long __get_hart_id(void)
Get hart id of current cluster.
__STATIC_FORCEINLINE unsigned long __get_hart_index(void)
Get hart index of current cluster.
#define CSR_MCFG_INFO
#define CSR_MIRGB_INFO
#define CLINT_MSIP(base, hartid)
#define SMP_CTRLREG(base, ofs)

◆ _fini()

void _fini ( void  )

_fini function called in __libc_fini_array()

This __libc_fini_array() function is called when exit main. user need to implement this function, otherwise when link it will error fini.c:(.text.__libc_fini_array+0x28): undefined reference to ‘_fini’

Note
Please use _postmain_fini function now

Definition at line 1554 of file system_Device.c.

1555 {
1556  /* Don't put any code here, please use _postmain_fini now */
1557 }

◆ _init()

void _init ( void  )

_init function called in __libc_init_array()

This __libc_init_array() function is called during startup code, user need to implement this function, otherwise when link it will error init.c:(.text.__libc_init_array+0x26): undefined reference to ‘_init’

Note
Please use _premain_init function now

Definition at line 1540 of file system_Device.c.

1541 {
1542  /* Don't put any code here, please use _premain_init now */
1543 }

◆ _postmain_fini()

void _postmain_fini ( int  status)

finish function after main

Parameters
[in]statusstatus code return from main

This function is executed right after main function. For RISC-V gnu toolchain, _fini function might not be called by __libc_fini_array function, so we defined a new function to do initialization

Definition at line 1518 of file system_Device.c.

1519 {
1520 #if defined(CODESIZE) && (CODESIZE == 1)
1521 #ifdef CFG_SIMULATION
1522  SIMULATION_EXIT(status);
1523 #endif
1524 #else
1525  /* TODO: Add your own finishing code here, called after main */
1526  extern void simulation_exit(int status);
1527  simulation_exit(status);
1528 #endif
1529 }

◆ _premain_init()

void _premain_init ( void  )

early init function before main

This function is executed right before main function. For RISC-V gnu toolchain, _init function might not be called by __libc_init_array function, so we defined a new function to do initialization.

Definition at line 1324 of file system_Device.c.

1325 {
1326 #if defined(CODESIZE) && (CODESIZE == 1)
1327  // TODO to reduce the code size of application
1328  // No need to do so complex premain initialization steps
1329  // You just need to initialize the cpu resource you need to use in your
1330  // application code.
1331 
1332 #ifndef CFG_IREGION_BASE_ADDR // Need to probe the cpu iregion base address
1333  // Probe CPUIRegionBase for other cpu internal peripheral to use
1334  CpuIRegionBase = (__RV_CSR_READ(CSR_MIRGB_INFO) >> 10) << 10;
1335 #endif
1336  // TODO Still need to initialize uart for other code need to do printf
1337  // If you want to reduce more code, you can comment below code
1338  uart_init(SOC_DEBUG_UART, 115200);
1339 
1340 #else
1341  // TODO to make it possible for configurable boot hartid
1342  unsigned long hartid = __get_hart_id();
1343  unsigned long mcfginfo = __RV_CSR_READ(CSR_MCFG_INFO);
1344 
1345  /* TODO: Add your own initialization code here, called before main */
1346  // TODO This code controlled by macros RUNMODE_* are only used internally by Nuclei
1347  // You can remove it if you don't want it
1348  // No need to use in your code
1349 #if defined(RUNMODE_ILM_EN) || defined(RUNMODE_ECC_EN)
1350  // Only disable ilm when it is present
1351  if (mcfginfo & MCFG_INFO_ILM) {
1352 #if defined(RUNMODE_ECC_EN)
1353 #if RUNMODE_ECC_EN == 0
1355 #else
1357 #endif
1358 #endif
1359 #if defined(RUNMODE_ILM_EN)
1360 #if RUNMODE_ILM_EN == 0
1362 #else
1364 #endif
1365 #endif
1366  }
1367 #endif
1368 
1369 #if defined(RUNMODE_DLM_EN) || defined(RUNMODE_ECC_EN)
1370  // Only disable dlm when it is present
1371  if (mcfginfo & MCFG_INFO_DLM) {
1372 #if defined(RUNMODE_ECC_EN)
1373 #if RUNMODE_ECC_EN == 0
1375 #else
1377 #endif
1378 #endif
1379 #if defined(RUNMODE_DLM_EN)
1380 #if RUNMODE_DLM_EN == 0
1382 #else
1384 #endif
1385 #endif
1386  }
1387 #endif
1388 
1389 #if defined(RUNMODE_LDSPEC_EN)
1390 #if RUNMODE_LDSPEC_EN == 1
1392 #else
1394 #endif
1395 #endif
1396 
1397  /* __ICACHE_PRESENT and __DCACHE_PRESENT are defined in evalsoc.h */
1398  // For our internal cpu testing, they want to set evalsoc __ICACHE_PRESENT/__DCACHE_PRESENT to be 1
1399  // __CCM_PRESENT is still default to 0 in evalsoc.h, since it is used in core_feature_eclic.h to register interrupt, if set to 1, it might cause exception
1400  // but in the cpu, icache or dcache might not exist due to cpu configuration, so here
1401  // we need to check whether icache/dcache really exist, if yes, then turn on it
1402 #if defined(__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1)
1403  if (ICachePresent()) { // Check whether icache real present or not
1404 #if defined(RUNMODE_ECC_EN)
1405 #if RUNMODE_ECC_EN == 0
1407 #else
1409 #endif
1410 #endif
1411  EnableICache();
1412  }
1413 #endif
1414 #if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1)
1415  if (DCachePresent()) { // Check whether dcache real present or not
1416 #if defined(RUNMODE_ECC_EN)
1417 #if RUNMODE_ECC_EN == 0
1419 #else
1421 #endif
1422 #endif
1423  EnableDCache();
1424  }
1425 #endif
1426 
1427  /* Do fence and fence.i to make sure previous ilm/dlm/icache/dcache control done */
1428  __RWMB();
1429  __FENCE_I();
1430 
1431  // BOOT_HARTID is defined <Device.h> and also controlled by BOOT_HARTID in conf/evalsoc/build.mk
1432 #ifndef CFG_IREGION_BASE_ADDR // Need to probe the cpu iregion base address
1433  if (hartid == BOOT_HARTID) { // only done in boot hart
1434  // IREGION INFO MUST BE AFTER L1/L2 Cache enabled and SMP enabled if SMP present
1435  CpuIRegionBase = (__RV_CSR_READ(CSR_MIRGB_INFO) >> 10) << 10;
1436  } else {
1437  // wait for correct iregion base addr is set by boot hart
1438  while (CpuIRegionBase == 0xFFFFFFFF);
1439  }
1440 #endif
1441 
1442 #if defined(RUNMODE_L2_EN)
1443  if ((mcfginfo & (0x1 << 11)) && SMP_CTRLREG(__SMPCC_BASEADDR, 0x4) & 0x1 ) { // L2 Cache present
1444 #if RUNMODE_L2_EN == 1
1445  // Enable L2, disable cluster local memory
1446  SMP_CTRLREG(__SMPCC_BASEADDR, 0x10) = 0x1;
1447  SMP_CTRLREG(__SMPCC_BASEADDR, 0xd8) = 0x0;
1448  __SMP_RWMB();
1449 #else
1450  // Disable L2, enable cluster local memory
1451  SMP_CTRLREG(__SMPCC_BASEADDR, 0x10) = 0x0;
1452  // use as clm or cache, when l2 disable, the affect to ddr is the same, l2 is really disabled
1453  SMP_CTRLREG(__SMPCC_BASEADDR, 0xd8) = 0;//0xFFFFFFFF;
1454  __SMP_RWMB();
1455 #endif
1456  }
1457 #endif
1458 
1459 #if defined(RUNMODE_BPU_EN)
1460 #if RUNMODE_BPU_EN == 1
1462 #else
1464 #endif
1465 #endif
1466 
1467 #if defined(__CCM_PRESENT) && (__CCM_PRESENT == 1)
1468  // NOTE: CFG_HAS_SMODE and CFG_HAS_UMODE are defined in auto generated cpufeature.h if present in cpu
1469 #if defined(CFG_HAS_SMODE) || defined(CFG_HAS_UMODE)
1470  EnableSUCCM();
1471 #endif
1472 #endif
1473 
1474  if (hartid == BOOT_HARTID) { // only required for boot hartid
1475  // TODO implement get_cpu_freq function to get real cpu clock freq in HZ or directly give the real cpu HZ
1476  // TODO you can directly give the correct cpu frequency here, if you know it without call get_cpu_freq function
1477  SystemCoreClock = get_cpu_freq();
1478  uart_init(SOC_DEBUG_UART, 115200);
1479  /* Display banner after UART initialized */
1481  /* Initialize exception default handlers */
1482  Exception_Init();
1483  /* Interrupt initialization */
1484  Interrupt_Init();
1485  // TODO: internal usage for Nuclei
1486 #ifdef RUNMODE_CONTROL
1487  NSDK_DEBUG("Current RUNMODE=%s, ilm:%d, dlm %d, icache %d, dcache %d, ccm %d\n", \
1488  RUNMODE_STRING, RUNMODE_ILM_EN, RUNMODE_DLM_EN, \
1489  RUNMODE_IC_EN, RUNMODE_DC_EN, RUNMODE_CCM_EN);
1490  // ILM and DLM need to be present
1491  if (mcfginfo & 0x180 == 0x180) {
1492  NSDK_DEBUG("CSR: MILM_CTL 0x%x, MDLM_CTL 0x%x\n", \
1494  }
1495  // I/D cache need to be present
1496  if (mcfginfo & 0x600) {
1497  NSDK_DEBUG("CSR: MCACHE_CTL 0x%x\n", __RV_CSR_READ(CSR_MCACHE_CTL));
1498  }
1499  NSDK_DEBUG("CSR: MMISC_CTL 0x%x\n", __RV_CSR_READ(CSR_MMISC_CTL));
1500 #endif
1501  } else {
1502  /* Interrupt initialization */
1503  Interrupt_Init();
1504  }
1505 
1506 #endif
1507 }
__STATIC_FORCEINLINE void __FENCE_I(void)
Fence.i Instruction.
#define __RWMB()
Read & Write Memory barrier.
#define MILM_CTL_ILM_ECC_EN
#define MCACHE_CTL_DC_ECC_CHK_EN
#define MDLM_CTL_DLM_ECC_CHK_EN
#define MCACHE_CTL_DC_ECC_EN
#define MILM_CTL_ILM_ECC_EXCP_EN
#define MILM_CTL_ILM_ECC_CHK_EN
#define MMISC_CTL_LDSPEC_ENABLE
#define MILM_CTL_ILM_EN
#define MCFG_INFO_DLM
#define MDLM_CTL_DLM_EN
#define MCACHE_CTL_IC_ECC_EXCP_EN
#define MCACHE_CTL_IC_ECC_CHK_EN
#define MCACHE_CTL_DC_ECC_EXCP_EN
#define MCFG_INFO_ILM
#define MCACHE_CTL_IC_ECC_EN
#define MMISC_CTL_BPU
#define MDLM_CTL_DLM_ECC_EXCP_EN
#define MDLM_CTL_DLM_ECC_EN
#define __RV_CSR_CLEAR(csr, val)
CSR operation Macro for csrc instruction.
#define __RV_CSR_SET(csr, val)
CSR operation Macro for csrs instruction.
#define CSR_MDLM_CTL
#define CSR_MCACHE_CTL
#define CSR_MILM_CTL
#define CSR_MMISC_CTL
__STATIC_FORCEINLINE void EnableSUCCM(void)
Enable CCM operation in Supervisor/User Mode.
__STATIC_FORCEINLINE int32_t DCachePresent(void)
Check DCache Unit Present or Not.
__STATIC_FORCEINLINE void EnableDCache(void)
Enable DCache.
__STATIC_FORCEINLINE int32_t ICachePresent(void)
Check ICache Unit Present or Not.
__STATIC_FORCEINLINE void EnableICache(void)
Enable ICache.
static void Exception_Init(void)
Initialize all the default core exception handlers.
volatile uint32_t SystemCoreClock
Variable to hold the system core clock value.
void SystemBannerPrint(void)
Banner Print for Nuclei SDK.
volatile unsigned long CpuIRegionBase
Nuclei RISC-V CPU IRegion Base Address Probed, you should avoid to use it in your application code,...
void Interrupt_Init(void)
initialize interrupt controller

References __FENCE_I(), __get_hart_id(), __RV_CSR_CLEAR, __RV_CSR_READ, __RV_CSR_SET, __RWMB, __SMP_RWMB, CpuIRegionBase, CSR_MCACHE_CTL, CSR_MCFG_INFO, CSR_MDLM_CTL, CSR_MILM_CTL, CSR_MIRGB_INFO, CSR_MMISC_CTL, DCachePresent(), EnableDCache(), EnableICache(), EnableSUCCM(), Exception_Init(), ICachePresent(), Interrupt_Init(), MCACHE_CTL_DC_ECC_CHK_EN, MCACHE_CTL_DC_ECC_EN, MCACHE_CTL_DC_ECC_EXCP_EN, MCACHE_CTL_IC_ECC_CHK_EN, MCACHE_CTL_IC_ECC_EN, MCACHE_CTL_IC_ECC_EXCP_EN, MCFG_INFO_DLM, MCFG_INFO_ILM, MDLM_CTL_DLM_ECC_CHK_EN, MDLM_CTL_DLM_ECC_EN, MDLM_CTL_DLM_ECC_EXCP_EN, MDLM_CTL_DLM_EN, MILM_CTL_ILM_ECC_CHK_EN, MILM_CTL_ILM_ECC_EN, MILM_CTL_ILM_ECC_EXCP_EN, MILM_CTL_ILM_EN, MMISC_CTL_BPU, MMISC_CTL_LDSPEC_ENABLE, SMP_CTRLREG, SystemBannerPrint(), and SystemCoreClock.

◆ CLINT_Interrupt_Init()

void CLINT_Interrupt_Init ( void  )

Do CLINT Interrupt configuration.

This function will initialize cpu interrupt mode to clint mode. It will

  • Set exception/interrupt entry to exc_entry, now interrupt and exception share the same entry point
  • Register interrupt handling routine system_core_interrupt_handler to core_interrupt_handler function, which will be called in core_exception_handler function

Definition at line 935 of file system_Device.c.

936 {
937  /* Register core interrupt handler for clint/plic interrupt mode */
939  /* Set as CLINT interrupt mode */
940  __RV_CSR_WRITE(CSR_MTVEC, (unsigned long)exc_entry);
941 #if defined(__SMODE_PRESENT) && (__SMODE_PRESENT == 1)
942  /*
943  * Set supervisor exception entry stvec to exc_entry_s
944  */
945  __RV_CSR_WRITE(CSR_STVEC, (unsigned long)exc_entry_s);
947 #endif
948  for (int i = 0; i < SYSTEM_CORE_INTNUM; i++) {
950 #if defined(__SMODE_PRESENT) && (__SMODE_PRESENT == 1)
952 #endif
953  }
954 }
#define __RV_CSR_WRITE(csr, val)
CSR operation Macro for csrw instruction.
#define CSR_MTVEC
#define CSR_STVEC
static unsigned long SystemCoreInterruptHandlers_S[SYSTEM_CORE_INTNUM]
static void system_default_interrupt_handler_s(unsigned long scause, unsigned long sp)
s-mode System Default Interrupt Handler for CLINT/PLIC Interrupt Mode
#define SYSTEM_CORE_INTNUM
static unsigned long SystemCoreInterruptHandlers[SYSTEM_CORE_INTNUM]
static INT_HANDLER system_core_interrupt_handler_s
static void core_interrupt_handler_s(unsigned long exccode, unsigned long sp)
S-Mode Common Interrupt handler entry when in clint/plic mode.
static INT_HANDLER system_core_interrupt_handler
static void system_default_interrupt_handler(unsigned long mcause, unsigned long sp)
M-Mode System Default Interrupt Handler for CLINT/PLIC Interrupt Mode.
static void core_interrupt_handler(unsigned long exccode, unsigned long sp)
M-Mode Common Interrupt handler entry when in clint/plic mode.
void exc_entry_s(void)
void exc_entry(void)

References __RV_CSR_WRITE, core_interrupt_handler(), core_interrupt_handler_s(), CSR_MTVEC, CSR_STVEC, exc_entry(), exc_entry_s(), system_core_interrupt_handler, system_core_interrupt_handler_s, SYSTEM_CORE_INTNUM, system_default_interrupt_handler(), system_default_interrupt_handler_s(), SystemCoreInterruptHandlers, and SystemCoreInterruptHandlers_S.

Referenced by PLIC_Interrupt_Init().

◆ Core_Register_IRQ()

int32_t Core_Register_IRQ ( uint32_t  irqn,
void *  handler 
)

Register a m-mode riscv core interrupt and register the handler.

This function set interrupt handler for core interrupt in non-eclic mode

Parameters
[in]irqninterrupt number
[in]handlerinterrupt handler, if NULL, handler will not be installed
Returns
-1 means invalid input parameter. 0 means successful.
Remarks
  • This function use to configure riscv core interrupt and register its interrupt handler and enable its interrupt.
  • You can only use it when you are not in eclic interrupt mode

Definition at line 1069 of file system_Device.c.

1070 {
1071  if ((irqn > SYSTEM_CORE_INTNUM)) {
1072  return -1;
1073  }
1074 
1075  if (handler != NULL) {
1076  /* register interrupt handler entry to core handlers */
1077  Interrupt_Register_CoreIRQ(irqn, (unsigned long)handler);
1078  }
1079  switch (irqn) {
1080  case SysTimerSW_IRQn:
1081  __enable_sw_irq();
1082  break;
1083  case SysTimer_IRQn:
1085  break;
1086  default:
1087  break;
1088  }
1089 
1090  return 0;
1091 }
__STATIC_FORCEINLINE void __enable_sw_irq(void)
Enable software IRQ Interrupts.
__STATIC_FORCEINLINE void __enable_timer_irq(void)
Enable Timer IRQ Interrupts.
void Interrupt_Register_CoreIRQ(uint32_t irqn, unsigned long int_handler)
Register a m-mode core interrupt handler for core interrupt number.
@ SysTimerSW_IRQn
System Timer SW interrupt.
@ SysTimer_IRQn
System Timer Interrupt.

References __enable_sw_irq(), __enable_timer_irq(), Interrupt_Register_CoreIRQ(), SYSTEM_CORE_INTNUM, SysTimer_IRQn, and SysTimerSW_IRQn.

◆ Core_Register_IRQ_S()

int32_t Core_Register_IRQ_S ( uint32_t  irqn,
void *  handler 
)

Register a riscv s-mode core interrupt and register the handler.

This function set interrupt handler for core interrupt in non-eclic mode

Parameters
[in]irqninterrupt number
[in]handlerinterrupt handler, if NULL, handler will not be installed
Returns
-1 means invalid input parameter. 0 means successful.
Remarks
  • This function use to configure riscv core interrupt and register its interrupt handler and enable its interrupt.
  • You can only use it when you are not in eclic interrupt mode

Definition at line 1105 of file system_Device.c.

1106 {
1107  if ((irqn > SYSTEM_CORE_INTNUM)) {
1108  return -1;
1109  }
1110 
1111  if (handler != NULL) {
1112  /* register interrupt handler entry to core handlers */
1113  Interrupt_Register_CoreIRQ_S(irqn, (unsigned long)handler);
1114  }
1115  switch (irqn) {
1116  case SysTimerSW_S_IRQn:
1118  break;
1119  case SysTimer_S_IRQn:
1121  break;
1122  default:
1123  break;
1124  }
1125 
1126  return 0;
1127 }
__STATIC_FORCEINLINE void __enable_timer_irq_s(void)
Enable Timer IRQ Interrupts in supervisor mode.
__STATIC_FORCEINLINE void __enable_sw_irq_s(void)
Enable software IRQ Interrupts in supervisor mode.
void Interrupt_Register_CoreIRQ_S(uint32_t irqn, unsigned long int_handler)
Register an s-mode core interrupt handler for core interrupt number.

References __enable_sw_irq_s(), __enable_timer_irq_s(), Interrupt_Register_CoreIRQ_S(), and SYSTEM_CORE_INTNUM.

◆ default_intexc_handler()

void default_intexc_handler ( void  )

default entry for s-mode exception entry

default eclic interrupt or exception interrupt handler

◆ ECLIC_Interrupt_Init()

void ECLIC_Interrupt_Init ( void  )

Do ECLIC Interrupt configuration.

This function will initialize cpu interrupt mode to eclic mode. It will

  • set common non-vector entry to irq_entry
  • set vector interrupt table to vector_base
  • set exception entry to exc_entry
  • set eclic mth to 0, and nlbits to the bigest bits it supports
  • set s-mode common non-vector entry to irq_entry_s if tee present
  • set s-mode vector interrupt table to vector_base_s if tee present
  • set s-mode exception entry to exc_entry_s if tee present
  • set eclic sth to 0 if tee present

Definition at line 879 of file system_Device.c.

880 {
881 #if defined(__ECLIC_PRESENT) && (__ECLIC_PRESENT == 1)
882  unsigned long mcfg_info;
883 
884  mcfg_info = __RV_CSR_READ(CSR_MCFG_INFO);
885  if (mcfg_info & MCFG_INFO_CLIC) {
886  /* Set ECLIC vector interrupt base address to vector_base */
887  __RV_CSR_WRITE(CSR_MTVT, (unsigned long)vector_base);
888  /* Set ECLIC non-vector entry to irq_entry */
889  __RV_CSR_WRITE(CSR_MTVT2, (unsigned long)irq_entry | 0x1);
890  /* Set as CLIC interrupt mode */
891  __RV_CSR_WRITE(CSR_MTVEC, (unsigned long)exc_entry | 0x3);
892  /* Global Configuration about MTH and NLBits.
893  * TODO: Please adapt it according to your system requirement.
894  * This function is called in _init function */
895  ECLIC_SetMth(0);
896  ECLIC_SetCfgNlbits(__ECLIC_INTCTLBITS);
897 
898 #if defined(__TEE_PRESENT) && (__TEE_PRESENT == 1)
899  if (mcfg_info & MCFG_INFO_TEE) {
900  /*
901  * Intialize ECLIC supervisor mode vector interrupt
902  * base address stvt to vector_table_s
903  */
904  __RV_CSR_WRITE(CSR_STVT, (unsigned long)vector_table_s);
905  /*
906  * Set ECLIC supervisor mode non-vector entry to be controlled
907  * by stvt2 CSR register.
908  * Intialize supervisor mode ECLIC non-vector interrupt
909  * base address stvt2 to irq_entry_s.
910  */
911  __RV_CSR_WRITE(CSR_STVT2, (unsigned long)irq_entry_s);
912  __RV_CSR_SET(CSR_STVT2, 0x01);
913  /*
914  * Set supervisor exception entry stvec to exc_entry_s */
915  __RV_CSR_WRITE(CSR_STVEC, (unsigned long)exc_entry_s);
916  /* Global Configuration about STH */
917  ECLIC_SetSth(0);
918  }
919 #endif
920  } else {
921  /* Set as CLINT interrupt mode */
922  __RV_CSR_WRITE(CSR_MTVEC, (unsigned long)exc_entry);
923  }
924 #endif
925 }
#define MCFG_INFO_TEE
#define MCFG_INFO_CLIC
#define CSR_MTVT
#define CSR_MTVT2
#define CSR_STVT2
#define CSR_STVT
#define ECLIC_SetMth
#define ECLIC_SetSth
#define ECLIC_SetCfgNlbits
unsigned long vector_base[]
void irq_entry(void)
void irq_entry_s(void)
default entry for s-mode non-vector irq entry

References __RV_CSR_READ, __RV_CSR_SET, __RV_CSR_WRITE, CSR_MCFG_INFO, CSR_MTVEC, CSR_MTVT, CSR_MTVT2, CSR_STVEC, CSR_STVT, CSR_STVT2, ECLIC_SetCfgNlbits, ECLIC_SetMth, ECLIC_SetSth, exc_entry(), exc_entry_s(), irq_entry(), irq_entry_s(), MCFG_INFO_CLIC, MCFG_INFO_TEE, and vector_base.

Referenced by Interrupt_Init().

◆ ECLIC_Register_IRQ()

int32_t ECLIC_Register_IRQ ( IRQn_Type  IRQn,
uint8_t  shv,
ECLIC_TRIGGER_Type  trig_mode,
uint8_t  lvl,
uint8_t  priority,
void *  handler 
)

Initialize a specific IRQ and register the handler.

This function set vector mode, trigger mode and polarity, interrupt level and priority, assign handler for specific IRQn.

Parameters
[in]IRQnNMI interrupt handler address
[in]shvECLIC_NON_VECTOR_INTERRUPT means non-vector mode, and ECLIC_VECTOR_INTERRUPT is vector mode
[in]trig_modesee ECLIC_TRIGGER_Type
[in]lvlinterupt level
[in]priorityinterrupt priority
[in]handlerinterrupt handler, if NULL, handler will not be installed
Returns
-1 means invalid input parameter. 0 means successful.
Remarks
  • This function use to configure specific eclic interrupt and register its interrupt handler and enable its interrupt.
  • If the vector table is placed in read-only section(FLASHXIP mode), handler could not be installed

Definition at line 1033 of file system_Device.c.

1034 {
1035  if ((IRQn > SOC_INT_MAX) || (shv > ECLIC_VECTOR_INTERRUPT) \
1036  || (trig_mode > ECLIC_NEGTIVE_EDGE_TRIGGER)) {
1037  return -1;
1038  }
1039 
1040  /* set interrupt vector mode */
1041  ECLIC_SetShvIRQ(IRQn, shv);
1042  /* set interrupt trigger mode and polarity */
1043  ECLIC_SetTrigIRQ(IRQn, trig_mode);
1044  /* set interrupt level */
1045  ECLIC_SetLevelIRQ(IRQn, lvl);
1046  /* set interrupt priority */
1047  ECLIC_SetPriorityIRQ(IRQn, priority);
1048  if (handler != NULL) {
1049  /* set interrupt handler entry to vector table */
1050  ECLIC_SetVector(IRQn, (rv_csr_t)handler);
1051  }
1052  /* enable interrupt */
1053  ECLIC_EnableIRQ(IRQn);
1054  return 0;
1055 }
#define ECLIC_VECTOR_INTERRUPT
Vector Interrupt Mode of ECLIC.
@ ECLIC_NEGTIVE_EDGE_TRIGGER
Negtive/Falling Edge Triggered, trig[0] = 1, trig[1] = 1.
#define ECLIC_SetShvIRQ
#define ECLIC_SetPriorityIRQ
#define ECLIC_SetVector
#define ECLIC_SetTrigIRQ
#define ECLIC_SetLevelIRQ
#define ECLIC_EnableIRQ
@ SOC_INT_MAX
Number of total interrupts.
unsigned long rv_csr_t
Type of Control and Status Register(CSR), depends on the XLEN defined in RISC-V.

References ECLIC_EnableIRQ, ECLIC_NEGTIVE_EDGE_TRIGGER, ECLIC_SetLevelIRQ, ECLIC_SetPriorityIRQ, ECLIC_SetShvIRQ, ECLIC_SetTrigIRQ, ECLIC_SetVector, ECLIC_VECTOR_INTERRUPT, and SOC_INT_MAX.

◆ ECLIC_Register_IRQ_S()

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 
)

Initialize a specific IRQ and register the handler for supervisor mode.

This function set vector mode, trigger mode and polarity, interrupt level and priority, assign handler for specific IRQn.

Parameters
[in]IRQnNMI interrupt handler address
[in]shvECLIC_NON_VECTOR_INTERRUPT means non-vector mode, and ECLIC_VECTOR_INTERRUPT is vector mode
[in]trig_modesee ECLIC_TRIGGER_Type
[in]lvlinterupt level
[in]priorityinterrupt priority
[in]handlerinterrupt handler, if NULL, handler will not be installed
Returns
-1 means invalid input parameter. 0 means successful.
Remarks
  • This function use to configure specific eclic S-mode interrupt and register its interrupt handler and enable its interrupt.
  • If the vector table is placed in read-only section (FLASHXIP mode), handler could not be installed.

Definition at line 1211 of file system_Device.c.

1212 {
1213  if ((IRQn > SOC_INT_MAX) || (shv > ECLIC_VECTOR_INTERRUPT) \
1214  || (trig_mode > ECLIC_NEGTIVE_EDGE_TRIGGER)) {
1215  return -1;
1216  }
1217 
1218  /* set interrupt vector mode */
1219  ECLIC_SetShvIRQ_S(IRQn, shv);
1220  /* set interrupt trigger mode and polarity */
1221  ECLIC_SetTrigIRQ_S(IRQn, trig_mode);
1222  /* set interrupt level */
1223  ECLIC_SetLevelIRQ_S(IRQn, lvl);
1224  /* set interrupt priority */
1225  ECLIC_SetPriorityIRQ_S(IRQn, priority);
1226  if (handler != NULL) {
1227  /* set interrupt handler entry to vector table */
1228  ECLIC_SetVector_S(IRQn, (rv_csr_t)handler);
1229  }
1230  /* enable interrupt */
1231  ECLIC_EnableIRQ_S(IRQn);
1232  return 0;
1233 }
#define ECLIC_SetPriorityIRQ_S
#define ECLIC_SetTrigIRQ_S
#define ECLIC_SetShvIRQ_S
#define ECLIC_SetVector_S
#define ECLIC_EnableIRQ_S
#define ECLIC_SetLevelIRQ_S

References ECLIC_EnableIRQ_S, ECLIC_NEGTIVE_EDGE_TRIGGER, ECLIC_SetLevelIRQ_S, ECLIC_SetPriorityIRQ_S, ECLIC_SetShvIRQ_S, ECLIC_SetTrigIRQ_S, ECLIC_SetVector_S, ECLIC_VECTOR_INTERRUPT, and SOC_INT_MAX.

◆ exc_entry()

void exc_entry ( void  )

◆ exc_entry_s()

void exc_entry_s ( void  )

◆ Interrupt_Init()

void Interrupt_Init ( void  )

initialize interrupt controller

Do CPU interrupt initialization, if plic present, init it, then init eclic if present. So if ECLIC present, the interrupt will default configured to ECLIC interrupt mode, if you want to switch to PLIC interrupt mode, you need to call PLIC_Interrupt_Init in you application code.

By default, if ECLIC present, eclic interrupt mode will be set, otherwise it will be clint/plic interrupt mode

Remarks
This function previously was ECLIC_Init, now ECLIC_Init is removed

Definition at line 997 of file system_Device.c.

998 {
999 #if defined(CODESIZE) && (CODESIZE == 1)
1000 #else
1001  /* Set as CLINT interrupt mode */
1002  __RV_CSR_WRITE(CSR_MTVEC, (unsigned long)exc_entry);
1003 
1004  /* Init interrupt as eclic mode when ECLIC present
1005  * Otherwise will init interrupt as plic mode when PLIC present
1006  * Only initialize necessary ones to reduce initialization code size usage */
1007 #if defined(__ECLIC_PRESENT) && (__ECLIC_PRESENT == 1)
1009 #elif defined(__PLIC_PRESENT) && (__PLIC_PRESENT == 1)
1011 #endif
1012 
1013 #endif
1014 }
void ECLIC_Interrupt_Init(void)
Do ECLIC Interrupt configuration.
void PLIC_Interrupt_Init(void)
Do PLIC Interrupt configuration.

References __RV_CSR_WRITE, CSR_MTVEC, ECLIC_Interrupt_Init(), exc_entry(), and PLIC_Interrupt_Init().

Referenced by _premain_init().

◆ irq_entry()

void irq_entry ( void  )

Referenced by ECLIC_Interrupt_Init().

◆ irq_entry_s()

void irq_entry_s ( void  )

default entry for s-mode non-vector irq entry

Referenced by ECLIC_Interrupt_Init().

◆ PLIC_Interrupt_Init()

void PLIC_Interrupt_Init ( void  )

Do PLIC Interrupt configuration.

This function will initialize cpu interrupt mode to clint/plic mode. It will

  • Initialize a software maintained SystemM/SExtInterruptHandlers and SystemCoreInterruptHandlers to default value
  • Set exception/interrupt entry to exc_entry, now interrupt and exception share the same entry point

Definition at line 963 of file system_Device.c.

964 {
966 #if defined(__PLIC_PRESENT) && (__PLIC_PRESENT == 1)
967  int i;
968  for (i = 0; i < __PLIC_INTNUM; i++) {
970 #if defined(__SMODE_PRESENT) && (__SMODE_PRESENT == 1)
972 #endif
973  }
974 
977 #if defined(__SMODE_PRESENT) && (__SMODE_PRESENT == 1)
980 #endif
981 #endif
982 }
static void system_smode_extirq_handler(unsigned long exccode, unsigned long sp)
S-Mode external interrupt handler common entry for plic interrupt mode.
static unsigned long SystemSExtInterruptHandlers[__PLIC_INTNUM]
static void system_mmode_extirq_handler(unsigned long exccode, unsigned long sp)
M-Mode external interrupt handler common entry for plic interrupt mode.
static unsigned long SystemMExtInterruptHandlers[__PLIC_INTNUM]
void CLINT_Interrupt_Init(void)
Do CLINT Interrupt configuration.

References CLINT_Interrupt_Init(), system_default_interrupt_handler(), system_default_interrupt_handler_s(), system_mmode_extirq_handler(), system_smode_extirq_handler(), SystemCoreInterruptHandlers, SystemCoreInterruptHandlers_S, SystemMExtInterruptHandlers, and SystemSExtInterruptHandlers.

Referenced by Interrupt_Init().

◆ PLIC_Register_IRQ()

int32_t PLIC_Register_IRQ ( uint32_t  source,
uint8_t  priority,
void *  handler 
)

Register a m-mode specific plic interrupt and register the handler.

This function set priority and handler for m-mode plic interrupt

Parameters
[in]sourceinterrupt source
[in]priorityinterrupt priority
[in]handlerinterrupt handler, if NULL, handler will not be installed
Returns
-1 means invalid input parameter. 0 means successful.
Remarks
  • This function use to configure specific plic interrupt and register its interrupt handler and enable its interrupt.
  • You can only use it when you are in plic interrupt mode

Definition at line 1143 of file system_Device.c.

1144 {
1145  if ((source >= __PLIC_INTNUM)) {
1146  return -1;
1147  }
1148 
1149  /* set interrupt priority */
1150  PLIC_SetPriority(source, priority);
1151  if (handler != NULL) {
1152  /* register interrupt handler entry to external handlers */
1153  Interrupt_Register_ExtIRQ(source, (unsigned long)handler);
1154  }
1155  /* enable interrupt */
1156  PLIC_EnableInterrupt(source);
1157  __enable_ext_irq();
1158  return 0;
1159 }
__STATIC_FORCEINLINE void __enable_ext_irq(void)
Enable External IRQ Interrupts.
void Interrupt_Register_ExtIRQ(uint32_t irqn, unsigned long int_handler)
Register a m-mode external interrupt handler for plic external interrupt number.
#define PLIC_EnableInterrupt(source)
__STATIC_FORCEINLINE void PLIC_SetPriority(uint32_t source, uint32_t priority)
Set interrupt priority for selected source plic.

References __enable_ext_irq(), Interrupt_Register_ExtIRQ(), PLIC_EnableInterrupt, and PLIC_SetPriority().

◆ PLIC_Register_IRQ_S()

int32_t PLIC_Register_IRQ_S ( uint32_t  source,
uint8_t  priority,
void *  handler 
)

Register a s-mode specific plic interrupt and register the handler.

This function set priority and handler for s-mode plic interrupt

Parameters
[in]sourceinterrupt source
[in]priorityinterrupt priority
[in]handlerinterrupt handler, if NULL, handler will not be installed
Returns
-1 means invalid input parameter. 0 means successful.
Remarks
  • This function use to configure specific plic interrupt and register its interrupt handler and enable its interrupt.
  • You can only use it when you are in plic interrupt mode

Definition at line 1174 of file system_Device.c.

1175 {
1176  if ((source >= __PLIC_INTNUM)) {
1177  return -1;
1178  }
1179 
1180  /* set interrupt priority */
1181  PLIC_SetPriority(source, priority);
1182  if (handler != NULL) {
1183  /* register interrupt handler entry to external handlers */
1184  Interrupt_Register_ExtIRQ_S(source, (unsigned long)handler);
1185  }
1186  /* enable interrupt */
1187  PLIC_EnableInterrupt_S(source);
1189  return 0;
1190 }
__STATIC_FORCEINLINE void __enable_ext_irq_s(void)
Enable External IRQ Interrupts in supervisor mode.
void Interrupt_Register_ExtIRQ_S(uint32_t irqn, unsigned long int_handler)
Register an s-mode external interrupt handler for plic external interrupt number.
#define PLIC_EnableInterrupt_S(source)

References __enable_ext_irq_s(), Interrupt_Register_ExtIRQ_S(), PLIC_EnableInterrupt_S, and PLIC_SetPriority().

◆ SystemBannerPrint()

void SystemBannerPrint ( void  )

Banner Print for Nuclei SDK.

Definition at line 847 of file system_Device.c.

848 {
849 #if defined(NUCLEI_BANNER) && (NUCLEI_BANNER == 1)
850  NSDK_DEBUG("Nuclei SDK Build Time: %s, %s\r\n", __DATE__, __TIME__);
851 #ifdef DOWNLOAD_MODE_STRING
852  NSDK_DEBUG("Download Mode: %s\r\n", DOWNLOAD_MODE_STRING);
853 #endif
854  NSDK_DEBUG("CPU Frequency %u Hz\r\n", (unsigned int)SystemCoreClock);
855  NSDK_DEBUG("CPU HartID: %u\r\n", (unsigned int)__get_hart_id());
856 #endif
857 }

References __get_hart_id(), and SystemCoreClock.

Referenced by _premain_init().

◆ SystemCoreClockUpdate()

void SystemCoreClockUpdate ( void  )

Function to update the variable SystemCoreClock.

Updates the variable SystemCoreClock and must be called whenever the core clock is changed during program execution. The function evaluates the clock register settings and calculates the current core clock.

Definition at line 197 of file system_Device.c.

198 {
199  /* ToDo: add code to calculate the system frequency based upon the current
200  * register settings.
201  * Note: This function can be used to retrieve the system core clock frequeny
202  * after user changed register settings.
203  */
204 }

◆ SystemInit()

void SystemInit ( void  )

Function to Initialize the system.

Initializes the microcontroller system. Typically, this function configures the oscillator (PLL) that is part of the microcontroller device. For systems with a variable clock speed, it updates the variable SystemCoreClock. SystemInit is called from the file startup_device.

Definition at line 214 of file system_Device.c.

215 {
216  /* ToDo: add code to initialize the system
217  * Warn: do not use global variables because this function is called before
218  * reaching pre-main. RW section maybe overwritten afterwards.
219  */
220 }

◆ Trap_Init()

static void Trap_Init ( void  )
static

do the init for trap

Definition at line 1312 of file system_Device.c.

1313 {
1314 }

Variable Documentation

◆ CpuIRegionBase

volatile unsigned long CpuIRegionBase = 0xFFFFFFFF

Nuclei RISC-V CPU IRegion Base Address Probed, you should avoid to use it in your application code, please use __IREGION_BASEADDR if you want.

Definition at line 1241 of file system_Device.c.

Referenced by _premain_init().

◆ SystemCoreClock

volatile uint32_t SystemCoreClock = SYSTEM_CLOCK

Variable to hold the system core clock value.

Holds the system core clock, which is the system clock frequency supplied to the SysTick timer and the processor core clock. This variable can be used by debuggers to query the frequency of the debug timer or to configure the trace clock speed.

Attention
Compilers must be configured to avoid removing this variable in case the application program is not using it. Debugging systems require the variable to be physically present in memory so that it can be examined to configure the debugger.

Definition at line 184 of file system_Device.c.

Referenced by _premain_init(), and SystemBannerPrint().

◆ vector_base

unsigned long vector_base[]
extern

Referenced by ECLIC_Interrupt_Init().