歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

ARM啟動文件2440init.s分析

找到了一些當初學習嵌入式linux時的資料,現在共享出來。方便大家學習之用,無所謂原創,無非就是在前人的基礎上,進行了系統化的分析和綜合而已。不過,還是加入了不少個人學習的思路跟方法,我覺得這才是最重要的。

最近在學習嵌入式軟件,現分享自己部分成果。平台:s3c2440 mcu

;=========================================

; NAME: 2440INIT.S

; DESC: C start up codes

;      Configure memory, ISR ,stacks

;Initialize C-variables

;========================================= 

 

;注意:axd調試時,可以看到 指令pc地址從0x30000000開始,這是因為ram的起始地址是0x30000000.

;並且如果從nand啟動,則處理器自動把nand首部的4k字節,復制到ram中,然後pc跳到0x30000000,開始執行。

;此源文件通常包含一些宏定義和常量定義

;通用的《啟動流程圖》:

;入口->屏蔽所有中斷,禁止看門狗->根據工作頻率設置PLL寄存器->初始化存儲控制相關寄存器->初始化各模式下的棧指針

;->設置缺省中斷處理函數->將數據拷貝到RAM中,數據段清零->跳轉到c語言main入口函數中

;GET偽指令用於將一個源文件包含到當前源文件中,並將被包含文件在當前位置進行匯編處理,類似於c的include指令

;GET INLCUDE偽指令不能 用來包含目標文件,INCBIN偽指令 可以包含目標文件,

;被INCBIN偽指令包含的文件, 不 進行匯編處理,該執行文件或數據直接放入當前文件,編譯器從INCBIN後邊開始繼續處理

;區分GET,INCLUDE,INCBIN的用法和作用

      

       GEToption.inc             ;定義芯片相關配置

       GETmemcfg.inc           ;定義存儲器配置

       GET2440addr.inc  ;定義寄存器符號

 

 

;REFRESH寄存器[22]bit :SDRAM刷新模式 0- auto refresh; 1 - self refresh

;用於節電模式中,SDRAM自動刷新

BIT_SELFREFRESH EQU   (1<<22)

 

;Pre-defined constants

;模式預定義常量,給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      大小不定,跟堆大小相對應。畢竟是用戶態棧

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位兩種工作狀態 程序的編譯器也是分16位和32兩種編譯方式 下面程序根據處理器工作狀態確定編譯器編譯方式

;code16偽指令指示匯編編譯器後面的指令為16位的thumb指令

;code32偽指令指示匯編編譯器後面的指令為32位的arm指令

 

;Arm上電時處於ARM狀態,故無論指令為ARM集或Thumb集,都先強制成ARM集,待init.s初始化完成後

;再根據用戶的編譯配置轉換成相應的指令模式。為此,定義變量THUMBCODE作為指示,跳轉到main之前

;根據其值切換指令模式

 

;Check if tasm.exe(armasm -16 ...@ADS 1.0)is used.

;檢測工作模式,根據CONFIG的數值,確定工作模式

;{CONFIG}應該來自於ADS環境,在本環境中設置是進入時在ARM環境下,沒有設置ARM/THUMB混合環境

;關於是否設置混合編程,在環境設置選項裡的ARM Assembler 選項下,由ATPCS -> ARM/Thumb interworking選項負責

;IF ELSE ENDIF指令

    

       GBLL    THUMBCODE

       [{CONFIG} = 16        

THUMBCODE SETL  {TRUE}         ;如果設置了config,則允許thumb指令,但THUMBCODE為真並不表明以下就是thumb指令,只是允許

           CODE32                      ;code32表示以下是arm指令,在處理器剛開始時,必須以arm模式運行

             |                                  ;此處容易產生錯覺,丟掉CODE32這一行

THUMBCODE SETL  {FALSE}

    ]

 

;bx是帶狀態切換的跳轉指令,跳轉到Rm指定的地址執行程序,若Rm的位[0]為1,則跳轉時自動將CPSR的標志T

;T置位,即把目標地址的代碼解釋為Thumb代碼;若Rm的位[0]為0,則跳轉時自動將CPSR中的標志T復位,即把

;目標地址的代碼解釋為ARM代碼

 

;定義兩個宏,宏的作用:子函數返回(無條件,有條件)。

             MACRO 

      MOV_PC_LR

             [ THUMBCODE                         ;如果允許thumb指令,則需要根據最低位設置狀態。

           bx lr                                   ;跳轉,附帶狀態切換

             |

           mov pc,lr

             ]

       MEND

 

             MACRO

       MOVEQ_PC_LR   ;相等則跳轉,相等與否由寄存器某些位確定,在此處,有其上一句的指令執行結果決定

             [ THUMBCODE

       bxeq lr

             |

           moveq pc,lr

             ]

       MEND

 

;重點分析下面這個宏,它對中斷處理函數的調用很重要

 

 

;MACRO和MEND偽指令用於宏定義,MACRO標識開始,MEND標識結束。用MACRO和MEND定義的一段代碼,稱為

;宏定義體,這樣在程序中就可以通過宏指令多次調用該代碼段。偽指令格式:

 

;MACRO

;{$label} macroname {$parameter} {$parameter} ...

              ;宏定義體

;MEND

 

;其中  $label 宏指令被展開時,label可被替換成相應的符號,通常為一個標號,在一個標號前使用$表示被匯編時將

;使用相應的值替代$後的符號。

;macroname 所定義的宏的名稱

;$parameter 宏指令的參數,當宏指令被展開時將被替換成相應的值,類似於函數中的形式參數

;對於子程序代碼較短,而需要傳遞的參數比較多的情況下,可以使用匯編技術。首先要用MACRO和MEND偽指令定義宏,包括宏定義

;體代碼。在MACRO偽指令之後的第一行定義宏的原型,其中包含該宏定義的名稱,及需要的參數。在匯編程序中可以通過該宏定義

;的名稱來調用它,當源程序被匯編時,匯編編譯器將  展開 每個宏調用,用宏定義體代替源程序中的宏定義的名稱,並用實際的參數

;值代替宏定義時的形式參數

 

 

;在arm中,用的是滿遞減堆棧:stmfd,ldmfd,如果用其他的方式,arm可能不能有效識別

;注意:滿遞減指的是在入棧時的操作方式,在出棧時則正好相反的次序

;關於堆棧在數據放置方式,存取順序上,可以參見《自學手冊》P84中的實例分析

;例子:

;STMFD sp!,{R0-R7,LR}:(滿遞減:先減再放數值)sp根據數據個數,減小相應個數值的數據單位(一步到位),然後利用for循環語句,從當前sp位置,依次存儲R0-R7,LR.即:sp處最後指向的是R0數據處

;LDMFD sp!,{R0-R7,LR}:復制一個變量為sp值,用該變量依次將數據存入R0-R7,LR,變量值增加,最後,變量指向下一個將要取的值,完成後sp獲得該變量值;

;risc模式,這是對ram的操作

 

 

;確切說,這是宏函數,編譯時對調用語句要做相應的展開

 

             MACRO

$HandlerLabel HANDLER $HandleLabel

 

$HandlerLabel                            ;標號

       sub  sp,sp,#4          ;留出一個空間,為了存放跳轉地址給pc。見:str r0,[sp,#4] ,注意sp值並未改變

      

       stmfd      sp!,{r0}  ;把r0中的內容入棧,保存起來

      

       ldr     r0,=$HandleLabel    ;這是一個偽指令,不是匯編指令,目的:把$HandleLabel本身所在的地址給r0

      

       ldr     r0,[r0]                           ;把HandleXXX所指向的內容(也就是中斷程序的入口地址)放入r0

      

       str     r0,[sp,#4]                  ;把入口地址放入剛才留出的一個空間裡

      

       ldmfd   sp!,{r0,pc}         ;出棧的方式恢復r0原值和為pc設定新值(也就完成了到ISR的轉跳)。注:棧中r0內容在低地址

      

       MEND

 

;這幾個變量是ads環境下自動設置的,可以見環境配置選項裡:ARM Linker->Output下,RO Base,RW Base

;RW Base 沒設置,因為代碼段的結束便是數據段的開始,這個ads可以自動設置

;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 ;想知道代碼具體內容見cp15手冊,並以cp15指令內容搜索2440a手冊

 

       IMPORT  Main            ;The main entry of mon program

       IMPORT  RdNF2SDRAM   ;Copy Image from Nand Flash to SDRAM

 

 

;AREA偽指令用於定義一個代碼段或數據段,一個ARM源程序至少需要一個代碼段,大的程序可以包含多個代碼段及數據段

;格式:AREA sectionname {,attr} {,attr}...

       AREA    Init,CODE,READONLY

 

;ENTRY偽指令用於指定程序的入口點

;一個程序(可以包含多個源文件)中至少要有一個ENTRY,可以有多個ENTRY,但一個源文件中最多只有一個ENTRY.

       ENTRY

      

;EXPORT聲明一個符號可以被其他文件引用,相當於聲明了一個全局變量。GLOBAL與EXPORT相同    

;格式:EXPORT symbol{[WEAK]}   [WEAK]聲明其他的同名符優先於本符號被引用

;導出符號__ENTRY

 

       EXPORT __ENTRY

__ENTRY

ResetEntry

       ;1)Thecode, which converts to Big-endian, should be in little endian code.

       ;2)Thefollowing 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.

      

;條件編譯,在編譯成機器碼前就設定好  大小端轉換

;判斷ENDIAN_CHANGE是否已定義,ASSERT 是斷言偽指令,語法是:ASSERT +邏輯表達式 ,def 是邏輯偽操作符,格式為::DEF:label,作用是:判斷label是否定義過

      

       ASSERT :DEF:ENDIAN_CHANGE

       [ENDIAN_CHANGE                                             ;definedin option.inc 默認是FALSE,所以此句不會加入代碼中

              ASSERT  :DEF:ENTRY_BUS_WIDTH            ;斷言指令,檢測是否定義該變量,若未定義,報錯

              [ENTRY_BUS_WIDTH=32                      ;definedin option.inc

                     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 ;本硬件用的是小端模式,這是第一個執行語句,直接跳轉到復位指令處 0X00

       ]

       b     HandlerUndef ;handler for Undefined mode            0X04

       b     HandlerSWI          ;handlerfor SWI interrupt                   0X08

       b     HandlerPabort ;handler for PAbort,指令預取中止    0X0C            

       b     HandlerDabort       ;handler for DAbort,數據中止          0X10

       b     .                           ;reserved 保留未用 注意小圓點         0X14

       b     HandlerIRQ    ;handlerfor IRQ interrupt                          0X18

       b     HandlerFIQ    ;handlerfor FIQ interrupt                          0X1C

;這7個中斷,每個中斷都有固定的中斷入口地址,它們位於代碼的最前端,不允許另作他用

;@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

;對存儲器控制寄存器操作,指定內存模式為Big-endian

;因為剛開始CPU都是按照32位總線的指令格式運行的,如果采用其他的話,CPU別不了,必須轉化

;但當系統初始化好以後,則CPU能自動識別

 

       ]

       [ENTRY_BUS_WIDTH=16

              DCD0x0f10ee11

              DCD0x0080e380

              DCD0x0f10ee01

;因為采用Big-endian模式,采用16位總線時,物理地址的高位和數據的地位對應

;所以指令的機器碼也相應的高低對調

 

       ]

       [ENTRY_BUS_WIDTH=8

              DCD0x100f11ee

              DCD0x800080e3

              DCD0x100f01ee

       ]

       DCD0xffffffff  ;swinv 0xffffff is similarwith NOP and run well in both endian mode.

       DCD0xffffffff

       DCD0xffffffff

       DCD0xffffffff

       DCD0xffffffff

       bResetHandler                     ;設置成大端後,再次跳到復位指令處

      

      

 

;本文件底部定義了一個數據區(在文件最後),34個字空間,存放相應中斷服務程序的首地址。每個字

;空間都有一個標號,以Handle***命名。

;這是宏實例   在這裡Handler***就是通過HANDLER這個宏和Handle***建立聯系的.

 

;詳細分析:

;    這是宏示例,也就是宏的調用指令,當編譯時編譯器會把宏調用指令展開

;    這是向量中斷

 

;展開方式(舉例):

 

;HandlerFIQ   HANDLERHandleFIQ

 

;展開後變成:

 

;HandlerFIQ                                ;標號,由 " b       HandlerFIQ  "指令使用(見上,復位處)

;         sub    sp,sp,#4              ;留出一個空間,為了存放跳轉地址給pc。見:strr0,[sp,#4] ,注意sp值並未改變

;     

;         stmfd sp!,{r0}      ;把r0中的內容入棧,保存起來

;     

;         ldr    r0,=HandleFIQ  ;HandleFIQ標號,在本文件最下方定義

;     

;         ldr    r0,[r0]               ;把HandleXXX所指向的內容(也就是中斷程序的入口地址)放入r0

;     

;         str    r0,[sp,#4]       ;把入口地址放入剛才留出的一個空間裡

;     

;        ldmfd  sp!,{r0,pc}            ;出棧的方式恢復r0原值和為pc設定新值(也就完成了到ISR的轉跳)。注:棧中r0內容在低地址

;     

; 後邊的語句展開方式,同上。編譯後,代碼都展開放置

 

HandlerFIQ    HANDLERHandleFIQ

HandlerIRQ    HANDLERHandleIRQ

HandlerUndef HANDLER HandleUndef

HandlerSWI   HANDLERHandleSWI

HandlerDabort       HANDLER HandleDabort

HandlerPabort HANDLER HandlePabort

 

 

 

;非向量中斷總入口(需要自己判斷中斷類型,而不是直接跳轉到相應程序)

;產生中斷後,需要中斷服務程序���己來判斷,到底是哪個中斷請求,根據的就是INTOFFSET寄存器中的偏移,再計算中斷服務地址

IsrIRQ

       sub  sp,sp,#4      ;reserved for PC,預留返回指針的存儲位置

       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中只是偏移單位的個數,需要*4變成具體字節偏移(相對於EINT0)

       ldr   r8,[r8]

       str    r8,[sp,#8]                     ;pc值放在了高位置

       ldmfd      sp!,{r8-r9,pc}

 

 

       LTORG

      

;LTORG用於聲明一個文字池,在使用LDR偽指令時,要在適當的地方加入LTORG聲明文字池,這樣就會把要加載的數據保存在

;文字池內,再用ARM的《加載指令》讀出數據。(若沒有使用LTORG聲明文字池,則匯編器會在程序末尾自動聲明)

;LTORG 偽指令常放在無條件跳轉指令之後,或者子程序返回指令之後,這樣處理器就不會錯誤地將文字池中的數據當做指令來執行

;注:在此,文字池內存儲的是INTOFFSET宏所代表的值:0x4a000014  。畢竟,當把指令編譯成二進制代碼時,arm指令(32位)

;不能既表示出指令內容,又表示出數據地址(32位)。估計在編譯時,會被匯編成其他的加載指令,再編譯成機器碼

;LTORG 只要單獨寫出來就可以了,其他的交給編譯器來做,而且它跟它下面的代碼沒有任何關系

 

 

;=======

; ENTRY

;=======            

ResetHandler               

       ldr   r0,=WTCON       ;watch dog disable   編譯時就是 ldr r0,=53000000;偽指令有=號

       ldr   r1,=0x0                 ;這些宏定義都位於2440addr.inc中。   區分:變量定義&& 宏定義

       str    r1,[r0]

 

       ldr   r0,=INTMSK

       ldr   r1,=0xffffffff  ;all interrupt disable   要理解子中斷和中斷之間的關系

       str    r1,[r0]

 

       ldr   r0,=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,=0x155500

              str    r1,[r0]

              ldr   r0,=GPBDAT

              ldr   r1,=0x0

              str    r1,[r0]

       ]

 

       ;Toreduce PLL lock time, adjust the LOCKTIME register.

       ldr   r0,=LOCKTIME

       ldr   r1,=0xffffff          

       str    r1,[r0]

 

       [PLL_ON_START               ;defined inoption.inc {TRUE},選擇要不要設置頻率值

              ;Added for confirm clock divide. for 2440.

              ;Setting value 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, 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              ; meansFclk:Hclk is not 1:1.

                     mrcp15,0,r0,c1,c0,0

                     orrr0,r0,#0xc0000000;R1_nF:OR:R1_iA

                     mcrp15,0,r0,c1,c0,0

                     |

                     mrcp15,0,r0,c1,c0,0

                     bicr0,r0,#0xc0000000;R1_iA:OR:R1_nF

                     mcrp15,0,r0,c1,c0,0

              ]

; 在配置UPLLCON和MPLLCON寄存器時,必須先配置UPLLCON,然後再配置MPLLCON,而且兩者之間要有7 nop的間隔。(這是2440文檔明確要求的)

              ;ConfigureUPLL

              ldr   r0,=UPLLCON

              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

              ;ConfigureMPLL

              ldr   r0,=MPLLCON                    ;計算公式是固定的,可計算得到

              ldr   r1,=((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV)                           ;Fin = 12.0MHz, FCLK= 400MHz

              str    r1,[r0]

       ]

 

       ;Checkif the boot is caused by the wake-up from SLEEP mode.

       ldr   r1,=GSTATUS2             ;這個寄存器數值表示哪個信號引起的復位動作產生

       ldr   r0,[r1]

       tst    r0,#0x2

       ;Incase of the wake-up from SLEEP mode, go to SLEEP_WAKEUP handler.

       bne  WAKEUP_SLEEP

 

       EXPORTStartPointAfterSleepWakeUp

StartPointAfterSleepWakeUp

 

       ;Setmemory control registers

                          ;ldr  r0,=SMRDATA  ;(等效於下邊的指令)

     

      adrl  r0,SMRDATA       ;be careful!中等范圍的地址讀取偽指令,用法類似於ldr(大范圍地址讀取)偽指令

       ldr   r1,=BWSCON       ;BWSCONAddress

       add  r2, r0, #52      ;Endaddress of SMRDATA    共有13個寄存器地址(4字節)需要賦值,13*4=52字節

 

0

       ldr   r3, [r0], #4            ;這些都是後變址指令

       str    r3, [r1], #4

       cmp r2, r0

       bne  %B0                                   ;當<的時候,跳轉到0標號處繼續執行

 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;       When EINT0 is pressed,  Clear 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               ;若不相等,則向下跳到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=****

 

       movr1,#0

       movr2,#0

       movr3,#0

       movr4,#0

       movr5,#0

       movr6,#0

       movr7,#0

       movr8,#0

      

       ldr   r9,=0x4000000   ;64MB      ;這幾條指令目的是:擦除sdram的所有數據

       ldr   r0,=0x30000000

0    

       stmia       r0!,{r1-r8}

       subs r9,r9,#32

       bne  %B0

 

;Clear SDRAM End

 

1

 

       ;Initializestacks

       bl    InitStacks

 

;===========================================================

;OM0是flash選擇開關,OM0接地時從nand 啟動,懸空時(核心板上有上拉電阻)從nor啟動

;OM1在核心板上,始終是接地.為0

;OM1:OM0取值:00 nandflash mode;01 16bit nor;10 32bit nor;11 test mode

;詳見:s3c2440 用戶手冊 5.memory controller 一節

 

       ldr   r0, =BWSCON

       ldr   r0, [r0]

       ands r0, r0, #6        ;OM[1:0]!= 0, NOR FLash boot do not read nand flash

       bne  copy_proc_beg             

       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

      

;ands指令,加s表示結果影響cpsr寄存器的值      

      

      

;===========================================================

;把nand中的數據,拷貝到ram中

nand_boot_beg

       [{TRUE}

              blRdNF2SDRAM                      

       ]

 

       ldr   pc, =copy_proc_beg

 

;這裡的一段代碼時對內存數據的初始化,涉及代碼段,數據段,bss段等

;因對這裡的變量設置等有異議,暫時未全面分析,但是基本原理想通,就是一個比較地址,復制數據的過程

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

; 把中斷服務函數的總入口地址,賦給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

InitStacks  ; 初始化棧空間(各個模式下的),為c函數運行做准備

       ;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)

 

       DCD0x32          ;SCLK power saving mode, BANKSIZE 128M/128M

 

       DCD0x30          ;MRSR6 CL=3clk

       DCD0x30          ;MRSR7 CL=3clk

      

;分配一個字的空間,並用後邊的數值來初始化該空間   ,這裡命名有些混亂

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

      

;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 mayhave not to be changed.

 

;void EnterPWDN(int CLKCON);

EnterPWDN

       movr2,r0              ;r2=rCLKCON

       tstr0,#0x8             ;SLEEP mode?

       bneENTER_SLEEP

 

ENTER_STOP

       ldrr0,=REFRESH

       ldrr3,[r0]              ;r3=rREFRESH

       movr1, r3

       orrr1, r1, #BIT_SELFREFRESH

       strr1, [r0]             ;Enable SDRAMself-refresh

 

       movr1,#16                   ;wait untilself-refresh is issued. may not be needed.

0     subsr1,r1,#1

       bne%B0

 

       ldrr0,=CLKCON          ;enter STOP mode.

       strr2,[r0]

 

       movr1,#32

0     subsr1,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.

 

       ldrr0,=REFRESH ;exit from SDRAM self refresh mode.

       strr3,[r0]

 

       MOV_PC_LR

 

ENTER_SLEEP

       ;NOTE.

       ;1)rGSTATUS3 should have the return address after wake-up from SLEEP mode.

 

       ldrr0,=REFRESH

       ldrr1,[r0]              ;r1=rREFRESH

       orrr1, r1, #BIT_SELFREFRESH

       strr1, [r0]             ;Enable SDRAMself-refresh

 

       movr1,#16                   ;Wait untilself-refresh is issued,which may not be needed.

0     subsr1,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]

 

       ldrr0,=CLKCON          ; Enter sleep mode

       strr2,[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

 

       movr1,#256

0     subsr1,r1,#1   ;1) wait until the SelfRefreshis released.

       bne%B0

 

       ldrr1,=GSTATUS3       ;GSTATUS3 has the startaddress just after SLEEP wake-up

       ldrr0,[r1]

 

       movpc,r0

      

;=====================================================================

; Clock division test

; Assemble code, because VSYNC time is veryshort

;=====================================================================

       EXPORTCLKDIV124

       EXPORTCLKDIV144

      

CLKDIV124

      

       ldr    r0, = 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

 

 

 

;定義數據段

;^ 標志等價於MAP偽指令

;MAP用於定義一個結構化的內存表首地址,此時內存表的位置計數器值,也變成該首地址值,就相當於在這個地址處操作

;#於FIELD同義,用於定義一個結構化的內存表的數據域,後邊數字表示該數據占用的字節數

;Handle*** 在此就是一個標號,為了標示數據量

;用法:把對應的終端處理函數的首地址,放到這裡的對應的預留空間處,當發生中斷時,就能根據宏函數,直接跳轉

 

 

 

       AREARamData, 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

Copyright © Linux教程網 All Rights Reserved