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