8983fcb5f2
Bootloader builds, normal does not. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@20574 a1c6a512-1295-4272-9138-f99709370657
274 lines
9.5 KiB
ArmAsm
274 lines
9.5 KiB
ArmAsm
/***************************************************************************
|
|
* __________ __ ___.
|
|
* 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
|