新聞中心

        EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > ARM啟動文件2440init.s分析

        ARM啟動文件2440init.s分析

        作者: 時間:2016-11-23 來源:網(wǎng)絡(luò) 收藏
        ;=========================================
        ; 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é),復(fù)制到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ù)處理
        GET option.inc ;定義芯片相關(guān)配置
        GET memcfg.inc ;定義存儲器配置
        GET 2440addr.inc ;定義寄存器符號
        ;REFRESH寄存器[22]bit :SDRAM刷新模式 0 - auto refresh
        ; 1 - self refresh
        ;用于節(jié)電模式中,SDRAM自動刷新
        BIT_SELFREFRESH EQU (1<<22)
        ;Pre-defined constants
        ;模式預(yù)定義常量,給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 大小不定,跟堆大小相對應(yīng)
        ;畢竟是用戶態(tài)棧
        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)換成相應(yīng)的指令模式。為此,定義變量THUMBCODE作為指示,跳轉(zhuǎn)到main之前根據(jù)其值切換指令
        ;模式
        ;Check if tasm.exe(armasm -16 ...@ADS 1.0)is used.
        ;檢測工作模式,根據(jù)CONFIG的數(shù)值,確定工作模式
        ;{CONFIG}應(yīng)該來自于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
        GBLL THUMBCODE
        [{CONFIG} = 16
        THUMBCODE SETL {TRUE} ;如果設(shè)置了config,則允許thumb指令,
        ;但THUMBCODE為真并不表明以下就是thumb指令,只是允許
        CODE32 ;code32表示以下是arm指令,在處理器剛開始時,必須以arm模式運行
        | ;此處容易產(chǎn)生錯覺,丟掉CODE32這一行
        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復(fù)位,即把
        ;目標地址的代碼解釋為ARM代碼
        ;定義兩個宏,宏的作用:子函數(shù)返回(無條件,有條件)。
        MACRO
        MOV_PC_LR
        [ THUMBCODE ;如果允許thumb指令,則需要根據(jù)最低位設(shè)置狀態(tài)。
        bx lr ;跳轉(zhuǎn),附帶狀態(tài)切換
        |
        mov pc,lr
        ]
        MEND
        MACRO
        MOVEQ_PC_LR ;相等則跳轉(zhuǎn),相等與否由寄存器某些位確定,在此處,有其上一句的指令執(zhí)行結(jié)果決定
        [ THUMBCODE
        bxeq lr
        |
        moveq pc,lr
        ]
        MEND
        ;MACRO和MEND偽指令用于宏定義,MACRO標識開始,MEND標識結(jié)束。用MACRO和MEND定義的一段代碼,稱為宏定義
        ;體,這樣在程序中就可以通過宏指令多次調(diào)用該代碼段。
        ;偽指令格式:
        ;MACRO
        ;{$label} macroname {$parameter} {$parameter} ...
        ;宏定義體
        ;MEND
        ;其中 $label 宏指令被展開時,label可被替換成相應(yīng)的符號,通常為一個標號,
        ;在一個標號前使用$表示被匯編時將使用相應(yīng)的值替代$后的符號。
        ;macroname 所定義的宏的名稱
        ;$parameter 宏指令的參數(shù),當宏指令被展開時將被替換成相應(yīng)的值,類似于函數(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ù),減小相應(yīng)個數(shù)值的數(shù)據(jù)單位(一步到
        ;位),然后利用for循環(huán)語句,從當前sp位置,依次存儲R0-R7,LR.即:sp處最后指向的是R0數(shù)據(jù)處
        ;LDMFD sp!,{R0-R7,LR}:復(fù)制一個變量為sp值,用該變量依次將數(shù)據(jù)存入R0-R7,LR,變量值增加,最后,變量指
        ;向下一個將要取的值,完成后sp獲得該變量值;
        ;重點分析下面這個宏,它對中斷處理函數(shù)的調(diào)用很重要
        ;確切說,這是宏函數(shù),編譯時對調(diào)用語句要做相應(yīng)的展開
        MACRO
        $HandlerLabel HANDLER $HandleLabel
        $HandlerLabel ;標號
        sub sp,sp,#4 ;留出一個空間,為了存放跳轉(zhuǎn)地址給pc。
        stmfd sp!,{r0} ;把r0中的內(nèi)容入棧,保存起來
        ldr r0,=$HandleLabel ;這是一個偽指令,不是匯編指令,
        ;目的:把$HandleLabel本身所在的地址給r0
        ldr r0,[r0] ;把$HandleLabel所指向的內(nèi)容(也就是中斷程序的入口地址)放入r0
        str r0,[sp,#4] ;把入口地址放入剛才留出的一個空間里
        ldmfd sp!,{r0,pc} ;出棧的方式恢復(fù)r0原值和為pc設(shè)定新值(也就完成了到ISR的轉(zhuǎn)跳)。
        ;注:棧中r0內(nèi)容在低地址
        MEND
        ;-------------------------------------------------------------------------------------------------
        ;下面幾個變量是ads環(huán)境下自動設(shè)置的,可以見環(huán)境配置選項里:ARM Linker->Output下,RO Base,RW Base
        ;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 ;想知道代碼具體內(nèi)容見cp15手冊,并以cp15指令內(nèi)容搜索2440a手冊
        IMPORT Main ;The main entry of mon program
        IMPORT RdNF2SDRAM ;Copy Image from Nand Flash to SDRAM
        ;-------------------------------------------------------------------------------------------------
        ;AREA偽指令用于定義一個代碼段或數(shù)據(jù)段,一個ARM源程序至少需要一個代碼段,大的程序可以包含多個代碼段
        ;及數(shù)據(jù)段
        ;格式:AREA sectionname {,attr} {,attr}...
        AREA Init,CODE,READONLY
        ;-------------------------------------------------------------------------------------------------
        ;ENTRY偽指令用于指定程序的入口點
        ;一個程序(可以包含多個源文件)中至少要有一個ENTRY,可以有多個ENTRY,但一個源文件中最多只有一個
        ;ENTRY.
        ENTRY
        ;-------------------------------------------------------------------------------------------------
        ;EXPORT聲明一個符號可以被其他文件引用,相當于聲明了一個全局變量。GLOBAL與EXPORT相同
        ;格式:EXPORT symbol{[WEAK]} [WEAK]聲明其他的同名符優(yōu)先于本符號被引用
        ;導出符號__ENTRY
        EXPORT __ENTRY
        ;-------------------------------------------------------------------------------------------------
        __ENTRY
        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 thememory bus width.
        ;3)Thepseudo instruction,DCD can not be used here because the linker generates error.
        ;條件編譯,在編譯成機器碼前就設(shè)定好大小端轉(zhuǎn)換
        ;判斷ENDIAN_CHANGE是否已定義,ASSERT 是斷言偽指令,語法是:ASSERT + 邏輯表達式,def 是邏輯偽操作符,
        ;格式為::DEF:label,作用是:判斷l(xiāng)abel是否定義過
        ASSERT :DEF:ENDIAN_CHANGE
        [ ENDIAN_CHANGE ;在 option.inc 有定義。默認是FALSE,所以此句不會加入代碼中
        ASSERT :DEF:ENTRY_BUS_WIDTH ;斷言指令,檢測是否定義該變量,若未定義,報錯
        [ ENTRY_BUS_WIDTH=32 ;defined in option.inc
        b ChangeBigEndian ;DCD 0xea000007
        ;如果是大端,則這是第一條指令,先設(shè)置成大端,
        ;再到復(fù)位指令
        ]
        [ 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 ;本硬件用的是小端模式,這是第一個執(zhí)行語句,
        ;直接跳轉(zhuǎn)到復(fù)位指令處 0X00
        ]
        ;-------------------------------------------------------------------------------------------------
        ;這7個中斷,每個中斷都有固定的中斷入口地址,它們位于代碼的最前端,不允許另作他用
        b HandlerUndef ;handler for Undefined mode 0X04
        b HandlerSWI ;handlerfor SWI interrupt 0X08
        b HandlerPabort ;handler for PAbort,指令預(yù)取中止 0X0C
        b HandlerDabort ;handler for DAbort,數(shù)據(jù)中止 0X10
        b . ;reserved 保留未用 注意小圓點 0X14
        b HandlerIRQ ;handlerfor IRQ interrupt 0X18
        b HandlerFIQ ;handlerfor FIQ interrupt 0X1C
        ;-------------------------------------------------------------------------------------------------
        ;@0x20
        b EnterPWDN ;Must be @0x20
        ;------------------------------------------------------------------------------------------------
        ;下面是改變大小端的程序,采用直接定義 <機器碼> 的方式,為什么這么做就得問三星了
        ;反正我們程序里這段代碼也不會去執(zhí)行,不用去管它
        ;每一個匯編指令,都對應(yīng)著一個二進制機器碼,這里沒有使用指令,直接用了機器碼,含義未知
        ChangeBigEndian
        ;@0x24
        ;對存儲器控制寄存器操作,指定內(nèi)存模式為Big-endian
        ;因為剛開始CPU都是按照32位總線的指令格式運行的,如果采用其他的話,CPU運行不了,必須轉(zhuǎn)化
        ;但當系統(tǒng)初始化好以后,則CPU能自動識別
        [ 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模式,采用16位總線時,物理地址的高位和數(shù)據(jù)的地位對應(yīng)
        ;所以指令的機器碼也相應(yīng)的高低對調(diào)
        [ 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 similarwith NOP and run well in both endian mode.
        DCD 0xffffffff
        DCD 0xffffffff
        DCD 0xffffffff
        DCD 0xffffffff
        b ResetHandler ;設(shè)置成大端后,再次跳到復(fù)位指令處
        ;-------------------------------------------------------------------------------------------------
        ;本文件底部定義了一個數(shù)據(jù)區(qū)(在文件最后),34個字空間,存放相應(yīng)中斷服務(wù)程序的首地址。每個字空間都
        ;有一個標號,以Handle***命名。
        ;這是宏實例,在這里Handler***就是通過HANDLER這個宏和Handle***建立聯(lián)系的.
        ;詳細分析:
        ;Handle*** 這是宏示例,也就是宏的調(diào)用指令,當編譯時編譯器會把宏調(diào)用指令展開
        ;Handler*** 這是向量中斷
        ;展開方式(舉例):
        ;HandlerFIQ HANDLER HandleFIQ
        ;展開后變成:
        ;標號HandlerFIQ,由 " b HandlerFIQ "指令使用(見上,復(fù)位處)
        ; 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}
        ;出棧的方式恢復(fù)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è)肟冢ㄐ枰约号袛嘀袛囝愋停皇侵苯犹D(zhuǎn)到相應(yīng)程序)
        ;產(chǎn)生中斷后,需要中斷服務(wù)程序自己來判斷,到底是哪個中斷請求,根據(jù)的就是INTOFFSET寄存器中的偏移,再
        ;計算中斷服務(wù)地址
        IsrIRQ
        sub sp,sp,#4 ;reserved for PC,預(yù)留返回指針的存儲位置
        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中只是偏移單位的個數(shù),需要*4變成具體字節(jié)偏移(相對于EINT0)
        ldr r8,[r8]
        str r8,[sp,#8] ;pc值放在了高位置
        ldmfd sp!,{r8-r9,pc}
        ;-------------------------------------------------------------------------------------------------
        ;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)系
        LTORG
        ;-------------------------------------------------------------------------------------------------
        ;=======
        ; ENTRY
        ;=======
        ResetHandler
        ;關(guān)看門狗
        ldr r0,=WTCON ;watch dog disable 編譯時就是 ldr r0,=53000000;偽指令有=號
        ldr r1,=0x0 ;這些宏定義都位于2440addr.inc中。 區(qū)分:變量定義 && 宏定義
        str r1,[r0]
        ;-------------------------------------------------------------------------------------------------
        ;屏蔽所有中斷
        ldr r0,=INTMSK ;在 INTMSK 寄存器設(shè)置屏蔽所有中斷
        ldr r1,=0xffffffff ;all interrupt disable 要理解子中斷和中斷之間的關(guān)系
        str r1,[r0]
        ldr r0,=INTSUBMSK ;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,=0x00555555
        str r1,[r0]
        ldr r0,=GPBDAT
        ldr r1,=0x07fe
        str r1,[r0]
        ]
        ;-------------------------------------------------------------------------------------------------
        ;初始化PLL和時鐘
        ;鎖相環(huán) PLL ,作用是將外部晶振的輸入頻率倍頻到一個較高的頻率
        ;To reduce PLL lock time, adjust the LOCKTIME register.
        ldr r0,=LOCKTIME ;LOCKTIME鎖定時間計數(shù)寄存器
        ldr r1,=0xffffff
        str r1,[r0]
        [ PLL_ON_START ;defined inoption.inc {TRUE},選擇要不要設(shè)置頻率值
        ;Added for confirm clock divide. for 2440.
        ;Setting value Fclk:Hclk:Pclk
        ldr r0,=CLKDIVN ;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 ; means Fclk:Hclk is not 1:1.
        ;Fclk為cpu的運行時鐘,Hclk驅(qū)動 AHB總線設(shè)備(例如:SDRAM)
        mrc p15,0,r0,c1,c0,0
        orr r0,r0,#0xc0000000 ;R1_nF:OR:R1_iA
        mcr p15,0,r0,c1,c0,0
        |
        mrc p15,0,r0,c1,c0,0
        bic r0,r0,#0xc0000000 ;R1_iA:OR:R1_nF
        mcr p15,0,r0,c1,c0,0
        ]
        ;在配置UPLLCON和MPLLCON寄存器時,必須先配置UPLLCON,然后再配置MPLLCON,而且兩者之間要有7 nop的間
        ;隔。(這是2440文檔明確要求的)
        ;Configure UPLL
        ldr r0,=UPLLCON ;UPLLCON: UPLL configuration register
        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
        ;Configure MPLL
        ldr r0,=MPLLCON ;MPLLCON: MPLL configuration register
        ldr r1,=((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV) ;Fin = 12.0MHz, FCLK= 400MHz
        str r1,[r0]
        ]
        ;-------------------------------------------------------------------------------------------------
        ;Check if the boot is caused by the wake-up from SLEEP mode.
        ldr r1,=GSTATUS2 ;這個寄存器數(shù)值表示哪個信號引起的復(fù)位動作產(chǎn)生
        ;檢測 GSTATUS2[2]來判斷是否是由 sleep 模式喚醒引起的電源開啟。
        ldr r0,[r1]
        tst r0,#0x2
        ;Incase of the wake-up from SLEEP mode, go to SLEEP_WAKEUP handler.
        bne WAKEUP_SLEEP
        ;-------------------------------------------------------------------------------------------------
        ;設(shè)置總線寬度&等待狀態(tài)控制寄存器
        EXPORT StartPointAfterSleepWakeUp
        StartPointAfterSleepWakeUp
        ;Set memory control registers
        ;ldr r0,=SMRDATA ;(等效于下邊的指令)
        adrl r0,SMRDATA ;be careful!中等范圍的地址讀取偽指令,
        ;用法類似于ldr(大范圍地址讀?。﹤沃噶?/div>
        ldr r1,=BWSCON ;BWSCON Address 總線寬度&等待狀態(tài)控制寄存器
        add r2, r0, #52 ;End address of SMRDATA,共有13個寄存器地址(4字節(jié))需要賦值,13*4=52字節(jié)
        0
        ldr r3, [r0], #4 ;這些都是后變址指令
        str r3, [r1], #4
        cmp r2, r0
        bne % B0 ;當<的時候,跳轉(zhuǎn)到0標號處繼續(xù)執(zhí)行
        ;------------------------------------------------------------------------------------------------
        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        ;;;;;;;;;;;;; When EINT0 is pressed, Clear SDRAM
        ;如果 EINT0 產(chǎn)生(這中斷就是我們按鍵產(chǎn)生的), 就清除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??? ;當按鍵0沒有被按下的時候,也就是不相等,則向下跳到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=****
        mov r1,#0
        mov r2,#0
        mov r3,#0
        mov r4,#0
        mov r5,#0
        mov r6,#0
        mov r7,#0
        mov r8,#0
        ldr r9,=0x4000000 ;64MB ,這幾條指令目的是:擦除sdram的所有數(shù)據(jù)
        ldr r0,=0x30000000
        0
        stmia r0!,{r1-r8}
        subs r9,r9,#32
        bne ?% B0?
        ;Clear SDRAM End
        1
        ;Initializestacks
        bl InitStacks
        ;------------------------------------------------------------------------------------------------
        ;===========================================================
        ;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寄存器的值
        ldr r0, =BWSCON ;BWSCON總線寬度&等待控制寄存器
        ldr r0, [r0]
        ands r0, r0, #6 ;OM[1:0]!= 0, NOR FLash boot
        bne copy_proc_beg ;do not read nand flash
        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
        ;===========================================================
        ;把nand中的數(shù)據(jù),拷貝到ram中
        nand_boot_beg
        [ {TRUE}
        bl RdNF2SDRAM
        ]
        ldr pc, =copy_proc_beg
        ;===========================================================
        ;這里的一段代碼時對內(nèi)存數(shù)據(jù)的初始化,涉及代碼段,數(shù)據(jù)段,bss段等
        ;因?qū)@里的變量設(shè)置等有異議,暫時未全面分析,但是基本原理想通,就是一個比較地址,復(fù)制數(shù)據(jù)的過程
        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
        ; 把中斷服務(wù)函數(shù)的總?cè)肟诘刂?,賦給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
        ; 初始化棧空間(各個模式下的),為c函數(shù)運行做準備
        InitStacks
        ;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)
        DCD 0x32 ;SCLK power saving mode, BANKSIZE 128M/128M
        DCD 0x30 ;MRSR6 CL=3clk
        DCD 0x30 ;MRSR7 CL=3clk
        ;分配一個字的空間,并用后邊的數(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|
        ALIGN ;按照4的倍數(shù)對齊
        ;------------------------------------------------------------------------------------------------
        ;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
        mov r2,r0 ;r2=rCLKCON
        tst r0,#0x8 ;SLEEP mode?
        bne ENTER_SLEEP
        ENTER_STOP
        ldr r0,=REFRESH ;REFRESH 是刷新控制寄存器
        ldr r3,[r0] ;r3=rREFRESH
        mov r1, r3
        orr r1, r1, #BIT_SELFREFRESH
        str r1, [r0] ;Enable SDRAMself-refresh
        mov r1,#16 ;wait untilself-refresh is issued. may not be needed.
        0 subs r1,r1,#1
        bne?% B0?
        ldr r0,=CLKCON ;enter STOP mode.
        str r2,[r0]
        mov r1,#32
        0 subs r1,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.
        ldr r0,=REFRESH ;exit from SDRAM self refresh mode.
        str r3,[r0]
        MOV_PC_LR
        ENTER_SLEEP
        ;NOTE.
        ;1)rGSTATUS3 should have the return address after wake-up from SLEEP mode.
        ldr r0,=REFRESH
        ldr r1,[r0] ;r1=rREFRESH
        orr r1, r1, #BIT_SELFREFRESH
        str r1, [r0] ;Enable SDRAMself-refresh
        mov r1,#16 ;Wait untilself-refresh is issued,which may not be needed.
        0 subs r1,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]
        ldr r0,=CLKCON ; Enter sleep mode
        str r2,[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??
        mov r1,#256
        0 subs r1,r1,#1 ;1) wait until the SelfRefreshis released.
        bne? % B0?
        ldr r1,=GSTATUS3 ;GSTATUS3 has the startaddress just after SLEEP wake-up
        ldr r0,[r1]
        mov pc,r0
        ;=====================================================================
        ; Clock division test
        ; Assemble code, because VSYNC time is veryshort
        ;=====================================================================
        EXPORT CLKDIV124
        EXPORT CLKDIV144
        CLKDIV124
        ldr r0, = CLKDIVN ;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
        ;------------------------------------------------------------------------------------------------
        ;定義數(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ù)量
        ;用法:把對應(yīng)的終端處理函數(shù)的首地址,放到這里的對應(yīng)的預(yù)留空間處,當發(fā)生中斷時,就能根據(jù)宏函數(shù),直
        ;接跳轉(zhuǎn)
        AREA RamData, 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


        關(guān)鍵詞: ARM啟動文件2440ini

        評論


        技術(shù)專區(qū)

        關(guān)閉
        主站蜘蛛池模板: 宜宾县| 石景山区| 旺苍县| 绥中县| 绥滨县| 定西市| 临安市| 章丘市| 灵武市| 河曲县| 达拉特旗| 义乌市| 金湖县| 登封市| 凌云县| 寿光市| 屏南县| 唐山市| 潞西市| 永新县| 无棣县| 松桃| 叙永县| 大庆市| 犍为县| 阳曲县| 新化县| 保定市| 苍山县| 泽库县| 调兵山市| 东方市| 榆中县| 巴林左旗| 衡阳县| 防城港市| 武安市| 吉木萨尔县| 延津县| 龙川县| 梅州市|