;/*****************************************************************************/
;/* S3C2440A.S: Startup file for Samsung S3C440A */
;/* This file is part of the uVision/ARM development tools. */
;/* Copyright (c) 2005-2006 Keil Software. All rights reserved. */
;/* This software may only be used under the terms of a valid, current, */
;/* end user licence from KEIL for a compatible version of KEIL software */
;/* development tools. Nothing else gives you the right to use this software. */
;/*****************************************************************************/
;elementary avocationA (rework:2008.09.24更新)
;***启动代码(执行复位后)***
; Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs//;向量中断模式/非向量中断模式 在PSRs设置(猜的)
; 系统的工作模式设定
Mode_USR EQU 0x10 ; 定义用户模式标志代码;// 用户模式的CPSR代码
Mode_FIQ EQU 0x11 ; 定义快速中断模式标志代码;// 快中断模式的CPSR代码
Mode_IRQ EQU 0x12 ; 定义普通中断模式标志代码;// 中断模式的CPSR代码
Mode_SVC EQU 0x13 ; 定义管理模式标志代码;// 管理模式的CPSR代码
Mode_ABT EQU 0x17 ; 定义中止模式标志代码;// 中止模式的CPSR代码
Mode_UND EQU 0x1B ; 定义未定义模式标志代码 ;// 未定义模式的CPSR代码
Mode_SYS EQU 0x1F ; 定义系统模式(特权模式)标志代码;// 系统(特权)模式的CPSR代码
I_Bit EQU 0x80 ;// 普通中断开关(0×80:打开;0×00:关闭)
F_Bit EQU 0x40 ;// 快速中断开关(0×40:打开;0×00:关闭)
;//栈配置()
;系统的栈空间设定
UND_Stack_Size EQU 0x00000000 ;未定义
SVC_Stack_Size EQU 0x00000008 ;管理模式端栈长度
ABT_Stack_Size EQU 0x00000000 ;中止模式端栈长度
FIQ_Stack_Size EQU 0x00000000 ;快速中断模式端栈长度
IRQ_Stack_Size EQU 0x00000080 ;普通中断模式模式端栈长度
USR_Stack_Size EQU 0x00000400 ;用户模端栈长度
;//
ISR_Stack_Size EQU (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + FIQ_Stack_Size + IRQ_Stack_Size);所有的堆栈大小进行相加,得到总堆栈大小
/**********************************************************************************************
;//arm的汇编程序由段组成,段是相对独立的指令或数据单位,每个段由AREA伪指令定义,并定义段的属性:
;//READWRITE(读写)READONLY(只读)
**********************************************************************************************/
AREA STACK, NOINIT, READWRITE, ALIGN=3 ;开辟端栈段,段名(STACK)定义为可读可写,不初始化内存单元或将内存写0,字节对齐
Stack_Mem SPACE USR_Stack_Size ;//申请栈内存空间
__initial_sp SPACE ISR_Stack_Size
Stack_Top EQU Stack_Mem + ISR_Stack_Size ;//定义堆栈开始地址(最大地址,堆栈向下访问)
;//堆配置
;//堆大小 (单位字节)//
Heap_Size EQU 0x00000000 ;系统的堆空间设定//定义堆空间大小(配合最后的动态内存申请使用)
AREA HEAP, NOINIT, READWRITE, ALIGN=3 ;//段名(HEAP)声明堆代码段(不初始化内存,可读写,字节对齐)
Heap_Mem SPACE Heap_Size ;//申请堆的内存空间
;时钟管理定义
CLK_BASE EQU 0x4C000000 ; 时钟基地址
LOCKTIME_OFS EQU 0x00 ; PLL锁定时间计数器对应基地址的偏移值
MPLLCON_OFS EQU 0x04 ; MPLL控制 对应基地址的偏移值//认为MPLL分出三种模式:FCLK、HCLK、PCLK
UPLLCON_OFS EQU 0X08 ; UPLL控制 对应基地址的偏移值//用于USB设备
CLKCON_OFS EQU 0x0C ; 时钟生成控制 对应基地址的偏移值
CLKSLOW_OFS EQU 0x10 ; 慢时钟控制 对应基地址的偏移值
CLKDIVN_OFS EQU 0X14 ; 时钟除法器控制 对应基地址的偏移值
CAMDIVN_OFS EQU 0X18 ; 摄象时钟除法器控制 对应基地址的偏移值//UPLL提供
CLOCK_SETUP EQU 1 ; 时钟设置
LOCKTIME_Val EQU 0x0FFF0FFF ; PLL锁定时间计数器 值
MPLLCON_Val EQU 0x00043011 ; MPLL控制 值
UPLLCON_Val EQU 0x00038021 ; UPLL控制 值
CLKCON_Val EQU 0x001FFFF0 ; 时钟生成控制 值
CLKSLOW_Val EQU 0x00000004 ; 慢时钟控制 值
CLKDIVN_Val EQU 0x0000000F ; 时钟除法器控制 值
CAMDIVN_Val EQU 0x00000000 ; 摄象时钟除法器控制 值
;Interrupt definitions ;中断定义
INTOFFSET EQU 0X4A000014 ;中断请求源偏移 地址
;//中断向量表
;// 中断向量地址 <0x20-0x3fffff78>
;// 中断向量表地址必须字对齐
;//</e>
IntVT_SETUP EQU 1 ;中断向量设置
IntVTAddress EQU 0x33ffff20 ;中断向量地址
;----------------------- 存储器设定 ------------------------------------
IRAM_BASE EQU 0x40000000 ; //内存基地址
; //看门狗定义
WT_BASE EQU 0x53000000 ; 看门狗基地址
WTCON_OFS EQU 0x00 ; 看门狗控制 对应基地址的偏移值
WTDAT_OFS EQU 0x04 ; 看门狗数据 对应基地址的偏移值
WTCNT_OFS EQU 0x08 ; 看门狗记数 对应基地址的偏移值
WT_SETUP EQU 1 ; 看门狗设置
WTCON_Val EQU 0x00000000 ; 看门狗控制
WTDAT_Val EQU 0x00008000 ; 看门狗数据
; 存储控制器设定
MC_BASE EQU 0x48000000 ; 存储控制器基地址
MC_SETUP EQU 0 ; 存储控制器设定
BWSCON_Val EQU 0x22000000 ;总线宽度和等待控制
BANKCON0_Val EQU 0x00000700 ;Boot ROM 控制
BANKCON1_Val EQU 0x00000700 ;BANK1 控制
BANKCON2_Val EQU 0x00000700 ;BANK2 控制
BANKCON3_Val EQU 0x00000700 ;BANK3 控制
BANKCON4_Val EQU 0x00000700 ;BANK4 控制
BANKCON5_Val EQU 0x00000700 ;BANK5 控制
BANKCON6_Val EQU 0x00018005 ;BANK6 控制
BANKCON7_Val EQU 0x00018005 ;BANK7 控制
REFRESH_Val EQU 0x008404F3 ;DRAM/SDRAM 刷新 控制
BANKSIZE_Val EQU 0x00000032 ;存储器大小 控制
MRSRB6_Val EQU 0x00000020 ;SDRAM 的模式设置寄存器 控制
MRSRB7_Val EQU 0x00000020 ;SDRAM 的模式设置寄存器 控制
; 存储控制器设定结束
; I/O 口设定
PIO_BASE EQU 0x56000000 ; 端口基地址
PCONA_OFS EQU 0x00 ; 端口A控制 对应基地址的偏移值
PCONB_OFS EQU 0x10 ; 端口B控制 对应基地址的偏移值
PCONC_OFS EQU 0x20 ; 端口C控制 对应基地址的偏移值
PCOND_OFS EQU 0x30 ; 端口D控制 对应基地址的偏移值
PCONE_OFS EQU 0x40 ; 端口E控制 对应基地址的偏移值
PCONF_OFS EQU 0x50 ; 端口F控制 对应基地址的偏移值
PCONG_OFS EQU 0x60 ; 端口G控制 对应基地址的偏移值
PCONH_OFS EQU 0x70 ; 端口H控制 对应基地址的偏移值
PCONJ_OFS EQU 0xD0 ; 端口J控制 对应基地址的偏移值
PUPB_OFS EQU 0x18 ; 端口B上拉控制 对应基地址的偏移值
PUPC_OFS EQU 0x28 ; 端口C上拉控制 对应基地址的偏移值
PUPD_OFS EQU 0x38 ; 端口D上拉控制 对应基地址的偏移值
PUPE_OFS EQU 0x48 ; 端口E上拉控制 对应基地址的偏移值
PUPF_OFS EQU 0x58 ; 端口F上拉控制 对应基地址的偏移值
PUPG_OFS EQU 0x68 ; 端口G上拉控制 对应基地址的偏移值
PUPH_OFS EQU 0x78 ; 端口H上拉控制 对应基地址的偏移值
PUPJ_OFS EQU 0xD8 ; 端口J上拉控制 对应基地址的偏移值
;--------端口 配置--------------
PIO_SETUP EQU 0
;端口A
PIOA_SETUP EQU 0
PCONA_Val EQU 0x000003FF
;端口B
PIOB_SETUP EQU 0
PCONB_Val EQU 0x00000000 ;
PUPB_Val EQU 0x00000000 ;端口B上拉开启
;端口C
PIOC_SETUP EQU 1
PCONC_Val EQU 0x00001401 ;
PUPC_Val EQU 0x00000000 ;端口C上拉开启
;端口D
PIOD_SETUP EQU 0
PCOND_Val EQU 0x00000000 ;
PUPD_Val EQU 0x00000000 ;端口D上拉开启
;端口E
PIOE_SETUP EQU 0
PCONE_Val EQU 0x00000000 ;
PUPE_Val EQU 0x00000000 ;端口E上拉开启
;端口F
PIOF_SETUP EQU 0
PCONF_Val EQU 0x00000000 ;
PUPF_Val EQU 0x00000000 ;端口F上拉开启
;端口G
PIOG_SETUP EQU 0
PCONG_Val EQU 0x00000000 ;
PUPG_Val EQU 0x00000000 ;端口G上拉开启
;端口H
PIOH_SETUP EQU 0
PCONH_Val EQU 0x000007FF
PUPH_Val EQU 0x00000000 ;端口H上拉开启
;端口J
PIOJ_SETUP EQU 0
PCONJ_Val EQU 0x00000000 ;
PUPJ_Val EQU 0x00000000 ;端口J上拉开启
; 汇编程序数据 8 字节对齐
PRESERVE8 ;c和汇编有8位对齐的要求,这个伪指令可以满足此要求
;//存储区设定和程序入口点
;//启动代码必须连接到第一个地址才能运行。
AREA RESET, CODE, READONLY ;//开辟端栈段,段名(RESET)定义RESET代码段为只读
ARM ;//ARM 模式运行程序
;//异常向量
;//影射到地址0
;//必须使用,绝对寻址方式。
;//虚处理(子程序)是用一个无限循环实现的, 它是可修改的..//(11942295)翻译
Vectors LDR PC, Reset_Addr ; 复位
LDR PC, Undef_Addr ; 未定义指令
LDR PC, SWI_Addr ; 软件中断
LDR PC, PAbt_Addr ; 中止(预取)
LDR PC, DAbt_Addr ; 中止(数据)
NOP ; 保留向量
LDR PC, IRQ_Addr ; 普通
LDR PC, FIQ_Addr ; 快速中断
IF IntVT_SETUP <> 0
;//中断向量表地址
HandleEINT0 EQU IntVTAddress
HandleEINT1 EQU IntVTAddress +4
HandleEINT2 EQU IntVTAddress +4*2
HandleEINT3 EQU IntVTAddress +4*3
HandleEINT4_7 EQU IntVTAddress +4*4
HandleEINT8_23 EQU IntVTAddress +4*5
HandleCAM EQU IntVTAddress +4*6
HandleBATFLT EQU IntVTAddress +4*7
HandleTICK EQU IntVTAddress +4*8
HandleWDT EQU IntVTAddress +4*9
HandleTIMER0 EQU IntVTAddress +4*10
HandleTIMER1 EQU IntVTAddress +4*11
HandleTIMER2 EQU IntVTAddress +4*12
HandleTIMER3 EQU IntVTAddress +4*13
HandleTIMER4 EQU IntVTAddress +4*14
HandleUART2 EQU IntVTAddress +4*15
HandleLCD EQU IntVTAddress +4*16
HandleDMA0 EQU IntVTAddress +4*17
HandleDMA1 EQU IntVTAddress +4*18
HandleDMA2 EQU IntVTAddress +4*19
HandleDMA3 EQU IntVTAddress +4*20
HandleMMC EQU IntVTAddress +4*21
HandleSPI0 EQU IntVTAddress +4*22
HandleUART1 EQU IntVTAddress +4*23
HandleNFCON EQU IntVTAddress +4*24
HandleUSBD EQU IntVTAddress +4*25
HandleUSBH EQU IntVTAddress +4*26
HandleIIC EQU IntVTAddress +4*27
HandleUART0 EQU IntVTAddress +4*28
HandleSPI1 EQU IntVTAddress +4*39
HandleRTC EQU IntVTAddress +4*30
HandleADC EQU IntVTAddress +4*31
IRQ_Entry
sub sp,sp,#4 ;//保留PC值
stmfd sp!,{r8-r9}
ldr r9,=INTOFFSET
ldr r9,[r9]
ldr r8,=HandleEINT0
add r8,r8,r9,lsl #2
ldr r8,[r8]
str r8,[sp,#8]
ldmfd sp!,{r8-r9,pc}
ENDIF
Reset_Addr DCD Reset_Handler ;定义中断的入口地址; 以Reset_Addr为Reset_Handler分配一段字对齐的内存单元
Undef_Addr DCD Undef_Handler ; 注:应该是将CODE映射(复制)到RAM的开始地址
SWI_Addr DCD SWI_Handler
PAbt_Addr DCD PAbt_Handler
DAbt_Addr DCD DAbt_Handler
DCD 0 ;//保留地址
IRQ_Addr DCD IRQ_Handler
FIQ_Addr DCD FIQ_Handler
Undef_Handler B Undef_Handler ;中断处理程序的入口地址//B为跳转指令|| ??自己跳转到自己??
SWI_Handler B SWI_Handler
PAbt_Handler B PAbt_Handler
DAbt_Handler B DAbt_Handler
IF IntVT_SETUP <> 1
IRQ_Handler B IRQ_Handler
ENDIF
IF IntVT_SETUP <> 0
IRQ_Handler B IRQ_Entry
ENDIF
FIQ_Handler B FIQ_Handler
;//存储控制器配制
IF MC_SETUP <> 0
MC_CFG
DCD BWSCON_Val
DCD BANKCON0_Val
DCD BANKCON1_Val
DCD BANKCON2_Val
DCD BANKCON3_Val
DCD BANKCON4_Val
DCD BANKCON5_Val
DCD BANKCON6_Val
DCD BANKCON7_Val
DCD REFRESH_Val
DCD BANKSIZE_Val
DCD MRSRB6_Val
DCD MRSRB7_Val
ENDIF
;//时钟管理配置
IF CLOCK_SETUP <> 0
CLK_CFG
DCD LOCKTIME_Val
DCD CLKDIVN_Val
DCD UPLLCON_Val
DCD MPLLCON_Val
DCD CLKSLOW_Val
DCD CLKCON_Val
DCD CAMDIVN_Val
ENDIF
;//I/O 配置
IF PIO_SETUP <> 0
PIOA_CFG
DCD PCONA_Val
PIOB_CFG DCD PCONB_Val
DCD PUPB_Val
PIOC_CFG DCD PCONC_Val
DCD PUPC_Val
PIOD_CFG DCD PCOND_Val
DCD PUPD_Val
PIOE_CFG DCD PCONE_Val
DCD PUPE_Val
PIOF_CFG DCD PCONF_Val
DCD PUPF_Val
PIOG_CFG DCD PCONG_Val
DCD PUPG_Val
PIOH_CFG DCD PCONH_Val
DCD PUPH_Val
PIOJ_CFG DCD PCONJ_Val
DCD PUPJ_Val
ENDIF
; //复位处理模块
;//下面是重起时的中断处理函数
EXPORT Reset_Handler ;//定义一个全局函数名变量
Reset_Handler
IF WT_SETUP <> 0 ;//看门狗处理;若WT_SETUP为1,则执行下一个语句
LDR R0, =WT_BASE
LDR R1, =WTCON_Val
LDR R2, =WTDAT_Val
STR R2, [R0, #WTCNT_OFS]
STR R2, [R0, #WTDAT_OFS]
STR R1, [R0, #WTCON_OFS]
ENDIF
IF CLOCK_SETUP <> 0 ;//时钟处理;若CLOCK_SETUP为1,则执行下一个语句
LDR R0, =CLK_BASE
ADR R8, CLK_CFG
LDMIA R8, {R1-R7}
STR R1, [R0, #LOCKTIME_OFS]
STR R2, [R0, #CLKDIVN_OFS]
STR R3, [R0, #UPLLCON_OFS]
nop
nop
nop
nop
nop
nop
nop
STR R4, [R0, #MPLLCON_OFS]
STR R5, [R0, #CLKSLOW_OFS]
STR R6, [R0, #CLKCON_OFS]
STR R7, [R0, #CAMDIVN_OFS]
ENDIF
IF MC_SETUP <> 0 ;//存储控制器处理;若MC_SETUP为1,则执行下一个语句
ADR R13, MC_CFG
LDMIA R13, {R0-R12}
LDR R13, =MC_BASE
STMIA R13, {R0-R12}
ENDIF
IF PIO_SETUP <> 0 ;//IO处理;若PIO_SETUP为1,则执行下一个语句
LDR R13, =PIO_BASE
IF PIOA_SETUP <> 0 ;//端口A处理;若PIOA_SETUP为1,则执行下一个语句
ADR R0, PIOA_CFG
STR R0, [R13, #PCONA_OFS]
ENDIF
IF PIOB_SETUP <> 0 ;//端口B处理
ADR R0, PIOB_CFG
LDR R1, [R0,#4]
STR R0, [R13, #PCONB_OFS]
STR R1, [R13, #PUPB_OFS]
ENDIF
IF PIOC_SETUP <> 0 ;//端口C处理
ADR R0, PIOC_CFG
LDR R1, [R0,#4]
STR R0, [R13, #PCONC_OFS]
STR R1, [R13, #PUPC_OFS]
ENDIF
IF PIOD_SETUP <> 0 ;//端口D处理
ADR R0, PIOD_CFG
LDR R1, [R0,#4]
STR R0, [R13, #PCOND_OFS]
STR R1, [R13, #PUPD_OFS]
ENDIF
IF PIOE_SETUP <> 0 ;//端口E处理
ADR R0, PIOE_CFG
LDR R1, [R0,#4]
STR R0, [R13, #PCONE_OFS]
STR R1, [R13, #PUPE_OFS]
ENDIF
IF PIOF_SETUP <> 0 ;//端口F处理
ADR R0, PIOF_CFG
LDR R1, [R0,#4]
STR R0, [R13, #PCONF_OFS]
STR R1, [R13, #PUPF_OFS]
ENDIF
IF PIOG_SETUP <> 0 ;//端口G处理
ADR R0, PIOG_CFG
LDR R1, [R0,#4]
STR R0, [R13, #PCONG_OFS]
STR R1, [R13, #PUPG_OFS]
ENDIF
IF PIOH_SETUP <> 0 ;//端口H处理
ADR R0, PIOH_CFG
LDR R1, [R0,#4]
STR R0, [R13, #PCONH_OFS]
STR R1, [R13, #PUPH_OFS]
ENDIF
IF PIOJ_SETUP <> 0 ;//端口J处理
ADR R0, PIOJ_CFG
LDR R1, [R0,#4]
STR R0, [R13, #PCONJ_OFS]
STR R1, [R13, #PUPJ_OFS]
ENDIF
ENDIF
;;以下函数为进入相应的模式,并定义相应模式的端栈大小
;//为每个模式设置栈
LDR R0, =Stack_Top
;//进入未定义指令模式并设定其栈指针
MSR CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #UND_Stack_Size
;//进入异常中断模式,并设定其栈指针
MSR CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #ABT_Stack_Size
;//进入 FIQ 模式,并设定其栈指针
MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #FIQ_Stack_Size
;//进入 IRQ 模式,并设定其栈指针
MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #IRQ_Stack_Size
;//进入 Supervisor 模式,并设定其栈指针
MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #SVC_Stack_Size
; IMPORT MMU_EnableICache
; bl MMU_EnableICache
;//进入 用户 模式,并设定其栈指针 //;最后进入用户模式
MSR CPSR_c, #Mode_USR
MOV SP, R0
SUB SL, SP, #USR_Stack_Size
;//进入C代码
;
IMPORT __main
LDR R0, =__main
BX R0
;//用护初始堆与栈 ;//用户设置堆栈程序(C外部接口:用于动态申请内存使用)
AREA |.text|, CODE, READONLY
; IMPORT __use_two_region_memory
EXPORT __user_initial_stackheap
__user_initial_stackheap
/**********************************************************************
//__user_initial_stackheap 库函数用法翻译
用法:
__user_initial_stackheap 返回这些值:
1. 堆基址(heap base) ---> RO
2. 栈基址(stack base,一般为栈的最高地址) ---> R1
3. 堆顶(heap limit) ---> R2
4. 栈顶(stack limit) ---> R3
***********************************************************************/
LDR R0, = Heap_Mem
LDR R1, =(Stack_Mem + USR_Stack_Size)
LDR R2, = (Heap_Mem + Heap_Size)
&nbs
__user_initial_stackheap 库函数用法翻译
__user_initial_stackheap返回初始化堆和栈的位置。
RVCT V2.X及其更早的版本中__user_initial_stackheap默认使用的是符号|Image$$ZI$$Limit|的值。当使用分散
加载文件的时候这个符号不会产生。如果你使用分散加载文件,那么你需要重新执行__user_initial_stackheap
函数,不然链接会失败。
在RVCT V3.X中__user_initial_stackheap的功能得到了加强,即使你使用分散加载文件也不需要你重新执行
__user_initial_stackheap函数。函数会根据你的分散加载文件的描述选择正确的功能函数段。
注意:如果你重新执行__user_initial_stackheap函数,这将忽略所有的库函数的执行。这就使得存在的应用程序不
需要修改。
语法:
__valu_in_regs struct __initial_stackheap __user_initial_stackheap(unsinged R0,
unsigned SP,
unsgined R2)
用法:
__user_initial_stackheap 返回这些值:
1. 堆基址(heap base) ---> RO
2. 栈基址(stack base,一般为栈的最高地址) ---> R1
3. 堆顶(heap limit) ---> R2
4. 栈顶(stack limit) ---> R3
如果这个函数被重新执行,那么必须满足以下条件:
1. 栈的使用不能超过88字节。
2. R12(ip)不能被破坏。
3. 堆要以8字节方式对齐(ALIGN = 3)。
默认的一段模式中R2,R3将被忽略,R0,R1间的存储空间将全部用来作为堆空间。
如果使用二段模式那么堆和栈的空间将分别受R2,R3的限制。
在rt_misc.h中__user_initial_stackheap的定义是这样的:
struct __initial_stackheap {
unsigned heap_base, stack_base, heap_limit, stack_limit
}
注意:
由于满递减堆栈的原因,stack_base的值比栈的最高地址要高出1个栈容量。
返回:
R0,R1,R2,R3中的返回值是由你使用的一段存储模式还是二段存储模式决定。
1. 一段模式中R1比R0大。R2和R3被忽略了。
2. 二段模式中R0和R2用来初始化堆,R1和R3用来初始化栈。R2 >= R0, R3 < R1
┏━━━┳━━━┓<----- R1 ----->┏━━━┳━━━┓<--- HIGH ADDR
┃ ↑ ┃ stack_base ┃ │ ┃
┃ │ ┃ ┃ │ ┃
┃ │ ┃ ┃ stacks ┃
┃ │ ┃ ┃ │ ┃
┃ │ ┃ ┃ ↓ ┃
┃ │ ┃ R3 ----->┃ ┻ ┃
┃ ↑ ┃ ┃ ┃
┃ │ ┃ ┃ ┃
┃ │ ┃ ┃ ┃
┃ │ ┃ R2 ----->┃ ┳ ┃
┃ │ ┃ ┃ ↑ ┃
┃ │ ┃ ┃ │ ┃
┃ │ ┃ ┃ │ ┃
┃ heaps ┃ ┃ heaps ┃
┃ │ ┃ ┃ │ ┃
┃ │ ┃ ┃ │ ┃
┃ │ ┃ ┃ │ ┃
┗━━━┻━━━┛<----- R0 ----->┗━━━┻━━━┛<--- LOW ADDR
_use_one_memory_region _use_two_memory_region
使用分散加载文件:
默认情况下__user_initial_stackhep()使用的是符号|Image$$ZI$$limit|的值。这个符号在用户使
用分散加载文件时不会产生。然而,C库提供了比较折中的方法:利用分散加载文件中的一些信息来
执行这个函数。
注意:
如果你重新执行__user_initial_stackhep()函数,那么其他的库的执行将被忽略。
选择使用一段存储模式:
定义一段特殊的执行域在你的分散加载文件中。使用这种符号:ARM_LIB_STACKHEAP,并使用EMPTY
属性。
这样库管理器就选择了一个把这个域当作堆和栈合并在一起的__user_initial_stackhep()函数。在
这个函数中使用了Image$$ARM_LIB_STACKHEAP$$Base和Image$$ARM_LIB_STACKHEAP$$ZI$$Limit符号
。
选择使用二段存储模式:
定义两个特殊的执行域再你的分散加载文件中。使用这两种符号:ARM_LIB_STACK, ARM_LIB_HEAP。
并且两个段都要使用EMPTY属性。
这样库管理器就会选择使用符号:Image$$ARM_LIB_HEAP$$Base、
Image$$ARM_LIB_STACK$$ZI$$ZI$$limit、
Image$$ARM_LIB_STACK$$Base
Image$$ARM_LIB_STACK$$ZI$$Limit
的__user_initial_stackhep()函数。
例子:
FLASH_LOAD 0x0000 0x00200000
{
VECTORS +0 0x400
{
* (:gdef:__vectab_stack_and_reset, +FIRST)
; 其他域可以放在这里
}
;; 最高256 异常深度 (256*4bytes == 1024 == 0x400)
CODE 0x400 FIXED
{
* (+RO)
}
DATA 0x20000000 0x00200000
{
* (+RW, +ZI)
}
;; 堆开始于 1MB ,向高地址生长
ARM_LIB_HEAP 0x20100000 EMPTY 0x100000-0x8000
{
}
;; 堆安排在 2MB RAM的最高地址处
;; 向低地址生长,空间为32KB
ARM_LIB_STACK 0x20200000 EMPTY - 0x8000
{
}
}
用户1681175 2013-4-16 19:38
用户67853 2011-4-21 08:59