summaryrefslogtreecommitdiff
path: root/ports/xtensa/xcc/src/xtensa_vectors_xea3.S
blob: 22d9db89281fc8a396652d2b080bdba87cd6b611 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
/**************************************************************************/
/*   Copyright (c) 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.                 */
/**************************************************************************/

/**************************************************************************/
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*  Xtensa exception and interrupt dispatch for XEA3.                     */
/*                                                                        */
/*  Interrupt handlers and user exception handlers support interaction    */
/*  with the RTOS by calling XT_RTOS_INT_ENTER and XT_RTOS_INT_EXIT       */
/*  before and after calling the user's specific interrupt handlers.      */
/*                                                                        */
/*  Users can install application-specific interrupt handlers by calling  */
/*  xt_set_interrupt_handler(). These handlers can be written in C and    */
/*  must follow the C calling convention. The handler table is indexed by */
/*  the interrupt number. Each handler may be provided with an argument.  */
/*                                                                        */
/*  Users can install application-specific exception handlers in the      */
/*  same way, by calling xt_set_exception_handler(). One handler slot is  */
/*  provided for each exception type. Note that some exceptions are       */
/*  handled by the porting layer itself, and cannot be taken over by      */
/*  application code. These are the alloca, syscall, and coprocessor      */
/*  exceptions.                                                           */
/*                                                                        */
/*  Exception handlers can be written in C, and must follow C calling     */
/*  convention. Each handler is passed a pointer to an exception frame as */
/*  its single argument. The exception frame is created on the stack and  */
/*  holds the saved context of the thread that took the exception. If the */
/*  handler returns, the context will be restored and the instruction     */
/*  that caused the exception will be retried. If the handler makes any   */
/*  changes to the saved state in the exception frame, the changes will   */
/*  be applied when restoring the context.                                */
/*                                                                        */
/**************************************************************************/


#include <xtensa/config/core.h>
#include <xtensa/coreasm.h>

#if XCHAL_HAVE_XEA3

#include "xtensa_context.h"

#if (XCHAL_HW_VERSION < XTENSA_HWVERSION_RH_2016_2)
#error Xtensa HW earlier than RH_2016.2 not supported.
#endif


//-----------------------------------------------------------------------------
// The entry point vectors are common for call0 and windowed configurations.
//-----------------------------------------------------------------------------

        .section .DispatchVector.text, "ax"
#if XCHAL_HAVE_VECBASE
        .align  64                      // 64-byte alignment needed when vecbase
#else                                   // is relocatable
        .align  4
#endif

        .org    0                       // Fixed offset for Reset Vector
        .global _DispatchVector
        .weak   _DispatchVector

_DispatchVector:
        j       _JumpToResetHandler

        .org    3                       // Reserved
        .local  _Reserved1

_Reserved1:
        ill

        .org    6                       // Fixed offset for Double Exception Vector
        .global _DoubleExceptionVector
        .weak   _DoubleExceptionVector

_DoubleExceptionVector:
        j       _DoubleExceptionHandler // Externally defined

        .org    9                       // Reserved
        .local  _Reserved2

_Reserved2:
        ill

//-----------------------------------------------------------------------------
// Start of dispatch code.
//-----------------------------------------------------------------------------

        .org    12                      // Fixed offset for Tailchain entry point
        .global _xt_dispatch

_xt_dispatch:
#ifdef __XTENSA_CALL0_ABI__

        // NOTE: for call0, a15 is expected to be holding the previous stack pointer
        // when we get to the Tailchain segment.

        s32si.x4         a2, a15        // Select interrupt, a2 <- (intnum << 2)
        movi             a0,   0
        l32dis.it        a0,  a0        // a0 <- wrapper addr (handler_table[0])
        s32stk           a9, a15, 96    // Set new stack pointer
#if XT_STK_XTRA_SZ
        addi             a1,  a1, -XT_STK_XTRA_SZ       // Adjust for extra save area
#endif
        s32dis.h         a0,  a0        // Jump to handler if interrupt else fall through
                                        // Note this also clears local exclusive monitor

#else // windowed

        s32si.x4        a10,  a1        // Select interrupt, a10 <- (intnum << 2)
        movi             a8,   0
        l32dis.it        a8,  a8        // a8 <- wrapper addr (handler_table[0])
        s32stk           a9,  a1, 96    // Set new stack pointer
#if XT_STK_XTRA_SZ
        addi             a9,  a9, -XT_STK_XTRA_SZ       // Adjust for extra save area
#endif
        s32dis.h         a8,  a8        // Jump to handler if interrupt else fall through
                                        // Note this also clears local exclusive monitor

#endif // __XTENSA_CALL0_ABI__

.Lexit:
        j       _xt_exit

#ifndef __XTENSA_CALL0_ABI__
        .org    36                      // Fixed offset for Underflow segment
        .global _xt_underflow

_xt_underflow:
        l32e     a8,  a1, -64           //  a8 <- [a1-32]
        l32e     a9,  a1, -64           //  a9 <- [a1-28]
        l32e    a10,  a1, -64           // a10 <- [a1-24]
        l32e    a11,  a1, -64           // a11 <- [a1-20]
        l32e    a12,  a1, -64           // a12 <- [a1-16]
        l32e    a13,  a1, -64           // a13 <- [a1-12]
        l32e    a14,  a1, -64           // a14 <- [a1-8]
        l32e    a15,  a1, -64           // a15 <- [a1-4] ; Return (branch to EPC)
#endif

        .org    60                      // Fixed offset for Save/Overflow segment
        .global _xt_save

_xt_save:
#ifdef __XTENSA_CALL0_ABI__
        s32e     a0,  a1, -64           // [a1-64] <-  a0
        s32e     a2,  a1, -48           // [a1-56] <-  a2 ; a2 <- EPC
        s32e     a3,  a1, -64           // [a1-52] <-  a3
        s32e     a4,  a1, -64           // [a1-48] <-  a4
        s32e     a5,  a1, -64           // [a1-44] <-  a5
        s32e     a6,  a1, -64           // [a1-40] <-  a6
        s32e     a7,  a1, -64           // [a1-36] <-  a7
#else
        .global _xt_overflow
_xt_overflow:
#endif
        s32e     a8,  a1, -52           // [a1-32] <-  a8 ;  a8 <- ExcVAddr
        s32e     a9,  a1, -28           // [a1-28] <-  a9 ;  a9 <- PS/SAR
        s32e    a10,  a1, -48           // [a1-24] <- a10 ; a10 <- EPC
        s32e    a11,  a1, -24           // [a1-20] <- a11 ; a11 <- ExcCause
        s32e    a12,  a1, -44           // [a1-16] <- a12 ; a12 <- LBEG
        s32e    a13,  a1, -40           // [a1-12] <- a13 ; a13 <- LEND
        s32e    a14,  a1, -36           // [a1-8]  <- a14 ; a14 <- LCOUNT
        s32e    a15,  a1, -32           // [a1-4]  <- a15 ; a15 <- a1
                                        // If Overflow then return (branch to EPC)

_xt_entry:
        s32e     a8,  a1, -4            // [a1-68] <-  a8 (ExcVAddr)
        s32e    a11,  a1, -8            // [a1-72] <- a11 (ExcCause)
#if XCHAL_HAVE_LOOPS
        s32e    a12,  a1, -20           // [a1-84] <- a12 (LBEG)
        s32e    a13,  a1, -24           // [a1-88] <- a13 (LEND)
        s32e    a14,  a1, -28           // [a1-92] <- a14 (LCOUNT)
#endif
#if XCHAL_HAVE_EXCLUSIVE
        movi    a12,  0
        getex   a12
        s32e    a12,  a1, -32           // [a1-96] <- a12 (ATOMCTL)
#endif

        j       1f                      // make room for literals

        .align  4
        .literal_position

.Le1:
        .word   _xt_exception_table

1:
        // Call OS-specific code for additional work to be done. Stay on interruptee's
        // stack in case more saves are required into stack frame.
        // NOTE: OS-specific code can use a8, a12-a14, (+a2-a7: call0, a15: windowed).
        // ALL other registers must be preserved.

        XT_RTOS_INT_ENTER

        // This sequence checks the interrupt controller and loads the interrupt
        // number if available, and also loads the wrapper handler address.
        // If there is an interrupt, execution will branch to the wrapper which
        // will then forward to the correct handler.
        // All this happens only if there is a pending interrupt. If not, execution
        // falls through to exception handling.

#ifdef __XTENSA_CALL0_ABI__

        s32si.x4         a2,  a1        // [a1-80] <- a2 (EPC) ; a2 <- (intnum << 2)
        movi             a0,   0
        l32dis.it        a0,  a0        // a0 <- wrapper addr (handler_table[0])
        s32stk           a9,  a1, 96    // [a1-76] <- a9 (PS/SAR) ; a1 = a1-96
#if XT_STK_XTRA_SZ
        addi             a1,  a1, -XT_STK_XTRA_SZ       // Adjust for extra save area
#endif
        s32dis.h         a0,  a0        // Jump to handler if interrupt else fall through

#else // windowed

        s32si.x4        a10,  a1        // [a1-80] <- a10 (EPC) ; a10 <- (intnum << 2)
        movi             a8,   0
        l32dis.it        a8,  a8        // a8 <- wrapper addr (handler_table[0])
        s32stk           a9,  a1, 96    // [a1-76] <- a9 (PS/SAR) ; a9 = a1-96
#if XT_STK_XTRA_SZ
        addi             a9,  a9, -XT_STK_XTRA_SZ       // Adjust for extra save area
#endif
        s32dis.h         a8,  a8        // Jump to handler if interrupt else fall through

#endif // __XTENSA_CALL0_ABI__

        // At this point we have:
        // (note window has rotated for windowed ABI)
        //    a0 holds return address (Tailchain+3)
        // For call0:
        //   a11 holds ExcCause, also saved in [oldsp - 72]
        //   a15 holds exception SP, a1 points to exception frame
        // For windowed:
        //    a3 holds ExcCause, also saved in [oldsp - 72]
        //    a1 points to exception frame

        .global _xt_exception

_xt_exception:
        l32r     a2,  .Le1                  // Load exc table address
#ifdef __XTENSA_CALL0_ABI__
        mov      a3, a11                    // Copy exception cause to a3
#endif
        extui    a4,  a3, 0, 4              // Extract exception cause
        addx4    a2,  a4, a2                // Index into exc table
        l32i     a4,  a2, 0                 // Load handler address
#if XT_STK_XTRA_SZ
        addi     a2,  a1, XT_STK_XTRA_SZ    // Argument = Exception frame ptr
#else
        mov      a2,  a1                    // Argument = Exception frame ptr
#endif
        jx       a4                         // Return directly from handler

        // Exit/restore sequence

        .global _xt_exit

_xt_exit:
#ifdef __XTENSA_CALL0_ABI__
        mov      a1, a15                    // Restore stack pointer
#endif

        // Run OS-specific code to determine what to restore.
        // Interrupts will remain disabled through this sequence.
        // WARNING: stack pointer may change within this macro
        // so all restores off the stack must happen afterwards.

        XT_RTOS_INT_EXIT

        .global _xt_restore

_xt_restore:
        // Some loads must happen before DISPST = Restore, as these
        // will not be accessible via L32E once DISPST = Restore.

#if XCHAL_HAVE_EXCLUSIVE
        l32e    a12,  a1, -32           // a12 <- [a1-96] (ATOMCTL)
        getex   a12
#endif
        l32e    a10,  a1, -12           // a10 <- [a1-76] (PS/SAR)
        l32e    a12,  a1, -20           // a12 <- [a1-84] (LBEG)
        l32e    a13,  a1, -24           // a13 <- [a1-88] (LEND)
        l32e    a14,  a1, -28           // a14 <- [a1-92] (LCOUNT)
        l32dis.epc  a11, a1             // a11 <- [a1-80] (EPC)
                                        // If interrupt goto tailchain else fall through

#ifdef __XTENSA_CALL0_ABI__
        l32e     a0,  a1, -64           // a0 <- [a1-64]
        l32e     a2,  a1, -64           // a2 <- [a1-56]
        l32e     a3,  a1, -64           // a3 <- [a1-52]
        l32e     a4,  a1, -64           // a4 <- [a1-48]
        l32e     a5,  a1, -64           // a5 <- [a1-44]
        l32e     a6,  a1, -64           // a6 <- [a1-40]
        l32e     a7,  a1, -64           // a7 <- [a1-36]
#endif

        // Important: the following restrictions must be observed:
        // 1) The LCOUNT register must be restored after LBEG/LEND.
        // 2) There must be at least 3 instructions between the LCOUNT
        //    restore and the last L32E (the one that branches).

        l32e    a12,  a1, -44           // LBEG   <- a12, a12 <- [a1-16]
        l32e    a13,  a1, -40           // LEND   <- a13, a13 <- [a1-12]
        l32e    a14,  a1, -36           // LCOUNT <- a14, a14 <- [a1-8]
        l32e     a8,  a1, -64           // a8 <- [a1-32]
        l32e     a9,  a1, -64           // a9 <- [a1-28]
        l32e    a10,  a1, -60           // PS/SAR <- a10, a10 <- [a1-24]
        l32e    a11,  a1, -48           // EPC    <- a11, a11 <- [a1-20]
        l32e    a15,  a1, -64           // a15 <- [a1-4], Branch to EPC if no interrupt
                                        // If interrupt, branch to Tailchain


//-----------------------------------------------------------------------------
// Branch to reset handler code from here. Use CALL0 as a branch, will expand
// to CALLX0 if needed when built with the -mlongcalls option.
//-----------------------------------------------------------------------------

        .align  4
        .local  _JumpToResetHandler

_JumpToResetHandler:
        call0   _ResetHandler


//-----------------------------------------------------------------------------
// Idle loop. On interrupt, no state needs saving.
//-----------------------------------------------------------------------------

        .align  4
        .global _xt_idle

_xt_idle:
        movi    a14, _xt_interrupt_stack_top
        mov      a1, a14                // a1 <- Top of interrupt stack
        movi    a14, 0                  // 0 = Normal
        wsr.ms  a14                     // Set DISPST = Normal
        rsync
        waiti   0                       // Wait for interrupt
        memw                            // HW erratum 569


//-----------------------------------------------------------------------------
// Scheduler interrupt handler. Triggered by context switch. At this time only
// useful for windowed ABI to spill register windows.
//-----------------------------------------------------------------------------

        .align  4
        .global xt_sched_handler

xt_sched_handler:
#ifdef __XTENSA_WINDOWED_ABI__
        entry   a1, 32
        ssai    1
        spillw
        retw
#else
        ret
#endif

#endif // XCHAL_HAVE_XEA3