新聞中心

        EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > s3c2440啟動(dòng)文件詳細(xì)分析

        s3c2440啟動(dòng)文件詳細(xì)分析

        作者: 時(shí)間:2016-11-19 來(lái)源:網(wǎng)絡(luò) 收藏
        啟動(dòng)文件就是引導(dǎo)ARM啟動(dòng),并進(jìn)入我們熟悉的C語(yǔ)言程序。它主要完成了ARM最基本的硬件初始化工作。雖然啟動(dòng)文件的內(nèi)容大同小異(就是設(shè)置系統(tǒng)時(shí)鐘、內(nèi)存、中斷向量表、棧等內(nèi)容),而且只要有一個(gè)現(xiàn)成的啟動(dòng)文件,即使不用詳細(xì)了解該文件的內(nèi)容,直接進(jìn)入C語(yǔ)言編程工作也可以對(duì)ARM進(jìn)行操作,但我認(rèn)為熟悉啟動(dòng)文件的內(nèi)容,還是有必要的,它對(duì)我們熟悉ARM的體系結(jié)構(gòu),編寫出更高效的程序是大有益處的。因此我花了一些時(shí)間詳細(xì)分析了s3c2440啟動(dòng)文件的內(nèi)容,讓它作為我進(jìn)入ARM領(lǐng)域研究的開(kāi)端,希望能有一個(gè)好的起點(diǎn),為以后的研究打下基礎(chǔ)。
        下面就是我對(duì)件的分析,標(biāo)注了較詳細(xì)的注解,不僅有我對(duì)啟動(dòng)文件的理解,同時(shí)也查閱其他網(wǎng)友的相關(guān)文章。理解不對(duì)的地方還望大家指正!

        ;=========================================
        ; NAME: 2440INIT.S
        ; DESC: C start up codes
        ;Configure memory, ISR ,stacks
        ;Initialize C-variables
        ;=========================================

        ;GET類似于C語(yǔ)言的include,option.inc文件內(nèi)定義了一些全局變量,memcfg.inc文件內(nèi)定義了關(guān)于內(nèi)存bank的符號(hào)和數(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位定義了處理器的七種工作模式,為以后切換模式時(shí)使用
        ;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位
        ;編譯器有相對(duì)應(yīng)的用16位和32位兩種編譯方式
        ;這段的目的是統(tǒng)一目前的處理器工作狀態(tài)和軟件編譯方式
        ;Check if tasm.exe(armasm -16 ...@ADS 1.0) is used.
        GBLLTHUMBCODE;聲明一個(gè)全局邏輯變量
        [ {CONFIG} = 16;if CONFIG == 16
        THUMBCODE SETL{TRUE};THUMBCODE = TRUE
        CODE32;指示編譯器為ARM指令
        |;else
        THUMBCODE SETL{FALSE};THUMBCODE = FALSE
        ]

        ;宏定義,在后面出現(xiàn)MOV_PC_LR時(shí),這個(gè)宏會(huì)被自動(dòng)展開(kāi)
        ;該宏的作用是跳出子程序,返回被調(diào)用處
        MACRO
        MOV_PC_LR
        [ THUMBCODE;if THUMBCODE == TRUE
        bx lr
        |;else即THUMBCODE == FALSE
        movpc,lr
        ]
        MEND
        ;該宏定義的作用是有條件地(當(dāng)Z=1時(shí))跳出子程序,返回被調(diào)用處
        MACRO
        MOVEQ_PC_LR
        [ THUMBCODE
        bxeq lr
        |
        moveq pc,lr
        ]
        MEND

        ;該宏定義是把中斷服務(wù)程序的首地址裝載到pc中
        ;在后面當(dāng)遇到HandlerXXX HANDLER HandleXXX時(shí),該宏被展開(kāi)
        ;注意:HANDLER前的符號(hào)HandlerXXX比其后的符號(hào)HandleXXX多了一個(gè)r
        ;HandlerXXX為ARM體系中統(tǒng)一定義的幾種異常中斷
        ;HandleXXX為每個(gè)ARM處理器各自定義的中斷,見(jiàn)該文件最后部分的中斷向量表
        MACRO
        $HandlerLabel HANDLER $HandleLabel

        $HandlerLabel
        subsp,sp,#4;ATPCS規(guī)定數(shù)據(jù)棧為FD類型
        ;即棧指針指向棧頂元素,數(shù)據(jù)棧向內(nèi)存地址減小的方向增長(zhǎng)
        ;該語(yǔ)句是使棧地址減小4個(gè)字節(jié),以留出空間裝載中斷服務(wù)函數(shù)首地址
        stmfdsp!,{r0};由于要利用r0寄存器來(lái)傳遞數(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)入連接器事先定義好的運(yùn)行域中三個(gè)段變量
        ;ARM的可執(zhí)行映像文件由RO、RW、ZI三個(gè)段組成
        ;RO為代碼段,RW為已初始化的全局變量,ZI為未初始化的全局變量
        IMPORT|Image
        RO
        Base|;RO段起始地址
        IMPORT|Image
        RO
        Limit|;RO段結(jié)束地址加1,等于RW段起始地址
        IMPORT|Image
        RW
        Base|;RW段起始地址
        IMPORT|Image
        ZI
        Base|;ZI段起始地址
        IMPORT|Image
        ZI
        Limit|;ZI段結(jié)束地址加1

        ;導(dǎo)入兩個(gè)關(guān)于MMU的函數(shù),用于設(shè)置時(shí)鐘模式為異步模式和快速總線模式
        IMPORTMMU_SetAsyncBusMode
        IMPORTMMU_SetFastBusMode;

        ;導(dǎo)入Main,它為C語(yǔ)言程序入口函數(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)開(kāi)始的8個(gè)字單元空間內(nèi),存放的是ARM異常中斷向量表,每個(gè)字單元空間都是一條跳轉(zhuǎn)指令,當(dāng)異常發(fā)生時(shí),ARM會(huì)自動(dòng)跳轉(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剑驗(yàn)榫幾g器初始模式是小端模式,如果要用大端模式,就要事先把該變量設(shè)置為TRUE,否則為FLASE
        ;變量ENTRY_BUS_WIDTH用于設(shè)置總線的寬度,因?yàn)橛?6位和8位寬度來(lái)表示32位數(shù)據(jù)時(shí),在大端模式下,數(shù)據(jù)的含義是不同的
        ;由于要考慮到大端和小端模式,以及總線的寬度,因此該處看似較復(fù)雜,其實(shí)只是一條跳轉(zhuǎn)指令:當(dāng)為大端模式時(shí),跳轉(zhuǎn)到ChangeBigEndian函數(shù)處,否則跳轉(zhuǎn)到ResetHandler函數(shù)處
        ASSERT:DEF:ENDIAN_CHANGE;判斷是否定義了ENDIAN_CHANGE
        ;如果沒(méi)有定義,則報(bào)告該處錯(cuò)誤信息
        [ ENDIAN_CHANGE;if ENDIAN_CHANGE ==TRUE
        ASSERT:DEF:ENTRY_BUS_WIDTH;判斷是否定義了ENTRY_BUS_WIDTH
        ;如果沒(méi)有定義,則報(bào)告該處錯(cuò)誤信息

        [ ENTRY_BUS_WIDTH=32;if ENTRY_BUS_WIDTH ==32
        ;跳轉(zhuǎn)到ChangeBigEndian(ChangeBigEndian在0x24),因此該條指令的機(jī)器碼為0xea000007
        ;所以該語(yǔ)句與在該處(即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ù),格式完全一致。但在大端模式下,格式就會(huì)發(fā)生變化
        ;在復(fù)位時(shí),系統(tǒng)默認(rèn)的是小端模式,所以就要人為地改變數(shù)據(jù)格式,使得用16位大端數(shù)據(jù)表示的32位數(shù)據(jù)也能被小端模式的系統(tǒng)識(shí)別
        ;該語(yǔ)句的目的也是跳轉(zhuǎn)到ChangeBigEndian,即機(jī)器碼也應(yīng)該是0xea000007,但為了讓小端模式系統(tǒng)識(shí)別,就要把機(jī)器碼的順序做一下調(diào)整,改為0x0007ea00,那么我們就可以用DCD 0x0007ea00把機(jī)器碼裝載進(jìn)去了,但由于該處不能使用DCD偽指令,因此我們就要用一條真實(shí)的指令來(lái)代替DCD 0x0007ea00,即該指令編譯后的機(jī)器碼也為0x0007ea00,而andeqr14,r7,r0,lsl #20就是一條編譯后機(jī)器碼為0x0007ea00的指令,所以我們?cè)谠撎帉懮显摋l指令
        andeqr14,r7,r0,lsl #20;DCD 0x0007ea00
        ]

        [ ENTRY_BUS_WIDTH=8;if ENTRY_BUS_WIDTH ==8
        ;該語(yǔ)句的分析與上一段代碼的分析相似
        ;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ù)訪問(wèn)中止
        b.;保留,跳轉(zhuǎn)到自身地址處,即進(jìn)入死循環(huán)
        bHandlerIRQ;外部中斷請(qǐng)求
        bHandlerFIQ;快速中斷請(qǐng)求
        ;以上為異常中斷向量表

        ;跳轉(zhuǎn)到EnterPWDN,處理電源管理的其他非正常模式,在C語(yǔ)言程序段中被調(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
        ;由于此時(shí)系統(tǒng)還不能識(shí)別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)就能夠自動(dòng)識(shí)別出不同總線寬度下的大端模式,因此以后就無(wú)需再人為調(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

        ;下面這段代碼是用于處理非向量中斷,即由軟件程序來(lái)判斷到底發(fā)生了哪種中斷,然后跳轉(zhuǎn)到相應(yīng)地中斷服務(wù)程序中
        ;具體地說(shuō)就是,當(dāng)發(fā)生中斷時(shí),會(huì)置INTOFFSET寄存器相應(yīng)的位為1,然后通過(guò)查表(見(jiàn)該程序末端部分的中斷向量表),找到相對(duì)應(yīng)的中斷入口地址
        ;觀察中斷向量表,會(huì)發(fā)現(xiàn)它與INTOFFSET寄存器中的中斷源正好相對(duì)應(yīng),即向量表的順序與INTOFFSET寄存器中的中斷源的由小到大的順序一致,因此我們可以用基址加變址的方式很容易找到相對(duì)應(yīng)的中斷入口地址。其中基址為向量表的首個(gè)中斷源地址,變址為INTOFFSET寄存器的值乘以4(因?yàn)橄到y(tǒng)是用4個(gè)字節(jié)單元來(lái)存放一個(gè)中斷向量)
        IsrIRQ
        subsp,sp,#4;在棧中留出4個(gè)字節(jié)空間,以便保存中斷入口地址
        stmfdsp!,{r8-r9};由于要用到r8和r9,因此保存這兩個(gè)寄存器內(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ù)程序中


        ;定義一個(gè)數(shù)據(jù)緩沖池,供ldr偽指令使用
        LTORG

        ;=======
        ; ENTRY
        ;=======
        ;系統(tǒng)上電或復(fù)位后,由0x0處的跳轉(zhuǎn)指令,跳轉(zhuǎn)到該處開(kāi)始真正執(zhí)行系統(tǒng)的初始化工作
        ResetHandler
        ;在系統(tǒng)初始化過(guò)程中,不需要看門狗,因此關(guān)閉看門狗功能
        ldrr0,=WTCON;watch dog disable
        ldrr1,=0x0
        strr1,[r0]

        ;同樣,此時(shí)也不應(yīng)該響應(yīng)任何中斷,因此屏蔽所有中斷,以及子中斷
        ldrr0,=INTMSK
        ldrr1,=0xffffffff;all interrupt disable
        strr1,[r0]

        ldrr0,=INTSUBMSK
        ldrr1,=0x7fff;all sub interrupt disable
        strr1,[r0]

        ;由于啟動(dòng)文件是無(wú)法仿真的,因此為了判斷該文件中語(yǔ)句的正確與否,往往在需要觀察的地方加上一段點(diǎn)亮LED的程序,這樣就可以知道程序是否已經(jīng)執(zhí)行到此處
        ;下面方括號(hào)內(nèi)的程序就是點(diǎn)亮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í)鐘頻率
        ;設(shè)置PLL的鎖定時(shí)間常數(shù),以得到一定時(shí)間的延時(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)的三個(gè)時(shí)鐘頻率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è)置時(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è)置時(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
        ;按照手冊(cè)中的計(jì)算公式,確定MDIV、PDIV和SDIV
        ;得到當(dāng)系統(tǒng)輸入時(shí)鐘頻率為12MHz的情況下,UCLK輸出頻率為48MHz
        ;Configure UPLL
        ldrr0,=UPLLCON
        ldrr1,=((U_MDIV<<12)+(U_PDIV<<4)+U_SDIV);Fin = 12.0MHz, UCLK = 48MHz
        strr1,[r0]
        ;等待至少7個(gè)時(shí)鐘周期,以保證系統(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處開(kāi)始執(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è)置一個(gè)被喚醒復(fù)位后的起始點(diǎn)地址標(biāo)號(hào),可以把它保存到GSTATUS3中
        ;導(dǎo)出該地址標(biāo)號(hào),以便在C語(yǔ)言程序中使用
        EXPORT StartPointAfterSleepWakeUp
        StartPointAfterSleepWakeUp

        ;設(shè)置內(nèi)存控制寄存器
        ;關(guān)于內(nèi)存控制寄存器一共有以BWSCON為開(kāi)始的連續(xù)放置的13個(gè)寄存器,我們要一次性批量完成這13個(gè)寄存器的配置
        ;因此開(kāi)辟一段以SMRDATA為地址起始點(diǎn)的13個(gè)字單元空間,按順序放入要寫入的13個(gè)寄存器內(nèi)容
        ;Set memory control registers
        ;ldrr0,=SMRDATA
        adrlr0, SMRDATA;得到SMRDATA空間的首地址
        ldrr1,=BWSCON;得到BWSCON的地址
        addr2, r0, #52;得到SMRDATA空間的末地址

        ;完成13個(gè)字?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,上拉功能無(wú)效

        ldrr1,=GPFDAT
        ldrr0,[r1];讀取F口數(shù)據(jù)
        bicr0,r0,#(0x1e<<1);僅保留第1位數(shù)據(jù),其他清0
        tstr0,#0x1;判斷第1位
        bne %F1;不為0表示按鈕沒(méi)有被按下,則向前跳轉(zhuǎn),不執(zhí)行清空SDRAM



        ; Clear SDRAM Start
        ;清空SDRAM
        ldrr0,=GPFCON
        ldrr1,=0x55aa
        strr1,[r0];GPF7~4為輸出,GPF3~0為中斷
        ;ldrr0,=GPFUP
        ;ldrr1,=0xff
        ;strr1,[r0];上拉功能無(wú)效
        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啟動(dòng),不為0則從NOR Flash啟動(dòng)
        bnecopy_proc_beg;跳轉(zhuǎn),不用讀取NAND Flash
        adrr0, ResetEntry;OM[1:0] == 0,從NAND Flash啟動(dòng)
        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
        ;修正非字對(duì)齊的情況
        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è)置時(shí)鐘模式為異步模式
        ;|
        ;bl MMU_SetFastBusMode;設(shè)置時(shí)鐘模式為快速總線模式
        ;]


        ;===========================================================
        ;普通中斷處理
        ;當(dāng)普通中斷發(fā)生時(shí),執(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語(yǔ)言撰寫的Main()函數(shù)內(nèi)繼續(xù)執(zhí)行其他程序
        ;這里不能寫main,因?yàn)閷懥薽ain,系統(tǒng)會(huì)自動(dò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.

        ;定義一個(gè)數(shù)據(jù)緩沖池
        LTORG

        ;連續(xù)13個(gè)內(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

        ;運(yùn)行域定義
        BaseOfROMDCD|Image
        RO
        Base|
        TopOfROMDCD|Image
        RO
        Limit|
        BaseOfBSSDCD|Image
        RW
        Base|
        BaseOfZeroDCD|Image
        ZI
        Base|
        EndOfBSSDCD|Image
        ZI
        Limit|

        ;重新使數(shù)據(jù)字對(duì)齊
        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語(yǔ)言中定義為:#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

        ;等待一段時(shí)間
        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模式

        ;等待一段時(shí)間
        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;返回,該語(yǔ)句為一個(gè)宏定義

        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

        ;等待一段時(shí)間
        mov r1,#16;Wait until self-refresh is issued,which may not be needed.
        0subs r1,r1,#1
        bne %B0

        ;在進(jìn)入SLEEP模式之前,配置必要的時(shí)鐘和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è)置時(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

        ;等待一段時(shí)間
        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é)尾


        關(guān)鍵詞: s3c2440啟動(dòng)文

        評(píng)論


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

        關(guān)閉
        主站蜘蛛池模板: 万全县| 红河县| 贡嘎县| 潍坊市| 布尔津县| 麦盖提县| 池州市| 弥勒县| 定日县| 永吉县| 木里| 玛沁县| 榆中县| 拜泉县| 大连市| 沙坪坝区| 安义县| 抚顺市| 谢通门县| 神农架林区| 清水河县| 塔城市| 开封市| 根河市| 台安县| 德钦县| 诸暨市| 田东县| 克什克腾旗| 无极县| 鄄城县| 鞍山市| 句容市| 揭阳市| 昌都县| 玉溪市| 桂平市| 铜川市| 惠水县| 龙门县| 耒阳市|