ARM指令
1. ARM指令集
1.1 資料處理指令
助記符 | 操作 | 助記符 | 操作 |
MOV | 資料傳送 | AND | 邏輯與 |
MVN | 資料取反傳送 | ORR | 邏輯或 |
ADD | 加 | EOR | 邏輯異或 |
ADC | 帶進位的加 | BIC | 位清零 |
SUB | 減 | CMP | 比較 |
SBC | 帶借位的減 | CMN | 相反數比較 |
RSB | 逆向減 | TST | 位測試 |
RSC | 帶借位逆向減 | TEQ | 測試相等 |
/*****資料處理指令示例*****/
MOV R0, #0xFF //R0 = 0xFF
MOV R0, R0 //R0 = R0...NOP指令
MOV R0, R0, LSL#3 //R0 = R0 << 3
MOV PC, R14 //退出到調用者,用于普通函數傳回,PC即R15
MOVS PC, R14 //退出到調用者并恢複标志位,用于異常函數傳回
MVN R0, #4 //R0 = ~(4)
MVN R0, #0 //R0 = ~(0)
ADD R0, R1, R2 //R0 = R1 + R2
ADD R0, R1, #0xFF //R0 = R1 + 0xFF
ADD R0, R2, R3, LSL#1 //R0 = R2 + (R3 << 1)
ADDS R0, R4, R8 //加低端的字
ADCS R1, R5, R9 //加下1個字,帶進位
ADCS R2, R6, R10 //加第3個字,帶進位
ADCS R3, R7, R11 //加高端的字,帶進位
SUB R0, R1, R2 //R0 = R1 - R2
SUB R0, R1, #0xFF //R0 = R1 - 0xFF
SUB R0, R2, R3, LSL#1 //R0 = R2 - (R3 << 1)
SUBS R0, R0, R2 //低位相減結果存儲在R0,同時更新CPSR中對應的條件标志位
SBCS R1, R1, R3 //高位相減同時減去低位的借位 R1 = R1 - R3 - (!C)
RSB R2, R0, #0xFF //R2 = 0xFF - R0
RSBS R2, R0, #0 //
RSC R3, R1, #0 //
AND R0, R0, #0x03 //R0寄存器的0、1位不變,其他位清零
AND R2, R1, R3 //R2 = R1 & R3
AND R0, R0, #0x01 //R0 = R0 & 0x01
ORR R0, R0, #0x03 //R0寄存器的0、1位設定為1
ORR R0, R0, #0x0F //R0寄存器的低4位設定為1
EOR R0, R0, #0x03 //反轉R0中的第0和1位
EOR R1, R1, #0x0F //将R1的低4位取反
EOR R2, R1, R0 //R2 = R1 ^ R0
EORS R0, R5, #0x01 //将R5和0x01進行邏輯異或,結果儲存到R0,并根據執行結果更新标志位
BIC R0, R0, #0x1011 //清除R0中的位0、1和3,保持其餘的不變
BIC R1, R2, R3 //将R3的反碼和R2邏輯與,結果儲存到R1中
CMP R1, #10 //比較R1和立即數10并更新相關的标志位
CMP R1, R2 //比較R1和R2中的值并設定相關的标志位
CMN R0, #1 //
TST R0, #1 //測試R0的最低位是否為0
TEQ R0, R1 //比較R0和R1是否相等,不影響CPSR中的V位和C位
1.2 乘法指令
助記符 | 操作 | 助記符 | 操作 |
MUL | 乘(保留32位結果) | UMLAL | 無符号數長乘–累加 |
MLA | 乘(32位結果) | SMULL | 有符号數長乘 |
UMULL | 無符号數長乘 | SMLAL | 有符号數長乘–累加 |
/***** 乘法指令示例*****/
MUL R1, R2, R3 //R0 = R2 * R3
MULS R0, R3, R7 //R0 = R3 * R7,并根據運算結果更新CPSR中的N位和Z位
MLA R1, R2, R3, R0 //R1 = R2*R3 + R0
UMULL R0, R1, R5, R8 //R0 = R5*R8[31:0]; R1 = R5*R8[63:32]
UMLAL R0, R1, R5, R8 //R0 = R5*R8[31:0] + R0; R1 = R5*R8[63:32] + R1
SMULL R2, R3, R7, R6 //R2 = (R7*R6)[31:0]; R3 = (R7*R6)[63:32]
SMLAL R2, R3, R7, R6 //R2 = (R7*R6)[31:0] + R2; R3 = (R7*R6)[63:32] + R3
1.3 跳轉指令
助記符 | 操作 | 助記符 | 操作 |
B | 跳轉 | BL | 帶傳回的連接配接跳轉 |
BX | 跳轉并切換狀态 | BLX | 帶傳回的跳轉并切換狀态 |
/***** 跳轉指令示例*****/
B LABLE //跳轉到LABLE标号處
B 0x1234 //跳轉到絕對位址0x1234處
BL func //跳轉到子程式func處執行
BX R14 //從Thumb狀态傳回到ARM狀态
1.4 Load/Store指令
- 單寄存器的Load/Store指令
助記符 | 操作 | 助記符 | 操作 |
LDR | 把存儲器中的一個字裝入寄存器 | LDRBT | 使用者模式下将一個位元組裝入寄存器 |
STR | 将寄存器中的字儲存到存儲器 | STRBT | 使用者模式下将寄存器中的低8位位元組儲存到存儲器 |
LDRB | 把一個位元組裝入一個寄存器 | LDRT | 使用者模式下把一個字裝入寄存器 |
STRB | 将寄存器中的低8位位元組儲存到存儲器 | STRT | 使用者模式下将存儲器中的字儲存到寄存器 |
LDRH | 把一個半字裝入一個寄存器 | LDRSB | 把一個有符号位元組裝入寄存器 |
STRH | 将寄存器中的低16位半字儲存到存儲器 | LDRSH | 把一個有符号半字裝入寄存器 |
/***** 單寄存器的Load/Store指令示例*****/
LDR R1, [R0, #0x12] //将R0+0x12位址處的資料讀出,儲存到R1中
LDR R1, [R0, R2, LSL#2] //将R0+(R2<<2)位址處的資料讀出,儲存到R1中
LDR Rd, [Rn], #0x04 //Rn位址中的資料傳送到Rd,傳送完成後Rn=Rn+0x04
STR R1, [R0] //儲存變量
- 多寄存器的Load/Store指令
助記符 | 操作 | 助記符 | 操作 |
LDM | 裝載多個寄存器 | STM | 儲存多個寄存器 |
/*****多寄存器的Load/Store指令示例*****/
LDMIA R0!, {R3~R9} //加載R0指向的位址上的多字資料,儲存到R3~R9中,R0值更新
STMIA R1!, {R3~R9} //将R3~R9的資料存儲到R1指向的位址上,R1值更新
STMFD SP!, {R0~R7, LR} //現場儲存,将R0~R7,LR入棧
LDMFD SP!, {R0~R7, PC} ^ //恢複現場,異常處理傳回,同時恢複SPSR中的值到CPSR
- 單資料交換指令
助記符 | 操作 | 助記符 | 操作 |
SWP | 字交換 | SWPB | 位元組交換 |
/*****單資料交換指令示例*****/
SWP R1, R1, [R0] //将R1的内容與R0指向的存儲單元内容進行交換
SWPB R1, R2, [R0] //将R0指向的存儲單元内容讀取一位元組資料到R1中,在将R2寄存器中的資料存儲到R0指向的記憶體單元中
1.5 狀态寄存器傳輸指令
助記符 | 操作 | 助記符 | 操作 |
MRS | 把程式狀态寄存器(PSR)的值送到通用寄存器 | MSR | 把通用寄存器的值送到PSR或把一個立即數送到PSR |
/*****狀态寄存器傳輸指令示例*****/
MRS R1, CPSR //将CPSR狀态寄存器讀出,儲存到R1中
MRS R2, SPSR //将SPSR狀态寄存器讀出,儲存到R2中
MSR CPSR_c, 0xD3 //CPSR[7:0] = 0xD3, 切換到管理模式
MSR CPSR_cxsf, R3 //CPSR = R3
1.6 協處理指令
助記符 | 操作 | 助記符 | 操作 |
CDP | 協處理器資料操作 | MRC | 從協處理器寄存器傳資料到ARM寄存器 |
LDC | 裝載協處理器寄存器 | STC | 存儲協處理器寄存器 |
MCR | 從ARM寄存器傳資料到協處理器寄存器 |
1.7 異常産生指令
助記符 | 操作 | 助記符 | 操作 |
SWI | 軟中斷指令 | BKPT | 斷點中斷指令 |
/*****異常産生指令示例*****/
SWI 0 //産生軟中斷,中斷立即數為0
SWI 0x123456 //産生軟中斷,中斷立即數為0x123456
2. ARM指令的尋址方式
2.1 資料處理指令操作數的尋址方式
ARM資料處理指令的基本文法格式如下示:
<opcode> {<cond>} {S} <Rd>, <Rn>, <shifter_operand>
- 立即數尋址:指令中的第二操作數<shifter_operand>是立即數
/*****立即數尋址示例*****/
//下面是一些應用立即數的指令
MOV R0, #0 //送0到R0
ADD R3, R3, #1 //R3的值加1
CMP R7, #1000 //R7的值和1000比較
BIC R9, R8, #0xff00 //将R8中8~15位清零,結果儲存在R9中
- 寄存器尋址:指令中的第二操作數<shifter_operand>是寄存器中的值
/*****寄存器尋址示例*****/
MOV R2, R0 //R0的值送R2
ADD R4, R3, R2 //R2加R3,結果送R4
CMP R7, R8 //比較R7和R8的值
- 寄存器移位尋址:指令中的第二操作數<shifter_operand>是由寄存器中的值移位得到
/*****寄存器移位尋址示例*****/
//下面是使用移位操作的例子
ADD R2, R0, R1, LSR#5
MOV R1, R0, LSL#1
RSB R9, R5, R5, LSL#1
2.2 字及無符号位元組的Load/Store指令的尋址方式
- 寄存器間接尋址:将位址放在一個通用寄存器中,即所需要的操作數儲存在寄存器指定位址的存儲單元中,即寄存器中的值為操作數的位址指針。寄存器間接尋址字及無符号位元組的Load/Store指令文法格式如下示:
LDR|STR {<cond>} {B} {T} <Rd>, [Rm]
/*****寄存器間接尋址示例*****/
LDR R1, [R2] //将R2中的數值作為位址,取出此位址中的資料儲存在R1中
STR R1, [R2] //将R2中的數值作為位址,取出R1中的值存入R2所指向的位址
- 基址變址尋址:是将基位址寄存器的内容與指令中給出的偏移量相加,形成操作數的有效位址。基址變址尋址的Load/Store指令文法格式如下示
LDR|STR {<cond>} {B} {T} <Rd>, [Rm, ±<addressing_mode>]
/*****基址變址尋址示例*****/
LDR R1, [R0, #0x0f] //将R0中的數值加0x0f作為位址,取出此位址的數值儲存在R1中
STR R1, [R0, #-2] //将R0中的數值減2作為位址,把R1中的内容儲存到此位址位置
STR R1, [R0, +R2] //将R0的值加上R2的值作為位址,把R1的内容儲存在該位址中
2.3 批量Load/Store指令的尋址方式
- 多寄存器/塊拷貝尋址:将一片連續記憶體單元的資料加載到通用寄存器組中或将一組通用寄存器的資料存儲到連續的記憶體單元中。該類的指令文法格式如下示:
LDM|STM {<cond>} <addressing_mode> <Rn> { ! }, < registers/>< ^/>
/*****多寄存器/塊拷貝尋址示例*****/
STMIA R0!, {R1-R7} //将R1~R7的資料儲存到R0所指向的存儲器中,R0的值之後增加,增長方向為向上增長,類似于C語言中的i++
STMIB RO!, {R1-R7} //R0的值先增加,後将R1~R7的資料儲存到R0所指向的存儲器中,增長方向為向上增長,類似于C語言中的++i
STMDA R0!, {R1-R7} //将R1~R7的資料儲存到R0所指向的存儲器中,R0的值之後減少,增長方向為向下增長,類似于C語言中的i--
STMDB RO!, {R1-R7} //R0的值先減少,後将R1~R7的資料儲存到R0所指向的存儲器中,增長方向為向下增長,類似于C語言中的--i
- 堆棧操作尋址方式:對于堆棧的操作,資料寫入記憶體和從記憶體中讀出要使用不同的尋址模式,因為進棧操作和出棧操作要在不同的方向上調整堆棧操作
根據不同的尋址方式,堆棧可分為:Full棧、Empty棧、遞減棧、遞增棧
根據堆棧的不同種類,尋址方式可分為:滿遞減FD、空遞減ED、滿遞增FA、空遞增EA
2.4 相對尋址
相對尋址是基址尋址的一種變通,由程式計數器PC提供基準位址,指令中的位址碼字段作為偏移量,兩者相加後得到的位址即為操作數的有效位址。有 B 和 BL 指令
/*****相對尋址示例*****/
BL FUN1 //調用到FUN1子程式
B LOOP //條件跳轉到LOOP标号處
關注我的公衆号,共同交流學習嵌入式開發相關技術: