<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁(yè) > 嵌入式系統(tǒng) > 學(xué)習(xí)方法與實(shí)踐 > arm開(kāi)發(fā)經(jīng)驗(yàn)筆記

          arm開(kāi)發(fā)經(jīng)驗(yàn)筆記

          ——
          作者: 時(shí)間:2007-11-29 來(lái)源:摘自網(wǎng)絡(luò)博客 收藏

              前一段時(shí)間做了的一些,主要是編寫(xiě)了的啟動(dòng)軟件和移植了uCOS-II到7。我做事情喜歡深入簡(jiǎn)出,及從最簡(jiǎn)單,最原理的方面先做一個(gè)框架,然后在這個(gè)框架里面進(jìn)行補(bǔ)充。我還是一個(gè)很喜歡和別人討論的人,希望有人可以給我提出意見(jiàn)和建議。我的這個(gè)心得很初級(jí),都是一些基本的東西?,F(xiàn)在拿出來(lái)和大家分享,希望在我畢業(yè)之前能給大家留一些紀(jì)念。^_^
              由于這些東西發(fā)paper實(shí)在是沒(méi)有價(jià)值,但是我感覺(jué)可以作為arm的入門(mén)。由于我的水平和經(jīng)驗(yàn)有限,錯(cuò)誤也是難免的。但是如果不拿出來(lái)和大家分享, 就算有錯(cuò)誤我也發(fā)現(xiàn)不了,是么?呵呵。我現(xiàn)試試發(fā)連載的第一篇,看看有多少價(jià)值,如果大家覺(jué)得有價(jià)值,我會(huì)繼續(xù)連載的。
          前言
              這個(gè)文檔是我學(xué)習(xí)ARM編程的總結(jié)和心得。閱讀這個(gè)文檔的人應(yīng)當(dāng)首先閱讀ADS1.2的幫助文檔及相關(guān)內(nèi)容。這個(gè)文檔不會(huì)對(duì)編譯器及連接器做出詳細(xì)的說(shuō)明, 在需要的時(shí)候會(huì)指出具體內(nèi)容在相關(guān)資料的章節(jié)。同時(shí)閱讀這個(gè)文檔的人需要了解ARM指令集和一些ARM匯編的基本內(nèi)容以及C和C++的相關(guān)編程內(nèi)容。同時(shí)還需要了解ARM的流水線(xiàn)結(jié)構(gòu)及一些基本的編程知識(shí)。同時(shí)為了方便查閱英文文檔,所有的相關(guān)術(shù)語(yǔ)都使用英文原文 
          第一章 STARTUP
          1 ARM的啟動(dòng)
          一般的系統(tǒng)在主程序執(zhí)行之前都需要執(zhí)行一些初始化的過(guò)程以創(chuàng)造程序運(yùn)行的環(huán)境,尤其是一些高級(jí)的系統(tǒng),由于核心芯片使用內(nèi)存映射、內(nèi)存保護(hù)等機(jī)制以及編程使用高級(jí)語(yǔ)言C,C++甚至JAVA語(yǔ)言,都需要先創(chuàng)建一個(gè)適合程序運(yùn)行的硬件環(huán)境,然后初始化或者配置或者剪裁run-time library, 這些工作都必須在主程序運(yùn)行前完成,所以一個(gè)startup程序或者程序組對(duì)于一個(gè)來(lái)說(shuō)是非常重要的。要編寫(xiě)startup程序,需要對(duì)編譯器、鏈接器和匯編器的細(xì)節(jié)有一定的了解,同時(shí)對(duì)ARM芯片硬件本身的地址分配以及memory mapping機(jī)制也需要有一些了解。

          2 ARM 程序的工作過(guò)程
              首先由各種source file經(jīng)過(guò)編譯產(chǎn)生object文件,然后object文件經(jīng)過(guò)鏈接生成Image文件,然后通過(guò)ICE的方法,根據(jù)描述文件的指定下載到目標(biāo)板上的固態(tài)存儲(chǔ)器指定地址當(dāng)中,比如flash,EEPROM, ROM等等。在程序執(zhí)行之前,根據(jù)某些描述文件,將需要讀寫(xiě)數(shù)據(jù)的部分讀出放入動(dòng)態(tài)存儲(chǔ)器比如RAM當(dāng)中,然后程序從ROM開(kāi)始執(zhí)行?;蛘哂袝r(shí)為了提高程序的運(yùn)行速度,也可以將所有的程序(有一些root的部分除外,以后會(huì)提及)通過(guò)一個(gè)描述文件放入指定的RAM當(dāng)中,然后程序從RAM開(kāi)始執(zhí)行,但是這樣會(huì)耗費(fèi)大量的動(dòng)態(tài)存儲(chǔ)器,所以大部分程序會(huì)取折中的方法,將需要快速運(yùn)行的部分和要讀寫(xiě)的部分放入RAM中(一般讀固態(tài)存儲(chǔ)器的過(guò)程和動(dòng)態(tài)存儲(chǔ)器的過(guò)程是一樣的,但是寫(xiě)就不同了,所以讀寫(xiě)的部分一定要放到RAM中),而只讀的部分和對(duì)速度要求不是那么高的部分放入固態(tài)存儲(chǔ)器。同時(shí)ARM結(jié)構(gòu)的異常向量表規(guī)定放在地址為0x00000000開(kāi)始的地址空間上,而一般的CPU為了提高異常相應(yīng)速度,會(huì)將這個(gè)向量段remap到其他的RAM當(dāng)中,所以在描述文件當(dāng)中必須精確指定異常向量跳轉(zhuǎn)程序的地址到remap的地方。在application程序執(zhí)行前,還需要由一些文件描述application程序執(zhí)行的環(huán)境。比如系統(tǒng)工作時(shí)鐘,總線(xiàn)頻率?,F(xiàn)在一般嵌入式編程語(yǔ)言為C,C++等。如果在使用它們的時(shí)候使用的runtime-library,那么在程序執(zhí)行前還需要為這些庫(kù)函數(shù)初始化heap。然后ARM可能工作在不同的模式,還需要為不同的工作模式設(shè)置stack。這樣,描述鏈接地址的文件,以及在 application運(yùn)行前所有的初始化程序就是startup程序組

          3 STARTUP分類(lèi)
          這樣,將startup程序所完成的功能分類(lèi)。一類(lèi)是鏈接地址描述,一類(lèi)是各種初始化的程序。根據(jù)不同的應(yīng)用,描述文件和初始化程序的內(nèi)容以及結(jié)構(gòu)和復(fù)雜程度都會(huì)不同。但是基本上,它們都必須實(shí)現(xiàn)以下功能。
          3.1 描述文件實(shí)現(xiàn)功能
          描述文件可以是鏈接命令行上簡(jiǎn)單的幾個(gè)字符,也可以是一個(gè)非常復(fù)雜的文件,但是它必須完成如下功能:
            指定程序下載的地址
            指定程序執(zhí)行的地址
          3.2 初始化程序?qū)崿F(xiàn)的功能
          初始化程序根據(jù)不同的應(yīng)用,其結(jié)構(gòu)和復(fù)雜度也不同,但是它必須完成如下基本功能:
            異常向量初始化
            內(nèi)存環(huán)境初始化
            其他硬件環(huán)境初始化

          4 描述文件
          要編寫(xiě)描述文件,必須知道ARM Image文件的組成及ARM Image文件執(zhí)行的機(jī)理。

          4.1 ARM Image的結(jié)構(gòu)
          一個(gè)ARM Image structure由linker在以下幾個(gè)方面定義:
            組成它的regions 和 output sections
            當(dāng)Image 下載的時(shí)候這些regions 和 sections 在內(nèi)存中的位置
            當(dāng)Image 執(zhí)行時(shí)這些regions和sections在內(nèi)存中的位置

          4.1.1 ARM Image的組成
          一個(gè)ARM Image被保存在可執(zhí)行文件當(dāng)中,它的層次結(jié)構(gòu)可以包括Image,regions,output sections和input sections。
             一個(gè)Image由一個(gè)或多個(gè)regions組成,每個(gè)region包括一個(gè)或多個(gè)output sections
             每個(gè)output section由一個(gè)或多個(gè)input sections組成
             Input sections是一個(gè)object file中的code和data信息。
          Image的結(jié)構(gòu)如下圖:

           
          NOTE Input section,output section和region的定義見(jiàn)ADS_LinkerGuide 3-3頁(yè)。
          同時(shí)Input section 有幾種屬性,分別為readonly,read-write,zero-initialized。分別稱(chēng)為RO,RW和ZI。屬性來(lái)源于A(yíng)REA后的attr屬性。
          比如CODE是RO,DATA是RW,NOINT默認(rèn)為ZI,即用0值初始化,但是可以選擇不進(jìn)行0值初始化。ZI屬性?xún)H僅來(lái)源于SPACE, DCB, DCD, DCDU, DCQ, DCQU, DCW, 或者DCWU。由以上定義,ZI屬性的包含于RW屬性,它是有初始值的RW數(shù)據(jù)。又例如在C語(yǔ)言中,代碼為RO,靜態(tài)變量和全局變量是RW,ZI的。

          4.1.2 Image 的Load view 和 execution view
          在下載的時(shí)候Image regions被放置在memory map當(dāng)中,而在執(zhí)行Image前,或許你需要將一些regions放置在它們執(zhí)行時(shí)的地址上,并建立起ZI regions。例如,你初始化的RW數(shù)據(jù)需要從它在下載時(shí)的在ROM中的地址處移動(dòng)到執(zhí)行時(shí)RAM的地址處。

            
          NOTE Load view 和execution view的詳細(xì)定義見(jiàn)ADS_LinkerGuide 3-4
          以上的描述包括二個(gè)內(nèi)容,一是要指定各個(gè)section在load view和execution view時(shí)的地址即memory map,二是要在執(zhí)行前根據(jù)這些地址進(jìn)行section的初始化。

          4.1.3 制定Memory map
          制定memory map的方法基本上有二種,一是在link時(shí)使用命令行選項(xiàng),并在程序執(zhí)行前利用linker pre-define symbol使用匯編語(yǔ)言制定section的段初始化,二是使用scatter file。以上二種方法依應(yīng)用程序的復(fù)雜度而定,一針對(duì)簡(jiǎn)單的情況,二針對(duì)復(fù)雜的情況。

          4.1.1.1 利用linker pre-define symbol使用匯編程序
          這是簡(jiǎn)單的方法,針對(duì)簡(jiǎn)單的memory map。在link時(shí)使用選項(xiàng)-ro, -rw, 等等指定memory map的地址。詳細(xì)說(shuō)明參看ADS_LinkerGuide中命令行選項(xiàng)說(shuō)明。然后利用匯編使用pre-define symbol,來(lái)進(jìn)行各種段的定位。Linker pre-define定義如下: 
            
           
          由前面對(duì)ZI的說(shuō)明,Image$$RW$$Limit = Image$$ZI$$Limit。
            


          這些都是linker預(yù)先定義的外部變量,在使用的時(shí)候可以用IMPORT引入。下面給出一個(gè)例子。
          假設(shè)linker 選項(xiàng)為:-ro-base 0x40000000 -rw-base 0x40003000。程序和只讀變量(const 變量)大小為0x84,這樣RO section的大小為0x84 bytes。Data的大小為0x04 bytes,并且data被初始化,則RW section的大小為0x04,ZI section的大小為0x04。這樣程序
          在load view,地址是這樣的:
          0x40000000開(kāi)始到地址0x40000080,是RO section部分(程序從0x40000000開(kāi)始),Image$$RO$$Limit = 0x40000084.
          0x40000084地址開(kāi)始到地址0x40000084,是RW section部分。

          在execution view,由linker的選項(xiàng),各個(gè)section的地址是這樣的:
          RO section的地址不變。
          RW section的起始地酚Φ蔽?x40003000,則Image$$RW$$Base = 0x40003000。
          因?yàn)槿康?x04 bytes data被初始化,所以Image$$RW$$Limit = Image$$ZI$$Limt = 0x40003004。
          現(xiàn)在要做的就是將RW section移到以0x40003000開(kāi)始的地方,并且創(chuàng)造一個(gè)ZI section。
          一個(gè)更通用的做法是:
          首先比較Image$$RO$$Limit和mage$$RW$$Base,如果相等,說(shuō)明execution view下RW section的地址和load view 下RW section的地址相同,這樣,不需要移動(dòng)RW section;如果不等,說(shuō)明需要移動(dòng)RW section 到它在execution view中的地方。然后將Image$$ZI$$Base地址到Image$$ZI$$Limt地址的內(nèi)容清零。
          示例代碼如下:
          ;讀入linker pre-define symbols

          IMPORT Image$$RO$$Limit
          IMPORT Image$$RW$$Base
          IMPORT Image$$ZI$$Base
          IMPORT Image$$ZI$$Limit

          ; .......一些其他的代碼或偽指令

          ;R0讀入section load address
          LDR R0,= Image$$RO$$Limit
          ;R1讀入section execution address
          LDR R1,= Image$$RW$$Base
          ;R2讀入execution section 后的緊跟的word address
          LDR R2,= Image$$ZI$$Base
          ;檢查RW section的地址在load view和execution view下
          ;是否相等,如果相等,就不移動(dòng)RW section,直接建立
          ;ZI scetion
          CMP R0,R1
          BEQ do_zi_init

          ;否則就copy RW section到execution view下指定的地址
          BL copy

          ; ......
          ; ......

          ;copy 是一個(gè)用于copy的子函數(shù),它把從R0中的地址開(kāi)始的
          ;section copy到R1中的地址開(kāi)始的section,這個(gè)section的
          ;上限地址后緊跟的word address保存在R2中
          copy
          CMP R1,R2
          LDRCC R3,[R0],#4
          STRCC R3,[R1],#4
          BCC copy
          MOV PC,LR

          ; ......
          ; ......
          ;do_zi_int子函數(shù)是為創(chuàng)建ZI section做一些準(zhǔn)備工作
          do_zi_int
          ;將ZI section開(kāi)始的地址裝入R1
          LDR R1,= Image$$ZI$$Base
          ;將ZI section結(jié)束后緊跟的word address裝入R2
          LDR R2,= Image$$ZI$$Limit
          ;將ZI section 需要的初始化量裝入R3
          MOV R3,#0
          BL zi_int

          ; ......
          ; ......
          ;zi_int子函數(shù)用于建立并初始化ZI section,ZI section的
          ;開(kāi)始地址儲(chǔ)存在R1,ZI section結(jié)束后緊跟的word address
          ;地址儲(chǔ)存在R2

          zi_int
          CMP R1,R2
          STRCC R3,[R1],#4
          BCC zi_int
          MOV PC,LR

          ; ......
          ; ......
          這個(gè)方法針對(duì)比較簡(jiǎn)單的應(yīng)用,如果需要進(jìn)行一個(gè)比較復(fù)雜的memory map,如下圖,那么這個(gè)方法就不適用了。為了解決復(fù)雜memory map的問(wèn)題
          需要用到scatter load 機(jī)制。 
            

           

          linux操作系統(tǒng)文章專(zhuān)題:linux操作系統(tǒng)詳解(linux不再難懂)


          評(píng)論


          相關(guān)推薦

          技術(shù)專(zhuān)區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();