--- /dev/null
+// Medium-Priority Interrupt Dispatcher Template
+// $Id: //depot/rel/Cottonwood/Xtensa/OS/xtos/int-medpri-dispatcher.S#4 $
+
+// Copyright (c) 2004-2010 Tensilica Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+//
+// By default, this file is included by inth-template.S .
+// The default Makefile defines _INTERRUPT_LEVEL when assembling
+// inth-template.S for each medium and high priority interrupt level.
+//
+// To use this template file, define a macro called _INTERRUPT_LEVEL
+// to be the interrupt priority level of the vector, then include this file.
+
+
+#include <xtensa/coreasm.h>
+#include "xtos-internal.h"
+
+
+#if XCHAL_HAVE_INTERRUPTS
+
+#define INTERRUPT_MASK XCHAL_INTLEVEL_MASK(_INTERRUPT_LEVEL)
+#define SINGLE_INTERRUPT ((INTERRUPT_MASK & (INTERRUPT_MASK - 1)) == 0)
+#define SINGLE_INT_NUM XCHAL_INTLEVEL_NUM(_INTERRUPT_LEVEL)
+
+
+// Strict non-preemptive prioritization
+
+
+ .text
+ .align 4
+ .global LABEL(_Level,FromVector)
+LABEL(_Level,FromVector):
+
+/* Allocate an exception stack frame, save a2, a4, and a5, and fix PS as:
+ *
+ * if not Call0 ABI
+ * - enable windowing for 'entry' (ps.woe=1, ps.excm=0)
+ * - setup ps.callinc to simulate call4
+ * endif
+ * - preserve user mode
+ * - mask all interrupts at EXCM_LEVEL and lower
+ *
+ * Then deallocate the stack, 'rsync' for the write to PS, then use
+ * 'entry' to re-allocate the stack frame and rotate the register
+ * window (like a call4, preserving a0..a3). */
+
+#if HAVE_XSR
+ xsr a2, EXCSAVE_LEVEL
+#else
+ rsr a2, EXCSAVE_LEVEL
+#endif
+ addi a1, a1, -ESF_TOTALSIZE
+ s32i a2, a1, UEXC_a2
+#ifdef __XTENSA_CALL0_ABI__
+ movi a2, PS_UM|PS_INTLEVEL(XCHAL_EXCM_LEVEL)
+#else
+ movi a2, PS_WOE|PS_CALLINC(1)|PS_UM|PS_INTLEVEL(XCHAL_EXCM_LEVEL)
+#endif
+ s32i a4, a1, UEXC_a4
+ s32i a5, a1, UEXC_a5
+ wsr a2, PS
+ rsync
+
+#ifdef __XTENSA_CALL0_ABI__
+ s32i a0, a1, UEXC_a0
+ s32i a3, a1, UEXC_a3
+ s32i a6, a1, UEXC_a6
+ s32i a7, a1, UEXC_a7
+ s32i a8, a1, UEXC_a8
+ s32i a9, a1, UEXC_a9
+ s32i a10, a1, UEXC_a10
+ s32i a11, a1, UEXC_a11
+ s32i a12, a1, UEXC_a12
+ s32i a13, a1, UEXC_a13
+ s32i a14, a1, UEXC_a14
+ s32i a15, a1, UEXC_a15
+ movi a0, 0 /* terminate stack frames */
+# if XTOS_DEBUG_PC
+ // TODO: setup return PC for call traceback through interrupt dispatch
+# endif
+#else
+# if XTOS_CNEST
+ l32i a2, a1, ESF_TOTALSIZE-20 // save nested-C-func call-chain ptr
+# endif
+ addi a1, a1, ESF_TOTALSIZE
+# if XTOS_DEBUG_PC
+ rsr a4, EPC+_INTERRUPT_LEVEL // [for debug] get return PC
+ movi a5, 0xC0000000 // [for debug] setup call size...
+ or a4, a5, a4 // [for debug] set upper two bits of return PC
+ addx2 a4, a5, a4 // [for debug] clear upper bit
+# else
+ movi a4, 0 /* terminate stack frames, overflow check */
+# endif
+ _entry a1, ESF_TOTALSIZE
+#endif
+
+/* Reset the interrupt level to mask all interrupts at the current
+ * priority level and lower. Note the current priority level may be
+ * less than or equal to EXCM_LEVEL. */
+
+ rsil a15, _INTERRUPT_LEVEL
+
+#if SINGLE_INTERRUPT /* if only one interrupt at this priority level... */
+
+/* Preserve the SAR, loop, and MAC16 regs. Also, clear the interrupt. */
+
+ rsr a14, SAR
+ movi a12, INTERRUPT_MASK
+ s32i a14, a1, UEXC_sar
+ wsr a12, INTCLEAR // clear if edge-trig or s/w or wr/err (else no effect)
+ save_loops_mac16 a1, a13, a14
+
+/* Load the handler from the table, initialize two args (interrupt
+ * number and exception stack frame), then call the interrupt handler.
+ * Note: The callx12 preserves the original user task's a4..a15.*/
+
+ movi a12, _xtos_interrupt_table + MAPINT(SINGLE_INT_NUM)*XIE_SIZE
+ l32i a13, a12, XIE_HANDLER
+# ifdef __XTENSA_CALL0_ABI__
+ l32i a2, a12, XIE_ARG
+ mov a3, a1
+ callx0 a13
+# else
+ l32i a14, a12, XIE_ARG
+ mov a15, a1
+ callx12 a13
+# endif
+
+#else /* > 1 interrupts at this priority level */
+
+/* Get bit list of pending interrupts at the current interrupt priority level.
+ * If bit list is empty, interrupt is spurious (can happen if a
+ * genuine interrupt brings control this direction, but the interrupt
+ * goes away before we read the INTERRUPT register). Also save off
+ * sar, loops, and mac16 registers. */
+
+ rsr a15, INTERRUPT
+ rsr a12, INTENABLE
+ movi a13, INTERRUPT_MASK
+ and a15, a15, a12
+ and a15, a15, a13
+ rsr a14, SAR
+ _beqz a15, LABEL(spurious,int)
+ s32i a14, a1, UEXC_sar
+ save_loops_mac16 a1, a13, a14
+
+/* Loop to handle all pending interrupts. */
+
+LABEL(.L1,_loop0):
+ neg a12, a15
+ and a12, a12, a15
+ wsr a12, INTCLEAR // clear if edge-trig or s/w or wr/err (else no effect)
+ movi a13, _xtos_interrupt_table
+ find_ms_setbit a15, a12, a14, 0
+ mapint a15
+ addx8 a12, a15, a13
+ l32i a13, a12, XIE_HANDLER
+# ifdef __XTENSA_CALL0_ABI__
+ l32i a2, a12, XIE_ARG
+ mov a3, a1
+ callx0 a13
+# else
+ l32i a14, a12, XIE_ARG
+ mov a15, a1
+ callx12 a13
+# endif
+ rsr a15, INTERRUPT
+ rsr a12, INTENABLE
+ movi a13, INTERRUPT_MASK
+ and a15, a15, a12
+ and a15, a15, a13
+ _bnez a15, LABEL(.L1,_loop0)
+
+#endif /* SINGLE_INTERRUPT */
+
+/* Restore everything, and return. */
+
+ restore_loops_mac16 a1, a13, a14, a15
+ l32i a14, a1, UEXC_sar
+LABEL(spurious,int):
+
+#ifdef __XTENSA_CALL0_ABI__
+ wsr a14, SAR
+ l32i a0, a1, UEXC_a0
+ l32i a2, a1, UEXC_a2
+ l32i a3, a1, UEXC_a3
+ l32i a4, a1, UEXC_a4
+ l32i a5, a1, UEXC_a5
+ l32i a6, a1, UEXC_a6
+ l32i a7, a1, UEXC_a7
+ l32i a8, a1, UEXC_a8
+ l32i a9, a1, UEXC_a9
+ l32i a10, a1, UEXC_a10
+ l32i a11, a1, UEXC_a11
+ l32i a12, a1, UEXC_a12
+ l32i a13, a1, UEXC_a13
+ l32i a14, a1, UEXC_a14
+ l32i a15, a1, UEXC_a15
+ addi a1, a1, ESF_TOTALSIZE // restore sp
+ rfi _INTERRUPT_LEVEL
+
+#else /* windowed ABI: */
+
+ movi a0, LABEL(return,from_exc)
+ movi a13, 0xC0000000
+ wsr a14, SAR
+ or a0, a0, a13
+ addx2 a0, a13, a0
+# if _INTERRUPT_LEVEL < XCHAL_EXCM_LEVEL
+/* Raise the interrupt mask before
+ * returning to avoid a race condition where we deallocate the
+ * exception stack frame but still have more register values to
+ * restore from it. */
+ rsil a14, XCHAL_EXCM_LEVEL
+# endif
+ retw
+LABEL(return,from_exc):
+# if XTOS_CNEST
+ s32i a2, a5, ESF_TOTALSIZE-20 // restore nested-C-func call-chain ptr
+# endif
+ l32i a2, a5, UEXC_a2
+ l32i a4, a5, UEXC_a4
+ l32i a5, a5, UEXC_a5
+ rfi _INTERRUPT_LEVEL
+#endif /* windowed ABI */
+
+ .size LABEL(_Level,FromVector), . - LABEL(_Level,FromVector)
+
+ // This symbol exists solely for the purpose of being able to pull-in this
+ // dispatcher using _xtos_dispatch_level<n>() routines with the tiny-rt LSP:
+ .global LABEL(_Level,HandlerLabel)
+ .set LABEL(_Level,HandlerLabel), 0
+
+#endif /* XCHAL_HAVE_INTERRUPT */
+