move sboot to the root directory
[open-ath9k-htc-firmware.git] / sboot / magpie_1_1 / sboot / athos / src / xtos / int-highpri-dispatcher.S
diff --git a/sboot/magpie_1_1/sboot/athos/src/xtos/int-highpri-dispatcher.S b/sboot/magpie_1_1/sboot/athos/src/xtos/int-highpri-dispatcher.S
new file mode 100755 (executable)
index 0000000..334caa2
--- /dev/null
@@ -0,0 +1,464 @@
+// High-Priority Interrupt Dispatcher Template
+// $Id: //depot/rel/Cottonwood/Xtensa/OS/xtos/int-highpri-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.
+
+//
+// This file allows writing high-priority interrupt handlers in C,
+// providing convenience at a significant cost in performance.
+//
+// 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)
+
+
+#define INTLEVEL_N_MASK                INTERRUPT_MASK  // mask of interrupts at this priority
+#define INTLEVEL_N_NUM         SINGLE_INT_NUM  // interrupt number if there is only one
+#define INTLEVEL_N_BELOW_MASK  XCHAL_INTLEVEL_ANDBELOW_MASK(_INTERRUPT_LEVEL)
+
+/*  Indicates whether there are multiple interrupts at this interrupt
+ *  priority, ie. mapped to this interrupt vector.
+ *  If there is only one, its number is INTLEVEL_N_NUM
+ */
+#define MULTIPLE_INTERRUPTS    (!SINGLE_INTERRUPT)
+
+/*
+ *  High priority interrupt stack frame:
+ */
+STRUCT_BEGIN
+STRUCT_FIELD (long,4,HESF_,SAR)
+STRUCT_FIELD (long,4,HESF_,WINDOWSTART)
+STRUCT_FIELD (long,4,HESF_,WINDOWBASE)
+STRUCT_FIELD (long,4,HESF_,EPC1)
+STRUCT_FIELD (long,4,HESF_,EXCCAUSE)
+STRUCT_FIELD (long,4,HESF_,EXCVADDR)
+STRUCT_FIELD (long,4,HESF_,EXCSAVE1)
+STRUCT_FIELD (long,4,HESF_,VPRI)       /* (XEA1 only) */
+#if XCHAL_HAVE_MAC16
+STRUCT_FIELD (long,4,HESF_,ACCLO)
+STRUCT_FIELD (long,4,HESF_,ACCHI)
+/*STRUCT_AFIELD(long,4,HESF_,MR, 4)*/
+#endif
+#if XCHAL_HAVE_LOOPS
+STRUCT_FIELD (long,4,HESF_,LCOUNT)
+STRUCT_FIELD (long,4,HESF_,LBEG)
+STRUCT_FIELD (long,4,HESF_,LEND)
+#endif
+STRUCT_AFIELD(long,4,HESF_,AREG, 64)   /* address registers ar0..ar63 */
+#define HESF_AR(n)     HESF_AREG+((n)*4)
+STRUCT_END(HighPriFrame)
+#define HESF_TOTALSIZE HighPriFrameSize+32     /* 32 bytes for interrupted code's save areas under SP */
+
+
+#if XCHAL_HAVE_XEA1 && HAVE_XSR                /* could be made true for T1040 and T1050 */
+# error "high-priority interrupt stack frame needs adjustment if HAVE_XSR is allowed with XEA1"
+#endif
+
+
+#define PRI_N_STACK_SIZE       1024    /* default to 1 kB stack for each level-N handling */
+
+
+       //  Allocate save area and stack:
+       //  (must use .bss, not .comm, because the subsequent .set does not work otherwise)
+       .section .bss, "aw"
+       .align  16
+LABEL(_Pri_,_Stack):   .space  PRI_N_STACK_SIZE + HESF_TOTALSIZE
+
+#if HAVE_XSR
+       .data
+       .global LABEL(_Pri_,_HandlerAddress)
+LABEL(_Pri_,_HandlerAddress):  .space 4
+#endif
+
+
+       .text
+       .align  4
+       .global LABEL(_Level,FromVector)
+LABEL(_Level,FromVector):
+       movi    a2, LABEL(_Pri_,_Stack) + PRI_N_STACK_SIZE      // get ptr to save area
+       // interlock
+
+       //  Save a few registers so we can do some work:
+       s32i    a0,  a2, HESF_AR(0)
+#if HAVE_XSR
+       //movi  a0, LABEL(_Level,FromVector)            // this dispatcher's address
+       movi    a0, LABEL(_Pri_,_HandlerAddress)        // dispatcher address var.
+       s32i    a1,  a2, HESF_AR(1)
+       l32i    a0, a0, 0                               // get dispatcher address
+       s32i    a3,  a2, HESF_AR(3)
+       xsr     a0, EXCSAVE_LEVEL       // get saved a2, restore dispatcher address
+#else
+       rsr     a0, EXCSAVE_LEVEL       // get saved a2
+       s32i    a1,  a2, HESF_AR(1)
+       s32i    a3,  a2, HESF_AR(3)
+#endif
+       s32i    a4,  a2, HESF_AR(4)
+       s32i    a0,  a2, HESF_AR(2)
+
+       //  Save/restore all exception state
+       //  (IMPORTANT:  this code assumes no general exceptions occur
+       //   during the execution of this dispatcher until this state
+       //   is completely saved and from the point it is restored.)
+       //
+       //  Exceptions that may normally occur within the C handler
+       //  include window exceptions (affecting EPC1), alloca exceptions
+       //  (affecting EPC1/EXCCAUSE and its handling uses EXCSAVE1),
+       //  and possibly others depending on the particular C handler
+       //  (possibly needing save/restore of EXCVADDR; and EXCVADDR
+       //   is also possibly corrupted by any access thru an auto-refill
+       //   way on a processor with a full MMU).
+       //
+       rsr     a3, EPC1
+       rsr     a4, EXCCAUSE
+       s32i    a3, a2, HESF_EPC1
+       s32i    a4, a2, HESF_EXCCAUSE
+#if !XCHAL_HAVE_XEA1
+       rsr     a3, EXCVADDR
+       s32i    a3, a2, HESF_EXCVADDR
+#endif
+       rsr     a4, EXCSAVE1
+       s32i    a4, a2, HESF_EXCSAVE1
+
+#ifdef __XTENSA_WINDOWED_ABI__
+       //  Save remainder of entire address register file (!):
+       movi    a0, XCHAL_NUM_AREGS - 8         // how many saved so far
+#endif
+
+       s32i    a5,  a2, HESF_AR(5)
+       s32i    a6,  a2, HESF_AR(6)
+       s32i    a7,  a2, HESF_AR(7)
+
+1:     s32i    a8,  a2, HESF_AR(8)
+       s32i    a9,  a2, HESF_AR(9)
+       s32i    a10, a2, HESF_AR(10)
+       s32i    a11, a2, HESF_AR(11)
+       s32i    a12, a2, HESF_AR(12)
+       s32i    a13, a2, HESF_AR(13)
+       s32i    a14, a2, HESF_AR(14)
+       s32i    a15, a2, HESF_AR(15)
+
+#ifdef __XTENSA_WINDOWED_ABI__
+       addi    a8, a0, -8
+       addi    a10, a2, 8*4
+       rotw    2
+       bnez    a0, 1b                  // loop until done
+
+       rotw    2
+       // back to original a2 ...
+
+       //  Save a few other registers required for C:
+       rsr     a3, WINDOWSTART
+       rsr     a4, WINDOWBASE
+       s32i    a3, a2, HESF_WINDOWSTART
+       s32i    a4, a2, HESF_WINDOWBASE
+
+       //  Setup window registers for first caller:
+       movi    a3, 1
+       movi    a4, 0
+       wsr     a3, WINDOWSTART
+       wsr     a4, WINDOWBASE
+       rsync
+
+       //  Note:  register window has rotated, ie. a0..a15 clobbered.
+
+#endif /* __XTENSA_WINDOWED_ABI__ */
+
+       movi    a1, LABEL(_Pri_,_Stack) + PRI_N_STACK_SIZE      // get ptr to save area (is also initial stack ptr)
+       movi    a0, 0           // mark start of call frames in stack
+
+       //  Critical state saved, a bit more to do to allow window exceptions...
+
+       //  We now have a C-coherent stack and window state.
+       //  Still have to fix PS while making sure interrupts stay disabled
+       //  at the appropriate level (ie. level 2 and below are disabled in this case).
+
+#if XCHAL_HAVE_XEA1
+       movi    a7, _xtos_intstruct             // address of interrupt management globals
+       rsilft  a3, _INTERRUPT_LEVEL, XTOS_LOCKLEVEL    // lockout
+       movi    a4, ~INTLEVEL_N_BELOW_MASK      // mask out all interrupts at this level or lower
+       l32i    a3, a7, XTOS_VPRI_ENABLED_OFS   // read previous _xtos_vpri_enabled
+       l32i    a5, a7, XTOS_ENABLED_OFS        // read _xtos_enabled
+       s32i    a4, a7, XTOS_VPRI_ENABLED_OFS   // set new _xtos_vpri_enabled (mask interrupts as if at _INTERRUPT_LEVEL)
+       s32i    a3, a1, HESF_VPRI               // save previous vpri
+       movi    a2, 0x50020                     // WOE=1, UM=1, INTLEVEL=0
+       and     a3, a5, a4                      // mask out selected interrupts
+       wsr     a3, INTENABLE                   // disable all low-priority interrupts
+#else
+       //  Load PS for C code, clear EXCM (NOTE: this step is different for XEA1):
+# ifdef __XTENSA_CALL0_ABI__
+       movi    a2, 0x00020 + _INTERRUPT_LEVEL  // WOE=0, CALLINC=0, UM=1, INTLEVEL=N, EXCM=0, RING=0
+# else
+       movi    a2, 0x50020 + _INTERRUPT_LEVEL  // WOE=1, CALLINC=1, UM=1, INTLEVEL=N, EXCM=0, RING=0
+# endif
+
+#endif
+       wsr     a2, PS                          // update PS to enable window exceptions, etc as per above
+       rsync
+
+       //  Okay, window exceptions can now happen (although we have to call
+       //  deep before any will happen because we've reset WINDOWSTART).
+
+       //  Save other state that might get clobbered by C code:
+
+//////////////////  COMMON DISPATCH CODE BEGIN
+
+       rsr     a14, SAR
+       s32i    a14, a1, HESF_SAR
+#if XCHAL_HAVE_LOOPS
+       rsr     a14, LCOUNT
+       s32i    a14, a1, HESF_LCOUNT
+       rsr     a14, LBEG
+       s32i    a14, a1, HESF_LBEG
+       rsr     a14, LEND
+       s32i    a14, a1, HESF_LEND
+#endif
+#if XCHAL_HAVE_MAC16
+       rsr     a14, ACCLO
+       s32i    a14, a1, HESF_ACCLO
+       rsr     a14, ACCHI
+       s32i    a14, a1, HESF_ACCHI
+#endif
+
+#if MULTIPLE_INTERRUPTS                /* > 1 interrupts at this priority */   // _split_ multi_setup
+#define TABLE_OFS      0
+
+       rsr     a15, INTERRUPT          // mask of pending interrupts
+# if XCHAL_HAVE_XEA1
+       l32i    a12, a7, XTOS_ENABLED_OFS       // mask of enabled interrupts
+# else
+       rsr     a12, INTENABLE          // mask of enabled interrupts
+# endif
+       movi    a13, INTLEVEL_N_MASK    // mask of interrupts at this priority level
+       and     a15, a15, a12
+       and     a15, a15, a13           // enabled & pending interrupts at this priority
+       _beqz   a15, LABEL(Pri_,_spurious)      // handle spurious interrupts (eg. level-trig.)
+LABEL(Pri_,_loop):                             // handle all enabled & pending interrupts
+       neg     a14, a15
+       and     a14, a14, a15           // single-out least-significant bit set in mask
+       wsr     a14, INTCLEAR           // clear if edge-trig. or s/w or wr/err (else no effect)
+
+       //  Compute pointer to interrupt table entry, given mask a14 with single bit set:
+
+# if XCHAL_HAVE_NSA
+       movi    a12, _xtos_interrupt_table - (32-XCHAL_NUM_INTERRUPTS)*8
+       nsau    a14, a14                // get index of bit in a14, numbered from msbit
+       addx8   a12, a14, a12
+# else /* XCHAL_HAVE_NSA */
+       movi    a12, _xtos_interrupt_table      // pointer to interrupt table
+       bltui   a14, 0x10000, 1f        // in 16 lsbits? (if so, check them)
+       addi    a12, a12, 16*8          // no, index is at least 16 entries further
+       // (the above ADDI expands to an ADDI+ADDMI sequence, +128 is outside its range)
+       extui   a14, a14, 16,16         // shift right upper 16 bits
+1:     bltui   a14, 0x100, 1f          // in 8 lsbits? (if so, check them)
+       addi    a12, a12, 8*8           // no, index is at least 8 entries further
+       srli    a14, a14, 8             // shift right upper 8 bits
+1:     bltui   a14, 0x10, 1f           // in 4 lsbits? (if so, check them)
+       addi    a12, a12, 4*8           // no, index is at least 4 entries further
+       srli    a14, a14, 4             // shift right 4 bits
+1:     bltui   a14, 0x4, 1f            // in 2 lsbits? (if so, check them)
+       addi    a12, a12, 2*8           // no, index is at least 2 entries further
+       srli    a14, a14, 2             // shift right 2 bits
+1:     bltui   a14, 0x2, 1f            // is it the lsbit?
+       addi    a12, a12, 1*8           // no, index is one entry further
+1:                                     // done! a12 points to interrupt's table entry
+# endif /* XCHAL_HAVE_NSA */
+
+#else /* !MULTIPLE_INTERRUPTS */
+
+# if XCHAL_HAVE_NSA
+#  define TABLE_OFS    8 * (XCHAL_NUM_INTERRUPTS - 1 - INTLEVEL_N_NUM)
+# else
+#  define TABLE_OFS    8 * INTLEVEL_N_NUM
+# endif
+
+       movi    a13, INTLEVEL_N_MASK    // (if interrupt is s/w or edge-triggered or write/err only)
+       movi    a12, _xtos_interrupt_table      // get pointer to its interrupt table entry
+       wsr     a13, INTCLEAR           // clear the interrupt (if s/w or edge or wr/err only)
+
+#endif /* ifdef MULTIPLE_INTERRUPTS */
+
+       l32i    a13, a12, TABLE_OFS + 0 // get pointer to handler from table entry
+#ifdef __XTENSA_CALL0_ABI__
+       l32i    a2, a12, TABLE_OFS + 4  // pass single argument to C handler
+       callx0  a13                     // call interrupt's C handler
+#else
+       l32i    a6, a12, TABLE_OFS + 4  // pass single argument to C handler
+       callx4  a13                     // call interrupt's C handler
+#endif
+
+#if XCHAL_HAVE_XEA1
+       movi    a7, _xtos_intstruct     // address of interrupt management globals
+#endif
+#if MULTIPLE_INTERRUPTS                /* > 1 interrupts at this priority */
+       rsr     a15, INTERRUPT          // get pending interrupts
+# if XCHAL_HAVE_XEA1
+       l32i    a12, a7, XTOS_ENABLED_OFS       // get enabled interrupts
+# else
+       rsr     a12, INTENABLE          // get enabled interrupts
+# endif
+       movi    a13, INTLEVEL_N_MASK    // get mask of interrupts at this priority level
+       and     a15, a15, a12
+       and     a15, a15, a13           // pending+enabled interrupts at this priority
+       _bnez   a15, LABEL(Pri_,_loop)  // if any remain, dispatch one
+LABEL(Pri_,_spurious):
+#endif /* MULTIPLE_INTERRUPTS */
+
+       //  Restore everything, and return.
+
+       //  Three temp registers are required for this code to be optimal (no interlocks) in
+       //  T2xxx microarchitectures with 7-stage pipe; otherwise only two
+       //  registers would be needed.
+       //
+#if XCHAL_HAVE_LOOPS
+       l32i    a13, a1, HESF_LCOUNT
+       l32i    a14, a1, HESF_LBEG
+       l32i    a15, a1, HESF_LEND
+       wsr     a13, LCOUNT
+       wsr     a14, LBEG
+       wsr     a15, LEND
+#endif
+
+#if XCHAL_HAVE_MAC16
+       l32i    a13, a1, HESF_ACCLO
+       l32i    a14, a1, HESF_ACCHI
+       wsr     a13, ACCLO
+       wsr     a14, ACCHI
+#endif
+       l32i    a15, a1, HESF_SAR
+       wsr     a15, SAR
+
+//////////////////  COMMON DISPATCH CODE END
+
+#if XCHAL_HAVE_XEA1
+       //  Here, a7 = address of interrupt management globals
+       l32i    a4, a1, HESF_VPRI               // restore previous vpri
+       rsil    a3, XTOS_LOCKLEVEL              // lockout
+       l32i    a5, a7, XTOS_ENABLED_OFS        // read _xtos_enabled
+       s32i    a4, a7, XTOS_VPRI_ENABLED_OFS   // set new _xtos_vpri_enabled
+       movi    a2, 0x00020 + _INTERRUPT_LEVEL  // WOE=0, UM=1, INTLEVEL=N
+       and     a3, a5, a4                      // mask out selected interrupts
+       wsr     a3, INTENABLE                   // disable all low-priority interrupts
+#else
+       //  Load PS for interrupt exit, set EXCM:
+       movi    a2, 0x00030 + _INTERRUPT_LEVEL  // WOE=0, CALLINC=0, UM=1, INTLEVEL=N, EXCM=1, RING=0
+#endif
+       wsr     a2, PS                          // update PS to disable window exceptions, etc as per above
+       rsync
+
+       //  NOTE:  here for XEA1, restore INTENABLE etc...
+
+#ifdef __XTENSA_WINDOWED_ABI__
+       //  Restore window registers:
+       l32i    a2, a1, HESF_WINDOWSTART
+       l32i    a3, a1, HESF_WINDOWBASE
+       wsr     a2, WINDOWSTART
+       wsr     a3, WINDOWBASE
+       rsync
+       //  Note:  register window has rotated, ie. a0..a15 clobbered.
+
+       //  Reload initial stack pointer:
+       movi    a1, LABEL(_Pri_,_Stack) + PRI_N_STACK_SIZE      // - 16
+       movi    a6, XCHAL_NUM_AREGS - 8         // how many saved so far
+       addi    a7, a1, -8*4
+
+       //  Restore entire register file (!):
+
+1:
+       addi    a14, a6, -8
+       addi    a15, a7, 8*4
+       l32i    a4, a15, HESF_AR(4)
+       l32i    a5, a15, HESF_AR(5)
+       l32i    a6, a15, HESF_AR(6)
+       l32i    a7, a15, HESF_AR(7)
+       l32i    a8, a15, HESF_AR(8)
+       l32i    a9, a15, HESF_AR(9)
+       l32i    a10,a15, HESF_AR(10)
+       l32i    a11,a15, HESF_AR(11)
+       rotw    2
+       bnez    a6, 1b                  // loop until done
+
+       l32i    a4, a7, HESF_AR(12)
+       l32i    a5, a7, HESF_AR(13)
+       l32i    a6, a7, HESF_AR(14)
+       l32i    a7, a7, HESF_AR(15)
+       rotw    2
+
+       // back to original a1 ...
+
+#else  /* Call0 ABI: */
+
+       l32i    a4, a1, HESF_AR(4)      // restore general registers
+       l32i    a5, a1, HESF_AR(5)
+       l32i    a6, a1, HESF_AR(6)
+       l32i    a7, a1, HESF_AR(7)
+       l32i    a8, a1, HESF_AR(8)
+       l32i    a9, a1, HESF_AR(9)
+       l32i    a10, a1, HESF_AR(10)
+       l32i    a11, a1, HESF_AR(11)
+       l32i    a12, a1, HESF_AR(12)
+       l32i    a13, a1, HESF_AR(13)
+       l32i    a14, a1, HESF_AR(14)
+       l32i    a15, a1, HESF_AR(15)
+
+#endif  /* __XTENSA_WINDOWED_ABI__ */
+
+       //  Restore exception state:
+       l32i    a2, a1, HESF_EPC1
+       l32i    a3, a1, HESF_EXCCAUSE
+       wsr     a2, EPC1
+       wsr     a3, EXCCAUSE
+#if !XCHAL_HAVE_XEA1
+       l32i    a2, a1, HESF_EXCVADDR
+       wsr     a2, EXCVADDR
+#endif
+       l32i    a3, a1, HESF_EXCSAVE1
+       wsr     a3, EXCSAVE1
+
+       l32i    a0,  a1, HESF_AR(0)
+       l32i    a2,  a1, HESF_AR(2)
+       l32i    a3,  a1, HESF_AR(3)
+       l32i    a1,  a1, HESF_AR(1)
+       rfi     _INTERRUPT_LEVEL
+
+       .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_INTERRUPTS */
+