1. 指令系统

ARM7TDMI-S

1.1 简介

  • ARM基于精简指令集RISC
  • 有32位ARM指令集和16位Thumb指令集,ARM指令集效率高代码密度低,Thumb密度较高,是ARM的子集
  • 所有ARM指令可有条件执行,而Thumb指令仅有一条指令(跳转指令)有条件执行功能
  • 两种指令集下的程序可相互调用

1.2 寻址方式分类

  • 根据指令中的地址字段实现寻找操作数地址的方式

  • 寄存器寻址

    • 操作数存在寄存器中,地址码字段是寄存器编号
    • MOV R1,R2 将R2的值存入R1
    • SUB R0,R1,R2 R0 = R1 - R2
  • 立即寻址
    • 操作码字段后面的地址吗部分就是操作数本身,操作数是指令的一部分
    • MOV R0,#0xFF00
  • 寄存器移位寻址
    • 第二个操作数是寄存器移位方式
    • MOV R0,R2,LSL #3 R2的值左移3位,放入R0
    • ANDS R1,R1,R2,LSL R3 R2的值左移R3里的数的位,并于R1相与存在R1中
  • 寄存器间接寻址
    • 所需的操作数保存在寄存器指定地址的存储单元中
    • LDR R1,[R2] 将R2指向的存储单元的数据读出,保存在R1中
    • SWP R1,R1,[R2] 将R1的值和R2指定的寄存器中的值交换
  • 基址寻址
    • 将基址寄存器的内容与指令中给出的偏移量相加
    • LDR R2,[R3,#0x0C] 读取R3+0x0C地址上的存储单元的内容存入R2,但不改变R3中的值
    • STR R1,[R0,#-4]! 将R1保存在R0-4指向的内存单元中,并更新R0中的值
  • 多寄存器寻址
    • 一次传送几个寄存器值
    • LDMIA R1!,{R2-R7,R12} 将R1指向的单元中的数据读出到R2~R7,R12中,每读出一个R1自动加4
    • 寄存器列表中的寄存器数不能多于16个,排列必须由大到小
  • 堆栈寻址
    • 后进先出
    • 堆栈寻址是隐含的,使用一个专门的寄存器(堆栈指针),指针指向栈顶
    • 生长方式分两种
      • 向上生长:向高地址生长
      • 向下生长:向低地址生长
    • 堆栈形式
      • 满堆栈:指针指向的是最后压入堆栈的有效数据项
      • 空堆栈:指针指向的是下一个待压入数据的空位置
    • 组合有四种堆栈的工作方式
      • 满递增 LDMFA STMFA
      • 空递增 LDMEA STMEA
      • 满递减 LDMFD STMFD
      • 空递减 LDMED STMED
  • 块拷贝寻址(多地址寻址)
    • 用于将一块数据从存储器的某一位置拷贝到另一位置
    • STMIA R0!,{R1-R7} 将R1-R7的数据存储到R0指向的地址空间中,每次R0,递增
  • 相对寻址
    • 基址寻址的变通,由程序计数器PC提供基准地址,指令中的地址码字段作为偏移量

1.3 指令集介绍

1.3.1指令格式

  1. <opcode> {<cond>} {S} <Rd>,<Rn>{,<operand2>}

< >项为必须项,{ }为可选项

opcode 指令助记符
cond 执行条件
S 是否影响CPSR寄存器的值
Rd 目标寄存器
Rn 第一个操作数的寄存器
operand2 第二个操作数

1.3.2 第二个操作数

  1. <opcode> {<cond>} {S} <Rd>,<Rn>{,<operand2>}

operand2:

  • #immed_8r 常数表达式

    • 该常数必须对应8位位图,即一个8位的常数通过循环右移偶数位得到
    • 判断一个常数是否合法:该常数是否小于8位,左移偶数位是否能放入低8位
  • Rm 寄存器方式

    • 操作数即为寄存器数值
  • Rm,shift 寄存器移位方式

    • 将寄存器的移位结果作为操作数,但Rm值保持不变(如果需要改变,使用!刷新)
移位操作码 说明
ASR #n 算术右移n位,首位复制空位补充
LSL #n 逻辑左移n位,0位补充
LSR #n 逻辑右移n位,0位补充
ROR #n 循环右移n位,溢出位空位补充
RRX 带扩展位的循环右移1位
Type Rs Type为移位的类型,Rs为偏移量寄存器,低8位有效

1.3.3 条件码

  1. <opcode>{<cond>}{S} <Rd>,<Rn>{,<operand2>}

cond:

  • 使用条件码可以实现高效的逻辑操作,提高代码效率
  • 所有的ARM指令都可条件执行,而Thumb指令只有跳转指令 B 具有条件执行功能
  • 如果指令不标明条件代码,默认为无条件执行( AL

image.png

CPSR 寄存器

image.png
示例:

  1. if(a > b)
  2. a++;
  3. else
  4. b++;

对应ASM

  1. CMP R0,R1 ;R0R1比较
  2. ADDHI R0,R0,#1 ;若R0>R1,则R0=R0+1
  3. ADDLS R1,R1,#1 ;若R0<=R1,则R1=R1+1

1.3.4 存储器访问指令

  • RISC处理器,对存储器的访问只能使用加载和存储指令
  • 分单寄存器操作指令和多寄存器操作指令

1.3.4.1 单寄存器存取

  • 单寄存器加载 | 助记符 | 说明 | 条件码位置 | | —- | —- | —- | | LDR | 加载字数据 | LDR{cond} | | LDRB | 加载无符号字节数据 | LDR{cond}B | | LDRT | 以用户模式加载字数据 | LDR{cond}T | | LDRBT | 以用户模式加载无符号字节数据 | LDR{cond}BT | | LDRH | 加载无符号半字数据 | LDR{cond}H | | LDRSB | 加载有符号字节数据 | LDR{cond}SB | | LDRSH | 加载有符号半字数据 | LDR{cond}SH |
  • 单寄存器存储 | 助记符 | 说明 | 条件码位置 | | —- | —- | —- | | STR | 存储字数据 | STR{cond} | | STRB | 存储字节数据 | STR{cond}B | | STRT | 以用户模式存储字数据 | STR{cond}T | | STRBT | 以用户模式存储字节数据 | STR{cond}BT | | STRH | 存储半字数据 | STR{cond}H |
  • LDR/STR指令用于对内存变量的访问,内存缓冲区数据的访问等
  • 使用LDR指令加载数据到PC寄存器,则实现程序的跳转
  • 可分为 字和无符号字节加载存储指令半字和有符号字节加载存储指令

字和无符号字节加载存储指令:

  • T为可选后缀,如果使用了T,即使处理器在特权模式下,存储系统也将访问看成是在用户模式下进行
  • T在用户模式下无效,不能与前索引偏移一起使用。 LDRT Rd,[Rn,#0x04]! 指令错误❌

寻址方式灵活:
基址寄存器(任一通用寄存器)+ 地址偏移量

⭕地址偏移量格式:

  1. 立即数 LDR R1,[R0,#0x12]
  2. 寄存器 LDR R1,[R0,R2]
  3. 寄存器及移位常数 LDR R1,[R0,R2,LSL #2]

⭕寻址方式的地址计算方法:

  1. 零偏移 LDR Rd,[Rn]
  2. 前索引偏移 LDR Rd,[Rn,#0x04]
  3. 程序相对偏移 LDR Rd,label
  4. 后索引偏移 LDR Rd,[Rn],#0x04

半字和有符号字节加载存储指令:

  • 偏移量格式、寻址方式与前者相同
  • 有符号位半字/字节加载是指用符号位加载扩展到32位
  • 无符号半字加载是指用零扩展到32位
  • 半字读写的指定地址必须为偶数,否则产生不可靠的结果

1.3.4.2多寄存器存取

LDM{cond}< 模式 > Rn{!},reglist{^}
STM{cond}< 模式 > Rn{!},reglist{^}

符号 说明
cond 执行条件
模式 地址增长模式
! 操作结束后,地址回写
reglist 寄存器列表
^ 加载/存储用户模式下的寄存器

image.png
IA与EA等效,IB和FA等效,DA和ED等效,DB和FD等效
使用多寄存器块取和块存时,
如果使用数据块式的操作,需要考虑对应关系(I和A均需要反转)
如果使用堆栈操作,不需要考虑对应关系,存取后缀一样即可

1.3.4.3 寄存器和存储器交换指令

SWP{cond}{B} Rd,Rm,[Rn]

符号 说明
B 可选,交换字节,否则交换字
Rd,Rm,Rn Rn指向地址的数存到Rd,Rm的数存入Rn指向的地址
若Rm=Rd 将Rd中的数与Rn指向的地址的数交换

1.3.5 数据处理指令

  • 数据处理指令只能对寄存器的内容操作,而不能对内存中的数据操作
  • 所有数据处理指令都可选择使用 S 后缀,影响状态标志

1.3.5.1 算术运算

  1. MOV{cond}{S} Rd,operand2 数据传送
  2. MVN{cond}{S} Rd,operand2 数据非传送
  3. ADD{cond}{S} Rd,Rn,operand2 加法运算指令
  4. SUB{cond}{S} Rd,Rn,operand2 减法运算指令
  5. RSB{cond}{S} Rd,Rn,operand2 逆向减法指令
  6. ADC{cond}{S} Rd,Rn,operand2 带进位加法指令
  7. SBC{cond}{S} Rd,Rn,operand2 带进位减法指令
  8. RSC{cond}{S} Rd,Rn,operand2 逆向带进位减法指令
  • 带进位指令一般用于32位加减法向64位扩展

1.3.5.2 逻辑运算

  1. AND{cond}{S} Rd,Rn,operand2 逻辑与操作指令
  2. ORR{cond}{S} Rd,Rn,operand2 逻辑或操作指令
  3. EOR{cond}{S} Rd,Rn,operand2 逻辑异或操作指令
  4. BIC{cond}{S} Rd,Rn,operand2 位清除指令

1.3.5.3 比较指令

  1. CMP{cond} Rd,operand2 比较指令指令
  2. CMN{cond} Rd,operand2 负数比较指令
  3. TST{cond} Rd,operand2 位测试指令
  4. TEQ{cond} Rd,operand2 相等测试指令
  • 实质上是减法,逻辑与,异或等运算
  • 与原运算相比的区别是,比较指令不保存计算结果,而将比较结果自动保存在CPSR中

1.3.5.4 乘法指令

  1. MUL{cond}{S} Rd,Rm,Rs 32位乘法指令
  2. MLA{cond}{S} Rd,Rm,Rs,Rn 32位乘加指令
  3. UMULL{cond}{S} RdLo,RdHi,Rm,Rs 64位无符号乘法指令
  4. UMLAL{cond}{S} RdLo,RdHi,Rm,Rs 64位无符号乘加指令
  5. SMULL{cond}{S} RdLo,RdHi,Rm,Rs 64位有符号乘法指令
  6. SMLAL{cond}{S} RdLo,RdHi,Rm,Rs 64位有符号乘加指令

1.3.5.5 ARM分支指令

  1. B{cond} Label 分支指令,跳转到指定地址±32MB范围
  2. BL{cond} Label 带链接的分支指令(调用子程序)
  3. 跳转前先将当前地址存至LR,然后再跳转至BL所指地址
  4. BX{cond} Label 带状态切换的分支指令(地址最低位存放要切换的状态标志)
  5. 跳转到Rm指定的地址执行
  6. Rm的最低位为1,跳转时自动将CPSR中的T置位,即把目标地址的代码解释为Thumb代码
  7. Rm的最低位为0,跳转时自动将CPSR中的T复位,即把目标地址的代码解释为ARM代码

1.3.6 杂项指令

1.3.6.1 软中断指令

  1. SWI{cond} immed_24 产生软中断,从其他模式切换到管理模式,实现用户程序调用操作系统的系统服务
  • SWI
    • 根据SWI指令传递的参数SWI异常处理程序可以做出相应的处理
    • 传递参数的方法有两种
    • 1.指令中的24位立即数指定了用户请求的服务类型
    • 2.指令中的24位立即数被忽略,用户请求的服务类型由寄存器R0的值决定,参数通过其它通用寄存器传递

1.3.6.2 状态寄存器指令

  1. MRS{cond} Rd,psr
  2. MSR{cond} psr_fields,#immed_8r
  3. MSR{cond} psr_fields,Rm
  • MRS
    • 仅有MRS指令可以对CPSR和SPSR进行读操作,了解当前处理器的工作状态
  • MSR
    • 仅有MSR指令可以对CPSR和SPSR进行写操作
    • 用于切换处理器,允许禁止中断等
field 含义
c 控制域屏蔽字节(psr[7-0])
x 扩展域屏蔽字节(psr[15-8])
s 状态域屏蔽字节(psr[23-16])
f 标志域屏蔽字节(psr[31-24])

1.3.7 伪指令

  • 伪指令不属于ARM指令,为了方便编程而定义
  • 编译时被等效为正常指令

    1.3.7.1 小范围地址读取

    1. ADR{cond} Rm,label
  • 将程序标号label的地址存入寄存器Rm

  • 编译时等效为pc的偏移地址存入Rm
  • 只能用一条ADD或SUB指令实现该伪指令功能,如果不能实现则产生错误,编译失败

    1.3.7.2 中等范围地址读取

    1. ADRL{cond} Rm,label
  • 比ADR伪指令更大的范围的地址

  • 编译时被替换为两条合适的指令

    1.3.7.3 大范围地址读取

  1. LDR{cond} Rm,=label
  2. LDR{cond} Rm,=#immed_8r
  • 将程序标号label或立即数到指定寄存器
  • 与ARM的基础指令相比,第二个参数要有=号

    1.3.7.4 空操作指令

  1. NOP
  • 用于延时