os_cpu_port.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. #include <stdio.h>
  2. #include "ucos_ii.h"
  3. #include "nuclei_sdk_soc.h"
  4. #include "os_cpu_port.h"
  5. #ifndef configSYSTICK_CLOCK_HZ
  6. #define configSYSTICK_CLOCK_HZ SOC_TIMER_FREQ
  7. #endif
  8. #ifndef configKERNEL_INTERRUPT_PRIORITY
  9. #define configKERNEL_INTERRUPT_PRIORITY 0
  10. #endif
  11. #define SYSTICK_TICK_CONST (configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ)
  12. /* Constants required to set up the initial stack. */
  13. #define portINITIAL_MSTATUS ( MSTATUS_MPP | MSTATUS_MPIE | MSTATUS_FS_INITIAL | MSTATUS_VS_INITIAL)
  14. #define portINITIAL_EXC_RETURN ( 0xfffffffd )
  15. /* Let the user override the pre-loading of the initial RA with the address of
  16. prvTaskExit() in case it messes up unwinding of the stack in the
  17. debugger. */
  18. #ifdef configTASK_RETURN_ADDRESS
  19. #define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS
  20. #else
  21. #define portTASK_RETURN_ADDRESS prvTaskExit
  22. #endif
  23. /*
  24. * Setup the timer to generate the tick interrupts. The implementation in this
  25. * file is weak to allow application writers to change the timer used to
  26. * generate the tick interrupt.
  27. */
  28. void vPortSetupTimerInterrupt(void);
  29. /*
  30. * Exception handlers.
  31. */
  32. #define xPortSysTickHandler eclic_mtip_handler
  33. void xPortSysTickHandler(void);
  34. /*
  35. * Start first task is a separate function so it can be tested in isolation.
  36. */
  37. extern void prvPortStartFirstTask(void) __attribute__((naked));
  38. /*
  39. * Used to catch tasks that attempt to return from their implementing function.
  40. */
  41. static void prvTaskExit(void);
  42. /*-----------------------------------------------------------*/
  43. /*
  44. *********************************************************************************************************
  45. * INITIALIZE A TASK'S STACK
  46. *
  47. * Description: This function is called by either OSTaskCreate() or OSTaskCreateExt() to initialize the
  48. * stack frame of the task being created. This function is highly processor specific.
  49. *
  50. * Arguments : task is a pointer to the task code
  51. *
  52. * p_arg is a pointer to a user supplied data area that will be passed to the task
  53. * when the task first executes.
  54. *
  55. * p_tos is a pointer to the top of stack. It is assumed that 'ptos' points to
  56. * a 'free' entry on the task stack. If OS_STK_GROWTH is set to 1 then
  57. * 'ptos' will contain the HIGHEST valid address of the stack. Similarly, if
  58. * OS_STK_GROWTH is set to 0, the 'ptos' will contains the LOWEST valid address
  59. * of the stack.
  60. *
  61. * opt specifies options that can be used to alter the behavior of OSTaskStkInit().
  62. * (see uCOS_II.H for OS_TASK_OPT_xxx).
  63. *
  64. * Returns : Always returns the location of the new top-of-stack once the processor registers have
  65. * been placed on the stack in the proper order.
  66. *
  67. * Note(s) : (1) Interrupts are enabled when task starts executing.
  68. *
  69. * (2) There is no need to save register x0 since it is a hard-wired zero.
  70. *
  71. * (3) RISC-V calling convention register usage:
  72. *
  73. * +-------------+-------------+----------------------------------+
  74. * | Register | ABI Name | Description |
  75. * +-------------+-------------+----------------------------------+
  76. * | x31 - x28 | t6 - t3 | Temporaries |
  77. * +-------------+-------------+----------------------------------+
  78. * | x27 - x18 | s11 - s2 | Saved registers |
  79. * +-------------+-------------+----------------------------------+
  80. * | x17 - x12 | a7 - a2 | Function arguments |
  81. * +-------------+-------------+----------------------------------+
  82. * | x11 - x10 | a1 - a0 | Function arguments/return values |
  83. * +-------------+-------------+----------------------------------+
  84. * | x9 | s1 | Saved register |
  85. * +-------------+-------------+----------------------------------+
  86. * | x8 | s0/fp | Saved register/frame pointer |
  87. * +-------------+-------------+----------------------------------+
  88. * | x7 - x5 | t2 - t0 | Temporaries |
  89. * +-------------+-------------+----------------------------------+
  90. * | x4 | tp | Thread pointer |
  91. * +-------------+-------------+----------------------------------+
  92. * | x3 | gp | Global pointer |
  93. * +-------------+-------------+----------------------------------+
  94. * | x2 | sp | Stack pointer |
  95. * +-------------+-------------+----------------------------------+
  96. * | x1 | ra | return address |
  97. * +-------------+-------------+----------------------------------+
  98. * | x0 | zero | Hard-wired zero |
  99. * +-------------+-------------+----------------------------------+
  100. *
  101. * As per the standard RISC-V ABI pxTopcOfStack is passed in in a0, pxCode in
  102. * a1, and pvParameters in a2. The new top of stack is passed out in a0.
  103. *
  104. * The RISC-V context is saved rtos tasks in the following stack frame,
  105. * where the global and thread pointers are currently assumed to be constant so
  106. * are not saved:
  107. *
  108. * mstatus
  109. * #ifndef __riscv_32e
  110. * rsv1
  111. * rsv0
  112. * x31
  113. * x30
  114. * x29
  115. * x28
  116. * x27
  117. * x26
  118. * x25
  119. * x24
  120. * x23
  121. * x22
  122. * x21
  123. * x20
  124. * x19
  125. * x18
  126. * x17
  127. * x16
  128. * #endif
  129. * x15
  130. * x14
  131. * x13
  132. * x12
  133. * x11
  134. * pvParameters
  135. * x9
  136. * x8
  137. * x7
  138. * x6
  139. * x5
  140. * portTASK_RETURN_ADDRESS
  141. * pxCode
  142. */
  143. OS_STK* OSTaskStkInit(void (*task)(void* pd), void* pdata, OS_STK* ptos, INT16U opt)
  144. {
  145. /* Simulate the stack frame as it would be created by a context switch
  146. interrupt. */
  147. /* Stack frame size 32 REGBYTES(4/8) for most cases, but for ilp32e mode, it's 14 REGBYTES(4) */
  148. // Force stack 8byte align for double floating point case
  149. OS_STK* pxTopOfStack = (OS_STK*)(((unsigned long)ptos) & (~(unsigned long)(portBYTE_ALIGNMENT - 1)));
  150. /* Offset added to account for the way the MCU uses the stack on entry/exit
  151. of interrupts, and to ensure alignment. */
  152. pxTopOfStack--;
  153. *pxTopOfStack = portINITIAL_MSTATUS; /* MSTATUS */
  154. /* Save code space by skipping register initialisation. */
  155. #ifndef __riscv_32e
  156. pxTopOfStack -= 24; /* X11 - X31, and 2 reserved regs space. */
  157. #else
  158. pxTopOfStack -= 6; /* X11 - X15. */
  159. #endif
  160. *pxTopOfStack = (StackType_t) pdata; /* X10/A0 */
  161. pxTopOfStack -= 6; /* X5 - X9 */
  162. *pxTopOfStack = (StackType_t) portTASK_RETURN_ADDRESS; /* RA, X1 */
  163. pxTopOfStack --;
  164. *pxTopOfStack = ((StackType_t) task) ; /* PC */
  165. return pxTopOfStack;
  166. }
  167. static void prvTaskExit(void)
  168. {
  169. while (1) {
  170. __WFI();
  171. }
  172. }
  173. /*
  174. * See header file for description.
  175. */
  176. void OSStartHighRdy(void)
  177. {
  178. __disable_irq();
  179. /* Start the timer that generates the tick ISR. Interrupts are disabled
  180. here already. */
  181. vPortSetupTimerInterrupt();
  182. /* Mark OSRunning to True */
  183. OSRunning = OS_TRUE;
  184. #if (OS_CPU_HOOKS_EN > 0) && (OS_TASK_SW_HOOK_EN > 0)
  185. /* Call OSTaskSwHook */
  186. OSTaskSwHook();
  187. #endif
  188. // Enable interrupt and task sp swap
  189. #if defined(ECLIC_HW_CTX_AUTO) && defined(CFG_HAS_ECLICV2)
  190. __RV_CSR_SET(CSR_MECLIC_CTL, MECLIC_CTL_TSP_EN);
  191. #endif
  192. /* Start the first task. */
  193. prvPortStartFirstTask();
  194. /* Should never get here as the tasks will now be executing! */
  195. prvTaskExit();
  196. /* Should not get here! */
  197. return;
  198. }
  199. /*-----------------------------------------------------------*/
  200. void xPortTaskSwitch(void)
  201. {
  202. /* Clear Software IRQ, A MUST */
  203. SysTimer_ClearSWIRQ();
  204. #if (OS_CPU_HOOKS_EN > 0) && (OS_TASK_SW_HOOK_EN > 0)
  205. /* Call OSTaskSwHook */
  206. OSTaskSwHook();
  207. #endif
  208. OSPrioCur = OSPrioHighRdy;
  209. OSTCBCur = OSTCBHighRdy;
  210. }
  211. /*-----------------------------------------------------------*/
  212. /*
  213. *********************************************************************************************************
  214. * SYS TICK HANDLER
  215. *
  216. * Description: Handle the system tick (SysTick) interrupt, which is used to generate the uC/OS-II tick
  217. * interrupt.
  218. *
  219. * Arguments : None.
  220. *
  221. * Note(s) : This function is defined with weak linking in 'riscv_hal_stubs.c' so that it can be
  222. * overridden by the kernel port with same prototype
  223. *********************************************************************************************************
  224. */
  225. void xPortSysTickHandler(void)
  226. {
  227. #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
  228. OS_CPU_SR cpu_sr;
  229. #endif
  230. /* The SysTick runs at the lowest interrupt priority, so when this interrupt
  231. executes all interrupts must be unmasked. There is therefore no need to
  232. save and then restore the interrupt mask value as its value is already
  233. known. */
  234. OS_ENTER_CRITICAL();
  235. SysTick_Reload(SYSTICK_TICK_CONST);
  236. OSIntEnter(); /* Tell uC/OS-II that we are starting an ISR */
  237. OS_EXIT_CRITICAL();
  238. OSTimeTick(); /* Call uC/OS-II's OSTimeTick() */
  239. OSIntExit(); /* Tell uC/OS-II that we are leaving the ISR */
  240. }
  241. /*-----------------------------------------------------------*/
  242. /*
  243. * Setup the systick timer to generate the tick interrupts at the required
  244. * frequency.
  245. */
  246. __attribute__((weak)) void vPortSetupTimerInterrupt(void)
  247. {
  248. TickType_t ticks = SYSTICK_TICK_CONST;
  249. /* Make SWI and SysTick the lowest priority interrupts. */
  250. /* Stop and clear the SysTimer. SysTimer as Non-Vector Interrupt */
  251. SysTick_Config(ticks);
  252. ECLIC_DisableIRQ(SysTimer_IRQn);
  253. ECLIC_SetLevelIRQ(SysTimer_IRQn, configKERNEL_INTERRUPT_PRIORITY);
  254. ECLIC_SetShvIRQ(SysTimer_IRQn, ECLIC_NON_VECTOR_INTERRUPT);
  255. ECLIC_EnableIRQ(SysTimer_IRQn);
  256. /* Set SWI interrupt level to lowest level/priority, SysTimerSW as Vector Interrupt */
  257. ECLIC_SetShvIRQ(SysTimerSW_IRQn, ECLIC_VECTOR_INTERRUPT);
  258. ECLIC_SetLevelIRQ(SysTimerSW_IRQn, configKERNEL_INTERRUPT_PRIORITY);
  259. ECLIC_EnableIRQ(SysTimerSW_IRQn);
  260. }
  261. /*-----------------------------------------------------------*/