This is the mail archive of the ecos-discuss@sources.redhat.com mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Gameboy Advance vectors.S (dealing with BIOS)


Hello all,
Attached is vectors.s that contains the modifications
for the Gameboy Advance (GBA).  The changes are
surrounded by ifdef's (simply search for
GAMEBOY_ADVANCE).  There are 11 modifications in all. 
They are listed and described below.  Please offer any
feedback you may have regarding the best way to
integrate these changes into the main source.  I'm
assuming that one of the goals is to modify vectors.s
as little as possible.  The primary issue with the GBA
is that it has BIOS that cannot be modified or
replaced.  Most changes are required because of BIOS.

thanks!
--bill

1) This is a Nintendo requirement where a predefined
header must be written at the beginning of ROM space. 
This area is filled with zeros to allocate the area
and is later modified with the correct data which
includes checksums, etc.  There is probably a cleaner
way to do this :)

2) Since BIOS exists where the vectors section wants
to go, this is commented out.  That is, BIOS contains
its own exception table.  As an alternative I could
simply tell the linker to put this somewhere out of
reach and move the modification to the linker
script(?)

3) patch_vectors is used to "patch through" the
illegal instruction trap used for debugging.  That is,
BIOS gets the original illegal instruction trap, but a
certain bit set in the ROM header will instruct BIOS
to call code at 0x9ffc000 before returning from the
exception.  Thus, patch_vectors is put in its own
section residing at 0x9ffc000.  This code can be put
in a separate file.  This alludes to a modification in
arm.ld -- what is the best way to add a section in
this way?  Putting ifdef's in arm.ld is probably not a
good idea either :)

4) This skips exception vector related code that is
not necessary for the GBA.  I'm not sure if this
breaks anything if it is included, however. 

5) Same reason as 4.  4 and 5 could not be combied due
to preprocessor matching of #if's and #endif's.

6) This loads the IRQ address into a BIOS register and
allows the IRQ routine to be called.  This should go
in hal_hardware_init() I believe.

7) Related to 6.

8) This had us scratching our heads for quite awhile! 
Since exceptions go through BIOS, which saves some
registers to the stack, not restoring the stack upon
exit will cause BIOS to save registers to the wrong
memory -- typically corrupting the supervisor stack.

9) This is required to restore registers that get
saved at the beginning of the BIOS exception routine. 
This can be moved somewhere else.

10) Same reason as 8.

11) Related to 3.
    
It seems that a good portion of this can be improved,
but 1, and especially 8 and 10 seem unavoidable. 
Please offer your input!
 



__________________________________________________
Do You Yahoo!?
Send FREE video emails in Yahoo! Mail!
http://promo.yahoo.com/videomail/
// #========================================================================
// #
// #    vectors.S
// #
// #    ARM exception vectors
// #
// #========================================================================
// ####COPYRIGHTBEGIN####
//                                                                          
// -------------------------------------------                              
// The contents of this file are subject to the Red Hat eCos Public License 
// Version 1.1 (the "License"); you may not use this file except in         
// compliance with the License.  You may obtain a copy of the License at    
// http://www.redhat.com/                                                   
//                                                                          
// 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 Configurable Operating System,      
// released September 30, 1998.                                             
//                                                                          
// The Initial Developer of the Original Code is Red Hat.                   
// Portions created by Red Hat are                                          
// Copyright (C) 1998, 1999, 2000, 2001 Red Hat, Inc.
// All Rights Reserved.                                                     
// -------------------------------------------                              
//                                                                          
// ####COPYRIGHTEND####
// #========================================================================
// ######DESCRIPTIONBEGIN####
// #
// # Author(s):     nickg, gthomas
// # Contributors:  nickg, gthomas
// # Date:          1999-02-20
// # Purpose:       ARM 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/hal.h>
#include <pkgconf/hal_arm.h>
#ifdef CYGPKG_KERNEL  // no CDL yet
#include <pkgconf/kernel.h>
#else
# undef CYGFUN_HAL_COMMON_KERNEL_SUPPORT
# undef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
#endif
#include <cyg/hal/hal_platform_setup.h>

#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
// The CDL should enforce this
#undef  CYGHWR_HAL_ARM_DUMP_EXCEPTIONS
#endif

#include "arm.inc"

#ifdef __thumb__
// Switch to thumb mode
#define THUMB_MODE(_r_, _l_)                     \
        ldr     _r_,=_l_ ## f+1                 ;\
        bx      _r_                             ;\
        .pool                                   ;\
        .code   16                              ;\
        .thumb_func                             ;\
 _l_:

// Switch to ARM mode
#define ARM_MODE(_r_, _l_)                       \
        ldr     _r_,=_l_ ## f                   ;\
        bx      _r_                             ;\
        .pool                                   ;\
        .code   32                              ;\
 _l_:

// Function definition, start executing body in ARM mode
#define FUNC_START_ARM(_name_, _r_)              \
        .code   16                              ;\
        .thumb_func                             ;\
        .globl _name_                           ;\
_name_:                                         ;\
        ldr     _r_,=_name_ ## _ARM             ;\
        bx      _r_                             ;\
        .code   32                              ;\
_name_ ## _ARM:

#else

// Switch to thumb mode
#define THUMB_MODE(_r_, _l_)

// Switch to ARM mode
#define ARM_MODE(_r_, _l_)

// Function definition, start executing body in ARM mode
#define FUNC_START_ARM(_name_, _r_) \
        .globl _name_; \
_name_: 

#endif

        

#define PTR(name)               \
.##name: .word  name

// CYGHWR_HAL_ROM_VADDR is used when compiling for a different location
// from the base of ROM.  hal_platform_setup.h might define it.  For
// example, if flash is from 0x50000000 upwards (as on SA11x0), and we are
// to execute at 0x50040000, then we want the reset vector to point to
// 0x0004pqrs - the unmapped ROM address of the code - rather than
// 0x0000pqrs, which is the offset into our flash block.
// 
// But usually it's not defined, so the behaviour is the obvious.

#ifndef UNMAPPED        
#ifdef CYGHWR_HAL_ARM_HAS_MMU
# ifndef CYGHWR_HAL_ROM_VADDR
#  define CYGHWR_HAL_ROM_VADDR __exception_handlers
# endif
# define UNMAPPED(x) ((x)-CYGHWR_HAL_ROM_VADDR)
#else
# define UNMAPPED(x) (x)
#endif
#endif        
                                
#define UNMAPPED_PTR(name)              \
.##name: .word  UNMAPPED(name)

        .file   "vectors.S"


// CYGHWR_LED_MACRO can be defined in hal_platform_setup.h. It's free to
// use r0+r1. Argument is in "\x" - cannot use macro arguments since the
// macro may contain #-chars and use of arguments cause these to be 
// interpreted as CPP stringify operators.
// See example in PID hal_platform_setup.h.
#ifndef CYGHWR_LED_MACRO
#define CYGHWR_LED_MACRO
#endif
        
.macro LED x
    CYGHWR_LED_MACRO
.endm

#ifdef GAMEBOY_ADVANCE // Change #1 
    .GLOBAL     reset_vector
reset_vector:

#ifndef CYG_HAL_STARTUP_ROM
// RAM startup (we assume that we are already in thumb mode)
        .ALIGN
        .code 16
        ARM_MODE(r0,10)
        b       start_vector

#else // ROM startup

        .ALIGN
        .code 32
rom_header:
        b       rom_header_end

// Nintendo Logo Character Data (8000004)
        .byte   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
        .byte   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
        .byte   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
        .byte   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
        .byte   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
        .byte   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
        .byte   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
        .byte   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
        .byte   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
        .byte   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
        .byte   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
        .byte   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
        .byte   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
        .byte   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
        .byte   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
        .byte   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
        .byte   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
        .byte   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
        .byte   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
        .byte   0x00,0x00,0x00,0x00

// Software Titles (80000A0)
        .byte   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
        .byte   0x00,0x00,0x00,0x00

// Initial Code (80000AC)
        .byte   0x00,0x00,0x00,0x00

// Maker Code (80000B0)
        .byte   0x30,0x31

// Fixed Value (80000B2)
        .byte   0x96

// Main Unit Code (80000B3)
        .byte   0x00

// Device Type (80000B4)
        .byte   0x00

// Unused Data (7Byte) (80000B5)
        .byte   0x00,0x00,0x00,0x00,0x00,0x00,0x00

// Software Version No (80000BC)
        .byte   0x00

// Complement Check (80000BD)
        .byte   0xf0

// Check Sum (80000BE)
        .byte   0x00,0x00

rom_header_end:
        b       start_vector

        .byte   0       // boot method 
	    .byte   0       // slave number
        .byte   0       // reserved
        .byte   0       // reserved
        .word   0       // reserved
        .word   0       // reserved
        .word   0       // reserved
        .word   0       // reserved
        .word   0       // reserved
        .word   0       // reserved

#endif
#endif // GAMEBOY_ADVANCE

//==========================================================================
// Hardware exception vectors.
//   This entire section will be copied to location 0x0000 at startup time.
//
#ifndef GAMEBOY_ADVANCE // Change #2 
        .code   32
        .section ".vectors","ax"
#endif

// This macro allows platforms to add their own code at the very start of
// the image.  This may be required in some circumstances where eCos ROM 
// based code does not run immediately upon reset and/or when some sort of
// special header is required at the start of the image.        
#ifdef PLATFORM_PREAMBLE
        PLATFORM_PREAMBLE
#endif
                        
        .global __exception_handlers
__exception_handlers:
#ifdef CYGSEM_HAL_ROM_RESET_USES_JUMP
// Assumption:  ROM code has these vectors at the hardware reset address.
// A simple jump removes any address-space dependencies [i.e. safer]
        b       reset_vector                    // 0x00
#else        
        ldr     pc,.reset_vector                // 0x00
#endif        
        ldr     pc,.undefined_instruction       // 0x04
        ldr     pc,.software_interrupt          // 0x08 start && software int
        ldr     pc,.abort_prefetch              // 0x0C
        ldr     pc,.abort_data                  // 0x10
        .word   0                               // unused
        ldr     pc,.IRQ                         // 0x18
        ldr     pc,.FIQ                         // 0x1C

// The layout of these pointers should match the vector table above since
// they are copied in pairs.
        .global vectors
vectors:
UNMAPPED_PTR(reset_vector)                      // 0x20
PTR(undefined_instruction)                      // 0x24
PTR(software_interrupt)                         // 0x28
PTR(abort_prefetch)                             // 0x2C
PTR(abort_data)                                 // 0x30
        .word   0                               // 0x34
PTR(IRQ)                                        // 0x38
PTR(FIQ)                                        // 0x3c
#ifdef CYGSEM_HAL_ARM_PID_ANGEL_BOOT         
PTR(start) // This is copied to 0x28 for bootup // 0x40
#endif        
           // location 0x40 is used for storing DRAM size if known
           // for some platforms.        

#if defined(GAMEBOY_ADVANCE) && defined(CYG_HAL_STARTUP_ROM) // Change #3  
//
// "Patch vectors" - used to patch illegal instruction into debug stub code
//  This code gets mapped to 0x9ffc000 (mirrored at 0x83fc000 for 4mb flash)
//
        .section ".patch_vectors", "ax"
		.code   32

        .globl  hal_patch_vector_code
hal_patch_vector_code:

		// restore registers and return to user code (not bios, which returns incorrectly)
		ldr		r13, .pv_cl1
		ldmfd	r13!, {r12,r14}
		msr		spsr, r12
		ldmfd	r13!, {r12,r14}

        b		undefined_instruction   

.pv_cl0:
		.word	0x6004000
.pv_cl1:
		.word	0x3007fe0

#endif // GAMEBOY_ADVANCE

//
// "Vectors" - fixed location data items
//    This section contains any data which might be shared between
// an eCos application and any other environment, e.g. the debug
// ROM.                        
//
        .section ".fixed_vectors"
        // Interrupt/exception VSR pointers
        .globl  hal_vsr_table
hal_vsr_table:
        .rept   8               
        .long   0
        .endr

        .globl  hal_dram_size
hal_dram_size:  
        .long   0
	// what, if anything, hal_dram_type means is up to the platform
        .globl  hal_dram_type
hal_dram_type:  
        .long   0

        .balign 16        
#ifdef CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT
	// Vectors used to communicate between eCos and ROM environments
        .globl  hal_virtual_vector_table
hal_virtual_vector_table:
        .rept   CYGNUM_CALL_IF_TABLE_SIZE
        .long   0
        .endr
#endif
        .balign 32
        
// Other vectors - this may include "fixed" locations
#ifdef PLATFORM_VECTORS
        PLATFORM_VECTORS
#endif
                        
        .text   
#ifdef GAMEBOY_ADVANCE // Change #4 
start_vector:
#else
// Startup code which will get the machine into supervisor mode
        .global reset_vector
        .type   reset_vector,function
reset_vector:
        PLATFORM_SETUP1         // Early stage platform initialization
                                // which can set DRAM size at 0x40
                                // see <cyg/hal/hal_platform_setup.h>

        // Come here to reset board
warm_reset:                 

#if defined(CYG_HAL_STARTUP_RAM) && \
    !defined(CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS)
        mrs     r7,cpsr                 // move back to IRQ mode
        and     r7,r7,#CPSR_MODE_BITS
        cmp     r7,#CPSR_SUPERVISOR_MODE
        beq     start
#endif

        // We cannot access any LED registers until after PLATFORM_SETUP1
        LED 7

        mov     r0,#0           // move vectors
        ldr     r1,=__exception_handlers
#ifndef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
        // Wait with this if stubs are included (see further down).
        ldr     r2,[r1,#0x04]   // undefined instruction
        str     r2,[r0,#0x04]
        ldr     r2,[r1,#0x24]   
        str     r2,[r0,#0x24]
#endif
        ldr     r2,[r1,#0x08]   // software interrupt
        str     r2,[r0,#0x08]


#if defined(CYGSEM_HAL_ARM_PID_ANGEL_BOOT)
// Ugly hack to get into supervisor mode
        ldr     r2,[r1,#0x40]
        str     r2,[r0,#0x28]

        LED 6
                
        swi                     // switch to supervisor mode
#endif        

// =========================================================================
// Real startup code. We jump here from the reset vector to set up the world.
        .globl  start
start:  

        LED 5

#if defined(CYG_HAL_STARTUP_RAM) && \
    !defined(CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS)
// If we get restarted, hang here to avoid corrupting memory
        ldr     r0,.init_flag
        ldr     r1,[r0]
1:      cmp     r1,#0
        bne     1b
        ldr     r1,init_done
        str     r1,[r0]
#endif

        // Reset software interrupt pointer
        mov     r0,#0           // move vectors
        ldr     r1,.__exception_handlers
#if defined(CYG_HAL_STARTUP_RAM) && \
    !defined(CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS)
        cmp     r7,#CPSR_SUPERVISOR_MODE
        beq     10f
#endif
        ldr     r2,[r1,#0x28]   // software interrupt
        str     r2,[r0,#0x28]
10:
        ldr     r2,[r1,#0x18]   // IRQ
        str     r2,[r0,#0x18]
        ldr     r2,[r1,#0x38]
        str     r2,[r0,#0x38]
        ldr     r2,[r1,#0x1C]   // FIQ
        str     r2,[r0,#0x1C]
        ldr     r2,[r1,#0x3C]
        str     r2,[r0,#0x3C]
        ldr     r2,[r1,#0x0C]   // abort (prefetch)
        str     r2,[r0,#0x0C]
        ldr     r2,[r1,#0x2C]   
        str     r2,[r0,#0x2C]
        ldr     r2,[r1,#0x10]   // abort (data)
        str     r2,[r0,#0x10]
        ldr     r2,[r1,#0x30]
        str     r2,[r0,#0x30]

        LED 4
#endif
#if defined(CYG_HAL_STARTUP_ROM) || defined(CYG_HAL_STARTUP_ROMRAM)
#ifndef GAMEBOY_ADVANCE // Change #5 
        // Set up reset vector
        mov     r0,#0
        ldr     r1,.__exception_handlers
        ldr     r2,[r1,#0x00]    // reset vector intstruction
        str     r2,[r0,#0x00]
        ldr     r2,=warm_reset
        str     r2,[r0,#0x20]
#endif
        // Relocate [copy] data from ROM to RAM
        ldr     r3,.__rom_data_start
        ldr     r4,.__ram_data_start
        ldr     r5,.__ram_data_end
        cmp     r4,r5           // jump if no data to move
        beq     2f
        sub     r3,r3,#4        // loop adjustments
        sub     r4,r4,#4
1:      ldr     r0,[r3,#4]!     // copy info
        str     r0,[r4,#4]!
        cmp     r4,r5
        bne     1b
2:
#endif

        // initialize interrupt/exception environments
        ldr     sp,.__startup_stack
        mov     r0,#(CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE|CPSR_IRQ_MODE)
        msr     cpsr,r0
        ldr     sp,.__exception_stack
        mov     r0,#(CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE|CPSR_UNDEF_MODE)
        msr     cpsr,r0
        ldr     sp,.__exception_stack

        // initialize CPSR (machine state register)
        mov     r0,#(CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE|CPSR_SUPERVISOR_MODE)
        msr     cpsr,r0

        // Note: some functions in LIBGCC1 will cause a "restore from SPSR"!!
        msr     spsr,r0

        // initialize stack
        ldr     sp,.__startup_stack

        // clear BSS
        ldr     r1,.__bss_start
        ldr     r2,.__bss_end
        mov     r0,#0
        cmp     r1,r2
        beq     2f
1:      str     r0,[r1],#4
        cmp     r1,r2
        bne     1b
2:

        // Run kernel + application in THUMB mode
        THUMB_MODE(r1,10)

#ifdef GAMEBOY_ADVANCE // Change #6 
		// setup gba interrupt address
        ldr     r1, int_addr					  
        adr     r0, IRQ
        str     r0, [r1]

//		bl		TDInit
#endif

        LED 3
        
        // Call platform specific hardware initialization
        bl      hal_hardware_init

#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
        bl      initialize_stub

        // Now that stub is initialized, change vector. It is possible
        // to single-step through most of the init code, except the below.
        // Put a breakpoint at the call to cyg_hal_invoke_constructors to
        // pass over this bit (s-s depends on internal state in the stub).
#endif

#if defined(CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS) || \
    defined(CYGIMP_HAL_PROCESS_ALL_EXCEPTIONS)
        mov     r0,#0           // move vectors
        ldr     r1,=__exception_handlers
        ldr     r2,[r1,#0x04]   // undefined instruction
        str     r2,[r0,#0x04]
        ldr     r2,[r1,#0x24]   
        str     r2,[r0,#0x24]
#endif

#if defined(CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT) \
    || defined(CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT)
        .extern hal_ctrlc_isr_init
        bl      hal_ctrlc_isr_init
#endif

        LED 2
        
        // Run through static constructors
        bl      cyg_hal_invoke_constructors

        LED 1
        
        // This starts up the eCos kernel
        bl      cyg_start
_start_hang:
        b       _start_hang
        .code   32
        
        .global reset_platform
        .type   reset_platform,function
reset_platform:         
#ifdef CYGSEM_HAL_ROM_MONITOR
        // initialize CPSR (machine state register)
        mov     r0,#(CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE|CPSR_SUPERVISOR_MODE)
        msr     cpsr,r0
        b		warm_reset
#else
        mov     r0,#0
        mov     pc,r0           // Jump to reset vector        
#endif                   
		
init_done:
        .long   0xDEADB00B

#ifdef GAMEBOY_ADVANCE // Change #7
int_addr:
		.long	0x3007ffc
#endif

//
// Exception handlers
// Assumption: get here from a Supervisor context [mode]
//
        .code   32
undefined_instruction:
        ldr     sp,.__undef_exception_stack     // get good stack
        stmfd   sp!,{r0,fp,ip,lr}               
        mrs     r0,spsr
        stmfd   sp!,{r0}
        mov     ip,sp                   // save SP which will vanish with
                                        //   mode switch
        mrs     r0,cpsr                 // switch to Supervisor Mode
        bic     r0,r0,#CPSR_MODE_BITS
        orr     r0,r0,#CPSR_SUPERVISOR_MODE
        msr     cpsr,r0                 // sp,lr are now old values
        mov     fp,sp
#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
        ldr     sp,.__GDB_stack
        cmp     fp,sp                   // already on GDB stack?
        bhi     10f     
        ldr     r0,.__GDB_stack_base            
        cmp     fp,r0
        bls     10f                     // no - switch to GDB stack
                                        //      (already in sp)
        mov     sp,fp                   // yes - no switch
10:
#endif
        sub     sp,sp,#ARMREG_SIZE      // make space for frame
        stmea   sp,{r0-r10,fp}          // save immediately visible registers
        ldmfd   ip,{r0-r4}              // saved registers
        // Adjust PC according to CPU mode
        tst     r0,#CPSR_THUMB_ENABLE
        subeq   r4,r4,#4                // PC at time of interrupt (ARM)
        subne   r4,r4,#2                // PC at time of interrupt (thumb)
        str     r0,[sp,#armreg_cpsr]    // CPSR at time of interrupt
        str     r1,[sp,#armreg_r0]      // saved R0
        str     r2,[sp,#armreg_fp]      // saved FP
        str     r3,[sp,#armreg_ip]      // saved IP
        str     r4,[sp,#armreg_pc]      // PC at time of interrupt
        str     lr,[sp,#armreg_lr]      // LR at time of interrupt
        add     r0,ip,#ARMREG_SIZE
        str     fp,[sp,#armreg_sp]      // SP at time of interrupt
#ifdef  CYGHWR_HAL_ARM_DUMP_EXCEPTIONS
        mov     r0,sp
        bl      cyg_hal_report_undefined_instruction
#endif
        mov     v1,#CYGNUM_HAL_EXCEPTION_ILLEGAL_INSTRUCTION
        b       call_exception_handler

        .code   32
software_interrupt:
        sub     sp,sp,#ARMREG_SIZE+16   // make space for frame
        stmea   sp,{r0-r10,fp}          // save immediately visible registers
        mrs     r0,spsr
        // Adjust PC according to CPU mode
        tst     r0,#CPSR_THUMB_ENABLE
        subeq   r3,lr,#4                // PC at time of interrupt (ARM)
        subne   r3,lr,#2                // PC at time of interrupt (thumb)
        str     r0,[sp,#armreg_cpsr]    // CPSR at time of interrupt
        str     ip,[sp,#armreg_ip]      // saved IP
        str     r3,[sp,#armreg_pc]      // PC at time of interrupt
        str     lr,[sp,#armreg_lr]      // LR at time of interrupt
        add     r0,sp,#ARMREG_SIZE+16
        str     r0,[sp,#armreg_sp]      // SP at time of interrupt
#ifdef  CYGHWR_HAL_ARM_DUMP_EXCEPTIONS
        mov     r0,sp
        bl      cyg_hal_report_software_interrupt
#endif
        mov     v1,#CYGNUM_HAL_EXCEPTION_INTERRUPT
        b       call_exception_handler

        .code   32
abort_prefetch:
        ldr     sp,.__undef_exception_stack     // get good stack
        sub     lr,lr,#4                // PC at time of interrupt
        stmfd   sp!,{r0,fp,ip,lr}               
        mrs     r0,spsr
        stmfd   sp!,{r0}
        mov     ip,sp                   // save SP which will vanish with
                                        //   mode switch
        mrs     r0,cpsr                 // switch to Supervisor Mode
        bic     r0,r0,#CPSR_MODE_BITS
        orr     r0,r0,#CPSR_SUPERVISOR_MODE
        msr     cpsr,r0                 // sp,lr are now old values
        mov     fp,sp
#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
        ldr     sp,.__GDB_stack
        cmp     fp,sp                   // already on GDB stack?
        bhi     10f     
        ldr     r0,.__GDB_stack_base            
        cmp     fp,r0
        bls     10f                     // no - switch to GDB stack
                                        //      (already in sp)
        mov     sp,fp                   // yes - no switch
10:
#endif
        sub     sp,sp,#ARMREG_SIZE      // make space for frame
        stmea   sp,{r0-r10,fp}          // save immediately visible registers
        ldmfd   ip,{r0-r4}              // saved registers
        str     r0,[sp,#armreg_cpsr]    // CPSR at time of interrupt
        str     r1,[sp,#armreg_r0]      // saved R0
        str     r2,[sp,#armreg_fp]      // saved FP
        str     r3,[sp,#armreg_ip]      // saved IP
        str     r4,[sp,#armreg_pc]      // PC at time of interrupt
        str     lr,[sp,#armreg_lr]      // LR at time of interrupt
        add     r0,ip,#ARMREG_SIZE
        str     fp,[sp,#armreg_sp]      // SP at time of interrupt
#ifdef  CYGHWR_HAL_ARM_DUMP_EXCEPTIONS
        mov     r0,sp
        bl      cyg_hal_report_abort_prefetch
#endif
        mov     v1,#CYGNUM_HAL_EXCEPTION_CODE_ACCESS
        b       call_exception_handler

        .code   32
abort_data:
        ldr     sp,.__undef_exception_stack     // get good stack
        sub     lr,lr,#4                // PC at time of interrupt
        stmfd   sp!,{r0,fp,ip,lr}               
        mrs     r0,spsr
        stmfd   sp!,{r0}
        mov     ip,sp                   // save SP which will vanish with
                                        //   mode switch
        mrs     r0,cpsr                 // switch to Supervisor Mode
        bic     r0,r0,#CPSR_MODE_BITS
        orr     r0,r0,#CPSR_SUPERVISOR_MODE
        msr     cpsr,r0                 // sp,lr are now old values
        mov     fp,sp
#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
        ldr     sp,.__GDB_stack
        cmp     fp,sp                   // already on GDB stack?
        bhi     10f     
        ldr     r0,.__GDB_stack_base            
        cmp     fp,r0
        bls     10f                     // no - switch to GDB stack
                                        //      (already in sp)
        mov     sp,fp                   // yes - no switch
10:
#endif
        sub     sp,sp,#ARMREG_SIZE      // make space for frame
        stmea   sp,{r0-r10,fp}          // save immediately visible registers
        ldmfd   ip,{r0-r4}              // saved registers
        str     r0,[sp,#armreg_cpsr]    // CPSR at time of interrupt
        str     r1,[sp,#armreg_r0]      // saved R0
        str     r2,[sp,#armreg_fp]      // saved FP
        str     r3,[sp,#armreg_ip]      // saved IP
        str     r4,[sp,#armreg_pc]      // PC at time of interrupt
        str     lr,[sp,#armreg_lr]      // LR at time of interrupt
        add     r0,ip,#ARMREG_SIZE
        str     fp,[sp,#armreg_sp]      // SP at time of interrupt
#ifdef  CYGHWR_HAL_ARM_DUMP_EXCEPTIONS
        mov     r0,sp
        bl      cyg_hal_report_abort_data
#endif
        mov     v1,#CYGNUM_HAL_EXCEPTION_DATA_ACCESS
        b       call_exception_handler

        
//
// Dispatch an exception handler.

        .code   32
call_exception_handler:
        str     v1,[sp,#armreg_vector]
        mov     r0,sp

        THUMB_MODE(r9,10)

        bl      exception_handler
#ifdef  CYGHWR_HAL_ARM_DUMP_EXCEPTIONS
        mov     r0,sp
        bl      cyg_hal_report_exception_handler_returned
#endif

        ARM_MODE(r1,10)

// Restore [interrupted] context
        mov     ip,sp                   // get stack pointer

        mrs     r0,cpsr                 // move back to IRQ mode
        orr     r0,r0,#CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE
        msr     cpsr,r0
        nop
        nop

        ldr     lr,[ip,#armreg_lr]
        ldr     sp,[sp,#armreg_sp]
                        
        bic     r0,r0,#CPSR_MODE_BITS
        orr     r0,r0,#CPSR_IRQ_MODE
        msr     cpsr,r0

        mov     sp,ip
        ldr     lr,[sp,#armreg_pc]
        ldr     r0,[sp,#armreg_cpsr]
        ldr     ip,[sp,#armreg_ip]
        msr     spsr,r0
        ldmfd   sp,{r0-r10,fp}
#ifdef GAMEBOY_ADVANCE // Change #8
        ldr     sp,.__undef_exception_stack   // restore good stack
#endif
        movs    pc,lr                   // restore PC from LR, CPSR from SPSR

// Handle device interrupts
// This is slightly more complicated than the other exception handlers because
// it needs to interface with the kernel (if present).

        .code   32
FIQ:
        // We can get here from supervisor mode or from IRQ mode.
        mrs     r8,spsr                 // CPSR at time of interrupt
        and     r9,r8,#CPSR_MODE_BITS   // isolate pre-interrupt mode
        cmp	r9,#CPSR_IRQ_MODE
        bne	1f
        // If FIQ interrupted IRQ mode, just return with FIQ disabled.
        // The common interrupt handling takes care of the rest.
        orr	r8,r8,#CPSR_FIQ_DISABLE
        msr	spsr,r8
        subs	pc,lr,#4
    1:
        // If FIQ interrupted supervisor mode, switch to IRQ mode and
        // fall through to IRQ handler.
        ldr     sp,.__exception_stack   // get good stack to save lr and spsr
        stmdb   sp,{r8,lr}
        mov     r8,#CPSR_IRQ_MODE|CPSR_FIQ_DISABLE|CPSR_IRQ_DISABLE
        msr     cpsr,r8			// switch to IRQ mode
        ldr     sp,.__exception_stack   // get regs saved in FIQ mode
        ldmdb	sp,{sp,lr}
        msr     spsr,sp

        // now it looks like we got an IRQ instead of an FIQ except that
        // FIQ is disabled so we don't recurse.


IRQ:
#ifdef GAMEBOY_ADVANCE // Change #9
		// This restores registers and stack from GBA bios
		ldmfd   r13!,{r0-r3,r12,r14}
#endif	
        // Note: I use this exception stack while saving the context because
        // the current SP does not seem to be always valid in this CPU mode.
        ldr     sp,.__exception_stack   // get good stack
        sub     lr,lr,#4                // PC at time of interrupt
        stmfd   sp!,{r0,fp,ip,lr}               
        mrs     r0,spsr
        stmfd   sp!,{r0}

handle_IRQ_or_FIQ:              
        mov     ip,sp                   // save SP which will vanish with
                                        //   mode switch
        mrs     r0,cpsr                 // switch to Supervisor Mode
        bic     r0,r0,#CPSR_MODE_BITS
        orr     r0,r0,#CPSR_SUPERVISOR_MODE|CPSR_FIQ_DISABLE|CPSR_IRQ_DISABLE
        msr     cpsr,r0                 // sp,lr are now old values
        mov     fp,sp                   // save old SP
        sub     sp,sp,#ARMREG_SIZE      // make space for frame
        stmea   sp,{r0-r10,fp}          // save immediately visible registers
        ldmfd   ip,{r0-r4}              // saved registers
        str     r0,[sp,#armreg_cpsr]    // CPSR at time of interrupt
        str     r1,[sp,#armreg_r0]      // saved R0
        str     r2,[sp,#armreg_fp]      // saved FP
        str     r3,[sp,#armreg_ip]      // saved IP
        str     r4,[sp,#armreg_pc]      // PC at time of interrupt
        str     lr,[sp,#armreg_lr]      // LR at time of interrupt
        str     fp,[sp,#armreg_sp]      // SP at time of interrupt
        mov     r0,#CYGNUM_HAL_VECTOR_IRQ       // FIXME: we don't distinguish
        str     r0,[sp,#armreg_vector]          // FIQ and IRQ here
        mov     v6,sp                   // Save pointer to register frame

//      mov     r0,sp
//      bl      _show_frame_in

#ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
        // Switch to interrupt stack
        ldr     r2,.irq_level           // current number of nested interrupts
        ldr     r0,[r2]
        add     r1,r0,#1
        str     r1,[r2]                 // if was zero, switch stacks
        cmp     r0,#0
        moveq   r1,sp                   // save old stack pointer
        ldreq   sp,.__interrupt_stack
        stmeqfd sp!,{r1}
10:
#endif

        // The entire CPU state is now stashed on the stack,
        // increment the scheduler lock and handle the interrupt

#ifdef CYGFUN_HAL_COMMON_KERNEL_SUPPORT                 
        .extern cyg_scheduler_sched_lock
        ldr     r3,.cyg_scheduler_sched_lock
        ldr     r4,[r3]
        add     r4,r4,#1
        str     r4,[r3]
#endif

        THUMB_MODE(r3,10)

        mov     r0,v6
        bl      hal_IRQ_handler         // determine interrupt source
        mov     v1,r0                   // returned vector #

#if defined(CYGPKG_KERNEL_INSTRUMENT) && \
    defined(CYGDBG_KERNEL_INSTRUMENT_INTR)
        ldr     r0,=RAISE_INTR          // arg0 = type = INTR,RAISE
        mov     r1,v1                   // arg1 = vector
        mov     r2,#0                   // arg2 = 0
        bl      cyg_instrument          // call instrument function
#endif

        ARM_MODE(r0,10)

        mov     r0,v1                   // vector #

#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 save interrupt state here so that we can
        // plant a breakpoint at some later time.

       .extern  hal_saved_interrupt_state
        ldr     r2,=hal_saved_interrupt_state
        str     v6,[r2]
#endif

        cmp     r0,#CYGNUM_HAL_INTERRUPT_NONE   // spurious interrupt
        bne     10f
#ifndef CYGIMP_HAL_COMMON_INTERRUPTS_IGNORE_SPURIOUS
        mov     r0,v6                   // register frame
        bl      hal_spurious_IRQ
#endif // CYGIMP_HAL_COMMON_INTERRUPTS_IGNORE_SPURIOUS
        b       spurious_IRQ
        
10:     ldr     r1,.hal_interrupt_data
        ldr     r1,[r1,v1,lsl #2]       // handler data
        ldr     r2,.hal_interrupt_handlers
        ldr     v3,[r2,v1,lsl #2]       // handler (indexed by vector #)
        mov     r2,v6                   // register frame (this is necessary
                                        // for the ISR too, for ^C detection)

#ifdef __thumb__
        ldr     lr,=10f
        bx      v3                      // invoke handler (thumb mode)
        .pool
        .code   16
        .thumb_func
IRQ_10T:
10:     ldr     r2,=15f
        bx      r2                      // switch back to ARM mode
        .pool
        .code   32
15:
IRQ_15A:
#else
        mov     lr,pc                   // invoke handler (call indirect
        mov     pc,v3                   // thru v3)
#endif

spurious_IRQ:           

#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.
        ldr     r2,.irq_level
        ldr     r3,[r2]
        subs    r1,r3,#1
        str     r1,[r2]
        ldreq   sp,[sp]         // This should be the saved stack pointer
#endif
#ifdef CYGFUN_HAL_COMMON_KERNEL_SUPPORT
        // The return value from the handler (in r0) 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.

                              // don't run this for spurious interrupts!
        cmp     v1,#CYGNUM_HAL_INTERRUPT_NONE
        beq     17f
        ldr     r1,.hal_interrupt_objects
        ldr     r1,[r1,v1,lsl #2]
        mov     r2,v6           // register frame

        THUMB_MODE(r3,10)

        bl      interrupt_end   // post any bottom layer handler
                                // threads and call scheduler
        ARM_MODE(r1,10)
17:
#endif

//      mov     r0,sp
//      bl      show_frame_out

        mov     ip,sp                   // get stack pointer

        mrs     r0,cpsr                 // move back to IRQ mode
        orr     r0,r0,#CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE
        msr     cpsr,r0
        nop
        nop

        ldr     lr,[ip,#armreg_lr]
        ldr     sp,[sp,#armreg_sp]
                        
        bic     r0,r0,#CPSR_MODE_BITS
        orr     r0,r0,#CPSR_IRQ_MODE
        msr     cpsr,r0

        mov     sp,ip
        ldr     lr,[sp,#armreg_pc]
        ldr     r0,[sp,#armreg_cpsr]
        ldr     ip,[sp,#armreg_ip]
        msr     spsr,r0
        ldmfd   sp,{r0-r10,fp}
#ifdef GAMEBOY_ADVANCE // Change #10 
        ldr     sp,.__exception_stack   // restore good stack
#endif
        movs    pc,lr                   // restore PC from LR, CPSR from SPSR

#ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
// Execute pending DSRs the interrupt stack
// Note: this can only be called from code running on a thread stack
FUNC_START_ARM(hal_interrupt_stack_call_pending_DSRs, r1)
        stmfd   sp!,{r4,r5,lr}
        // Disable interrupts
        mrs     r4,cpsr                 // disable IRQ's
        orr     r2,r4,#CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE
        bic     r5,r4,#CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE
        msr     cpsr,r2
        // Switch to interrupt stack
        mov     r3,sp                   // save old stack pointer
        ldr     sp,.__interrupt_stack
        stmfd   sp!,{r3}                // stored at top of interrupt stack
        ldr     r2,.irq_level           // current number of nested interrupts
        ldr     r3,[r2]
        add     r3,r3,#1                // bump nesting level
        str     r3,[r2]
        msr     cpsr,r5                 // enable interrupts

        THUMB_MODE(r1,20)

        bl      cyg_interrupt_call_pending_DSRs


        ARM_MODE(r1,22)

        // Disable interrupts
        mrs     r1,cpsr                 // disable IRQ's
        orr     r2,r1,#CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE
        msr     cpsr,r2

        // Move back to the thread stack.
        ldr     r2,.irq_level
        ldr     r3,[r2]
        sub     r3,r3,#1                // decrement nesting level
        str     r3,[r2]
        ldr     sp,[sp]                 // This should be the saved stack pointer
        msr     cpsr,r4                 // restore interrupts to original state

#ifdef __thumb__
        ldmfd   sp!,{r4,r5,lr}          // return
        bx      lr
#else
        ldmfd   sp!,{r4,r5,pc}          // return
#endif // __thumb__
#endif // CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
        
// Thumb-only support functions
#ifdef __thumb__

FUNC_START_ARM(hal_disable_interrupts, r1)
        mrs     r0,cpsr                 // current state
        orr     r1,r0,#0xC0             // mask both FIQ and IRQ
        msr     cpsr,r1
        bx      lr                      // exit, _old_ in r0        

FUNC_START_ARM(hal_enable_interrupts, r1)
        mrs     r0,cpsr                 // current state
        bic     r1,r0,#0xC0             // mask both FIQ and IRQ
        msr     cpsr,r1
        bx      lr                      // exit
        
FUNC_START_ARM(hal_restore_interrupts, r1)
        mrs     r1,cpsr                 // current state
        bic     r1,r1,#0xC0             // mask out FIQ/IRQ bits
        and     r0,r0,#0xC0             // keep only FIQ/IRQ
        orr     r1,r1,r0                // mask both FIQ and IRQ
        msr     cpsr,r1
        bx      lr                      // exit        

FUNC_START_ARM(hal_query_interrupts, r1)
        mrs     r0,cpsr                 // current state
        bx      lr                      // exit, state in r0

#endif // __thumb__

// Dummy/support functions

        .global __gccmain
        .global _psr
        .global _sp

#ifdef __thumb__
        .code   16
        .thumb_func
__gccmain:
        bx      lr

        .code   16
        .thumb_func
_psr:
        ARM_MODE(r1,10)
        mrs     r0,cpsr
        bx      lr

        .code   16
        .thumb_func
_sp:
        mov     r0,sp
        bx      lr
#else
__gccmain:
        mov     pc,lr   

_psr:
        mrs     r0,cpsr
        mov     pc,lr

_sp:
        mov     r0,sp
        mov     pc,lr
#endif                


//
// Pointers to various objects.
//
#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
PTR(__GDB_stack_base)
PTR(__GDB_stack)
#endif
PTR(__startup_stack)
PTR(__exception_stack)
PTR(__undef_exception_stack)
PTR(__bss_start)
PTR(__bss_end)
PTR(_end)
PTR(__rom_data_start)
PTR(__ram_data_start)
PTR(__ram_data_end)
PTR(hal_interrupt_handlers)
PTR(hal_interrupt_data)
PTR(hal_interrupt_objects)
PTR(__exception_handlers)
PTR(init_flag)
#ifdef CYGFUN_HAL_COMMON_KERNEL_SUPPORT
PTR(cyg_scheduler_sched_lock)
#endif
#ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
PTR(irq_level)
PTR(__interrupt_stack)
#endif
#if defined(GAMEBOY_ADVANCE) && defined(CYG_HAL_STARTUP_ROM) // Change #11 
PTR(hal_patch_vector_code)
#endif

//
// Identification - useful to find out when a system was configured
_eCos_id:
        .asciz  "eCos : " __DATE__


// -------------------------------------------------------------------------
// Interrupt vector tables.
// These tables contain the isr, data and object pointers used to deliver
// interrupts to user code.

// Despite appearances, their sizes are not #defines, but .equ symbols
// generated by magic without proper dependencies in arm.inc
// Recompiling will not DTRT without manual intervention.

        .data

init_flag:
        .balign 4
        .long   0

        .extern hal_default_isr

        .globl  hal_interrupt_handlers
hal_interrupt_handlers:
        .rept   CYGNUM_HAL_ISR_COUNT
        .long   hal_default_isr
        .endr

        .globl  hal_interrupt_data
hal_interrupt_data:
        .rept   CYGNUM_HAL_ISR_COUNT
        .long   0
        .endr

        .globl  hal_interrupt_objects
hal_interrupt_objects:
        .rept   CYGNUM_HAL_ISR_COUNT
        .long   0
        .endr

// -------------------------------------------------------------------------
// Temporary interrupt stack
        
        .section ".bss"

// Small stacks, only used for saving information between CPU modes
__exception_stack_base: 
        .rept   32
        .long   0
        .endr
__exception_stack:
        .rept   32
        .long   0
        .endr
__undef_exception_stack:

// Runtime stack used during all interrupt processing
#ifndef CYGNUM_HAL_COMMON_INTERRUPTS_STACK_SIZE
#define CYGNUM_HAL_COMMON_INTERRUPTS_STACK_SIZE 4096
#endif
#ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
        .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:
irq_level:
        .long   0
#endif

#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
        .balign 16
__GDB_stack_base:
        .rept CYGNUM_HAL_COMMON_INTERRUPTS_STACK_SIZE // rather than 1k
        .byte 0
        .endr
__GDB_stack:
#endif
        .balign 16
__startup_stack_base:
#ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
        .rept 512
#else
        .rept CYGNUM_HAL_COMMON_INTERRUPTS_STACK_SIZE
#endif
        .byte 0
        .endr
        .balign 16
__startup_stack:

#ifdef PLATFORM_EXTRAS
#include PLATFORM_EXTRAS
#endif                                

// --------------------------------------------------------------------------
//  end of vectors.S

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]