ARM啟動程式碼分析
把MDK自帶的S3C2440A.S檔案的註釋發一下,這些是懶貓結合資料手冊與ARM指令表理解了,可能會有錯誤,放在這裡只是引導一下像我一樣還沒有入門的兄弟們,希望你們不要害怕ARM害怕嵌入式,老毛他老人家說的對,世上無難事,只怕有心人,ARM指令就那麼多,看一遍不會就多看幾遍,還有一定要學習看軟體自帶的幫助檔案.
;/*****************************************************************************/
;/* S3C2440.S: Startup file for Samsung S3C440 */
;/*****************************************************************************/
;/* <<< Use Configuration Wizard in Context Menu >>> */
;/*****************************************************************************/
;/* This file is part of the uVision/ARM development tools. */
;/* Copyright (c) 2005-2008 Keil Software. All rights reserved. */
;/* This software may only be used under the terms of a valid, current, */
;/* end user licence from KEIL for a compatible version of KEIL software */
;/* development tools. Nothing else gives you the right to use this software. */
;/*****************************************************************************/
;下面這些引數是與CPSR狀態暫存器有關
;引數的由來:這裡各個模式的引數是由暫存器CPSR的模式位設定M[4:0]得來的,
;比如這裡的使用者模式,CPSR的M[4:0]設定為10000就是0x10。
;
;Mode_USR -- 使用者模式,正常程式執行模式,用於應用程式
;Mode_FIQ -- 快速中斷模式,用於高速資料傳輸和通道處理。
;Mode_IRQ -- 外部中斷模式,用於通用的中斷處理。
;Mode_SVC -- 管理模式,使用的一種保護模式。
;Mode_ABT -- 資料訪問中止模式,用於虛擬儲存用儲存保護
;Mode_UND -- 未定義指令中止模式,當未定義指令執行時進入此模式。
;Mode_SYS -- 系統模式,用於特權級的作業系統任務。
;I_Bit -- 如果I位被置1,則外部中斷被禁止(IRQ is disabled)
;F_Bit -- 如果F位被置1,則快速中斷被禁止(FIQ is disabled)
;
;----------------------------------------------------------------------
Mode_USR EQU 0x10
Mode_FIQ EQU 0x11
Mode_IRQ EQU 0x12
Mode_SVC EQU 0x13
Mode_ABT EQU 0x17
Mode_UND EQU 0x1B
Mode_SYS EQU 0x1F
I_Bit EQU 0x80 ; when I bit is set, IRQ is disabled
F_Bit EQU 0x40 ; when F bit is set, FIQ is disabled
;-----------------------------棧初始化定義-----------------------------------
;下面這些主要是棧配置,系統的棧空間設定
;
;UND_Stack_Size -- 未定義模式的棧大小
;SVC_Stack_Size -- 超級使用者模式的棧大小
;ABT_Stack_Size -- 資料訪問終止模式的棧大小
;FIQ_Stack_Size -- 快速中斷模式的棧大小
;IRQ_Stack_Size -- 外部中斷模式的棧大小
;USR_Stack_Size -- 使用者模式的棧大小
;ISR_Stack_Size -- 總堆疊的大小,也就是也有模式下堆疊相加
;
;-----------------------------------------------------------------------
UND_Stack_Size EQU 0x00000000
SVC_Stack_Size EQU 0x00000008
ABT_Stack_Size EQU 0x00000000
FIQ_Stack_Size EQU 0x00000000
IRQ_Stack_Size EQU 0x00000080
USR_Stack_Size EQU 0x00000400
ISR_Stack_Size EQU (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \
FIQ_Stack_Size + IRQ_Stack_Size)
;-----------------------------------------------------------------------
;AREA -- 是一個偽指令,用於段定義。ARM的彙編程式由段組成,段是相對獨立
; 的指令或資料單位,每個段由AREA偽指令定義,並定義段的屬性。
; STACK -- AREA指令的一個引數,定義段名稱
; NOINIT -- AREA指令的一個引數,指定本資料段僅僅保留了內在單元,而
; 將句初始值寫入記憶體單元,也即將記憶體單元值初始化為0
; READWRITE -- 指定本段為可讀可寫,資料段預設為READWRITE。
; READWRITE(讀寫)、READONLY(只讀)
;ALIGN -- 也是一個偽指令,指定對齊方式。ALIGN n 指令的對齊值有兩種方案
; 即n 或2^n,這裡採用第二種方案即指定後面的指令8位元組對齊。
;
;下面這句話的意思是:
;開闢一個堆疊段,段名字為STACK,定義為可讀可寫,將記憶體單元初始化為0,
;-----------------------------------------------------------------------
AREA STACK, NOINIT, READWRITE, ALIGN=3
;-----------------------------------------------------------------------
;SPACE -- 偽指令,用於分配一塊記憶體單元,並用0初始化,與%同義
;其指令格式為:
; {lable} SPACE expr
;lable -- 記憶體起始地址標號 expr -- 所要分配的記憶體位元組數
;-----------------------------------------------------------------------
Stack_Mem SPACE USR_Stack_Size ;堆疊記憶體起始地址標號
__initial_sp SPACE ISR_Stack_Size ;彙編程式碼的地址標號
Stack_Top ;堆疊段內容結束,在這裡放個標號,用來獲得堆疊頂部地址
Heap_Size EQU 0x00000000 ;定義堆大小設定
;開闢一個名字為HEAP可讀可寫,不初始化記憶體單的記憶體單元。
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base ;堆的基址
Heap_Mem SPACE Heap_Size ;堆記憶體起始地址標號
__heap_limit ;堆結束
;----------------------------記憶體初始化定義-----------------------------
;在一些應用系統中除了擴充套件Flash,RAM掛接在外部儲存器介面上外,可能還有其它
;的外設掛接在外部儲存器介面上,不同外設的操作時序什麼的都是不一樣的,所以
;在使用這些外設之前必須初始化連線這些外設儲存器介面。這裡因為沒擴充套件,所以
;只定義一個片上記憶體基地址。
;-----------------------------------------------------------------------
IRAM_BASE EQU 0x40000000 ;片上SRAM的基地址,即記憶體基地址
;-------------------------看門狗初始化定義------------------------------
;看門狗在防止程式跑飛,進入無限死迴圈時起著重要作用。有些應用可能用不上
;看門狗功能,也可能有些應用會用到外部看門狗。在這個時候內部看門狗必須禁
;止,所以有時候會在初始化時將內部看門狗禁止,當以後應用用到時再開啟它。
;看門狗定時器包括三個暫存器:
;WTCON -- 看門狗控制暫存器,設定看門狗定時器模式
;WTDAT -- 看門狗資料暫存器,用於設定超時寬度
;WTCNT -- 看門狗計數暫存器,裡面存放的是看門狗定時器當前值
;
;WT_BASE -- 看門狗定時器基地址
;WTCON_OFS -- 看門狗控制暫存器偏移地址,相對於基址
;WTDAT_OFS -- 看門狗資料暫存器偏移地址,相對於基址
;WTCNT_OFS -- 看門狗計數暫存器偏移地址,相對於基址
;WT_SETUP -- 看門狗設定
;WTCON_Val -- 看門狗控制暫存器設定,關閉看門狗
;WTDAT_Val -- 看門狗資料暫存器設定,初始值即為0x8000
;-----------------------------------------------------------------------
WT_BASE EQU 0x53000000 ; Watchdog Timer Base Address
WTCON_OFS EQU 0x00 ; Watchdog Timer Control Register Offset
WTDAT_OFS EQU 0x04 ; Watchdog Timer Data Register Offset
WTCNT_OFS EQU 0x08 ; Watchdog Timer Count Register Offset
WT_SETUP EQU 0
WTCON_Val EQU 0x00000000
WTDAT_Val EQU 0x00008000
;----------------------------時鐘與電源管理定義-------------------------
;S3C2440A中的時鐘控制邏輯可以產生必須的時鐘訊號,包括CPU的FCLK,AHB匯流排的
;HCLK 以及APB匯流排外設的PCLK3C2440A內部有兩個鎖相環(PLL):一個提供FCLK,
;HCLK及PCLK,另一個專用於USB模組(48MHz).
;
;CLOCK_BASE -- 時鐘基地址
;LOCKTIME_OFS -- 鎖相環鎖定時間計數暫存器偏移地址,相對於基址
;MPLLCON_OFS -- MPLL配置暫存器偏移地址,相對於基址,主時鐘源PLL
;UPLLCON_OFS -- UPLL配置暫存器偏移地址,相對於基址,USB時鐘源PLL
;CLKCON_OFS -- 時鐘控制暫存器偏移地址,相對於基址
;CLKSLOW_OFS -- 時鐘減慢控制暫存器偏移地址,相對於基址
;CLKDIVN_OFS -- 時鐘分頻器控制暫存器偏移地址,相對於基址
;CAMDIVN_OFS -- 攝像頭時鐘分頻器控制暫存器偏移地址,相對於基址,UPLL提供
;
;CLOCK_SETUP -- 時鐘設定
;LOCKTIME_Val -- PLL鎖定時間計數器值
;MPLLCON_Val -- MPLL配置暫存器值
;UPLLCON_Val -- UPLL配置暫存器值
;CLKCON_Val -- 時鐘配置暫存器值
;CLKSLOW_Val -- 時鐘減慢控制暫存器值
;CLKDIVN_Val -- 時鐘分頻控制暫存器值
;CAMDIVN_Val -- 攝像頭分頻控制暫存器值
;-----------------------------------------------------------------------
CLOCK_BASE EQU 0x4C000000 ; Clock Base Address
LOCKTIME_OFS EQU 0x00 ; PLL Lock Time Count Register Offset
MPLLCON_OFS EQU 0x04 ; MPLL Configuration Register Offset
UPLLCON_OFS EQU 0x08 ; UPLL Configuration Register Offset
CLKCON_OFS EQU 0x0C ; Clock Generator Control Reg Offset
CLKSLOW_OFS EQU 0x10 ; Clock Slow Control Register Offset
CLKDIVN_OFS EQU 0x14 ; Clock Divider Control Register Offset
CAMDIVN_OFS EQU 0x18 ; Camera Clock Divider Register Offset
CLOCK_SETUP EQU 0
LOCKTIME_Val EQU 0x0FFF0FFF
MPLLCON_Val EQU 0x00043011
UPLLCON_Val EQU 0x00038021
CLKCON_Val EQU 0x001FFFF0
CLKSLOW_Val EQU 0x00000004
CLKDIVN_Val EQU 0x0000000F
CAMDIVN_Val EQU 0x00000000
;--------------------儲存控制器設定定義---------------------------------
;下面這些都是一些關於儲存控制器的地址巨集定義
;
;MC_BASE -- 儲存控制器基地址
;BWSCON_OFS -- 匯流排寬度和等待控制暫存器偏移地址
;BANKCON0_OFS -- BANK1控制暫存器偏移地址
; .
; .
;BANKCON7_OFS -- BANK7控制暫存器偏移地址
;REFRESH_OFS -- DRAM/SDRAM重新整理控制暫存器偏移地址
;BANKSIZE_OFS -- 可調的bank大小暫存器偏移地址
;MRSRB6_OFS -- bank6模式控制暫存器偏移地址
;MRSRB7_OFS -- bank7模式控制暫存器偏移地址
;
;MC_SETUP -- 儲存器控制暫存器設定
;BWSCON_Val -- 寫入匯流排寬度和等待控制寄存值
;BANKCON0_Val -- 寫入Blank0的值
; .
; .
;BANKCON7_Val -- 寫入BANK7 的值
;REFRESH_Val -- 寫入DRAM/SDRAM重新整理控制寄存的值
;BANKSIZE_Val -- 寫入可調的bank大小寄存的值
;MRSRB6_Val -- 寫入bank6模式控制暫存器的值
;MRSRB7_Val -- 寫入bank7模式控制暫存器的值
;-----------------------------------------------------------------------
MC_BASE EQU 0x48000000 ; Memory Controller Base Address
BWSCON_OFS EQU 0x00 ; Bus Width and Wait Status Ctrl Offset
BANKCON0_OFS EQU 0x04 ; Bank 0 Control Register Offset
BANKCON1_OFS EQU 0x08 ; Bank 1 Control Register Offset
BANKCON2_OFS EQU 0x0C ; Bank 2 Control Register Offset
BANKCON3_OFS EQU 0x10 ; Bank 3 Control Register Offset
BANKCON4_OFS EQU 0x14 ; Bank 4 Control Register Offset
BANKCON5_OFS EQU 0x18 ; Bank 5 Control Register Offset
BANKCON6_OFS EQU 0x1C ; Bank 6 Control Register Offset
BANKCON7_OFS EQU 0x20 ; Bank 7 Control Register Offset
REFRESH_OFS EQU 0x24 ; SDRAM Refresh Control Register Offset
BANKSIZE_OFS EQU 0x28 ; Flexible Bank Size Register Offset
MRSRB6_OFS EQU 0x2C ; Bank 6 Mode Register Offset
MRSRB7_OFS EQU 0x30 ; Bank 7 Mode Register Offset
MC_SETUP EQU 1
BWSCON_Val EQU 0x22000000
BANKCON0_Val EQU 0x00000700
BANKCON1_Val EQU 0x00000700
BANKCON2_Val EQU 0x00000700
BANKCON3_Val EQU 0x00000700
BANKCON4_Val EQU 0x00000700
BANKCON5_Val EQU 0x00000700
BANKCON6_Val EQU 0x00018005
BANKCON7_Val EQU 0x00018005
REFRESH_Val EQU 0x008404F3
BANKSIZE_Val EQU 0x00000032
MRSRB6_Val EQU 0x00000020
MRSRB7_Val EQU 0x00000020
;---------------------I/O埠巨集定義--------------------------------------
;GPA_BASE -- 埠A基地址
; .
;GPJ_BASE -- 埠J基地址
;GPCON_OFS -- 埠配置暫存器偏移地址
;GPDAT_OFS -- 埠資料暫存器偏移地址
;GPUP_OFS -- 埠上拉暫存器偏移地址
;GP_SETUP -- 埠設定
;GPA_SETUP -- 埠A配置
;GPACON_Val -- 寫入埠A配置暫存器的值
; .
; .
;GPJ_SETUP -- 埠J配置
;GPJCON_Val -- 寫入埠J配置暫存器的值
;GPJUP_Val -- 寫入埠J上拉暫存器的值
;-----------------------------------------------------------------------
GPA_BASE EQU 0x56000000 ; GPA Base Address
GPB_BASE EQU 0x56000010 ; GPB Base Address
GPC_BASE EQU 0x56000020 ; GPC Base Address
GPD_BASE EQU 0x56000030 ; GPD Base Address
GPE_BASE EQU 0x56000040 ; GPE Base Address
GPF_BASE EQU 0x56000050 ; GPF Base Address
GPG_BASE EQU 0x56000060 ; GPG Base Address
GPH_BASE EQU 0x56000070 ; GPH Base Address
GPJ_BASE EQU 0x560000D0 ; GPJ Base Address
GPCON_OFS EQU 0x00 ; Control Register Offset
GPDAT_OFS EQU 0x04 ; Data Register Offset
GPUP_OFS EQU 0x08 ; Pull-up Disable Register Offset
GP_SETUP EQU 1
;-----------------------------------------------------------------------
;埠A配置
;-----------------------------------------------------------------------
GPA_SETUP EQU 0
GPACON_Val EQU 0x000003FF
;-----------------------------------------------------------------------
;埠B配置
;-----------------------------------------------------------------------
GPB_SETUP EQU 0
GPBCON_Val EQU 0x00000000
GPBUP_Val EQU 0x00000000
;-----------------------------------------------------------------------
;埠C配置
;-----------------------------------------------------------------------
GPC_SETUP EQU 0
GPCCON_Val EQU 0x00000000
GPCUP_Val EQU 0x00000000
;-----------------------------------------------------------------------
;埠D配置
;-----------------------------------------------------------------------
GPD_SETUP EQU 0
GPDCON_Val EQU 0x00000000
GPDUP_Val EQU 0x00000000
;-----------------------------------------------------------------------
;埠E配置
;-----------------------------------------------------------------------
GPE_SETUP EQU 0
GPECON_Val EQU 0x00000000
GPEUP_Val EQU 0x00000000
;-----------------------------------------------------------------------
;埠F配置
;-----------------------------------------------------------------------
GPF_SETUP EQU 0
GPFCON_Val EQU 0x00000000
GPFUP_Val EQU 0x00000000
;-----------------------------------------------------------------------
;埠G配置
;-----------------------------------------------------------------------
GPG_SETUP EQU 0
GPGCON_Val EQU 0x00000000
GPGUP_Val EQU 0x00000000
;-----------------------------------------------------------------------
;埠H配置
;-----------------------------------------------------------------------
GPH_SETUP EQU 0
GPHCON_Val EQU 0x00000000
GPHUP_Val EQU 0x00000000
;-----------------------------------------------------------------------
;埠J配置
;-----------------------------------------------------------------------
GPJ_SETUP EQU 0
GPJCON_Val EQU 0x00000000
GPJUP_Val EQU 0x00000000
;-----------------------------------------------------------------------
;PRESERVE8 -- 偽指令,指示當前檔案請求堆疊為8位元組對齊。
; 彙編程式資料8位元組對齊,c和彙編有8位對齊的要求.
;-----------------------------------------------------------------------
PRESERVE8
;-----------------------------------------------------------------------
;儲存區設定和程式入口點
;啟動程式碼必須連線到第一個地址才能執行
;下面這句話的意思是:
; 宣告一個名為RESET的程式碼段,屬性為只讀
;-----------------------------------------------------------------------
AREA RESET, CODE, READONLY
ARM ;ARM模式執行程式
;-----------------------------------------------------------------------
;IMPORT -- 相當於C語言中的關鍵字extern
; 指當前的符號在其他原始檔中定義的,在本原始檔中可能引用該符號.
;EXPORT -- 相當於C語言中的關鍵字global
; 宣告一個符號可以被其它檔案引用.相當於聲明瞭一個全域性變數
;下面這幾句話是的意思是:
; 如果定義了_EVAL這個變數,引用RO輸出區的位元組長度與RW輸出區的位元組長度
;注意:
;ARM聯結器定義了一些包含$$的符號。這些符號及其他所有包含$$的名稱都是ARM的
;保留字。這些符號被用於指定域的基地址,輸出段的基地址和輸入段的基地址及其
;大小。我們可以自己的組合語言程式中引用這些符號地址,把它們用作可重定位的
;地址,也可能在C或C++程式碼中使用extern關鍵字來引用它們。這個可以檢視uVision
;Help 的Region-related symbols這一節。
;-----------------------------------------------------------------------
IF :LNOT::DEF:__EVAL ;邏輯判斷是否定義了_EVAL這個變數
IMPORT ||Image$$ER_ROM1$$RO$$Length||
IMPORT ||Image$$RW_RAM1$$RW$$Length||
ENDIF
;-----------------------------------------------------------------------
; 異常向量,對映到地址0,必須使用絕對定址方式,子程式用無限迴圈方式
;實現可以被修改。
;-----------------------------------------------------------------------
Vectors LDR PC, Reset_Addr ;將復位地址裝載到程式指標,即復位
LDR PC, Undef_Addr ;未定義指令
LDR PC, SWI_Addr ;軟體中斷
LDR PC, PAbt_Addr ;中止(預取)
LDR PC, DAbt_Addr ;中止(資料)
IF :DEF:__EVAL ;如果定義了__EVAL 變數
DCD 0x4000 ;分配2k空間
ELSE ;否則分配空間大小為RO輸出區的位元組
;長度與RW輸出區的位元組長度之和
DCD ||Image$$ER_ROM1$$RO$$Length||+\
||Image$$RW_RAM1$$RW$$Length||
ENDIF
LDR PC, IRQ_Addr ;外部中斷
LDR PC, FIQ_Addr ;快速中斷
IF :DEF:__RTX ;如果定義了__RTX
IMPORT SWI_Handler ;則定義中斷子程式
IMPORT IRQ_Handler_RTX ;定義快速中斷子程式
ENDIF
;-----------------------------------------------------------------------
;下面這幾句的任務是把各個子程式的入口地址分配給相應的地址變數
;-----------------------------------------------------------------------
Reset_Addr DCD Reset_Handler ;復位子程式入口地址賦值給Reset_Addr
Undef_Addr DCD Undef_Handler ;未定義子程式入口地址賦值給Undef_Addr
SWI_Addr DCD SWI_Handler ;中斷子程式入口地址賦值給SWI_Addr
PAbt_Addr DCD PAbt_Handler ;中止(預存)子程式入口地址賦給PAbt_Addr
DAbt_Addr DCD DAbt_Handler ;中止(資料)子程式入口地址賦給DAbt_Addr
DCD 0 ;保留地址
IF :DEF:__RTX ;如果定義了__RTX
IRQ_Addr DCD IRQ_Handler_RTX ;快速中斷子程式入口地址給IRQ_Addr
ELSE
IRQ_Addr DCD IRQ_Handler ;否則把IRQ_Handler入口地址給IRQ_Addr
ENDIF
FIQ_Addr DCD FIQ_Handler ;快速中斷入口地址給FIQ_Addr
;-----------------------------------------------------------------------
;這些子程式都是用無限迴圈方式實現的可以被修改。
;-----------------------------------------------------------------------
Undef_Handler
B Undef_Handler ;跳轉到Undef_Handler,還是在這個地方
IF :DEF:__RTX ;如果定義了DEF:__RTX,在此等待中斷
ELSE
SWI_Handler
B SWI_Handler ;否則跳轉到軟體中斷
ENDIF
PAbt_Handler
B PAbt_Handler ;中止(預存)子程
DAbt_Handler
B DAbt_Handler ;中止(資料)子程
;-----------------------------------------------------------------------
;外部中斷子程式
; 如果函式標有PROC與ENDP,但沒有FRAME PUSH 或FRAME POP,則堆疊作用量
;假定為0.這意味著無需手動新增FRAME PUSH 0或FRAME POP 0
;-----------------------------------------------------------------------
IRQ_Handler
PROC
EXPORT IRQ_Handler [WEAK] ;宣告一個全域性變數,並且其它
;同名符優先於本符號被引用
B . ;跳轉到當前地址即在此等待“.”代表當前指令地址
ENDP
FIQ_Handler ;快速中斷子程式
B FIQ_Handler
;-----------------------------------------------------------------------
;復位子程式
;-----------------------------------------------------------------------
EXPORT Reset_Handler ; 宣告一個全域性變數
Reset_Handler
;-----------------------------------------------------------------------
;配置看門狗
;前面已經初始化WT_SETUP == 0,要想執行下面的程式需將WT_SETUP置1
;-----------------------------------------------------------------------
IF WT_SETUP != 0
LDR R0, =WT_BASE ;載入看門狗基址
LDR R1, =WTCON_Val ;載入看門狗控制暫存器資料
LDR R2, =WTDAT_Val ;載入看門狗資料暫存器資料
STR R2, [R0, #WTCNT_OFS] ;將WTDAT_Val配置給看門狗
;計數暫存器
STR R2, [R0, #WTDAT_OFS] ;將WTDAT_Val 配置給看門狗
;資料暫存器
STR R1, [R0, #WTCON_OFS] ;將WTCON_Val配置給看門狗
;控制暫存器
ENDIF
;-----------------------------------------------------------------------
;配置時鐘
;如果邏輯上沒有定義NO_CLOCK_SETUP並且CLOCK_SETUP != 0執行下面程式
;-----------------------------------------------------------------------
IF (:LNOT:(:DEF:NO_CLOCK_SETUP)):LAND:(CLOCK_SETUP != 0)
LDR R0, =CLOCK_BASE ;載入時鐘基址
LDR R1, =LOCKTIME_Val ;載入PLL鎖定時間計數值
STR R1, [R0, #LOCKTIME_OFS] ;並將該值配置到PLL鎖定時間計數器
MOV R1, #CLKDIVN_Val
STR R1, [R0, #CLKDIVN_OFS] ;配置時鐘分頻器
LDR R1, =CAMDIVN_Val
STR R1, [R0, #CAMDIVN_OFS] ;配置攝像頭分頻控制暫存器
LDR R1, =MPLLCON_Val
STR R1, [R0, #MPLLCON_OFS] ;配置MPLL配置暫存器
LDR R1, =UPLLCON_Val
STR R1, [R0, #UPLLCON_OFS] ;配置UPLL配置暫存器
MOV R1, #CLKSLOW_Val
STR R1, [R0, #CLKSLOW_OFS] ;配置時鐘減慢控制暫存器
LDR R1, =CLKCON_Val
STR R1, [R0, #CLKCON_OFS] ;配置時鐘配控制暫存器
ENDIF
;-----------------------------------------------------------------------
;儲存器設定
;如果沒有定義NO_MC_SETUP且CLOCK_SETUP != 0則執行下面的程式
;-----------------------------------------------------------------------
IF (:LNOT:(:DEF:NO_MC_SETUP)):LAND:(CLOCK_SETUP != 0)
LDR R0, =MC_BASE ;載入儲存控制器基址
LDR R1, =BWSCON_Val
STR R1, [R0, #BWSCON_OFS] ;配置匯流排寬度和等待控制暫存器
LDR R1, =BANKCON0_Val
STR R1, [R0, #BANKCON0_OFS] ;配置BLANK0控制暫存器
LDR R1, =BANKCON1_Val
STR R1, [R0, #BANKCON1_OFS] ;配置BLANK1控制暫存器
LDR R1, =BANKCON2_Val
STR R1, [R0, #BANKCON2_OFS] ;配置BLANK2控制暫存器
LDR R1, =BANKCON3_Val
STR R1, [R0, #BANKCON3_OFS] ;配置BLANK3控制暫存器
LDR R1, =BANKCON4_Val
STR R1, [R0, #BANKCON4_OFS] ;配置BLANK4控制暫存器
LDR R1, =BANKCON5_Val
STR R1, [R0, #BANKCON5_OFS] ;配置BLANK5控制暫存器
LDR R1, =BANKCON6_Val
STR R1, [R0, #BANKCON6_OFS] ;配置BLANK6控制暫存器
LDR R1, =BANKCON7_Val
STR R1, [R0, #BANKCON7_OFS] ;配置BLANK7控制暫存器
LDR R1, =REFRESH_Val
STR R1, [R0, #REFRESH_OFS] ;配置DRAM/SDRAM重新整理控制暫存器
MOV R1, #BANKSIZE_Val
STR R1, [R0, #BANKSIZE_OFS] ;配置可調的bank大小暫存器
MOV R1, #MRSRB6_Val
STR R1, [R0, #MRSRB6_OFS] ;配置bank6模式控制暫存器
MOV R1, #MRSRB7_Val
STR R1, [R0, #MRSRB7_OFS] ;配置bank7模式控制暫存器
ENDIF
;-----------------------------------------------------------------------
;IO埠配置
;如果沒有定義NO_GP_SETUP並且GP_SETUP != 0則執行下面的程式
;-----------------------------------------------------------------------
IF (:LNOT:(:DEF:NO_GP_SETUP)):LAND:(GP_SETUP != 0)
IF GPA_SETUP != 0
LDR R0, =GPA_BASE ;配置埠A功能
LDR R1, =GPACON_Val ;A口有25個口,做IO時只能做輸出口
STR R1, [R0, #GPCON_OFS]
ENDIF
IF GPB_SETUP != 0
LDR R0, =GPB_BASE ;配置埠B功能
LDR R1, =GPBCON_Val
STR R1, [R0, #GPCON_OFS]
LDR R1, =GPBUP_Val ;配置埠B上拉暫存器
STR R1, [R0, #GPUP_OFS]
ENDIF
IF GPC_SETUP != 0
LDR R0, =GPC_BASE ;配置埠C功能
LDR R1, =GPCCON_Val
STR R1, [R0, #GPCON_OFS]
LDR R1, =GPCUP_Val ;配置埠C上拉暫存器
STR R1, [R0, #GPUP_OFS]
ENDIF
IF GPD_SETUP != 0
LDR R0, =GPD_BASE ;配置埠D功能
LDR R1, =GPDCON_Val
STR R1, [R0, #GPCON_OFS]
LDR R1, =GPDUP_Val ;配置埠D上位暫存器
STR R1, [R0, #GPUP_OFS]
ENDIF
IF GPE_SETUP != 0
LDR R0, =GPE_BASE
LDR R1, =GPECON_Val ;配置埠E功能
STR R1, [R0, #GPCON_OFS]
LDR R1, =GPEUP_Val ;配置埠E上位暫存器
STR R1, [R0, #GPUP_OFS]
ENDIF
IF GPF_SETUP != 0
LDR R0, =GPF_BASE
LDR R1, =GPFCON_Val ;配置埠F功能
STR R1, [R0, #GPCON_OFS]
LDR R1, =GPFUP_Val ;配置埠F上位暫存器
STR R1, [R0, #GPUP_OFS]
ENDIF
IF GPG_SETUP != 0
LDR R0, =GPG_BASE
LDR R1, =GPGCON_Val ;配置埠G功能
STR R1, [R0, #GPCON_OFS]
LDR R1, =GPGUP_Val ;配置埠G上位暫存器
STR R1, [R0, #GPUP_OFS]
ENDIF
IF GPH_SETUP != 0
LDR R0, =GPH_BASE
LDR R1, =GPHCON_Val ;配置埠H功
STR R1, [R0, #GPCON_OFS]
LDR R1, =GPHUP_Val ;配置埠H上位暫存器
STR R1, [R0, #GPUP_OFS]
ENDIF
IF GPJ_SETUP != 0
LDR R0, =GPJ_BASE
LDR R1, =GPJCON_Val ;配置埠J功
STR R1, [R0, #GPCON_OFS]
LDR R1, =GPJUP_Val ;配置埠J上位寄存
STR R1, [R0, #GPUP_OFS]
ENDIF
ENDIF
;-----------------------------------------------------------------------
;拷貝異常向量到內部RAM
;如果定義了RAM_INTVEC就執行下面一段程式
;-----------------------------------------------------------------------
IF :DEF:RAM_INTVEC
ADR R8, Vectors ; 讀取向量源地址
LDR R9, =IRAM_BASE ; 讀取片上SRAM的基地址
LDMIA R8!, {R0-R7} ; 批量載入異常向量
STMIA R9!, {R0-R7} ; 批量儲存向量
LDMIA R8!, {R0-R7} ; 載入程式入口地址(Load Handler Addresses )
STMIA R9!, {R0-R7} ; 儲存程式入口地址(Store Handler Addresses)
ENDIF
;-----------------------------------------------------------------------
;配置相應模式棧的大小(Setup Stack for each mode )
;下面這一段主要是設定各個異常模式的堆疊,注意在設定的時候需要禁止IRQ和FIQ.
;這段程式碼也是系統復位後執行的第一段程式碼。執行完這段程式碼後系統處於系統模
;式,並且IRQ和FIQ都是禁止的。
;-----------------------------------------------------------------------
LDR R0, =Stack_Top ;載入棧頂指標地址
;-----------------------------------------------------------------------
;進入未定義模式,並設定其棧指標
;-----------------------------------------------------------------------
;將(Mode_UND | I_Bit | F_Bit)賦值給CPSR_c即CPSR[7:0]
MSR CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit
MOV SP, R0 ;棧頂指標地址賦值給SP指標
SUB R0, R0, #UND_Stack_Size ;分其棧指標
;-----------------------------------------------------------------------
;進入異常中斷模式,並設定其棧指標
;下面這三句話與上面原理一樣
;-----------------------------------------------------------------------
MSR CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #ABT_Stack_Size
;-----------------------------------------------------------------------
;進入FIQ模式,並設定其棧指標
;下面這三句話與上面原理一樣
;-----------------------------------------------------------------------
MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #FIQ_Stack_Size
;-----------------------------------------------------------------------
;進入IRQ模式,並設定其棧指標
;下面這三句話與上面原理一樣
;-----------------------------------------------------------------------
MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #IRQ_Stack_Size
;-----------------------------------------------------------------------
;進入Supervisor模式,並設定其棧指標
;下面這三句話與上面原理一樣
;-----------------------------------------------------------------------
MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #SVC_Stack_Size
;-----------------------------------------------------------------------
;進入使用者模式,並設定其棧指標
;下面這三句話與上面原理一樣
;-----------------------------------------------------------------------
; Enter User Mode and set its Stack Pointer
MSR CPSR_c, #Mode_USR
MOV SP, R0
SUB SL, SP, #USR_Stack_Size
;-----------------------------------------------------------------------
;進入使用者模式
;-----------------------------------------------------------------------
MSR CPSR_c, #Mode_USR
IF :DEF:__MICROLIB ;如果定義了__MICROLIB
EXPORT __initial_sp ;那麼就宣告__initial_sp
ELSE
MOV SP, R0 ;否則就設定使用者模式棧指標
SUB SL, SP, #USR_Stack_Size
ENDIF
;-----------------------------------------------------------------------
;些處開始正式進入C程式碼區
;反彙編以後C程式中的main函式名就變成了__main
;-----------------------------------------------------------------------
IMPORT __main ;宣告__main 函式
LDR R0, =__main ;載入__main 函式入口地址
BX R0 ;跳轉到__main處
IF :DEF:__MICROLIB ;如果定義了__MICROLIB
EXPORT __heap_base ;則宣告__heap_base
EXPORT __heap_limit ;宣告__heap_limit
ELSE
;-----------------------------------------------------------------------
;使用者初始化堆與棧,用於動態申請記憶體使用
;__use_two_region_memory這是MDK的庫函
;__user_initial_stackheap也是一個庫函式,它的返回值有
; * 堆基址(heap base) --> R0
; * 棧基址(stack base) --> R1 一般為棧的最高地址
; * 堆頂(heap limit) --> R2
; * 棧頂(stack limit) --> R3
;
;-----------------------------------------------------------------------
AREA |.text|, CODE, READONLY
IMPORT __use_two_region_memory
EXPORT __user_initial_stackheap
__user_initial_stackheap
LDR R0, = Heap_Mem ;堆記憶體起始地址-->R0
LDR R1, =(Stack_Mem + USR_Stack_Size) ;棧起始地址-->R1
LDR R2, = (Heap_Mem + Heap_Size) ;堆頂-->R2
LDR R3, = Stack_Mem ;棧頂地址--> R3
BX LR ;子程式返回
ENDIF
END
不多說了,最後再吼一下懶貓的口號:
每天進步一點點,開心多一點^_^
相關推薦
ARM啟動程式碼分析
ARM啟動程式碼相當於我們電腦的BIOS,也就是ARM啟動時對處理器的一些初始化及嵌入式系統硬體的一些初始化。由於它直接面對處理器核心和硬體控制器進行程式設計,一般都是用匯編語言。一般包括:中斷向量表,初始化儲存器系統,初始化堆疊,初始化有特殊要求的斷口,裝置初始化,變數初
ARM啟動程式碼的分析
估計以後會忘記,所以記下來。 一上電,硬體自動把NandFlash中的前4K資料拷貝進片內的SRAM。開始執行指令 @************************************************************************* @ File:head
嵌入式ARM啟動程式碼的工作
嵌入式ARM啟動程式碼的工作 (1)定義程式碼的初始入口點:初始入口點是指程式碼執行時的起始點,它
專題4-我是bootloader設計師-Souce Insight+ARM啟動流程分析
一、bootloader設計藍圖 寫在前面:不想當將軍的士兵不是好士兵,不想當設計師的程式設計師不是好程式設計師 1、bootloader的作用 就像航天器的助推器,將航天器帶到指定的軌道。(啟動linux核心) 程式碼包括兩部分: 第一部分程式碼主要
STM32F4啟動程式碼分析
;******************** (C) COPYRIGHT 2014 STMicroelectronics ******************** ;* File Name : startup_stm32f40_41xxx.s ;* Auth
STM32 eCos 啟動程式碼分析(三)系統時鐘滴答
時鐘滴答好比人的心臟一樣,是作業系統必不可少的一個部件,線上程的切換和軟體延時等系統時間相關功能中起著無法替代的角色。 作業系統中的時鐘滴答,需要一個週期性的可配置的訊號源來實現,並且一般都是以中斷的方式在後臺通知系統下一個滴答的到來。 eCos中為了提供移植性,一般會用
STM32 eCos 啟動程式碼分析(一)系統復位
概述 最近接觸了STM32,開始瞭解CortexM3系列ARM處理器上RTOS的移植和啟動。 開始總是艱難的,CortexM3是arm7tdmi的升級產品,但實際上和之前的ARM7有著很大的區別。 首先,我們必須有支援CortexM3的編譯器,因為CortexM3採用的是T
Cortex-M3 (NXP LPC1788)之啟動程式碼分析
在Keil uVision4中新建一個基於NXP1788的工程後,會提示新增啟動彙編程式碼startup_LPC177x_8x.S。該檔案進行從彙編到C語言執行環境的初始化工作。 ;/************************************
sbl1啟動程式碼分析
sbl1程式的入口點在0xF800_C000,從memory map可以看出此地址位於L2 cache中,所以sbl1實際上是執行在L2 cache上的; 1)設定中斷向量表 中斷向量表位於0xFE80_5FC0(OCIMEM),覆蓋PBL的中斷向量表 AREA
EasyDarwin流媒體伺服器啟動函式StartServer程式碼分析
在前面部落格中分析EasyDarwin字典類QTSS_Dictionary時瞭解到相關QTSS_DictionaryMap,QTSSAttrInfoDict等屬性內容,其初始化分配記憶體是在伺服器啟動的時候。 正好回過來分析伺服器的初始化啟動函式QTSS_ServerSta
為什麼ARM的啟動程式碼是彙編?
啟動程式碼 為什麼啟動程式碼一定一要用匯編語言編寫,啟動程式碼的主要功能是什麼?微控制器不用啟動程式碼,為什麼arm要用啟動程式碼? ------解決方案-----------------------
u-boot_smdkv210 分析二:啟動程式碼start.s分析
1.連結檔案 . = 0x00000000; . = ALIGN(4); .text : { cpu/s5pc11x/start.o (.text) cpu/s5pc11x/s5pc110/cpu_init.o (.text) 又連結檔案可知,首先啟動的是start.o,現在從st
惡意程式碼分析實戰-啟動一個惡意的DLL
如果不能把惡意程式碼執行起來,那麼動態分析基礎技術沒有什麼用。 Windows版本中包含rundll32.exe程式,提供了一個執行DLL的平臺。 rundll32.exe Dllname,Export arguments Export值必須是一個DLL檔案匯出函式表中的函式名或者序號。 PEID可以
ARM Linux啟動流程分析——start_kernel前啟動階段(彙編部分)
本文整理了ARM Linxu啟動流程的第二階段——start_kernel前啟動階段(彙編部分),核心版本為3.12.35。我以手上的樹莓派b(ARM11)為平臺示例來分析Linux核心在自解壓後到跳轉執行start_kernel之前所做的主要初始化工作:包括引數有效性驗證
linux2.4 啟動程式碼head.S分析
32位啟動程式碼,暫時不考慮SMP的情況。關鍵程式碼分析 頁目錄表的起始地址在0x101000,由於目前仍然處於真實模式,地址都是 實體地址 開始啟動核心 startup_32: 清方向標誌位 cld 用核心資料段的地址來初始化ds,es,fs,gs暫存器 巨
關於ARM啟動流程的分析(NandFlash Or NorFlash)
學習了S3C2440的啟動流程,如何讓bootLoader成功載入。並且找到了一篇講的非常好的部落格,試著結合著自己的理解總結一下,以備以後的複習。 第一部分關於內部的SRAM: 部分ARM9的
ARM-Linux程式碼的執行效率分析
//目的:企圖定位ARM-Linux下程式執行速度緩慢的原因。 // TYPE, 緩衝區的操作型別(比較同樣的運算規模下int8, int16, int32的執行速度差異) // // buf, 一個大小為SIZE*2(Bytes)的緩衝區 // SIZE,
FREERTOS的啟動第一個任務程式碼分析
1.freertos的啟動第一個任務的彙編程式碼如下,是在一個嵌入彙編形式的C函式裡面,具體如下: __asm void vPortSVCHandler( void ) { PRESERVE8 ldr r3, =pxCurrentTCB /* Restore the co
pjsip學習筆記13 -- pjsua的啟動過程程式碼分析
PJSUA是一個開源的命令列SIP使用者代理(軟電話),用PJSIP協議,PJNATH,和PJMEDIA實現PJSUA雖然只有很簡單的命令列介面,但是功能齊全。如何在PJSUA基礎上改建自己的USER agent? 首先要理清PJSUA的程式框架。原始碼閱讀提示,實現呼叫棧的
ARM多核處理器啟動過程分析
說明: 該流程圖按照程式碼執行時間順序劃分為4部分: 1. Bootloader在圖片上半部,最先啟動; 2. Kernel在圖片下半部,由bootloader引導啟動; 3.CPU0執行流程在圖片左半部,bootloader程式碼會進行判斷,先行啟