mirror of
https://github.com/espressif/ESP8266_RTOS_SDK.git
synced 2025-05-22 17:47:04 +08:00
339 lines
12 KiB
ArmAsm
339 lines
12 KiB
ArmAsm
/*******************************************************************************
|
|
Copyright (c) 2006-2009 by Tensilica Inc. ALL RIGHTS RESERVED.
|
|
These coded instructions, statements, and computer programs are the
|
|
copyrighted works and confidential proprietary information of Tensilica Inc.
|
|
They may not be modified, copied, reproduced, distributed, or disclosed to
|
|
third parties in any manner, medium, or form, in whole or in part, without
|
|
the prior written consent of Tensilica Inc.
|
|
--------------------------------------------------------------------------------
|
|
|
|
XTENSA CONTEXT SAVE AND RESTORE ROUTINES
|
|
|
|
Low-level Call0 functions for handling generic context save and restore of
|
|
registers not specifically addressed by the interrupt vectors and handlers.
|
|
Those registers (not handled by these functions) are PC, PS, A0, A1 (SP).
|
|
Except for the calls to RTOS functions, this code is generic to Xtensa.
|
|
|
|
Note that in Call0 ABI, interrupt handlers are expected to preserve the callee-
|
|
save regs (A12-A15), which is always the case if the handlers are coded in C.
|
|
However A12, A13 are made available as scratch registers for interrupt dispatch
|
|
code, so are presumed saved anyway, and are always restored even in Call0 ABI.
|
|
Only A14, A15 are truly handled as callee-save regs.
|
|
|
|
Because Xtensa is a configurable architecture, this port supports all user
|
|
generated configurations (except restrictions stated in the release notes).
|
|
This is accomplished by conditional compilation using macros and functions
|
|
defined in the Xtensa HAL (hardware adaptation layer) for your configuration.
|
|
Only the processor state included in your configuration is saved and restored,
|
|
including any processor state added by user configuration options or TIE.
|
|
|
|
*******************************************************************************/
|
|
|
|
/* Warn nicely if this file gets named with a lowercase .s instead of .S: */
|
|
#define NOERROR #
|
|
NOERROR: .error "C preprocessor needed for this file: make sure its filename\
|
|
ends in uppercase .S, or use xt-xcc's -x assembler-with-cpp option."
|
|
|
|
|
|
#include "freertos/xtensa_rtos.h"
|
|
|
|
// .section .iram.text
|
|
.section .text
|
|
|
|
/*******************************************************************************
|
|
|
|
_xt_context_save
|
|
|
|
!! MUST BE CALLED ONLY BY 'CALL0' INSTRUCTION !!
|
|
|
|
Saves all Xtensa processor state except PC, PS, A0, A1 (SP), A12, A13, in the
|
|
interrupt stack frame defined in xtensa_rtos.h.
|
|
Its counterpart is _xt_context_restore (which also restores A12, A13).
|
|
|
|
Caller is expected to have saved PC, PS, A0, A1 (SP), A12, A13 in the frame.
|
|
This function preserves A12 & A13 in order to provide the caller with 2 scratch
|
|
regs that need not be saved over the call to this function. The choice of which
|
|
2 regs to provide is governed by xthal_window_spill_nw and xthal_save_extra_nw,
|
|
to avoid moving data more than necessary. Caller can assign regs accordingly.
|
|
|
|
Entry Conditions:
|
|
A0 = Return address in caller.
|
|
A1 = Stack pointer of interrupted thread or handler ("interruptee").
|
|
Original A12, A13 have already been saved in the interrupt stack frame.
|
|
Other processor state except PC, PS, A0, A1 (SP), A12, A13, is as at the
|
|
point of interruption.
|
|
If windowed ABI, PS.EXCM = 1 (exceptions disabled).
|
|
|
|
Exit conditions:
|
|
A0 = Return address in caller.
|
|
A1 = Stack pointer of interrupted thread or handler ("interruptee").
|
|
A12, A13 as at entry (preserved).
|
|
If windowed ABI, PS.EXCM = 1 (exceptions disabled).
|
|
|
|
*******************************************************************************/
|
|
|
|
.global _xt_context_save
|
|
.type _xt_context_save,@function
|
|
.align 4
|
|
_xt_context_save:
|
|
|
|
s32i a2, sp, XT_STK_A2
|
|
s32i a3, sp, XT_STK_A3
|
|
s32i a4, sp, XT_STK_A4
|
|
s32i a5, sp, XT_STK_A5
|
|
s32i a6, sp, XT_STK_A6
|
|
s32i a7, sp, XT_STK_A7
|
|
s32i a8, sp, XT_STK_A8
|
|
s32i a9, sp, XT_STK_A9
|
|
s32i a10, sp, XT_STK_A10
|
|
s32i a11, sp, XT_STK_A11
|
|
|
|
/*
|
|
Call0 ABI callee-saved regs a12-15 do not need to be saved here.
|
|
a12-13 are the caller's responsibility so it can use them as scratch.
|
|
So only need to save a14-a15 here for Windowed ABI (not Call0).
|
|
*/
|
|
#ifndef __XTENSA_CALL0_ABI__
|
|
s32i a14, sp, XT_STK_A14
|
|
s32i a15, sp, XT_STK_A15
|
|
#endif
|
|
|
|
rsr a3, SAR
|
|
s32i a3, sp, XT_STK_SAR
|
|
|
|
#if XCHAL_HAVE_LOOPS
|
|
rsr a3, LBEG
|
|
s32i a3, sp, XT_STK_LBEG
|
|
rsr a3, LEND
|
|
s32i a3, sp, XT_STK_LEND
|
|
rsr a3, LCOUNT
|
|
s32i a3, sp, XT_STK_LCOUNT
|
|
#endif
|
|
|
|
#if XCHAL_EXTRA_SA_SIZE > 0 || !defined(__XTENSA_CALL0_ABI__)
|
|
mov a9, a0 /* preserve ret addr */
|
|
#endif
|
|
|
|
#ifndef __XTENSA_CALL0_ABI__
|
|
/*
|
|
To spill the reg windows, temp. need pre-interrupt stack ptr and a4-15.
|
|
Need to save a9,12,13 temporarily (in frame temps) and recover originals.
|
|
Interrupts need to be disabled below XCHAL_EXCM_LEVEL and window overflow
|
|
and underflow exceptions disabled (assured by PS.EXCM == 1).
|
|
*/
|
|
s32i a12, sp, XT_STK_TMP+0 /* temp. save stuff in stack frame */
|
|
s32i a13, sp, XT_STK_TMP+4
|
|
s32i a9, sp, XT_STK_TMP+8
|
|
l32i a12, sp, XT_STK_A12 /* recover original a9,12,13 */
|
|
l32i a13, sp, XT_STK_A13
|
|
l32i a9, sp, XT_STK_A9
|
|
addi sp, sp, XT_STK_FRMSZ /* restore the interruptee's SP */
|
|
call0 xthal_window_spill_nw /* preserves only a4,5,8,9,12,13 */
|
|
addi sp, sp, -XT_STK_FRMSZ
|
|
l32i a12, sp, XT_STK_TMP+0 /* recover stuff from stack frame */
|
|
l32i a13, sp, XT_STK_TMP+4
|
|
l32i a9, sp, XT_STK_TMP+8
|
|
#endif
|
|
|
|
#if XCHAL_EXTRA_SA_SIZE > 0
|
|
/*
|
|
NOTE: Normally the xthal_save_extra_nw macro only affects address
|
|
registers a2-a5. It is theoretically possible for Xtensa processor
|
|
designers to write TIE that causes more address registers to be
|
|
affected, but it is generally unlikely. If that ever happens,
|
|
more registers need to be saved/restored around this macro invocation.
|
|
Here we assume a9,12,13 are preserved.
|
|
Future Xtensa tools releases might limit the regs that can be affected.
|
|
*/
|
|
addi a2, sp, XT_STK_EXTRA /* where to save it */
|
|
call0 xthal_save_extra_nw /* destroys a0,2,3,4,5 */
|
|
#endif
|
|
|
|
#if XCHAL_EXTRA_SA_SIZE > 0 || !defined(__XTENSA_CALL0_ABI__)
|
|
mov a0, a9 /* retrieve ret addr */
|
|
#endif
|
|
|
|
ret
|
|
|
|
/*******************************************************************************
|
|
|
|
_xt_context_restore
|
|
|
|
!! MUST BE CALLED ONLY BY 'CALL0' INSTRUCTION !!
|
|
|
|
Restores all Xtensa processor state except PC, PS, A0, A1 (SP) (and in Call0
|
|
ABI, A14, A15 which are preserved by all interrupt handlers) from an interrupt
|
|
stack frame defined in xtensa_rtos.h .
|
|
Its counterpart is _xt_context_save (whose caller saved A12, A13).
|
|
|
|
Caller is responsible to restore PC, PS, A0, A1 (SP).
|
|
|
|
Entry Conditions:
|
|
A0 = Return address in caller.
|
|
A1 = Stack pointer of interrupted thread or handler ("interruptee").
|
|
|
|
Exit conditions:
|
|
A0 = Return address in caller.
|
|
A1 = Stack pointer of interrupted thread or handler ("interruptee").
|
|
Other processor state except PC, PS, A0, A1 (SP), is as at the point
|
|
of interruption.
|
|
|
|
*******************************************************************************/
|
|
|
|
.global _xt_context_restore
|
|
.type _xt_context_restore,@function
|
|
.align 4
|
|
_xt_context_restore:
|
|
|
|
#if XCHAL_EXTRA_SA_SIZE > 0
|
|
/*
|
|
NOTE: Normally the xthal_restore_extra_nw macro only affects address
|
|
registers a2-a5. It is theoretically possible for Xtensa processor
|
|
designers to write TIE that causes more address registers to be
|
|
affected, but it is generally unlikely. If that ever happens,
|
|
more registers need to be saved/restored around this macro invocation.
|
|
Here we only assume a13 is preserved.
|
|
Future Xtensa tools releases might limit the regs that can be affected.
|
|
*/
|
|
mov a13, a0 /* preserve ret addr */
|
|
addi a2, sp, XT_STK_EXTRA /* where to find it */
|
|
call0 xthal_restore_extra_nw /* destroys a0,2,3,4,5 */
|
|
mov a0, a13 /* retrieve ret addr */
|
|
#endif
|
|
|
|
#if XCHAL_HAVE_LOOPS
|
|
l32i a2, sp, XT_STK_LBEG
|
|
l32i a3, sp, XT_STK_LEND
|
|
wsr a2, LBEG
|
|
l32i a2, sp, XT_STK_LCOUNT
|
|
wsr a3, LEND
|
|
wsr a2, LCOUNT
|
|
#endif
|
|
|
|
l32i a3, sp, XT_STK_SAR
|
|
l32i a2, sp, XT_STK_A2
|
|
wsr a3, SAR
|
|
l32i a3, sp, XT_STK_A3
|
|
l32i a4, sp, XT_STK_A4
|
|
l32i a5, sp, XT_STK_A5
|
|
l32i a6, sp, XT_STK_A6
|
|
l32i a7, sp, XT_STK_A7
|
|
l32i a8, sp, XT_STK_A8
|
|
l32i a9, sp, XT_STK_A9
|
|
l32i a10, sp, XT_STK_A10
|
|
l32i a11, sp, XT_STK_A11
|
|
|
|
/*
|
|
Call0 ABI callee-saved regs a12-15 do not need to be restored here.
|
|
However a12-13 were saved for scratch before XT_RTOS_INT_ENTER(),
|
|
so need to be restored anyway, despite being callee-saved in Call0.
|
|
*/
|
|
l32i a12, sp, XT_STK_A12
|
|
l32i a13, sp, XT_STK_A13
|
|
#ifndef __XTENSA_CALL0_ABI__
|
|
l32i a14, sp, XT_STK_A14
|
|
l32i a15, sp, XT_STK_A15
|
|
#endif
|
|
|
|
ret
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
_xt_coproc_init
|
|
|
|
Initializes global co-processor management data, setting all co-processors
|
|
to "unowned". Leaves CPENABLE as it found it (does NOT clear it).
|
|
|
|
Called during initialization of the RTOS, before any threads run.
|
|
|
|
This may be called from normal Xtensa single-threaded application code which
|
|
might use co-processors. The Xtensa run-time initialization enables all
|
|
co-processors. They must remain enabled here, else a co-processor exception
|
|
might occur outside of a thread, which the exception handler doesn't expect.
|
|
|
|
Entry Conditions:
|
|
Xtensa single-threaded run-time environment is in effect.
|
|
No thread is yet running.
|
|
|
|
Exit conditions:
|
|
None.
|
|
|
|
Obeys ABI conventions per prototype:
|
|
void _xt_coproc_init(void)
|
|
|
|
*******************************************************************************/
|
|
|
|
#if XCHAL_CP_NUM > 0
|
|
|
|
.global _xt_coproc_init
|
|
.type _xt_coproc_init,@function
|
|
.align 4
|
|
_xt_coproc_init:
|
|
ENTRY0
|
|
|
|
/* Initialize thread co-processor ownerships to 0 (unowned). */
|
|
movi a2, _xt_coproc_owner_sa /* a2 = base of owner array */
|
|
addi a3, a2, XCHAL_CP_MAX << 2 /* a3 = top+1 of owner array */
|
|
movi a4, 0 /* a4 = 0 (unowned) */
|
|
1: s32i a4, a2, 0
|
|
addi a2, a2, 4
|
|
bltu a2, a3, 1b
|
|
|
|
RET0
|
|
|
|
#endif
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
_xt_coproc_release
|
|
|
|
Releases any and all co-processors owned by a given thread. The thread is
|
|
identified by it's co-processor state save area defined in xtensa_context.h .
|
|
|
|
Must be called before a thread's co-proc save area is deleted to avoid
|
|
memory corruption when the exception handler tries to save the state.
|
|
May be called when a thread terminates or completes but does not delete
|
|
the co-proc save area, to avoid the exception handler having to save the
|
|
thread's co-proc state before another thread can use it (optimization).
|
|
|
|
Entry Conditions:
|
|
A2 = Pointer to base of co-processor state save area.
|
|
|
|
Exit conditions:
|
|
None.
|
|
|
|
Obeys ABI conventions per prototype:
|
|
void _xt_coproc_release(void * coproc_sa_base)
|
|
|
|
*******************************************************************************/
|
|
|
|
#if XCHAL_CP_NUM > 0
|
|
|
|
.global _xt_coproc_release
|
|
.type _xt_coproc_release,@function
|
|
.align 4
|
|
_xt_coproc_release:
|
|
ENTRY0 /* a2 = base of save area */
|
|
|
|
movi a3, _xt_coproc_owner_sa /* a3 = base of owner array */
|
|
addi a4, a3, XCHAL_CP_MAX << 2 /* a4 = top+1 of owner array */
|
|
movi a5, 0 /* a5 = 0 (unowned) */
|
|
|
|
rsil a6, XCHAL_EXCM_LEVEL /* lock interrupts */
|
|
|
|
1: l32i a7, a3, 0 /* a7 = owner at a3 */
|
|
bne a2, a7, 2f /* if (coproc_sa_base == owner) */
|
|
s32i a5, a3, 0 /* owner = unowned */
|
|
2: addi a3, a3, 1<<2 /* a3 = next entry in owner array */
|
|
bltu a3, a4, 1b /* repeat until end of array */
|
|
|
|
3: wsr a6, PS /* restore interrupts */
|
|
|
|
RET0
|
|
|
|
#endif
|
|
|
|
|