MENU

笔记-ARM常用指令集

April 7, 2021 • 阅读: 2750 • 笔记&折腾

因为毕设需要,接触了 ARM 指令集。记录一下。

<opcode>{<cond>} {S} <Rd>,<Rn>{,<opcode2>}

  • <>为必须项
  • {}为可选项
  • <opcode>为指令,必须项,如 LDR, STR
  • {<cond>}为指令执行条件,可选项, 如EQ, NE
  • {S} 是否影响CPSR寄存器的值,不写则不影响
  • Rd 目标寄存器
  • Rn 第一个操作数的寄存器
  • opcode2 第二个操作数

<opcode>

BIC

BIC指令的格式为: BIC{条件}{S} 目的寄存器,操作数1,操作数2。
BIC指令用于清除操作数1的某些位,并把结果放置到目的寄存器中。
操作数1应是一个寄存器, 操作数2可以是一个寄存器、被移位的寄存器、或一个立即数。
操作数2为32位的掩码,如果在 掩码中置了某一位1,则清除这一位。未设置的掩码位保持不变。
BIC R0, R0, # 0x1F ; (0x1F = 00011111 b),清除 R0 中的 bit[4:0] 位。

EOR

逻辑异或指令
EOR R0, R0, #3 ; 反转 R0 中的位 0 和 1
EOR R0, R0, #0x0F ; 将 R0 的第四位取反

MUL

乘法指令
MUL R1, R2, R3 ; R1 = R2 X R3

RSB

逆向相减指令
RSB R0, R1, R2 ; R0 = R2 -R1

ORR

或运算
ORR R0, R0 ,#3 ; R0 = R0 | 3

AND

与运算
AND R0, R1, R2 ; R0 = R1 & R2

MLA

乘-累加指令
MLA R1, R2, R3, R0 ; R1=R2×R3+R0

TST

位测试指令,检查是否设置了特定的位。操作数 1 是要测试的数据字而操作数 2 是一个位掩码,TST指令将操作数1与操作数2做逻辑与运算,和ANDS的区别就是不保存结果
注意 :与掩码逻辑与运算之后,全部测试位为0的时候,标志位Z = 1,此时EQ成立,反之则 Z = 0,NE成立。
TST R0, #1 ; 把 R0 与 1 位测试

CMN

CMN R0, #1 ; 把 R0 与 -1 比较

MOV

MOV R0, #3 ; 常数 3 传输到 R0 中。
MOV R0, R1 ; R1 的数据传输到 R0 。
MOV R1, R3, LSL, #3 ;将R3的数据 (R3)x8 存入 R1 中。
MOV PC, LR ;当 PC 为目标寄存器时,可以实现程序的跳转。

MVN

MVN R0, #3 ; 常数 3 取反再传输到 R0 中。
MVN R0, R1 ; R1 的数据取反传输到 R0 。
MVN R1, R3, LSL, #3 ;将R3的数据 (R3)x8 取反存入 R1 中。
MVN PC, LR ;当 PC 为目标寄存器时,可以实现程序的跳转。

LDR

LDR R0,[R1] ;将存储器地址为R1的字数据读入寄存器R0。
LDR R0,[R1,R2] ;将存储器地址为R1+R2的字数据读入寄存器R0。
LDR R0,[R1,#8] ;将存储器地址为R1+8的字数据读入寄存器R0。
LDR R0,[R1,R2] ! ;将存储器地址为R1+R2的字数据读入寄存器R0,并将新地址R1+R2写入R1。
LDR R0,[R1,#8] ! ;将存储器地址为R1+8的字数据读入寄存器R0,并将新地址R1+8写入R1。
LDR R0,[R1],R2 ;将存储器地址为R1的字数据读入寄存器R0,并将新地址R1+R2写入R1。
LDR R0,[R1,R2,LSL#2]! ;将存储器地址为R1+R2×4的字数据读入寄存器R0,并将新地址R1+R2×4写入R1。
LDR R0,[R1],R2,LSL#2 ;将存储器地址为R1的字数据读入寄存器R0,并将新地址R1+R2×4写入R1。

LDRB

操作的字节数据为源寄存器的低字节
LDRB R0,[R1] ;将存储器地址为R1的字节数据读入寄存器R0,并将R0的高24位清零。
LDRB R0,[R1,#8] ;将存储器地址为R1+8的字节数据读入寄存器R0,并将R0的高24位清零。

LDRH

操作的半字数据为源寄存器的低半字
LDRH R0,[R1] ;将存储器地址为R1的半字数据读入寄存器R0,并将R0的高16位清零。
LDRH R0,[R1,#8] ;将存储器地址为R1+8的半字数据读入寄存器R0,并将R0的高16位清零。
LDRH R0,[R1,R2] ;将存储器地址为R1+R2的半字数据读入寄存器R0,并将R0的高16位清零。

STR

STR R0,[R1],#8 ;将R0中的字数据写入以R1为地址的存储器中,并将新地址R1+8写入R1。
STR R0,[R1,#8] ;将R0中的字数据写入以R1+8为地址的存储器中。

STRB

操作的字节数据为源寄存器的低字节
STRB R0,[R1] ;将寄存器R0中的字节数据写入以R1为地址的存储器中。
STRB R0,[R1,#8] ;将寄存器R0中的字节数据写入以R1+8为地址的存储器中。

STRH

操作的半字数据为源寄存器的低半字
STRH R0,[R1] ;将寄存器R0中的半字数据写入以R1为地址的存储器中。
STRH R0,[R1,#8] ;将寄存器R0中的半字数据写入以R1+8为地址的存储器中。

STM

STMFD SP!, {R0} ;把R0保存到堆栈(sp指向的地址)中。

LDM

LDMFD SP!, {R0, R1, R2} ;把sp指向的3个连续地址段(应该是3*4=12字节(因为为r0,r1,r2都是32位))中的数据拷贝到r0,r1,r2这3个寄存器中去。

<cond>

EQ

  • 条件 : 相等
  • 标志位 : Z == 1

NE

  • 条件 : 不相等
  • 标志位 : Z == 0

CS/HS

  • 条件 : 进位,无符号数高于或相等
  • 标志位 : C == 1

CC/L0

  • 条件 : 未进位,无符号数低于
  • 标志位 : C == 0

MI

  • 条件 : 负数
  • 标志位 : N == 1

PL

  • 条件 : 非负数
  • 标志位 : N == 0

VS

  • 条件 : 溢出
  • 标志位 : V == 1

VC

  • 条件 : 未溢出
  • 标志位 : V == 0

HI

  • 条件 : 无符号数大于
  • 标志位 : C == 1 && Z == 0

LS

  • 条件 : 无符号数小于等于
  • 标志位 : C == 0 || Z == 1

GE

  • 条件 : 带符号数大于等于
  • 标志位 : N == V

LT

  • 条件 : 带符号数小于
  • 标志位 : N != V

GT

  • 条件 : 带符号数大于
  • 标志位 : Z == 0 && N == V

LE

  • 条件 : 带符号数小于等于
  • 标志位 : Z == 1 && N != V

AL

  • 条件 : 无条件执行
  • 标志位 : -

NV

  • 条件 : 从不执行
  • 标志位 : -

移位操作

LSL

逻辑左移,将操作数向左移位,低位补零,移除的高位进行丢弃
MOV R1, R0, LSL #2 ; r1 = r0 << 2

ASL

算术左移,将操作数向左移位,低位补零,移除的高位进行丢弃

LSR

逻辑右移,将操作数向右移位,高位补零,移除的低位进行丢弃

ASR

算术右移,将操作数向右移位,高位补零,移除的低位进行丢弃

ROR

循环右移,将操作数向右移位,移除的低位补高位

寄存器

r0~r3

子程序间传递参数

r4~r11

保存局部变量
Thumb 程序中,使用 r4~r7保存局部变量

r12

子程序间 scratch 寄存器,即 ip 寄存器

r13

栈指针,即sp

r14

连接寄存器(lr),保存子程序及其中断的返回地址

r15

程序计数器(pc)
正确读取了 PC 的值后,该值为当前指令地址加 8 个字节,即 PC 指向当前指令的下两条指令地址

Last Modified: April 11, 2021