portasm.S 22 KB

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