portasm.S 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677
  1. /*
  2. //-----------------------------------------------------------------------------
  3. // Copyright (c) 2003-2015 Cadence Design Systems, Inc.
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining
  6. // a copy of this software and associated documentation files (the
  7. // "Software"), to deal in the Software without restriction, including
  8. // without limitation the rights to use, copy, modify, merge, publish,
  9. // distribute, sublicense, and/or sell copies of the Software, and to
  10. // permit persons to whom the Software is furnished to do so, subject to
  11. // the following conditions:
  12. //
  13. // The above copyright notice and this permission notice shall be included
  14. // in all copies or substantial portions of the Software.
  15. //
  16. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  17. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  18. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  19. // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  20. // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  21. // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  22. // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  23. //-----------------------------------------------------------------------------
  24. */
  25. #include "xtensa_rtos.h"
  26. #include "sdkconfig.h"
  27. #define TOPOFSTACK_OFFS 0x00 /* StackType_t *pxTopOfStack */
  28. #define CP_TOPOFSTACK_OFFS 0x04 /* xMPU_SETTINGS.coproc_area */
  29. .extern pxCurrentTCB
  30. /*
  31. *******************************************************************************
  32. * Interrupt stack. The size of the interrupt stack is determined by the config
  33. * parameter "configISR_STACK_SIZE" in FreeRTOSConfig.h
  34. *******************************************************************************
  35. */
  36. .data
  37. .align 16
  38. .global port_IntStack
  39. .global port_IntStackTop
  40. .global port_switch_flag
  41. port_IntStack:
  42. .space configISR_STACK_SIZE*portNUM_PROCESSORS /* This allocates stacks for each individual CPU. */
  43. port_IntStackTop:
  44. .word 0
  45. port_switch_flag:
  46. .space portNUM_PROCESSORS*4 /* One flag for each individual CPU. */
  47. .text
  48. /*
  49. *******************************************************************************
  50. * _frxt_setup_switch
  51. * void _frxt_setup_switch(void);
  52. *
  53. * Sets an internal flag indicating that a task switch is required on return
  54. * from interrupt handling.
  55. *
  56. *******************************************************************************
  57. */
  58. .global _frxt_setup_switch
  59. .type _frxt_setup_switch,@function
  60. .align 4
  61. _frxt_setup_switch:
  62. ENTRY(16)
  63. getcoreid a3
  64. movi a2, port_switch_flag
  65. addx4 a2, a3, a2
  66. movi a3, 1
  67. s32i a3, a2, 0
  68. RET(16)
  69. /*
  70. *******************************************************************************
  71. * _frxt_int_enter
  72. * void _frxt_int_enter(void)
  73. *
  74. * Implements the Xtensa RTOS porting layer's XT_RTOS_INT_ENTER function for
  75. * freeRTOS. Saves the rest of the interrupt context (not already saved).
  76. * May only be called from assembly code by the 'call0' instruction, with
  77. * interrupts disabled.
  78. * See the detailed description of the XT_RTOS_ENTER macro in xtensa_rtos.h.
  79. *
  80. *******************************************************************************
  81. */
  82. .globl _frxt_int_enter
  83. .type _frxt_int_enter,@function
  84. .align 4
  85. _frxt_int_enter:
  86. /* Save a12-13 in the stack frame as required by _xt_context_save. */
  87. s32i a12, a1, XT_STK_A12
  88. s32i a13, a1, XT_STK_A13
  89. /* Save return address in a safe place (free a0). */
  90. mov a12, a0
  91. /* Save the rest of the interrupted context (preserves A12-13). */
  92. call0 _xt_context_save
  93. /*
  94. Save interrupted task's SP in TCB only if not nesting.
  95. Manage nesting directly rather than call the generic IntEnter()
  96. (in windowed ABI we can't call a C function here anyway because PS.EXCM is still set).
  97. */
  98. getcoreid a4
  99. movi a2, port_xSchedulerRunning
  100. addx4 a2, a4, a2
  101. movi a3, port_interruptNesting
  102. addx4 a3, a4, a3
  103. l32i a2, a2, 0 /* a2 = port_xSchedulerRunning */
  104. beqz a2, 1f /* scheduler not running, no tasks */
  105. l32i a2, a3, 0 /* a2 = port_interruptNesting */
  106. addi a2, a2, 1 /* increment nesting count */
  107. s32i a2, a3, 0 /* save nesting count */
  108. bnei a2, 1, .Lnested /* !=0 before incr, so nested */
  109. movi a2, pxCurrentTCB
  110. addx4 a2, a4, a2
  111. l32i a2, a2, 0 /* a2 = current TCB */
  112. beqz a2, 1f
  113. s32i a1, a2, TOPOFSTACK_OFFS /* pxCurrentTCB->pxTopOfStack = SP */
  114. movi a1, port_IntStack+configISR_STACK_SIZE /* a1 = top of intr stack for CPU 0 */
  115. movi a2, configISR_STACK_SIZE /* add configISR_STACK_SIZE * cpu_num to arrive at top of stack for cpu_num */
  116. mull a2, a4, a2
  117. add a1, a1, a2 /* for current proc */
  118. #ifdef CONFIG_FREERTOS_FPU_IN_ISR
  119. #if XCHAL_CP_NUM > 0
  120. rsr a3, CPENABLE /* Restore thread scope CPENABLE */
  121. addi sp, sp,-4 /* ISR will manage FPU coprocessor by forcing */
  122. s32i a3, a1, 0 /* its trigger */
  123. #endif
  124. #endif
  125. .Lnested:
  126. 1:
  127. #ifdef CONFIG_FREERTOS_FPU_IN_ISR
  128. #if XCHAL_CP_NUM > 0
  129. movi a3, 0 /* whilst ISRs pending keep CPENABLE exception active */
  130. wsr a3, CPENABLE
  131. rsync
  132. #endif
  133. #endif
  134. mov a0, a12 /* restore return addr and return */
  135. ret
  136. /*
  137. *******************************************************************************
  138. * _frxt_int_exit
  139. * void _frxt_int_exit(void)
  140. *
  141. * Implements the Xtensa RTOS porting layer's XT_RTOS_INT_EXIT function for
  142. * FreeRTOS. If required, calls vPortYieldFromInt() to perform task context
  143. * switching, restore the (possibly) new task's context, and return to the
  144. * exit dispatcher saved in the task's stack frame at XT_STK_EXIT.
  145. * May only be called from assembly code by the 'call0' instruction. Does not
  146. * return to caller.
  147. * See the description of the XT_RTOS_ENTER macro in xtensa_rtos.h.
  148. *
  149. *******************************************************************************
  150. */
  151. .globl _frxt_int_exit
  152. .type _frxt_int_exit,@function
  153. .align 4
  154. _frxt_int_exit:
  155. getcoreid a4
  156. movi a2, port_xSchedulerRunning
  157. addx4 a2, a4, a2
  158. movi a3, port_interruptNesting
  159. addx4 a3, a4, a3
  160. rsil a0, XCHAL_EXCM_LEVEL /* lock out interrupts */
  161. l32i a2, a2, 0 /* a2 = port_xSchedulerRunning */
  162. beqz a2, .Lnoswitch /* scheduler not running, no tasks */
  163. l32i a2, a3, 0 /* a2 = port_interruptNesting */
  164. addi a2, a2, -1 /* decrement nesting count */
  165. s32i a2, a3, 0 /* save nesting count */
  166. bnez a2, .Lnesting /* !=0 after decr so still nested */
  167. #ifdef CONFIG_FREERTOS_FPU_IN_ISR
  168. #if XCHAL_CP_NUM > 0
  169. l32i a3, sp, 0 /* Grab last CPENABLE before leave ISR */
  170. addi sp, sp, 4
  171. wsr a3, CPENABLE
  172. rsync /* ensure CPENABLE was modified */
  173. #endif
  174. #endif
  175. movi a2, pxCurrentTCB
  176. addx4 a2, a4, a2
  177. l32i a2, a2, 0 /* a2 = current TCB */
  178. beqz a2, 1f /* no task ? go to dispatcher */
  179. l32i a1, a2, TOPOFSTACK_OFFS /* SP = pxCurrentTCB->pxTopOfStack */
  180. movi a2, port_switch_flag /* address of switch flag */
  181. addx4 a2, a4, a2 /* point to flag for this cpu */
  182. l32i a3, a2, 0 /* a3 = port_switch_flag */
  183. beqz a3, .Lnoswitch /* flag = 0 means no switch reqd */
  184. movi a3, 0
  185. s32i a3, a2, 0 /* zero out the flag for next time */
  186. 1:
  187. /*
  188. Call0 ABI callee-saved regs a12-15 need to be saved before possible preemption.
  189. However a12-13 were already saved by _frxt_int_enter().
  190. */
  191. #ifdef __XTENSA_CALL0_ABI__
  192. s32i a14, a1, XT_STK_A14
  193. s32i a15, a1, XT_STK_A15
  194. #endif
  195. #ifdef __XTENSA_CALL0_ABI__
  196. call0 vPortYieldFromInt /* call dispatch inside the function; never returns */
  197. #else
  198. call4 vPortYieldFromInt /* this one returns */
  199. call0 _frxt_dispatch /* tail-call dispatcher */
  200. /* Never returns here. */
  201. #endif
  202. .Lnoswitch:
  203. /*
  204. If we came here then about to resume the interrupted task.
  205. */
  206. .Lnesting:
  207. /*
  208. We come here only if there was no context switch, that is if this
  209. is a nested interrupt, or the interrupted task was not preempted.
  210. In either case there's no need to load the SP.
  211. */
  212. /* Restore full context from interrupt stack frame */
  213. call0 _xt_context_restore
  214. /*
  215. Must return via the exit dispatcher corresponding to the entrypoint from which
  216. this was called. Interruptee's A0, A1, PS, PC are restored and the interrupt
  217. stack frame is deallocated in the exit dispatcher.
  218. */
  219. l32i a0, a1, XT_STK_EXIT
  220. ret
  221. /*
  222. **********************************************************************************************************
  223. * _frxt_timer_int
  224. * void _frxt_timer_int(void)
  225. *
  226. * Implements the Xtensa RTOS porting layer's XT_RTOS_TIMER_INT function for FreeRTOS.
  227. * Called every timer interrupt.
  228. * Manages the tick timer and calls xPortSysTickHandler() every tick.
  229. * See the detailed description of the XT_RTOS_ENTER macro in xtensa_rtos.h.
  230. *
  231. * Callable from C (obeys ABI conventions). Implemented in assmebly code for performance.
  232. *
  233. **********************************************************************************************************
  234. */
  235. .globl _frxt_timer_int
  236. .type _frxt_timer_int,@function
  237. .align 4
  238. _frxt_timer_int:
  239. /*
  240. Xtensa timers work by comparing a cycle counter with a preset value. Once the match occurs
  241. an interrupt is generated, and the handler has to set a new cycle count into the comparator.
  242. To avoid clock drift due to interrupt latency, the new cycle count is computed from the old,
  243. not the time the interrupt was serviced. However if a timer interrupt is ever serviced more
  244. than one tick late, it is necessary to process multiple ticks until the new cycle count is
  245. in the future, otherwise the next timer interrupt would not occur until after the cycle
  246. counter had wrapped (2^32 cycles later).
  247. do {
  248. ticks++;
  249. old_ccompare = read_ccompare_i();
  250. write_ccompare_i( old_ccompare + divisor );
  251. service one tick;
  252. diff = read_ccount() - old_ccompare;
  253. } while ( diff > divisor );
  254. */
  255. ENTRY(16)
  256. #ifdef CONFIG_PM_TRACE
  257. movi a6, 1 /* = ESP_PM_TRACE_TICK */
  258. getcoreid a7
  259. call4 esp_pm_trace_enter
  260. #endif // CONFIG_PM_TRACE
  261. .L_xt_timer_int_catchup:
  262. /* Update the timer comparator for the next tick. */
  263. #ifdef XT_CLOCK_FREQ
  264. movi a2, XT_TICK_DIVISOR /* a2 = comparator increment */
  265. #else
  266. movi a3, _xt_tick_divisor
  267. l32i a2, a3, 0 /* a2 = comparator increment */
  268. #endif
  269. rsr a3, XT_CCOMPARE /* a3 = old comparator value */
  270. add a4, a3, a2 /* a4 = new comparator value */
  271. wsr a4, XT_CCOMPARE /* update comp. and clear interrupt */
  272. esync
  273. #ifdef __XTENSA_CALL0_ABI__
  274. /* Preserve a2 and a3 across C calls. */
  275. s32i a2, sp, 4
  276. s32i a3, sp, 8
  277. #endif
  278. /* Call the FreeRTOS tick handler (see port.c). */
  279. #ifdef __XTENSA_CALL0_ABI__
  280. call0 xPortSysTickHandler
  281. #else
  282. call4 xPortSysTickHandler
  283. #endif
  284. #ifdef __XTENSA_CALL0_ABI__
  285. /* Restore a2 and a3. */
  286. l32i a2, sp, 4
  287. l32i a3, sp, 8
  288. #endif
  289. /* Check if we need to process more ticks to catch up. */
  290. esync /* ensure comparator update complete */
  291. rsr a4, CCOUNT /* a4 = cycle count */
  292. sub a4, a4, a3 /* diff = ccount - old comparator */
  293. blt a2, a4, .L_xt_timer_int_catchup /* repeat while diff > divisor */
  294. #ifdef CONFIG_PM_TRACE
  295. movi a6, 1 /* = ESP_PM_TRACE_TICK */
  296. getcoreid a7
  297. call4 esp_pm_trace_exit
  298. #endif // CONFIG_PM_TRACE
  299. RET(16)
  300. /*
  301. **********************************************************************************************************
  302. * _frxt_tick_timer_init
  303. * void _frxt_tick_timer_init(void)
  304. *
  305. * Initialize timer and timer interrrupt handler (_xt_tick_divisor_init() has already been been called).
  306. * Callable from C (obeys ABI conventions on entry).
  307. *
  308. **********************************************************************************************************
  309. */
  310. .globl _frxt_tick_timer_init
  311. .type _frxt_tick_timer_init,@function
  312. .align 4
  313. _frxt_tick_timer_init:
  314. ENTRY(16)
  315. /* Set up the periodic tick timer (assume enough time to complete init). */
  316. #ifdef XT_CLOCK_FREQ
  317. movi a3, XT_TICK_DIVISOR
  318. #else
  319. movi a2, _xt_tick_divisor
  320. l32i a3, a2, 0
  321. #endif
  322. rsr a2, CCOUNT /* current cycle count */
  323. add a2, a2, a3 /* time of first timer interrupt */
  324. wsr a2, XT_CCOMPARE /* set the comparator */
  325. /*
  326. Enable the timer interrupt at the device level. Don't write directly
  327. to the INTENABLE register because it may be virtualized.
  328. */
  329. #ifdef __XTENSA_CALL0_ABI__
  330. movi a2, XT_TIMER_INTEN
  331. call0 xt_ints_on
  332. #else
  333. movi a6, XT_TIMER_INTEN
  334. call4 xt_ints_on
  335. #endif
  336. RET(16)
  337. /*
  338. **********************************************************************************************************
  339. * DISPATCH THE HIGH READY TASK
  340. * void _frxt_dispatch(void)
  341. *
  342. * Switch context to the highest priority ready task, restore its state and dispatch control to it.
  343. *
  344. * This is a common dispatcher that acts as a shared exit path for all the context switch functions
  345. * including vPortYield() and vPortYieldFromInt(), all of which tail-call this dispatcher
  346. * (for windowed ABI vPortYieldFromInt() calls it indirectly via _frxt_int_exit() ).
  347. *
  348. * The Xtensa port uses different stack frames for solicited and unsolicited task suspension (see
  349. * comments on stack frames in xtensa_context.h). This function restores the state accordingly.
  350. * If restoring a task that solicited entry, restores the minimal state and leaves CPENABLE clear.
  351. * If restoring a task that was preempted, restores all state including the task's CPENABLE.
  352. *
  353. * Entry:
  354. * pxCurrentTCB points to the TCB of the task to suspend,
  355. * Because it is tail-called without a true function entrypoint, it needs no 'entry' instruction.
  356. *
  357. * Exit:
  358. * If incoming task called vPortYield() (solicited), this function returns as if from vPortYield().
  359. * If incoming task was preempted by an interrupt, this function jumps to exit dispatcher.
  360. *
  361. **********************************************************************************************************
  362. */
  363. .globl _frxt_dispatch
  364. .type _frxt_dispatch,@function
  365. .align 4
  366. _frxt_dispatch:
  367. #ifdef __XTENSA_CALL0_ABI__
  368. call0 vTaskSwitchContext // Get next TCB to resume
  369. movi a2, pxCurrentTCB
  370. getcoreid a3
  371. addx4 a2, a3, a2
  372. #else
  373. call4 vTaskSwitchContext // Get next TCB to resume
  374. movi a2, pxCurrentTCB
  375. getcoreid a3
  376. addx4 a2, a3, a2
  377. #endif
  378. l32i a3, a2, 0
  379. l32i sp, a3, TOPOFSTACK_OFFS /* SP = next_TCB->pxTopOfStack; */
  380. s32i a3, a2, 0
  381. /* Determine the type of stack frame. */
  382. l32i a2, sp, XT_STK_EXIT /* exit dispatcher or solicited flag */
  383. bnez a2, .L_frxt_dispatch_stk
  384. .L_frxt_dispatch_sol:
  385. /* Solicited stack frame. Restore minimal context and return from vPortYield(). */
  386. l32i a3, sp, XT_SOL_PS
  387. #ifdef __XTENSA_CALL0_ABI__
  388. l32i a12, sp, XT_SOL_A12
  389. l32i a13, sp, XT_SOL_A13
  390. l32i a14, sp, XT_SOL_A14
  391. l32i a15, sp, XT_SOL_A15
  392. #endif
  393. l32i a0, sp, XT_SOL_PC
  394. #if XCHAL_CP_NUM > 0
  395. /* Ensure wsr.CPENABLE is complete (should be, it was cleared on entry). */
  396. rsync
  397. #endif
  398. /* As soons as PS is restored, interrupts can happen. No need to sync PS. */
  399. wsr a3, PS
  400. #ifdef __XTENSA_CALL0_ABI__
  401. addi sp, sp, XT_SOL_FRMSZ
  402. ret
  403. #else
  404. retw
  405. #endif
  406. .L_frxt_dispatch_stk:
  407. #if XCHAL_CP_NUM > 0
  408. /* Restore CPENABLE from task's co-processor save area. */
  409. movi a3, pxCurrentTCB /* cp_state = */
  410. getcoreid a2
  411. addx4 a3, a2, a3
  412. l32i a3, a3, 0
  413. l32i a2, a3, CP_TOPOFSTACK_OFFS /* StackType_t *pxStack; */
  414. l16ui a3, a2, XT_CPENABLE /* CPENABLE = cp_state->cpenable; */
  415. wsr a3, CPENABLE
  416. #endif
  417. /* Interrupt stack frame. Restore full context and return to exit dispatcher. */
  418. call0 _xt_context_restore
  419. /* In Call0 ABI, restore callee-saved regs (A12, A13 already restored). */
  420. #ifdef __XTENSA_CALL0_ABI__
  421. l32i a14, sp, XT_STK_A14
  422. l32i a15, sp, XT_STK_A15
  423. #endif
  424. #if XCHAL_CP_NUM > 0
  425. /* Ensure wsr.CPENABLE has completed. */
  426. rsync
  427. #endif
  428. /*
  429. Must return via the exit dispatcher corresponding to the entrypoint from which
  430. this was called. Interruptee's A0, A1, PS, PC are restored and the interrupt
  431. stack frame is deallocated in the exit dispatcher.
  432. */
  433. l32i a0, sp, XT_STK_EXIT
  434. ret
  435. /*
  436. **********************************************************************************************************
  437. * PERFORM A SOLICTED CONTEXT SWITCH (from a task)
  438. * void vPortYield(void)
  439. *
  440. * This function saves the minimal state needed for a solicited task suspension, clears CPENABLE,
  441. * then tail-calls the dispatcher _frxt_dispatch() to perform the actual context switch
  442. *
  443. * At Entry:
  444. * pxCurrentTCB points to the TCB of the task to suspend
  445. * Callable from C (obeys ABI conventions on entry).
  446. *
  447. * Does not return to caller.
  448. *
  449. **********************************************************************************************************
  450. */
  451. .globl vPortYield
  452. .type vPortYield,@function
  453. .align 4
  454. vPortYield:
  455. #ifdef __XTENSA_CALL0_ABI__
  456. addi sp, sp, -XT_SOL_FRMSZ
  457. #else
  458. entry sp, XT_SOL_FRMSZ
  459. #endif
  460. rsr a2, PS
  461. s32i a0, sp, XT_SOL_PC
  462. s32i a2, sp, XT_SOL_PS
  463. #ifdef __XTENSA_CALL0_ABI__
  464. s32i a12, sp, XT_SOL_A12 /* save callee-saved registers */
  465. s32i a13, sp, XT_SOL_A13
  466. s32i a14, sp, XT_SOL_A14
  467. s32i a15, sp, XT_SOL_A15
  468. #else
  469. /* Spill register windows. Calling xthal_window_spill() causes extra */
  470. /* spills and reloads, so we will set things up to call the _nw version */
  471. /* instead to save cycles. */
  472. movi a6, ~(PS_WOE_MASK|PS_INTLEVEL_MASK) /* spills a4-a7 if needed */
  473. and a2, a2, a6 /* clear WOE, INTLEVEL */
  474. addi a2, a2, XCHAL_EXCM_LEVEL /* set INTLEVEL */
  475. wsr a2, PS
  476. rsync
  477. call0 xthal_window_spill_nw
  478. l32i a2, sp, XT_SOL_PS /* restore PS */
  479. wsr a2, PS
  480. #endif
  481. rsil a2, XCHAL_EXCM_LEVEL /* disable low/med interrupts */
  482. #if XCHAL_CP_NUM > 0
  483. /* Save coprocessor callee-saved state (if any). At this point CPENABLE */
  484. /* should still reflect which CPs were in use (enabled). */
  485. call0 _xt_coproc_savecs
  486. #endif
  487. movi a2, pxCurrentTCB
  488. getcoreid a3
  489. addx4 a2, a3, a2
  490. l32i a2, a2, 0 /* a2 = pxCurrentTCB */
  491. movi a3, 0
  492. s32i a3, sp, XT_SOL_EXIT /* 0 to flag as solicited frame */
  493. s32i sp, a2, TOPOFSTACK_OFFS /* pxCurrentTCB->pxTopOfStack = SP */
  494. #if XCHAL_CP_NUM > 0
  495. /* Clear CPENABLE, also in task's co-processor state save area. */
  496. l32i a2, a2, CP_TOPOFSTACK_OFFS /* a2 = pxCurrentTCB->cp_state */
  497. movi a3, 0
  498. wsr a3, CPENABLE
  499. beqz a2, 1f
  500. s16i a3, a2, XT_CPENABLE /* clear saved cpenable */
  501. 1:
  502. #endif
  503. /* Tail-call dispatcher. */
  504. call0 _frxt_dispatch
  505. /* Never reaches here. */
  506. /*
  507. **********************************************************************************************************
  508. * PERFORM AN UNSOLICITED CONTEXT SWITCH (from an interrupt)
  509. * void vPortYieldFromInt(void)
  510. *
  511. * This calls the context switch hook (removed), saves and clears CPENABLE, then tail-calls the dispatcher
  512. * _frxt_dispatch() to perform the actual context switch.
  513. *
  514. * At Entry:
  515. * Interrupted task context has been saved in an interrupt stack frame at pxCurrentTCB->pxTopOfStack.
  516. * pxCurrentTCB points to the TCB of the task to suspend,
  517. * Callable from C (obeys ABI conventions on entry).
  518. *
  519. * At Exit:
  520. * Windowed ABI defers the actual context switch until the stack is unwound to interrupt entry.
  521. * Call0 ABI tail-calls the dispatcher directly (no need to unwind) so does not return to caller.
  522. *
  523. **********************************************************************************************************
  524. */
  525. .globl vPortYieldFromInt
  526. .type vPortYieldFromInt,@function
  527. .align 4
  528. vPortYieldFromInt:
  529. ENTRY(16)
  530. #if XCHAL_CP_NUM > 0
  531. /* Save CPENABLE in task's co-processor save area, and clear CPENABLE. */
  532. movi a3, pxCurrentTCB /* cp_state = */
  533. getcoreid a2
  534. addx4 a3, a2, a3
  535. l32i a3, a3, 0
  536. l32i a2, a3, CP_TOPOFSTACK_OFFS
  537. rsr a3, CPENABLE
  538. s16i a3, a2, XT_CPENABLE /* cp_state->cpenable = CPENABLE; */
  539. movi a3, 0
  540. wsr a3, CPENABLE /* disable all co-processors */
  541. #endif
  542. #ifdef __XTENSA_CALL0_ABI__
  543. /* Tail-call dispatcher. */
  544. call0 _frxt_dispatch
  545. /* Never reaches here. */
  546. #else
  547. RET(16)
  548. #endif
  549. /*
  550. **********************************************************************************************************
  551. * _frxt_task_coproc_state
  552. * void _frxt_task_coproc_state(void)
  553. *
  554. * Implements the Xtensa RTOS porting layer's XT_RTOS_CP_STATE function for FreeRTOS.
  555. *
  556. * May only be called when a task is running, not within an interrupt handler (returns 0 in that case).
  557. * May only be called from assembly code by the 'call0' instruction. Does NOT obey ABI conventions.
  558. * Returns in A15 a pointer to the base of the co-processor state save area for the current task.
  559. * See the detailed description of the XT_RTOS_ENTER macro in xtensa_rtos.h.
  560. *
  561. **********************************************************************************************************
  562. */
  563. #if XCHAL_CP_NUM > 0
  564. .globl _frxt_task_coproc_state
  565. .type _frxt_task_coproc_state,@function
  566. .align 4
  567. _frxt_task_coproc_state:
  568. /* We can use a3 as a scratchpad, the instances of code calling XT_RTOS_CP_STATE don't seem to need it saved. */
  569. getcoreid a3
  570. movi a15, port_xSchedulerRunning /* if (port_xSchedulerRunning */
  571. addx4 a15, a3,a15
  572. l32i a15, a15, 0
  573. beqz a15, 1f
  574. movi a15, port_interruptNesting /* && port_interruptNesting == 0 */
  575. addx4 a15, a3, a15
  576. l32i a15, a15, 0
  577. bnez a15, 1f
  578. movi a15, pxCurrentTCB
  579. addx4 a15, a3, a15
  580. l32i a15, a15, 0 /* && pxCurrentTCB != 0) { */
  581. beqz a15, 2f
  582. l32i a15, a15, CP_TOPOFSTACK_OFFS
  583. ret
  584. 1: movi a15, 0
  585. 2: ret
  586. #endif /* XCHAL_CP_NUM > 0 */