新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > ARM匯編編程基礎之六-其它尋址模式與其它指令

        ARM匯編編程基礎之六-其它尋址模式與其它指令

        作者: 時間:2016-11-27 來源:網絡 收藏
        現在我們已經掌握了所有知識,可以編寫簡單的ARM匯編程序,但如果要編寫較為復雜的ARM程序,就必須掌握更多的尋址模式和指令,這就是本文的重點所在。

        我們在“基本尋址模式與基本指令”一文中學習了最常用的3種尋址方式。下面介紹其它尋址方式。

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

        1、基址尋址

        基址尋址就是將基址寄存器的內容與指令中給出的偏移量相加,形成操作數的有效地址。基址尋址用于訪問基址附近的存儲單元,常用于查表、數組操作、功能部件寄存器訪問等。基址尋址指令舉例如下:

        LDR R1,[R2,#0x0C]

        R2的值+0x0C形成內存地址,讀取內存中該地址上的內容,放入R1

        其它額外需要了解的內容:

        §零偏移。 如:LDR R0,[R1]

        §前索引偏移。 如:LDR R0,[R1,#0x04]!,表示將R1的值加上4后作為內存地址,并且指令執行結束時,R1本身的值也要加4。這里!表示要回寫

        §程序相對偏移。 如:LDR R0,labe1,表示將標號label所代表的地址處存放的內容放入R0,相當于LDR R0, [PC, #某個常數]

        §后索引偏移。 如:LDR R0,[R1],#0x04,表示將R1的值作為內存地址,并且指令執行結束時,R1本身的值要加4

        2、多寄存器尋址

        多寄存器尋址一次可傳送幾個寄存器值,允許一條指令傳送16個寄存器的任何子集或所有寄存器。多寄存器尋址指令舉例如下:

        LDMIA R1!,{R2-R4,R6} ,它是ldr的多寄存版本,將內存中的4個字放入寄存器R2,R3,R4,R6中

        指令執行前指令執行后

        兩點說明:

        1)、R1!中的!號表示在指令執行完成后,要改變(回寫)基址寄存器(R1)的值

        2)、寄存器列表{R2-R4, R6}中的順序并不要緊。最終寄存器與內存地址的對應關系是:編號小的寄存器與內存的低地址相對應

        兩點問題:

        1)、為什么內存起地址是0x40000000,而不是0x40000004

        2)、為什么內存地址是從0x40000000 ---- 0x4000000C,而不是從0x3FFFFFF4 ----0x40000000

        要解釋上面2個問題,其實也很簡單。其實多寄存加載指令ldm總共有4個:ldmia、 ldmib、 ldmda、 ldmdb。ia的意思是increase after,ib的意思是increase before,da的意思是decrease after,db的意思是decrease before。以LDMIA R1!, {R2-R4, R6}為例子,這里的ia是指辦事(將內存中的數加載到寄存器)之后增加基址寄存器(R1)的值。這條指令的執行過程從邏輯上看,如下:

        1)、先辦事:將R1的值(0x40000000)作為內存地址,到該地址處取得數(0x01),加載到寄存器R2中

        2)、后增加:將R1的值從0x40000000增加為0x40000004

        再重復上面的操作3次,分別將內存中的數0x02、0x03、0x04放到寄存器中R3、R4、R6中,最后R1的值變為0x40000010。

        這個例子中,如果將ldmia改為ldmib,則R2、R3、R4、R6中存放的是0x02、0x03、0x04、內存0x40000010處的內容,最后R1的值為0x40000010。

        除了4條多寄存器加載指令外,還有4條類似的多寄存器存儲指令,分別是stria、 strib、 strda、 strdb

        3、堆棧尋址

        由于ARM指令集沒有專門的出棧和入棧指令,所以ARM匯編程序是采用SP作為棧指針,以stm指令完成入棧操作,以ldm指令完成出棧操作。

        以入棧后SP的值是增加還是減少為依據,可將堆棧類型劃分為遞增堆棧(向上生長)和遞減堆棧(向下生長);

        以SP所指向的內存處存放的是棧頂元素還是下一次要入棧的元素,可將堆棧類型劃分為滿堆棧和空堆棧

        那么當堆棧類型為空遞減堆棧時候,入棧操作應該使用什么指令?出棧操作應該使用什么指令?進一步,如果堆棧類型為空遞增、滿遞增、滿遞減堆棧,又將如何呢?如果你不看下面的答案,我相信你一定會讓這幾個問題折磨得做很多的腦力體操,然后感嘆ARM指令集的設計者太不為你這樣的程序員考慮了,給了你本不應該由你承擔的負荷。但事實上正相反,ARM指令集的設計者充分理解了你作為程序員的苦惱,請看下面的答案。

        數據塊傳送堆棧操作說明
        存儲壓棧
        STMDASTMED空遞減
        STMIASTMEA空遞增
        STMDBSTMFD滿遞減
        STMIBSTMFA滿遞增
        數據塊傳送堆棧操作說明
        加載出棧
        LDMDALDMFA滿遞增
        LDMIALDMFD滿遞減
        LDMDBLDMEA空遞增
        LDMIBLDMED空遞減

        這2張表的第一、三列回答了前面你絞盡腦汁回答的問題。而第二列則體現了ARM指令集的設計者對作為程序員的你的充分體貼。第二列中的ED、EA、FD、FA分別表示empty descend(空遞減)、 empty ascend(空遞增)、 full descend(滿遞減)、 full ascend(滿遞增),其含義是說,如果你采用的是空遞減(空遞增、滿遞減、滿遞增)堆棧的話,入棧操作則使用指令STMED(STMEA、STMFD、STMFA),出棧操作則使用指令LDMED(LDMEA、LDMFD、LDMFA)。從此你再也不會為你應該使用ia、ib、da還是db來實現出、入棧操作而苦惱了。


        上一頁 1 2 下一頁

        評論


        技術專區

        關閉
        主站蜘蛛池模板: 陇西县| 合阳县| 宣武区| 大洼县| 长汀县| 呼玛县| 汾西县| 荣昌县| 樟树市| 韶关市| 镇坪县| 汪清县| 洪雅县| 仁寿县| 开江县| 江津市| 泸溪县| 郯城县| 济宁市| 巫山县| 兴宁市| 黄梅县| 达州市| 阳西县| 横峰县| 浦东新区| 辛集市| 临潭县| 金堂县| 鹤岗市| 休宁县| 临夏市| 凤阳县| 宁陕县| 玉环县| 汉中市| 鹿泉市| 丰县| 瑞昌市| 灵山县| 八宿县|