新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > ARM學習b,bl指令淺析

        ARM學習b,bl指令淺析

        作者: 時間:2016-11-21 來源:網絡 收藏
        B或BL指令引起處理器轉移到“子程序名”處開始執行。兩者的不同之處在于BL指令在轉移到子

        程序執行之前,將其下一條指令的地址拷貝到R14(LR,鏈接寄存器)。由于BL指令保存了下條指令的地

        本文引用地址:http://www.104case.com/article/201611/319307.htm

        址,因此使用指令“MOV PC ,LR”即可實現子程序的返回。而B指令則無法實現子程序的返回,只能實

        現單純的跳轉。用戶在編程的時候,可根據具體應用選用合適的子程序調用語句。

        AREA Init,CODE,READONLY

        ;該偽指令定義了一個代碼段,段名為Init,屬性只讀
        ENTRY ;程序的入口點標識

        .

        .

        bl delay ;調用延遲

        .

        .

        mov pc,lr ;返回

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

        ARM匯編指令的一些總結
        ARM匯編指令很多,但是真正常用的不是很多,而且需要認真琢磨的又更少了。
        比較有用的是MOV B BL LDR STR
        還是通過具體匯編代碼來學習吧。
        @ disable watch dog timer
        mov r1, #0x53000000 //立即數尋址方式
        mov r2, #0x0
        str r2, [r1]
        立即數尋址方式,立即數要求以“#”作前綴,對于十六進制的數,還要求在#后面加上0x或者&。STR是

        比較重要的指令了,跟它對應的是LDR。ARM指令集是加載/存儲型的,也就是說它只處理在寄存器中的

        數據。那么對于系統存儲器的訪問就經常用到STR和LDR了。STR是把寄存器上的數據傳輸到指定地址的

        存儲器上。它的格式我個人認為很特殊:
        STR(條件) 源寄存器,<存儲器地址>
        比如 STR R0, [R1] ,意思是R0-> [R1],它把源寄存器寫在前面,跟MOV、LDR都相反。
        LDR應該是非常常見了。LDR就是把數據從存儲器傳輸到寄存器上。而且有個偽指令也是LDR,因此我有

        個百思不得其解的問題。看這段代碼:
        mov r1, #GPIO_CTL_BASE
        add r1, r1, #oGPIO_F
        ldr r2,=0x55aa // 0x55aa是個立即數啊,前面加個=干什么?
        對于當中的ldr 那句,我就不明白了,如果你把=去掉,是不能通過編譯的。我查了一些資料,個人感

        覺知道了原因:這個=應該表示LDR不是ARM指令,而是偽指令。作為偽指令的時候,LDR的格式如下:
        LDR 寄存器, =數字常量/Label
        它的作用是把一個32位的地址或者常量調入寄存器。嗬嗬,那大家可能會問,
        “MOV r2,#0x55aa”也可以啊。應該是這樣的。不過,LDR是偽指令啊,也就是說編譯時編譯器會處理

        它的。怎么處理的呢?——規則如下:如果該數字常量在MOV指令范圍內,匯編器會把這個指令作為MOV

        。如果不在MOV范圍中,匯編器把該常量放在程序后面,用LDR來讀取,PC和該常量的偏移量不能超過

        4KB。
        然后說一下跳轉指令。ARM有兩種跳轉方式。
        (1) mov pc <跳轉地址〉
        這種向程序計數器PC直接寫跳轉地址,能在4GB連續空間內任意跳轉。
        (2)通過 B BL BLX BX 可以完成在當前指令向前或者向后32MB的地址空間的跳轉(為什么是32MB呢?

        寄存器是32位的,此時的值是24位有符號數,所以32MB)。
        B是最簡單的跳轉指令。要注意的是,跳轉指令的實際值不是絕對地址,而是相對地址——是相對當前

        PC值的一個偏移量,它的值由匯編器計算得出。
        BL非常常用。它在跳轉之前會在寄存器LR(R14)中保存PC的當前內容。BL的經典用法如下:
        bl NEXT ; 跳轉到NEXT
        ……
        NEXT
        ……
        mov pc, lr ; 從子程序返回。
        最后提一下Thumb指令。ARM體系結構還支持16位的Thumb指令集。Thumb指令集是ARM指令集的子集,它

        保留了32位代碼優勢的同時還大大節省了存儲空間。由于Thumb指令集的長度只有16位,所以它的指令

        比較多。它和ARM各有自己的應用場合。對于系統性能有較高要求,應使用32位存儲系統和ARM指令集;

        對于系統成本和功耗有較高要求,應使用16位存儲系統和ARM指令集。
        對ARM異常(Exceptions)的理解
        分類:技術筆記
        畢設筆記
        1.對ARM異常(Exceptions)的理解
        所有的系統引導程序前面中會有一段類似的代碼,如下:
        .globl _start ;系統復位位置
        _start: b reset ;各個異常向量對應的跳轉代碼
        ldr pc, _undefined_instruction ;未定義的指令異常
        ldr pc, _software_interrupt ;軟件中斷異常
        ldr pc, _prefetch_abort ;內存操作異常
        ldr pc, _data_abort ;數據異常
        ldr pc, _not_used ;未使用
        ldr pc, _irq ;慢速中斷異常
        ldr pc, _fiq ;快速中斷異常

        從中我們可以看出,ARM支持7種異常。問題時發生了異常后ARM是如何響應的呢?第一個復位異常很好

        理解,它放在0x0的位置,一上電就執行它,而且我們的程序總是從復位異常處理程序開始執行的,因

        此復位異常處理程序不需要返回。那么怎么會執行到后面幾個異常處理函數呢?
        看看書后,明白了ARM對異常的響應過程,于是就能夠回答以前的這個疑問。
        當一個異常出現以后,ARM會自動執行以下幾個步驟:
        (1)把下一條指令的地址放到連接寄存器LR(通常是R14),這樣就能夠在處理異常返回時從正確的位置

        繼續執行。
        (2)將相應的CPSR(當前程序狀態寄存器)復制到SPSR(備份的程序狀態寄存器)中。從異常退出的時

        候,就可以由SPSR來恢復CPSR。
        (3) 根據異常類型,強制設置CPSR的運行模式位。
        (4)強制PC(程序計數器)從相關異常向量地址取出下一條指令執行,從而跳轉到相應的異常處理程

        序中。
        至于這些異常類型各代表什么,我也沒有深究。因為平常就關心reset了,也沒有必要弄清楚。
        ARM規定了異常向量的地址:
        b reset ; 復位 0x0
        ldr pc, _undefined_instruction ;未定義的指令異常 0x4
        ldr pc, _software_interrupt ;軟件中斷異常 0x8
        ldr pc, _prefetch_abort ;預取指令 0xc
        ldr pc, _data_abort ;數據 0x10
        ldr pc, _not_used ;未使用 0x14
        ldr pc, _irq ;慢速中斷異常 0x18
        ldr pc, _fiq ;快速中斷異常 0x1c
        這樣理解這段代碼就非常簡單了。碰到異常時,PC會被強制設置為對應的異常向量,從而跳轉到相應的

        處理程序,然后再返回到主程序繼續執行。
        這些引導程序的中斷向量,是僅供引導程序自己使用的,一旦引導程序引導Linux內核完畢后,會使用

        自己的中斷向量。
        嗬嗬,這又有問題了。比如,ARM發生中斷(irq)的時候,總是會跑到0x18上執行啊。那Linux內核又怎

        么能使用自己的中斷向量呢?原因在于Linux內核采用頁式存儲管理。開通MMU的頁面映射以后,CPU所

        發出的地址就是虛擬地址而不是物理地址。就Linux內核而言,虛擬地址0x18經過映射以后的物理地址

        就是0xc000 0018。所以Linux把中斷向量放到0xc000 0018就可以了。
        MMU的兩個主要作用:
        (1)安全性:規定訪問權限
        (2) 提供地址空間:把不連續的空間轉換成連續的。
        第2點是不是實現頁式存儲的意思?

        .globl _start ;系統復位位置
        _start: b reset ;各個異常向量對應的跳轉代碼
        ldr pc, _undefined_instruction ;未定義的指令異常

        ……

        _undefined_instruction :
        .word undefined_instruction

        也許有人會有疑問,同樣是跳轉指令,為什么第一句用的是 b reset;
        而后面的幾個都是用ldr?

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

        當發生了這個異常后,CPU總是跳轉到0x4,這個地址是虛擬地址,它映射到哪個物理地址
        取決于具體的映射。
        ldr pc, _undefined_instruction
        相對尋址,跳轉到標號_undefined_instruction,然而真正的跳轉地址其實是_undefined_instruction

        的內容——undefined_instruction。那句.word的相當于:
        _undefined_instruction dw undefined_instruction (詳見畢設筆記3)。
        這個地址undefined_instruction到底有多遠就難說了,也許和標號_undefined_instruction在同一個

        頁面,也許在很遠的地方。不過除了reset,其他的異常是MMU開始工作之后才可能發生的,因此

        undefined_instruction 的地址也經過了MMU的映射。
        在剛加電的時候,CPU從0x0開始執行,MMU還沒有開始工作,此時的虛擬地址和物理地址相同;另一方

        面,重啟在MMU開始工作后也有可能發生,如果reset也用ldr就有問題了,因為這時候虛擬地址和物理

        地址完全不同。

        因此,之所以reset用b,就是因為reset在MMU建立前后都有可能發生,而其他的異常只有在MMU建立之

        后才會發生。用b reset,reset子程序與reset向量在同一頁面,這樣就不會有問題(b是相對跳轉的)

        。如果二者相距太遠,那么編譯器會報錯的




        關鍵詞: ARM指令淺

        評論


        技術專區

        關閉
        主站蜘蛛池模板: 上林县| 沙洋县| 贵溪市| 化德县| 图们市| 安远县| 蒙自县| 政和县| 碌曲县| 开原市| 公安县| 镇康县| 遂昌县| 平江县| 余庆县| 鸡泽县| 阿城市| 南投县| 勐海县| 洛南县| 略阳县| 菏泽市| 南乐县| 浦江县| 深水埗区| 阜康市| 武冈市| 延津县| 石楼县| 贵定县| 永川市| 云和县| 墨竹工卡县| 金平| 罗平县| 景宁| 星座| 安福县| 普格县| 科技| 姜堰市|