Mercurial > flash_v2
view packages/hal/mips/arch/current/src/vectors.S @ 52:7b011d1ab50f ecos-sw-1999-11-05
Merge from eCos master repository on 1999-11-05-17:34:28-GMT
| author | jlarmour |
|---|---|
| date | Fri, 05 Nov 1999 18:39:11 +0000 |
| parents | a0774359f013 |
| children | 7a6ac9edc838 |
line wrap: on
line source
##============================================================================= ## ## vectors.S ## ## MIPS exception vectors ## ##============================================================================= #####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): nickg ## Contributors: nickg ## Date: 1998-02-04 ## Purpose: MIPS exception vectors ## Description: This file defines the code placed into the exception ## vectors. It also 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> #ifdef CYGPKG_KERNEL # include <pkgconf/kernel.h> #endif #include <cyg/hal/arch.inc> .extern cyg_instrument ##----------------------------------------------------------------------------- ## Hardware supplied vectors .set noreorder .section ".reset_vector","ax" # Reset vector at 0xBFC00000 FUNC_START(reset_vector) #ifndef CYG_HAL_STARTUP_RAM # Decide whether this is an NMI, cold or warm boot. mfc0 k0,status # get status reg lui k1,0x0008 # isolate NMI bit and k1,k1,k0 beqz k1,1f # skip if zero nop lar k1,__nmi_entry # jump to ROM nmi code jalr k1 nop 1: lui k1,0x0010 # isolate soft reset bit and k1,k1,k0 beqz k1,2f # skip if zero nop lar k1,__warm_start # jump to ROM warm_start code jr k1 nop 2: la k0,INITIAL_CONFIG0 # Set up config0 register mtc0 k0,config0 # to disable cache #endif lar v0,_start # jump to start jr v0 nop # (delay slot) FUNC_END(reset_vector) .section ".debug_vector","ax" # Debug vector at 0xBFC00200 FUNC_START(debug_vector) la k0,32 la k1,hal_vsr_table # Get VSR table lw k1,32*4(k1) # load debug vector jr k1 # go there nop # (delay slot) FUNC_END(debug_vector) .section ".other_vector","ax" # Common vector at 0x80000080 or 0xBFC00180 FUNC_START(other_vector) mfc0 k0,cause # K0 = exception cause nop andi k0,k0,0x7F # isolate exception code la k1,hal_vsr_table # address of VSR table add k1,k1,k0 # offset of VSR entry lw k1,0(k1) # k1 = pointer to VSR jr k1 # go there nop # (delay slot) FUNC_END(other_vector) .section ".utlb_vector","ax" FUNC_START(utlb_vector) la k0,33 la k1,hal_vsr_table # Get VSR table lw k1,33*4(k1) # load utlb vector jr k1 # go there nop # (delay slot) FUNC_END(utlb_vector) ##----------------------------------------------------------------------------- ## Startup code .text FUNC_START(_start) # Initialize hardware hal_cpu_init hal_diag_init hal_mmu_init hal_fpu_init hal_memc_init hal_intc_init hal_cache_init hal_timer_init # Load Global Pointer register. la gp,_gp # load initial stack pointer la a0,__interrupt_stack move sp,a0 hal_mon_init #ifdef CYG_HAL_STARTUP_ROM # Copy data from ROM to RAM .extern hal_copy_data jal hal_copy_data nop #endif # Zero BSS .extern hal_zero_bss jal hal_zero_bss nop # Call variant and platform HAL # initialization routines. .extern hal_variant_init jal hal_variant_init nop .extern hal_platform_init jal hal_platform_init nop # Call constructors .extern cyg_hal_invoke_constructors jal cyg_hal_invoke_constructors nop #if defined(CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS) .extern initialize_stub jal initialize_stub nop #endif # Call cyg_start .extern cyg_start jal cyg_start nop 9: b 9b # Loop if we return nop # (delay slot) FUNC_END(_start ) ##----------------------------------------------------------------------------- FUNC_START(__warm_start) ## The following is debug code left in here for now in case it ## proves useful in the near future. #if 0 move s0,t0 move s1,a1 # hal_diag_init hal_diag_writec '$' mfc0 a0,$30 # get ErrorEPC lar k0,hal_diag_ai_write_hex8 jalr k0 nop hal_diag_writec '-' move a0,s0 jalr k0 nop hal_diag_writec '-' move a0,s1 jalr k0 nop 1: b 1b nop #endif # At present we treat this like an NMI. b __nmi_entry nop FUNC_END(__warm_start) ##----------------------------------------------------------------------------- FUNC_START(__nmi_entry) # Clear exception state hal_cpu_except_enable # Move the ErrorEPC register to the EPC register so that the # default exception handler saves the right PC value. mfc0 k0,$30 nop; nop; nop; mtc0 k0,epc nop; nop; nop; #if (INITIAL_SR & 0x00400000) == 0 # Taking this exception will have set the BEV bit to 1. # If we normally run with it zero, we must clear it here. mfc0 k0,status la k1,0xFFBFFFFF and k0,k0,k1 mtc0 k0,status #endif la k0,34*4 la k1,hal_vsr_table # Get VSR table lw k1,34*4(k1) # load NMI vector jr k1 # go there nop # (delay slot) FUNC_END(__nmi_entry) ##----------------------------------------------------------------------------- ## Default exception VSR. ## Saves machine state and calls external handling code. FUNC_START(__default_exception_vsr) # We enter here with all of the CPU state still # in its registers except: # K0 = vector index # K1 = address of this function move k1,sp # K1 = original SP #ifdef CYG_HAL_ROM_MONITOR # Switch to interrupt stack to handle exception la sp,__interrupt_stack #endif addi sp,sp,-mips_exception_decrement # space for registers + safety margin sw k0,mipsreg_vector(sp) # store vector # store GPRs .set noat sw $0,(mipsreg_regs+0*4)(sp) sw $1,(mipsreg_regs+1*4)(sp) sw $2,(mipsreg_regs+2*4)(sp) sw $3,(mipsreg_regs+3*4)(sp) sw $4,(mipsreg_regs+4*4)(sp) sw $5,(mipsreg_regs+5*4)(sp) sw $6,(mipsreg_regs+6*4)(sp) sw $7,(mipsreg_regs+7*4)(sp) sw $8,(mipsreg_regs+8*4)(sp) sw $9,(mipsreg_regs+9*4)(sp) sw $10,(mipsreg_regs+10*4)(sp) sw $11,(mipsreg_regs+11*4)(sp) sw $12,(mipsreg_regs+12*4)(sp) sw $13,(mipsreg_regs+13*4)(sp) sw $14,(mipsreg_regs+14*4)(sp) sw $15,(mipsreg_regs+15*4)(sp) sw $16,(mipsreg_regs+16*4)(sp) sw $17,(mipsreg_regs+17*4)(sp) sw $18,(mipsreg_regs+18*4)(sp) sw $19,(mipsreg_regs+19*4)(sp) sw $20,(mipsreg_regs+20*4)(sp) sw $21,(mipsreg_regs+21*4)(sp) sw $22,(mipsreg_regs+22*4)(sp) sw $23,(mipsreg_regs+23*4)(sp) sw $24,(mipsreg_regs+24*4)(sp) sw $25,(mipsreg_regs+25*4)(sp) # sw $26,(mipsreg_regs+26*4)(sp) # == K0 # sw $27,(mipsreg_regs+27*4)(sp) # == K1 sw $28,(mipsreg_regs+28*4)(sp) # == GP # sw $29,(mipsreg_regs+29*4)(sp) # == SP sw $30,(mipsreg_regs+30*4)(sp) # == FP sw $31,(mipsreg_regs+31*4)(sp) # == RA .set at mfhi a0 mflo a1 sw a0,mipsreg_hi(sp) sw a1,mipsreg_lo(sp) # K1 contains original SP sw k1,(mipsreg_regs+29*4)(sp) # store in reg dump # save remaining machine state registers mfc0 t0,cause mfc0 t1,status mfc0 t2,cachectrl mfc0 t3,badvr mfc0 t4,config mfc0 t5,prid mfc0 t6,epc sw t0,mipsreg_cause(sp) sw t1,mipsreg_sr(sp) sw t2,mipsreg_cachectrl(sp) sw t3,mipsreg_badvr(sp) sw t4,mipsreg_config(sp) sw t5,mipsreg_prid(sp) sw t6,mipsreg_pc(sp) hal_fpu_save sp # The machine state is now all saved on the stack. hal_diag_excpt_start # Load Global Pointer register. la gp,_gp move s0,sp # save pointer to saved state addi sp,sp,-mips_stack_frame_size # make a null frame # Need to set up back pointers etc. ??? la ra,restore_state # load return address hal_cpu_except_enable # reenable exceptions .extern cyg_hal_exception_handler j cyg_hal_exception_handler # call C code move a0,s0 # arg0 = register dump (delay slot) # When the exception handler returns, it will # go back to restore_state, below. FUNC_END(__default_exception_vsr) ##------------------------------------------------------------------------------ ## Default interrupt VSR. ## Saves machine state and calls appropriate ISR. When done, calls ## interrupt_end() to finish up and possibly reschedule. FUNC_START(__default_interrupt_vsr) # We enter here with all of the CPU state still # in its registers except: # K0 = vector index # K1 = address of this function move k1,sp # K1 = original SP addi sp,sp,-mips_exception_decrement # space for registers + safety margin sw k0,mipsreg_vector(sp) # store vector # store GPRs .set noat sw $0,(mipsreg_regs+0*4)(sp) sw $1,(mipsreg_regs+1*4)(sp) sw $2,(mipsreg_regs+2*4)(sp) sw $3,(mipsreg_regs+3*4)(sp) sw $4,(mipsreg_regs+4*4)(sp) sw $5,(mipsreg_regs+5*4)(sp) sw $6,(mipsreg_regs+6*4)(sp) sw $7,(mipsreg_regs+7*4)(sp) sw $8,(mipsreg_regs+8*4)(sp) sw $9,(mipsreg_regs+9*4)(sp) sw $10,(mipsreg_regs+10*4)(sp) sw $11,(mipsreg_regs+11*4)(sp) sw $12,(mipsreg_regs+12*4)(sp) sw $13,(mipsreg_regs+13*4)(sp) sw $14,(mipsreg_regs+14*4)(sp) sw $15,(mipsreg_regs+15*4)(sp) sw $16,(mipsreg_regs+16*4)(sp) sw $17,(mipsreg_regs+17*4)(sp) sw $18,(mipsreg_regs+18*4)(sp) sw $19,(mipsreg_regs+19*4)(sp) sw $20,(mipsreg_regs+20*4)(sp) sw $21,(mipsreg_regs+21*4)(sp) sw $22,(mipsreg_regs+22*4)(sp) sw $23,(mipsreg_regs+23*4)(sp) sw $24,(mipsreg_regs+24*4)(sp) sw $25,(mipsreg_regs+25*4)(sp) # sw $26,(mipsreg_regs+26*4)(sp) # == K0 # sw $27,(mipsreg_regs+27*4)(sp) # == K1 sw $28,(mipsreg_regs+28*4)(sp) # == GP # sw $29,(mipsreg_regs+29*4)(sp) # == SP sw $30,(mipsreg_regs+30*4)(sp) # == FP sw $31,(mipsreg_regs+31*4)(sp) # == RA .set at mfhi a0 mflo a1 sw a0,mipsreg_hi(sp) sw a1,mipsreg_lo(sp) # K1 contains original SP sw k1,(mipsreg_regs+29*4)(sp) # store in reg dump mfc0 t1,status mfc0 t2,cachectrl mfc0 t3,epc sw t1,mipsreg_sr(sp) sw t2,mipsreg_cachectrl(sp) sw t3,mipsreg_pc(sp) hal_fpu_save sp # The machine state is now all saved on the stack. # Load Global Pointer register. la gp,_gp #ifdef CYGFUN_HAL_COMMON_KERNEL_SUPPORT .extern cyg_scheduler_sched_lock la v0,cyg_scheduler_sched_lock lw a0,0(v0) addi a0,a0,1 sw a0,0(v0) #endif move s0,sp # save pointer to saved state #ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK la a0,__interrupt_stack # a0 = stack top la a1,__interrupt_stack_base # a1 = stack base sub a3,sp,a1 # a3 = sp - base bltz a3,1f # if < 0 - not on istack nop # delay slot sub t0,a0,sp # t0 = top - sp bgtz t0,8f # if > 0 - already on istack nop # delay slot 1: move sp,a0 # switch to istack 8: addi sp,sp,-8 # space for old SP # (8 to keep dword alignment!) sw s0,0(sp) # save old SP on stack #endif subu sp,sp,mips_stack_frame_size # make a null frame # Need to set up back pointers etc. ??? # Decode external interrupt via interrupt controller hal_intc_decode s2 # Here, s2 contains the number of the interrupt being serviced, # we need to derive from that the vector number to call in the ISR # table. hal_intc_translate s2,s1 # Here s1 is the number of the vector to be called and s2 is # the number of the interrupt being serviced. hal_diag_intr_start #if defined(CYGPKG_KERNEL_INSTRUMENT) && defined(CYGDBG_KERNEL_INSTRUMENT_INTR) # Call cyg_instrument to record that this interrupt is being raised. li a0,0x0301 # a0 = type = INTR,RAISE move a1,s1 # a1 = vector number jal cyg_instrument # call instrument function move a2,s2 # a2 = interrupt number #endif #if defined(CYGDBG_HAL_MIPS_DEBUG_GDB_CTRLC_SUPPORT) # If we are supporting Ctrl-C interrupts from GDB, we must squirrel # away a pointer to the save interrupt state here so that we can # plant a breakpoint at some later time. .extern hal_saved_interrupt_state la v0,hal_saved_interrupt_state sw s0,0(v0) #endif sll s1,s1,2 # s1 = byte offset of vector hal_cpu_except_enable # reenable exceptions la t2,hal_interrupt_handlers # handler table add t2,t2,s1 # address of ISR ptr lw t2,0(t2) # ISR pointer la a1,hal_interrupt_data # data table add a1,a1,s1 # address of data ptr lw a1,0(a1) # Data pointer move a0,s2 # pass interrupt number jalr t2 # call ISR via t2 nop # (delay slot) #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. lw sp,mips_stack_frame_size(sp) # sp = *sp subu sp,sp,mips_stack_frame_size # make a null frame #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. # On return v0 bit 1 will indicate whether a DSR is # to be posted. Pass this together with a pointer to # the interrupt object we have just used to the # interrupt tidy up routine. # Note that s0, s1 and s2 are defined to be preserved across # calls by the calling convention, so they still contain # the register dump, the vector offset and the interrupt number # respectively. move s2,v0 la a1,hal_interrupt_objects # interrupt object table add a1,a1,s1 # address of object ptr lw a1,0(a1) # a1 = object ptr move a2,s0 # arg3 = saved register dump .extern interrupt_end jal interrupt_end # call into C to finish off move a0,v0 # put ISR result in arg0 move v0,s2 # return value from isr #endif restore_state: move k0,v0 # All done, restore CPU state and continue addi sp,sp,mips_stack_frame_size # retrieve CPU state ptr # Disable interrupts again while we restore state. hal_diag_restore hal_fpu_load sp lw t0,mipsreg_cachectrl(sp) lw t1,mipsreg_hi(sp) lw t2,mipsreg_lo(sp) mtc0 t0,cachectrl mthi t1 mtlo t2 # load GPRs .set noat # lw $0,(mipsreg_regs+0*4)(sp) lw $1,(mipsreg_regs+1*4)(sp) lw $2,(mipsreg_regs+2*4)(sp) lw $3,(mipsreg_regs+3*4)(sp) lw $4,(mipsreg_regs+4*4)(sp) lw $5,(mipsreg_regs+5*4)(sp) lw $6,(mipsreg_regs+6*4)(sp) lw $7,(mipsreg_regs+7*4)(sp) lw $8,(mipsreg_regs+8*4)(sp) lw $9,(mipsreg_regs+9*4)(sp) lw $10,(mipsreg_regs+10*4)(sp) lw $11,(mipsreg_regs+11*4)(sp) lw $12,(mipsreg_regs+12*4)(sp) lw $13,(mipsreg_regs+13*4)(sp) lw $14,(mipsreg_regs+14*4)(sp) lw $15,(mipsreg_regs+15*4)(sp) lw $16,(mipsreg_regs+16*4)(sp) lw $17,(mipsreg_regs+17*4)(sp) lw $18,(mipsreg_regs+18*4)(sp) lw $19,(mipsreg_regs+19*4)(sp) lw $20,(mipsreg_regs+20*4)(sp) lw $21,(mipsreg_regs+21*4)(sp) lw $22,(mipsreg_regs+22*4)(sp) lw $23,(mipsreg_regs+23*4)(sp) lw $24,(mipsreg_regs+24*4)(sp) lw $25,(mipsreg_regs+25*4)(sp) # lw $26,(mipsreg_regs+26*4)(sp) # == K0 # lw $27,(mipsreg_regs+27*4)(sp) # == K1 lw $28,(mipsreg_regs+28*4)(sp) # == GP # lw $29,(mipsreg_regs+29*4)(sp) # == SP lw $30,(mipsreg_regs+30*4)(sp) # == FP lw $31,(mipsreg_regs+31*4)(sp) # == RA .set at #if defined(CYG_HAL_USE_ROM_MONITOR_CYGMON) # If we have a Cygmon that wants to listen to network interrupts, then # the return code from the earlier call to hal_default_isr() will # have been negative to indicate this. So we jump into Cygmon here # because Cygmon requires the processor state to be the same as when # the interrupt was taken, but with k0 as the exception number. bgez k0,1f nop # Check for new cygmon sw k0,(mipsreg_regs+26*4)(sp) # save k0 la k1,0x80000100 + 41*4 # New cygmon "magic" id lw k1,0(k1) lui k0,0x55aa ori k0,0x4321 bne k0,k1,1f # Need to let cygmon handle this la k1,0x80000100 + 39*4 # stub entry vector lw k0,(mipsreg_regs+26*4)(sp) # restore k0 lw k1,0(k1) lw sp,(mipsreg_regs+29*4)(sp) # restore SP sll k0,1 # clear bit 31. jr k1 srl k0,1 1: #endif lw k0,mipsreg_pc(sp) # K0 = return PC lw k1,mipsreg_sr(sp) # K1 = saved SR lw sp,(mipsreg_regs+29*4)(sp) # load SP # Invoke CPU specific mechanism for returning from this # exception hal_cpu_eret k0,k1 FUNC_END(__default_interrupt_vsr) hal_intc_decode_data ##----------------------------------------------------------------------------- ## 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) mfc0 t0,status # get status register value la v0,__interrupt_stack # v0 = interrupt stack move v1,sp # v1 = original stack ptr move sp,v0 # sp = interrupt stack addi sp,sp,-32 # make a null frame sw v1,16(sp) # save old sp sw ra,20(sp) # save old ra sw t0,24(sp) # save old sr hal_cpu_int_enable jal cyg_interrupt_call_pending_DSRs # call back to kernel nop lw a0,24(sp) # get status reg hal_cpu_int_merge a0 # merge with current SR lw ra,20(sp) # restore ra lw sp,16(sp) # restore sp jr ra # go back nop # delay slot FUNC_END(hal_interrupt_stack_call_pending_DSRs) #endif ##----------------------------------------------------------------------------- ## Short circuit in case any code tries to use "__gccmain()" FUNC_START(__gccmain) jr ra nop FUNC_END(__gccmain) ##----------------------------------------------------------------------------- ## Interrupt Stack. ## Used during intialization and for executing ISRs. .bss .balign 16 .global cyg_interrupt_stack_base cyg_interrupt_stack_base: __interrupt_stack_base: .rept CYGNUM_HAL_COMMON_INTERRUPTS_STACK_SIZE .byte 0 .endr .balign 16 .global cyg_interrupt_stack cyg_interrupt_stack: __interrupt_stack: .long 0,0,0,0,0,0,0,0 ##----------------------------------------------------------------------------- ## VSR table. ## The main interrupt code indirects through here to find the VSR ## to execute for each architecture defined interrupt. ## This is only used for simulated targets, on real targets a fixed location VSR ## table is now allocated at 0x80000100. #ifndef CYG_HAL_MIPS_VSR_TABLE_DEFINED ## .section ".vsr_table","a" .data .globl hal_vsr_table hal_vsr_table: .long __default_interrupt_vsr .rept 63 .long __default_exception_vsr .endr #endif #------------------------------------------------------------------------------ # Interrupt vector tables. # These tables contain the isr, data and object pointers used to deliver # interrupts to user code. # hal_interrupt_level contains the interrupt level set by # HAL_INTERRUPT_CONFIGURE(). # This is a default set that provide support only for the 6 external # interrupts in the status/cause registers. Platforms or boards are expected # to define their own versions of these if they have their own interrupt mappings. #ifndef CYG_HAL_MIPS_ISR_TABLES_DEFINED .extern hal_default_isr .data .globl hal_interrupt_handlers hal_interrupt_handlers: .long hal_default_isr .long hal_default_isr .long hal_default_isr .long hal_default_isr .long hal_default_isr .long hal_default_isr .globl hal_interrupt_data hal_interrupt_data: .rept 6 .long 0 .endr .globl hal_interrupt_objects hal_interrupt_objects: .rept 6 .long 0 .endr #endif ##----------------------------------------------------------------------------- ## end of vectors.S
