歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> ARM啟動文件2440init.s分析

ARM啟動文件2440init.s分析

日期:2017/3/1 10:41:03   编辑:Linux編程

找到了一些當初學習嵌入式linux時的資料,現在共享出來。方便大家學習之用,無所謂原創,無非就是在前人的基礎上,進行了系統化的分析和綜合而已。不過,還是加入了不少個人學習的思路跟方法,我覺得這才是最重要的。

最近在學習嵌入式軟件,現分享自己部分成果。平台:s3c2440 mcu

;=========================================

; NAME: 2440INIT.S

; DESC: C start up codes

; Configure memory, ISR ,stacks

;Initialize C-variables

;=========================================

;注意:axd調試時,可以看到 指令pc地址從0x30000000開始,這是因為ram的起始地址是0x30000000.

;並且如果從nand啟動,則處理器自動把nand首部的4k字節,復制到ram中,然後pc跳到0x30000000,開始執行。

;此源文件通常包含一些宏定義和常量定義

;通用的《啟動流程圖》:

;入口->屏蔽所有中斷,禁止看門狗->根據工作頻率設置PLL寄存器->初始化存儲控制相關寄存器->初始化各模式下的棧指針

;->設置缺省中斷處理函數->將數據拷貝到RAM中,數據段清零->跳轉到c語言main入口函數中

;GET偽指令用於將一個源文件包含到當前源文件中,並將被包含文件在當前位置進行匯編處理,類似於c的include指令

;GET INLCUDE偽指令不能 用來包含目標文件,INCBIN偽指令 可以包含目標文件,

;被INCBIN偽指令包含的文件, 不 進行匯編處理,該執行文件或數據直接放入當前文件,編譯器從INCBIN後邊開始繼續處理

;區分GET,INCLUDE,INCBIN的用法和作用

GEToption.inc ;定義芯片相關配置

GETmemcfg.inc ;定義存儲器配置

GET2440addr.inc ;定義寄存器符號

;REFRESH寄存器[22]bit :SDRAM刷新模式 0- auto refresh; 1 - self refresh

;用於節電模式中,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位兩種工作狀態 程序的編譯器也是分16位和32兩種編譯方式 下面程序根據處理器工作狀態確定編譯器編譯方式

;code16偽指令指示匯編編譯器後面的指令為16位的thumb指令

;code32偽指令指示匯編編譯器後面的指令為32位的arm指令

;Arm上電時處於ARM狀態,故無論指令為ARM集或Thumb集,都先強制成ARM集,待init.s初始化完成後

;再根據用戶的編譯配置轉換成相應的指令模式。為此,定義變量THUMBCODE作為指示,跳轉到main之前

;根據其值切換指令模式

;Check if tasm.exe(armasm -16 ...@ADS 1.0)is used.

;檢測工作模式,根據CONFIG的數值,確定工作模式

;{CONFIG}應該來自於ADS環境,在本環境中設置是進入時在ARM環境下,沒有設置ARM/THUMB混合環境

;關於是否設置混合編程,在環境設置選項裡的ARM Assembler 選項下,由ATPCS -> ARM/Thumb interworking選項負責

;IF ELSE ENDIF指令

GBLL THUMBCODE

[{CONFIG} = 16

THUMBCODE SETL {TRUE} ;如果設置了config,則允許thumb指令,但THUMBCODE為真並不表明以下就是thumb指令,只是允許

CODE32 ;code32表示以下是arm指令,在處理器剛開始時,必須以arm模式運行

| ;此處容易產生錯覺,丟掉CODE32這一行

THUMBCODE SETL {FALSE}

]

;bx是帶狀態切換的跳轉指令,跳轉到Rm指定的地址執行程序,若Rm的位[0]為1,則跳轉時自動將CPSR的標志T

;T置位,即把目標地址的代碼解釋為Thumb代碼;若Rm的位[0]為0,則跳轉時自動將CPSR中的標志T復位,即把

;目標地址的代碼解釋為ARM代碼

;定義兩個宏,宏的作用:子函數返回(無條件,有條件)。

MACRO

MOV_PC_LR

[ THUMBCODE ;如果允許thumb指令,則需要根據最低位設置狀態。

bx lr ;跳轉,附帶狀態切換

|

mov pc,lr

]

MEND

MACRO

MOVEQ_PC_LR ;相等則跳轉,相等與否由寄存器某些位確定,在此處,有其上一句的指令執行結果決定

[ THUMBCODE

bxeq lr

|

moveq pc,lr

]

MEND

;重點分析下面這個宏,它對中斷處理函數的調用很重要

;MACRO和MEND偽指令用於宏定義,MACRO標識開始,MEND標識結束。用MACRO和MEND定義的一段代碼,稱為

;宏定義體,這樣在程序中就可以通過宏指令多次調用該代碼段。偽指令格式:

;MACRO

;{$label} macroname {$parameter} {$parameter} ...

;宏定義體

;MEND

;其中 $label 宏指令被展開時,label可被替換成相應的符號,通常為一個標號,在一個標號前使用$表示被匯編時將

;使用相應的值替代$後的符號。

;macroname 所定義的宏的名稱

;$parameter 宏指令的參數,當宏指令被展開時將被替換成相應的值,類似於函數中的形式參數

;對於子程序代碼較短,而需要傳遞的參數比較多的情況下,可以使用匯編技術。首先要用MACRO和MEND偽指令定義宏,包括宏定義

;體代碼。在MACRO偽指令之後的第一行定義宏的原型,其中包含該宏定義的名稱,及需要的參數。在匯編程序中可以通過該宏定義

;的名稱來調用它,當源程序被匯編時,匯編編譯器將 展開 每個宏調用,用宏定義體代替源程序中的宏定義的名稱,並用實際的參數

;值代替宏定義時的形式參數

;在arm中,用的是滿遞減堆棧:stmfd,ldmfd,如果用其他的方式,arm可能不能有效識別

;注意:滿遞減指的是在入棧時的操作方式,在出棧時則正好相反的次序

;關於堆棧在數據放置方式,存取順序上,可以參見《自學手冊》P84中的實例分析

;例子:

;STMFD sp!,{R0-R7,LR}:(滿遞減:先減再放數值)sp根據數據個數,減小相應個數值的數據單位(一步到位),然後利用for循環語句,從當前sp位置,依次存儲R0-R7,LR.即:sp處最後指向的是R0數據處

;LDMFD sp!,{R0-R7,LR}:復制一個變量為sp值,用該變量依次將數據存入R0-R7,LR,變量值增加,最後,變量指向下一個將要取的值,完成後sp獲得該變量值;

;risc模式,這是對ram的操作

;確切說,這是宏函數,編譯時對調用語句要做相應的展開

MACRO

$HandlerLabel HANDLER $HandleLabel

$HandlerLabel ;標號

sub sp,sp,#4 ;留出一個空間,為了存放跳轉地址給pc。見:str r0,[sp,#4] ,注意sp值並未改變

stmfd sp!,{r0} ;把r0中的內容入棧,保存起來

ldr r0,=$HandleLabel ;這是一個偽指令,不是匯編指令,目的:把$HandleLabel本身所在的地址給r0

ldr r0,[r0] ;把HandleXXX所指向的內容(也就是中斷程序的入口地址)放入r0

str r0,[sp,#4] ;把入口地址放入剛才留出的一個空間裡

ldmfd sp!,{r0,pc} ;出棧的方式恢復r0原值和為pc設定新值(也就完成了到ISR的轉跳)。注:棧中r0內容在低地址

MEND

;這幾個變量是ads環境下自動設置的,可以見環境配置選項裡:ARM Linker->Output下,RO Base,RW Base

;RW Base 沒設置,因為代碼段的結束便是數據段的開始,這個ads可以自動設置

;IMPORT 引用變量

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 to zero initialise

IMPORT |Image$$ZI$$Limit|

IMPORT MMU_SetAsyncBusMode

IMPORT MMU_SetFastBusMode ;想知道代碼具體內容見cp15手冊,並以cp15指令內容搜索2440a手冊

IMPORT Main ;The main entry of mon program

IMPORT RdNF2SDRAM ;Copy Image from Nand Flash to SDRAM

;AREA偽指令用於定義一個代碼段或數據段,一個ARM源程序至少需要一個代碼段,大的程序可以包含多個代碼段及數據段

;格式:AREA sectionname {,attr} {,attr}...

AREA Init,CODE,READONLY

;ENTRY偽指令用於指定程序的入口點

;一個程序(可以包含多個源文件)中至少要有一個ENTRY,可以有多個ENTRY,但一個源文件中最多只有一個ENTRY.

ENTRY

;EXPORT聲明一個符號可以被其他文件引用,相當於聲明了一個全局變量。GLOBAL與EXPORT相同

;格式:EXPORT symbol{[WEAK]} [WEAK]聲明其他的同名符優先於本符號被引用

;導出符號__ENTRY

EXPORT __ENTRY

__ENTRY

ResetEntry

;1)Thecode, which converts to Big-endian, should be in little endian code.

;2)Thefollowing little endian code will be compiled in Big-Endian mode.

; The code byte order should be changed as thememory bus width.

;3)Thepseudo instruction,DCD can not be used here because the linker generates error.

;條件編譯,在編譯成機器碼前就設定好 大小端轉換

;判斷ENDIAN_CHANGE是否已定義,ASSERT 是斷言偽指令,語法是:ASSERT +邏輯表達式 ,def 是邏輯偽操作符,格式為::DEF:label,作用是:判斷label是否定義過

ASSERT :DEF:ENDIAN_CHANGE

[ENDIAN_CHANGE ;definedin option.inc 默認是FALSE,所以此句不會加入代碼中

ASSERT :DEF:ENTRY_BUS_WIDTH ;斷言指令,檢測是否定義該變量,若未定義,報錯

[ENTRY_BUS_WIDTH=32 ;definedin option.inc

b ChangeBigEndian ;DCD 0xea000007 ;如果是大端,則這是第一條指令,先設置成大端,再到復位指令

]

[ENTRY_BUS_WIDTH=16

andeq r14,r7,r0,lsl #20 ;DCD 0x0007ea00

]

[ENTRY_BUS_WIDTH=8

streq r0,[r0,-r10,ror #1] ;DCD 0x070000ea

]

|

b ResetHandler ;本硬件用的是小端模式,這是第一個執行語句,直接跳轉到復位指令處 0X00

]

b HandlerUndef ;handler for Undefined mode 0X04

b HandlerSWI ;handlerfor SWI interrupt 0X08

b HandlerPabort ;handler for PAbort,指令預取中止 0X0C

b HandlerDabort ;handler for DAbort,數據中止 0X10

b . ;reserved 保留未用 注意小圓點 0X14

b HandlerIRQ ;handlerfor IRQ interrupt 0X18

b HandlerFIQ ;handlerfor FIQ interrupt 0X1C

;這7個中斷,每個中斷都有固定的中斷入口地址,它們位於代碼的最前端,不允許另作他用

;@0x20

b EnterPWDN ;Must be 0x20

;下面是改變大小端的程序,采用直接定義 <機器碼> 的方式,為什麼這麼做就得問三星了

;反正我們程序裡這段代碼也不會去執行,不用去管它

;每一個匯編指令,都對應著一個二進制機器碼,這裡沒有使用指令,直接用了機器碼,含義未知

ChangeBigEndian

;@0x24

[ENTRY_BUS_WIDTH=32

DCD 0xee110f10 ;0xee110f10 => mrc p15,0,r0,c1,c0,0

DCD 0xe3800080 ;0xe3800080 => orr r0,r0,#0x80; //Big-endian

DCD 0xee010f10 ;0xee010f10 => mcr p15,0,r0,c1,c0,0

;對存儲器控制寄存器操作,指定內存模式為Big-endian

;因為剛開始CPU都是按照32位總線的指令格式運行的,如果采用其他的話,CPU別不了,必須轉化

;但當系統初始化好以後,則CPU能自動識別

]

[ENTRY_BUS_WIDTH=16

DCD0x0f10ee11

DCD0x0080e380

DCD0x0f10ee01

;因為采用Big-endian模式,采用16位總線時,物理地址的高位和數據的地位對應

;所以指令的機器碼也相應的高低對調

]

[ENTRY_BUS_WIDTH=8

DCD0x100f11ee

DCD0x800080e3

DCD0x100f01ee

]

DCD0xffffffff ;swinv 0xffffff is similarwith NOP and run well in both endian mode.

DCD0xffffffff

DCD0xffffffff

DCD0xffffffff

DCD0xffffffff

bResetHandler ;設置成大端後,再次跳到復位指令處

;本文件底部定義了一個數據區(在文件最後),34個字空間,存放相應中斷服務程序的首地址。每個字

;空間都有一個標號,以Handle***命名。

;這是宏實例 在這裡Handler***就是通過HANDLER這個宏和Handle***建立聯系的.

;詳細分析:

; 這是宏示例,也就是宏的調用指令,當編譯時編譯器會把宏調用指令展開

; 這是向量中斷

;展開方式(舉例):

;HandlerFIQ HANDLERHandleFIQ

;展開後變成:

;HandlerFIQ ;標號,由 " b HandlerFIQ "指令使用(見上,復位處)

; sub sp,sp,#4 ;留出一個空間,為了存放跳轉地址給pc。見:strr0,[sp,#4] ,注意sp值並未改變

;

; stmfd sp!,{r0} ;把r0中的內容入棧,保存起來

;

; ldr r0,=HandleFIQ ;HandleFIQ標號,在本文件最下方定義

;

; ldr r0,[r0] ;把HandleXXX所指向的內容(也就是中斷程序的入口地址)放入r0

;

; str r0,[sp,#4] ;把入口地址放入剛才留出的一個空間裡

;

; ldmfd sp!,{r0,pc} ;出棧的方式恢復r0原值和為pc設定新值(也就完成了到ISR的轉跳)。注:棧中r0內容在低地址

;

; 後邊的語句展開方式,同上。編譯後,代碼都展開放置

HandlerFIQ HANDLERHandleFIQ

HandlerIRQ HANDLERHandleIRQ

HandlerUndef HANDLER HandleUndef

HandlerSWI HANDLERHandleSWI

HandlerDabort HANDLER HandleDabort

HandlerPabort HANDLER HandlePabort

;非向量中斷總入口(需要自己判斷中斷類型,而不是直接跳轉到相應程序)

;產生中斷後,需要中斷服務程序���己來判斷,到底是哪個中斷請求,根據的就是INTOFFSET寄存器中的偏移,再計算中斷服務地址

IsrIRQ

sub sp,sp,#4 ;reserved for PC,預留返回指針的存儲位置

stmfd sp!,{r8-r9}

ldr r9,=INTOFFSET ;the interrupt request source offset

ldr r9,[r9]

ldr r8,=HandleEINT0 ;HandleEINT0 ,在本文件最下邊定義的

add r8,r8,r9,lsl #2 ;r9中只是偏移單位的個數,需要*4變成具體字節偏移(相對於EINT0)

ldr r8,[r8]

str r8,[sp,#8] ;pc值放在了高位置

ldmfd sp!,{r8-r9,pc}

LTORG

;LTORG用於聲明一個文字池,在使用LDR偽指令時,要在適當的地方加入LTORG聲明文字池,這樣就會把要加載的數據保存在

;文字池內,再用ARM的《加載指令》讀出數據。(若沒有使用LTORG聲明文字池,則匯編器會在程序末尾自動聲明)

;LTORG 偽指令常放在無條件跳轉指令之後,或者子程序返回指令之後,這樣處理器就不會錯誤地將文字池中的數據當做指令來執行

;注:在此,文字池內存儲的是INTOFFSET宏所代表的值:0x4a000014 。畢竟,當把指令編譯成二進制代碼時,arm指令(32位)

;不能既表示出指令內容,又表示出數據地址(32位)。估計在編譯時,會被匯編成其他的加載指令,再編譯成機器碼

;LTORG 只要單獨寫出來就可以了,其他的交給編譯器來做,而且它跟它下面的代碼沒有任何關系

;=======

; ENTRY

;=======

ResetHandler

ldr r0,=WTCON ;watch dog disable 編譯時就是 ldr r0,=53000000;偽指令有=號

ldr r1,=0x0 ;這些宏定義都位於2440addr.inc中。 區分:變量定義&& 宏定義

str r1,[r0]

ldr r0,=INTMSK

ldr r1,=0xffffffff ;all interrupt disable 要理解子中斷和中斷之間的關系

str r1,[r0]

ldr r0,=INTSUBMSK

ldr r1,=0x7fff ;allsub interrupt disable

str r1,[r0]

[{FALSE}

;rGPFDAT= (rGPFDAT & ~(0xf<<4)) | ((~data & 0xf)<<4);

;Led_Display

ldr r0,=GPBCON

ldr r1,=0x155500

str r1,[r0]

ldr r0,=GPBDAT

ldr r1,=0x0

str r1,[r0]

]

;Toreduce PLL lock time, adjust the LOCKTIME register.

ldr r0,=LOCKTIME

ldr r1,=0xffffff

str r1,[r0]

[PLL_ON_START ;defined inoption.inc {TRUE},選擇要不要設置頻率值

;Added for confirm clock divide. for 2440.

;Setting value Fclk:Hclk:Pclk

ldr r0,=CLKDIVN

ldr r1,=CLKDIV_VAL ; 0=1:1:1, 1=1:1:2, 2=1:2:2, 3=1:2:4, 4=1:4:4, 5=1:4:8,6=1:3:3, 7=1:3:6.

str r1,[r0]

;programhas not been copied, so use these directly

[CLKDIV_VAL>1 ; meansFclk:Hclk is not 1:1.

mrcp15,0,r0,c1,c0,0

orrr0,r0,#0xc0000000;R1_nF:OR:R1_iA

mcrp15,0,r0,c1,c0,0

|

mrcp15,0,r0,c1,c0,0

bicr0,r0,#0xc0000000;R1_iA:OR:R1_nF

mcrp15,0,r0,c1,c0,0

]

; 在配置UPLLCON和MPLLCON寄存器時,必須先配置UPLLCON,然後再配置MPLLCON,而且兩者之間要有7 nop的間隔。(這是2440文檔明確要求的)

;ConfigureUPLL

ldr r0,=UPLLCON

ldr r1,=((U_MDIV<<12)+(U_PDIV<<4)+U_SDIV) ;Fin = 12.0MHz, UCLK =48MHz,對於usb來說必須是48MHz

str r1,[r0]

nop ; Caution: After UPLL setting, at least7-clocks delay must be inserted for setting hardware be completed.

nop

nop

nop

nop

nop

nop

;ConfigureMPLL

ldr r0,=MPLLCON ;計算公式是固定的,可計算得到

ldr r1,=((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV) ;Fin = 12.0MHz, FCLK= 400MHz

str r1,[r0]

]

;Checkif the boot is caused by the wake-up from SLEEP mode.

ldr r1,=GSTATUS2 ;這個寄存器數值表示哪個信號引起的復位動作產生

ldr r0,[r1]

tst r0,#0x2

;Incase of the wake-up from SLEEP mode, go to SLEEP_WAKEUP handler.

bne WAKEUP_SLEEP

EXPORTStartPointAfterSleepWakeUp

StartPointAfterSleepWakeUp

;Setmemory control registers

;ldr r0,=SMRDATA ;(等效於下邊的指令)

adrl r0,SMRDATA ;be careful!中等范圍的地址讀取偽指令,用法類似於ldr(大范圍地址讀取)偽指令

ldr r1,=BWSCON ;BWSCONAddress

add r2, r0, #52 ;Endaddress of SMRDATA 共有13個寄存器地址(4字節)需要賦值,13*4=52字節

0

ldr r3, [r0], #4 ;這些都是後變址指令

str r3, [r1], #4

cmp r2, r0

bne %B0 ;當<的時候,跳轉到0標號處繼續執行

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;; When EINT0 is pressed, Clear SDRAM

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; check if EIN0 button is pressed

ldr r0,=GPFCON ;input,無上拉電阻

ldr r1,=0x0

str r1,[r0]

ldr r0,=GPFUP

ldr r1,=0xff

str r1,[r0]

ldr r1,=GPFDAT

ldr r0,[r1]

bic r0,r0,#(0x1e<<1) ; bit clear

tst r0,#0x1

bne%F1 ;若不相等,則向下跳到1標號,跳過下邊代碼

; Clear SDRAM Start

ldr r0,=GPFCON

ldr r1,=0x55aa

str r1,[r0]

; ldr r0,=GPFUP

; ldr r1,=0xff

; str r1,[r0]

ldr r0,=GPFDAT

ldr r1,=0x0

str r1,[r0] ;LED=****

movr1,#0

movr2,#0

movr3,#0

movr4,#0

movr5,#0

movr6,#0

movr7,#0

movr8,#0

ldr r9,=0x4000000 ;64MB ;這幾條指令目的是:擦除sdram的所有數據

ldr r0,=0x30000000

0

stmia r0!,{r1-r8}

subs r9,r9,#32

bne %B0

;Clear SDRAM End

1

;Initializestacks

bl InitStacks

;===========================================================

;OM0是flash選擇開關,OM0接地時從nand 啟動,懸空時(核心板上有上拉電阻)從nor啟動

;OM1在核心板上,始終是接地.為0

;OM1:OM0取值:00 nandflash mode;01 16bit nor;10 32bit nor;11 test mode

;詳見:s3c2440 用戶手冊 5.memory controller 一節

ldr r0, =BWSCON

ldr r0, [r0]

ands r0, r0, #6 ;OM[1:0]!= 0, NOR FLash boot do not read nand flash

bne copy_proc_beg

adr r0, ResetEntry ;OM[1:0] == 0, NAND FLash boot

cmp r0, #0 ;ifuse Multi-ice,

bne copy_proc_beg ;donot read nand flash for boot

;nop

;ands指令,加s表示結果影響cpsr寄存器的值

;===========================================================

;把nand中的數據,拷貝到ram中

nand_boot_beg

[{TRUE}

blRdNF2SDRAM

]

ldr pc, =copy_proc_beg

;這裡的一段代碼時對內存數據的初始化,涉及代碼段,數據段,bss段等

;因對這裡的變量設置等有異議,暫時未全面分析,但是基本原理想通,就是一個比較地址,復制數據的過程

copy_proc_beg

adr r0, ResetEntry

ldr r2, BaseOfROM

cmp r0, r2

ldreq r0, TopOfROM

beq InitRam

ldrr3, TopOfROM

0

ldmia r0!, {r4-r7}

stmia r2!, {r4-r7}

cmp r2, r3

bcc %B0

sub r2, r2, r3

sub r0, r0, r2

InitRam

ldr r2, BaseOfBSS

ldr r3, BaseOfZero

0

cmp r2, r3

ldrcc r1, [r0], #4

strcc r1, [r2], #4

bcc %B0

mov r0, #0

ldr r3, EndOfBSS

1

cmp r2, r3

strcc r0, [r2], #4

bcc %B1

ldr pc, =%F2 ;gotocompiler address

2

; [CLKDIV_VAL>1 ; meansFclk:Hclk is not 1:1.

; bl MMU_SetAsyncBusMode

; |

; blMMU_SetFastBusMode ; default value.

; ]

;===========================================================

; Setup IRQ handler

; 把中斷服務函數的總入口地址,賦給HandleIRQ地址(文件最低端定義)

ldr r0,=HandleIRQ ;Thisroutine is needed

ldr r1,=IsrIRQ ;ifthere is not 'subs pc,lr,#4' at 0x18, 0x1c

str r1,[r0]

[:LNOT:THUMBCODE

bl Main ;Do not use main() because ......

b .

]

[THUMBCODE ;for start-up code for Thumbmode

orr lr,pc,#1

bx lr

CODE16

bl Main ;Do not use main() because ......

b .

CODE32

]

;function initializing stacks

InitStacks ; 初始化棧空間(各個模式下的),為c函數運行做准備

;Donot use DRAM,such as stmfd,ldmfd......

;SVCstackis initialized before

;Undertoolkit ver 2.5, 'msr cpsr,r1' can be used instead of 'msr cpsr_cxsf,r1'

mrs r0,cpsr

bic r0,r0,#MODEMASK

orr r1,r0,#UNDEFMODE|NOINT

msr cpsr_cxsf,r1 ;UndefMode

ldr sp,=UndefStack ; UndefStack=0x33FF_5C00

orr r1,r0,#ABORTMODE|NOINT

msr cpsr_cxsf,r1 ;AbortMode

ldr sp,=AbortStack ; AbortStack=0x33FF_6000

orr r1,r0,#IRQMODE|NOINT

msr cpsr_cxsf,r1 ;IRQMode

ldr sp,=IRQStack ;IRQStack=0x33FF_7000

orr r1,r0,#FIQMODE|NOINT

msr cpsr_cxsf,r1 ;FIQMode

ldr sp,=FIQStack ;FIQStack=0x33FF_8000

bic r0,r0,#MODEMASK|NOINT

orr r1,r0,#SVCMODE

msr cpsr_cxsf,r1 ;SVCMode

ldr sp,=SVCStack ;SVCStack=0x33FF_5800

;USERmode has not be initialized.

mov pc,lr

;TheLR register will not be valid if the current mode is not SVC mode.

LTORG

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.

DCD(0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))

DCD((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC)) ;GCS0

DCD((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC)) ;GCS1

DCD((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC)) ;GCS2

DCD((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC)) ;GCS3

DCD((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC)) ;GCS4

DCD((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC)) ;GCS5

DCD((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN)) ;GCS6

DCD((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN)) ;GCS7

DCD((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Tsrc<<18)+(Tchr<<16)+REFCNT)

DCD0x32 ;SCLK power saving mode, BANKSIZE 128M/128M

DCD0x30 ;MRSR6 CL=3clk

DCD0x30 ;MRSR7 CL=3clk

;分配一個字的空間,並用後邊的數值來初始化該空間 ,這裡命名有些混亂

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|

ALIGN

;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 mayhave not to be changed.

;void EnterPWDN(int CLKCON);

EnterPWDN

movr2,r0 ;r2=rCLKCON

tstr0,#0x8 ;SLEEP mode?

bneENTER_SLEEP

ENTER_STOP

ldrr0,=REFRESH

ldrr3,[r0] ;r3=rREFRESH

movr1, r3

orrr1, r1, #BIT_SELFREFRESH

strr1, [r0] ;Enable SDRAMself-refresh

movr1,#16 ;wait untilself-refresh is issued. may not be needed.

0 subsr1,r1,#1

bne%B0

ldrr0,=CLKCON ;enter STOP mode.

strr2,[r0]

movr1,#32

0 subsr1,r1,#1 ;1) wait until the STOP mode isin effect.

bne%B0 ;2) Or wait here until theCPU&Peripherals will be turned-off

; Entering SLEEP mode, only the reset bywake-up is available.

ldrr0,=REFRESH ;exit from SDRAM self refresh mode.

strr3,[r0]

MOV_PC_LR

ENTER_SLEEP

;NOTE.

;1)rGSTATUS3 should have the return address after wake-up from SLEEP mode.

ldrr0,=REFRESH

ldrr1,[r0] ;r1=rREFRESH

orrr1, r1, #BIT_SELFREFRESH

strr1, [r0] ;Enable SDRAMself-refresh

movr1,#16 ;Wait untilself-refresh is issued,which may not be needed.

0 subsr1,r1,#1

bne%B0

ldr r1,=MISCCR

ldr r0,[r1]

orr r0,r0,#(7<<17) ;Set SCLK0=0, SCLK1=0, SCKE=0.

str r0,[r1]

ldrr0,=CLKCON ; Enter sleep mode

strr2,[r0]

b. ;CPU will die here.

WAKEUP_SLEEP

;ReleaseSCLKn after wake-up from the SLEEP mode.

ldr r1,=MISCCR

ldr r0,[r1]

bic r0,r0,#(7<<17) ;SCLK0:0->SCLK, SCLK1:0->SCLK,SCKE:0->=SCKE.

str r0,[r1]

;Setmemory control registers

ldr r0,=SMRDATA ;be careful!

ldr r1,=BWSCON ;BWSCONAddress

add r2, r0, #52 ;Endaddress of SMRDATA

0

ldr r3, [r0], #4

str r3, [r1], #4

cmp r2, r0

bne %B0

movr1,#256

0 subsr1,r1,#1 ;1) wait until the SelfRefreshis released.

bne%B0

ldrr1,=GSTATUS3 ;GSTATUS3 has the startaddress just after SLEEP wake-up

ldrr0,[r1]

movpc,r0

;=====================================================================

; Clock division test

; Assemble code, because VSYNC time is veryshort

;=====================================================================

EXPORTCLKDIV124

EXPORTCLKDIV144

CLKDIV124

ldr r0, = CLKDIVN

ldr r1, = 0x3 ;0x3 = 1:2:4

str r1, [r0]

; waituntil clock is stable

nop

nop

nop

nop

nop

ldr r0, = REFRESH

ldr r1, [r0]

bic r1, r1, #0xff

bic r1, r1, #(0x7<<8)

orr r1, r1, #0x470 ; REFCNT135

str r1, [r0]

nop

nop

nop

nop

nop

mov pc, lr

CLKDIV144

ldr r0, = CLKDIVN

ldr r1, = 0x4 ;0x4 = 1:4:4

str r1, [r0]

; waituntil clock is stable

nop

nop

nop

nop

nop

ldr r0, = REFRESH

ldr r1, [r0]

bic r1, r1, #0xff

bic r1, r1, #(0x7<<8)

orr r1, r1, #0x630 ; REFCNT675 - 1520

str r1, [r0]

nop

nop

nop

nop

nop

mov pc, lr

ALIGN

;定義數據段

;^ 標志等價於MAP偽指令

;MAP用於定義一個結構化的內存表首地址,此時內存表的位置計數器值,也變成該首地址值,就相當於在這個地址處操作

;#於FIELD同義,用於定義一個結構化的內存表的數據域,後邊數字表示該數據占用的字節數

;Handle*** 在此就是一個標號,為了標示數據量

;用法:把對應的終端處理函數的首地址,放到這裡的對應的預留空間處,當發生中斷時,就能根據宏函數,直接跳轉

AREARamData, DATA, READWRITE

^ _ISR_STARTADDRESS ; _ISR_STARTADDRESS=0x33FF_FF00

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

END

Copyright © Linux教程網 All Rights Reserved