system_evalsoc.c 65 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661
  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_evalsoc.c
  21. * @brief NMSIS Nuclei Core Device Peripheral Access Layer Source File for
  22. * Nuclei Eval SoC which support Nuclei N/NX class cores
  23. * @version V1.00
  24. * @date 22. Nov 2019
  25. ******************************************************************************/
  26. #include <stdint.h>
  27. #include <stdio.h>
  28. #include "nuclei_sdk_hal.h"
  29. // TODO: This implementation contains many extra code controlled by macros
  30. // which may be not suitable for your SoC, you can directly remove the code
  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. // NOTE: SYSTEM_CLOCK can be overwritten by make variable SYSCLK defined in build.mk.
  37. // eg. make SYSCLK=500000000 clean all
  38. #ifndef SYSTEM_CLOCK
  39. #define SYSTEM_CLOCK (16000000UL)
  40. #endif
  41. /**
  42. * \defgroup NMSIS_Core_SystemConfig System Device Configuration
  43. * \brief Functions for system and clock setup available in system_<device>.c.
  44. * \details
  45. * Nuclei provides a template file **system_Device.c** that must be adapted by
  46. * the silicon vendor to match their actual device. As a <b>minimum requirement</b>,
  47. * this file must provide:
  48. * - A device-specific system configuration function, \ref SystemInit.
  49. * - Global c library \ref _premain_init and \ref _postmain_fini functions called right before calling main function.
  50. * - A global variable that contains the system frequency, \ref SystemCoreClock.
  51. * - A global eclic configuration initialization, \ref ECLIC_Init.
  52. * - A global exception and trap configuration initialization, \ref Trap_Init and \ref Exception_Init.
  53. * - Vendor customized interrupt, exception and nmi handling code, see \ref NMSIS_Core_IntExcNMI_Handling
  54. *
  55. * The file configures the device and, typically, initializes the oscillator (PLL) that is part
  56. * of the microcontroller device. This file might export other functions or variables that provide
  57. * a more flexible configuration of the microcontroller system.
  58. *
  59. * And this file also provided common interrupt, exception and NMI exception handling framework template,
  60. * Silicon vendor can customize these template code as they want.
  61. *
  62. * \note Please pay special attention to the static variable \c SystemCoreClock. This variable might be
  63. * used throughout the whole system initialization and runtime to calculate frequency/time related values.
  64. * Thus one must assure that the variable always reflects the actual system clock speed.
  65. *
  66. * \attention
  67. * Be aware that a value stored to \c SystemCoreClock during low level initialization (i.e. \c SystemInit()) might get
  68. * overwritten by C libray startup code and/or .bss section initialization.
  69. * Thus its highly recommended to call \ref SystemCoreClockUpdate at the beginning of the user \c main() routine.
  70. *
  71. * @{
  72. */
  73. #if (defined(__SMODE_PRESENT) && (__SMODE_PRESENT == 1))
  74. extern void exc_entry_s(void);
  75. /* default s-mode exception handler, which user can modify it at your need */
  76. static void system_default_exception_handler_s(unsigned long scause, unsigned long sp);
  77. #endif
  78. static void system_default_exception_handler(unsigned long mcause, unsigned long sp);
  79. #if defined(__SMODE_PRESENT) && (__SMODE_PRESENT == 1)
  80. /* for the following variables, see intexc_evalsoc.S and intexc_evalsoc_s.S */
  81. /** default entry for s-mode non-vector irq entry */
  82. extern void irq_entry_s(void);
  83. /** default entry for s-mode exception entry */
  84. /** default eclic interrupt or exception interrupt handler */
  85. extern void default_intexc_handler(void);
  86. #ifndef __ICCRISCV__
  87. /** eclic s-mode software interrupt handler in eclic mode */
  88. extern void eclic_ssip_handler(void) __WEAK;
  89. /** eclic s-mode time interrupt handler in eclic mode */
  90. extern void eclic_stip_handler(void) __WEAK;
  91. #else
  92. /** eclic s-mode software interrupt handler in eclic mode */
  93. __WEAK __SUPERVISOR_INTERRUPT void eclic_ssip_handler(void) { }
  94. /** eclic s-mode time interrupt handler in eclic mode */
  95. __WEAK __SUPERVISOR_INTERRUPT __WEAK void eclic_stip_handler(void) { }
  96. #endif
  97. // TODO: change the aligned(1024) 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. #ifndef __ICCRISCV__
  100. #define __SMODE_VECTOR_ATTR __attribute__((section (".text.vtable_s"), aligned(1024)))
  101. #else
  102. #define __SMODE_VECTOR_ATTR __attribute__((section (".sintvec"), aligned(1024)))
  103. #endif
  104. /**
  105. * \var unsigned long vector_table_s[SOC_INT_MAX]
  106. * \brief vector interrupt storing ISRs for supervisor mode
  107. * \details
  108. * vector_table_s is hold by stvt register, the address must align according
  109. * to actual interrupt numbers as below, now align to 512(rv32) or 1024(rv64) bytes considering we put up to 128 interrupts here
  110. * alignment must comply to table below if you increase or decrease vector interrupt number
  111. * rv64 alignment is double of rv32 alignment
  112. * interrupt number rv32 alignment
  113. * 0 to 16 64-byte
  114. * 17 to 32 128-byte
  115. * 33 to 64 256-byte
  116. * 65 to 128 512-byte
  117. * 129 to 256 1KB
  118. * 257 to 512 2KB
  119. * 513 to 1024 4KB
  120. */
  121. const unsigned long vector_table_s[SOC_INT_MAX] __SMODE_VECTOR_ATTR =
  122. {
  123. (unsigned long)(default_intexc_handler), /* 0: Reserved */
  124. #if defined(__SSTC_PRESENT) && __SSTC_PRESENT == 1
  125. (unsigned long)(eclic_ssip_handler), /* 1: supervisor software interrupt triggered by SSIP */
  126. #else
  127. (unsigned long)(default_intexc_handler), /* 1: Reserved */
  128. #endif
  129. (unsigned long)(default_intexc_handler), /* 2: Reserved */
  130. (unsigned long)(eclic_ssip_handler), /* 3: machine software interrupt triggered by MSIP but handled in S-Mode */
  131. (unsigned long)(default_intexc_handler), /* 4: Reserved */
  132. #if defined(__SSTC_PRESENT) && __SSTC_PRESENT == 1
  133. (unsigned long)(eclic_stip_handler), /* 5: supervisor timer interrupt triggered by stimecmp(SSTC) */
  134. #else
  135. (unsigned long)(default_intexc_handler), /* 5: Reserved */
  136. #endif
  137. (unsigned long)(default_intexc_handler), /* 6: Reserved */
  138. (unsigned long)(eclic_stip_handler), /* 7: machine timer interrupt triggered by mtimecmp but handled in S-Mode */
  139. (unsigned long)(default_intexc_handler), /* 8: Reserved */
  140. (unsigned long)(default_intexc_handler), /* 9: Reserved */
  141. (unsigned long)(default_intexc_handler), /* 10: Reserved */
  142. (unsigned long)(default_intexc_handler), /* 11: Reserved */
  143. (unsigned long)(default_intexc_handler), /* 12: Reserved */
  144. (unsigned long)(default_intexc_handler), /* 13: Reserved */
  145. (unsigned long)(default_intexc_handler), /* 14: Reserved */
  146. (unsigned long)(default_intexc_handler), /* 15: Reserved */
  147. (unsigned long)(default_intexc_handler), /* 16: Reserved */
  148. (unsigned long)(default_intexc_handler), /* 17: Reserved */
  149. (unsigned long)(default_intexc_handler), /* 18: Reserved */
  150. /* TODO other external interrupt handler don't provide default value, if you want to provide default value, please do it by yourself */
  151. };
  152. #endif
  153. /*----------------------------------------------------------------------------
  154. System Core Clock Variable
  155. *----------------------------------------------------------------------------*/
  156. /* ToDo: initialize SystemCoreClock with the system core clock frequency value
  157. achieved after system intitialization.
  158. This means system core clock frequency after call to SystemInit() */
  159. /**
  160. * \brief Variable to hold the system core clock value
  161. * \details
  162. * Holds the system core clock, which is the system clock frequency supplied to the SysTick
  163. * timer and the processor core clock. This variable can be used by debuggers to query the
  164. * frequency of the debug timer or to configure the trace clock speed.
  165. *
  166. * \attention
  167. * Compilers must be configured to avoid removing this variable in case the application
  168. * program is not using it. Debugging systems require the variable to be physically
  169. * present in memory so that it can be examined to configure the debugger.
  170. */
  171. volatile uint32_t SystemCoreClock = SYSTEM_CLOCK; /* System Clock Frequency (Core Clock) */
  172. /*----------------------------------------------------------------------------
  173. Clock functions
  174. *----------------------------------------------------------------------------*/
  175. /**
  176. * \brief Function to update the variable \ref SystemCoreClock
  177. * \details
  178. * Updates the variable \ref SystemCoreClock and must be called whenever the core clock is changed
  179. * during program execution. The function evaluates the clock register settings and calculates
  180. * the current core clock.
  181. */
  182. void SystemCoreClockUpdate(void) /* Get Core Clock Frequency */
  183. {
  184. /* ToDo: add code to calculate the system frequency based upon the current
  185. * register settings.
  186. * Note: This function can be used to retrieve the system core clock frequeny
  187. * after user changed register settings.
  188. */
  189. }
  190. /**
  191. * \brief Function to Initialize the system.
  192. * \details
  193. * Initializes the microcontroller system. Typically, this function configures the
  194. * oscillator (PLL) that is part of the microcontroller device. For systems
  195. * with a variable clock speed, it updates the variable \ref SystemCoreClock.
  196. * SystemInit is called from the file <b>startup<i>_device</i></b>.
  197. */
  198. void SystemInit(void)
  199. {
  200. /* ToDo: add code to initialize the system
  201. * Warn: do not use global variables because this function is called before
  202. * reaching pre-main. RW section maybe overwritten afterwards.
  203. */
  204. }
  205. /**
  206. * \defgroup NMSIS_Core_IntExcNMI_Handling Interrupt and Exception and NMI Handling
  207. * \brief Functions for interrupt, exception and nmi handle available in system_<device>.c.
  208. * \details
  209. * Nuclei provide a template for interrupt, exception and NMI handling. Silicon Vendor could adapat according
  210. * to their requirement. Silicon vendor could implement interface for different exception code and
  211. * replace current implementation.
  212. *
  213. * @{
  214. */
  215. /**
  216. * \brief Exception Handler Function Typedef
  217. * \note
  218. * This typedef is only used internal in this system_<Device>.c file.
  219. * It is used to do type conversion for registered exception handler before calling it.
  220. */
  221. typedef void (*EXC_HANDLER)(unsigned long cause, unsigned long sp);
  222. typedef void (*INT_HANDLER)(unsigned long cause, unsigned long sp);
  223. /** \brief Max exception handler number, don't include the NMI(0xFFF) one */
  224. #define MAX_SYSTEM_EXCEPTION_NUM 26
  225. /**
  226. * \brief Store the exception handlers for each exception ID
  227. * \note
  228. * - This SystemExceptionHandlers are used to store all the handlers for all
  229. * the exception codes Nuclei N/NX core provided.
  230. * - Exception code 0 - MAX_SYSTEM_EXCEPTION_NUM, totally MAX_SYSTEM_EXCEPTION_NUM + 1 exceptions are mapped to SystemExceptionHandlers[0:MAX_SYSTEM_EXCEPTION_NUM]
  231. * - 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]
  232. */
  233. static unsigned long SystemExceptionHandlers[MAX_SYSTEM_EXCEPTION_NUM + 1];
  234. #if defined(__PLIC_PRESENT) && (__PLIC_PRESENT == 1)
  235. static unsigned long SystemMExtInterruptHandlers[__PLIC_INTNUM];
  236. #endif
  237. #define SYSTEM_CORE_INTNUM 16 // >=16 Designated for platform use
  238. static void system_mmode_extirq_handler(unsigned long exccode, unsigned long sp);
  239. static void core_interrupt_handler(unsigned long exccode, unsigned long sp);
  240. static unsigned long SystemCoreInterruptHandlers[SYSTEM_CORE_INTNUM];
  241. uint32_t core_exception_handler(unsigned long mcause, unsigned long sp);
  242. static INT_HANDLER system_core_interrupt_handler = NULL;
  243. // NOTE: define top of stack, it will be used as non-vector interrupt/exception stack when OS started
  244. #ifndef __ICCRISCV__
  245. // _sp is defined in linker script such as gcc_evalsoc_ilm.ld
  246. extern char _sp[];
  247. #define __TOP_OF_STACK (_sp)
  248. #else
  249. // CSTACK$$Limit is defined in iar linker script such iar_evalsoc_ilm.icf
  250. extern char CSTACK$$Limit[];
  251. #define __TOP_OF_STACK (CSTACK$$Limit)
  252. #endif
  253. /**
  254. * \brief Store the exception handlers for each exception ID in supervisor mode
  255. * \note
  256. * - This SystemExceptionHandlers_S are used to store all the handlers for all
  257. * the exception codes Nuclei N/NX core provided.
  258. * - Exception code 0 - MAX_SYSTEM_EXCEPTION_NUM, totally MAX_SYSTEM_EXCEPTION_NUM + 1 exceptions are mapped to SystemExceptionHandlers_S[0:MAX_SYSTEM_EXCEPTION_NUM]
  259. */
  260. #if (defined(__SMODE_PRESENT) && (__SMODE_PRESENT == 1))
  261. static unsigned long SystemExceptionHandlers_S[MAX_SYSTEM_EXCEPTION_NUM];
  262. static void system_default_interrupt_handler_s(unsigned long scause, unsigned long sp);
  263. static void system_smode_extirq_handler(unsigned long exccode, unsigned long sp);
  264. static void core_interrupt_handler_s(unsigned long exccode, unsigned long sp);
  265. static INT_HANDLER system_core_interrupt_handler_s = NULL;
  266. static unsigned long SystemCoreInterruptHandlers_S[SYSTEM_CORE_INTNUM];
  267. #if defined(__PLIC_PRESENT) && (__PLIC_PRESENT == 1)
  268. static unsigned long SystemSExtInterruptHandlers[__PLIC_INTNUM];
  269. #endif
  270. #endif
  271. /**
  272. * \brief Dump Exception Frame
  273. * \details
  274. * This function provided feature to dump exception frame stored in stack.
  275. * \param [in] sp stackpoint
  276. * \param [in] mode privileged mode to decide whether to dump msubm CSR
  277. */
  278. void Exception_DumpFrame(unsigned long sp, uint8_t mode)
  279. {
  280. #if defined(CODESIZE) && (CODESIZE == 1)
  281. #else
  282. EXC_Frame_Type *exc_frame = (EXC_Frame_Type *)sp;
  283. #ifndef __riscv_32e
  284. NSDK_DEBUG("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" \
  285. "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" \
  286. "cause: 0x%lx, epc: 0x%lx\n", exc_frame->ra, exc_frame->tp, exc_frame->t0, \
  287. exc_frame->t1, exc_frame->t2, exc_frame->t3, exc_frame->t4, exc_frame->t5, exc_frame->t6, \
  288. exc_frame->a0, exc_frame->a1, exc_frame->a2, exc_frame->a3, exc_frame->a4, exc_frame->a5, \
  289. exc_frame->a6, exc_frame->a7, exc_frame->cause, exc_frame->epc);
  290. #else
  291. NSDK_DEBUG("ra: 0x%lx, tp: 0x%lx, t0: 0x%lx, t1: 0x%lx, t2: 0x%lx\n" \
  292. "a0: 0x%lx, a1: 0x%lx, a2: 0x%lx, a3: 0x%lx, a4: 0x%lx, a5: 0x%lx\n" \
  293. "cause: 0x%lx, epc: 0x%lx\n", exc_frame->ra, exc_frame->tp, exc_frame->t0, \
  294. exc_frame->t1, exc_frame->t2, exc_frame->a0, exc_frame->a1, exc_frame->a2, exc_frame->a3, \
  295. exc_frame->a4, exc_frame->a5, exc_frame->cause, exc_frame->epc);
  296. #endif
  297. if (PRV_M == mode) {
  298. /* msubm is exclusive to machine mode */
  299. NSDK_DEBUG("msubm: 0x%lx\n", exc_frame->msubm);
  300. #if defined(CPU_SERIES) && CPU_SERIES == 100
  301. if (__RV_CSR_READ(CSR_MTIME) != 0 && __RV_CSR_READ(CSR_MIRGB_INFO) == 0) {
  302. NSDK_DEBUG("ERROR: you are using nuclei sdk for n100 with IRQC controller, please use nuclei n100 sdk!\n");
  303. }
  304. #endif
  305. }
  306. #endif
  307. }
  308. /**
  309. * \brief M-Mode System Default Exception Handler
  310. * \details
  311. * This function provides a default exception and NMI handler for all exception ids.
  312. * By default, It will just print some information for debug, Vendor can customize it according to its requirements.
  313. * \param [in] mcause code indicating the reason that caused the trap in machine mode
  314. * \param [in] sp stack pointer
  315. */
  316. static void system_default_exception_handler(unsigned long mcause, unsigned long sp)
  317. {
  318. #if defined(CODESIZE) && (CODESIZE == 1)
  319. #else
  320. NSDK_DEBUG("MCAUSE : 0x%lx\r\n", mcause);
  321. NSDK_DEBUG("MDCAUSE: 0x%lx\r\n", __RV_CSR_READ(CSR_MDCAUSE));
  322. NSDK_DEBUG("MEPC : 0x%lx\r\n", __RV_CSR_READ(CSR_MEPC));
  323. NSDK_DEBUG("MTVAL : 0x%lx\r\n", __RV_CSR_READ(CSR_MTVAL));
  324. NSDK_DEBUG("HARTID : %u\r\n", (unsigned int)__get_hart_id());
  325. Exception_DumpFrame(sp, PRV_M);
  326. #if defined(SIMULATION_MODE)
  327. // directly exit if in SIMULATION
  328. extern void simulation_exit(int status);
  329. simulation_exit(1);
  330. #else
  331. while (1);
  332. #endif
  333. #endif
  334. }
  335. /**
  336. * \brief M-Mode System Default Interrupt Handler for CLINT/PLIC Interrupt Mode
  337. * \details
  338. * This function provided a default interrupt handling code for all interrupt ids.
  339. */
  340. static void system_default_interrupt_handler(unsigned long mcause, unsigned long sp)
  341. {
  342. #if defined(CODESIZE) && (CODESIZE == 1)
  343. #else
  344. NSDK_DEBUG("Trap in Interrupt\r\n");
  345. NSDK_DEBUG("MCAUSE: 0x%lx\r\n", mcause);
  346. NSDK_DEBUG("MEPC : 0x%lx\r\n", __RV_CSR_READ(CSR_MEPC));
  347. NSDK_DEBUG("MTVAL : 0x%lx\r\n", __RV_CSR_READ(CSR_MTVAL));
  348. #endif
  349. }
  350. /**
  351. * \brief M-Mode Common Interrupt handler entry when in clint/plic mode
  352. * \details
  353. * This function provided a command entry for interrupt in clint/plic mode
  354. * \param [in] exccode Exception Code
  355. * \param [in] sp stack pointer
  356. * \remarks
  357. * - This is not used for clic interrupt mode, which is only used for clint/plic interrupt mode,
  358. * you should call \ref CLINT_Interrupt_Init or \ref PLIC_Interrupt_Init first to make sure this handler entry registered
  359. * - If you are not in eclic interrupt mode, please use please use \ref Interrupt_Register_CoreIRQ to register internal interrupt
  360. * and use \ref Interrupt_Register_ExtIRQ to register external interrupt
  361. */
  362. static void core_interrupt_handler(unsigned long exccode, unsigned long sp)
  363. {
  364. INT_HANDLER int_handler = NULL;
  365. int_handler = (INT_HANDLER)(SystemCoreInterruptHandlers[exccode]);
  366. if (int_handler != NULL) {
  367. int_handler(exccode, sp);
  368. }
  369. }
  370. /**
  371. * \brief M-Mode Common NMI/Exception/Interrupt handler entry
  372. * \details
  373. * This function provided a command entry for NMI and exception. Silicon Vendor could modify
  374. * this template implementation according to requirement.
  375. * \param [in] mcause code indicating the reason that caused the trap in machine mode
  376. * \param [in] sp stack pointer
  377. * \remarks
  378. * - RISCV provided common entry for all types of exception and interrupt if not in eclic mode. This is proposed code template
  379. * for exception entry function, Silicon Vendor could modify the implementation.
  380. * - For the core_exception_handler template, we provided exception register function \ref Exception_Register_EXC
  381. * which can help developer to register your exception handler for specific exception number.
  382. * - If you are in eclic interrupt mode, please use \ref ECLIC_Register_IRQ to register both internal and external interrupt
  383. * - If you are not in eclic interrupt mode, please use please use \ref Interrupt_Register_CoreIRQ to register internal interrupt
  384. * and use \ref Interrupt_Register_ExtIRQ to register external interrupt
  385. */
  386. uint32_t core_exception_handler(unsigned long mcause, unsigned long sp)
  387. {
  388. #if defined(CODESIZE) && (CODESIZE == 1)
  389. // TODO when CODESIZE macro is defined
  390. // Exception_xxx APIs will not be used, all the m-mode exception handlers
  391. // will goto this function, and you can handle it here by yourself
  392. while (1);
  393. #else
  394. unsigned long exccode = (mcause & MCAUSE_CAUSE);
  395. EXC_HANDLER exc_handler;
  396. if (mcause & MCAUSE_INTR) {
  397. if (system_core_interrupt_handler != NULL) {
  398. system_core_interrupt_handler(exccode, sp);
  399. }
  400. } else {
  401. if (exccode < MAX_SYSTEM_EXCEPTION_NUM) {
  402. exc_handler = (EXC_HANDLER)SystemExceptionHandlers[exccode];
  403. } else if (exccode == NMI_EXCn) {
  404. exc_handler = (EXC_HANDLER)SystemExceptionHandlers[MAX_SYSTEM_EXCEPTION_NUM];
  405. } else {
  406. exc_handler = (EXC_HANDLER)system_default_exception_handler;
  407. }
  408. if (exc_handler != NULL) {
  409. exc_handler(mcause, sp);
  410. }
  411. }
  412. return 0;
  413. #endif
  414. }
  415. /**
  416. * \brief M-Mode external interrupt handler common entry for plic interrupt mode
  417. * \details
  418. * This function provide common entry for m-mode external interrupt for plic interrupt mode.
  419. * \param [in] exccode exception code indicating the reason that caused the trap in machine mode
  420. * \param [in] sp stack pointer
  421. */
  422. static void system_mmode_extirq_handler(unsigned long exccode, unsigned long sp)
  423. {
  424. #if defined(__PLIC_PRESENT) && (__PLIC_PRESENT == 1)
  425. uint32_t irqn = PLIC_ClaimInterrupt();
  426. INT_HANDLER int_handler = NULL;
  427. if (irqn < __PLIC_INTNUM) {
  428. int_handler = (INT_HANDLER)(SystemMExtInterruptHandlers[irqn]);
  429. if (int_handler != NULL) {
  430. int_handler(exccode, sp);
  431. }
  432. }
  433. PLIC_CompleteInterrupt(irqn);
  434. #endif
  435. }
  436. /**
  437. * \brief Register a m-mode core interrupt handler for core interrupt number
  438. * \details
  439. * * For irqn <= SYSTEM_CORE_INTNUM, it will be registered into SystemCoreInterruptHandlers[irqn-1], only used in non-eclic mode.
  440. * \param irqn See \ref IRQn
  441. * \param int_handler The core interrupt handler for this interrupt code irqn
  442. * \remarks
  443. * You can only use it when you are not in ECLIC interrupt mode.
  444. */
  445. void Interrupt_Register_CoreIRQ(uint32_t irqn, unsigned long int_handler)
  446. {
  447. if ((irqn < SYSTEM_CORE_INTNUM) && (irqn >= 0)) {
  448. SystemCoreInterruptHandlers[irqn] = int_handler;
  449. }
  450. }
  451. /**
  452. * \brief Get a m-mode core interrupt handler for core interrupt number
  453. * \param irqn See \ref IRQn
  454. * \return
  455. * The core interrupt handler for this interrupt code irqn, only used in non-eclic mode.
  456. * \remarks
  457. * You can only use it when you are not in ECLIC interrupt mode.
  458. */
  459. unsigned long Interrupt_Get_CoreIRQ(uint32_t irqn)
  460. {
  461. if ((irqn < SYSTEM_CORE_INTNUM) && (irqn >= 0)) {
  462. return SystemCoreInterruptHandlers[irqn];
  463. }
  464. return 0;
  465. }
  466. /**
  467. * \brief Register a m-mode external interrupt handler for plic external interrupt number
  468. * \details
  469. * * For irqn <= \ref __PLIC_INTNUM, it will be registered into SystemMExtInterruptHandlers[irqn-1].
  470. * \param irqn See \ref IRQn
  471. * \param int_handler The external interrupt handler for this interrupt code irqn
  472. * \remarks
  473. * You can only use it when you are in PLIC interrupt mode.
  474. */
  475. void Interrupt_Register_ExtIRQ(uint32_t irqn, unsigned long int_handler)
  476. {
  477. #if defined(__PLIC_PRESENT) && (__PLIC_PRESENT == 1)
  478. if ((irqn < __PLIC_INTNUM) && (irqn >= 0)) {
  479. SystemMExtInterruptHandlers[irqn] = int_handler;
  480. }
  481. #endif
  482. }
  483. /**
  484. * \brief Get a m-mode external interrupt handler for external interrupt number
  485. * \param irqn See \ref IRQn
  486. * \return
  487. * The external interrupt handler for this interrupt code irqn
  488. * \remarks
  489. * You can only use it when you are in PLIC interrupt mode.
  490. */
  491. unsigned long Interrupt_Get_ExtIRQ(uint32_t irqn)
  492. {
  493. #if defined(__PLIC_PRESENT) && (__PLIC_PRESENT == 1)
  494. if ((irqn < __PLIC_INTNUM) && (irqn >= 0)) {
  495. return SystemMExtInterruptHandlers[irqn];
  496. }
  497. #endif
  498. return 0;
  499. }
  500. /**
  501. * \brief Register a m-mode exception handler for exception code EXCn
  502. * \details
  503. * - For EXCn < \ref MAX_SYSTEM_EXCEPTION_NUM, it will be registered into SystemExceptionHandlers[EXCn-1].
  504. * - For EXCn == NMI_EXCn, it will be registered into SystemExceptionHandlers[MAX_SYSTEM_EXCEPTION_NUM].
  505. * \param [in] EXCn See \ref EXCn_Type
  506. * \param [in] exc_handler The exception handler for this exception code EXCn
  507. */
  508. void Exception_Register_EXC(uint32_t EXCn, unsigned long exc_handler)
  509. {
  510. #if defined(CODESIZE) && (CODESIZE == 1)
  511. #else
  512. if (EXCn < MAX_SYSTEM_EXCEPTION_NUM) {
  513. SystemExceptionHandlers[EXCn] = exc_handler;
  514. } else if (EXCn == NMI_EXCn) {
  515. SystemExceptionHandlers[MAX_SYSTEM_EXCEPTION_NUM] = exc_handler;
  516. }
  517. #endif
  518. }
  519. /**
  520. * \brief Get current m-mode exception handler for exception code EXCn
  521. * \details
  522. * - For EXCn < \ref MAX_SYSTEM_EXCEPTION_NUM, it will return SystemExceptionHandlers[EXCn-1].
  523. * - For EXCn == NMI_EXCn, it will return SystemExceptionHandlers[MAX_SYSTEM_EXCEPTION_NUM].
  524. * \param [in] EXCn See \ref EXCn_Type
  525. * \return Current exception handler for exception code EXCn, if not found, return 0.
  526. */
  527. unsigned long Exception_Get_EXC(uint32_t EXCn)
  528. {
  529. #if defined(CODESIZE) && (CODESIZE == 1)
  530. return 0;
  531. #else
  532. if (EXCn < MAX_SYSTEM_EXCEPTION_NUM) {
  533. return SystemExceptionHandlers[EXCn];
  534. } else if (EXCn == NMI_EXCn) {
  535. return SystemExceptionHandlers[MAX_SYSTEM_EXCEPTION_NUM];
  536. } else {
  537. return 0;
  538. }
  539. #endif
  540. }
  541. /**
  542. * \brief Initialize all the default core exception handlers
  543. * \details
  544. * The core exception handler for each exception id will be initialized to \ref system_default_exception_handler.
  545. * \note
  546. * Called in \ref _init function, used to initialize default exception handlers for all exception IDs
  547. * SystemExceptionHandlers contains NMI, but SystemExceptionHandlers_S not, because NMI can't be delegated to S-mode.
  548. */
  549. static void Exception_Init(void)
  550. {
  551. #if defined(CODESIZE) && (CODESIZE == 1)
  552. // TODO when CODESIZE macro is defined
  553. // the exception handler table for m/s mode will not be initialized
  554. // since all the exception handlers will not be classified, and just
  555. // goto core_exception_handler or core_exception_handler_s for m/s exception
  556. #else
  557. for (int i = 0; i < MAX_SYSTEM_EXCEPTION_NUM; i++) {
  558. SystemExceptionHandlers[i] = (unsigned long)system_default_exception_handler;
  559. #if (defined(__SMODE_PRESENT) && (__SMODE_PRESENT == 1))
  560. SystemExceptionHandlers_S[i] = (unsigned long)system_default_exception_handler_s;
  561. #endif
  562. }
  563. SystemExceptionHandlers[MAX_SYSTEM_EXCEPTION_NUM] = (unsigned long)system_default_exception_handler;
  564. #endif
  565. // NOTE: setup mscratch csr to __TOP_OF_STACK in case of interrupt or exception stack for rtos not yet setup
  566. __RV_CSR_WRITE(CSR_MSCRATCH, (unsigned long)__TOP_OF_STACK);
  567. }
  568. #if (defined(__SMODE_PRESENT) && (__SMODE_PRESENT == 1))
  569. /**
  570. * \brief Supervisor mode system Default Exception Handler
  571. * \details
  572. * This function provided a default supervisor mode exception and NMI handling code for all exception ids.
  573. * By default, It will just print some information for debug, Vendor can customize it according to its requirements.
  574. * \param [in] scause code indicating the reason that caused the trap in supervisor mode
  575. * \param [in] sp stack pointer
  576. */
  577. static void system_default_exception_handler_s(unsigned long scause, unsigned long sp)
  578. {
  579. #if defined(CODESIZE) && (CODESIZE == 1)
  580. #else
  581. /* TODO: Uncomment this if you have implement NSDK_DEBUG function */
  582. NSDK_DEBUG("SCAUSE : 0x%lx\r\n", scause);
  583. NSDK_DEBUG("SDCAUSE: 0x%lx\r\n", __RV_CSR_READ(CSR_SDCAUSE));
  584. NSDK_DEBUG("SEPC : 0x%lx\r\n", __RV_CSR_READ(CSR_SEPC));
  585. NSDK_DEBUG("STVAL : 0x%lx\r\n", __RV_CSR_READ(CSR_STVAL));
  586. Exception_DumpFrame(sp, PRV_S);
  587. #if defined(SIMULATION_MODE)
  588. // directly exit if in SIMULATION
  589. extern void simulation_exit(int status);
  590. simulation_exit(1);
  591. #else
  592. while (1);
  593. #endif
  594. #endif
  595. }
  596. /**
  597. * \brief s-mode System Default Interrupt Handler for CLINT/PLIC Interrupt Mode
  598. * \details
  599. * This function provided a default interrupt handling code for all interrupt ids.
  600. */
  601. static void system_default_interrupt_handler_s(unsigned long scause, unsigned long sp)
  602. {
  603. #if defined(CODESIZE) && (CODESIZE == 1)
  604. #else
  605. NSDK_DEBUG("Trap in S-Mode Interrupt\r\n");
  606. NSDK_DEBUG("SCAUSE: 0x%lx\r\n", scause);
  607. NSDK_DEBUG("SEPC : 0x%lx\r\n", __RV_CSR_READ(CSR_SEPC));
  608. NSDK_DEBUG("STVAL : 0x%lx\r\n", __RV_CSR_READ(CSR_STVAL));
  609. #endif
  610. }
  611. /**
  612. * \brief S-Mode Common Interrupt handler entry when in clint/plic mode
  613. * \details
  614. * This function provided a command entry for interrupt in clint/plic mode
  615. * \param [in] exccode Exception Code
  616. * \param [in] sp stack pointer
  617. * \remarks
  618. * - This is not used for clic interrupt mode, which is only used for clint/plic interrupt mode,
  619. * you should call \ref CLINT_Interrupt_Init or \ref PLIC_Interrupt_Init first to make sure this handler entry registered
  620. * - If you are not in eclic interrupt mode, please use please use \ref Interrupt_Register_CoreIRQ to register internal interrupt
  621. * and use \ref Interrupt_Register_ExtIRQ to register external interrupt
  622. */
  623. static void core_interrupt_handler_s(unsigned long exccode, unsigned long sp)
  624. {
  625. #if defined(__SMODE_PRESENT) && (__SMODE_PRESENT == 1)
  626. INT_HANDLER int_handler = NULL;
  627. int_handler = (INT_HANDLER)(SystemCoreInterruptHandlers_S[exccode]);
  628. if (int_handler != NULL) {
  629. int_handler(exccode, sp);
  630. }
  631. #endif
  632. }
  633. /**
  634. * \brief S-Mode external interrupt handler common entry for plic interrupt mode
  635. * \details
  636. * This function provide common entry for s-mode external interrupt for plic interrupt mode.
  637. * \param [in] exccode exception code indicating the reason that caused the trap in supervisor mode
  638. * \param [in] sp stack pointer
  639. */
  640. static void system_smode_extirq_handler(unsigned long exccode, unsigned long sp)
  641. {
  642. #if defined(__PLIC_PRESENT) && (__PLIC_PRESENT == 1)
  643. uint32_t irqn = PLIC_ClaimInterrupt_S();
  644. INT_HANDLER int_handler = NULL;
  645. if (irqn < __PLIC_INTNUM) {
  646. int_handler = (INT_HANDLER)(SystemSExtInterruptHandlers[irqn]);
  647. if (int_handler != NULL) {
  648. int_handler(exccode, sp);
  649. }
  650. }
  651. PLIC_CompleteInterrupt_S(irqn);
  652. #endif
  653. }
  654. /**
  655. * \brief common Exception handler entry of supervisor mode
  656. * \details
  657. * This function provided a supervisor mode common entry for exception. Silicon Vendor could modify
  658. * this template implementation according to requirement.
  659. * \param [in] scause code indicating the reason that caused the trap in supervisor mode
  660. * \param [in] sp stack pointer
  661. * \remarks
  662. * - RISCV provided supervisor mode common entry for all types of exception. This is proposed code template
  663. * for exception entry function, Silicon Vendor could modify the implementation.
  664. * - For the core_exception_handler_s template, we provided exception register function \ref Exception_Register_EXC_S
  665. * which can help developer to register your exception handler for specific exception number.
  666. */
  667. uint32_t core_exception_handler_s(unsigned long scause, unsigned long sp)
  668. {
  669. #if defined(CODESIZE) && (CODESIZE == 1)
  670. // TODO when CODESIZE macro is defined
  671. // Exception_xxx_S APIs will not be used, all the s-mode exception handlers
  672. // will goto this function, and you can handle it here by yourself
  673. while(1);
  674. #else
  675. unsigned long exccode = (scause & SCAUSE_CAUSE);
  676. EXC_HANDLER exc_handler;
  677. if (scause & MCAUSE_INTR) {
  678. if (system_core_interrupt_handler_s != NULL) {
  679. system_core_interrupt_handler_s(exccode, sp);
  680. }
  681. } else {
  682. if (exccode < MAX_SYSTEM_EXCEPTION_NUM) {
  683. exc_handler = (EXC_HANDLER)SystemExceptionHandlers_S[exccode];
  684. } else {
  685. exc_handler = (EXC_HANDLER)system_default_exception_handler_s;
  686. }
  687. if (exc_handler != NULL) {
  688. exc_handler(scause, sp);
  689. }
  690. }
  691. return 0;
  692. #endif
  693. }
  694. /**
  695. * \brief Register an exception handler for exception code EXCn of supervisor mode
  696. * \details
  697. * -For EXCn < \ref MAX_SYSTEM_EXCEPTION_NUM, it will be registered into SystemExceptionHandlers_S[EXCn-1].
  698. * -For EXCn == NMI_EXCn, The NMI (Non-maskable-interrupt) cannot be trapped to the supervisor-mode or user-mode for any
  699. * configuration, so NMI won't be registered into SystemExceptionHandlers_S.
  700. * \param [in] EXCn See \ref EXCn_Type
  701. * \param [in] exc_handler The exception handler for this exception code EXCn
  702. */
  703. void Exception_Register_EXC_S(uint32_t EXCn, unsigned long exc_handler)
  704. {
  705. #if defined(CODESIZE) && (CODESIZE == 1)
  706. #else
  707. if (EXCn < MAX_SYSTEM_EXCEPTION_NUM) {
  708. SystemExceptionHandlers_S[EXCn] = exc_handler;
  709. }
  710. #endif
  711. }
  712. /**
  713. * \brief Get current exception handler for exception code EXCn of supervisor mode
  714. * \details
  715. * - For EXCn < \ref MAX_SYSTEM_EXCEPTION_NUM, it will return SystemExceptionHandlers_S[EXCn-1].
  716. * \param [in] EXCn See \ref EXCn_Type
  717. * \return Current exception handler for exception code EXCn, if not found, return 0.
  718. */
  719. unsigned long Exception_Get_EXC_S(uint32_t EXCn)
  720. {
  721. #if defined(CODESIZE) && (CODESIZE == 1)
  722. return 0;
  723. #else
  724. if (EXCn < MAX_SYSTEM_EXCEPTION_NUM) {
  725. return SystemExceptionHandlers_S[EXCn];
  726. } else {
  727. return 0;
  728. }
  729. #endif
  730. }
  731. /**
  732. * \brief Register an s-mode core interrupt handler for core interrupt number
  733. * \details
  734. * * For irqn <= SYSTEM_CORE_INTNUM, it will be registered into SystemCoreInterruptHandlers[irqn-1], only used in non-eclic mode.
  735. * \param irqn See \ref IRQn
  736. * \param int_handler The core interrupt handler for this interrupt code irqn
  737. * \remarks
  738. * You can only use it when you are not in ECLIC interrupt mode.
  739. */
  740. void Interrupt_Register_CoreIRQ_S(uint32_t irqn, unsigned long int_handler)
  741. {
  742. if ((irqn < SYSTEM_CORE_INTNUM) && (irqn >= 0)) {
  743. SystemCoreInterruptHandlers_S[irqn] = int_handler;
  744. }
  745. }
  746. /**
  747. * \brief Get a s-mode core interrupt handler for core interrupt number
  748. * \param irqn See \ref IRQn
  749. * \return
  750. * The core interrupt handler for this interrupt code irqn, only used in non-eclic mode.
  751. * \remarks
  752. * You can only use it when you are not in ECLIC interrupt mode.
  753. */
  754. unsigned long Interrupt_Get_CoreIRQ_S(uint32_t irqn)
  755. {
  756. if ((irqn < SYSTEM_CORE_INTNUM) && (irqn >= 0)) {
  757. return SystemCoreInterruptHandlers_S[irqn];
  758. }
  759. return 0;
  760. }
  761. /**
  762. * \brief Register an s-mode external interrupt handler for plic external interrupt number
  763. * \details
  764. * * For irqn <= \ref __PLIC_INTNUM, it will be registered into SystemSExtInterruptHandlers[irqn-1].
  765. * \param irqn See \ref IRQn
  766. * \param int_handler The external interrupt handler for this interrupt code irqn
  767. * \remarks
  768. * You can only use it when you are in PLIC interrupt mode.
  769. */
  770. void Interrupt_Register_ExtIRQ_S(uint32_t irqn, unsigned long int_handler)
  771. {
  772. #if defined(__PLIC_PRESENT) && (__PLIC_PRESENT == 1)
  773. #if defined(__SMODE_PRESENT) && (__SMODE_PRESENT == 1)
  774. if ((irqn < __PLIC_INTNUM) && (irqn >= 0)) {
  775. SystemSExtInterruptHandlers[irqn] = int_handler;
  776. }
  777. #endif
  778. #endif
  779. }
  780. /**
  781. * \brief Get an s-mode external interrupt handler for external interrupt number
  782. * \param irqn See \ref IRQn
  783. * \return
  784. * The external interrupt handler for this interrupt code irqn
  785. * \remarks
  786. * You can only use it when you are in PLIC interrupt mode.
  787. */
  788. unsigned long Interrupt_Get_ExtIRQ_S(uint32_t irqn)
  789. {
  790. #if defined(__PLIC_PRESENT) && (__PLIC_PRESENT == 1)
  791. #if defined(__SMODE_PRESENT) && (__SMODE_PRESENT == 1)
  792. if ((irqn < __PLIC_INTNUM) && (irqn >= 0)) {
  793. return SystemSExtInterruptHandlers[irqn];
  794. }
  795. #endif
  796. #endif
  797. return 0;
  798. }
  799. #endif
  800. /** @} */ /* End of Doxygen Group NMSIS_Core_ExceptionAndNMI */
  801. /** Banner Print for Nuclei SDK */
  802. void SystemBannerPrint(void)
  803. {
  804. #if defined(NUCLEI_BANNER) && (NUCLEI_BANNER == 1)
  805. NSDK_DEBUG("Nuclei SDK Build Time: %s, %s\r\n", __DATE__, __TIME__);
  806. #ifdef DOWNLOAD_MODE_STRING
  807. NSDK_DEBUG("Download Mode: %s\r\n", DOWNLOAD_MODE_STRING);
  808. #endif
  809. NSDK_DEBUG("CPU Frequency %u Hz\r\n", (unsigned int)SystemCoreClock);
  810. NSDK_DEBUG("CPU HartID: %u\r\n", (unsigned int)__get_hart_id());
  811. #endif
  812. }
  813. #if defined(__ECLIC_PRESENT) && (__ECLIC_PRESENT == 1)
  814. extern unsigned long vector_base[];
  815. extern void irq_entry(void);
  816. #endif
  817. extern void exc_entry(void);
  818. /**
  819. * \brief Do ECLIC Interrupt configuration
  820. * \details
  821. * This function will initialize cpu interrupt mode to eclic mode. It will
  822. * - set common non-vector entry to irq_entry
  823. * - set vector interrupt table to vector_base
  824. * - set exception entry to exc_entry
  825. * - set eclic mth to 0, and nlbits to the bigest bits it supports
  826. * - set s-mode common non-vector entry to irq_entry_s if s-mode present
  827. * - set s-mode vector interrupt table to vector_base_s if s-mode present
  828. * - set s-mode exception entry to exc_entry_s if s-mode present
  829. * - set eclic sth to 0 if s-mode present
  830. */
  831. void ECLIC_Interrupt_Init(void)
  832. {
  833. #if defined(__ECLIC_PRESENT) && (__ECLIC_PRESENT == 1)
  834. #if defined(CPU_SERIES) && CPU_SERIES == 100
  835. // NOTE: when CSR_MIRGB_INFO CSR exist and not zero, it means eclic and systimer present
  836. if (__RV_CSR_READ(CSR_MIRGB_INFO)) {
  837. #if defined(__SYSTIMER_PRESENT) && (__SYSTIMER_PRESENT == 1)
  838. // NOTE: Workaround to make n100 software able to run on qemu and xlmodel
  839. // TIMECMPH in n100 is zero, so we need to manually set high 32b of TIMECMP to 0
  840. SysTimer->RESERVED2 = 0;
  841. // NOTE: Workaround for Nuclei Qemu 2025.10, need to read higher 32b then it can be really clear to 0
  842. SysTimer->MTIMERCMP = SysTimer->RESERVED2;
  843. __RWMB();
  844. #endif
  845. #else
  846. unsigned long csr_val;
  847. csr_val = __RV_CSR_READ(CSR_MCFG_INFO);
  848. if (csr_val & MCFG_INFO_CLIC) {
  849. #endif
  850. /* Set ECLIC vector interrupt base address to vector_base */
  851. __RV_CSR_WRITE(CSR_MTVT, (unsigned long)vector_base);
  852. /* Set ECLIC non-vector entry to irq_entry */
  853. __RV_CSR_WRITE(CSR_MTVT2, (unsigned long)irq_entry | 0x1);
  854. /* Set as CLIC interrupt mode */
  855. __RV_CSR_WRITE(CSR_MTVEC, (unsigned long)exc_entry | 0x3);
  856. /* Global Configuration about MTH and NLBits.
  857. * TODO: Please adapt it according to your system requirement.
  858. * This function is called in _init function */
  859. ECLIC_SetMth(0);
  860. ECLIC_SetCfgNlbits(__ECLIC_INTCTLBITS);
  861. #if defined(ECLIC_HW_CTX_AUTO) && defined(CFG_HAS_ECLICV2)
  862. __RV_CSR_WRITE(CSR_MTSP, (unsigned long)__TOP_OF_STACK);
  863. /* Enable Hardware Auto Save Context */
  864. __RV_CSR_SET(CSR_MMISC_CTL, MMISC_CTL_HW_AUTO_CONTEXT);
  865. /* Enable ECLIC Hardware Acceleration */
  866. /* Enable Interrupt and Exception Auto Save, and Shadow GPR, dont swap stack */
  867. __RV_CSR_WRITE(CSR_MECLIC_CTL, MECLIC_CTL_SHADOW_EN);
  868. #endif
  869. #if defined(__SMODE_PRESENT) && (__SMODE_PRESENT == 1)
  870. #if defined(CPU_SERIES) && CPU_SERIES == 100
  871. #else
  872. csr_val = __RV_CSR_READ(CSR_MISA);
  873. if (csr_val & (1 << 18)) { // Check whether supervisor mode implemented
  874. /*
  875. * Intialize ECLIC supervisor mode vector interrupt
  876. * base address stvt to vector_table_s
  877. */
  878. __RV_CSR_WRITE(CSR_STVT, (unsigned long)vector_table_s);
  879. /*
  880. * Set ECLIC supervisor mode non-vector entry to be controlled
  881. * by stvt2 CSR register.
  882. * Intialize supervisor mode ECLIC non-vector interrupt
  883. * base address stvt2 to irq_entry_s.
  884. */
  885. __RV_CSR_WRITE(CSR_STVT2, (unsigned long)irq_entry_s);
  886. __RV_CSR_SET(CSR_STVT2, 0x01);
  887. /*
  888. * Set supervisor exception entry stvec to exc_entry_s */
  889. __RV_CSR_WRITE(CSR_STVEC, (unsigned long)exc_entry_s);
  890. /* Global Configuration about STH */
  891. ECLIC_SetSth(0);
  892. #if defined(ECLIC_HW_CTX_AUTO) && defined(CFG_HAS_ECLICV2)
  893. // NOTE: CSR_STSP is not yet set, please setup by yourself to your S-Mode stack pointer
  894. /* Enable Interrupt and Exception Auto Save, and Shadow GPR, dont swap stack for S-Mode */
  895. __RV_CSR_WRITE(CSR_SECLIC_CTL, SECLIC_CTL_SHADOW_EN);
  896. #endif
  897. }
  898. #endif
  899. #endif
  900. } else {
  901. /* Set as CLINT interrupt mode */
  902. __RV_CSR_WRITE(CSR_MTVEC, (unsigned long)exc_entry);
  903. }
  904. #endif
  905. }
  906. /**
  907. * \brief Do CLINT Interrupt configuration
  908. * \details
  909. * This function will initialize cpu interrupt mode to clint mode. It will
  910. * - Set exception/interrupt entry to exc_entry, now interrupt and exception share the same entry point
  911. * - Register interrupt handling routine system_core_interrupt_handler to core_interrupt_handler function,
  912. * which will be called in core_exception_handler function
  913. */
  914. void CLINT_Interrupt_Init(void)
  915. {
  916. /* Register core interrupt handler for clint/plic interrupt mode */
  917. system_core_interrupt_handler = core_interrupt_handler;
  918. /* Set as CLINT interrupt mode */
  919. __RV_CSR_WRITE(CSR_MTVEC, (unsigned long)exc_entry);
  920. #if defined(__SMODE_PRESENT) && (__SMODE_PRESENT == 1)
  921. /*
  922. * Set supervisor exception entry stvec to exc_entry_s
  923. */
  924. __RV_CSR_WRITE(CSR_STVEC, (unsigned long)exc_entry_s);
  925. system_core_interrupt_handler_s = core_interrupt_handler_s;
  926. #endif
  927. for (int i = 0; i < SYSTEM_CORE_INTNUM; i++) {
  928. SystemCoreInterruptHandlers[i] = (unsigned long)system_default_interrupt_handler;
  929. #if defined(__SMODE_PRESENT) && (__SMODE_PRESENT == 1)
  930. SystemCoreInterruptHandlers_S[i] = (unsigned long)system_default_interrupt_handler_s;
  931. #endif
  932. }
  933. }
  934. /**
  935. * \brief Do PLIC Interrupt configuration
  936. * \details
  937. * This function will initialize cpu interrupt mode to clint/plic mode. It will
  938. * - Initialize a software maintained SystemM/SExtInterruptHandlers and SystemCoreInterruptHandlers to default value
  939. * - Set exception/interrupt entry to exc_entry, now interrupt and exception share the same entry point
  940. */
  941. void PLIC_Interrupt_Init(void)
  942. {
  943. CLINT_Interrupt_Init();
  944. #if defined(__PLIC_PRESENT) && (__PLIC_PRESENT == 1)
  945. int i;
  946. for (i = 0; i < __PLIC_INTNUM; i++) {
  947. SystemMExtInterruptHandlers[i] = (unsigned long)system_default_interrupt_handler;
  948. #if defined(__SMODE_PRESENT) && (__SMODE_PRESENT == 1)
  949. SystemSExtInterruptHandlers[i] = (unsigned long)system_default_interrupt_handler_s;
  950. #endif
  951. }
  952. SystemCoreInterruptHandlers[9] = (unsigned long)system_mmode_extirq_handler;
  953. SystemCoreInterruptHandlers[11] = (unsigned long)system_mmode_extirq_handler;
  954. #if defined(__SMODE_PRESENT) && (__SMODE_PRESENT == 1)
  955. SystemCoreInterruptHandlers_S[9] = (unsigned long)system_smode_extirq_handler;
  956. SystemCoreInterruptHandlers_S[11] = (unsigned long)system_smode_extirq_handler;
  957. #endif
  958. #endif
  959. }
  960. /**
  961. * \brief initialize interrupt controller
  962. * \details
  963. * Do CPU interrupt initialization, if plic present, init it, then init eclic if present.
  964. * So if ECLIC present, the interrupt will default configured to ECLIC interrupt mode,
  965. * if you want to switch to PLIC interrupt mode, you need to call PLIC_Interrupt_Init in
  966. * you application code.
  967. *
  968. * By default, if ECLIC present, eclic interrupt mode will be set, otherwise it will be
  969. * clint/plic interrupt mode
  970. * \remarks
  971. * This function previously was ECLIC_Init, now ECLIC_Init is removed
  972. */
  973. void Interrupt_Init(void)
  974. {
  975. #if defined(CODESIZE) && (CODESIZE == 1)
  976. #else
  977. /* Set as CLINT interrupt mode */
  978. __RV_CSR_WRITE(CSR_MTVEC, (unsigned long)exc_entry);
  979. /* Init interrupt as eclic mode when ECLIC present
  980. * Otherwise will init interrupt as plic mode when PLIC present
  981. * Only initialize necessary ones to reduce initialization code size usage */
  982. #if defined(__ECLIC_PRESENT) && (__ECLIC_PRESENT == 1)
  983. ECLIC_Interrupt_Init();
  984. #elif defined(__PLIC_PRESENT) && (__PLIC_PRESENT == 1)
  985. PLIC_Interrupt_Init();
  986. #endif
  987. #endif
  988. }
  989. #if defined(__ECLIC_PRESENT) && (__ECLIC_PRESENT == 1)
  990. /**
  991. * \brief Initialize a specific IRQ and register the handler
  992. * \details
  993. * This function set vector mode, trigger mode and polarity, interrupt level and priority,
  994. * assign handler for specific IRQn.
  995. * \param [in] IRQn NMI interrupt handler address
  996. * \param [in] shv \ref ECLIC_NON_VECTOR_INTERRUPT means non-vector mode, and \ref ECLIC_VECTOR_INTERRUPT is vector mode
  997. * \param [in] trig_mode see \ref ECLIC_TRIGGER_Type
  998. * \param [in] lvl interupt level
  999. * \param [in] priority interrupt priority
  1000. * \param [in] handler interrupt handler, if NULL, handler will not be installed
  1001. * \return -1 means invalid input parameter. 0 means successful.
  1002. * \remarks
  1003. * - This function use to configure specific eclic interrupt and register its interrupt handler and enable its interrupt.
  1004. * - If the vector table is placed in read-only section(FLASHXIP mode), handler could not be installed
  1005. */
  1006. int32_t ECLIC_Register_IRQ(IRQn_Type IRQn, uint8_t shv, ECLIC_TRIGGER_Type trig_mode, uint8_t lvl, uint8_t priority, void* handler)
  1007. {
  1008. if ((IRQn > SOC_INT_MAX) || (shv > ECLIC_VECTOR_INTERRUPT) \
  1009. || (trig_mode > ECLIC_NEGTIVE_EDGE_TRIGGER)) {
  1010. return -1;
  1011. }
  1012. /* set interrupt vector mode */
  1013. ECLIC_SetShvIRQ(IRQn, shv);
  1014. /* set interrupt trigger mode and polarity */
  1015. ECLIC_SetTrigIRQ(IRQn, trig_mode);
  1016. /* set interrupt level */
  1017. ECLIC_SetLevelIRQ(IRQn, lvl);
  1018. /* set interrupt priority */
  1019. ECLIC_SetPriorityIRQ(IRQn, priority);
  1020. if (handler != NULL) {
  1021. /* set interrupt handler entry to vector table */
  1022. ECLIC_SetVector(IRQn, (rv_csr_t)handler);
  1023. }
  1024. /* enable interrupt */
  1025. ECLIC_EnableIRQ(IRQn);
  1026. return 0;
  1027. }
  1028. #endif
  1029. /**
  1030. * \brief Register a m-mode riscv core interrupt and register the handler
  1031. * \details
  1032. * This function set interrupt handler for core interrupt in non-eclic mode
  1033. * \param [in] irqn interrupt number
  1034. * \param [in] handler interrupt handler, if NULL, handler will not be installed
  1035. * \return -1 means invalid input parameter. 0 means successful.
  1036. * \remarks
  1037. * - This function use to configure riscv core interrupt and register its interrupt handler and enable its interrupt.
  1038. * - You can only use it when you are not in eclic interrupt mode
  1039. */
  1040. int32_t Core_Register_IRQ(uint32_t irqn, void *handler)
  1041. {
  1042. if ((irqn > SYSTEM_CORE_INTNUM)) {
  1043. return -1;
  1044. }
  1045. if (handler != NULL) {
  1046. /* register interrupt handler entry to core handlers */
  1047. Interrupt_Register_CoreIRQ(irqn, (unsigned long)handler);
  1048. }
  1049. switch (irqn) {
  1050. case SysTimerSW_IRQn:
  1051. __enable_sw_irq();
  1052. break;
  1053. case SysTimer_IRQn:
  1054. __enable_timer_irq();
  1055. break;
  1056. default:
  1057. break;
  1058. }
  1059. return 0;
  1060. }
  1061. #if defined(__SMODE_PRESENT) && (__SMODE_PRESENT == 1)
  1062. /**
  1063. * \brief Register a riscv s-mode core interrupt and register the handler
  1064. * \details
  1065. * This function set interrupt handler for core interrupt in non-eclic mode
  1066. * \param [in] irqn interrupt number
  1067. * \param [in] handler interrupt handler, if NULL, handler will not be installed
  1068. * \return -1 means invalid input parameter. 0 means successful.
  1069. * \remarks
  1070. * - This function use to configure riscv core interrupt and register its interrupt handler and enable its interrupt.
  1071. * - You can only use it when you are not in eclic interrupt mode
  1072. */
  1073. int32_t Core_Register_IRQ_S(uint32_t irqn, void *handler)
  1074. {
  1075. if ((irqn > SYSTEM_CORE_INTNUM)) {
  1076. return -1;
  1077. }
  1078. if (handler != NULL) {
  1079. /* register interrupt handler entry to core handlers */
  1080. Interrupt_Register_CoreIRQ_S(irqn, (unsigned long)handler);
  1081. }
  1082. switch (irqn) {
  1083. case SysTimerSW_S_IRQn:
  1084. __enable_sw_irq_s();
  1085. break;
  1086. case SysTimer_S_IRQn:
  1087. __enable_timer_irq_s();
  1088. break;
  1089. default:
  1090. break;
  1091. }
  1092. return 0;
  1093. }
  1094. #endif
  1095. #if defined(__PLIC_PRESENT) && (__PLIC_PRESENT == 1)
  1096. /**
  1097. * \brief Register a m-mode specific plic interrupt and register the handler
  1098. * \details
  1099. * This function set priority and handler for m-mode plic interrupt
  1100. * \param [in] source interrupt source
  1101. * \param [in] priority interrupt priority
  1102. * \param [in] handler interrupt handler, if NULL, handler will not be installed
  1103. * \return -1 means invalid input parameter. 0 means successful.
  1104. * \remarks
  1105. * - This function use to configure specific plic interrupt and register its interrupt handler and enable its interrupt.
  1106. * - You can only use it when you are in plic interrupt mode
  1107. */
  1108. int32_t PLIC_Register_IRQ(uint32_t source, uint8_t priority, void *handler)
  1109. {
  1110. if ((source >= __PLIC_INTNUM)) {
  1111. return -1;
  1112. }
  1113. /* set interrupt priority */
  1114. PLIC_SetPriority(source, priority);
  1115. if (handler != NULL) {
  1116. /* register interrupt handler entry to external handlers */
  1117. Interrupt_Register_ExtIRQ(source, (unsigned long)handler);
  1118. }
  1119. /* enable interrupt */
  1120. PLIC_EnableInterrupt(source);
  1121. __enable_ext_irq();
  1122. return 0;
  1123. }
  1124. #if defined(__SMODE_PRESENT) && (__SMODE_PRESENT == 1)
  1125. /**
  1126. * \brief Register a s-mode specific plic interrupt and register the handler
  1127. * \details
  1128. * This function set priority and handler for s-mode plic interrupt
  1129. * \param [in] source interrupt source
  1130. * \param [in] priority interrupt priority
  1131. * \param [in] handler interrupt handler, if NULL, handler will not be installed
  1132. * \return -1 means invalid input parameter. 0 means successful.
  1133. * \remarks
  1134. * - This function use to configure specific plic interrupt and register its interrupt handler and enable its interrupt.
  1135. * - You can only use it when you are in plic interrupt mode
  1136. */
  1137. int32_t PLIC_Register_IRQ_S(uint32_t source, uint8_t priority, void *handler)
  1138. {
  1139. if ((source >= __PLIC_INTNUM)) {
  1140. return -1;
  1141. }
  1142. /* set interrupt priority */
  1143. PLIC_SetPriority(source, priority);
  1144. if (handler != NULL) {
  1145. /* register interrupt handler entry to external handlers */
  1146. Interrupt_Register_ExtIRQ_S(source, (unsigned long)handler);
  1147. }
  1148. /* enable interrupt */
  1149. PLIC_EnableInterrupt_S(source);
  1150. __enable_ext_irq_s();
  1151. return 0;
  1152. }
  1153. #endif
  1154. #endif
  1155. #if defined(__SMODE_PRESENT) && (__SMODE_PRESENT == 1)
  1156. #if defined(__ECLIC_PRESENT) && (__ECLIC_PRESENT == 1)
  1157. /**
  1158. * \brief Initialize a specific IRQ and register the handler for supervisor mode
  1159. * \details
  1160. * This function set vector mode, trigger mode and polarity, interrupt level and priority,
  1161. * assign handler for specific IRQn.
  1162. * \param [in] IRQn NMI interrupt handler address
  1163. * \param [in] shv \ref ECLIC_NON_VECTOR_INTERRUPT means non-vector mode, and \ref ECLIC_VECTOR_INTERRUPT is vector mode
  1164. * \param [in] trig_mode see \ref ECLIC_TRIGGER_Type
  1165. * \param [in] lvl interupt level
  1166. * \param [in] priority interrupt priority
  1167. * \param [in] handler interrupt handler, if NULL, handler will not be installed
  1168. * \return -1 means invalid input parameter. 0 means successful.
  1169. * \remarks
  1170. * - This function use to configure specific eclic S-mode interrupt and register its interrupt handler and enable its interrupt.
  1171. * - If the vector table is placed in read-only section (FLASHXIP mode), handler could not be installed.
  1172. */
  1173. 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)
  1174. {
  1175. if ((IRQn > SOC_INT_MAX) || (shv > ECLIC_VECTOR_INTERRUPT) \
  1176. || (trig_mode > ECLIC_NEGTIVE_EDGE_TRIGGER)) {
  1177. return -1;
  1178. }
  1179. /* set interrupt vector mode */
  1180. ECLIC_SetShvIRQ_S(IRQn, shv);
  1181. /* set interrupt trigger mode and polarity */
  1182. ECLIC_SetTrigIRQ_S(IRQn, trig_mode);
  1183. /* set interrupt level */
  1184. ECLIC_SetLevelIRQ_S(IRQn, lvl);
  1185. /* set interrupt priority */
  1186. ECLIC_SetPriorityIRQ_S(IRQn, priority);
  1187. if (handler != NULL) {
  1188. /* set interrupt handler entry to vector table */
  1189. ECLIC_SetVector_S(IRQn, (rv_csr_t)handler);
  1190. }
  1191. /* enable interrupt */
  1192. ECLIC_EnableIRQ_S(IRQn);
  1193. return 0;
  1194. }
  1195. #endif
  1196. #endif
  1197. // NOTE: FALLBACK_DEFAULT_ECLIC_BASE/FALLBACK_DEFAULT_SYSTIMER_BASE macros are removed
  1198. // No longer support for cpu without iregion feature
  1199. #ifndef CFG_IREGION_BASE_ADDR
  1200. /** 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 */
  1201. volatile unsigned long CpuIRegionBase = 0xFFFFFFFF;
  1202. #endif
  1203. #define CLINT_MSIP(base, hartid) (*(volatile uint32_t *)((uintptr_t)((base) + ((hartid) * 4))))
  1204. #define SMP_CTRLREG(base, ofs) (*(volatile uint32_t *)((uintptr_t)((base) + (ofs))))
  1205. #define MAX_SYNC_HARTS_WAITCNT 10000
  1206. void __sync_harts(void) __attribute__((section(".text.init")));
  1207. /**
  1208. * \brief Synchronize all harts
  1209. * \details
  1210. * This function is used to synchronize all the harts,
  1211. * especially to wait the boot hart finish initialization of
  1212. * data section, bss section and c runtines initialization
  1213. * This function must be placed in .text.init section, since
  1214. * section initialization is not ready, global variable
  1215. * and static variable should be avoid to use in this function,
  1216. * and avoid to call other functions
  1217. */
  1218. void __sync_harts(void)
  1219. {
  1220. // Only do synchronize when SMP_CPU_CNT is defined and number > 0
  1221. // TODO: If you don't need to support SMP, you can directly remove code in it
  1222. #if defined(SMP_CPU_CNT) && (SMP_CPU_CNT > 1)
  1223. unsigned long hartid = __get_hart_id();
  1224. unsigned long tmr_hartid = __get_hart_index();
  1225. unsigned long clint_base, irgb_base, smp_base;
  1226. unsigned long mcfg_info;
  1227. volatile unsigned long cnt = 0;
  1228. // NOTE: we should avoid to use global variable such as CpuIRegionBase before smp cpu are configured
  1229. mcfg_info = __RV_CSR_READ(CSR_MCFG_INFO);
  1230. // Assume IREGION feature present
  1231. if (mcfg_info & MCFG_INFO_IREGION_EXIST) { // IRegion Info present
  1232. // clint base = system timer base + 0x1000
  1233. irgb_base = (__RV_CSR_READ(CSR_MIRGB_INFO) >> 10) << 10;
  1234. clint_base = irgb_base + IREGION_TIMER_OFS + 0x1000;
  1235. smp_base = irgb_base + IREGION_SMP_OFS;
  1236. } else {
  1237. // Should not enter to here if iregion feature present
  1238. while(1);
  1239. }
  1240. // pre-condition: interrupt must be disabled, this is done before calling this function
  1241. // BOOT_HARTID is defined <Device.h>
  1242. if (hartid == BOOT_HARTID) { // boot hart
  1243. // Enable L2, disable cluster local memory
  1244. if (SMP_CTRLREG(smp_base, 0x4) & 0x1) {
  1245. SMP_CTRLREG(smp_base, 0x10) |= 0x1;
  1246. SMP_CTRLREG(smp_base, 0xd8) = 0x0;
  1247. }
  1248. // Enable SMP
  1249. SMP_CTRLREG(smp_base, 0xc) = 0xFFFFFFFF;
  1250. __SMP_RWMB();
  1251. // L1 I/D Cache Enable is done in _premain_init
  1252. // clear msip pending
  1253. for (int i = 0; i < SMP_CPU_CNT; i ++) {
  1254. // NOTE: Here you must make sure other harts are bringup, otherwise main
  1255. // hart will wait it here, so banner will be print
  1256. cnt = 0;
  1257. if (i != hartid) { // wait for other harts software pending bit set
  1258. do {
  1259. cnt += 1;
  1260. if (cnt > MAX_SYNC_HARTS_WAITCNT) {
  1261. __NOP();
  1262. break;
  1263. }
  1264. } while (CLINT_MSIP(clint_base, i) == 0);
  1265. }
  1266. CLINT_MSIP(clint_base, i) = 0;
  1267. }
  1268. __SMP_RWMB();
  1269. } else {
  1270. // Set machine software interrupt pending to 1
  1271. CLINT_MSIP(clint_base, tmr_hartid) = 1;
  1272. __SMP_RWMB();
  1273. // wait for pending bit cleared by boot hart
  1274. while (CLINT_MSIP(clint_base, tmr_hartid) == 1);
  1275. }
  1276. #endif
  1277. }
  1278. /**
  1279. * \brief do the init for trap
  1280. * \details
  1281. */
  1282. static void Trap_Init(void)
  1283. {
  1284. }
  1285. /**
  1286. * \brief Get system clock frequency
  1287. * \details Determines the system clock frequency by checking if performance counters are available.
  1288. * If the mcycle CSR is zero (indicating performance counters are not implemented),
  1289. * it returns the default SYSTEM_CLOCK macro value. Otherwise, it returns the CPU frequency
  1290. * obtained from get_cpu_freq() implemented in evalsoc_common.c.
  1291. * \return System clock frequency in Hz
  1292. */
  1293. static uint32_t get_system_clock(void)
  1294. {
  1295. if (__RV_CSR_READ(CSR_MCYCLE) == 0) {
  1296. return SYSTEM_CLOCK;
  1297. }
  1298. return get_cpu_freq();
  1299. }
  1300. /**
  1301. * \brief early init function before main
  1302. * \details
  1303. * This function is executed right before main function.
  1304. * For RISC-V gnu toolchain, _init function might not be called
  1305. * by __libc_init_array function, so we defined a new function
  1306. * to do initialization.
  1307. */
  1308. void _premain_init(void)
  1309. {
  1310. #if defined(CODESIZE) && (CODESIZE == 1)
  1311. // TODO to reduce the code size of application
  1312. // No need to do so complex premain initialization steps
  1313. // You just need to initialize the cpu resource you need to use in your
  1314. // application code.
  1315. #ifndef CFG_IREGION_BASE_ADDR // Need to probe the cpu iregion base address
  1316. // Probe CPUIRegionBase for other cpu internal peripheral to use
  1317. CpuIRegionBase = (__RV_CSR_READ(CSR_MIRGB_INFO) >> 10) << 10;
  1318. #endif
  1319. // TODO Still need to initialize uart for other code need to do printf
  1320. // If you want to reduce more code, you can comment below code
  1321. uart_init(SOC_DEBUG_UART, 115200);
  1322. #else
  1323. // TODO to make it possible for configurable boot hartid
  1324. unsigned long hartid = __get_hart_id();
  1325. #if defined(CPU_SERIES) && CPU_SERIES == 100
  1326. #ifndef CFG_IREGION_BASE_ADDR // Need to probe the cpu iregion base address
  1327. if (hartid == BOOT_HARTID) { // only done in boot hart
  1328. // IREGION INFO MUST BE AFTER L1/L2 Cache enabled and SMP enabled if SMP present
  1329. CpuIRegionBase = (__RV_CSR_READ(CSR_MIRGB_INFO) >> 10) << 10;
  1330. } else {
  1331. // wait for correct iregion base addr is set by boot hart
  1332. while (CpuIRegionBase == 0xFFFFFFFF);
  1333. }
  1334. #endif
  1335. #else
  1336. unsigned long mcfginfo = __RV_CSR_READ(CSR_MCFG_INFO);
  1337. /* TODO: Add your own initialization code here, called before main */
  1338. // TODO This code controlled by macros RUNMODE_* are only used internally by Nuclei
  1339. // You can remove it if you don't want it
  1340. // No need to use in your code
  1341. #if defined(RUNMODE_ILM_EN) || defined(RUNMODE_ECC_EN)
  1342. // Only disable ilm when it is present
  1343. if (mcfginfo & MCFG_INFO_ILM) {
  1344. #if defined(RUNMODE_ECC_EN)
  1345. #if RUNMODE_ECC_EN == 0
  1346. __RV_CSR_CLEAR(CSR_MILM_CTL, MILM_CTL_ILM_ECC_EN | MILM_CTL_ILM_ECC_EXCP_EN | MILM_CTL_ILM_ECC_CHK_EN);
  1347. #else
  1348. __RV_CSR_SET(CSR_MILM_CTL, MILM_CTL_ILM_ECC_EN | MILM_CTL_ILM_ECC_EXCP_EN | MILM_CTL_ILM_ECC_CHK_EN);
  1349. #endif
  1350. #endif
  1351. #if defined(RUNMODE_ILM_EN)
  1352. #if RUNMODE_ILM_EN == 0
  1353. __RV_CSR_CLEAR(CSR_MILM_CTL, MILM_CTL_ILM_EN);
  1354. #else
  1355. __RV_CSR_SET(CSR_MILM_CTL, MILM_CTL_ILM_EN);
  1356. #endif
  1357. #endif
  1358. }
  1359. #endif
  1360. #if defined(RUNMODE_DLM_EN) || defined(RUNMODE_ECC_EN)
  1361. // Only disable dlm when it is present
  1362. if (mcfginfo & MCFG_INFO_DLM) {
  1363. #if defined(RUNMODE_ECC_EN)
  1364. #if RUNMODE_ECC_EN == 0
  1365. __RV_CSR_CLEAR(CSR_MDLM_CTL, MDLM_CTL_DLM_ECC_EN | MDLM_CTL_DLM_ECC_EXCP_EN | MDLM_CTL_DLM_ECC_CHK_EN);
  1366. #else
  1367. __RV_CSR_SET(CSR_MDLM_CTL, MDLM_CTL_DLM_ECC_EN | MDLM_CTL_DLM_ECC_EXCP_EN | MDLM_CTL_DLM_ECC_CHK_EN);
  1368. #endif
  1369. #endif
  1370. #if defined(RUNMODE_DLM_EN)
  1371. #if RUNMODE_DLM_EN == 0
  1372. __RV_CSR_CLEAR(CSR_MDLM_CTL, MDLM_CTL_DLM_EN);
  1373. #else
  1374. __RV_CSR_SET(CSR_MDLM_CTL, MDLM_CTL_DLM_EN);
  1375. #endif
  1376. #endif
  1377. }
  1378. #endif
  1379. #if defined(RUNMODE_LDSPEC_EN)
  1380. #if RUNMODE_LDSPEC_EN == 1
  1381. __RV_CSR_SET(CSR_MMISC_CTL, MMISC_CTL_LDSPEC_ENABLE);
  1382. #else
  1383. __RV_CSR_CLEAR(CSR_MMISC_CTL, MMISC_CTL_LDSPEC_ENABLE);
  1384. #endif
  1385. #endif
  1386. /* __ICACHE_PRESENT and __DCACHE_PRESENT are defined in evalsoc.h */
  1387. // For our internal cpu testing, they want to set evalsoc __ICACHE_PRESENT/__DCACHE_PRESENT to be 1
  1388. // __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
  1389. // but in the cpu, icache or dcache might not exist due to cpu configuration, so here
  1390. // we need to check whether icache/dcache really exist, if yes, then turn on it
  1391. #if defined(__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1)
  1392. if (ICachePresent()) { // Check whether icache real present or not
  1393. #if defined(RUNMODE_ECC_EN)
  1394. #if RUNMODE_ECC_EN == 0
  1395. __RV_CSR_CLEAR(CSR_MCACHE_CTL, MCACHE_CTL_IC_ECC_EN | MCACHE_CTL_IC_ECC_EXCP_EN | MCACHE_CTL_IC_ECC_CHK_EN);
  1396. #else
  1397. __RV_CSR_SET(CSR_MCACHE_CTL, MCACHE_CTL_IC_ECC_EN | MCACHE_CTL_IC_ECC_EXCP_EN | MCACHE_CTL_IC_ECC_CHK_EN);
  1398. #endif
  1399. #endif
  1400. EnableICache();
  1401. // Enable canceling previous accesses in icache e1 stage when change flow happens
  1402. __RV_CSR_SET(CSR_MCACHE_CTL, MCACHE_CTL_IC_PF_EN);
  1403. }
  1404. #endif
  1405. #if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1)
  1406. if (DCachePresent()) { // Check whether dcache real present or not
  1407. #if defined(RUNMODE_ECC_EN)
  1408. #if RUNMODE_ECC_EN == 0
  1409. __RV_CSR_CLEAR(CSR_MCACHE_CTL, MCACHE_CTL_DC_ECC_EN | MCACHE_CTL_DC_ECC_EXCP_EN | MCACHE_CTL_DC_ECC_CHK_EN);
  1410. #else
  1411. __RV_CSR_SET(CSR_MCACHE_CTL, MCACHE_CTL_DC_ECC_EN | MCACHE_CTL_DC_ECC_EXCP_EN | MCACHE_CTL_DC_ECC_CHK_EN);
  1412. #endif
  1413. #endif
  1414. EnableDCache();
  1415. }
  1416. #endif
  1417. /* Do fence and fence.i to make sure previous ilm/dlm/icache/dcache control done */
  1418. __RWMB();
  1419. __FENCE_I();
  1420. // BOOT_HARTID is defined <Device.h> and also controlled by BOOT_HARTID in conf/evalsoc/build.mk
  1421. #ifndef CFG_IREGION_BASE_ADDR // Need to probe the cpu iregion base address
  1422. if (hartid == BOOT_HARTID) { // only done in boot hart
  1423. // IREGION INFO MUST BE AFTER L1/L2 Cache enabled and SMP enabled if SMP present
  1424. CpuIRegionBase = (__RV_CSR_READ(CSR_MIRGB_INFO) >> 10) << 10;
  1425. } else {
  1426. // wait for correct iregion base addr is set by boot hart
  1427. while (CpuIRegionBase == 0xFFFFFFFF);
  1428. }
  1429. #endif
  1430. if ( (hartid == BOOT_HARTID) && ((mcfginfo & (0x1 << 11)) && (SMP_CTRLREG(__SMPCC_BASEADDR, 0x4) & 0x1)) ) { // L2 Cache present
  1431. // NOTE: Enable L2 Cache by default when L2 Cache Present
  1432. #if !(defined(RUNMODE_L2_EN) && RUNMODE_L2_EN == 0)
  1433. // Enable L2, disable cluster local memory
  1434. SMP_CTRLREG(__SMPCC_BASEADDR, 0x10) |= 0x1;
  1435. SMP_CTRLREG(__SMPCC_BASEADDR, 0xd8) = 0x0;
  1436. __SMP_RWMB();
  1437. #else
  1438. // Disable L2, enable cluster local memory
  1439. SMP_CTRLREG(__SMPCC_BASEADDR, 0x10) &= ~0x1;
  1440. // use as clm or cache, when l2 disable, the affect to ddr is the same, l2 is really disabled
  1441. SMP_CTRLREG(__SMPCC_BASEADDR, 0xd8) = 0;//0xFFFFFFFF;
  1442. __SMP_RWMB();
  1443. #endif
  1444. }
  1445. /* Enable prefetch overall */
  1446. IINFO_EnablePrefetchOverall();
  1447. #if defined(RUNMODE_BPU_EN)
  1448. #if RUNMODE_BPU_EN == 1
  1449. __RV_CSR_SET(CSR_MMISC_CTL, MMISC_CTL_BPU);
  1450. #else
  1451. __RV_CSR_CLEAR(CSR_MMISC_CTL, MMISC_CTL_BPU);
  1452. #endif
  1453. #endif
  1454. #if defined(__CCM_PRESENT) && (__CCM_PRESENT == 1)
  1455. // NOTE: CFG_HAS_SMODE and CFG_HAS_UMODE are defined in auto generated cpufeature.h if present in cpu
  1456. #if defined(CFG_HAS_SMODE) || defined(CFG_HAS_UMODE)
  1457. EnableSUCCM();
  1458. #endif
  1459. #endif
  1460. #endif
  1461. if (hartid == BOOT_HARTID) { // only required for boot hartid
  1462. // TODO implement system_system_clock function to get real cpu clock freq in HZ or directly give the real cpu HZ
  1463. // TODO you can directly give the correct cpu frequency here, if you know it without call get_cpu_freq function
  1464. SystemCoreClock = get_system_clock();
  1465. uart_init(SOC_DEBUG_UART, 115200);
  1466. /* Display banner after UART initialized */
  1467. SystemBannerPrint();
  1468. /* Initialize exception default handlers */
  1469. Exception_Init();
  1470. /* Interrupt initialization */
  1471. Interrupt_Init();
  1472. // TODO: internal usage for Nuclei
  1473. #ifdef RUNMODE_CONTROL
  1474. NSDK_DEBUG("Current RUNMODE=%s, ilm:%d, dlm %d, icache %d, dcache %d, ccm %d\n", \
  1475. RUNMODE_STRING, RUNMODE_ILM_EN, RUNMODE_DLM_EN, \
  1476. RUNMODE_IC_EN, RUNMODE_DC_EN, RUNMODE_CCM_EN);
  1477. // ILM and DLM need to be present
  1478. if (mcfginfo & 0x180 == 0x180) {
  1479. NSDK_DEBUG("CSR: MILM_CTL 0x%x, MDLM_CTL 0x%x\n", \
  1480. __RV_CSR_READ(CSR_MILM_CTL), __RV_CSR_READ(CSR_MDLM_CTL));
  1481. }
  1482. // I/D cache need to be present
  1483. if (mcfginfo & 0x600) {
  1484. NSDK_DEBUG("CSR: MCACHE_CTL 0x%x\n", __RV_CSR_READ(CSR_MCACHE_CTL));
  1485. }
  1486. NSDK_DEBUG("CSR: MMISC_CTL 0x%x\n", __RV_CSR_READ(CSR_MMISC_CTL));
  1487. #endif
  1488. } else {
  1489. /* Interrupt initialization */
  1490. Interrupt_Init();
  1491. }
  1492. #endif
  1493. }
  1494. /**
  1495. * \brief finish function after main
  1496. * \param [in] status status code return from main
  1497. * \details
  1498. * This function is executed right after main function.
  1499. * For RISC-V gnu toolchain, _fini function might not be called
  1500. * by __libc_fini_array function, so we defined a new function
  1501. * to do initialization
  1502. */
  1503. void _postmain_fini(int status)
  1504. {
  1505. #if defined(CODESIZE) && (CODESIZE == 1)
  1506. #ifdef CFG_SIMULATION
  1507. SIMULATION_EXIT(status);
  1508. #endif
  1509. #else
  1510. /* TODO: Add your own finishing code here, called after main */
  1511. extern void simulation_exit(int status);
  1512. simulation_exit(status);
  1513. #endif
  1514. }
  1515. /**
  1516. * \brief _init function called in __libc_init_array()
  1517. * \details
  1518. * This `__libc_init_array()` function is called during startup code,
  1519. * user need to implement this function, otherwise when link it will
  1520. * error init.c:(.text.__libc_init_array+0x26): undefined reference to `_init'
  1521. * \note
  1522. * Please use \ref _premain_init function now
  1523. */
  1524. void _init(void)
  1525. {
  1526. /* Don't put any code here, please use _premain_init now */
  1527. }
  1528. /**
  1529. * \brief _fini function called in __libc_fini_array()
  1530. * \details
  1531. * This `__libc_fini_array()` function is called when exit main.
  1532. * user need to implement this function, otherwise when link it will
  1533. * error fini.c:(.text.__libc_fini_array+0x28): undefined reference to `_fini'
  1534. * \note
  1535. * Please use \ref _postmain_fini function now
  1536. */
  1537. void _fini(void)
  1538. {
  1539. /* Don't put any code here, please use _postmain_fini now */
  1540. }
  1541. /** @} */ /* End of Doxygen Group NMSIS_Core_SystemConfig */