第三章 ARM指令集
3.1 ARM指令集簡介
- ARM微處理器的ARM指令集 ,所有的指令長度都是32位 ,并且大多數指令都在一個單獨指令周期內執行。
- 主要特點:
- 指令是條件執行的
- ARM微處理器的指令集是加載/存儲型的
- 在多寄存器操作指令中一次最多可以完成 16個寄存器的數據傳送
- 主要特點:
3.1.1 ARM指令格式
一、 ARM指令格式
<opcode>{<Condition>}{S} {<Rd>}{,<Rn>}{,<Operand2>}
-
格式中
< >
的內容必不可少,{ }
中的內容可省略。<opcode>
表示操作碼,如ADD表示算術加法{<cond>}
表示指令執行的條件域,如EQ、NE等{S}
決定指令的執行結果是否影響CPSR的值,使用該后綴則指令執行的結將果影響CPSR的值,否則不影響。<Rd>
表示目標或源寄存器<Rn>
表示第一個操作數,為寄存器<Operand2>
表示第二個操作數,可以是立即數、寄存器和寄存器移位操作數
-
除了
<opcode>
其余域都可以選擇使用。 -
舉例
例如: 指令ADDEQS R0,R1,#8;操作碼為ADD,條件域cond為EQ,S表示該指令的執行影響CPSR寄存器的值,目的寄存器Rd為R0,第一個操作數寄存器Rn為R1,第二個操作數OP2為立即數#8。執行結果:R0 = R1+ 8
二、 指令的機器碼
- 從形式上看,ARM指令在機器中的表示格式是用32位的二進制數表示。
- 如ARM中有一條指令為:
ADDEQS R0, R1, #8
- 其二進制代碼形式為
- 如ARM中有一條指令為:
31~28 | 27~25 | 24~21 | 20 | 19~16 | 15~12 | 11~0 |
---|---|---|---|---|---|---|
0000 | 001 | 0100 | 1 | 0001 | 0000 | 000000001000 |
cond | opcode | s | Rn | Rd | Op2 |
-
ARM指令一般可以分為5個域
- 第1個域–4位
- 是4位[31:28]的條件碼域,4位條件碼共有16種組合
- 第2個域–8位
- 是指令代碼域[27:20],除了指令編碼外,還包含幾個很重要的指令特征和可選后綴的編碼
- 第3個域–4位
- 是第1個操作數寄存器Rn,是4位[19:16],為R0~R15共16個寄存器編碼
- 第4個域–4位
- 是目標或源寄存器Rd,是4位[15:12],為R0~R15共16個寄存器編碼
- 第5個域–12位
- 是第二個操作數[11:0]。
- 第1個域–4位
三、指令的可選后綴
-
S后綴
- 指令中使用S后綴時,指令執行后,CPSR的條件標志位將被刷新
- 不使用S后綴時,指令執行后,CPSR的條件標志將不會發生變化。
例:假設R0=0x1,R3=0x3,指令執行之前CPSR部分標志位為 nZcv,分別執行如下指令CPSR的值有何變化?SUB R1,R0,R3SUBS R1,R0,R3
- 分析:
- 執行第1條指令對于標志寄存器的值沒有任何影響,因此CPSR的值不變。
- 執行第2條指令后CPSR=Nzcv。
-
!后綴
-
如果指令地址表達式中不含!后綴,則基址寄存器中的地址值不會發生變化。
-
指令中的地址表達式中含有!后綴時,指令執行后,基址寄存器中的地址值將發生變化,變化的結果如下:
- 基址寄存器中的值(指令執行后)=指令執行前的值+地址偏移量
例:分別執行下面兩條指令有何區別?LDR R3,[R0,#4] LDR R3,[R0,#4]!
- 分析:
- 第1條指令沒有!后綴,指令的結果是把R0加4作為地址指針,把這個指針所指向的地址單元所存儲的數據讀入R3,R0的值不變
- 第2條指令除了實現以上操作外,還把R0+4的結果送到R0中
-
使用!后綴需要注意如下事項:
- !后綴必須緊跟在地址表達式后面,而地址表達式要有明確的地址偏移量
- !后綴不能用于R15(PC)的后面
- 當用在單個地址寄存器后面時,必須確信這個寄存器有隱性的偏移量
- 例如“STMIA R7!, {R0 – R3}”
- 此時地址基址寄存器R7的隱性偏移量是16字節(因為連續壓棧了4個寄存器的值,每一個寄存器的值為4字節長度,即一個字)
- 如果R7的初始值為 0X40000000,則該語句結束后為0X40000010
- 例如“STMIA R7!, {R0 – R3}”
-
-
B后綴
- 指令所涉及的數據是一個字節,不是一個字或半字
LDR R4,[R0]R4=[R0],指令傳送一個字 LDRB R4,[R0]R4=[R0],指令傳送一個字節 LDREQB R4,[R0]如果相等則執行,R4=[R0],指令傳送一個字節
3.1.2 ARM指令的條件碼
-
當處理器工作在 ARM狀態時,幾乎所有的指令均能根據CPSR中的條件標志位的狀態和指令的條件域有條件地執行。
- 當指令的執行條件滿足時,指令被執行,否則指令被忽略
- 條件后綴只影響指令是否執行,不影響指令的內容
-
ARM指令的條件碼和助記符如下表所示:(不用記)
條件碼 條件碼助記符 CPSR中條件標志位值 含義 0000 EQ Z=1 相等 0001 NE Z=0 不相等 0010 CS/HS C=1 無符號數大于或等于 0011 CC/LO C=0 無符號數小于 0100 MI N=1 負數 0101 PL N=0 正數或零 0110 VS V=1 溢出 0111 VC V=0 未溢出 1000 HI C=1且Z=0 無符號數大于 1001 LS C=0或Z=1 無符號數小于或等于 1010 GE N=V 帶符號數大于或等于 1011 LT N!=V 帶符號數小于 1100 GT Z=0且N=V 帶符號數大于 1101 LE Z=1或N!=V 帶符號數小于或等于 1110 AL 無條件執行 1111 NV ARMV3之前 從不執行(不要使用) - 條件后綴和S后綴的關系
- 如果既有條件后綴又有S后綴,則書寫時S排在后面
- 如:
ADDEQS R1,R0,R2
- 該指令在Z=1時執行,將R0+R2的值放入R1,同時刷新條件標志位
- 如:
- 條件后綴是要測試條件標志位,而S后綴是要刷新條件標志位
- 條件后綴要測試的是執行前的標志位,而S后綴是依據指令的結果改變條件標志
- 如果既有條件后綴又有S后綴,則書寫時S排在后面
- 條件后綴和S后綴的關系
3.1.3 ARM指令分類
- ARM 指令可以分為:分支指令、數據處理指令、存儲訪問指令、協處理器指令、雜項指令五類。
- 分支指令:分支指令用于控制程序的執行流程、實現ARM代碼與Thumb代碼之間進行切換。
- 數據處理指令:數據處理指令在通用寄存器上執行計算
- 主要分為3種:算術/邏輯指令、比較指令和乘法指令。
- 存儲訪問指令:用于 加載/存儲 存放于MCU片外存儲系統中的數據。
- 加載指令用于從內存中讀取數據放入寄存器中
- 存儲指令用于將寄存器中的數據保存到內存中
- 協處理器指令:ARM協處理器指令用于控制外部的協處理器。包括:
- 數據處理指令:啟動一個協處理器專用的內部操作。
- 數據轉移指令:使數據在協處理器和存儲器之間進行轉移。
- 寄存器轉移指令:協處理器值轉移到ARM寄存器或ARM寄存器的值轉移到協處理器。
- 雜項指令:包括狀態寄存器轉移指令和異常中斷產生指令。
- 狀態寄存器轉移指令
- 將CPSR或SPSR的內容轉移到一個通用寄存器,或者反過來將通用寄存器的內容寫入CPSR或SPSR寄存器
- ARM有兩條異常中斷產生指令,分別為 軟中斷指令SWI 和 斷點中斷指令BKPT
- 狀態寄存器轉移指令
3.2 指令尋址方式
3.2.1 立即數尋址
-
立即數尋址也叫立即尋址,操作數本身就在指令中給出,取出指令也就取到了操作數。這個操作數被稱為立即數,對應的尋址方式也就叫做立即數尋址。
-
立即數要求以“#”為前綴
- 對于以十六進制表示的立即數,還要求在“#”后加上**“0x”或“&”**
- 對于以二進制表示的立即數,要求在“#”后加上**“0b”**
- 對于以十進制表示的立即數,要求在“#”后加上**“0d”或缺省**
-
舉例
-
MOV R0, #15 ; R0←#15
-
此指令是將立即數15傳送到R0中,該指令的機器編碼為E3A0000FH(H表示16進制)
-
由指令編碼中0x00F即可得到一個32位的立即0x0000000FH,這個數再送入R0
-
-
Q:如何在指令編碼中表達32位立即數?
-
A:
-
-
3.2.2 寄存器尋址
- 寄存器尋址就是利用寄存器中的數值作為操作數,這種尋址方式是各類微處理器經常采用的一種方式,也是一種執行效率較高的尋址方式
- 例:
- MOV R1,R2 ;R1←R2
- ADD R0,R1,R2 ;R0←R1+R2
- 例:
3.2.3 寄存器移位尋址
- 當第二操作數為寄存器型時,在執行寄存器尋址操作時,也可以對第二操作數寄存器進行移位,此時第二操作數形式為:
- ADD Rd, Rn, Rm,{<shift>}
- 其中:
- Rm:稱為第二操作數寄存器
- <shift>:用來指定移位類型和移位位數,有兩種形式:
- 5位立即數(其值小于32)
- 寄存器(用Rs表示)(其值小于32)
- 其中:
- ADD Rd, Rn, Rm,{<shift>}
- 在指令執行時,將寄存器移位后的內容,作為第二操作數參與運算。
- 例如指令:
- ADD R3,R2,R1,LSR #2 ;R3←R2+(R1右移2位)
- ADD R3,R2,R1,LSR R0 ;R3←R2+(R1右移R0位)
- 例如指令:
- 第二操作數的移位方式
- LSL 邏輯左移 :
- 邏輯左移,空出的最低有效位用0填充。
- SUB R3,R2,R1,LSL #2 ;R3←R2-(R1左移2位)
- LSR 邏輯右移 :
- 邏輯右移,空出的最高有效位用0填充。
- SUB R3,R2,R1,LSR R0 ;R3←R2-(R1右移R0位)
- ASL 算術左移 :
- 算術左移,由于左移空出的有效位用0填充,因此它與LSL同義。
- ASR 算術右移 :
- 算術右移 (Arithmetic Shift Right) 。算術移位的對象是帶符號數,移位過程中必須保持操作數的符號不變。如果源操作數是正數,空出的最高有效位用0填充,如果是負數用1填充。
- ROR 循環右移
- 循環右移(Rotate Right),移出的字的最低有效位依次填入空出的最高有效位
- RRX 帶擴展的循環右移
- 帶進位位的循環右移(Rotate Right Extended) 。將寄存器的內容循環右移1位,空位用原來C標志位填充
- SUB R3,R2,R1,RRX ;R3←R2-(R1帶進位位循環右移1位)
- LSL 邏輯左移 :
- 第二操作數的移位位數
- 移位位數可以用立即數方式或者寄存器方式給出,其值均小于32,應為0—31。
- 如下所示:
- ADD R3,R2,R1,LSR #2 ;R3=R2+(R1右移2位)
- ADD R3,R2,R1,LSR R4 ;R3=R2+(R1右移R4位)
- 寄存器R1的內容分別邏輯右移2位、R4位,再與寄存器R2的內容相加,結果放入R3中。
3.2.4 寄存器間接尋址
- 寄存器間接尋址就是以寄存器中的值作為操作數的地址,而操作數本身存放在存儲器中。
- 例:LDR R0,[R4] ;R0←[R4]
3.2.5 基址變址尋址
-
變址尋址
-
也叫基址變址尋址:將基址寄存器的內容與指令中給出的地址偏移量相加,得到操作數所在的存儲器的有效地址。
-
變址尋址方式常用于訪問某基地址附近的地址單元。(4K范圍的偏移)
- 例如: LDR R0,[R1,#4] ;R0←mem32[R1+4]
-
-
加偏移地址的方式
-
前變址模式(不修改基址寄存器):
-
先基址+偏址,生成操作數地址,再做指令指定的操作。也叫前索引偏移。
-
-
自動變址模式(修改基址寄存器):
- 先基址+偏址,生成操作數地址,做指令指定的操作
- 然后自動修改基址寄存器。
- 例如:LDR R0,[R1,#4]!
- 先 R0←mem32 [R1+4]
- 然后 R1←R1+4
- ! 表示更新基址寄存器。
- 例如:LDR R0,[R1,#4]!
-
后變址模式(修改基址寄存器):
-
基址寄存器不加偏移作為操作數地址。
-
完成指令操作后,用(基址+偏移)的值修改基址寄存器
-
即先用基地址傳數,然后修改基地址(基址+偏移),也叫后索引偏移
-
-
-
偏移地址形式
-
可以是一個立即數,也可以是另一個寄存器,并且還可以是寄存器移位操作。
- 常用的是立即數偏移的形式。
-
如下所示:
-
LDR R2,[R3,#0X0C] ;R2< —[R3+0X0C]
-
STR R1,[R0,#-0x4]!
- ;R1 —>mem32[R0-4],
- ;R0=R0-4
-
LDR r0,[r1,r2] ;r0<—mem32[r1+r2]
-
LDR r0,[r1,r2,LSL #2] ;r0<—mem32[r1+r2*4]]
-
-
3.2.6 多寄存器尋址
- 采用多寄存器尋址方式,一條指令可以完成多個寄存器值的傳送。
- 這種尋址方式是多寄存器傳送指令 LDM/STM 的尋址方式,這種尋址方式中用一條指令最多可傳送16個通用寄存器的值。
- 連續的寄存器間用
-
連接,否則用,
分隔。- LDMIA R0!,{R1-R4} ;R1←**[R0]、R2←[R0+4]、R3←[R0+8]、R4←[R0+12]**
- 注意:
- 對于所有LDM/STM指令而言,寄存器序號低的,在低地址單元,序號大的在高地址單元!
- 與書寫順序無關!
?
- 4種尋址操作
- LDMIA/STMIA Increment After(先傳送,后地址加4)
- LDMIB/STMIB Increment Before(先地址加4 ,后傳送)
- LDMDA/STMDA Decrement After(先傳送,后地址減4)
- LDMDB/STMDB Decrement Before (先地址減4,后傳送)
3.2.7 堆棧尋址
-
堆棧是一種數據結構,按后進先出(Last In First Out, LIFO)的方式工作,使用一個稱作堆棧指針的專用寄存器指示當前的操作位置,堆棧指針總是指向棧頂。
-
堆棧可分為兩種增長方式:
- 向上生長:向高地址方向生長,稱為遞增堆棧
- 向下生長:向低地址方向生長,稱為遞減堆棧
-
根據堆棧指針指向的數據位置的不同,可分為:
- 滿堆棧:堆棧指針指向最后壓入堆棧的有效數據項,稱為滿堆棧;
- 空堆棧:堆棧指針指向下一個待壓入數據的空位置,稱為空堆棧。
-
這樣就有4種類型的堆棧表示遞增和遞減的滿和空堆棧的各種組合。
- 四種類型的堆棧工作方式
- 滿遞增堆棧FA(Full Ascending):堆棧指針指向最后壓入的數據,且由低地址向高地址生長。
- 滿遞減堆棧FD(Full Descending) :堆棧指針指向最后壓入的數據,且由高地址向低地址生長。
- 空遞增堆棧EA(Empty Ascending):堆棧指針指向下一個將要放入數據的空位置,且由低地址向高地址生長。
- 空遞減堆棧ED(Empty Descending):堆棧指針指向下一個將要放入數據的空位置,且由高地址向低地址生長。
- 也就是說上面的遞增遞減都指的是堆棧生長方向,即入棧時遞增還是遞減
- 四種類型的堆棧工作方式
3.2.8 相對尋址
- 與基址變址尋址方式相類似,相對尋址以程序計數器PC的當前值為基地址,指令中的地址標號作為偏移量,將兩者相加之后得到操作數的有效地址。
3.3 ARM指令集
3.3.1 分支指令
-
在ARM中有兩種方式可以實現程序的跳轉:
- 一種是使用分支轉移指令直接跳轉;
- 另一種則是直接向PC寄存器賦值來實現跳轉。
-
ARM的分支轉移指令,可以從當前指令向前或向后的32MB的地址空間跳轉,根據完成的功能它可以分為以下4種
一、B & BL
-
B 指令與 BL 指令的編碼格式如下:
- 從編碼中看到L控制了PC與LR寄存器之間的開關。
- 當L=0 時,該開關斷開,指令為B指令;
- 當L=1時,該開關接通,指令為BL指令。
- Signed_immed_24表示24位有符號的立即數(偏移量)
- 從編碼中看到L控制了PC與LR寄存器之間的開關。
-
B 和 BL 指令的助記符格式為:
- B{<cond>} <target>和BL{<cond>} <target>
- cond表示指令執行條件
- target表示跳轉地址
- 功能:跳轉到指定地址執行,地址范圍限制在當前PC寄存器所指向的指令地址的±32MB范圍
- 跳轉指令也叫程序轉移指令。
- 寫匯編程序時,可以跳轉到一個絕對地址,如:
- B 0x1234 (注: B #0x1234是錯誤的 )
- 編譯器會把該絕對地址轉換為相對地址放入指令中
- B{<cond>} <target>和BL{<cond>} <target>
-
signed_immed_24 間接提供目標地址,真正的目標地址是由處理器根據這個有符號數和當前的PC值計算出來的。
- 具體計算為:
- 先將 signed_immed_24 左移兩位(即具有26位的偏移量),并擴展為32位有符號數
- 然后再將這32位有符號數與 PC 的當前值相加,得到實際的跳轉地址。
- 因此B 和 BL 指令轉移的偏移量為 26 位,即轉移的跨度為前后 32MB 地址空間
- 具體計算為:
-
B和BL的區別:
- BL在跳轉之前會把BL指令的下一條指令地址(斷點地址)保存到連接寄存器 LR(R14),因此程序在必要的時候可以通過將 LR 的內容加載到 PC 中,使程序返回到跳轉點。
- BL 指令經常被用來調用一個子程序。
二、BX
-
BX 指令的格式:
- BX{<cond>} Rm
- cond表示指令執行條件
- Rm寄存器,值是絕對地址值,不是偏移量,在指令執行后,Rm中的地址值與#0XFFFF FFFE 進行 “與” 運算,再被復制到程序計數器PC。
- Rm[0]為1時,強制程序從ARM指令狀態跳轉到Thumb指令狀態。
- Rm[0]為0時,強制程序從Thumb 指令狀態跳轉到ARM指令狀態。
- 功能: 跳轉到指令中所指定的目標地址,并實現狀態切換。(T<-Rm[0])
-
指令編碼格式
三、BLX
- BLX 指令的格式有兩種:
- BLX <target> 和 BLX{<cond>} Rm
- 以target方式提供目標地址的 BLX 指令的功能是:
- 把程序跳轉到指令中所指定的目標地址繼續執行,并同時將處理器的工作狀態從ARM狀態切換到Thumb狀態,并將下一條的地址保存到寄存器 LR 中。
- 以 Rm 方式提供目標地址的 BLX 指令,除了跳轉和下一條的地址保存到LR之外,也可進行狀態切換,但其切換的依據是Rm最低位的值。
- 如果值為0 ,則目標地址處應為 ARM指令
- 如果值為1 ,則目標地址處應為 Thumb 指令
- 以target方式提供目標地址的 BLX 指令的功能是:
- BLX <target> 和 BLX{<cond>} Rm
四、長跳轉
- 另一種實現指令跳轉的方式是通過直接向 PC 寄存器中寫入目標地址值,實現在4GB 地址空間中任意跳轉,這種跳轉又稱為長跳轉。
- 如果在長跳轉指令之前使用“MOV LR,PC” 等指令,可以保存將來返回的地址值,也就實現了在 4GB 的地址空間中的子程序調用。
3.3.2 數據處理指令
一、數據處理指令概述
-
ARM數據處理指令的功能
- 主要完成寄存器中數據的算術和邏輯運算操作。
-
ARM數據處理指令的特點
- 操作數來源:所有的操作數要么來自寄存器,要么來自立即數,不會來自存儲器。
- 操作結果:如果有結果,則結果一定是為32位寬、或64位寬(長乘法指令),并且放在一個或兩個寄存器中,不會寫入存儲器。
- 有第二個操作數(除了乘法指令)Operand2 :切記其三種形式:立即數、寄存器、寄存器移位。
- 乘法指令的操作數:全部是寄存器。
-
ARM數據處理指令分類
- 22條可分為5類:
- 算術運算指令:ADD ADC SUB SBC RSB RSC MUL MLA UMULL UMLAL SMULL SMLAL
- 邏輯運算指令:AND ORR EOR BIC
- 數據傳送指令:MOV MVN
- 比較指令:CMP CMN
- 測試指令:TST TEQ
- 上述指令只能對寄存器操作,不能針對存儲器
- 22條可分為5類:
-
數據處理指令對程序狀態寄存器CPSR的影響
-
指令中可以選擇s后綴,以影響狀態標志。
- 但是比較指令(CMP和CMN)和測試指令(TST和TEQ)不需要后綴S,它們總會直接影響CPSR中的狀態標志
-
關于恢復CPSR原值問題:
-
如果指令帶有S后綴(除了比較指令以外),同時又以PC為目標寄存器進行操作:
-
在異常模式下:則操作的同時從SPSR恢復CPSR
-
比如:
movs pc, #0xff /* cpsr = spsr; pc = 0xff */ adds pc, r1, #0xff00/* cpsr = spsr; pc = r1 + 0xff00 */ ands pc, r1, r2 /* cpsr = spsr; pc = r1 & r2; */
- 在user或者system模式:會產生不可預料的結果,因為在這兩種模式下沒有SPSR
-
-
-
-
數據處理指令的詳細列表(未含6條乘法指令)
-
指令編碼格式
- opcode為數據處理指令操作碼
- I用于區別立即數(I為1)或寄存器移位(I為0)
- S用于設置標志位
- Rn為第一操作數寄存器,Rd為目標寄存器
- operand2為第二個操作數,若指令不需要全部的可用操作數時(如MOV指令的Rn),不用的寄存器域應設置為0(由編譯器自動完成)
- 對于比較指令,b20位固定為1。
-
二、算術運算指令
-
加減運算指令
-
ADD——加法運算指令
-
指令格式:ADD{cond}{S} Rd,Rn,operand2
-
ADD指令把第1源操作數寄存器Rn和第2源操作數operand2相加后,將結果存放到目的寄存器 Rd
-
執行流程(后面的指令,流程類似便不再列舉了)
- 舉例:
- ADD R0,R1,R2 ;R0←(R1)+(R2)
- ADD R0,R1,#255 ;R0 ←(R1)+ 255
- ADD R0,R2,R3,LSL#1 ;R0 ←(R2) +(R3<<1)
- 舉例:
-
受影響的CPSR標志位 取值 N 寄存器Rd[31]被復制到N Z 如果Rd為0,則Z=1,否則Z=0 C 運算結果有進位C=1,否則C=0 V 運算結果有溢出V=1,否則V=0
-
-
ADC——帶進位加法指令
- 指令格式:ADC{cond}{S} Rd,Rn,operand2
- ADC指令將operand2的數據與Rn的值相加,再加上CPSR中的C條件標志位,結果保存到Rd寄存器。
- 標志位只修改 N、Z、C、V這4個標志位
- ADC通常用來實現字長大于32位的加法運算。
-
SUB——減法運算指令
-
指令格式:SUB{cond}{S} Rd,Rn,operand2
-
SUB指令用寄存器Rn減去operand2,結果保存到Rd中
-
受影響的CPSR標志位 取值 N 寄存器Rd[31]被復制到N Z 如果Rd為0則Z=1,否則Z=0 C 運算結果有借位則C=0,否則C=1 V 運算結果有溢出則V=1,否則V=0
-
-
SBC——帶進位減法指令
- 指令格式:SBC{cond}{S} Rd,Rn,operand2
- SBC指令用寄存器Rn減去operand2,再減去CPSR中的C條件標志位的反碼,結果保存到Rd中。
- 標志位的修改同 SUB。
- 該指令主要用于字長大于 32 位的數據的減法運算。
-
RSB——逆(反)向減法指令
- 指令格式:RSB{cond}{S} Rd,Rn,operand2
- RSB指令用operand2減去寄存器Rn,結果保存到Rd中。
-
RSC——帶進位反向減法指令
- 指令格式:RSC{cond}{S} Rd,Rn,operand2
- RSC 指令用寄存器operand2減去Rn,再減去CPSR中的C條件標志位的反碼,結果保存到Rd中。
-
-
乘法指令
-
ARM有兩類乘法指令:
-
32位的乘法指令,即乘法操作的結果為32位
-
64位的乘法指令,即乘法操作的結果為64位
-
-
MUL——32位乘法指令
-
指令格式:MUL{cond}{S} Rd,Rm,Rs
-
MUL指令將Rm和Rs中的值相乘,結果的低32位保存到Rd中(Rd ≠ Rm)
-
受影響的CPSR標志位 取值 N 寄存器Rd[31]被復制到N Z 如果Rd為0則Z=1,否則Z=0
-
-
MLA——32位乘加指令
- 格式:MLA{cond}{S} Rd,Rm,Rs,Rn
- 指令將Rm和Rs中的值相乘,再將乘積加上第3個操作數,結果的低32位保存到Rd中( Rd ≠ Rm )
- 標志位的修改同 MUL
-
UMULL——64位無符號乘法指令
-
指令格式:UMULL{cond}{S} RdLo,RdHi,Rm,Rs ; RdHi, RdLo← Rm*Rs
-
UMULL指令將Rm和Rs中的值作無符號數相乘,結果的低32位保存到RdLo中,高32位保存到RdHi中
-
受影響的CPSR標志位 取值 N 寄存器**RdHi[31]**被復制到N Z 如果RdHi且Rdlo為0,則Z=1,否則Z=0
-
-
**UMLAL——64位無符號乘加指令 **
- 指令格式:UMLAL{cond}{S} RdLo,RdHi,Rm,Rs ;RdHi, RdLo← Rm*Rs+ RdHi, RdLo
- UMLAL指令將Rm和Rs中的值作無符號數相乘,64位乘積與RdHi、RdLo相加,結果的低32位保存到RdLo中,而高32位保存到RdHi中
- 標志的修改同 UMULL
-
SMLAL—64位有符號乘加指令
- 指令格式:SMLAL{cond}{S} RdLo,RdHi,Rm,Rs ; RdHi, RdLo← Rm*Rs+ RdHi, RdLo
- SMLAL指令將Rm和Rs中的值作有符號數相乘,64位乘積與RdHi、RdLo相加,結果的低32位保存到RdLo中,高32位保存到RdHi中
- 標志的修改同 SMULL。
-
乘法指令的特點
- 不支持第2操作數為立即數
- 結果寄存器不能與第一源寄存器相同。
- Rd、RdHi、RdLo不能與Rm為同一寄存器。
- RdHi和RdLo不能為同一寄存器。
- 避免將R15定義為任一操作數或結果寄存器。
-
乘法指令對標志位的影響
- 對N標志位:
- 若結果是32位指令形式,Rd的第31位是標志位N
- 對于產生長結果的指令形式,RdHi的第31位是標志位N
- 對Z標志位:如果Rd或RdHi、RdLo為0,則標志位Z置位
- 對V標志位:乘法指令不影響V標志位
- 對C標志位: ARM v5及以上的版本不影響C標志位; ARM v5以前的版本,C標志位數值不確定
- 對N標志位:
-
指令編碼格式
- opcode為乘法指令操作碼
- S為設置標志位
- Rm為被乘數寄存器,Rs為乘數的寄存器
- Rn/RdLo用于MLA指令相加的寄存器或64位乘法指令的目標寄存器(低32位)。
- Rd/RdHi用于目標寄存器或64位乘法指令的目標寄存器(高32位)。
- 若指令不需要全部的可用操作數時(如MUL指令的Rn),不用的寄存器域應設置為0(由編譯器自動完成)。
-
三、邏輯運算指令(按位邏輯操作指令)
-
AND——邏輯“與”操作指令
-
指令格式:AND{cond}{S} Rd,Rn,operand2
-
AND指令將operand2的值與寄存器Rn的值**按位邏輯“與”**操作,結果保存到Rd中。
-
執行流程
-
受影響的CPSR標志位 取值 N 寄存器Rd[31]被復制到N Z 如果Rd為0則Z=1,否則Z=0 C 不影響C標志位 AND指令可用于提取寄存器中某些位的值,也可以用于把指定位清0
-
-
ORR——邏輯“或”操作指令
- 指令格式: ORR{cond}{S} Rd,Rn,operand2
- ORR指令將**operand2的值與寄存器Rn的值按位邏輯“或”**操作,結果保存到Rd中。
- ORR指令用于將寄存器中某些位的值設置成1
- 標志位的影響同AND。
-
EOR——邏輯“異或”操作指令
- 指令格式:EOR{cond}{S} Rd,Rn,operand2
- EOR指令將**operand2的值與寄存器Rn的值按位邏輯“異或”**操作,結果保存到Rd中。
- EOR指令可用于將寄存器中某些位的值取反
- 與0異或,該位值不變
- 與1異或,該位值被求反
- 標志位的影響同AND
-
BIC——位清除指令
- 指令格式:BIC{cond}{S} Rd,Rn,operand2
- BIC指令將寄存器Rn的值與operand2的值的反碼按位邏輯**“與”**操作,結果保存到Rd中。
- BIC指令可用于將寄存器中某些位的值清除為0
- 將某一位 與1 做BIC操作,該位值被清除為0 ;
- 將某一位 與0 做BIC操作,該位值不變。
四、數據傳送指令
-
MOV——數據傳送指令
-
指令格式:MOV{cond}{S} Rd,operand2
-
MOV指令將operand2傳送到目標寄存器Rd中。
-
受影響的CPSR標志位 取值 N 寄存器Rd[31]被復制到N Z 如果Rd為0,則Z=1,否則Z=0 C C=0 -
功能總結
- 寄存器之間傳送。
- 立即數傳送到寄存器中。(8位立即數位圖)
- 實現單純的移位操作。MOV Rd,Rd,LSL,#3
- 實現子程序調用、從子程序中返回。當PC寄存器作為目標寄存器時可以實現程序跳轉。
- 實現異常模式的返回,并把當前處理器模式的SPSR寄存器內容復制到CPSR中
- 例:MOVS PC,LR ;PC←LR,異常模式下返回,且CPSR←SPSR
-
-
MVN——數據求反傳送指令
- 指令格式:MVN{cond}{S} Rd,operand2
- MVN指令將operand2按位取反后傳送到目標寄存器Rd中。
五、比較指令
-
CMP——比較指令
-
指令格式:CMP{cond} Rn,operand2
-
CMP指令將寄存器Rn的值減去operand2的值,但不存儲運算結果,只根據操作的結果更新CPSR中的相應條件標志位,以便后面的指令根據相應的條件標志來判斷是否執行。
-
受影響的CPSR標志位 取值 N 運算結果的第31位被復制到N Z 運算結果為0則Z=1,否則Z=0 C 運算結果有借位則C=0,否則C=1 V 運算結果有溢出則V=1,否則V=0 -
比較類指令本身帶有更新 CPSR的功能,故在該指令中不能使用后綴 S
-
-
CMN——負數比較指令
- 指令格式:CMN{cond} Rn,operand2
- CMN指令將寄存器Rn的值減去operand2的負數(即加上operand2的值),但不存儲運算結果,只根據操作的結果更新CPSR中的相應條件標志位,以便后面的指令根據相應的條件標志來判斷是否執行。
六、測試指令
- TST——位測試指令
- 指令格式:TST{cond} Rn,operand2
- TST指令將寄存器Rn的值與operand2的值按位邏輯“與”操作,但不存儲運算結果,只根據操作的結果更新CPSR中的相應條件標志位。
- 該指令一般用來檢測是否設置了特定的位。
- TEQ——測試相等指令
- 指令格式:TEQ{cond} Rn,operand2
- TEQ指令將寄存器Rn的值與operand2的值**按位邏輯“異或”**操作,但不存儲運算結果,只根據操作的結果更新CPSR中的相應條件標志位,以便后面的指令根據相應的條件標志來判斷是否執行。
- 例子:
- TEQ R0,R1
- ;比較R0與R1是否相等
- ;(不影響V位和C位)
- 例子:
3.3.3 存儲器訪問指令
- ARM微處理器用加載/存儲指令訪問存儲器,實現在寄存器和存儲器之間傳送數據。
- 由于ARM處理器對外設寄存器、I/O映射空間與存儲器統一編址,因此,對外圍設備的I/O操作也用此類指令。
- 基本的加載/存儲指令僅有5條,分為3種:
- LDR和STR,單寄存器加載/存儲指令
- LDM和STM,多寄存器加載/存儲指令
- SWP,寄存器和存儲器數據交換指令
一、 單寄存器的存取指令
- 單寄存器加載/存儲指令是ARM在寄存器和存儲器間傳送單個字節和字的最靈活方式。
- 根據傳送數據的類型不同,單個寄存器存取指令又可以分為以下兩類:
- 單字和無符號字節的加載/存儲指令
- 半字和有符號字節的加載/存儲指令
-
單字和無符號字節的加載/存儲指令
-
LDR:指令從內存中取32位字或8位無符號字節數據放入寄存器
- 內存到寄存器
-
STR:指令將寄存器中的32位字或8位無符號字節數據保存到存儲器中。
- 寄存器到內存
-
注意:無符號字節加載時,用0將8位的操作數擴展到32位
-
指令格式
LDR{cond}{T} Rd,<地址>
;加載指定地址上的字數據,放入Rd中。STR{cond}{T} Rd,<地址>
;存儲Rd中字數據,到指定地址的存儲單元。LDR{cond}B{T} Rd,<地址>
;加載字節數據到Rd低8位數據位中,高24位為0。STR{cond}B{T} Rd,<地址>
;存儲Rd中字節數據, Rd中最低字節為傳送數據。- T后綴
- T為可選后綴,若指令有T,存儲系統將訪問看成是處理器在用戶模式下。
- 用于存儲器保護。
- 不能與后變址模式、自動變址模式一起使用(即不能改變基址寄存器值)。
- T在用戶模式下無效。
-
操作數尋址方式
-
LDR/STR指令為基址變址尋址(或寄存器間接尋址),由兩部分組成:
-
基地址部分:為一個基址寄存器,可以為任一個通用寄存器
-
偏移地址部分:這一部分非常靈活,實際就類似第二個操作數,可以有以下3種格式:
-
立即數:12位立即數是一個無符號的數值。這個數據可以加到基址寄存器,也可以從基址寄存器中減去這個數值。
-
指令舉例如下:
LDR R1,[R0,#0x10] ;將R0+0x10地址處的數據讀出, ;保存到R1中(R0的值不變) LDR R1,[R0,# -0x10] ;將R0-0x10地址處的數據讀出, ;保存到R1中(R0的值不變)
-
-
寄存器:寄存器中的數值(無符號數)可以加到基址寄存器,也可以從基址寄存器中減去這個數值。
-
指令舉例如下:
LDR R1,[R0,R2] ;將R0+R2地址處的數據讀出,保存到R1中 LDR R1,[R0,-R2] ;將R0-R2地址處的數據讀出,保存到R1中
-
-
寄存器及移位常數:寄存器移位后的值(無符號數)可以加到基址寄存器,也可以從基址寄存器中減去這個數值。
-
指令舉例如下:
LDR R1,[R0,R2,LSL #2];將R0+R2×4地址處的數據讀出,;保存到R1中(R0、R2的值不變) LDR R1,[R0,-R2,LSL #2];將R0-R2×4地址處的數據讀出,;保存到R1中(R0、R2的值不變)
- 注意:移位位數只能是5位的立即數,不能使用寄存器指定移位位數
-
-
-
-
-
指令編碼格式
-
-
半字和有符號字節的加載/存儲指令
-
這類LDR/STR指令可實現半字(有符號和無符號)、有符號字節數據的傳送。
-
特點:
- 偏移量格式、尋址方式與加載/存儲字和無符號字節指令基本相同
- 立即數偏移量限定在8位
- 寄存器偏移量不可經過移位得到。
-
指令格式
LDR {cond}SB Rd,<地址>
;加載指定地址上有符號字節到Rd中,高24位用符號位擴展LDR {cond}SH Rd,<地址>
;加載指定地址上的有符號半字到Rd中,高16位用符號位擴展LDR {cond}H Rd,<地址>
;加載無符號半字數據到Rd的低16位,高16位清零。STR{cond}H Rd,<地址>
;存儲Rd中的低16位半字數據。
-
兩點說明:
- 符號位
- 有符號字節或有符號半字的加載,用**“符號位”擴展到32位**
- 無符號半字傳送是用0擴展到32位
- 地址對齊
- 對半字傳送的地址必須為偶數。非半字對齊的半字加載將使Rd內容不可靠
- 非半字對齊的半字存儲將使指定地址的2字節存儲內容不可靠。
- 符號位
-
指令編碼格式
-
- 看PPT的例子P127-130
二、多寄存器的存取指令
-
LDM和STM指令可以實現在一組寄存器和一塊連續的內存單元之間存/取數據。
- LDM為加載多個寄存器(內存到寄存器)
- STM為存儲多個寄存器(**寄存器到內存)
-
這兩條指令,允許傳送16個寄存器R0—R15的任何子集或所有寄存器。
-
指令格式
LDM{cond}<模式> Rn{!},<reglist>{^}
STM{cond} <模式> Rn{!},<reglist>{^}
- 指令格式說明
- Rn:表示基址寄存器,裝有傳送數據的初始地址,Rn不允許為R15(即PC)
- Rn后綴 **“!” **:表示最后的地址寫回到Rn中
- reglist:表示寄存器列表,其中包含一個或多個寄存器。當寄存器不連續時,中間使用“,”隔開。
- 格式例子:{R1,R2,R6-R9}
- 列表寄存器和存儲器地址的關系規則:編號低的寄存器對應于存儲器中低地址單元,編號高的寄存器對應于存儲器中高地址單元
- 后綴 “^” 說明
- 寄存器列表不包含PC:
- 使用后綴“^”進行數據傳送時,加載/存儲的是用戶模式的寄存器,而不是當前模式的寄存器
- 寄存器列表包含有PC:
- 除了正常的多寄存器傳送外,還要將SPSR拷貝到CPSR中。該用法可用于異常處理返回。
- 禁用情況:后綴“^”不允許在用戶模式或系統模式下使用。 因為它們沒有SPSR
- 寄存器列表不包含PC:
- 當Rn在寄存器列表中且使用后綴“!”
- 對于STM指令,若Rn為寄存器列表中的最低序號的寄存器,則會將Rn的初值保存;
- 其它情況下Rn的編譯無法通過。
- 地址字對齊:這些指令尋址是字對齊的,即忽略地址位[1:0]。
-
指令編碼格式
-
模式項
-
LDM/STM的主要用途是現場保護、數據復制和參數傳送等。
-
其模式有如下8種(前面4種用于數據塊的傳輸(為存儲操作), 后面4種是堆棧操作):
類型 每次基址寄存器的操作 傳送起始地址 Rn序號的變化 IA 先傳送數據,后基地址加4 (Rn) 增加 IB 先基地址加4,后傳送數據 (Rn)+4 增加 DA 先傳送數據,后基地址減4 (Rn) 減少 DB 先基地址減4,后傳送數據 (Rn)-4 減少 類型 堆棧類型 彈出(pop)指令 壓入(push)指令 FA 遞增滿堆棧 LDMFA STMFA FD 遞減滿堆棧 LDMFD STMFD EA 遞增空堆棧 LDMEA STMEA ED 遞減空堆棧 LDMED STMED -
堆棧操作與批量傳輸對應
尋址方式 說明 pop =LDM push =STM FA 遞增滿 LDMFA LDMDA STMFA STMIB FD 遞減滿 LDMFD LDMIA STMFD STMDB EA 遞增空 LDMEA LDMDB STMEA STMIA ED 遞減空 LDMED LDMIB STMED STMDA
-
-
-
示例
- 這里能看出來序號高的寄存器一定會存/取地址高的地址
三、單寄存器交換指令(SWP)
-
SWP指令用于將一個存儲單元(該單元地址放在寄存器Rn中)的內容讀取到一個寄存器Rd中,同時將另一個寄存器Rm的內容寫入到該存儲單元中。
-
交換指令是一個原子操作,也就是說,在連續的總線操作中讀/寫一個存儲單元,在操作期間阻止其它任何指令對該存儲單元的讀寫
-
指令格式
SWP{cond}{B} Rd,Rm,[Rn]
- B為可選后綴,若有B,則交換無符號字節,否則交換32位字
- Rd為被加載的寄存器
- Rm的數據用于存儲到Rn所指的地址中,若Rm與Rd相同,則為寄存器與存儲器內容進行交換
- Rn為要進行數據交換的存儲器地址,Rn不能與Rd和Rm相同。
- 功能:將一個內存單元[Rn]的內容讀取到一個寄存器Rd中,同時將另一個寄存器Rm的內容寫入到該內存單元中
-
指令編碼格式
-
指令舉例
- SWP R1,R1,[R0];將R1的內容與R0指向的存儲單元的內容進行交換。
- SWPB R1,R2,[R0];將R0指向的存儲單元的內容讀取1字節數據到R1中(高24位清零),并將R2的內容寫入到該內存單元中(最低字節有效)
3.3.5 雜項指令
- 主要由兩種類型指令組成,程序狀態寄存器操作指令、中斷操作指令,一共有5條指令。
- 狀態寄存器操作指令:
- MRS:讀程序狀態寄存器指令
- MSR:寫程序狀態寄存器指令
- 異常中斷操作指令:
- SWI: 軟件中斷指令
- BKPT:斷點指令(v5T體系)
- CLZ: 前導0計數(v5T體系)
- 狀態寄存器操作指令:
一、程序狀態寄存器處理指令
- ARM指令中有兩條指令,用于在狀態寄存器和通用寄存器之間傳送數據。修改狀態寄存器一般是通過“讀取-修改-寫回”三個步驟的操作來實現的。
-
MRS–讀狀態寄存器指令
-
指令格式:
MRS{cond} Rd,psr
; Rd <- psr -
把**狀態寄存器psr(CPSR或SPSR)**的內容傳送到目標寄存器中。
- Rd —— 目標寄存器。Rd不允許為R15。
- psr —— CPSR或SPSR。
-
指令編碼格式
- 注意:在ARM處理器中,只有MRS指令可以將狀態寄存器CPSR或SPSR讀出到通用寄存器中。
-
-
MSR–寫狀態寄存器指令
-
在ARM處理器中,只有MSR指令可以直接設置狀態寄存器CPSR或SPSR。
-
指令格式如下:
-
MSR{cond} psr_fields,#immed
-
MSR{cond} psr_fields,Rm
-
其中:
-
psr:CPSR或SPSR
-
immed:要傳送到狀態寄存器指定域的8位立即數
-
Rm:要傳送到狀態寄存器指定域的數據的源寄存器
-
fields:指定傳送的區域。fields可以是以下的一種或多種:
-
c 控制域 (psr[7…0]);
-
x 擴展域(psr[15…8]);(暫未用)
-
s 狀態域 (psr[23…16]);(暫未用)
-
f 標志位域 (psr[31…24])。
-
-
-
-
指令舉例
- MSR CPSR_cxsf,R0 ;傳送R0的內容到CPSR
- MSR SPSR_cxsf,R0 ;傳送R0的內容到SPSR
- MSR CPSR_c,R0 ;傳送R0的內容到CPSR,但僅僅修改CPSR中的控制位域
- MSR CPSR_cfxs,R0 ;傳送R0的內容到CPSR,修改所有域
-
注 意:
- 控制域的修改問題:只有在特權模式下才能修改狀態寄存器的控制域[7:0],以實現處理器模式轉換,或設置開/關異常中斷 。
- T控制位的修改問題:程序中不能通過MSR指令,直接修改CPSR中的T控制位來實現ARM狀態/Thumb狀態的切換,必須使用BX指令完成處理器狀態的切換。
- 用戶模式下能夠修改的位:在用戶模式只能修改“標志位域”,不能對CPSR[23:0]做修改。
- S后綴的使用問題:在MRS/MSR指令中不可以使用S后綴
-
二、異常中斷產生指令
- 異常中斷指令可以分為以下幾種:
- SWI: 軟件中斷指令
- BKPT:斷點指令(v5T及以上體系)
- CLZ: 前導0計數(v5T及以上體系)
-
SWI——軟件中斷指令
-
軟件中斷指令SWI產生軟件異常中斷,用來實現用戶模式到特權模式的切換。
-
用于在用戶模式下對操作系統中特權模式的程序的調用;
-
它將處理器置于管理(svc)模式,中斷矢量地址為0x08。
-
指令格式如下:
SWI {<cond>} <24位立即數>
- 24位立即數,指定用戶程序調用系統例程的類型,相關參數通過寄存器傳遞,當指令中24位立即數被忽略時(立即數為0),用戶程序調用系統例程的類型由通用寄存器R0決定,同時參數通過其它寄存器傳遞
-
指令編碼格式
-
說明:
- 主要用于用戶程序調用操作系統的API。
- 參數傳遞通常有兩種方法:
- 指令中的24bit立即數指定API號,其它參數通過寄存器傳遞。
- 忽略指令中的24bit立即數,r0指定API號,其它參數通過其它寄存器傳遞。
-
舉例
- 軟中斷號在指令中,不傳遞其它參數:
- SWI 10 ;中斷類型號為10(注:沒有#號)
- SWI 0x123456 ;中斷類型號為0x123456
- 軟中斷號在指令中,其它參數在寄存器中傳遞:
- MOV R0,#34 ;準備參數
- SWI 12 ;調用12號軟中斷
- 不用指令中的立即數,軟中斷類型號和其它參數都在寄存器中傳遞:
- MOV R0,#12 ;準備中斷類型號
- MOV R1,#34 ;準備參數
- SWI 0 ;進入軟中斷。
- 軟中斷號在指令中,不傳遞其它參數:
-
-
BKPT——斷點指令(了解)
- 斷點中斷指令BKPT用于產生軟件斷點,供調試程序用。
- v5T及以上體系使用。
- 指令格式如下:
BKPT { immed_16}
- immed_16:16位的立即數。該立即數被調試軟件用來保存額外的斷點信息。
- 斷點指令用于軟件調試;它使處理器停止執行正常指令而進入相應的調試程序。
-
CLZ——前導0計數指令(了解)
-
前導0計數指令CLZ 對Rm中的前導0的個數進行計數,結果放到Rd中。
-
v5T及以上體系使用。
-
指令格式:
CLZ{<cond>} Rd, Rm
-
舉例如下:
MOV R2, #0X17C00 ;R2=0b0000 0000 0000 0001 0111 1100 0000 0000 CLZ R3, R2 ;R3=15
-