|
啟動代碼是幾乎是每個arm程序程序必備的,剛開始看的時候看別人的啟動代碼時感覺云里霧里,所以懶惰的想法浮現腦中:別人都寫好了我還寫什么,直接拿來用不就行了,對在我懂得情況下,我一定會拿來就用,但是現在我還不懂,一切就要從頭開始,經過幾天的努力,現在的感覺是啟動代碼不過如此 :) ,呵呵。
;---------------------------------------------------------------------
;startup.s
;系統啟動代碼
;起始時間 : 2009.5.7 ----->2009.5.11
;---------------------------------------------------------------------
;---------------------------------------------------------------------
GET ./Include/s3c2440.inc ;寄存器地址信息
GET ./Include/memcfg.inc ;內存控制器配置信息
;處理器模式
USERMODE EQU 0x10
FIQMODE EQU 0x11
IRQMODE EQU 0x12
SVCMODE EQU 0x13
ABORTMODE EQU 0x17
UNDEFMODE EQU 0x1b
SYSMODE EQU 0x1f
;相關掩碼
MODEMASK EQU 0x1f
NOINT EQU 0xc0
;各個處理器模式下堆棧設置
_STACK_BASEADDRESS EQU 0x33ff8000 ;BANK6 64MB頂部
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 ~
;導入操作系統入口函數
IMPORT OSEntry
;導入外部C語言編寫的異常與中斷處理函數
IMPORT vectorUNDEF
IMPORT vectorSWI
IMPORT vectorPABT
IMPORT vectorDABT
IMPORT vectorIRQ
IMPORT vectorFIQ
;導入鏡像裝載域段起始地址
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
IMPORT |Image$$ZI$$Limit| ; to zero initialise
;--------------------------------------------------------------------
;------------------------------------------------------
AREA startup, CODE, READONLY
ENTRY
;系統向量表
b vectorRESET ;復位向量
b vectorUNDEF ;未定義指令
b vectorSWI ;軟中斷
b vectorPABT ;預取指終止
b vectorDABT ;數據終止
b . ;系統保留
b vectorIRQ ;外部中斷
b vectorFIQ ;快速中斷
;-------------------------------------------------------
;--------------------------------------------------------------------------
;復位向量
;復位向量是ARM處理器上電后第一個被執行的異常
;此時系統處理管理(SVC)模式
vectorRESET
;復位向量有以下六件事要做
;第一步 : 關閉看門狗定時器屏蔽所有中斷
;第二步 : 配置系統時鐘
;第三步 : 配置內存控制器
;第四步 : 配置每種處理器模式下堆棧指針
;第五步 : 初始化鏡像運行域
;第六步 : 跳轉到操作系統入口
;------------------------------------------
;第一步 : 關閉看門狗定時器
;具體內容請參看s3c2440a數據手冊的第18章
ldr r0, =WTCON
ldr r1, =0x0
str r1, [r0, #0x0]
;屏蔽所有中斷
ldr r0, =INTMSK
ldr r1, =0xffffffff
str r1, [r0]
;------------------------------------------
;------------------------------------------
;第二步 : 配置系統時鐘
;具體內容請看手冊第7章
;先減少鎖相環鎖定時間,s3c2440a要求PLL
;鎖定時間>300us,在上電時s3c2440a預設值
;mpll為晶體頻率,我用的晶體頻率為12MHz
;300us*12M = 3600設置LOCKTIME = 0xfff
;足夠了
ldr r0, =LOCKTIME
ldr r1, =0xfff0fff0 ;高16為對應UPLL
;低16為對應MPLL
str r1, [r0, #0x0]
;根據器件手冊我們還有以下幾個事要做
;step1.配置UPLL
;step2.配置MPLL
;注:手冊要求先配置UPLL后MPLL
; 且之間要間隔7NOP
; 詳請看手冊第7-21.
;step3.配置分頻系數
;step1:
ldr r0, =UPLLCON
ldr r1, =((56<<12) + (2<<4) + 2)
ldr r1, [r0]
;按手冊要求插入7個NOP
nop
nop
nop
nop
nop
nop
nop
;step2:
ldr r0, =MPLLCON
ldr r1, =((127<<12) + (2<<4) + 1)
ldr r1, [r0]
;step3:
ldr r0, =CLKDIVN
ldr r1, =((0<<3) + (2 << 2) + 1)
ldr r1, [r0]
;------------------------------------------
;------------------------------------------
;第三步 : 配置內存控制器
;內存控制內的寄存器器地址是連續分布的
;從0x4800_0000 -- 0x4800_0030,所以可以
;通過一個循環依次填入各個寄存器的內容
ldr r0, =SMRDATA ;裝入配置值的地址
ldr r1, =BWSCON ;裝入起始寄存器地址
add r2, r0, #0x34 ;計算結束地址
;下面是用于向內存控制器
;裝入配置信息的循環
0
ldr r3, [r0], #4 ;裝入配置值到r3,后變址
str r3, [r1], #4 ;把r3內包含的配置值寫入
;內存控制器的寄存器
cmp r2, r0 ;結束否?
bne %B0 ;沒結束則繼續
;------------------------------------------
;------------------------------------------
;第四步 : 配置每種處理器模式下堆棧指針
;方法與原則:
;1: 通過CPSR寄存器切換處理器模式
;2: 對CPSR的操作方式為 讀-修改-寫回
;3: 絕對不要跳到用戶模式,跳過去容易
; 回來就難了
;4: 切到新處理器模式后要屏蔽IRQ和FIQ
; 防止在未設置好堆棧前進入中斷處理
; 程序,但是在啟動代碼的最先我們已
; 經屏蔽了所有的32個中斷源,所以感
; 覺是否屏蔽都可以
;step1: 先把程序狀態寄存器讀到r0
mrs r0, cpsr
;step2: 清除處理器模式位(最前面5位)
bic r0, r0, #MODEMASK
;step3: 設置未定義狀態下的堆棧指針
orr r1, r0, #UNDEFMODE|NOINT
msr cpsr_cxsf, r1 ;UndefMode
ldr sp, =UndefStack ;UndefStack=0x33FF_5C00
;step4: 設置終止狀態下的堆棧指針
orr r1, r0, #ABORTMODE|NOINT
msr cpsr_cxsf, r1 ;AbortMode
ldr sp, =AbortStack ;AbortStack=0x33FF_6000
;step5: 設置中斷模式下的堆棧指針
orr r1, r0, #IRQMODE|NOINT
msr cpsr_cxsf, r1 ;IRQMode
ldr sp, =IRQStack ;IRQStack=0x33FF_7000
;step6: 設置快速中斷模式下的堆棧指針
orr r1, r0, #FIQMODE|NOINT
msr cpsr_cxsf, r1 ;FIQMode
ldr sp, =FIQStack ;FIQStack=0x33FF_8000
;step7: 設置管理模式下的堆棧指針
orr r1, r0, #SVCMODE|NOINT
msr cpsr_cxsf, r1 ;SVCMode
ldr sp, =SVCStack ;SVCStack=0x33FF_5800
;step8: 因為管理模式與用戶模式共用
; 堆棧指針,所以借著系統模式
; 來設置用戶模式的堆棧指針
orr r1, r0, #SYSMODE|NOINT
msr cpsr_cxsf, r1 ;SYSMode
ldr sp, =UserStack ;SVCStack & USERMode=0x33ff4800
;現在處理器處于系統模式
;------------------------------------------
;------------------------------------------
;第五步 : 初始化鏡像運行域
;復制RW段和ZI段到SDRAM指定地址
LDR r0, =|Image$$RO$$Limit| ; 裝入RO段結束地址
LDR r1, =|Image$$RW$$Base| ; 裝入RW段起始地址
LDR r3, =|Image$$ZI$$Base| ; 裝入ZI段起始地址
;|Image$$RO$$Limit| == |Image$$RW$$Base| ? 跳過RW段復制 : 復制RW段
CMP r0, r1
BEQ %F2
;復制RW段
1
CMP r1, r3
LDRCC r2, [r0], #4
STRCC r2, [r1], #4
BCC %B1
2
LDR r1, =|Image$$ZI$$Limit|
MOV r2, #0
;構造ZI段
3
CMP r3, r1
STRCC r2, [r3], #4
BCC %B3
;------------------------------------------
;------------------------------------------
;第六步 : 跳轉到操作系統入口
b OSEntry ;不要使用main,因為如果使用main
;ads還會調用_main()初始化RW和ZI
;段,但是那里的數據和本程序不同
b .
;------------------------------------------
;---------------------------------------------------------------------------
SMRDATA DATA
;這里是內存控制器的配置數據
;配置數據需要根據你使用的存儲器修改
;在第三步時會將以下數據寫入
;內存控制器的相關寄存器中
;共13個寄存器的配置值
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)+(Trc<<18)+(Tchr<<16)+REFCNT)
DCD 0x32 ;SCLK power saving mode, BANKSIZE 128M/128M
DCD 0x30 ;MRSR6 CL=3clk
DCD 0x30 ;MRSR7 CL=3clk
ALIGN ;數據邊界對齊
END
我在寫一個arm920T的微型OS,主要是想借著寫OS的過程學習ARM的底層編程,然后跳到Linux。啟動代碼是固件的一部分,最經學校要搞個設計,不知OS什么時候能寫好,反正搞定后立即發帖。
下邊是完整的工程
運行平臺:mini2440
51heiarm5845.rar
(61.48 KB, 下載次數: 22)
2015-4-5 17:55 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
大家好像都對地址,裝載很感興趣,我來嘮嘮:)
我認為之所以要指定鏡像的各段的起始位置是因為程序中的標號,函數,變量的位置是在編譯時根據鏡像運行時(注意)計算出來的,所以鏡像的各段的位置設置在哪里就一定要把鏡像的各段放在那里,否者程序就會由于地址對不上而跑飛。
但是究竟位置應該設定在哪呢 ?
主要有兩種情況:
1。 程序放在Nor里
程序的代碼段可知放在Nor里運行,為什么?想想看,你的程序應該不會在運行時動態改變程序的指令吧,也就意味著只會讀Nor,cpu(在有內存控制器的時候)讀Nor和讀RAM除了速度慢其他的沒什么區別。
但是對于RW ZI 不只有讀還有寫,應為沒法向寫RAM一樣的寫Nor,所以RW ZI 一定要放到 RAM里(不管是SRAM還是DRAM),只有在那里程序才能寫RW ZI
如何裝載?
編譯好的鏡像處于一種“壓縮”的狀態。這么壓縮的? 比如鏡像運行時 RO從0x0 - 0x10 RW從Ox3000_0000 - 0x3000_0004 ZI 0x3000_0008 - 0x3000_000C 如果直接原樣鏡像,鏡像文件肯定會有很大空隙,且ZI全是零完全沒必要鏡像下來,只要記住起始 結束地址就行了。所以鏡像文件在運行前RO RW ZI 是連載一起的,且RO在最前邊
所以就以上分析裝載分兩大步
step1:由bootloader完成
(1).bootloader直接把整個鏡像copy到RAM里,從哪讀鏡像無所謂,ROM,uart,usb,SD卡,以太,甚至是無線都可以,但是目的位置一定是RO$$Base
(2).然后PC = Ro$$Base
step2:由鏡像自己干
上邊過后由于Ro段在鏡像的最前邊且RO的起始位置正好就在Ro$$base所以鏡像Ro順利運行,但是RW ZI還不一定在正確位置上,所以有了啟動代碼的第五步
2. 程序在Nand上
這是的區別就是與nor相比想直接讀nand都難了,所以這是要想讓程序順利運行就必須把Ro段也搬到RAM里,這時要有兩個東西,一個小程序 《4k 在NAND最前邊,負責裝載,就是bootloader。把正真想完成任務的程序放在后邊,上電時小程序最先被自動copy到sram,sram是定位在0x0的,所以bootloader 的 Ro起始地址必須設置在0x0,然后bootloader就和上邊的沒什么區別了,先把nand里的大程序整個copy到DRAM,然后大程序執行把自己的RW ZI copy 到正確位置,所以大程序的RO$$Base可以是DRAM的地址。
“這個B后面要是跳到MAIN話,ADS會根據
|Image$$RO$$Limit|
|Image$$RW$$Base|
算出你程序的代碼段地址(也就是程序的運行段)和讀寫段地址(也就是已初始的變量段) "
我覺得bootloader完全沒必要分析鏡像,只要直接copy就行了,只要鏡像自己保證自己的Ro在最前邊就行了,這是編譯器的事,后邊的RW zi 鏡像自己就搞定了。
”說白一點,如果你想把程序在FLASH里面運行,這時要把|Image$$RO$$Limit|設為0X00000000(FLASH地址),
|Image$$RW$$Base| 設為0X0C000000(RAM地址) “
這個|Image$$RO$$Limit| =0x0 那Base在哪?沒看見ADS可以設置Limit啊.
"想用UBOOT引導后在RAM運行,這時要把|Image$$RO$$Limit|設為0X0C000000(RAM地址),
|Image$$RW$$Base| 設為0X0C000000(RAM地址)”
在ads里如果只設置 ro$$base 那后邊的段是接起來的
請看

我想自己設置肯定可以,如果開MMU的話具體放在哪應該還是要仔細考慮的。
|
|