;/*****************************************************************************/
;/* S3C2440.S: Startup file for Samsung S3C440 */
;/*****************************************************************************/
; Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs
;标准模式定义和中断标志使能位,不同处理器模式可能不同,需要修改
Mode_USR EQU 0x10 ;用户模式
Mode_FIQ EQU 0x11 ;快速中断模式
Mode_IRQ EQU 0x12 ;中断模式
Mode_SVC EQU 0x13 ;管理模式
Mode_ABT EQU 0x17 ;终止模式
Mode_UND EQU 0x1B ;未定义模式
Mode_SYS EQU 0x1F ;系统模式
I_Bit EQU 0x80 ;I位设置为1,IRQ不使能
F_Bit EQU 0x40 ;F位设置为1,FIQ不使能
;----------------------- Stack and Heap Definitions ----------------------------
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)
;定义名为STACK的区域,可读可写,以2的3次方对齐
AREA STACK, NOINIT, READWRITE, ALIGN=3
;分配内存空间
Stack_Mem SPACE USR_Stack_Size ;内存堆栈分配空间
__initial_sp SPACE ISR_Stack_Size ;汇编代码地址标号
Stack_Top ;标号,获得堆栈的地址
;堆的大小,用于动态分配内存
Heap_Size EQU 0x00000000
;定义名为HEAP的区域,可读可写,以2的3次方对齐
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base ;标号,获得堆的基地址
Heap_Mem SPACE Heap_Size ;分配堆的空间,获得堆的地址标号
__heap_limit ;分配结束
;----------------------- Memory Definitions ------------------------------------
;内存初始化定义
; Internal Memory Base Addresses
IRAM_BASE EQU 0x40000000 ;内存基地址
;----------------------- Watchdog Timer Definitions ----------------------------
;看门狗初始化定义,移植到其他处理器地址可能不同,需要修改
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 ;看门狗数据寄存器设置,初始化为0x8000
;----------------------- Clock and Power Management Definitions ----------------
;时钟与电源管理定义,移植到其他处理器地址可能不同,需要修改
CLOCK_BASE EQU 0x4C000000 ; 时钟基地址
LOCKTIME_OFS EQU 0x00 ; 锁相环锁定时间计数寄存器相对于基地址偏移地址
MPLLCON_OFS EQU 0x04 ; 主时钟锁相环配置寄存器相对于基地址偏移地址
UPLLCON_OFS EQU 0x08 ; USB时钟锁相环配置寄存器相对于基地址偏移地址
CLKCON_OFS EQU 0x0C ; 时钟控制寄存器相对于基地址的偏移地址
CLKSLOW_OFS EQU 0x10 ; 时钟减慢控制寄存器相对于基地址的偏移地址
CLKDIVN_OFS EQU 0x14 ; 时钟分频控制寄存器相对于基地址的偏移地址
CAMDIVN_OFS EQU 0x18 ; 相机时钟分频寄存器相对于基地址的偏移地址
CLOCK_SETUP EQU 0 ;时钟设置
LOCKTIME_Val EQU 0x0FFF0FFF ;锁相环锁定时间计数器值
MPLLCON_Val EQU 0x00043011 ;主锁相环控制寄存器的值
UPLLCON_Val EQU 0x00038021 ;USB锁相环控制寄存器的值
CLKCON_Val EQU 0x001FFFF0 ;始终控制寄存器的值
CLKSLOW_Val EQU 0x00000004 ;始终减慢控制寄存器的值
CLKDIVN_Val EQU 0x0000000F ;时钟分频控制寄存器的值
CAMDIVN_Val EQU 0x00000000 ;摄像头分频控制寄存器的值
;----------------------- Memory Controller Definitions -------------------------
;内存控制定义,移植到其他处理器地址可能不同,需要修改
MC_BASE EQU 0x48000000 ; 存储控制器基地址
BWSCON_OFS EQU 0x00 ; 总线宽度和等待控制寄存器偏移地址
BANKCON0_OFS EQU 0x04 ; Bank0控制寄存器偏移地址
BANKCON1_OFS EQU 0x08 ; Bank1控制寄存器偏移地址
BANKCON2_OFS EQU 0x0C ; Bank2控制寄存器偏移地址
BANKCON3_OFS EQU 0x10 ; Bank3控制寄存器偏移地址
BANKCON4_OFS EQU 0x14 ; Bank4控制寄存器偏移地址
BANKCON5_OFS EQU 0x18 ; Bank5控制寄存器偏移地址
BANKCON6_OFS EQU 0x1C ; Bank6控制寄存器偏移地址
BANKCON7_OFS EQU 0x20 ; Bank7控制寄存器偏移地址
REFRESH_OFS EQU 0x24 ; SDRAM刷新控制寄存器偏移地址
BANKSIZE_OFS EQU 0x28 ; 可调节的BANK大小寄存器的偏移地址
MRSRB6_OFS EQU 0x2C ; Bank6模式寄存器的偏移地址
MRSRB7_OFS EQU 0x30 ; Bank7模式寄存器的偏移地址
MC_SETUP EQU 0 ;存储器寄存器设置
BWSCON_Val EQU 0x22000000 ;总线宽度和等待控制寄存器值
BANKCON0_Val EQU 0x00000700 ;BANK0控制寄存器的值
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 ;可调的BANK大小控制寄存器的值
MRSRB6_Val EQU 0x00000020 ;BANK6模式控制寄存器的值
MRSRB7_Val EQU 0x00000020 ;BANK6模式控制寄存器的值
;----------------------- I/O Port Definitions ----------------------------------
;I/O端口定义,移植到其他处理器地址可能不同,需要修改
GPA_BASE EQU 0x56000000 ; GPA基地址
GPB_BASE EQU 0x56000010 ; GPB基地址
GPC_BASE EQU 0x56000020 ; GPC基地址
GPD_BASE EQU 0x56000030 ; GPD基地址
GPE_BASE EQU 0x56000040 ; GPE基地址
GPF_BASE EQU 0x56000050 ; GPF基地址
GPG_BASE EQU 0x56000060 ; GPG基地址
GPH_BASE EQU 0x56000070 ; GPH基地址
GPJ_BASE EQU 0x560000D0 ; GPJ基地址
GPCON_OFS EQU 0x00 ; 控制寄存器偏移地址
GPDAT_OFS EQU 0x04 ; 数据寄存器偏移地址
GPUP_OFS EQU 0x08 ; 上拉寄存器偏移地址
GPA_SETUP EQU 0 ;端口A设置
GPACON_Val EQU 0x000003FF ;端口A控制寄存器的值
GPB_SETUP EQU 0 ;端口B设置
GPBCON_Val EQU 0x00000000 ;端口B控制寄存器的值
GPBUP_Val EQU 0x00000000 ;端口B上拉寄存器的值
GPC_SETUP EQU 0 ;端口C设置
GPCCON_Val EQU 0x00000000 ;端口C控制寄存器的值
GPCUP_Val EQU 0x00000000 ;端口C上拉寄存器的值
GPE_SETUP EQU 0 ;端口E设置
GPECON_Val EQU 0x00000000 ;端口E控制寄存器的值
GPEUP_Val EQU 0x00000000 ;端口E上拉寄存器的值
GPF_SETUP EQU 0 ;端口F设置
GPFCON_Val EQU 0x00000000 ;端口F控制寄存器的值
GPFUP_Val EQU 0x00000000 ;端口F上拉寄存器的值
GPG_SETUP EQU 0 ;端口G设置
GPGCON_Val EQU 0x00000000 ;端口G控制寄存器的值
GPGUP_Val EQU 0x00000000 ;端口G上拉寄存器的值
GPH_SETUP EQU 0 ;端口H设置
GPHCON_Val EQU 0x00000000 ;端口H控制寄存器的值
GPHUP_Val EQU 0x00000000 ;端口H上拉寄存器的值
GPJ_SETUP EQU 0 ;端口J设置
GPJCON_Val EQU 0x00000000 ;端口J控制寄存器的值
GPJUP_Val EQU 0x00000000 ;端口J上拉寄存器的值
;----------------------- CODE --------------------------------------------------
;代码段,8字节对齐
PRESERVE8
; 存储区定义和程序入口点
; Startup Code must be linked first at Address at which it expects to run.
;resret区域,代码段,只读,ARM模式
AREA RESET, CODE, READONLY
ARM
IF :LNOT::DEF:__EVAL ;如果定义了__EVAL,则继续执行,如果没有则定义
IMPORT ||Image$$ER_ROM1$$RO$$Length|| ;引入RO输出区字节长度
IMPORT ||Image$$RW_RAM1$$RW$$Length|| ;引入RW输出区字节长度
ENDIF ;结束IF
Vectors LDR PC, Reset_Addr ;将复位地址装载到程序指针
LDR PC, Undef_Addr ;将未定义指令装载到程序指针
LDR PC, SWI_Addr ;将软件中断地址装载到程序指针
LDR PC, PAbt_Addr ;将预取终止地址装载到程序指针
LDR PC, DAbt_Addr ;将数据终止地址加载到程序指针
IF :DEF:__EVAL ;如果定义了__EVAL
DCD 0x4000 ;分配空间
ELSE ;否则
DCD ||Image$$ER_ROM1$$RO$$Length||+\;分配空间为RO输出区的字节长度
||Image$$RW_RAM1$$RW$$Length|| ;RW输出区的字节长度
ENDIF ;结束IF
LDR PC, IRQ_Addr ;将外部中断地址装载到程序指针
LDR PC, FIQ_Addr ;将快速中断地址装载到程序指针
IF :DEF:__RTX ;如果定义__RTX
IMPORT SWI_Handler ;定义软中断服务程序
IMPORT IRQ_Handler_RTX ;引入外部中断服务程序
ENDIF
Reset_Addr DCD Reset_Handler ;将复位中断服务程序入口地址赋给Reset_Addr
Undef_Addr DCD Undef_Handler ;将未定义中断服务程序入口地址赋给Undef_Addr
SWI_Addr DCD SWI_Handler ;将软中断中断服务程序入口地址赋给SWI_Addr
PAbt_Addr DCD PAbt_Handler ;将预取终止中断服务程序入口地址赋给PAbt_Addr
DAbt_Addr DCD DAbt_Handler ;将数据终止中断服务程序入口地址赋给DAbt_Addr
DCD 0 ;保留地址
IF :DEF:__RTX ;如果定义__RTX
IRQ_Addr DCD IRQ_Handler_RTX ;将快速中断中断服务程序入口地址赋给IRQ_Addr
ELSE;否则
IRQ_Addr DCD IRQ_Handler ;将外部中断中断服务程序入口地址赋给IRQ_Addr
ENDIF;结束IF
FIQ_Addr DCD FIQ_Handler ;将快速中断中断服务程序入口地址赋给FIQ_Addr
Undef_Handler B Undef_Handler ;跳转循环
IF :DEF:__RTX ;如果定义__RTX
ELSE ;否则
SWI_Handler B SWI_Handler ;跳转到软中断服务程序
ENDIF ;结束IF
PAbt_Handler B PAbt_Handler ;跳转到预取终止服务程序
DAbt_Handler B DAbt_Handler ;跳转到数据终止服务程序
IRQ_Handler PROC
EXPORT IRQ_Handler [WEAK];声明一个全局变量,同名符优先于本符号被使用
B .
ENDP
FIQ_Handler B FIQ_Handler ;跳转到快速中断服务程序
; Reset Handler
EXPORT Reset_Handler ;声明一个全局变量,同名符优先于本符号被使用
Reset_Handler
; Watchdog Setup ---------------------------------------------------------------
;看门狗设置
IF WT_SETUP != 0 ;如果WT_SETUP不为0
LDR R0, =WT_BASE ;加载看门狗基地址
LDR R1, =WTCON_Val ;加载看门口控制寄存器的值
LDR R2, =WTDAT_Val ;加载看门狗数据寄存器的值
STR R2, [R0, #WTCNT_OFS] ;将WTDAT_Val加载到看门狗计数寄存器
STR R2, [R0, #WTDAT_OFS] ;将WTDAT_Val加载到看门狗数据寄存器
STR R1, [R0, #WTCON_OFS] ;将WTCON_Val加载到看门狗控制寄存器
ENDIF
; Clock Setup ------------------------------------------------------------------
;时钟设置 ,如果没有定义NO_CLOCK_SETUP并且CLOCK_SETUP != 0则执行下面程序
IF (:LNOT:(:DEF:NO_CLOCK_SETUP)):LAND:(CLOCK_SETUP != 0)
LDR R0, =CLOCK_BASE ;将时钟基地址加载到R0
LDR R1, =LOCKTIME_Val ;加载PLL锁定时间计数器的值
STR R1, [R0, #LOCKTIME_OFS] ;将该值配置到PLL锁定时间计数器
MOV R1, #CLKDIVN_Val ;将时钟分频计数器的值加载到R1
STR R1, [R0, #CLKDIVN_OFS] ;将该值配置到时钟分频寄存器
LDR R1, =CAMDIVN_Val ;将摄像头分频值加载到R1
STR R1, [R0, #CAMDIVN_OFS] ;配置摄像头分频控制寄存器
LDR R1, =MPLLCON_Val ;将主锁相环控制寄存器的值加载到R1
STR R1, [R0, #MPLLCON_OFS] ;配置MPLL寄存器
LDR R1, =UPLLCON_Val ;将USB锁相环控制寄存器的值加载到R1
STR R1, [R0, #UPLLCON_OFS] ;配置UPLL寄存器
MOV R1, #CLKSLOW_Val ;将时钟减慢控制寄存器的值加载到R1
STR R1, [R0, #CLKSLOW_OFS] ;配置时钟减慢寄存器
LDR R1, =CLKCON_Val ;将时钟控制寄存器的值加载到R1
STR R1, [R0, #CLKCON_OFS] ;配置时钟控制寄存器
ENDIF;结束IF
; Memory Controller Setup ------------------------------------------------------
;存储控制设置,如果没有定义NO_MC_SETUP并且CLOCK_SETUP != 0,则执行下面程序
IF (:LNOT:(:DEF:NO_MC_SETUP)):LAND:(CLOCK_SETUP != 0)
LDR R0, =MC_BASE ;将存储控制寄存器基地址加载到R0
LDR R1, =BWSCON_Val ;将总线宽度和等待控制寄存器的值加载到R1
STR R1, [R0, #BWSCON_OFS] ;配置总线宽度和等待寄存器
LDR R1, =BANKCON0_Val ;将BANK0控制寄存器的值加载到R1
STR R1, [R0, #BANKCON0_OFS] ;配置BANK0寄存器
LDR R1, =BANKCON1_Val ;将BANK1控制寄存器的值加载到R1
STR R1, [R0, #BANKCON1_OFS] ;配置BANK1寄存器
LDR R1, =BANKCON2_Val ;将BANK2控制寄存器的值加载到R1
STR R1, [R0, #BANKCON2_OFS] ;配置BANK2寄存器
LDR R1, =BANKCON3_Val ;将BANK3控制寄存器的值加载到R1
STR R1, [R0, #BANKCON3_OFS] ;配置BANK3寄存器
LDR R1, =BANKCON4_Val ;将BANK4控制寄存器的值加载到R1
STR R1, [R0, #BANKCON4_OFS] ;配置BANK4寄存器
LDR R1, =BANKCON5_Val ;将BANK5控制寄存器的值加载到R1
STR R1, [R0, #BANKCON5_OFS] ;配置BANK5寄存器
LDR R1, =BANKCON6_Val ;将BANK6控制寄存器的值加载到R1
STR R1, [R0, #BANKCON6_OFS] ;配置BANK6寄存器
LDR R1, =BANKCON7_Val ;将BANK7控制寄存器的值加载到R1
STR R1, [R0, #BANKCON7_OFS] ;配置BANK7寄存器
LDR R1, =REFRESH_Val ;将DRAM/SDRAM控制寄存器的值加载到R1
STR R1, [R0, #REFRESH_OFS] ;配置DRAM/SDRAM刷新寄存器的值
MOV R1, #BANKSIZE_Val ;将可调节BANK大小的值加载到R1
STR R1, [R0, #BANKSIZE_OFS] ;配置可调节BANK大小寄存器
MOV R1, #MRSRB6_Val ;将BANK6模式控制寄存器的是加载到R1
STR R1, [R0, #MRSRB6_OFS] ;配置BANK6模式控制寄存器
MOV R1, #MRSRB7_Val ;将BANK7模式控制寄存器的值加载到R1
STR R1, [R0, #MRSRB7_OFS] ;配置BANK7模式控寄存器
ENDIF ;结束IF
; I/O Pins Setup ---------------------------------------------------------------
;I/O端口设置,如果没有定义NO_GP_SETUP并且GP_SETUP != 0,则执行以下程序
IF (:LNOT:(:DEF:NO_GP_SETUP)):LAND:(GP_SETUP != 0)
IF GPA_SETUP != 0 ;如果端口A设置不为0
LDR R0, =GPA_BASE ;将端口A的基地址加载到R0
LDR R1, =GPACON_Val ;将端口A的控制寄存器的值加载到R1
STR R1, [R0, #GPCON_OFS] ;配置端口A控制寄存器
ENDIF ;结束IF
IF GPB_SETUP != 0 ;如果端口B设置不为0
LDR R0, =GPB_BASE ;将端口B的基地址加载到R0
LDR R1, =GPBCON_Val ;将端口B的控制寄存器的值加载到R1
STR R1, [R0, #GPCON_OFS] ;配置端口B控制寄存器
LDR R1, =GPBUP_Val ;将端口B上拉控制寄存器的值加载到R1
STR R1, [R0, #GPUP_OFS] ;配置端口B上拉控制寄存器
ENDIF ;结束IF
IF GPC_SETUP != 0 ;如果端口C设置不为0
LDR R0, =GPC_BASE ;将端口C的基地址加载到R0
LDR R1, =GPCCON_Val ;将端口C的控制寄存器的值加载到R1
STR R1, [R0, #GPCON_OFS] ;配置端口C控制寄存器
LDR R1, =GPCUP_Val ;将端口C上拉控制寄存器的值加载到R1
STR R1, [R0, #GPUP_OFS] ;配置端口C上拉控制寄存器
ENDIF ;结束IF
IF GPD_SETUP != 0 ;如果端口D设置不为0
LDR R0, =GPD_BASE ;将端口D的基地址加载到R0
LDR R1, =GPDCON_Val ;将端口D的控制寄存器的值加载到R1
STR R1, [R0, #GPCON_OFS] ;配置端口D控制寄存器
LDR R1, =GPDUP_Val ;将端口D上拉控制寄存器的值加载到R1
STR R1, [R0, #GPUP_OFS] ;配置端口D上拉控制寄存器
ENDIF ;结束IF
IF GPE_SETUP != 0 ;如果端口E设置不为0
LDR R0, =GPE_BASE ;将端口E的基地址加载到R0
LDR R1, =GPECON_Val ;将端口E的控制寄存器的值加载到R1
STR R1, [R0, #GPCON_OFS] ;配置端口E控制寄存器
LDR R1, =GPEUP_Val ;将端口E上拉控制寄存器的值加载到R1
STR R1, [R0, #GPUP_OFS] ;配置端口E上拉控制寄存器
ENDIF ;结束IF
IF GPF_SETUP != 0 ;如果端口F设置不为0
LDR R0, =GPF_BASE ;将端口F的基地址加载到R0
LDR R1, =GPFCON_Val ;将端口F的控制寄存器的值加载到R1
STR R1, [R0, #GPCON_OFS] ;配置端口F控制寄存器
LDR R1, =GPFUP_Val ;将端口F上拉控制寄存器的值加载到R1
STR R1, [R0, #GPUP_OFS] ;配置端口F上拉控制寄存器
ENDIF ;结束IF
IF GPG_SETUP != 0 ;如果端口G设置不为0
LDR R0, =GPG_BASE ;将端口G的基地址加载到R0
LDR R1, =GPGCON_Val ;将端口G的控制寄存器的值加载到R1
STR R1, [R0, #GPCON_OFS] ;配置端口G控制寄存器
LDR R1, =GPGUP_Val ;将端口G上拉控制寄存器的值加载到R1
STR R1, [R0, #GPUP_OFS] ;配置端口G上拉控制寄存器上拉控制寄存器
ENDIF ;结束IF
IF GPH_SETUP != 0 ;如果端口H设置不为0
LDR R0, =GPH_BASE ;将端口H的基地址加载到R0
LDR R1, =GPHCON_Val ;将端口H的控制寄存器的值加载到R1
STR R1, [R0, #GPCON_OFS] ;配置端口H控制寄存器
LDR R1, =GPHUP_Val ;将端口H上拉控制寄存器的值加载到R1
STR R1, [R0, #GPUP_OFS] ;配置端口H上拉控制寄存器
ENDIF ;结束IF
IF GPJ_SETUP != 0 ;如果端口J设置不为0
LDR R0, =GPJ_BASE ;将端口J的基地址加载到R0
LDR R1, =GPJCON_Val ;将端口J的控制寄存器的值加载到R1
STR R1, [R0, #GPCON_OFS] ;配置端口J控制寄存器
LDR R1, =GPJUP_Val ;将端口J上拉控制寄存器的值加载到R1
STR R1, [R0, #GPUP_OFS] ;配置端口J上拉控制寄存器
ENDIF ;结束IF
ENDIF ;结束IF
; Copy Exception Vectors to Internal RAM ---------------------------------------
;拷贝异畅向量到内部RAM
IF :DEF:RAM_INTVEC ;如果定义RAM_INTVEC,则执行下面程序
ADR R8, Vectors ;读取向量原地址
LDR R9, =IRAM_BASE ;读取偏上SRAM的基地址
LDMIA R8!, {R0-R7} ;批量加载异常向量
STMIA R9!, {R0-R7} ;批量存储异常向量
LDMIA R8!, {R0-R7} ;加载程序入口地址
STMIA R9!, {R0-R7} ;存储程序入口地址
ENDIF
; Setup Stack for each mode ----------------------------------------------------
;配置每种模式栈的大小
LDR R0, =Stack_Top ;加载栈顶指针
; Enter Undefined Instruction Mode and set its Stack Pointer
;进入未定义模式并设定栈指针
MSR CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit ;将(Mode_UND | I_Bit | F_Bit)赋值给 CPSR_c即CPSR[7:0]
MOV SP, R0; ;栈顶指针地址赋值给SP指针
SUB R0, R0, #UND_Stack_Size ;分其栈指针
; Enter Abort Mode and set its Stack Pointer
;进入预取终止模式并设定栈指针
MSR CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit ;将(Mode_UND | I_Bit | F_Bit)赋值给 CPSR_c即CPSR[7:0]
MOV SP, R0 ;栈顶指针地址赋值给SP指针
SUB R0, R0, #ABT_Stack_Size ;分其栈指针
; Enter FIQ Mode and set its Stack Pointer
;进入快速中断式并设定栈指针
MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit ;将(Mode_UND | I_Bit | F_Bit)赋值给 CPSR_c即CPSR[7:0]
MOV SP, R0 ;栈顶指针地址赋值给SP指针
SUB R0, R0, #FIQ_Stack_Size ;分其栈指针
; Enter IRQ Mode and set its Stack Pointer
;进入外部中断模式并设定栈指针
MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit ;将(Mode_UND | I_Bit | F_Bit)赋值给 CPSR_c即CPSR[7:0]
MOV SP, R0 ;栈顶指针地址赋值给SP指针
SUB R0, R0, #IRQ_Stack_Size ;分其栈指针
; Enter Supervisor Mode and set its Stack Pointer
;进入管理模式并设定栈指针
MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit ;将(Mode_UND | I_Bit | F_Bit)赋值给 CPSR_c即CPSR[7:0]
MOV SP, R0 ;栈顶指针地址赋值给SP指针
SUB R0, R0, #SVC_Stack_Size ;分其栈指针
; Enter User Mode and set its Stack Pointer
;进入正常模式并设定栈指针
MSR CPSR_c, #Mode_USR ;将Mode_USR赋值给 CPSR_c即CPSR[7:0]
MOV SP, R0 ;栈顶指针地址赋值给SP指针
SUB SL, SP, #USR_Stack_Size ;分其栈指针
; Enter User Mode and set its Stack Pointer
;进入正常模式并设定栈指针
MSR CPSR_c, #Mode_USR
IF :DEF:__MICROLIB ;如果定义了__MICROLIB
EXPORT __initial_sp ;那么就声明__initial_sp
ELSE
MOV SP, R0 ;否则就设定用户模式栈指针
SUB SL, SP, #USR_Stack_Size ;分其栈指针
ENDIF
; Enter the C code -------------------------------------------------------------
;进入C代码区
IMPORT __main ;声明__main 函数
LDR R0, =__main ;加载__main 函数入口地址
BX R0 ;跳转到__main处
IF :DEF:__MICROLIB ;如果定义了__MICROLIB
EXPORT __heap_base ;则声明__heap_base
EXPORT __heap_limit ;声明__heap_limit
ELSE
; User Initial Stack & Heap
;用户初始化堆与栈,名称|.text|,代码区,只读
AREA |.text|, CODE, READONLY
IMPORT __use_two_region_memory ;__use_two_region_memory这是MDK的库函
EXPORT __user_initial_stackheap ;__user_initial_stackheap也是一个库函数,它的返回值有
__user_initial_stackheap
LDR R0, = Heap_Mem ;堆内存起始地址 -->R0
LDR R1, =(Stack_Mem + USR_Stack_Size) ;栈起始地址 -->R1
LDR R2, = (Heap_Mem + Heap_Size) ;堆顶 -->R2
LDR R3, = Stack_Mem ;栈顶地址 --> R3
BX LR ;子程序返回
ENDIF ;结束IF
END