| /**************************************************************************** |
| * arch/xtensa/src/common/xtensa_window_vector.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_window_vector.S" |
| |
| /**************************************************************************** |
| * Included Files |
| ****************************************************************************/ |
| |
| #include <nuttx/config.h> |
| |
| #include <arch/xtensa/xtensa_specregs.h> |
| #include <arch/xtensa/core.h> |
| #include <arch/chip/core-isa.h> |
| |
| /**************************************************************************** |
| * Window Vectors |
| ****************************************************************************/ |
| |
| /* WINDOW OVERFLOW AND UNDERFLOW EXCEPTION VECTORS AND ALLOCA EXCEPTION HANDLER |
| * |
| * Here is the code for each window overflow/underflow exception vector and |
| * (interspersed) efficient code for handling the alloca exception cause. |
| * Window exceptions are handled entirely in the vector area and are very |
| * tight for performance. The alloca exception is also handled entirely in |
| * the window vector area so comes at essentially no cost in code size. |
| * Users should never need to modify them and Cadence Design Systems recommends |
| * they do not. |
| * |
| * Window handlers go at predetermined vector locations according to the |
| * Xtensa hardware configuration, which is ensured by their placement in a |
| * special section known to the Xtensa linker support package (LSP). Since |
| * their offsets in that section are always the same, the LSPs do not define |
| * a section per vector. |
| * |
| * These things are coded for XEA2 only (XEA1 is not supported). |
| * |
| * Note on Underflow Handlers: |
| * The underflow handler for returning from call[i+1] to call[i] |
| * must preserve all the registers from call[i+1]'s window. |
| * In particular, a0 and a1 must be preserved because the RETW instruction |
| * will be reexecuted (and may even underflow if an intervening exception |
| * has flushed call[i]'s registers). |
| * Registers a2 and up may contain return values. |
| */ |
| |
| #if XCHAL_HAVE_WINDOWED |
| |
| .section .window_vectors.text, "ax" |
| |
| /* Window Overflow Exception for Call4. |
| * |
| * Invoked if a call[i] referenced a register (a4-a15) that contains data from |
| * ancestor call[j]; call[j] had done a call4 to call[j+1]. |
| * |
| * On entry here: |
| * window rotated to call[j] start point; |
| * a0-a3 are registers to be saved; |
| * a4-a15 must be preserved; |
| * a5 is call[j+1]'s stack pointer. |
| */ |
| |
| .org 0x0 |
| .global _window_overflow4 |
| _window_overflow4: |
| |
| s32e a0, a5, -16 /* Save a0 to call[j+1]'s stack frame */ |
| s32e a1, a5, -12 /* Save a1 to call[j+1]'s stack frame */ |
| s32e a2, a5, -8 /* Save a2 to call[j+1]'s stack frame */ |
| s32e a3, a5, -4 /* Save a3 to call[j+1]'s stack frame */ |
| #ifdef CONFIG_XTENSA_HAVE_WINDOW_EXCEPTION_HOOKS |
| j _overflow4_exit_hook |
| #else |
| rfwo /* Rotates back to call[i] position */ |
| #endif |
| |
| /* Window Underflow Exception for Call4 |
| * |
| * Invoked by RETW returning from call[i+1] to call[i] where call[i]'s |
| * registers must be reloaded (not live in ARs); where call[i] had done a |
| * call4 to call[i+1]. |
| * |
| * On entry here: |
| * window rotated to call[i] start point; |
| * a0-a3 are undefined, must be reloaded with call[i].reg[0..3]; |
| * a4-a15 must be preserved (they are call[i+1].reg[0..11]); |
| * a5 is call[i+1]'s stack pointer. |
| */ |
| |
| .org 0x40 |
| .global _window_underflow4 |
| _window_underflow4: |
| |
| l32e a0, a5, -16 /* Restore a0 from call[i+1]'s stack frame */ |
| l32e a1, a5, -12 /* Restore a1 from call[i+1]'s stack frame */ |
| l32e a2, a5, -8 /* Restore a2 from call[i+1]'s stack frame */ |
| l32e a3, a5, -4 /* Restore a3 from call[i+1]'s stack frame */ |
| #ifdef CONFIG_XTENSA_HAVE_WINDOW_EXCEPTION_HOOKS |
| j _underflow4_exit_hook |
| #else |
| rfwu |
| #endif |
| |
| /* Handle alloca exception generated by interruptee executing 'movsp'. |
| * This uses space between the window vectors, so is essentially "free". |
| * All interruptee's regs are intact except a0 which is saved in EXCSAVE_1, |
| * and PS.EXCM has been set by the exception hardware (can't be interrupted). |
| * The fact the alloca exception was taken means the registers associated with |
| * the base-save area have been spilled and will be restored by the underflow |
| * handler, so those 4 registers are available for scratch. |
| * The code is optimized to avoid unaligned branches and minimize cache misses. |
| */ |
| |
| .align 4 |
| .global _xtensa_alloca_handler |
| _xtensa_alloca_handler: |
| |
| rsr a0, WINDOWBASE /* Grab WINDOWBASE before rotw changes it */ |
| rotw -1 /* WINDOWBASE goes to a4, new a0-a3 are scratch */ |
| rsr a2, PS |
| extui a3, a2, XCHAL_PS_OWB_SHIFT, XCHAL_PS_OWB_BITS |
| xor a3, a3, a4 /* Bits changed from old to current windowbase */ |
| rsr a4, EXCSAVE_1 /* Restore original a0 (now in a4) */ |
| slli a3, a3, XCHAL_PS_OWB_SHIFT |
| xor a2, a2, a3 /* Flip changed bits in old window base */ |
| wsr a2, PS /* Update PS.OWB to new window base */ |
| rsync |
| |
| _bbci.l a4, 31, _window_underflow4 |
| rotw -1 /* Original a0 goes to a8 */ |
| _bbci.l a8, 30, _window_underflow8 |
| rotw -1 |
| j _window_underflow12 |
| |
| /* Window Overflow Exception for Call8 |
| * |
| * Invoked if a call[i] referenced a register (a4-a15) that contains data from |
| * ancestor call[j]; call[j] had done a call8 to call[j+1]. |
| * |
| * On entry here: |
| * window rotated to call[j] start point; |
| * a0-a7 are registers to be saved; |
| * a8-a15 must be preserved; |
| * a9 is call[j+1]'s stack pointer. |
| */ |
| |
| .org 0x80 |
| .global _window_overflow8 |
| _window_overflow8: |
| |
| s32e a0, a9, -16 /* Save a0 to call[j+1]'s stack frame */ |
| l32e a0, a1, -12 /* a0 <- call[j-1]'s sp |
| * (used to find end of call[j]'s frame) */ |
| s32e a1, a9, -12 /* Save a1 to call[j+1]'s stack frame */ |
| s32e a2, a9, -8 /* Save a2 to call[j+1]'s stack frame */ |
| s32e a3, a9, -4 /* Save a3 to call[j+1]'s stack frame */ |
| s32e a4, a0, -32 /* Save a4 to call[j]'s stack frame */ |
| s32e a5, a0, -28 /* Save a5 to call[j]'s stack frame */ |
| s32e a6, a0, -24 /* Save a6 to call[j]'s stack frame */ |
| s32e a7, a0, -20 /* Save a7 to call[j]'s stack frame */ |
| #ifdef CONFIG_XTENSA_HAVE_WINDOW_EXCEPTION_HOOKS |
| j _overflow8_exit_hook |
| #else |
| rfwo /* Rotates back to call[i] position */ |
| #endif |
| |
| /* Window Underflow Exception for Call8 |
| * |
| * Invoked by RETW returning from call[i+1] to call[i] where call[i]'s |
| * registers must be reloaded (not live in ARs); where call[i] had done a |
| * call8 to call[i+1]. |
| * |
| * On entry here: |
| * window rotated to call[i] start point; |
| * a0-a7 are undefined, must be reloaded with call[i].reg[0..7]; |
| * a8-a15 must be preserved (they are call[i+1].reg[0..7]); |
| * a9 is call[i+1]'s stack pointer. |
| */ |
| |
| .org 0xc0 |
| .global _window_underflow8 |
| _window_underflow8: |
| |
| l32e a0, a9, -16 /* Restore a0 from call[i+1]'s stack frame */ |
| l32e a1, a9, -12 /* Restore a1 from call[i+1]'s stack frame */ |
| l32e a2, a9, -8 /* Restore a2 from call[i+1]'s stack frame */ |
| l32e a7, a1, -12 /* a7 <- call[i-1]'s sp |
| * (used to find end of call[i]'s frame) */ |
| l32e a3, a9, -4 /* Restore a3 from call[i+1]'s stack frame */ |
| l32e a4, a7, -32 /* Restore a4 from call[i]'s stack frame */ |
| l32e a5, a7, -28 /* Restore a5 from call[i]'s stack frame */ |
| l32e a6, a7, -24 /* Restore a6 from call[i]'s stack frame */ |
| l32e a7, a7, -20 /* Restore a7 from call[i]'s stack frame */ |
| #ifdef CONFIG_XTENSA_HAVE_WINDOW_EXCEPTION_HOOKS |
| j _underflow8_exit_hook |
| #else |
| rfwu |
| #endif |
| |
| /* Window Overflow Exception for Call12 |
| * |
| * Invoked if a call[i] referenced a register (a4-a15) that contains data |
| * from ancestor call[j]; call[j] had done a call12 to call[j+1]. |
| * |
| * On entry here: |
| * window rotated to call[j] start point; |
| * a0-a11 are registers to be saved; |
| * a12-a15 must be preserved; |
| * a13 is call[j+1]'s stack pointer. |
| */ |
| |
| .org 0x100 |
| .global _window_overflow12 |
| _window_overflow12: |
| |
| s32e a0, a13, -16 /* Save a0 to call[j+1]'s stack frame */ |
| l32e a0, a1, -12 /* a0 <- call[j-1]'s sp |
| * (used to find end of call[j]'s frame) */ |
| s32e a1, a13, -12 /* Save a1 to call[j+1]'s stack frame */ |
| s32e a2, a13, -8 /* Save a2 to call[j+1]'s stack frame */ |
| s32e a3, a13, -4 /* Save a3 to call[j+1]'s stack frame */ |
| s32e a4, a0, -48 /* Save a4 to end of call[j]'s stack frame */ |
| s32e a5, a0, -44 /* Save a5 to end of call[j]'s stack frame */ |
| s32e a6, a0, -40 /* Save a6 to end of call[j]'s stack frame */ |
| s32e a7, a0, -36 /* Save a7 to end of call[j]'s stack frame */ |
| s32e a8, a0, -32 /* Save a8 to end of call[j]'s stack frame */ |
| s32e a9, a0, -28 /* Save a9 to end of call[j]'s stack frame */ |
| s32e a10, a0, -24 /* Save a10 to end of call[j]'s stack frame */ |
| s32e a11, a0, -20 /* Save a11 to end of call[j]'s stack frame */ |
| rfwo /* Rotates back to call[i] position */ |
| |
| /* Window Underflow Exception for Call12 |
| * |
| * Invoked by RETW returning from call[i+1] to call[i] where call[i]'s |
| * registers must be reloaded (not live in ARs); where call[i] had done a |
| * call12 to call[i+1]. |
| * |
| * On entry here: |
| * window rotated to call[i] start point; |
| * a0-a11 are undefined, must be reloaded with call[i].reg[0..11]; |
| * a12-a15 must be preserved (they are call[i+1].reg[0..3]); |
| * a13 is call[i+1]'s stack pointer. |
| */ |
| |
| .org 0x140 |
| .global _window_underflow12 |
| _window_underflow12: |
| |
| l32e a0, a13, -16 /* Restore a0 from call[i+1]'s stack frame */ |
| l32e a1, a13, -12 /* Restore a1 from call[i+1]'s stack frame */ |
| l32e a2, a13, -8 /* Restore a2 from call[i+1]'s stack frame */ |
| l32e a11, a1, -12 /* a11 <- call[i-1]'s sp |
| * (used to find end of call[i]'s frame) */ |
| l32e a3, a13, -4 /* Restore a3 from call[i+1]'s stack frame */ |
| l32e a4, a11, -48 /* Restore a4 from end of call[i]'s stack frame */ |
| l32e a5, a11, -44 /* Restore a5 from end of call[i]'s stack frame */ |
| l32e a6, a11, -40 /* Restore a6 from end of call[i]'s stack frame */ |
| l32e a7, a11, -36 /* Restore a7 from end of call[i]'s stack frame */ |
| l32e a8, a11, -32 /* Restore a8 from end of call[i]'s stack frame */ |
| l32e a9, a11, -28 /* Restore a9 from end of call[i]'s stack frame */ |
| l32e a10, a11, -24 /* Restore a10 from end of call[i]'s stack frame */ |
| l32e a11, a11, -20 /* Restore a11 from end of call[i]'s stack frame */ |
| rfwu |
| |
| #endif /* XCHAL_HAVE_WINDOWED */ |