Mercurial > ecos
diff packages/hal/sparclite/arch/current/src/vec_ivsr.S @ 2:443894e2e912 ecos-v1_2_1-release
Block commit of eCos version 1.2.1
| author | jlarmour |
|---|---|
| date | Tue, 11 May 1999 12:24:34 +0000 |
| parents | |
| children | ece80412419a |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/packages/hal/sparclite/arch/current/src/vec_ivsr.S @@ -0,0 +1,308 @@ +/*=========================================================================== +// +// 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> +#endif + +!------------------------------------------------------------------------ + +#include <cyg/hal/vectors.h> + +#define DELAYS_AFTER_WRPSR_SAME_WINDOW +#define DELAYS_AFTER_WRWIM + +!------------------------------------------------------------------------ + + .text + +!--------------------------------------------------------------------------- +! default interrupt VSR, which calls the appropriate ISR after scheduler +! lock andinterrupt masking, then interrupt_end(). interrupt_end() must be +! called with interrupts enabled, on the original thread stack. + + .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 + +#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 JIC + 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. + + ! 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 + ! 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 + + +! end of vec_ivsr.S
