1/* Assembly functions for libgcc2. 2 Copyright (C) 2001-2021 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, 48 38#if XCHAL_NUM_AREGS > 16 39 call12 1f 40 retw 41 .align 4 421: 43 .rept (XCHAL_NUM_AREGS - 24) / 12 44 _entry sp, 48 45 mov a12, a0 46 .endr 47 _entry sp, 16 48#if XCHAL_NUM_AREGS % 12 == 0 49 mov a4, a4 50#elif XCHAL_NUM_AREGS % 12 == 4 51 mov a8, a8 52#elif XCHAL_NUM_AREGS % 12 == 8 53 mov a12, a12 54#endif 55 retw 56#else 57 mov a8, a8 58 retw 59#endif 60 .size __xtensa_libgcc_window_spill, .-__xtensa_libgcc_window_spill 61#endif 62 63 64/* __xtensa_nonlocal_goto: This code does all the hard work of a 65 nonlocal goto on Xtensa. It is here in the library to avoid the 66 code size bloat of generating it in-line. There are two 67 arguments: 68 69 a2 = frame pointer for the procedure containing the label 70 a3 = goto handler address 71 72 This function never returns to its caller but instead goes directly 73 to the address of the specified goto handler. */ 74 75#if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__ 76 .align 4 77 .global __xtensa_nonlocal_goto 78 .type __xtensa_nonlocal_goto,@function 79__xtensa_nonlocal_goto: 80 entry sp, 32 81 82 /* Flush registers. */ 83 call8 __xtensa_libgcc_window_spill 84 85 /* Because the save area for a0-a3 is stored one frame below 86 the one identified by a2, the only way to restore those 87 registers is to unwind the stack. If alloca() were never 88 called, we could just unwind until finding the sp value 89 matching a2. However, a2 is a frame pointer, not a stack 90 pointer, and may not be encountered during the unwinding. 91 The solution is to unwind until going _past_ the value 92 given by a2. This involves keeping three stack pointer 93 values during the unwinding: 94 95 next = sp of frame N-1 96 cur = sp of frame N 97 prev = sp of frame N+1 98 99 When next > a2, the desired save area is stored relative 100 to prev. At this point, cur will be the same as a2 101 except in the alloca() case. 102 103 Besides finding the values to be restored to a0-a3, we also 104 need to find the current window size for the target 105 function. This can be extracted from the high bits of the 106 return address, initially in a0. As the unwinding 107 proceeds, the window size is taken from the value of a0 108 saved _two_ frames below the current frame. */ 109 110 addi a5, sp, -16 /* a5 = prev - save area */ 111 l32i a6, a5, 4 112 addi a6, a6, -16 /* a6 = cur - save area */ 113 mov a8, a0 /* a8 = return address (for window size) */ 114 j .Lfirstframe 115 116.Lnextframe: 117 l32i a8, a5, 0 /* next return address (for window size) */ 118 mov a5, a6 /* advance prev */ 119 addi a6, a7, -16 /* advance cur */ 120.Lfirstframe: 121 l32i a7, a6, 4 /* a7 = next */ 122 bgeu a2, a7, .Lnextframe 123 124 /* At this point, prev (a5) points to the save area with the saved 125 values of a0-a3. Copy those values into the save area at the 126 current sp so they will be reloaded when the return from this 127 function underflows. We don't have to worry about exceptions 128 while updating the current save area, because the windows have 129 already been flushed. */ 130 131 addi a4, sp, -16 /* a4 = save area of this function */ 132 l32i a6, a5, 0 133 l32i a7, a5, 4 134 s32i a6, a4, 0 135 s32i a7, a4, 4 136 l32i a6, a5, 8 137 l32i a7, a5, 12 138 s32i a6, a4, 8 139 s32i a7, a4, 12 140 141 /* Set return address to goto handler. Use the window size bits 142 from the return address two frames below the target. */ 143 extui a8, a8, 30, 2 /* get window size from return addr. */ 144 slli a3, a3, 2 /* get goto handler addr. << 2 */ 145 ssai 2 146 src a0, a8, a3 /* combine them with a funnel shift */ 147 148 retw 149 .size __xtensa_nonlocal_goto, .-__xtensa_nonlocal_goto 150#endif 151 152 153/* __xtensa_sync_caches: This function is called after writing a trampoline 154 on the stack to force all the data writes to memory and invalidate the 155 instruction cache. a2 is the address of the new trampoline. 156 157 After the trampoline data is written out, it must be flushed out of 158 the data cache into memory. We use DHWB in case we have a writeback 159 cache. At least one DHWB instruction is needed for each data cache 160 line which may be touched by the trampoline. An ISYNC instruction 161 must follow the DHWBs. 162 163 We have to flush the i-cache to make sure that the new values get used. 164 At least one IHI instruction is needed for each i-cache line which may 165 be touched by the trampoline. An ISYNC instruction is also needed to 166 make sure that the modified instructions are loaded into the instruction 167 fetch buffer. */ 168 169/* Use the maximum trampoline size. Flushing a bit extra is OK. */ 170#define TRAMPOLINE_SIZE 60 171 172 .text 173 .align 4 174 .global __xtensa_sync_caches 175 .type __xtensa_sync_caches,@function 176__xtensa_sync_caches: 177#if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__ 178 entry sp, 32 179#endif 180#if XCHAL_DCACHE_SIZE > 0 181 /* Flush the trampoline from the data cache. */ 182 extui a4, a2, 0, XCHAL_DCACHE_LINEWIDTH 183 addi a4, a4, TRAMPOLINE_SIZE 184 addi a4, a4, (1 << XCHAL_DCACHE_LINEWIDTH) - 1 185 srli a4, a4, XCHAL_DCACHE_LINEWIDTH 186 mov a3, a2 187.Ldcache_loop: 188 dhwb a3, 0 189 addi a3, a3, (1 << XCHAL_DCACHE_LINEWIDTH) 190 addi a4, a4, -1 191 bnez a4, .Ldcache_loop 192 isync 193#endif 194#if XCHAL_ICACHE_SIZE > 0 195 /* Invalidate the corresponding lines in the instruction cache. */ 196 extui a4, a2, 0, XCHAL_ICACHE_LINEWIDTH 197 addi a4, a4, TRAMPOLINE_SIZE 198 addi a4, a4, (1 << XCHAL_ICACHE_LINEWIDTH) - 1 199 srli a4, a4, XCHAL_ICACHE_LINEWIDTH 200.Licache_loop: 201 ihi a2, 0 202 addi a2, a2, (1 << XCHAL_ICACHE_LINEWIDTH) 203 addi a4, a4, -1 204 bnez a4, .Licache_loop 205#endif 206 isync 207#if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__ 208 retw 209#else 210 ret 211#endif 212 .size __xtensa_sync_caches, .-__xtensa_sync_caches 213