ARM啟動(dòng)文件2440init.s分析
; NAME: 2440INIT.S
; DESC: C start up codes
; Configure memory, ISR ,stacks
;Initialize C-variables
;=========================================
;注意:axd調(diào)試時(shí),可以看到指令pc地址從0x30000000開始,這是因?yàn)閞am的起始地址是0x30000000.
;并且如果從nand啟動(dòng),則處理器自動(dòng)把nand首部的4k字節(jié),復(fù)制到ram中,然后pc跳到0x30000000,開始執(zhí)行。
;此源文件通常包含一些宏定義和常量定義
;通用的《啟動(dòng)流程圖》:
;入口->屏蔽所有中斷,禁止看門狗->根據(jù)工作頻率設(shè)置PLL寄存器->初始化存儲(chǔ)控制相關(guān)寄存器
;->初始化各模式下的棧指針->設(shè)置缺省中斷處理函數(shù)->將數(shù)據(jù)拷貝到RAM中,數(shù)據(jù)段清零
;->跳轉(zhuǎn)到c語(yǔ)言main入口函數(shù)中
;GET偽指令用于將一個(gè)源文件包含到當(dāng)前源文件中,并將被包含文件在當(dāng)前位置進(jìn)行匯編處理
;類似于c的include指令
;GET INLCUDE偽指令不能用來包含目標(biāo)文件,INCBIN偽指令可以包含目標(biāo)文件,
;被INCBIN偽指令包含的文件,不進(jìn)行匯編處理,該執(zhí)行文件或數(shù)據(jù)直接放入當(dāng)前文件,
;編譯器從INCBIN后邊開始繼續(xù)處理
;REFRESH寄存器[22]bit :SDRAM刷新模式 0 - auto refresh
; 1 - self refresh
;用于節(jié)電模式中,SDRAM自動(dòng)刷新
BIT_SELFREFRESH EQU (1<<22)
;Pre-defined constants
;模式預(yù)定義常量,給cpsr【4-0】賦值,改變運(yùn)行模式
USERMODE EQU 0x10
FIQMODE EQU 0x11
IRQMODE EQU 0x12
SVCMODE EQU 0x13
ABORTMODE EQU 0x17
UNDEFMODE EQU 0x1b
MODEMASK EQU 0x1f ;模式屏蔽位
NOINT EQU 0xc0 ;1100 0000,中斷屏蔽掩碼
;The location of stacks
;0x30000000 = 768M
;定義各模式下的堆棧常量,是一個(gè)遞減棧,后邊標(biāo)上了各個(gè)棧的大小
UserStack EQU (_STACK_BASEADDRESS-0x3800) ; ~ 0x33ff4800 大小不定,跟堆大小相對(duì)應(yīng)
SVCStack EQU (_STACK_BASEADDRESS-0x2800) ; ~ 0x33ff5800 4M
UndefStack EQU (_STACK_BASEADDRESS-0x2400) ; ~ 0x33ff5c00 1M
AbortStack EQU (_STACK_BASEADDRESS-0x2000) ; ~ 0x33ff6000 1M
IRQStack EQU (_STACK_BASEADDRESS-0x1000) ; ~ 0x33ff7000 4M
FIQStack EQU (_STACK_BASEADDRESS-0x0) ; ~ 0x33ff8000 4M
;處理器分為16位 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ù)其值切換指令
;模式
;Check if tasm.exe(armasm -16 ...@ADS 1.0)is used.
;檢測(cè)工作模式,根據(jù)CONFIG的數(shù)值,確定工作模式
;{CONFIG}應(yīng)該來自于ADS環(huán)境,在本環(huán)境中設(shè)置是進(jìn)入時(shí)在ARM環(huán)境下,沒有設(shè)置ARM/THUMB混合環(huán)境
;關(guān)于是否設(shè)置混合編程,在環(huán)境設(shè)置選項(xiàng)里的ARM Assembler 選項(xiàng)下,由ATPCS -> ARM/Thumb interworking選
;項(xiàng)負(fù)責(zé)
;IF ELSE ENDIF指令
;[ 為 IF ; | 為 ELSE ; ] 為 ENDIF
THUMBCODE SETL {TRUE} ;如果設(shè)置了config,則允許thumb指令,
THUMBCODE SETL {FALSE}
;-------------------------------------------------------------------------------------------------
;bx是帶狀態(tài)切換的跳轉(zhuǎn)指令,跳轉(zhuǎn)到Rm指定的地址執(zhí)行程序,若Rm的位[0]為1,則跳轉(zhuǎn)時(shí)自動(dòng)將CPSR的標(biāo)志T
;T置位,即把目標(biāo)地址的代碼解釋為Thumb代碼;若Rm的位[0]為0,則跳轉(zhuǎn)時(shí)自動(dòng)將CPSR中的標(biāo)志T復(fù)位,即把
;目標(biāo)地址的代碼解釋為ARM代碼
;定義兩個(gè)宏,宏的作用:子函數(shù)返回(無條件,有條件)。
;MACRO和MEND偽指令用于宏定義,MACRO標(biāo)識(shí)開始,MEND標(biāo)識(shí)結(jié)束。用MACRO和MEND定義的一段代碼,稱為宏定義
;體,這樣在程序中就可以通過宏指令多次調(diào)用該代碼段。
;偽指令格式:
;MACRO
;{$label} macroname {$parameter} {$parameter} ...
;MEND
;其中 $label 宏指令被展開時(shí),label可被替換成相應(yīng)的符號(hào),通常為一個(gè)標(biāo)號(hào),
;在一個(gè)標(biāo)號(hào)前使用$表示被匯編時(shí)將使用相應(yīng)的值替代$后的符號(hào)。
;macroname 所定義的宏的名稱
;$parameter 宏指令的參數(shù),當(dāng)宏指令被展開時(shí)將被替換成相應(yīng)的值,類似于函數(shù)中的形式參數(shù)
;對(duì)于子程序代碼較短,而需要傳遞的參數(shù)比較多的情況下,可以使用匯編技術(shù)。
;首先要用MACRO和MEND偽指令定義宏,包括宏定義體代碼。在MACRO偽指令之后的第一行定義宏的原型,其中包
;含該宏定義的名稱,及需要的參數(shù)。在匯編程序中可以通過該宏定義的名稱來調(diào)用它,當(dāng)源程序被匯編時(shí),匯
;編編譯器將展開每個(gè)宏調(diào)用,用宏定義體代替源程序中的宏定義的名稱,并用實(shí)際的參數(shù)值代替宏定義時(shí)的形
;式參數(shù)
;-------------------------------------------------------------------------------------------------
;在arm中,用的是滿遞減堆棧:stmfd,ldmfd,如果用其他的方式,arm可能不能有效識(shí)別
;注意:滿遞減指的是在入棧時(shí)的操作方式,在出棧時(shí)則正好相反的次序
;例子:
;STMFD sp!,{R0-R7,LR}:(滿遞減:先減再放數(shù)值)sp根據(jù)數(shù)據(jù)個(gè)數(shù),減小相應(yīng)個(gè)數(shù)值的數(shù)據(jù)單位(一步到
;位),然后利用for循環(huán)語(yǔ)句,從當(dāng)前sp位置,依次存儲(chǔ)R0-R7,LR.即:sp處最后指向的是R0數(shù)據(jù)處
;LDMFD sp!,{R0-R7,LR}:復(fù)制一個(gè)變量為sp值,用該變量依次將數(shù)據(jù)存入R0-R7,LR,變量值增加,最后,變量指
;向下一個(gè)將要取的值,完成后sp獲得該變量值;
;重點(diǎn)分析下面這個(gè)宏,它對(duì)中斷處理函數(shù)的調(diào)用很重要
;確切說,這是宏函數(shù),編譯時(shí)對(duì)調(diào)用語(yǔ)句要做相應(yīng)的展開
$HandlerLabel HANDLER $HandleLabel
$HandlerLabel ;標(biāo)號(hào)
;-------------------------------------------------------------------------------------------------
;下面幾個(gè)變量是ads環(huán)境下自動(dòng)設(shè)置的,可以見環(huán)境配置選項(xiàng)里:ARM Linker->Output下,RO Base,RW Base
;IMPORT 引用變量
;-------------------------------------------------------------------------------------------------
;AREA偽指令用于定義一個(gè)代碼段或數(shù)據(jù)段,一個(gè)ARM源程序至少需要一個(gè)代碼段,大的程序可以包含多個(gè)代碼段
;及數(shù)據(jù)段
;格式:AREA sectionname {,attr} {,attr}...
;-------------------------------------------------------------------------------------------------
;ENTRY偽指令用于指定程序的入口點(diǎn)
;一個(gè)程序(可以包含多個(gè)源文件)中至少要有一個(gè)ENTRY,可以有多個(gè)ENTRY,但一個(gè)源文件中最多只有一個(gè)
;ENTRY.
;-------------------------------------------------------------------------------------------------
;EXPORT聲明一個(gè)符號(hào)可以被其他文件引用,相當(dāng)于聲明了一個(gè)全局變量。GLOBAL與EXPORT相同
;格式:EXPORT symbol{[WEAK]} [WEAK]聲明其他的同名符優(yōu)先于本符號(hào)被引用
;導(dǎo)出符號(hào)__ENTRY
;-------------------------------------------------------------------------------------------------
__ENTRY
ResetEntry
;條件編譯,在編譯成機(jī)器碼前就設(shè)定好大小端轉(zhuǎn)換
;判斷ENDIAN_CHANGE是否已定義,ASSERT 是斷言偽指令,語(yǔ)法是:ASSERT + 邏輯表達(dá)式,def 是邏輯偽操作符,
;格式為::DEF:label,作用是:判斷l(xiāng)abel是否定義過
;-------------------------------------------------------------------------------------------------
;這7個(gè)中斷,每個(gè)中斷都有固定的中斷入口地址,它們位于代碼的最前端,不允許另作他用
;-------------------------------------------------------------------------------------------------
;@0x20
;------------------------------------------------------------------------------------------------
;下面是改變大小端的程序,采用直接定義 <機(jī)器碼> 的方式,為什么這么做就得問三星了
;反正我們程序里這段代碼也不會(huì)去執(zhí)行,不用去管它
;每一個(gè)匯編指令,都對(duì)應(yīng)著一個(gè)二進(jìn)制機(jī)器碼,這里沒有使用指令,直接用了機(jī)器碼,含義未知
ChangeBigEndian
;@0x24
;對(duì)存儲(chǔ)器控制寄存器操作,指定內(nèi)存模式為Big-endian
;因?yàn)閯傞_始CPU都是按照32位總線的指令格式運(yùn)行的,如果采用其他的話,CPU運(yùn)行不了,必須轉(zhuǎn)化
;但當(dāng)系統(tǒng)初始化好以后,則CPU能自動(dòng)識(shí)別
;因?yàn)椴捎肂ig-endian模式,采用16位總線時(shí),物理地址的高位和數(shù)據(jù)的地位對(duì)應(yīng)
;所以指令的機(jī)器碼也相應(yīng)的高低對(duì)調(diào)
;-------------------------------------------------------------------------------------------------
;本文件底部定義了一個(gè)數(shù)據(jù)區(qū)(在文件最后),34個(gè)字空間,存放相應(yīng)中斷服務(wù)程序的首地址。每個(gè)字空間都
;有一個(gè)標(biāo)號(hào),以Handle***命名。
;這是宏實(shí)例,在這里Handler***就是通過HANDLER這個(gè)宏和Handle***建立聯(lián)系的.
;詳細(xì)分析:
;Handle*** 這是宏示例,也就是宏的調(diào)用指令,當(dāng)編譯時(shí)編譯器會(huì)把宏調(diào)用指令展開
;Handler*** 這是向量中斷
;展開方式(舉例):
;HandlerFIQ HANDLER HandleFIQ
;展開后變成:
;標(biāo)號(hào) HandlerFIQ,由 " b HandlerFIQ "指令使用(見上,復(fù)位處)
; sub sp,sp,#4
;留出一個(gè)空間,為了存放跳轉(zhuǎn)地址給pc。見:str r0,[sp,#4] ,注意sp值并未改變
; stmfd sp!,{r0}
;把r0中的內(nèi)容入棧,保存起來
; ldr r0,=HandleFIQ
;HandleFIQ標(biāo)號(hào),在本文件最下方定義
; ldr r0,[r0]
;把 HandleFIQ 所指向的內(nèi)容(也就是中斷程序的入口地址)放入r0
; str r0,[sp,#4]
;把入口地址放入剛才留出的一個(gè)空間里
; ldmfd sp!,{r0,pc}
;出棧的方式恢復(fù)r0原值和為pc設(shè)定新值(也就完成了到ISR的轉(zhuǎn)跳)。注:棧中r0內(nèi)容在低地址
;后邊的語(yǔ)句展開方式,同上。編譯后,代碼都展開放置
HandlerFIQ HANDLER HandleFIQ
HandlerIRQ HANDLER HandleIRQ
HandlerUndef HANDLER HandleUndef
HandlerSWI HANDLER HandleSWI
HandlerDabort HANDLER HandleDabort
HandlerPabort HANDLER HandlePabort
;-------------------------------------------------------------------------------------------------
;非向量中斷總?cè)肟冢ㄐ枰约号袛嘀袛囝愋?,而不是直接跳轉(zhuǎn)到相應(yīng)程序)
;產(chǎn)生中斷后,需要中斷服務(wù)程序自己來判斷,到底是哪個(gè)中斷請(qǐng)求,根據(jù)的就是INTOFFSET寄存器中的偏移,再
;計(jì)算中斷服務(wù)地址
IsrIRQ
;-------------------------------------------------------------------------------------------------
;LTORG用于聲明一個(gè)文字池,在使用LDR偽指令時(shí),要在適當(dāng)?shù)牡胤郊尤隠TORG聲明文字池,這樣就會(huì)把要加載的
;數(shù)據(jù)保存在文字池內(nèi),再用ARM的《加載指令》讀出數(shù)據(jù)。(若沒有使用LTORG聲明文字池,則匯編器會(huì)在程序
;末尾自動(dòng)聲明)
;LTORG 偽指令常放在無條件跳轉(zhuǎn)指令之后,或者子程序返回指令之后,這樣處理器就不會(huì)錯(cuò)誤地將文字池中的
;數(shù)據(jù)當(dāng)做指令來執(zhí)行
;注:在此,文字池內(nèi)存儲(chǔ)的是INTOFFSET宏所代表的值:0x4a000014 。畢竟,當(dāng)把指令編譯成二進(jìn)制代碼時(shí),
;arm指令(32位)不能既表示出指令內(nèi)容,又表示出數(shù)據(jù)地址(32位)。估計(jì)在編譯時(shí),會(huì)被匯編成其他的加載
;指令,再編譯成機(jī)器碼
;LTORG 只要單獨(dú)寫出來就可以了,其他的交給編譯器來做,而且它跟它下面的代碼沒有任何關(guān)系
;-------------------------------------------------------------------------------------------------
;=======
; ENTRY
;=======
ResetHandler
;關(guān)看門狗
;-------------------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------------------
;初始化PLL和時(shí)鐘
;鎖相環(huán) PLL ,作用是將外部晶振的輸入頻率倍頻到一個(gè)較高的頻率;在配置UPLLCON和MPLLCON寄存器時(shí),必須先配置UPLLCON,然后再配置MPLLCON,而且兩者之間要有7 nop的間
;隔。(這是2440文檔明確要求的)
;-------------------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------------------
;設(shè)置總線寬度&等待狀態(tài)控制寄存器
StartPointAfterSleepWake Up
0
;------------------------------------------------------------------------------------------------
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;; When EINT0 is pressed, Clear SDRAM
;如果 EINT0 產(chǎn)生(這中斷就是我們按鍵產(chǎn)生的), 就清除SDRAM ,不過好像沒人會(huì)在這個(gè)時(shí)候按
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; check if EIN0 button is pressed
; Clear SDRAM Start
; ldr r0,=GPFUP
; ldr r1,=0xff
; str r1,[r0]
0
;Clear SDRAM End
1
;------------------------------------------------------------------------------------------------
;===========================================================
;OM0是flash選擇開關(guān),OM0接地時(shí)從nand 啟動(dòng),懸空時(shí)(核心板上有上拉電阻)從nor啟動(dòng)
;OM1在核心板上,始終是接地,為0
;OM1:OM0取值:00 nandflash mode
; 01 16bit nor
; 10 32bit nor
; 11 test mode
;詳見:s3c2440 用戶手冊(cè) 5.memory controller 一節(jié)
;ands指令,加s表示結(jié)果影響cpsr寄存器的值
;===========================================================
;把nand中的數(shù)據(jù),拷貝到ram中
nand_boot_beg
;===========================================================
;這里的一段代碼時(shí)對(duì)內(nèi)存數(shù)據(jù)的初始化,涉及代碼段,數(shù)據(jù)段,bss段等
;因?qū)@里的變量設(shè)置等有異議,暫時(shí)未全面分析,但是基本原理想通,就是一個(gè)比較地址,復(fù)制數(shù)據(jù)的過程
copy_proc_beg
0
InitRam
0
1
2
; [CLKDIV_VAL>1 ; meansFclk:Hclk is not 1:1.
; bl MMU_SetAsyncBusMode
; |
; blMMU_SetFastBusMode ; default value.
; ]
;===========================================================
;------------------------------------------------------------------------------------------------
;function initializing stacks
; 初始化??臻g(各個(gè)模式下的),為c函數(shù)運(yùn)行做準(zhǔn)備
InitStacks
;------------------------------------------------------------------------------------------------
SMRDATA DATA
;配置存儲(chǔ)器的管理方式
; Memory configuration should be optimizedfor best performance
; The following parameter is not optimized.
; Memory access cycle parameter strategy
; 1) The memory settings is safe parameters even at HCLK=75Mhz.
; 2) SDRAM refresh period is forHCLK<=75Mhz.
;分配一個(gè)字的空間,并用后邊的數(shù)值來初始化該空間,這里命名有些混亂
BaseOfROM DCD |Image$$RO$$Base|
TopOfROM DCD |Image$$RO$$Limit|
BaseOfBSS DCD |Image$$RW$$Base|
BaseOfZero DCD |Image$$ZI$$Base|
EndOfBSS DCD |Image$$ZI$$Limit|
;------------------------------------------------------------------------------------------------
;Function for entering power down mode
; 1. SDRAM should be in self-refresh mode.
; 2. All interrupt should be maksked forSDRAM/DRAM self-refresh.
; 3. LCD controller should be disabled forSDRAM/DRAM self-refresh.
; 4. The I-cache may have to be turned on.
; 5. The location of the following code may have not to be changed.
;void EnterPWDN(int CLKCON);
EnterPWDN
ENTER_STOP
0 subs r1,r1,#1
0 subs r1,r1,#1 ;1) wait until the STOP mode isin effect.
ENTER_SLEEP
0 subs r1,r1,#1
WAKEUP_SLEEP
0
0 subs r1,r1,#1 ;1) wait until the SelfRefreshis released.
;=====================================================================
; Clock division test
; Assemble code, because VSYNC time is veryshort
;=====================================================================
CLKDIV124
; waituntil clock is stable
CLKDIV144
; waituntil clock is stable
;------------------------------------------------------------------------------------------------
;------------------------------------------------------------------------------------------------
;定義數(shù)據(jù)段
;^ 標(biāo)志等價(jià)于MAP偽指令
;MAP用于定義一個(gè)結(jié)構(gòu)化的內(nèi)存表首地址,此時(shí)內(nèi)存表的位置計(jì)數(shù)器值,也變成該首地址值,就相當(dāng)于在這個(gè)地
;址處操作
;#于FIELD同義,用于定義一個(gè)結(jié)構(gòu)化的內(nèi)存表的數(shù)據(jù)域,后邊數(shù)字表示該數(shù)據(jù)占用的字節(jié)數(shù)
;Handle*** 在此就是一個(gè)標(biāo)號(hào),為了標(biāo)示數(shù)據(jù)量
;用法:把對(duì)應(yīng)的終端處理函數(shù)的首地址,放到這里的對(duì)應(yīng)的預(yù)留空間處,當(dāng)發(fā)生中斷時(shí),就能根據(jù)宏函數(shù),直
;接跳轉(zhuǎn)
HandleReset # 4
HandleUndef # 4
HandleSWI # 4
HandlePabort # 4
HandleDabort # 4
HandleReserved # 4
HandleIRQ # 4
HandleFIQ # 4
;Do not use the label IntVectorTable,
;The value of IntVectorTable is differentwith the address you think it may be.
;IntVectorTable
;@0x33FF_FF20
HandleEINT0 # 4
HandleEINT1 # 4
HandleEINT2 # 4
HandleEINT3 # 4
HandleEINT4_7 # 4
HandleEINT8_23 # 4
HandleCAM # 4 ;Added for 2440.
HandleBATFLT # 4
HandleTICK # 4
HandleWDT # 4
HandleTIMER0 # 4
HandleTIMER1 # 4
HandleTIMER2 # 4
HandleTIMER3 # 4
HandleTIMER4 # 4
HandleUART2 # 4
;@0x33FF_FF60
HandleLCD # 4
HandleDMA0 # 4
HandleDMA1 # 4
HandleDMA2 # 4
HandleDMA3 # 4
HandleMMC # 4
HandleSPI0 # 4
HandleUART1 # 4
HandleNFCON # 4 ;Added for 2440.
HandleUSBD # 4
HandleUSBH # 4
HandleIIC # 4
HandleUART0 # 4
HandleSPI1 # 4
HandleRTC # 4
HandleADC # 4
;@0x33FF_FFA0
評(píng)論