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

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > 分析ARM啟動代碼和中斷處理過程

          分析ARM啟動代碼和中斷處理過程

          作者: 時間:2016-11-25 來源:網(wǎng)絡(luò) 收藏
          之前有分析過44b0下的這個啟動代碼,差別不是非常大,今天再重新看了一遍。啟動代碼與 Bootloader不同,主要是指進入C語言之前的匯編代碼,網(wǎng)上都稱為是bootloader的stage1,一般通用的內(nèi)容包括:
          1. 定義程序入口點
          2. 設(shè)置異常向量表
          3. 初始化存儲系統(tǒng)
          4. 初始化用戶程序的執(zhí)行環(huán)境
          5. 初始化堆棧指針寄存器,改變處理器的模式
          6. 設(shè)置FIQ/IRQ中斷處理程序入口
          7. 進入C程序

          1)編譯器選擇
          GBLL THUMBCODE
          [ {CONFIG} = 16
          THUMBCODE SETL {TRUE}
          CODE32
          |
          THUMBCODE SETL {FALSE}
          ]
          因為處理器分為16位 32位兩種工作狀態(tài),程序的編譯器也是分16位和32兩種編譯方式,所以這段程序用于根據(jù)處理器工作狀態(tài)確定編譯器編譯方式,程序不難理解,主要解釋一下 符號“[ | ]”的意思,上面的程序是指:
          if({CONFIG} = 16 )
          { THUMBCODE SETL {TRUE}
          CODE32 }
          else
          THUMBCODE SETL {FALSE}
          還 是沒有不明白CONFIG怎么區(qū)分是16位還是32位?哪里決定它的取值?應(yīng)該是編譯器指定的這個值。

          2)宏定義
          MACRO
          $HandlerLabel HANDLER $HandleLabel
          $HandlerLabel
          sub sp,sp,#4
          stmfd sp!,{r0}
          ldr r0,=$HandleLabel
          ldr r0,[r0]
          str r0,[sp,#4]
          ldmfd sp!,{r0,pc}
          MEND
          $HandlerLabel是宏的地址標 號,HANDLER是宏名,$HandleLabel是宏的參數(shù),$標號在宏指令展開時,標號會替換為用戶定義的符號。在此后,所有遇 到$HandlerLabel HANDLER $HandleLabel這種形式的表達式都會被展開成$HandlerLabel到MEND之間的函數(shù)。
          例如:ADC_IRQ HANDLER HandleADC即代表如下函數(shù),語句ldr pc,=ADC_IRQ的作用也就是跳轉(zhuǎn)到這個函數(shù):
          ADC_IRQ
          sub sp,sp,#4
          stmfd sp!,{r0}
          ldr r0,=HandleADC
          ldr r0,[r0]
          str r0,[sp,#4]
          ldmfd sp!,{r0,pc}
          這段程序用于把ADC中斷服務(wù)程序的首地址裝載到pc中,跳轉(zhuǎn)到中斷處理函數(shù),稱之為 “加載程序”。HandleADC是一個地址標號,它的內(nèi)容就是ADC中斷服務(wù)程序的地址標號,即文件最后的那個表HandleADC # 4所示,將HandleADC # 4中的4換成中斷服務(wù)程序的地址標號即是,程序在這里定義了一個數(shù)據(jù)區(qū),存放各種中斷服務(wù)程序的首地址。每個字空間都有一個標號,以Handle***命 名。

          3)寄存器及堆棧設(shè)置
          按照上面的順序,可以比較容易讀懂啟動代碼的作用,主要就是通過設(shè)置特殊功能寄存器來達到對系統(tǒng)參數(shù)的 設(shè)定。依次禁止看門狗,中斷,設(shè)定時鐘控制寄存器,存儲器控制寄存器等等。
          由于各個工作模式下的堆棧指針是相互獨立的,所以要分別進入各個模式下 設(shè)置其堆棧指針,基本上都差不多,比如未定義指令模式下的設(shè)置:
          mrs r0,cpsr
          bic r0,r0,#MODEMASK
          orr r1,r0,#UNDEFMODE|NOINT
          msr cpsr_cxsf,r1
          ldr sp,=UndefStack
          UnderStack是在程序后面用UnderStack # 256建立的一個堆棧空間的首地址,這部分空間建立在RAM中,256字節(jié)空間的堆棧大小。

          4)初始化用戶程序的執(zhí)行環(huán)境
          之前在 44B0里的啟動代碼里還有包括把ROM里的程序拷貝到RAM中并跳轉(zhuǎn)到RAM運行程序,也就是把加載狀態(tài)下的程序按照編譯連接時的設(shè)置重新排布成運行時 的程序狀態(tài),以達到符號能夠正確連接的目的,這里是涉及到了所謂的映像文件,但是2410這里沒有這一段,即程序的加載態(tài)就是它的運行態(tài),所以要求燒寫程 序時必須要把它燒寫在設(shè)置的RO地址上,否則程序?qū)⒉荒苷_執(zhí)行。下面這段程序?qū)崿F(xiàn)RW數(shù)據(jù)初始化,只是把數(shù)據(jù)段復(fù)制到高地址,如果沒有設(shè)置RW的話這段 代碼也不會執(zhí)行。
          ;Copy and paste RW data/zero initialized data
          ldr r0, =|Image$$RO$$Limit| ; Get pointer to ROM data
          ldr r1, =|Image$$RW$$Base| ; and RAM copy
          ldr r3, =|Image$$ZI$$Base|

          ;Zero init base => top of initialised data
          cmp r0, r1 ; Check that they are different
          beq %F2
          1
          cmp r1, r3
          ldrcc r2, [r0], #4
          strcc r2, [r1], #4
          bcc %B1
          2
          ldr r1, =|Image$$ZI$$Limit|
          mov r2, #0
          3
          cmp r3, r1 ; Zero init
          strcc r2, [r3], #4
          bcc %B3
          b %F1(B1)的意思是在臨近的地址標號跳轉(zhuǎn),F(xiàn)是向后尋找,B是向前尋找。

          5) 說說映象文件
          用ADS編譯產(chǎn)生的映像文件有.axf、.bin、.hex等等格式,就拿要直接燒進Flash里的.bin文件來說,在其他書上看 到有這么句話“映像文件一般由域組成,域由最多三個輸出段(RO,RW,ZI)組成,輸出段又由輸入段組成。”
          對于這段話,前兩句是比較好理解 的,域就是整個映像文件,對于大部分程序來說就只有一個域,也就是燒進Flash里的那部分東東,稱作加載域;輸出段就是用AREA定義的RO,Rw,一 般就這兩個,拿前面的bootloader來說,整體框架是這樣的:
          AREA Init,CODE,READONLY ;<--RO段
          ENTRY
          Entry ;<--CODE部分

          … …

          SMRDATA DATA ;<--DATA部分

          … …

          AREA RamData, DATA, READWRITE ;<--RW段

          … …

          然而對于 輸出段又由輸入段組成卻著實糊涂了好一陣,輸入段是指源程序的代碼(CODE)部分和數(shù)據(jù)(DATA)部分。上面這個框架中,在RO輸出段的Entry下 開始一系列的匯編指令操作,這個應(yīng)該是CODE輸入段,而SMRDATA DATA引領(lǐng)DCD用于開辟一片數(shù)據(jù)存儲空間,這部分應(yīng)該是DATA輸入段,它與RW里的數(shù)據(jù)不同之處在于這部分數(shù)據(jù)不能被修改。
          在ADS編譯前 在ARM-Linker里的Ro_Base和Rw_Base兩個地址值,就是指兩個輸出段的起始地址,即程序是按照你設(shè)置的這種方式排布在內(nèi)存中的,各個 地址標號根據(jù)這兩個值確定。然而,用Ultraedit打開bin文件卻發(fā)現(xiàn)其實Rw是跟在Ro后面的,也就是說,這兩個段并沒有按照你設(shè)置的地址起始, 由此引出映像文件的加載域和運行時域兩個概念。

          上一頁 1 2 下一頁

          關(guān)鍵詞: ARM啟動代碼中斷處

          評論


          技術(shù)專區(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); })();