ARM寄存器及其汇编指令

ARM处理器

第一款RISC(精简指令集)微处理器,(arm)32位设计,但配有16位指令集(thumb)

32位和16位可以相互调用,且开销几乎为0

使用大量寄存器,功耗低,效率高

ps:具体发展,系列之类请参考百度百科:https://baike.baidu.com/item/arm/5907

arm寄存器

arm包括37个寄存器,都是32位

31个通用寄存器,6个状态寄存器

arm有7种处理器模式,每个模式中有一组相应的寄存器

在任何一种处理器模式下可见的寄存器包括15个通用寄存器(r0-r14),一个或者两个状态寄存器,程序技术器(pc)

所有寄存器中,有些是各模式公用的物理寄存器,有些是某个模式独立拥有的物理寄存器

七个处理器模式: 用户模式(User),快速中断模式(FIQ),普通中断模式(IRQ),管理模式(Svc),数据访问中止模

(Abort),未定义指令中止模式(Und),系统模式(Sys)

寄存器用途

r0 - r3:传参

r4 - r11:保存局部变量,但在thumb(16位程序)中,通常只能用r4-r7来保存局部变量

r12:ip寄存器

r13:栈帧,即sp

r14:lr,被称为连接寄存器,用于保存子程序以及中断的返回地址

r15:程序计数器,即pc,但由于arm使用的是三级流水线结构,所以我们读取正确的pc的值之后应该在该值基础上加八个字节,即指向pc下两条指令的地址

ps:关于三级流水线,另一片相关文章会具体解释

CPSR:当前程序状态寄存器,在任何模式下可以被访问。包含条件标志位、中断禁止位、当前处理器模式标志以及其他的一些控制和状态位。CPSR在用户编程时由于存储条件码。

SPSR:每一种模式下都有一个状态寄存器SPSR,用于保存CPSR的状态,以便异常返回后恢复异常发生时的工作状态。用户模式和系统模式不是异常状态,所以没有SPSR,在这两种模式下访问SPSR,将产生不可预知的后果。

CPSR详解:

image-20220402140909199

ps:长度为32

cpsr包括条件标志位、中断禁止位、当前处理器模式标志以及其他的一些控制和状态位

image-20220402140916144

通过上图就可以理解cpsr_cxsf的意思了

条件码标志

N:结果是有符号的二进制补码情况下,结果为负的话N=1,结果为非负的话N=0

Z:结果如果为零的话Z=1,结果非零的话Z=0

C:有多种情况

对于加法指令(包括比较指令CMN),产生进位的话C=1,否则C=0。

对于减法指令(包括比较指令CMP),如果产生借位,则C=0;否则C=1。

对于有移位操作的非法指令,C为移位操作中最后移出位的值。

对于其他指令,C通常不变。

ps:比较指令CMN与CMP其实才是算数指令,之后会有详解

V:对于加减法指令,在操作数和结果是有符号的整数时,如果发生溢出,则V=1;如果无溢出发生,则V=0;对于其他指令,V通常不发生变化

ARM指令集

指令格式

{} {S} , {,}

<>内是必须项,{}内是可选项,不写代表无条件执行

opcode 指令助记符,如LDR,STR 等

cond 执行条件,如EQ,NE 等

S 是否影响CPSR 寄存器的值,书写时影响CPSR,否则不影响

Rd 目标寄存器

Rn 第一个操作数的寄存器

operand2 第二个操作数

储存器访问指令

ARM 处理是加载/存储体系结构的典型的RISC处理器

对存储器的访问只能使用加载和存储指令实现

ARM 的加载/存储指令是可以实现字、半字、无符/有符字节操作

批量加载/存储指令可实现一条指令加载/存储多个寄存器的内容

SWP指令是一条寄存器和存储器内容交换的指令,可用于信号量操作等

ARM 处理器是冯.诺依曼存储结构,程序空间、RAM 空间及IO 映射空间统一编址,除对对RAM 操作以外,对外围IO、程序数据的访问均要通过加载/存储指令进行

下图给出ARM存储访问指令表

image-20220402140923882

LDR/STR

LDR{cond}{T} Rd,<地址>;

STR{cond}{T} Rd,<地址>;

LDR从内存中读取数据放入寄存器,STR用于将寄存器内的数据放到内存

LDR R2, [R7,#0x10+var_C] 将R7 + 0x10+var_C地址的数据放到R2

STR R3, [R7,#0x10+var_4] 将R3的数据储存在R7 + 0x10+var_4

{T}为可选项,若指令有T,那么即使处理器是在特权模式下,存储系统也将访问看成是处理器是在用户模式下

T在用户模式下无效,不能与前索引偏移一起使用T

LDR Rd,[Rn] 零偏移,将Rn的值作为内存地址

LDR Rd,[Rn,#0x04]! 前索引偏移,将Rn+0x04地址的值放到Rd,并且更新Rn的值为Rn = Rn + 0x04,如果没有后边感叹号,则Rn不更新

LDR Rd,label ; 程序相对偏移,label 为程序标号,label 必须是在当前指令的±4KB范围内

LDR Rd,[Rn],#0x04 后索引偏移,将Rn中的地址的数据加载到Rd中,然后将Rn更新Rn = Rn + 0x04

ps:前索引偏移就是在索引前偏移,看有无!决定时候更新寄存器的内容。后索引偏移就是在索引后偏移,索引时并不偏移,索引后更新寄存器内容

LDM/STM

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

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

LDM 加载多个寄存器,STM储存多个寄存器

主要用途是现场保护、数据复制、参数传送等

其模式有8种,如下所列:(前面4 种用于数据块的传输,后面4 种是堆栈操作)

(1) IA:每次传送后地址加4

(2) IB:每次传送前地址加4

(3) DA:每次传送后地址减4

(4) DB:每次传送前地址减4

(5) FD:满递减堆栈

(6) ED:空递增堆栈

(7) FA:满递增堆栈

(8) EA:空递增堆栈

寄存器Rn为基址寄存器,装有传送数据的初始地址,Rn 不允许为R15;缀!表示最后的地址写回到Rn中

寄存器列表reglist 可包含多于一个寄存器或寄存器范围,使用“,”分开,如{R1,R2,R6-R9},寄存器排列由小到大排列

^后缀不允许在用户模式呈系统模式下使用,若在LDM 指令用寄存器列表中包含有PC 时使用,那么除了正常的多寄存器传送外,将SPSR 拷贝到CPSR 中,这可用于异常处理返回

使用^后缀进行数据传送且寄存器列表不包含PC时,加载/存储的是用户模式的寄存器,而不是当前模式的寄存器

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}^;恢复现场,异常处理返回

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

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

SWP指令用于将一个内存单元(该单元地址放在寄存器Rn中)的内容读取到一个寄存器Rd中,同时将另一个寄存器Rm 的内容写入到该内存单元中

B 为可选后缀,若有B,则交换字节,否则交换32 位字:Rd 为数据从存储器加载到的寄存器;Rm的数据用于存储到存储器中,若Rm 与Rn 相同,则为寄存器与存储器内容进行交换;Rn 为要进行数据交换的存储器地址,Rn 不能与Rd 和Rm 相同

SWP R1,R1,[R0] ; 将R1 的内容与R0 指向的存储单元的内容进行交换

SWP R1,R2,,[R0] ; 将R0 指向的存储单元内容读取一字节数据到R1中(高24 位清零) ; 并将R2 的内容写入到该内存单元中(最低字节有效)

ARM 数据处理指令

MOV 数据传送指令

MOV{cond}{S} Rd,operand2

将8 位立即数或寄存器(operant2)传送到目标寄存器Rd,可用于移位运算等操作

MOV R1#0x10 ;R1=0x10

MOV R0,R1 ;R0=R1

MOVS R3,R1,LSL #2 ;R3=R1<<2,并影响标志位

MOV PC,LR ;PC=LR ,子程序返回

MVN 数据非传送指令

MVN{cond}{S} Rd,operand2

将8 位图立即数或寄存器(operand2)按位取反后传送到目标寄存器(Rd),因为其具有取反功能,所以可以装载范围更广的立即数

MVN R1,#0xFF ;R1=0xFFFFFF00

MVN R1,R2 ;将R2 取反,结果存到R1

ADD 加法运算指令

ADD{cond}{S} Rd,Rn,operand2

将operand2 数据与Rn 的值相加,结果保存到Rd 寄存器

ADDS R1,R1,#1 ;R1=R1+1

ADD R1,R1,R2 ;R1=R1+R2

ADDS R3,R1,R2,LSL #2 ;R3=R1+R2<<2

SUB 减法运算指令

SUB{cond}{S} Rd,Rn,operand2

用寄存器Rn 减去operand2。结果保存到Rd 中

SUBS R0,R0,#1 ;R0=R0-1

SUBS R2,R1,R2 ;R2=R1-R2

SUB R6,R7,#0x10 ;R6=R7-0x10

RSB 逆向减法指令

RSB{cond}{S} Rd,Rn,operand2

用寄存器operand2 减法Rn,结果保存到Rd 中

RSB R3,R1,#0xFF00 ;R3=0xFF00-R1

RSBS R1,R2,R2,LSL #2 ;R1=R2<<2-R2=R2×3

RSB R0,R1,#0 ;R0=-R1

ADC 带进位加法指令

ADC{cond}{S} Rd,Rn,operand2

将operand2 的数据与Rn 的值相加,再加上CPSR中的C 条件标志位,结果保存到Rd 寄存器

ADC R1,R1,R3 ;使用ADC 实现64 位加法,R1=R1+R3

SBC 带进位减法指令

SCB{cond}{S}Rd,Rn,operand2

用寄存器Rn 减去operand2,再减去CPSR 中的C条件标志位的非(即若C 标志清零,则结果减去1),结果保存到Rd 中

SBC R1,R1,R3 ;使用SBC 实现64 位减法,R1 = R1 - R3

RSC 带进位逆向减法指令

RSC{cond}{S} Rd,Rn,operand2

用寄存器operand2 减去Rn,再减去CPSR 中的C条件标志位,结果保存到Rd 中

RSC R3,R1,#0 ;使用RSC 指令实现求64 位数值的负数 R3 = 0 -R1

**AND **逻辑与操作指令

AND{cond}{S} Rd,Rn,operand2

将operand2 值与寄存器Rn 的值按位作逻辑与操作,结果保存到Rd中

逻辑与操作,都为1则返回1

ANDS R0,R0,#x01 ;R0=R0&0x01,取出最低位数据

AND R2,R1,R3 ;R2=R1&R3

**ORR **逻辑或操作指令

ORR{cond}{S} Rd,Rn,operand2

将operand2 的值与寄存器Rn的值按位作逻辑或操作,结果保存到Rd 中

ORR R0,R0,#x0F ;将R0 的低4 位置1

MOV R1,R2,LSR #4

ORR R3,R1,R3,LSL #8 ;使用ORR 指令将近R2 的高8位数据移入到R3 低8 位中

**EOR **逻辑异或操作指令

EOR{cond}{S}Rd,Rn,operand2

将operand2 的值与寄存器Rn 的值按位作逻辑异或操作,结果保存到Rd中

EOR R1,R1,#0x0F ;将R1 的低4 位取反

EOR R2,R1,R0 ;R2=R1^R0

EORS R0,R5,#0x01 ;将R5 和0x01 进行逻辑异或,结果保存到R0,并影响标志位

BIC 位清除指令

BIC{cond}{S}Rd,Rn,operand2

将寄存器Rn 的值与operand2 的值的反码按位作逻辑与操作,结果保存到Rd中。

BIC R1,R1,#0x0F ;将R1 的低4 位清零,其它位不变

BIC R1,R2,R3 ;将拭的反码和R2 相逻辑与,结果保存到R1

CMP 比较指令

CMP{cond} Rn,operand2

指令使用寄存器Rn 的值减去operand2 的值,根据操作的结果更新CPSR中的相应条件标志位,以便后面的指令根据相应的条件标志来判断是否执行

CMP 指令不保存运算结果

CMP R1,#10 ;R1 与10 比较,设置相关标志位

CMP R1,R2 ;R1 与R2 比较,设置相关标志位

**CMN **负数比较指令

CMN{cond} Rn,operand2

指令使用寄存器Rn 与值加上operand2 的值,根据操作的结果更新CPSR中的相应条件标志位,以便后面的指令根据相应的条件标志来判断是否执行

CMN R0,#1 ;R0+1,判断R0 是否为1 的补码,若是Z 置位

CMN 指令与ADDS 指令的区别在于CMN 指令不保存运算结果。CMN指令可用于负数比较,比如CMNR0,#1 指令则表示R0 与-1 比较,若R0 为-(即1 的补码),则Z 置位,否则Z复位。

TST 位测试指令

TST{cond} Rn,operand2

指令将寄存器Rn 的值与operand2 的值按位作逻辑与操作,根据操作的结果更新CPSR中相应的条件标志位(当结果为0时,EQ位被设置),以便后面指令根据相应的条件标志来判断是否执行

TST R0,#0x01 ;判断R0 的最低位是否为0

TST R1,#0x0F ;判断R1 的低4 位是否为0

TST 指令与ANDS 指令的区别在于TST4 指令不保存运算结果。TST指令通常于EQ、NE条件码配合使用,当所有测试位均为0 时,EQ 有效,而只要有一个测试为不为0,则NE 有效。

TEQ 相等测试指令

TEQ{cond} Rn,operand2

指令寄存器Rn 的值与operand2 的值按位作逻辑异或操作,根据操作的结果更新CPSR中相应条件标志位,以便后面的指令根据相应的条件标志来判断是否执行

TEQ R0,R1 ;比较R0 与R1 是否相等(不影响V 位和C 位)

TST 指令与EORS 指令的区别在于TST 指令不保存运算结果。使用TEQ进行相等测试,常与EQNE 条件码配合使用,当两个数据相等时,EQ 有效,否则NE 有效。

MUL 32 位乘法指令

MUL{cond}{S} Rd,Rm,Rs

指令将Rm 和Rs 中的值相乘,结果的低32 位保存到Rd中

MUL R1,R2,R3 ;R1=R2×R3

MULS R0,R3,R7 ;R0=R3×R7,同时设置CPSR 中的N位和Z 位

MLA 32 位乘加指令

MLA{cond}{S} Rd,Rm,Rs,Rn

指令将Rm 和Rs 中的值相乘,再将乘积加上第3 个操作数,结果的低32位保存到Rd 中

MLA R1,R2,R3,R0 ;R1=R2×R3+R0

**UMULL ** 64 位无符号乘法指令

UMULL{cond}{S} RdLo,RdHi,Rm,Rs

指令将Rm 和Rs 中的值作无符号数相乘,结果的低32位保存到RsLo 中,而高32 位保存到RdHi 中

UMULL R0,R1,R5,R8 ;(R1、R0)=R5×R8

UMLAL 64 位无符号乘加指令

UMLAL{cond}{S} RdLo,RdHi,Rm,Rs

指令将Rm 和Rs 中的值作无符号数相乘,64 位乘积与RdHi、RdLo相加,结果的低32 位保存到RdLo 中,而高32 位保存到RdHi 中

UMLAL R0,R1,R5,R8;(R1,R0)=R5×R8+(R1,R0)

**SMULL **64 位有符号乘法指令

SMULL{cond}{S} RdLo,RdHi,Rm,Rs

指令将Rm 和Rs 中的值作有符号数相乘,结果的低32位保存到RdLo 中,而高32 位保存到RdHi 中

SMULL R2,R3,R7,R6 ;(R3,R2)=R7×R6

SMLAL 64 位有符号乘加指令

SMLAL{cond}{S} RdLo,RdHi,Rm,Rs

指令将Rm 和Rs 中的值作有符号数相乘,64 位乘积与RdHi、RdLo,相加,结果的低32位保存到RdLo 中,而高32 位保存到RdHi 中

SMLAL R2,R3,R7,R6;(R3,R2)=R7×R6+(R3,R2)

ARM跳转指令

B

B{cond} label

跳转到指定的地址执行程序,跳转到指令B 限制在当前指令的±32Mb 的范围内

B WAITA ;跳转到WAITA 标号处

B 0x1234 ;跳转到绝对地址0x1234 处

**BL **带链接的跳转指令

BL{cond} label

指令将下一条指令的地址拷贝到R14(即LR)链接寄存器中,然后跳转到指定地址运行程序

跳转指令B 限制在当前指令的±32MB 的范围内。BL 指令用于子程序调用

BL DELAY

BX 带状态切换的跳转指令

BX{cond} Rm

跳转到Rm 指定的地址执行程序,若Rm 的位[0]为1,则跳转时自动将CPSR 中的标志T 置位,即把目标地址的代码解释为Thumb代码;若Rm 的位[0]为0,则跳转时自动将CPSR 中的标志T 复位,即把目标地址的代码解释为ARM代码

ADRL R0,ThumbFun+1

BX R0 ;跳转到R0 指定的地址,并根据R0 的最低位来切换处理器状态

BLX

BLX目标地址:跳转,改变状态及保存PC值

ARM 协处理器指令

CDP 协处理器数据操作指令

CDP{cond}coproc,opcodel,CRd,CRn,CRm{,opcode2}

coproc 指令操作的协处理器名。标准名为pn,n 为0~15。

opcodel 协处理器的特定操作码。

CRd 作为目标寄存器的协处理器寄存器。

CRN 存放第1 个操作数的协处理器寄存器。

CRm 存放第2 个操作数的协处理器寄存器。

Opcode2 可选的协处理器特定操作码。

ARM 处理器通过CDP 指令通知ARM 协处理器执行特定的操作。该操作由协处理器完成,即对命令的参数的解释与协处理器有关,指令的使用取决于协处理器。若协处理器不能成功地执行该操作,将产生未定义指令异常中断

CDP p7,0,c0,c2,c3,0 ;协处理器7 操作,操作码为0,可选操作码为0

CDP p6,1,c3,c4,c5 ;协处理器操作,操作码为1

LDC 协处理器数据读取指令

LDC{cond}{L} coproc,CRd,<地址>

L 可选后缀,指明是长整数传送。

coproc 指令操作的协处理器名。标准名为pn,n 为0~15

CRd 作为目标寄存的协处理器寄存器。

<地址> 指定的内存地址

LDC指令从某一连续的内存单元将数据读取到协处理器的寄存器中。协处理器数据的数据的传送,由协处理器来控传送的字数。若协处理器不能成功地执行该操作,将产生未定义指令异常中断

LDC p5,c2,[R2,#4];读取R2+4指向的内存单元的数据,传送到协处理器p5的c2寄存器中

LDC p6,c2,[R1] ;读取是指向的内存单元的数据,传送到协处理器p6的c2 寄存器中

STC 协处理器数据写入指令

STC{cond}{L} coproc,CRd,<地址>

L 可选后缀,指明是长整数传送。

coproc 指令操作的协处理器名。标准名为pn,n 为0~15

CRd 作为目标寄存的协处理器寄存器。

<地址> 指定的内存地址

STC指令将协处理器的寄存器数据写入到某一连续的内存单元中。进行协处理器数据的数据传送,由协处理器来控制传送的字数。若协处理器不能成功地执行该操作,将产生未定义指令异常中断

STC p5,c1,[R0]

STC p5,c1,[Ro,#-0x04]

MCR ARM寄存器到协处理器寄存器的数据传送指令

MCR{cond}coproc,opcodel,Rd,CRn,CRm{,opcode2}

coproc 指令操作的协处理器名。标准名为pn,n 为0~15。

cpcodel 协处理器的特定操作码。

RD 作为目标寄存器。

CRn 存放第1 个操作数的协处理器寄存器

CRm 存放第2 个操作数的协处理器寄存器。

Opcode2 可选的协处理器特定操作码。

MCR 指令将ARM 处理器的寄存器中的数据传送到协处理器的寄存器中。若协处理器不能成功地执行该操作,将产生未定义指令异常中断

MCR p6,2,R7,c1,c2,

MCR P7,0,R1,c3,c2,1,

MRC 协处理器寄存器到ARM寄存器到的数据传送指令

MRC {cond}coproc,opcodel,Rd,CRn,CRm{,opcode2}

coproc 指令操作的协处理器名。标准名为pn,n为0~15。

opcodel 协处理器的特定操作码。

Rd 作为目标寄存器。

CRn 存放第1 个操作数的协处理器寄存器。

CRm 存放第2 个操作数的协处理器寄存器。

opcode2 可选的协处理器特定操作码。

MRC 指令将协处理器寄存器中的数据传送到ARM 处理器的寄存器中。若协处理器不能成功地执行该操作。将产生未定义异常中断

MRC p5,2,R2,c3,c2

MRC p7,0,R0,c1,c2,1

ARM 杂项指令

SWI 软中断指令

SWI{cond} immed_24

immed_24 24 位立即数,值为0~16777215 之间的整数。

SWI 指令用于产生软中断,从而实现在用户模式变换到管理模式,CPSR保存到管理模式的SPSR中,执行转移到SWI 向量,在其它模式下也可使用SWI 指令,处理同样地切换到管理模式

SWI 0 ;软中断,中断立即数为0

SWI 0x123456 ;软中断,中断立即数为0x123456

使用SWI 指令时,通常使用以下两种方法进行传递参数,SWI 异常中断处理程序就可以提供相关的服务,这两种方法均是用户软件协定。SWI异常中断处理程序要通过读取引起软中断的SWI 指令,以取得24 位立即数。
    (A)指令24 位的立即数指定了用户请求的服务类型,参数通过用寄存器传递。
    MOV R0,#34   ;设置了功能号为34
    SWI 12     ;调用12 号软中断
    (B)指令中的24 位立即数被忽略,用户请求的服务类型由寄存器R0 的值决定,参数通过其它的通用寄存器传递。
    MOV R0,#12   ;调用12 号软中断
    MOV R1,#34   ;设置子功能号为34
    SWI 0    ;SWI 异常中断处理程序中,取出SWI 立即数的步骤为:首先确定引起软中断的SWI指令是ARM指令还时Thumb 指令,这可通过对SPSR 访问得到:然后要取得该SWI 指令的地址,这可通过访问LR 寄存器得到:接着读出指令,分解出立即数。
    读出SWI 立即数:
    T_bit EQU 0x20
    SWI_Hander
    STMFD SP!,{R0_R3,R12,LR}    ;现场保护
    MRS R0,SPSR           ;读取SPSR
    STMFD SP!,{R0}           ;保存SPSR
    TST R0,#T_bit           ;测试T标志位
    LDRNEH R0,[LR,#-2]        ;若是Thumb指令,读取指令码(16 位)
    BICNE R0,R0,#0xFF00      ;取得Thumb 指令的8 位立即数
    LDREQ R0,[LR,#-4]         ;若是ARM 指令,读取指令码(32 位)
    BICNQ R0,R0,#0xFF00000      ;取得ARM 指令的24 位立即数LDMFD SP!,{R0-R3,R12,PC}^ ;SWI 异常中断返回

MRS 读状态寄存器指令

MRS{cond} Rd ,psr

Rd 目标寄存器。Rd 不允许为R15。

psr CPSR 或SPSR

在ARM 处理器中,只有MRS 指令可以状态寄存器CPSR或SPSR读出到通用寄存器中

MRS 指令读取CPSR,可用来判断ALU 的状态标志,或IRQ、FIQ中断是否允许等;在异常处理程序中,读SPSR 可知道进行异常前的处理器状态等。MRS 与MSR 配合使用,实现CPSR 或SPSR 寄存器的读—修改—写操作,可用来进行处理器模式切换(),允许/禁止IRQ/FIQ中断等设置。另外,进程切换或允许异常中断嵌套时,也需要使用MRS 指令读取SPSR 状态值。保存起来

MRS R1,CPSR ;将CPSR状态寄存器读取,保存到R1 中

MRS R2,SPSR ;将SPSR状态寄存器读取,保存到R2 中

使能IRQ 中断例程:
        ENABLE_IRQ
        MRS R0,CPSR
        BIC R0R0,#0x80
        MSR CPSR_c,R0
        MOV PC,LR
禁能IRQ 中断例程:
        DISABLE_IRQ
        MRS R0,CPSR
        ORR R0,R0,#0x80
        MSR CPSR_c,R0
        MOV PC,LR

MSR 写状态寄存器指令

MSR{cond} psr_fields,#immed_8r

MSR{cond} psr_fields,Rm

其中: psr CPSR 或SPSR

fields 指定传送的区域。Fields 可以是以下的一种或多种(字母必须为小写):

c 控制域屏蔽字节(psr[7…0])

x 扩展域屏蔽字节(psr[15…8])

s 状态域屏蔽字节(psr[23。…16])

f 标志域屏蔽字节(psr[31…24])

immed_8r 要传送到状态寄存器指定域的立即数,8 位。

Rm 要传送到状态寄存器指定域的数据的源寄存器。

在ARM 处理器中。只有MSR 指令可以直接设置状态寄存器CPSR或SPSR

MSR CPSR_c,#0xD3 ;CPSR[7…0]=0xD3,即切换到管理模式。

MSR CPSR_cxsf,R3 ;CPSR=R3

只有在特权模式下才能修改状态寄存器。
程序中不能通过MSR 指令直接修改CPSR 中的T 控制位来实现ARM 状态/Thumb状态的切换,必须使用BX 指令完成处理器状态的切换(因为BX 指令属转移指令,它会打断流水线状态,实现处理器状态切换)。MRS 与MSR 配合使用,实现CPSR或SPSR 寄存器的读-修改-写操作,可用来进行处理器模式切换、允许/禁止IRQ/FIQ 中断等设置。

堆栈指令实始化例程:
        INITSTACK
        MOV R0,LR ;保存返回地址
    ;设置管理模式堆栈
        MSR CPSR_c,#0xD3
        LDR SP,StackSvc
    ;设置中断模式堆栈
        MSR CPSR_c,#0xD2
        LDR SP,StackIrq

ARM 伪指令

ADR 小范围的地址读取伪指令

ADR{cond} register,exper

register 加载的目标寄存器。

exper 地址表达式。当地址值是非字地齐时,取值范围-255~255 字节之间;当地址是字对齐时,取值范围-1020~1020字节之间。

对于基于PC 相对偏移的地址值时,给定范围是相对当前指令地址后两个字处(因为ARM7TDMI为三级流水线)。

ADR 指令将基于PC 相对偏移的地址值读取到寄存器中。在汇编编译源程序时,ADR伪指令被编译器替换成一条合适的指令。通常,编译器用一条ADD 指令或SUB 指令来实现该ADR 伪指令的功能,若不能用一条指令实现,则产生错误,编译失败

LOOP MOV R1, #0xF0

ADR R2, LOOP ;将LOOP 的地址放入R2

ADR R3, LOOP+4

可以用ADR 加载地址,实现查表:

ADR R0,DISP_TAB ;加载转换表地址

LDRB R1,[R0,R2] ;使用R2作为参数,进行查表

DISP_TAB

DCB0Xc0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90

ADRL 中等范围的地址读取伪指令

ADR{cond} register,exper

register 加载的目标寄存器。

expr 地址表达式。当地址值是非字对齐时,取范围-64K~64K 字节之间;当地址值是字对齐时,取值范围-256K~256K字节之间。

ADRL 指令将基于PC 相对偏移的地址值或基于寄存器相对偏移的地址值读取到寄存器中,比ADR伪指令可以读取更大范围的地址。在汇编编译源程序时,ADRL 伪指令被编译器替换成两个条合适的指令。若不能用两条指令实现ADRL 伪指令功能,则产生错误,编译失败

ADRL R0,DATA_BUF

ADRL R1 DATA_BUF+80

DATA_BUF

SPACE 100 ;定义100 字节缓冲区

可以且用ADRL 加载地址,实现程序跳转,中等范围地址的加载:

ADR LR,RETURNI ;设置返回地址

ADRL R1Thumb_Sub+1 ;取得了Thumb 子程序入口地址,且R1 的0 位置1

BX R1 ;调用Thumb子程序,并切换处理器状态

RETURNI

CODE16

Thumb_Sub

MOV R1,#10

LDR 大范围的地址读取伪指令

LDR{cond} register,=expr/label_expr

register 加载的目标寄存器

expr 32 位立即数。

label_expr 基于PC 的地址表达式或外部表达式。

LDR 伪指令用于加载32 位的立即数或一个地址值到指定寄存器。在汇编编译源程序时,LDR伪指令被编译器替换成一条合适的指令。若加载的常数未超出MOV 或MVN 的范围,则使用MOV 或MVN 指令代替该LDR 伪指令,否则汇编器将常量放入字池,并使用一条程序相对偏移的LDR指令从文字池读出常量

LDR R0,=0x123456 ;加载32 位立即数0x12345678

LDR R0,=DATA_BUF+60 ;加载DATA_BUF 地址+60

LTORG ;声明文字池

伪指令LDR 常用于加载芯片外围功能部件的寄存器地址(32 位立即数),以实现各种控制操作加载32位立即数:

LDR R0,=IOPIN ;加载GPIO 寄存器IOPIN 的地址

LDR R1,[R0] ;读取IOPIN 寄存器的值

LDR R0,=IOSET

LDR R1,=0x00500500

STR R1,[R0] ;IOSET=0x00500500

从PC 到文字池的偏移量必须小于4KB。与ARM 指令的LDR 相比,伪指令的LDR的参数有“=”号

NOP 空操作伪指令

NOP 伪指令在汇编时将会被代替成ARM 中的空操作,比如可能为“MOV R0, R0”指令等

使用就单NOP

ARM寻址

立即数寻址

立即数前面有“#”号,并且如果是十六进制数则在“#”后添加“0x”或“&”,二进制数“#”后面加“%”

寄存器间接寻址

操作数的地址在寄存器中

ADD R0,R1,[R2]

基址变址寻址

将寄存器的内容与指令中给出的地址偏移量相加,从而得到一个操作数的有效地址

ADD R0,R1,[R2]

多寄存器寻址

一条指令可以完成多个寄存器值得传递,一条指令传送最多16个通用寄存器的值

LDMIA R0,{R1,R2,R3,R4}

相对寻址

以程序计数器PC的值作为基地址,指令中的地址标号作为偏移量,将两者相加后得到的操作数的有效地址

例如:BL NEXT

ARM堆栈的增长方式

当堆栈指针指向最后压入堆栈的数据时,称为满堆栈(FullStack)

当堆栈指针指向最后压入堆栈的数据时,称为满堆栈(FullStack)

递增堆栈:向高地址方向生长

递减堆栈:向低地址方向生长


ARM寄存器及其汇编指令
http://example.com/article/c21195a7.html
Author
p1yang
Posted on
August 17, 2021
Licensed under