新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 關(guān)于啟動(dòng)代碼2440init.s(一)

關(guān)于啟動(dòng)代碼2440init.s(一)

作者: 時(shí)間:2016-11-21 來源:網(wǎng)絡(luò) 收藏
停滯了這么長的時(shí)間沒有寫博客,這次獻(xiàn)上啟動(dòng)代碼吧,也就是我們通常所說的bootloader了。這里獻(xiàn)上別人整理出來的東西,光看啟動(dòng)代碼我都花了挺長的時(shí)間,關(guān)鍵是為了通過啟動(dòng)代碼知道開機(jī)時(shí)板子是怎么運(yùn)作的,對硬件理解非常有用。順便說一下,啟動(dòng)代碼每個(gè)程序都有,文件叫做2440init.s,匯編的哈,看之前好好去看看匯編的內(nèi)容去吧。哇咔咔~廢話少說,獻(xiàn)上程序,程序從ENTRY開始執(zhí)行,看到前面眼花繚亂那些其實(shí)是宏來的,一開始從ResetEntry執(zhí)行。慢慢分析去吧,作者XXX講的挺詳細(xì)的了。

; NAME: 2440INIT.S
; DESC: C start up codes
;Configure memory, ISR ,stacks
;Initialize C-variables
;完全注釋;=========================================
; NAME: 2440INIT.S
; DESC: C start up codes
;Configure memory, ISR ,stacks
;Initialize C-variables
;完全注釋=============================================
; HISTORY:
; 2002.02.25:kwtark: ver 0.0
; 2002.03.20:purnnamu: Add some functions for testing STOP,Sleep mode
; 2003.03.14:DonGo: Modified for 2440.
; 2009 06.24:Tinko Modified
;=========================================


;匯編不能使用include包含頭文件,所有用Get
;匯編也不認(rèn)識(shí)*.h 文件,所有只能用*.inc
GET option.inc ;定義芯片相關(guān)的配置
GET memcfg.inc ;定義存儲(chǔ)器配置
GET 2440addr.inc ;定義了寄存器符號(hào)


;REFRESH寄存器[22]bit : 0- auto refresh; 1 - self refresh
BIT_SELFREFRESH EQU (1<<22) ;用于節(jié)電模式中,SDRAM自動(dòng)刷新


;處理器模式常量: CPSR寄存器的后5位決定目前處理器模式 M[4:0]
USERMODE EQU 0x10
FIQMODE EQU 0x11
IRQMODE EQU 0x12
SVCMODE EQU 0x13
ABORTMODE EQU 0x17
UNDEFMODE EQU 0x1b
MODEMASK EQU 0x1f ;M[4:0]
NOINT EQU 0xc0


;定義處理器各模式下堆棧地址常量
UserStack EQU (_STACK_BASEADDRESS-0x3800) ;0x33ff4800 ~ _STACK_BASEADDRESS定義在option.inc中
SVCStack EQU (_STACK_BASEADDRESS-0x2800) ;0x33ff5800 ~
UndefStack EQU (_STACK_BASEADDRESS-0x2400) ;0x33ff5c00 ~
AbortStack EQU (_STACK_BASEADDRESS-0x2000) ;0x33ff6000 ~
IRQStack EQU (_STACK_BASEADDRESS-0x1000) ;0x33ff7000 ~
FIQStack EQU (_STACK_BASEADDRESS-0x0) ;0x33ff8000 ~


;arm處理器有兩種工作狀態(tài) 1.arm:32位 這種工作狀態(tài)下執(zhí)行字對準(zhǔn)的arm指令 2.Thumb:16位 這種工作狀
;態(tài)執(zhí)行半字對準(zhǔn)的Thumb指令
;因?yàn)樘幚砥鞣譃?6位 32位兩種工作狀態(tài) 程序的編譯器也是分16位和32兩種編譯方式 所以下面的程序用
;于根據(jù)處理器工作狀態(tài)確定編譯器編譯方式
;code16偽指令指示匯編編譯器后面的指令為16位的thumb指令
;code32偽指令指示匯編編譯器后面的指令為32位的arm指令
;
;Arm上電時(shí)處于ARM狀態(tài),故無論指令為ARM集或Thumb集,都先強(qiáng)制成ARM集,待init.s初始化完成后
;再根據(jù)用戶的編譯配置轉(zhuǎn)換成相應(yīng)的指令模式。為此,定義變量THUMBCODE作為指示,跳轉(zhuǎn)到main之前
;根據(jù)其值切換指令模式
;
;這段是為了統(tǒng)一目前的處理器工作狀態(tài)和軟件編譯方式(16位編譯環(huán)境使用tasm.exe編譯
;Check if tasm.exe(armasm -16 ...@ADS 1.0) is used.
GBLL THUMBCODE ;定義THUMBCODE全局變量注意EQU所定義的宏與變量的區(qū)別

[ {CONFIG} = 16 ;如果發(fā)現(xiàn)是在用16位代碼的話(編譯選項(xiàng)中指定使用thumb指令)

THUMBCODE SETL {TRUE} ;一方面把THUMBCODE設(shè)置為TURE

CODE32 ;另一方面暫且把處理器設(shè)置成為ARM模式,以方便初始化

| ;(|表示else)如果編譯選項(xiàng)本來就指定為ARM模式
THUMBCODE SETL {FALSE} ;把THUMBCODE設(shè)置為FALSE就行了

] ;結(jié)束


MACRO ;一個(gè)根據(jù)THUMBCODE把PC寄存的值保存到LR的宏
MOV_PC_LR ;宏名稱
[ THUMBCODE ;如果定義了THUMBCODE,則
bx lr ;在ARM模式中要使用BX指令轉(zhuǎn)跳到THUMB指令,并轉(zhuǎn)換模式. bx指令會(huì)根據(jù)PC最后1位來確定是否進(jìn)入thumb狀態(tài)
| ;否則,
mov pc,lr ;如果目標(biāo)地址也是ARM指令的話就采用這種方式
]
MEND ;宏定義結(jié)束標(biāo)志

MACRO ;和上面的宏一樣,只是多了一個(gè)相等的條件
MOVEQ_PC_LR
[ THUMBCODE
bxeq lr
|
moveq pc,lr
]
MEND


;=======================================================================================
;下面這個(gè)宏是用于第一次查表過程的實(shí)現(xiàn)中斷向量的重定向,如果你比較細(xì)心的話就是發(fā)現(xiàn)
;在_ISR_STARTADDRESS=0x33FF_FF00里定義的第一級(jí)中斷向量表是采用型如Handle***的方式的.
;而在程序的ENTRY處(程序開始處)采用的是b Handler***的方式.
;在這里Handler***就是通過HANDLER這個(gè)宏和Handle***建立聯(lián)系的.
;這種方式的優(yōu)點(diǎn)就是正真定義的向量數(shù)據(jù)在內(nèi)存空間里,而不是在ENTRY處的ROM(FLASH)空間里,
;這樣,我們就可以在程序里靈活的改動(dòng)向量的數(shù)據(jù)了.
;========================================================================================
;;這段程序用于把中斷服務(wù)程序的首地址裝載到pc中,有人稱之為“加載程序”。
;本初始化程序定義了一個(gè)數(shù)據(jù)區(qū)(在文件最后),34個(gè)字空間,存放相應(yīng)中斷服務(wù)程序的首地址。每個(gè)字
;空間都有一個(gè)標(biāo)號(hào),以Handle***命名。
;在向量中斷模式下使用“加載程序”來執(zhí)行中斷服務(wù)程序。
;這里就必須講一下向量中斷模式和非向量中斷模式的概念
;向量中斷模式是當(dāng)cpu讀取位于0x18處的IRQ中斷指令的時(shí)候,系統(tǒng)自動(dòng)讀取對應(yīng)于該中斷源確定地址上的;
;指令取代0x18處的指令,通過跳轉(zhuǎn)指令系統(tǒng)就直接跳轉(zhuǎn)到對應(yīng)地址
;函數(shù)中 節(jié)省了中斷處理時(shí)間提高了中斷處理速度標(biāo) 例如 ADC中斷的向量地址為0xC0,則在0xC0處放如下
;代碼:ldr PC,=HandlerADC 當(dāng)ADC中斷產(chǎn)生的時(shí)候系統(tǒng)會(huì)
;自動(dòng)跳轉(zhuǎn)到HandlerADC函數(shù)中
;非向量中斷模式處理方式是一種傳統(tǒng)的中斷處理方法,當(dāng)系統(tǒng)產(chǎn)生中斷的時(shí)候,系統(tǒng)將interrupt
;pending寄存器中對應(yīng)標(biāo)志位置位 然后跳轉(zhuǎn)到位于0x18處的統(tǒng)一中斷
;函數(shù)中 該函數(shù)通過讀取interrupt pending寄存器中對應(yīng)標(biāo)志位 來判斷中斷源 并根據(jù)優(yōu)先級(jí)關(guān)系再跳到
;對應(yīng)中斷源的處理代碼中
;
;H|------| H|------| H|------| H|------| H|------|
; |/ / / | |/ / / | |/ / / | |/ / / | |/ / / |
; |------|<----sp |------| |------| |------| |------|<------sp
;L| | |------|<----sp L|------| |-isr--| |------| isr==>pc
; | | | | |--r0--|<----sp |---r0-|<----sp L|------| r0==>r0
; (0) (1) (2) (3) (4)

MACRO
$HandlerLabel HANDLER $HandleLabel(入口地址)

$HandlerLabel ;標(biāo)號(hào)
sub sp,sp,#4 ;(1)減少sp(用于存放轉(zhuǎn)跳地址)
stmfd sp!,{r0} ;(2)把工作寄存器壓入棧(lr does not push because it return to original address)
ldr r0,=$HandleLabel;將HandleXXX的址址放入r0
ldr r0,[r0] ;把HandleXXX所指向的內(nèi)容(也就是中斷程序的入口)放入r0
str r0,[sp,#4] ;(3)把中斷服務(wù)程序(ISR)壓入棧
ldmfd sp!,{r0,pc} ;(4)用出棧的方式恢復(fù)r0的原值和為pc設(shè)定新值(也就完成了到ISR的轉(zhuǎn)跳)
MEND


;=========================================================================================
;在這里用IMPORT偽指令(和c語言的extren一樣)引入|Image$$RO$$Base|,|Image$$RO$$Limit|...
;這些變量是通過ADS的工程設(shè)置里面設(shè)定的RO Base和RW Base設(shè)定的,
;最終由編譯腳本和連接程序?qū)氤绦?
;那為什么要引入這玩意呢,最簡單的用處是可以根據(jù)它們拷貝自已
;==========================================================================================
;Image$$RO$$Base等比較古怪的變量是編譯器生成的。RO, RW, ZI這三個(gè)段都保存在Flash中,但RW,ZI在Flash中
;的地址肯定不是程序運(yùn)行時(shí)變量所存儲(chǔ)的位置,因此我們的程序在初始化時(shí)應(yīng)該把Flash中的RW,ZI拷貝到RAM的對應(yīng)位置。
;一般情況下,我們可以利用編譯器替我們實(shí)現(xiàn)這個(gè)操作。比如我們跳轉(zhuǎn)到main()時(shí),使用 b __Main,編譯器就會(huì)在__Main
;和Main之間插入一段匯編代碼,來替我們完成RW,ZI段的初始化。 如果我們使用b Main, 那么初始化工作要我們自己做。
;編譯器會(huì)生成如下變量告訴我們RO,RW,ZI三個(gè)段應(yīng)該位于什么位置,但是它并沒有告訴我們RW,ZI在Flash中存儲(chǔ)在什么位置,
;實(shí)際上RW,ZI在Flash中的位置就緊接著RO存儲(chǔ)。我們知道了Image$$RO$$Base,Image$$RO$$Limit,那么Image$$RO$$Limit就
;是RW(ROM data)的開始。

IMPORT |Image$$RO$$Base| ; Base of ROM code
IMPORT |Image$$RO$$Limit| ; End of ROM code (=start of ROM data)
IMPORT |Image$$RW$$Base| ; Base of RAM to initialise
IMPORT |Image$$ZI$$Base| ; Base and limit of area
IMPORT |Image$$ZI$$Limit| ; to zero initialise

;這里引入一些在其它文件中實(shí)現(xiàn)在函數(shù),包括為我們所熟知的main函數(shù)

本文引用地址:http://m.butianyuan.cn/article/201611/319092.htm;( 引入外部變量MMU 的快速總線模式和異步總線模式兩個(gè)變量)
;IMPORT MMU_SetAsyncBusMode
;IMPORT MMU_SetFastBusMode ;hzh

IMPORT Main
(上面都是宏,下篇文章程序真正開始)



關(guān)鍵詞: 啟動(dòng)代碼244

評(píng)論


技術(shù)專區(qū)

關(guān)閉