先說一下啓動代碼的位置,啓動代碼是在板子加電後首先執行的。所以非要用匯編來寫纔行。要完成處理器模式的初始化、設置中斷向量表、設置各個模式下的堆棧、初始某些變量從而把系統帶到一個合適的運行環境中開始用戶程序的運行。
;-------------------------------------------------------------------------------
;
; 本段設置處理器的模式相關常量
;
;-------------------------------------------------------------------------------
; Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs
; 定義常量,處理器的幾種工作模式。
; ARM 有7種工作模式:
;
; User: 非特權模式,大部分任務執行在這種模式 正常程序執行的模式
; FIQ: 當一個高優先級(fast)中斷產生時將會進入這種模式 高速數據傳輸和通道處理
; IRQ: 當一個低優先級(normal)中斷產生時將會進入這種模式 通常的中斷處理
; SVC: 用於操作系統的保護模式
; Abort: 當存取異常時將會進入這種模式 虛擬存儲及存儲保護
; Undef: 當執行未定義指令時會進入這種模式 軟件仿真硬件協處理器
; System: 使用和User模式相同寄存器集的特權模式
;
; 這個值將被寫到CPSR寄存器的第0,1,2,3,4,5位,以表示當前的狀態。
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
; 設置IRQ和FIQ中斷禁止位,這兩個值將被寫到CPSR寄存器的第6位(FIQ)和第7位(IRQ)。1是禁止,0是允許。
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 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)
; 初始化棧空間
; 定義一個數據段,名爲STACK,NOINIT - 僅僅保留內存單元,還沒有寫入值,可讀寫,ALIGN=3 - 按字節對齊。
AREA STACK, NOINIT, READWRITE, ALIGN=3
; 分配內存,用戶模式棧名爲Stack_Mem,大小爲1024字節;異常模式堆棧__initial_sp 大小爲128+8字節。
Stack_Mem SPACE USR_Stack_Size
__initial_sp SPACE ISR_Stack_Size
Stack_Top
;
Heap_Size EQU 0x00000000
;堆空間,其中__heap_base 與__heap_limit 這兩個符號是給採用了MICROLIB的程序準備的。
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
;-------------------------------------------------------------------------------------------
;
; 初始化 VPB總線的頻率,Start的時候將分頻因子設置爲1,表示與CPU CLOCK相同
;-------------------------------------------------------------------------------------------
; VPBDIV 是VPB總線的分頻因子
;
; VPBDIV definitions
VPBDIV EQU 0xE01FC100 ; VPBDIV Address
VPBDIV_SETUP EQU 1
VPBDIV_Val EQU 0x00000000
;-------------------------------------------------------------------------------------------
; 定義與鎖相環相關的寄存器
; Phase Locked Loop (PLL) definitions
;-------------------------------------------------------------------------------------------
; 定義 PLL相關寄存器的基地址
PLL_BASE EQU 0xE01FC080 ; PLL Base Address
; 用偏移量的方法定義其他寄存器
PLLCON_OFS EQU 0x00 ; PLL Control Offset ;控制寄存器,寫入該寄存器的值在饋送序列執行前不起作用
PLLCFG_OFS EQU 0x04 ; PLL Configuration Offset ;配置寄存器,屬性同上
PLLSTAT_OFS EQU 0x08 ; PLL Status Offset ;狀態寄存器,讀取狀態
PLLFEED_OFS EQU 0x0C ; PLL Feed Offset ;饋送寄存器,使能裝載PLL控制和配置信息
PLLCON_PLLE EQU (1<<0) ; PLL Enable ;PLL使能,寫入到配置寄存器的第0位,
; 初始爲0,表示沒有激活
PLLCON_PLLC EQU (1<<1) ; PLL Connect ;PLL連接使能位 ,寫入到配置寄存器的第1位,當PLLC和
; PLLE都爲1,且在有效的PLLE饋送後,將PLLE作爲時鐘源接
; 入Core,否則Core直接使用振盪器時鐘。
PLLCFG_MSEL EQU (0x1F<<0) ; PLL Multiplier ;PLL 倍頻因子
PLLCFG_PSEL EQU (0x03<<5) ; PLL Divider ;PLLE 分頻因子
PLLSTAT_PLOCK EQU (1<<10) ; PLL Lock Status ;PLL鎖定狀態位,應該是從PLLSTAT寄存器的第10位讀取數值
; 然後與 PLLSTAT_PLOCK 相比較,相同則爲PLL鎖定狀態。
PLL_SETUP EQU 1
PLLCFG_Val EQU 0x00000024 ;表示向CFG配置寄存器寫入的值爲0 01 00100,跟系統所需的頻率有關。
;LPC2119的主頻最高是60MHz,振盪器的主頻是10MHz
;分頻值爲1,倍頻值爲4,所以主頻爲40Mhz。
;-------------------------------------------------------------------------------------
; 存儲器加速模塊
;
;-------------------------------------------------------------------------------------
; Memory Accelerator Module (MAM) definitions
MAM_BASE EQU 0xE01FC000 ; MAM Base Address
MAMCR_OFS EQU 0x00 ; MAM Control Offset
MAMTIM_OFS EQU 0x04 ; MAM Timing Offset
MAM_SETUP EQU 1
MAMCR_Val EQU 0x00000002
MAMTIM_Val EQU 0x00000004
;---------------------------------------------------------------------------
; 外部存儲器擴展
;
;---------------------------------------------------------------------------
; External Memory Controller (EMC) definitions
EMC_BASE EQU 0xFFE00000 ; EMC Base Address
BCFG0_OFS EQU 0x00 ; BCFG0 Offset
BCFG1_OFS EQU 0x04 ; BCFG1 Offset
BCFG2_OFS EQU 0x08 ; BCFG2 Offset
BCFG3_OFS EQU 0x0C ; BCFG3 Offset
;// <e> External Memory Controller (EMC)
EMC_SETUP EQU 0
BCFG0_SETUP EQU 0
BCFG0_Val EQU 0x0000FBEF
BCFG1_SETUP EQU 0
BCFG1_Val EQU 0x0000FBEF
BCFG2_SETUP EQU 0
BCFG2_Val EQU 0x0000FBEF
BCFG3_SETUP EQU 0
BCFG3_Val EQU 0x0000FBEF
;// </e> End of EMC
; External Memory Pins definitions
PINSEL2 EQU 0xE002C014 ; PINSEL2 Address
PINSEL2_Val EQU 0x0E6149E4 ; CS0..3, OE, WE, BLS0..3,
; D0..31, A2..23, JTAG Pins
PRESERVE8 ;彙編僞指令,堆棧8字節對準
;-------------------------------------------------------------------------------
; 前面都是對寄存器位置的聲明,以下是具體代碼。定義了一個代碼段
;
;-------------------------------------------------------------------------------
;
; Area Definition and Entry Point
; Startup Code must be linked first at Address at which it expects to run.
;定義個名爲RESET的代碼段
AREA RESET, CODE, READONLY
ARM
; 中斷向量表的異常入口共8條語句32字節,在鏈接的時候保證在0地址處
Vectors LDR PC, Reset_Addr ;將Reset_Addr加載到PC中,程序就跳到reset_addr所指位置。
LDR PC, Undef_Addr
LDR PC, SWI_Addr
LDR PC, PAbt_Addr
LDR PC, DAbt_Addr
NOP ; Reserved Vector
; LDR PC, IRQ_Addr
LDR PC, [PC, #-0x0FF0] ; Vector from VicVectAddr
LDR PC, FIQ_Addr
Reset_Addr DCD Reset_Handler ;分配一段字內存單元給程序段Reset_Handler
Undef_Addr DCD Undef_Handler
SWI_Addr DCD SWI_Handler
PAbt_Addr DCD PAbt_Handler
DAbt_Addr DCD DAbt_Handler
DCD 0 ; Reserved Address
IRQ_Addr DCD IRQ_Handler
FIQ_Addr DCD FIQ_Handler
;
Undef_Handler B Undef_Handler
SWI_Handler B SWI_Handler
PAbt_Handler B PAbt_Handler
DAbt_Handler B DAbt_Handler
IRQ_Handler B IRQ_Handler
FIQ_Handler B FIQ_Handler
;-----------------------------------------------------------------------------------
;
;
;-----------------------------------------------------------------------------------
; Reset Handler
EXPORT Reset_Handler
Reset_Handler
;設置擴展存儲的引腳
; Setup External Memory Pins
IF :DEF:EXTERNAL_MODE ;判斷 EXTERNAL_MODE 是否定義,如果定義了就設置響應的管腳。見某論壇上的一個人問,外部存儲器設置了但是不能工作,就是這裏的 EXTERNAL_MODE 沒有被定義導致擴展 存儲的引腳的代碼沒有被編譯所以沒有被初始化,EXTERNAL_MODE EQU 1,應該就可以了 ,還沒測試。
LDR R0, =PINSEL2
LDR R1, =PINSEL2_Val ;前面 PINSEL2_Val 被初始化爲0x0E6149E4,完成一系列管腳的初始化
STR R1, [R0]
ENDIF
;設置擴展存儲器的控制寄存器,分別檢測幾個bank是否存在,分別進行設置
; Setup External Memory Controller
IF EMC_SETUP <> 0
LDR R0, =EMC_BASE
IF BCFG0_SETUP <> 0
LDR R1, =BCFG0_Val
STR R1, [R0, #BCFG0_OFS]
ENDIF
IF BCFG1_SETUP <> 0
LDR R1, =BCFG1_Val
STR R1, [R0, #BCFG1_OFS]
ENDIF
IF BCFG2_SETUP <> 0
LDR R1, =BCFG2_Val
STR R1, [R0, #BCFG2_OFS]
ENDIF
IF BCFG3_SETUP <> 0
LDR R1, =BCFG3_Val
STR R1, [R0, #BCFG3_OFS]
ENDIF
ENDIF ; EMC_SETUP
;設置VPB總線的分頻因子,這裏分頻因子被設置爲0
; Setup VPBDIV
IF VPBDIV_SETUP <> 0
LDR R0, =VPBDIV
LDR R1, =VPBDIV_Val
STR R1, [R0]
ENDIF
;設置鎖相環
; Setup PLL
IF PLL_SETUP <> 0
LDR R0, =PLL_BASE
MOV R1, #0xAA
MOV R2, #0x55
; Configure and Enable PLL
MOV R3, #PLLCFG_Val
STR R3, [R0, #PLLCFG_OFS] ;PLLCFG_Val = 0x00000024
MOV R3, #PLLCON_PLLE ;R3 = 1
STR R3, [R0, #PLLCON_OFS] ; PLLCON = 1,PLL 使能
STR R1, [R0, #PLLFEED_OFS] ; 寫 饋送寄存器命令序列一次是10101010一次01010101,0xAA,0x55。規定的。
STR R2, [R0, #PLLFEED_OFS]
;等待PLL穩定
; Wait until PLL Locked
PLL_Loop LDR R3, [R0, #PLLSTAT_OFS] ;將狀態寄存器裝載到R3中
ANDS R3, R3, #PLLSTAT_PLOCK ;PLLSTAT_OFS 與1<<10 進行與且影響 CPSR 的Z位,
BEQ PLL_Loop ;Z位爲1 跳到PLL_Loop
; Switch to PLL Clock
MOV R3, #(PLLCON_PLLE:OR:PLLCON_PLLC)
STR R3, [R0, #PLLCON_OFS]
STR R1, [R0, #PLLFEED_OFS]
STR R2, [R0, #PLLFEED_OFS]
ENDIF ; PLL_SETUP
;-----------------------------------------------------------------------------
; 存儲器加速模塊
; Setup MAM
IF MAM_SETUP <> 0
LDR R0, =MAM_BASE
MOV R1, #MAMTIM_Val
STR R1, [R0, #MAMTIM_OFS]
MOV R1, #MAMCR_Val
STR R1, [R0, #MAMCR_OFS]
ENDIF ; MAM_SETUP
;--------------------------------------------------------------------------
;內存映射,結構有點複雜額,總之就是根據不同的情況去設置存儲器映射控制寄存器,
; 00 Boot裝載,中斷向量從BootBlock重新映射
; 01 用戶FLASH模式,中斷向量不重新映射,就在FLASH裏面
; 10 用戶RAM模式,中斷向量從靜態RAM重新映射
; 11 用戶外部存儲器模式,中斷向量從外部存儲器重新映射。
; Memory Mapping (when Interrupt Vectors are in RAM)
;----------------------------------------------------------------------------
MEMMAP EQU 0xE01FC040 ; Memory Mapping Control ;
IF :DEF:REMAP
LDR R0, =MEMMAP
IF :DEF:EXTMEM_MODE ;判斷是不是擴展模式 是就往R1裏寫3
MOV R1, #3
ELIF :DEF:RAM_MODE ;如果是RAM中,往R1裏寫2
MOV R1, #2
ELSE
MOV R1, #1 ;否則R1裏寫1,唉彙編的編譯判斷真夠煩的。
ENDIF
STR R1, [R0] ;寫到MEMMAP寄存器。
ENDIF
; Initialise Interrupt System
; ...
;爲處理器的每種處理模式初始化棧空間
; Setup Stack for each mode
LDR R0, =Stack_Top
; Enter Undefined Instruction Mode and set its Stack Pointer
MSR CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit ;CPSR_c = 0x1B|0x80|0x40 = 意思爲禁止IRQ和FIQ,ARM狀態,處理
器進入了未定義模式
MOV SP, R0 ;棧指針指向了Stack_Top
SUB R0, R0, #UND_Stack_Size ;Stack_Top = Stack_Top - ABT_Stack_Size
; Enter Abort Mode and set its Stack Pointer
MSR CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #ABT_Stack_Size
; Enter FIQ Mode and set its Stack Pointer
MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #FIQ_Stack_Size
; Enter IRQ Mode and set its Stack Pointer
MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #IRQ_Stack_Size
; Enter Supervisor Mode and set its Stack Pointer
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
IF :DEF:__MICROLIB ;支持 MICROLIB庫,如果C程序的運行庫是MICROLIB 則將__initial_sp 導出
EXPORT __initial_sp
ELSE
MOV SP, R0
SUB SL, SP, #USR_Stack_Size
ENDIF
;進入C代碼的執行,爲C代碼的執行創造一個運行環境
; Enter the C code
IMPORT __main ;導入外部符號
LDR R0, =__main ;將main的地址加載到r0中
BX R0 ;帶狀態的跳到main 去執行
IF :DEF:__MICROLIB ;還是有關使用MICROLIB庫的,如果使用了該庫就要導出下面連個符號。
EXPORT __heap_base
EXPORT __heap_limit
ELSE
; User Initial Stack & Heap
AREA |.text|, CODE, READONLY
IMPORT __use_two_region_memory
EXPORT __user_initial_stackheap
__user_initial_stackheap
LDR R0, = Heap_Mem
LDR R1, =(Stack_Mem + USR_Stack_Size)
LDR R2, = (Heap_Mem + Heap_Size)
LDR R3, = Stack_Mem
BX LR
ENDIF
END
一直對底層的東西不太懂,總是朦朦朧朧的感覺,索性拿啓動代碼看一下吧,指望着能學一下彙編。週末的學習效率是在太低了,一個小小的啓動文件竟然費了兩天功夫。費了牛勁了看是看完了,還是有好多地方一頭霧水。因爲認識的深度有限,錯誤的地方肯定少不了,所以還請您校正。