LPC2xxx啟動代碼分析
/**********************************************************************************************
*File: startup.s
*Author: Embest w.h.xie 2005.02.21
*Desc: lpc22xx/lpc212x/lpc211x/lpc210x startup code
*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#系統(tǒng)模式
#中斷屏蔽位
.EQU I_Bit, 0x80 //IRQ中斷控制位,當被置位時,IRQ中斷被禁止
.EQU F_Bit, 0x40 //FIQ中斷控制位,當被置位時,F(xiàn)IQ中斷被禁止
#狀態(tài)屏蔽位
.EQU T_bit, 0x20//T位,置位時在Thumb模式下運行,清零時在ARM下運行
#定義程序入口點
.globl _start
.code 32
.TEXT
_start:
#中斷向量表
Vectors:
LDR PC, Reset_Addr//把Reset_Addr地址處的內(nèi)容放入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: #地址標號處存放一個無效的數(shù)據(jù)
.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}//入棧,現(xiàn)場數(shù)據(jù)保護
MOV r1, sp //把堆棧指針SP存入R1中
MRS r0, spsr//把SPSR值存入R0,SPSR值為產(chǎn)生軟中斷時的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}^ //出棧,現(xiàn)場數(shù)據(jù)恢復
#快速響應中斷的中斷服務自程序的入口地址
FIQ_Handler:
STMFD SP!, {R0-R3, LR} //入棧的現(xiàn)場保護
# BL FIQ_Exception//進入FIQ的中斷處理程序
LDMFD SP!, {R0-R3, LR} //出棧,恢復現(xiàn)場
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,二者相減
//如果相等則說明當前處在用戶模式下,需要通過產(chǎn)生11號軟中斷進入系統(tǒng)模式。因為下面的初始化堆棧
//需要在不同的工作模式下切換,而在用戶模式下不能直接切換,只有系統(tǒng)模式可以,所以要通過產(chǎn)生11
//號軟中斷切換到用戶模式。
SWIEQ #11
BL InitStack //進行堆棧初始化工作
ARM啟動代碼分析-philips的LPC2xxx系列32006-7-24 14:33:00
#------------------------------------------------------------------------------
#-初始化C變量
#------------------------
#-下表由連接器自動產(chǎn)生
#- RO:只讀=代碼區(qū)。
#- RW:可讀可寫=預先初始化的數(shù)據(jù)(初始化的全局變量)和預先被清零的數(shù)據(jù)(未初始化的全局變量)。.
#- ZI:預先被清零的數(shù)據(jù)區(qū)(未初始化的全局變量)
#-預先被初始化的數(shù)據(jù)區(qū)定位在代碼區(qū)之后。
#-預先被清零的數(shù)據(jù)區(qū)定位在預先被初始化的數(shù)據(jù)區(qū)之后。
#-注意數(shù)據(jù)區(qū)的位置:
#- I如果用ARM SDT,當鏈接器選擇no -rw-base時,數(shù)據(jù)區(qū)被映射在代碼區(qū)之后
#-你可以把數(shù)據(jù)區(qū)房子內(nèi)部的SRAM( -rw-base=0x40 or 0x34)中
#-或者放在外部的SRAM( -rw-base=0x2000000 )中。
#-注意:為了提高代碼的密度,預先被初始化的數(shù)據(jù)必須盡可能的少。
#------------------------------------------------------------------------------
#該部分程序功能:先判斷當前是在RAM中運行還是在FLASH中運行,如果在FLASH中運行,先把FLASH
#中的預先賦值的RW段數(shù)據(jù)和未賦值的ZI段數(shù)據(jù)都搬移到RAM區(qū)中,再把ZI段數(shù)據(jù)全部清零;如果程#序就是在RAM中運行,則直接把ZI段數(shù)據(jù)清零。
.extern Image_RO_Limit /* ROM區(qū)中數(shù)據(jù)段的起始地址*/
.extern Image_RW_Base /* RW段起始地址*/
.extern Image_ZI_Base /* ZI段的起始地址*/
.extern Image_ZI_Limit /* ZI段的結(jié)束地址加1 */
ldr r0, =Image_RO_Limit /*取ROM區(qū)中數(shù)據(jù)段的首地址*/
ldr r1, =Image_RW_Base/*取RAM區(qū)中RW段的目標首地址*/
ldr r3, =Image_ZI_Base/*取RAM區(qū)中ZI段的首地址*/
cmp r0, r1/*比較ROM區(qū)中數(shù)據(jù)段首地址和RAM區(qū)中RW段目標首地址*/
beq NoRW /*相等代表當前是在RAM中運行*/
LoopRw: cmp r1, r3 /*不相等則和RAM區(qū)中ZI段的目標地址比較*/
ldrcc r2, [r0], #4/*如果r1
strcc r2, [r1], #4/*如果r1
bcc LoopRw/*如果r1
NoRW: ldr r1, =Image_ZI_Limit /*取ZI段的結(jié)束地址*/
mov r2, #0 /*將r2賦0*/
LoopZI: cmp r3, r1/*將ZI段清零*/
strcc r2, [r3], #4/*如果r3
bcc LoopZI /*如果r3
.externMain /*聲明外部變量*/
B Main /*t跳轉(zhuǎn)到用戶的主程序入口*/
#為每一種模式建立堆棧,ARM堆棧指針向下生長
InitStack:
MOV R1, LR //把該子程序返回地址保留在R1中
LDR R0, =Top_Stack//取棧定地址到R0中
#進入未定義模式,并禁止FIQ中斷和IRQ中斷
MSR CPSR_c, #Mode_UND|I_Bit|F_Bit
#設置未定義模式下堆棧的棧頂指針
MOV SP, R0
SUB R0, R0, #UND_Stack_Size#未定義模式下堆棧深度
#進入終止模式,并禁止禁止FIQ中斷和IRQ中斷
MSR CPSR_c, #Mode_ABT|I_Bit|F_Bit
#緊接著未定義模式下的堆棧,設置終止模式下棧頂指針
MOV SP, R0
SUB R0, R0, #ABT_Stack_Size#終止模式下堆棧深度
#進入FIQ模式,并禁止FIQ中斷和IRQ中斷
MSR CPSR_c, #Mode_FIQ|I_Bit|F_Bit
#緊接著終止模式下的堆棧,設置下FIQ模式下棧頂指針
MOV SP, R0
SUB R0, R0, #FIQ_Stack_Size#FIQ模式下的堆棧深度
#進入IRQ模式,并禁止FIQ中斷和IRQ中斷
MSR CPSR_c, #Mode_IRQ|I_Bit|F_Bit
#緊接著FIQ模式下的堆棧,設置IRQ模式下的棧頂指針
MOV SP, R0
SUB R0, R0, #IRQ_Stack_Size#IRQ模式下的堆棧深度
#進入超級用戶模式,并禁止FIQ中斷和IRQ中斷
MSR CPSR_c, #Mode_SVC|I_Bit|F_Bit
#緊接著IRQ模式下的堆棧,設置超級用戶下的棧頂指針
MOV SP, R0
SUB R0, R0, #SVC_Stack_Size#超級用戶下的堆棧深度
#設置進入用戶模式
MSR CPSR_c, #Mode_USR
#緊接著超級用戶模式下的堆棧,設置用戶模式下的棧頂指針,剩余的空間都開辟為堆棧
MOV SP, R0
MOV PC, R1 #堆棧初始化子程序返回
#重映射SRAM區(qū)
RemapSRAM:
MOV R0, #0x40000000 //RAM區(qū)首地址
LDR R1, =Vectors //向量表首地址
#下面一段程序是把從0x00000000開始的64個字節(jié)(FLASH中的中斷向量表和地址表)搬移到以
#0x40000000為首地址的RAM區(qū)中
LDMIAR1!, {R2-R9}//把以[R1]為首地址的32個字節(jié)數(shù)據(jù)裝載到R2-R9中
STMIAR0!, {R2-R9}//把R2-R9中的數(shù)據(jù)存入以[R0]為首地址的單元中
LDMIAR1!, {R2-R9}//把以[R1]為首地址的32個字節(jié)數(shù)據(jù)裝載到R2-R9中
STMIAR0!, {R2-R9}////把R2-R9中的數(shù)據(jù)存入以[R0]為首地址的單元中
#下面幾行代碼設置存儲器映射控制寄存器
LDR R0, =MEMMAP//取MEMMAP地址到R0
MOV R1, #0x02
STR R1, [R0]//給MEMMAP賦值為0x02,設置中斷向量從RAM區(qū)從新映射
mov pc,lr //跳轉(zhuǎn)到主程序
#下面一段程序代碼是進入軟中斷來切換系統(tǒng)的工作模式,當希望從一種模式切換入另一種模式時,可以通
#過調(diào)用下面對應標號的程序段進入軟中斷。在軟中斷處理程序中會根據(jù)所給定的中斷號處理,執(zhí)行SWI #num后軟中斷號被存入R0中。
.globl disable_IRQ
.globl restore_IRQ
.globl ToSys
.globl ToUser
#禁止IRQ
disable_IRQ:
STMFD SP!, {LR} //把LR值壓入堆棧
swi #0 //產(chǎn)生0號軟中斷,0 -〉R0
LDMFD SP!, {pc} //恢復PC值,返回
#恢復IRQ
restore_IRQ:
STMFD SP!, {LR} //把LR值壓入堆棧
swi #1 //產(chǎn)生1號軟中斷,1 –〉R0
LDMFD SP!, {pc} //恢復PC值,返回
#進入系統(tǒng)工作模式
ToSys:
STMFD SP!, {LR} //把LR值壓入堆棧
swi #11 //產(chǎn)生11號軟中斷,11 –〉R0
LDMFD SP!, {pc} //恢復PC值,返回
#進入用戶工作模式
ToUser:
STMFD SP!, {LR} //把LR值壓入堆棧
swi #12 //產(chǎn)生12號軟中斷,11 –〉R0
LDMFD SP!, {pc} //恢復PC值,返回
關(guān)鍵詞:
LPC2xxx啟動代
評論