ARM指令集——條件執行、內存操作指令、跳轉指令


 

 

ARM 匯編指令條件執行

在ARM模式下,任何一條數據處理指令可以選擇是否根據操作的結果來更新CPSR寄存器中的ALU狀態標志位。在數據處理指令中使用S后綴來實現該功能。 

不要在CMP,CMN,TST或者TEQ指令中使用S后綴。這些比較指令總是會更新標志位。 

在Thumb模式下,所有數據處理指令都更新CPSR中的標志位。有一個例外就是:當一個或更多個高寄存器被用在MOV和ADD指令時,此時MOV和ADD不能更新狀態標志. 

幾乎所有的ARM指令都可以根據CPSR中的ALU狀態標志位來條件執行。參見表2-1條件執行后綴表。 

在ARM模式下,你可以: 

  • 根據數據操作的結果更新CPSR中的ALU狀態標志;
  • 執行其他幾種操作,但不更新狀態標志;
  • 根據當前狀態標志,決定是否執行接下來的指令。 

在Thumb模式,大多數操作總是更新狀態標志位,並且只能使用條件轉移指令(B)來實現條件執行。該指令(B)的后綴和在ARM模式下是一樣的。其他指令不能使用條件執行。

 

ALU狀態標志 

CPSR寄存器包含下面的ALU狀態標志:

  N       Set when the result of the operation was Negative
  Z Set when the result of the operation was Zero
  C Set when the operation result in a Carry(發生進位,或借位)
  V Set when the operation caused oVerflow(操作造成溢出)
  Q ARM architecture v5E only sticky flag

 

 

 

 

  

2.5.2 執行條件

 N,Z,C,V相關的條件碼后綴如下表所列:

示例1

  ADD  r0, r1, r2              ; r0 = r1 + r2, 不更新標志位
  ADDS  r0, r1, r2      ; r0 = r1 + r2, 后綴S表示更新標志位
  ADCSS  r0, r1, r2      ; If C 標志為1,則執行r0 = r1 + r2, 且更新標志,
  CMP  r0, r1            ; CMP指令肯定會更新標志. 

示例2 求最大公約數

gcd
  CMP r0, r1    
  BEQ end    ; r0 = r0 結束程序
  BLT less    ; r0 < r1 跳轉至 less
  SUB r0, r0, r1  ; r0 > r1時 r0 = r0 - r1
  B gcd  ; 條件都不滿足是繼續循環
less
  SUB r1, r1, r0    ; r0 < r1 r1 = r1 - r0
  B gcd
end

示例3

MAIN
  mov r1, #1   mov r2, #1   cmp r1, r2   beq FUNC      ;if(eq) b FUNC => 實質:if(z == 1) b FUNC   bne FUNC    ;實質:if(z == 0) b FUNC   mov r3, #3   mov r4, #4 FUNC   mov r5, #5   mov r6, #6

 

尋址方式 

基地址變址尋址方式 

種類 格式 模式
1 [Rn, #±<offset_12]> 立即數前索引尋址
2 [Rn, ±Rm] 寄存器前索引尋址
3 [Rn, Rm, <shift>#<offset_12>] 寄存器位移的前索引尋址
4 [Rn, #±<offset_12>]! 立即數自動索引尋址
5 [Rn, ±Rm]! 寄存器自動索引尋址
6 [Rn, Rm, <shift<#<offset_12>]! 寄存器移位的自動索引尋址
7 [Rn], #±<offset_12> 立即數后索引尋址
8 [Rn], ±<Rm> 寄存器后索引尋址
9 [Rn], ±<Rm>, <shift>#<offset_12> 帶移位的寄存器后索引尋址

 

 

 

 

 

 

 

 

 

寄存器前索引尋址

  mov r0, #0x40000000
  mov r1, #0xF000000F
  str r1, [r0, #4]  ;將 r1 中的數據存儲到地址為 r0 + 4 的內存空間中

 寄存器移位的前索引尋址

  mov r2, #8
  str r1, [r0, r2, lsl #1]  ;將 r1 中的數據存儲到地址為 r0 + (r2 << 1)的內存空間中

 寄存器后索引尋址

  str r1, [r0], #4  ;將 r1 中的數據存儲到地址為 r0 的內存空間中,然后 r0 = r0 + 4

 寄存器自動索引尋址 

str r1, [r0, #4]!  ;將 r1 中的數據存儲到 r0 + 4 的內存空間中, 然后 r0 = r0 + 4

  多寄存器尋址/塊拷貝尋址  LDM STM

對棧進行操作是,使用較多  比如說 用 IA 自動索引尋址存,就用 DB 自動索引讀

 

Load/Store指令

Load/store是一組內存訪問指令,用來在ARM寄存器和內存之間進行數據傳送,ARM指令中有3種基本的數據傳送指令。

  1. 單寄存器 Load/Store 內存訪問指令(single register):這些指令為ARM寄存器和存儲器提供了更靈活的單數據項傳送方式。數據可以使字節,16位半字或32位字
  2. 多寄存器 Load/Store 內存訪問指令:可以實現大量數據的同時傳送,主要用於進程的進入和退出、保存和恢復工作寄存器以及復制寄存器中的一片(一塊)數據
  3. 但寄存器交換指令(single register swap): 實現寄存器數據和內存數據進行交換,而且是在一條指令中完成,執行過程中不會受到中斷干擾

單寄存器Load/Store指令

LDR指令:用於從內存中將一個32位的字讀取到目標寄存器  指令格式  LDR{<cond>} <Rd>, <addr_mode> 

;指令舉例
  LDR R1, [R0, #0x12]  ;將R0 + 12地址處的數據讀出,保存到R1中(R0保持不變)
  LDR Rd,[Rn], #0x04 ;立即數后索引尋址,Rn的值用作傳輸數據的存儲地址。在數據傳送后,將偏移量 0x04 與Rn相加,記過寫回到 Rd中

 STR指令:用於將一個32位的字節數據寫入到指令中指定的內存單元  指令格式  STR{<cond>} <Rd>,<addr_mode> 

;LOAD/STORE指令
;向內存寫入數據 STR
mov r0, #40000000
mov r1, #ff000000
str r1, [r0]  ;用於將一個32位的字數據寫入到指令指定的內存單元(以 r0 值為起始地址的 4byte 內存單元)
strb r1, [r0]  ;將r1 中的 [7:0]存儲到 r0 對應的內存空間
strh r1, [r0]  ;將r1 中的 [15:0]存儲到 r0 為起始地址的兩個字節的內存空間
          ;在對數據進行操作時,應根據數據本身的屬性(幾個字節)進行操作

 多寄存器Load/Store指令

LDM指令:實現數據從連續的內存單元中讀取到指令指定的寄存器列表中。值得注意的是 LDM指令和STM指令:序號的寄存器對應內存中高地址的數據

指令格式: LDM{<cond>}<addressing_mode> <Rn>{!}, <registers> 

STM指令:實現將指令中寄存器列表里的數值寫入到一塊連續的內存單元之中

指令格式: STM{<cond>} <addressing_mode> <Rn>{!}, <register> 

LDM/STM <cond>的幾種尋址方式:

  格  式 地址變化格式  
1 IA(Increment After) 后遞增方式 先存儲后增長
2 IB(Increment Before) 先遞增方式 現增長后存儲
3 DA(Decrement After) 后遞減方式 先存儲后遞減
4 DB(Decrement Before) 先遞減方式 先遞減后存儲

   

 

 

 

 

mov r0, #0x40000000
  mov r1, #1
  mov r2, #2
  mov r3, #3
  ldm r0, {r1-r3}
  stm r0, {r1-r3}  ;將 r1 - r3 寄存器(連續寄存器)中的數據存儲到 以 r0 位起始地址的內存空間中
  stm r0, {r3, r1}   ;將 r1 、 r3 寄存器(不連續寄存器)中的數據存儲到 以 r0 位起始地址的內存空間中
            ;批量操作時,低編號的寄存器數據對應內存中的低地址
  stm r0!, {r1-r3}  ;寄存器批量存儲,也適用自動索引尋址, 操作完成后   r0 = r0 + (寄存器個數)*4

 

 跳轉指令

B和BL跳轉指令

MAIN
  mov r0, #2
  mov r1, #3
  mov lr, pc  ;B 指令不會自動保存 PC;手動保存返回地址、當前PC
  b lable    ;跳轉到標號 FUNC (標號的實質是地址)
  mov r3, r0
FUNC
  sub r0, r1, r0
  mov pc,lr  ;返回主程序繼續執行

跳轉指令是改變指令執行順序的標准方式 (控制流指令)

B 和 BL 指令都是 相對跳轉(短跳轉) 指令,通過偏移量跳轉, 最大跳轉距離是 ±32M

使用 mov pc, <>可以實現 對跳轉(長跳轉)(不會保存當前 PC 值)

關於B指令和BL指令最大跳轉距離是 ±32M:

  ARM匯編每條指令占用 4byte,生成機器碼 B 、BL存放在bits[31:24], bits[23:0]是立即數空間,可以表示 2^24個地址。由於每條匯編指令占用4byte字節(最低兩位都為 0),因此可以使用 24位二進制數來表示 26 位的尋址空間。

B指令和BL指令的區別

  • B指令在使用時不會對當前 PC 值進行保存,為保證跳轉指令執行后能正常返回,要手動對其進行保存
  • BL (帶連接的跳轉指令)能夠在跳轉時對當前 PC 值自動進行保存。 

 

帶狀態切換的跳轉指令 BX

不會保存跳轉前 PC 值 ±32M范圍

帶狀態切換(ARM&Thmub)的跳轉指令BX  ,語法格式:BX{<cond>} <Rm> ,使程序跳轉到指令中參數 Rm 指定的地址進行執行。並將 Rm 的第 0 位復制到 CPRS 中的 T 位, bit[31: 1]存入PC。

   PC也可以作為 Rm 寄存器使用,當PC作為 Rm 使用時,指令 BX PC 便跳轉到當前指令下面第 2 條指令出執行(三級流水線:當前正在執行的指令地址為 PC - 8,正在譯碼的指令為 PC - 4, 正在取指的指令是 PC)。但這種方式不值得推薦,最好使用下面的方式完成這種跳轉。

  mov pc, pc
;或者
  add pc, pc, #0

 

帶狀態切換的連接跳轉指令

 與BX功能一致,但會自動保存跳轉時的 PC 值,語法格式: BLX <target_add> 。target_add為指令的跳轉目標地址,該地址是一個立即數

 

狀態(寄存器)操作指令

ARM指令集提供了兩條指令(MSR,MRS),用來操作狀態寄存器PSR

MRS指令,語法格式 MRS {cond} Rd, PSR 用於把CPSR或SPSR的值傳送到一個寄存器;

MSR指令,語法格式 MSR {cond} PSR_filed, #immed_8r 或 MSR {cond} PSR_filed, Rm 用於把一個寄存器的值或一個立即數傳送到CPSR或SPSR;使用這兩條只能可以實現對程序狀態寄存器的狀態修改操作。

  在使用MSR指令對PSR進行修改操作時,要通過field設置狀態寄存器需要操作的域。狀態寄存器的32位被分為4個8位的域(filed)分別為:bits[31:24]條件域,用 F 表示; bits[23: 16]狀態域,用 S 表示;bits[15:8]預留域,用 X 表示;bits[7:0]控制域,用 C 表示。

;程序舉例:是能IRQ中斷
ENABLE_IRQ
  MRS  R0,CPSR  
  BIC   R0,R0,#080  ;將CPSR bit7 I 清零,是能IRQ
  MSR  CPSR_c,R0  ;典型的讀-改-回寫操作
  MOV   PC,LR

  

異常產生指令

ARM指令集提供了兩條產生異常的指令(中斷指令 SWI,斷點中斷指令 BKPT),通過這兩條指令可以用軟件的方法實現異常。 

中斷指令

軟件中斷指令 SWI (software Interrupt)用於產生軟中斷,實現從用戶模式切換到管理模式,CPSR保存到管理模式的 SPSR 中,執行轉移到 SWI 向量。

語法格式 SWI {<cond>} <immed_24>  immed_24 為中斷號

 

 

 

棧:按增長方向分為 遞增棧;遞減棧

按壓棧操作順序(sp位置)分為;滿棧和空棧

滿棧(FULL):sp指向棧頂元素

空棧(EMPTY):sp指向棧頂元素相鄰位置

根據棧的不同分類,將其尋址方式分為以下4種

1)滿遞減 FD(Full Descending)

2)空遞減 ED(Empty Descending)

3)滿遞增 FA(Full Asceding)

4)空遞增 EA(Empty Ascending)

 習慣上大都使用滿減棧。

壓棧出棧的幾種操作方式 

  ;初始化棧 
  mov sp, #0x40000018
MAIN
  mov r0, #1
  mov r1, #1
  bl FUNC          
  add r2, r0, r1
FUNC
  ;壓棧保護現場
  stmfd sp!, {r0, r1}
  mov r0, #2
  mov r1, #4
  sub r2, r1, r0
  ;出棧恢復現場
  ldmfd sp!, {r0, r1}
  mov pc, lr   

;初始化棧 
MAIN
  mov r0, #1
  mov r1, #1
  bl FUNC          
  add r2, r0, r1
FUNC
  ;壓棧保護現場
  stmfd sp!, {r0, r1, lr}
  mov r0, #2
  mov r1, #4
  sub r2, r1, r0
  ;出棧恢復現場
  ldmfd sp!, {r0, r1, pc}   

 

 

 

swp r0, r1, [r2]
 ;將r0中的數據放入內存地址是r2的地址空間,同時將r2中的值放入r1寄存器
 ;處理器與內存之間進行數據交換  交換過程不會被打斷

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM