#ARM指令与汇编 #寻址方式与指令格式 [ARM Register]: http://data.linuxtoy.cn/image/ARM_Registers.png "ARM register organisation" [ARM CPSR]: http://data.linuxtoy.cn/image/ARM_CPSR.png "ARM CPSR" [ARM Exception Vector Table]: http://data.linuxtoy.cn/image/ARM_ExceptionVector.png "ARM Exception Vector Table" [ARM Condition Code]: http://data.linuxtoy.cn/image/ARM_ConditionCode.png "ARM Condition Code" [Harvard Architecture]: http://data.linuxtoy.cn/image/Harvard_architecture.png "Harvard architecture" [Von Neumann Architecture]: http://data.linuxtoy.cn/image/Von_Neumann_architecture.png "Von Neumann architecture" ## 寻址方式 根据指令中地址码字段来寻址操作数地址的方式。 ### 寄存器寻址 操作数的值在寄存器中, 指令中的地址码字段为寄存器编号,指令执行时直接取出寄存器值操作。 ``` MOV R1, R2 ; R2 -> R1 SUB R0, R1, R2 ; R1 - R2 -> R0 ``` ### 立即数寻址 指令中操作码字段后面的地址码部分就是操作数本身, 数据就包含在指令中。取出指令也就取出了可以立即使用的操作数 ``` SUBS R0, R0, #1 ; R0 - 1 -> R0 MOV R0, #0xff00 ; 0xff00 -> R0 ``` ### 寄存器移位寻址 ARM指令集特有的寻址方式, 第2个操作数与第1个操作数结合前先进行移位操作 ``` MOV R0, R2, LSL #3 ; R2的值左移3位,结果放入R0中 ANDS R1, R1, R2, LSL R3 ; R2左移R3位,然后与R1相与,结果存入R1中 ``` 可使用的移位操作如下: > *LSL*: 逻辑左移(Logical Shift Left) 低位补0 > *LSR*: 逻辑右移(Logical Shift Right) 高位补0 > *ASR*: 算术右移(Arithmetical Shift Right) 移位过程中保持符号位不变,即如果源操作数为正数,则高位补0, 如果源操作数为负数,则高位补1 > *ROR*: 循环右移(Rotate Right) 字的低端移出的位填入高端空出的位。 > *RRX*: 带扩展的循环右移(Rotate Right eXtended by 1 place) 操作数右移移位,高端空出的位用原C标志填充。 ### 寄存器间接寻址 指令中地址码给出的是寄存器编号,操作数保存在寄存器指定地址的存储单元中,即寄存器存放的是操作数的地址 ``` LDR R1, [R2] ; R2中为操作数的地址,取出地址中的数据保存在R1中 ``` ### 基址寻址 将寄存器中的内容与给定的偏移量相加,得到操作数的有效地址。 基址寻址用于访问基址附近的存储单元,一般用于查表,数组操作... ``` LDR R2, [R3, #0x0f] ; 将R3中的数值作为基址加上0xf作为操作数的地址,取出地址的数据保存在R2中。 STR R1, [R0, #-2] ; 将R0中的数值作为基址减2作为操作数的地址,把R1中的内容保存在此地址中。 ``` ### 多寄存器寻址 一次可以传送多个寄存器的值,允许一条指令传送16个寄存器的任何子集 ``` LDMIA R1!, {R2-R7, R12} ; R1指向地址中的数据读出到R2到R7和R12中, R1自动加1 STMIA R0!, {R3-R6, R10} ; 将R3-R6和R10中的数据保存在R0指定的地址中,R0自动加1 ``` 寄存器子集的顺序由小到大排列,连续的寄存器可用"-"连接,否则用","分开书写 > I: 地址增加 > D: 地址减小 > A: 数据读取后,地址加减 > B: 数据读取前, 地址加减 ### 堆栈寻址 堆栈是按特定顺序进行存取的存储区,操作顺序为"先进后出" 或 "后进先出" 堆栈寻址使用一个专门的寄存器(堆栈指针sp)指向一块存储区域,指针指向的存储单元就是堆栈的栈顶。 **生长方向** 递增堆栈: 向高地址方向生长 Ascend 递减堆栈: 向低地址方向生长 Descend 根据堆栈指针指向的位置又可以分为满堆栈和空堆栈 满堆栈: 堆栈指针指向最后压入堆栈的有效数据项 Full 空堆栈: 堆栈指针指向下一个要压入的空位置 Empty 根据生长方向和堆栈指针位置可以组合出来4种类型的堆栈 > 满递增: > 堆栈通过增大存储器的地址向上增长,堆栈指针指向含有有效数据项的最高地址。指令如 LDMFA STMFA等 > > 空递增: > 堆栈通过增大存储器的地址向上增长,堆栈指针指向堆栈上的第一个空位置。指令如 LDMEA STMEA等 > > 满递减: > 堆栈通过减小存储器的地址向下增长,堆栈指针指向含有有效数据项的最低地址。指令如 LDMFD STMFD等 > > 空递减: > 堆栈通过减小存储器的地址向下增长,堆栈指针指向堆栈的下一个空地址。指令如 LDMED STMED等 > 举例: ``` STMFD SP!, {R1-R7, LR} ; 将R1-R7, LR入栈, 满递减堆栈 LDMFD SP!, {R1-R7, LR} ; 数据出栈,存放如R1-R7, LR , 满递减堆栈 ``` ### 相对寻址 相对寻址是基址寻址的一种变通,由PC提供基址,指令总的地址码字段作为偏移量,两者相加后得到的值为操作数的有效地址。 例: ``` BL ROUTE1 ; 跳转到ROUTE1子程序 BEQ LOOP ; 条件跳转到LOOP标号 ``` ## Processor Modes and CPSR ### 工作模式 > User User mode, 程序通常运行在这种模式下 > FIQ (entered when a high priority (fast) interrupt raised) > IRQ (entered when a low priority (normal) interrupt raised) > Supervisor (entered on reset and when a Software Interrupt instruction is executed) > Abort (used to handle memory access violations) > Undef (used to handle undefined instructions) > System (特权工作模式,和User Mode使用同一套寄存器) ### 寄存器组织 ![ARM Register Organisation][ARM Register] ARM总共有37个寄存器,每个寄存器都是32bit 1个用于PC(程序计数器) 1个用于当前的程序状态寄存器CPSR 5个用于保存程序状态寄存器SPSR 30个通用寄存器 这些寄存器根据工作模式分为7组 R13 用于堆栈指针SP R14 用于连接寄存器LR R15 用于程序计数器 ### 程序状态字寄存器 ![ARM CPSR Register][ARM CPSR] *条件码标志* copies of the ALU status flags > N = Negative result from ALU flag > Z = Zero result from ALU flag > C = ALU operation Carried out (进位) > V = ALU operation oVerflowed (溢出) *Interrupt Disable bits* Bit[7:6] > I = 1, disable the IRQ > F = 1, disable the FIQ *ARM/Thumb Mode* Bit[5] > T = 0, ARM state > T = 1, Thumb state *Working mode* Bit[4:0] ### 程序计数器PC(R15) 当处理器在ARM模式下执行时: 所有指令长度为32bit 所有指令必须以字对齐,所以PC指针的bit[1:0]应该等于0 当跳转指令执行时,R14用于保存根据PC计算得到的返回地址 ## 异常处理 *异常向量表* ![ARM exception vector table][ARM Exception Vector Table] *异常处理流程* 异常产生时: ``` . 拷贝CPSR to SPSR_ . 设置相应的CPSR状态位 . 将返回地址存储在LR_ . 将PC设置为对应的向量地址 ``` 从异常返回: ``` . 将SPSR_恢复到CPSR . 将LR_恢复到PC ``` ## ARM指令格式 *基本格式* ``` {} {S} , {,} <>内的项是必须的, {}内的项是可选的 ``` > opcode 指令助记符, 如 LDR, STR等 > cond 执行条件,如EQ,NE等,如果没有指定cond,则默认为AL(无条件执行) > S 是否影响CPSR的条件码标志 > Rd 目的寄存器 > Rn 第一个操作数的寄存器 > operand2 第二个操作数 ### 第二操作数operand2 #### `立即数#immed_8r` 立即数,该常数必须对应8位位图,即该常数由一个8位的常数循环移位偶数位得到 合法常量: 0x3FC, 0, 0xF0000000, 200, 非法常量: 0x1FE, 511, 0xFFFF, 0x1010, 0xF0000010 例: MOV R1, #1 #### 寄存器方式 Rm 操作数为寄存器的值 例如: SUB R1, R1, R2 ; R1 - R2 -> R1 MOV PC, R1 ; PC = R1 #### 寄存器移位方式 Rm, shift 将寄存器移位后的结果作为操作数,但寄存器Rm的值保持不变 ADD R1, R1, LSL #3 ; R1 = R1 * 9 SUB R1, R1, R2, LSR #2 ; R1 = R1 - R2 / 4 ### 条件码 cond ![ARM condition code][ARM Condition Code] 对于thum指令集,只有B指令具有条件执行能力 ## 哈弗结构与冯.诺依曼结构 *the Harvard architectrue* 哈弗结构是一种将指令和数据分开存储的计算机结构。Harvard architecture这一术语来源于Harvard Mark I型继电器式计算机。 Hardvard Mark I是IBM的自动顺序控制计算机ASCC(Automatic Sequence Controlled Calculator), 被哈佛大学的研究人员称为Mark I(马克一号) Mark I 将指令存储在纸带上,数据存储在机电计数器上,处理器首先到指令存储器中读取指令内容,解码后得到数据地址,再到相应的数据存储器中读取数据。 程序指令和数据分开存储。数据和指令的存取可以分开进行,可以是指令和数据的有不同的宽度。 使用哈佛结构的处理器和微控制器有很多,例如Atmel的AVR系列,ARM公司的ARM9, ARM10, ARM11... ... ![the Hardvard architecture, from wikipedia][Harvard Architecture] ------------ *the von Neumann architecture* ![the von Neumann architectrue, from wikipedia][Von Neumann Architecture] 冯诺依曼体系结构描述了一种电子数字计算机,由以下几部分组成: 1. Processing unit: ALU(arithmetic logic unit, processor registers) 2. Control unit: instruction register and Program Counter 3. a memory to store both data and instructions 4. input and output machanisms 典型情况下完成一个指令需要3个步骤: 取指,译码,执行。 由于取指令和存取数据都需要从同一个存储空间存取,并使用同一总线传输。他们不能重叠执行,只能顺序执行。