system_evalsoc.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  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. /*----------------------------------------------------------------------------
  30. Define clocks
  31. *----------------------------------------------------------------------------*/
  32. /* ToDo: add here your necessary defines for device initialization
  33. following is an example for different system frequencies */
  34. #ifndef SYSTEM_CLOCK
  35. #define SYSTEM_CLOCK (16000000UL)
  36. #endif
  37. #ifdef CFG_HAS_EXCP
  38. extern void exc_entry(void);
  39. #endif
  40. /**
  41. * \defgroup NMSIS_Core_SystemConfig System Device Configuration
  42. * \brief Functions for system and clock setup available in system_<device>.c.
  43. * \details
  44. * Nuclei provides a template file **system_Device.c** that must be adapted by
  45. * the silicon vendor to match their actual device. As a <b>minimum requirement</b>,
  46. * this file must provide:
  47. * - A device-specific system configuration function, \ref SystemInit.
  48. * - Global c library \ref _premain_init and \ref _postmain_fini functions called right before calling main function.
  49. * - A global variable that contains the system frequency, \ref SystemCoreClock.
  50. * - A global interrupt configuration initialization, \ref Interrupt_Init.
  51. * - A global exception and trap configuration initialization, \ref Trap_Init and \ref Exception_Init.
  52. * - Vendor customized interrupt, exception handling code, see \ref NMSIS_Core_IntExcNMI_Handling
  53. *
  54. * The file configures the device and, typically, initializes the oscillator (PLL) that is part
  55. * of the microcontroller device. This file might export other functions or variables that provide
  56. * a more flexible configuration of the microcontroller system.
  57. *
  58. * And this file also provided common interrupt, exception exception handling framework template,
  59. * Silicon vendor can customize these template code as they want.
  60. *
  61. * \note Please pay special attention to the static variable \c SystemCoreClock. This variable might be
  62. * used throughout the whole system initialization and runtime to calculate frequency/time related values.
  63. * Thus one must assure that the variable always reflects the actual system clock speed.
  64. *
  65. * \attention
  66. * Be aware that a value stored to \c SystemCoreClock during low level initialization (i.e. \c SystemInit()) might get
  67. * overwritten by C libray startup code and/or .bss section initialization.
  68. * Thus its highly recommended to call \ref SystemCoreClockUpdate at the beginning of the user \c main() routine.
  69. *
  70. * @{
  71. */
  72. /*----------------------------------------------------------------------------
  73. System Core Clock Variable
  74. *----------------------------------------------------------------------------*/
  75. /* ToDo: initialize SystemCoreClock with the system core clock frequency value
  76. achieved after system intitialization.
  77. This means system core clock frequency after call to SystemInit() */
  78. /**
  79. * \brief Variable to hold the system core clock value
  80. * \details
  81. * Holds the system core clock, which is the system clock frequency supplied to the SysTick
  82. * timer and the processor core clock. This variable can be used by debuggers to query the
  83. * frequency of the debug timer or to configure the trace clock speed.
  84. *
  85. * \attention
  86. * Compilers must be configured to avoid removing this variable in case the application
  87. * program is not using it. Debugging systems require the variable to be physically
  88. * present in memory so that it can be examined to configure the debugger.
  89. */
  90. volatile uint32_t SystemCoreClock = SYSTEM_CLOCK; /* System Clock Frequency (Core Clock) */
  91. /*----------------------------------------------------------------------------
  92. Clock functions
  93. *----------------------------------------------------------------------------*/
  94. /**
  95. * \brief Function to update the variable \ref SystemCoreClock
  96. * \details
  97. * Updates the variable \ref SystemCoreClock and must be called whenever the core clock is changed
  98. * during program execution. The function evaluates the clock register settings and calculates
  99. * the current core clock.
  100. */
  101. void SystemCoreClockUpdate(void) /* Get Core Clock Frequency */
  102. {
  103. /* ToDo: add code to calculate the system frequency based upon the current
  104. * register settings.
  105. * Note: This function can be used to retrieve the system core clock frequeny
  106. * after user changed register settings.
  107. */
  108. }
  109. /**
  110. * \brief Function to Initialize the system.
  111. * \details
  112. * Initializes the microcontroller system. Typically, this function configures the
  113. * oscillator (PLL) that is part of the microcontroller device. For systems
  114. * with a variable clock speed, it updates the variable \ref SystemCoreClock.
  115. * SystemInit is called from the file <b>startup<i>_device</i></b>.
  116. */
  117. void SystemInit(void)
  118. {
  119. /* ToDo: add code to initialize the system
  120. * Warn: do not use global variables because this function is called before
  121. * reaching pre-main. RW section maybe overwritten afterwards.
  122. */
  123. }
  124. /**
  125. * \defgroup NMSIS_Core_IntExcNMI_Handling Interrupt and Exception Handling
  126. * \brief Functions for interrupt, exception and nmi handle available in system_<device>.c.
  127. * \details
  128. * Nuclei provide a template for interrupt, exception handling. Silicon Vendor could adapat according
  129. * to their requirement. Silicon vendor could implement interface for different exception code and
  130. * replace current implementation.
  131. *
  132. * @{
  133. */
  134. // TODO If you don't want any exception handler print any thing, uncomment below macro
  135. // Define this will reduce code size and less debug message when exception happened
  136. //#define DISABLE_EXCEPTION_DEBUG
  137. #if defined(__IRQC_PRESENT) && (__IRQC_PRESENT == 1)
  138. extern __WEAK void irqc_mtip_handler(void);
  139. extern __WEAK void irqc_msip_handler(void);
  140. extern __WEAK void irqc_uart0_handler(void);
  141. extern void default_intexc_handler(void);
  142. typedef void (*__fp)(void);
  143. // TODO irqc vector table, you can change 32 to real value of our interrupt number
  144. // Please fill in this irq vector table with your real interrupt function name
  145. // MUST marked as __USED to avoid unused variable elimination
  146. static const __fp vector_base[__IRQC_INTNUM] __USED __attribute__((section (".mintvec"))) = {
  147. irqc_msip_handler, /* irq 0 , internal irq 0 */
  148. irqc_mtip_handler, /* irq 1 , internal irq 1 */
  149. /* TODO Below are external interrupt handlers, please define them as your requirements, you need to increase or decrease it, and define correct interrupt handler name */
  150. #if __IRQC_INTNUM > 2
  151. irqc_uart0_handler, /* irq 2 , ext_irq 0 */
  152. #endif
  153. };
  154. #endif
  155. #if defined(__EXCP_PRESENT) && (__EXCP_PRESENT == 1)
  156. /* TODO: Using default exception handling code provided by NMSIS Device Template.
  157. * If you want to disable it and use your own one, you can implement Exception_Init and core_exception_handler function
  158. */
  159. #if defined(__Vendor_EXCEPTION) && (__Vendor_EXCEPTION == 0)
  160. /** \brief Max exception handler number */
  161. #define MAX_SYSTEM_EXCEPTION_NUM 12
  162. /**
  163. * \brief Store the exception handlers for each exception ID
  164. * \note
  165. * - This SystemExceptionHandlers are used to store all the handlers for all
  166. * the exception codes Nuclei N100 core provided.
  167. * - Exception code 0 - 11, totally 12 exceptions are mapped to SystemExceptionHandlers[0:11]
  168. * - Exception code 0xFFF, represent NMI, mapped to SystemExceptionHandlers[12]
  169. */
  170. static unsigned long SystemExceptionHandlers[MAX_SYSTEM_EXCEPTION_NUM + 1];
  171. /**
  172. * \brief Exception Handler Function Typedef
  173. * \note
  174. * This typedef is only used internal in this system_<Device>.c file.
  175. * It is used to do type conversion for registered exception handler before calling it.
  176. */
  177. typedef void (*EXC_HANDLER)(unsigned long cause, unsigned long sp);
  178. /**
  179. * \brief System Default Exception Handler
  180. * \details
  181. * This function provides a default exception handler for all exception ids.
  182. * By default, It will just print some information for debug, Vendor can customize it according to its requirements.
  183. * \param [in] mcause code indicating the reason that caused the trap in machine mode
  184. * \param [in] sp stack pointer
  185. */
  186. static void system_default_exception_handler(unsigned long mcause, unsigned long sp)
  187. {
  188. #if defined(CODESIZE) && (CODESIZE == 1)
  189. #else
  190. #ifndef DISABLE_EXCEPTION_DEBUG
  191. /* TODO: Uncomment this if you have implement NSDK_DEBUG function */
  192. NSDK_DEBUG("MCAUSE : 0x%lx\r\n", mcause);
  193. NSDK_DEBUG("MEPC : 0x%lx\r\n", __RV_CSR_READ(CSR_MEPC));
  194. NSDK_DEBUG("HARTID : %u\r\n", (unsigned int)__get_hart_id());
  195. Exception_DumpFrame(sp, PRV_M);
  196. #if defined(SIMULATION_MODE)
  197. // directly exit if in SIMULATION
  198. extern void simulation_exit(int status);
  199. simulation_exit(1);
  200. #endif
  201. #endif
  202. while (1) {
  203. __WFI();
  204. }
  205. #endif
  206. }
  207. /**
  208. * \brief Initialize all the default core exception handlers
  209. * \details
  210. * The core exception handler for each exception id will be initialized to \ref system_default_exception_handler.
  211. * \note
  212. * Called in \ref _premain_init function, used to initialize default exception handlers for all exception IDs
  213. */
  214. void Exception_Init(void)
  215. {
  216. #if defined(CODESIZE) && (CODESIZE == 1)
  217. #else
  218. #if defined(__EXCP_PRESENT) && (__EXCP_PRESENT == 1)
  219. #ifdef CFG_HAS_TRAP_CSR
  220. /* TODO when the exception entry csr MTVEC is writable, you can remap exception entry */
  221. /* but you need to handle the remap by yourself by update linker script */
  222. __RV_CSR_WRITE(CSR_MTVEC, (rv_csr_t)exc_entry);
  223. #endif
  224. #endif
  225. for (int i = 0; i < (MAX_SYSTEM_EXCEPTION_NUM + 1); i++) {
  226. SystemExceptionHandlers[i] = (unsigned long)system_default_exception_handler;
  227. }
  228. #endif
  229. }
  230. /**
  231. * \brief Dump Exception Frame
  232. * \details
  233. * This function provided feature to dump exception frame stored in stack.
  234. * \param [in] sp stackpoint
  235. * \param [in] mode privileged mode
  236. */
  237. void Exception_DumpFrame(unsigned long sp, uint8_t mode)
  238. {
  239. #if defined(CODESIZE) && (CODESIZE == 1)
  240. #else
  241. #ifndef DISABLE_EXCEPTION_DEBUG
  242. EXC_Frame_Type *exc_frame = (EXC_Frame_Type *)sp;
  243. #ifndef __riscv_32e
  244. 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" \
  245. "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" \
  246. "cause: 0x%lx, epc: 0x%lx\n", exc_frame->ra, exc_frame->tp, exc_frame->t0, \
  247. exc_frame->t1, exc_frame->t2, exc_frame->t3, exc_frame->t4, exc_frame->t5, exc_frame->t6, \
  248. exc_frame->a0, exc_frame->a1, exc_frame->a2, exc_frame->a3, exc_frame->a4, exc_frame->a5, \
  249. exc_frame->a6, exc_frame->a7, exc_frame->cause, exc_frame->epc);
  250. #else
  251. NSDK_DEBUG("ra: 0x%lx, tp: 0x%lx, t0: 0x%lx, t1: 0x%lx, t2: 0x%lx\n" \
  252. "a0: 0x%lx, a1: 0x%lx, a2: 0x%lx, a3: 0x%lx, a4: 0x%lx, a5: 0x%lx\n" \
  253. "cause: 0x%lx, epc: 0x%lx\n", exc_frame->ra, exc_frame->tp, exc_frame->t0, \
  254. exc_frame->t1, exc_frame->t2, exc_frame->a0, exc_frame->a1, exc_frame->a2, exc_frame->a3, \
  255. exc_frame->a4, exc_frame->a5, exc_frame->cause, exc_frame->epc);
  256. #endif
  257. #endif
  258. #endif
  259. }
  260. /**
  261. * \brief Register an exception handler for exception code EXCn
  262. * \details
  263. * - For EXCn < \ref MAX_SYSTEM_EXCEPTION_NUM, it will be registered into SystemExceptionHandlers[EXCn].
  264. * \param [in] EXCn See \ref EXCn_Type
  265. * \param [in] exc_handler The exception handler for this exception code EXCn
  266. */
  267. void Exception_Register_EXC(uint32_t EXCn, unsigned long exc_handler)
  268. {
  269. #if defined(CODESIZE) && (CODESIZE == 1)
  270. #else
  271. if (EXCn < MAX_SYSTEM_EXCEPTION_NUM) {
  272. SystemExceptionHandlers[EXCn] = exc_handler;
  273. } else if (EXCn == 0xFFF) {
  274. SystemExceptionHandlers[MAX_SYSTEM_EXCEPTION_NUM] = exc_handler;
  275. }
  276. #endif
  277. }
  278. /**
  279. * \brief Get current exception handler for exception code EXCn
  280. * \details
  281. * - For EXCn < \ref MAX_SYSTEM_EXCEPTION_NUM, it will return SystemExceptionHandlers[EXCn].
  282. * \param [in] EXCn See \ref EXCn_Type
  283. * \return Current exception handler for exception code EXCn, if not found, return 0.
  284. */
  285. unsigned long Exception_Get_EXC(uint32_t EXCn)
  286. {
  287. #if defined(CODESIZE) && (CODESIZE == 1)
  288. #else
  289. if (EXCn < MAX_SYSTEM_EXCEPTION_NUM) {
  290. return SystemExceptionHandlers[EXCn];
  291. } else if (EXCn == 0xFFF) {
  292. return SystemExceptionHandlers[MAX_SYSTEM_EXCEPTION_NUM];
  293. }
  294. #endif
  295. return 0;
  296. }
  297. /**
  298. * \brief Common Exception handler entry
  299. * \details
  300. * This function provided a command entry for exception. Silicon Vendor could modify
  301. * this template implementation according to requirement.
  302. * \param [in] mcause code indicating the reason that caused the trap in machine mode
  303. * \param [in] sp stack pointer
  304. * \remarks
  305. * - RISCV provided common entry for all types of exception. This is proposed code template
  306. * for exception entry function, Silicon Vendor could modify the implementation.
  307. * - For the core_exception_handler template, we provided exception register function \ref Exception_Register_EXC
  308. * which can help developer to register your exception handler for specific exception number.
  309. */
  310. uint32_t core_exception_handler(unsigned long mcause, unsigned long sp)
  311. {
  312. #if defined(CODESIZE) && (CODESIZE == 1)
  313. while(1);
  314. #else
  315. uint32_t EXCn = (uint32_t)(mcause & 0x00000fff);
  316. EXC_HANDLER exc_handler;
  317. if (EXCn < MAX_SYSTEM_EXCEPTION_NUM) {
  318. exc_handler = (EXC_HANDLER)SystemExceptionHandlers[EXCn];
  319. } else if (EXCn == 0xFFF) {
  320. exc_handler = (EXC_HANDLER)SystemExceptionHandlers[MAX_SYSTEM_EXCEPTION_NUM];
  321. } else {
  322. exc_handler = (EXC_HANDLER)system_default_exception_handler;
  323. }
  324. if (exc_handler != NULL) {
  325. exc_handler(mcause, sp);
  326. }
  327. return 0;
  328. #endif
  329. }
  330. #else /* Use Vendor implemented exception handling code __Vendor_EXCEPTION == 1 */
  331. // TODO implement core_exception_handler and Exception_Init if __Vendor_EXCEPTION == 1
  332. __WEAK uint32_t core_exception_handler(unsigned long mcause, unsigned long sp)
  333. {
  334. while (1) {
  335. __WFI();
  336. }
  337. }
  338. __WEAK void Exception_Init(void)
  339. {
  340. }
  341. #endif
  342. #endif
  343. /** @} */ /* End of Doxygen Group NMSIS_Core_ExceptionAndNMI */
  344. /** Banner Print for Nuclei SDK */
  345. void SystemBannerPrint(void)
  346. {
  347. #if defined(CODESIZE) && (CODESIZE == 1)
  348. #else
  349. // TODO to reduce code size and less message output.
  350. // you can set NUCLEI_BANNER to 0 in nuclei_sdk_hal.h
  351. // but it will show no messsage when bringup
  352. #if defined(NUCLEI_BANNER) && (NUCLEI_BANNER == 1)
  353. NSDK_DEBUG("N100 Nuclei SDK Build Time: %s, %s\r\n", __DATE__, __TIME__);
  354. #ifdef DOWNLOAD_MODE_STRING
  355. NSDK_DEBUG("Download Mode: %s\r\n", DOWNLOAD_MODE_STRING);
  356. #endif
  357. NSDK_DEBUG("CPU Frequency %u Hz\r\n", (unsigned int)SystemCoreClock);
  358. NSDK_DEBUG("CPU HartID: %u\r\n", (unsigned int)__get_hart_id());
  359. #endif
  360. #endif
  361. }
  362. /**
  363. * \brief initialize interrupt config
  364. * \details
  365. * interrupt needs be initialized after boot up
  366. */
  367. void Interrupt_Init(void)
  368. {
  369. #if defined(__IRQC_PRESENT) && (__IRQC_PRESENT == 1)
  370. #ifdef CFG_HAS_TRAP_CSR
  371. /* TODO when the interrupt vector entry csr MTVT is writable, you can remap your vector table */
  372. /* but you need to handle the remap by yourself by update linker script */
  373. __RV_CSR_WRITE(CSR_MTVT, (rv_csr_t)vector_base);
  374. #endif
  375. #endif
  376. }
  377. #if defined(__IRQC_PRESENT) && (__IRQC_PRESENT == 1)
  378. /**
  379. * \brief Initialize a specific IRQ and register the handler
  380. * \details
  381. * This function set vector mode, trigger mode and polarity, interrupt level and priority,
  382. * assign handler for specific IRQn.
  383. * \param [in] IRQn interrupt handler address
  384. * \param [in] handler interrupt handler, if NULL, handler will not be installed
  385. * \return -1 means invalid input parameter. 0 means successful.
  386. * \remarks
  387. * - This function use to configure specific irqc interrupt and register its interrupt handler and enable its interrupt.
  388. * - If the vector table is placed in read-only section, handler could not be installed
  389. */
  390. int32_t IRQC_Register_IRQ(IRQn_Type IRQn, void* handler)
  391. {
  392. if (IRQn >= SOC_INT_MAX) {
  393. return -1;
  394. }
  395. if (handler != NULL) {
  396. IRQC_SetVector(IRQn, (rv_csr_t)handler);
  397. }
  398. IRQC_EnableIRQ(IRQn);
  399. return 0;
  400. }
  401. #endif
  402. /**
  403. * \brief do the init for trap
  404. * \details
  405. */
  406. static void Trap_Init(void)
  407. {
  408. }
  409. /**
  410. * \brief early init function before main
  411. * \details
  412. * This function is executed right before main function.
  413. * For RISC-V gnu toolchain, _init function might not be called
  414. * by __libc_init_array function, so we defined a new function
  415. * to do initialization.
  416. */
  417. void _premain_init(void)
  418. {
  419. #if defined(CODESIZE) && (CODESIZE == 1)
  420. // TODO to reduce the code size of application
  421. // No need to do so complex premain initialization steps
  422. // You just need to initialize the cpu resource you need to use in your
  423. // application code.
  424. // TODO Still need to initialize uart for other code need to do printf
  425. // If you want to reduce more code, you can comment below code
  426. uart_init(SOC_DEBUG_UART, 115200);
  427. #else
  428. // TODO Code below used to do premain init, you can place pre main init code here
  429. // TODO implement get_cpu_freq function to get real cpu clock freq in HZ or directly give the real cpu HZ
  430. // Or directly give the correct freqency, no need to use this function
  431. SystemCoreClock = get_cpu_freq();
  432. uart_init(SOC_DEBUG_UART, 115200);
  433. /* Display banner after UART initialized */
  434. SystemBannerPrint();
  435. /* Initialize exception default handlers */
  436. #if defined(__EXCP_PRESENT) && (__EXCP_PRESENT == 1)
  437. Exception_Init();
  438. #endif
  439. /* Interrupt initialization, mainly MTH and NLBIT */
  440. #if defined(__IRQC_PRESENT) && (__IRQC_PRESENT == 1)
  441. Interrupt_Init();
  442. #endif
  443. Trap_Init();
  444. #endif
  445. }
  446. /**
  447. * \brief finish function after main
  448. * \param [in] status status code return from main
  449. * \details
  450. * This function is executed right after main function.
  451. * For RISC-V gnu toolchain, _fini function might not be called
  452. * by __libc_fini_array function, so we defined a new function
  453. * to do initialization
  454. */
  455. void _postmain_fini(int status)
  456. {
  457. #if defined(CODESIZE) && (CODESIZE == 1)
  458. #ifdef CFG_SIMULATION
  459. SIMULATION_EXIT(status);
  460. #endif
  461. #else
  462. /* TODO: Add your own finishing code here, called after main */
  463. extern void simulation_exit(int status);
  464. simulation_exit(status);
  465. #endif
  466. }
  467. /** @} */ /* End of Doxygen Group NMSIS_Core_SystemConfig */