URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [hal/] [coldfire/] [arch/] [current/] [src/] [vectors.S] - Rev 786
Compare with Previous | Blame | View Log
|==========================================================================
|
| vectors.S
|
| ColdFire exception vectors
|
|==========================================================================
| ####ECOSGPLCOPYRIGHTBEGIN####
| -------------------------------------------
| This file is part of eCos, the Embedded Configurable Operating System.
| Copyright (C) 1998, 1999, 2000, 2001, 2002, 2006 Free Software Foundation, Inc.
|
| eCos is free software; you can redistribute it and/or modify it under
| the terms of the GNU General Public License as published by the Free
| Software Foundation; either version 2 or (at your option) any later
| version.
|
| eCos is distributed in the hope that it will be useful, but WITHOUT
| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
| FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
| for more details.
|
| You should have received a copy of the GNU General Public License
| along with eCos; if not, write to the Free Software Foundation, Inc.,
| 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
| As a special exception, if other files instantiate templates or use
| macros or inline functions from this file, or you compile this file
| and link it with other works to produce a work based on this file,
| this file does not by itself cause the resulting work to be covered by
| the GNU General Public License. However the source code for this file
| must still be made available in accordance with section (3) of the GNU
| General Public License v2.
|
| This exception does not invalidate any other reasons why a work based
| on this file might be covered by the GNU General Public License.
| -------------------------------------------
| ####ECOSGPLCOPYRIGHTEND####
|=============================================================================
|#####DESCRIPTIONBEGIN####
|
| Author(s): Enrico Piria
| Contributors: Wade Jensen
| Date: 2005-25-06
| Purpose: ColdFire exception vectors
| Description: This file contains the first level default VSRs
| that save and restore state for both exceptions and
| interrupts.
|
|####DESCRIPTIONEND####
|==========================================================================
#include <pkgconf/system.h>
#include <pkgconf/hal.h>
#include <cyg/hal/cf_offsets.inc>
#include <cyg/hal/arch.inc>
#include <cyg/hal/variant.inc>
#ifdef CYGPKG_KERNEL
#include <pkgconf/kernel.h>
#endif
| ----------------------------------------------------------------------------
| Hardware reset vector
.section ".boot","x"
.balign 4
.globl cyg_hal_reset_vsr
cyg_hal_reset_vsr:
| Define the entry point for the linker.
.globl _start
_start:
| Make sure that all interrupts are masked.
hal_cpu_int_disable
| Initial setup. Just do the minimum to be able to perform
| initialization in C.
| Initialize CPU variant
hal_cpu_init
| Platform specific hardware initialization.
| This may include memory controller initialization.
hal_hardware_init
| Setup boot stack
hal_boot_stack_init
| Set up the initial frame pointer.
lea 0,%fp
link %fp,#0
| Call the C routine to complete the reset process.
.extern hal_reset
jsr hal_reset
| If we return, stop.
9:
stop #0x2000
bra 9b
| ----------------------------------------------------------------------------
| Default exception vector handler
|
| The default handler for all machine exceptions. We save the
| machine state and call the default C exception handler. This routine passes a
| pointer to the saved state to the C exception handler. The stack pointer in
| the saved state points to the the sp before the exception.
| The format/vector word in the exception stack contains the vector
| number.
| void hal_exception_handler(CYG_WORD vector, HAL_SavedRegisters *regs);
.text
.balign 4
.globl cyg_hal_default_exception_vsr
cyg_hal_default_exception_vsr:
| Disable all interrupts
hal_cpu_int_disable
| Preserve the entire state.
| Allocate space for all registers (including the stack pointer).
| Write all registers to the stack space.
lea.l -CYGARC_CF_EXCEPTION_DECREMENT(%sp),%sp
movem.l %d0-%d7,CYGARC_CFREG_DREGS(%sp)
movem.l %a0-%a6,CYGARC_CFREG_AREGS(%sp)
#ifdef CYGHWR_HAL_COLDFIRE_MAC
save_mac_registers %d0
#endif
| Write the original stack pointer value to the stack.
| The format/vector word, sr, and pc are already on the stack.
find_original_sp %d0
move.l %d0,CYGARC_CFREG_SP(%sp)
| Calculate the vector number. The format/vector word on the stack
| contains the vector number.
move.w CYGARC_CF_FMTVECWORD(%sp),%d0
and.l #0x000003fc,%d0
lsr.l #2,%d0
| Pass a pointer to the saved state to the exception handler.
pea.l (%sp)
| Push the vector number parameter.
move.l %d0,-(%sp)
| Call the default exception handler. This routine may modify
| the exception context.
.extern hal_exception_handler
jsr hal_exception_handler
| Remove the vector number and the state pointer from the stack.
addq.l #2*4,%sp
| Get a pointer to the location following the exception context.
find_original_sp %d0
| Restore all of the registers that we do not need in the following
| code. We will copy all registers that are not restored here
| to the new stack before restoring them.
#ifdef CYGHWR_HAL_COLDFIRE_MAC
restore_mac_registers %d0
#endif
movem.l CYGARC_CFREG_D2(%sp),%d2-%d7
movem.l CYGARC_CFREG_A1(%sp),%a1-%a6
| Load the address of the new SP.
move.l CYGARC_CFREG_SP(%sp),%d1
| We now have:
| d0.l : original stack pointer
| d1.l : final stack pointer
| ColdFire programmer's manual doesn't tell if rte instruction expects
| the stack frame to be aligned at 32-bit boundaries.
| So, we align the new stack value, and adjust the format field
| accordingly. At the end of rte instruction the stack will thus point
| to the desired location.
| Compare the new stack address to the end of the exception context.
| This will tell us the order that we need to copy the exception
| stack and the remaining registers from the old exception context to
| the new one. The order is important because the stack frames might
| overlap.
cmp.l %d0,%d1
| If the new SP and the old one coincide.
beq 2f
| If the new SP is at a higher address than the old one.
bgt 1f
| The new SP is at a lower address than the old one. Copy from the
| lowest address to the highest address.
| Align stack at longword boundary
move.l %d1,%d0
and.l #0xfffffffc,%d0
move.l %d0,%a0
| Allocate new frame
sub.l #CYGARC_CF_CONTEXT_SIZE,%a0
| Copy D0, D1, A0, FVW, SR, and PC from the old stack to the new stack.
| Note that we copy in ascending order.
| Copy D0, D1, A0
move.l CYGARC_CFREG_D0(%sp),CYGARC_CFREG_D0(%a0)
move.l CYGARC_CFREG_D1(%sp),CYGARC_CFREG_D1(%a0)
move.l CYGARC_CFREG_A0(%sp),CYGARC_CFREG_A0(%a0)
| Based on target SP address, construct new format field
and.l #0x00000003,%d1
or.l #0x4,%d1
lsl.l #8,%d1
lsl.l #4,%d1
| Load old format field
move.w CYGARC_CF_FMTVECWORD(%sp),%d0
| Clear old format field
and.l #0x0fff,%d0
| Write the new one
or.l %d1,%d0
move.w %d0,CYGARC_CF_FMTVECWORD(%a0)
| Copy SR and PC
move.w CYGARC_CF_SR(%sp),CYGARC_CF_SR(%a0)
move.l CYGARC_CFREG_PC(%sp),CYGARC_CFREG_PC(%a0)
| A0 points to the top of the new stack
move.l %a0,%sp
| Restore remaining registers and exit
jmp 2f
1:
| The new SP is at a higher address than the old one. Copy from the
| highest address to the lowest address.
| Align stack at longword boundary
move.l %d1,%d0
and.l #0xfffffffc,%d0
move.l %d0,%a0
| Allocate new frame
sub.l #CYGARC_CF_CONTEXT_SIZE,%a0
| Copy D0, D1, A0, FVW, SR, and PC from the old stack to the new stack.
| Note that we copy in descending order.
| Copy PC and SR
move.l CYGARC_CFREG_PC(%sp),CYGARC_CFREG_PC(%a0)
move.w CYGARC_CF_SR(%sp),CYGARC_CF_SR(%a0)
| Based on target SP address, construct new format field
and.l #0x00000003,%d1
or.l #0x4,%d1
lsl.l #8,%d1
lsl.l #4,%d1
| Load old format field
move.w CYGARC_CF_FMTVECWORD(%sp),%d0
| Clear old format field
and.l #0x0fff,%d0
| Write the new one
or.l %d1,%d0
move.w %d0,CYGARC_CF_FMTVECWORD(%a0)
| Copy A0, D1, D0
move.l CYGARC_CFREG_A0(%sp),CYGARC_CFREG_A0(%a0)
move.l CYGARC_CFREG_D1(%sp),CYGARC_CFREG_D1(%a0)
move.l CYGARC_CFREG_D0(%sp),CYGARC_CFREG_D0(%a0)
| A0 points to the top of the new stack
move.l %a0,%sp
2:
| Restore remaining registers
move.l CYGARC_CFREG_D0(%sp),%d0
move.l CYGARC_CFREG_D1(%sp),%d1
move.l CYGARC_CFREG_A0(%sp),%a0
add.l #CYGARC_CF_EXCEPTION_DECREMENT,%sp
| Return from exception
rte
| ----------------------------------------------------------------------------
| Spurious interrupt vector handler
|
| Used for spurious and uninitialized interrupts.
| It is unknown at which priority spurious interrupts are generated. So, the
| safest thing to do is to disable all interrupts while processing spurious
| ones.
.text
.balign 4
.globl cyg_hal_default_spurious_vsr
cyg_hal_default_spurious_vsr:
#ifndef CYGIMP_HAL_COMMON_INTERRUPTS_IGNORE_SPURIOUS
| Disable all interrupts. On the first instruction, interrupt sampling
| is always disabled.
hal_cpu_int_disable
| Preserve all registers that this handler needs to preserve.
| The C code will preserve all other registers.
int_pres_regs
| Pass a pointer to the saved state to the interrupt handler.
pea.l (%sp)
| Call spurious interrupt handler
.extern hal_spurious_interrupt
jsr hal_spurious_interrupt
| Remove the arguments from the stack.
addq.l #4,%sp
| Restore the preserved registers for the current thread.
int_rest_regs
#endif /* ifndef CYGIMP_HAL_COMMON_INTERRUPTS_IGNORE_SPURIOUS */
| Just return from interrupt.
rte
| ----------------------------------------------------------------------------
| User interrupt vector handler
|
| Control is transferred here from a user interrupt vector (#64-255).
| Before branching to common code, load a value to translate the
| vector table offset to the ISR table offset.
.text
.balign 4
.globl cyg_hal_default_interrupt_vsr
cyg_hal_default_interrupt_vsr:
| Disable all interrupts. On the first instruction, interrupt sampling
| is always disabled.
hal_cpu_int_disable
| Preserve all registers that this handler needs to preserve.
| The C code will preserve all other registers.
int_pres_regs
| It is safe to use breakpoints below this point.
.globl _cyg_hal_default_interrupt_vsr_bp_safe
_cyg_hal_default_interrupt_vsr_bp_safe:
| Adding this value to the vector table offset will result in the
| corresponding offset into the ISR table.
move.l #(-CYGNUM_HAL_ISR_MIN)*4,%d2
| d2.l: Contains a value to translate the vector table offset to
| the ISR table offset.
| Calculate the vector offset. The format/vector word on the stack
| contains the vector number. Mask off all unused bits. The bit
| position of the vector number field makes it automatically multiplied
| by four.
move.w CYGARC_CF_FMTVECWORD(%sp),%d1
and.l #0x000003fc,%d1
| Calculate the ISR table offset. Add the vector table offset to the
| translation value.
add.l %d1,%d2
| Calculate the vector number using the vector table offset.
asr.l #2,%d1
| d2.l: Contains the offset into the ISR table.
| d1.l: Contains the vector number.
#if defined(CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT) \
|| defined(CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT)
| If we are supporting Ctrl-C interrupts from GDB, we must squirrel
| away a pointer to the saved interrupt state here so that we can
| plant a breakpoint at some later time.
.extern hal_saved_interrupt_state
move.l %sp,(hal_saved_interrupt_state)
#endif
#ifdef CYGFUN_HAL_COMMON_KERNEL_SUPPORT
| Lock the scheduler if we are using the kernel.
.extern cyg_scheduler_sched_lock
addq.l #1,cyg_scheduler_sched_lock
#endif /* CYGFUN_HAL_COMMON_KERNEL_SUPPORT */
#ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
| a0 = sp. We'll need it later
move.l %sp,%a0
cmp.l #__interrupt_stack_base,%sp
| If sp < base : not on istack
blt 1f
cmp.l #__interrupt_stack,%sp
| If sp <= top : already on istack
ble 2f
1:
| Switch to istack
lea __interrupt_stack,%sp
2:
| Save old SP on istack
pea (%a0)
#endif
#if defined(CYGPKG_KERNEL_INSTRUMENT) && defined(CYGDBG_KERNEL_INSTRUMENT_INTR)
.extern cyg_instrument
| Save d1
move.l %d1,-(%sp)
| arg2 = 0
move.l #0,-(%sp)
| arg1 = vector number
move.l %d1,-(%sp)
| type = INTR,RAISE
move.l #0x0301,-(%sp)
| Call instrumentation
jsr cyg_instrument
| Remove args from stack
add.l #12,%sp
| Restore %d1
move.l (%sp)+,%d1
#endif
#ifdef CYGSEM_HAL_COMMON_INTERRUPTS_ALLOW_NESTING
| If interrupt nesting is enabled, we have to determine the IPL of the
| current interrupt. We inline the following macro, which is defined
| by ColdFire variants. The vector number of the current interrupt
| is passed in d0, and the return value is in d0.
| Registers a0-a1/d0-d1 are for use by the macro, other registers
| must be saved explicitly before being used.
| Save %d1
move.l %d1,-(%sp)
| Pass d1 as argument to macro
move.l %d1,%d0
| Retrieve IPL, which will be contained in d0
hal_variant_retrieve_ipl
| Shift IPL up to the same position occupied in sr
lsl.l #8,%d0
| Transform d0 in a mask to be applied to sr
or.l #0xfffff0ff,%d0
| Update sr. Use d1 as working register
move.w %sr,%d1
and.l %d0,%d1
move.w %d1,%sr
| Restore d1
move.l (%sp)+,%d1
#endif
| We need to call the following routines. The isr address, data, and
| intr are all from the ISR table. The interrupt_end routine is
| only called if we are using the kernel. regs points to the saved
| registers on the stack. isr_ret is the return value from the ISR.
| vector is the vector number.
| static cyg_uint32 isr(CYG_ADDRWORD vector, CYG_ADDRWORD data)
| externC void interrupt_end(cyg_uint32 isr_ret, Cyg_Interrupt *intr,
| HAL_SavedRegisters *regs)
| Push the data value from the table.
.extern cyg_hal_interrupt_data
lea cyg_hal_interrupt_data,%a0
move.l (%a0,%d2.l),-(%sp)
| Get the address of the ISR from the table.
.extern cyg_hal_interrupt_handlers
lea cyg_hal_interrupt_handlers,%a0
move.l (%a0,%d2.l),%a0
| Push the vector number parameter.
move.l %d1,-(%sp)
| Call the ISR.
jsr (%a0)
| Remove the isr parameters from the stack.
addq.l #4*2,%sp
| d0.l now contains the return value from the ISR.
#ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
| If we are returning from the last nested interrupt, move back
| to the thread stack. interrupt_end() must be called on the
| thread stack since it potentially causes a context switch.
| Since we have arranged for the top of stack location to
| contain the sp we need to go back to here, just pop it off
| and put it in SP.
move.l (%sp),%sp | sp = *sp
#endif
#ifdef CYGFUN_HAL_COMMON_KERNEL_SUPPORT
| We only need to call interrupt_end() when there is a kernel
| present to do any tidying up. To keep the following code simple,
| we enable all interrupts before calling DSRs only if a common
| interrupt stack is in use.
| Push the regs pointer.
pea (%sp)
| Push the intr object pointer from the table.
.extern cyg_hal_interrupt_objects
lea cyg_hal_interrupt_objects,%a0
move.l (%a0,%d2.l),-(%sp)
| Push ISR return value
move.l %d0,-(%sp)
| Even when this is not the last nested interrupt, we must call
| interrupt_end() to post the DSR and decrement the scheduler
| lock.
| Call the interrupt_end C routine.
.extern interrupt_end
jsr interrupt_end
| Remove the isr_ret, intr, and regs parameters from the stack.
lea (4*3)(%sp),%sp
#endif /* ifdef CYGFUN_HAL_COMMON_KERNEL_SUPPORT */
| Restore the preserved registers for the current thread.
int_rest_regs
| Restore the SR and PC.
rte
| ----------------------------------------------------------------------------
| Execute pending DSRs on the interrupt stack with interrupts enabled.
| Note: this can only be called from code running on a thread stack
#ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
.extern cyg_interrupt_call_pending_DSRs
FUNC_START(hal_interrupt_stack_call_pending_DSRs)
| Change to interrupt stack, save state and set up stack for
| calls to C code.
| By virtue of GNU C calling conventions, we are free to use registers
| %d0-%d1 and %a0-%a1 without saving them.
| a0 = sp
move.l %sp, %a0
| Switch to istack
lea __interrupt_stack,%sp
| Save old SP on istack
pea (%a0)
| Save sr
move.w %sr,%d0
move.l %d0,-(%sp)
| Enable interrupts
hal_cpu_int_enable %d0
| Call into kernel which will execute DSRs
jsr cyg_interrupt_call_pending_DSRs
move.l (%sp)+,%d0
| Restore previous interrupt state
hal_cpu_int_merge %d0,%d1
| Restore sp
move.l (%sp),%sp
| return to caller
rts
#endif
| ----------------------------------------------------------------------------
| Interrupt and reset stack
|
| WARNING: Do not put this in any memory section that gets initialized.
| Doing so may cause the C code to initialize its own stack.
.section ".uninvar","aw",@nobits
.balign 16
.global cyg_interrupt_stack_base
cyg_interrupt_stack_base:
__interrupt_stack_base:
.skip CYGNUM_HAL_COMMON_INTERRUPTS_STACK_SIZE
.balign 16
.global cyg_interrupt_stack
cyg_interrupt_stack:
__interrupt_stack:
.skip 0x10