rockbox/firmware/target/arm/at91sam/lyre_proto1/crt0.S

275 lines
9.5 KiB
ArmAsm
Raw Normal View History

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
*
*
* Copyright (C) 2009 by Jorge Pinto
*
* This program 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
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "at91sam9260.h"
#define DRAMORIG AT91C_EBI_SDRAM_32BIT
#define DRAMSIZE (MEMORYSIZE * 0x100000)
#define IRAM0ORIG AT91C_IRAM_1
#define IRAM0SIZE AT91C_IRAM_1_SIZE
#define TOP_OF_MEMORY (IRAM0ORIG + IRAM0SIZE)
#define ABT_STACK_SIZE 8*3*4
#define IRQ_STACK_SIZE 8*3*4
#define ARM_MODE_ABT 0x17
#define ARM_MODE_FIQ 0x11
#define ARM_MODE_IRQ 0x12
#define ARM_MODE_SVC 0x13
#define I_BIT 0x80
#define F_BIT 0x40
/* Application startup entry point */
.globl reset_handler
.align 4
.section .vectors
.arm
/* Exception vectors (should be a branch to be detected as a valid code
* by the rom) */
_exception_vectors:
reset_vector:
ldr pc, =reset_handler
undef_vector:
b undef_vector /* Undefined Instruction */
swi_vector:
b swi_vector /* Software Interrupt */
pabt_vector:
ldr pc, =pabt_handler /* Prefetch Abort */
dabt_vector:
ldr pc, =dabt_handler /* Data Abort */
rsvd_vector:
b rsvd_vector /* reserved */
irq_vector:
b irq_handler /* IRQ : read the AIC */
fiq_vector:
/*-----------------------------------------------------------------------------
*- Function : fiq_handler
*- Treatments : FIQ (Fast Interrupt) Interrupt Handler.
*- Called Functions :
*---------------------------------------------------------------------------*/
fiq_handler:
pabt_handler:
dabt_handler:
b fiq_handler
/*-----------------------------------------------------------------------------
*- Function : irq_handler
*- Treatments : IRQ Controller Interrupt Handler.
*- Called Functions : AIC_IVR[interrupt]
*---------------------------------------------------------------------------*/
irq_handler:
/*- Manage Exception Entry */
/*- Adjust and save LR_irq in IRQ stack - (LR - Link Register) */
sub lr, lr, #4
stmfd sp!, {lr}
/*- Save r0 and SPSR (Saved Program Status Register) in IRQ stack */
mrs r14, SPSR
stmfd sp!, {r0,r14}
/*- Write in the IVR (Interrupt Vector Register) 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
/*- 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, #ARM_MODE_IRQ | I_BIT
/*- 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 : reset_handler
*- Treatments : Reset Interrupt Handler.
*- Called Functions : lowlevel_init
* main
*---------------------------------------------------------------------------*/
.section .text
reset_handler:
/*-----------------------------------------------------------------------------
*- Low level Init is performed in a C function: lowlevel_init
*- Init Stack Pointer to a valid memory area before calling lowlevel_init
*
* Put Stack Pointer on end of IRAM 1 and branches to lowlevel_init function.
*---------------------------------------------------------------------------*/
/*- Temporary stack in internal RAM for Low Level Init execution */
_low_level_init:
ldr r2, =_litteral_pool_lowlevel_init /* Load r2 with the address of
* _litteral_pool_lowlevel_init
*/
ldmia r2, {r0, r1} /* r0 = lowlevel_init and r1 = TOP_OF_MEMORY */
mov sp, r1 /* sp (Stack Pointer) = TOP_OF_MEMORY (end of IRAM 1) */
mov lr, pc /* lr (Link register) = pc (Program Counter) */
bx r0 /* Branch on C function (interworking) -- branch to
* lowlevel_init
*/
/*-----------------------------------------------------------------------------
*- Setup the stack for each mode
*
* Executes this code after returning from lowlevel_init fucntion.
* Configures Abort Mode Stack + Interrupt Mode Stack + Supervisor Mode Stack,
* reserves 3 blocks, one for each mode and they start at end of IRAM 1.
*---------------------------------------------------------------------------*/
_stack_init:
ldr r2, =_litteral_pool_stack_init
ldmia r2, {r0, r1, r2} /* r0 = TOP_OF_MEMORY (end of IRAM 1);
* r1 = ABT_STACK_SIZE;
* r2 = IRQ_STACK_SIZE
*/
/*- Set up Abort Mode and set ABT Mode Stack */
msr CPSR_c, #ARM_MODE_ABT | I_BIT | F_BIT /* Enter in Mode Abort
* and disable IRQ (Interrupt) and FIQ (Fast Interrupt)
*/
mov sp, r0 /* sp (ABT Mode Stack Pointer) = TOP_OF_MEMORY
* (end of IRAM 1)
*/
/* put r0 with value of the new address for next Stack */
sub r0, r0, r1 /* r0 = r0 - r1 --> r0 = (end of IRAM 1) -
* (ABT_STACK_SIZE)
*/
/*- Set up Interrupt Mode and set IRQ Mode Stack */
msr CPSR_c, #ARM_MODE_IRQ | I_BIT | F_BIT /* Enter in Mode Interrupt
* and disable IRQ (Interrupt) and FIQ (Fast Interrupt)
*/
mov sp, r0 /* sp (Interrupt Mode Stack Pointer) =
* TOP_OF_MEMORY (end of IRAM 1) - (ABT_STACK_SIZE)
*/
sub r0, r0, r2 /* Put on r0 the new address for next
* Stack (Supervisor Mode)
*/
/*- Enable interrupt & Set up Supervisor Mode and set Supervisor Mode Stack */
msr CPSR_c, #ARM_MODE_SVC | F_BIT
mov sp, r0
/*-----------------------------------------------------------------------------
*- Segments initialization
*---------------------------------------------------------------------------*/
/* Copy the vectors section code from the LMA address to the LVA address */
_init_vectors:
ldr r1, =_litteral_pool_vectors /* Load r1 with the address of
* _litteral_pool_vectors
*/
ldmia r1, {r2, r3, r4} /* r2 = DRAMORIG; r3 = _start_vectors_section;
* r4 = _end_vectors_section;
*/
1:
cmp r3, r4 /* Compare r3 with r4 (r3 - r4) */
ldrcc r5, [r2], #4 /* if (_start_vectors_section < _end_vectors_section)
* { r5 = [r2]; r2 = r2 + 4; }
*/
strcc r5, [r3], #4 /* if (_start_vectors_section < _end_vectors_section)
* { [r3] = r5; r3 = r3 + 4; }
*/
bcc 1b /* loop while (_start_vectors_section < _end_vectors_section) */
/* Clear the bss segment */
_init_bss:
ldr r2, =_litteral_pool_bss
ldmia r2, {r3, r4} /* r3 = _start_bss_section; r4 = _end_bss_section */
mov r2, #0 /* r2 = 0 */
1:
cmp r3, r4 /* Compare --> (_start_bss_section - _end_bss_section) */
strcc r2, [r3], #4 /* if (_start_bss_section < _end_bss_section) {
* [r3] = 0; r3 = r3 + 4; }
*/
bcc 1b /* loop while _start_bss_section < _end_bss_section */
/* Set up some stack and munge it with 0xdeadbeef */
ldr sp, =stackend
mov r3, sp
ldr r2, =stackbegin
ldr r4, =0xdeadbeef
stackmunge:
cmp r3, r2
strhi r4, [r2], #4
bhi stackmunge
/*-----------------------------------------------------------------------------
*- Branch to the main
*---------------------------------------------------------------------------*/
_branch_main:
ldr r0, =main
mov lr, pc
bx r0
/*-----------------------------------------------------------------------------
*- Litteral pools
*---------------------------------------------------------------------------*/
_litteral_pool_lowlevel_init:
.word lowlevel_init
.word TOP_OF_MEMORY /* Default SVC stack after power up */
_litteral_pool_stack_init:
.word TOP_OF_MEMORY /* Top of the stack */
.word ABT_STACK_SIZE /* ABT stack size */
.word IRQ_STACK_SIZE /* IRQ stack size */
_litteral_pool_bss:
.word _start_bss_section
.word _end_bss_section
_litteral_pool_vectors:
#if defined(BOOTLOADER)
.word (DRAMORIG + DRAMSIZE - 0x100000) /* LMA address of vectors are at
* end of DRAM minus 1MByte
*/
#else
.word DRAMORIG /* LMA address of vectors are at DRAMORIG */
#endif
.word _start_vectors_section
.word _end_vectors_section