1/* Assembly functions for libgcc2. 2 Copyright (C) 2001-2015 Free Software Foundation, Inc. 3 Contributed by Bob Wilson (bwilson@tensilica.com) at Tensilica. 4 5This file is part of GCC. 6 7GCC is free software; you can redistribute it and/or modify it under 8the terms of the GNU General Public License as published by the Free 9Software Foundation; either version 3, or (at your option) any later 10version. 11 12GCC is distributed in the hope that it will be useful, but WITHOUT ANY 13WARRANTY; without even the implied warranty of MERCHANTABILITY or 14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15for more details. 16 17Under Section 7 of GPL version 3, you are granted additional 18permissions described in the GCC Runtime Library Exception, version 193.1, as published by the Free Software Foundation. 20 21You should have received a copy of the GNU General Public License and 22a copy of the GCC Runtime Library Exception along with this program; 23see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 24<http://www.gnu.org/licenses/>. */ 25 26#include "xtensa-config.h" 27 28/* __xtensa_libgcc_window_spill: This function flushes out all but the 29 current register window. This is used to set up the stack so that 30 arbitrary frames can be accessed. */ 31 32#if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__ 33 .align 4 34 .global __xtensa_libgcc_window_spill 35 .type __xtensa_libgcc_window_spill,@function 36__xtensa_libgcc_window_spill: 37 entry sp, 32 38 movi a2, 0 39 syscall 40 retw 41 .size __xtensa_libgcc_window_spill, .-__xtensa_libgcc_window_spill 42#endif 43 44 45/* __xtensa_nonlocal_goto: This code does all the hard work of a 46 nonlocal goto on Xtensa. It is here in the library to avoid the 47 code size bloat of generating it in-line. There are two 48 arguments: 49 50 a2 = frame pointer for the procedure containing the label 51 a3 = goto handler address 52 53 This function never returns to its caller but instead goes directly 54 to the address of the specified goto handler. */ 55 56#if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__ 57 .align 4 58 .global __xtensa_nonlocal_goto 59 .type __xtensa_nonlocal_goto,@function 60__xtensa_nonlocal_goto: 61 entry sp, 32 62 63 /* Flush registers. */ 64 mov a5, a2 65 movi a2, 0 66 syscall 67 mov a2, a5 68 69 /* Because the save area for a0-a3 is stored one frame below 70 the one identified by a2, the only way to restore those 71 registers is to unwind the stack. If alloca() were never 72 called, we could just unwind until finding the sp value 73 matching a2. However, a2 is a frame pointer, not a stack 74 pointer, and may not be encountered during the unwinding. 75 The solution is to unwind until going _past_ the value 76 given by a2. This involves keeping three stack pointer 77 values during the unwinding: 78 79 next = sp of frame N-1 80 cur = sp of frame N 81 prev = sp of frame N+1 82 83 When next > a2, the desired save area is stored relative 84 to prev. At this point, cur will be the same as a2 85 except in the alloca() case. 86 87 Besides finding the values to be restored to a0-a3, we also 88 need to find the current window size for the target 89 function. This can be extracted from the high bits of the 90 return address, initially in a0. As the unwinding 91 proceeds, the window size is taken from the value of a0 92 saved _two_ frames below the current frame. */ 93 94 addi a5, sp, -16 /* a5 = prev - save area */ 95 l32i a6, a5, 4 96 addi a6, a6, -16 /* a6 = cur - save area */ 97 mov a8, a0 /* a8 = return address (for window size) */ 98 j .Lfirstframe 99 100.Lnextframe: 101 l32i a8, a5, 0 /* next return address (for window size) */ 102 mov a5, a6 /* advance prev */ 103 addi a6, a7, -16 /* advance cur */ 104.Lfirstframe: 105 l32i a7, a6, 4 /* a7 = next */ 106 bgeu a2, a7, .Lnextframe 107 108 /* At this point, prev (a5) points to the save area with the saved 109 values of a0-a3. Copy those values into the save area at the 110 current sp so they will be reloaded when the return from this 111 function underflows. We don't have to worry about exceptions 112 while updating the current save area, because the windows have 113 already been flushed. */ 114 115 addi a4, sp, -16 /* a4 = save area of this function */ 116 l32i a6, a5, 0 117 l32i a7, a5, 4 118 s32i a6, a4, 0 119 s32i a7, a4, 4 120 l32i a6, a5, 8 121 l32i a7, a5, 12 122 s32i a6, a4, 8 123 s32i a7, a4, 12 124 125 /* Set return address to goto handler. Use the window size bits 126 from the return address two frames below the target. */ 127 extui a8, a8, 30, 2 /* get window size from return addr. */ 128 slli a3, a3, 2 /* get goto handler addr. << 2 */ 129 ssai 2 130 src a0, a8, a3 /* combine them with a funnel shift */ 131 132 retw 133 .size __xtensa_nonlocal_goto, .-__xtensa_nonlocal_goto 134#endif 135 136 137/* __xtensa_sync_caches: This function is called after writing a trampoline 138 on the stack to force all the data writes to memory and invalidate the 139 instruction cache. a2 is the address of the new trampoline. 140 141 After the trampoline data is written out, it must be flushed out of 142 the data cache into memory. We use DHWB in case we have a writeback 143 cache. At least one DHWB instruction is needed for each data cache 144 line which may be touched by the trampoline. An ISYNC instruction 145 must follow the DHWBs. 146 147 We have to flush the i-cache to make sure that the new values get used. 148 At least one IHI instruction is needed for each i-cache line which may 149 be touched by the trampoline. An ISYNC instruction is also needed to 150 make sure that the modified instructions are loaded into the instruction 151 fetch buffer. */ 152 153/* Use the maximum trampoline size. Flushing a bit extra is OK. */ 154#define TRAMPOLINE_SIZE 60 155 156 .text 157 .align 4 158 .global __xtensa_sync_caches 159 .type __xtensa_sync_caches,@function 160__xtensa_sync_caches: 161#if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__ 162 entry sp, 32 163#endif 164#if XCHAL_DCACHE_SIZE > 0 165 /* Flush the trampoline from the data cache. */ 166 extui a4, a2, 0, XCHAL_DCACHE_LINEWIDTH 167 addi a4, a4, TRAMPOLINE_SIZE 168 addi a4, a4, (1 << XCHAL_DCACHE_LINEWIDTH) - 1 169 srli a4, a4, XCHAL_DCACHE_LINEWIDTH 170 mov a3, a2 171.Ldcache_loop: 172 dhwb a3, 0 173 addi a3, a3, (1 << XCHAL_DCACHE_LINEWIDTH) 174 addi a4, a4, -1 175 bnez a4, .Ldcache_loop 176 isync 177#endif 178#if XCHAL_ICACHE_SIZE > 0 179 /* Invalidate the corresponding lines in the instruction cache. */ 180 extui a4, a2, 0, XCHAL_ICACHE_LINEWIDTH 181 addi a4, a4, TRAMPOLINE_SIZE 182 addi a4, a4, (1 << XCHAL_ICACHE_LINEWIDTH) - 1 183 srli a4, a4, XCHAL_ICACHE_LINEWIDTH 184.Licache_loop: 185 ihi a2, 0 186 addi a2, a2, (1 << XCHAL_ICACHE_LINEWIDTH) 187 addi a4, a4, -1 188 bnez a4, .Licache_loop 189#endif 190 isync 191#if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__ 192 retw 193#else 194 ret 195#endif 196 .size __xtensa_sync_caches, .-__xtensa_sync_caches 197