ARM彙編程序特點:

ARM彙編程序特點:

l         所有運算處理都是發生通用寄存器(一般是R0~R14)的之中.所有存儲器空間(如C語言變量的本質就是一個存儲器空間上的幾個BYTE).的值的處理,都是要傳送到通用寄存器來完成.因此代碼中大量看到LDR,STR指令來傳送值.

l         ARM彙編語句中.當前語句很多時候要隱含的使用上一句的執行結果.而且上一句的執行結果,是放在CPSR寄存器裏,(比如說進位,爲0,爲負…)

CMP R0,R1

BNE NoMatch

比如上一句,BNE隱含的使用的上一句CMP執行結果.NE後綴表示使用Z標誌位.兩句合起來的意思就是,如果R0,R1的值不相等,就跳轉到NoMatch處執行.

注意,PC=R15,CPSR=R16,

    ARM僞指令不是必須的,但是一個完整沒有僞指令幾乎很難寫出來.

n         比如一個程序至少包含READONLY AREA和ENTRY,否則CPU都無法知道從哪裏開始運行

l         ARM的屬於RISC,指令並不多,但是可以帶後綴表示擴展出不同用法,這裏與X86彙編完全不同風格

n         如BNE實際上是B指令的變種,本質還同一類指令.只是多一個對CPSR的Z標誌位的判斷。

ARM常用指令,僞指令

ARM常用指令並不太多,因此使用閱讀ARM彙編代碼,並不太困難.以下是使用頻率最高的指令和僞指令,並不是完整的指令集的教材。詳細指令參見參考資料。

l         B,BL

l         MOV,MVN

l         LDR,STR

l         ADD,SUB,ADC,SBC,MUL

l         AND,ORR,XOR,TST,BIC

l         CMP

l         LDM/STM

l         nop

1.         跳轉語句 B,BL

      程序流程的跳轉,在 ARM 程序中有兩種方法可以實現程序流程的跳轉指令用於實現

l  使用專門的跳轉指令 B

l  直接向程序計數器PC 寫入跳轉地址值

n  這是幾乎是任何一種CPU必備的機器,PC表示CPU當前執行語句位置,改變PC的值,相當於實現程序跳轉

n  如實現類似C語言的Return 語句,就是用MOV PC,LR

n  這裏可以在任意4G的空間進行跳轉

 

B指令(Branch)表示無條件跳轉.

   B main ;跳轉到標號爲main地代碼處

 

BL指令(Branch with Link)表示帶返回值的跳轉.

   BL比B多做一步,在跳轉前,BL會把當前位置保存在R14(即LR寄存器),當跳轉代碼結束後,用MOV PC,LR指令跳回來,這實際上就是C語言執行函數的用法,

   彙編裏調子程序都用BL,執行完子函數後,可以用MOV PC,LR跳回來.

   BL delay ;執行子函數或代碼段delay ,delay可以爲C函數.

 

與MOV PC,XXX能在4G空間跳轉不同,B語句只能32M空間跳轉,(因爲偏移量是一個有符號26bit的數值=32M)

2.         傳輸數據指令MOV,MVN

n  MOV(MOVE)指令可完成從另一個寄存器、被移位的寄存器或將一個立即數加載到目的寄存器

MOV R0,R1 ; 把R1的值傳到R0

MOV R3,#3 ;把常數3傳給R3,MOV中用#表示常數,這個值不能超過

n  MVN( MOVE Negative)取反後再傳值,比MOV多了一步取反

MVN R0, #0 ;把0取反(即-1)傳給R0

MVN R1,R2  ;把R2的值取反傳給R1

3.         加載/存儲指令,LDR,STR

n  LDR,STR是用於寄存器和外部存儲器交換數據指令,注意與MOV的區別,後面只在寄存器或常數交換.

u              LDR/STR可以採用多種尋址方式,以下只舉出使用頻率最高几種用法

n  LDR(load)用於把一個32Bit的WORD數據從外部存儲空間裝入到寄存器中

LDR R0,[R1]; R1的值當成地址,再從這個地址裝入數據到R0 (R0=*R1)

LDR R1,=0x30008000 ; 把地址0x30008000的值裝入到R1中,LDR中用常數要用=打頭.(注意跟MOV的區別,MOV是#)

ldr  r0, =(0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0)

用位與的方法賦值

n  STR(Store) 用於把一個寄存器的值存入外部存儲空間,是LDR的逆操作.

STR R0,[R1] ; 把R0的值,存入到R1對應地址空間上(*R1 = R0)

STR R0,=0x30008000 ;把R0中值存入到地址0x30008000

S2C2440的中CPU內核以外的模塊的控制寄存器空間也是屬於外部空間,所以也得用如下指令LDR R0,=GPFDAT

4.         算術運算指令,ADD/ADC,SUB/SBC ,MUL

n         ADD加法指令

ADD R0,R1,R2; R0=R1+R2

ADD R0,R1,#3 ;R0=R1+3

n         ADC帶進位加法指令,即除了加兩個數以外,還要把CPSR的C值也要帶進來

u              通常用於大數(超過32Bit整數)相加,這時單用ADD不能處理,必須折成兩步,其中一步用ADC.

u              以下是做64Bit的加法

ADDS R0,R1,R2; R0=R1+R2,ADDS中S表示把進位結果寫入CPSR

ADC R5,R3,R4 ;R5=R3+R4+C

n         SUB減法指令

SUB R0,R1,R2; R0=R1-R2

SUB R0,R1,#3 ;R0=R1-3

n         SBC帶進位減法指令,即除了加兩個數以外,還要把CPSR的C值也要帶進來,類似ADC

u              以下是做64Bit的減法

SUBS R0,R1,R2; R0=R1-R2,SUBS中S表示把進位結果寫入CPSR

SBC R5,R3,R4 ;R5=R3-R4-C

n         MUL 乘法指令

MUL R0,R1,R2; R0=R1*R2

MUL R0,R1,#3 ;R0=R1*3

5.         位操作指令 AND,ORR, TST,BIC

n         AND位與指令

AND R0,R1,R2; R0=R1 & R2

AND R0,R1,#0xFF ;R0=R1 & 0xFF

n         ORR位或指令

ORR R0,R1,R2; R0=R1 | R2

ORR R0,R1,#0xFF ;R0=R1 | 0xFF

n         TST測試某一位是否爲1,並把結果寫入CPSR,供下一句使用

TST R1,#0xffe;   等同於if(R1 & 0xffe)

TST R1,#%1;測試最低位是否爲1,%表示二進制

n         BIC清位操作

BIC   R0,R0,#0xF          ; 等同於 R0 &=~(0xF)

BIC   R0,R0,#%1011   ; 該指令清除 R0 中的位 0 1  3,其餘的位保持;   %表示是二進制,0x表示十六進制

6.         比較指令 CMP

n         CMP比較兩個操作數,並把結果存入CPSR供下一句語句使用

CMP R0,R1; 比較R0,R1

7.         多寄存器語句傳輸指令,LDM,STM

類似於一次傳一個BUFFER到寄存器當中,或反過來.後面一般要接一個地址改變方法

n         LDM 從BUFFER傳數據多個寄存器傳輸數據到

LDMIA R0! ,{R3-R9} ;加R0指向的地址上連續空間的數據,保存到R3-R9當中,!表示R0值更新,IA後綴表示按WORD遞增

LDMFD SP!,{R0-R7,PC}^;恢復現場,異常處理返回,^表示不允許在用戶模式下使用。

n         STM 從寄存器列表向存儲空間傳值。

STMIA R1!,{R3-R9} ;將R3-R9的數據存儲到R1指向的地址上,R1值更新。

STMFD SP!,{R0-R7,LR}; 現場保存,將R0~R7,LR入棧

  stmfd    sp!,{r8-r9} ,把SP寄存器對慶的地址的值存到R8,R9當中.!表示最後的值寫入SP中。Fd表示

8.         ARM指令的變形

大部分指令後位可以接 與S兩個特殊位來表示,對CPSR特殊的一些判斷

S,表示當前指令執行後把結果改寫CPSR

subs,Adds

取決於具體條件,只有CPSR滿足指定條件時才指這一指令

BEQ 實際上B+ EQ的條件執行.

addne 表示ADD +NE 纔開始加.

9.         ARM指令的尋址方式

  尋址方式是根據指令中給出的地址碼來定位真實的地址,ARM中有9種尋址方法

l  寄存器尋址

直接用寄存器編號來尋址,最爲常用

  MOV R1,R2 ;R2->R1

l  立即數尋址

即指令中的地址碼是操作數本身,可以立即取出使用,立即數前帶一個#表示,否則表示一個地址

SUBS R0,R0,#1   ;R0 -1 ->R0

注意與SUBS R0,R0,1區別

l  寄存器偏移尋址

這是ARM特有的尋址模式,當第2操作數是寄存器,在執行操作之前,可以做一次移位操作

MOV R0,R2,LSL #3 ;R2的邏輯左移3位,結果放入R0,即R0=R2*8

ANDS R1,R1,R2,LSL R3;RS的值左移R3位,然後和R1相與操作,結果放入R1

移位操作有LSL (邏輯左移),LSR(邏輯右移) ,ASR(算術右移),ROR(循環右移)RRX帶擴展的循環右移

 

l         寄存器間接尋址

即寄存器中值是一個地址,用[]來取出定位到地址當中

 LDR R2,[R0] ;把R0的值當成地址,取出相應值,賦給R2

l         基址尋址

把寄存器的地址值加上一個偏移量

LDR R2,[R3,#0x0F]; R3中的值加上0x0F,從這個地址取出值賦給R@

l         相對尋址

基址尋址的變形,由PC寄存器提供基準地址,指令中地址段作爲偏移量.兩者相加即是有效地址,以下是BL採用相對尋址

BL NEXT

NEXT

    …

MOV PC,LR ;從子程序返回

10.     ADS ARM的僞指令

  類似於C語言的宏,由彙編程序預處理.

l         符號定義指令

全局變量定義 GBLA ,GBLL,GBLS

局域變量定義 LCLA,LCLL,LCLS

變量賦值SETA,SETL,SETS

其中上述僞指令中,最後面的A表示給一個算術變量賦值,L表示用於給一個邏輯變量賦值,s表示給一個字符串賦值

GBLL codedbg; 聲明一個全局的邏輯變量

Codebg SETL  {TRUE}  ; 設置變量爲{TRUE}

LCLA bitno;  聲明一個算術變量

Bitno SETA 8 ;設變量值爲8

l         數據定義僞指令

n         SPACE 定義一個內存空間,並用0初始化

{label }  SPACE expr

 DataBuf SPACE 100 ;定義100字節長空間, unsigned char DataBuf[100];

n         DCB 定義一個連續字節內存空間,用僞指令的表達式expr來初始化.一般可以用定義數據表格,或文字字符串.(這時等同於SETS),用於初始二進制BUFFER

      {label} DCB expr{,expr …}

       Dest DCB -120,20,36,55 ;等同於 unsigned char Dest[]={-120,20,36,55};

n         DCU定義的一段字的內存空間(DCB是字節),並用後面表達式初始化

      _RESET DCU Reset ; 等同於 DWORD _RESET[]={Reset};

 

n          MAP定一個結構化內存,相當於定義一個C結構

n         FILED 定義一個結構化內存的成員

MAP 0x00,R9 ; 定義內存表,地址爲R9

Timer   FIELD 4 ; 定義數據域Timer,長爲4字

Attrib  FIELD 4 ; 定義數據域Attrib,長爲4字

String  FILED 100  ; 定義數據域String ,長爲100字

相當於C語言的定義:

struct {

DWORD Timer ;

DWORD Attrib ;

Char String[100];

} R9;

 

11.     雜項的僞指令

n         字節對齊 ALIGN

ALIGN; 聲明4字節對齊

n         定義一個數字常量定義 EQU

NAME EQU expr {type}

  PLLCON EQU 0xE01FC080;定義PLLCON,類似於C的宏或C++的常量

n         包含文件 GET和INCLUDE

INCLUDE lpc2106.inc

n         NOP 空指令

在彙編時會被ARM的空操作代替,比如MOV R0,R0,一般用於延時與佔位。

n         聲明一個外部符符號 IMPORT,EXTERN

IMPORT,EXTERN 向外部導入一個符號,一般是外部程序全局變量

 

n         條件編譯:[]。類似於C的#ifdef 之類定義。

格式 :條件表達式

        滿足條件分支

        |

        不滿足條件分支

      ]

示例1:

 [ ENTRY_BUS_WIDTH=32  ;類似#if ENTRY_BUS_WIDTH=32

      b   ChangeBigEndian     ;DCD 0xea000007

   ] ; 類似#endif 

示例2:   [ CLKDIV_VAL>1      ; 類似#if CLKDIV_VAL>1

bl MMU_SetAsyncBusMode

          |;類似#else 

        bl MMU_SetFastBusMode ; default value.

]; 類似#endif

          示例3 [ THUMBCODE  類似#ifdef  THUMBCODE

                                   bx lr

                                 | ;類似#else

                              mov   pc,lr

                               ]  ;類似#endif

n         段定義 AREA

n         指令集定義 CODE16和CODE32

指示是Thumb 指令集(壓縮指令集,每個指令16位)。還是普通32位指令集

n         彙編結束:END

n         程序入口ENTRY

 

一個基本ARM程序結構

ARM彙編程序結構

源代碼由文本文件組成.按照彙編的編譯器不同,分爲兩大量,一類是ADS的彙編程序,一類是GNU彙編格式,兩者在指令集是完成一樣,但是在僞指令.程序結構等方法各不同相同.本節主要是講解ADS彙編格式.

   ADS彙編程序,主要包含如下幾類程序

n         彙編源程序,後綴名是.S

n         彙編包含文件,後綴名是.inc

n         如果是與C混和編程..C,.h也能識別

         ARM 彙編語句格式    

           [標號]  <指令|條件|S> <操作數> [;註釋]

 

l         所有標號頂格寫,而指令和僞指令不能頂格寫

l         標識符(標號,指令)大小寫敏感,所以要在標號和指令時書寫一致,一般僞指令,指令,寄存器名可以全部爲大寫

l         註釋以;開頭,可以頂格寫

l         可以使用\來分行寫太長語句

l         變量,常量的定義必須在一行頂格寫

 

常量的書寫

l         數字常量

在程序中直接寫數字 ,十進制 12,256,十六進制 0x1228,

l         字符常量

類似於C的定義,用SETS來定義字符常量

HELLO SETS “hello,the world!”

l         邏輯常量

邏輯真爲{TRUE},邏輯假爲{FLASE}

  Testno SETS {TURE}

       彙編程序的段定義

            任何一個程序都要分段,C語言一般由編譯器自動分段,(分成.Text,.Data段之類),但在彙編程序這樣的底層程序中,由開發者自行分段.  它包含如下段

l         至少一個代碼段,並且代碼段是隻讀的,對應(.Text)

l         數據段可以沒有,也可以有多個.

l         每一個段用END結束

 

AREA 定義一個段

AREA  段名    屬性1, 屬性2,

例子:AREA Init,CODE,READONLY

l         ENTRY 指明一個段的入口

l         END結束一個段

 

         ABC EQU 0x12

            AREA Example,CODE,READONLY

            ENTRY

        START MOV R7,#10

              MOV R6,#5

              ADD R6,R6,R7

              B   

              END

 

ADS ARM彙編程序格式要求

1.     所有標號要頂格寫.

2.     所有指令不能頂格寫,一般插入Tab鍵在行首

3.     ADS ARM中,是大小寫敏感的.建議標號,指令,僞指令,寄存器名全部爲大寫

4.     註釋採用;打頭

5.     每個程序至少有一個AREA在代碼裏(READONLY)

6.     每個段都要用END結束(不能頂格)

 

最常見幾個僞指令 AREA,EQU,DCB,END ,ENTRY,EXPORT,GOBEL,IMPORT,

 

常見僞定義

l         DCB 定義字符中

   Str DCB “hello, world “

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章