久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 14626|回復: 1
打印 上一主題 下一主題
收起左側

幾乎是每個arm程序程序必備的啟動代碼

[復制鏈接]
跳轉到指定樓層
樓主
ID:76190 發表于 2015-4-5 17:56 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
啟動代碼是幾乎是每個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)



大家好像都對地址,裝載很感興趣,我來嘮嘮:)

我認為之所以要指定鏡像的各段的起始位置是因為程序中的標號,函數,變量的位置是在編譯時根據鏡像運行時(注意)計算出來的,所以鏡像的各段的位置設置在哪里就一定要把鏡像的各段放在那里,否者程序就會由于地址對不上而跑飛。

但是究竟位置應該設定在哪呢 ?

主要有兩種情況:

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的話具體放在哪應該還是要仔細考慮的。




分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏3 分享淘帖 頂 踩
回復

使用道具 舉報

沙發
ID:87961 發表于 2015-8-9 06:55 | 只看該作者
作為入門者,還是值得學習的
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: av在线免费网 | 亚洲精品1区 | 视频一区二区三区中文字幕 | 中文字幕日韩欧美一区二区三区 | 亚洲品质自拍视频网站 | 国产精品1区2区 | 欧美一区二区三区在线观看 | 精品欧美一区免费观看α√ | 亚洲欧美日韩久久久 | 精品久久久久一区 | 人人干天天干 | 老司机精品福利视频 | 久久久亚洲综合 | 韩日有码 | 在线视频中文字幕 | 久久久精品一区二区 | 欧美色综合一区二区三区 | 国产精品美女久久久久久久久久久 | 久在线视频播放免费视频 | 在线看成人av | 国产 日韩 欧美 中文 在线播放 | 久久久影院 | 亚洲精品一区二区 | 99精品国产在热久久 | 久久久久久久香蕉 | 国产这里只有精品 | 99精品99久久久久久宅男 | 少妇精品亚洲一区二区成人 | 国产成人精品一区二区三区 | 亚洲国产欧美一区二区三区久久 | www国产亚洲精品久久网站 | 91国内精品| 成人超碰 | 91精品国产一区二区三区 | 超碰成人在线观看 | 亚洲视频在线观看 | 伊人网站 | 国产精品美女久久久久久久网站 | 国产极品粉嫩美女呻吟在线看人 | 欧美精品网站 | 亚洲一区 中文字幕 |