/* Cesar project {{{ * * Copyright (C) 2008 Spidcom * * <<>> * * }}} */ /** * \file hal/phy/src/vsr.S * \brief HAL Phy vector service routine. * \ingroup hal_phy */ #include #include #include #include CYGBLD_HAL_PLATFORM_H // Platform config file #ifdef CYGPKG_KERNEL # include #else # undef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK # undef CYGFUN_HAL_COMMON_KERNEL_SUPPORT #endif #include #include "hal/trace/trace_cpu.h" #include "hal/leon/itc2.h" #include #define DELAYS_AFTER_WRPSR_SAME_WINDOW #define DELAYS_AFTER_WRWIM #if defined (CYGHWR_HAL_SPARC_FPU) # error "No support for FPU" #endif #if (__WINSIZE != 2) || !defined (CYGHWR_HAL_SPARC_FLAT) # error "Only support flat" #endif #ifndef CYGDBG_HAL_COMMON_INTERRUPTS_SAVE_MINIMUM_CONTEXT # error "Only support save minimum context" #endif ! PHY interrupt stack & data. .section ".dlram_bss" .global phy_interrupt_data phy_interrupt_data: .long 0 .size phy_interrupt_data, . - phy_interrupt_data .balign 16 .global phy_interrupt_stack_base phy_interrupt_stack_base: .rept 3 * 1024 .byte 0 .endr .size phy_interrupt_stack_base, . - phy_interrupt_stack_base .global phy_interrupt_stack phy_interrupt_stack: .long 0,0,0,0,0,0,0,0 .size phy_interrupt_stack, . - phy_interrupt_stack ! PHY VSR. .section ".ilram" .global phy_vsr phy_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. restore 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] save ! now save away the regs we must preserve sub %fp, SAVE_REGS_SIZE, %sp 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] sub %sp, 24 * 4, %sp ! fresh frame including ! arg spill area for callees set phy_interrupt_stack, %g1 ! 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 #if defined(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 #if HAL_TRACE_CPU ! Trace. ! load bare->data_tail and bare->data_end sethi %hi(hal_trace_cpu_bare_buffer), %o1 ldd [ %o1 + %lo(hal_trace_cpu_bare_buffer) ], %o2 set HAL_TRACE_CPU_PHY_ID, %o4 sethi %hi(HAL_TRACE_CPU_DATE_ADDR), %o5 ld [ %o5 + %lo(HAL_TRACE_CPU_DATE_ADDR) ], %o5 ! load date std %o4, [ %o2 ] ! store them set 0, %o4 ! nothing sethi %hi(LEON_ITC2_STATUS_HIGH_ADDR), %o5 ld [ %o5 + %lo(LEON_ITC2_STATUS_HIGH_ADDR) ], %o5 and %o5, 31, %o5 ! interrupt level std %o4, [ %o2 + 8 ] ! store them add %o2, 16, %o2 ! increment bare->data_tail cmp %o2, %o3 ! if same as bare->data_end be,a 1f ! set to bare->data, thanks to 16 byte alignment ld [ %o1 + %lo(hal_trace_cpu_bare_buffer + 8) ], %o2 ! store modified bare->data_tail 1: st %o2, [ %o1 + %lo(hal_trace_cpu_bare_buffer) ] #endif ! now call the ISR and so on with the appropriate args: ! ie. ! isr_retcode = phy_isr (vector, phy_interrupt_data); mov %l3, %o0 sethi %hi(phy_interrupt_data), %l7 or %l7, %lo(phy_interrupt_data), %l7 ld [ %l7 ], %o1 call phy_isr nop #if HAL_TRACE_CPU ! Trace. ! load bare->data_tail and bare->data_end sethi %hi(hal_trace_cpu_bare_buffer), %o1 ldd [ %o1 + %lo(hal_trace_cpu_bare_buffer) ], %o2 set HAL_TRACE_CPU_PHY_EXIT_ID, %o4 sethi %hi(HAL_TRACE_CPU_DATE_ADDR), %o5 ld [ %o5 + %lo(HAL_TRACE_CPU_DATE_ADDR) ], %o5 ! load date std %o4, [ %o2 ] ! store them set 0, %o4 ! nothing set 0, %o5 ! nothing std %o4, [ %o2 + 8 ] ! store them add %o2, 16, %o2 ! increment bare->data_tail cmp %o2, %o3 ! if same as bare->data_end be,a 1f ! set to bare->data, thanks to 16 byte alignment ld [ %o1 + %lo(hal_trace_cpu_bare_buffer + 8) ], %o2 ! store modified bare->data_tail 1: st %o2, [ %o1 + %lo(hal_trace_cpu_bare_buffer) ] #endif ! switch to the thread stack set phy_interrupt_stack - (24 * 4), %g1 ld [ %g1 + (24 * 4) ], %sp ! there is spare above stack #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 sll %l3, 2, %l3 ! %l3 to a word offset ld [ %l7 + %l3 ], %o1 add %sp, 24 * 4, %o2 ! saved regset (maybe tiny) .extern interrupt_end call interrupt_end nop ! 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 #endif ! restore the Y register having done our callouts to C wr %l4, %y ! 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 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 ! 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