Mercurial > nand-ecoscentric
view packages/hal/sparclite/arch/current/src/vec_ivsr.S @ 8:ece80412419a ecos-sw-1999-05-21
Merge from eCos master repository on 1999-05-21-22:05:54-BST
| author | jlarmour |
|---|---|
| date | Fri, 21 May 1999 15:09:30 +0000 |
| parents | 443894e2e912 |
| children | a3cc6665b684 |
line wrap: on
line source
/*=========================================================================== // // vec_ivsr.S // // SPARClite vectors: interrupt vector service routine // //=========================================================================== //####COPYRIGHTBEGIN#### // // ------------------------------------------- // The contents of this file are subject to the Cygnus eCos Public License // Version 1.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at // http://sourceware.cygnus.com/ecos // // Software distributed under the License is distributed on an "AS IS" // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the // License for the specific language governing rights and limitations under // the License. // // The Original Code is eCos - Embedded Cygnus Operating System, released // September 30, 1998. // // The Initial Developer of the Original Code is Cygnus. Portions created // by Cygnus are Copyright (C) 1998,1999 Cygnus Solutions. All Rights Reserved. // ------------------------------------------- // //###COPYRIGHTEND#### //=========================================================================== //#####DESCRIPTIONBEGIN#### // // Author(s): hmt // Contributors: hmt // Date: 1999-02-20 // Purpose: SPARClite vector code // Description: see vectors.S; this is the default vector service routine // for interrupts. // //####DESCRIPTIONEND#### // //=========================================================================*/ !---------------------------------------------------------------------------- .file "vec_ivsr.S" !---------------------------------------------------------------------------- #include <pkgconf/system.h> #include <pkgconf/hal.h> #ifdef CYGPKG_KERNEL # include <pkgconf/kernel.h> #else # undef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK # undef CYGFUN_HAL_COMMON_KERNEL_SUPPORT #endif !------------------------------------------------------------------------ #include <cyg/hal/vectors.h> #define DELAYS_AFTER_WRPSR_SAME_WINDOW #define DELAYS_AFTER_WRWIM ! Macro to mark the stack as we descend, for debugging, because it is likely ! that actually running the ISR won~t touch the stack, but the memory needs ! to be there. Normally blank. //#define MARKSTACKUSED st %sp, [ %sp ] #define MARKSTACKUSED !------------------------------------------------------------------------ .text !--------------------------------------------------------------------------- ! default interrupt VSR, which calls the appropriate ISR after scheduler ! lock and interrupt masking, then interrupt_end(). interrupt_end() must be ! called with interrupts enabled, on the original thread stack (no separate ! interrupt stack) or with interrupts masked, on the original stack (when ! separate interrupt stack is supported). .global hal_default_interrupt_vsr hal_default_interrupt_vsr: ! here,locals have been set up as follows: ! %l0 = psr (with this CWP/window-level in it) ! %l1 = pc ! %l2 = npc ! %l3 = vector number (1-15 for interrupts) ! and we are in our own register window, though it is likely that ! the next one will need to be saved before we can use it: ! ie. this one is the invalid register window. ! must establish a safe stack before re-enabling interrupts + traps and %l0, __WINBITS, %l7 ! CWP extracted mov 1, %l6 sll %l6, %l7, %l6 ! 1 << CWP rd %wim, %l5 cmp %l5, %l6 ! are they the same? bne 1f ! No, so the stack is OK as is. ! now do by hand an overflow trap, effectively mov %g1, %l7 ! (DELAY SLOT) srl %l5, 1, %l5 sll %l6, __WINSIZE-1, %l6 or %l6, %l5, %g1 ! new WIM in %g1 so we can get it ! within the save: save ! Slip into next window mov %g1, %wim ! Install the new wim ! (invalidates current window!) #ifdef DELAYS_AFTER_WRWIM nop nop nop #endif std %l0, [%sp + 0 * 4] ! save L & I registers std %l2, [%sp + 2 * 4] std %l4, [%sp + 4 * 4] std %l6, [%sp + 6 * 4] std %i0, [%sp + 8 * 4] std %i2, [%sp + 10 * 4] std %i4, [%sp + 12 * 4] std %i6, [%sp + 14 * 4] restore ! Go back to trap window. mov %l7, %g1 ! Restore %g1 1: ! now save away the regs we must preserve sub %fp, 32 * 4, %sp #ifdef CYGDBG_HAL_COMMON_INTERRUPTS_SAVE_MINIMUM_CONTEXT std %g0, [%sp + 16 * 4] ! save G registers std %g2, [%sp + 18 * 4] ! (set %g0 place to 0 to flag special context) std %g4, [%sp + 20 * 4] std %g6, [%sp + 22 * 4] #else // not CYGDBG_HAL_COMMON_INTERRUPTS_SAVE_MINIMUM_CONTEXT std %l0, [%sp + 0 * 4] ! save L & I registers std %l2, [%sp + 2 * 4] std %l4, [%sp + 4 * 4] std %l6, [%sp + 6 * 4] std %i0, [%sp + 8 * 4] std %i2, [%sp + 10 * 4] std %i4, [%sp + 12 * 4] std %i6, [%sp + 14 * 4] st %g1, [%sp + 17 * 4] ! save G registers std %g2, [%sp + 18 * 4] std %g4, [%sp + 20 * 4] std %g6, [%sp + 22 * 4] ! no point whatsoever in saving O registers ! and save the CWP in %g0 save place st %l0, [%sp + 16 * 4] #endif // ! CYGDBG_HAL_COMMON_INTERRUPTS_SAVE_MINIMUM_CONTEXT sub %sp, 24 * 4, %sp ! fresh frame including ! arg spill area for callees MARKSTACKUSED ! kilroy was here #ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK ! we will switch to the interrupt stack unless already running on it .extern cyg_interrupt_stack .extern cyg_interrupt_stack_base set cyg_interrupt_stack, %g1 set cyg_interrupt_stack_base, %g2 cmp %sp, %g2 ! below base? blu 1f ! if so, switch. cmp %sp, %g1 ! below top? (DELAY SLOT) blu 2f ! if so, DON~T switch. nop ! (DELAY SLOT) 1: ! switch to the interrupt stack st %sp, [ %g1 ] ! there is spare above stack sub %g1, 24 * 4, %sp ! fresh frame including ! arg spill area for callees MARKSTACKUSED ! kilroy was here 2: ! continue as before, already in the interrupt stack. #endif // CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK #ifdef CYGFUN_HAL_COMMON_KERNEL_SUPPORT ! Lock the scheduler .extern SCHED_LOCK_MANGLED_NAME sethi %hi(SCHED_LOCK_MANGLED_NAME), %l7 ld [ %l7 + %lo(SCHED_LOCK_MANGLED_NAME) ], %l6 add %l6, 1, %l6 st %l6, [ %l7 + %lo(SCHED_LOCK_MANGLED_NAME) ] #endif ! HELP_GDB_WITH_BACKTRACE mov %i7, %l5 ! preserve it in l5 mov %l1, %i7 ! bogus return link here ! and we must preserve the Y register (multiply/divide auxiliary) ! over these calls; we will keep it in %l4 which is otherwise unused. rd %y, %l4 ! Now we can reenable traps and mask off only lower prio interrupts: andn %l0, 0xf00, %l7 ! clear PIL field or %l7, 0x0e0, %l7 ! and ET (+S,PS) sll %l3, 8, %l6 ! trap number (1-15) into PIL bitfield wr %l7, %l6, %psr ! and enable! #ifdef DELAYS_AFTER_WRPSR_SAME_WINDOW nop nop nop #endif ! now call the ISR and so on with the appropriate args: ! ie. ! isr_retcode = (*(hal_interrupt_handlers[ vector ])) ! ( vector, hal_interrupt_data[ vector ] ); ! from hal_arch.h !// ISR tables !CYG_ADDRESS hal_interrupt_handlers[CYGNUM_HAL_ISR_COUNT]; !CYG_ADDRWORD hal_interrupt_data[CYGNUM_HAL_ISR_COUNT]; !CYG_ADDRESS hal_interrupt_objects[CYGNUM_HAL_ISR_COUNT]; mov %l3, %o0 sll %l3, 2, %l3 ! %l3 to a word offset sethi %hi(hal_interrupt_data), %l7 or %l7, %lo(hal_interrupt_data), %l7 ld [ %l7 + %l3 ], %o1 sethi %hi(hal_interrupt_handlers), %l7 or %l7, %lo(hal_interrupt_handlers), %l7 ld [ %l7 + %l3 ], %l6 call %l6 nop #ifdef CYGFUN_HAL_COMMON_KERNEL_SUPPORT ! We only need to call _interrupt_end() when there is a kernel ! present to do any tidying up. #ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK ! now we switch back to the user stack (if we~re at the top ! of the interrupt stack). or %l0, 0xfe0, %l7 wr %l7, %psr ! Interrupts all masked, ET #ifdef DELAYS_AFTER_WRPSR_SAME_WINDOW nop nop nop #endif .extern cyg_interrupt_stack set cyg_interrupt_stack - (24 * 4), %g1 cmp %sp, %g1 ! is SP less? blu 1f ! if so, do not change back nop ! switch to the thread stack ld [ %g1 + (24 * 4) ], %sp ! there is spare above stack 1: #else // CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK ! First restore the processor interrupt level to that interrupted ! (otherwise a task-switch runs at the current PIL) on the assumption ! that the ISR dealt with the interrupt source per se, so it is safe ! to unmask it, effectively: or %l0, 0x0e0, %l7 ! original PSR and ET (+S,PS) wr %l7, %psr ! and enable! #ifdef DELAYS_AFTER_WRPSR_SAME_WINDOW nop nop nop #endif #endif // CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK ! then call interrupt_end( isr_retcode, &intr_object, ®save ) ! to unlock the scheduler and do any rescheduling that~s needed. ! argument 0 (isr_retcode) is already in place in %o0 sethi %hi(hal_interrupt_objects), %l7 or %l7, %lo(hal_interrupt_objects), %l7 ld [ %l7 + %l3 ], %o1 add %sp, 24 * 4, %o2 ! saved regset (maybe tiny) .extern interrupt_end call interrupt_end nop #endif ! restore the Y register having done our callouts to C wr %l4, %y ! We can reinstall the original CWP here; even if interrupt_end() ! performed a reschedule (ie. yield/resume pair) we will be in the ! same window. The window is preserved by reschedule precisely ! because it is impossible atomically to disable traps here without ! involving a CWP living in a register for a time when other ! interrupts may occur. ! disable traps (using the saved psr is fastest way) wr %l0, %psr ! restores flags, disables traps, and old PIL #ifdef DELAYS_AFTER_WRPSR_SAME_WINDOW nop nop nop #endif ! HELP_GDB_WITH_BACKTRACE mov %l5, %i7 ! restore (unused) return link ! and restore other saved regs ! (see CYGDBG_HAL_COMMON_INTERRUPTS_SAVE_MINIMUM_CONTEXT) add %sp, 24 * 4, %sp ! undo fresh frame ld [%sp + 17 * 4], %g1 ! restore G registers ldd [%sp + 18 * 4], %g2 ldd [%sp + 20 * 4], %g4 ldd [%sp + 22 * 4], %g6 ! and do NOT restore any other registers L, I or O ! Now test for window underflow here and fix up if needs be. ! ! Why? interrupt_end() might have yielded us, when only ! its own frame was restored; its own return to us caused a ! window underflow trap, as would our return to interruptee ! unless we deal with it now. add %l0, 1, %l7 ! interruptee~s CWP plus noise and %l7, __WINBITS, %l7 ! CWP only mov 1, %l6 sll %l6, %l7, %l6 ! 1 << CWP rd %wim, %l5 cmp %l5, %l6 ! are they the same? bne 2f ! No, so the stack is OK as is. ! now do by hand an underflow trap, effectively sll %l5, 1, %l5 ! Rotate wim left srl %l6, __WINSIZE-1, %l6 wr %l5, %l6, %wim #ifdef DELAYS_AFTER_WRWIM nop ! are these delays needed? nop ! (following restore uses wim) nop #endif restore ! Interruptee~s window ldd [%sp + 0 * 4], %l0 ! restore L & I registers ldd [%sp + 2 * 4], %l2 ldd [%sp + 4 * 4], %l4 ldd [%sp + 6 * 4], %l6 ldd [%sp + 8 * 4], %i0 ldd [%sp + 10 * 4], %i2 ldd [%sp + 12 * 4], %i4 ldd [%sp + 14 * 4], %i6 save ! Back to trap window 2: ! restore the condition codes, PSR and PIL and return from trap. wr %l0, %psr ! restores flags, disables traps, and old PIL #ifdef DELAYS_AFTER_WRPSR_SAME_WINDOW nop nop nop #endif jmpl %l1, %g0 rett %l2 !---------------------------------------------------------------------------- #ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK ! This routine can only be called from a thread stack, maybe ! with interrupts (but not traps) disabled. ! It switches to the interrupt stack then calls back to the ! kernel to execute DSRs. .global hal_interrupt_stack_call_pending_DSRs hal_interrupt_stack_call_pending_DSRs: save %sp, -24 * 4, %sp MARKSTACKUSED ! kilroy was here ! be atomic rd %psr, %l0 andn %l0, 0x20, %l1 ! clear ET to disable traps wr %l1, %psr ! into the PSR nop nop nop mov %sp, %l7 ! save calling stack location ! now switch stack to the interrupt stack, plus some headroom ! for saving a register set if we are interrupted .extern cyg_interrupt_stack set cyg_interrupt_stack - 4 * 24, %sp MARKSTACKUSED ! kilroy was here ! and enable interrupts unconditionally to call the DSRs or %l0, 0x0e0, %l2 ! set ET, S, PS andn %l2, 0xf00, %l2 ! PIL to zero wr %l2, %psr ! into the PSR nop nop nop .extern cyg_interrupt_call_pending_DSRs call cyg_interrupt_call_pending_DSRs nop mov %l7, %sp ! restore calling stack wr %l0, %psr ! restore interrupt status nop nop nop ret restore #endif // CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK !---------------------------------------------------------------------------- ! end of vec_ivsr.S
