nes-proj/cpu/at91sam7s/startup-SAM7S.S
ksb b105b40e9a Added ELF-loader code, should probably eventually end up in core/loader.
Added some replacements for newlib's stdout.
Added missing startup code.
Some minor fixes.
2007-03-07 16:07:25 +00:00

499 lines
16 KiB
ArmAsm

/***********************************************************************/
/* */
/* startup_SAM7S.S: Startup file for Atmel AT91SAM7S device series */
/* */
/***********************************************************************/
/* ported to arm-elf-gcc / WinARM by Martin Thomas, KL, .de */
/* <eversmith@heizung-thomas.de> */
/* modifications Copyright Martin Thomas 2005 */
/* */
/* Based on a file that has been a part of the uVision/ARM */
/* development tools, Copyright KEIL ELEKTRONIK GmbH 2002-2004 */
/***********************************************************************/
/*
Modifications by Martin Thomas:
- added handling of execption vectors in RAM ("ramfunc")
- added options to remap the interrupt vectors to RAM
(see makefile for switch-option)
- replaced all ";" and "#" for comments with // or / * * /
- added C++ ctor handling
- .text in RAM for debugging (RAM_RUN)
*/
/*
Modifications by Simon Berg
- added stack segment
- running program as system by defining RUN_AS_SYSTEM
*/
// mt: this file should not be used with the Configuration Wizard
// since a lot of changes have been done for the WinARM/gcc example
/*
// *** <<< Use Configuration Wizard in Context Menu >>> ***
*/
// *** Startup Code (executed after Reset) ***
// Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs
.equ Mode_USR, 0x10
.equ Mode_FIQ, 0x11
.equ Mode_IRQ, 0x12
.equ Mode_SVC, 0x13
.equ Mode_ABT, 0x17
.equ Mode_UND, 0x1B
.equ Mode_SYS, 0x1F
.equ I_Bit, 0x80 /* when I bit is set, IRQ is disabled */
.equ F_Bit, 0x40 /* when F bit is set, FIQ is disabled */
// Internal Memory Base Addresses
.equ FLASH_BASE, 0x00100000
.equ RAM_BASE, 0x00200000
/*
// <h> Stack Configuration
// <o> Top of Stack Address <0x0-0xFFFFFFFF:4>
// <h> Stack Sizes (in Bytes)
// <o1> Undefined Mode <0x0-0xFFFFFFFF:4>
// <o2> Supervisor Mode <0x0-0xFFFFFFFF:4>
// <o3> Abort Mode <0x0-0xFFFFFFFF:4>
// <o4> Fast Interrupt Mode <0x0-0xFFFFFFFF:4>
// <o5> Interrupt Mode <0x0-0xFFFFFFFF:4>
// <o6> User/System Mode <0x0-0xFFFFFFFF:4>
// </h>
// </h>
*/
.equ Top_Stack, 0x00204000
.equ UND_Stack_Size, 0x00000004
.equ SVC_Stack_Size, 0x00000400
.equ ABT_Stack_Size, 0x00000004
.equ FIQ_Stack_Size, 0x00000004
.equ IRQ_Stack_Size, 0x00000400
.equ USR_Stack_Size, 0x00000400
.bss
.section .stack , "aw", %nobits
USR_Stack_Start:
.skip USR_Stack_Size
USR_Stack_End:
IRQ_Stack_Start:
.skip IRQ_Stack_Size
IRQ_Stack_End:
FIQ_Stack_Start:
.skip FIQ_Stack_Size
FIQ_Stack_End:
ABT_Stack_Start:
.skip ABT_Stack_Size
ABT_Stack_End:
SVC_Stack_Start:
.skip SVC_Stack_Size
SVC_Stack_End:
UND_Stack_Start:
.skip UND_Stack_Size
UND_Stack_End:
// Embedded Flash Controller (EFC) definitions
.equ EFC_BASE, 0xFFFFFF00 /* EFC Base Address */
.equ EFC_FMR, 0x60 /* EFC_FMR Offset */
/*
// <e> Embedded Flash Controller (EFC)
// <o1.16..23> FMCN: Flash Microsecond Cycle Number <0-255>
// <i> Number of Master Clock Cycles in 1us
// <o1.8..9> FWS: Flash Wait State
// <0=> Read: 1 cycle / Write: 2 cycles
// <1=> Read: 2 cycle / Write: 3 cycles
// <2=> Read: 3 cycle / Write: 4 cycles
// <3=> Read: 4 cycle / Write: 4 cycles
// </e>
*/
.equ EFC_SETUP, 1
.equ EFC_FMR_Val, 0x00320100
// Watchdog Timer (WDT) definitions
.equ WDT_BASE, 0xFFFFFD40 /* WDT Base Address */
.equ WDT_MR, 0x04 /* WDT_MR Offset */
/*
// <e> Watchdog Timer (WDT)
// <o1.0..11> WDV: Watchdog Counter Value <0-4095>
// <o1.16..27> WDD: Watchdog Delta Value <0-4095>
// <o1.12> WDFIEN: Watchdog Fault Interrupt Enable
// <o1.13> WDRSTEN: Watchdog Reset Enable
// <o1.14> WDRPROC: Watchdog Reset Processor
// <o1.28> WDDBGHLT: Watchdog Debug Halt
// <o1.29> WDIDLEHLT: Watchdog Idle Halt
// <o1.15> WDDIS: Watchdog Disable
// </e>
*/
.equ WDT_SETUP, 1
.equ WDT_MR_Val, 0x00008000 // Disable watchdog
// Power Mangement Controller (PMC) definitions
.equ PMC_BASE, 0xFFFFFC00 /* PMC Base Address */
.equ PMC_MOR, 0x20 /* PMC_MOR Offset */
.equ PMC_MCFR, 0x24 /* PMC_MCFR Offset */
.equ PMC_PLLR, 0x2C /* PMC_PLLR Offset */
.equ PMC_MCKR, 0x30 /* PMC_MCKR Offset */
.equ PMC_SR, 0x68 /* PMC_SR Offset */
.equ PMC_MOSCEN, (1<<0) /* Main Oscillator Enable */
.equ PMC_OSCBYPASS, (1<<1) /* Main Oscillator Bypass */
.equ PMC_OSCOUNT, (0xFF<<8) /* Main OScillator Start-up Time */
.equ PMC_DIV, (0xFF<<0) /* PLL Divider */
.equ PMC_PLLCOUNT, (0x3F<<8) /* PLL Lock Counter */
.equ PMC_OUT, (0x03<<14) /* PLL Clock Frequency Range */
.equ PMC_MUL, (0x7FF<<16) /* PLL Multiplier */
.equ PMC_USBDIV, (0x03<<28) /* USB Clock Divider */
.equ PMC_CSS, (3<<0) /* Clock Source Selection */
.equ PMC_PRES, (7<<2) /* Prescaler Selection */
.equ PMC_MOSCS, (1<<0) /* Main Oscillator Stable */
.equ PMC_LOCK, (1<<2) /* PLL Lock Status */
/*
// <e> Power Mangement Controller (PMC)
// <h> Main Oscillator
// <o1.0> MOSCEN: Main Oscillator Enable
// <o1.1> OSCBYPASS: Oscillator Bypass
// <o1.8..15> OSCCOUNT: Main Oscillator Startup Time <0-255>
// </h>
// <h> Phase Locked Loop (PLL)
// <o2.0..7> DIV: PLL Divider <0-255>
// <o2.16..26> MUL: PLL Multiplier <0-2047>
// <i> PLL Output is multiplied by MUL+1
// <o2.14..15> OUT: PLL Clock Frequency Range
// <0=> 80..160MHz <1=> Reserved
// <2=> 150..220MHz <3=> Reserved
// <o2.8..13> PLLCOUNT: PLL Lock Counter <0-63>
// <o2.28..29> USBDIV: USB Clock Divider
// <0=> None <1=> 2 <2=> 4 <3=> Reserved
// </h>
// <o3.0..1> CSS: Clock Source Selection
// <0=> Slow Clock
// <1=> Main Clock
// <2=> Reserved
// <3=> PLL Clock
// <o3.2..4> PRES: Prescaler
// <0=> None
// <1=> Clock / 2 <2=> Clock / 4
// <3=> Clock / 8 <4=> Clock / 16
// <5=> Clock / 32 <6=> Clock / 64
// <7=> Reserved
// </e>
*/
.equ PMC_SETUP, 1
.equ PMC_MOR_Val, 0x00000601 /* Enable main oscilator,
48 cycles startup */
.equ PMC_PLLR_Val, 0x00191C05 /* 28 cycles startup,
PLL = 5.2* * main clock */
.equ PMC_MCKR_Val, 0x0000000B /* MCK = PLL/4 */
/* Reset controller */
.equ RSTC_BASE, 0xfffffd00
.equ RSTC_CR, 0x00
.equ RSTC_SR, 0x04
.equ RSTC_MR, 0x08
.equ RSTC_SETUP, 1
.equ RSTC_MR_Val, 0xa5000001 /* Enable user reset */
#if (defined(VECTORS_IN_RAM) && defined(ROM_RUN)) || defined(USE_SAMBA)
/*
Exception Vectors to be placed in RAM - added by mt
-> will be used after remapping in ROM_RUN
-> not needed for RAM_RUN
-> moved to address 0 after remapping
Mapped to Address 0 after remapping in ROM_RUN
Absolute addressing mode must be used.
Dummy Handlers are implemented as infinite loops which can be modified.
VECTORS_IN_RAM defined in makefile/by commandline
*/
.text
.arm
.section .vectram, "ax"
VectorsRAM: LDR PC,Reset_AddrR
LDR PC,Undef_AddrR
LDR PC,SWI_AddrR
LDR PC,PAbt_AddrR
LDR PC,DAbt_AddrR
NOP /* Reserved Vector */
LDR PC,[PC,#-0xF20] /* Vector From AIC_IVR */
LDR PC,[PC,#-0xF20] /* Vector From AIC_FVR */
Reset_AddrR: .word Reset_Handler
Undef_AddrR: .word Undef_HandlerR
SWI_AddrR: .word SWI_HandlerR
PAbt_AddrR: .word PAbt_HandlerR
DAbt_AddrR: .word DAbt_HandlerR
// .word 0xdeadbeef /* Test Reserved Address */
.word 0 /* Reserved Address */
IRQ_AddrR: .word IRQ_HandlerR
FIQ_AddrR: .word FIQ_HandlerR
Undef_HandlerR: B Undef_HandlerR
SWI_HandlerR: B SWI_HandlerR
PAbt_HandlerR: B PAbt_HandlerR
DAbt_HandlerR: B DAbt_HandlerR
IRQ_HandlerR: B IRQ_HandlerR
FIQ_HandlerR: B FIQ_HandlerR
VectorsRAM_end:
#endif /* VECTORS_IN_RAM && ROM_RUN */
#ifndef USE_SAMBA
/*
Exception Vectors
- for ROM_RUN: placed in 0x00000000
- for RAM_RUN: placed at 0x00200000 (on AT91SAM7S64)
- for USE_SAMBA: not used
-> will be used during startup before remapping with target ROM_RUN
-> will be used "always" in code without remapping or with target RAM_RUN
Mapped to Address relative address 0 of .text
Absolute addressing mode must be used.
Dummy Handlers are implemented as infinite loops which can be modified.
*/
.text
.arm
.section .vectrom, "ax"
Vectors: LDR PC,Reset_Addr
LDR PC,Undef_Addr
LDR PC,SWI_Addr
LDR PC,PAbt_Addr
LDR PC,DAbt_Addr
NOP /* Reserved Vector */
// LDR PC,IRQ_Addr
LDR PC,[PC,#-0xF20] /* Vector From AIC_IVR */
// LDR PC,FIQ_Addr
LDR PC,[PC,#-0xF20] /* Vector From AIC_FVR */
Reset_Addr: .word Reset_Handler
Undef_Addr: .word Undef_Handler
SWI_Addr: .word SWI_Handler
PAbt_Addr: .word PAbt_Handler
DAbt_Addr: .word DAbt_Handler
.word 0 /* Reserved Address */
IRQ_Addr: .word IRQ_Handler
FIQ_Addr: .word FIQ_Handler
Undef_Handler: B Undef_Handler
SWI_Handler: B SWI_Handler
PAbt_Handler: B PAbt_Handler
DAbt_Handler: B DAbt_Handler
IRQ_Handler: B IRQ_Handler
FIQ_Handler: B FIQ_Handler
#endif
// Starupt Code must be linked first at Address at which it expects to run.
.text
.arm
.section .init, "ax"
.global _startup
.func _startup
_startup:
// Reset Handler
LDR pc, =Reset_Handler
Reset_Handler:
// Setup EFC
.if EFC_SETUP
LDR R0, =EFC_BASE
LDR R1, =EFC_FMR_Val
STR R1, [R0, #EFC_FMR]
.endif
// Setup WDT
.if WDT_SETUP
LDR R0, =WDT_BASE
LDR R1, =WDT_MR_Val
STR R1, [R0, #WDT_MR]
.endif
// Setup reset controller
.if RSTC_SETUP
LDR R0, =RSTC_BASE
LDR R1, =RSTC_MR_Val
STR R1, [R0, #RSTC_MR]
.endif
// Setup PMC
.if PMC_SETUP
LDR R0, =PMC_BASE
// Setup Main Oscillator
LDR R1, =PMC_MOR_Val
STR R1, [R0, #PMC_MOR]
// Wait until Main Oscillator is stablilized
.if (PMC_MOR_Val & PMC_MOSCEN)
MOSCS_Loop: LDR R2, [R0, #PMC_SR]
ANDS R2, R2, #PMC_MOSCS
BEQ MOSCS_Loop
.endif
// Setup the PLL
.if (PMC_PLLR_Val & PMC_MUL)
LDR R1, =PMC_PLLR_Val
STR R1, [R0, #PMC_PLLR]
// Wait until PLL is stabilized
PLL_Loop: LDR R2, [R0, #PMC_SR]
ANDS R2, R2, #PMC_LOCK
BEQ PLL_Loop
.endif
// Select Clock
LDR R1, =PMC_MCKR_Val
STR R1, [R0, #PMC_MCKR]
.endif
// Setup Stack for each mode
LDR R0, =Top_Stack
// Enter Undefined Instruction Mode and set its Stack Pointer
MSR CPSR_c, #Mode_UND|I_Bit|F_Bit
LDR SP, =UND_Stack_End
// Enter Abort Mode and set its Stack Pointer
MSR CPSR_c, #Mode_ABT|I_Bit|F_Bit
LDR SP, =ABT_Stack_End
// Enter FIQ Mode and set its Stack Pointer
MSR CPSR_c, #Mode_FIQ|I_Bit|F_Bit
LDR SP, =FIQ_Stack_End
// Enter IRQ Mode and set its Stack Pointer
MSR CPSR_c, #Mode_IRQ|I_Bit|F_Bit
LDR SP, =IRQ_Stack_End
// Enter Supervisor Mode and set its Stack Pointer
MSR CPSR_c, #Mode_SVC|I_Bit|F_Bit
LDR SP, =SVC_Stack_End
// Enter User Mode and set its Stack Pointer
#ifndef RUN_AS_SYSTEM
MSR CPSR_c, #Mode_SYS
#else
MSR CPSR_c, #Mode_USR
#endif
LDR SP, =USR_Stack_End
// Setup a default Stack Limit (when compiled with "-mapcs-stack-check")
LDR SL, =USR_Stack_End
#ifdef ROM_RUN
// Relocate .data section (Copy from ROM to RAM)
LDR R1, =_etext
LDR R2, =_data
LDR R3, =_edata
LoopRel: CMP R2, R3
LDRLO R0, [R1], #4
STRLO R0, [R2], #4
BLO LoopRel
#endif
// Clear .bss section (Zero init)
MOV R0, #0
LDR R1, =__bss_start__
LDR R2, =__bss_end__
LoopZI: CMP R1, R2
STRLO R0, [R1], #4
BLO LoopZI
#if defined(VECTORS_IN_RAM) || defined(RAM_RUN)
/*
*** Remap ***
ROM_RUN: exception vectors for RAM have been already copied
to 0x00200000 by the .data copy-loop
RAM_RUN: exception vectors are already placed at 0x0020000 by
linker settings
*/
.equ MC_BASE,0xFFFFFF00 /* MC Base Address */
.equ MC_RCR, 0x00 /* MC_RCR Offset */
LDR R0, =MC_BASE
MOV R1, #1
STR R1, [R0, #MC_RCR] // Remap
#endif /* VECTORS_IN_RAM || RAM_RUN */
#ifdef USE_SAMBA
// Copy interrupt vectors to RAM, that has previously been mapped to 0
MOV R1, #0
LDR R2, = VectorsRAM
LDR R3, = VectorsRAM_end
LoopVectCopy: CMP R2, R3
LDRLO R0, [R2], #4
STRLO R0, [R1], #4
BLO LoopVectCopy
#endif
/*
Call C++ constructors (for objects in "global scope")
added by Martin Thomas based on a Anglia Design
example-application for STR7 ARM
*/
LDR r0, =__ctors_start__
LDR r1, =__ctors_end__
ctor_loop:
CMP r0, r1
BEQ ctor_end
LDR r2, [r0], #4 /* this ctor's address */
STMFD sp!, {r0-r1} /* save loop counters */
MOV lr, pc /* set return address */
// MOV pc, r2
BX r2 /* call ctor */
LDMFD sp!, {r0-r1} /* restore loop counters */
B ctor_loop
ctor_end:
// Enter the C code
mov r0,#0 // no arguments (argc = 0)
mov r1,r0
mov r2,r0
mov fp,r0 // null frame pointer
mov r7,r0 // null frame pointer for thumb
ldr r10,=main
adr lr, __main_exit
bx r10 // enter main()
__main_exit: B __main_exit
.size _startup, . - _startup
.endfunc
.end