port.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808
  1. /*
  2. * FreeRTOS Kernel Port For Nuclei RISC-V Processor
  3. * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining a copy of
  6. * this software and associated documentation files (the "Software"), to deal in
  7. * the Software without restriction, including without limitation the rights to
  8. * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  9. * the Software, and to permit persons to whom the Software is furnished to do so,
  10. * subject to the following conditions:
  11. *
  12. * The above copyright notice and this permission notice shall be included in all
  13. * copies or substantial portions of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  17. * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  18. * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  19. * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  20. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21. *
  22. * http://www.FreeRTOS.org
  23. * http://aws.amazon.com/freertos
  24. *
  25. * 1 tab == 4 spaces!
  26. */
  27. /*-----------------------------------------------------------
  28. * Implementation of functions defined in portable.h for the Nuclei N/NX Processor port.
  29. *----------------------------------------------------------*/
  30. /* Scheduler includes. */
  31. #include <stdio.h>
  32. #include "FreeRTOS.h"
  33. #include "task.h"
  34. // #define ENABLE_KERNEL_DEBUG
  35. #ifdef ENABLE_KERNEL_DEBUG
  36. #define FREERTOS_PORT_DEBUG(...) printf(__VA_ARGS__)
  37. #else
  38. #define FREERTOS_PORT_DEBUG(...)
  39. #endif
  40. #ifndef configSYSTICK_CLOCK_HZ
  41. #define configSYSTICK_CLOCK_HZ SOC_TIMER_FREQ
  42. #endif
  43. #ifndef configKERNEL_INTERRUPT_PRIORITY
  44. #define configKERNEL_INTERRUPT_PRIORITY 0
  45. #endif
  46. /* Constants required to check the validity of an interrupt priority. */
  47. #define portFIRST_USER_INTERRUPT_NUMBER ( 18 )
  48. #define SYSTICK_TICK_CONST (configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ)
  49. /* Masks off all bits but the ECLIC MTH bits in the MTH register. */
  50. #define portMTH_MASK ( 0xFFUL )
  51. /* Constants required to set up the initial stack. */
  52. #define portINITIAL_MSTATUS ( MSTATUS_MPP | MSTATUS_MPIE | MSTATUS_FS_INITIAL | MSTATUS_VS_INITIAL)
  53. #define portINITIAL_EXC_RETURN ( 0xfffffffd )
  54. /* The systick is a 64-bit counter. */
  55. #define portMAX_BIT_NUMBER ( SysTimer_MTIMER_Msk )
  56. /* A fiddle factor to estimate the number of SysTick counts that would have
  57. occurred while the SysTick counter is stopped during tickless idle
  58. calculations. */
  59. #define portMISSED_COUNTS_FACTOR ( 45UL )
  60. /* Let the user override the pre-loading of the initial LR with the address of
  61. prvTaskExitError() in case it messes up unwinding of the stack in the
  62. debugger. */
  63. #ifdef configTASK_RETURN_ADDRESS
  64. #define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS
  65. #else
  66. #define portTASK_RETURN_ADDRESS prvTaskExitError
  67. #endif
  68. /*
  69. * Setup the timer to generate the tick interrupts. The implementation in this
  70. * file is weak to allow application writers to change the timer used to
  71. * generate the tick interrupt.
  72. */
  73. void vPortSetupTimerInterrupt(void);
  74. /*
  75. * Exception handlers.
  76. */
  77. void xPortSysTickHandler(void);
  78. /*
  79. * Start first task is a separate function so it can be tested in isolation.
  80. */
  81. extern void prvPortStartFirstTask(void) __attribute__((naked));
  82. /*
  83. * Used to catch tasks that attempt to return from their implementing function.
  84. */
  85. static void prvTaskExitError(void);
  86. #define xPortSysTickHandler eclic_mtip_handler
  87. /*-----------------------------------------------------------*/
  88. /* Each task maintains its own interrupt status in the critical nesting
  89. variable. */
  90. #if ( configNUMBER_OF_CORES == 1 )
  91. UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
  92. #else /* #if ( configNUMBER_OF_CORES == 1 ) */
  93. UBaseType_t uxCriticalNestings[ configNUMBER_OF_CORES ] = { 0 };
  94. #endif /* #if ( configNUMBER_OF_CORES == 1 ) */
  95. #if configMAX_SYSCALL_INTERRUPT_PRIORITY < 255
  96. /*
  97. * Record the real MTH calculated by the configMAX_SYSCALL_INTERRUPT_PRIORITY
  98. * The configMAX_SYSCALL_INTERRUPT_PRIORITY is not the left-aligned level value,
  99. * See equations below:
  100. * Level Bits number: lvlbits = min(nlbits, CLICINTCTLBITS)
  101. * Left align Bits number: lfabits = 8-lvlbits
  102. * 0 < configMAX_SYSCALL_INTERRUPT_PRIORITY <= (2^lvlbits-1)
  103. * uxMaxSysCallMTH = (configMAX_SYSCALL_INTERRUPT_PRIORITY << lfabits) | ((2^lfabits)-1)
  104. * If nlbits = 3, CLICINTCTLBITS=3, then lvlbits = 3, lfabits = 5
  105. * Set configMAX_SYSCALL_INTERRUPT_PRIORITY to 6
  106. * Then uxMaxSysCallMTH = (6<<5) | (2^5 - 1) = 223
  107. *
  108. * See function prvCheckMaxSysCallPrio and prvCalcMaxSysCallMTH
  109. */
  110. uint8_t uxMaxSysCallMTH = 255;
  111. #endif
  112. /*
  113. * The number of SysTick increments that make up one tick period.
  114. */
  115. #if( configUSE_TICKLESS_IDLE == 1 )
  116. static TickType_t ulTimerCountsForOneTick = 0;
  117. #endif /* configUSE_TICKLESS_IDLE */
  118. /*
  119. * The maximum number of tick periods that can be suppressed is limited by the
  120. * 24 bit resolution of the SysTick timer.
  121. */
  122. #if( configUSE_TICKLESS_IDLE == 1 )
  123. static TickType_t xMaximumPossibleSuppressedTicks = 0;
  124. #endif /* configUSE_TICKLESS_IDLE */
  125. /*
  126. * Compensate for the CPU cycles that pass while the SysTick is stopped (low
  127. * power functionality only.
  128. */
  129. #if( configUSE_TICKLESS_IDLE == 1 )
  130. static TickType_t ulStoppedTimerCompensation = 0;
  131. #endif /* configUSE_TICKLESS_IDLE */
  132. /*
  133. * Used by the portASSERT_IF_INTERRUPT_PRIORITY_INVALID() macro to ensure
  134. * FreeRTOS API functions are not called from interrupts that have been assigned
  135. * a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY.
  136. */
  137. #if( configASSERT_DEFINED == 1 )
  138. #if configMAX_SYSCALL_INTERRUPT_PRIORITY < 255
  139. static uint8_t ucMaxSysCallPriority = 0;
  140. #endif
  141. #endif /* configASSERT_DEFINED */
  142. #if ( configNUMBER_OF_CORES > 1 )
  143. spin_lock_t hw_sync_locks[portRTOS_SPINLOCK_COUNT] = {0, 0};
  144. /* Note this is a single method with uxAcquire parameter since we have
  145. * static vars, the method is always called with a compile time constant for
  146. * uxAcquire, and the compiler should do the right thing! */
  147. void vPortRecursiveLock(unsigned long ulLockNum, spin_lock_t *pxSpinLock, BaseType_t uxAcquire)
  148. {
  149. /* Track, per-core, which locks this core currently owns. */
  150. static volatile uint8_t ucOwnedByCore[portMAX_CORE_COUNT];
  151. /* Track, per-lock, how many times it has been recursively taken. */
  152. static volatile uint8_t ucRecursionCountByLock[portRTOS_SPINLOCK_COUNT];
  153. configASSERT(ulLockNum < portRTOS_SPINLOCK_COUNT);
  154. unsigned long ulCoreNum = __get_hart_index(); /* ID of current hart */
  155. unsigned long ulLockBit = 1u << ulLockNum; /* Bit mask for lock */
  156. configASSERT(ulLockBit < 256u);
  157. if (uxAcquire) { /* ACQUIRE PATH */
  158. /* Case 1: lock already held by THIS core -> pure recursion. */
  159. if ((!*pxSpinLock == 0)) {
  160. if (ucOwnedByCore[ulCoreNum] & ulLockBit) {
  161. configASSERT(ucRecursionCountByLock[ulLockNum] != 255u);
  162. ucRecursionCountByLock[ulLockNum]++;
  163. return;
  164. }
  165. }
  166. /* Case 2: lock not held (or held by another core). */
  167. do {
  168. /* Spin-wait until the lock appears free. */
  169. while ((!*pxSpinLock == 0)) {
  170. __NOP();
  171. }
  172. /* Atomically attempt to take the lock. */
  173. if (__AMOSWAP_W(pxSpinLock, 1) == 0) { /* success */
  174. __RWMB(); /* mem-barrier */
  175. break; /* lock taken */
  176. }
  177. } while (1);
  178. /* First successful take on THIS core -> init recursion state.*/
  179. configASSERT(ucRecursionCountByLock[ulLockNum] == 0);
  180. ucRecursionCountByLock[ulLockNum] = 1;
  181. ucOwnedByCore[ulCoreNum] |= ulLockBit; /* mark ownership */
  182. } else { /* RELEASE PATH */
  183. configASSERT((ucOwnedByCore[ulCoreNum] & ulLockBit) != 0);
  184. configASSERT(ucRecursionCountByLock[ulLockNum] != 0);
  185. /* Decrease recursion counter. */
  186. if (!--ucRecursionCountByLock[ulLockNum]) {
  187. /* Last release -> clear ownership and unlock. */
  188. ucOwnedByCore[ulCoreNum] &= ~ulLockBit;
  189. __RWMB(); /* ensure prior stores visible */
  190. *pxSpinLock = 0; /* hand the lock back */
  191. }
  192. }
  193. }
  194. #endif
  195. static volatile unsigned long ulSchedulerReady = 0;
  196. /*-----------------------------------------------------------*/
  197. /*
  198. * See header file for description.
  199. * As per the standard RISC-V ABI pxTopcOfStack is passed in in a0, pxCode in
  200. * a1, and pvParameters in a2. The new top of stack is passed out in a0.
  201. *
  202. * RISC-V maps registers to ABI names as follows (X1 to X31 integer registers
  203. * for the 'I' profile, X1 to X15 for the 'E' profile, currently I assumed).
  204. *
  205. * Register ABI Name Description Saver
  206. * x0 zero Hard-wired zero -
  207. * x1 ra Return address Caller
  208. * x2 sp Stack pointer Callee
  209. * x3 gp Global pointer -
  210. * x4 tp Thread pointer -
  211. * x5-7 t0-2 Temporaries Caller
  212. * x8 s0/fp Saved register/Frame pointer Callee
  213. * x9 s1 Saved register Callee
  214. * x10-11 a0-1 Function Arguments/return values Caller
  215. * x12-17 a2-7 Function arguments Caller
  216. * x18-27 s2-11 Saved registers Callee
  217. * x28-31 t3-6 Temporaries Caller
  218. *
  219. * The RISC-V context is saved RTOS tasks in the following stack frame,
  220. * where the global and thread pointers are currently assumed to be constant so
  221. * are not saved:
  222. *
  223. * mstatus
  224. * #ifndef __riscv_32e
  225. * rsv1
  226. * rsv0
  227. * x31
  228. * x30
  229. * x29
  230. * x28
  231. * x27
  232. * x26
  233. * x25
  234. * x24
  235. * x23
  236. * x22
  237. * x21
  238. * x20
  239. * x19
  240. * x18
  241. * x17
  242. * x16
  243. * #endif
  244. * x15
  245. * x14
  246. * x13
  247. * x12
  248. * x11
  249. * pvParameters
  250. * x9
  251. * x8
  252. * x7
  253. * x6
  254. * x5
  255. * portTASK_RETURN_ADDRESS
  256. * pxCode
  257. */
  258. StackType_t* pxPortInitialiseStack(StackType_t* pxTopOfStack, TaskFunction_t pxCode, void* pvParameters)
  259. {
  260. /* Simulate the stack frame as it would be created by a context switch
  261. interrupt. */
  262. /* Stack frame size 32 REGBYTES(4/8) for most cases, but for ilp32e mode, it's 14 REGBYTES(4) */
  263. /* Offset added to account for the way the MCU uses the stack on entry/exit
  264. of interrupts, and to ensure alignment. */
  265. pxTopOfStack--;
  266. *pxTopOfStack = portINITIAL_MSTATUS; /* MSTATUS */
  267. /* Save code space by skipping register initialisation. */
  268. #ifndef __riscv_32e
  269. pxTopOfStack -= 24; /* X11 - X31, and 2 reserved regs space. */
  270. #else
  271. pxTopOfStack -= 6; /* X11 - X15. */
  272. #endif
  273. *pxTopOfStack = (StackType_t) pvParameters; /* X10/A0 */
  274. pxTopOfStack -= 6; /* X5 - X9 */
  275. *pxTopOfStack = (StackType_t) portTASK_RETURN_ADDRESS; /* RA, X1 */
  276. pxTopOfStack --;
  277. *pxTopOfStack = ((StackType_t) pxCode) ; /* PC */
  278. return pxTopOfStack;
  279. }
  280. /*-----------------------------------------------------------*/
  281. static void prvTaskExitError(void)
  282. {
  283. volatile uint32_t ulDummy = 0;
  284. /* A function that implements a task must not exit or attempt to return to
  285. its caller as there is nothing to return to. If a task wants to exit it
  286. should instead call vTaskDelete( NULL ).
  287. Artificially force an assert() to be triggered if configASSERT() is
  288. defined, then stop here so application writers can catch the error. */
  289. configASSERT(portGET_CRITICAL_NESTING_COUNT() == ~0UL);
  290. portDISABLE_INTERRUPTS();
  291. while (ulDummy == 0) {
  292. /* This file calls prvTaskExitError() after the scheduler has been
  293. started to remove a compiler warning about the function being defined
  294. but never called. ulDummy is used purely to quieten other warnings
  295. about code appearing after this function is called - making ulDummy
  296. volatile makes the compiler think the function could return and
  297. therefore not output an 'unreachable code' warning for code that appears
  298. after it. */
  299. /* Sleep and wait for interrupt */
  300. __WFI();
  301. }
  302. }
  303. /*-----------------------------------------------------------*/
  304. #if configMAX_SYSCALL_INTERRUPT_PRIORITY < 255
  305. static uint8_t prvCheckMaxSysCallPrio(uint8_t max_syscall_prio)
  306. {
  307. uint8_t nlbits = __ECLIC_GetCfgNlbits();
  308. uint8_t intctlbits = __ECLIC_INTCTLBITS;
  309. uint8_t lvlbits, temp;
  310. if (nlbits <= intctlbits) {
  311. lvlbits = nlbits;
  312. } else {
  313. lvlbits = intctlbits;
  314. }
  315. temp = ((1 << lvlbits) - 1);
  316. if (max_syscall_prio > temp) {
  317. max_syscall_prio = temp;
  318. }
  319. return max_syscall_prio;
  320. }
  321. static uint8_t prvCalcMaxSysCallMTH(uint8_t max_syscall_prio)
  322. {
  323. uint8_t nlbits = __ECLIC_GetCfgNlbits();
  324. uint8_t intctlbits = __ECLIC_INTCTLBITS;
  325. uint8_t lvlbits, lfabits;
  326. uint8_t maxsyscallmth = 0;
  327. uint8_t temp;
  328. if (nlbits <= intctlbits) {
  329. lvlbits = nlbits;
  330. } else {
  331. lvlbits = intctlbits;
  332. }
  333. lfabits = 8 - lvlbits;
  334. temp = ((1 << lvlbits) - 1);
  335. if (max_syscall_prio > temp) {
  336. max_syscall_prio = temp;
  337. }
  338. maxsyscallmth = (max_syscall_prio << lfabits) | ((1 << lfabits) - 1);
  339. return maxsyscallmth;
  340. }
  341. #endif
  342. /*
  343. * See header file for description.
  344. */
  345. BaseType_t xPortStartScheduler(void)
  346. {
  347. #if configMAX_SYSCALL_INTERRUPT_PRIORITY < 255
  348. /* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. */
  349. configASSERT(configMAX_SYSCALL_INTERRUPT_PRIORITY);
  350. /* Get the real MTH should be set to ECLIC MTH register */
  351. uxMaxSysCallMTH = prvCalcMaxSysCallMTH(configMAX_SYSCALL_INTERRUPT_PRIORITY);
  352. FREERTOS_PORT_DEBUG("Max SysCall MTH is set to 0x%x\n", uxMaxSysCallMTH);
  353. #if( configASSERT_DEFINED == 1 )
  354. {
  355. /* Use the same mask on the maximum system call priority. */
  356. ucMaxSysCallPriority = prvCheckMaxSysCallPrio(configMAX_SYSCALL_INTERRUPT_PRIORITY);
  357. FREERTOS_PORT_DEBUG("Max SysCall Priority is set to %d\n", ucMaxSysCallPriority);
  358. }
  359. #endif /* conifgASSERT_DEFINED */
  360. #endif
  361. __disable_irq();
  362. /* Start the timer that generates the tick ISR. Interrupts are disabled
  363. here already. */
  364. vPortSetupTimerInterrupt();
  365. #if ( configNUMBER_OF_CORES > 1 )
  366. if (__get_hart_index() == BOOT_HARTID) {
  367. ulSchedulerReady = 1;
  368. } else {
  369. // other cores wait for scheduler ready signal
  370. while (ulSchedulerReady == 0);
  371. }
  372. #endif
  373. /* Initialise the critical nesting count ready for the first task. */
  374. portSET_CRITICAL_NESTING_COUNT(0);
  375. __RWMB();
  376. #if configMAX_SYSCALL_INTERRUPT_PRIORITY < 255
  377. /* Initialise base priority to zero. */
  378. vPortSetBASEPRI(0);
  379. #endif
  380. // Enable interrupt and task sp swap
  381. #if defined(ECLIC_HW_CTX_AUTO) && defined(CFG_HAS_ECLICV2)
  382. __RV_CSR_SET(CSR_MECLIC_CTL, MECLIC_CTL_TSP_EN);
  383. #endif
  384. /* Start the first task. */
  385. prvPortStartFirstTask();
  386. /* Should never get here as the tasks will now be executing! Call the task
  387. exit error function to prevent compiler warnings about a static function
  388. not being called in the case that the application writer overrides this
  389. functionality by defining configTASK_RETURN_ADDRESS. Call
  390. vTaskSwitchContext() so link time optimisation does not remove the
  391. symbol. */
  392. #if ( configNUMBER_OF_CORES > 1 )
  393. vTaskSwitchContext( portGET_CORE_ID() );
  394. #else
  395. vTaskSwitchContext();
  396. #endif
  397. prvTaskExitError();
  398. /* Should not get here! */
  399. return 0;
  400. }
  401. /*-----------------------------------------------------------*/
  402. void vPortEndScheduler(void)
  403. {
  404. /* Not implemented in ports where there is nothing to return to.
  405. Artificially force an assert. */
  406. configASSERT(portGET_CRITICAL_NESTING_COUNT() == 1000UL);
  407. }
  408. /*-----------------------------------------------------------*/
  409. void vPortEnterCritical(void)
  410. {
  411. portDISABLE_INTERRUPTS();
  412. portINCREMENT_CRITICAL_NESTING_COUNT();
  413. #if configMAX_SYSCALL_INTERRUPT_PRIORITY < 255
  414. /* This is not the interrupt safe version of the enter critical function so
  415. assert() if it is being called from an interrupt context. Only API
  416. functions that end in "FromISR" can be used in an interrupt. Only assert if
  417. the critical nesting count is 1 to protect against recursive calls if the
  418. assert function also uses a critical section. */
  419. if (portGET_CRITICAL_NESTING_COUNT() == 1) {
  420. configASSERT((__ECLIC_GetMth() & portMTH_MASK) == uxMaxSysCallMTH);
  421. }
  422. #endif
  423. }
  424. /*-----------------------------------------------------------*/
  425. void vPortExitCritical(void)
  426. {
  427. configASSERT(portGET_CRITICAL_NESTING_COUNT());
  428. portDECREMENT_CRITICAL_NESTING_COUNT();
  429. if (portGET_CRITICAL_NESTING_COUNT() == 0) {
  430. portENABLE_INTERRUPTS();
  431. }
  432. }
  433. /*-----------------------------------------------------------*/
  434. void vPortAssert(int32_t x)
  435. {
  436. TaskHandle_t th;
  437. if ((x) == 0) {
  438. taskDISABLE_INTERRUPTS();
  439. #if (INCLUDE_xTaskGetCurrentTaskHandle == 1)
  440. th = xTaskGetCurrentTaskHandle();
  441. if (th) {
  442. printf("Assert in task %s\n", pcTaskGetName(th));
  443. }
  444. #endif
  445. while (1) {
  446. /* Sleep and wait for interrupt */
  447. __WFI();
  448. };
  449. }
  450. }
  451. /*-----------------------------------------------------------*/
  452. void xPortTaskSwitch(void)
  453. {
  454. /* Clear Software IRQ, A MUST */
  455. SysTimer_ClearSWIRQ();
  456. #if ( configNUMBER_OF_CORES > 1 )
  457. vTaskSwitchContext( portGET_CORE_ID() );
  458. #else
  459. vTaskSwitchContext();
  460. #endif
  461. }
  462. /*-----------------------------------------------------------*/
  463. void xPortSysTickHandler(void)
  464. {
  465. /* The SysTick runs at the lowest interrupt priority, so when this interrupt
  466. executes all interrupts must be unmasked. There is therefore no need to
  467. save and then restore the interrupt mask value as its value is already
  468. known. */
  469. #if ( configNUMBER_OF_CORES == 1 )
  470. portDISABLE_INTERRUPTS();
  471. {
  472. SysTick_Reload(SYSTICK_TICK_CONST);
  473. /* Increment the RTOS tick. */
  474. if (xTaskIncrementTick() != pdFALSE) {
  475. /* A context switch is required. Context switching is performed in
  476. the SWI interrupt. Pend the SWI interrupt. */
  477. portYIELD();
  478. }
  479. }
  480. portENABLE_INTERRUPTS();
  481. #else
  482. UBaseType_t ulPreviousMask;
  483. /* Tasks or ISRs running on other cores may still in critical section in
  484. * multiple cores environment. Incrementing tick needs to performed in
  485. * critical section. */
  486. ulPreviousMask = taskENTER_CRITICAL_FROM_ISR();
  487. {
  488. SysTick_Reload(SYSTICK_TICK_CONST);
  489. /* Increment the RTOS tick. */
  490. if (xTaskIncrementTick() != pdFALSE) {
  491. /* A context switch is required. Context switching is performed in
  492. the SWI interrupt. Pend the SWI interrupt. */
  493. portYIELD();
  494. }
  495. }
  496. taskEXIT_CRITICAL_FROM_ISR( ulPreviousMask );
  497. #endif
  498. }
  499. /*-----------------------------------------------------------*/
  500. #if( configUSE_TICKLESS_IDLE == 1 )
  501. __attribute__((weak)) void vPortSuppressTicksAndSleep(TickType_t xExpectedIdleTime)
  502. {
  503. uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements;
  504. volatile TickType_t xModifiableIdleTime, xTickCountBeforeSleep, XLastLoadValue;
  505. FREERTOS_PORT_DEBUG("Enter TickLess %d\n", (uint32_t)xExpectedIdleTime);
  506. /* Make sure the SysTick reload value does not overflow the counter. */
  507. if (xExpectedIdleTime > xMaximumPossibleSuppressedTicks) {
  508. xExpectedIdleTime = xMaximumPossibleSuppressedTicks;
  509. }
  510. /* Stop the SysTick momentarily. The time the SysTick is stopped for
  511. is accounted for as best it can be, but using the tickless mode will
  512. inevitably result in some tiny drift of the time maintained by the
  513. kernel with respect to calendar time. */
  514. SysTimer_Stop();
  515. /* Calculate the reload value required to wait xExpectedIdleTime
  516. tick periods. -1 is used because this code will execute part way
  517. through one of the tick periods. */
  518. ulReloadValue = (ulTimerCountsForOneTick * (xExpectedIdleTime - 1UL));
  519. if (ulReloadValue > ulStoppedTimerCompensation) {
  520. ulReloadValue -= ulStoppedTimerCompensation;
  521. }
  522. /* Enter a critical section but don't use the taskENTER_CRITICAL()
  523. method as that will mask interrupts that should exit sleep mode. */
  524. __disable_irq();
  525. /* If a context switch is pending or a task is waiting for the scheduler
  526. to be unsuspended then abandon the low power entry. */
  527. if (eTaskConfirmSleepModeStatus() == eAbortSleep) {
  528. /* Restart from whatever is left in the count register to complete
  529. this tick period. */
  530. /* Restart SysTick. */
  531. SysTimer_Start();
  532. /* Reset the reload register to the value required for normal tick
  533. periods. */
  534. SysTick_Reload(ulTimerCountsForOneTick);
  535. /* Re-enable interrupts - see comments above the cpsid instruction()
  536. above. */
  537. __enable_irq();
  538. } else {
  539. xTickCountBeforeSleep = xTaskGetTickCount();
  540. /* Set the new reload value. */
  541. SysTick_Reload(ulReloadValue);
  542. /* Get System timer load value before sleep */
  543. XLastLoadValue = SysTimer_GetLoadValue();
  544. /* Restart SysTick. */
  545. SysTimer_Start();
  546. ECLIC_EnableIRQ(SysTimer_IRQn);
  547. __RWMB();
  548. /* Sleep until something happens. configPRE_SLEEP_PROCESSING() can
  549. set its parameter to 0 to indicate that its implementation contains
  550. its own wait for interrupt or wait for event instruction, and so wfi
  551. should not be executed again. However, the original expected idle
  552. time variable must remain unmodified, so a copy is taken. */
  553. xModifiableIdleTime = xExpectedIdleTime;
  554. configPRE_SLEEP_PROCESSING(xModifiableIdleTime);
  555. if (xModifiableIdleTime > 0) {
  556. __WFI();
  557. }
  558. configPOST_SLEEP_PROCESSING(xExpectedIdleTime);
  559. /* Re-enable interrupts to allow the interrupt that brought the MCU
  560. out of sleep mode to execute immediately. */
  561. __enable_irq();
  562. /* Make sure interrupt enable is executed */
  563. __RWMB();
  564. __FENCE_I();
  565. __NOP();
  566. /* Disable interrupts again because the clock is about to be stopped
  567. and interrupts that execute while the clock is stopped will increase
  568. any slippage between the time maintained by the RTOS and calendar
  569. time. */
  570. __disable_irq();
  571. /* Disable the SysTick clock. Again,
  572. the time the SysTick is stopped for is accounted for as best it can
  573. be, but using the tickless mode will inevitably result in some tiny
  574. drift of the time maintained by the kernel with respect to calendar
  575. time*/
  576. ECLIC_DisableIRQ(SysTimer_IRQn);
  577. /* Determine if SysTimer Interrupt is not yet happened,
  578. (in which case an interrupt other than the SysTick
  579. must have brought the system out of sleep mode). */
  580. if (SysTimer_GetLoadValue() >= (XLastLoadValue + ulReloadValue)) {
  581. /* As the pending tick will be processed as soon as this
  582. function exits, the tick value maintained by the tick is stepped
  583. forward by one less than the time spent waiting. */
  584. ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
  585. FREERTOS_PORT_DEBUG("TickLess - SysTimer Interrupt Entered!\n");
  586. } else {
  587. /* Something other than the tick interrupt ended the sleep.
  588. Work out how long the sleep lasted rounded to complete tick
  589. periods (not the ulReload value which accounted for part
  590. ticks). */
  591. xModifiableIdleTime = SysTimer_GetLoadValue();
  592. if (xModifiableIdleTime > XLastLoadValue) {
  593. ulCompletedSysTickDecrements = (xModifiableIdleTime - XLastLoadValue);
  594. } else {
  595. ulCompletedSysTickDecrements = (xModifiableIdleTime + portMAX_BIT_NUMBER - XLastLoadValue);
  596. }
  597. /* How many complete tick periods passed while the processor
  598. was waiting? */
  599. ulCompleteTickPeriods = ulCompletedSysTickDecrements / ulTimerCountsForOneTick;
  600. /* The reload value is set to whatever fraction of a single tick
  601. period remains. */
  602. SysTick_Reload(ulTimerCountsForOneTick);
  603. FREERTOS_PORT_DEBUG("TickLess - External Interrupt Happened!\n");
  604. }
  605. FREERTOS_PORT_DEBUG("End TickLess %d\n", (uint32_t)ulCompleteTickPeriods);
  606. /* Restart SysTick */
  607. vTaskStepTick(ulCompleteTickPeriods);
  608. /* Exit with interrupts enabled. */
  609. ECLIC_EnableIRQ(SysTimer_IRQn);
  610. __enable_irq();
  611. }
  612. }
  613. #endif /* #if configUSE_TICKLESS_IDLE */
  614. /*-----------------------------------------------------------*/
  615. /*
  616. * Setup the systick timer to generate the tick interrupts at the required
  617. * frequency.
  618. */
  619. __attribute__((weak)) void vPortSetupTimerInterrupt(void)
  620. {
  621. /**
  622. * NOTICE:
  623. *
  624. * Nuclei CPU Systimer's tick and software interrupt
  625. * are required for FreeRTOS porting:
  626. * - Tick interrupt(SysTimer_IRQn) is a eclic non-vector interrupt, lowest interrupt level and priority
  627. * - Software interrupt(SysTimerSW_IRQn) is a eclic vector interrupt, lowest interrupt level and priority
  628. **/
  629. /* Calculate the constants required to configure the tick interrupt. */
  630. #if( configUSE_TICKLESS_IDLE == 1 )
  631. {
  632. ulTimerCountsForOneTick = (SYSTICK_TICK_CONST);
  633. xMaximumPossibleSuppressedTicks = portMAX_BIT_NUMBER / ulTimerCountsForOneTick;
  634. ulStoppedTimerCompensation = portMISSED_COUNTS_FACTOR / (configCPU_CLOCK_HZ / configSYSTICK_CLOCK_HZ);
  635. FREERTOS_PORT_DEBUG("CountsForOneTick, SuppressedTicks and TimerCompensation: %u, %u, %u\n", \
  636. (uint32_t)ulTimerCountsForOneTick, (uint32_t)xMaximumPossibleSuppressedTicks, (uint32_t)ulStoppedTimerCompensation);
  637. }
  638. #endif /* configUSE_TICKLESS_IDLE */
  639. TickType_t ticks = SYSTICK_TICK_CONST;
  640. /* Make SWI and SysTick the lowest priority interrupts. */
  641. /* Stop and clear the SysTimer. SysTimer as Non-Vector Interrupt */
  642. #if ( configNUMBER_OF_CORES > 1 )
  643. if (__get_hart_index() == BOOT_HARTID) {
  644. #else
  645. if (1) {
  646. #endif
  647. SysTick_Config(ticks);
  648. ECLIC_DisableIRQ(SysTimer_IRQn);
  649. ECLIC_SetLevelIRQ(SysTimer_IRQn, configKERNEL_INTERRUPT_PRIORITY);
  650. ECLIC_SetShvIRQ(SysTimer_IRQn, ECLIC_NON_VECTOR_INTERRUPT);
  651. ECLIC_EnableIRQ(SysTimer_IRQn);
  652. }
  653. /* Set SWI interrupt level to lowest level/priority, SysTimerSW as Vector Interrupt */
  654. ECLIC_SetShvIRQ(SysTimerSW_IRQn, ECLIC_VECTOR_INTERRUPT);
  655. ECLIC_SetLevelIRQ(SysTimerSW_IRQn, configKERNEL_INTERRUPT_PRIORITY);
  656. ECLIC_EnableIRQ(SysTimerSW_IRQn);
  657. }
  658. /*-----------------------------------------------------------*/
  659. /*-----------------------------------------------------------*/
  660. #if( configASSERT_DEFINED == 1 )
  661. void vPortValidateInterruptPriority(void)
  662. {
  663. #if configMAX_SYSCALL_INTERRUPT_PRIORITY < 255
  664. uint32_t ulCurrentInterrupt;
  665. uint8_t ucCurrentPriority;
  666. /* Obtain the number of the currently executing interrupt. */
  667. CSR_MCAUSE_Type mcause;
  668. mcause.d = __RV_CSR_READ(CSR_MCAUSE);
  669. /* Make sure current trap type is interrupt */
  670. configASSERT(mcause.b.interrupt == 1);
  671. if (mcause.b.interrupt) {
  672. ulCurrentInterrupt = mcause.b.exccode;
  673. /* Is the interrupt number a user defined interrupt? */
  674. if (ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER) {
  675. /* Look up the interrupt's priority. */
  676. ucCurrentPriority = __ECLIC_GetLevelIRQ(ulCurrentInterrupt);
  677. /* The following assertion will fail if a service routine (ISR) for
  678. an interrupt that has been assigned a priority above
  679. ucMaxSysCallPriority calls an ISR safe FreeRTOS API
  680. function. ISR safe FreeRTOS API functions must *only* be called
  681. from interrupts that have been assigned a priority at or below
  682. ucMaxSysCallPriority.
  683. Numerically low interrupt priority numbers represent logically high
  684. interrupt priorities, therefore the priority of the interrupt must
  685. be set to a value equal to or numerically *higher* than
  686. ucMaxSysCallPriority.
  687. Interrupts that use the FreeRTOS API must not be left at their
  688. default priority of zero as that is the highest possible priority,
  689. which is guaranteed to be above ucMaxSysCallPriority,
  690. and therefore also guaranteed to be invalid.
  691. FreeRTOS maintains separate thread and ISR API functions to ensure
  692. interrupt entry is as fast and simple as possible.
  693. The following links provide detailed information:
  694. http://www.freertos.org/FAQHelp.html */
  695. configASSERT(ucCurrentPriority <= ucMaxSysCallPriority);
  696. }
  697. }
  698. #endif
  699. }
  700. #endif /* configASSERT_DEFINED */