2.02k likes | 2.13k Views
ARM 指令集与编程. 目录. 总体介绍:指令分类,特点,格式,条件码 ARM 指令寻址方式 数据处理指令:数据传输指令,算术指令,逻辑指令,比较指令,乘法指令 ( 略 ) ,前导零计数 ( 略 ) 程序状态访问指令 跳转指令 单数据访存指令 多数据访存指令 其它指令:信号量操作指令,异常中断产生指令,协处理器指令 ( 略 ) 伪指令 基于 ARM 的编程. 1 总体介绍:指令分类,特点,格式,条件码. 1.1 指令分类. ARM 指令集总体分为 6 类指令 数据处理指令:数据传输指令,算术指令,逻辑指令,比较指令,乘法指令,前导零计数。
E N D
目录 • 总体介绍:指令分类,特点,格式,条件码 • ARM 指令寻址方式 • 数据处理指令:数据传输指令,算术指令,逻辑指令,比较指令,乘法指令(略),前导零计数(略) • 程序状态访问指令 • 跳转指令 • 单数据访存指令 • 多数据访存指令 • 其它指令:信号量操作指令,异常中断产生指令,协处理器指令(略) • 伪指令 • 基于ARM的编程
1 总体介绍:指令分类,特点,格式,条件码
1.1 指令分类 ARM指令集总体分为6类指令 • 数据处理指令:数据传输指令,算术指令,逻辑指令,比较指令,乘法指令,前导零计数。 • 程序状态访问指令:mrs和msr。 • 跳转指令:b和bl。 • 访存指令:单数据访存指令,多数据访存指令,信号量操作指令。 • 异常中断产生指令:swi和bkpt。 • 协处理器指令。
1.2 指令特点 • 所有指令都是32bit。 • 大多数指令都在单周期内完成。 • 所有指令都可以条件执行。 • load/store体系结构。 • 指令集可以通过协处理器扩展
31 28 27 25 24 21 20 19 16 15 12 11 8 7 0 Cond 001 Opcode S Rn Rd Operand2 1.3 ARM指令的格式 <Opcode>{<cond>}{s} <Rd>, <Rn>, <Operand2> • Cond:指令的条件码。 • Opcode:指令操作码。 • S:操作是否影响cpsr。 • Rn:包含第一个操作数的寄存器编码。 • Rd:目标寄存器编码。 • Operand2:第2操作数。
if ( (a == b) && (c == d) ) { e++; } // r0, r1, r2, r3, r4 : a, b, c, d, e cmp r0, r1 cmpeq r2, r3 addeq r4, r4, #1 1.4 ARM指令的条件执行 所有的ARM指令可包含一个可选的条件码,只有在cpsr中的条件标志位满足指定的条件时,指令才会被执行。不符合条件的代码依然占用一个时钟周期(相当于一个NOP指令)。
1.4.1 ARM指令的条件域 • EQ/NE: 等于/不等于(equal / not equal) • HS/LO: 无符号数高于或等于/无符号数小于(higher or same/lower) • HI/LS: 无符号数高于/无符号数低于或等于(higher/lower or same) • GE/LT: 有符号数大于或等于/有符号数小于(greater or equal / less than) • GT/LE: 有符号数大于/有符号数小于或等于(greater than / less or equal) • MI/PL: 负/非负 • VS/VC: 溢出/不溢出(overflow set / overflow clear) • CS/CC: 进位/无进位(carry set / carry clear)
1.4.2 ARM指令的条件码(续) 注:AL是默认的,NV不建议使用。
目录 • 总体介绍:指令分类,特点,格式,条件码 • ARM 指令寻址方式 • 数据处理指令:数据传输指令,算术指令,逻辑指令,比较指令,乘法指令(略),前导零计数(略) • 程序状态访问指令 • 跳转指令 • 单数据访存指令 • 多数据访存指令 • 其它指令:信号量操作指令,异常中断产生指令,协处理器指令(略) • 伪指令 • 基于ARM的编程
2.1 寄存器寻址 ADD R0,R1,R2 ; R0 =R1+R2 这条指令将两个寄存器(R1和R2)的内容相加,结果放入第3个寄存器R0中。必须注意写操作数的顺序,第1个是结果寄存器,然后是第一操作数寄存器,最后是第二操作数寄存器。
2.2 立即寻址 指令中在操作码字段后面的地址码部分不是通常意义上的操作数地址,而是操作数本身。 ADD R3,R3,#1 ; R3= R3+1 AND R8,R7,#0xff ; R8= R7[7:0] 第2个源操作数为一个立即数,以“#”为前缀,十六进制值以在“#”后加“0x”或“&”表示。
2.3 寄存器移位寻址 这种寻址方式是ARM指令集特有的。第2个寄存器操作数在与第1个操作数结合之前,选择进行移位操作。 ADD R3,R2,R1,LSL #3 ; R3 =R2+8×R1 寄存器R1的内容逻辑左移3位,再与寄存器R2内容相加,结果放入R3中。
逻辑移位 • LSL:逻辑左移(Logical Shift Left)。寄存器中字的低端空出的位补0。 • ·LSR:逻辑右移(Logical Shift Right)。寄存器中字的高端空出的位补0。 • ·ASR:算术右移(Arithmetic Shift Right)。算术移位的对象是带符号数,在移位过程中必须保持操作数的符号不变。若源操作数为正数,则字的高端空出的位补0。若源操作数为负数,则字的高端空出的位补1。 • ·ROR:循环右移(Rotate Right)。从字的最低端移出的位填入字的高端空出的位。 • ·RRX:扩展为1的循环右移(Rotate Right Extended by 1 place)。操作数右移一位,空位(位[31])用原C标志填充。
移位操作 • 在任何数据处理指令中,第二寄存器操作数可以有应用该操作数的移位操作. • 逻辑移位 • LSL:逻辑左移字的最小位空位清零 • LSR:逻辑右移字的最大位空位清零.
移位操作(cont’d) • 算术移位 • ASR: 正数的ASR= LSR • 循环移位: ROR, RRX
2.4 寄存器间接寻址 指令中的地址码给出某一通用寄存器的编号。在被指定的寄存器中存放操作数的有效地址,而操作数则存放在存储单元中,即寄存器为地址指针。 LDR R0,[R1] ; R0 =[R1] STR R0,[R1] ; [R1] = R0 寄存器间接寻址使用一个寄存器(基址寄存器)的值作为存储器的地址。
2.5 变址寻址 • 变址寻址就是将基址寄存器的内容与指令中给出的位移量相加,形成操作数有效地址。变址寻址用于访问基址附近的存储单元,包括: • 基址加偏移 • 基址加索引寻址。 寄存器间接寻址是偏移量为0的基址加偏移寻址。
基址加偏移寻址中的基址寄存器包含地址,需加(或减)(最大4 KB)的偏移来计算访问的地址。 • LDR R0,[R1,#4] ; R0 =[R1+4] • 这是前索引寻址方式。 • 带自动索引的前索引寻址。 • LDR R0,[R1,#4]! ; R0= [R1+4] ; R1 =R1+4 • “!”符号表明指令在完成数据传送后应该更新基址寄存器
后索引寻址。基址不带偏移作为传送的地址,传送后自动索引。 LDR R0,[R1],#4 ; R0= [R1] ; R1= R1+4 • 基址加索引寻址有时指令指定一个基址寄存器,再指定另一个寄存器(索引),其值作为偏移加到基址上形成存储器地址。例如指令: LDR R0,[R1,R2] ; R0= [R1+R2]
2.6 块拷贝寻址 • ARM支持两种不同角度的块寻址机制,两者都映射到相同的基本指令——多寄存器传送指令。多寄存器传送指令可以用于把一块数据从存储器的某一位置拷贝到另一位置;基于数据是存储在基址寄存器的地址之上还是之下,地址是在存储第1个值之前还是之后增加还是减少。 • 下 图说明了4种不同情况的多字节传送指令传送前后的内存变化,以及使用自动寻址时如何修改基址寄存器。指令执行前的基寄存器是R9 ,指令执行后的基寄存器是R9’。
2.7 堆栈寻址 • 堆栈是一种按特定顺序进行存取的存储区。“后进先出”(LIFO)。栈指针所指定的存储单元就是堆栈的栈顶。存储器堆栈可分为两种: • ·向上生长:即向高地址方向生长,称为递增堆栈(ascending stack)。 • ·向下生长:即向低地址方向生长,称为递减堆栈(descending stack)。 • 堆栈指针指向最后压入堆栈的有效数据项,称为满堆栈(full stack)。堆栈指针指向下一个数据项放入的空位置,称为空堆栈(empty stack)。
ARM对堆栈的使用一般用多寄存器传送指令,是一种有效的保存处理器状态和多字节传送的有效方式。ARM硬件中的堆栈分为以下四种类型:ARM对堆栈的使用一般用多寄存器传送指令,是一种有效的保存处理器状态和多字节传送的有效方式。ARM硬件中的堆栈分为以下四种类型: ①满向上生长型(FA):堆栈按高地址方向生长,当前堆栈指针指向最高有效值; ②空向上生长型(EA):堆栈按高地址方向生长,当前堆栈指针指向第一个空值; ③满向下生长型(FD) :堆栈按低地址方向生长,当前堆栈指针指向最低有效值; ④空向下生长型(ED) :堆栈按低地址方向生长,当前堆栈指针指向第一个空值。
若R3~R9保存的是有用的值,就应该把它们压进堆栈进行保存。即 • STMFD R13!,{R3-R9} ; 存储寄存器到堆栈 • 。。。。。。 • LDMFD R13!,{R3-R9} ; 从堆栈恢复 • 其中第一条和最后一条指令的“FD”表明是满递减堆栈寻址方式。
堆栈和块拷贝角度的多寄存器加载和存储指令映射堆栈和块拷贝角度的多寄存器加载和存储指令映射
2.8 相对寻址 • 相对寻址是变址寻址的一种变通,由程序计数器PC提供基地址。指令中的地址码字段作为位移量。 • BL SUBR ; 转移到SUBR • … … ; 返回到此 • … … • SUBR … ; 子程序入口地址 • MOV PC,R14 ; 返回
目录 • 总体介绍:指令分类,特点,格式,条件码 • ARM 指令寻址方式 • 数据处理指令:数据传输指令,算术指令,逻辑指令,比较指令,乘法指令(略),前导零计数(略) • 程序状态访问指令 • 跳转指令 • 单数据访存指令 • 多数据访存指令 • 其它指令:信号量操作指令,异常中断产生指令,协处理器指令(略) • 伪指令 • 基于ARM的编程
3 数据处理指令 • 数据传输指令:mov和mvn • 算数指令:add、adc、sub、sbc,rsb和rsc • 逻辑指令:and、orr、eor和bic • 比较指令:cmp、cmn、tst和teq
3.1 数据处理指令的特点 • 所有的操作数要么来自寄存器,要么来自立即数,不会来自内存。 • 如果有结果,则结果一定是为32位宽,并且放在一个寄存器中,不会写入内存。(有一个例外:长乘法指令产生64位结果) • 每一个操作数寄存器和结果寄存器都在指令中独立指出,即:ARM指令采用3地址模式:<Operation> Rd, Rn, Rm
31 28 27 25 24 21 20 19 16 15 12 11 8 7 0 Cond 00X opcode S Rn Rd 第 2 操作数 11 8 7 0 方式1:#immed #rot #immed_8 add r0, r1, #0xff 11 4 3 0 方式2:Rm 0 0 0 0 0 0 0 0 Rm 11 8 7 4 3 0 方式3:Rm LSL Rs Rs 0 0 0 0 Rm add r0, r1, r1, LSL r2 11 7 6 4 3 0 方式4:Rm LSL #immed_5 (#immed_5取值范围0-31) #immed_5 shift Rm add r0, r1, r1, LSL #31 3.2 四种寻址方式和s后缀 add r0, r1, r2
寄存器,可能需要移位。 • 如需移位,移位值可为: • 5bit的无符号整数(0-31) • 在指令的最低字节指定的另一寄存器 • 立即数 • 8比特数 • 8比特数循环右移偶数位 • 右移位数由汇编器自动计算 3.2.1 四种寻址方式的硬件支持
3.2.2 立即数方式 • ARM指令中的立即数,由一个8bit的常数循环右移偶数位得到: 立即数 =(0->255) 循环右移 2N位 • 例子: • 合法立即数:0x3fc,0x0,0xf0000000,0xf0000001 • 非法立即数:0x1fe,0xffff,0x1010,0xf0000010
3.2.2 立即数方式(续) • 同一个立即数可能有多个表示方法。如: • 0x3f0 = 0x3f 循环右移 28位 • 0x3f0 = 0xfc 循环右移 30位 • 对立即数的编码规则: • 如果立即数在0 – 0xff之间,移位数为0。 • 否则,就取决于编译器了。指令“mov r0, #0x3f0”在ADS1.2中被编译为0xe3a00ffc,在arm-elf-gcc-2.95.3中被编译为0xe3a00e3f。
3.2.2 立即数方式(续) • 对于有互补操作的指令,编译器可以做智能的转换,比如: • mvn r1, 0xffffff00 -> mov r1, 0xff • add r1, r1, #0xffffff00 -> sub r1, r1, #0x100 • adc r1, r1, #0xffffff00 -> sbc r1, r1, #0xff • and r1, r1,#0xffffff00 -> bic r1, r1, #0xff 这样,一些原本非法的立即数也可以正常编译通过。如果一个立即数,经过上述转换后是合法的,那么它也可以用在数据操作指令中。
3.2.3 寄存器移位寻址 ASR 算术右移 LSL 逻辑左移 LSR 逻辑右移 ROR 循环右移 RRX 扩展的循环右移
3.2.3 寄存器移位寻址(续) • 如果移位的位数由立即数(5bit,取值范围0 - 31)给出,就叫作 immediate specified shift;如果由Rs的低5位决定,就叫做register specified shift。 • Register specified shift的两点问题: • 不能使用pc:如果将pc寄存器用在Rn,Rd,Rm和Rs的位置上时,会产生不可预知的结果。 • 额外代价(overhead):需要更多的周期才能完成指令,因为ARM没有能力一次读取3个寄存器。 • Immediate specified shift 没有上述问题。
3.2.3 寄存器移位寻址(续) • 在register specified shift寻址方式下使用pc寄存器,编译器提示如下警告: • 在ADS1.2种编译产生如下警告之一: • Warning A1477W:This register combination results in UNPREDICTABLE behavior • Warning : A1320E: Undefined effect (using PC as Rn or Rm in register specified shift) • Warning : A1319E: Undefined effect (using PC as Rs) • 但是在arm-elf-gcc-2.95.3中没有报告错误。
3.2.4 后缀s • 数据处理指令可以选择s后缀,以影响状态标志。但是比较指令(cmp、cmn、tst和teq)不需要后缀s,它们总会直接影响cpsr中的状态标志。 • 在数据操作指令中,除了比较指令以外,其它的指令如果带有s后缀,同时又以pc为目标寄存器进行操作,则操作的同时从spsr恢复cpsr。比如: • movs pc, #0xff /* cpsr = spsr; pc = 0xff */ • adds pc, r1, #0xffffff00 /* cpsr = spsr; pc = r1 + 0xffffff00 */ • ands pc, r1, r2 /* cpsr = spsr; pc = r1 & r2; */ • 如果在user或者system模式下使用带有s后缀的数据操作指令,同时以pc为目标寄存器,那么会产生不可预料的结果。因为user和system模式下没有spsr。
3.3 数据传输指令 • 语法 • <Operation>{<cond>}{s} <Rd>, #<immed> • <Operation>{<cond>}{s} <Rd>, <Rm> • <Operation>{<cond>}{s} <Rd>, <Rm>, LSL #<immed_5> • <Operation>{<cond>}{s} <Rd>, <Rm>, LSL <Rs> • 伪代码 if ConditionPassed(cond) then Rd = 第2操作数 if s == 1 and Rd == pc then cpsr == spsr else if s == 1 then set NZCV flags in cpsr
3.3 数据传输指令(续) • 举例 • mov r0, r1 /* r0 = r1,不修改cpsr */ • mov r0, #0x0 /* r0 = 0,不修改cpsr */ • movs r0, #0x0 /* r0 = 0,同时设置cpsr的Z位 */ • movs r0, # -10 /* r0 = 0xfffffff6,同时设置cpsr的N位 */ • mvn r0, r2 /* r0 = NOT r2,不修改cpsr */ • mvn r0, 0xffffffff /* r0 = 0x0,不修改cpsr */ • mvns r0, 0xffffffff /* r0 = 0x0,同时设置cpsr的Z位 */ • mov r0, r1, LSL #1 /* r0 = r1 << 1 */ • mov r0, r1, LSR r2 /* r0 = r1 >> r2 */
3.3 数据传输指令(续) • 说明 • mvn意为“取反传输”,它把源寄存器的每一位取反,将得到的结果写入结果寄存器。 • movs和mvns指令对pc寄存器赋值时有特殊含义,表示要求在赋值的同时从spsr中恢复cpsr。 • 对于mov和mvn指令,编译器会进行智能的转化。比如指令“mov r1, 0xffffff00”中的立即数是非法的。在编译时,编译器将其转化为“mvn r1, 0xff”,这样就不违背立即数的要求。所以对于mov和mvn指令,可以认为:合法的立即数反码也是合法的立即数。
3.4 算术指令 • 语法 • <Operation>{<cond>}{s} <Rd>, <Rn>, #<immed> • <Operation>{<cond>}{s} <Rd>, <Rn>, <Rm> • <Operation>{<cond>}{s} <Rd>, <Rn>, <Rm>, LSL #<immed_5> • <Operation>{<cond>}{s} <Rd>, <Rn>, <Rm>, LSL <Rs> • 伪代码(以加法add为例) if ConditionPassed(cond) then Rd = Rn + 第2操作数 if s == 1 and Rd == pc then cpsr = spsr else if s == 1 then set NZCV flags in cpsr