473 lines
14 KiB
ArmAsm
473 lines
14 KiB
ArmAsm
/****************************************************************************
|
|
* arch/xtensa/src/common/xtensa_coproc.S
|
|
*
|
|
* Adapted from use in NuttX by:
|
|
*
|
|
* Copyright (C) 2016 Gregory Nutt. All rights reserved.
|
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
|
*
|
|
* Derives from logic originally provided by Cadence Design Systems Inc.
|
|
*
|
|
* Copyright (c) 2006-2015 Cadence Design Systems Inc.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining
|
|
* a copy of this software and associated documentation files (the
|
|
* "Software"), to deal in the Software without restriction, including
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
* permit persons to whom the Software is furnished to do so, subject to
|
|
* the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included
|
|
* in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*
|
|
****************************************************************************/
|
|
|
|
.file "xtensa_coproc.S"
|
|
|
|
/****************************************************************************
|
|
* Included Files
|
|
****************************************************************************/
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
#include <arch/xtensa/core.h>
|
|
#include <arch/xtensa/xtensa_coproc.h>
|
|
#include <arch/xtensa/xtensa_specregs.h>
|
|
#include <arch/chip/core-isa.h>
|
|
#include <arch/chip/tie.h>
|
|
#include <arch/chip/tie-asm.h>
|
|
|
|
#include "xtensa_abi.h"
|
|
|
|
#if XCHAL_CP_NUM > 0
|
|
|
|
/****************************************************************************
|
|
* Public Data
|
|
****************************************************************************/
|
|
|
|
.section .rodata, "a"
|
|
|
|
/* Offset to CP n save area in thread's CP save area. */
|
|
|
|
.global _xtensa_coproc_saoffsets
|
|
.type _xtensa_coproc_saoffsets, @object
|
|
.align 16 /* Minimize crossing cache boundaries */
|
|
|
|
_xtensa_coproc_saoffsets:
|
|
|
|
.word XTENSA_CP0_SA, XTENSA_CP1_SA, XTENSA_CP2_SA, XTENSA_CP3_SA
|
|
.word XTENSA_CP4_SA, XTENSA_CP5_SA, XTENSA_CP6_SA, XTENSA_CP7_SA
|
|
|
|
.size _xtensa_coproc_saoffsets, . - _xtensa_coproc_saoffsets
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|
|
.text
|
|
|
|
/****************************************************************************
|
|
* Name: _xtensa_coproc_savestate
|
|
*
|
|
* Description:
|
|
* If there is a current thread and it has a coprocessor state save area,
|
|
* then save all callee-saved state into this area. This function is
|
|
* called from the solicited context switch handler. It calls a system-
|
|
* specific function to get the coprocessor save area base address.
|
|
*
|
|
* It is also called from xtensa_coproc_savestate() for synchronous
|
|
* context switches. xtensa_coproc_savestate() is simply a C wrapper
|
|
* around the assembly language call to _xtensa_coproc_savestate.
|
|
*
|
|
* Entry Conditions:
|
|
* - A2 holds the address of the co-processor state save area
|
|
* - The thread being switched out is still the current thread.
|
|
* - CPENABLE state reflects which coprocessors are active.
|
|
* - Registers have been saved/spilled already.
|
|
*
|
|
* Exit conditions:
|
|
* - All necessary CP callee-saved state has been saved.
|
|
* - Registers a2-a7, a13-a15 have been trashed.
|
|
*
|
|
* Must be called from assembly code only, using CALL0.
|
|
*
|
|
****************************************************************************/
|
|
|
|
.global _xtensa_coproc_savestate
|
|
.type _xtensa_coproc_savestate, @function
|
|
|
|
.align 4
|
|
.literal_position
|
|
.align 4
|
|
|
|
_xtensa_coproc_savestate:
|
|
|
|
/* Move the address of the thread state save area to R15 */
|
|
|
|
mov a15, a2 /* A15 is now the address of the save area */
|
|
|
|
/* CPENABLE should show which CPs are enabled. */
|
|
|
|
rsr a2, CPENABLE /* a2 = which CPs are enabled */
|
|
beqz a2, .Ldone1 /* Quick exit if none */
|
|
|
|
s16i a2, a15, XTENSA_CPSTORED /* Save mask of CPs being stored */
|
|
movi a13, _xtensa_coproc_saoffsets /* Array of CP save offsets */
|
|
l32i a15, a15, XTENSA_CPASA /* a15 = base of aligned save area */
|
|
|
|
#if XCHAL_CP0_SA_SIZE > 0
|
|
bbci.l a2, 0, 2f /* CP 0 not enabled */
|
|
l32i a14, a13, 0 /* a14 = _xtensa_coproc_saoffsets[0] */
|
|
add a3, a14, a15 /* a3 = save area for CP 0 */
|
|
xchal_cp0_store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
|
|
2:
|
|
#endif
|
|
|
|
#if XCHAL_CP1_SA_SIZE > 0
|
|
bbci.l a2, 1, 2f /* CP 1 not enabled */
|
|
l32i a14, a13, 4 /* a14 = _xtensa_coproc_saoffsets[1] */
|
|
add a3, a14, a15 /* a3 = save area for CP 1 */
|
|
xchal_cp1_store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
|
|
2:
|
|
#endif
|
|
|
|
#if XCHAL_CP2_SA_SIZE > 0
|
|
bbci.l a2, 2, 2f
|
|
l32i a14, a13, 8
|
|
add a3, a14, a15
|
|
xchal_cp2_store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
|
|
2:
|
|
#endif
|
|
|
|
#if XCHAL_CP3_SA_SIZE > 0
|
|
bbci.l a2, 3, 2f
|
|
l32i a14, a13, 12
|
|
add a3, a14, a15
|
|
xchal_cp3store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
|
|
2:
|
|
#endif
|
|
|
|
#if XCHAL_CP4_SA_SIZE > 0
|
|
bbci.l a2, 4, 2f
|
|
l32i a14, a13, 16
|
|
add a3, a14, a15
|
|
xchal_cp4store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
|
|
2:
|
|
#endif
|
|
|
|
#if XCHAL_CP5_SA_SIZE > 0
|
|
bbci.l a2, 5, 2f
|
|
l32i a14, a13, 20
|
|
add a3, a14, a15
|
|
xchal_cp5store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
|
|
2:
|
|
#endif
|
|
|
|
#if XCHAL_CP6_SA_SIZE > 0
|
|
bbci.l a2, 6, 2f
|
|
l32i a14, a13, 24
|
|
add a3, a14, a15
|
|
xchal_cp6store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
|
|
2:
|
|
#endif
|
|
|
|
#if XCHAL_CP7_SA_SIZE > 0
|
|
bbci.l a2, 7, 2f
|
|
l32i a14, a13, 28
|
|
add a3, a14, a15
|
|
xchal_cp7store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
|
|
2:
|
|
#endif
|
|
|
|
.Ldone1:
|
|
ret
|
|
|
|
.size _xtensa_coproc_savestate, . - _xtensa_coproc_savestate
|
|
|
|
/****************************************************************************
|
|
* Name: xtensa_coproc_savestate
|
|
*
|
|
* Description:
|
|
* If there is a current thread and it has a coprocessor state save area,
|
|
* then save all callee-saved state into this area. xtensa_coproc_savestate()
|
|
* is simply a C wrapper around the assembly language call to
|
|
* _xtensa_coproc_savestate.
|
|
*
|
|
* Input Parameters:
|
|
* A2 - Address of co-processor save area
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
* Assumptions:
|
|
* Called with interrupts disabled.
|
|
*
|
|
****************************************************************************/
|
|
|
|
.global xtensa_coproc_savestate
|
|
.type xtensa_coproc_savestate, @function
|
|
|
|
.align 4
|
|
.literal_position
|
|
.align 4
|
|
|
|
xtensa_coproc_savestate:
|
|
|
|
#ifdef __XTENSA_CALL0_ABI__
|
|
|
|
/* Need to preserve a8-11. _xtensa_coproc_savestate modifies a2-a7,
|
|
* a13-a15. a12-a15 are callee saved registers so a13-a14 must be
|
|
* preserved.
|
|
*/
|
|
|
|
ENTRY(16)
|
|
s32i a13, sp, LOCAL_OFFSET(1) /* Save clobbered registers */
|
|
s32i a14, sp, LOCAL_OFFSET(2)
|
|
s32i a15, sp, LOCAL_OFFSET(3)
|
|
|
|
/* Call _xtensa_coproc_savestate() with A2=address of co-processor
|
|
* save area.
|
|
*/
|
|
|
|
call0 _xtensa_coproc_savestate
|
|
|
|
/* Restore a13-15 and return */
|
|
|
|
l32i a13, sp, LOCAL_OFFSET(1) /* Restore clobbered registers */
|
|
l32i a14, sp, LOCAL_OFFSET(2)
|
|
l32i a15, sp, LOCAL_OFFSET(3)
|
|
RET(16)
|
|
|
|
#else
|
|
/* Need to preserve a8-15. _xtensa_coproc_savestate modifies a2-a7,
|
|
* a13-a15. So a13-a15 may need to be preserved.
|
|
*/
|
|
|
|
ENTRY(32 /*16*/) /* REVISIT: Why 32? */
|
|
s32i a0, sp, LOCAL_OFFSET(1) /* Save return address */
|
|
|
|
/* Call _xtensa_coproc_savestate() with A2=address of co-processor
|
|
* save area.
|
|
*/
|
|
|
|
call0 _xtensa_coproc_savestate
|
|
|
|
/* Restore a0 and return */
|
|
|
|
l32i a0, sp, LOCAL_OFFSET(1) /* Recover return address */
|
|
RET(32 /*16*/) /* REVISIT: Why 32? */
|
|
|
|
#endif
|
|
|
|
.size xtensa_coproc_savestate, . - xtensa_coproc_savestate
|
|
|
|
/****************************************************************************
|
|
* Name: _xtensa_coproc_restorestate
|
|
*
|
|
* Description:
|
|
* Restore any callee-saved coprocessor state for the incoming thread.
|
|
* This function is called from coprocessor exception handling, when
|
|
* giving ownership to a thread that solicited a context switch earlier.
|
|
* It calls a system-specific function to get the coprocessor save area
|
|
* base address.
|
|
*
|
|
* It is also called from xtensa_coproc_restorestate() for synchronous
|
|
* context switches. xtensa_coproc_restorestate() is simply a C wrapper
|
|
* around the assembly language call to _xtensa_coproc_restorestate.
|
|
*
|
|
* Entry Conditions:
|
|
* - A2 holds the address of the co-processor state save area
|
|
* - The incoming thread is set as the current thread.
|
|
*
|
|
* Exit conditions:
|
|
* - All necessary CP callee-saved state has been restored.
|
|
* - CPENABLE - Set up correctly for the current thread.
|
|
* - Registers a2-a7, a13-a15 have been trashed.
|
|
*
|
|
* Must be called from assembly code only, using CALL0.
|
|
*
|
|
****************************************************************************/
|
|
|
|
.global _xtensa_coproc_restorestate
|
|
.type _xtensa_coproc_restorestate, @function
|
|
|
|
.align 4
|
|
.literal_position
|
|
.align 4
|
|
|
|
_xtensa_coproc_restorestate:
|
|
|
|
/* Move the address of the thread state save area to R15 */
|
|
|
|
mov a15, a2 /* A15 is now the address of the save area */
|
|
|
|
#ifdef CONFIG_XTENSA_CP_LAZY
|
|
movi a2, 0 /* a2 = Will disable all coprocessors */
|
|
#else
|
|
l16ui a2, a15, XTENSA_CPENABLE /* a2 = Which CPs have been enable for this thread? */
|
|
#endif
|
|
wsr a2, CPENABLE /* Set CPENABLE correctly for this thread */
|
|
l16ui a2, a15, XTENSA_CPSTORED /* a2 = Which CPs have been saved for this thread? */
|
|
movi a3, 0 /* Clear the ones being restored (all of them) */
|
|
s16i a3, a15, XTENSA_CPSTORED /* Clear saved CP mask */
|
|
|
|
movi a13, _xtensa_coproc_saoffsets /* Array of CP save offsets */
|
|
l32i a15, a15, XTENSA_CPASA /* a15 = base of aligned save area */
|
|
|
|
#if XCHAL_CP0_SA_SIZE
|
|
bbci.l a2, 0, 2f /* CP 0 not enabled */
|
|
l32i a14, a13, 0 /* a14 = _xtensa_coproc_saoffsets[0] */
|
|
add a3, a14, a15 /* a3 = save area for CP 0 */
|
|
xchal_cp0_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
|
|
2:
|
|
#endif
|
|
|
|
#if XCHAL_CP1_SA_SIZE
|
|
bbci.l a2, 1, 2f /* CP 1 not enabled */
|
|
l32i a14, a13, 4 /* a14 = _xtensa_coproc_saoffsets[1] */
|
|
add a3, a14, a15 /* a3 = save area for CP 1 */
|
|
xchal_cp1_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
|
|
2:
|
|
#endif
|
|
|
|
#if XCHAL_CP2_SA_SIZE
|
|
bbci.l a2, 2, 2f
|
|
l32i a14, a13, 8
|
|
add a3, a14, a15
|
|
xchal_cp2_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
|
|
2:
|
|
#endif
|
|
|
|
#if XCHAL_CP3_SA_SIZE
|
|
bbci.l a2, 3, 2f
|
|
l32i a14, a13, 12
|
|
add a3, a14, a15
|
|
xchal_cp3_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
|
|
2:
|
|
#endif
|
|
|
|
#if XCHAL_CP4_SA_SIZE
|
|
bbci.l a2, 4, 2f
|
|
l32i a14, a13, 16
|
|
add a3, a14, a15
|
|
xchal_cp4_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
|
|
2:
|
|
#endif
|
|
|
|
#if XCHAL_CP5_SA_SIZE
|
|
bbci.l a2, 5, 2f
|
|
l32i a14, a13, 20
|
|
add a3, a14, a15
|
|
xchal_cp5_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
|
|
2:
|
|
#endif
|
|
|
|
#if XCHAL_CP6_SA_SIZE
|
|
bbci.l a2, 6, 2f
|
|
l32i a14, a13, 24
|
|
add a3, a14, a15
|
|
xchal_cp6_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
|
|
2:
|
|
#endif
|
|
|
|
#if XCHAL_CP7_SA_SIZE
|
|
bbci.l a2, 7, 2f
|
|
l32i a14, a13, 28
|
|
add a3, a14, a15
|
|
xchal_cp7_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
|
|
2:
|
|
#endif
|
|
/* Ensure wsr.CPENABLE has completed. */
|
|
|
|
rsync
|
|
ret
|
|
|
|
.size _xtensa_coproc_restorestate, . - _xtensa_coproc_restorestate
|
|
|
|
/****************************************************************************
|
|
* Name: xtensa_coproc_restorestate
|
|
*
|
|
* Description:
|
|
* Restore any callee-saved coprocessor state for the incoming thread.
|
|
* xtensa_coproc_restorestate() is simply a C wrapper around the assembly
|
|
* language call to _xtensa_coproc_restorestate.
|
|
*
|
|
* Input Parameters:
|
|
* - A2 holds the address of the threads state save area
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
* Assumptions:
|
|
* Called with interrupts disabled.
|
|
*
|
|
****************************************************************************/
|
|
|
|
.global xtensa_coproc_restorestate
|
|
.type xtensa_coproc_restorestate, @function
|
|
|
|
.align 4
|
|
.literal_position
|
|
.align 4
|
|
|
|
xtensa_coproc_restorestate:
|
|
|
|
#ifdef __XTENSA_CALL0_ABI__
|
|
|
|
/* Need to preserve a8-11. _xtensa_coproc_restorestate modifies a2-a7,
|
|
* a13-a15. a12-a15 are callee saved registers so a13-a14 must be
|
|
* preserved.
|
|
*/
|
|
|
|
ENTRY(16)
|
|
s32i a13, sp, LOCAL_OFFSET(1) /* Save clobbered values */
|
|
s32i a14, sp, LOCAL_OFFSET(2)
|
|
s32i a15, sp, LOCAL_OFFSET(3)
|
|
|
|
/* Call _xtensa_coproc_restorestate() with A2=address of co-processor
|
|
* save area. Registers a0, a2-a7, a13-a15 have been trashed.
|
|
*/
|
|
|
|
call0 _xtensa_coproc_restorestate
|
|
|
|
/* Restore a13-a15 and return */
|
|
|
|
l32i a13, sp, LOCAL_OFFSET(1) /* Restore clobbered registers */
|
|
l32i a14, sp, LOCAL_OFFSET(2)
|
|
l32i a15, sp, LOCAL_OFFSET(3)
|
|
RET(16)
|
|
|
|
#else
|
|
/* Need to preserve a8-15. _xtensa_coproc_savestate modifies a2-a7,
|
|
* a13-a15. So a13-a15 may need to be preserved.
|
|
*/
|
|
|
|
ENTRY(32 /*16*/) /* REVISIT: Why 32? */
|
|
s32i a0, sp, LOCAL_OFFSET(1) /* Save return address */
|
|
|
|
/* Call _xtensa_coproc_restorestate() with A2=address of co-processor
|
|
* save area. Registers a0, a2-a7, a13-a15 have been trashed.
|
|
*/
|
|
|
|
call0 _xtensa_coproc_restorestate
|
|
|
|
/* Restore a0 and return */
|
|
|
|
l32i a0, sp, LOCAL_OFFSET(1) /* Recover return address */
|
|
RET(32 /*16*/) /* REVISIT: Why 32? */
|
|
|
|
#endif
|
|
|
|
.size xtensa_coproc_restorestate, . - xtensa_coproc_restorestate
|
|
|
|
#endif /* XCHAL_CP_NUM > 0 */
|