]> begriffs open source - freertos/blob - portable/ThirdParty/XCC/Xtensa/xtensa_vectors.S
[AUTO][RELEASE]: Bump file header version to "11.1.0"
[freertos] / portable / ThirdParty / XCC / Xtensa / xtensa_vectors.S
1  /*
2  * FreeRTOS Kernel V11.1.0
3  * Copyright (C) 2015-2019 Cadence Design Systems, Inc.
4  * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5  *
6  * SPDX-License-Identifier: MIT
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a copy of
9  * this software and associated documentation files (the "Software"), to deal in
10  * the Software without restriction, including without limitation the rights to
11  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
12  * the Software, and to permit persons to whom the Software is furnished to do so,
13  * subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in all
16  * copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
20  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
21  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
22  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  *
25  * https://www.FreeRTOS.org
26  * https://github.com/FreeRTOS
27  *
28  */
29
30 /*
31         XTENSA VECTORS AND LOW LEVEL HANDLERS FOR AN RTOS
32
33   Xtensa low level exception and interrupt vectors and handlers for an RTOS.
34
35   Interrupt handlers and user exception handlers support interaction with
36   the RTOS by calling XT_RTOS_INT_ENTER and XT_RTOS_INT_EXIT before and
37   after user's specific interrupt handlers. These macros are defined in
38   xtensa_<rtos>.h to call suitable functions in a specific RTOS.
39
40   Users can install application-specific interrupt handlers for low and
41   medium level interrupts, by calling xt_set_interrupt_handler(). These
42   handlers can be written in C, and must obey C calling convention. The
43   handler table is indexed by the interrupt number. Each handler may be
44   provided with an argument.
45
46   Note that the system timer interrupt is handled specially, and is
47   dispatched to the RTOS-specific handler. This timer cannot be hooked
48   by application code.
49
50   Optional hooks are also provided to install a handler per level at
51   run-time, made available by compiling this source file with
52   '-DXT_INTEXC_HOOKS' (useful for automated testing).
53
54 !!  This file is a template that usually needs to be modified to handle       !!
55 !!  application specific interrupts. Search USER_EDIT for helpful comments    !!
56 !!  on where to insert handlers and how to write them.                        !!
57
58   Users can also install application-specific exception handlers in the
59   same way, by calling xt_set_exception_handler(). One handler slot is
60   provided for each exception type. Note that some exceptions are handled
61   by the porting layer itself, and cannot be taken over by application
62   code in this manner. These are the alloca, syscall, and coprocessor
63   exceptions.
64
65   The exception handlers can be written in C, and must follow C calling
66   convention. Each handler is passed a pointer to an exception frame as
67   its single argument. The exception frame is created on the stack, and
68   holds the saved context of the thread that took the exception. If the
69   handler returns, the context will be restored and the instruction that
70   caused the exception will be retried. If the handler makes any changes
71   to the saved state in the exception frame, the changes will be applied
72   when restoring the context.
73
74   Because Xtensa is a configurable architecture, this port supports all user
75   generated configurations (except restrictions stated in the release notes).
76   This is accomplished by conditional compilation using macros and functions
77   defined in the Xtensa HAL (hardware adaptation layer) for your configuration.
78   Only the relevant parts of this file will be included in your RTOS build.
79   For example, this file provides interrupt vector templates for all types and
80   all priority levels, but only the ones in your configuration are built.
81
82   NOTES on the use of 'call0' for long jumps instead of 'j':
83    1. This file should be assembled with the -mlongcalls option to xt-xcc.
84    2. The -mlongcalls compiler option causes 'call0 dest' to be expanded to
85       a sequence 'l32r a0, dest' 'callx0 a0' which works regardless of the
86       distance from the call to the destination. The linker then relaxes
87       it back to 'call0 dest' if it determines that dest is within range.
88       This allows more flexibility in locating code without the performance
89       overhead of the 'l32r' literal data load in cases where the destination
90       is in range of 'call0'. There is an additional benefit in that 'call0'
91       has a longer range than 'j' due to the target being word-aligned, so
92       the 'l32r' sequence is less likely needed.
93    3. The use of 'call0' with -mlongcalls requires that register a0 not be
94       live at the time of the call, which is always the case for a function
95       call but needs to be ensured if 'call0' is used as a jump in lieu of 'j'.
96    4. This use of 'call0' is independent of the C function call ABI.
97
98  */
99
100 #include "xtensa_rtos.h"
101
102
103 /* Enable stack backtrace across exception/interrupt - see below */
104 #define XT_DEBUG_BACKTRACE    1
105
106
107 /*
108 --------------------------------------------------------------------------------
109   Defines used to access _xtos_interrupt_table.
110 --------------------------------------------------------------------------------
111 */
112 #define XIE_HANDLER     0
113 #define XIE_ARG         4
114 #define XIE_SIZE        8
115
116 /*
117 --------------------------------------------------------------------------------
118   Macro extract_msb - return the input with only the highest bit set.
119
120   Input  : "ain"  - Input value, clobbered.
121   Output : "aout" - Output value, has only one bit set, MSB of "ain".
122   The two arguments must be different AR registers.
123 --------------------------------------------------------------------------------
124 */
125
126     .macro  extract_msb     aout ain
127 1:
128     addi    \aout, \ain, -1         /* aout = ain - 1        */
129     and     \ain, \ain, \aout       /* ain  = ain & aout     */
130     bnez    \ain, 1b                /* repeat until ain == 0 */
131     addi    \aout, \aout, 1         /* return aout + 1       */
132     .endm
133
134 /*
135 --------------------------------------------------------------------------------
136   Macro dispatch_c_isr - dispatch interrupts to user ISRs.
137   This will dispatch to user handlers (if any) that are registered in the
138   XTOS dispatch table (_xtos_interrupt_table). These handlers would have
139   been registered by calling _xtos_set_interrupt_handler(). There is one
140   exception - the timer interrupt used by the OS will not be dispatched
141   to a user handler - this must be handled by the caller of this macro.
142
143   Level triggered and software interrupts are automatically deasserted by
144   this code.
145
146   ASSUMPTIONS:
147     -- PS.INTLEVEL is set to "level" at entry
148     -- PS.EXCM = 0, C calling enabled
149
150   NOTE: For CALL0 ABI, a12-a15 have not yet been saved.
151
152   NOTE: This macro will use registers a0 and a2-a6. The arguments are:
153     level -- interrupt level
154     mask  -- interrupt bitmask for this level
155 --------------------------------------------------------------------------------
156 */
157
158     .macro  dispatch_c_isr    level  mask
159
160     /* Get mask of pending, enabled interrupts at this level into a2. */
161
162 .L_xt_user_int_&level&:
163     rsr     a2, INTENABLE
164     rsr     a3, INTERRUPT
165     movi    a4, \mask
166     and     a2, a2, a3
167     and     a2, a2, a4
168     beqz    a2, 9f                          /* nothing to do */
169
170     /* This bit of code provides a nice debug backtrace in the debugger.
171        It does take a few more instructions, so undef XT_DEBUG_BACKTRACE
172        if you want to save the cycles.
173     */
174     #if XT_DEBUG_BACKTRACE
175     #ifndef __XTENSA_CALL0_ABI__
176     rsr     a0, EPC_1 + \level - 1          /* return address */
177     movi    a4, 0xC0000000                  /* constant with top 2 bits set (call size) */
178     or      a0, a0, a4                      /* set top 2 bits */
179     addx2   a0, a4, a0                      /* clear top bit -- simulating call4 size   */
180     #endif
181     #endif
182
183     #ifdef XT_INTEXC_HOOKS
184     /* Call interrupt hook if present to (pre)handle interrupts. */
185     movi    a4, _xt_intexc_hooks
186     l32i    a4, a4, \level << 2
187     beqz    a4, 2f
188     #ifdef __XTENSA_CALL0_ABI__
189     callx0  a4
190     beqz    a2, 9f
191     #else
192     mov     a6, a2
193     callx4  a4
194     beqz    a6, 9f
195     mov     a2, a6
196     #endif
197 2:
198     #endif
199
200     /* Now look up in the dispatch table and call user ISR if any. */
201     /* If multiple bits are set then MSB has highest priority.     */
202
203     extract_msb  a4, a2                     /* a4 = MSB of a2, a2 trashed */
204
205     #ifdef XT_USE_SWPRI
206     /* Enable all interrupts at this level that are numerically higher
207        than the one we just selected, since they are treated as higher
208        priority.
209     */
210     movi    a3, \mask                       /* a3 = all interrupts at this level */
211     add     a2, a4, a4                      /* a2 = a4 << 1 */
212     addi    a2, a2, -1                      /* a2 = mask of 1's <= a4 bit */
213     and     a2, a2, a3                      /* a2 = mask of all bits <= a4 at this level */
214     movi    a3, _xt_intdata
215     l32i    a6, a3, 4                       /* a6 = _xt_vpri_mask */
216     neg     a2, a2
217     addi    a2, a2, -1                      /* a2 = mask to apply */
218     and     a5, a6, a2                      /* mask off all bits <= a4 bit */
219     s32i    a5, a3, 4                       /* update _xt_vpri_mask */
220     rsr     a3, INTENABLE
221     and     a3, a3, a2                      /* mask off all bits <= a4 bit */
222     wsr     a3, INTENABLE
223     rsil    a3, \level - 1                  /* lower interrupt level by 1 */
224     #endif
225
226     movi    a3, XT_TIMER_INTEN              /* a3 = timer interrupt bit */
227     wsr     a4, INTCLEAR                    /* clear sw or edge-triggered interrupt */
228     beq     a3, a4, 7f                      /* if timer interrupt then skip table */
229
230     find_ms_setbit a3, a4, a3, 0            /* a3 = interrupt number */
231
232     movi    a4, _xt_interrupt_table
233     addx8   a3, a3, a4                      /* a3 = address of interrupt table entry */
234     l32i    a4, a3, XIE_HANDLER             /* a4 = handler address */
235     #ifdef __XTENSA_CALL0_ABI__
236     mov     a12, a6                         /* save in callee-saved reg */
237     l32i    a2, a3, XIE_ARG                 /* a2 = handler arg */
238     callx0  a4                              /* call handler */
239     mov     a2, a12
240     #else
241     mov     a2, a6                          /* save in windowed reg */
242     l32i    a6, a3, XIE_ARG                 /* a6 = handler arg */
243     callx4  a4                              /* call handler */
244     #endif
245
246     #ifdef XT_USE_SWPRI
247     j       8f
248     #else
249     j       .L_xt_user_int_&level&          /* check for more interrupts */
250     #endif
251
252 7:
253
254     .ifeq XT_TIMER_INTPRI - \level
255 .L_xt_user_int_timer_&level&:
256     /*
257     Interrupt handler for the RTOS tick timer if at this level.
258     We'll be reading the interrupt state again after this call
259     so no need to preserve any registers except a6 (vpri_mask).
260     */
261
262     #ifdef __XTENSA_CALL0_ABI__
263     mov     a12, a6
264     call0   XT_RTOS_TIMER_INT
265     mov     a2, a12
266     #else
267     mov     a2, a6
268     call4   XT_RTOS_TIMER_INT
269     #endif
270     .endif
271
272     #ifdef XT_USE_SWPRI
273     j       8f
274     #else
275     j       .L_xt_user_int_&level&          /* check for more interrupts */
276     #endif
277
278     #ifdef XT_USE_SWPRI
279 8:
280     /* Restore old value of _xt_vpri_mask from a2. Also update INTENABLE from
281        virtual _xt_intenable which _could_ have changed during interrupt
282        processing. */
283
284     movi    a3, _xt_intdata
285     l32i    a4, a3, 0                       /* a4 = _xt_intenable    */
286     s32i    a2, a3, 4                       /* update _xt_vpri_mask  */
287     and     a4, a4, a2                      /* a4 = masked intenable */
288     wsr     a4, INTENABLE                   /* update INTENABLE      */
289     #endif
290
291 9:
292     /* done */
293
294     .endm
295
296
297 /*
298 --------------------------------------------------------------------------------
299   Panic handler.
300   Should be reached by call0 (preferable) or jump only. If call0, a0 says where
301   from. If on simulator, display panic message and abort, else loop indefinitely.
302 --------------------------------------------------------------------------------
303 */
304
305     .text
306     .global     _xt_panic
307     .type       _xt_panic,@function
308     .align      4
309     .literal_position
310
311 _xt_panic:
312     #ifdef XT_SIMULATOR
313     addi    a4, a0, -3                      /* point to call0 */
314     movi    a3, _xt_panic_message
315     movi    a2, SYS_log_msg
316     simcall
317     movi    a2, SYS_gdb_abort
318     simcall
319     #else
320     rsil    a2, XCHAL_EXCM_LEVEL            /* disable all low & med ints */
321 1:  j       1b                              /* loop infinitely */
322     #endif
323
324     .section    .rodata, "a"
325     .align      4
326
327 _xt_panic_message:
328     .string "\n*** _xt_panic() was called from 0x%08x or jumped to. ***\n"
329
330
331 /*
332 --------------------------------------------------------------------------------
333     Hooks to dynamically install handlers for exceptions and interrupts.
334     Allows automated regression frameworks to install handlers per test.
335     Consists of an array of function pointers indexed by interrupt level,
336     with index 0 containing the entry for user exceptions.
337     Initialized with all 0s, meaning no handler is installed at each level.
338     See comment in xtensa_rtos.h for more details.
339 --------------------------------------------------------------------------------
340 */
341
342     #ifdef XT_INTEXC_HOOKS
343     .data
344     .global     _xt_intexc_hooks
345     .type       _xt_intexc_hooks,@object
346     .align      4
347
348 _xt_intexc_hooks:
349     .fill       XT_INTEXC_HOOK_NUM, 4, 0
350     #endif
351
352
353 /*
354 --------------------------------------------------------------------------------
355   EXCEPTION AND LEVEL 1 INTERRUPT VECTORS AND LOW LEVEL HANDLERS
356   (except window exception vectors).
357
358   Each vector goes at a predetermined location according to the Xtensa
359   hardware configuration, which is ensured by its placement in a special
360   section known to the Xtensa linker support package (LSP). It performs
361   the minimum necessary before jumping to the handler in the .text section.
362
363   The corresponding handler goes in the normal .text section. It sets up
364   the appropriate stack frame, saves a few vector-specific registers and
365   calls XT_RTOS_INT_ENTER to save the rest of the interrupted context
366   and enter the RTOS, then sets up a C environment. It then calls the
367   user's interrupt handler code (which may be coded in C) and finally
368   calls XT_RTOS_INT_EXIT to transfer control to the RTOS for scheduling.
369
370   While XT_RTOS_INT_EXIT does not return directly to the interruptee,
371   eventually the RTOS scheduler will want to dispatch the interrupted
372   task or handler. The scheduler will return to the exit point that was
373   saved in the interrupt stack frame at XT_STK_EXIT.
374 --------------------------------------------------------------------------------
375 */
376
377
378 /*
379 --------------------------------------------------------------------------------
380 Debug Exception.
381 --------------------------------------------------------------------------------
382 */
383
384 #if XCHAL_HAVE_DEBUG
385
386     .begin      literal_prefix .DebugExceptionVector
387     .section    .DebugExceptionVector.text, "ax"
388     .global     _DebugExceptionVector
389     .align      4
390     .literal_position
391
392 _DebugExceptionVector:
393
394     #ifdef XT_SIMULATOR
395     /*
396     In the simulator, let the debugger (if any) handle the debug exception,
397     or simply stop the simulation:
398     */
399     wsr     a2, EXCSAVE+XCHAL_DEBUGLEVEL    /* save a2 where sim expects it */
400     movi    a2, SYS_gdb_enter_sktloop
401     simcall                                 /* have ISS handle debug exc. */
402     #elif 0 /* change condition to 1 to use the HAL minimal debug handler */
403     wsr     a3, EXCSAVE+XCHAL_DEBUGLEVEL
404     movi    a3, xthal_debugexc_defhndlr_nw  /* use default debug handler */
405     jx      a3
406     #else
407     wsr     a0, EXCSAVE+XCHAL_DEBUGLEVEL    /* save original a0 somewhere */
408     call0   _xt_panic                       /* does not return */
409     rfi     XCHAL_DEBUGLEVEL                /* make a0 point here not later */
410     #endif
411
412     .end        literal_prefix
413
414 #endif
415
416 /*
417 --------------------------------------------------------------------------------
418 Double Exception.
419 Double exceptions are not a normal occurrence. They indicate a bug of some kind.
420 --------------------------------------------------------------------------------
421 */
422
423 #ifdef XCHAL_DOUBLEEXC_VECTOR_VADDR
424
425     .begin      literal_prefix .DoubleExceptionVector
426     .section    .DoubleExceptionVector.text, "ax"
427     .global     _DoubleExceptionVector
428     .align      4
429     .literal_position
430
431 _DoubleExceptionVector:
432
433     #if XCHAL_HAVE_DEBUG
434     break   1, 4                            /* unhandled double exception */
435     #endif
436     call0   _xt_panic                       /* does not return */
437     rfde                                    /* make a0 point here not later */
438
439     .end        literal_prefix
440
441 #endif /* XCHAL_DOUBLEEXC_VECTOR_VADDR */
442
443 /*
444 --------------------------------------------------------------------------------
445 Kernel Exception (including Level 1 Interrupt from kernel mode).
446 --------------------------------------------------------------------------------
447 */
448
449     .begin      literal_prefix .KernelExceptionVector
450     .section    .KernelExceptionVector.text, "ax"
451     .global     _KernelExceptionVector
452     .align      4
453     .literal_position
454
455 _KernelExceptionVector:
456
457     wsr     a0, EXCSAVE_1                   /* preserve a0 */
458     call0   _xt_kernel_exc                  /* kernel exception handler */
459     /* never returns here - call0 is used as a jump (see note at top) */
460
461     .end        literal_prefix
462
463     .text
464     .align      4
465
466 _xt_kernel_exc:
467     #if XCHAL_HAVE_DEBUG
468     break   1, 0                            /* unhandled kernel exception */
469     #endif
470     call0   _xt_panic                       /* does not return */
471     rfe                                     /* make a0 point here not there */
472
473
474 /*
475 --------------------------------------------------------------------------------
476 User Exception (including Level 1 Interrupt from user mode).
477 --------------------------------------------------------------------------------
478 */
479
480     .begin      literal_prefix .UserExceptionVector
481     .section    .UserExceptionVector.text, "ax"
482     .global     _UserExceptionVector
483     .type       _UserExceptionVector,@function
484     .align      4
485     .literal_position
486
487 _UserExceptionVector:
488
489     wsr     a0, EXCSAVE_1                   /* preserve a0 */
490     call0   _xt_user_exc                    /* user exception handler */
491     /* never returns here - call0 is used as a jump (see note at top) */
492
493     .end        literal_prefix
494
495 /*
496 --------------------------------------------------------------------------------
497   Insert some waypoints for jumping beyond the signed 8-bit range of
498   conditional branch instructions, so the conditional branchces to specific
499   exception handlers are not taken in the mainline. Saves some cycles in the
500   mainline.
501 --------------------------------------------------------------------------------
502 */
503
504     .text
505
506     #if XCHAL_HAVE_WINDOWED
507     .align      4
508 _xt_to_alloca_exc:
509     call0   _xt_alloca_exc                  /* in window vectors section */
510     /* never returns here - call0 is used as a jump (see note at top) */
511     #endif
512
513     .align      4
514 _xt_to_syscall_exc:
515     call0   _xt_syscall_exc
516     /* never returns here - call0 is used as a jump (see note at top) */
517
518     #if XCHAL_CP_NUM > 0
519     .align      4
520 _xt_to_coproc_exc:
521     call0   _xt_coproc_exc
522     /* never returns here - call0 is used as a jump (see note at top) */
523     #endif
524
525
526 /*
527 --------------------------------------------------------------------------------
528   User exception handler.
529 --------------------------------------------------------------------------------
530 */
531
532     .type       _xt_user_exc,@function
533     .align      4
534
535 _xt_user_exc:
536
537     /* If level 1 interrupt then jump to the dispatcher */
538     rsr     a0, EXCCAUSE
539     beqi    a0, EXCCAUSE_LEVEL1INTERRUPT, _xt_lowint1
540
541     /* Handle any coprocessor exceptions. Rely on the fact that exception
542        numbers above EXCCAUSE_CP0_DISABLED all relate to the coprocessors.
543     */
544     #if XCHAL_CP_NUM > 0
545     bgeui   a0, EXCCAUSE_CP0_DISABLED, _xt_to_coproc_exc
546     #endif
547
548     /* Handle alloca and syscall exceptions */
549     #if XCHAL_HAVE_WINDOWED
550     beqi    a0, EXCCAUSE_ALLOCA,  _xt_to_alloca_exc
551     #endif
552     beqi    a0, EXCCAUSE_SYSCALL, _xt_to_syscall_exc
553
554     /* Handle all other exceptions. All can have user-defined handlers. */
555     /* NOTE: we'll stay on the user stack for exception handling.       */
556
557     /* Allocate exception frame and save minimal context. */
558     mov     a0, sp
559     addi    sp, sp, -XT_STK_FRMSZ
560     s32i    a0, sp, XT_STK_A1
561     #if XCHAL_HAVE_WINDOWED
562     s32e    a0, sp, -12                     /* for debug backtrace */
563     #endif
564     rsr     a0, PS                          /* save interruptee's PS */
565     s32i    a0, sp, XT_STK_PS
566     rsr     a0, EPC_1                       /* save interruptee's PC */
567     s32i    a0, sp, XT_STK_PC
568     rsr     a0, EXCSAVE_1                   /* save interruptee's a0 */
569     s32i    a0, sp, XT_STK_A0
570     #if XCHAL_HAVE_WINDOWED
571     s32e    a0, sp, -16                     /* for debug backtrace */
572     #endif
573     s32i    a12, sp, XT_STK_A12             /* _xt_context_save requires A12- */
574     s32i    a13, sp, XT_STK_A13             /* A13 to have already been saved */
575     call0   _xt_context_save
576
577     /* Save exc cause and vaddr into exception frame */
578     rsr     a0, EXCCAUSE
579     s32i    a0, sp, XT_STK_EXCCAUSE
580     rsr     a0, EXCVADDR
581     s32i    a0, sp, XT_STK_EXCVADDR
582
583     /* Set up PS for C, reenable hi-pri interrupts, and clear EXCM. */
584     #ifdef __XTENSA_CALL0_ABI__
585     movi    a0, PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM
586     #else
587     movi    a0, PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM | PS_WOE
588     #endif
589     wsr     a0, PS
590
591     #ifdef XT_DEBUG_BACKTRACE
592     #ifndef __XTENSA_CALL0_ABI__
593     rsr     a0, EPC_1                       /* return address for debug backtrace */
594     movi    a5, 0xC0000000                  /* constant with top 2 bits set (call size) */
595     rsync                                   /* wait for WSR.PS to complete */
596     or      a0, a0, a5                      /* set top 2 bits */
597     addx2   a0, a5, a0                      /* clear top bit -- thus simulating call4 size */
598     #else
599     rsync                                   /* wait for WSR.PS to complete */
600     #endif
601     #endif
602
603     rsr     a2, EXCCAUSE                    /* recover exc cause */
604
605     #ifdef XT_INTEXC_HOOKS
606     /*
607     Call exception hook to pre-handle exceptions (if installed).
608     Pass EXCCAUSE in a2, and check result in a2 (if -1, skip default handling).
609     */
610     movi    a4, _xt_intexc_hooks
611     l32i    a4, a4, 0                       /* user exception hook index 0 */
612     beqz    a4, 1f
613 .Ln_xt_user_exc_call_hook:
614     #ifdef __XTENSA_CALL0_ABI__
615     callx0  a4
616     beqi    a2, -1, .L_xt_user_done
617     #else
618     mov     a6, a2
619     callx4  a4
620     beqi    a6, -1, .L_xt_user_done
621     mov     a2, a6
622     #endif
623 1:
624     #endif
625
626     rsr     a2, EXCCAUSE                    /* recover exc cause */
627     movi    a3, _xt_exception_table
628     addx4   a4, a2, a3                      /* a4 = address of exception table entry */
629     l32i    a4, a4, 0                       /* a4 = handler address */
630     #ifdef __XTENSA_CALL0_ABI__
631     mov     a2, sp                          /* a2 = pointer to exc frame */
632     callx0  a4                              /* call handler */
633     #else
634     mov     a6, sp                          /* a6 = pointer to exc frame */
635     callx4  a4                              /* call handler */
636     #endif
637
638 .L_xt_user_done:
639
640     /* Restore context and return */
641     call0   _xt_context_restore
642     l32i    a0, sp, XT_STK_PS               /* retrieve interruptee's PS */
643     wsr     a0, PS
644     l32i    a0, sp, XT_STK_PC               /* retrieve interruptee's PC */
645     wsr     a0, EPC_1
646     l32i    a0, sp, XT_STK_A0               /* retrieve interruptee's A0 */
647     l32i    sp, sp, XT_STK_A1               /* remove exception frame */
648     rsync                                   /* ensure PS and EPC written */
649     rfe                                     /* PS.EXCM is cleared */
650
651
652 /*
653 --------------------------------------------------------------------------------
654   Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT
655   on entry and used to return to a thread or interrupted interrupt handler.
656 --------------------------------------------------------------------------------
657 */
658
659     .global     _xt_user_exit
660     .type       _xt_user_exit,@function
661     .align      4
662 _xt_user_exit:
663     l32i    a0, sp, XT_STK_PS               /* retrieve interruptee's PS */
664     wsr     a0, PS
665     l32i    a0, sp, XT_STK_PC               /* retrieve interruptee's PC */
666     wsr     a0, EPC_1
667     l32i    a0, sp, XT_STK_A0               /* retrieve interruptee's A0 */
668     l32i    sp, sp, XT_STK_A1               /* remove interrupt stack frame */
669     rsync                                   /* ensure PS and EPC written */
670     rfe                                     /* PS.EXCM is cleared */
671
672
673 /*
674 --------------------------------------------------------------------------------
675 Syscall Exception Handler (jumped to from User Exception Handler).
676 Syscall 0 is required to spill the register windows (no-op in Call 0 ABI).
677 Only syscall 0 is handled here. Other syscalls return -1 to caller in a2.
678 --------------------------------------------------------------------------------
679 */
680
681     .text
682     .type       _xt_syscall_exc,@function
683     .align      4
684 _xt_syscall_exc:
685
686     #ifdef __XTENSA_CALL0_ABI__
687     /*
688     Save minimal regs for scratch. Syscall 0 does nothing in Call0 ABI.
689     Use a minimal stack frame (16B) to save A2 & A3 for scratch.
690     PS.EXCM could be cleared here, but unlikely to improve worst-case latency.
691     rsr     a0, PS
692     addi    a0, a0, -PS_EXCM_MASK
693     wsr     a0, PS
694     */
695     addi    sp, sp, -16
696     s32i    a2, sp, 8
697     s32i    a3, sp, 12
698     #else   /* Windowed ABI */
699     /*
700     Save necessary context and spill the register windows.
701     PS.EXCM is still set and must remain set until after the spill.
702     Reuse context save function though it saves more than necessary.
703     For this reason, a full interrupt stack frame is allocated.
704     */
705     addi    sp, sp, -XT_STK_FRMSZ           /* allocate interrupt stack frame */
706     s32i    a12, sp, XT_STK_A12             /* _xt_context_save requires A12- */
707     s32i    a13, sp, XT_STK_A13             /* A13 to have already been saved */
708     call0   _xt_context_save
709     #endif
710
711     /*
712     Grab the interruptee's PC and skip over the 'syscall' instruction.
713     If it's at the end of a zero-overhead loop and it's not on the last
714     iteration, decrement loop counter and skip to beginning of loop.
715     */
716     rsr     a2, EPC_1                       /* a2 = PC of 'syscall' */
717     addi    a3, a2, 3                       /* ++PC                 */
718     #if XCHAL_HAVE_LOOPS
719     rsr     a0, LEND                        /* if (PC == LEND       */
720     bne     a3, a0, 1f
721     rsr     a0, LCOUNT                      /*     && LCOUNT != 0)  */
722     beqz    a0, 1f                          /* {                    */
723     addi    a0, a0, -1                      /*   --LCOUNT           */
724     rsr     a3, LBEG                        /*   PC = LBEG          */
725     wsr     a0, LCOUNT                      /* }                    */
726     #endif
727 1:  wsr     a3, EPC_1                       /* update PC            */
728
729     /* Restore interruptee's context and return from exception. */
730     #ifdef __XTENSA_CALL0_ABI__
731     l32i    a2, sp, 8
732     l32i    a3, sp, 12
733     addi    sp, sp, 16
734     #else
735     call0   _xt_context_restore
736     addi    sp, sp, XT_STK_FRMSZ
737     #endif
738     movi    a0, -1
739     movnez  a2, a0, a2                      /* return -1 if not syscall 0 */
740     rsr     a0, EXCSAVE_1
741     rfe
742
743 /*
744 --------------------------------------------------------------------------------
745 Co-Processor Exception Handler (jumped to from User Exception Handler).
746 These exceptions are generated by co-processor instructions, which are only
747 allowed in thread code (not in interrupts or kernel code). This restriction is
748 deliberately imposed to reduce the burden of state-save/restore in interrupts.
749 --------------------------------------------------------------------------------
750 */
751 #if XCHAL_CP_NUM > 0
752
753     .section .rodata, "a"
754
755 /* Offset to CP n save area in thread's CP save area. */
756     .global _xt_coproc_sa_offset
757     .type   _xt_coproc_sa_offset,@object
758     .align  16                      /* minimize crossing cache boundaries */
759 _xt_coproc_sa_offset:
760     .word   XT_CP0_SA, XT_CP1_SA, XT_CP2_SA, XT_CP3_SA
761     .word   XT_CP4_SA, XT_CP5_SA, XT_CP6_SA, XT_CP7_SA
762
763 /* Bitmask for CP n's CPENABLE bit. */
764     .type   _xt_coproc_mask,@object
765     .align  16,,8                   /* try to keep it all in one cache line */
766     .set    i, 0
767 _xt_coproc_mask:
768     .rept   XCHAL_CP_MAX
769     .long   (i<<16) | (1<<i)    // upper 16-bits = i, lower = bitmask
770     .set    i, i+1
771     .endr
772
773     .data
774
775 /* Owner thread of CP n, identified by thread's CP save area (0 = unowned). */
776     .global _xt_coproc_owner_sa
777     .type   _xt_coproc_owner_sa,@object
778     .align  16,,XCHAL_CP_MAX<<2     /* minimize crossing cache boundaries */
779 _xt_coproc_owner_sa:
780     .space  XCHAL_CP_MAX << 2
781
782     .text
783
784
785     .align  4
786 .L_goto_invalid:
787     j   .L_xt_coproc_invalid    /* not in a thread (invalid) */
788     .align  4
789 .L_goto_done:
790     j   .L_xt_coproc_done
791
792
793 /*
794 --------------------------------------------------------------------------------
795   Coprocessor exception handler.
796   At entry, only a0 has been saved (in EXCSAVE_1).
797 --------------------------------------------------------------------------------
798 */
799
800     .type   _xt_coproc_exc,@function
801     .align  4
802
803 _xt_coproc_exc:
804
805     /* Allocate interrupt stack frame and save minimal context. */
806     mov     a0, sp                          /* sp == a1 */
807     addi    sp, sp, -XT_STK_FRMSZ           /* allocate interrupt stack frame */
808     s32i    a0, sp, XT_STK_A1               /* save pre-interrupt SP */
809     #if XCHAL_HAVE_WINDOWED
810     s32e    a0, sp, -12                     /* for debug backtrace */
811     #endif
812     rsr     a0, PS                          /* save interruptee's PS */
813     s32i    a0, sp, XT_STK_PS
814     rsr     a0, EPC_1                       /* save interruptee's PC */
815     s32i    a0, sp, XT_STK_PC
816     rsr     a0, EXCSAVE_1                   /* save interruptee's a0 */
817     s32i    a0, sp, XT_STK_A0
818     #if XCHAL_HAVE_WINDOWED
819     s32e    a0, sp, -16                     /* for debug backtrace */
820     #endif
821     movi    a0, _xt_user_exit               /* save exit point for dispatch */
822     s32i    a0, sp, XT_STK_EXIT
823
824     rsr     a0, EXCCAUSE
825     s32i    a5, sp, XT_STK_A5               /* save a5 */
826     addi    a5, a0, -EXCCAUSE_CP0_DISABLED  /* a5 = CP index */
827
828     /* Save a few more of interruptee's registers (a5 was already saved). */
829     s32i    a2,  sp, XT_STK_A2
830     s32i    a3,  sp, XT_STK_A3
831     s32i    a4,  sp, XT_STK_A4
832     s32i    a15, sp, XT_STK_A15
833
834     /* Get co-processor state save area of new owner thread. */
835     call0   XT_RTOS_CP_STATE                /* a15 = new owner's save area */
836     beqz    a15, .L_goto_invalid            /* not in a thread (invalid) */
837
838     /* Enable the co-processor's bit in CPENABLE. */
839     movi    a0, _xt_coproc_mask
840     rsr     a4, CPENABLE                    /* a4 = CPENABLE */
841     addx4   a0, a5, a0                      /* a0 = &_xt_coproc_mask[n] */
842     l32i    a0, a0, 0                       /* a0 = (n << 16) | (1 << n) */
843     movi    a3, _xt_coproc_owner_sa     /* (placed here for load slot) */
844     extui   a2, a0, 0, 16                   /* coprocessor bitmask portion */
845     or      a4, a4, a2                      /* a4 = CPENABLE | (1 << n) */
846     wsr     a4, CPENABLE
847
848     /* Get old coprocessor owner thread (save area ptr) and assign new one.  */
849     addx4   a3,  a5, a3                      /* a3 = &_xt_coproc_owner_sa[n] */
850     l32i    a2,  a3, 0                       /* a2 = old owner's save area */
851     s32i    a15, a3, 0                       /* _xt_coproc_owner_sa[n] = new */
852     rsync                                    /* ensure wsr.CPENABLE is complete */
853
854     /* Only need to context switch if new owner != old owner. */
855     beq     a15, a2, .L_goto_done           /* new owner == old, we're done */
856
857     /* If no old owner then nothing to save. */
858     beqz    a2, .L_check_new
859
860     /* If old owner not actively using CP then nothing to save. */
861     l16ui   a4,  a2,  XT_CPENABLE           /* a4 = old owner's CPENABLE */
862     bnone   a4,  a0,  .L_check_new          /* old owner not using CP    */
863
864 .L_save_old:
865     /* Save old owner's coprocessor state. */
866
867     movi    a5, _xt_coproc_sa_offset
868
869     /* Mark old owner state as no longer active (CPENABLE bit n clear). */
870     xor     a4,  a4,  a0                    /* clear CP bit in CPENABLE    */
871     s16i    a4,  a2,  XT_CPENABLE           /* update old owner's CPENABLE */
872
873     extui   a4,  a0,  16,  5                /* a4 = CP index = n */
874     addx4   a5,  a4,  a5                    /* a5 = &_xt_coproc_sa_offset[n] */
875
876     /* Mark old owner state as saved (CPSTORED bit n set). */
877     l16ui   a4,  a2,  XT_CPSTORED           /* a4 = old owner's CPSTORED */
878     l32i    a5,  a5,  0                     /* a5 = XT_CP[n]_SA offset */
879     or      a4,  a4,  a0                    /* set CP in old owner's CPSTORED */
880     s16i    a4,  a2,  XT_CPSTORED           /* update old owner's CPSTORED */
881     l32i    a2, a2, XT_CP_ASA               /* ptr to actual (aligned) save area */
882     extui   a3, a0, 16, 5                   /* a3 = CP index = n */
883     add     a2, a2, a5                      /* a2 = old owner's area for CP n */
884
885     /*
886     The config-specific HAL macro invoked below destroys a2-5, preserves a0-1.
887     It is theoretically possible for Xtensa processor designers to write TIE
888     that causes more address registers to be affected, but it is generally
889     unlikely. If that ever happens, more registers needs to be saved/restored
890     around this macro invocation, and the value in a15 needs to be recomputed.
891     */
892     xchal_cpi_store_funcbody
893
894 .L_check_new:
895     /* Check if any state has to be restored for new owner. */
896     /* NOTE: a15 = new owner's save area, cannot be zero when we get here. */
897
898     l16ui   a3,  a15, XT_CPSTORED           /* a3 = new owner's CPSTORED */
899     movi    a4, _xt_coproc_sa_offset
900     bnone   a3,  a0,  .L_check_cs           /* full CP not saved, check callee-saved */
901     xor     a3,  a3,  a0                    /* CPSTORED bit is set, clear it */
902     s16i    a3,  a15, XT_CPSTORED           /* update new owner's CPSTORED */
903
904     /* Adjust new owner's save area pointers to area for CP n. */
905     extui   a3,  a0, 16, 5                  /* a3 = CP index = n */
906     addx4   a4,  a3, a4                     /* a4 = &_xt_coproc_sa_offset[n] */
907     l32i    a4,  a4, 0                      /* a4 = XT_CP[n]_SA */
908     l32i    a5, a15, XT_CP_ASA              /* ptr to actual (aligned) save area */
909     add     a2,  a4, a5                     /* a2 = new owner's area for CP */
910
911     /*
912     The config-specific HAL macro invoked below destroys a2-5, preserves a0-1.
913     It is theoretically possible for Xtensa processor designers to write TIE
914     that causes more address registers to be affected, but it is generally
915     unlikely. If that ever happens, more registers needs to be saved/restored
916     around this macro invocation.
917     */
918     xchal_cpi_load_funcbody
919
920     /* Restore interruptee's saved registers. */
921     /* Can omit rsync for wsr.CPENABLE here because _xt_user_exit does it. */
922 .L_xt_coproc_done:
923     l32i    a15, sp, XT_STK_A15
924     l32i    a5,  sp, XT_STK_A5
925     l32i    a4,  sp, XT_STK_A4
926     l32i    a3,  sp, XT_STK_A3
927     l32i    a2,  sp, XT_STK_A2
928     call0   _xt_user_exit                   /* return via exit dispatcher */
929     /* Never returns here - call0 is used as a jump (see note at top) */
930
931 .L_check_cs:
932     /* a0 = CP mask in low bits, a15 = new owner's save area */
933     l16ui   a2, a15, XT_CP_CS_ST            /* a2 = mask of CPs saved    */
934     bnone   a2,  a0, .L_xt_coproc_done      /* if no match then done     */
935     and     a2,  a2, a0                     /* a2 = which CPs to restore */
936     extui   a2,  a2, 0, 8                   /* extract low 8 bits        */
937     s32i    a6,  sp, XT_STK_A6              /* save extra needed regs    */
938     s32i    a7,  sp, XT_STK_A7
939     s32i    a13, sp, XT_STK_A13
940     s32i    a14, sp, XT_STK_A14
941     call0   _xt_coproc_restorecs            /* restore CP registers      */
942     l32i    a6,  sp, XT_STK_A6              /* restore saved registers   */
943     l32i    a7,  sp, XT_STK_A7
944     l32i    a13, sp, XT_STK_A13
945     l32i    a14, sp, XT_STK_A14
946     j       .L_xt_coproc_done
947
948     /* Co-processor exception occurred outside a thread (not supported). */
949 .L_xt_coproc_invalid:
950     #if XCHAL_HAVE_DEBUG
951     break   1, 1                            /* unhandled user exception */
952     #endif
953     call0   _xt_panic                       /* not in a thread (invalid) */
954     /* never returns */
955
956
957 #endif /* XCHAL_CP_NUM */
958
959
960 /*
961 -------------------------------------------------------------------------------
962   Level 1 interrupt dispatch. Assumes stack frame has not been allocated yet.
963 -------------------------------------------------------------------------------
964 */
965
966     .text
967     .type       _xt_lowint1,@function
968     .align      4
969
970 _xt_lowint1:
971     mov     a0, sp                          /* sp == a1 */
972     addi    sp, sp, -XT_STK_FRMSZ           /* allocate interrupt stack frame */
973     s32i    a0, sp, XT_STK_A1               /* save pre-interrupt SP */
974     rsr     a0, PS                          /* save interruptee's PS */
975     s32i    a0, sp, XT_STK_PS
976     rsr     a0, EPC_1                       /* save interruptee's PC */
977     s32i    a0, sp, XT_STK_PC
978     rsr     a0, EXCSAVE_1                   /* save interruptee's a0 */
979     s32i    a0, sp, XT_STK_A0
980     movi    a0, _xt_user_exit               /* save exit point for dispatch */
981     s32i    a0, sp, XT_STK_EXIT
982
983     /* Save rest of interrupt context and enter RTOS. */
984     call0   XT_RTOS_INT_ENTER               /* common RTOS interrupt entry */
985
986     /* !! We are now on the RTOS system stack !! */
987
988     /* Set up PS for C, enable interrupts above this level and clear EXCM. */
989     #ifdef __XTENSA_CALL0_ABI__
990     movi    a0, PS_INTLEVEL(1) | PS_UM
991     #else
992     movi    a0, PS_INTLEVEL(1) | PS_UM | PS_WOE
993     #endif
994     wsr     a0, PS
995     rsync
996
997     /* OK to call C code at this point, dispatch user ISRs */
998
999     dispatch_c_isr 1 XCHAL_INTLEVEL1_MASK
1000
1001     /* Done handling interrupts, transfer control to OS */
1002     call0   XT_RTOS_INT_EXIT                /* does not return directly here */
1003
1004
1005 /*
1006 -------------------------------------------------------------------------------
1007   MEDIUM PRIORITY (LEVEL 2+) INTERRUPT VECTORS AND LOW LEVEL HANDLERS.
1008
1009   Medium priority interrupts are by definition those with priority greater
1010   than 1 and not greater than XCHAL_EXCM_LEVEL. These are disabled by
1011   setting PS.EXCM and therefore can easily support a C environment for
1012   handlers in C, and interact safely with an RTOS.
1013
1014   Each vector goes at a predetermined location according to the Xtensa
1015   hardware configuration, which is ensured by its placement in a special
1016   section known to the Xtensa linker support package (LSP). It performs
1017   the minimum necessary before jumping to the handler in the .text section.
1018
1019   The corresponding handler goes in the normal .text section. It sets up
1020   the appropriate stack frame, saves a few vector-specific registers and
1021   calls XT_RTOS_INT_ENTER to save the rest of the interrupted context
1022   and enter the RTOS, then sets up a C environment. It then calls the
1023   user's interrupt handler code (which may be coded in C) and finally
1024   calls XT_RTOS_INT_EXIT to transfer control to the RTOS for scheduling.
1025
1026   While XT_RTOS_INT_EXIT does not return directly to the interruptee,
1027   eventually the RTOS scheduler will want to dispatch the interrupted
1028   task or handler. The scheduler will return to the exit point that was
1029   saved in the interrupt stack frame at XT_STK_EXIT.
1030 -------------------------------------------------------------------------------
1031 */
1032
1033 #if XCHAL_EXCM_LEVEL >= 2
1034
1035     .begin      literal_prefix .Level2InterruptVector
1036     .section    .Level2InterruptVector.text, "ax"
1037     .global     _Level2Vector
1038     .type       _Level2Vector,@function
1039     .align      4
1040     .literal_position
1041
1042 _Level2Vector:
1043     wsr     a0, EXCSAVE_2                   /* preserve a0 */
1044     call0   _xt_medint2                     /* load interrupt handler */
1045     /* never returns here - call0 is used as a jump (see note at top) */
1046
1047     .end        literal_prefix
1048
1049     .text
1050     .type       _xt_medint2,@function
1051     .align      4
1052 _xt_medint2:
1053     mov     a0, sp                          /* sp == a1 */
1054     addi    sp, sp, -XT_STK_FRMSZ           /* allocate interrupt stack frame */
1055     s32i    a0, sp, XT_STK_A1               /* save pre-interrupt SP */
1056     rsr     a0, EPS_2                       /* save interruptee's PS */
1057     s32i    a0, sp, XT_STK_PS
1058     rsr     a0, EPC_2                       /* save interruptee's PC */
1059     s32i    a0, sp, XT_STK_PC
1060     rsr     a0, EXCSAVE_2                   /* save interruptee's a0 */
1061     s32i    a0, sp, XT_STK_A0
1062     movi    a0, _xt_medint2_exit            /* save exit point for dispatch */
1063     s32i    a0, sp, XT_STK_EXIT
1064
1065     /* Save rest of interrupt context and enter RTOS. */
1066     call0   XT_RTOS_INT_ENTER               /* common RTOS interrupt entry */
1067
1068     /* !! We are now on the RTOS system stack !! */
1069
1070     /* Set up PS for C, enable interrupts above this level and clear EXCM. */
1071     #ifdef __XTENSA_CALL0_ABI__
1072     movi    a0, PS_INTLEVEL(2) | PS_UM
1073     #else
1074     movi    a0, PS_INTLEVEL(2) | PS_UM | PS_WOE
1075     #endif
1076     wsr     a0, PS
1077     rsync
1078
1079     /* OK to call C code at this point, dispatch user ISRs */
1080
1081     dispatch_c_isr 2 XCHAL_INTLEVEL2_MASK
1082
1083     /* Done handling interrupts, transfer control to OS */
1084     call0   XT_RTOS_INT_EXIT                /* does not return directly here */
1085
1086     /*
1087     Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT
1088     on entry and used to return to a thread or interrupted interrupt handler.
1089     */
1090     .global     _xt_medint2_exit
1091     .type       _xt_medint2_exit,@function
1092     .align      4
1093 _xt_medint2_exit:
1094     /* Restore only level-specific regs (the rest were already restored) */
1095     l32i    a0, sp, XT_STK_PS               /* retrieve interruptee's PS */
1096     wsr     a0, EPS_2
1097     l32i    a0, sp, XT_STK_PC               /* retrieve interruptee's PC */
1098     wsr     a0, EPC_2
1099     l32i    a0, sp, XT_STK_A0               /* retrieve interruptee's A0 */
1100     l32i    sp, sp, XT_STK_A1               /* remove interrupt stack frame */
1101     rsync                                   /* ensure EPS and EPC written */
1102     rfi     2
1103
1104 #endif  /* Level 2 */
1105
1106 #if XCHAL_EXCM_LEVEL >= 3
1107
1108     .begin      literal_prefix .Level3InterruptVector
1109     .section    .Level3InterruptVector.text, "ax"
1110     .global     _Level3Vector
1111     .type       _Level3Vector,@function
1112     .align      4
1113     .literal_position
1114
1115 _Level3Vector:
1116     wsr     a0, EXCSAVE_3                   /* preserve a0 */
1117     call0   _xt_medint3                     /* load interrupt handler */
1118     /* never returns here - call0 is used as a jump (see note at top) */
1119
1120     .end        literal_prefix
1121
1122     .text
1123     .type       _xt_medint3,@function
1124     .align      4
1125 _xt_medint3:
1126     mov     a0, sp                          /* sp == a1 */
1127     addi    sp, sp, -XT_STK_FRMSZ           /* allocate interrupt stack frame */
1128     s32i    a0, sp, XT_STK_A1               /* save pre-interrupt SP */
1129     rsr     a0, EPS_3                       /* save interruptee's PS */
1130     s32i    a0, sp, XT_STK_PS
1131     rsr     a0, EPC_3                       /* save interruptee's PC */
1132     s32i    a0, sp, XT_STK_PC
1133     rsr     a0, EXCSAVE_3                   /* save interruptee's a0 */
1134     s32i    a0, sp, XT_STK_A0
1135     movi    a0, _xt_medint3_exit            /* save exit point for dispatch */
1136     s32i    a0, sp, XT_STK_EXIT
1137
1138     /* Save rest of interrupt context and enter RTOS. */
1139     call0   XT_RTOS_INT_ENTER               /* common RTOS interrupt entry */
1140
1141     /* !! We are now on the RTOS system stack !! */
1142
1143     /* Set up PS for C, enable interrupts above this level and clear EXCM. */
1144     #ifdef __XTENSA_CALL0_ABI__
1145     movi    a0, PS_INTLEVEL(3) | PS_UM
1146     #else
1147     movi    a0, PS_INTLEVEL(3) | PS_UM | PS_WOE
1148     #endif
1149     wsr     a0, PS
1150     rsync
1151
1152     /* OK to call C code at this point, dispatch user ISRs */
1153
1154     dispatch_c_isr 3 XCHAL_INTLEVEL3_MASK
1155
1156     /* Done handling interrupts, transfer control to OS */
1157     call0   XT_RTOS_INT_EXIT                /* does not return directly here */
1158
1159     /*
1160     Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT
1161     on entry and used to return to a thread or interrupted interrupt handler.
1162     */
1163     .global     _xt_medint3_exit
1164     .type       _xt_medint3_exit,@function
1165     .align      4
1166 _xt_medint3_exit:
1167     /* Restore only level-specific regs (the rest were already restored) */
1168     l32i    a0, sp, XT_STK_PS               /* retrieve interruptee's PS */
1169     wsr     a0, EPS_3
1170     l32i    a0, sp, XT_STK_PC               /* retrieve interruptee's PC */
1171     wsr     a0, EPC_3
1172     l32i    a0, sp, XT_STK_A0               /* retrieve interruptee's A0 */
1173     l32i    sp, sp, XT_STK_A1               /* remove interrupt stack frame */
1174     rsync                                   /* ensure EPS and EPC written */
1175     rfi     3
1176
1177 #endif  /* Level 3 */
1178
1179 #if XCHAL_EXCM_LEVEL >= 4
1180
1181     .begin      literal_prefix .Level4InterruptVector
1182     .section    .Level4InterruptVector.text, "ax"
1183     .global     _Level4Vector
1184     .type       _Level4Vector,@function
1185     .align      4
1186     .literal_position
1187
1188 _Level4Vector:
1189     wsr     a0, EXCSAVE_4                   /* preserve a0 */
1190     call0   _xt_medint4                     /* load interrupt handler */
1191
1192     .end        literal_prefix
1193
1194     .text
1195     .type       _xt_medint4,@function
1196     .align      4
1197 _xt_medint4:
1198     mov     a0, sp                          /* sp == a1 */
1199     addi    sp, sp, -XT_STK_FRMSZ           /* allocate interrupt stack frame */
1200     s32i    a0, sp, XT_STK_A1               /* save pre-interrupt SP */
1201     rsr     a0, EPS_4                       /* save interruptee's PS */
1202     s32i    a0, sp, XT_STK_PS
1203     rsr     a0, EPC_4                       /* save interruptee's PC */
1204     s32i    a0, sp, XT_STK_PC
1205     rsr     a0, EXCSAVE_4                   /* save interruptee's a0 */
1206     s32i    a0, sp, XT_STK_A0
1207     movi    a0, _xt_medint4_exit            /* save exit point for dispatch */
1208     s32i    a0, sp, XT_STK_EXIT
1209
1210     /* Save rest of interrupt context and enter RTOS. */
1211     call0   XT_RTOS_INT_ENTER               /* common RTOS interrupt entry */
1212
1213     /* !! We are now on the RTOS system stack !! */
1214
1215     /* Set up PS for C, enable interrupts above this level and clear EXCM. */
1216     #ifdef __XTENSA_CALL0_ABI__
1217     movi    a0, PS_INTLEVEL(4) | PS_UM
1218     #else
1219     movi    a0, PS_INTLEVEL(4) | PS_UM | PS_WOE
1220     #endif
1221     wsr     a0, PS
1222     rsync
1223
1224     /* OK to call C code at this point, dispatch user ISRs */
1225
1226     dispatch_c_isr 4 XCHAL_INTLEVEL4_MASK
1227
1228     /* Done handling interrupts, transfer control to OS */
1229     call0   XT_RTOS_INT_EXIT                /* does not return directly here */
1230
1231     /*
1232     Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT
1233     on entry and used to return to a thread or interrupted interrupt handler.
1234     */
1235     .global     _xt_medint4_exit
1236     .type       _xt_medint4_exit,@function
1237     .align      4
1238 _xt_medint4_exit:
1239     /* Restore only level-specific regs (the rest were already restored) */
1240     l32i    a0, sp, XT_STK_PS               /* retrieve interruptee's PS */
1241     wsr     a0, EPS_4
1242     l32i    a0, sp, XT_STK_PC               /* retrieve interruptee's PC */
1243     wsr     a0, EPC_4
1244     l32i    a0, sp, XT_STK_A0               /* retrieve interruptee's A0 */
1245     l32i    sp, sp, XT_STK_A1               /* remove interrupt stack frame */
1246     rsync                                   /* ensure EPS and EPC written */
1247     rfi     4
1248
1249 #endif  /* Level 4 */
1250
1251 #if XCHAL_EXCM_LEVEL >= 5
1252
1253     .begin      literal_prefix .Level5InterruptVector
1254     .section    .Level5InterruptVector.text, "ax"
1255     .global     _Level5Vector
1256     .type       _Level5Vector,@function
1257     .align      4
1258     .literal_position
1259
1260 _Level5Vector:
1261     wsr     a0, EXCSAVE_5                   /* preserve a0 */
1262     call0   _xt_medint5                     /* load interrupt handler */
1263
1264     .end        literal_prefix
1265
1266     .text
1267     .type       _xt_medint5,@function
1268     .align      4
1269 _xt_medint5:
1270     mov     a0, sp                          /* sp == a1 */
1271     addi    sp, sp, -XT_STK_FRMSZ           /* allocate interrupt stack frame */
1272     s32i    a0, sp, XT_STK_A1               /* save pre-interrupt SP */
1273     rsr     a0, EPS_5                       /* save interruptee's PS */
1274     s32i    a0, sp, XT_STK_PS
1275     rsr     a0, EPC_5                       /* save interruptee's PC */
1276     s32i    a0, sp, XT_STK_PC
1277     rsr     a0, EXCSAVE_5                   /* save interruptee's a0 */
1278     s32i    a0, sp, XT_STK_A0
1279     movi    a0, _xt_medint5_exit            /* save exit point for dispatch */
1280     s32i    a0, sp, XT_STK_EXIT
1281
1282     /* Save rest of interrupt context and enter RTOS. */
1283     call0   XT_RTOS_INT_ENTER               /* common RTOS interrupt entry */
1284
1285     /* !! We are now on the RTOS system stack !! */
1286
1287     /* Set up PS for C, enable interrupts above this level and clear EXCM. */
1288     #ifdef __XTENSA_CALL0_ABI__
1289     movi    a0, PS_INTLEVEL(5) | PS_UM
1290     #else
1291     movi    a0, PS_INTLEVEL(5) | PS_UM | PS_WOE
1292     #endif
1293     wsr     a0, PS
1294     rsync
1295
1296     /* OK to call C code at this point, dispatch user ISRs */
1297
1298     dispatch_c_isr 5 XCHAL_INTLEVEL5_MASK
1299
1300     /* Done handling interrupts, transfer control to OS */
1301     call0   XT_RTOS_INT_EXIT                /* does not return directly here */
1302
1303     /*
1304     Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT
1305     on entry and used to return to a thread or interrupted interrupt handler.
1306     */
1307     .global     _xt_medint5_exit
1308     .type       _xt_medint5_exit,@function
1309     .align      4
1310 _xt_medint5_exit:
1311     /* Restore only level-specific regs (the rest were already restored) */
1312     l32i    a0, sp, XT_STK_PS               /* retrieve interruptee's PS */
1313     wsr     a0, EPS_5
1314     l32i    a0, sp, XT_STK_PC               /* retrieve interruptee's PC */
1315     wsr     a0, EPC_5
1316     l32i    a0, sp, XT_STK_A0               /* retrieve interruptee's A0 */
1317     l32i    sp, sp, XT_STK_A1               /* remove interrupt stack frame */
1318     rsync                                   /* ensure EPS and EPC written */
1319     rfi     5
1320
1321 #endif  /* Level 5 */
1322
1323 #if XCHAL_EXCM_LEVEL >= 6
1324
1325     .begin      literal_prefix .Level6InterruptVector
1326     .section    .Level6InterruptVector.text, "ax"
1327     .global     _Level6Vector
1328     .type       _Level6Vector,@function
1329     .align      4
1330     .literal_position
1331
1332 _Level6Vector:
1333     wsr     a0, EXCSAVE_6                   /* preserve a0 */
1334     call0   _xt_medint6                     /* load interrupt handler */
1335
1336     .end        literal_prefix
1337
1338     .text
1339     .type       _xt_medint6,@function
1340     .align      4
1341 _xt_medint6:
1342     mov     a0, sp                          /* sp == a1 */
1343     addi    sp, sp, -XT_STK_FRMSZ           /* allocate interrupt stack frame */
1344     s32i    a0, sp, XT_STK_A1               /* save pre-interrupt SP */
1345     rsr     a0, EPS_6                       /* save interruptee's PS */
1346     s32i    a0, sp, XT_STK_PS
1347     rsr     a0, EPC_6                       /* save interruptee's PC */
1348     s32i    a0, sp, XT_STK_PC
1349     rsr     a0, EXCSAVE_6                   /* save interruptee's a0 */
1350     s32i    a0, sp, XT_STK_A0
1351     movi    a0, _xt_medint6_exit            /* save exit point for dispatch */
1352     s32i    a0, sp, XT_STK_EXIT
1353
1354     /* Save rest of interrupt context and enter RTOS. */
1355     call0   XT_RTOS_INT_ENTER               /* common RTOS interrupt entry */
1356
1357     /* !! We are now on the RTOS system stack !! */
1358
1359     /* Set up PS for C, enable interrupts above this level and clear EXCM. */
1360     #ifdef __XTENSA_CALL0_ABI__
1361     movi    a0, PS_INTLEVEL(6) | PS_UM
1362     #else
1363     movi    a0, PS_INTLEVEL(6) | PS_UM | PS_WOE
1364     #endif
1365     wsr     a0, PS
1366     rsync
1367
1368     /* OK to call C code at this point, dispatch user ISRs */
1369
1370     dispatch_c_isr 6 XCHAL_INTLEVEL6_MASK
1371
1372     /* Done handling interrupts, transfer control to OS */
1373     call0   XT_RTOS_INT_EXIT                /* does not return directly here */
1374
1375     /*
1376     Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT
1377     on entry and used to return to a thread or interrupted interrupt handler.
1378     */
1379     .global     _xt_medint6_exit
1380     .type       _xt_medint6_exit,@function
1381     .align      4
1382 _xt_medint6_exit:
1383     /* Restore only level-specific regs (the rest were already restored) */
1384     l32i    a0, sp, XT_STK_PS               /* retrieve interruptee's PS */
1385     wsr     a0, EPS_6
1386     l32i    a0, sp, XT_STK_PC               /* retrieve interruptee's PC */
1387     wsr     a0, EPC_6
1388     l32i    a0, sp, XT_STK_A0               /* retrieve interruptee's A0 */
1389     l32i    sp, sp, XT_STK_A1               /* remove interrupt stack frame */
1390     rsync                                   /* ensure EPS and EPC written */
1391     rfi     6
1392
1393 #endif  /* Level 6 */
1394
1395
1396 /*******************************************************************************
1397
1398 HIGH PRIORITY (LEVEL > XCHAL_EXCM_LEVEL) INTERRUPT VECTORS AND HANDLERS
1399
1400 High priority interrupts are by definition those with priorities greater
1401 than XCHAL_EXCM_LEVEL. This includes non-maskable (NMI). High priority
1402 interrupts cannot interact with the RTOS, that is they must save all regs
1403 they use and not call any RTOS function.
1404
1405 A further restriction imposed by the Xtensa windowed architecture is that
1406 high priority interrupts must not modify the stack area even logically
1407 "above" the top of the interrupted stack (they need to provide their
1408 own stack or static save area).
1409
1410 Cadence Design Systems recommends high priority interrupt handlers be coded in assembly
1411 and used for purposes requiring very short service times.
1412
1413 Here are templates for high priority (level 2+) interrupt vectors.
1414 They assume only one interrupt per level to avoid the burden of identifying
1415 which interrupts at this level are pending and enabled. This allows for
1416 minimum latency and avoids having to save/restore a2 in addition to a0.
1417 If more than one interrupt per high priority level is configured, this burden
1418 is on the handler which in any case must provide a way to save and restore
1419 registers it uses without touching the interrupted stack.
1420
1421 Each vector goes at a predetermined location according to the Xtensa
1422 hardware configuration, which is ensured by its placement in a special
1423 section known to the Xtensa linker support package (LSP). It performs
1424 the minimum necessary before jumping to the handler in the .text section.
1425
1426 *******************************************************************************/
1427
1428 /*
1429 Currently only shells for high priority interrupt handlers are provided
1430 here. However a template and example can be found in the Cadence Design Systems tools
1431 documentation: "Microprocessor Programmer's Guide".
1432 */
1433
1434 #if XCHAL_NUM_INTLEVELS >=2 && XCHAL_EXCM_LEVEL <2 && XCHAL_DEBUGLEVEL !=2
1435
1436     .begin      literal_prefix .Level2InterruptVector
1437     .section    .Level2InterruptVector.text, "ax"
1438     .global     _Level2Vector
1439     .type       _Level2Vector,@function
1440     .align      4
1441 _Level2Vector:
1442     wsr     a0, EXCSAVE_2                   /* preserve a0 */
1443     call0   _xt_highint2                    /* load interrupt handler */
1444
1445     .end        literal_prefix
1446
1447     .text
1448     .type       _xt_highint2,@function
1449     .align      4
1450 _xt_highint2:
1451
1452     #ifdef XT_INTEXC_HOOKS
1453     /* Call interrupt hook if present to (pre)handle interrupts. */
1454     movi    a0, _xt_intexc_hooks
1455     l32i    a0, a0, 2<<2
1456     beqz    a0, 1f
1457 .Ln_xt_highint2_call_hook:
1458     callx0  a0                              /* must NOT disturb stack! */
1459 1:
1460     #endif
1461
1462     /* USER_EDIT:
1463     ADD HIGH PRIORITY LEVEL 2 INTERRUPT HANDLER CODE HERE.
1464     */
1465
1466     .align  4
1467 .L_xt_highint2_exit:
1468     rsr     a0, EXCSAVE_2                   /* restore a0 */
1469     rfi     2
1470
1471 #endif  /* Level 2 */
1472
1473 #if XCHAL_NUM_INTLEVELS >=3 && XCHAL_EXCM_LEVEL <3 && XCHAL_DEBUGLEVEL !=3
1474
1475     .begin      literal_prefix .Level3InterruptVector
1476     .section    .Level3InterruptVector.text, "ax"
1477     .global     _Level3Vector
1478     .type       _Level3Vector,@function
1479     .align      4
1480 _Level3Vector:
1481     wsr     a0, EXCSAVE_3                   /* preserve a0 */
1482     call0   _xt_highint3                    /* load interrupt handler */
1483     /* never returns here - call0 is used as a jump (see note at top) */
1484
1485     .end        literal_prefix
1486
1487     .text
1488     .type       _xt_highint3,@function
1489     .align      4
1490 _xt_highint3:
1491
1492     #ifdef XT_INTEXC_HOOKS
1493     /* Call interrupt hook if present to (pre)handle interrupts. */
1494     movi    a0, _xt_intexc_hooks
1495     l32i    a0, a0, 3<<2
1496     beqz    a0, 1f
1497 .Ln_xt_highint3_call_hook:
1498     callx0  a0                              /* must NOT disturb stack! */
1499 1:
1500     #endif
1501
1502     /* USER_EDIT:
1503     ADD HIGH PRIORITY LEVEL 3 INTERRUPT HANDLER CODE HERE.
1504     */
1505
1506     .align  4
1507 .L_xt_highint3_exit:
1508     rsr     a0, EXCSAVE_3                   /* restore a0 */
1509     rfi     3
1510
1511 #endif  /* Level 3 */
1512
1513 #if XCHAL_NUM_INTLEVELS >=4 && XCHAL_EXCM_LEVEL <4 && XCHAL_DEBUGLEVEL !=4
1514
1515     .begin      literal_prefix .Level4InterruptVector
1516     .section    .Level4InterruptVector.text, "ax"
1517     .global     _Level4Vector
1518     .type       _Level4Vector,@function
1519     .align      4
1520 _Level4Vector:
1521     wsr     a0, EXCSAVE_4                   /* preserve a0 */
1522     call0   _xt_highint4                    /* load interrupt handler */
1523     /* never returns here - call0 is used as a jump (see note at top) */
1524
1525     .end        literal_prefix
1526
1527     .text
1528     .type       _xt_highint4,@function
1529     .align      4
1530 _xt_highint4:
1531
1532     #ifdef XT_INTEXC_HOOKS
1533     /* Call interrupt hook if present to (pre)handle interrupts. */
1534     movi    a0, _xt_intexc_hooks
1535     l32i    a0, a0, 4<<2
1536     beqz    a0, 1f
1537 .Ln_xt_highint4_call_hook:
1538     callx0  a0                              /* must NOT disturb stack! */
1539 1:
1540     #endif
1541
1542     /* USER_EDIT:
1543     ADD HIGH PRIORITY LEVEL 4 INTERRUPT HANDLER CODE HERE.
1544     */
1545
1546     .align  4
1547 .L_xt_highint4_exit:
1548     rsr     a0, EXCSAVE_4                   /* restore a0 */
1549     rfi     4
1550
1551 #endif  /* Level 4 */
1552
1553 #if XCHAL_NUM_INTLEVELS >=5 && XCHAL_EXCM_LEVEL <5 && XCHAL_DEBUGLEVEL !=5
1554
1555     .begin      literal_prefix .Level5InterruptVector
1556     .section    .Level5InterruptVector.text, "ax"
1557     .global     _Level5Vector
1558     .type       _Level5Vector,@function
1559     .align      4
1560 _Level5Vector:
1561     wsr     a0, EXCSAVE_5                   /* preserve a0 */
1562     call0   _xt_highint5                    /* load interrupt handler */
1563     /* never returns here - call0 is used as a jump (see note at top) */
1564
1565     .end        literal_prefix
1566
1567     .text
1568     .type       _xt_highint5,@function
1569     .align      4
1570 _xt_highint5:
1571
1572     #ifdef XT_INTEXC_HOOKS
1573     /* Call interrupt hook if present to (pre)handle interrupts. */
1574     movi    a0, _xt_intexc_hooks
1575     l32i    a0, a0, 5<<2
1576     beqz    a0, 1f
1577 .Ln_xt_highint5_call_hook:
1578     callx0  a0                              /* must NOT disturb stack! */
1579 1:
1580     #endif
1581
1582     /* USER_EDIT:
1583     ADD HIGH PRIORITY LEVEL 5 INTERRUPT HANDLER CODE HERE.
1584     */
1585
1586     .align  4
1587 .L_xt_highint5_exit:
1588     rsr     a0, EXCSAVE_5                   /* restore a0 */
1589     rfi     5
1590
1591 #endif  /* Level 5 */
1592
1593 #if XCHAL_NUM_INTLEVELS >=6 && XCHAL_EXCM_LEVEL <6 && XCHAL_DEBUGLEVEL !=6
1594
1595     .begin      literal_prefix .Level6InterruptVector
1596     .section    .Level6InterruptVector.text, "ax"
1597     .global     _Level6Vector
1598     .type       _Level6Vector,@function
1599     .align      4
1600 _Level6Vector:
1601     wsr     a0, EXCSAVE_6                   /* preserve a0 */
1602     call0   _xt_highint6                    /* load interrupt handler */
1603     /* never returns here - call0 is used as a jump (see note at top) */
1604
1605     .end        literal_prefix
1606
1607     .text
1608     .type       _xt_highint6,@function
1609     .align      4
1610 _xt_highint6:
1611
1612     #ifdef XT_INTEXC_HOOKS
1613     /* Call interrupt hook if present to (pre)handle interrupts. */
1614     movi    a0, _xt_intexc_hooks
1615     l32i    a0, a0, 6<<2
1616     beqz    a0, 1f
1617 .Ln_xt_highint6_call_hook:
1618     callx0  a0                              /* must NOT disturb stack! */
1619 1:
1620     #endif
1621
1622     /* USER_EDIT:
1623     ADD HIGH PRIORITY LEVEL 6 INTERRUPT HANDLER CODE HERE.
1624     */
1625
1626     .align  4
1627 .L_xt_highint6_exit:
1628     rsr     a0, EXCSAVE_6                   /* restore a0 */
1629     rfi     6
1630
1631 #endif  /* Level 6 */
1632
1633 #if XCHAL_HAVE_NMI
1634
1635     .begin      literal_prefix .NMIExceptionVector
1636     .section    .NMIExceptionVector.text, "ax"
1637     .global     _NMIExceptionVector
1638     .type       _NMIExceptionVector,@function
1639     .align      4
1640 _NMIExceptionVector:
1641     wsr     a0, EXCSAVE + XCHAL_NMILEVEL  _ /* preserve a0 */
1642     call0   _xt_nmi                         /* load interrupt handler */
1643     /* never returns here - call0 is used as a jump (see note at top) */
1644
1645     .end        literal_prefix
1646
1647     .text
1648     .type       _xt_nmi,@function
1649     .align      4
1650 _xt_nmi:
1651
1652     #ifdef XT_INTEXC_HOOKS
1653     /* Call interrupt hook if present to (pre)handle interrupts. */
1654     movi    a0, _xt_intexc_hooks
1655     l32i    a0, a0, XCHAL_NMILEVEL<<2
1656     beqz    a0, 1f
1657 .Ln_xt_nmi_call_hook:
1658     callx0  a0                              /* must NOT disturb stack! */
1659 1:
1660     #endif
1661
1662     /* USER_EDIT:
1663     ADD HIGH PRIORITY NON-MASKABLE INTERRUPT (NMI) HANDLER CODE HERE.
1664     */
1665
1666     .align  4
1667 .L_xt_nmi_exit:
1668     rsr     a0, EXCSAVE + XCHAL_NMILEVEL    /* restore a0 */
1669     rfi     XCHAL_NMILEVEL
1670
1671 #endif  /* NMI */
1672
1673
1674 /*******************************************************************************
1675
1676 WINDOW OVERFLOW AND UNDERFLOW EXCEPTION VECTORS AND ALLOCA EXCEPTION HANDLER
1677
1678 Here is the code for each window overflow/underflow exception vector and
1679 (interspersed) efficient code for handling the alloca exception cause.
1680 Window exceptions are handled entirely in the vector area and are very
1681 tight for performance. The alloca exception is also handled entirely in
1682 the window vector area so comes at essentially no cost in code size.
1683 Users should never need to modify them and Cadence Design Systems recommends
1684 they do not.
1685
1686 Window handlers go at predetermined vector locations according to the
1687 Xtensa hardware configuration, which is ensured by their placement in a
1688 special section known to the Xtensa linker support package (LSP). Since
1689 their offsets in that section are always the same, the LSPs do not define
1690 a section per vector.
1691
1692 These things are coded for XEA2 only (XEA1 is not supported).
1693
1694 Note on Underflow Handlers:
1695 The underflow handler for returning from call[i+1] to call[i]
1696 must preserve all the registers from call[i+1]'s window.
1697 In particular, a0 and a1 must be preserved because the RETW instruction
1698 will be reexecuted (and may even underflow if an intervening exception
1699 has flushed call[i]'s registers).
1700 Registers a2 and up may contain return values.
1701
1702 *******************************************************************************/
1703
1704 #if XCHAL_HAVE_WINDOWED
1705
1706     .section .WindowVectors.text, "ax"
1707
1708 /*
1709 --------------------------------------------------------------------------------
1710 Window Overflow Exception for Call4.
1711
1712 Invoked if a call[i] referenced a register (a4-a15)
1713 that contains data from ancestor call[j];
1714 call[j] had done a call4 to call[j+1].
1715 On entry here:
1716     window rotated to call[j] start point;
1717         a0-a3 are registers to be saved;
1718         a4-a15 must be preserved;
1719         a5 is call[j+1]'s stack pointer.
1720 --------------------------------------------------------------------------------
1721 */
1722
1723     .org    0x0
1724     .global _WindowOverflow4
1725 _WindowOverflow4:
1726
1727     s32e    a0, a5, -16     /* save a0 to call[j+1]'s stack frame */
1728     s32e    a1, a5, -12     /* save a1 to call[j+1]'s stack frame */
1729     s32e    a2, a5,  -8     /* save a2 to call[j+1]'s stack frame */
1730     s32e    a3, a5,  -4     /* save a3 to call[j+1]'s stack frame */
1731     rfwo                    /* rotates back to call[i] position */
1732
1733 /*
1734 --------------------------------------------------------------------------------
1735 Window Underflow Exception for Call4
1736
1737 Invoked by RETW returning from call[i+1] to call[i]
1738 where call[i]'s registers must be reloaded (not live in ARs);
1739 where call[i] had done a call4 to call[i+1].
1740 On entry here:
1741         window rotated to call[i] start point;
1742         a0-a3 are undefined, must be reloaded with call[i].reg[0..3];
1743         a4-a15 must be preserved (they are call[i+1].reg[0..11]);
1744         a5 is call[i+1]'s stack pointer.
1745 --------------------------------------------------------------------------------
1746 */
1747
1748     .org    0x40
1749     .global _WindowUnderflow4
1750 _WindowUnderflow4:
1751
1752     l32e    a0, a5, -16     /* restore a0 from call[i+1]'s stack frame */
1753     l32e    a1, a5, -12     /* restore a1 from call[i+1]'s stack frame */
1754     l32e    a2, a5,  -8     /* restore a2 from call[i+1]'s stack frame */
1755     l32e    a3, a5,  -4     /* restore a3 from call[i+1]'s stack frame */
1756     rfwu
1757
1758 /*
1759 --------------------------------------------------------------------------------
1760 Handle alloca exception generated by interruptee executing 'movsp'.
1761 This uses space between the window vectors, so is essentially "free".
1762 All interruptee's regs are intact except a0 which is saved in EXCSAVE_1,
1763 and PS.EXCM has been set by the exception hardware (can't be interrupted).
1764 The fact the alloca exception was taken means the registers associated with
1765 the base-save area have been spilled and will be restored by the underflow
1766 handler, so those 4 registers are available for scratch.
1767 The code is optimized to avoid unaligned branches and minimize cache misses.
1768 --------------------------------------------------------------------------------
1769 */
1770
1771     .align  4
1772     .global _xt_alloca_exc
1773 _xt_alloca_exc:
1774
1775     rsr     a0, WINDOWBASE  /* grab WINDOWBASE before rotw changes it */
1776     rotw    -1              /* WINDOWBASE goes to a4, new a0-a3 are scratch */
1777     rsr     a2, PS
1778     extui   a3, a2, XCHAL_PS_OWB_SHIFT, XCHAL_PS_OWB_BITS
1779     xor     a3, a3, a4      /* bits changed from old to current windowbase */
1780     rsr     a4, EXCSAVE_1   /* restore original a0 (now in a4) */
1781     slli    a3, a3, XCHAL_PS_OWB_SHIFT
1782     xor     a2, a2, a3      /* flip changed bits in old window base */
1783     wsr     a2, PS          /* update PS.OWB to new window base */
1784     rsync
1785
1786     _bbci.l a4, 31, _WindowUnderflow4
1787     rotw    -1              /* original a0 goes to a8 */
1788     _bbci.l a8, 30, _WindowUnderflow8
1789     rotw    -1
1790     j               _WindowUnderflow12
1791
1792 /*
1793 --------------------------------------------------------------------------------
1794 Window Overflow Exception for Call8
1795
1796 Invoked if a call[i] referenced a register (a4-a15)
1797 that contains data from ancestor call[j];
1798 call[j] had done a call8 to call[j+1].
1799 On entry here:
1800     window rotated to call[j] start point;
1801         a0-a7 are registers to be saved;
1802         a8-a15 must be preserved;
1803         a9 is call[j+1]'s stack pointer.
1804 --------------------------------------------------------------------------------
1805 */
1806
1807     .org    0x80
1808     .global _WindowOverflow8
1809 _WindowOverflow8:
1810
1811     s32e    a0, a9, -16     /* save a0 to call[j+1]'s stack frame */
1812     l32e    a0, a1, -12     /* a0 <- call[j-1]'s sp
1813                                (used to find end of call[j]'s frame) */
1814     s32e    a1, a9, -12     /* save a1 to call[j+1]'s stack frame */
1815     s32e    a2, a9,  -8     /* save a2 to call[j+1]'s stack frame */
1816     s32e    a3, a9,  -4     /* save a3 to call[j+1]'s stack frame */
1817     s32e    a4, a0, -32     /* save a4 to call[j]'s stack frame */
1818     s32e    a5, a0, -28     /* save a5 to call[j]'s stack frame */
1819     s32e    a6, a0, -24     /* save a6 to call[j]'s stack frame */
1820     s32e    a7, a0, -20     /* save a7 to call[j]'s stack frame */
1821     rfwo                    /* rotates back to call[i] position */
1822
1823 /*
1824 --------------------------------------------------------------------------------
1825 Window Underflow Exception for Call8
1826
1827 Invoked by RETW returning from call[i+1] to call[i]
1828 where call[i]'s registers must be reloaded (not live in ARs);
1829 where call[i] had done a call8 to call[i+1].
1830 On entry here:
1831         window rotated to call[i] start point;
1832         a0-a7 are undefined, must be reloaded with call[i].reg[0..7];
1833         a8-a15 must be preserved (they are call[i+1].reg[0..7]);
1834         a9 is call[i+1]'s stack pointer.
1835 --------------------------------------------------------------------------------
1836 */
1837
1838     .org    0xC0
1839     .global _WindowUnderflow8
1840 _WindowUnderflow8:
1841
1842     l32e    a0, a9, -16     /* restore a0 from call[i+1]'s stack frame */
1843     l32e    a1, a9, -12     /* restore a1 from call[i+1]'s stack frame */
1844     l32e    a2, a9,  -8     /* restore a2 from call[i+1]'s stack frame */
1845     l32e    a7, a1, -12     /* a7 <- call[i-1]'s sp
1846                                (used to find end of call[i]'s frame) */
1847     l32e    a3, a9,  -4     /* restore a3 from call[i+1]'s stack frame */
1848     l32e    a4, a7, -32     /* restore a4 from call[i]'s stack frame */
1849     l32e    a5, a7, -28     /* restore a5 from call[i]'s stack frame */
1850     l32e    a6, a7, -24     /* restore a6 from call[i]'s stack frame */
1851     l32e    a7, a7, -20     /* restore a7 from call[i]'s stack frame */
1852     rfwu
1853
1854 /*
1855 --------------------------------------------------------------------------------
1856 Window Overflow Exception for Call12
1857
1858 Invoked if a call[i] referenced a register (a4-a15)
1859 that contains data from ancestor call[j];
1860 call[j] had done a call12 to call[j+1].
1861 On entry here:
1862     window rotated to call[j] start point;
1863         a0-a11 are registers to be saved;
1864         a12-a15 must be preserved;
1865         a13 is call[j+1]'s stack pointer.
1866 --------------------------------------------------------------------------------
1867 */
1868
1869     .org    0x100
1870     .global _WindowOverflow12
1871 _WindowOverflow12:
1872
1873     s32e    a0,  a13, -16   /* save a0 to call[j+1]'s stack frame */
1874     l32e    a0,  a1,  -12   /* a0 <- call[j-1]'s sp
1875                                (used to find end of call[j]'s frame) */
1876     s32e    a1,  a13, -12   /* save a1 to call[j+1]'s stack frame */
1877     s32e    a2,  a13,  -8   /* save a2 to call[j+1]'s stack frame */
1878     s32e    a3,  a13,  -4   /* save a3 to call[j+1]'s stack frame */
1879     s32e    a4,  a0,  -48   /* save a4 to end of call[j]'s stack frame */
1880     s32e    a5,  a0,  -44   /* save a5 to end of call[j]'s stack frame */
1881     s32e    a6,  a0,  -40   /* save a6 to end of call[j]'s stack frame */
1882     s32e    a7,  a0,  -36   /* save a7 to end of call[j]'s stack frame */
1883     s32e    a8,  a0,  -32   /* save a8 to end of call[j]'s stack frame */
1884     s32e    a9,  a0,  -28   /* save a9 to end of call[j]'s stack frame */
1885     s32e    a10, a0,  -24   /* save a10 to end of call[j]'s stack frame */
1886     s32e    a11, a0,  -20   /* save a11 to end of call[j]'s stack frame */
1887     rfwo                    /* rotates back to call[i] position */
1888
1889 /*
1890 --------------------------------------------------------------------------------
1891 Window Underflow Exception for Call12
1892
1893 Invoked by RETW returning from call[i+1] to call[i]
1894 where call[i]'s registers must be reloaded (not live in ARs);
1895 where call[i] had done a call12 to call[i+1].
1896 On entry here:
1897         window rotated to call[i] start point;
1898         a0-a11 are undefined, must be reloaded with call[i].reg[0..11];
1899         a12-a15 must be preserved (they are call[i+1].reg[0..3]);
1900         a13 is call[i+1]'s stack pointer.
1901 --------------------------------------------------------------------------------
1902 */
1903
1904     .org 0x140
1905     .global _WindowUnderflow12
1906 _WindowUnderflow12:
1907
1908     l32e    a0,  a13, -16   /* restore a0 from call[i+1]'s stack frame */
1909     l32e    a1,  a13, -12   /* restore a1 from call[i+1]'s stack frame */
1910     l32e    a2,  a13,  -8   /* restore a2 from call[i+1]'s stack frame */
1911     l32e    a11, a1,  -12   /* a11 <- call[i-1]'s sp
1912                                (used to find end of call[i]'s frame) */
1913     l32e    a3,  a13,  -4   /* restore a3 from call[i+1]'s stack frame */
1914     l32e    a4,  a11, -48   /* restore a4 from end of call[i]'s stack frame */
1915     l32e    a5,  a11, -44   /* restore a5 from end of call[i]'s stack frame */
1916     l32e    a6,  a11, -40   /* restore a6 from end of call[i]'s stack frame */
1917     l32e    a7,  a11, -36   /* restore a7 from end of call[i]'s stack frame */
1918     l32e    a8,  a11, -32   /* restore a8 from end of call[i]'s stack frame */
1919     l32e    a9,  a11, -28   /* restore a9 from end of call[i]'s stack frame */
1920     l32e    a10, a11, -24   /* restore a10 from end of call[i]'s stack frame */
1921     l32e    a11, a11, -20   /* restore a11 from end of call[i]'s stack frame */
1922     rfwu
1923
1924 #endif /* XCHAL_HAVE_WINDOWED */