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

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > arm匯編ldr,str,b,bl指令

          arm匯編ldr,str,b,bl指令

          作者: 時(shí)間:2016-11-09 來源:網(wǎng)絡(luò) 收藏
          B或BL指令引起處理器轉(zhuǎn)移到“子程序名”處開始執(zhí)行。兩者的不同之處在于BL指令在轉(zhuǎn)移到子程序執(zhí)行之前,將其下一條指令的地址拷貝到R14(LR,鏈 接寄存器)。由于BL指令保存了下條指令的地址,因此使用指令“MOV PC ,LR”即可實(shí)現(xiàn)子程序的返回。而B指令則無法實(shí)現(xiàn)子程序的返回,只能實(shí)現(xiàn)單純的跳轉(zhuǎn)。用戶在編程的時(shí)候,可根據(jù)具體應(yīng)用選用合適的子程序調(diào)用語句。

          &nbsp; AREA Init,CODE,READONLY

          本文引用地址:http://www.ex-cimer.com/article/201611/317898.htm

          ;該偽指令定義了一個(gè)代碼段,段名為Init,屬性只讀
          ENTRY ;程序的入口點(diǎn)標(biāo)識

          .

          .

          bl delay ;調(diào)用延遲

          .

          .

          mov pc,lr ;返回

          下面的在BLOG中看到覺得講得比較詳細(xì)就拷過來了

          ARM匯編指令的一些總結(jié)
          ARM匯編指令很多,但是真正常用的不是很多,而且需要認(rèn)真琢磨的又更少了。
          比較有用的是MOV B BL LDR STR
          還是通過具體匯編代碼來學(xué)習(xí)吧。
          @ disable watch dog timer
          mov r1, #0x53000000 //立即數(shù)尋址方式
          mov r2, #0x0
          str r2, [r1]
          立即數(shù)尋址方式,立即數(shù)要求以“#”作前綴,對于十六進(jìn)制的數(shù),還要求在#后面加上0x或者&。STR是比較重要的指令了,跟它對應(yīng)的是LDR。 ARM指令集是加載/存儲(chǔ)型的,也就是說它只處理在寄存器中的數(shù)據(jù)。那么對于系統(tǒng)存儲(chǔ)器的訪問就經(jīng)常用到STR和LDR了。STR是把寄存器上的數(shù)據(jù)傳輸 到指定地址的存儲(chǔ)器上。它的格式我個(gè)人認(rèn)為很特殊:
          STR(條件) 源寄存器,<存儲(chǔ)器地址>
          比如 STR R0, [R1] ,意思是R0-> [R1],它把源寄存器寫在前面,跟MOV、LDR都相反。
          LDR應(yīng)該是非常常見了。LDR就是把數(shù)據(jù)從存儲(chǔ)器傳輸?shù)郊拇嫫魃?。而且有個(gè)偽指令也是LDR,因此我有個(gè)百思不得其解的問題??催@段代碼:
          mov r1, #GPIO_CTL_BASE
          add r1, r1, #oGPIO_F
          ldr r2,=0x55aa // 0x55aa是個(gè)立即數(shù)啊,前面加個(gè)=干什么?
          對于當(dāng)中的ldr 那句,我就不明白了,如果你把=去掉,是不能通過編譯的。我查了一些資料,個(gè)人感覺知道了原因:這個(gè)=應(yīng)該表示LDR不是ARM指令,而是偽指令。作為偽指令的時(shí)候,LDR的格式如下:
          LDR 寄存器, =數(shù)字常量/Label
          它的作用是把一個(gè)32位的地址或者常量調(diào)入寄存器。嗬嗬,那大家可能會(huì)問,
          “MOV r2,#0x55aa”也可以啊。應(yīng)該是這樣的。不過,LDR是偽指令啊,也就是說編譯時(shí)編譯器會(huì)處理它的。怎么處理的呢?——規(guī)則如下:如果該數(shù)字常量 在MOV指令范圍內(nèi),匯編器會(huì)把這個(gè)指令作為MOV。如果不在MOV范圍中,匯編器把該常量放在程序后面,用LDR來讀取,PC和該常量的偏移量不能超過 4KB。
          然后說一下跳轉(zhuǎn)指令。ARM有兩種跳轉(zhuǎn)方式。
          (1) mov pc <跳轉(zhuǎn)地址〉
          這種向程序計(jì)數(shù)器PC直接寫跳轉(zhuǎn)地址,能在4GB連續(xù)空間內(nèi)任意跳轉(zhuǎn)。
          (2)通過 B BL BLX BX 可以完成在當(dāng)前指令向前或者向后32MB的地址空間的跳轉(zhuǎn)(為什么是32MB呢?寄存器是32位的,此時(shí)的值是24位有符號數(shù),所以32MB)。
          B是最簡單的跳轉(zhuǎn)指令。要注意的是,跳轉(zhuǎn)指令的實(shí)際值不是絕對地址,而是相對地址——是相對當(dāng)前PC值的一個(gè)偏移量,它的值由匯編器計(jì)算得出。
          BL非常常用。它在跳轉(zhuǎn)之前會(huì)在寄存器LR(R14)中保存PC的當(dāng)前內(nèi)容。BL的經(jīng)典用法如下:
          bl NEXT ; 跳轉(zhuǎn)到NEXT
          ……
          NEXT
          ……
          mov pc, lr ; 從子程序返回。
          最后提一下Thumb指令。ARM體系結(jié)構(gòu)還支持16位的Thumb指令集。Thumb指令集是ARM指令集的子集,它保留了32位代碼優(yōu)勢的同時(shí)還大大 節(jié)省了存儲(chǔ)空間。由于Thumb指令集的長度只有16位,所以它的指令比較多。它和ARM各有自己的應(yīng)用場合。對于系統(tǒng)性能有較高要求,應(yīng)使用32位存儲(chǔ) 系統(tǒng)和ARM指令集;對于系統(tǒng)成本和功耗有較高要求,應(yīng)使用16位存儲(chǔ)系統(tǒng)和ARM指令集。
          對ARM異常(Exceptions)的理解
          分類:技術(shù)筆記
          畢設(shè)筆記
          1.對ARM異常(Exceptions)的理解
          所有的系統(tǒng)引導(dǎo)程序前面中會(huì)有一段類似的代碼,如下:
          .globl _start ;系統(tǒng)復(fù)位位置
          _start: b reset ;各個(gè)異常向量對應(yīng)的跳轉(zhuǎn)代碼
          ldr pc, _undefined_instruction ;未定義的指令異常
          ldr pc, _software_interrupt ;軟件中斷異常
          ldr pc, _prefetch_abort ;內(nèi)存操作異常
          ldr pc, _data_abort ;數(shù)據(jù)異常
          ldr pc, _not_used ;未使用
          ldr pc, _irq ;慢速中斷異常
          ldr pc, _fiq ;快速中斷異常

          從中我們可以看出,ARM支持7種異常。問題時(shí)發(fā)生了異常后ARM是如何響應(yīng)的呢?第一個(gè)復(fù)位異常很好理解,它放在0x0的位置,一上電就執(zhí)行它, 而且我們的程序總是從復(fù)位異常處理程序開始執(zhí)行的,因此復(fù)位異常處理程序不需要返回。那么怎么會(huì)執(zhí)行到后面幾個(gè)異常處理函數(shù)呢?
          看看書后,明白了ARM對異常的響應(yīng)過程,于是就能夠回答以前的這個(gè)疑問。
          當(dāng)一個(gè)異常出現(xiàn)以后,ARM會(huì)自動(dòng)執(zhí)行以下幾個(gè)步驟:
          (1)把下一條指令的地址放到連接寄存器LR(通常是R14),這樣就能夠在處理異常返回時(shí)從正確的位置繼續(xù)執(zhí)行。
          (2)將相應(yīng)的CPSR(當(dāng)前程序狀態(tài)寄存器)到SPSR(備份的程序狀態(tài)寄存器)中。從異常退出的時(shí)候,就可以由SPSR來恢復(fù)CPSR。
          (3) 根據(jù)異常類型,強(qiáng)制設(shè)置CPSR的運(yùn)行模式位。
          (4)強(qiáng)制PC(程序計(jì)數(shù)器)從相關(guān)異常向量地址取出下一條指令執(zhí)行,從而跳轉(zhuǎn)到相應(yīng)的異常處理程序中。
          至于這些異常類型各代表什么,我也沒有深究。因?yàn)槠匠>完P(guān)心reset了,也沒有必要弄清楚。
          ARM規(guī)定了異常向量的地址:
          b reset ; 復(fù)位 0x0
          ldr pc, _undefined_instruction ;未定義的指令異常 0x4
          ldr pc, _software_interrupt ;軟件中斷異常 0x8
          ldr pc, _prefetch_abort ;預(yù)取指令 0xc
          ldr pc, _data_abort ;數(shù)據(jù) 0x10
          ldr pc, _not_used ;未使用 0x14
          ldr pc, _irq ;慢速中斷異常 0x18
          ldr pc, _fiq ;快速中斷異常 0x1c
          這樣理解這段代碼就非常簡單了。碰到異常時(shí),PC會(huì)被強(qiáng)制設(shè)置為對應(yīng)的異常向量,從而跳轉(zhuǎn)到相應(yīng)的處理程序,然后再返回到主程序繼續(xù)執(zhí)行。
          這些引導(dǎo)程序的中斷向量,是僅供引導(dǎo)程序自己使用的,一旦引導(dǎo)程序引導(dǎo)Linux內(nèi)核完畢后,會(huì)使用自己的中斷向量。
          嗬嗬,這又有問題了。比如,ARM發(fā)生中斷(irq)的時(shí)候,總是會(huì)跑到0x18上執(zhí)行啊。那Linux內(nèi)核又怎么能使用自己的中斷向量呢?原因在于 Linux內(nèi)核采用頁式存儲(chǔ)管理。開通MMU的頁面映射以后,CPU所發(fā)出的地址就是虛擬地址而不是物理地址。就Linux內(nèi)核而言,虛擬地址0x18經(jīng) 過映射以后的物理地址就是0xc000 0018。所以Linux把中斷向量放到0xc000 0018就可以了。
          MMU的兩個(gè)主要作用:
          (1)安全性:規(guī)定訪問權(quán)限
          (2) 提供地址空間:把不連續(xù)的空間轉(zhuǎn)換成連續(xù)的。
          第2點(diǎn)是不是實(shí)現(xiàn)頁式存儲(chǔ)的意思?

          .globl _start ;系統(tǒng)復(fù)位位置
          _start: b reset ;各個(gè)異常向量對應(yīng)的跳轉(zhuǎn)代碼
          ldr pc, _undefined_instruction ;未定義的指令異常

          ……

          _undefined_instruction :
          .word undefined_instruction

          也許有人會(huì)有疑問,同樣是跳轉(zhuǎn)指令,為什么第一句用的是 b reset;
          而后面的幾個(gè)都是用ldr?

          為了理解這個(gè)問題,我們以未定義的指令異常為例。

          當(dāng)發(fā)生了這個(gè)異常后,CPU總是跳轉(zhuǎn)到0x4,這個(gè)地址是虛擬地址,它映射到哪個(gè)物理地址
          取決于具體的映射。
          ldr pc, _undefined_instruction
          相對尋址,跳轉(zhuǎn)到標(biāo)號_undefined_instruction,然而真正的跳轉(zhuǎn)地址其實(shí)是_undefined_instruction的內(nèi)容——undefined_instruction。那句.word的相當(dāng)于:
          _undefined_instruction dw undefined_instruction (詳見畢設(shè)筆記3)。
          這個(gè)地址undefined_instruction到底有多遠(yuǎn)就難說了,也許和標(biāo)號_undefined_instruction在同一個(gè)頁面,也許在 很遠(yuǎn)的地方。不過除了reset,其他的異常是MMU開始工作之后才可能發(fā)生的,因此undefined_instruction 的地址也經(jīng)過了MMU的映射。
          在剛加電的時(shí)候,CPU從0x0開始執(zhí)行,MMU還沒有開始工作,此時(shí)的虛擬地址和物理地址相同;另一方面,重啟在MMU開始工作后也有可能發(fā)生,如果reset也用ldr就有問題了,因?yàn)檫@時(shí)候虛擬地址和物理地址完全不同。

          因此,之所以reset用b,就是因?yàn)閞eset在MMU建立前后都有可能發(fā)生,而其他的異常只有在MMU建立之后才會(huì)發(fā)生。用b reset,reset子程序與reset向量在同一頁面,這樣就不會(huì)有問題(b是相對跳轉(zhuǎn)的)。如果二者相距太遠(yuǎn),那么編譯器會(huì)報(bào)錯(cuò)的



          關(guān)鍵詞: arm匯編ldrstrbbl指

          評論


          技術(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); })();