新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > S3C2440 2440init.s分析第二篇(一)

        S3C2440 2440init.s分析第二篇(一)

        作者: 時間:2016-11-20 來源:網絡 收藏
        S3C2440 2440init.s分析第二篇(一)
        ;=========================================
        ; 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.
        ;=========================================

        ;首先,啟動代碼定義了一些常量
        GET option.inc
        GET memcfg.inc
        GET 2440addr.inc

        BIT_SELFREFRESH EQU (1<<22)

        ;處理器模式常量
        USERMODE EQU 0x10
        FIQMODE EQU 0x11
        IRQMODE EQU 0x12
        SVCMODE EQU 0x13
        ABORTMODE EQU 0x17
        UNDEFMODE EQU 0x1b
        MODEMASK EQU 0x1f
        NOINT EQU 0xc0

        ;定義處理器各模式下堆棧地址常量
        UserStack EQU (_STACK_BASEADDRESS-0x3800) ;0x33ff4800 ~
        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 ~

        ;檢查在tasm.exe里是否設置了采用THUMB(16位)代碼(armasm -16 ...@ADS 1.0)
        GBLL THUMBCODE ;定義THUMBCODE全局變量
        [ {CONFIG} = 16 ;如果發現是才用16位代碼的話
        THUMBCODE SETL {TRUE} ;把THUMBCODE設置為TURE
        CODE32 ;把處理器從新設置成為ARM模式
        | ;如果處理器現在就是ARM模式
        THUMBCODE SETL {FALSE} ;把THUMBCODE設置為FALSE就行了
        ]

        MACRO ;一個根據THUMBCODE把PC寄存的值保存到LR的宏
        MOV_PC_LR
        [ THUMBCODE
        bx lr ;在ARM模式中要使用BX指令轉跳到THUMB指令,并轉換模式
        |
        mov pc,lr ;如果目標地址也是ARM指令的話就采用這種方式
        ]
        MEND

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

        ;=======================================================================================
        ;下面這個宏是用于第一次查表過程的實現中斷向量的重定向,如果你比較細心的話就是發現
        ;在_ISR_STARTADDRESS=0x33FF_FF00里定義的第一級中斷向量表是采用型如Handle***的方式的.
        ;而在程序的ENTRY處(程序開始處)采用的是b Handler***的方式.
        ;在這里Handler***就是通過HANDLER這個宏和Handle***進立聯系的.
        ;這種方式的優點就是正真定義的向量數據在內存空間里,而不是在ENTRY處的ROM(FLASH)空間里,
        ;這樣,我們就可以在程序里靈活的改動向量的數據了.
        ;========================================================================================

        MACRO
        $HandlerLabel HANDLER $HandleLabel

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


        ;=========================================================================================
        ;在這里用IMPORT偽指令(和c語言的extren一樣)引入|Image$$RO$$Base|,|Image$$RO$$Limit|...
        ;這些變量是通過ADS的工程設置里面設定的RO Base和RW Base設定的,
        ;最終由編譯腳本和連接程序導入程序.
        ;那為什么要引入這玩意呢,最簡單的用處是可以根據它們拷貝自已
        ;==========================================================================================
        IMPORT |Image$$RO$$Base| ; ROM code(也就是代碼)的開始地址
        IMPORT |Image$$RO$$Limit| ; ROM code的結束地址 (=ROM data的開始地址)
        IMPORT |Image$$RW$$Base| ; 要初始化的RAM的開始地址
        IMPORT |Image$$ZI$$Base| ; area(需要清零的RAM區域)的開始地址
        IMPORT |Image$$ZI$$Limit| ; area的結束地址

        ;這里引入一些在其它文件中實現在函數,包括為我們所熟知的main函數
        IMPORT MMU_SetAsyncBusMode
        IMPORT MMU_SetFastBusMode ;hzh

        IMPORT Main ; The main entry of mon program

        ;從這里開始就是正真的代碼入口了!
        AREA Init,CODE,READONLY ;這表明下面的是一個名為Init的代碼段

        ENTRY ;定義程序的入口(調試用)

        EXPORT __ENTRY ;導出符號_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 the memory bus width.
        ;3)The pseudo instruction,DCD can not be used here because the linker generates error.
        ASSERT :DEF:ENDIAN_CHANGE
        [ ENDIAN_CHANGE ;下面是大小端的一個判斷,在Option.inc里已經設為FALSE
        ASSERT :DEF:ENTRY_BUS_WIDTH
        [ ENTRY_BUS_WIDTH=32
        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的話就來到這了,轉跳到復位程序入口
        ]
        b HandlerUndef ;轉跳到Undefined mode程序入口
        b HandlerSWI ;轉跳到SWI 中斷程序入口
        b HandlerPabort ;轉跳到PAbort(指令異常)程序入口
        b HandlerDabort ;轉跳到DAbort(數據異常)程序入口
        b . ;保留
        b HandlerIRQ ;轉跳到IRQ 中斷程序入口
        b HandlerFIQ ;轉跳到FIQ 中斷程序入口

        ;@0x20
        b EnterPWDN ; Must be @0x20.

        ;==================================================================================
        ;下面是改變大小端的程序,這里采用直接定義機器碼的方式,至說為什么這么做就得問三星了
        ;反正我們程序里這段代碼也不會去執行,不用去管它
        ;==================================================================================
        ChangeBigEndian
        ;@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

        ;如上所說,這里采用HANDLER宏去建立Hander***和Handle***之間的聯系
        HandlerFIQ HANDLER HandleFIQ
        HandlerIRQ HANDLER HandleIRQ
        HandlerUndef HANDLER HandleUndef
        HandlerSWI HANDLER HandleSWI
        HandlerDabort HANDLER HandleDabort
        HandlerPabort HANDLER HandlePabort

        ;===================================================================================
        ;呵呵,來了來了.好戲來了,這一段程序就是用來進行第二次查表的過程了.
        ;如果說第一次查表是由硬件來完成的,那這一次查表就是由軟件來實現的了.
        ;為什么要查兩次表??
        ;沒有辦法,ARM把所有的中斷都歸納成一個IRQ中斷異常和一個FIRQ中斷異常
        ;第一次查表主要是查出是什么異常,可我們總要知道是這個中斷異常中的什么中斷呀!
        ;沒辦法了,再查一次表唄!
        ;===================================================================================
        IsrIRQ
        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了,跳轉成功!


        LTORG ;聲明文字池,因為我們用了ldr偽指令


        ;==============================================================================
        ; ENTRY(好了,我們的CPU要在這復位了.)
        ;==============================================================================
        ResetHandler
        ldr r0,=WTCON ;1.關看門狗
        ldr r1,=0x0
        str r1,[r0]

        ldr r0,=INTMSK
        ldr r1,=0xffffffff ;2.關中斷
        str r1,[r0]

        ldr r0,=INTSUBMSK
        ldr r1,=0x7fff ;3.關子中斷
        str r1,[r0]

        [ {FALSE} ;4.得有些表示了,該點點LED燈了,不過被FALSE掉了.
        ;rGPFDAT = (rGPFDAT & ~(0xf<<4)) | ((~data & 0xf)<<4);
        ; Led_Display
        ldr r0,=GPFCON
        ldr r1,=0x5500
        str r1,[r0]
        ldr r0,=GPFDAT
        ldr r1,=0x10
        str r1,[r0]
        ]

        ;5.為了減少PLL的lock time, 調整LOCKTIME寄存器.
        ldr r0,=LOCKTIME
        ldr r1,=0xffffff
        str r1,[r0]

        [ PLL_ON_START ;6.下面就來設置PLL了,你的板快不快就看這了!!
        ; Added for confirm clock divide. for 2440.
        ; 設定Fclk:Hclk:Pclk
        ldr r0,=CLKDIVN
        ldr r1,=CLKDIV_VAL ; 0=1:1:1, 1=1:1:2, 2=1:2:2, 3=1:2:4,
        str r1,[r0] ; 4=1:4:4, 5=1:4:8, 6=1:3:3, 7=1:3:6.

        ;===============================================================================
        ;MMU_SetAsyncBusMode 和 MMU_SetFastBusMode 都在4K代碼以上,
        ;如果你想你編譯出來的程序能在NAND上運行的話,就不要在這調用這兩函數了.
        ;如果你不要求的話,你就用把.啥事沒有.
        ;為什么是4K,問三星吧,就提供4K的內部SRAM,要是提供400K多好呀.
        ;好了,好了,4K就4K吧,不能用這兩函數,自己寫還不行嗎,下面的代碼這這么來了,
        ;實現和上面兩函數一樣的功能.
        ;===============================================================================
        ; [ CLKDIV_VAL>1 ; 意思是 Fclk:Hclk 不是 1:1.
        ; bl MMU_SetAsyncBusMode
        ; |
        ; bl MMU_SetFastBusMode ; default value.
        ; ]

        [ CLKDIV_VAL>1 ; 意思是 Fclk:Hclk 不是 1:1.
        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
        ]

        ;配置 UPLL
        ldr r0,=UPLLCON
        ldr r1,=((U_MDIV<<12)+(U_PDIV<<4)+U_SDIV)
        str r1,[r0]
        nop ; Caution: After UPLL setting, at least 7-clocks
        nop ; delay must be inserted for setting hardware be completed.
        nop
        nop
        nop
        nop
        nop
        ;配置 MPLL 一定要使最后的頻率為16.9344MHz,不然你甭想用USB接口了,哈哈.
        ldr r0,=MPLLCON
        ldr r1,=((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV)
        str r1,[r0]
        ]

        ;檢查是否從SLEEP模式中恢復
        ldr r1,=GSTATUS2
        ldr r0,[r1]
        tst r0,#0x2
        ;如果是從SLEEP模式中恢復, 轉跳到SLEEP_WAKEUP.
        bne WAKEUP_SLEEP

        EXPORT StartPointAfterSleepWakeUp ;導出符號StartPointAfterSleepWakeUp
        StartPointAfterSleepWakeUp

        ;===============================================================================
        ;設置內存控制器等寄存器的值,因為這些寄存器是連續排列的,所以采用如下辦法對這些
        ;寄存器進行連續設置.其中用到了SMRDATA的數據,這在代碼后面有定義
        ;===============================================================================
        ;ldr r0,=SMRDATA
        adrl r0, SMRDATA ;be careful!, hzh
        ldr r1,=BWSCON ;BWSCON 地址
        add r2, r0, #52 ;SMRDATA數據的結束地址,共有52字節的數據

        0
        ldr r3, [r0], #4
        str r3, [r1], #4
        cmp r2, r0
        bne %B0

        ;================================================================================
        ;如果 EINT0 產生(這中斷就是我們按鍵產生的), 就清除SDRAM ,不過好像沒人會在這個時候按
        ;================================================================================
        ; check if EIN0 button is pressed

        ldr r0,=GPFCON
        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 ;如果沒有按,就跳到后面的1標號處



        ; 這就是清零內存的代碼

        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
        ldr r0,=0x30000000
        0
        stmia r0!,{r1-r8}
        subs r9,r9,#32
        bne %B0

        ;到這就結束了.

        1
        bl InitStacks ;初始化堆棧
        ;bl Led_Test ;又是LED,注掉了

        ;=======================================================================
        ; 哈哈,下面又有看頭了,這個初始化程序好像被名曰hzh的高手改過
        ; 能在NOR NAND 還有內存中運行,當然了,在內存中運行最簡單了.
        ; 在NOR NAND中運行的話都要先把自己拷到內存中.
        ; 此外,還記得上面提到的|Image$$RO$$Base|,|Image$$RO$$Limit|...嗎?
        ; 這就是拷貝的依據了!!!
        ;=========================================================================
        ldr r0, =BWSCON
        ldr r0, [r0]
        ands r0, r0, #6 ;OM[1:0] != 0, 從NOR FLash啟動或直接在內存運行
        bne copy_proc_beg ;不讀取NAND FLASH
        adr r0, ResetEntry ;OM[1:0] == 0, 否則,為從NAND FLash啟動
        cmp r0, #0 ;再比較入口是否為0地址處
        ;==========================================================================
        ;如果不是,則表示主板設置了從NAND啟動,但這個程序由于其它原因,
        ;并沒有從NAND從啟動,這種情況最有可能的原因就是用仿真器.
        ;==========================================================================
        bne copy_proc_beg ;這種情況也不讀取NAND FLASH.
        ;nop
        ;===========================================================
        nand_boot_beg ;這一段代碼完成從NAND讀代碼到RAM
        mov r5, #NFCONF ;首先設定NAND的一些控制寄存器
        ;set timing value
        ldr r0, =(7<<12)|(7<<8)|(7<<4)
        str r0, [r5]
        ;enable control
        ldr r0, =(0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0)
        str r0, [r5, #4]

        bl ReadNandID ;按著讀取NAND的ID號,結果保存在r5里
        mov r6, #0 ;r6設初值0.
        ldr r0, =0xec73 ;期望的NAND ID號
        cmp r5, r0 ;這里進行比較
        beq %F1 ;相等的話就跳到下一個1標號處
        ldr r0, =0xec75 ;這是另一個期望值
        cmp r5, r0
        beq %F1 ;相等的話就跳到下一個1標號處
        mov r6, #1 ;不相等了,設置r6=1.
        1
        bl ReadNandStatus ;讀取NAND狀態,結果放在r1里

        mov r8, #0 ;r8設初值0,意義為頁號
        ldr r9, =ResetEntry ;r9設初值為初始化程序入口地址
        ;=========================================================================
        ; 注意,在這里使用的是ldr偽指令,而不是上面用的adr偽指令,它加載的是ResetEntry
        ; 的決對地址,也就是我們期望的RAM中的地址,在這里,它和|Image$$RO$$Base|一樣
        ; 也就是說,我如我們編譯程序時RO BASE指定的地址在RAM里,而把生成的文件拷到
        ; NAND里運行,由ldr加載的r9的值還是定位在內存.
        ;=========================================================================
        2
        ands r0, r8, #0x1f ;凡r8為0x1f(32)的整數倍-1,eq有效,ne無效
        bne %F3 ;這句的意思是對每個塊(32頁)進行檢錯
        mov r0, r8 ;r8->r0
        bl CheckBadBlk ;檢查NAND的壞區
        cmp r0, #0 ;比較r0和0
        addne r8, r8, #32 ;存在壞塊的話就跳過這個壞塊
        bne %F4 ;沒有的話就跳到標號4處
        3
        mov r0, r8 ;當前頁號->r0
        mov r1, r9 ;當前目標地址->r1
        bl ReadNandPage ;讀取該頁的NAND數據到RAM
        add r9, r9, #512 ;每一頁的大小是512Bytes
        add r8, r8, #1 ;r8指向下一頁
        4
        cmp r8, #256 ;比較是否讀完256頁即128KBytes
        bcc %B2 ;如果r8小于256(沒讀完),就返回前面的標號2處

        mov r5, #NFCONF ;DsNandFlash
        ldr r0, [r5, #4]
        bic r0, r0, #1
        str r0, [r5, #4]
        ldr pc, =copy_proc_beg ;調用copy_proc_beg
        ;===========================================================
        copy_proc_beg
        adr r0, ResetEntry ;ResetEntry值->r0
        ldr r2, BaseOfROM ;BaseOfROM值(后面有定義)->r2
        cmp r0, r2 ;比較r0和r2
        ldreq r0, TopOfROM ;如果相等的話(在內存運行),TopOfROM->r0
        beq InitRam ;同時跳到InitRam

        ;=========================================================
        ;下面這個是針對代碼在NOR FLASH時的拷貝方法
        ;功能為把從ResetEntry起,TopOfROM-BaseOfROM大小的數據拷到BaseOfROM
        ;TopOfROM和BaseOfROM為|Image$$RO$$Limit|和|Image$$RO$$Base|
        ;|Image$$RO$$Limit|和|Image$$RO$$Base|由連接器生成
        ;為生成的代碼的代碼段運行時的起啟和終止地址
        ;BaseOfBSS和BaseOfZero為|Image$$RW$$Base|和|Image$$ZI$$Base|
        ;|Image$$RW$$Base|和|Image$$ZI$$Base|也是由連接器生成
        ;兩者之間就是初始化數據的存放地放
        ;=======================================================

        ldr r3, TopOfROM
        0
        ldmia r0!, {r4-r7}
        stmia r2!, {r4-r7}
        cmp r2, r3
        bcc %B0

        sub r2, r2, r3 ;r2=BaseOfROM-TopOfROM=(-)代碼長度
        sub r0, r0, r2 ;r0=ResetEntry-(-)代碼長度=ResetEntry+代碼長度

        InitRam
        ldr r2, BaseOfBSS ;BaseOfBSS->r2
        ldr r3, BaseOfZero ;BaseOfZero->r3
        0
        cmp r2, r3 ;比較BaseOfBSS和BaseOfZero
        ldrcc r1, [r0], #4 ;要是r21 ; means Fclk:Hclk is not 1:1.
        ; bl MMU_SetAsyncBusMode
        ; |
        ; bl MMU_SetFastBusMode ; default value.
        ; ]

        ;bl Led_Test

        ;===========================================================
        ; 進入C語言前的最后一步了,就是把我們用說查二級向量表
        ; 的中斷例程安裝到一級向量表(異常向量表)里.
        ldr r0,=HandleIRQ ;This routine is needed
        ldr r1,=IsrIRQ ;if there is not subs pc,lr,#4 at 0x18, 0x1c
        str r1,[r0]

        ; ;Copy and paste RW data/zero initialized data
        ; ldr r0, =|Image$$RO$$Limit| ; Get pointer to ROM data
        ; ldr r1, =|Image$$RW$$Base| ; and RAM copy
        ; ldr r3, =|Image$$ZI$$Base|
        ;
        ; ;Zero init base => top of initialised data
        ; cmp r0, r1 ; Check that they are different
        ; beq %F2
        ;1
        ; cmp r1, r3 ; Copy init data
        ; ldrcc r2, [r0], #4 ;--> LDRCC r2, [r0] + ADD r0, r0, #4
        ; strcc r2, [r1], #4 ;--> STRCC r2, [r1] + ADD r1, r1, #4
        ; bcc %B1
        ;2
        ; ldr r1, =|Image$$ZI$$Limit| ; Top of zero init segment
        ; mov r2, #0
        ;3
        ; cmp r3, r1 ; Zero init
        ; strcc r2, [r3], #4
        ; bcc %B3



        關鍵詞: S3C24402440init.

        評論


        技術專區

        關閉
        主站蜘蛛池模板: 旌德县| 阳春市| 尚义县| 延川县| 小金县| 满洲里市| 巴里| 湄潭县| 闸北区| 德昌县| 财经| 宁乡县| 泸州市| 林周县| 巴林右旗| 无棣县| 镇平县| 祁阳县| 海安县| 双江| 西和县| 开江县| 公安县| 明光市| 磐石市| 香河县| 苗栗县| 资源县| 阿城市| 清水河县| 哈巴河县| 阳江市| 鲁甸县| 福州市| 宾阳县| 南华县| 丹凤县| 东阳市| 济阳县| 孝昌县| 河池市|