// High-Priority Interrupt Handler Template // $Id: //depot/rel/Cottonwood/Xtensa/OS/xtos/int-highpri-template.S#3 $ // 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 provides skeleton code for writing high-priority interrupt // handlers in assembler for 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 #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) // NOTE: It is strongly recommended that high-priority // interrupt handlers be written in assembly. // // High-priority interrupt handlers can be written in C, // but only at the cost of an unreasonable amount of state // save and restore (including the entire physical address // register file and others, see int-highpri-dispatcher.S) // that makes high-priority interrupt dispatching much slower // than for low and medium priority interrupts. // (Low and medium priority interrupts are masked by atomic // register window operations, so they take advantage of a // coherent window state for fast entry. High priority // interrupts are not masked by window operations so they // can interrupt them, leading to a potentially incoherent // window state at the time of the interrupt. Given that // high priority handlers must save and restore everything // they touch, they end up needing to save and restore the // entire window state [physical address register file etc.] // and all exception state which they can also interrupt.) // See also the Microprocessor Programmer's Guide. // High-priority interrupts are designed to be very fast and with // very low latency. // Typical high-priority interrupt service routines are kept // relatively small and fast. Either there is little to do, // or the routine handles only the necessary high priority // activities related to a device and leaves the rest // (other more complex and time-consuming activities) // to be scheduled later, eg. by triggering a level-one // (low-priority) or medium-priority software interrupt whose // handler can be written in C for the more extensive processing. // NOTE: The following handler is just skeleton example // code. It is NOT a functional handler. For software, edge- // triggered and write-error interrupts, it simply does nothing // and return. For other types (timer and level-triggered), // this code does not clear the source(s) of interrupt, // hence if any interrupt at this priority level are both enabled // and triggered, the processor repeatedly takes the interrupt // in a loop. This is all okay as a default, because // XTOS (and other operating systems) clears the INTENABLE // register at startup, requiring the application to // enable specific interrupts before they can be taken. // So as long as you don't enable any interrupt of this // priority level, this example handler will never execute. // Exports .global LABEL(_Level,FromVector) .data .align 4 LABEL(int,save): .space 4 // save area .text .align 4 LABEL(_Level,FromVector): // The vectoring code has already saved a2 in EXCSAVEn. // Save any other registers we'll use: movi a2, LABEL(int,save) s32i a1, a2, 0 // ... add more as needed (increase save area accordingly) ... // WRITE YOUR INTERRUPT HANDLING CODE HERE... // If multiple interrupts are mapped to this priority level, // you'll probably need to distinguish which interrupt(s) // occurred by reading the INTERRUPT (INTREAD) and // INTENABLE registers, and'ing them together, and // looking at what bits are set in both. // If any of the interrupts are level-triggered, be ready // to handle the case where no interrupts are to be handled // -- this is called a spurious interrupt, and can happen // when the level-triggered interrupt line goes inactive // after the interrupt is taken but before the INTERRUPT // register is read. // You'll also normally want to clear the source of // the interrupt before returning, to avoid getting // the same interrupt again immediately. For illustration, // this code clears all software, edge-triggered, and // write-error interrupts at this priority level (if any). // NOTE: Timer interrupts must be cleared by writing to // the corresponding CCOMPAREn register; and level-sensitive // interrupts can only be cleared externally, usually by // requesting the associated device to do so (in a // device-specific manner). // movi a1, INTERRUPT_MASK wsr a1, INTCLEAR // Restore registers: l32i a1, a2, 0 #if HAVE_XSR movi a2, LABEL(_Level,FromVector) // restore handler address xsr a2, EXCSAVE_LEVEL #else rsr a2, EXCSAVE_LEVEL #endif // ... add more if more are saved above ... // Return: rfi _INTERRUPT_LEVEL .size LABEL(_Level,FromVector), . - LABEL(_Level,FromVector) #endif /* XCHAL_HAVE_INTERRUPTS */