ARM啟動文件2440init.s分析
; NAME: 2440INIT.S
; DESC: C start up codes
; Configure memory, ISR ,stacks
;Initialize C-variables
;=========================================
;注意:axd調(diào)試時,可以看到指令pc地址從0x30000000開始,這是因為ram的起始地址是0x30000000.
;并且如果從nand啟動,則處理器自動把nand首部的4k字節(jié),復制到ram中,然后pc跳到0x30000000,開始執(zhí)行。
;此源文件通常包含一些宏定義和常量定義
;通用的《啟動流程圖》:
;入口->屏蔽所有中斷,禁止看門狗->根據(jù)工作頻率設(shè)置PLL寄存器->初始化存儲控制相關(guān)寄存器
;->初始化各模式下的棧指針->設(shè)置缺省中斷處理函數(shù)->將數(shù)據(jù)拷貝到RAM中,數(shù)據(jù)段清零
;->跳轉(zhuǎn)到c語言main入口函數(shù)中
;GET偽指令用于將一個源文件包含到當前源文件中,并將被包含文件在當前位置進行匯編處理
;類似于c的include指令
;GET INLCUDE偽指令不能用來包含目標文件,INCBIN偽指令可以包含目標文件,
;被INCBIN偽指令包含的文件,不進行匯編處理,該執(zhí)行文件或數(shù)據(jù)直接放入當前文件,
;編譯器從INCBIN后邊開始繼續(xù)處理
;REFRESH寄存器[22]bit :SDRAM刷新模式 0 - auto refresh
; 1 - self refresh
;用于節(jié)電模式中,SDRAM自動刷新
BIT_SELFREFRESH EQU (1<<22)
;Pre-defined constants
;模式預定義常量,給cpsr【4-0】賦值,改變運行模式
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
;定義各模式下的堆棧常量,是一個遞減棧,后邊標上了各個棧的大小
UserStack EQU (_STACK_BASEADDRESS-0x3800) ; ~ 0x33ff4800 大小不定,跟堆大小相對應
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上電時處于ARM狀態(tài),故無論指令為ARM集或Thumb集,都先強制成ARM集,待init.s初始化完成后,再根據(jù)用
;戶的編譯配置轉(zhuǎn)換成相應的指令模式。為此,定義變量THUMBCODE作為指示,跳轉(zhuǎn)到main之前根據(jù)其值切換指令
;模式
;Check if tasm.exe(armasm -16 ...@ADS 1.0)is used.
;檢測工作模式,根據(jù)CONFIG的數(shù)值,確定工作模式
;{CONFIG}應該來自于ADS環(huán)境,在本環(huán)境中設(shè)置是進入時在ARM環(huán)境下,沒有設(shè)置ARM/THUMB混合環(huán)境
;關(guān)于是否設(shè)置混合編程,在環(huán)境設(shè)置選項里的ARM Assembler 選項下,由ATPCS -> ARM/Thumb interworking選
;項負責
;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)時自動將CPSR的標志T
;T置位,即把目標地址的代碼解釋為Thumb代碼;若Rm的位[0]為0,則跳轉(zhuǎn)時自動將CPSR中的標志T復位,即把
;目標地址的代碼解釋為ARM代碼
;定義兩個宏,宏的作用:子函數(shù)返回(無條件,有條件)。
;MACRO和MEND偽指令用于宏定義,MACRO標識開始,MEND標識結(jié)束。用MACRO和MEND定義的一段代碼,稱為宏定義
;體,這樣在程序中就可以通過宏指令多次調(diào)用該代碼段。
;偽指令格式:
;MACRO
;{$label} macroname {$parameter} {$parameter} ...
;MEND
;其中 $label 宏指令被展開時,label可被替換成相應的符號,通常為一個標號,
;在一個標號前使用$表示被匯編時將使用相應的值替代$后的符號。
;macroname 所定義的宏的名稱
;$parameter 宏指令的參數(shù),當宏指令被展開時將被替換成相應的值,類似于函數(shù)中的形式參數(shù)
;對于子程序代碼較短,而需要傳遞的參數(shù)比較多的情況下,可以使用匯編技術(shù)。
;首先要用MACRO和MEND偽指令定義宏,包括宏定義體代碼。在MACRO偽指令之后的第一行定義宏的原型,其中包
;含該宏定義的名稱,及需要的參數(shù)。在匯編程序中可以通過該宏定義的名稱來調(diào)用它,當源程序被匯編時,匯
;編編譯器將展開每個宏調(diào)用,用宏定義體代替源程序中的宏定義的名稱,并用實際的參數(shù)值代替宏定義時的形
;式參數(shù)
;-------------------------------------------------------------------------------------------------
;在arm中,用的是滿遞減堆棧:stmfd,ldmfd,如果用其他的方式,arm可能不能有效識別
;注意:滿遞減指的是在入棧時的操作方式,在出棧時則正好相反的次序
;例子:
;STMFD sp!,{R0-R7,LR}:(滿遞減:先減再放數(shù)值)sp根據(jù)數(shù)據(jù)個數(shù),減小相應個數(shù)值的數(shù)據(jù)單位(一步到
;位),然后利用for循環(huán)語句,從當前sp位置,依次存儲R0-R7,LR.即:sp處最后指向的是R0數(shù)據(jù)處
;LDMFD sp!,{R0-R7,LR}:復制一個變量為sp值,用該變量依次將數(shù)據(jù)存入R0-R7,LR,變量值增加,最后,變量指
;向下一個將要取的值,完成后sp獲得該變量值;
;重點分析下面這個宏,它對中斷處理函數(shù)的調(diào)用很重要
;確切說,這是宏函數(shù),編譯時對調(diào)用語句要做相應的展開
$HandlerLabel HANDLER $HandleLabel
$HandlerLabel ;標號
;-------------------------------------------------------------------------------------------------
;下面幾個變量是ads環(huán)境下自動設(shè)置的,可以見環(huán)境配置選項里:ARM Linker->Output下,RO Base,RW Base
;IMPORT 引用變量
;-------------------------------------------------------------------------------------------------
;AREA偽指令用于定義一個代碼段或數(shù)據(jù)段,一個ARM源程序至少需要一個代碼段,大的程序可以包含多個代碼段
;及數(shù)據(jù)段
;格式:AREA sectionname {,attr} {,attr}...
;-------------------------------------------------------------------------------------------------
;ENTRY偽指令用于指定程序的入口點
;一個程序(可以包含多個源文件)中至少要有一個ENTRY,可以有多個ENTRY,但一個源文件中最多只有一個
;ENTRY.
;-------------------------------------------------------------------------------------------------
;EXPORT聲明一個符號可以被其他文件引用,相當于聲明了一個全局變量。GLOBAL與EXPORT相同
;格式:EXPORT symbol{[WEAK]} [WEAK]聲明其他的同名符優(yōu)先于本符號被引用
;導出符號__ENTRY
;-------------------------------------------------------------------------------------------------
__ENTRY
ResetEntry
;條件編譯,在編譯成機器碼前就設(shè)定好大小端轉(zhuǎn)換
;判斷ENDIAN_CHANGE是否已定義,ASSERT 是斷言偽指令,語法是:ASSERT + 邏輯表達式,def 是邏輯偽操作符,
;格式為::DEF:label,作用是:判斷l(xiāng)abel是否定義過
;-------------------------------------------------------------------------------------------------
;這7個中斷,每個中斷都有固定的中斷入口地址,它們位于代碼的最前端,不允許另作他用
;-------------------------------------------------------------------------------------------------
;@0x20
;------------------------------------------------------------------------------------------------
;下面是改變大小端的程序,采用直接定義 <機器碼> 的方式,為什么這么做就得問三星了
;反正我們程序里這段代碼也不會去執(zhí)行,不用去管它
;每一個匯編指令,都對應著一個二進制機器碼,這里沒有使用指令,直接用了機器碼,含義未知
ChangeBigEndian
;@0x24
;對存儲器控制寄存器操作,指定內(nèi)存模式為Big-endian
;因為剛開始CPU都是按照32位總線的指令格式運行的,如果采用其他的話,CPU運行不了,必須轉(zhuǎn)化
;但當系統(tǒng)初始化好以后,則CPU能自動識別
;因為采用Big-endian模式,采用16位總線時,物理地址的高位和數(shù)據(jù)的地位對應
;所以指令的機器碼也相應的高低對調(diào)
;-------------------------------------------------------------------------------------------------
;本文件底部定義了一個數(shù)據(jù)區(qū)(在文件最后),34個字空間,存放相應中斷服務程序的首地址。每個字空間都
;有一個標號,以Handle***命名。
;這是宏實例,在這里Handler***就是通過HANDLER這個宏和Handle***建立聯(lián)系的.
;詳細分析:
;Handle*** 這是宏示例,也就是宏的調(diào)用指令,當編譯時編譯器會把宏調(diào)用指令展開
;Handler*** 這是向量中斷
;展開方式(舉例):
;HandlerFIQ HANDLER HandleFIQ
;展開后變成:
;標號 HandlerFIQ,由 " b HandlerFIQ "指令使用(見上,復位處)
; sub sp,sp,#4
;留出一個空間,為了存放跳轉(zhuǎn)地址給pc。見:str r0,[sp,#4] ,注意sp值并未改變
; stmfd sp!,{r0}
;把r0中的內(nèi)容入棧,保存起來
; ldr r0,=HandleFIQ
;HandleFIQ標號,在本文件最下方定義
; ldr r0,[r0]
;把 HandleFIQ 所指向的內(nèi)容(也就是中斷程序的入口地址)放入r0
; str r0,[sp,#4]
;把入口地址放入剛才留出的一個空間里
; ldmfd sp!,{r0,pc}
;出棧的方式恢復r0原值和為pc設(shè)定新值(也就完成了到ISR的轉(zhuǎn)跳)。注:棧中r0內(nèi)容在低地址
;后邊的語句展開方式,同上。編譯后,代碼都展開放置
HandlerFIQ HANDLER HandleFIQ
HandlerIRQ HANDLER HandleIRQ
HandlerUndef HANDLER HandleUndef
HandlerSWI HANDLER HandleSWI
HandlerDabort HANDLER HandleDabort
HandlerPabort HANDLER HandlePabort
;-------------------------------------------------------------------------------------------------
;非向量中斷總?cè)肟冢ㄐ枰约号袛嘀袛囝愋?,而不是直接跳轉(zhuǎn)到相應程序)
;產(chǎn)生中斷后,需要中斷服務程序自己來判斷,到底是哪個中斷請求,根據(jù)的就是INTOFFSET寄存器中的偏移,再
;計算中斷服務地址
IsrIRQ
;-------------------------------------------------------------------------------------------------
;LTORG用于聲明一個文字池,在使用LDR偽指令時,要在適當?shù)牡胤郊尤隠TORG聲明文字池,這樣就會把要加載的
;數(shù)據(jù)保存在文字池內(nèi),再用ARM的《加載指令》讀出數(shù)據(jù)。(若沒有使用LTORG聲明文字池,則匯編器會在程序
;末尾自動聲明)
;LTORG 偽指令常放在無條件跳轉(zhuǎn)指令之后,或者子程序返回指令之后,這樣處理器就不會錯誤地將文字池中的
;數(shù)據(jù)當做指令來執(zhí)行
;注:在此,文字池內(nèi)存儲的是INTOFFSET宏所代表的值:0x4a000014 。畢竟,當把指令編譯成二進制代碼時,
;arm指令(32位)不能既表示出指令內(nèi)容,又表示出數(shù)據(jù)地址(32位)。估計在編譯時,會被匯編成其他的加載
;指令,再編譯成機器碼
;LTORG 只要單獨寫出來就可以了,其他的交給編譯器來做,而且它跟它下面的代碼沒有任何關(guān)系
;-------------------------------------------------------------------------------------------------
;=======
; ENTRY
;=======
ResetHandler
;關(guān)看門狗
;-------------------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------------------
;初始化PLL和時鐘
;鎖相環(huán) PLL ,作用是將外部晶振的輸入頻率倍頻到一個較高的頻率;在配置UPLLCON和MPLLCON寄存器時,必須先配置UPLLCON,然后再配置MPLLCON,而且兩者之間要有7 nop的間
;隔。(這是2440文檔明確要求的)
;-------------------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------------------
;設(shè)置總線寬度&等待狀態(tài)控制寄存器
StartPointAfterSleepWake Up
0
;------------------------------------------------------------------------------------------------
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;; When EINT0 is pressed, Clear SDRAM
;如果 EINT0 產(chǎn)生(這中斷就是我們按鍵產(chǎn)生的), 就清除SDRAM ,不過好像沒人會在這個時候按
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 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接地時從nand 啟動,懸空時(核心板上有上拉電阻)從nor啟動
;OM1在核心板上,始終是接地,為0
;OM1:OM0取值:00 nandflash mode
; 01 16bit nor
; 10 32bit nor
; 11 test mode
;詳見:s3c2440 用戶手冊 5.memory controller 一節(jié)
;ands指令,加s表示結(jié)果影響cpsr寄存器的值
;===========================================================
;把nand中的數(shù)據(jù),拷貝到ram中
nand_boot_beg
;===========================================================
;這里的一段代碼時對內(nèi)存數(shù)據(jù)的初始化,涉及代碼段,數(shù)據(jù)段,bss段等
;因?qū)@里的變量設(shè)置等有異議,暫時未全面分析,但是基本原理想通,就是一個比較地址,復制數(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(各個模式下的),為c函數(shù)運行做準備
InitStacks
;------------------------------------------------------------------------------------------------
SMRDATA DATA
;配置存儲器的管理方式
; 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.
;分配一個字的空間,并用后邊的數(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ù)段
;^ 標志等價于MAP偽指令
;MAP用于定義一個結(jié)構(gòu)化的內(nèi)存表首地址,此時內(nèi)存表的位置計數(shù)器值,也變成該首地址值,就相當于在這個地
;址處操作
;#于FIELD同義,用于定義一個結(jié)構(gòu)化的內(nèi)存表的數(shù)據(jù)域,后邊數(shù)字表示該數(shù)據(jù)占用的字節(jié)數(shù)
;Handle*** 在此就是一個標號,為了標示數(shù)據(jù)量
;用法:把對應的終端處理函數(shù)的首地址,放到這里的對應的預留空間處,當發(fā)生中斷時,就能根據(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
評論