1 // Medium-Priority Interrupt Dispatcher Template
2 // $Id: //depot/rel/Cottonwood/Xtensa/OS/xtos/int-medpri-dispatcher.S#4 $
4 // Copyright (c) 2004-2010 Tensilica Inc.
6 // Permission is hereby granted, free of charge, to any person obtaining
7 // a copy of this software and associated documentation files (the
8 // "Software"), to deal in the Software without restriction, including
9 // without limitation the rights to use, copy, modify, merge, publish,
10 // distribute, sublicense, and/or sell copies of the Software, and to
11 // permit persons to whom the Software is furnished to do so, subject to
12 // the following conditions:
14 // The above copyright notice and this permission notice shall be included
15 // in all copies or substantial portions of the Software.
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21 // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 // By default, this file is included by inth-template.S .
27 // The default Makefile defines _INTERRUPT_LEVEL when assembling
28 // inth-template.S for each medium and high priority interrupt level.
30 // To use this template file, define a macro called _INTERRUPT_LEVEL
31 // to be the interrupt priority level of the vector, then include this file.
34 #include <xtensa/coreasm.h>
35 #include "xtos-internal.h"
38 #if XCHAL_HAVE_INTERRUPTS
40 #define INTERRUPT_MASK XCHAL_INTLEVEL_MASK(_INTERRUPT_LEVEL)
41 #define SINGLE_INTERRUPT ((INTERRUPT_MASK & (INTERRUPT_MASK - 1)) == 0)
42 #define SINGLE_INT_NUM XCHAL_INTLEVEL_NUM(_INTERRUPT_LEVEL)
45 // Strict non-preemptive prioritization
50 .global LABEL(_Level,FromVector)
51 LABEL(_Level,FromVector):
53 /* Allocate an exception stack frame, save a2, a4, and a5, and fix PS as:
56 * - enable windowing for 'entry' (ps.woe=1, ps.excm=0)
57 * - setup ps.callinc to simulate call4
59 * - preserve user mode
60 * - mask all interrupts at EXCM_LEVEL and lower
62 * Then deallocate the stack, 'rsync' for the write to PS, then use
63 * 'entry' to re-allocate the stack frame and rotate the register
64 * window (like a call4, preserving a0..a3). */
71 addi a1, a1, -ESF_TOTALSIZE
73 #ifdef __XTENSA_CALL0_ABI__
74 movi a2, PS_UM|PS_INTLEVEL(XCHAL_EXCM_LEVEL)
76 movi a2, PS_WOE|PS_CALLINC(1)|PS_UM|PS_INTLEVEL(XCHAL_EXCM_LEVEL)
83 #ifdef __XTENSA_CALL0_ABI__
90 s32i a10, a1, UEXC_a10
91 s32i a11, a1, UEXC_a11
92 s32i a12, a1, UEXC_a12
93 s32i a13, a1, UEXC_a13
94 s32i a14, a1, UEXC_a14
95 s32i a15, a1, UEXC_a15
96 movi a0, 0 /* terminate stack frames */
98 // TODO: setup return PC for call traceback through interrupt dispatch
102 l32i a2, a1, ESF_TOTALSIZE-20 // save nested-C-func call-chain ptr
104 addi a1, a1, ESF_TOTALSIZE
106 rsr a4, EPC+_INTERRUPT_LEVEL // [for debug] get return PC
107 movi a5, 0xC0000000 // [for debug] setup call size...
108 or a4, a5, a4 // [for debug] set upper two bits of return PC
109 addx2 a4, a5, a4 // [for debug] clear upper bit
111 movi a4, 0 /* terminate stack frames, overflow check */
113 _entry a1, ESF_TOTALSIZE
116 /* Reset the interrupt level to mask all interrupts at the current
117 * priority level and lower. Note the current priority level may be
118 * less than or equal to EXCM_LEVEL. */
120 rsil a15, _INTERRUPT_LEVEL
122 #if SINGLE_INTERRUPT /* if only one interrupt at this priority level... */
124 /* Preserve the SAR, loop, and MAC16 regs. Also, clear the interrupt. */
127 movi a12, INTERRUPT_MASK
128 s32i a14, a1, UEXC_sar
129 wsr a12, INTCLEAR // clear if edge-trig or s/w or wr/err (else no effect)
130 save_loops_mac16 a1, a13, a14
132 /* Load the handler from the table, initialize two args (interrupt
133 * number and exception stack frame), then call the interrupt handler.
134 * Note: The callx12 preserves the original user task's a4..a15.*/
136 movi a12, _xtos_interrupt_table + MAPINT(SINGLE_INT_NUM)*XIE_SIZE
137 l32i a13, a12, XIE_HANDLER
138 # ifdef __XTENSA_CALL0_ABI__
139 l32i a2, a12, XIE_ARG
143 l32i a14, a12, XIE_ARG
148 #else /* > 1 interrupts at this priority level */
150 /* Get bit list of pending interrupts at the current interrupt priority level.
151 * If bit list is empty, interrupt is spurious (can happen if a
152 * genuine interrupt brings control this direction, but the interrupt
153 * goes away before we read the INTERRUPT register). Also save off
154 * sar, loops, and mac16 registers. */
158 movi a13, INTERRUPT_MASK
162 _beqz a15, LABEL(spurious,int)
163 s32i a14, a1, UEXC_sar
164 save_loops_mac16 a1, a13, a14
166 /* Loop to handle all pending interrupts. */
171 wsr a12, INTCLEAR // clear if edge-trig or s/w or wr/err (else no effect)
172 movi a13, _xtos_interrupt_table
173 find_ms_setbit a15, a12, a14, 0
176 l32i a13, a12, XIE_HANDLER
177 # ifdef __XTENSA_CALL0_ABI__
178 l32i a2, a12, XIE_ARG
182 l32i a14, a12, XIE_ARG
188 movi a13, INTERRUPT_MASK
191 _bnez a15, LABEL(.L1,_loop0)
193 #endif /* SINGLE_INTERRUPT */
195 /* Restore everything, and return. */
197 restore_loops_mac16 a1, a13, a14, a15
198 l32i a14, a1, UEXC_sar
201 #ifdef __XTENSA_CALL0_ABI__
212 l32i a10, a1, UEXC_a10
213 l32i a11, a1, UEXC_a11
214 l32i a12, a1, UEXC_a12
215 l32i a13, a1, UEXC_a13
216 l32i a14, a1, UEXC_a14
217 l32i a15, a1, UEXC_a15
218 addi a1, a1, ESF_TOTALSIZE // restore sp
221 #else /* windowed ABI: */
223 movi a0, LABEL(return,from_exc)
228 # if _INTERRUPT_LEVEL < XCHAL_EXCM_LEVEL
229 /* Raise the interrupt mask before
230 * returning to avoid a race condition where we deallocate the
231 * exception stack frame but still have more register values to
232 * restore from it. */
233 rsil a14, XCHAL_EXCM_LEVEL
236 LABEL(return,from_exc):
238 s32i a2, a5, ESF_TOTALSIZE-20 // restore nested-C-func call-chain ptr
244 #endif /* windowed ABI */
246 .size LABEL(_Level,FromVector), . - LABEL(_Level,FromVector)
248 // This symbol exists solely for the purpose of being able to pull-in this
249 // dispatcher using _xtos_dispatch_level<n>() routines with the tiny-rt LSP:
250 .global LABEL(_Level,HandlerLabel)
251 .set LABEL(_Level,HandlerLabel), 0
253 #endif /* XCHAL_HAVE_INTERRUPT */