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