s3c2440啟動文件詳細(xì)分析
下面就是我對s3c2440啟動文件的分析,標(biāo)注了較詳細(xì)的注解,不僅有我對啟動文件的理解,同時也查閱其他網(wǎng)友的相關(guān)文章。理解不對的地方還望大家指正!
;=========================================
; NAME: 2440INIT.S
; DESC: C start up codes
;Configure memory, ISR ,stacks
;Initialize C-variables
;=========================================
;GET類似于C語言的include,option.inc文件內(nèi)定義了一些全局變量,memcfg.inc文件內(nèi)定義了關(guān)于內(nèi)存bank的符號和數(shù)字常量,2440addr.inc文件內(nèi)定義了用于匯編的s3c2440寄存器變量和地址
GET option.inc
GET memcfg.inc
GET 2440addr.inc
;SDRAM自刷新位,把寄存器REFRESH的第22位處置1
BIT_SELFREFRESH EQU(1<<22)
;CPSR中的低5位定義了處理器的七種工作模式,為以后切換模式時使用
;Pre-defined constants
USERMODEEQU 0x10
FIQMODEEQU0x11
IRQMODEEQU0x12
SVCMODEEQU0x13
ABORTMODEEQU0x17
UNDEFMODEEQU0x1b
MODEMASKEQU0x1f
;CPSR中的I位和F位置1,表示禁止任何中斷
NOINTEQU0xc0
;定義了7種處理器模式下的棧的起始地址,其中用戶模式和系統(tǒng)模式共有一個??臻g
;_STACK_BASEADDRESS在option.inc文件內(nèi)定義,值為0x33ff8000
;The location of stacks
UserStackEQU(_STACK_BASEADDRESS-0x3800);0x33ff4800 ~
SVCStackEQU(_STACK_BASEADDRESS-0x2800);0x33ff5800 ~
UndefStackEQU(_STACK_BASEADDRESS-0x2400);0x33ff5c00 ~
AbortStackEQU(_STACK_BASEADDRESS-0x2000);0x33ff6000 ~
IRQStackEQU(_STACK_BASEADDRESS-0x1000);0x33ff7000 ~
FIQStackEQU(_STACK_BASEADDRESS-0x0);0x33ff8000 ~
;ARM處理器的兩種工作狀態(tài):16位和32位
;編譯器有相對應(yīng)的用16位和32位兩種編譯方式
;這段的目的是統(tǒng)一目前的處理器工作狀態(tài)和軟件編譯方式
;Check if tasm.exe(armasm -16 ...@ADS 1.0) is used.
GBLLTHUMBCODE;聲明一個全局邏輯變量
[ {CONFIG} = 16;if CONFIG == 16
THUMBCODE SETL{TRUE};THUMBCODE = TRUE
CODE32;指示編譯器為ARM指令
|;else
THUMBCODE SETL{FALSE};THUMBCODE = FALSE
]
;宏定義,在后面出現(xiàn)MOV_PC_LR時,這個宏會被自動展開
;該宏的作用是跳出子程序,返回被調(diào)用處
MACRO
MOV_PC_LR
[ THUMBCODE;if THUMBCODE == TRUE
bx lr
|;else即THUMBCODE == FALSE
movpc,lr
]
MEND
;該宏定義的作用是有條件地(當(dāng)Z=1時)跳出子程序,返回被調(diào)用處
MACRO
MOVEQ_PC_LR
[ THUMBCODE
bxeq lr
|
moveq pc,lr
]
MEND
;該宏定義是把中斷服務(wù)程序的首地址裝載到pc中
;在后面當(dāng)遇到HandlerXXX HANDLER HandleXXX時,該宏被展開
;注意:HANDLER前的符號HandlerXXX比其后的符號HandleXXX多了一個r
;HandlerXXX為ARM體系中統(tǒng)一定義的幾種異常中斷
;HandleXXX為每個ARM處理器各自定義的中斷,見該文件最后部分的中斷向量表
MACRO
$HandlerLabel HANDLER $HandleLabel
$HandlerLabel
subsp,sp,#4;ATPCS規(guī)定數(shù)據(jù)棧為FD類型
;即棧指針指向棧頂元素,數(shù)據(jù)棧向內(nèi)存地址減小的方向增長
;該語句是使棧地址減小4個字節(jié),以留出空間裝載中斷服務(wù)函數(shù)首地址
stmfdsp!,{r0};由于要利用r0寄存器來傳遞數(shù)據(jù),所以要保存r0數(shù)據(jù),使其入棧
ldrr0,=$HandleLabel;把HandleXXX的地址裝到r0
ldrr0,[r0];裝載中斷服務(wù)函數(shù)的起始地址
strr0,[sp,#4];中斷函數(shù)首地址入棧
ldmfdsp!,{r0,pc};將事先保存的r0數(shù)據(jù)和中斷函數(shù)首地址出棧
;并使系統(tǒng)跳轉(zhuǎn)到相應(yīng)的中斷處理函數(shù)
MEND
;導(dǎo)入連接器事先定義好的運行域中三個段變量
;ARM的可執(zhí)行映像文件由RO、RW、ZI三個段組成
;RO為代碼段,RW為已初始化的全局變量,ZI為未初始化的全局變量
IMPORT|Image
IMPORT|Image
IMPORT|Image
IMPORT|Image
IMPORT|Image
;導(dǎo)入兩個關(guān)于MMU的函數(shù),用于設(shè)置時鐘模式為異步模式和快速總線模式
IMPORTMMU_SetAsyncBusMode
IMPORTMMU_SetFastBusMode;
;導(dǎo)入Main,它為C語言程序入口函數(shù)
IMPORTMain; The main entry of mon program
;導(dǎo)入用于復(fù)制從Nand Flash中的映像文件到SDRAM中的函數(shù)
IMPORTRdNF2SDRAM; Copy Image from Nand Flash to SDRAM
;定義代碼段,名為Init
AREAInit,CODE,READONLY
;在入口處(0x0)開始的8個字單元空間內(nèi),存放的是ARM異常中斷向量表,每個字單元空間都是一條跳轉(zhuǎn)指令,當(dāng)異常發(fā)生時,ARM會自動跳轉(zhuǎn)到相應(yīng)的中斷向量處,并由該處的跳轉(zhuǎn)指令再跳轉(zhuǎn)到相應(yīng)的執(zhí)行函數(shù)處
ENTRY;程序入口處
EXPORT__ENTRY;導(dǎo)出__ENTRY,即導(dǎo)出代碼段入口地址
__ENTRY;主要用于MMU
ResetEntry
;1)The code, which converts to Big-endian, should be in little endian code.
;2)The following little endian code will be compiled in Big-Endian mode.
;The code byte order should be changed as the memory bus width.
;3)The pseudo instruction,DCD can not be used here because the linker generates error.
;在0x0處的異常中斷是復(fù)位異常中斷,是上電后執(zhí)行的第一條指令
;變量ENDIAN_CHANGE用于標(biāo)記是否要從小端模式改變?yōu)榇蠖四J?,因為編譯器初始模式是小端模式,如果要用大端模式,就要事先把該變量設(shè)置為TRUE,否則為FLASE
;變量ENTRY_BUS_WIDTH用于設(shè)置總線的寬度,因為用16位和8位寬度來表示32位數(shù)據(jù)時,在大端模式下,數(shù)據(jù)的含義是不同的
;由于要考慮到大端和小端模式,以及總線的寬度,因此該處看似較復(fù)雜,其實只是一條跳轉(zhuǎn)指令:當(dāng)為大端模式時,跳轉(zhuǎn)到ChangeBigEndian函數(shù)處,否則跳轉(zhuǎn)到ResetHandler函數(shù)處
ASSERT:DEF:ENDIAN_CHANGE;判斷是否定義了ENDIAN_CHANGE
;如果沒有定義,則報告該處錯誤信息
[ ENDIAN_CHANGE;if ENDIAN_CHANGE ==TRUE
ASSERT:DEF:ENTRY_BUS_WIDTH;判斷是否定義了ENTRY_BUS_WIDTH
;如果沒有定義,則報告該處錯誤信息
[ ENTRY_BUS_WIDTH=32;if ENTRY_BUS_WIDTH ==32
;跳轉(zhuǎn)到ChangeBigEndian(ChangeBigEndian在0x24),因此該條指令的機(jī)器碼為0xea000007
;所以該語句與在該處(即0x0處)直接放入0xea000007數(shù)據(jù)(即DCD 0xea000007)作用相同
bChangeBigEndian
]
[ ENTRY_BUS_WIDTH=16;if ENTRY_BUS_WIDTH ==16
;在小端模式下,用16位或8位數(shù)據(jù)總線寬度表示32位數(shù)據(jù),與用32位總線寬度表示32位數(shù)據(jù),格式完全一致。但在大端模式下,格式就會發(fā)生變化
;在復(fù)位時,系統(tǒng)默認(rèn)的是小端模式,所以就要人為地改變數(shù)據(jù)格式,使得用16位大端數(shù)據(jù)表示的32位數(shù)據(jù)也能被小端模式的系統(tǒng)識別
;該語句的目的也是跳轉(zhuǎn)到ChangeBigEndian,即機(jī)器碼也應(yīng)該是0xea000007,但為了讓小端模式系統(tǒng)識別,就要把機(jī)器碼的順序做一下調(diào)整,改為0x0007ea00,那么我們就可以用DCD 0x0007ea00把機(jī)器碼裝載進(jìn)去了,但由于該處不能使用DCD偽指令,因此我們就要用一條真實的指令來代替DCD 0x0007ea00,即該指令編譯后的機(jī)器碼也為0x0007ea00,而andeqr14,r7,r0,lsl #20就是一條編譯后機(jī)器碼為0x0007ea00的指令,所以我們在該處寫上該條指令
andeqr14,r7,r0,lsl #20;DCD 0x0007ea00
]
[ ENTRY_BUS_WIDTH=8;if ENTRY_BUS_WIDTH ==8
;該語句的分析與上一段代碼的分析相似
;streqr0,[r0,-r10,ror #1]編譯后的機(jī)器碼為0x070000ea
streqr0,[r0,-r10,ror #1] ;DCD 0x070000ea
]
|;else即ENDIAN_CHANGE ==FALSE
bResetHandler;跳轉(zhuǎn)到ResetHandler處,復(fù)位
]
bHandlerUndef;未定義
bHandlerSWI;軟件中斷
bHandlerPabort;指令預(yù)取中止
bHandlerDabort;數(shù)據(jù)訪問中止
b.;保留,跳轉(zhuǎn)到自身地址處,即進(jìn)入死循環(huán)
bHandlerIRQ;外部中斷請求
bHandlerFIQ;快速中斷請求
;以上為異常中斷向量表
;跳轉(zhuǎn)到EnterPWDN,處理電源管理的其他非正常模式,在C語言程序段中被調(diào)用
;該處地址為0x20,至于為什么要在該處執(zhí)行,我認(rèn)為可能是該處離異常中斷向量表最近吧
bEnterPWDN; Must be @0x20.
;由0x0跳轉(zhuǎn)至此,目的是把小端模式改為大端模式,即把CP15中的寄存器C1中的第7位置1
ChangeBigEndian
;@0x24
[ ENTRY_BUS_WIDTH=32;if ENTRY_BUS_WIDTH == 32
;執(zhí)行mrc p15,0,r0,c1,c0,0,得到CP15中的寄存器C1,放入r0中
;由于mrc p15,0,r0,c1,c0,0的機(jī)器碼為0xee110f10
;因此DCD0xee110f10的意思就是mrc p15,0,r0,c1,c0,0。下同
DCD0xee110f10;0xee110f10 => mrc p15,0,r0,c1,c0,0
;執(zhí)行orr r0,r0,#0x80,置r0中的第7位為1,表示選擇大端模式
DCD0xe3800080;0xe3800080 => orr r0,r0,#0x80;//Big-endian
;執(zhí)行mcr p15,0,r0,c1,c0,0,把r0寫入CP15中的寄存器C1
DCD0xee010f10;0xee010f10 => mcr p15,0,r0,c1,c0,0
]
[ ENTRY_BUS_WIDTH=16;if ENTRY_BUS_WIDTH == 16
;由于此時系統(tǒng)還不能識別16位或8位大端模式下表示的32為數(shù)據(jù)
;因此還需人為地進(jìn)行數(shù)據(jù)調(diào)整,即把0xee110f10變?yōu)?x0f10ee11
;然后用DCD指令存入該數(shù)據(jù)。下同
DCD 0x0f10ee11
DCD 0x0080e380
DCD 0x0f10ee01
]
[ ENTRY_BUS_WIDTH=8;if ENTRY_BUS_WIDTH == 8
DCD 0x100f11ee
DCD 0x800080e3
DCD 0x100f01ee
]
;相當(dāng)于NOP指令
;作用是等待系統(tǒng)從小端模式向大端模式轉(zhuǎn)換
;此后系統(tǒng)就能夠自動識別出不同總線寬度下的大端模式,因此以后就無需再人為調(diào)整指令了
DCD 0xffffffff;swinv 0xffffff is similar with NOP and run well in both endian mode.
DCD 0xffffffff
DCD 0xffffffff
DCD 0xffffffff
DCD 0xffffffff
b ResetHandler;跳轉(zhuǎn)到ResetHandler
;當(dāng)系統(tǒng)進(jìn)入異常中斷后,由存放在0x0~0x1C處的中斷向量地址中的跳轉(zhuǎn)指令,跳轉(zhuǎn)到此處相應(yīng)的位置,并由事先定義好的宏定義再次跳轉(zhuǎn)到相應(yīng)的中斷服務(wù)程序中
HandlerFIQHANDLER HandleFIQ
HandlerIRQHANDLER HandleIRQ
HandlerUndefHANDLER HandleUndef
HandlerSWIHANDLER HandleSWI
HandlerDabortHANDLER HandleDabort
HandlerPabortHANDLER HandlePabort
;下面這段代碼是用于處理非向量中斷,即由軟件程序來判斷到底發(fā)生了哪種中斷,然后跳轉(zhuǎn)到相應(yīng)地中斷服務(wù)程序中
;具體地說就是,當(dāng)發(fā)生中斷時,會置INTOFFSET寄存器相應(yīng)的位為1,然后通過查表(見該程序末端部分的中斷向量表),找到相對應(yīng)的中斷入口地址
;觀察中斷向量表,會發(fā)現(xiàn)它與INTOFFSET寄存器中的中斷源正好相對應(yīng),即向量表的順序與INTOFFSET寄存器中的中斷源的由小到大的順序一致,因此我們可以用基址加變址的方式很容易找到相對應(yīng)的中斷入口地址。其中基址為向量表的首個中斷源地址,變址為INTOFFSET寄存器的值乘以4(因為系統(tǒng)是用4個字節(jié)單元來存放一個中斷向量)
IsrIRQ
subsp,sp,#4;在棧中留出4個字節(jié)空間,以便保存中斷入口地址
stmfdsp!,{r8-r9};由于要用到r8和r9,因此保存這兩個寄存器內(nèi)的值
ldrr9,=INTOFFSET;把INTOFFSET寄存器地址裝入r9內(nèi)
ldrr9,[r9];讀取INTOFFSET寄存器內(nèi)容
ldrr8,=HandleEINT0;得到中斷向量表的基址
addr8,r8,r9,lsl #2;用基址加變址的方式得到中斷向量表的地址
ldrr8,[r8];得到中斷服務(wù)程序入口地址
strr8,[sp,#8];使中斷服務(wù)程序入口地址入棧
ldmfdsp!,{r8-r9,pc};使r8,r9和入口地址出棧,并跳到中斷服務(wù)程序中
;定義一個數(shù)據(jù)緩沖池,供ldr偽指令使用
LTORG
;=======
; ENTRY
;=======
;系統(tǒng)上電或復(fù)位后,由0x0處的跳轉(zhuǎn)指令,跳轉(zhuǎn)到該處開始真正執(zhí)行系統(tǒng)的初始化工作
ResetHandler
;在系統(tǒng)初始化過程中,不需要看門狗,因此關(guān)閉看門狗功能
ldrr0,=WTCON;watch dog disable
ldrr1,=0x0
strr1,[r0]
;同樣,此時也不應(yīng)該響應(yīng)任何中斷,因此屏蔽所有中斷,以及子中斷
ldrr0,=INTMSK
ldrr1,=0xffffffff;all interrupt disable
strr1,[r0]
ldrr0,=INTSUBMSK
ldrr1,=0x7fff;all sub interrupt disable
strr1,[r0]
;由于啟動文件是無法仿真的,因此為了判斷該文件中語句的正確與否,往往在需要觀察的地方加上一段點亮LED的程序,這樣就可以知道程序是否已經(jīng)執(zhí)行到此處
;下面方括號內(nèi)的程序就是點亮LED的小程序
[ {FALSE}
;rGPFDAT = (rGPFDAT & ~(0xf<<4)) | ((~data & 0xf)<<4);
; Led_Display
ldrr0,=GPBCON
ldrr1,=0x155500
strr1,[r0]
ldrr0,=GPBDAT
ldrr1,=0x0
strr1,[r0]
]
;下列程序是用于設(shè)置系統(tǒng)時鐘頻率
;設(shè)置PLL的鎖定時間常數(shù),以得到一定時間的延時
;To reduce PLL lock time, adjust the LOCKTIME register.
ldrr0,=LOCKTIME
ldrr1,=0xffffff
strr1,[r0]
[ PLL_ON_START
; Added for confirm clock divide. for 2440.
; Setting value Fclk:Hclk:Pclk
;設(shè)置系統(tǒng)的三個時鐘頻率FCLK、HCLK、PCLK
ldrr0,=CLKDIVN
ldrr1,=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.
strr1,[r0]
;program has not been copied, so use these directly
[ CLKDIV_VAL>1;if FCLK:HCLK≠1:1
;設(shè)置時鐘模式為異步模式
mrc p15,0,r0,c1,c0,0
orr r0,r0,#0xc0000000;R1_nF:OR:R1_iA
mcr p15,0,r0,c1,c0,0
|;else
;設(shè)置時鐘模式為快速總線模式
mrc p15,0,r0,c1,c0,0
bic r0,r0,#0xc0000000;R1_iA:OR:R1_nF
mcr p15,0,r0,c1,c0,0
]
;配置UPLL
;按照手冊中的計算公式,確定MDIV、PDIV和SDIV
;得到當(dāng)系統(tǒng)輸入時鐘頻率為12MHz的情況下,UCLK輸出頻率為48MHz
;Configure UPLL
ldrr0,=UPLLCON
ldrr1,=((U_MDIV<<12)+(U_PDIV<<4)+U_SDIV);Fin = 12.0MHz, UCLK = 48MHz
strr1,[r0]
;等待至少7個時鐘周期,以保證系統(tǒng)的正確配置
nop; Caution: After UPLL setting, at least 7-clocks delay must be inserted for setting hardware be completed.
nop
nop
nop
nop
nop
nop
;配置MPLL,同UPLL
;Configure MPLL
ldrr0,=MPLLCON
ldrr1,=((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV);Fin = 12.0MHz, FCLK = 400MHz
strr1,[r0]
]
;從SLEEP模式下被喚醒,類似于RESET引腳被觸發(fā),因此它也要從0x0處開始執(zhí)行
;在此處要判斷是否是由SLEEP模式喚醒引起的復(fù)位
;Check if the boot is caused by the wake-up from SLEEP mode.
ldrr1,=GSTATUS2
ldrr0,[r1]
tstr0,#0x2;檢查GSTATUS2寄存器的第1位
;In case of the wake-up from SLEEP mode, go to SLEEP_WAKEUP handler.
bneWAKEUP_SLEEP;是被喚醒的,則跳轉(zhuǎn)
;設(shè)置一個被喚醒復(fù)位后的起始點地址標(biāo)號,可以把它保存到GSTATUS3中
;導(dǎo)出該地址標(biāo)號,以便在C語言程序中使用
EXPORT StartPointAfterSleepWakeUp
StartPointAfterSleepWakeUp
;設(shè)置內(nèi)存控制寄存器
;關(guān)于內(nèi)存控制寄存器一共有以BWSCON為開始的連續(xù)放置的13個寄存器,我們要一次性批量完成這13個寄存器的配置
;因此開辟一段以SMRDATA為地址起始點的13個字單元空間,按順序放入要寫入的13個寄存器內(nèi)容
;Set memory control registers
;ldrr0,=SMRDATA
adrlr0, SMRDATA;得到SMRDATA空間的首地址
ldrr1,=BWSCON;得到BWSCON的地址
addr2, r0, #52;得到SMRDATA空間的末地址
;完成13個字?jǐn)?shù)據(jù)的復(fù)制
0
ldrr3, [r0], #4
strr3, [r1], #4
cmpr2, r0
bne%B0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;When EINT0 is pressed,Clear SDRAM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; check if EIN0 button is pressed
;檢查EIN0按鈕是否被按下
ldrr0,=GPFCON
ldrr1,=0x0
strr1,[r0];GPFCON=0,F(xiàn)口為輸入
ldrr0,=GPFUP
ldrr1,=0xff
strr1,[r0];GPFUP=0xff,上拉功能無效
ldrr1,=GPFDAT
ldrr0,[r1];讀取F口數(shù)據(jù)
bicr0,r0,#(0x1e<<1);僅保留第1位數(shù)據(jù),其他清0
tstr0,#0x1;判斷第1位
bne %F1;不為0表示按鈕沒有被按下,則向前跳轉(zhuǎn),不執(zhí)行清空SDRAM
; Clear SDRAM Start
;清空SDRAM
ldrr0,=GPFCON
ldrr1,=0x55aa
strr1,[r0];GPF7~4為輸出,GPF3~0為中斷
;ldrr0,=GPFUP
;ldrr1,=0xff
;strr1,[r0];上拉功能無效
ldrr0,=GPFDAT
ldrr1,=0x0
strr1,[r0];GPFDAT = 0
mov r1,#0
mov r2,#0
mov r3,#0
mov r4,#0
mov r5,#0
mov r6,#0
mov r7,#0
mov r8,#0
ldrr9,=0x4000000;64MB RAM
ldrr0,=0x30000000;RAM首地址
;清空64MB的RAM
0
stmiar0!,{r1-r8}
subsr9,r9,#32
bne%B0
;Clear SDRAM End
1
;初始化各種處理器模式下的堆棧
;Initialize stacks
blInitStacks;跳轉(zhuǎn)到InitStacks
;===========================================================
;下面的代碼為把ROM中的數(shù)據(jù)復(fù)制到RAM中
ldrr0, =BWSCON
ldrr0, [r0]
andsr0, r0, #6;讀取OM[1:0]引腳狀態(tài)
;為0表示從NAND Flash啟動,不為0則從NOR Flash啟動
bnecopy_proc_beg;跳轉(zhuǎn),不用讀取NAND Flash
adrr0, ResetEntry;OM[1:0] == 0,從NAND Flash啟動
cmpr0, #0;if use Multi-ice,
bnecopy_proc_beg;do not read nand flash for boot
;nop
;===========================================================
nand_boot_beg
[ {TRUE}
bl RdNF2SDRAM;復(fù)制NAND Flash到SDRAM
]
ldrpc, =copy_proc_beg
;===========================================================
copy_proc_beg
adrr0, ResetEntry
ldrr2, BaseOfROM
cmpr0, r2;比較程序入口地址與連接器定義的RO基地址
ldreqr0, TopOfROM;如果相等,把RO尾地址讀取到r0中
beqInitRam;如果相等,則跳轉(zhuǎn)
ldr r3, TopOfROM;否則,把RO尾地址讀取到r3中
;下列循環(huán)體為在程序入口地址與連接器定義的RO基地址不相等的情況下,把程序復(fù)制到RAM中
0
ldmiar0!, {r4-r7}
stmiar2!, {r4-r7}
cmpr2, r3
bcc%B0
;修正非字對齊的情況
subr2, r2, r3
subr0, r0, r2
InitRam
ldrr2, BaseOfBSS
ldrr3, BaseOfZero
;下面循環(huán)體為復(fù)制已初始化的全局變量
0
cmpr2, r3
ldrccr1, [r0], #4
strccr1, [r2], #4
bcc%B0
;下面循環(huán)體是為未初始化的全局變量賦值為0
movr0,#0
ldrr3,EndOfBSS
1
cmpr2,r3
strccr0, [r2], #4
bcc%B1
ldrpc, =%F2;goto compiler address
2
;[ CLKDIV_VAL>1;if FCLK:HCLK≠1:1
;blMMU_SetAsyncBusMode;設(shè)置時鐘模式為異步模式
;|
;bl MMU_SetFastBusMode;設(shè)置時鐘模式為快速總線模式
;]
;===========================================================
;普通中斷處理
;當(dāng)普通中斷發(fā)生時,執(zhí)行的是IsrIRQ
; Setup IRQ handler
ldrr0,=HandleIRQ;This routine is needed
ldrr1,=IsrIRQ;if there is not subs pc,lr,#4 at 0x18, 0x1c
strr1,[r0]
;完成最基本的初始化任務(wù),跳轉(zhuǎn)到由C語言撰寫的Main()函數(shù)內(nèi)繼續(xù)執(zhí)行其他程序
;這里不能寫main,因為寫了main,系統(tǒng)會自動為我們完成一些初始化工作,而這些工作在這段程序中是由我們顯式地人為完成的。
[ :LNOT:THUMBCODE
blMain;Do not use main() because ......
b.
]
[ THUMBCODE;for start-up code for Thumb mode
orrlr,pc,#1
bxlr
CODE16
blMain;Do not use main() because ......
b.
CODE32
]
;初始化堆棧函數(shù)
;function initializing stacks
InitStacks
;Do not use DRAM,such as stmfd,ldmfd......
;Under toolkit ver 2.5, msr cpsr,r1 can be used instead of msr cpsr_cxsf,r1
;改變CPSR中M控制位,切換到相應(yīng)的處理器模式下
;為各自模式下的SP賦值
mrsr0,cpsr
bicr0,r0,#MODEMASK
orrr1,r0,#UNDEFMODE|NOINT
msrcpsr_cxsf,r1;UndefMode
ldrsp,=UndefStack; UndefStack=0x33FF_5C00
orrr1,r0,#ABORTMODE|NOINT
msrcpsr_cxsf,r1;AbortMode
ldrsp,=AbortStack; AbortStack=0x33FF_6000
orrr1,r0,#IRQMODE|NOINT
msrcpsr_cxsf,r1;IRQMode
ldrsp,=IRQStack; IRQStack=0x33FF_7000
orrr1,r0,#FIQMODE|NOINT
msrcpsr_cxsf,r1;FIQMode
ldrsp,=FIQStack; FIQStack=0x33FF_8000
bicr0,r0,#MODEMASK|NOINT
orrr1,r0,#SVCMODE
msrcpsr_cxsf,r1;SVCMode
ldrsp,=SVCStack; SVCStack=0x33FF_5800
;系統(tǒng)模式和用戶模式共用一個??臻g,因此不用再重復(fù)設(shè)置用戶模式堆棧
;系統(tǒng)復(fù)位后進(jìn)入的是SVC模式,而且各種模式下的lr不同,因此要想從該函數(shù)內(nèi)返回,要首先切換到SVC模式,再使用lr,這樣可以正確返回了
movpc,lr
;The LR register will not be valid if the current mode is not SVC mode.
;定義一個數(shù)據(jù)緩沖池
LTORG
;連續(xù)13個內(nèi)存控制寄存器的定義空間
SMRDATA DATA
; Memory configuration should be optimized for best performance
; The following parameter is not optimized.
; Memory access cycle parameter strategy
; 1) The memory settings issafe parameters even at HCLK=75Mhz.
; 2) SDRAM refresh period is for HCLK<=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)
DCD 0x32;SCLK power saving mode, BANKSIZE 128M/128M
DCD 0x30;MRSR6 CL=3clk
DCD 0x30;MRSR7 CL=3clk
;運行域定義
BaseOfROMDCD|Image
TopOfROMDCD|Image
BaseOfBSSDCD|Image
BaseOfZeroDCD|Image
EndOfBSSDCD|Image
;重新使數(shù)據(jù)字對齊
ALIGN
;Function for entering power down mode
; 1. SDRAM should be in self-refresh mode.
; 2. All interrupt should be maksked for SDRAM/DRAM self-refresh.
; 3. LCD controller should be disabled for SDRAM/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.
;掉電模式函數(shù)
;在C語言中定義為:#define EnterPWDN(clkcon) ((void (*)(int))0x20)(clkcon)
;void EnterPWDN(int clkcon);
EnterPWDN
mov r2,r0;r0為該函數(shù)輸入?yún)?shù)clkcon
tst r0,#0x8;判斷clkcon中的第3位,是否要切換到SLEEP模式
bne ENTER_SLEEP;切換到SLEEP模式
ENTER_STOP;IDLE模式
;設(shè)置SDRAM為自刷新方式
ldr r0,=REFRESH
ldr r3,[r0];r3=rREFRESH
mov r1, r3
orr r1, r1, #BIT_SELFREFRESH
str r1, [r0];Enable SDRAM self-refresh
;等待一段時間
mov r1,#16;wait until self-refresh is issued. may not be needed.
0subs r1,r1,#1
bne %B0
ldr r0,=CLKCON
str r2,[r0];置第2位,進(jìn)入IDLE模式
;等待一段時間
mov r1,#32
0subs r1,r1,#1;1) wait until the STOP mode is in effect.
bne %B0;2) Or wait here until the CPU&Peripherals will be turned-off
;Entering SLEEP mode, only the reset by wake-up is available.
;從IDLE模式下被喚醒,系統(tǒng)從該處繼續(xù)執(zhí)行
;取消SDRAM自刷新方式
ldr r0,=REFRESH ;exit from SDRAM self refresh mode.
str r3,[r0]
MOV_PC_LR;返回,該語句為一個宏定義
ENTER_SLEEP;SLEEP模式
;NOTE.
;1) rGSTATUS3 should have the return address after wake-up from SLEEP mode.
;設(shè)置SDRAM為自刷新方式
ldr r0,=REFRESH
ldr r1,[r0];r1=rREFRESH
orr r1, r1, #BIT_SELFREFRESH
str r1, [r0];Enable SDRAM self-refresh
;等待一段時間
mov r1,#16;Wait until self-refresh is issued,which may not be needed.
0subs r1,r1,#1
bne %B0
;在進(jìn)入SLEEP模式之前,配置必要的時鐘和OFFREFRESH
ldrr1,=MISCCR
ldrr0,[r1]
orrr0,r0,#(7<<17);Set SCLK0=0, SCLK1=0, SCKE=0.
strr0,[r1]
ldr r0,=CLKCON
str r2,[r0];置第3位,進(jìn)入SLEEP模式
b .;CPU will die here.
;從SLEEP模式下被喚醒函數(shù)
WAKEUP_SLEEP
;Release SCLKn after wake-up from the SLEEP mode.
;設(shè)置時鐘和OFFREFRESH
ldrr1,=MISCCR
ldrr0,[r1]
bicr0,r0,#(7<<17);SCLK0:0->SCLK, SCLK1:0->SCLK, SCKE:0->=SCKE.
strr0,[r1]
;Set memory control registers
;配置內(nèi)存控制寄存器
ldrr0,=SMRDATA;be careful!
ldrr1,=BWSCON;BWSCON Address
addr2, r0, #52;End address of SMRDATA
0
ldrr3, [r0], #4
strr3, [r1], #4
cmpr2, r0
bne%B0
;等待一段時間
mov r1,#256
0subs r1,r1,#1;1) wait until the SelfRefresh is released.
bne %B0
;GSTATUS3存放著想要從SLEEP模式喚醒后的執(zhí)行地址
ldr r1,=GSTATUS3 ;GSTATUS3 has the start address just after SLEEP wake-up
ldr r0,[r1]
mov pc,r0;跳轉(zhuǎn)到GSTATUS3存放的地址處
;=====================================================================
; Clock division test
; Assemble code, because VSYNC time is very short
;=====================================================================
EXPORT CLKDIV124
EXPORT CLKDIV144
CLKDIV124
ldrr0, = CLKDIVN
ldrr1, = 0x3; 0x3 = 1:2:4
strr1, [r0]
;wait until clock is stable
nop
nop
nop
nop
nop
ldrr0, = REFRESH
ldrr1, [r0]
bicr1, r1, #0xff
bicr1, r1, #(0x7<<8)
orrr1, r1, #0x470; REFCNT135
strr1, [r0]
nop
nop
nop
nop
nop
movpc, lr
CLKDIV144
ldrr0, = CLKDIVN
ldrr1, = 0x4; 0x4 = 1:4:4
strr1, [r0]
;wait until clock is stable
nop
nop
nop
nop
nop
ldrr0, = REFRESH
ldrr1, [r0]
bicr1, r1, #0xff
bicr1, r1, #(0x7<<8)
orrr1, r1, #0x630; REFCNT675 - 1520
strr1, [r0]
nop
nop
nop
nop
nop
movpc, lr
ALIGN
AREA RamData, DATA, READWRITE
;在0x33FF_FF00處定義中斷向量表
;^是MAP的同義詞,#是FIELD的同義詞
^_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 different with 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;程序結(jié)尾
評論