全部博文(395)
分类: 嵌入式
2011-05-11 22:45:34
学习笔记 2010-10-07 19:19:04 阅读79 评论0 字号:大中小
进入第3章,ARM指令集。
总的来说ARM指令集里都是32位的指令。ARM指令只对放在寄存器里的数据处理,在存储器里的数据用store load指令
ARM指令集分为:
1数据处理指令
2分支指令
3load store指令
4软件中断指令
5程序状态指令
3.1数据处理指令
它又可以细分:
1move传送指令
2算术指令
3比较指令
4乘法指令
3.1.1MOVE指令
《指令》{cond}{S} Rd,N
其中cond是条件 如EQ相等,NE不等
加S可以改变cpsr状态
Rd是目标寄存器
N可以是立即数(立即数要#num格式)或者Rm 或者进过桶形移位器的预处理之后的寄存器。
那么来介绍具体move指令
MOV 把一个32位数送到一个寄存器 Rd=N
MVN 把一个32位数的非送到一个寄存器 Rd=~N
3.1.2桶形移位器
数据处理指令是在算术逻辑单元ALU处理的,在此之前Rm寄存器可以进过桶形移位器预处理。
具体操作如下。
mov r7 r5,LSL #2 含义是r5左移2位然后放到r7
LSL 逻辑左移 x LSL y x《y
LSR 逻辑右移 x LSR y (unsigned)x》y
ASR 算术右移 x ASR y (signed)x》y
ROR 循环右移 x ROR y ((unsigned)x》y)|(x《(32-y))
RRX 扩展的循环右移 x RRX (c flag 《31)|(unsigned)x》1)
注:为什么没有ASL,因为ASL不涉及符号 所以ASL和LSL性质一样,所以只有R方向才有算术移动。
3.1.3算术指令
《指令》《cond》{S}Rd,Rn,N
ADC 32位带进位加法 Rd=Rn+N+carry
ADD 32位加法 Rd=Rn+N
SUB 32位减法 Rd=Rn-N
SBC 32位带进位的减法 Rd=Rn-N-!(carry flag)
RSB 32位逆向减法 Rd=N-Rn
RSC 32位带进位的逆向减法 Rd=N-Rn-!(carry flag)
3.1.4算术指令使用桶形移位置器
在算术指令和逻辑指令中,广泛使用第2操作数的移位功能
3.1.5逻辑指令
《指令》《cond》{S}Rd,Rn,N
AND 32位逻辑与 Rd=Rn&N
ORR 32位逻辑或 RD=Rn|N
EOR 32位逻辑异或 Rd=Rn^N
BIC 32为逻辑与非 Rd=Rn&~N
BIC在位操作时候很有用
3.1.6比较指令
比较指令通常把一个寄存器与一个32位的值进行比较,对于比较指令,不需要使用S后缀就可以改变标志位。
《指令》《cond》Rn,N
CMN 取负比较 Rn+N
CMP 比较 Rn-N
TEQ 等值比较 Rn^N
TST 位测试 Rn&N
它不改变寄存器中的值 值改变cpsr
3.1.7乘法指令
乘法指令比较特殊,由于是2个32位的乘法,所以有一般情况下,需要64位长整形。
RdLo表示低32位,RdHi表示高32位。
普通32位指令
MUL Rd,Rm,Rs
MUL: 乘法 Rd=Rm*Rn
MLA Rd,Rm,Rs,Rn
MLA 乘累加 Rd=(Rm*Rs)+Rn
以下是64位的乘法指令。
《指令《cond》《s》RdLo,RdHi,Rm,Rs
SMULL 长整形有符号乘法 [RdHi,RdLo]=Rm*Rs
UMULL 长整形无符号乘法 [RdHi,RdLo]=Rm*Rs
SMLAL 长整形有符号乘累加 [RdHi,RdLo]=Rm*Rs+[RdHi,RdLo]
UMLAL 长整形有符号乘累加 [RdHi,RdLo]=Rm*Rs+[RdHi,RdLo]
3.2分支指令
结束第一类数据处理指令,接下来第2类,分支处理指令。它可以改变程序执行的流程或者调用子程序,让pc指向一个新的地址。
B{cond} label
BL{cond} label
BX{cond}Rm
BLX {cond}label | Rm
地址label以一个有符号的相对于pc的偏移量保存在指令中,不过要在分支指令32M范围内
B 跳转 pc = label
BL 带返回的跳转 pc=label lr=BL后的第一条指令
以上是arm'指令跳转到arm指令
如果是arm指令跳转到thumb指令 则要用
BX 跳转并切换状态 pc=RM &0xfffffffe,T=RM&1 (不明白为什么)
BLX 带返回的跳转并切换 pc=RM &0xfffffffe,T=RM&1 lr=BLX后的第一条指令
T对应与cpsr中的T位,由分支寄存器的最低位来更新。第4章中将有描述
BX指令使用一个存储在寄存器Rm中的绝对地址,主要用于跳转到thumb代码。
3.3load-store指令
第3种类型指令,load store 这个指令也可以分3大类
1单寄存器传输指令
2多寄存器传输指令
3交换指令
3.3.1单寄存器传送指令
这个指令是把单一的数据传入寄存器 或者从寄存器送入存储器。
它支持的数据类型有 8位 字节 16位 半字 32位 字
<LDR|STR>
LDR
STR
其中没有STRSB与STRSH因为STRH完全实现了前2者的功能。
LDR是指从存储器load到寄存器
STR是从寄存器store到存储器
而且要求数据边界对齐,例如 32位的 要4字节的整数倍。
其中无符号字节 和 字 用 addressing1 它能使用桶形移位器。
而 有符号字节,半字,以及双字 用 addressing2 。它不能使用桶形移位器。
且addressing1中的立即数最大是12位
而addressing2中的立即数最大才8位
LDR 把一个字装入一个寄存器 Rd<-mem32[address]
STR 从寄存器中保存一个字到存储器 Rd-》mem32[address]
LDRB 字节
STRB 字节
LDRH 半字
STRH 半字
LDRSB 有符号字节
LDRSH 有符号半字
3.3.2单寄存器load store指令的寻址方式
以下介绍3种变址
1.回写前变址 数据:mem[base+offset] 基地址加上偏移量 LDR r0,[r1,#4]!
其实就是实际送到寄存器r0中的数据是r1寄存器中的数据加上4作为地址寻址找到的数据,而r1中的数据也要改变
2前变址 数据:mem[base+offset] 原先的值 LDR r0,[r1,#4]
与之前相比,送到r0中的数据还是要偏移后的地址得到,但r1中数据不会发生加4偏移
3后变址 数据:mem[base] 基地址加上偏移量 LDR r0,[r1],#4
r0中的值不变,r1中的值要发生偏移4.(注:这个地方有些问题,//先进行操作然后R1+4->R1,操作完毕后,R1 = R1+4。不需要"!"号。
)
3.3.3多寄存器传送指令
可以用一条指令来传送多个寄存器的值到内存。
语法:
首先说下Rn,指令是从Rn寄存器中的值作为地址,复制到之后的Registers中。
而后面的!可选,如果选上,Rn的值将随传送而改变。
而寻址模式有4类:
寻址模式 描述 起始地址 结束地址 Rn!
IA(increase after) 执行后增加 Rn Rn+4*N-4 Rn+4*N
IB 执行前增加 Rn+4 Rn+4*N Rn+4*N
DA 执行后减少 Rn Rn-4*N+4 Rn-4*N
DB 执行前减少 Rn-4 Rn-4*N Rn-4*N
指令的配对:
STMIA LDMDB
STMIB LDMDA
STMDA LDMIB
STMDB LDMIA
例子:
r9存放源数据起始地址
r10存放目标起始地址
r11存放源的结束地址
loop:
LDMIA r9!,{r0-r7}
STMIA r10!,{r0-r7}
CMP r9,r11
BNE loop
简单说明下:把r9中的地址存放的数据复制到寄存器,再从寄存器复制到r10中的地址。本事就是拷贝数据。如果r9没达到r11的位置,就循环
注意:多寄存器的load store指令会增加中断的延迟,ARM通常不会打断正在执行的指令去响应中断
堆栈操作:
可以利用多寄存器的load store指令来实现push 与pop操作
ARM中有一些多寄存器loadstore指令的别名支持堆栈。
寻址方式 说明 pop LDM push STM
FA 递增满 LDMFA LDMDA STMFA STMIB
FD 递减满 LDMFD LDMIA STMFD STMDA
EA 递增空 LDMEA LDMDB STMEA STMIA
ED 递减空 LDMED LDMIB STMED STMDA
F为满堆栈sp指向最后一个数据的位置。E为空堆栈sp执行最后一个数据的下一个位置。
A为向上,D为向下。
ARM制定了ARM-Thumb过程调用标准(ATPCS),定义了历程如何被调用,寄存器如何被分配。其中定义堆栈为递减满。
3.3.4交换指令
把一个存储单元的内容与寄存器内容相交换,这个是原子操作。
语法:
SWP
SWP 字交换 tmp=mem32[Rn] mem32[Rn]=Rm Rd=tmp
SWPB 字节交换
其实是【Rn】中的数值,放入Rd,Rm中的数据放入【Rm】。
交换指令多用于实现操作系统中的信号量和互斥量。
例子:
spin
MOV R1 = semaphore (这是传一个semaphore信号量的32位地址偏移量)
MOV R2,#1
SWP R3,R2,[R1] 把信号量送入R3,而自己的用R2=1来继续锁闭原来的锁。
CMP R3,#1
BEQ spin 等于1的话就继续循环,不等的话就能执行接下来的操作,这把锁就给这个程序。
3.4软件中断指令
软件中断指令可以产生一个软件中断异常。这为应用程序调用系统例程提供一直机制
语法:
SWI 《cond》SWI_number
SWI 软件中断 lr_svc=SWI的下一条指令。即原先没有切换到管理模式的时候,(一般是用户模式)的lr的值。
spsr_svc=cpsr
pc = vectors +0X8 pc切换到0x00000008或者0xffff0008;
cpsr模式为SVC I=1 (屏蔽IRQ中断)
其中SWI_number是用来给中断处理程序传参的,告诉它是软件的中断号。
中断处理程序利用原先模式下(一般为用户模式下)的lr来通过AND NOT 提取出来
SWI_number=《SWI 那条指令32位编码》AND NOT (0xff000000)
来看个例子吧
这是一个中断处理程序,环境是这样的,程序执行了SWI之后,进入到了管理模式中,在中断向量表+0x8的位置找到了我们下面写的这个程序的起始位置。
SWI-handler:
STMFD sp!,{r0 - r12,lr}把寄存器都压栈
LDR r10,[lr,#-4] 把用户模式下的lr减去4找到原先SWI指令的位置,并把存储器中的值给r10
BIC r10,r10,#0xff000000 r10过滤出后24位,即中断码
BL service-routine 跳转去其他处理子程序并设返回地址lr-svc
LDMFD sp!,{r0-r12,pc} 出栈
3.5程序状态寄存器
ARM指令集提供2条指令,可以控制psr中的值传到另一个寄存器,或者把寄存器中的值或者立即数送到psr;
语法:
MRS《cond》 Rd,《cpsr|spsr》
MSR《cond》 Rd,《cpsr|spsr》—《field》,Rm或立即数
MRS 把程序状态寄存器送到一个通用寄存器
MSR 把寄存器中的值或者立即数送到psr;
其中filed是域,如果选择了一个域就不改变其他域的值,分4个域c控制(模式 中断) x扩展 s状态 f标志(NZCV)
3.5.1协处理器指令
协处理器指令用于扩展指令集,它即可以提供附加的计算能力,也可以控制包括cache和内存管理的存储子系统
语法
CDP
CDP 协处理器数据处理,在协处理器内部执行数据
MRC,MCR 协处理寄存器传输,把数据送入或取出协处理器寄存器
LDC, STC 协处理器内存传输,从协处理器装载,存储一个内存的数据块
cp是协处理器编号p0~p15,opcode1是要在协处理器中执行的操作 Cd Cn Cm是在协处理器里的寄存器的描述。
要看具体协处理器来操作。
3.6常量的装载
ARM中有2条伪指令,用于把32位立即数装载到寄存器里。因为指令都是32位编码的,里面不可能容下32位的立即数。所以增加了这个伪代码。
形式:
LDR Rd,=constant 常量装载指令
ADR Rd,label 32位相对地址装载指令
ADR是把一个标号的地址,与pc的地址相加或相减,放入寄存器
3.7ARMv5E扩展
它扩展了许多新的指令,其中最重要的是16位数据的有符号乘累加。
3.7.1零计数指令
这个指令用于计算最高符号位与第一个1之间的0的个数。
CLZ 《cond》 Rd,Rm
3.7.2饱和算术指令
就是大发生值超过最大值时,数据保持在最大值,不会变成负数。并且改变cpsr中的Q位。
QADD 《cond》 Rd,Rm,Rn Rd=Rn+Rm
QDADD 《cond》 Rd,Rm,Rn Rd=Rn+(Rm*2)
QSUB 《cond》 Rd,Rm,Rn Rd=Rn-Rm
QDSUB 《cond》 Rd,Rm,Rn Rd=Rn-(Rm*2)
cspr中的Q位 只能手动清除。
3.7.3乘法指令
SMLAxy 《cond》 Rd,Rm,Rs,Rn Rd=Rm(x)*Rs(y)+Rn
SMULxy 《cond》 Rd,Rm,Rs Rd=Rm(x)*Rs(y)
如果x取T表示取Rm中的高16位,取B表示低16位
SMLALxy 《cond》 RdLo,RdHi,Rm,Rs 【RdHi,RdLo】+=Rm(x)*Rs(y)
SMLAWy 《cond》 Rd,Rm,Rs,Rn Rd=((Rm*Rs(y))>>16)+Rn
SMULWy 《cond》 Rd,Rm,Rs Rd=((Rm*Rs(y))>>16)
加个W表示 Rm取32位,与Rs的16位相乘后要把结果的高16位取出。
3.8条件执行
大多数ARM指令都支持条件执行,它是指指令的条件代码标志要与cpsr中的标志位相符合时才执行该指令,默认情况下是AL,就是无条件。
而在指令后面加上S表示改变cpsr,而CMP命令无需加S也能改变cspr
一个不错的例子:
求最大公约数
c代码
while(a!=b)
{
if(a>b) a-=b;else b-=a;
}
ARM汇编
gcd
CMP r1, r2 比较a和b是不是相等
SUBGT r1,r1,r2 如果a大于b 执行a-=b
SUBLT r2,r2,r1 如果b大于a 执行b-=a
BNE gcd 分支指令,查看CMP之后的标志位 与 分支的条件是不是吻合。
这一章结束了,学了好几天了,主要是针对ARM指令集的叙述。从move传送指令开始,算术指令 逻辑指令 比较指令等等,Rm可以使用桶型移位器。 接下来就是3种load store指令的介绍 单寄存器的load store 其中分addressing1 和addressing2 这是因为发展的关系 只有老的一批 32位和 无符号8位才继承多一点的功能(桶型移位器)。之后多寄存器主要是堆栈服务的。最后的交换指令是一个原子操作,它提供了互斥量这些系统应用方面编程的接口。
之后就是软件中断指令SWI 为应用层提供编程的接口。 之后的MRS与MSR是改变psr用的。
协处理器的CDP MRC MCR LDC STC 等操作。之后是常量装载与增强指令 0技术 饱和加减法 16位乘法运算。最后说明条件执行。
接下去一章开始Thumb 16位指令集。