1 /*******************************************************************************
\r
2 Copyright (c) 2006-2015 Cadence Design Systems Inc.
\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
12 The above copyright notice and this permission notice shall be included
\r
13 in all copies or substantial portions of the Software.
\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
24 XTENSA VECTORS AND LOW LEVEL HANDLERS FOR AN RTOS
\r
26 Xtensa low level exception and interrupt vectors and handlers for an RTOS.
\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
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
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
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
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
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
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
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
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
91 *******************************************************************************/
\r
93 #include "xtensa_rtos.h"
\r
96 /* Enable stack backtrace across exception/interrupt - see below */
\r
97 #define XT_DEBUG_BACKTRACE 1
\r
101 --------------------------------------------------------------------------------
\r
102 Defines used to access _xtos_interrupt_table.
\r
103 --------------------------------------------------------------------------------
\r
105 #define XIE_HANDLER 0
\r
110 --------------------------------------------------------------------------------
\r
111 Macro extract_msb - return the input with only the highest bit set.
\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
119 .macro extract_msb aout ain
\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
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
136 Level triggered and software interrupts are automatically deasserted by
\r
140 -- PS.INTLEVEL is set to "level" at entry
\r
141 -- PS.EXCM = 0, C calling enabled
\r
143 NOTE: For CALL0 ABI, a12-a15 have not yet been saved.
\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
151 .macro dispatch_c_isr level mask
\r
153 /* Get mask of pending, enabled interrupts at this level into a2. */
\r
155 .L_xt_user_int_&level&:
\r
161 beqz a2, 9f /* nothing to do */
\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
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
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
181 #ifdef __XTENSA_CALL0_ABI__
\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
196 extract_msb a4, a2 /* a4 = MSB of a2, a2 trashed */
\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
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
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
214 and a3, a3, a2 /* mask off all bits <= a4 bit */
\r
216 rsil a3, \level - 1 /* lower interrupt level by 1 */
\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
223 find_ms_setbit a3, a4, a3, 0 /* a3 = interrupt number */
\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
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
239 #ifdef XT_USE_SWPRI
\r
242 j .L_xt_user_int_&level& /* check for more interrupts */
\r
247 .ifeq XT_TIMER_INTPRI - \level
\r
248 .L_xt_user_int_timer_&level&:
\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
255 #ifdef __XTENSA_CALL0_ABI__
\r
257 call0 XT_RTOS_TIMER_INT
\r
261 call4 XT_RTOS_TIMER_INT
\r
265 #ifdef XT_USE_SWPRI
\r
268 j .L_xt_user_int_&level& /* check for more interrupts */
\r
271 #ifdef XT_USE_SWPRI
\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
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
291 --------------------------------------------------------------------------------
\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
300 .type _xt_panic,@function
\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
309 movi a2, SYS_gdb_abort
\r
312 rsil a2, XCHAL_EXCM_LEVEL /* disable all low & med ints */
\r
313 1: j 1b /* loop infinitely */
\r
316 .section .rodata, "a"
\r
320 .string "\n*** _xt_panic() was called from 0x%08x or jumped to. ***\n"
\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
334 #ifdef XT_INTEXC_HOOKS
\r
336 .global _xt_intexc_hooks
\r
337 .type _xt_intexc_hooks,@object
\r
341 .fill XT_INTEXC_HOOK_NUM, 4, 0
\r
346 --------------------------------------------------------------------------------
\r
347 EXCEPTION AND LEVEL 1 INTERRUPT VECTORS AND LOW LEVEL HANDLERS
\r
348 (except window exception vectors).
\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
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
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
371 --------------------------------------------------------------------------------
\r
373 --------------------------------------------------------------------------------
\r
376 #if XCHAL_HAVE_DEBUG
\r
378 .begin literal_prefix .DebugExceptionVector
\r
379 .section .DebugExceptionVector.text, "ax"
\r
380 .global _DebugExceptionVector
\r
383 _DebugExceptionVector:
\r
385 #ifdef XT_SIMULATOR
\r
387 In the simulator, let the debugger (if any) handle the debug exception,
\r
388 or simply stop the simulation:
\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
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
403 .end literal_prefix
\r
408 --------------------------------------------------------------------------------
\r
410 Double exceptions are not a normal occurrence. They indicate a bug of some kind.
\r
411 --------------------------------------------------------------------------------
\r
414 #ifdef XCHAL_DOUBLEEXC_VECTOR_VADDR
\r
416 .begin literal_prefix .DoubleExceptionVector
\r
417 .section .DoubleExceptionVector.text, "ax"
\r
418 .global _DoubleExceptionVector
\r
421 _DoubleExceptionVector:
\r
423 #if XCHAL_HAVE_DEBUG
\r
424 break 1, 4 /* unhandled double exception */
\r
426 call0 _xt_panic /* does not return */
\r
427 rfde /* make a0 point here not later */
\r
429 .end literal_prefix
\r
431 #endif /* XCHAL_DOUBLEEXC_VECTOR_VADDR */
\r
434 --------------------------------------------------------------------------------
\r
435 Kernel Exception (including Level 1 Interrupt from kernel mode).
\r
436 --------------------------------------------------------------------------------
\r
439 .begin literal_prefix .KernelExceptionVector
\r
440 .section .KernelExceptionVector.text, "ax"
\r
441 .global _KernelExceptionVector
\r
444 _KernelExceptionVector:
\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
450 .end literal_prefix
\r
456 #if XCHAL_HAVE_DEBUG
\r
457 break 1, 0 /* unhandled kernel exception */
\r
459 call0 _xt_panic /* does not return */
\r
460 rfe /* make a0 point here not there */
\r
464 --------------------------------------------------------------------------------
\r
465 User Exception (including Level 1 Interrupt from user mode).
\r
466 --------------------------------------------------------------------------------
\r
469 .begin literal_prefix .UserExceptionVector
\r
470 .section .UserExceptionVector.text, "ax"
\r
471 .global _UserExceptionVector
\r
472 .type _UserExceptionVector,@function
\r
475 _UserExceptionVector:
\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
481 .end literal_prefix
\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
489 --------------------------------------------------------------------------------
\r
494 #if XCHAL_HAVE_WINDOWED
\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
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
506 #if XCHAL_CP_NUM > 0
\r
509 call0 _xt_coproc_exc
\r
510 /* never returns here - call0 is used as a jump (see note at top) */
\r
515 --------------------------------------------------------------------------------
\r
516 User exception handler.
\r
517 --------------------------------------------------------------------------------
\r
520 .type _xt_user_exc,@function
\r
525 /* If level 1 interrupt then jump to the dispatcher */
\r
527 beqi a0, EXCCAUSE_LEVEL1INTERRUPT, _xt_lowint1
\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
532 #if XCHAL_CP_NUM > 0
\r
533 bgeui a0, EXCCAUSE_CP0_DISABLED, _xt_to_coproc_exc
\r
536 /* Handle alloca and syscall exceptions */
\r
537 #if XCHAL_HAVE_WINDOWED
\r
538 beqi a0, EXCCAUSE_ALLOCA, _xt_to_alloca_exc
\r
540 beqi a0, EXCCAUSE_SYSCALL, _xt_to_syscall_exc
\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
545 /* Allocate exception frame and save minimal context. */
\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
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
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
565 /* Save exc cause and vaddr into exception frame */
\r
567 s32i a0, sp, XT_STK_EXCCAUSE
\r
569 s32i a0, sp, XT_STK_EXCVADDR
\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
575 movi a0, PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM | PS_WOE
\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
587 rsync /* wait for WSR.PS to complete */
\r
591 rsr a2, EXCCAUSE /* recover exc cause */
\r
593 #ifdef XT_INTEXC_HOOKS
\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
598 movi a4, _xt_intexc_hooks
\r
599 l32i a4, a4, 0 /* user exception hook index 0 */
\r
601 .Ln_xt_user_exc_call_hook:
\r
602 #ifdef __XTENSA_CALL0_ABI__
\r
604 beqi a2, -1, .L_xt_user_done
\r
608 beqi a6, -1, .L_xt_user_done
\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
622 mov a6, sp /* a6 = pointer to exc frame */
\r
623 callx4 a4 /* call handler */
\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
632 l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */
\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
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
647 .global _xt_user_exit
\r
648 .type _xt_user_exit,@function
\r
651 l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */
\r
653 l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */
\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
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
670 .type _xt_syscall_exc,@function
\r
674 #ifdef __XTENSA_CALL0_ABI__
\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
680 addi a0, a0, -PS_EXCM_MASK
\r
686 #else /* Windowed ABI */
\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
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
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
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
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
715 1: wsr a3, EPC_1 /* update PC */
\r
717 /* Restore interruptee's context and return from exception. */
\r
718 #ifdef __XTENSA_CALL0_ABI__
\r
723 call0 _xt_context_restore
\r
724 addi sp, sp, XT_STK_FRMSZ
\r
727 movnez a2, a0, a2 /* return -1 if not syscall 0 */
\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
739 #if XCHAL_CP_NUM > 0
\r
741 .section .rodata, "a"
\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
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
757 .long (i<<16) | (1<<i) // upper 16-bits = i, lower = bitmask
\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
775 j .L_xt_coproc_invalid /* not in a thread (invalid) */
\r
778 j .L_xt_coproc_done
\r
782 --------------------------------------------------------------------------------
\r
783 Coprocessor exception handler.
\r
784 At entry, only a0 has been saved (in EXCSAVE_1).
\r
785 --------------------------------------------------------------------------------
\r
788 .type _xt_coproc_exc,@function
\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
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
809 movi a0, _xt_user_exit /* save exit point for dispatch */
\r
810 s32i a0, sp, XT_STK_EXIT
\r
813 s32i a5, sp, XT_STK_A5 /* save a5 */
\r
814 addi a5, a0, -EXCCAUSE_CP0_DISABLED /* a5 = CP index */
\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
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
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
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
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
845 /* If no old owner then nothing to save. */
\r
846 beqz a2, .L_check_new
\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
853 /* Save old owner's coprocessor state. */
\r
855 movi a5, _xt_coproc_sa_offset
\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
861 extui a4, a0, 16, 5 /* a4 = CP index = n */
\r
862 addx4 a5, a4, a5 /* a5 = &_xt_coproc_sa_offset[n] */
\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
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
880 xchal_cpi_store_funcbody
\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
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
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
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
906 xchal_cpi_load_funcbody
\r
908 /* Restore interruptee's saved registers. */
\r
909 /* Can omit rsync for wsr.CPENABLE here because _xt_user_exit does it. */
\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
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
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
941 call0 _xt_panic /* not in a thread (invalid) */
\r
942 /* never returns */
\r
945 #endif /* XCHAL_CP_NUM */
\r
949 -------------------------------------------------------------------------------
\r
950 Level 1 interrupt dispatch. Assumes stack frame has not been allocated yet.
\r
951 -------------------------------------------------------------------------------
\r
955 .type _xt_lowint1,@function
\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
971 /* Save rest of interrupt context and enter RTOS. */
\r
972 call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */
\r
974 /* !! We are now on the RTOS system stack !! */
\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
980 movi a0, PS_INTLEVEL(1) | PS_UM | PS_WOE
\r
985 /* OK to call C code at this point, dispatch user ISRs */
\r
987 dispatch_c_isr 1 XCHAL_INTLEVEL1_MASK
\r
989 /* Done handling interrupts, transfer control to OS */
\r
990 call0 XT_RTOS_INT_EXIT /* does not return directly here */
\r
994 -------------------------------------------------------------------------------
\r
995 MEDIUM PRIORITY (LEVEL 2+) INTERRUPT VECTORS AND LOW LEVEL HANDLERS.
\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
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
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
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
1021 #if XCHAL_EXCM_LEVEL >= 2
\r
1023 .begin literal_prefix .Level2InterruptVector
\r
1024 .section .Level2InterruptVector.text, "ax"
\r
1025 .global _Level2Vector
\r
1026 .type _Level2Vector,@function
\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
1033 .end literal_prefix
\r
1036 .type _xt_medint2,@function
\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
1051 /* Save rest of interrupt context and enter RTOS. */
\r
1052 call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */
\r
1054 /* !! We are now on the RTOS system stack !! */
\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
1060 movi a0, PS_INTLEVEL(2) | PS_UM | PS_WOE
\r
1065 /* OK to call C code at this point, dispatch user ISRs */
\r
1067 dispatch_c_isr 2 XCHAL_INTLEVEL2_MASK
\r
1069 /* Done handling interrupts, transfer control to OS */
\r
1070 call0 XT_RTOS_INT_EXIT /* does not return directly here */
\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
1076 .global _xt_medint2_exit
\r
1077 .type _xt_medint2_exit,@function
\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
1083 l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */
\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
1090 #endif /* Level 2 */
\r
1092 #if XCHAL_EXCM_LEVEL >= 3
\r
1094 .begin literal_prefix .Level3InterruptVector
\r
1095 .section .Level3InterruptVector.text, "ax"
\r
1096 .global _Level3Vector
\r
1097 .type _Level3Vector,@function
\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
1104 .end literal_prefix
\r
1107 .type _xt_medint3,@function
\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
1122 /* Save rest of interrupt context and enter RTOS. */
\r
1123 call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */
\r
1125 /* !! We are now on the RTOS system stack !! */
\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
1131 movi a0, PS_INTLEVEL(3) | PS_UM | PS_WOE
\r
1136 /* OK to call C code at this point, dispatch user ISRs */
\r
1138 dispatch_c_isr 3 XCHAL_INTLEVEL3_MASK
\r
1140 /* Done handling interrupts, transfer control to OS */
\r
1141 call0 XT_RTOS_INT_EXIT /* does not return directly here */
\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
1147 .global _xt_medint3_exit
\r
1148 .type _xt_medint3_exit,@function
\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
1154 l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */
\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
1161 #endif /* Level 3 */
\r
1163 #if XCHAL_EXCM_LEVEL >= 4
\r
1165 .begin literal_prefix .Level4InterruptVector
\r
1166 .section .Level4InterruptVector.text, "ax"
\r
1167 .global _Level4Vector
\r
1168 .type _Level4Vector,@function
\r
1171 wsr a0, EXCSAVE_4 /* preserve a0 */
\r
1172 call0 _xt_medint4 /* load interrupt handler */
\r
1174 .end literal_prefix
\r
1177 .type _xt_medint4,@function
\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
1192 /* Save rest of interrupt context and enter RTOS. */
\r
1193 call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */
\r
1195 /* !! We are now on the RTOS system stack !! */
\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
1201 movi a0, PS_INTLEVEL(4) | PS_UM | PS_WOE
\r
1206 /* OK to call C code at this point, dispatch user ISRs */
\r
1208 dispatch_c_isr 4 XCHAL_INTLEVEL4_MASK
\r
1210 /* Done handling interrupts, transfer control to OS */
\r
1211 call0 XT_RTOS_INT_EXIT /* does not return directly here */
\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
1217 .global _xt_medint4_exit
\r
1218 .type _xt_medint4_exit,@function
\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
1224 l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */
\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
1231 #endif /* Level 4 */
\r
1233 #if XCHAL_EXCM_LEVEL >= 5
\r
1235 .begin literal_prefix .Level5InterruptVector
\r
1236 .section .Level5InterruptVector.text, "ax"
\r
1237 .global _Level5Vector
\r
1238 .type _Level5Vector,@function
\r
1241 wsr a0, EXCSAVE_5 /* preserve a0 */
\r
1242 call0 _xt_medint5 /* load interrupt handler */
\r
1244 .end literal_prefix
\r
1247 .type _xt_medint5,@function
\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
1262 /* Save rest of interrupt context and enter RTOS. */
\r
1263 call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */
\r
1265 /* !! We are now on the RTOS system stack !! */
\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
1271 movi a0, PS_INTLEVEL(5) | PS_UM | PS_WOE
\r
1276 /* OK to call C code at this point, dispatch user ISRs */
\r
1278 dispatch_c_isr 5 XCHAL_INTLEVEL5_MASK
\r
1280 /* Done handling interrupts, transfer control to OS */
\r
1281 call0 XT_RTOS_INT_EXIT /* does not return directly here */
\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
1287 .global _xt_medint5_exit
\r
1288 .type _xt_medint5_exit,@function
\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
1294 l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */
\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
1301 #endif /* Level 5 */
\r
1303 #if XCHAL_EXCM_LEVEL >= 6
\r
1305 .begin literal_prefix .Level6InterruptVector
\r
1306 .section .Level6InterruptVector.text, "ax"
\r
1307 .global _Level6Vector
\r
1308 .type _Level6Vector,@function
\r
1311 wsr a0, EXCSAVE_6 /* preserve a0 */
\r
1312 call0 _xt_medint6 /* load interrupt handler */
\r
1314 .end literal_prefix
\r
1317 .type _xt_medint6,@function
\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
1332 /* Save rest of interrupt context and enter RTOS. */
\r
1333 call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */
\r
1335 /* !! We are now on the RTOS system stack !! */
\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
1341 movi a0, PS_INTLEVEL(6) | PS_UM | PS_WOE
\r
1346 /* OK to call C code at this point, dispatch user ISRs */
\r
1348 dispatch_c_isr 6 XCHAL_INTLEVEL6_MASK
\r
1350 /* Done handling interrupts, transfer control to OS */
\r
1351 call0 XT_RTOS_INT_EXIT /* does not return directly here */
\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
1357 .global _xt_medint6_exit
\r
1358 .type _xt_medint6_exit,@function
\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
1364 l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */
\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
1371 #endif /* Level 6 */
\r
1374 /*******************************************************************************
\r
1376 HIGH PRIORITY (LEVEL > XCHAL_EXCM_LEVEL) INTERRUPT VECTORS AND HANDLERS
\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
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
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
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
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
1404 *******************************************************************************/
\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
1412 #if XCHAL_NUM_INTLEVELS >=2 && XCHAL_EXCM_LEVEL <2 && XCHAL_DEBUGLEVEL !=2
\r
1414 .begin literal_prefix .Level2InterruptVector
\r
1415 .section .Level2InterruptVector.text, "ax"
\r
1416 .global _Level2Vector
\r
1417 .type _Level2Vector,@function
\r
1420 wsr a0, EXCSAVE_2 /* preserve a0 */
\r
1421 call0 _xt_highint2 /* load interrupt handler */
\r
1423 .end literal_prefix
\r
1426 .type _xt_highint2,@function
\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
1435 .Ln_xt_highint2_call_hook:
\r
1436 callx0 a0 /* must NOT disturb stack! */
\r
1441 ADD HIGH PRIORITY LEVEL 2 INTERRUPT HANDLER CODE HERE.
\r
1445 .L_xt_highint2_exit:
\r
1446 rsr a0, EXCSAVE_2 /* restore a0 */
\r
1449 #endif /* Level 2 */
\r
1451 #if XCHAL_NUM_INTLEVELS >=3 && XCHAL_EXCM_LEVEL <3 && XCHAL_DEBUGLEVEL !=3
\r
1453 .begin literal_prefix .Level3InterruptVector
\r
1454 .section .Level3InterruptVector.text, "ax"
\r
1455 .global _Level3Vector
\r
1456 .type _Level3Vector,@function
\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
1463 .end literal_prefix
\r
1466 .type _xt_highint3,@function
\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
1475 .Ln_xt_highint3_call_hook:
\r
1476 callx0 a0 /* must NOT disturb stack! */
\r
1481 ADD HIGH PRIORITY LEVEL 3 INTERRUPT HANDLER CODE HERE.
\r
1485 .L_xt_highint3_exit:
\r
1486 rsr a0, EXCSAVE_3 /* restore a0 */
\r
1489 #endif /* Level 3 */
\r
1491 #if XCHAL_NUM_INTLEVELS >=4 && XCHAL_EXCM_LEVEL <4 && XCHAL_DEBUGLEVEL !=4
\r
1493 .begin literal_prefix .Level4InterruptVector
\r
1494 .section .Level4InterruptVector.text, "ax"
\r
1495 .global _Level4Vector
\r
1496 .type _Level4Vector,@function
\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
1503 .end literal_prefix
\r
1506 .type _xt_highint4,@function
\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
1515 .Ln_xt_highint4_call_hook:
\r
1516 callx0 a0 /* must NOT disturb stack! */
\r
1521 ADD HIGH PRIORITY LEVEL 4 INTERRUPT HANDLER CODE HERE.
\r
1525 .L_xt_highint4_exit:
\r
1526 rsr a0, EXCSAVE_4 /* restore a0 */
\r
1529 #endif /* Level 4 */
\r
1531 #if XCHAL_NUM_INTLEVELS >=5 && XCHAL_EXCM_LEVEL <5 && XCHAL_DEBUGLEVEL !=5
\r
1533 .begin literal_prefix .Level5InterruptVector
\r
1534 .section .Level5InterruptVector.text, "ax"
\r
1535 .global _Level5Vector
\r
1536 .type _Level5Vector,@function
\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
1543 .end literal_prefix
\r
1546 .type _xt_highint5,@function
\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
1555 .Ln_xt_highint5_call_hook:
\r
1556 callx0 a0 /* must NOT disturb stack! */
\r
1561 ADD HIGH PRIORITY LEVEL 5 INTERRUPT HANDLER CODE HERE.
\r
1565 .L_xt_highint5_exit:
\r
1566 rsr a0, EXCSAVE_5 /* restore a0 */
\r
1569 #endif /* Level 5 */
\r
1571 #if XCHAL_NUM_INTLEVELS >=6 && XCHAL_EXCM_LEVEL <6 && XCHAL_DEBUGLEVEL !=6
\r
1573 .begin literal_prefix .Level6InterruptVector
\r
1574 .section .Level6InterruptVector.text, "ax"
\r
1575 .global _Level6Vector
\r
1576 .type _Level6Vector,@function
\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
1583 .end literal_prefix
\r
1586 .type _xt_highint6,@function
\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
1595 .Ln_xt_highint6_call_hook:
\r
1596 callx0 a0 /* must NOT disturb stack! */
\r
1601 ADD HIGH PRIORITY LEVEL 6 INTERRUPT HANDLER CODE HERE.
\r
1605 .L_xt_highint6_exit:
\r
1606 rsr a0, EXCSAVE_6 /* restore a0 */
\r
1609 #endif /* Level 6 */
\r
1611 #if XCHAL_HAVE_NMI
\r
1613 .begin literal_prefix .NMIExceptionVector
\r
1614 .section .NMIExceptionVector.text, "ax"
\r
1615 .global _NMIExceptionVector
\r
1616 .type _NMIExceptionVector,@function
\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
1623 .end literal_prefix
\r
1626 .type _xt_nmi,@function
\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
1635 .Ln_xt_nmi_call_hook:
\r
1636 callx0 a0 /* must NOT disturb stack! */
\r
1641 ADD HIGH PRIORITY NON-MASKABLE INTERRUPT (NMI) HANDLER CODE HERE.
\r
1646 rsr a0, EXCSAVE + XCHAL_NMILEVEL /* restore a0 */
\r
1647 rfi XCHAL_NMILEVEL
\r
1652 /*******************************************************************************
\r
1654 WINDOW OVERFLOW AND UNDERFLOW EXCEPTION VECTORS AND ALLOCA EXCEPTION HANDLER
\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
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
1670 These things are coded for XEA2 only (XEA1 is not supported).
\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
1680 *******************************************************************************/
\r
1682 #if XCHAL_HAVE_WINDOWED
\r
1684 .section .WindowVectors.text, "ax"
\r
1687 --------------------------------------------------------------------------------
\r
1688 Window Overflow Exception for Call4.
\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
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
1702 .global _WindowOverflow4
\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
1712 --------------------------------------------------------------------------------
\r
1713 Window Underflow Exception for Call4
\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
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
1727 .global _WindowUnderflow4
\r
1728 _WindowUnderflow4:
\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
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
1750 .global _xt_alloca_exc
\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
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
1764 _bbci.l a4, 31, _WindowUnderflow4
\r
1765 rotw -1 /* original a0 goes to a8 */
\r
1766 _bbci.l a8, 30, _WindowUnderflow8
\r
1768 j _WindowUnderflow12
\r
1771 --------------------------------------------------------------------------------
\r
1772 Window Overflow Exception for Call8
\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
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
1786 .global _WindowOverflow8
\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
1802 --------------------------------------------------------------------------------
\r
1803 Window Underflow Exception for Call8
\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
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
1817 .global _WindowUnderflow8
\r
1818 _WindowUnderflow8:
\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
1833 --------------------------------------------------------------------------------
\r
1834 Window Overflow Exception for Call12
\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
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
1848 .global _WindowOverflow12
\r
1849 _WindowOverflow12:
\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
1868 --------------------------------------------------------------------------------
\r
1869 Window Underflow Exception for Call12
\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
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
1883 .global _WindowUnderflow12
\r
1884 _WindowUnderflow12:
\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
1902 #endif /* XCHAL_HAVE_WINDOWED */
\r