找到了一些當初學習嵌入式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