新聞中心

        EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > 關于啟動代碼2440init.s(一)

        關于啟動代碼2440init.s(一)

        作者: 時間:2016-11-21 來源:網(wǎng)絡 收藏
        停滯了這么長的時間沒有寫博客,這次獻上啟動代碼吧,也就是我們通常所說的bootloader了。這里獻上別人整理出來的東西,光看啟動代碼我都花了挺長的時間,關鍵是為了通過啟動代碼知道開機時板子是怎么運作的,對硬件理解非常有用。順便說一下,啟動代碼每個程序都有,文件叫做2440init.s,匯編的哈,看之前好好去看看匯編的內(nèi)容去吧。哇咔咔~廢話少說,獻上程序,程序從ENTRY開始執(zhí)行,看到前面眼花繚亂那些其實是宏來的,一開始從ResetEntry執(zhí)行。慢慢分析去吧,作者XXX講的挺詳細的了。

        ; NAME: 2440INIT.S
        ; DESC: C start up codes
        ;Configure memory, ISR ,stacks
        ;Initialize C-variables
        ;完全注釋;=========================================
        ; NAME: 2440INIT.S
        ; DESC: C start up codes
        ;Configure memory, ISR ,stacks
        ;Initialize C-variables
        ;完全注釋=============================================
        ; HISTORY:
        ; 2002.02.25:kwtark: ver 0.0
        ; 2002.03.20:purnnamu: Add some functions for testing STOP,Sleep mode
        ; 2003.03.14:DonGo: Modified for 2440.
        ; 2009 06.24:Tinko Modified
        ;=========================================


        ;匯編不能使用include包含頭文件,所有用Get
        ;匯編也不認識*.h 文件,所有只能用*.inc
        GET option.inc ;定義芯片相關的配置
        GET memcfg.inc ;定義存儲器配置
        GET 2440addr.inc ;定義了寄存器符號


        ;REFRESH寄存器[22]bit : 0- auto refresh; 1 - self refresh
        BIT_SELFREFRESH EQU (1<<22) ;用于節(jié)電模式中,SDRAM自動刷新


        ;處理器模式常量: CPSR寄存器的后5位決定目前處理器模式 M[4:0]
        USERMODE EQU 0x10
        FIQMODE EQU 0x11
        IRQMODE EQU 0x12
        SVCMODE EQU 0x13
        ABORTMODE EQU 0x17
        UNDEFMODE EQU 0x1b
        MODEMASK EQU 0x1f ;M[4:0]
        NOINT EQU 0xc0


        ;定義處理器各模式下堆棧地址常量
        UserStack EQU (_STACK_BASEADDRESS-0x3800) ;0x33ff4800 ~ _STACK_BASEADDRESS定義在option.inc中
        SVCStack EQU (_STACK_BASEADDRESS-0x2800) ;0x33ff5800 ~
        UndefStack EQU (_STACK_BASEADDRESS-0x2400) ;0x33ff5c00 ~
        AbortStack EQU (_STACK_BASEADDRESS-0x2000) ;0x33ff6000 ~
        IRQStack EQU (_STACK_BASEADDRESS-0x1000) ;0x33ff7000 ~
        FIQStack EQU (_STACK_BASEADDRESS-0x0) ;0x33ff8000 ~


        ;arm處理器有兩種工作狀態(tài) 1.arm:32位 這種工作狀態(tài)下執(zhí)行字對準的arm指令 2.Thumb:16位 這種工作狀
        ;態(tài)執(zhí)行半字對準的Thumb指令
        ;因為處理器分為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)換成相應的指令模式。為此,定義變量THUMBCODE作為指示,跳轉(zhuǎn)到main之前
        ;根據(jù)其值切換指令模式
        ;
        ;這段是為了統(tǒng)一目前的處理器工作狀態(tài)和軟件編譯方式(16位編譯環(huán)境使用tasm.exe編譯
        ;Check if tasm.exe(armasm -16 ...@ADS 1.0) is used.
        GBLL THUMBCODE ;定義THUMBCODE全局變量注意EQU所定義的宏與變量的區(qū)別

        [ {CONFIG} = 16 ;如果發(fā)現(xiàn)是在用16位代碼的話(編譯選項中指定使用thumb指令)

        THUMBCODE SETL {TRUE} ;一方面把THUMBCODE設置為TURE

        CODE32 ;另一方面暫且把處理器設置成為ARM模式,以方便初始化

        | ;(|表示else)如果編譯選項本來就指定為ARM模式
        THUMBCODE SETL {FALSE} ;把THUMBCODE設置為FALSE就行了

        ] ;結束


        MACRO ;一個根據(jù)THUMBCODE把PC寄存的值保存到LR的宏
        MOV_PC_LR ;宏名稱
        [ THUMBCODE ;如果定義了THUMBCODE,則
        bx lr ;在ARM模式中要使用BX指令轉(zhuǎn)跳到THUMB指令,并轉(zhuǎn)換模式. bx指令會根據(jù)PC最后1位來確定是否進入thumb狀態(tài)
        | ;否則,
        mov pc,lr ;如果目標地址也是ARM指令的話就采用這種方式
        ]
        MEND ;宏定義結束標志

        MACRO ;和上面的宏一樣,只是多了一個相等的條件
        MOVEQ_PC_LR
        [ THUMBCODE
        bxeq lr
        |
        moveq pc,lr
        ]
        MEND


        ;=======================================================================================
        ;下面這個宏是用于第一次查表過程的實現(xiàn)中斷向量的重定向,如果你比較細心的話就是發(fā)現(xiàn)
        ;在_ISR_STARTADDRESS=0x33FF_FF00里定義的第一級中斷向量表是采用型如Handle***的方式的.
        ;而在程序的ENTRY處(程序開始處)采用的是b Handler***的方式.
        ;在這里Handler***就是通過HANDLER這個宏和Handle***建立聯(lián)系的.
        ;這種方式的優(yōu)點就是正真定義的向量數(shù)據(jù)在內(nèi)存空間里,而不是在ENTRY處的ROM(FLASH)空間里,
        ;這樣,我們就可以在程序里靈活的改動向量的數(shù)據(jù)了.
        ;========================================================================================
        ;;這段程序用于把中斷服務程序的首地址裝載到pc中,有人稱之為“加載程序”。
        ;本初始化程序定義了一個數(shù)據(jù)區(qū)(在文件最后),34個字空間,存放相應中斷服務程序的首地址。每個字
        ;空間都有一個標號,以Handle***命名。
        ;在向量中斷模式下使用“加載程序”來執(zhí)行中斷服務程序。
        ;這里就必須講一下向量中斷模式和非向量中斷模式的概念
        ;向量中斷模式是當cpu讀取位于0x18處的IRQ中斷指令的時候,系統(tǒng)自動讀取對應于該中斷源確定地址上的;
        ;指令取代0x18處的指令,通過跳轉(zhuǎn)指令系統(tǒng)就直接跳轉(zhuǎn)到對應地址
        ;函數(shù)中 節(jié)省了中斷處理時間提高了中斷處理速度標 例如 ADC中斷的向量地址為0xC0,則在0xC0處放如下
        ;代碼:ldr PC,=HandlerADC 當ADC中斷產(chǎn)生的時候系統(tǒng)會
        ;自動跳轉(zhuǎn)到HandlerADC函數(shù)中
        ;非向量中斷模式處理方式是一種傳統(tǒng)的中斷處理方法,當系統(tǒng)產(chǎn)生中斷的時候,系統(tǒng)將interrupt
        ;pending寄存器中對應標志位置位 然后跳轉(zhuǎn)到位于0x18處的統(tǒng)一中斷
        ;函數(shù)中 該函數(shù)通過讀取interrupt pending寄存器中對應標志位 來判斷中斷源 并根據(jù)優(yōu)先級關系再跳到
        ;對應中斷源的處理代碼中
        ;
        ;H|------| H|------| H|------| H|------| H|------|
        ; |/ / / | |/ / / | |/ / / | |/ / / | |/ / / |
        ; |------|<----sp |------| |------| |------| |------|<------sp
        ;L| | |------|<----sp L|------| |-isr--| |------| isr==>pc
        ; | | | | |--r0--|<----sp |---r0-|<----sp L|------| r0==>r0
        ; (0) (1) (2) (3) (4)

        MACRO
        $HandlerLabel HANDLER $HandleLabel(入口地址)

        $HandlerLabel ;標號
        sub sp,sp,#4 ;(1)減少sp(用于存放轉(zhuǎn)跳地址)
        stmfd sp!,{r0} ;(2)把工作寄存器壓入棧(lr does not push because it return to original address)
        ldr r0,=$HandleLabel;將HandleXXX的址址放入r0
        ldr r0,[r0] ;把HandleXXX所指向的內(nèi)容(也就是中斷程序的入口)放入r0
        str r0,[sp,#4] ;(3)把中斷服務程序(ISR)壓入棧
        ldmfd sp!,{r0,pc} ;(4)用出棧的方式恢復r0的原值和為pc設定新值(也就完成了到ISR的轉(zhuǎn)跳)
        MEND


        ;=========================================================================================
        ;在這里用IMPORT偽指令(和c語言的extren一樣)引入|Image$$RO$$Base|,|Image$$RO$$Limit|...
        ;這些變量是通過ADS的工程設置里面設定的RO Base和RW Base設定的,
        ;最終由編譯腳本和連接程序?qū)氤绦?
        ;那為什么要引入這玩意呢,最簡單的用處是可以根據(jù)它們拷貝自已
        ;==========================================================================================
        ;Image$$RO$$Base等比較古怪的變量是編譯器生成的。RO, RW, ZI這三個段都保存在Flash中,但RW,ZI在Flash中
        ;的地址肯定不是程序運行時變量所存儲的位置,因此我們的程序在初始化時應該把Flash中的RW,ZI拷貝到RAM的對應位置。
        ;一般情況下,我們可以利用編譯器替我們實現(xiàn)這個操作。比如我們跳轉(zhuǎn)到main()時,使用 b __Main,編譯器就會在__Main
        ;和Main之間插入一段匯編代碼,來替我們完成RW,ZI段的初始化。 如果我們使用b Main, 那么初始化工作要我們自己做。
        ;編譯器會生成如下變量告訴我們RO,RW,ZI三個段應該位于什么位置,但是它并沒有告訴我們RW,ZI在Flash中存儲在什么位置,
        ;實際上RW,ZI在Flash中的位置就緊接著RO存儲。我們知道了Image$$RO$$Base,Image$$RO$$Limit,那么Image$$RO$$Limit就
        ;是RW(ROM data)的開始。

        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
        IMPORT |Image$$ZI$$Limit| ; to zero initialise

        ;這里引入一些在其它文件中實現(xiàn)在函數(shù),包括為我們所熟知的main函數(shù)

        本文引用地址:http://www.104case.com/article/201611/319092.htm;( 引入外部變量MMU 的快速總線模式和異步總線模式兩個變量)
        ;IMPORT MMU_SetAsyncBusMode
        ;IMPORT MMU_SetFastBusMode ;hzh

        IMPORT Main
        (上面都是宏,下篇文章程序真正開始)



        關鍵詞: 啟動代碼244

        評論


        技術專區(qū)

        關閉
        主站蜘蛛池模板: 芮城县| 永仁县| 伊宁县| 平谷区| 库尔勒市| 措美县| 墨竹工卡县| 南安市| 云林县| 成安县| 贺州市| 惠东县| 颍上县| 扶绥县| 开阳县| 博客| 盐津县| 绥宁县| 辉南县| 海门市| 宁安市| 呼和浩特市| 天祝| 化州市| 葫芦岛市| 泾川县| 肥西县| 基隆市| 漳州市| 合川市| 无锡市| 温宿县| 庐江县| 浦北县| 昆山市| 双鸭山市| 陇川县| 峨边| 新源县| 侯马市| 宁晋县|