ARM及Thumb指令集
ARM指令小节目录 1.指令格式 2.条件码 3.存储器访问指令 4.数据处理指令 5.乘法指令 6.ARM分支指令 7.杂项指令 8.伪指令
ARM指令长度概述 ARM指令长度 指令集可以是以下任一种 32 bits 长 (ARM状态) 16 bits 长 (Thumb 状态) ARM7TDMI 支持3种数据类型 字节 (8-bit) 半字 (16-bit) 字 (32-bit) 字必须被排成4个字节边界对齐,半字必须被排列成2个字节边界对齐
ARM指令长度概述 向后兼容:新版本增加指令,并保持指令向后兼容; Load-store 结构* load/store –从存储器中读某个值,操作完后再将其放回存储器中 只对存放在寄存器的数据进行处理 对于存储器中的数据,只能使用load/store指令进行存取
简单的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 指令集介绍 ARM指令集——指令格式
4.2 指令集介绍 ARM是三地址指令格式,指令的基本格式如下: 4.2 指令集介绍 ARM指令集——基本指令格式 ARM是三地址指令格式,指令的基本格式如下: <opcode> {<cond>} {S} <Rd> ,<Rn>{,<operand2>} 其中<>号内的项是必须的,{}号内的项是可选的。各项的说明如下: opcode:指令助记符; cond:执行条件; S:是否影响CPSR寄存器的值; Rd:目标寄存器; Rn:第1个操作数的寄存器; operand2:第2个操作数; 指令语法 目标寄存器(Rd) 源寄存器1(Rn) 源寄存器2(Rm) ADD r3,r1,r2 r3 r1 r2 例:
4.2 指令集介绍 ARM指令的基本格式如下: 灵活的使用第2个操作数“operand2”能够提高代码效率。它有如下的形式: 4.2 指令集介绍 ARM指令集——第2个操作数 ARM指令的基本格式如下: <opcode> {<cond>} {S} <Rd> ,<Rn>{,<operand2>} 灵活的使用第2个操作数“operand2”能够提高代码效率。它有如下的形式: #immed_8r——常数表达式; Rm——寄存器方式; Rm,shift——寄存器移位方式;
4.2 指令集介绍 #immed_8r——常数表达式 该常数必须对应8位位图,即一个8位的常数通过循环右移偶数位得到。 循环右移10位 4.2 指令集介绍 ARM指令集——第2个操作数 #immed_8r——常数表达式 该常数必须对应8位位图,即一个8位的常数通过循环右移偶数位得到。 循环右移10位 0x00 0x12 1 8位常数 0x00 0x80 1 0x04
4.2 指令集介绍 Rm——寄存器方式 在寄存器方式下,操作数即为寄存器的数值。 例如: SUB R1,R1,R2 4.2 指令集介绍 ARM指令集——第2个操作数 Rm——寄存器方式 在寄存器方式下,操作数即为寄存器的数值。 例如: SUB R1,R1,R2
4.2 指令集介绍 Rm,shift——寄存器移位方式 4.2 指令集介绍 ARM指令集——第2个操作数 Rm,shift——寄存器移位方式 将寄存器的移位结果作为操作数(移位操作不消耗额外的时间),但Rm值保持不变,移位方法如下: 操作码 说明 ASR #n 算术右移n位 ROR #n 循环右移n位 LSL #n 逻辑左移n位 RRX 带扩展的循环右移1位 LSR #n 逻辑右移n位 Type Rs Type为移位的一种类型,Rs为偏移量寄存器,低8位有效。
4.2 指令集介绍 桶形移位器 ALU 桶形移位器 Rd 结果N Rm Rn
4.2 指令集介绍 桶形移位器操作 助记符 说明 移位操作 结果 Y值 LSL 逻辑左移 x LSL y x<<y 4.2 指令集介绍 桶形移位器操作 助记符 说明 移位操作 结果 Y值 LSL 逻辑左移 x LSL y x<<y #0-31 or Rs LSR 逻辑右移 x LSR y (unsigned)x>>y #1-32 or Rs ASR 算术右移 x ASR y (signed)x>>Y ROR 算术左移 x ROR y ((unsigned)x>>y|(x<<32-y)) RRX 扩展的循环右移 x RRX y (c flag<<31)|((unsigned)x>>1) none
4.2 指令集介绍 LSL移位操作: LSR移位操作: ASR移位操作: ROR移位操作: RRX移位操作: C 4.2 指令集介绍 ARM指令集——第2个操作数 LSL移位操作: LSR移位操作: ASR移位操作: ROR移位操作: RRX移位操作: C
4.2 指令集介绍 Rm,shift——寄存器移位方式 例如: ADD R1,R1,R1,LSL #3 ;R1=R1+R1<<3 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>>R3
ARM指令目录 1.指令格式 2.条件码 3.存储器访问指令 4.数据处理指令 5.乘法指令 6.ARM分支指令 7.杂项指令 8.伪指令
4.2 指令集介绍 ARM指令的基本格式如下: 使用条件码“cond”可以实现高效的逻辑操作(节省跳转和条件语句),提高代码效率。 4.2 指令集介绍 ARM指令集——条件码 ARM指令的基本格式如下: <opcode> {<cond>} {S} <Rd> ,<Rn>{,<operand2>} 使用条件码“cond”可以实现高效的逻辑操作(节省跳转和条件语句),提高代码效率。 所有的ARM指令都可以条件执行,而Thumb指令只有B(跳转)指令具有条件执行 功能。如果指令不标明条件代码,将默认为无条件(AL)执行。
指令条件码表 操作码 条件助记符 标志 含义 0000 EQ Z=1 相等 0001 NE Z=0 不相等 0010 CS/HS C=1 无符号数大于或等于 0011 CC/LO C=0 无符号数小于 0100 MI N=1 负数 0101 PL N=0 正数或零 0110 VS V=1 溢出 0111 VC V=0 没有溢出 1000 HI C=1,Z=0 无符号数大于 1001 LS C=0,Z=1 无符号数小于或等于 1010 GE N=V 有符号数大于或等于 1011 LT N!=V 有符号数小于 1100 GT Z=0,N=V 有符号数大于 1101 LE Z=1,N!=V 有符号数小于或等于 1110 AL 任何 无条件执行 (指令默认条件) 1111 NV 从不执行(不要使用)
4.2 指令集介绍 示例: C代码: If(a > b) a++; Else b++; 对应的汇编代码: 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 如果 Z标志清零则跳转 R1减1,并设置标志位 ARM指令有一个与众不同而又功能强大的特点,就是所有ARM指令(V5T以前的版本)都可以条件执行,这样可以提高代码密度和性能。这里给出了一个减少指令数目的例子,左边的程序有4条指令,其中条件分支指令为BEQ 这是ARM指令集的一个与众不同的、但又功能强大的特性。其他结构通常只有条件分支跳转。 一些新添加的ARM指令 (如在v5T和v5TE体系中)是不能条件执行的,如 v5T体系中的 BLX 偏移量。 内核把指令中的条件代码区域与NZCV标志位进行比较,从而判断指令是否该执行。
条件码 下表为所有可能的条件码: 注意:AL为默认状态,不需要单独指出 EQ NE CS/HS CC/LO MI PL VS VC HI 不等于(Not equal) 无符号的大于或等于 无符号的小于 负数(Minus) 等于(Equal) 溢出(Overflow) 没溢出 无符号的大于 无符号的小于或大于 正数或零 小于(Less Than) 大于(Greater Than) 小于等于 总是执行(Always) 大于等于 EQ NE CS/HS CC/LO PL VS HI LS GE LT GT LE AL MI VC Suffix 描述 Z=0 C=1 C=0 Z=1 测试的标志位 N=1 N=0 V=1 V=0 C=1 & Z=0 C=0 or Z=1 N=V N!=V Z=0 & N=V Z=1 or N=!V 条件码就是一种简单的测试ALU状态标志位的方法。
程序状态寄存器 条件位: 中断禁止位: T Bit Q 位: Mode位: J 位 N = Negative result from ALU 27 31 N Z C V Q 28 6 7 I F T mode 16 23 8 15 5 4 24 f s x c U n d e f i n e d J 条件位: N = Negative result from ALU Z = Zero result from ALU C = ALU operation Carried out V = ALU operation oVerflowed Q 位: 仅ARM 5TE/J架构支持 指示饱和状态 J 位 J = 1: 处理器处于Jazelle状态 中断禁止位: I = 1: 禁止 IRQ. F = 1: 禁止 FIQ. T Bit 仅ARM xT架构支持 T = 0: 处理器处于 ARM 状态 T = 1: 处理器处于 Thumb 状态 Mode位: 处理器模式位 大家现在看到的是程序状态寄存器的内部定义,其中28-31位为条件标志位,包括N、Z、C、V 4个标志。 N位——符号位。如果结果为负数,则N = 1;如果结果为正数或0,则 N = 0 Z位——如果指令的结果为0,则置1(通常用来表示比较的结果为“相等”);否则至0 C位——表示运算的进位、借位等 V位——益出标志位 第27位为Q标志位,只出现在V5以上带E的版本中,指出在增强型DSP指令中是否出现益出或饱和。 第24位为J位 第6、7位为中断禁止位,当I=1时,禁止IRQ中断;当F=1时,禁止FIQ中断。 第5位为T位,主要用于对ARM体系带T的版本,当T=0,处理器处于ARM状态;当T=1,处理器处于Thumb状态。 接下来的第0-4位为处理器的模式位,决定目前处理器所处在的工作模式,也就是7中工作模式中的一种。 另外寄存器中灰色的这些部分为保留位,以方便以后的扩展。 ALU 状态标识(被设置如果“S“-bit设置,在 Thumb 状态)。 粘连溢出标志 (Q flag) 被设置当: 当 QADD, QDADD, QSUB or QDSUB时发生饱和, 或者SMLAxy or SMLAWx 的结果超出32-bits。 一旦置位就不能使用上述指令来修改标识位而必须使用MSR 指令写 CPSR 来清除 PSRs 分为 4 个可以分别写的 8-bit 区: 控制(c) bits 0-7 扩展(x) bits 8-15 保留为将来使用 状态(s) bits 16-23 保留为将来使用 标识(f) bits 24-31 保留为将来使用的位将不能被当前的软件修改。 Typically, a read-modify-write strategy should be used to update the value of a status register to ensure future compatibility. Note that the T/J bits in the CPSR should never be changed directly by writing to the PSR (use the BX/BXJ instruction to change state instead). However, in cases where the processor state is known in advance (e.g. on reset, following an interrupt, or some other exception), an immediate value may be written directly into the status registers, to change only specific bits (e.g. to change 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,#0 使用系列条件指令必须满足: -没有必须复位条件码标志的指令 - 象BL这样会损坏标志位的指令必须最后执行 - 限制指令数不超过3条,否则不如采用判断并跳转 讲解如何使用不同的条件码时,可给一个if—then—else的例子。注意GCD练习快到了。 条件比较 - 如果执行,会复位条件码。 - 编译器经常使用此方法。 - 可能会很复杂,让人很难理解。 不仅仅针对比较指令,使用条件数据处理指令(加S bit)在某些情况下很有用。 LDM/LDR指令不能设置标志位,因为数据通道问题, (数据在周期非常靠后的时候才送回,这样来不及执行比较和设置状态标志位)。
4.2 指令集介绍 ARM指令集——存储器访问指令 ARM处理器是典型的RISC处理器,对存储器的访问只能使用加载和存储指令实现。ARM7处理器是冯•诺依曼存储结构,RAM存储空间及I/O映射空间统一编址,除对RAM操作以外,对外围IO、程序数据的访问均要通过加载/存储指令进行。 存储器访问指令分为单寄存器操作指令和多寄存器操作指令。
ARM存储器访问指令——单寄存器加载 助记符 说明 操作 条件码位置 LDR Rd,addressing 加载字数据 Rd←[addressing],addressing索引 LDR{cond} LDRB Rd,addressing 加载无符号字节数据 LDR{cond}B LDRT Rd,addressing 以用户模式加载字数据 LDR{cond}T LDRBT Rd, addressing 以用户模式加载无符号字节数据 LDR{cond}BT LDRH Rd, addressing 加载无符号半字数据 LDR{cond}H LDRSB Rd, addressing 加载有符号字节数据 LDR{cond}SB LDRSH Rd, addressing 加载有符号半字数据 LDR{cond}SH
ARM存储器访问指令——单寄存器存储 助记符 说明 操作 条件码位置 STR Rd, addressing 存储字数据 [addressing]←Rd, addressing索引 STR{cond} STRB Rd,addressing 存储字节数据 STR{cond}B STRT Rd,addressing 以用户模式存储字数据 STR{cond}T STRBT Rd,addressing 以用户模式存储字节数据 STR{cond}BT STRH Rd,addressing 存储半字数据 [addressing] ←Rd, STR{cond}H LDR/STR指令用于对内存变量的访问、内存缓冲区数据的访问、查表、外围部件的控制操作等。若使用LDR指令加载数据到PC寄存器,则实现程序跳转功能,这样也就实现了程序散转。 所有单寄存器加载/存储指令可分为“字和无符号字节加载存储指令”和“半字和有符号字节加载存储指令。 散转程序是分支程序的一种, 它可根据运算结果或用户输入数据将程序转入不同的分支.
ARM存储器访问指令——单寄存器存储 LDR和STR——字和无符号字节加载/存储指令 LDR{cond}{T} Rd,<地址> ;将指定地址上的字数据读入Rd STR{cond}{T} Rd,<地址> ;将Rd中的字数据存入指定地址 LDR{cond}B{T} Rd,<地址> ;将指定地址上的字节数据读入Rd STR{cond}B{T} Rd,<地址> ;将Rd中的字节数据存入指定地址 前索引偏移指令:LDR R0,[R1,#4] 其中,T为可选后缀。若指令有T,那么即使处理器是在特权模式下,存储系统也将访问看成是在用户模式下进行的。T在用户模式下无效,不能与前索引偏移一起使用T。
ARM存储器访问指令——单寄存器存储 LDR和STR——字和无符号字节加载/存储指令编码 B为1表示字节访问,为0表示字访问 P表示前/后变址 L用于区别加载(L为1)或存储(L为0) 指令执行的条件码 I为0时,偏移量为12位立即数,为1时,偏移量为寄存器移位 为指令的寻址方式 Rd为源/目标寄存器 Rn为基址寄存器 U表示加/减 W表示回写
ARM存储器访问指令——单寄存器存储 LDR和STR——字和无符号字节加载/存储指令 立即数。立即数可以是一个无符号的数值。这个数据可以加到基址寄存器,也可以从基址寄存器中减去这个数值。 如: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]
ARM存储器访问指令——单寄存器存储 LDR和STR——字和无符号字节加载/存储指令 立即数。立即数可以是一个无符号的数值。这个数据可以加到基址寄存器,也可以从基址寄存器中减去这个数值。 如: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]
ARM存储器访问指令——单寄存器存储 LDR和STR——字和无符号字节加载/存储指令 从寻址方式的地址计算方法分,加载/存储指令有以下4种格式: 零偏移。 如:LDR Rd,[Rn] 前索引偏移。 如:LDR Rd,[Rn,#0x04]! 程序相对偏移。 如:LDR Rd,labe1 后索引偏移。 如:LDR Rd,[Rn],#-0x04 注意:必须保证字数据操作的地址是32位对齐的。 若Rn是R15则不能使用!
ARM存储器访问指令——单寄存器存储 LDR和STR——半字和有符号字节加载/存储指令 LDR{cond}SB Rd,<地址> ;将指定地址上的有符号字节读入Rd LDR{cond}SH Rd,<地址> ;将指定地址上的有符号半字读入Rd LDR{cond}H Rd,<地址> ;将指定地址上的半字数据读入Rd STR{cond}H Rd,<地址> ;将Rd中的半字数据存入指定地址 注意: 1.有符号位半字/字节加载是指用符号位加载扩展到32位,无符号半字加载是指用零扩展到32位; 2.半字读写的指定地址必须为偶数,否则将产生不可靠的结果;
ARM存储器访问指令——单寄存器存储 LDR和STR——半字和有符号字节加载/存储指令编码 S为1表示有符号访问,为0表示无符号访问 W表示回写 P表示前/后变址 H为1表示半字访问,为0表示字节访问 指令执行的条件码 U表示加/减 为指令的寻址方式 I为0时,偏移量为12位立即数,为1时,偏移量为寄存器移位 Rd为源/目标寄存器 Rn为基址寄存器 L用于区别加载(L为1)或存储(L为0)
ARM存储器访问指令——单寄存器存储 LDR和STR指令应用示例: 1.加载/存储字和无符号字节指令 2.加载/存储半字和有符号字节指令 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+2
练习 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后缀指令 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时的数据传送 LDR R15,[R5] LDR R6,[R15] LDR R7,[R15,R7]! STR R15,[R7,R1] STR R0,[R15,#0X4]!
LDM{mode} Rn{!},reglist STM{mode} Rn{!},reglist ARM存储器访问指令——多寄存器存取 助记符 说明 操作 条件码位置 LDM{mode} Rn{!},reglist 多寄存器加载 reglist←[Rn...],Rn回写等 LDM{cond} {mode} STM{mode} Rn{!},reglist 多寄存器存储 [Rn...]←reglist,Rn回写等 STM{cond} 多寄存器加载/存储指令可以实现在一组寄存器和一块连续的内存单元之间传输数据。LDM为加载多个寄存器;STM为存储多个寄存器。允许一条指令传送16个寄存器的任何子集或所有寄存器。它们主要用于现场保护、数据复制、常数传递等。
ARM存储器访问指令——多寄存器存取 多寄存器加载/存储指令格式如下: LDM{cond}<模式> Rn{!},reglist{^} STM{cond}<模式> Rn{!},reglist{^} cond:指令执行的条件; 模式:控制地址的增长方式,一共有8种模式; !:表示在操作结束后,将最后的地址写回Rn中; reglist :表示寄存器列表,可以包含多个寄存器,它们使用“,”隔开,如{R1,R2,R6-R9},寄存器由小到大排列; ^:可选后缀。允许在用户模式或系统模式下使用。它有以下两个功能: 1)若op是LDM且寄存器列表包含R15时,那么除了正常的多寄存器传送外,还将SPSR也复制到CPSR中。这用于异常处理返回,仅在异常模式下使用。 2)数据传入或传出的是用户模式下的寄存器,而不是当前模式的寄存器。
ARM存储器访问指令——多寄存器存取 LDM和STM——多寄存器加载/存储指令编码 指令执行的条件码 P表示前/后变址 寄存器列表 U表示加/减 Rn为基址寄存器 S对应于指令中的”^”符号 L用于区别加载(L为1)或存储(L为0) W表示回写
ARM存储器访问指令——多寄存器存取 多寄存器加载/存储指令的8种模式如下表所示,右边四种为堆栈操作、左边四种为数据传送操作。 说明 IA 每次传送后地址加4 FD 满递减堆栈 IB 每次传送前地址加4 ED 空递减堆栈 DA 每次传送后地址减4 FA 满递增堆栈 DB 每次传送前地址减4 EA 空递增堆栈 数据块传送操作 堆栈操作 进行数据复制时,先设置好源数据指针和目标指针,然后使用块拷贝寻址指令LDMIA/STMIA、LDMIB/STMIB、LDMDA/STMDA、LDMDB/STMDB进行读取和存储 。 进行堆栈操作操作时,要先设置堆栈指针(SP),然后使用堆栈寻址指令STMFD/LDMFD 、STMED/LDMED、STMFA/LDMFA和STMEA/LDMEA实现堆栈操作。
ARM存储器访问指令——多寄存器存取 数据块传送指令操作过程如右图所示,其中R1为指令执行前的基址寄存器,R1’则为指令执行后的基址寄存器。 指令STMIA R1!,{R5-R7} 4008H 4004H 4000H 4014H 4010H 400CH 指令STMDA R1!,{R5-R7} 指令STMIB R1!,{R5-R7} R1’ R1 指令STMDB R1!,{R5-R7} 数据块传送指令操作过程如右图所示,其中R1为指令执行前的基址寄存器,R1’则为指令执行后的基址寄存器。
ARM存储器访问指令——多寄存器存取 堆栈操作(详见“4.1 寻址方式堆栈寻址”)和数据块传送指令类似,也有4种模式,它们之间的关系如下表所示: 数据块传送 存储 堆栈操作 压栈 说明 加载 出栈 STMDA STMED 空递减 LDMDA LDMFA 满递减 STMIA STMEA 空递增 LDMIA LDMFD 满递增 STMDB STMFD LDMDB LDMEA STMIB STMFA LDMIB LDMED ;使用数据块传送指令进行堆栈操作 STMDA R0!,{R5-R6} . . . LDMIB R0!,{R5-R6} ;使用堆栈指令进行堆栈操作 STMED R13!,{R5-R6} . . . LDMED R13!,{R5-R6} 两段代码的执行结果是一样的,但是使用堆栈指令的压栈和出栈操作编程很简单(只要前后一致即可),而使用数据块指令进行压栈和出栈操作则需要考虑空与满、加与减对应的问题。
4.1 ARM处理器寻址方式 寻址方式分类——堆栈寻址 堆栈是一个按特定顺序进行存取的存储区,操作顺序为“后进先出” 。堆栈寻址是隐含的,它使用一个专门的寄存器(堆栈指针)指向一块存储区域(堆栈),指针所指向的存储单元即是堆栈的栈顶。存储器堆栈可分为两种: 向上生长:向高地址方向生长,称为递增堆栈 向下生长:向低地址方向生长,称为递减堆栈
4.1 ARM处理器寻址方式 0x12345678 堆栈压栈 向下增长 向上增长 栈底 栈顶 栈区 SP 堆栈存储区 栈顶 栈底 栈区 寻址方式分类——堆栈寻址 0x12345678 堆栈压栈 向下增长 向上增长 栈底 栈顶 栈区 SP 堆栈存储区 栈顶 栈底 栈区 SP 堆栈压栈 0x12345678
4.1 ARM处理器寻址方式 堆栈指针指向最后压入的堆栈的有效数据项,称为满堆栈;堆栈指针指向下一个待压入数据的空位置,称为空堆栈。 栈顶 寻址方式分类——堆栈寻址 堆栈指针指向最后压入的堆栈的有效数据项,称为满堆栈;堆栈指针指向下一个待压入数据的空位置,称为空堆栈。 栈顶 SP 栈底 空堆栈 满堆栈 压栈 0x12345678 压栈 0x12345678 栈顶 SP 0x12345678 栈顶 SP
4.1 ARM处理器寻址方式 LDMIA R4,{R0,R1,R2,R3,R5} 所以可以组合出四种类型的堆栈方式: 寻址方式分类——堆栈寻址 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}
ARM存储器访问指令——寄存器和存储器交换指令 助记符 说明 操作 条件码位置 SWP Rd,Rm,Rn 寄存器和存储器字数据交换 Rd←[Rn],[Rn]←Rm (Rn≠Rd或Rm) SWP{cond} SWPB Rd,Rm,Rn 寄存器和存储器字节数据交换 SWP{cond}B SWP指令用于将一个内存单元(该单元地址放在寄存器Rn中)的内容读取到一个寄存器Rd中,同时将另一个寄存器Rm的内容写入到该内存单元中。使用SWP可实现信号量操作。 指令格式如下: SWP{cond}{B} Rd,Rm,[Rn] 其中,B为可选后缀,若有B,则交换字节,否则交换32位字;Rd用于保存从存储器中读入的数据;Rm的数据用于存储到存储器中,若Rm与Rd相同,则为寄存器与存储器内容进行互换;Rn为要进行数据交换的存储器地址,Rn不能与Rd和Rm相同。
ARM存储器访问指令——寄存器和存储器交换指令 SWP和SWPB——寄存器和存储器交换指令编码 指令执行的条件码 Rm源寄存器 B用于区别无符号字节(B为1)或字(B为0) 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{<cond>}{<size>} Rd, <address> STR{<cond>}{<size>} Rd, <address> e.g. LDREQB 注意: LDR指令中,目的地址(寄存器)在前,而 STR指令中,目的地址(寄存器)在后。这与Motorola相反。但这样保证了指令助记符格式的一致性。通常寄存器装载/存储在先,访问在后。 尺寸指定器(size specifier)发出MAS (存储器访问宽度)信号。 重要的是存储器必须支持所有访问宽度,尤其重要的是写,必须只有指定的宽度被写。 特定类型的符号扩展装载,必需!因为ARM 寄存器只保留32-bit值。( 可以画一个框图解释)。 但不需要特别的存储指令。 指令周期 数: STR LDR 7TDMI 2 周期 3 周期 9TDMI 1 周期 1 周期 – 如果 下个周期被使用,则会interlock StrongARM1 1 周期 1 周期 -如果 下个周期被使用,则会interlock Xscale 1 周期 1 周期 -如果 下2个周期被使用,则会interlock 注意:尺寸指定器(size specifier)放在条件码后面。 <address> 的解释见下一页。 注意:装载/存储指令不能设置条件码
地址访问 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方式寻址 v4T体系结构中加入了Halfword 和带符号的halfword/byte访问。 这是因为偏移量 不像普通的 word/byte 装载/存储那样灵活,不过不要紧,这样的访问很少。 框图见下一页
Pre or Post Indexed 寻址? Pre-indexed: STR r0,[r1,#12] 偏移量 r0 源寄存器 for STR 12 0x5 0x20c 0x5 r1 基址 寄存器 0x200 0x200 通过 STR r0,[r1,#12]!来自动更新基址寄存器 Post-indexed: STR r0,[r1],#12 更新 基址寄存器 r1 偏移量 0x20c 12 0x20c “!”表示“writeback”,也就是说,基址寄存器在这条指令后要更新。 在post-indexed方式下没有 “!”,这是因为此时基址寄存器已经被更新,(除非偏移量区域根本没使用)。 下面是一个 C程序例子: int *ptr; x = *ptr++; 这将编译为一条单指令: LDR r0, [r1], #4 r0 源寄存器 for STR 原基址 寄存器 0x5 r1 0x5 0x200 0x200
块数据传送 LDM / STM指令允许一次传送1到16个寄存器到/从存储器中。 基址寄存器指定存储器访问开始的地址 寄存器传送顺序不能被指定 最小数字的寄存器总是被传送到/从存储器的最低地址上。 LDMIA r10,{r0,r1,r4} 基址寄存器指定存储器访问开始的地址 块传送指令针对下列情况很有效: 从存储器中搬运一块数据 保存或恢复堆栈中的内容 如果是慢速存储器,会影响中断响应时间 r4 r1 地址增加 r10 r0 LDM/STM采用顺序访问模式,对于支持burst传输的存储器设备,性能可以达到最佳。 此时使用中断要小心,LDM/STM 会延长中断响应时间,尤其是使用慢速外部存储器 (窄总线,加等待) SDT编译器中,C 编译选项 ‘-zr’ 允许控制中断响应时间,通过指定每条指令中用于传送的寄存器数,最少为3(-zr3),最多为16(-zr16,默认设置) ADS 1.0x编译器中,此开关不存在,armcc (&tcc) 编译时指定LDM的最大寄存器数为 9。 ADS 1.1编译器中,开关‘-split_ldm’ 可减小最大寄存器数: 5 针对所有的 STM和不装载PC的 LDM 4 装载PC的LDM 通常此选项不需要提供, C 代码仅访问快速存储设备。 特权模式下, ‘^’用于访问用户模式寄存器。
LDM / STM 操作 IA IB DA DB LDMxx r10, {r0,r1,r4} STMxx r10, {r0,r1,r4} 语法: <LDM|STM>{<cond>}<addressing_mode> Rb{!}, <寄存器 list> 4 种寻址操作: LDMIA / STMIA Increment After(先操作,后增加) LDMIB / STMIB Increment Before(先增加,后操作) LDMDA / STMDA Decrement After (先操作,后递减) LDMDB / STMDB Decrement Before (先递减,后操作) IA IB DA DB LDMxx r10, {r0,r1,r4} STMxx r10, {r0,r1,r4} r4 r4 r1 r1 r0 地址 增加 永远是最低寄存器在先。 永远是访问存储器的低地址在先。 采用顺序周期加快访问。 ‘addressing_mode’ 确定基址指针是增(I)还是减(D),基址指针地址指向的内容是访问(A)还是跳过(B)。不能加任何偏移量到基址指针上。 注意:比较 LDM/STM和 LDR/STR 注意:基址指针不被装载或存储,除非是寄存器列表。 基址寄存器 (Rb) r10 r0 r4 r1 r4 r0 r1 r0
堆栈 ARM堆栈操作通过块传送指令来完成: STMFD sp!,{r4-r7,lr} LDMFD sp!,{r4-r7,pc} STMFD (Push) 块存储- Full Descending stack [STMDB] LDMFD (Pop) 块装载- Full Descending stack [LDMIA] STMFD sp!,{r4-r7,lr} LDMFD sp!,{r4-r7,pc} SP 100 FF 1234 AOBE 8034 1010 8420 9753 r4 1 r5 14544 r6 r7 12 lr 9048 pc 9020 r4 100 r5 FF r6 1234 r7 A0BE lr 8034 ABCD 8765 102E 16 FFFF 1010 8420 9753 存储器顶 SP 8034 pc SP Old SP 100 FF 1234 A0BE 8034 SP 8034 ** ANIMATED ** 其它类型的堆栈可使用下列后缀来执行 : FA Full Ascending, (满,正增长) ED Empty Descending, (空,负增长) EA Empty Ascending (空,正增长) STM=PUSH=DB LDM=POP=IA 讨论弹出 lr 到PC(用于子程序返回)。 也可使用 ! 来强制堆栈指针回写。 强调:低位寄存器永远放在低位存储器中。 A0BE A0BE r7 1234 1234 r6 FF FF r5 100 r4 100
SWP 在寄存器和存储器之间,由一次存储器读和一次存储器写组成的原子操作。完成一个字节或字的交换。 语法: SWP{<cond>}{B} Rd, Rm, [Rn] 1 Rn temp 2 3 Rm Rd 存储器 一个存储地址可看作为一个信号量,比如一个标志,表示串口空闲与否。为零表示标志被清除,串口空闲;为1表示置位标志,串口被使用。 在多处理器系统的各处理器之间, SWP可用来实现信号量,当然存储器系统要支持LOCK信号。它也适用于 作单处理器系统的多任务间的信号量,但不能用于用户模式,因为此时中断不能被临时屏蔽。 当一个处理器希望使用一个串口,它需要设置标志位。通过使用SWP 指令来设置标志。每次它尝试置位前,它必须检查标志是否在此之前被清除。 如果标志在SWP之前被清零,则处理器将置位该标志,并知道它拥有该信号量。如果标志在SWP之前被置位,则 SWP不影响该标志,如果处理器知道它没能成功获取此信号量,它必须重试。 当一个处理器完成信号量操作,则它简单写清除的值到此位置,不需要执行一个SWP。
4.2 指令集介绍 ARM指令集——分支指令 在ARM中有两种方式可以实现程序的跳转,一种是使用分支指令直接跳转,另一种则是直接向PC寄存器赋值实现跳转。 分支指令有以下三种: 分支指令B; 带链接的分支指令BL; 带状态切换的分支指令BX。
ARM分支指令——指令编码 分支指令B/BL指令编码格式 分支指令BX指令编码格式 指令执行的条件码 L区别B指令(L为0)和BL指令(L为1) 24位有符号立即数(偏移量) 分支指令BX指令编码格式 指令执行的条件码 Rm目标地址寄存器,该寄存器装载跳转地址
ARM指令——分支指令 助记符 说明 操作 条件码位置 B label 分支指令 PC←label B{cond} BL label 带链接的分支指令 LR←PC-4,PC←label BL{cond} BX Rm 带状态切换的分支指令 PC←Rm,切换处理器状态 BX{cond}
ARM指令——分支指令 助记符 说明 操作 条件码位置 B label 分支指令 PC←label B{cond} BL label 带链接的分支指令 LR←PC-4,PC←label BL{cond} BX Rm 带状态切换的分支指令 PC←Rm,切换处理器状态 BX{cond} 分支指令——B指令,该指令跳转范围限制在当前指令的±32M字节地址内(ARM指令为字对齐,最低2位地址固定为0)。指令格式如下: B{cond} Label 应用示例: B WAITA ; 跳转到WAITA标号处 B 0x1234 ; 跳转到绝对地址0x1234处
ARM指令——分支指令 助记符 说明 操作 条件码位置 B label 分支指令 PC←label B{cond} BL label 带链接的分支指令 LR←PC-4,PC←label BL{cond} BX Rm 带状态切换的分支指令 PC←Rm,切换处理器状态 BX{cond} 带链接的分支指令——BL指令适用于子程序调用,使用该指令后,下一条指令的地址被拷贝到R14(即LR) 连接寄存器中,然后跳转到指定地址运行程序。跳转范围限制在当前指令的±32M字节地址内。指令格式如下: BL{cond} Label 1.当程序执行到BL跳转指令时,硬件将下一条指令的地址Addr2装入LR寄存器,并把跳转地址装入程序计数器(PC) 2. 程序跳转到目标地址Label继续执行,当子程序执行结束后,将LR寄存器内容存入PC,返回调用函数继续执行 BL Label xxx Label MOV PC,LR Addr1 Addr2 LR PC Addr1 Addr2 Label Addr2 应用示例(调用子程序): BL Label
ARM指令——分支指令 助记符 说明 操作 条件码位置 B label 分支指令 PC←label B{cond} BL label 带链接的分支指令 LR←PC-4,PC←label BL{cond} BX Rm 带状态切换的分支指令 PC←Rm,切换处理器状态 BX{cond} 带状态切换的分支指令——BX指令,该指令可以根据跳转地址(Rm)的最低位来切换处理器状态。其跳转范围限制在当前指令的±32M字节地址内(ARM指令为字对齐,最低2位地址固定为0)。指令格式如下: BX{cond} Rm 跳转地址Rm[0] 跳转后 CPSR标志T位 处理器状态 ARM 1 Thumb
ARM指令——分支指令 助记符 说明 操作 条件码位置 B label 分支指令 PC←label B{cond} BL label 带链接的分支指令 LR←PC-4,PC←label BL{cond} BX Rm 带状态切换的分支指令 PC←Rm,切换处理器状态 BX{cond} 带状态切换的分支指令——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的最低位来切换处理器状态
桶型移位器 LSL : Logical Left Shift ASR: Arithmetic Right Shift CF Destination Destination CF (无符号数)乘2 除2,并保留符号位 LSR : Logical Shift Right ROR: Rotate Right Destination CF Destination CF ...0 (无符号数)除2 位轮换 左轮换可通过右轮换来实现(向右32-number),比如,左轮换10位等于右轮换22位。 RRX 用于特殊应用,如加密算法,不能由C编译器产生。我们把它用于 64/64位的除法。RRX 允许右移多精度数 。此命令也用于 ARM的MPEG算法中的一段非常巧妙的代码。 ANSI C没有轮换操作,它只有 “<<“和“>>”,相当于 LSL, LSR和ASR。然而ARM编译器认识轮换表达式,并优化为ROR,如: int f(无符号int a) { return (a << 10) | (a >>22) ; } => MOV a1,a1,ROR #22 对于*logical*数据处理操作,进位标志(Carry flag)接收移位器的输出 RRX: Rotate Right Extended Destination CF 位轮换,从 CF到MSB都参与操作
桶型移位器: 第二个操作数 操作数1 操作数2 结果 寄存器, 可选择是否增加移位操作. 立即数 移位值可以是: 用于常数乘法 5 bit 无符号整数 放在另一个寄存器的低字节 用于常数乘法 立即数 8 bit ,大小范围0-255。 右移偶数位 允许直接加载32-bit 常数到寄存器中。 操作数1 Barrel Shifter 操作数2 ALU 可以适当提及 7TDMI 核里的A bus和B bus, 例子程序: ADD r0, r1, r2 ADD r0, r1, r2, LSL#7 ADD r0, r1, r2, LSL r3 ADD r0, r1, #0x4E 结果
Quick Quiz: 0xe3a004ff MOV r0, #??? 立即数 (1) 没有任何一条ARM 指令可包括一个32 bit的立即数 所有的ARM指令都是32 bits固定长度 数据处理指令格式中,第二个操作数有12位 4 bit 移位值 (0-15)乘于2,得到一个范围在0-30,步长为 2的移位值。 记住一条准则: “最后8位一定要移动偶数位”. 11 8 7 rot immed_8 Quick Quiz: 0xe3a004ff MOV r0, #??? x2 Shifter ROR 可允许直接使用12 bits立即数(0-4095)。但这样不适用于大数,如 目标系统中的存储器设备的基址 大但是简单的大数如0x10000 研究表明,需要的数据大部分是小数,但也有部分大数。 常数的 50%处在 –15到+15之间,90%处于 –511到+511之间。取决于是何种应用。 ROR #n 相当于ROL #32-n 操作码 0xe3a004ff = MOV r0, #0xff, 8 表示内核右移0xff 8位(4对位)=> MOV r0, #0xff000000
立即数 (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 立即数不能使用上述方法产生,否则将导致错误。 31 ror #0 range 0-0x000000ff step 0x00000001 ror #8 range 0-0xff000000 step 0x01000000 ror #30 range 0-0x000003fc step 0x00000004 讲课时指出,立即数必须是由一个最多8-bit数字移动偶数位产生的32位数字,这样其它位必须为零。 注意,移位可能使8-bit 立即数部分在前,部分在后。 mov r0, #256 ; mov r0, #0x100 mov r1, #0x40, 30 ; mov r1, #0x100 这种产生常数的方法可产生3073个数,比直接使用12bit来产生的数据个数少,大约25%不到。然而,更有效。
装载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 建议把常数装载到寄存器中时一律使用该伪指令。 数据池(Literal pools) 汇编器把常数嵌入到代码中,或用户使用LTORG来指定放在哪里,此数据必须不被执行(否则为未定义指令)。ARM C 编译器通常加入一小段literal pools来自动处理。 26
测验 #1 1. 写一条 ARM 指令,分别完成下列操作: 2. 下面哪些立即数是数据处理指令中有效的数据? 3. BIC指令做什么用? 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 指令? 1a) MOV r0,#16 or LDR r0,=16 1b) MOV r0,r1,ASR#4 (注意,但是编译器不会产生此指令,因为该指令不会正确截取) 1c) RSB r1,r2,r2,LSL#2 or ADD r1,r2,r2,LSL#1 1d) RSB r0,r0,#0 2a) YES 2b) NO 2c) YES 2d) NO 2e) YES 2f) NO – 但可使用MVN rn,#0来获取 3) 相当于AND NOT 操作 ,位清零(‘bit clear’) 4) 为保证指令集的正交性,第二个操作数相对更灵活,但减法是不可交换的 (x-y不等同于y-x)。 如果问到更多问题,如为什么需要BIC指令?因为AND是一种清零的普通操作 。通常编程人员希望清除一些位,这样AND所带的立即数会包括很多1,确保其它的位不被改变。然而这种立即数(很多1,少量的0)不能通过ARM “8 bits移位偶数次得到。因此需要 BIC。
测验 #2 - GCD 新建一个 ‘ARM Executable Image’ 项目 新建一个 text文件 另存为 “gcd.s” 加入到项目中 Build 并执行 Start Yes r0 = r1 ? Stop No AREA myarea, CODE ENTRY MOV r0, #9 MOV r1, #15 start ; your code here stop B stop END r0 > r1 ? Yes No r0 = r0 - r1 r1 = r1 - r0 使用Euclid’s 算法来计算最大公约数(GCD, Greatest Common Divisor)。 示例中 9和15的GCD为3。 解释主要汇编语言源程序。 END是伪指令,表示程序结束。 stop B stop 为死循环 必须添加文件到项目中。可使用Project ‘Add Window’ or ‘Add Files…’ 按stop按钮中止执行(ARM没有stop指令) 2109 和 4161 的GCD 为57 (0x39). 最优代码: start CMP r0, r1 SUBLT r1, r1, r0 SUBGT r0, r0, r1 BNE start 结果保存在 r0 你只需要使用CMP、SUB和B指令。 充分使用条件执行! 大家可以尝试计算 2109 和 4161 的GCD
乘法 语法: 占用的周期数 以上均为一般规则,确切细节查看相应手册。 基本 MUL 指令 ARM9TDMI 比 ARM7TDMI多1 周期 MUL{<cond>}{S} Rd, Rm, Rs Rd = Rm * Rs MLA{<cond>}{S} Rd,Rm,Rs,Rn Rd = (Rm * Rs) + Rn [U|S]MULL{<cond>}{S} RdLo, RdHi, Rm, Rs RdHi,RdLo := Rm*Rs [U|S]MLAL{<cond>}{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 周期 以上均为一般规则,确切细节查看相应手册。 一些处理器因为采用“提前结束”(early termination)技术,故占用的周期数不定。 如果Rs小,则乘法运算就快 。 ARM7TDMI和ARM9TDMI采用8-bit Booth算法,对于Rs中的每个BYTE都要花费1 周期。如果Rs中剩余的部分为全0或全1,则终止。 MUL/MLA不区分有符号数还是无符号数。因为返回结果的低32-bit相同,而不管是否带符号。 以上周期信息是一种普遍描述,特定的内核有些不同。 XScale和StrongARM有一个split流水线用于乘法运算。所以乘法可能占用1 到 2 个周期,并继续下面的指令(假定没有其它结果或源依赖此结果)。 XScale 可在1 周期内执行MUL/MLA/MULL (MLAL 需要 2 周期)。 已经不再使用原来提供的乘法器。 周期数取决于结果的存在周期,比如一条指令如果在乘法完成前尝试使用结果,则内核将暂停。 注意: 乘法指令不包含立即数,只有寄存器。 对于感兴趣的学生:如果在V5以前的内核上设置了S,则C标记是不确定的。 MULS/MLAS 一般花费 4 周期; MULLS, MLALS一般花费5个。
SWI number (ignored by processor) 31 28 27 24 23 Cond 1 1 1 1 SWI number (ignored by processor) 条件域 产生一个异常陷阱,跳转到SWI 硬件向量。 SWI 处理程序可以检测SWI号,从而决定采取何种操作。 通过SWI机制,运行在用户模式下的应用程序,可请求操作系统执行一系列特权操作。 语法: SWI{<cond>} <SWI number> 事实上,SWI是一种用户自定义指令。 用于调用操作系统(切换到特权模式) SWI号用于指定操作号码,区别处理。例如:SWI 1启动一个新任务,SWI 2分配一段存储空间。等等。 使用号码有一个好处:操作系统可以有不同的版本,同一个应用程序将可以在每个操作系统上使用。
PSR 传送指令 MRS和MSR允许传送CPSR / SPSR中的内容到/从一个通用寄存器中。 语法: 在这里: 27 31 N Z C V Q 28 6 7 I F T mode 16 23 8 15 5 4 24 f s x c U n d e f i n e d J MRS和MSR允许传送CPSR / SPSR中的内容到/从一个通用寄存器中。 语法: MRS{<cond>} Rd,<psr> ; Rd = <psr> MSR{<cond>} <psr[_fields]>,Rm ; <psr[_fields]> = Rm 在这里: <psr> = CPSR or SPSR [_fields] = ‘fsxc’的任意组合 也允许送一个立即数到 psr_fields MSR{<cond>} <psr_fields>,#Immediate 用户模式下,所有位均可以被读取,但只有条件标志位 (_f)可被写。 状态寄存器分成四个8-bit的区域,每个区域可单独改写: 位31到24:标志位区域 ,包含NZCV 标志位和4未使用的位 位23到16:状态区域(ARMV3、V4、V4T结构中没使用) 位15到8 : 扩展区域(ARMV3、V4、V4T结构中没使用) 位7到0 : 控制区域(I & F 中断使能位,5个处理器模式位,T bit on ARMv4T.) MSR的这种分区域的特性,可以精确地修改某部分,而屏蔽其它部分。但当心 ,尽量采用read-modify-write策略,这样目前尚未分配地位保证不受影响。否则这种代码会不能直接用在将来使用该位的内核上。 当使用标志位时,选择好立即数,屏蔽27到24位,保证其为只读属性。 对于MSR 操作,建议只修改需要改变的区域,因为将来 ARM 执行时可能需要花费额外的周期来改写特定的区域。 不写你不想修改的区域,这将节省那些额外的周期。 例如:用一个MRS/BIC/ORR/MSR 序列 来修改处理器模式,这优于指令 MSR CPSR_c,Rm。
协处理器指令 ARM体系支持16个协处理器 针对每个协处理器的指令占用 ARM指令集中的固定部分 这有三种协处理器指令 如果相应的协处理器不存在, 将发生一个未定义指令异常。 这有三种协处理器指令 协处理器数据处理指令 CDP:初始化协处理器数据处理操作 协处理器寄存器传送指令 MRC:从协处理器寄存器移到ARM 寄存器 MCR:从 ARM 寄存器移到协处理器寄存器 协处理器存储器传送指令 LDC:从存储器装载到协处理器寄存器 STC:从协处理器寄存器存储到存储器 每条协处理器指令包含在它解码所指向的协处理器内,只有它才能执行此特殊指令。 CDP:协处理器执行一些只发生在自身内部的处理。如读协处理器的寄存器,运算,回写协处理器寄存器。ARM 不需要暂停来等待此操作完成,允许并行处理。 协处理器需要使用interlock (或stall) 来保证不发生更进一步的操作。 MCR/MRC:在协处理器和ARM之间传送寄存器中的值 。 ARM不执行任何处理,但协处理器可以,如传送过程中转换浮点寄存器为整型。ARM部分解码此指令,再通过协处理器接口发送/接收一个32-bit 寄存器值 。 LDC/STC:把数据从存储器装载/存储到协处理器寄存器。ARM执行寻址 (ARM 寄存器 + 偏移量)并传送数据到/从协处理器。可以装载多个字到协处理器中(由协处理器通知ARM什么时候停止)。协处理器也可以在加载数据的同时执行一些操作。 比如:MOVE 协处理器和VFP 协处理器。MOVE指令是从第一幀加载一个 8x8象素块,然后求方差和,并同时再从第二幀的不同地址加载一个 8x8象素块。
测试 #4 1. 写几条ARM 指令,使能IRQ中断 2. 下列 ARM 指令将做什么? a) LDRH r0,[r1,#6] b) LDR r0, =0x999 3.在装载或存储指令中, “!”表示什么? 4. 当 执行SWI 指令时,会发生什么? 5. SWP 指令的优势是什么? 1) 仅工作在特权模式,一般在初始化时使用。 MRS r0, cpsr BIC r0, r0, #0x80 MSR cpsr_c, r0 2a)从 (r1+6)处 装载Halfword 到 r0。 不更新 r1,清除高16 bits 2b) 创建一个literal pool(包含 0x999),并用LDR指令来装载。 3) 更新基址寄存器 (用于 pre-indexed和LDM/STM)。 Post-indexed 一直更新基址寄存器. 4) 跳到SWI向量入口处(0x8),并切换为SVC模式。 主要用于操作系统入口。后面还会详细讲述。 5) 原子操作 (即不可中断)。执行信号量时特别有用。也可以设置LOCK信号,使其他总线控制器不能进入。适用于多处理器系统。
议程 ARM 指令集 Thumb 指令集 v5TE体系结构扩展 ARM指令集:针对v4体系 Thumb指令集:主要解释v4T体系增加的部分 v5TE体系结构: v4T到v5TE体系增加的部分 各种版本的体系总是向后兼容的!v4T体系的代码可以运行在v5TE体系的芯片上。
Thumb ADDS r2,r2,#1 ADD r2,#1 Thumb 是16-bit 指令集 核存在一个执行状态 – Thumb状态 代码密度优化 (总代码大小约为ARM指令的65%) 使用窄总线存储器时可以大大提高性能。 是 ARM 指令集的一个子集。 核存在一个执行状态 – Thumb状态 ARM和Thumb之间切换使用BX 指令 31 32-bit ARM 指令 ADDS r2,r2,#1 对于由编译器产生的大部分指令: 没有条件执行 源、目的寄存器必须相同 仅能使用低寄存器 常数大小有限制 不能使用在线移位器 15 16-bit Thumb 指令 ADD r2,#1
ARM / Thumb 交互工作 Rn BX跳转的地址 使用Branch Exchange 指令来完成 Interworking BX Rn ; Thumb 状态下的Bx指令 BX<condition> Rn ; ARM状态下的Bx指令 也可以只是执行一个绝对跳转,无须状态更换。 31 1 Rn ARM / Thumb 选择 0 - ARM 状态 1 - Thumb 状态 31 BX跳转的地址 1 一个Thumb兼容的处理器可工作在ARM或Thumb两种状态下。 有时需要从某种状态下切换成另一种状态。这就要使用 branch exchange 指令。 两种状态下,均实现:拷贝通用寄存器 Rn的内容到PC中,完成跳转;流水线清空,从Rn所指地址处取指重装载; BX与PC无关,为绝对跳转。 ARM状态下,指令格式为: BX{<cond>} Rn Thumb状态下,指令格式为: BX Rn ; Rn 可以是高位寄存器(R8-R15)或低位寄存器(R0-R7) 由于所有的 ARM 指令字对齐,所有的Thumb 指令半字对齐。这样,Rn的最低位就必须为0。 所以处理器利用该位来判断跳转后指令应当为什么状态。 如果 bit 0为1,则切换为Thumb状态 如果 bit 0为0,则切换为ARM状态。
写 Thumb汇编程序 Thumb不是一个“好” 指令集! 代码处理通常优于ARM 指令 更多细节,参看: 最好用编译器来产生 约束并不一致 ARM “Architecture Reference Manual” Chapters A6和A7
议程 ARM 指令集 Thumb 指令集 v5TE体系结构扩展 ARM指令集:针对v4体系 Thumb指令集:主要解释v4T体系增加的部分 v5TE体系结构: v4T到v5TE体系增加的部分 各种版本的体系总是向后兼容的!v4T体系的代码可以运行在v5TE体系的芯片上。
v5TE结构 v5TE体系包括全部的 v4T ARM和Thumb 指令集,还有: 更支持interworking Breakpoint 指令 (ARM和Thumb) CLZ(Count Leading Zeros)指令 扩展协处理器指令 - MCR2等等 支持饱和处理 封装的带符号的半字乘法指令 双字装载/ 存储指令 Cache预装载指令 双字协处理器 传送指令 - MCRR/MRRC 提升了interworking能力,ARM和Thumb代码之间切换不再需要veneers。这意味着更短代码、更高性能。 Breakpoint 指令:提高了调试功能,不再必须使用无条件断点指令。 CLZ :允许检测一个字中的最高位 1,这比完成同种功能的指令序列更快。 无条件的协处理器指令:双字指令,更有效地利用了协处理器空间,同时又没有占用更多的指令集空间。 饱和处理、DSP乘法和Q标志位(CPSR的27位)提高了DSP类型的算法的速度。Q标志位在执行 QADD, QDADD, QSUB或QDSUB时会被影响,如果SMLAxy或SMLAWx的结果溢出(相对32-bits)也将被置位。一旦Q标志位被置位,只能通过 MSR指令来修改CPSR,以清除标志位。 注意: Thumb 状态下只有breakpoint和增强的interworking 指令有效,其它附加指令只适用于 ARM状态。
你采用的处理器是哪种结构? 处理器核 结构体系 7TDMI & 9TDMI v4T 9E-S rev1 v5TE 处理器核 结构体系 7TDMI & 9TDMI v4T 9E-S rev1 v5TE 926EJ-S/1026EJ-S v5TEJ 1020E v5TE StrongARM v4 XScale Microarchitecture v5TE v5TExP和v5TE之间的区别很小,不单独列出: LDRD/STRD 不能用在 v5TExP的用户模式下 MCRR/MRRC 对某些协处理器可能不适用 PLD cache hint, 不是很重要
前导零计数指令 CLZ R1, R0 MOV R0, R0 LSL R1 EOR R1, R0, R0, LSL#1 CLZ R1, R1 CLZ{cond} Rd, Rm 计算寄存器中的值有多少个前导0 源寄存器从最高位开始计算。 1个周期完成 (ARM9E-S/ARM102x) 如果没有任何一位被置位,结果是32;如果 bit 31被置位,结果为0。 Rm 左移 Rd位即可标准化Rm 带符号的标准化需要额外的 1个周期 R0 = 0000 0010 1110 1101...0 CLZ R1, R0 R1 = 0x6 MOV R0, R0 LSL R1 Rm = 1011 1011 0100 0000...0 Main applications: 加速除法 (Newton Raphson) 从中断状态寄存器中找出中断源 浮点标准化 Newton-Raphson 除法性能: 16-bit 无符号除法占用22-周期 32-bit 无符号除法占用38 周期 标准化移位通常用于统一随后发生的数据处理指令,使用CLZ 指令缩短标准化时间。 带符号位的标准化: 首先找到 1111‘10’ 对(或 0000‘01’对),然后移位到顶,这样就保留了符号位。 奇妙的EOR 指令是ARM公司汇编人员的一大发明,如果不懂也没关系。 EOR R1, R0, R0, LSL#1 CLZ R1, R1 MOV R0, R0, LSL R1
扩展协处理器指令 CDP2, LDC2, STC2, MCR2, MRC2 新格式的标准协处理器指令为协处理器设计人员提供了附加的操作码空间。 同样是无条件执行的
新的有符号乘法操作 Rn SMULxy{cond} Rd, Rm, Rs SMULWy{cond} Rd, Rm, Rs (RdHi,RdLo) 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’位) Rm Rs T B T B 16 16 16 16 32/64 W option 32 16 Fractional multiplies are common in many DSP algorithms, and at some point, you’re going to want to multiply two fractions together, keeping the upper bits of the product which represent the most significant bits of the fraction. The signed multiplies all take two source operands, multiply them together, then either add another operand into the result or just give the result to the register bank. SMULxy: 16x16->32. For all of these instructions, the upper or lower half of both the source registers can be chosen with ‘T’ and ’B’. SMULWy: 32x16->32. ‘y’ selects top or bottom half of second source. Note 32-bit result is generated by discarding lower 16 bits of intermediate 48-bit product. SMLAxy: 16x16+32->32. SMLAWy: 32x16+32->32. SMLALxy: 16x16+64->64. Accumulation is into pair of registers. On ARM9E, all instructions except SMLAL issue in a single-cycle but result latency is longer. On ARM1020E, SMUL issues in 1 cycle, SMLA in 2 cycles and SMLAL in 3. The ARM1020E is read-port limited and therefore takes an additional cycle to read the accumulate value (if anyone asks). Although Q flag is set if accumulation overflows (in SMLA* instructions), there is no saturation. These instructions never change NZCV flags. Rd (RdHi,RdLo) 32/64
测试 #5 - DSP power calculation 1) 写一段汇编代码 ‘qtest’ 测试标志位 Q 并清零。 源文件模板在文件 ‘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位累加器 x r0 x[0] x[1] x[2] x[3] x[4] x[5] x[62] x[63] To calculate the power of a signal, must square all the samples and total. There is a possibility that the Qflag will be set during the calculation - it is a sticky overflow flag so we don’t need to check it during the loop. This detects overflow only: saturation is not part of this example. 1) CPSR must be copied to an ARM register where it can be operated on. Question to class: how to test the Qflag? - use AND or TST. Question to class: how to clear the Qflag? - use BIC. Ideally, should conform to APCS. Intended optimal answer is: MRS r0, cpsr BIC r1, r0, #Qflag AND r0, r0, #Qflag MSR cpsr_f, r1 MOV pc, lr 2) mov r2,#64 mov r4,#0 loop: ldrh r1,[r0],#2 smlabb r4,r1,r1,r4 subs r2,r2,#1 bgt loop Answer is: r4 = 0x011d4324 3) Yes, on r1 between ldrh and smlabb (can be partially removed by swapping smlabb and subs, because smlabb does not affect condition codes - can’t be completely removed since ldrh takes one more cycle than ldr to deliver the result due to the rotation required) 6) mov r2,#64 mov r4,#0 loop: ldr r1,[r0],#4 subs r2,r2,#1 ; note - scheduled to avoid interlock smlabb r4,r1,r1,r4 smlatt r4,r1,r1,r4 bgt loop 7) Use smlalbb/smlaltt to accumulate into two registers (don’t forget to set both to zero at start). High word of result is 0x00000003 NOTE - must assemble with “-cpu 5TE” in order to use these instructions.
饱和算术 0x7FFFFFFF 加上1产生一个负的结果 0x80000000 减去1,会产生一个正的结果 饱和算术指令会区分这两种情况,使得在最大值和最小值越界时产生饱和 经常用于表示 1 到 -1 “Q31” 算术 AXD 可以显示 Q31 格式 0x7FFFFFFF - Most Positive Number +ve 0x0 -ve This foil demonstrates saturated maths operations. It shows the most positive signed numbers and the most negative numbers. Point out that the condition that needs trapping is when one of the boundaries is crossed. “Q31” representation is explained in section A.10.3 of the ARM ARM. Worth reading this in advance and referring students to it. 0x80000000 - 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)) 这些指令影响标志位Q Math/Maths joke if US audience VoIP - voice over IP AMR - adaptive MultiRate codec for 3G phones These instructions all saturate their results. If the result is used in the next instruction as an operand besides an accumulate within a multiply then there will be a cycle of interlock. Note the double operation saturates as well as the add - this is important for correctness (to handle -1*-1). Use of QDADD will be demonstrated later. Note that these instructions never affect the NZCV flags (specifying ‘S’ is not allowed).
QADD 示例 + + 例 1 没有超过最大值边界,因此不会产生饱和 例 2 计算结果超过最大值边界,因此产生饱和且标志位 Q 被置位 R1 = 0x7F000000 0x7F001000 + Saturate 0x7F001000 R2 = 0x00001000 R1 = 0x7F000000 0x80000000 + Saturate 0x7FFFFFFF R3 = 0x01000000 The top example just shows how an QADD simply operates as an ADD without any saturation. In the second example the QADD operation effectively overflows. Instead of overflowing the result is saturated at the most positive value and the Q flag is set. Note that, although it might appear this way from the diagram, saturation cannot be determined by examining the result of the addition alone - the inputs must also be examined. 例 1 没有超过最大值边界,因此不会产生饱和 例 2 计算结果超过最大值边界,因此产生饱和且标志位 Q 被置位
QDADD 示例 (1) 0x2000 (1/4) x 0x4000 (1/2) 0x08000000 (1/16) Q15 format 15 S 1/2 1/4 1/8 1/16 1/32768 该示例表示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) A 32-bit signed quantity used to represent a fractional number between +1 and -1 is referred to as a “Q31 number” (a 16-bit quantity would be a “Q15 number”). Normal saturated addition and subtraction operations work on numbers represented this way. Multiplication however, of e.g. two Q15 numbers gives a Q30 result i.e. there are 30 fractional bits. Typically, we work with Q15 and Q31, not Q30, so this Q30 result needs to be converted to Q31 form. To do this, it must be doubled. The example on this foil show how the Q15 numbers used to show 1 to -1 when multiplied together give the “incorrect” result. This is corrected by the D of the QD instruction. Negative numbers work because it is a signed multiplier. E.g. 0x4000 (1/2) x 0xE000 (-1/4 2’s complement) 0xF8000000 (-1/16) LSL 1 0xF0000000 (-1/8 2’s complement) There is no need to convert the answer coming out of the multiplier from Q30 to Q31 form after every instruction. If you have a series of multiply and accumulates, then so long as the accumulator is initially in Q30 form, the multiply and accumulates work. Only when you try to use the accumulator somewhere else does it need converting, hence requiring QDADD or QDSUB
+ QDADD 示例 (2) 输入 1 和 –1之间的乘数 乘法结果是 Q30格式** QDADD 在加法操作之前将 Rn 转化为 Q31 格式 ** 注: ARM 可以正确的处理 -1*-1的情况 S 15 S 15 SMULxy 30 SS Q30 Now Q31 S 30 Rm + QDADD This foil shows why you need a QD operation. When the a 16 bit value is showing values between 1 and -1 then the top bit is used as a sign bit. When you multiply two Q15 numbers like this together, you get a Q30 result. The QD operations can take this Q30 result and convert it into a Q31 number before combining it with other another Q31 operand to give a result in Q31 format. 30 S Q31
Load / Store 双寄存器 LDR/STR{<cond>}D <Rd>, <addressing_mode> 内存中两个相邻的字与寄存器对 (r0,r1), (r2,r3), (r4,r5), (r6,r7), (r8,r9), (r10,r11) 或 (r12,r13)的传送 Rd 指示偶数寄存器号。相邻的奇数寄存器自动作为传送的第二个寄存器。 与 LDRH/STRH寻址模式相同。 地址必须是双字对齐 (8-byte) 。 Main benefit of LDRD/STRD over LDM/STM of 2 regs is ability to have an offset (e.g. for accessing values on the stack or in a struct), and better code density than 2x LDR/STR. Offset can be: An unsigned 8 bit immediate value (ie 0-255 bytes). A register (unshifted). This can be either added or subtracted from the base register: Prefix the offset value or register with ‘+’ (default) or ‘-’. This offset can be applied: before the transfer is made: Pre-indexed addressing after the transfer is made: Post-indexed addressing Autoupdate on pre-indexed form by postfixing instruction with ! ADS1.1 C compiler can generate these instructions, but only if -Oldrd option is specified when compiling for architecture 5TE. In this case, note that the alignment requirement for double and long long will be 8 bytes and that the output object will be marked as requiring 8-byte alignment (including the stack). Such an object would be unlikely to link with objects built with earlier tools.
Cache 预读 PLD [Rn,<offset>] 偏移量可以是 偏移量可以为正的,也可以为负 无符号12位立即数 (ie 0 - 4095 bytes). 寄存器,可以使用立即数移位操作 偏移量可以为正的,也可以为负 通知存储器系统某一地址的数据极可能即将被访问 存储器系统将数据调入缓存以便后面访问 对于不支持该操作的存储器系统,该指令 相当于NOP。 无条件执行 Xscale, ARM1020, ARM1022, ARM1026EJ-S all support this instruction.
MRRC/ MCRR MRRC{<cond>} <coproc>, <opcode>, <Rd>, <Rn>, <CRm> MCRR{<cond>} <coproc>, <opcode>, <Rd>, <Rn>, <CRm> 传送两个 ARM 寄存器与协处理器而不是一个 提高了ARM–coprocessor 传送带宽。提高代码宽度到64位 一条指令传送存放在两个ARM寄存器的双精度浮点数到一个浮点寄存器就是一个浮点协处理器的例子 。 使用 r15会产生不可预知的问题
测试 #6 1) CLZ 可用于那些运算? 2) 哪一条指令会置位标志位 Q? 3) 标志位Q值为后,怎样清零? 4) 下面这条指令合法吗? 4) 下面这条指令合法吗? LDRD r7, [r1,#0x100] 5) PLD 指令做什么操作? 6) 哪些ARM指令总是无条件执行? 1) - speeding up divide operations (work out how many iterations required) - speeding up floating point maths - faster interrupt source identification 2) Flag is set either when - saturation occurs during QADD, QDADD, QSUB or QDSUB, or - the result of SMLAxy or SMLAWx overflows 32-bits 3) Only by writing to CPSR using MSR instruction 4) No - destination register (r7) is odd (should be even) - offset is too big (greater than 255) 5) Provides a hint to the memory system that the specified address should be loaded into the cache. 6) - BLX (pc-rel - the BLX Rn form is conditional) - PLD - CDP2, STC2, LDC2, MRC2, MCR2
参考材料 ARM “Architecture Reference Manual” - 2nd edition edited by David Seal ARM DDI 0100E is latest, covering v5TE DSP extensions ISBN 0-201-737191 (Addison-Wesley) PDF on ADS和‘Technical Documentation’ CDs Steve Furber “ARM 系统-on-chip architecture” - 2nd edition ISBN 0-201-67519-6 (Addison-Wesley) Quick Reference Card ARM QRC 0001E comes with ADS 1.2 ADS 1.2 Assembler Guide refers to ADS Examples directory
分支指令 Link bit 0 = Branch 条件码区域 Branch : B{<cond>} label Branch with Link : BL{<cond>} subroutine_label 处理器核按偏移量左移两位,符号扩展,再把该值加到当前PC寄存器内 跳转范围:± 32 Mbyte 如何执行长跳转? 31 28 27 25 24 23 Cond 1 0 1 L 偏移量 Link bit 0 = Branch 1 = Branch with link 条件码区域 PC-relative允许独立于代码位置、受限制的跳转范围(邻近范围)。 如何访问全部32-bit地址空间?可以手动设置LR寄存器,然后装载到PC中。 MOV lr, pc LDR pc, =dest ADS连接器(linker)会自动为长跳转(超过32Mb范围)生成veneers(桌布)。