ARM启动代码分析-philips的LPC2xxx系列
时间:11-10
来源:互联网
点击:
**********************************************************************************************
*File: startup.s
*Author: Embest w.h.xie 2005.02.21
*Desc: lpc22xx\lpc212x\lpc211x\lpc210x startup co de
*History:
* note modify: cui jian jie 2006-4-25
*comment:
**********************************************************************************************/
# 处理器的七种工作方式的常量定义
.EQU Mode_USR, 0x10 #用户模式
.EQU Mode_FIQ, 0x11 #FIQ模式
.EQU Mode_IRQ, 0x12 #IRQ模式
.EQU Mode_SVC, 0x13 #超级用户模式
.EQU Mode_ABT, 0x17 #终止模式
.EQU Mode_UND, 0x1B #未定义模式
.EQU Mode_SYS, 0x1F #系统模式
# 中断屏蔽位
.EQU I_Bit, 0x80 //IRQ中断控制位,当被置位时,IRQ中断被禁止
.EQU F_Bit, 0x40 //FIQ中断控制位,当被置位时,FIQ中断被禁止
# 状态屏蔽位
.EQU T_bit, 0x20 //T位,置位时在Thumb模式下运行,清零时在ARM下运行
# 定义程序入口点
.globl _start
.co de 32
.TEXT
_start:
# 中断向量表
Vectors:
LDR PC, Reset_Addr //把Reset_Addr地址处的内容放入PC中
LDR PC, Undef_Addr
LDR PC, SWI_Addr
LDR PC, PAbt_Addr
LDR PC, DAbt_Addr
.long 0xb9205f80 @ keep interrupt vectors sum is 0
LDR PC, [PC, #-0xff0] //当前PC值减去0xFF0等于IRQ中断入口地址
LDR PC, FIQ_Addr
#地址表
Reset_Addr: #该地址标号存放Reset_Handler程序段的入口地址
.long Reset_Handler
Undef_Addr: #该地址标号存放Undef_Handler程序段的入口地址
.long Undef_Handler
SWI_Addr: #该地址标号存放SWI_Handler程序段的入口地址
.long SWI_Handler
PAbt_Addr: #该地址标号存放PAbt_Handler程序段的入口地址
.long PAbt_Handler
DAbt_Addr:
.long DAbt_Handler
.long 0
IRQ_Addr: #地址标号处存放一个无效的数据
.long 0
FIQ_Addr: #该地址标号存放FIQ_Handler程序段的入口地址
.long FIQ_Handler
Undef_Handler:
B Undef_Handler
PAbt_Handler:
B PAbt_Handler
DAbt_Handler:
B DAbt_Handler
#软中断的中断服务子程序入口地址
SWI_Handler:
STMFD sp!, {r0-r3, r12, lr} //入栈,现场数据保护
MOV r1, sp //把堆栈指针SP存入R1中
MRS r0, spsr //把SPSR值存入R0,SPSR值为产生软中断时的CPSR
TST r0, #T_bit //判断R0(SPSR)的T位是否为0
#SPSR的T位不为0,工作在Thumb模式下
LDRNEH r0, [lr,#-2] //SPSR的T位不为0,则[lr-2]-〉r0
BICNE r0, r0, #0xFF00 // SPSR的T位不为0,清除r0的Bit8~Bit15位
# SPSR的T位为0,工作在ARM模式下
LDREQ r0, [lr,#-4] // SPSR的T位为0,则[lr-4] -〉r0
BICEQ r0, r0, #0xFF000000 // SPSR的T位为0,清除r0的Bit24~Bit131位
# R0 is interrupt number //R0是中断号
# R1 is stack point //R1是堆栈指针
BL SWI_Exception //进入软中断处理程序
LDMFD sp!, {r0-r3, r12, pc}^ //出栈,现场数据恢复
# 快速响应中断的中断服务自程序的入口地址
FIQ_Handler:
STMFD SP!, {R0-R3, LR} //入栈的现场保护
# BL FIQ_Exception //进入FIQ的中断处理程序
LDMFD SP!, {R0-R3, LR} //出栈,恢复现场
SUBS PC, LR, #4 //返回到主程序
# 复位后程序处理的入口地址
Reset_Handler:
BL RemapSRAM //进行存储器映射的操作
#下面几行代码用来判断当前的工作模式
MRS R0, CPSR //读CPSR到寄存器R0
AND R0, R0, #0x1F //R0 = R0 AND 0x1F
CMP R0, #Mode_USR //比较R0 和 #Mode_USR,二者相减
//如果相等则说明当前处在用户模式下,需要通过产生11号软中断进入系统模式。因为下面的初始化堆栈
//需要在不同的工作模式下切换,而在用户模式下不能直接切换,只有系统模式可以,所以要通过产生11
//号软中断切换到用户模式。
SWIEQ #11
BL InitStack //进行堆栈初始化工作
ARM启动代码分析-philips的LPC2xxx系列32006-7-24 14:33:00
#------------------------------------------------------------------------------
#- 初始化C变量
#------------------------
#- 下表由连接器自动产生
#- RO: 只读=代码区。
#- RW: 可读可写=预先初始化的数据(初始化的全局变量)和预先被清零的数据(未初始化的全局变量)。.
#- ZI: 预先被清零的数据区(未初始化的全局变量)
#- 预先被初始化的数据区定位在代码区之后。
#- 预先被清零的数据区定位在预先被初始化的数据区之后。
#- 注意数据区的位置 :
#- I如果用 ARM SDT, 当链接器选择no -rw-base时, 数据区被映射在代码区之后
#- 你可以把数据区房子内部的SRAM( -rw-base=0x40 or 0x34)中
#- 或者放在外部的SRAM( -rw-base=0x2000000 )中。
#- 注意:为了提高代码的密度,预先被初始化的数据必须尽可能的少。
#------------------------------------------------------------------------------
#该部分程序功能:先判断当前是在RAM中运行还是在FLASH中运行,如果在FLASH中运行,先把FLASH
#中的预先赋值的RW段数据和未赋值的ZI段数据都搬移到RAM区中,再把ZI段数据全部清零;如果程#序就是在RAM中运行,则直接把ZI段数据清零。
.extern Image_RO_Limit /* ROM区中数据段的起始地址*/
.extern Image_RW_Base /* RW段起始地址 */
.extern Image_ZI_Base /* ZI段的起始地址*/
.extern Image_ZI_Limit /* ZI段的结束地址加1 */
ldr r0, =Image_RO_Limit /* 取ROM区中数据段的首地址 */
ldr r1, =Image_RW_Base /* 取RAM区中RW段的目标首地址*/
ldr r3, =Image_ZI_Base /*取RAM区中ZI段的首地址 */
cmp r0, r1 /* 比较ROM区中数据段首地址和RAM区中RW段目标首地址 */
beq NoRW /*相等代表当前是在RAM中运行*/
LoopRw: cmp r1, r3 /*不相等则和RAM区中ZI段的目标地址比较*/
ld
*File: startup.s
*Author: Embest w.h.xie 2005.02.21
*Desc: lpc22xx\lpc212x\lpc211x\lpc210x startup co
*History:
* note modify: cui jian jie 2006-4-25
*comment:
**********************************************************************************************/
# 处理器的七种工作方式的常量定义
.EQU Mode_USR, 0x10 #用户模式
.EQU Mode_FIQ, 0x11 #FIQ模式
.EQU Mode_IRQ, 0x12 #IRQ模式
.EQU Mode_SVC, 0x13 #超级用户模式
.EQU Mode_ABT, 0x17 #终止模式
.EQU Mode_UND, 0x1B #未定义模式
.EQU Mode_SYS, 0x1F #系统模式
# 中断屏蔽位
.EQU I_Bit, 0x80 //IRQ中断控制位,当被置位时,IRQ中断被禁止
.EQU F_Bit, 0x40 //FIQ中断控制位,当被置位时,FIQ中断被禁止
# 状态屏蔽位
.EQU T_bit, 0x20 //T位,置位时在Thumb模式下运行,清零时在ARM下运行
# 定义程序入口点
.globl _start
.co
.TEXT
_start:
# 中断向量表
Vectors:
LDR PC, Reset_Addr //把Reset_Addr地址处的内容放入PC中
LDR PC, Undef_Addr
LDR PC, SWI_Addr
LDR PC, PAbt_Addr
LDR PC, DAbt_Addr
.long 0xb9205f80 @ keep interrupt vectors sum is 0
LDR PC, [PC, #-0xff0] //当前PC值减去0xFF0等于IRQ中断入口地址
LDR PC, FIQ_Addr
#地址表
Reset_Addr: #该地址标号存放Reset_Handler程序段的入口地址
.long Reset_Handler
Undef_Addr: #该地址标号存放Undef_Handler程序段的入口地址
.long Undef_Handler
SWI_Addr: #该地址标号存放SWI_Handler程序段的入口地址
.long SWI_Handler
PAbt_Addr: #该地址标号存放PAbt_Handler程序段的入口地址
.long PAbt_Handler
DAbt_Addr:
.long DAbt_Handler
.long 0
IRQ_Addr: #地址标号处存放一个无效的数据
.long 0
FIQ_Addr: #该地址标号存放FIQ_Handler程序段的入口地址
.long FIQ_Handler
Undef_Handler:
B Undef_Handler
PAbt_Handler:
B PAbt_Handler
DAbt_Handler:
B DAbt_Handler
#软中断的中断服务子程序入口地址
SWI_Handler:
STMFD sp!, {r0-r3, r12, lr} //入栈,现场数据保护
MOV r1, sp //把堆栈指针SP存入R1中
MRS r0, spsr //把SPSR值存入R0,SPSR值为产生软中断时的CPSR
TST r0, #T_bit //判断R0(SPSR)的T位是否为0
#SPSR的T位不为0,工作在Thumb模式下
LDRNEH r0, [lr,#-2] //SPSR的T位不为0,则[lr-2]-〉r0
BICNE r0, r0, #0xFF00 // SPSR的T位不为0,清除r0的Bit8~Bit15位
# SPSR的T位为0,工作在ARM模式下
LDREQ r0, [lr,#-4] // SPSR的T位为0,则[lr-4] -〉r0
BICEQ r0, r0, #0xFF000000 // SPSR的T位为0,清除r0的Bit24~Bit131位
# R0 is interrupt number //R0是中断号
# R1 is stack point //R1是堆栈指针
BL SWI_Exception //进入软中断处理程序
LDMFD sp!, {r0-r3, r12, pc}^ //出栈,现场数据恢复
# 快速响应中断的中断服务自程序的入口地址
FIQ_Handler:
STMFD SP!, {R0-R3, LR} //入栈的现场保护
# BL FIQ_Exception //进入FIQ的中断处理程序
LDMFD SP!, {R0-R3, LR} //出栈,恢复现场
SUBS PC, LR, #4 //返回到主程序
# 复位后程序处理的入口地址
Reset_Handler:
BL RemapSRAM //进行存储器映射的操作
#下面几行代码用来判断当前的工作模式
MRS R0, CPSR //读CPSR到寄存器R0
AND R0, R0, #0x1F //R0 = R0 AND 0x1F
CMP R0, #Mode_USR //比较R0 和 #Mode_USR,二者相减
//如果相等则说明当前处在用户模式下,需要通过产生11号软中断进入系统模式。因为下面的初始化堆栈
//需要在不同的工作模式下切换,而在用户模式下不能直接切换,只有系统模式可以,所以要通过产生11
//号软中断切换到用户模式。
SWIEQ #11
BL InitStack //进行堆栈初始化工作
ARM启动代码分析-philips的LPC2xxx系列32006-7-24 14:33:00
#------------------------------------------------------------------------------
#- 初始化C变量
#------------------------
#- 下表由连接器自动产生
#- RO: 只读=代码区。
#- RW: 可读可写=预先初始化的数据(初始化的全局变量)和预先被清零的数据(未初始化的全局变量)。.
#- ZI: 预先被清零的数据区(未初始化的全局变量)
#- 预先被初始化的数据区定位在代码区之后。
#- 预先被清零的数据区定位在预先被初始化的数据区之后。
#- 注意数据区的位置 :
#- I如果用 ARM SDT, 当链接器选择no -rw-base时, 数据区被映射在代码区之后
#- 你可以把数据区房子内部的SRAM( -rw-base=0x40 or 0x34)中
#- 或者放在外部的SRAM( -rw-base=0x2000000 )中。
#- 注意:为了提高代码的密度,预先被初始化的数据必须尽可能的少。
#------------------------------------------------------------------------------
#该部分程序功能:先判断当前是在RAM中运行还是在FLASH中运行,如果在FLASH中运行,先把FLASH
#中的预先赋值的RW段数据和未赋值的ZI段数据都搬移到RAM区中,再把ZI段数据全部清零;如果程#序就是在RAM中运行,则直接把ZI段数据清零。
.extern Image_RO_Limit /* ROM区中数据段的起始地址*/
.extern Image_RW_Base /* RW段起始地址 */
.extern Image_ZI_Base /* ZI段的起始地址*/
.extern Image_ZI_Limit /* ZI段的结束地址加1 */
ldr r0, =Image_RO_Limit /* 取ROM区中数据段的首地址 */
ldr r1, =Image_RW_Base /* 取RAM区中RW段的目标首地址*/
ldr r3, =Image_ZI_Base /*取RAM区中ZI段的首地址 */
cmp r0, r1 /* 比较ROM区中数据段首地址和RAM区中RW段目标首地址 */
beq NoRW /*相等代表当前是在RAM中运行*/
LoopRw: cmp r1, r3 /*不相等则和RAM区中ZI段的目标地址比较*/
ld
ARM启动代码LPC2xxx系 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)