nullARM及Thumb指令集ARM及Thumb指令集nullARM指令小节目录1.指令格式
2.条件码
3.存储器访问指令
4.数据处理指令
5.乘法指令
6.ARM分支指令
7.杂项指令
8.伪指令ARM指令长度概述ARM指令长度概述ARM指令长度
指令集可以是以下任一种
32 bits 长 (ARM状态)
16 bits 长 (Thumb 状态)
ARM7TDMI 支持3种数据类型
字节 (8-bit)
半字 (16-bit)
字 (32-bit)
字必须被排成4个字节边界对齐,半字必须被排列成2个字节边界对齐 ARM指令长度概述 ARM指令长度概述向后兼容:新版本增加指令,并保持指令向后兼容;
Load-store 结构*
load/store –从存储器中读某个值,操作完后再将其放回存储器中
只对存放在寄存器的数据进行处理
对于存储器中的数据,只能使用load/store指令进行存取
null简单的ARM程序;文件名:TEST1.S
;功能:实现两个寄存器相加
;说明:使用ARMulate软件仿真调试
AREA Example1,CODE,READONLY ;声明代码段Example1
ENTRY ;标识程序入口
CODE32 ;声明32位ARM指令
START MOV R0,#0 ;设置参数
MOV R1,#10
LOOP BL ADD_SUB ;调用子程序ADD_SUB
B LOOP ;跳转到LOOP
ADD_SUB
ADDS R0,R0,R1 ;R0 = R0 + R1
MOV PC,LR ;子程序返回
END ;文件结束 使用“;”进行注释标号顶格写实际代码段声明文件结束4.2 指令集介绍4.2 指令集介绍 ARM指令集——指令格式4.2 指令集介绍4.2 指令集介绍ARM指令集——基本指令格式 ARM是三地址指令格式,指令的基本格式如下:
{} {S} ,{,} 其中<>号内的项是必须的,{}号内的项是可选的。各项的说明如下:opcode:指令助记符; cond:执行条件;
S:是否影响CPSR寄存器的值;
Rd:目标寄存器; Rn:第1个操作数的寄存器;
operand2:第2个操作数;例:4.2 指令集介绍4.2 指令集介绍ARM指令集——第2个操作数 ARM指令的基本格式如下: {} {S} ,{,} 灵活的使用第2个操作数“operand2”能够提高代码效率。它有如下的形式:
#immed_8r——常数表达式;
Rm——寄存器方式;
Rm,shift——寄存器移位方式;4.2 指令集介绍4.2 指令集介绍ARM指令集——第2个操作数#immed_8r——常数表达式
该常数必须对应8位位图,即一个8位的常数通过循环右移偶数位得到。循环右移10位8位常数4.2 指令集介绍4.2 指令集介绍ARM指令集——第2个操作数Rm——寄存器方式
在寄存器方式下,操作数即为寄存器的数值。
例如:
SUB R1,R1,R24.2 指令集介绍4.2 指令集介绍ARM指令集——第2个操作数Rm,shift——寄存器移位方式
将寄存器的移位结果作为操作数(移位操作不消耗额外的时间),但Rm值保持不变,移位方法如下: 桶形移位器 桶形移位器4.2 指令集介绍 桶形移位器操作 桶形移位器操作4.2 指令集介绍4.2 指令集介绍4.2 指令集介绍ARM指令集——第2个操作数4.2 指令集介绍4.2 指令集介绍ARM指令集——第2个操作数Rm,shift——寄存器移位方式
例如:
ADD R1,R1,R1,LSL #3 ;R1=R1+R1<<3
SUB R1,R1,R2,LSR R3 ;R1=R1-R2>>R3nullARM指令目录1.指令格式
2.条件码
3.存储器访问指令
4.数据处理指令
5.乘法指令
6.ARM分支指令
7.杂项指令
8.伪指令4.2 指令集介绍4.2 指令集介绍ARM指令集——条件码 ARM指令的基本格式如下: {} {S} ,{,} 使用条件码“cond”可以实现高效的逻辑操作(节省跳转和条件语句),提高代码效率。
所有的ARM指令都可以条件执行,而Thumb指令只有B(跳转)指令具有条件执行 功能。如果指令不标明条件代码,将默认为无条件(AL)执行。null指令条件码表4.2 指令集介绍4.2 指令集介绍ARM指令集——条件码C代码:
If(a > b)
a++;
Else
b++;对应的汇编代码:
CMP R0,R1 ;R0(a)与R1(b)比较
ADDHI R0,R0,#1 ;若R0>R1,则R0=R0+1
ADDLS R1,R1,#1 ;若R0≤1,则R1=R1+1示例:条件执行及标志位条件执行及标志位ARM指令可以通过添加适当的条件码前缀来达到条件执行的目的。
这样可以提高代码密度,减少分支跳转指令数目,提高性能。
CMP r3,#0 CMP r3,#0 BEQ skip ADDNE r0,r1,r2 ADD r0,r1,r2 skip
默认情况下,数据处理指令不影响条件码标志位,但可以选择通过添加“S”来影响标志位。 CMP不需要增加 “S”就可改变相应的标志位。
loop … SUBS r1,r1,#1 BNE loop
条件码 条件码
下表为所有可能的条件码:
注意:AL为默认状态,不需要单独指出程序状态寄存器程序状态寄存器 条件位:
N = Negative result from ALU
Z = Zero result from ALU
C = ALU operation Carried out
V = ALU operation oVerflowed
Q 位:
仅ARM 5TE/J架构支持
指示饱和状态
J 位
仅ARM 5TE/J架构支持
J = 1: 处理器处于Jazelle状态中断禁止位:
I = 1: 禁止 IRQ.
F = 1: 禁止 FIQ.
T Bit
仅ARM xT架构支持
T = 0: 处理器处于 ARM 状态
T = 1: 处理器处于 Thumb 状态
Mode位:
处理器模式位
条件执行示例条件执行示例一系列的指令都使用条件指令
if (a==0) func(1);
CMP r0,#0 MOVEQ r0,#1 BLEQ func
置标志位,再使用不同的条件码
if (a==0) x=0; if (a>0) x=1;
CMP r0,#0 MOVEQ r1,#0 MOVGT r1,#1
使用条件比较指令
if (a==4 || a==10) x=0;
CMP r0,#4 CMPNE r0,#10 MOVEQ r1,#04.2 指令集介绍4.2 指令集介绍ARM指令集——存储器访问指令 ARM处理器是典型的RISC处理器,对存储器的访问只能使用加载和存储指令实现。ARM7处理器是冯•诺依曼存储结构,RAM存储空间及I/O映射空间统一编址,除对RAM操作以外,对外围IO、程序数据的访问均要通过加载/存储指令进行。
存储器访问指令分为单寄存器操作指令和多寄存器操作指令。nullARM存储器访问指令——单寄存器加载nullARM存储器访问指令——单寄存器存储 LDR/STR指令用于对内存变量的访问、内存缓冲区数据的访问、查表、外围部件的控制操作等。若使用LDR指令加载数据到PC寄存器,则实现程序跳转功能,这样也就实现了程序散转。
所有单寄存器加载/存储指令可分为“字和无符号字节加载存储指令”和“半字和有符号字节加载存储指令。nullLDR和STR——字和无符号字节加载/存储指令
LDR指令用于从内存中读取单一字或字节数据存入寄存器中,STR指令用于将寄存器中的单一字或字节数据保存到内存。指令格式如下:ARM存储器访问指令——单寄存器存储 LDR{cond}{T} Rd,<地址> ;将指定地址上的字数据读入Rd
STR{cond}{T} Rd,<地址> ;将Rd中的字数据存入指定地址
LDR{cond}B{T} Rd,<地址> ;将指定地址上的字节数据读入Rd
STR{cond}B{T} Rd,<地址> ;将Rd中的字节数据存入指定地址 其中,T为可选后缀。若指令有T,那么即使处理器是在特权模式下,存储系统也将访问看成是在用户模式下进行的。T在用户模式下无效,不能与前索引偏移一起使用T。 nullARM存储器访问指令——单寄存器存储LDR和STR——字和无符号字节加载/存储指令编码指令执行的条件码I为0时,偏移量为12位立即数,为1时,偏移量为寄存器移位P表示前/后变址U表示加/减B为1表示字节访问,为0表示字访问W表示回写为指令的寻址方式Rd为源/目标寄存器Rn为基址寄存器L用于区别加载(L为1)或存储(L为0)nullARM存储器访问指令——单寄存器存储LDR和STR——字和无符号字节加载/存储指令
LDR/STR指令寻址非常灵活,它由两部分组成,其中一部分为一个基址寄存器,可以为任一个通用寄存器;另一部分为一个地址偏移量。地址偏移量有以下3种格式:
立即数。立即数可以是一个无符号的数值。这个数据可以加到基址寄存器,也可以从基址寄存器中减去这个数值。
如:LDR R1,[R0,#0x12] ;R1<-[R0+0x12]
寄存器。寄存器中的数值可以加到基址寄存器,也可以从基址寄存器中减去这个数值。
如:LDR R1,[R0,R2] ; R1<-[R0+R2]
LDR R1,[R0,-R2] ; R1<-[R0-R2]
寄存器及移位常数。寄存器移位后的值可以加到基址寄存器,也可以从基址寄存器中减去这个数值。
如:LDR R1,[R0,R2,LSL #2] ;R1<-[R0+R2*4] nullARM存储器访问指令——单寄存器存储LDR和STR——字和无符号字节加载/存储指令
LDR/STR指令寻址非常灵活,它由两部分组成,其中一部分为一个基址寄存器,可以为任一个通用寄存器;另一部分为一个地址偏移量。地址偏移量有以下3种格式:
立即数。立即数可以是一个无符号的数值。这个数据可以加到基址寄存器,也可以从基址寄存器中减去这个数值。
如:LDR R1,[R0,#0x12] ;R1<-[R0+0x12]
寄存器。寄存器中的数值可以加到基址寄存器,也可以从基址寄存器中减去这个数值。
如:LDR R1,[R0,R2] ; R1<-[R0+R2]
LDR R1,[R0,-R2] ; R1<-[R0-R2]
寄存器及移位常数。寄存器移位后的值可以加到基址寄存器,也可以从基址寄存器中减去这个数值。
如:LDR R1,[R0,R2,LSL #2] ;R1<-[R0+R2*4] nullARM存储器访问指令——单寄存器存储 从寻址方式的地址计算方法分,加载/存储指令有以下4种格式:
零偏移。 如:LDR Rd,[Rn]
前索引偏移。 如:LDR Rd,[Rn,#0x04]!
程序相对偏移。 如:LDR Rd,labe1
后索引偏移。 如:LDR Rd,[Rn],#-0x04
注意:必须保证字数据操作的地址是32位对齐的。
LDR和STR——字和无符号字节加载/存储指令nullLDR和STR——半字和有符号字节加载/存储指令
这类LDR/STR指令可加载有符号半字或字节,可加载/存储无符号半字。偏移量格式、寻址方式与加载/存储字和无符号字节指令相同。 ARM存储器访问指令——单寄存器存储 LDR{cond}SB Rd,<地址> ;将指定地址上的有符号字节读入Rd
LDR{cond}SH Rd,<地址> ;将指定地址上的有符号半字读入Rd
LDR{cond}H Rd,<地址> ;将指定地址上的半字数据读入Rd
STR{cond}H Rd,<地址> ;将Rd中的半字数据存入指定地址注意:
1.有符号位半字/字节加载是指用符号位加载扩展到32位,无符号半字加载是指用零扩展到32位;
2.半字读写的指定地址必须为偶数,否则将产生不可靠的结果;nullARM存储器访问指令——单寄存器存储LDR和STR——半字和有符号字节加载/存储指令编码指令执行的条件码I为0时,偏移量为12位立即数,为1时,偏移量为寄存器移位P表示前/后变址U表示加/减W表示回写为指令的寻址方式Rd为源/目标寄存器Rn为基址寄存器L用于区别加载(L为1)或存储(L为0)S为1表示有符号访问,为0表示无符号访问H为1表示半字访问,为0表示字节访问nullLDR和STR指令应用示例:
1.加载/存储字和无符号字节指令
LDR R2,[R5] ;将R5指向地址的字数据存入R2
STR R1,[R0,#0x04] ;将R1的数据存储到R0+0x04地址
LDRB R3,[R2],#-1 ;将R2指向地址的字节数据存入R3,R2=R2-1
STRB R0,[R3,-R8 ASR #2] ;R0->[R3-R8/4],存储R0的最低有效字节
2.加载/存储半字和有符号字节指令
LDRSB R1,[R0,R3] ;将R0+R3地址上的字节数据存入R1,
;高24位用符号扩展
LDRH R6,[R2],#2 ;将R2指向地址的半字数据存入R6,高16位用0扩展
;读出后,R2=R2+2
STRH R1,[R0,#2]! ;将R1的半字数据保存到R0+2地址,
;只修改低2字节数据,然后R0=R0+2ARM存储器访问指令——单寄存器存储 练习 练习 STR R1, [R2,R5]!
LDR R5,[R3,#-0X03]
STREQ R4 [R0,R4,LSL R5]
STREQ R4 [R6],#-0X08
LDR R0,[R2]!,-R6
LDRNE R4,R5,[R3,R6]
LDR R4 ,START
LDR R1, [R0]!
LDR [SP,#-0X04]
STR R1,START ;(必须保证START处可以存贮数据)
LDR PC,R5
LDR PC , [R5]
半字和字节命令半字和字节命令STRB R5,[SP,R3]
LDRB R0,[R2],-R5,LSL,#0X02
LDRB PC, [R5]
STRB R0,[R15,#-0X02]!
LDRHNE R3,[R5,R8]
LDRH R6,[R15,#-0X20]!
STRH R0,[R4,R2,LSL#0X02]
STRH R0,[PC,#0X08]有符号半字和有符号字节命令有符号半字和有符号字节命令LDRSH R5, [R3-R6]
LDRSB R0, [R4],#0X0FF
LSRSH R15, [R0-R6]
LSRSB R5,[R4,0X101]
LDRNESH R6,[SP,#0X06]!
STRSH R6,[R6]T后缀指令T后缀指令LDRT R5,[R6,R7]
LDRBT R3,[R7],R0
STRBT R0,R2,LSL#0X01
STRT R7,[R3,#0X02]!
LDRT R5,[R7],R3,LSL#0X040
SDRT R5,R6,LSL#0X03
LDRT R6,START目标寄存器器和基址寄存器是同一寄存器目标寄存器器和基址寄存器是同一寄存器LDR R4,[R4,R3,LSL#2]
LDR R4,[R4,R3,LSL#2]!
LDR R4,[R4],R3,LSL#2
LDR R4,[R3,R4,LSL#2]!
STR R4,[R4,R3,LSL#2]!
STR R4,[R4,R3,LSL#2]使用R15时的数据传送使用R15时的数据传送LDR R15,[R5]
LDR R6,[R15]
LDR R7,[R15,R7]!
STR R15,[R7,R1]
STR R0,[R15]
STR R0,[R15,R8]
STR R0,[R15,#0X4]!null ARM存储器访问指令——多寄存器存取 多寄存器加载/存储指令可以实现在一组寄存器和一块连续的内存单元之间传输数据。LDM为加载多个寄存器;STM为存储多个寄存器。允许一条指令传送16个寄存器的任何子集或所有寄存器。它们主要用于现场保护、数据复制、常数传递等。nullARM存储器访问指令——多寄存器存取 多寄存器加载/存储指令格式如下:
LDM{cond}<模式> Rn{!},reglist{^}
STM{cond}<模式> Rn{!},reglist{^}
cond:指令执行的条件;
模式:控制地址的增长方式,一共有8种模式;
!:表示在操作结束后,将最后的地址写回Rn中;
reglist :表示寄存器列表,可以包含多个寄存器,它们使用“,”隔开,如{R1,R2,R6-R9},寄存器由小到大排列;
^:可选后缀。允许在用户模式或系统模式下使用。它有以下两个功能:
1)若op是LDM且寄存器列表包含R15时,那么除了正常的多寄存器传送外,还将SPSR也复制到CPSR中。这用于异常处理返回,仅在异常模式下使用。
2)数据传入或传出的是用户模式下的寄存器,而不是当前模式的寄存器。nullARM存储器访问指令——多寄存器存取LDM和STM——多寄存器加载/存储指令编码指令执行的条件码S对应于指令中的”^”符号P表示前/后变址U表示加/减W表示回写寄存器列表Rn为基址寄存器L用于区别加载(L为1)或存储(L为0)nullARM存储器访问指令——多寄存器存取 多寄存器加载/存储指令的8种模式如下表所示,右边四种为堆栈操作、左边四种为数据传送操作。 进行数据复制时,先设置好源数据指针和目标指针,然后使用块拷贝寻址指令LDMIA/STMIA、LDMIB/STMIB、LDMDA/STMDA、LDMDB/STMDB进行读取和存储 。
进行堆栈操作操作时,要先设置堆栈指针(SP),然后使用堆栈寻址指令STMFD/LDMFD 、STMED/LDMED、STMFA/LDMFA和STMEA/LDMEA实现堆栈操作。nullARM存储器访问指令——多寄存器存取数据块传送指令操作过程如右图所示,其中R1为指令执行前的基址寄存器,R1’则为指令执行后的基址寄存器。nullARM存储器访问指令——多寄存器存取;使用数据块传送指令进行堆栈操作
STMDA R0!,{R5-R6}
. . .
LDMIB R0!,{R5-R6};使用堆栈指令进行堆栈操作
STMED R13!,{R5-R6}
. . .
LDMED R13!,{R5-R6} 两段代码的执行结果是一样的,但是使用堆栈指令的压栈和出栈操作编程很简单(只要前后一致即可),而使用数据块指令进行压栈和出栈操作则需要考虑空与满、加与减对应的问题。4.1 ARM处理器寻址方式4.1 ARM处理器寻址方式寻址方式分类——堆栈寻址 堆栈是一个按特定顺序进行存取的存储区,操作顺序为“后进先出” 。堆栈寻址是隐含的,它使用一个专门的寄存器(堆栈指针)指向一块存储区域(堆栈),指针所指向的存储单元即是堆栈的栈顶。存储器堆栈可分为两种:
向上生长:向高地址方向生长,称为递增堆栈
向下生长:向低地址方向生长,称为递减堆栈4.1 ARM处理器寻址方式4.1 ARM处理器寻址方式寻址方式分类——堆栈寻址0x123456780x123456784.1 ARM处理器寻址方式4.1 ARM处理器寻址方式寻址方式分类——堆栈寻址 堆栈指针指向最后压入的堆栈的有效数据项,称为满堆栈;堆栈指针指向下一个待压入数据的空位置,称为空堆栈。 0x123456784.1 ARM处理器寻址方式4.1 ARM处理器寻址方式寻址方式分类——堆栈寻址
LDMIA R4,{R0,R1,R2,R3,R5}所以可以组合出四种类型的堆栈方式:
满递增:堆栈向上增长,堆栈指针指向内含有效数据项的最高地址。指令如LDMFA、STMFA等;
空递增:堆栈向上增长,堆栈指针指向堆栈上的第一个空位置。指令如LDMEA、STMEA等;
满递减:堆栈向下增长,堆栈指针指向内含有效数据项的最低地址。指令如LDMFD、STMFD等;
空递减:堆栈向下增长,堆栈指针向堆栈下的第一个空位置。指令如LDMED、STMED等。 数据块传送指令 数据块传送指令STMFD R13! ,{R0,R4-R6,R13}
LDMID R4,{R0,R1,R2,R3,R4,R6 }
LDMFD SP!, {R12,R15}
LDMFD SP! ,{R12,R15}^
STMID R0,{R0-R5}
STMIA R1,{R0-R5}nullARM存储器访问指令——寄存器和存储器交换指令 SWP指令用于将一个内存单元(该单元地址放在寄存器Rn中)的内容读取到一个寄存器Rd中,同时将另一个寄存器Rm的内容写入到该内存单元中。使用SWP可实现信号量操作。
指令格式如下:
SWP{cond}{B} Rd,Rm,[Rn]
其中,B为可选后缀,若有B,则交换字节,否则交换32位字;Rd用于保存从存储器中读入的数据;Rm的数据用于存储到存储器中,若Rm与Rd相同,则为寄存器与存储器内容进行互换;Rn为要进行数据交换的存储器地址,Rn不能与Rd和Rm相同。 nullARM存储器访问指令——寄存器和存储器交换指令SWP和SWPB——寄存器和存储器交换指令编码指令执行的条件码B用于区别无符号字节(B为1)或字(B为0)Rm源寄存器Rd目标寄存器Rn为基址寄存器SWP指令应用示例:
SWP R1,R1,[R0] ;将R1的内容与R0指向的存储单元的内容进行互换
SWPB R1,R2,[R0] ;将R0指向的存储单元低字节数据读取到R1中
;(高24位清零),并将R2的内容写入到该内存单元中
;(最低字节有效) 复习 复习单寄存器数据传送单寄存器数据传送 LDR STR Word
LDRB STRB Byte
LDRH STRH Halfword
LDRSB 带符号的byte load
LDRSH 带符号的halfword load
存储器系统必须支持所有访问宽度
语法:
LDR{}{} Rd,
STR{}{} Rd,
e.g. LDREQB 地址访问 地址访问LDR/STR访问的地址由基址寄存器加上偏移量来产生。
针对word和无符号byte 的访问, 偏移量可以是:
一个无符号12-bit立即数 (如 0 - 4095 bytes). LDR r0,[r1,#8]
一个寄存器,或再加上移位(由立即数指定) LDR r0,[r1,r2] LDR r0,[r1,r2,LSL#2]
可以是从基址寄存器上加或减去偏移量: LDR r0,[r1,#-8] LDR r0,[r1,-r2] LDR r0,[r1,-r2,LSL#2]
对于halfword和带符号的halfword / byte, 偏移量可以是:
一个无符号8 bit 立即数 (如 0-255 bytes).
一个寄存器 (不能偏移)。
可选择采用pre-indexed或post-indexed方式寻址Pre or Post Indexed 寻址?Pre or Post Indexed 寻址? Pre-indexed: STR r0,[r1,#12]0x50x5r10x200基址 寄存器0x200r00x5源寄存器 for STR偏移量120x20cr10x200原基址 寄存器0x200r00x5源寄存器 for STR偏移量120x20cr10x20c更新 基址寄存器通过 STR r0,[r1,#12]!来自动更新基址寄存器 Post-indexed: STR r0,[r1],#12块数据传送块数据传送LDM / STM指令允许一次传送1到16个寄存器到/从存储器中。
寄存器传送顺序不能被指定
最小数字的寄存器总是被传送到/从存储器的最低地址上。
LDMIA r10,{r0,r1,r4}
基址寄存器指定存储器访问开始的地址
块传送指令针对下列情况很有效:
从存储器中搬运一块数据
保存或恢复堆栈中的内容
如果是慢速存储器,会影响中断响应时间r1r4r0r10地址增加LDM / STM 操作LDM / STM 操作语法:
{} Rb{!}, <寄存器 list>
4 种寻址操作:
LDMIA / STMIA Increment After(先操作,后增加)
LDMIB / STMIB Increment Before(先增加,后操作)
LDMDA / STMDA Decrement After (先操作,后递减)
LDMDB / STMDB Decrement Before (先递减,后操作)IAr1地址
增加r4r0r1r4r0r1r4r0r1r4r0r10IBDADBLDMxx r10, {r0,r1,r4}
STMxx r10, {r0,r1,r4}基址寄存器 (Rb)堆栈堆栈ARM堆栈操作通过块传送指令来完成:
STMFD (Push) 块存储- Full Descending stack [STMDB]
LDMFD (Pop) 块装载- Full Descending stack [LDMIA]100FF1234A0BE8034STMFD sp!,{r4-r7,lr}SWPSWP在寄存器和存储器之间,由一次存储器读和一次存储器写组成的原子操作。完成一个字节或字的交换。
语法:
SWP{}{B} Rd, Rm, [Rn]
RmRdtemp存储器Rn4.2 指令集介绍4.2 指令集介绍ARM指令集——分支指令 在ARM中有两种方式可以实现程序的跳转,一种是使用分支指令直接跳转,另一种则是直接向PC寄存器赋值实现跳转。 分支指令有以下三种:
分支指令B;
带链接的分支指令BL;
带状态切换的分支指令BX。nullARM分支指令——指令编码分支指令B/BL指令编码格式指令执行的条件码L区别B指令(L为0)和BL指令(L为1)24位有符号立即数(偏移量)分支指令BX指令编码格式指令执行的条件码Rm目标地址寄存器,该寄存器装载跳转地址nullARM指令——分支指令nullARM指令——分支指令 分支指令——B指令,该指令跳转范围限制在当前指令的±32M字节地址内(ARM指令为字对齐,最低2位地址固定为0)。指令格式如下:
B{cond} Label
应用示例:
B WAITA ; 跳转到WAITA标号处
B 0x1234 ; 跳转到绝对地址0x1234处 nullARM指令——分支指令 带链接的分支指令——BL指令适用于子程序调用,使用该指令后,下一条指令的地址被拷贝到R14(即LR) 连接寄存器中,然后跳转到指定地址运行程序。跳转范围限制在当前指令的±32M字节地址内。指令格式如下:
BL{cond} LabelAddr1Addr21.当程序执行到BL跳转指令时,硬件将下一条指令的地址Addr2装入LR寄存器,并把跳转地址装入程序计数器(PC)2. 程序跳转到目标地址Label继续执行,当子程序执行结束后,将LR寄存器内容存入PC,返回调用函数继续执行 应用示例(调用子程序):
BL Label nullARM指令——分支指令 带状态切换的分支指令——BX指令,该指令可以根据跳转地址(Rm)的最低位来切换处理器状态。其跳转范围限制在当前指令的±32M字节地址内(ARM指令为字对齐,最低2位地址固定为0)。指令格式如下:
BX{cond} RmnullARM指令——分支指令 带状态切换的分支指令——BX指令,该指令可以根据跳转地址(Rm)的最低位来切换处理器状态。其跳转范围限制在当前指令的±32M字节地址内(ARM指令为字对齐,最低2位地址固定为0)。 Rm的位[0]不用作地址的一部分。若Rm的位[0]为1,则指令将CPSR中的标志T置位,且将目标地址的代码解释为Thumb代码;若Rm的位[0]为0,则Rm的位[1]就不能为1 。指令格式如下:
BX{cond} Rm 应用示例:
ADRL R0,ThumbFun+1 ;将Thumb程序的入口地址加1存入R0
BX R0 ; 跳转到R0指定的地址,
;并根据R0的最低位来切换处理器状态桶型移位器桶型移位器DestinationCF0DestinationCFLSL : Logical Left ShiftASR: Arithmetic Right Shift(无符号数)乘2除2,并保留符号位DestinationCF...0DestinationCFLSR : Logical Shift RightROR: Rotate Right(无符号数)除2位轮换DestinationRRX: Rotate Right Extended位轮换,从 CF到MSB都参与操作CF桶型移位器:
第二个操作数桶型移位器:
第二个操作数 寄存器, 可选择是否增加移位操作.
移位值可以是:
5 bit 无符号整数
放在另一个寄存器的低字节
用于常数乘法
立即数
8 bit ,大小范围0-255。
右移偶数位
允许直接加载32-bit 常数到寄存器中。
结果立即数 (1)立即数 (1)没有任何一条ARM 指令可包括一个32 bit的立即数
所有的ARM指令都是32 bits固定长度
数据处理指令格式中,第二个操作数有12位
4 bit 移位值 (0-15)乘于2,得到一个范围在0-30,步长为 2的移位值。
记住一条准则: “最后8位一定要移动偶数位”.07118immed_8Shifter RORrotx2Quick Quiz: 0xe3a004ff MOV r0, #???立即数 (2)立即数 (2)Examples:
下列命令中,汇编器把立即数转换为移位操作:
MOV r0,#4096 ; uses 0x40 ror 26
ADD r1,r2,#0xFF0000 ; uses 0xFF ror 16
也可使用 MVN来进行位反转:
MOV r0, #0xFFFFFFFF ; assembles to MVN r0,#0
立即数不能使用上述方法产生,否则将导致错误。031ror #0 range 0-0xff000000 step 0x01000000 ror #8 range 0-0x000000ff step 0x00000001 range 0-0x000003fc step 0x00000004 ror #30 000000000000000000000000000000000000000000000000000000000000000000000000装载32 bit常数装载32 bit常数为允许装载大常数,汇编器提供了一条伪指令:
LDR rd, =const
它可能汇编成下列指令:
MOV or MVN。
或
LDR 指令,从数据池(Literal pools)读取常数。
For example
LDR r0,=0xFF => MOV r0,#0xFF
LDR r0,=0x55555555 => LDR r0,[PC,#Imm12] … … DCD 0x55555555
建议把常数装载到寄存器中时一律使用该伪指令。测验 #1测验 #11. 写一条 ARM 指令,分别完成下列操作:
a) r0 = 16
b) r0 = r1 / 16 (带符号的数字)
c) r1 = r2 * 3
d) r0 = -r0
2. 下面哪些立即数是数据处理指令中有效的数据?
a) 0x00AB0000 b) 0x0000FFFF c) 0xF000000F
d) 0x08000012 e) 0x00001f80 f) 0xFFFFFFFF
3. BIC指令做什么用?
4. 为什么ARM 处理器增加了一条RSB 指令?测验 #2 - GCD测验 #2 - GCD新建一个 ‘ARM Executable Image’ 项目
新建一个 text文件
另存为 “gcd.s”
加入到项目中
Build 并执行StartStopr0 = r1 ?r0 > r1 ?r0 = r0 - r1r1 = r1 - r0Yes No Yes No 你只需要使用CMP、SUB和B指令。
充分使用条件执行!
大家可以尝试计算 2109 和 4161 的GCD AREA myarea, CODE
ENTRY
MOV r0, #9
MOV r1, #15
start
; your code here
stop
B stop
END乘法乘法语法:
MUL{}{S} Rd, Rm, Rs Rd = Rm * Rs
MLA{}{S} Rd,Rm,Rs,Rn Rd = (Rm * Rs) + Rn
[U|S]MULL{}{S} RdLo, RdHi, Rm, Rs RdHi,RdLo := Rm*Rs
[U|S]MLAL{}{S} RdLo, RdHi, Rm, Rs RdHi,RdLo := (Rm*Rs)+RdHi,RdLo
占用的周期数
基本 MUL 指令
ARM7TDMI 上为2-5 周期
StrongARM/XScale上为1-3 周期
ARM9E/ARM102xE上为2 周期
ARM9TDMI 比 ARM7TDMI多1 周期
累加再多1 周期 (不针对9E,尽管结果延迟多于1周期)
对于“long”型数据,多1 周期
以上均为一般规则,确切细节查看相应手册。软件中断 (SWI)软件中断 (SWI)产生一个异常陷阱,跳转到SWI 硬件向量。
SWI 处理程序可以检测SWI号,从而决定采取何种操作。
通过SWI机制,运行在用户模式下的应用程序,可请求操作系统执行一系列特权操作。
语法:
SWI{} 283124270 Cond 1 1 1 1SWI number (ignored by processor)23条件域PSR 传送指令PSR 传送指令MRS和MSR允许传送CPSR / SPSR中的内容到/从一个通用寄存器中。
语法:
MRS{} Rd, ; Rd =
MSR{} ,Rm ; = Rm
在这里:
= CPSR or SPSR
[_fields] = ‘fsxc’的任意组合
也允许送一个立即数到 psr_fields
MSR{} ,#Immediate
用户模式下,所有位均可以被读取,但只有条件标志位 (_f)可被写。协处理器指令协处理器指令ARM体系支持16个协处理器
针对每个协处理器的指令占用 ARM指令集中的固定部分
如果相应的协处理器不存在, 将发生一个未定义指令异常。
这有三种协处理器指令
协处理器数据处理指令
CDP:初始化协处理器数据处理操作
协处理器寄存器传送指令
MRC:从协处理器寄存器移到ARM 寄存器
MCR:从 ARM 寄存器移到协处理器寄存器
协处理器存储器传送指令
LDC:从存储器装载到协处理器寄存器
STC:从协处理器寄存器存储到存储器测试 #4测试 #41. 写几条ARM 指令,使能IRQ中断
2. 下列 ARM 指令将做什么?
a) LDRH r0,[r1,#6]
b) LDR r0, =0x999
3.在装载或存储指令中, “!”表示什么?
4. 当 执行SWI 指令时,会发生什么?
5. SWP 指令的优势是什么?议程议程 ARM 指令集
Thumb 指令集
v5TE体系结构扩展
ThumbThumbThumb 是16-bit 指令集
代码密度优化 (总代码大小约为ARM指令的65%)
使用窄总线存储器时可以大大提高性能。
是 ARM 指令集的一个子集。
核存在一个执行状态 – Thumb状态
ARM和Thumb之间切换使用BX 指令015310ADDS r2,r2,#1ADD r2,#132-bit ARM 指令16-bit Thumb 指令对于由编译器产生的大部分指令:
没有条件执行
源、目的寄存器必须相同
仅能使用低寄存器
常数大小有限制
不能使用在线移位器ARM / Thumb 交互工作ARM / Thumb 交互工作使用Branch Exchange 指令来完成 Interworking
BX Rn ; Thumb 状态下的Bx指令
BX Rn ; ARM状态下的Bx指令
也可以只是执行一个绝对跳转,无须状态更换。RnBX跳转的地址31013101ARM / Thumb 选择
0 - ARM 状态
1 - Thumb 状态0写 Thumb汇编程序写 Thumb汇编程序Thumb不是一个“好” 指令集!
最好用编译器来产生
约束并不一致
代码处理通常优于ARM 指令
更多细节,参看:
ARM “Architecture Reference Manual”
Chapters A6和A7
议程议程 ARM 指令集
Thumb 指令集
v5TE体系结构扩展
v5TE结构v5TE结构v5TE体系包括全部的 v4T ARM和Thumb 指令集,还有:
更支持interworking
同时支持ARM / Thumb状态
Breakpoint 指令 (ARM和Thumb)
CLZ(Count Leading Zeros)指令
扩展协处理器指令 - MCR2等等
支持饱和处理
封装的带符号的半字乘法指令
双字装载/ 存储指令
Cache预装载指令
双字协处理器 传送指令 - MCRR/MRRC你采用的处理器是哪种结构?你采用的处理器是哪种结构?处理器核 结构体系
7TDMI & 9TDMI v4T
9E-S rev1 v5TE
926EJ-S/1026EJ-S v5TEJ
1020E v5TE
StrongARM v4
XScale Microarchitecture v5TE前导零计数指令前导零计数指令CLZ{cond} Rd, Rm
计算寄存器中的值有多少个前导0
源寄存器从最高位开始计算。
1个周期完成
(ARM9E-S/ARM102x)
如果没有任何一位被置位,结果是32;如果 bit 31被置位,结果为0。
Rm 左移 Rd位即可标准化Rm
带符号的标准化需要额外的 1个周期0000 0010 1110 1101...0R0 =CLZ R1, R00x6R1 =1011 1011 0100 0000...0Rm =MOV R0, R0 LSL R1EOR R1, R0, R0, LSL#1
CLZ R1, R1
MOV R0, R0, LSL R1扩展协处理器指令扩展协处理器指令CDP2, LDC2, STC2, MCR2, MRC2
新格式的标准协处理器指令为协处理器设计人员提供了附加的操作码空间。
同样是无条件执行的新的有符号乘法操作新的有符号乘法操作SMULxy{cond} Rd, Rm, Rs
SMULWy{cond} Rd, Rm, Rs
SMLAxy{cond} Rd, Rm, Rs, Rn
SMLAWy{cond} Rd, Rm, Rs, Rn
SMLALxy{cond} RdLo, RdHi, Rm, Rs
SMLA 指令影响标志位Q
x, y 用于选择寄存器的高一半和低一半
W 用于选择48位结果的高32位
不影响 NZCV (没有‘S’位)
TRmRsBTBW option16161616321632/6432/64Rd
(RdHi,RdLo)Rn
(RdHi,RdLo)测试 #5 - DSP power calculation测试 #5 - DSP power calculation1) 写一段汇编代码 ‘qtest’ 测试标志位 Q 并清零。
源文件
模板
个人简介word模板免费下载关于员工迟到处罚通告模板康奈尔office模板下载康奈尔 笔记本 模板 下载软件方案模板免费下载
在文件 ‘asm\dsp.s’ 中给出
返回根据标志位Q的值
2) 写一段汇编主程序,累加16位有符号数组的所有元素的平方。
int total=0;
for (n=0; n<64; n++)
total += x[n]*x[n];
取值指令 使用LDRH
平方累加指令使用 SMLABB
3) 是否存在互锁?
4) 使用AXD检查 Q标志位(通过改变cpsr模式为 E-PSR)
5) 在循环后面增加一个 BL 调用 qtest 并检查返回值
6) 专家题: 改用 LDR,每次取两个值
7) 专家题: 修改代码,使用64位累加器xx[0]x[1]x[2]x[3]x[4]x[63]r0x[62]x[5]饱和算术饱和算术0x7FFFFFFF 加上1产生一个负的结果
0x80000000 减去1,会产生一个正的结果
饱和算术指令会区分这两种情况,使得在最大值和最小值越界时产生饱和
经常用于表示 1 到 -1
“Q31” 算术
AXD 可以显示 Q31 格式0x00x7FFFFFFF0x80000000-ve+ve- Most Positive Number- Most Negative Number饱和算术指令饱和算术指令饱和算术在几个通信DSP算法中是必须的
G.723.1 - VoIP
AMR - Adaptive MultiRate
QSUB{cond} Rd, Rm, Rn Rd = saturate(Rm - Rn)
QADD{cond} Rd, Rm, Rn Rd = saturate(Rm + Rn)
QDSUB{cond} Rd, Rm, Rn Rd = saturate(Rm - saturate(Rn2))
QDADD{cond} Rd, Rm, Rn Rd = saturate(Rm + saturate(Rn2))
这些指令影响标志位QQADD 示例QADD 示例例 1 没有超过最大值边界,因此不会产生饱和
例 2 计算结果超过最大值边界,因此产生饱和且标志位 Q 被置位R1 = 0x7F000000SaturateR2 = 0x000010000x7F0010000x7F001000SaturateR1 = 0x7F000000R3 = 0x010000000x800000000x7FFFFFFFQDADD 示例 (1)QDADD 示例 (1)该示例表示1/4 与 1/2 的Q31格式乘法,结果为1/16。产生该结果的原因是使用了Q15格式的整数乘法。
结果乘以2就得到了正确的结果(Q31格式)。
QDADD 和 QDSUB 节省了现有的分离指令 0x2000 (1/4)
x 0x4000 (1/2)
0x08000000 (1/16)
double & sat
0x10000000 (1/8)S1/21/41/81/161/32768015Q15 formatQDADD 示例 (2)QDADD 示例 (2)输入 1 和 –1之间的乘数
乘法结果是 Q30格式**
QDADD 在加法操作之前将 Rn 转化为 Q31 格式
** 注: ARM 可以正确的处理 -1*-1的情况15S15S30SS30S0+Rm30SSMULxyQDADDQ15Q15Q31Now Q31Q30Load / Store 双寄存器Load / Store 双寄存器LDR/STR{}D ,
内存中两个相邻的字与寄存器对 (r0,r1), (r2,r3), (r4,r5), (r6,r7), (r8,r9), (r10,r11) 或 (r12,r13)的传送
Rd 指示偶数寄存器号。相邻的奇数寄存器自动作为传送的第二个寄存器。
与 LDRH/STRH寻址模式相同。
地址必须是双字对齐 (8-byte) 。Cache 预读Cache 预读PLD [Rn,]
偏移量可以是
无符号12位立即数 (ie 0 - 4095 bytes).
寄存器,可以使用立即数移位操作
偏移量可以为正的,也可以为负
通知存储器系统某一地址的数据极可能即将被访问
存储器系统将数据调入缓存以便后面访问
对于不支持该操作的存储器系统,该指令 相当于NOP。
无条件执行MRRC/ MCRRMRRC/ MCRRMRRC{} , , , ,
MCRR{} , , , ,
传送两个 ARM 寄存器与协处理器而不是一个
提高了ARM–coprocessor 传送带宽。提高代码宽度到64位
一条指