/* ****************************************************************************************************** */ /* crt.s */ /* */ /* Assembly Language Startup Code for Atmel AT91SAM7S256 */ /* */ /* */ /* */ /* */ /* Author: James P Lynch May 12, 2007 */ /* ****************************************************************************************************** */ /* Stack Sizes */ .set UND_STACK_SIZE, 0x00000010 /* stack for "undefined instruction" interrupts is 16 bytes */ .set ABT_STACK_SIZE, 0x00000010 /* stack for "abort" interrupts is 16 bytes */ .set FIQ_STACK_SIZE, 0x00000080 /* stack for "FIQ" interrupts is 128 bytes */ .set IRQ_STACK_SIZE, 0X00000080 /* stack for "IRQ" normal interrupts is 128 bytes */ .set SVC_STACK_SIZE, 0x00000080 /* stack for "SVC" supervisor mode is 128 bytes */ /* Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs (program status registers) */ .set ARM_MODE_USR, 0x10 /* Normal User Mode */ .set ARM_MODE_FIQ, 0x11 /* FIQ Processing Fast Interrupts Mode */ .set ARM_MODE_IRQ, 0x12 /* IRQ Processing Standard Interrupts Mode */ .set ARM_MODE_SVC, 0x13 /* Supervisor Processing Software Interrupts Mode */ .set ARM_MODE_ABT, 0x17 /* Abort Processing memory Faults Mode */ .set ARM_MODE_UND, 0x1B /* Undefined Processing Undefined Instructions Mode */ .set ARM_MODE_SYS, 0x1F /* System Running Priviledged Operating System Tasks Mode */ .set I_BIT, 0x80 /* when I bit is set, IRQ is disabled (program status registers) */ .set F_BIT, 0x40 /* when F bit is set, FIQ is disabled (program status registers) */ /* Addresses and offsets of AIC and PIO */ .set AT91C_BASE_AIC, 0xFFFFF000 /* (AIC) Base Address */ .set AT91C_PIOA_CODR, 0xFFFFF434 /* (PIO) Clear Output Data Register */ .set AT91C_AIC_IVR, 0xFFFFF100 /* (AIC) IRQ Interrupt Vector Register */ .set AT91C_AIC_FVR, 0xFFFFF104 /* (AIC) FIQ Interrupt Vector Register */ .set AIC_IVR, 256 /* IRQ Vector Register offset from base above */ .set AIC_FVR, 260 /* FIQ Vector Register offset from base above */ .set AIC_EOICR, 304 /* End of Interrupt Command Register */ /* identify all GLOBAL symbols */ .global _vec_reset .global _vec_undef .global _vec_swi .global _vec_pabt .global _vec_dabt .global _vec_rsv .global _vec_irq .global _vec_fiq .global AT91F_Irq_Handler .global AT91F_Fiq_Handler .global AT91F_Default_FIQ_handler .global AT91F_Default_IRQ_handler .global AT91F_Spurious_handler .global AT91F_Dabt_Handler .global AT91F_Pabt_Handler .global AT91F_Undef_Handler /* GNU assembler controls */ .text /* all assembler code that follows will go into .text section */ .arm /* compile for 32-bit ARM instruction set */ .align /* align section on 32-bit boundary */ /* ============================================================ */ /* VECTOR TABLE */ /* */ /* Must be located in FLASH at address 0x00000000 */ /* */ /* Easy to do if this file crt.s is first in the list */ /* for the linker step in the makefile, e.g. */ /* */ /* $(LD) $(LFLAGS) -o main.out crt.o main.o */ /* */ /* ============================================================ */ _vec_reset: b _init_reset /* RESET vector - must be at 0x00000000 */ _vec_undef: b AT91F_Undef_Handler /* Undefined Instruction vector */ _vec_swi: b _vec_swi /* Software Interrupt vector */ _vec_pabt: b AT91F_Pabt_Handler /* Prefetch abort vector */ _vec_dabt: b AT91F_Dabt_Handler /* Data abort vector */ _vec_rsv: nop /* Reserved vector */ _vec_irq: b AT91F_Irq_Handler /* Interrupt Request (IRQ) vector */ _vec_fiq: /* Fast interrupt request (FIQ) vector */ /* ======================================================================== */ /* Function: AT91F_Fiq_Handler */ /* */ /* The FIQ interrupt asserts when switch SW1 is pressed. */ /* */ /* This simple FIQ handler turns on LED3 (Port PA2). The LED3 will be */ /* turned off by the background loop in main() thus giving a visual */ /* indication that the interrupt has occurred. */ /* */ /* This FIQ_Handler supports non-nested FIQ interrupts (a FIQ interrupt */ /* cannot itself be interrupted). */ /* */ /* The Fast Interrupt Vector Register (AIC_FVR) is read to clear the */ /* interrupt. */ /* */ /* A global variable FiqCount is also incremented. */ /* */ /* Remember that switch SW1 is not debounced, so the FIQ interrupt may */ /* occur more than once for a single button push. */ /* */ /* Programmer: James P Lynch */ /* ======================================================================== */ AT91F_Fiq_Handler: /* Adjust LR_irq */ sub lr, lr, #4 /* Read the AIC Fast Interrupt Vector register to clear the interrupt */ ldr r12, =AT91C_AIC_FVR ldr r11, [r12] /* Return from Fiq interrupt */ movs pc, lr /* ======================================================================== */ /* _init_reset Handler */ /* */ /* RESET vector 0x00000000 branches to here. */ /* */ /* ARM microprocessor begins execution after RESET at address 0x00000000 */ /* in Supervisor mode with interrupts disabled! */ /* */ /* _init_reset handler: creates a stack for each ARM mode. */ /* sets up a stack pointer for each ARM mode. */ /* turns off interrupts in each mode. */ /* leaves CPU in SYS (System) mode. */ /* */ /* block copies the initializers to .data section */ /* clears the .bss section to zero */ /* */ /* branches to main( ) */ /* ======================================================================== */ .text /* all assembler code that follows will go into .text section */ .align /* align section on 32-bit boundary */ _init_reset: /* Setup a stack for each mode with interrupts initially disabled. */ ldr r0, =_stack_end /* r0 = top-of-stack */ msr CPSR_c, #ARM_MODE_UND|I_BIT|F_BIT /* switch to Undefined Instruction Mode */ mov sp, r0 /* set stack pointer for UND mode */ sub r0, r0, #UND_STACK_SIZE /* adjust r0 past UND stack */ msr CPSR_c, #ARM_MODE_ABT|I_BIT|F_BIT /* switch to Abort Mode */ mov sp, r0 /* set stack pointer for ABT mode */ sub r0, r0, #ABT_STACK_SIZE /* adjust r0 past ABT stack */ msr CPSR_c, #ARM_MODE_FIQ|I_BIT|F_BIT /* switch to FIQ Mode */ mov sp, r0 /* set stack pointer for FIQ mode */ sub r0, r0, #FIQ_STACK_SIZE /* adjust r0 past FIQ stack */ msr CPSR_c, #ARM_MODE_IRQ|I_BIT|F_BIT /* switch to IRQ Mode */ mov sp, r0 /* set stack pointer for IRQ mode */ sub r0, r0, #IRQ_STACK_SIZE /* adjust r0 past IRQ stack */ msr CPSR_c, #ARM_MODE_SVC|I_BIT|F_BIT /* switch to Supervisor Mode */ mov sp, r0 /* set stack pointer for SVC mode */ sub r0, r0, #SVC_STACK_SIZE /* adjust r0 past SVC stack */ msr CPSR_c, #ARM_MODE_SYS|I_BIT|F_BIT /* switch to System Mode */ mov sp, r0 /* set stack pointer for SYS mode */ /* we now start execution in SYSTEM mode */ /* This is exactly like USER mode (same stack) */ /* but SYSTEM mode has more privileges */ /* copy initialized variables .data section (Copy from ROM to RAM) */ ldr R1, =_etext ldr R2, =_data ldr R3, =_edata 1: cmp R2, R3 ldrlo R0, [R1], #4 strlo R0, [R2], #4 blo 1b /* Clear uninitialized variables .bss section (Zero init) */ mov R0, #0 ldr R1, =_bss_start ldr R2, =_bss_end 2: cmp R1, R2 strlo R0, [R1], #4 blo 2b /* Enter the C code */ b main /* ======================================================================== */ /* Function: AT91F_Irq_Handler */ /* */ /* This IRQ_Handler supports nested interrupts (an IRQ interrupt can itself */ /* be interrupted). */ /* */ /* This handler re-enables interrupts and switches to "Supervisor" mode to */ /* prevent any corruption to the link and IP registers. */ /* */ /* The Interrupt Vector Register (AIC_IVR) is read to determine the address */ /* of the required interrupt service routine. The ISR routine can be a */ /* standard C function since this handler minds all the save/restore */ /* protocols. */ /* */ /* */ /* Programmers: */ /*--------------------------------------------------------------------------*/ /* ATMEL Microcontroller Software Support - ROUSSET - */ /*--------------------------------------------------------------------------*/ /* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS */ /* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */ /* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ /* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR */ /* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR */ /* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT */ /* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR */ /* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, */ /* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE */ /* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */ /* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* File source : Cstartup.s79 */ /* Object : Generic CStartup to AT91SAM7S256 */ /* 1.0 09/May/06 JPP : Creation */ /* */ /* */ /* Note: taken from Atmel web site (www.at91.com) */ /* Keil example project: AT91SAM7S-Interrupt_SAM7S */ /* ======================================================================== */ AT91F_Irq_Handler: /* Manage Exception Entry */ /* Adjust and save LR_irq in IRQ stack */ sub lr, lr, #4 stmfd sp!, {lr} /* Save r0 and SPSR (need to be saved for nested interrupt) */ mrs r14, SPSR stmfd sp!, {r0,r14} /* Write in the IVR to support Protect Mode */ /* No effect in Normal Mode */ /* De-assert the NIRQ and clear the source in Protect Mode */ ldr r14, =AT91C_BASE_AIC ldr r0 , [r14, #AIC_IVR] str r14, [r14, #AIC_IVR] /* Enable Interrupt and Switch in Supervisor Mode */ msr CPSR_c, #ARM_MODE_SVC /* Save scratch/used registers and LR in User Stack */ stmfd sp!, { r1-r3, r12, r14} /* Branch to the routine pointed by the AIC_IVR */ mov r14, pc bx r0 /* Manage Exception Exit */ /* Restore scratch/used registers and LR from User Stack */ ldmia sp!, { r1-r3, r12, r14} /* Disable Interrupt and switch back in IRQ mode */ msr CPSR_c, #I_BIT | ARM_MODE_IRQ /* Mark the End of Interrupt on the AIC */ ldr r14, =AT91C_BASE_AIC str r14, [r14, #AIC_EOICR] /* Restore SPSR_irq and r0 from IRQ stack */ ldmia sp!, {r0,r14} msr SPSR_cxsf, r14 /* Restore adjusted LR_irq from IRQ stack directly in the PC */ ldmia sp!, {pc}^ /* ======================================================================== */ /* Function: AT91F_Dabt_Handler */ /* */ /* Entered on Data Abort exception. */ /* Enters blink routine (3 blinks followed by a pause) */ /* processor hangs in the blink loop forever */ /* */ /* ======================================================================== */ AT91F_Dabt_Handler: mov R0, #3 b blinker /* ======================================================================== */ /* Function: AT91F_Pabt_Handler */ /* */ /* Entered on Prefetch Abort exception. */ /* Enters blink routine (2 blinks followed by a pause) */ /* processor hangs in the blink loop forever */ /* */ /* ======================================================================== */ AT91F_Pabt_Handler: mov R0, #2 b blinker /* ======================================================================== */ /* Function: AT91F_Undef_Handler */ /* */ /* Entered on Undefined Instruction exception. */ /* Enters blink routine (1 blinks followed by a pause) */ /* processor hangs in the blink loop forever */ /* */ /* ======================================================================== */ AT91F_Undef_Handler: mov R0, #1 b blinker AT91F_Default_FIQ_handler: b AT91F_Default_FIQ_handler AT91F_Default_IRQ_handler: b AT91F_Default_IRQ_handler AT91F_Spurious_handler: b AT91F_Spurious_handler .end