.nolist .psize 0 /* * Copyright (C) 2005-2006 by egnite Software GmbH * Copyright (C) 2011 by egnite GmbH * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS 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. * * For additional information see http://www.ethernut.de/ */ /* * $Id$ */ #include .list /* * This file contains the runtime initialization for AT91X40 based systems. * It replaces the older crtat91_rom.S, which is now deprecated. * * The related linker file is at91x40_rom.ld. * * Code is running in Flash memory, which also contains all constant data. * Internal RAM is used for variables and may be used for functions, * which require to run at maximum speed. * * Tested on AT91R40008 only. * */ /* * Stack sizes. * * Interrupt nesting is currently not supported. Therefore dedicated * stacks are used for all exceptions. */ #ifndef INI_STACK_SIZE #define INI_STACK_SIZE (128 * 4) #endif #ifndef IRQ_STACK_SIZE #define IRQ_STACK_SIZE (128 * 4) #endif #ifndef FIQ_STACK_SIZE #define FIQ_STACK_SIZE (64 * 4) #endif #ifndef EXC_STACK_SIZE #define EXC_STACK_SIZE (32 * 4) #endif #define TOTAL_STACK_SIZE (INI_STACK_SIZE + IRQ_STACK_SIZE + FIQ_STACK_SIZE + EXC_STACK_SIZE) /* We start in ARM mode. */ .arm /* * Vector Section: Must be copied to RAM during runtime. */ .section .vectors,"ax",%progbits /* * After reset these vectors are located at the beginning of * flash memory, which starts at address 0x00000000. After * remap, flash will be relocated at 0x10000000 and these * vectors are copied to the RAM base address, which will * be remapped to address 0x00000000. * * Actually this is overdone. With weakly defined exception * pointers and auto vectoring interrupts there is no need * to modify the vector table. Keeping the Flash at address * 0x00000000 would protect the system against overwriting * exception vectors with NULL pointers. Unfortunately, the * remap command is required to configure the AT91X40 chip * selects. * * Note, that we must use relative addressing for all code * proceeding the remap. While the linker will put this * code at address 0x10000000, it will actually start * running at address 0x00000000. */ .global __vectors __vectors: /* Reset entry. */ b _start /* Undefined instruction exception entry. */ ldr pc, [pc, #(5 * 4)] /* Software interrupt entry. */ ldr pc, [pc, #(5 * 4)] /* Prefetch abort exception entry. */ ldr pc, [pc, #(5 * 4)] /* Data abort exception entry. */ ldr pc, [pc, #(5 * 4)] /* * Reserved entry, used by some boot loaders to store the * size of the binary image. */ .word 0 /* * On IRQ/FIQ the PC will be loaded from AIC_IVR, which * provides the address previously set in AIC_SVR(). * The interrupt routine will be called in ARM_MODE_IRQ * with IRQ disabled and FIQ unchanged. */ ldr pc, [pc, #-0xF20] ldr pc, [pc, #-0xF20] /* * Exceptions are weakly linked to endless loops. * * This may look a bit confusing. The following words contain * the jump addresses that are loaded at each entry, see above. * They contain weakly defined addresses pointing to executable * code. Each of them may be overridden by the operating system * or the application, if a function with the same name exist. * By default they simply point to endless loops. * * We intentionally use a dedicated loop with a global label * for each exception. If an unhandled exception occurs, we * can use a simple debugger (like OpenOCD) to retrieve the * current program counter and check the linker map to determine * the type of the exception. */ .word __undef .word __swi .word __prefetch_abort .word __data_abort .weak __undef, __swi, __prefetch_abort, __data_abort .set __undef, __undef_stop .set __swi, __swi_stop .set __prefetch_abort, __prefetch_abort_stop .set __data_abort, __data_abort_stop /* * Init Section 0: Exception Dummies. */ .section .init0,"ax",%progbits __undef_stop: b __undef_stop __swi_stop: b __swi_stop __prefetch_abort_stop: b __prefetch_abort_stop __data_abort_stop: b __data_abort_stop /* Make sure that the literal pool is empty before the section ends. */ .ltorg /* * User Init Section 0 * * Additional code may be added here by placing functions in * section .init0.user. Only relocatable code is allowed. * * Memory test routines are good candidates. */ .global _start _start: /* * Init Section 1: Remapping. */ .section .init1,"ax",%progbits /* * Disable interrupts and switch to supervisor mode. This is * actually the same state as after hardware reset. We explicitly * set it here for debugging. It may not be possible to halt the * CPU at address zero immediately after reset. In this case we * can use the debugger to reset the PC to zero or to this address * and resume. */ msr CPSR_c, #ARM_MODE_SVC | ARM_CPSR_I_BIT | ARM_CPSR_F_BIT /* * Move vectors from Flash to RAM. */ mov r0, #0x00000000 mov r1, #0x00300000 ldmia r0!, {r2-r7} stmia r1!, {r2-r7} ldmia r0!, {r2-r7} stmia r1!, {r2-r7} /* * Remapping memory. * * A bit tricky for newbies. The ldmia opcode loads the complete * table including the EBI base address in r10 and the jump * address into our remapped flash memory in r11. Immediately * after remap our code moved to 0x10000000, but the next opcode * 'move pc,r11' is still in the instruction pipeline and will * be executed. * * ARM assembler programming is wonderful, isn't it? */ adr r12, _rmap_tab ldmia r12!, {r0-r11} stmia r10!, {r0-r9} /* After remap, this is still in the pipeline. */ mov pc, r11 _rmap_tab: /* * Chip select NCS0 enables 16-bit Flash memory at 0x10000000. * We need 4 wait states. */ .word 0x10000000 | EBI_CSEN | EBI_PAGES_16M | EBI_WSE | EBI_NWS_4 | EBI_DBW_16 /* * Chip select NCS1 enables 16-bit Ethernet controller at 0x20000000. * We need 3 wait states. */ .word 0x20000000 | EBI_CSEN | EBI_BAT_BYTE_SELECT | EBI_PAGES_1M | EBI_WSE | EBI_NWS_3 | EBI_DBW_16 /* * Chip select NCS2 selects 8-bit NPL registers at 0x21000000. * The CPLD is quite fast and may run at one or zero wait states. * This pin is shared with GPIO pin 26. */ .word 0x21000000 | EBI_CSEN | EBI_PAGES_1M | EBI_WSE | EBI_NWS_2 | EBI_DBW_8 /* * Chip select NCS3 is not used. * This pin os shared with GPIO pin 27 and available at the expansion port. */ .word 0x30000000 /* * Chip select CS4 selects the 8-bit NPL expansion bus at 0x22000000. * This pin is shared with GPIO pin 31 and address bit 23. */ .word 0x22000000 | EBI_CSEN | EBI_TDF_7 | EBI_PAGES_1M | EBI_WSE | EBI_NWS_8 | EBI_DBW_8 /* * Chip select CS5 is not used. * This pin is shared with GPIO pin 30 and address bit 22. */ .word 0x50000000 /* * Chip select CS6 is not available, but used as address bit 21. */ .word 0x60000000 /* * Chip select CS7 is not available, but used as address bit 20. */ .word 0x70000000 /* * EBI remap command. */ .word EBI_RCB /* * Maximum address space of 4 MBytes per chip select. * This occupies A0 to A21. */ .word EBI_ALE_4M /* * EBI base address. */ .word EBI_BASE /* * Jump after relocation. */ .word _init_rt /* Make sure that the literal pool is empty before the section ends. */ .ltorg /* * User Init Section 1 * * Additional code may be added here by placing functions in * section .init1.user. CPU is running in relocated Flash. */ _init_rt: /* * Init Section 2: Set stack pointers and initialize C variables. */ .section .init2,"ax",%progbits /* * Set stack pointers with disabled interrupts. */ ldr r0, =__stack msr CPSR_c, #ARM_MODE_SVC | ARM_CPSR_I_BIT | ARM_CPSR_F_BIT mov sp, r0 sub r0, r0, #INI_STACK_SIZE msr CPSR_c, #ARM_MODE_FIQ | ARM_CPSR_I_BIT | ARM_CPSR_F_BIT mov sp, r0 sub r0, r0, #FIQ_STACK_SIZE msr CPSR_c, #ARM_MODE_IRQ | ARM_CPSR_I_BIT | ARM_CPSR_F_BIT mov sp, r0 sub r0, r0, #IRQ_STACK_SIZE msr CPSR_c, #ARM_MODE_ABORT | ARM_CPSR_I_BIT | ARM_CPSR_F_BIT mov sp, r0 msr CPSR_c, #ARM_MODE_UNDEF | ARM_CPSR_I_BIT | ARM_CPSR_F_BIT mov sp, r0 /* * Nut/OS system and application are running in system mode. * Note, that we re-use the supervisory stack. */ msr CPSR_c, #ARM_MODE_SYS | ARM_CPSR_I_BIT | ARM_CPSR_F_BIT ldr r0, =__stack mov sp, r0 /* * Clear bss. */ ldr r1, =__bss_start ldr r2, =__bss_end ldr r3, =0 1: cmp r1, r2 strne r3, [r1], #+4 bne 1b /* * Copy data and RAM functions from Flash to RAM. */ ldr r0, =__data_load_start ldr r1, =__data_start ldr r2, =__data_end subs r2, r2, r1 beq _init_hw 1: ldr r3, [r0], #4 str r3, [r1], #4 subs r2, r2, #4 bne 1b /* Jump over the literal pool. */ b _init_hw /* Make sure that the literal pool is empty before the section ends. */ .ltorg /* * User Init Section 2 * * Additional code may be added here by placing functions in * section .init2.user. * * This section may be used for early hardware initialization * routines written in C. */ _init_hw: /* * Init Section 3: Hardware initialization. */ .section .init3,"ax",%progbits /* * Enable all clocks. */ mvn r0, #0 ldr r1, =PS_BASE str r0, [r1, #(PS_PCER - PS_BASE)] /* * Initialize the interrupt controller. */ add r0, pc,#-(8 + . - __aic_table) ldmia r0, {r1-r4} str r4, [r1, #AIC_SPU] mov r0, #8 1: str r1, [r1, #AIC_EOICR] subs r0, r0, #1 bhi 1b str r2, [r1, #AIC_SVR(0)] add r1, r1, #AIC_SVR(0) mov r0, #31 1: str r3, [r1, r0, LSL #2] subs r0, r0, #1 bhi 1b b _enter_rtos __aic_table: .word AIC_BASE .word _irq_dummy .word _irq_dummy .word _irq_dummy /* Interrupt dummy. */ .global _irq_dummy _irq_dummy: b _irq_dummy /* Make sure that the literal pool is empty before the section ends. */ .ltorg /* * User Init Section 3 * * Additional code may be added here by placing functions in * section .init3.user. * * This section may be used for additional hardware initialization * routines written in C. Native interrupt routines may be used. */ _enter_rtos: /* * Init Section 4: Enter system. */ .section .init4,"ax",%progbits /* Jump to Nut/OS initialization. */ ldr r0, =NutInit mov lr, pc bx r0 /* * Exit Section 0: Endless loop. */ .section .exit0,"ax",%progbits 1: b 1b /* * Stack Section. */ .section .stack, "w", %nobits .space TOTAL_STACK_SIZE