天天看點

ARM指令集 算術和邏輯指令 移位指令 乘法指令 比較指令 分支指令 條件執行 SWI 指令

算術和邏輯指令

ADC : 帶進位的加法

(Addition with Carry)

ADC{條件}{S}  <dest>, <op 1>, <op 2>

                dest = op_1 + op_2 + carry      

ADC

 将把兩個操作數加起來,并把結果放置到目的寄存器中。它使用一個進位标志位,這樣就可以做比 32 位大的加法。下列例子将加兩個 128 位的數。

128 位結果: 寄存器 0、1、2、和 3

第一個 128 位數: 寄存器 4、5、6、和 7

第二個 128 位數: 寄存器 8、9、10、和 11。

ADDS    R0, R4, R8              ; 加低端的字
  ADCS    R1, R5, R9              ; 加下一個字,帶進位
  ADCS    R2, R6, R10             ; 加第三個字,帶進位
  ADCS    R3, R7, R11             ; 加高端的字,帶進位      

如果如果要做這樣的加法,不要忘記設定 S 字尾來更改進位标志。

 

ADD : 加法

(Addition)

ADD{條件}{S}  <dest>, <op 1>, <op 2>

                dest = op_1 + op_2      

ADD

 将把兩個操作數加起來,把結果放置到目的寄存器中。操作數 1 是一個寄存器,操作數 2 可以是一個寄存器,被移位的寄存器,或一個立即值:

ADD     R0, R1, R2              ; R0 = R1 + R2
  ADD     R0, R1, #256            ; R0 = R1 + 256
  ADD     R0, R2, R3,LSL#1        ; R0 = R2 + (R3 << 1)      

加法可以在有符号和無符号數上進行。

 

AND : 邏輯與

(logical AND)

AND{條件}{S}  <dest>, <op 1>, <op 2>

                dest = op_1 AND op_2      

AND

 将在兩個操作數上進行邏輯與,把結果放置到目的寄存器中;對屏蔽你要在上面工作的位很有用。 操作數 1 是一個寄存器,操作數 2 可以是一個寄存器,被移位的寄存器,或一個立即值:

AND     R0, R0, #3              ; R0 = 保持 R0 的位 0 和 1,丢棄其餘的位。      

AND 的真值表(二者都是 1 則結果為 1):

Op_1   Op_2   結果

  0      0      0
  0      1      0
  1      0      0
  1      1      1
       

BIC : 位清除

(Bit Clear)

BIC{條件}{S}  <dest>, <op 1>, <op 2>

                dest = op_1 AND (!op_2)      

BIC

 是在一個字中清除位的一種方法,與 OR 位設定是相反的操作。操作數 2 是一個 32 位位掩碼(mask)。如果如果在掩碼中設定了某一位,則清除這一位。未設定的掩碼位訓示此位保持不變。

BIC     R0, R0, #%1011          ; 清除 R0 中的位 0、1、和 3。保持其餘的不變。      

BIC 真值表 :

Op_1   Op_2   結果

  0      0      0
  0      1      0
  1      0      1
  1      1      0      
譯注:邏輯表達式為 Op_1 AND NOT Op_2      

 

EOR : 邏輯異或

(logical Exclusive OR)

EOR{條件}{S}  <dest>, <op 1>, <op 2>

                dest = op_1 EOR op_2      

EOR

 将在兩個操作數上進行邏輯異或,把結果放置到目的寄存器中;對反轉特定的位有用。操作數 1 是一個寄存器,操作數 2 可以是一個寄存器,被移位的寄存器,或一個立即值:

EOR     R0, R0, #3              ; 反轉 R0 中的位 0 和 1      

EOR 真值表(二者不同則結果為 1):

Op_1   Op_2   結果

  0      0      0
  0      1      1
  1      0      1
  1      1      0
       

MOV : 傳送

(Move)

MOV{條件}{S}  <dest>, <op 1>

                dest = op_1      

MOV

 從另一個寄存器、被移位的寄存器、或一個立即值裝載一個值到目的寄存器。你可以指定相同的寄存器來實作 NOP 指令的效果,你還可以專門移位一個寄存器:

MOV     R0, R0                  ; R0 = R0... NOP 指令

  MOV     R0, R0, LSL#3           ; R0 = R0 * 8      

如果 R15 是目的寄存器,将修改程式計數器或标志。這用于傳回到調用代碼,方法是把連接配接寄存器的内容傳送到 R15:

MOV     PC, R14                 ; 退出到調用者

  MOVS    PC, R14                 ; 退出到調用者并恢複标志位
                                    (不遵從 32-bit 體系)
       

MVN : 傳送取反的值

(Move Negative)

MVN{條件}{S}  <dest>, <op 1>

                dest = !op_1      

MVN

 從另一個寄存器、被移位的寄存器、或一個立即值裝載一個值到目的寄存器。不同之處是在傳送之前位被反轉了,是以把一個被取反的值傳送到一個寄存器中。這是邏輯非操作而不是算術操作,這個取反的值加 1 才是它的取負的值:

MVN     R0, #4                  ; R0 = -5

  MVN     R0, #0                  ; R0 = -1
       

ORR : 邏輯或

(logical OR)

ORR{條件}{S}  <dest>, <op 1>, <op 2>

                dest = op_1 OR op_2      

OR

 将在兩個操作數上進行邏輯或,把結果放置到目的寄存器中;對設定特定的位有用。操作數 1 是一個寄存器,操作數 2 可以是一個寄存器,被移位的寄存器,或一個立即值:

ORR     R0, R0, #3              ; 設定 R0 中位 0 和 1      

OR 真值表(二者中存在 1 則結果為 1):

Op_1   Op_2   結果

  0      0      0
  0      1      1
  1      0      1
  1      1      1
       

RSB : 反向減法

(Reverse Subtraction)

RSB{條件}{S}  <dest>, <op 1>, <op 2>

                dest = op_2 - op_1      

SUB

 用操作數 two 減去操作數 one,把結果放置到目的寄存器中。操作數 1 是一個寄存器,操作數 2 可以是一個寄存器,被移位的寄存器,或一個立即值:

RSB     R0, R1, R2              ; R0 = R2 - R1
  RSB     R0, R1, #256            ; R0 = 256 - R1
  RSB     R0, R2, R3,LSL#1        ; R0 = (R3 << 1) - R2      

反向減法可以在有符号或無符号數上進行。

 

RSC : 帶借位的反向減法

(Reverse Subtraction with Carry)

RSC{條件}{S}  <dest>, <op 1>, <op 2>

                dest = op_2 - op_1 - !carry      

同于 

SBC

,但倒換了兩個操作數的前後位置。

 

SBC : 帶借位的減法

(Subtraction with Carry)

SBC{條件}{S}  <dest>, <op 1>, <op 2>

                dest = op_1 - op_2 - !carry      

SBC

 做兩個操作數的減法,把結果放置到目的寄存器中。它使用進位标志來表示借位,這樣就可以做大于 32 位的減法。

SUB

 和 

SBC

 生成進位标志的方式不同于正常,如果需要借位則清除進位标志。是以,指令要對進位标志進行一個非操作 - 在指令執行期間自動的反轉此位。

 

SUB : 減法

(Subtraction)

SUB{條件}{S}  <dest>, <op 1>, <op 2>

                dest = op_1 - op_2      

SUB

 用操作數 one 減去操作數 two,把結果放置到目的寄存器中。操作數 1 是一個寄存器,操作數 2 可以是一個寄存器,被移位的寄存器,或一個立即值:

SUB     R0, R1, R2              ; R0 = R1 - R2
  SUB     R0, R1, #256            ; R0 = R1 - 256
  SUB     R0, R2, R3,LSL#1        ; R0 = R2 - (R3 << 1)      

減法可以在有符号和無符号數上進行。

移位指令

       ARM 處理器組建了可以與資料處理指令(ADC、ADD、AND、BIC、CMN、CMP、EOR、MOV、MVN、ORR、RSB、SBC、SUB、TEQ、TST)一起使用的桶式移位器(barrel shifter)。你還可以使用桶式移位器影響在 LDR/STR 操作中的變址值。

譯注:移位操作在 ARM 指令集中不作為單獨的指令使用,它是指令格式中是一個字段,在彙編語言中表示為指令中的選項。如果資料處理指令的第二個操作數或者單一資料傳送指令中的變址是寄存器,則可以對它進行各種移位操作。如果資料處理指令的第二個操作數是立即值,在指令中用 8 位立即值和 4 位循環移位來表示它,是以對大于 255 的立即值,彙編器嘗試通過在指令中設定循環移位數量來表示它,如果不能表示則生成一個錯誤。在邏輯類指令中,邏輯運算指令由指令中 S 位的設定或清除來确定是否影響進位标志,而比較指令的 S 位總是設定的。在單一資料傳送指令中指定移位的數量隻能用立即值而不能用寄存器。

下面是給不同的移位類型的六個助記符:

LSL  邏輯左移
  ASL  算術左移
  LSR  邏輯右移
  ASR  算術右移
  ROR  循環右移
  RRX  帶擴充的循環右移      

ASL

 和 

LSL

 是等同的,可以自由互換。

你可以用一個立即值(從 0 到 31)指定移位數量,或用包含在 0 和 31 之間的一個值的寄存器指定移位數量。

邏輯或算術左移

(Logical or Arithmetic Shift Left)

Rx, LSL #n    or
  Rx, ASL #n    or
  Rx, LSL Rn    or
  Rx, ASL Rn      

接受 Rx 的内容并按用‘n’或在寄存器 Rn 中指定的數量向高有效位方向移位。最低有效位用零來填充。除了概念上的第 33 位(就是被移出的最小的那位)之外丢棄移出最左端的高位,如果邏輯類指令中 S 位被設定了,則此位将成為從桶式移位器退出時進位标志的值。

考慮下列:

MOV    R1, #12
  MOV    R0, R1, LSL#2      

在退出時,R0 是 48。 這些指令形成的總和是 

R0 = #12, LSL#2

 等同于 BASIC 的 

R0 = 12 << 2

邏輯右移

(Logical Shift Right)

Rx, LSR #n    or
  Rx, LSR Rn      

它在概念上與左移相對。把所有位向更低有效位方向移動。如果邏輯類指令中 S 位被設定了,則把最後被移出最右端的那位放置到進位标志中。它同于 BASIC 的 

register = value >>> shift

算術右移

(Arithmetic Shift Right)

Rx, ASR #n    or
  Rx, ASR Rn      

類似于 LSR,但使用要被移位的寄存器(Rx)的第 31 位的值來填充高位,用來保護補碼表示中的符号。如果邏輯類指令中 S 位被設定了,則把最後被移出最右端的那位放置到進位标志中。它同于 BASIC 的 

register = value >> shift

循環右移

(Rotate Right)

Rx, ROR #n    or
  Rx, ROR Rn      

循環右移類似于邏輯右移,但是把從右側移出去的位放置到左側,如果邏輯類指令中 S 位被設定了,則同時放置到進位标志中,這就是位的‘循環’。一個移位量為 32 的操作将導緻輸出與輸入完全一緻,因為所有位都被移位了 32 個位置,又回到了開始時的位置!

帶擴充的循環右移

(Rotate Right with extend)

Rx, RRX      

這是一個 ROR#0 操作,它向右移動一個位置 - 不同之處是,它使用處理器的進位标志來提供一個要被移位的 33 位的數量。

乘法指令

指令格式

這兩個指令與普通算術指令在對操作數的限制上有所不同:

  1. 給出的所有操作數、和目的寄存器必須為簡單的寄存器。
  2. 你不能對操作數 2 使用立即值或被移位的寄存器。
  3. 目的寄存器和操作數 1 必須是不同的寄存器。
  4. 最後,你不能指定 R15 為目的寄存器。

MLA : 帶累加的乘法

(Multiplication with Accumulate)

MLA{條件}{S}  <dest>, <op 1>, <op 2>, <op 3>

                dest = (op_1 * op_2) + op_3      

MLA

 的行為同于 

MUL

,但它把操作數 3 的值加到結果上。這在求總和時有用。

 

MUL : 乘法

(Multiplication)

MUL{條件}{S}  <dest>, <op 1>, <op 2>

                dest = op_1 * op_2      

MUL

 提供 32 位整數乘法。如果操作數是有符号的,可以假定結果也是有符号的。

比較指令

指令格式

譯注:CMP 和 CMP 是算術指令,TEQ 和 TST 是邏輯指令。把它們歸入一類的原因是它們的 S 位總是設定的,就是說,它們總是影響标志位。

CMN : 比較取負的值

(Compare Negative)

CMN{條件}{P}  <op 1>, <op 2>

                status = op_1 - (- op_2)      

CMN

 同于 

CMP

,但它允許你與小負值(操作數 2 的取負的值)進行比較,比如難于用其他方法實作的用于結束清單的 -1。這樣與 -1 比較将使用:

CMN     R0, #1                  ; 把 R0 與 -1 進行比較      

詳情參照 

CMP

 指令。

 

CMP : 比較

(Compare)

CMP{條件}{P}  <op 1>, <op 2>

                status = op_1 - op_2      

CMP

 允許把一個寄存器的内容如另一個寄存器的内容或立即值進行比較,更改狀态标志來允許進行條件執行。它進行一次減法,但不存儲結果,而是正确的更改标志。标志表示的是操作數 1 比操作數 2 如何(大小等)。如果操作數 1 大于操作操作數 2,則此後的有 GT 字尾的指令将可以執行。

明顯的,你不需要顯式的指定 

S

 字尾來更改狀态标志... 如果你指定了它則被忽略。

 

TEQ : 測試等價

(Test Equivalence)

TEQ{條件}{P}  <op 1>, <op 2>

                Status = op_1 EOR op_2      

TEQ

 類似于 

TST

。差別是這裡的概念上的計算是 EOR 而不是 AND。這提供了一種檢視兩個操作數是否相同而又不影響進位标志(不象 

CMP 

那樣)的方法。加上 

P

 字尾的 

TEQ

 還可用于改變 R15 中的标志(在 26-bit 模式中)。詳情請參照 psr.html,在 32-bit 模式下如何做請參見這裡。

 

TST : 測試位

(Test bits)

TST{條件}{P}  <op 1>, <op 2>

                Status = op_1 AND op_2      

TST

 類似于 

CMP

,不産生放置到目的寄存器中的結果。而是在給出的兩個操作數上進行操作并把結果反映到狀态标志上。使用 

TST

 來檢查是否設定了特定的位。操作數 1 是要測試的資料字而操作數 2 是一個位掩碼。經過測試後,如果比對則設定 Zero 标志,否則清除它。象 

CMP

那樣,你不需要指定 

S

 字尾。

TST     R0, #%1                 ; 測試在 R0 中是否設定了位 0。      

分支指令

B : 分支

(Branch)      
B{條件}  <位址>      
B                 是最簡單的分支。一旦遇到一個          B                 指令,ARM 處理器将立即跳轉到給定的位址,從那裡繼續執行。      
注意存儲在分支指令中的實際的值是相對目前的 R15 的值的一個偏移量;而不是一個絕對位址。      
它的值由彙編器來計算,它是 24 位有符号數,左移兩位後有符号擴充為 32 位,表示的有效偏移為 26 位(+/- 32 M)。      
在其他處理器上,你可能經常見到這樣的指令:      
OPT 1
  LDA &70
  CMP #0
  BEQ Zero
  STA &72
 .Zero RTS      
(取自 Acorn Electron User Guide issue 1 page 213)      
在 ARM 處理器上,它們将變成下面這些東西:      
OPT     1
  ADR     R1, #&70
  LDR     R0, [R1]
  CMP     #0
  BEQ     Zero
  STR     R0, [R1, #2]
 .Zero
  MOV     PC, R14      
這不是一個很好的例子,但你可以構想如何更好的去條件執行而不是分支。另一方面,如果你有大段的代碼或者你的代碼使用狀态标志,那麼你可以使用條件執行來實作各類分支: 這樣一個單一的簡單條件執行指令可以替代在其他處理器中存在的所有這些分支和跳轉指令。      
OPT     1
  ADR     R1, #&70
  LDR     R0, [R1]
  CMP     R0, #0
  STRNE   R0, [R1, #2]
  MOV     PC, R14      

BL : 帶連接配接的分支

(Branch with Link)      
BL{條件}  <位址>      
BL                 是另一個分支指令。就在分支之前,在寄存器 14 中裝載上 R15 的内容。你可以重新裝載 R14 到 R15 中來傳回到在這個分支之後的那個指令,      
它是子例程的一個基本但強力的實作。它的作用在螢幕裝載器 2 (例子 4)中得以很好的展現...      
.load_new_format
      BL     switch_screen_mode
      BL     get_screen_info
      BL     load_palette

    .new_loop
      MOV    R1, R5
      BL     read_byte
      CMP    R0, #255
      BLEQ   read_loop
      STRB   R0, [R2, #1]!      
...在這裡我們見到在裝載器循環之前調用了三個子例程。接着,一旦滿足了條件執行就在循環中調用了 read_byte 子例程。      

條件執行

 

ARM 處理器的一個非常特殊的特征是它的條件執行。我們指的不是基本的如果進位則分支,ARM 使這個邏輯階段進一步深化為如果進位則 

XXX 

- 這裡的 XXX 是任何東西。

為了舉例,下面是 Intel 8086 處理器分支指令的一個清單:

JA    Jump if Above
  JAE   Jump if Above or Equal
  JB    Jump if Below
  JBE   Jump if Below or Equal
  JC    Jump if Carry
  JCXZ  Jump if CX Zero (CX is a register that can be used for loop counts)
  JE    Jump if Equal
  JG    Jump if Greater than
  JGE   Jump if Greater than or Equal
  JL    Jump if Less than
  JLE   Jump if Less Than or Equal
  JMP   JuMP
  JNA   Jump if Not Above
  JNAE  Jump if Not Above or Equal
  JNB   Jump if Not Below
  JNBE  Jump if Not Below or Equal
  JNC   Jump if No Carry
  JNE   Jump if Not Equal
  JNG   Jump if Not Greater than
  JNGE  Jump if Not Greater than or Equal
  JNL   Jump if Not Less than
  JNLE  Jump if Not Less than or Equal
  JNO   Jump if Not Overflow
  JNP   Jump if Not Parity
  JNS   Jump if Not Sign
  JNZ   Jump if Not Zero
  JO    Jump if Overflow
  JP    Jump if Parity
  JPE   Jump if Parity Even
  JPO   Jump if Parity Odd
  JS    Jump if Sign
  JZ    Jump if Zero

80386 添加了:
  JECXZ Jump if ECX Zero      
作為對比,ARM 處理器隻提供了:      
B     分支
  BL    帶連接配接的分支      
但 ARM 提供了條件執行,你可以不受這個表面上不靈活的方式的限制:      
BEQ   Branch if EQual
  BNE   Branch if Not Equal
  BVS   Branch if oVerflow Set
  BVC   Branch if oVerflow Clear
  BHI   Branch if HIgher
  BLS   Branch if Lower or the Same
  BPL   Branch if PLus
  BMI   Branch if MInus
  BCS   Branch if Carry Set
  BCC   Branch if Carry Clear
  BGE   Branch if Greater than or Equal
  BGT   Branch if Greater Than
  BLE   Branch if Less than or Equal
  BLT   Branch if Less Than

  BLEQ  Branch with Link if EQual
  ....
  BLLT  Branch with Link if Less Than      
還有兩個代碼,      
  • AL

     - ALways,預設條件是以不須指定
  • NV

     - NeVer,不是非常有用。你無論如何不要使用這個代碼...
當你發現所有 Bxx 指令實際上是同一個指令的時候,緊要關頭就到了。      
接着你會想,如果你可以在一個分支指令上加上所有這些條件,那麼對一個寄存器裝載指令能否加上它們? 答案是可以。      

下面是可獲得的條件代碼的清單:

EQ : 等于
如果一次比較之後設定了 Z 标志。
  NE : 不等于
如果一次比較之後清除了 Z 标志。
  VS : 溢出設定
如果在一次算術操作之後設定了 V 标志,計算的結果不适合放入一個 32bit 目标寄存器中。
  VC : 溢出清除
如果清除了 V 标志,與 VS 相反。
  HI : 高于(無符号)
如果一次比較之後設定了 C 标志 并清除了 Z 标志。
  LS : 低于或同于(無符号)
如果一次比較操作之後清除了 C 标志 或設定了 Z 标志。
  PL : 正号
如果一次算術操作之後清除了 N。出于定義‘正号’的目的,零是正數的原因是它不是負數...
  MI : 負号
如果一次算術操作之後設定了 N 标志。
  CS : 進位設定
如果一次算術操作或移位操作之後設定了 C 标志,操作的結果不能表示為 32bit。你可以把 C 标志當作結果的第 33 位。
  CC : 進位清除
與 CS 相反。
  GE : 大于或等于(有符号)

如果一次比較之後...

設定了 N 标志 并設定了 V 标志

或者...

清除了 N 标志 并清除了 V 标志。

  GT : 大于(有符号)

如果一次比較之後...

設定了 N 标志 并設定了 V 标志

或者...

清除了 N 标志 并清除了 V 标志

并且...

清除了 Z 标志。

  LE : 小于或等于(有符号)

如果一次比較之後...

設定了 N 标志 并清除了 V 标志

或者...

清除了 N 标志 并設定了 V 标志

并且...

設定了 Z 标志。

  LT : 小于(有符号)

如果一次比較之後...

設定了 N 标志 并清除了 V 标志。

或者...

清除了 N 标志 并設定了 V 标志。

  AL : 總是
預設條件,是以不用明顯聲明。
  NV : 從不

不是特别有用,它表示應當永遠不執行這個指令。是窮人的 NOP。

包含 NV 是為了完整性(與 AL 相對),你不應該在你的代碼中使用它。

有一個在最後的條件代碼          S,                它以相反的方式工作。當用于一個指令的時候,導緻更改狀态标志。這不是自動發生的 - 除非這些指令的目的是設定狀态。例如:      
ADD     R0, R0, R1

  ADDS    R0, R0, R1

  ADDEQS  R0, R0, R1      
第一個例子是一個基本的加法(把 R1 的值增加到 R0),它不影響狀态寄存器。      

第二個例子是同一個加法,隻不過它導緻更改狀态寄存器。

最後一個例子是同一個加法,更改狀态寄存器。不同在于它是一個有條件的指令。隻有前一個操作的結果是 EQ (如果設定了 Z 标志)的時候它才執行。

下面是條件執行的一個工作中的例子。你把寄存器 0 與存儲在寄存器 10 中内容相比較。

如果不等于 R10,則調用一個軟體中斷,增加它并分支回來再次做這些。否則清除 R10 并傳回到調用它的那部分代碼(它的位址存儲在 R14)。

\ 條件執行的一個例子

  .loop                           ; 标記循環開始位置
  CMP     R0, R10                 ; 把 R0 與 R10 相比較
  SWINE   &40017                  ; 不等于: 調用 SWI &40017
  ADDNE   R0, R0, #1              ;         向 R0 加 1
  BNE     loop                    ;         分支到 'loop'
  MOV     R10, #0                 ; 等于  : 設定 R10 為零
  LDMFD   R13!, {R0-R12,PC}       ;         傳回到調用者      
注解:      
  • SWI 編号就象我寫的這樣。在 RISC OS 下,它是給 Econet_DoImmediate 的編号。不要字面的接受它,這隻是一個例子!
  • 你可能以前沒見過 

    LDMFD,

    它從棧中裝載多個寄存器。在這個例子中,我們從一個完全正式的棧中裝載 R0 至 R12 和 R14。關于寄存器裝載和存儲的更多資訊請參閱 str.html。
  • 我說要裝載 R14。那麼為什麼要把它放入 PC 中? 原因是此時 R14 存儲的值包含傳回位址。我們也可以采用:

    LDMFD    R13!, {R0-R12,R14} MOV      PC, R14

    但是直接恢複到 PC 中可以省略這個 

    MOV

     語句。
  • 最後,這些寄存器很有可能被一個 SWI 調用所占用(依賴于在調用期間執行的代碼),是以你最好把你的重要的寄存器壓入棧中,以後在恢複它們。

SWI 指令

SWI : 軟體中斷

(Software Interrupt)

SWI{條件}  <24 位編号>      
指令格式      

這是一個簡單的設施,但可能是最常用的。多數作業系統設施是用 SWI 提供的。沒有 SWI 的 RISC OS 是不可想象的。

Nava Whiteford 解釋了 SWI 是如何工作的(最初在 Frobnicate issue 12½)...

 

SWI 是什麼?

SWI 表示 Software Interrupt。在 RISC OS  中使用 SWI 來通路作業系統例程或第三方生産的子產品。許多應用使用子產品來給其他應用提供低層外部通路。      

SWI 的例子有:

  • 檔案器 SWI,它輔助讀寫磁盤、設定屬性等。
  • 列印機驅動器 SWI,用來輔助使用列印并行端口。
  • FreeNet/Acorn TCP/IP 協定棧 SWI,用 TCP/IP 協定在 Internet 上發送和接收資料。

在以這種方式使用的時候,SWI 允許作業系統擁有一個子產品結構,這意味着用來建立完整的作業系統的所需的代碼可以被分割成許多小的部分(子產品)和一個子產品處理程式(handler)。

當 SWI 處理程式得到對特定的例程編号的一個請求的時候,它找到這個例程的位置并執行它,并傳遞(有關的)任何資料。

它是如何工作的?

首先檢視一下如何使用它。一個 SWI 指令(彙編語言)看起來如下:      
SWI &02      
SWI "OS_Write0"      
這些指令實際上是相同的,将被彙編成相同的指令。唯一的不同是第二個指令使用一個字元串來表示 SWI 編号 &02。      
在使用采用了字元串編号的程式的時候,在執行之前首先查找這個字元串。      

在這裡我們不想處理字元串,因為它不能給出它要進行什麼的一個真實表示。它們通常用于增進一個程式的清晰程度,但不是實際執行的指令。

讓我們再次看一下第一個指令:

SWI &02      
這是什麼意思? 字面的意思是進入 SWI 處理程式并傳遞值 &02。在 RISC OS 中這意味着執行編号是 &02 的例程。      

它是如何這麼作的? 它如何傳遞 SWI 編号和進入 SWI 處理程式?

如果你檢視記憶體的開始 32 位元組(位于 0-&1C)并反彙編它們(查開實際的 ARM 指令)你将見到如下:

 

位址       内容               反彙編
00000000 : 0..å : E5000030 : STR     R0,[R0,#-48]
00000004 : .óŸå : E59FF31C : LDR     PC,&00000328
00000008 : .óŸå : E59FF31C : LDR     PC,&0000032C
0000000C : .óŸå : E59FF31C : LDR     PC,&00000330
00000010 : .óŸå : E59FF31C : LDR     PC,&00000334
00000014 : .óŸå : E59FF31C : LDR     PC,&00000338
00000018 : .óŸå : E59FF31C : LDR     PC,&0000033C
0000001C :  2?ã : E3A0A632 : MOV     R10,#&3200000      
讓我們仔細看一下。      

除了第一個和最後一個指令之外(它們是特殊情況)你見到的都是把一個新值裝載到 PC (程式計數器)的指令,它們告訴計算機到哪裡去執行下一個指令。

還展示了這個值是從記憶體中的一個位址接受來的。(你可以在 !Zap 主菜單上使用“Read Memory”選項去自己檢視一下。)

這看起來好象與 SWI 沒多少關系,下面做進一步的說明。

一個 SWI 所做的一切就是把模式改變成超級使用者并設定 PC 來執行在位址 &08 處的下一個指令!

把處理器轉換到超級使用者模式會切換掉兩個寄存器 r13 和 r14 并用 r13_svc 和 r14_svc 替換它們。

在進入超級使用者模式的時候,還把 r14_svc 設定為在這個 SWI 指令之後的位址。

這個實際上就象一個連接配接到位址 &08 的分支指令(BL &08),但帶有用于一些資料(SWI 編号)的空間。

象我說過的那樣,位址 &08 包含跳轉到另一個位址的一個指令,就是實際的 SWI 程式的位址!

此時你可能會想“稍等一會! 還有 SWI 編号呢?”。實際上處理器忽略這個值本身。SWI 處理程式使用傳遞來的 r14_svc 的值來擷取它。

下面是完成它的步驟(在存儲寄存器 r0-r12 之後):

  1. 它從 r14 中減去 4 來獲得 SWI 指令的位址。
  2. 把這個指令裝載到一個寄存器。
  3. 清除這個指令的高端 8 位,去掉了 OpCode 而隻剩下的 SWI 編号。
  4. 使用這個值來找到要被執行的代碼的例程的位址(使用查找表等)。
  5. 恢複寄存器 r0-r12。
  6. 使處理器離開超級使用者模式。
  7. 跳轉到這個例程的位址。
容易吧! ;)      

下面是一個例子,來自 ARM610 datasheet:

0x08 B Supervisor

EntryTable
 DCD ZeroRtn
 DCD ReadCRtn
 DCD WriteIRtn

 ...

Zero   EQU 0
ReadC  EQU 256
WriteI EQU 512
 
; SWI 包含需要的例程在位 8-23 中和資料(如果有的話)在位 0-7 中。
; 假定 R13_svc 指向了一個合适的棧

STMFD R13, {r0-r2 , R14}
 ; 儲存工作寄存器和傳回位址。
LDR R0,[R14,#-4]
 ; 得到 SWI 指令。
BIC R0,R0, #0xFF000000
 ; 清除高端的 8 位。
MOV R1, R0, LSR #8
 ; 得到例程偏移量。
ADR R2, EntryTable
 ; 得到入口表(EntryTable)的開始位址。
LDR R15,[R2,R1,LSL #2]
 ; 分支到正确的例程

WriteIRtn
 ; 寫 R0 中的位 0 - 7 中的字元。

.............
 LDMFD R13, {r0-r2 , R15}^
 ; 恢複工作空間,并傳回、恢複處理器模式和标志。      
這就是 SWI 指令的基本處理步驟。      
ARM指令的基本格式

ARM指令的基本格式為:

<Opcode>   {<Cond>}  {S}  <Rd> ,  <Rn>  { , <Opcode2> }

其中,<  >内的項是必需的,{  }内的項是可選的。

(1)Opcode項

Opcode是指令助記符,即操作碼,說明指令需要執行的操作,在指令中是必需的。

(2)Cond項(command)

Cond項表明了指令的執行的條件,每一條ARM指令都可以在規定的條件下執行,每條ARM指令包含4位的條件碼,位于指令的最高4位[31:28]。條件碼共有16種,每種條件碼用2個字元表示,這兩個字元可以添加至指令助記符的後面,與指令同時使用。當指令的執行條件滿足時,指令才被執行,否則指令被忽略。如果在指令後不寫條件碼,則使用預設條件AL(無條件執行)。

指令的條件碼

 
        
條 件 碼 助記符字尾 标    志 含    義
0000 EQ Z置位 相等equal
0001 NE Z清零 不相等not equal
0010 CS C置位 無符号數大于或等于Carry Set
0011 CC C清零 無符号數小于
0100 MI N置位 負數minus
0101 PL N清零 正數或零plus
0110 VS V置位 溢出
0111 VC V清零 沒有溢出
1000 HI C置位Z清零 無符号數大于high
1001 LS Z置位C清零 無符号數小于或等于less
1010 GE N等于V 帶符号數大于或等于
1011 LT N不等于V 帶符号數小于least
1100 GT Z清零且(N等于V) 帶符号數大于great
1101 LE Z清零或(N不等于V) 帶符号數小于或等于
1110 AL 忽略 無條件執行all
1111

條件碼應用舉例:

例:比較兩個值大小,并進行相應加1處理,C語言代碼為:

if  ( a > b )  a++;

else  b++;

對應的ARM指令如下(其中R0中儲存a 的值,R1中儲存b的值):

CMP  R0, R1  ; R0與R1比較,做R0-R1的操作

ADDHI  R0, R0, #1  ;若R0 > R1, 則R0 = R0 + 1

ADDLS  R1, R1, #1  ; 若R0 <= R1, 則R1 = R1 + 1

CMP比較指令,用于把一個寄存器的内容和另一個寄存器的内容或一個立即數進行比較,同時更新CPSR中條件标志位的值。指令将第一操作數減去第二操作數,但不存儲結果,隻更改條件标志位。

CMP  R1, R0  ;做R1-R0的操作。

CMP  R1,#10  ;做R1-10的操作。

(3) S項(sign)

S項是條件碼設定項,它決定本次指令執行的結果是否影響至CPSR寄存器的相應狀态位的值。該項是可選的,使用時影響CPSR,否則不影響CPSR。

(4)Rd項(destination)

Rd是指令中的目标寄存器,它是必需的。根據指令的不同,有些指令中要求Rd必須有R0~R7之間,有些要求Rd必須在R0~R14之間,有些則沒有特殊要求。

(5)Rn項

Rn是第一個操作數的寄存器,和Rd一樣,不同的指令對其的使用有不同的要求。

(6)Opcode2項

Opcode2項是第二個操作數,在ARM指令中,該操作數有三種形式:立即數形式、寄存器Rm形式和寄存器加移位形式(Rm, shift)。

例如:

SUB  R3,  R1,  #10

SUB  R3,  R1,  R2

SUB  R3,  R1,  R2,  LSL  #2

SUB  R3,  R1,  R2,  LSL  R0

ARM指令詳解

ARM指令集可分為以下6類:

l  跳轉指令

l  資料處理指令

l  程式狀态寄存器(PSR)處理指令

l  加載/存儲指令

l  協處理器指令

l  異常産生指令

ARM指令及功能描述

助 記 符 指令功能描述
ADC 帶進位加法指令
ADD 加法指令
AND 邏輯與指令
B 跳轉指令
BIC 位清零指令
BKPT 軟體斷點
BL 帶傳回的跳轉指令
BLX 帶傳回和狀态切換的跳轉指令
BX 帶狀态切換的跳轉指令
CDP 協處理器資料操作指令
CMN 取反比較指令
CMP 比較指令
EOR 邏輯異或指令
LDC 存儲器到協處理器的資料傳輸指令
LDM 加載多個寄存器的指令
LDR 存儲器到寄存器的資料傳輸指令
MCR 從ARM寄存器到協處理器寄存器的資料傳輸指令
MLA 乘加運算指令
MOV 資料傳輸指令
MRC 從協處理器寄存器到ARM寄存器的資料傳輸指令
MRS 傳送CPSR或SPSR的值到通用寄存器的指令
MSR 傳送通用寄存器的值到CPSR或SPSR的指令
MUL 32位乘法指令
MVN 資料取反傳送指令
ORR 邏輯或指令
RSB 反向減法指令
RSC 帶借位的反向減法指令
SBC 帶借位的減法指令
STC 協處理器寄存器寫入存儲器指令
STM 存儲多個寄存器的值到存儲器指令
STR 存儲寄存器的值到存儲器的指令
SUB 減法指令
SWI 軟體中斷指令
SWP 寄存器與存儲器 或 寄存器與寄存器之間的資料交換指令
TEQ 相等測試指令
TST 位測試指令

1. 跳轉指令

用于實作程式流程的跳轉,在ARM程式中有兩種方法可以實作程式流程的跳轉:一是使用專門的跳轉指令,二是直接向程式計數器PC寫入跳轉位址值。第二種方法可以實作在4GB的位址空間中的任意跳轉,在跳轉之前結合使用“MOV LR , PC”等類似指令,可以儲存将來的傳回位址值,進而實作在4GB連續的線性位址空間的子程式調用。

1)ARM指令集中的跳轉指令可以實作從目前指令向前或向後的32MB的位址空間的跳轉。

l  B指令

格式:

B{條件}  目标位址

注意,存儲在跳轉指令中的實際值是相對目前PC值的一個偏移量,而不是一個絕對位址,它的值由彙編器來計算(相對尋址)。這個偏移量是一個24位的有符号數,左移兩位後表示的有效偏移為26位(前後32MB的位址空間)。{}表示可以省略。

如:B Label     程式無條件跳轉到标号Label處執行。

CMP R1,#0

BEQ Label

當CPSR寄存器中的Z條件碼置位時,程式跳轉到Label處執行。

目前PC:是指跳轉指令本身的起始位址。

l  BL指令

格式:

BL{條件}  目标位址

這條指令在跳轉之前,會在寄存器R14中儲存目前的下一條指令的位址,是以,可以通過将R14重新加載到PC中,來傳回到跳轉指令之後的那條指令處執行。該指令是實作子程式調用的一種常用手段。

l  BX 指令

格式:

BX {條件}  目标位址

BX指令中所指定的目标位址,隻能使用寄存器的尋址方式,即跳轉的目标位址應先儲存在一個寄存器中。指令在實作跳轉的同時,完成處理器的工作狀态的切換(ARM狀态與Thumb狀态間的切換)。

BX指令中,用寄存器的最低位來訓示切換到哪一個工作狀态。如寄存器最低位為1,則把目标位址處的代碼解釋為Thumb代碼,進入Thumb工作狀态,并自動将CPSR中的控制位T置1。若寄存器最低位為0,則把目标位址處的代碼解釋為ARM代碼,進入ARM工作狀态,并自動将CPSR中的控制位T置0。

ADRL  R0,  ThumbFun + 1     ;生成分支位址并置最低位為 1

BX  R0    ;跳轉到R0所指定的位址,并切換處理器到Thumb工作狀态

ThumbFun  

…         ;Thumb彙編指令

| BLX指令

以上兩條指令的綜合。

2. 資料處理指令

資料處理指令可分資料傳送指令、算術邏輯運算指令和比較指令等。資料傳送指令用于在寄存器和存儲器之間進行資料的雙向的傳輸。所有ARM資料處理指令均可選擇使用S字尾,以影響狀态标志CPSR。比較指令(CMP、CMN、TST、TEQ)不儲存運算結果,這些指令也不使用S字尾,但會直接影響CPSR中的相應的狀态标志位。

(1)資料傳送指令MOV 和MVN

格式:

MOV {條件} {S} 目的寄存器, 源操作數

MOV指令可以完成從另一個寄存器、被移位的寄存器、或将一個立即數加載到目的寄存器。與MVN指令不同的是在傳送之前,将被傳送的對象先按位取反,再傳送到目的寄存器。

例:MVN  R1 ,  #0XFF    ;R1 ← 0X FFFF FF00

  MVN  R1 ,  R2

  MOV PC,R14;将寄存器R14的值傳送給PC,用于子程式傳回。

(2) 資料比較指令CMP , CMN , TST , TEQ

例:

CMP  R1,  R2  ; 做R1 – R2 的操作,結果不儲存,但影響标志位。

CMP R1 , #10  ;做R1 - 10的操作,結果不儲存,但影響标志位。

CMN 指令用于把一個寄存器的内容和另一個寄存器的内容或立即數取反後進行比較操作,根據運算結果影響CPSR中的标志位。該指令實際完成操作數1和操作數2相加,并根據結果更改條件标志位。

TST位測試指令,用于把一個寄存器的内容和另一個寄存器的内容或立即數進行按位的與運算,并根據運算結果更新CPSR中條件标志位的值。操作數1是要測試的數,而操作數2 是一個位掩碼,該指令一般用來檢測是否設定了特定的位。

TST {條件} 操作數1, 操作數2

例:TST  R0,  #0X0000 0040 ; 指令用來測試R0的位3是否為1。

TST指令通常和EQ、NE條件碼配合使用,當所有測試位為0時,EQ有效,而隻要有一個測試位不為0,則NE有效。

TEQ相等測試指令,用于把一個寄存器的内容和另一個寄存器的内容或立即數進行按位的異或運算,并根據運算結果更新CPSR中的條件标志位。指令用于比較兩個操作數是否相等。如果相等,則 Z = 1,否則Z = 0。指令通常和EQ、NE條件碼配合使用

例:TEQ  R1, R2

TST R1,#%1;測試R1中是否設定了最低位(%表示二進制數)

(3)邏輯運算類指令:AND、ORR、EOR、BIC

格式:邏輯類指令 {條件} {S} 目的寄存器,操作數1, 操作數2

S選項,說明運算結果影響CPSR的條件标志位,沒有S選項,則不影響CPSR的條件标志位。

操作數1應該是一個寄存器,操作數2可以是一個寄存器、被移位的寄存器或一個立即數。

AND指令常用于将操作數1的某個位置0;ORR指令常用于将操作數1的某個位置1;EOR(異或)指令常用于将操作數1的某個位取反。與0相異或,保持不變,與1相異或,則取反。BIC指令用于清除操作數1的某些位,并把結果放置到目的寄存器中,如果在掩碼中設定了某一位,則清除這一位。未設定的掩碼位保持不變。

例:BIC R1, R1, #0X0F    ;将R1的低四位清零,其他位不變。

(4)算術運算類指令:ADD、ADC、SUB、SBC、RSB、RSC

格式:算術運算類指令 {條件} {S} 目的寄存器,操作數1,操作數2

目的寄存器,操作數1和操作數2使用的寄存器必須在R0~R7之間。

操作數1應該是一個寄存器,操作數2可以是一個寄存器、被移位的寄存器或一個立即數。

例:ADDS  R1, R1,#10   ;結果影響标志位

    ADD   R1, R1, R2   ;結果不影響标志位

    ADD   R3, R1, R2, LSL #2   ; R3 = R1 + ( R2 << 2 )

ADD指令完成的功能是将操作數1加上操作數2,結果送到目的寄存器。

ADC指令完成的功能是将操作數1加上操作數2,再加上标志位C的值,結果送到目的寄存器。

SUB指令完成的功能是将操作數1減去操作數2,結果送到目的寄存器。

SBC指令完成的功能是将操作數1減去操作數2,再減去标志位C的取反值,結果送到目的寄存器。

RSB逆向減法指令完成的功能是将操作數2減去操作數1,結果送到目的寄存器。

RSC帶借位的逆向減法指令完成的功能是将操作數2減去操作數1,再減去标志位C的取反值,結果送到目的寄存器。

例:

SUB  R0, R1, #256  ;R0 = R1 - 256 , 結果不影響标志位

SUBS  R0, R2,R3,LSL #1 ;R0 = R2 - ( R3 <<1 ),結果影響标志位

SUB  SP , #380   ;SP = SP - 380

SBC  R0, R1, R2 ;R0 = R1 - R2 - !C

RSC  R0, R1, R2 ;R0 = R2 - R1 - !C

(5)乘法指令與乘加指令

ARM微處理器支援的乘法指令與乘加指令共有6條,可分為運算結果為32位和結果為64位兩類,與前面的資料處理指令不同,指令中的所有操作數、目的寄存器必須為通用寄存器,不能對操作數使用立即數或被移位的寄存器,同時,目的寄存器和操作數1必須是不同的寄存器。

l  MUL指令

格式:

MUL {條件} {S} 目的寄存器,操作數1, 操作數2

功能:

目的寄存器 = 操作數1 × 操作數2,同時可以根據運算結果設定CPSR中相應的條件标志位N和Z。操作數1和操作數2均為32位的有符号數或無符号數。

l  MLA指令

格式:

MLA {條件} {S} 目的寄存器,操作數1, 操作數2, 操作數3

功能:

目的寄存器 = 操作數1 × 操作數2 + 操作數3,同時可以根據運算結果設定CPSR中相應的條件标志位N和Z。操作數1和操作數2均為32位的有符号數或無符号數。

l  SMULL指令(S:Signed, 有符号)

格式:

SMULL {條件} {S} 目的寄存器Low,目的寄存器High,操作數1, 操作數2

功能:

目的寄存器Low = (操作數1 × 操作數2 )的低32位,

目的寄存器High = (操作數1 × 操作數2 )的高32位,同時可以根據運算結果設定CPSR中相應的條件标志位。操作數1和操作數2均為32位的有符号數。

例:

SMULL  R0, R1, R2, R3

;R0 = (R2 ×R3)的低32位, R1 = (R2 ×R3)的高32位。

l  SMLAL指令(S:Signed, 有符号)

格式:

SMLAL {條件} {S} 目的寄存器Low,目的寄存器High,操作數1, 操作數2

功能:

目的寄存器Low = (操作數1 × 操作數2 )的低32位 + 目的寄存器Low,

目的寄存器High = (操作數1 × 操作數2 )的高32位 + 目的寄存器High,同時可以根據運算結果設定CPSR中相應的條件标志位。操作數1和操作數2均為32位的有符号數。

例:

SMLAL  R0, R1, R2, R3

;R0 = (R2 ×R3)的低32位 + R0,

;R1 = (R2 ×R3)的高32位 + R1。

l  UMULL指令(U:UnSigned, 無符号)

格式:

UMULL {條件} {S} 目的寄存器Low,目的寄存器High,操作數1, 操作數2

功能:

目的寄存器Low = (操作數1 × 操作數2 )的低32位,

目的寄存器High = (操作數1 × 操作數2 )的高32位,同時可以根據運算結果設定CPSR中相應的條件标志位。操作數1和操作數2均為32位的無符号數。

例:

UMULL  R0, R1, R2, R3

;R0 = (R2 ×R3)的低32位, R1 = (R2 ×R3)的高32位。

l  UMLAL指令(U:UnSigned, 無符号)

格式:

UMLAL {條件} {S} 目的寄存器Low,目的寄存器High,操作數1, 操作數2

功能:

目的寄存器Low = (操作數1 × 操作數2 )的低32位 + 目的寄存器Low,

目的寄存器High = (操作數1 × 操作數2 )的高32位 + 目的寄存器High,同時可以根據運算結果設定CPSR中相應的條件标志位。操作數1和操作數2均為32位的無符号數。

例:

UMLAL  R0, R1, R2, R3

;R0 = (R2 ×R3)的低32位 + R0,

;R1 = (R2 ×R3)的高32位 + R1。

3. 程式狀态寄存器通路指令

功能:用于在程式狀态寄存器和通用寄存器之間傳送資料。

l  MRS指令

格式:

MRS {條件}  通用寄存器, 程式狀态寄存器(CPSR、SPSR)

功能:

将狀态寄存器的内容傳送到通用寄存器。

使用環境:

(1)當需要改變程式狀态寄存器的内容時,可用MRS将狀态寄存器的内容讀入到通用寄存器,修改後再寫回到程式狀态寄存器。

(2)當在異常處理或程序切換時,需要儲存程式狀态寄存器的值,可先用該指令讀出程式狀态寄存器的值,然後儲存。

l  MSR指令

格式:

MSR {條件}  程式狀态寄存器(CPSR、SPSR)_<域>,操作數

功能:

将操作數的内容傳送到程式狀态寄存器的特定域中。其中,操作數可以為通用寄存器或立即數。<域>用于設定程式狀态寄存器中需要操作的位,32位的程式狀态寄存器分為4個域:

F域:位31~位24為條件标志位域;

S域:位23~位16為狀态位域;

X域:位15~位8為擴充位域;

C域:位7~位0為控制位域;

使用環境:

(1)當需要改變程式狀态寄存器的内容時,可用MRS将狀态寄存器的内容讀入到通用寄存器,修改後再寫回到程式狀态寄存器。

(2)當在異常處理或程序切換時,需要儲存程式狀态寄存器的值,可先用該指令讀出程式狀态寄存器的值,然後儲存。

例:

MSR  CPSR , R0   ;CPSR←R0

MSR  SPSR_c , R0  ;傳送R0到SPSR,但僅修改SPSR中的控制位域

MSR  CPSR_c ,  #0XD3   ; CPSR[7..0] = 0XD3 ,  即切換到管理模式

MSR  CPSR_cxsf ,  R3  ; CPSR ← R3

注意:隻有在特權模式下,才能修改狀态寄存器。

程式中不能通過MSR指令直接修改CPSR中的T控制位來實作ARM/Thumb狀态的切換,必須使用BX指令來完成處理器狀态的切換。

MRS與MSR配合使用,可以實作CPSR或SPSR寄存器的讀/修改/寫操作,進行處理器模式 切換,進行允許/禁止IRQ/FIQ中斷等的設定。

例:使能IRQ中斷

MRS  R0 ,  CPSR

BIC   R0 ,  R0 ,  #0X80

MSR  CPSR_c  ,  R0

MOV  PC ,  LR

例:禁止IRQ中斷

MRS  R0 ,  CPSR

ORR   R0 ,  R0 ,  #0X80

MSR  CPSR_c  ,  R0

MOV  PC ,  LR

4. 存儲器加載/存儲指令

功能:用于在寄存器和存儲器之間傳送資料,加載指令用于将存儲器中的資料傳送到寄存器,存儲指令則将寄存器中的資料傳送到存儲器。

存儲器加載/存儲指令分為單個存儲器加載/存儲指令和多個存儲器加載/存儲指令。

(1)單個存儲器加載/存儲指令

LDR字資料加載指令;

LDRH(Half)半字資料加載指令;

LDRB位元組資料加載指令;

STR字資料存儲指令;

STRH半字資料存儲指令;

STRB位元組資料存儲指令。

l  加載指令

格式:

加載指令 {條件} 目的寄存器, <存儲器位址>

例:

LDR  R0 , [R1]   ;将位址為R1的字資料讀入R0。

LDR  R0 , [R1,R2]  ;将位址為R1+R2的字資料讀入R0。

LDR  R0 , [R1, #4] ;将位址為R1+4的字資料讀入R0。

LDR  R0 , [R1, R2]! ;将位址為R1+R2的字資料讀入R0,并将新位址R1+R2寫入R1。

LDR  R0 , [R1, R2, LSL #2 ] !

;将位址為R1 + R2 × 4的字資料讀入R0,并将新位址R1 + R2 × 4寫入R1。

LDRH指令用于從存儲器中将一個16位的半字資料傳送到目的寄存器中,同時将寄存器的高16位清零。

LDRH  R0 , [R1]   ;将位址為R1的半字資料讀入R0,并将R0的高16位清零。

LDRB指令用于從存儲器中将一個8位的位元組資料傳送到目的寄存器中,同時将寄存器的高24位清零。

LDRB  R0 , [R1]   ;将位址為R1的位元組資料讀入R0,并将R0的高24位清零。

注意:當是字操作時,操作數的位址必須是字對齊的,如果是半字操作,操作數的位址必須是半字對齊。否則,讀出的資料是無效,随機的。

例:

LDR  R0 ,   [R1 ,  # 2 ]

LDRH  R0 ,   [R1 ,  # 1 ]

l  存儲指令

格式:

存儲指令 {條件} 源寄存器, <存儲器位址>

例:

STR  R0 , [R1] , #8  

;将R0中的字資料寫入以R1為位址的存儲器中,并将新位址R1+8寫入R1。

STR  R0 , [R1 , #8]  ;将R0中的字資料寫入以R1+8為位址的存儲器中。

STRH指令用于從源寄存器中将一個16位的半字資料傳送到存儲器中。該半字資料為源寄存器中的低16位。

STRH  R0 , [R1, #8]  ;将寄存器R0中的低16位寫入以R1 + 8為位址的存儲器中。

STRB指令用于從源寄存器中将一個8位的位元組資料傳送到存儲器中。該位元組資料為源寄存器中的低8位。

注意:當是字操作時,操作的位址必須是字對齊的,如果是半字操作,操作的位址必須是半字對齊。否則,讀出的資料是無效,随機的。

(2)批量資料加載/存儲指令

功能:可以一次在一片連續的存儲器單元和多個寄存器之間傳送資料,批量加載指令用于将一片連續的存儲器中的資料傳送到多個寄存器,批量資料存儲指令完成相反的操作。

LDM(或STM)指令(Load Data To Multiple Register)

格式:

LDM(或STM) {條件} {類型} 基址寄存器{!}  ,寄存器清單{^}

{類型}為以下幾種情況:

類 型 含     義
IA 每次操作後,位址加4
IB 每次操作前,位址加4
DA 每次操作後,位址減4
DB 每次操作前,位址減4
FD 滿遞減堆棧
ED 空遞減堆棧
FA 滿遞增堆棧
EA 空遞增堆棧

{!}為可選字尾,若選用,則當資料傳送完畢之後,将最後的位址寫入基址寄存器,否則基址寄存器的内容不改變。

基址寄存器不允許為R15,寄存器清單可以為R0 ~ R15的任意組合。

{^}為可選字尾,當指令為LDM且寄存器清單中包含有R15,選用該字尾表示:除了正常的資料傳送之外,還将SPSR複制到CPSR。同時,該字尾還表示傳入或付傳出的是使用者模式下的寄存器,而不是目前模式下的寄存器。

例:

STMFD  SP!, {R0 - R7 , LR}   ;現場儲存,将R0 - R7 , LR入棧,滿遞減堆棧。

LDMFD  SP!, {R0 - R7 , PC}^  ;恢複現場,異常處理傳回,滿遞減堆棧

在進行資料複制時,先設定好源資料指針,然後使用塊拷貝尋址指令進行讀取和存儲。而在堆棧操作中,則要先設定堆棧指針SP,然後使用堆棧尋址指令實作堆棧操作。

5. 資料交換指令

功能:支援在存儲器和寄存器之間交換資料。

SWP ( Swap )  字資料交換指令;

SWPB  位元組資料交換指令。

格式:

交換指令  {條件} 目的寄存器, 源寄存器1, [源寄存器2]

例:

SWP  R0, R1, [R2] ;将R2所指的存儲器中的字資料傳送到R0,同時将R1中的字資料傳送到R2所指的存儲器單元。

顯然,當源寄存器1與目的寄存器是同一個寄存器時,就完成了寄存器與存儲器間的交換操作。

SWPB指令用于将源寄存器2所指向的存儲器中的位元組資料到目的寄存器中,目的寄存器的高24位清零,同時将源寄存器1中的低8位資料(低位位元組)傳送到源寄存器2所指向的存儲器中。

6. 異常産生指令

異常指令有兩條:SWI軟體中斷指令和BKPT斷點中斷指令。

l  SWI中斷指令

格式:

SWI  {條件}  24位的立即數

功能:

産生軟體中斷,友善使用者程式調用作業系統的系統例程。

操作:

切換運作模式到管理模式,設定PC來執行在位址0X08處的下一條指令,設定相應的R13_svc和R14_svc。該指令的操作與執行BL 0X08這條指令的效果是相同的。不同的地方在于,SWI還帶有指明系統例程的類型的“24位的立即數”。在具體應用中,為便于記憶,可以使用字元串代替“24位的立即數”,例如:SWI  “OS_Write0”和 SWI  0X02是一樣的。當指令中24位的立即數被忽略時,系統例程的類型由通用寄存器R0的内容決定。傳送給系統例程的參數通過通用寄存器來傳遞。

l  BKPT指令

格式:

BKPT  16位的立即數

功能:

用于産生軟體斷點中斷,執行時中斷正常指令,進入相應的調試子程式。

7. 協處理器指令

ARM處理器可支援多達16個協處理器,每個協處理器隻執行針對其自身的協處理指令。ARM的協處理器指令主要用于ARM處理器初始化、協處理器的資料處理操作、在ARM處理器與協處理器的寄存器之間傳送資料、在協處理器和存儲器之間傳送資料。ARM協處理器指令有以下5條:

l  CDP協處理器資料操作指令;

l  LDC協處理器資料加載指令;

l  STC協處理器資料存儲指令;

l  MCR  ARM處理器寄存器到協處理器寄存器的資料傳送指令;

l  MRC  協處理器寄存器到ARM處理器寄存器的資料傳送指令。

(1)CDP指令

格式:

CDP {條件}協處理器編碼,協處理器操作碼1,目的寄存器,源寄存器1,源寄存器2,協處理器操作碼2

功能:用于ARM處理器通知協處理器執行特定的操作,若協處理器不能執行指定的操作,則産生未定義指令異常。

注意:指令中涉及到的寄存器都是協處理器的寄存器,不涉及ARM處理器的寄存器和存儲器。操作碼1、操作碼2是協處理器要執行的操作。

例: CDP  p5 ,  1 ,  c3 ,  c4 ,  c5 , 2

;訓示協處理器P5,執行操作1,可選操作為2;C3, C4, C5是相應的協處理器寄存器。

(2) LDC指令

格式:

LDC {條件}{L}協處理器編碼,目的寄存器,[源寄存器]

功能:

用于将源寄存器所指向的存儲器中的字資料傳送到目的寄存器中。若協處理器不能成功執行,則産生未定義指令異常。選項{L}表示指令為長讀取操作,可用于雙精度資料的傳輸。

注意:指令中涉及到的源寄存器是ARM處理器的寄存器。

例:LDC  P3, C4, [R2, #4]

(3) STC指令

格式:

STC {條件}{L}協處理器編碼,源寄存器,[目的寄存器]

功能:

用于将源寄存器中的字資料傳送到目的寄存器所指向的存儲器中。若協處理器不能成功執行,則産生未定義指令異常。選項{L}表示指令為長讀取操作,可用于雙精度資料的傳輸。

注意:指令中涉及到的目的寄存器是ARM處理器的寄存器。

例:STC  P3, C4, [R0]

;将協處理器P3的寄存器C4中的資料傳送到ARM處理器的寄存器R0所指向的存儲器.

(4)  MCR指令

格式:

MCR {條件}協處理器編碼,協處理器操作碼1,源寄存器,目的寄存器1,目的寄存器2,協處理器操作碼2

功能:

MCR指令用于将ARM處理器寄存器中的資料傳送到協處理器的寄存器中。若協處理器不能完成這個操作,将引發未定義指令異常。源寄存器為ARM處理器的寄存器。

(5)  MRC指令

格式:

MRC {條件}協處理器編碼,協處理器操作碼1,目的寄存器,源寄存器1,源寄存器2,協處理器操作碼2

功能:

MRC指令用于将協處理器寄存器中的數送到ARM處理器的寄存器中。若協處理器不能完成這個操作,将引發未定義指令異常。源寄存器為ARM處理器的寄存器。

例:MRC  P3  , 3 , R0 , C4 , C5 , 6

;将協處理器P3的寄存器C4與C5中的資料傳送到ARM的寄存器中,并執行編号為3和6的操作。

Thumb指令集合

Thumb指令集是ARM指令集的一個子集,允許指令編碼為16位的長度,Thumb指令集在保留32位代碼優勢的同時,大大節省了系統的存儲空間。

當處理器在執行ARM程式段時,稱ARM處理器處于ARM工作狀态,當處理器在執行Thumb程式段時,稱ARM處理器處于Thumb工作狀态。

在編寫Thumb指令時,先要用僞指令CODE16聲明以下為Thumb指令代碼,在ARM指令代碼中可以使用BX指令跳轉到Thumb指令代碼片。同樣編寫ARM代碼時,則使用僞指令CODE32進行聲明,在Thumb指令代碼中使用BX指令可以跳轉到ARM指令代碼處。

大多數Thumb指令是無條件執行的,而幾乎所有的ARM指令都是有條件執行的。由于Thumb資料處理指令中的目的寄存器與其中的一個源寄存器相同,Thumb指令在指令編碼時由三個操作數改為兩個操作數。

通常實作同樣的程式功能時,所需的Thumb指令的條數比ARM指令多。但使用Thumb指令集合的代碼有以下特點:

l  比ARM代碼更節略存儲空間。

l  使用的指令條數比ARM代碼多。

l  若使用32位的存儲器,ARM代碼比Thumb代碼快約40%。

l  若使用16位的存儲器,Thumb代碼比ARM代碼快約40%~50%。

l  與ARM代碼相比較,使用Thumb代碼,存儲器的功耗會降低約30%。

繼續閱讀