1/**************************************************************************/
2/*   Copyright (c) Cadence Design Systems, Inc.                           */
3/*                                                                        */
4/* Permission is hereby granted, free of charge, to any person obtaining  */
5/* a copy of this software and associated documentation files (the        */
6/* "Software"), to deal in the Software without restriction, including    */
7/* without limitation the rights to use, copy, modify, merge, publish,    */
8/* distribute, sublicense, and/or sell copies of the Software, and to     */
9/* permit persons to whom the Software is furnished to do so, subject to  */
10/* the following conditions:                                              */
11/*                                                                        */
12/* The above copyright notice and this permission notice shall be         */
13/* included in all copies or substantial portions of the Software.        */
14/*                                                                        */
15/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
16/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
17/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
18/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
19/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
20/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
21/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
22/**************************************************************************/
23
24/**************************************************************************/
25/*                                                                        */
26/*  DESCRIPTION                                                           */
27/*                                                                        */
28/*  Xtensa exception and interrupt dispatch for XEA3.                     */
29/*                                                                        */
30/*  Interrupt handlers and user exception handlers support interaction    */
31/*  with the RTOS by calling XT_RTOS_INT_ENTER and XT_RTOS_INT_EXIT       */
32/*  before and after calling the user's specific interrupt handlers.      */
33/*                                                                        */
34/*  Users can install application-specific interrupt handlers by calling  */
35/*  xt_set_interrupt_handler(). These handlers can be written in C and    */
36/*  must follow the C calling convention. The handler table is indexed by */
37/*  the interrupt number. Each handler may be provided with an argument.  */
38/*                                                                        */
39/*  Users can install application-specific exception handlers in the      */
40/*  same way, by calling xt_set_exception_handler(). One handler slot is  */
41/*  provided for each exception type. Note that some exceptions are       */
42/*  handled by the porting layer itself, and cannot be taken over by      */
43/*  application code. These are the alloca, syscall, and coprocessor      */
44/*  exceptions.                                                           */
45/*                                                                        */
46/*  Exception handlers can be written in C, and must follow C calling     */
47/*  convention. Each handler is passed a pointer to an exception frame as */
48/*  its single argument. The exception frame is created on the stack and  */
49/*  holds the saved context of the thread that took the exception. If the */
50/*  handler returns, the context will be restored and the instruction     */
51/*  that caused the exception will be retried. If the handler makes any   */
52/*  changes to the saved state in the exception frame, the changes will   */
53/*  be applied when restoring the context.                                */
54/*                                                                        */
55/*  RELEASE HISTORY                                                       */
56/*                                                                        */
57/*    DATE              NAME                      DESCRIPTION             */
58/*                                                                        */
59/*  12-31-2020     Cadence Design Systems   Initial Version 6.1.3         */
60/*                                                                        */
61/**************************************************************************/
62
63
64#include <xtensa/config/core.h>
65#include <xtensa/coreasm.h>
66
67#if XCHAL_HAVE_XEA3
68
69#include "xtensa_context.h"
70
71#if (XCHAL_HW_VERSION < XTENSA_HWVERSION_RH_2016_2)
72#error Xtensa HW earlier than RH_2016.2 not supported.
73#endif
74
75
76//-----------------------------------------------------------------------------
77// The entry point vectors are common for call0 and windowed configurations.
78//-----------------------------------------------------------------------------
79
80        .section .DispatchVector.text, "ax"
81#if XCHAL_HAVE_VECBASE
82        .align  64                      // 64-byte alignment needed when vecbase
83#else                                   // is relocatable
84        .align  4
85#endif
86
87        .org    0                       // Fixed offset for Reset Vector
88        .global _DispatchVector
89        .weak   _DispatchVector
90
91_DispatchVector:
92        j       _JumpToResetHandler
93
94        .org    3                       // Reserved
95        .local  _Reserved1
96
97_Reserved1:
98        ill
99
100        .org    6                       // Fixed offset for Double Exception Vector
101        .global _DoubleExceptionVector
102        .weak   _DoubleExceptionVector
103
104_DoubleExceptionVector:
105        j       _DoubleExceptionHandler // Externally defined
106
107        .org    9                       // Reserved
108        .local  _Reserved2
109
110_Reserved2:
111        ill
112
113//-----------------------------------------------------------------------------
114// Start of dispatch code.
115//-----------------------------------------------------------------------------
116
117        .org    12                      // Fixed offset for Tailchain entry point
118        .global _xt_dispatch
119
120_xt_dispatch:
121#ifdef __XTENSA_CALL0_ABI__
122
123        // NOTE: for call0, a15 is expected to be holding the previous stack pointer
124        // when we get to the Tailchain segment.
125
126        s32si.x4         a2, a15        // Select interrupt, a2 <- (intnum << 2)
127        movi             a0,   0
128        l32dis.it        a0,  a0        // a0 <- wrapper addr (handler_table[0])
129        s32stk           a9, a15, 96    // Set new stack pointer
130#if XT_STK_XTRA_SZ
131        addi             a1,  a1, -XT_STK_XTRA_SZ       // Adjust for extra save area
132#endif
133        s32dis.h         a0,  a0        // Jump to handler if interrupt else fall through
134                                        // Note this also clears local exclusive monitor
135
136#else // windowed
137
138        s32si.x4        a10,  a1        // Select interrupt, a10 <- (intnum << 2)
139        movi             a8,   0
140        l32dis.it        a8,  a8        // a8 <- wrapper addr (handler_table[0])
141        s32stk           a9,  a1, 96    // Set new stack pointer
142#if XT_STK_XTRA_SZ
143        addi             a9,  a9, -XT_STK_XTRA_SZ       // Adjust for extra save area
144#endif
145        s32dis.h         a8,  a8        // Jump to handler if interrupt else fall through
146                                        // Note this also clears local exclusive monitor
147
148#endif // __XTENSA_CALL0_ABI__
149
150.Lexit:
151        j       _xt_exit
152
153#ifndef __XTENSA_CALL0_ABI__
154        .org    36                      // Fixed offset for Underflow segment
155        .global _xt_underflow
156
157_xt_underflow:
158        l32e     a8,  a1, -64           //  a8 <- [a1-32]
159        l32e     a9,  a1, -64           //  a9 <- [a1-28]
160        l32e    a10,  a1, -64           // a10 <- [a1-24]
161        l32e    a11,  a1, -64           // a11 <- [a1-20]
162        l32e    a12,  a1, -64           // a12 <- [a1-16]
163        l32e    a13,  a1, -64           // a13 <- [a1-12]
164        l32e    a14,  a1, -64           // a14 <- [a1-8]
165        l32e    a15,  a1, -64           // a15 <- [a1-4] ; Return (branch to EPC)
166#endif
167
168        .org    60                      // Fixed offset for Save/Overflow segment
169        .global _xt_save
170
171_xt_save:
172#ifdef __XTENSA_CALL0_ABI__
173        s32e     a0,  a1, -64           // [a1-64] <-  a0
174        s32e     a2,  a1, -48           // [a1-56] <-  a2 ; a2 <- EPC
175        s32e     a3,  a1, -64           // [a1-52] <-  a3
176        s32e     a4,  a1, -64           // [a1-48] <-  a4
177        s32e     a5,  a1, -64           // [a1-44] <-  a5
178        s32e     a6,  a1, -64           // [a1-40] <-  a6
179        s32e     a7,  a1, -64           // [a1-36] <-  a7
180#else
181        .global _xt_overflow
182_xt_overflow:
183#endif
184        s32e     a8,  a1, -52           // [a1-32] <-  a8 ;  a8 <- ExcVAddr
185        s32e     a9,  a1, -28           // [a1-28] <-  a9 ;  a9 <- PS/SAR
186        s32e    a10,  a1, -48           // [a1-24] <- a10 ; a10 <- EPC
187        s32e    a11,  a1, -24           // [a1-20] <- a11 ; a11 <- ExcCause
188        s32e    a12,  a1, -44           // [a1-16] <- a12 ; a12 <- LBEG
189        s32e    a13,  a1, -40           // [a1-12] <- a13 ; a13 <- LEND
190        s32e    a14,  a1, -36           // [a1-8]  <- a14 ; a14 <- LCOUNT
191        s32e    a15,  a1, -32           // [a1-4]  <- a15 ; a15 <- a1
192                                        // If Overflow then return (branch to EPC)
193
194_xt_entry:
195        s32e     a8,  a1, -4            // [a1-68] <-  a8 (ExcVAddr)
196        s32e    a11,  a1, -8            // [a1-72] <- a11 (ExcCause)
197#if XCHAL_HAVE_LOOPS
198        s32e    a12,  a1, -20           // [a1-84] <- a12 (LBEG)
199        s32e    a13,  a1, -24           // [a1-88] <- a13 (LEND)
200        s32e    a14,  a1, -28           // [a1-92] <- a14 (LCOUNT)
201#endif
202#if XCHAL_HAVE_EXCLUSIVE
203        movi    a12,  0
204        getex   a12
205        s32e    a12,  a1, -32           // [a1-96] <- a12 (ATOMCTL)
206#endif
207
208        j       1f                      // make room for literals
209
210        .align  4
211        .literal_position
212
213.Le1:
214        .word   _xt_exception_table
215
2161:
217        // Call OS-specific code for additional work to be done. Stay on interruptee's
218        // stack in case more saves are required into stack frame.
219        // NOTE: OS-specific code can use a8, a12-a14, (+a2-a7: call0, a15: windowed).
220        // ALL other registers must be preserved.
221
222        XT_RTOS_INT_ENTER
223
224        // This sequence checks the interrupt controller and loads the interrupt
225        // number if available, and also loads the wrapper handler address.
226        // If there is an interrupt, execution will branch to the wrapper which
227        // will then forward to the correct handler.
228        // All this happens only if there is a pending interrupt. If not, execution
229        // falls through to exception handling.
230
231#ifdef __XTENSA_CALL0_ABI__
232
233        s32si.x4         a2,  a1        // [a1-80] <- a2 (EPC) ; a2 <- (intnum << 2)
234        movi             a0,   0
235        l32dis.it        a0,  a0        // a0 <- wrapper addr (handler_table[0])
236        s32stk           a9,  a1, 96    // [a1-76] <- a9 (PS/SAR) ; a1 = a1-96
237#if XT_STK_XTRA_SZ
238        addi             a1,  a1, -XT_STK_XTRA_SZ       // Adjust for extra save area
239#endif
240        s32dis.h         a0,  a0        // Jump to handler if interrupt else fall through
241
242#else // windowed
243
244        s32si.x4        a10,  a1        // [a1-80] <- a10 (EPC) ; a10 <- (intnum << 2)
245        movi             a8,   0
246        l32dis.it        a8,  a8        // a8 <- wrapper addr (handler_table[0])
247        s32stk           a9,  a1, 96    // [a1-76] <- a9 (PS/SAR) ; a9 = a1-96
248#if XT_STK_XTRA_SZ
249        addi             a9,  a9, -XT_STK_XTRA_SZ       // Adjust for extra save area
250#endif
251        s32dis.h         a8,  a8        // Jump to handler if interrupt else fall through
252
253#endif // __XTENSA_CALL0_ABI__
254
255        // At this point we have:
256        // (note window has rotated for windowed ABI)
257        //    a0 holds return address (Tailchain+3)
258        // For call0:
259        //   a11 holds ExcCause, also saved in [oldsp - 72]
260        //   a15 holds exception SP, a1 points to exception frame
261        // For windowed:
262        //    a3 holds ExcCause, also saved in [oldsp - 72]
263        //    a1 points to exception frame
264
265        .global _xt_exception
266
267_xt_exception:
268        l32r     a2,  .Le1                  // Load exc table address
269#ifdef __XTENSA_CALL0_ABI__
270        mov      a3, a11                    // Copy exception cause to a3
271#endif
272        extui    a4,  a3, 0, 4              // Extract exception cause
273        addx4    a2,  a4, a2                // Index into exc table
274        l32i     a4,  a2, 0                 // Load handler address
275#if XT_STK_XTRA_SZ
276        addi     a2,  a1, XT_STK_XTRA_SZ    // Argument = Exception frame ptr
277#else
278        mov      a2,  a1                    // Argument = Exception frame ptr
279#endif
280        jx       a4                         // Return directly from handler
281
282        // Exit/restore sequence
283
284        .global _xt_exit
285
286_xt_exit:
287#ifdef __XTENSA_CALL0_ABI__
288        mov      a1, a15                    // Restore stack pointer
289#endif
290
291        // Run OS-specific code to determine what to restore.
292        // Interrupts will remain disabled through this sequence.
293        // WARNING: stack pointer may change within this macro
294        // so all restores off the stack must happen afterwards.
295
296        XT_RTOS_INT_EXIT
297
298        .global _xt_restore
299
300_xt_restore:
301        // Some loads must happen before DISPST = Restore, as these
302        // will not be accessible via L32E once DISPST = Restore.
303
304#if XCHAL_HAVE_EXCLUSIVE
305        l32e    a12,  a1, -32           // a12 <- [a1-96] (ATOMCTL)
306        getex   a12
307#endif
308        l32e    a10,  a1, -12           // a10 <- [a1-76] (PS/SAR)
309        l32e    a12,  a1, -20           // a12 <- [a1-84] (LBEG)
310        l32e    a13,  a1, -24           // a13 <- [a1-88] (LEND)
311        l32e    a14,  a1, -28           // a14 <- [a1-92] (LCOUNT)
312        l32dis.epc  a11, a1             // a11 <- [a1-80] (EPC)
313                                        // If interrupt goto tailchain else fall through
314
315#ifdef __XTENSA_CALL0_ABI__
316        l32e     a0,  a1, -64           // a0 <- [a1-64]
317        l32e     a2,  a1, -64           // a2 <- [a1-56]
318        l32e     a3,  a1, -64           // a3 <- [a1-52]
319        l32e     a4,  a1, -64           // a4 <- [a1-48]
320        l32e     a5,  a1, -64           // a5 <- [a1-44]
321        l32e     a6,  a1, -64           // a6 <- [a1-40]
322        l32e     a7,  a1, -64           // a7 <- [a1-36]
323#endif
324
325        // Important: the following restrictions must be observed:
326        // 1) The LCOUNT register must be restored after LBEG/LEND.
327        // 2) There must be at least 3 instructions between the LCOUNT
328        //    restore and the last L32E (the one that branches).
329
330        l32e    a12,  a1, -44           // LBEG   <- a12, a12 <- [a1-16]
331        l32e    a13,  a1, -40           // LEND   <- a13, a13 <- [a1-12]
332        l32e    a14,  a1, -36           // LCOUNT <- a14, a14 <- [a1-8]
333        l32e     a8,  a1, -64           // a8 <- [a1-32]
334        l32e     a9,  a1, -64           // a9 <- [a1-28]
335        l32e    a10,  a1, -60           // PS/SAR <- a10, a10 <- [a1-24]
336        l32e    a11,  a1, -48           // EPC    <- a11, a11 <- [a1-20]
337        l32e    a15,  a1, -64           // a15 <- [a1-4], Branch to EPC if no interrupt
338                                        // If interrupt, branch to Tailchain
339
340
341//-----------------------------------------------------------------------------
342// Branch to reset handler code from here. Use CALL0 as a branch, will expand
343// to CALLX0 if needed when built with the -mlongcalls option.
344//-----------------------------------------------------------------------------
345
346        .align  4
347        .local  _JumpToResetHandler
348
349_JumpToResetHandler:
350        call0   _ResetHandler
351
352
353//-----------------------------------------------------------------------------
354// Idle loop. On interrupt, no state needs saving.
355//-----------------------------------------------------------------------------
356
357        .align  4
358        .global _xt_idle
359
360_xt_idle:
361        movi    a14, _xt_interrupt_stack_top
362        mov      a1, a14                // a1 <- Top of interrupt stack
363        movi    a14, 0                  // 0 = Normal
364        wsr.ms  a14                     // Set DISPST = Normal
365        rsync
366        waiti   0                       // Wait for interrupt
367        memw                            // HW erratum 569
368
369
370//-----------------------------------------------------------------------------
371// Scheduler interrupt handler. Triggered by context switch. At this time only
372// useful for windowed ABI to spill register windows.
373//-----------------------------------------------------------------------------
374
375        .align  4
376        .global xt_sched_handler
377
378xt_sched_handler:
379#ifdef __XTENSA_WINDOWED_ABI__
380        entry   a1, 32
381        ssai    1
382        spillw
383        retw
384#else
385        ret
386#endif
387
388#endif // XCHAL_HAVE_XEA3
389
390