S3C2410啟動代碼詳解(2)
//在這里用IMP
//這些變量是通過ADS的工程設置里面設定的RO Base和RW Base設定的,最終由編譯腳本和連接程序導入程序.
//那為什么要引入這玩意呢,最簡單的用處是可以根據(jù)它們拷貝自已,從把RW和ZI變量從加載域中復制到運行域中
//一個arm由RO,RW,ZI三個斷組成其中RO為代碼段,RW是已經(jīng)初始化的全局變量,ZI是未初始化的全局變量(對于GNU工具對應的概念是TEXT ,DA
IMP
IMP
IMP
IMP
IMP
;這里引入一些在其它文件中實現(xiàn)在函數(shù),包括為我們所熟知的main函數(shù)
IMP
;從這里開始就是正真的代碼入口了!
AREA Init,CO
ENTRY ;定義程序的入口(調試用)其中關鍵字ENTRY是指定編譯器保留這段代碼,因為
編譯器可能會認為這是一段亢余代碼而加以優(yōu)化。鏈接的時候要確保這段代碼
被鏈接在0地址處,并且作為整個程序的入口
;1)The co
;2)The following little endian co
; The co
;3)The pseudo instruction,DCD can not be used here because the linker generates error.
ASSERT :DEF:ENDIAN_CHANGE
[ ENDIAN_CHANGE ;下面是大小端的一個判斷,在Option.inc里已經(jīng)設為FALSE
ASSERT :DEF:ENTRY_BUS_WIDTH
[ ENTRY_BUS_WIDTH=32 //‘[’=IF
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 ;因為設成FALSE,所以系統(tǒng)復位后就來到這了,轉跳到復位程序入口
]
//=====================================================================================
;ARM要求中斷向量表必須放置在仿地址開始,連續(xù)8X4字節(jié)的空間內.每當一個中斷發(fā)生以后,ARM處理器便強制把PC指針置為向量表中對應中斷類型的地址值。因為每個中斷只占據(jù)向量表中1個字的存儲空間,只能放置一條ARM指令,使程序跳轉到存儲器的其他地方,再執(zhí)行中斷處理
//=====================================================================================
b HandlerUndef ;轉跳到Undefined mode程序入口
b HandlerSWI ;轉跳到SWI 中斷程序入口
b HandlerPabort ;轉跳到PAbort(指令異常)程序入口
b HandlerDabort ;轉跳到DAbort(數(shù)據(jù)異常)程序入口
b . ;保留
b HandlerIRQ ;轉跳到IRQ 中斷程序入口
b HandlerFIQ ;轉跳到FIQ 中斷程序入口
;@0x20不知道是什么意思,地址?
b EnterPWDN ; Must be @0x20.
;==================================================================================
;下面是改變大小端的程序,這里采用直接定義機器碼的方式,至說為什么這么做就得問三星了
;反正我們程序里這段代碼也不會去執(zhí)行,不用去管它
;==================================================================================
ChangeBigEndian //通過設置CP15中的C1的位7來設置存儲格式為大端模式。
;@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
]
[ ENTRY_BUS_WIDTH=16
DCD 0x0f10ee11
DCD 0x0080e380
DCD 0x0f10ee01
]
[ ENTRY_BUS_WIDTH=8
DCD 0x100f11ee
DCD 0x800080e3
DCD 0x100f01ee
]
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
;Function for entering power down mode,下面這段程序為進入掉電模式及從掉電模式中喚醒的相關設置和處理
; 1. SDRAM should be in self-refresh mode. SDRAm應該設置為自刷新的模式
; 2. All interrupt should be maksked for SDRAM/DRAM self-refresh. 所有中斷必須屏蔽 for SDRAM/DRAM self-ref
; 3. LCD controller should be disabled for SDRAM/DRAM self-refresh. LCD 控制器關閉
; 4. The I-cache may have to be turned on.
; 5. The location of the following co
//;void EnterPWDN(int CLKCON); //PWDN:powerdown
EnterPWDN
mov r2,r0;r2=rCLKCON //rCLKCONr [3;2]位為電源模式標置位。若[3]為1,表示轉為了掉電模式
tst r0,#0x8;POWER_OFF mode?//按位與判斷,若[3]為1則跳轉到ENTER_POWER_OFF
bne ENTER_POWER_OFF
ENTER_STOP//進入停止模式相關處理
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//表示不相等則往回跳轉到標號為0的位置,在此為上一句。
ldr r0,=CLKCON;enter STOP mode.
str r2,[r0]
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 POWER_OFF mode, on
//進入掉電 模式后,僅喚醒中斷有效
ldr r0,=REFRESH;exit from SDRAM self refresh mode.
str r3,[r0]
MOV_PC_LR//開始處定義的返回跳轉宏
ENTER_POWER_OFF
;NOTE.注意在rGSTATUS3寄存器中應該保存掉電模式喚醒的返回地址,rGSTATUS3,4可在掉電下保存信息
;1) rGSTATUS3 should have the return address after wake-up from POWER_OFF mode.
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
ldr r1,=MISCCR
ldrr0,[r1]
orrr0,r0,#(7<<17) ;Make sure that SCLK0:SCLK->0, SCLK1:SCLK->0, SCKE=L during boot-up
strr0,[r1]
ldr r0,=CLKCON
str r2,[r0]
b .;CPU will die here.
;=================================================================================
從掉電模式喚醒的過程
1、某個喚醒源生效將產(chǎn)生一個內部復位信號。復位時間由一個內部16位計數(shù)器決定,此計數(shù)器的時鐘是tRST=(65535/XTAL_frequency)。
2、查詢GSTATUS[2]位看從掉電模式喚醒是否產(chǎn)生了一個POWER-UP。
3、通過將MISCCR[19:17]設置為000b,釋放SDRAM信號保護。
4、配置SDRAM控制器。
5、等待SDRAM自我刷新完畢。大部分SDRAM需要refresh cycle of all SDRAM row。
6、GSTATUS3,4的信息可以被用戶使用,因為GSTATUS3,4的值已經(jīng)在掉電模式下被保存了。
7、對于EINT[3:0],檢查SRCPND寄存器;對于EINT[15:4],檢查EINTPND寄存器;對于RTC報警喚醒,檢查RTC時間,因為在喚醒時SRCPND寄存器的RTC位不被置位;如果在掉電模式期間有nBATT-FLT assertion,SRCPND寄存器的相關位被置位。
;==================================================================================
WAKEUP_POWER_OFF
;Release SCLKn after wake-up from the POWER_OFF mode.
ldr r1,=MISCCR//MISCCR寄存器用來設置一些USB等相關的時鐘周期等
ldrr0,[r1]
bicr0,r0,#(7<<17)//SCLK0:0->SCLK, SCLK1:0->SCLK, SCKE:L->H
strr0,[r1]//通過將MISCCR[19:17]設置為000b,釋放SDRAM信號保護。
;Set memory control registers配置內存控制寄存器。
ldrr0,=SMRDATA//在程序的后面LTORGSMRDATA DA
//一個數(shù)據(jù)緩沖池就是用來配置相關的內存控制寄存器的
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
ldr r1,=GSTATUS3 ; GSTATUS3 has the start address just after POWER_OFF wake-up
ldr r0,[r1]
mov pc,r0 //從掉電模式下喚醒后,將保存在GSTATUS3 返回地址傳給PC
如上所說,這里采用HANDLER宏去建立Hander***和Handle***之間的聯(lián)系
LTORG ;聲明文字池,因為我們用了ldr偽指令
HandlerFIQ HANDLER HandleFIQ
HandlerIRQ HANDLER HandleIRQ
HandlerUndef HANDLER HandleUndef
HandlerSWI HANDLER HandleSWI
HandlerDabort HANDLER HandleDabort
HandlerPabort HANDLER HandlePabort
;===================================================================================
;呵呵,來了來了.好戲來了,這一段程序就是用來進行第二次查表的過程了.
;如果說第一次查表是由硬件來完成的,那這一次查表就是由軟件來實現(xiàn)的了.
;為什么要查兩次表??
;沒有辦法,ARM把所有的中斷都歸納成一個IRQ中斷異常和一個FIRQ中斷異常
;第一次查表主要是查出是什么異常,可我們總要知道是這個中斷異常中的什么中斷呀!
;沒辦法了,再查一次表唄!
;===================================================================================
IsrIRQ//第二次中斷查表,因為ARM把所有的中斷都歸為一個IRQ異常,通過此處查表可知道具體中斷
sub sp,sp,#4 ;給PC寄存器保留
stmfd sp!,{r8-r9} ;把r8-r9壓入棧
ldr r9,=INTOFFSET ;把INTOFFSET的地址裝入r9
ldr r9,[r9] ;把INTOFFSET的值裝入r9
ldr r8,=HandleEINT0 ;這就是我們第二個中斷向量表的入口的,先裝入r8
;===================================================================================
;哈哈,這查表方法夠好了吧,r8(入口)+index*4(別望了一條指令是4 bytes的喔),
;這不就是我們要找的那一項了嗎.找到了表項,下一步做什么?肯定先裝入了!
;==================================================================================
add r8,r8,r9,lsl #2
ldr r8,[r8] ;裝入中斷服務程序的入口
str r8,[sp,#8] ;把入口也入棧,準備用舊招
ldmfd sp!,{r8-r9,pc};施招,彈出棧,哈哈,順便把r8彈出到PC,O了,跳轉成功!
評論