87
ARM指指指指指指 1 ARM 指指指指指指 1. 指指指 指指指指指 指指指 指指指 指指指 体:,,, 2. 指指指指指指 指指指指指指指 指指指指指 指指指指指 指指指指指 指指指指 :,,,, (指) 指指 指指指 ( 指 ) 3. 指指指指指指指指 4. 指指指指 5. 指指指指指指指 6. 指指指指指指指 7. 指指指指 指指指指指指指指 指指指指指指指指指 指指指指指指 :,, (指) 8. 指指指 ( 指 ) 9. 指指 ARM 指指指

ARM 指令集与编程

  • Upload
    colum

  • View
    104

  • Download
    0

Embed Size (px)

DESCRIPTION

ARM 指令集与编程. 总体介绍:指令分类,特点,格式,条件码 数据处理指令:数据传输指令,算术指令,逻辑指令,比较指令,乘法指令 ( 略 ) ,前导零计数 ( 略 ) 程序状态访问指令 跳转指令 单数据访存指令 多数据访存指令 其它指令:信号量操作指令,异常中断产生指令,协处理器指令 ( 略 ) 伪指令 ( 略 ) 基于 ARM 的编程. 1 总体介绍. 指令分类、特点、格式、条件码. 1.1 指令分类. ARM 指令集总体分为 6 类指令 数据处理指令:数据传输指令,算术指令,逻辑指令,比较指令,乘法指令,前导零计数。 - PowerPoint PPT Presentation

Citation preview

Page 1: ARM 指令集与编程

ARM指令集与编程 1

ARM 指令集与编程

1. 总体介绍:指令分类,特点,格式,条件码2. 数据处理指令:数据传输指令,算术指令,逻辑指令,比

较指令,乘法指令 ( 略 ) ,前导零计数 ( 略 )3. 程序状态访问指令4. 跳转指令5. 单数据访存指令6. 多数据访存指令7. 其它指令:信号量操作指令,异常中断产生指令,协处理

器指令 ( 略 )8. 伪指令 ( 略 )9. 基于 ARM 的编程

Page 2: ARM 指令集与编程

1 总体介绍

指令分类、特点、格式、条件码

Page 3: ARM 指令集与编程

ARM指令集与编程 3

1.1 指令分类 ARM 指令集总体分为 6 类指令

– 数据处理指令:数据传输指令,算术指令,逻辑指令,比较指令,乘法指令,前导零计数。

– 程序状态访问指令: mrs 和 msr 。– 跳转指令: b 和 bl 。– 访存指令:单数据访存指令,多数据访存指令,信号

量操作指令。– 异常中断产生指令: swi 和 bkpt 。– 协处理器指令。

Page 4: ARM 指令集与编程

ARM指令集与编程 4

1.2 指令特点• 所有指令都是 32bit 。• 大多数指令都在单周期内完成。• 所有指令都可以条件执行。• load/store 体系结构。• 指令集可以通过协处理器扩展

Page 5: ARM 指令集与编程

ARM指令集与编程 5

1.3 ARM 指令的格式

<Opcode>{<cond>}{s} <Rd>, <Rn>, <Operand2>

• Cond :指令的条件码。• Opcode :指令操作码。• S :操作是否影响 cpsr 。• Rn :包含第一个操作数的寄存器编码。• Rd :目标寄存器编码。• Operand2 :第 2 操作数。

Cond 001 Opcode S Rn Rd Operand2

0111215161920212425272831 78

Page 6: ARM 指令集与编程

ARM指令集与编程 6

1.3 ARM 指令的格式 ( 续 )

Page 7: ARM 指令集与编程

ARM指令集与编程 7

1.4 ARM 指令的条件执行所有的 ARM 指令可包含一个可选的条件码,只有在 cpsr 中的条件标志位满足指定的条件时,指令才会被执行。不符合条件的代码依然占用一个时钟周期(相当于一个NOP 指令)。

// r0, r1, r2, r3, r4 : a, b, c, d, ecmp r0, r1cmpeq r2, r3addeq r4, r4, #1

if ( (a == b) && (c == d) ) {

e++;}

Page 8: ARM 指令集与编程

ARM指令集与编程 8

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)

Page 9: ARM 指令集与编程

ARM指令集与编程 9

1.4.2 ARM 指令的条件码

0000 EQ Z 置位 相等 / 等于 0

0001 NE Z 清 0 不等0010 CS/HS C 置位 进位 / 无符号高于或等

于0011 CC/LO C 清 0 无进位 / 无符号低于0100 MI N 置位 负数0101 PL N 清 0 非负数0110 VS V 置位 溢出0111 VC V 清 0 无溢出

Page 10: ARM 指令集与编程

ARM指令集与编程 10

1.4.2 ARM 指令的条件码 ( 续 )

1000 HI C 置位且 Z 清 0 无符号高于

1001 LS C 清 0 或 Z 置位 无符号低于或等于1010 GE N 等于 V 有符号大于或等于1011 LT N 不等于 V 有符号小于1100 GT Z 清 0 且 N 等于 V 有符号大于1101 LE Z 置位或 N 不等于 V 有符号小于或等于1110 AL 任何状态 总是( always )1111 NV 无 从不( never )

注: AL 是默认的, NV 不建议使用。

Page 11: ARM 指令集与编程

ARM指令集与编程 11

目录1. 总体介绍:指令分类,特点,格式,条件码2. 数据处理指令:数据传输指令,算术指令,逻辑指令,比

较指令,乘法指令 ( 略 ) ,前导零计数 ( 略 )3. 程序状态访问指令4. 跳转指令5. 单数据访存指令6. 多数据访存指令7. 其它指令:信号量操作指令,异常中断产生指令,协处理

器指令 ( 略 )8. 伪指令 ( 略 )9. 基于 ARM 的编程

Page 12: ARM 指令集与编程

ARM指令集与编程 12

2 数据处理指令

• 数据传输指令: mov 和 mvn

• 算数指令: add 、 adc 、 sub 、 sbc , rsb 和 rsc

• 逻辑指令: and 、 orr 、 eor 和 bic

• 比较指令: cmp 、 cmn 、 tst 和 teq

Page 13: ARM 指令集与编程

ARM指令集与编程 13

2.1 数据处理指令的特点• 所有的操作数要么来自寄存器,要么来自立即数,

不会来自内存。• 如果有结果,则结果一定是为 32 位宽,并且放在

一个寄存器中,不会写入内存。(有一个例外:长乘法指令产生 64 位结果)

• 每一个操作数寄存器和结果寄存器都在指令中独立指出,即: ARM 指令采用 3 地址模式: <Operation> Rd, Rn, Rm

Page 14: ARM 指令集与编程

ARM指令集与编程 14

2.2 四种寻址方式和 s 后缀

add r0, r1, r2

add r0, r1, #0xff

add r0, r1, r1, LSL r2

Cond S Rn Rd 第 2 操作数078111215161920

opcode

2124

00X

25272831

#immed_8#rot

07811

0 0 0 0 0 0 0 0 Rm

03411

方式 1 : #immed

方式 2 : Rm

0 0 0 0 Rm

03411

Rs

78

方式 3 : Rm LSL Rs

shift Rm

03411

#immed_5

67方式 4 : Rm LSL #immed_5( #immed_5 取值范围 0-31 )add r0, r1, r1, LSL #31

Page 15: ARM 指令集与编程

ARM指令集与编程 15

2.2.1 四种寻址方式的硬件支持

•寄存器,可能需要移位。•如需移位,移位值可为:

•5bit 的无符号整数( 0-31 )•在指令的最低字节指定的另一寄存器

•立即数• 8 比特数•8 比特数循环右移偶数位•右移位数由汇编器自动计算

Page 16: ARM 指令集与编程

ARM指令集与编程 16

2.2.2 立即数寻址• ARM 指令中的立即数,由一个 8bit 的常数

循环右移偶数位得到:立即数 = ( 0->255) 循环右移 2N 位

• 例子:– 合法立即数: 0x3fc , 0x0 , 0xf0000000 , 0

xf0000001– 非法立即数: 0x1fe , 0xffff , 0x1010 , 0xf0

000010

Page 17: ARM 指令集与编程

ARM指令集与编程 17

2.2.2 立即数寻址 ( 续 )

• 同一个立即数可能有多个表示方法。如:– 0x3f0 = 0x3f 循环右移 28 位– 0x3f0 = 0xfc 循环右移 30 位

• 对立即数的编码规则:– 如果立即数在 0 – 0xff 之间,移位数为 0 。– 否则,就取决于编译器了。指令“ mov r0, #0x3f

0” 在 ADS1.2 中被编译为 0xe3a00ffc ,在 arm-elf-gcc-2.95.3 中被编译为 0xe3a00e3f 。

Page 18: ARM 指令集与编程

ARM指令集与编程 18

2.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

这样,一些原本非法的立即数也可以正常编译通过。如果一个立即数,经过上述转换后是合法的,那么它也可以用在数据操作指令中。

Page 19: ARM 指令集与编程

ARM指令集与编程 19

2.2.3 寄存器移位寻址

ASR 算术右移

LSL 逻辑左移

LSR 逻辑右移

ROR 循环右移

RRX 扩展的循环右移

Page 20: ARM 指令集与编程

ARM指令集与编程 20

2.2.3 寄存器移位寻址(续)

• 如果移位的位数由立即数( 5bit ,取值范围 0 - 31 )给出,就叫作 immediate specified shift ;如果由 Rs 的低 5 位决定,就叫做 register specified shift 。

• Register specified shift 的两点问题:– 不能使用 pc :如果将 pc 寄存器用在 Rn , Rd , R

m 和 Rs 的位置上时,会产生不可预知的结果。– 额外代价( overhead ):需要更多的周期才能完成

指令,因为 ARM没有能力一次读取 3 个寄存器。• Immediate specified shift 没有上述问题。

Page 21: ARM 指令集与编程

ARM指令集与编程 21

2.2.3 寄存器移位寻址(续)• 在 register specified shift 寻址方式下使用 p

c 寄存器,编译器提示如下警告:– 在 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 中没有报告错误。

Page 22: ARM 指令集与编程

ARM指令集与编程 22

2.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 。

Page 23: ARM 指令集与编程

ARM指令集与编程 23

2.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 == spsrelse if s == 1 then

set NZCV flags in cpsr

Page 24: ARM 指令集与编程

ARM指令集与编程 24

2.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 */

Page 25: ARM 指令集与编程

ARM指令集与编程 25

2.3 数据传输指令(续)• 说明

– mvn意为“取反传输”,它把源寄存器的每一位取反,将得到的结果写入结果寄存器。

– movs 和 mvns 指令对 pc 寄存器赋值时有特殊含义,表示要求在赋值的同时从 spsr 中恢复 cpsr 。

– 对于 mov 和 mvn 指令,编译器会进行智能的转化。比如指令“ mov r1, 0xffffff00” 中的立即数是非法的。在编译时,编译器将其转化为“ mvn r1, 0xff” ,这样就不违背立即数的要求。所以对于 mov 和 mvn 指令,可以认为:合法的立即数反码也是合法的立即数。

Page 26: ARM 指令集与编程

ARM指令集与编程 26

2.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 = spsrelse if s == 1 then

set NZCV flags in cpsr

Page 27: ARM 指令集与编程

ARM指令集与编程 27

2.4 算术指令(续)

• 举例– add r0, r1, r2 /* r0 = r1 + r2 */– adc r0, r1, r2 /* r0 = r1 + r2 + carry */– sub r0, r1, r2 /* r0 = r1 – r2 */– sbc r0, r1, r2 /* r0 = r1 – r2 + carry -1 */– rsb r0, r1, r2 /* r0 = r2 – r1 */– rsc r0, r1, r2 /* r0 = r2 – r1 + carry – 1 */– add r0, r1, r1, LSL #31 /* r0 = r1 + r1 << 31 */– add r0, r1, r1, LSL r2 /* r0 = r1 + r1 << r2 */

• 说明– adds 和 adcs 在进位时将 cpsr 的 C 标志置 1 ;否则置 0 。– subs 和 sbcs 在产生借位时将 cpsr 的 C 标志置 0 ;否则置 1 。

Page 28: ARM 指令集与编程

ARM指令集与编程 28

2.5 逻辑指令• 语法

– <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>

• 伪代码(以 and 为例)If ConditionPassed(cond) then

Rd = Rn AND 第 2 操作数if s == 1 and Rd == pc then

cpsr = spsrelse if s == 1 then

set NZCV flags in cpsr

Page 29: ARM 指令集与编程

ARM指令集与编程 29

2.5 逻辑指令(续)

• 举例– and r0, r1, r2 /* r0 = r1 AND r2 */– and r1, r1,#0xffffff00 /* r1 = r1 AND 0xffffff00 */– orr r0, r1, r2 /* r0 = r1 OR r2 */– eor r0, r1, r2 /* r0 = r1 XOR r2 */– bic r0, r1, r2 /* r0 = r1 AND NOT r2 */– bic r1, r1, #0x0f /* 清空 r1 的低 4 位 */– and r0, r1, r1, LSL #31 /* r0 = r1 AND (r1 << 31) */– and r0, r1, r1, LSR r2 /* r0 = r1 AND (r1 >> r2) */

Page 30: ARM 指令集与编程

ARM指令集与编程 30

2.6 比较指令

• 语法– <Operation>{<cond>} <Rn>, #<immed>– <Operation>{<cond>} <Rn>, <Rm>– <Operation>{<cond>} <Rn>, <Rm>, LSL #<immed_5

>– <Operation>{<cond>} <Rn>, <Rm>, LSL <Rs>

• 伪代码(以 cmp 为例)If ConditionPassed(cond) then

alu_out = Rn – 第 2 操作数 set NZCV flags in cpsr

Page 31: ARM 指令集与编程

ARM指令集与编程 31

2.6 比较指令(续)

• 举例– cmp r1, r2 /*根据 r1 – r2 的结果设置 cpsr ,结果不写回 */– cmn r1, r2 /*根据 r1 + r2 的结果设置 cpsr ,结果不写回 */– tst r1, r2 /*根据 r1 AND r2 的结果设置 cpsr ,结果不写回 */– teq r1, r2 /*根据 r1 XOR r2 的结果设置 cpsr ,结果不写回 */– cmp r2, #5 /*根据 r2 – 5 的结果设置 cpsr ,结果不写回 */– cmp r1, r2, LSL #5 /* 根据 r1 – (r2 << 5)设置 cpsr */– cmp r1, r2, LSL r3 /* 根据 r1 – (r2 << r3)设置 cpsr */

• 说明– 如果不考虑结果的写回, cmp 、 cmn 、 tst 和 teq 分别等价于 sub

s 、 adds 、 ands 和 eors 。

Page 32: ARM 指令集与编程

ARM指令集与编程 32

目录

1. 总体介绍:指令分类,特点,格式,条件码2. 数据处理指令:数据传输指令,算术指令,逻辑指令,比

较指令,乘法指令 ( 略 ) ,前导零计数 ( 略 )3. 程序状态访问指令4. 跳转指令5. 单数据访存指令6. 多数据访存指令7. 其它指令:信号量操作指令,异常中断产生指令,协处理

器指令 ( 略 )8. 伪指令 ( 略 )9. 基于 ARM 的编程

Page 33: ARM 指令集与编程

ARM指令集与编程 33

3 程序状态访问指令• 当需要修改 cpsr/spsr 的内容时,首先要读

取它的值到一个通用寄存器,然后修改某些位,最后将数据写回到状态寄存器。

• cpsr/spsr 不是通用寄存器,不能使用 mov指令来读写。在 ARM 处理器中,只有 mrs指令可以读取 cpsr/spsr ;只有 msr 可以写cpsr/spsr 。

Page 34: ARM 指令集与编程

ARM指令集与编程 34

3.1 读指令 mrs

• 语法– mrs{<cond>} <Rd>, cpsr|spsr

• 伪代码if ConditionPassed(cond) then

if R == 1 thenRd = spsr

else Rd = cpsr

Page 35: ARM 指令集与编程

ARM指令集与编程 35

3.1读指令 mrs (续)• 举例

– mrs r0, cpsr /* 读取 cpsr 到 r0 */– mrs r3, spsr /* 读取 spsr 到 r3 */

• 说明– user 和 system 模式没有 spsr ,因此这些模式下不能读取 spsr 。

Page 36: ARM 指令集与编程

ARM指令集与编程 36

3.2 写指令 msr 的二进制格式

0

cond R 1 0 f s x c 1111 操作数01112151619202122

1 0

2324

#

25

0 0

26272831

1 8 位立即数#rot

07811

0 0 0 0 0 0 0 0 Rm

03411

cpsr/spsr

域屏蔽

立即数对准

操作数寄存器

Page 37: ARM 指令集与编程

ARM指令集与编程 37

3.2.1 写指令 msr 的语法

• msr{<cond>} <psr>_<fields>, #<immed>• msr{<cond>} <psr>_<fields>, <Rm>

– <immed> 表示合法的立即数: 8bit 循环右移偶数位– <psr> 代表 cpsr 或 spsr– <fields> 指定传送的区域,可进一步细分 ( 只能小

写 )• c 控制域字节( psr[7:0] )• x 扩展域字节( psr[15:8] )• s 状态域字节( psr[23:16] )• f 标志域字节( psr[31:24] )

Page 38: ARM 指令集与编程

ARM指令集与编程 38

3.2.2 写指令 msr 的伪代码

• 伪代码if ConditionPassed(cond) then

if opcode[25] == 1operand = 8 立即数 Rotate_Right (#rot * 2)

else /* opcode[25] == 0 */operand = Rm

if R == 0 thenif field_mask[0] == 1 and InAPrivilegeMode() then cpsr[7:0] = operand[7:0]if field_mask[1] == 1 and InAPrivilegeMode() then cpsr[15:8] == operand[15:8]if field_mask[2] == 1 and InAPrivilegeMode() then cpsr[23:16] == operand[23:16]if field_mask[3] == 1 then cpsr[31:24] = operand[31:24]

else /* R == 1 */if field_mask[0] == 1 and CurrentModeHasSPSR() then spsr[7:0] = operand[7:0]if field_mask[1] == 1 and CurrentModeHasSPSR() then spsr[15:8] == operand[15:8]if field_mask[2] == 1 and CurrentModeHasSPSR() then spsr[23:16] == operand[23:16]if field_mask[3] == 1 and CurrentModeHasSPSR() then spsr[31:24] = operand[31:24]

Page 39: ARM 指令集与编程

ARM指令集与编程 39

3.2.3 msr举例和说明

• 举例– msr cpsr_c, #0xd3 /* 切换到 SVC 模式 */– msr cpsr_cxsf, r3 /* cpsr = r3 */

• 说明① user 和 system 模式没有 spsr ,因此这些模式下不能对 spsr

操作。② 由于权限问题,在 user 模式下对 cpsr[23:0]修改无效。③ 如果使用立即数,要使用合法的立即数。④ 程序不能同过“ msr修改 cpsr 的 T 位”来完成 ARM/Thumb

态的切换。必须使用 bx 指令,因为 bx属于分支指令,它会打断流水线,实现处理器状态切换。

⑤ 如果要修改读出的值,仅修改必要的位,其它位保持不变,这样保持了最大兼容性。

Page 40: ARM 指令集与编程

ARM指令集与编程 40

目录

1. 总体介绍:指令分类,特点,格式,条件码2. 数据处理指令:数据传输指令,算术指令,逻辑指令,比

较指令,乘法指令 ( 略 ) ,前导零计数 ( 略 )3. 程序状态访问指令4. 跳转指令5. 单数据访存指令6. 多数据访存指令7. 其它指令:信号量操作指令,异常中断产生指令,协处理

器指令 ( 略 )8. 伪指令 ( 略 )9. 基于 ARM 的编程

Page 41: ARM 指令集与编程

ARM指令集与编程 41

4 跳转指令• 语法

– b{<cond>} label– bl{<cond>} label

• 说明– 寻址范围 +32MB

Page 42: ARM 指令集与编程

ARM指令集与编程 42

4 跳转指令(续)• 当转移指令执行时,处理器将指令中的 offset(24b

it) 左移 2bit ,变成 26bit ,表示 + 32M 的范围。• pc 从新的地址执行,流水线重新填充。• 如果是“ bl” 指令,将返回地址写入 lr 寄存器。子

程序返回时只需要用 lr恢复 pc 就可以:– mov pc, lr

• “b” 指令不影响 lr 寄存器

Page 43: ARM 指令集与编程

ARM指令集与编程 43

目录

1. 总体介绍:指令分类,特点,格式,条件码2. 数据处理指令:数据传输指令,算术指令,逻辑指令,比

较指令,乘法指令 ( 略 ) ,前导零计数 ( 略 )3. 程序状态访问指令4. 跳转指令5. 单数据访存指令6. 多数据访存指令7. 其它指令:信号量操作指令,异常中断产生指令,协处理

器指令 ( 略 )8. 伪指令 ( 略 )9. 基于 ARM 的编程

Page 44: ARM 指令集与编程

ARM指令集与编程 44

5 单数据访存指令• 第一类:

–读写字 : ldr / str–读写无符号字节 : ldrb / strb

• 第二类:–读写无符号半字: ldrh / strh–读有符号半字: ldrsh–读有符号字节: ldrsb

Page 45: ARM 指令集与编程

ARM指令集与编程 45

5.1 第一类指令的指令格式

0 0 0 0 0 0 0 0 0 0 Rm

03411方式 2 : Rm例子: ldr r0, [r1, +r2]

011

#immed_12方式 1 : #immed_12 (取值范围 0 – 0xfff )例子: ldr r0, [r1, #+0xfff]

shift Rm

03411

#immed_5

67方式 3 : Rm LSL #immed_5 (取值范围 0-31 )例子: ldr r0, [r1, r2 LSL #31] 0

5

0/1 : str/ldr

0/1 : 无 / 有 (!)0/1 : 后变址 / 前变址

0/1 : 字 / 无符号字节

cond Rn Rd 第 2 操作数07811121516192022

01

272831 2324

U B W L

2126

PI

25

0/1 : 加 /减 ( 第 2 操作数 )

0/1 : 立即数 ( 方式 1)/ 寄存器 ( 方式 2,3)

Page 46: ARM 指令集与编程

ARM指令集与编程 46

5.2 第一类指令的语法

• 语法– ldr|str{<cond>}{b} <Rd>, [<Rn>, #+<immed_12]{!}– ldr|str{<cond>}{b} <Rd>, [<Rn>, +<Rm>]{!}– ldr|str{<cond>}{b} <Rd>, [<Rn>, +<Rm>, <shift> #<immed_5>]{!}– ldr|str{<cond>}{b} <Rd>, [<Rn>], #+<immed_12– ldr|str{<cond>}{b} <Rd>, [<Rn>], +<Rm>– ldr|str{<cond>}{b} <Rd>, [<Rn>], +<Rm>, <shift> #<immed_5>

• 举例– ldrb r0, [r1, #+0xfff] /* 把 r1+0xfff 地址的字节读入 r0 */– ldr r0, [r1, +r2]! /*把 r1+r2 地址的 32 比特数读入 r0 ,然后 r1= r1+r2 */– str r0, [r1, +r2, LSL #31] /* 把 r0 ( 32bit )写到地址 r1+(r2<<31) */– ldr r0, [r1], #+0xfff /* 把 r1 地址的数读入 r0 ,然后 r1=r1+0xfff */– ldr r0, [r1], +r2 /* 把 r1 地址的数读入 r0 ,然后 r1=r1+r2 */– ldr r0, [r1], +r2, LSL #31 /* 把 r1 地址的数读入 r0 ,然后 r1=r1+(r2<<31) */

Page 47: ARM 指令集与编程

ARM指令集与编程 47

5.2 第一类指令说明• 说明

– ldr / str 读 / 写一个 32bit 字到 / 从一个 32bit 的寄存器,要求读 / 写地址字对齐。

– ldrb :读一个 8bit 字节到一个 32bit 的寄存器,不要求地址对齐,寄存器的高 24 位清零。

– strb :将寄存器的低 8 位,写入内存的某个地址。不要求地址对齐。

Page 48: ARM 指令集与编程

ARM指令集与编程 48

5.3 第二类指令• 语法

– 同第一类指令• 说明

– ldrh :读取 16bit半字到一个 32bit 寄存器,要求地址半字对齐,目标寄存的高 16bit 清零。

– strh :将寄存器的低 16bit 存放到内存中,要求地址半字对齐。– ldrsh :将内存中的一个 16bit半字读到一个 32bit 寄存器中,要求

地址半字对齐。寄存器高 16bit根据符号位扩展。– ldrsb :将内存中的一个 8bit 字节读到一个 32bit 寄存器中,寄存

器高 24bit根据符号位扩展。不要求地址对齐。

Page 49: ARM 指令集与编程

ARM指令集与编程 49

5.4 前 / 后变址

0 0 0 0 0 0 0 0 0 0 Rm

03411方式 2 : Rm例子: ldr r0, [r1, +r2]

011

#immed_12方式 1 : #immed_12 (取值范围 0 – 0xfff )例子: ldr r0, [r1, #+0xfff]

shift Rm

03411

#immed_5

67方式 3 : Rm LSL #immed_5 (取值范围 0-31 )例子: ldr r0, [r1, r2 LSL #31] 0

5

0/1 : str/ldr

0/1 : 无 / 有 (!)0/1 : 后变址 / 前变址

0/1 : 字 / 无符号字节

cond Rn Rd 第 2 操作数07811121516192022

01

272831 2324

U B W L

2126

PI

25

0/1 : 加 /减 ( 第 2 操作数 )

0/1 : 立即数 ( 方式 1)/ 寄存器 ( 方式 2,3)

Page 50: ARM 指令集与编程

ARM指令集与编程 50

5.4.1 简单的基址寻址• 基址寄存器数据访问

– str r0, [r1] ldr r2, [r1]

Page 51: ARM 指令集与编程

ARM指令集与编程 51

5.4.2 前变址寻址• str r0,[r1,#12]{! } ;

• mem32[r1+12] = r0;{r1 = r1 + 12;}

Page 52: ARM 指令集与编程

ARM指令集与编程 52

5.4.3 后变址寻址数据访问• str r0, [r1], #12

• mem32[r1] = r0; r1 = r1 + 12;

Page 53: ARM 指令集与编程

ARM指令集与编程 53

5.5 三种寻址方式 ( 第一类 )

0 0 0 0 0 0 0 0 0 0 Rm

03411方式 2 : Rm例子: ldr r0, [r1, +r2]

011

#immed_12方式 1 : #immed_12 (取值范围 0 – 0xfff )例子: ldr r0, [r1, #+0xfff]

shift Rm

03411

#immed_5

67方式 3 : Rm LSL #immed_5 (取值范围 0-31 )例子: ldr r0, [r1, r2 LSL #31] 0

5

0/1 : str/ldr

0/1 : 无 / 有 (!)0/1 : 后变址 / 前变址

0/1 : 字 / 无符号字节

cond Rn Rd 第 2 操作数07811121516192022

01

272831 2324

U B W L

2126

PI

25

0/1 : 加 /减 ( 第 2 操作数 )

0/1 : 立即数 ( 方式 1)/ 寄存器 ( 方式 2,3)

Page 54: ARM 指令集与编程

ARM指令集与编程 54

5.5 寻址方式 1— 立即数寻址• ldr|str{<cond>}{b} <Rd>, [<Rn>, #+<immed_12]{!}

• ldr|str{<cond>}{b} <Rd>, [<Rn>], #+<immed_12

• 说明:– 无叹号的前变址,当 pc 作为 Rn 时,内存基地址为当前指令地址加 8 字节偏移 ;

后变址或有叹号的前变址,当 pc 作为 Rn 时,会产生不可预知的结果• 在 ADS1.2 中,提示错误 Error : A1324E Undefined effect (PC + writeback)

• 在 arm-elf-gcc-2.95.3 中,没有提示– 后变址或有叹号的前变址,如果 Rn 和 Rd 是同一个寄存器,编译出错

• 在 ADS1.2 中,提示错误 Error : A1325E: Undefined effect (destination same as written-back base)

• 在 arm-elf-gcc-2.95.3 中,提示 Warning: destination register same as write-back base

– 如果 immed_12超过 0xfff ,编译会出错• 在 ADS1.2 中,提示错误 Error : A1174E: Data transfer offset out of range

• 在 arm-elf-gcc-2.95.3 中,提示 Error: address offset too large

Page 55: ARM 指令集与编程

ARM指令集与编程 55

5.5 寻址方式 2— 寄存器寻址• ldr|str{<cond>}{B} <Rd>, [<Rn>, +<Rm>]{!}• ldr|str{<cond>}{B} <Rd>, [<Rn>], +<Rm>• 说明:

– 无论如何, pc 都不能作 Rm 。– 无叹号的前变址,当 pc 作为 Rn 时,内存基地址为当前指令地址加 8 字

节偏移;后变址或有叹号的前变址,当 pc 作为 Rn 时,会产生不可预知的结果。

– 后变址或有叹号的前变址,如果 Rn 和 Rd 是同一个寄存器,会出现不可预知的结果。

Page 56: ARM 指令集与编程

ARM指令集与编程 56

5.5 寻址方式 3- 寄存器移位寻址

• ldr|str{<cond>}{B} <Rd>, [<Rn>, +<Rm>, <shift> #<immed_5>]{!}• ldr|str{<cond>}{B} <Rd>, [<Rn>], +<Rm>, <shift> #<immed_5>• 说明:

– 无论如何, pc 都不能作 Rm 。– 无叹号的前变址,当 pc 作为 Rn 时,内存基地址为当前指令地址加 8 字

节偏移;后变址或有叹号的前变址,当 pc 作为 Rn 时,会产生不可预知的结果。

– 后变址或有叹号的前变址,如果 Rn 和 Rd 是同一个寄存器,会出现不可预知的结果。

– 如果 immed_5超过 31 ,编译器报错。

Page 57: ARM 指令集与编程

ARM指令集与编程 57

目录

1. 总体介绍:指令分类,特点,格式,条件码2. 数据处理指令:数据传输指令,算术指令,逻辑指令,比

较指令,乘法指令 ( 略 ) ,前导零计数 ( 略 )3. 程序状态访问指令4. 跳转指令5. 单数据访存指令6. 多数据访存指令7. 其它指令:信号量操作指令,异常中断产生指令,协处理

器指令 ( 略 )8. 伪指令 ( 略 )9. 基于 ARM 的编程

Page 58: ARM 指令集与编程

ARM指令集与编程 58

6 多数据访存指令• 批量访存指令可以实现一组( 1-16 )寄

存器和一块( 4-64 字节)连续内存单元之间的数据传输。

Page 59: ARM 指令集与编程

ARM指令集与编程 59

6.1 指令格式

Page 60: ARM 指令集与编程

ARM指令集与编程 60

6.2 ldm/stm 指令的语法

• 语法– ldm|stm{<cond>}<addressing_mode> <Rn>{!}, <registers>{^}– <addressing_mode> 有 4 种:

• IA (Increment After) 事后递增• IB (Increment Before) 事先递增• DA (Decrement After) 事后递减• DB (Decrement Before) 事先递减

• 例子– ldmia r0, {r5-r8}/* 将内存中 (r0) 到 (r0+12)4 个字读取到 r5~r8 的 4 个寄存器中 */– ldmib r0, {r5-r8}/* 将内存中 (r0+4) 到 (r0+16)4 个字读取到 r5~r8 的 4 个寄存器中 */– ldmda r0, {r5-r8}/* 将内存中 (r0-12) 到 (r0)4 个字读取到 r5~r8 的 4 个寄存器中 */– ldmdb r0, {r5-r8}/* 将内存中 (r0-16) 到 (r0)4 个字读取到 r5~r8 的 4 个寄存器中 */

Page 61: ARM 指令集与编程

ARM指令集与编程 61

6.2 ldm/stm 指令的语法 ( 续 )

• 说明– 递增方式和递减方式处理寄存器列表和内存地址对应关系时采用不同的顺序,见前面的例子。可以总结为:编号低的寄存器对应低内存地址。

– pc 不能作为 stm 指令的 <Rn> ,否则结果不可预知。– 感叹号“!”表示执行后将更新 <Rn> 。– “^” 不能在 usr 和 system 模式下使用,否则结果不可预

知。在其它模式下使用时,含义和寄存器列表是否包含 pc 有关,见后面的详述。

Page 62: ARM 指令集与编程

ARM指令集与编程 62

6.3 ldm 指令的三种用法

编号! ^ pc ldm 指令不同的功能 用

法1 是 是 是 同 (5) ,但是更新 <Rn> 3

2 是 是 否 编译警告 (ADS1.2) : Warning : A1329W: Unsafe instruction (forced user mode xfer with write-back to base)

2

3 是 否 是 同 (7) ,但是更新 <Rn> 1

4 是 否 否 同 (8) ,但是更新 <Rn> ,且 <Rn> 不能出现在 <registers> 中

1

5 否 是 是 数据读取的同时,拷贝 spsr 到 cpsr 3

6 否 是 否 <registers> 采用 user 模态下的寄存器 2

7 否 否 是 同 (8) ,可用于程序跳转。 1

8 否 否 否 正常读取 1

Page 63: ARM 指令集与编程

ARM指令集与编程 63

6.4 stm 指令的两种用法

编号! ^ ldm 指令不同的功能 用

法1 是 是 同 (3) ,但是更新 <Rn> 2

2 是 否 同 (4) ,但是更新 <Rn> 。当 <Rn> 是 <registers> 中编号最小的寄存器时,指令将 <Rn> 的初值保存;否则结果不

可预测。

1

3 否 是 <registers> 采用 user 模态下的寄存器 2

4 否 否 正常写入 1

Page 64: ARM 指令集与编程

ARM指令集与编程 64

6.5 多数据访存的程序例子

/* r12 指向源数据起点 */

/* r14 指向源数据终点 */

/* r13 指向目标地址 */

loop:

ldmia r12!, {r0-r11} /* 读 48 字节 */

stmia r13!, {r0-r11} /* 写 48 字节 */

cmp r12, r14 /* 是否到末尾 */

bne loop /* 重复循环 */

Page 65: ARM 指令集与编程

ARM指令集与编程 65

6.6 模拟栈• ARM 指令集中没有用于栈的操作指令,但

是可以用多数据访存指令来模拟。

Page 66: ARM 指令集与编程

ARM指令集与编程 66

6.6.1 栈的分类

• 栈的分类(按指针) :– 栈指针指向最后一个被占用的地址 (Full Stack)

• 在 push 前需要先将栈指针减小– 栈指针指向下一个被占用的地址 (Empty Stack)

• 在 push 之后需要将栈指针减小

• 栈的分类(按方向):– 上升的栈( Ascending Stack )

• 向高地址扩展– 下降的栈( Descending Stack )

• 向低地址扩展

Page 67: ARM 指令集与编程

ARM指令集与编程 67

6.6.2 模拟压栈操作

块数据访问指令 栈访问指令 说明stmda stmed 下降型空栈stmia stmea 上升型空栈stmdb stmfd 下降型满栈stmib stmfa 上升型满栈

Page 68: ARM 指令集与编程

ARM指令集与编程 68

6.6.3 模拟退栈操作

块数据访问指令 栈访问指令 说明ldmda ldmfa 上升型满栈ldmia ldmfd 下降型满栈ldmdb ldmea 上升型空栈ldmib ldmed 下降型空栈

Page 69: ARM 指令集与编程

ARM指令集与编程 69

6.6.4 模拟栈操作• 模拟 stack 的访问

– stmfd / ldmfd : Full Descending Stack– stmfa / ldmfa : Full Ascending Stack.– stmed / ldmed : Empty Descending Stack– stmea / ldmea : Empty Ascending Stack

• 常见的情况– stmfd sp!, {r0-r12, lr} // 保存所有有寄存器(包括返回地址)

……

– ldmfd sp!, {r0-r12, pc} // 恢复所有寄存器(包括 pc )

Page 70: ARM 指令集与编程

ARM指令集与编程 70

6.6.5 栈操作图示

Page 71: ARM 指令集与编程

ARM指令集与编程 71

目录

1. 总体介绍:指令分类,特点,格式,条件码2. 数据处理指令:数据传输指令,算术指令,逻辑指令,比

较指令,乘法指令 ( 略 ) ,前导零计数 ( 略 )3. 程序状态访问指令4. 跳转指令5. 单数据访存指令6. 多数据访存指令7. 其它指令:信号量操作指令,异常中断产生指令,协处理

器指令 ( 略 )8. 伪指令 ( 略 )9. 基于 ARM 的编程

Page 72: ARM 指令集与编程

ARM指令集与编程 72

7 其它指令• 信号量操作指令:用于进程间的同步互斥,提供对信号量的原子操作。

• 异常中断产生指令:用于系统调用和调试。

Page 73: ARM 指令集与编程

ARM指令集与编程 73

7.1 信号量操作指令• 语法

– swp|swpb{<cond>} <Rd>, <Rm>, [<Rn>]

• 例子– swp r1, r2, [r3] /* 将内存单元 (r3) 中的字读取到 r

1 ,同时将 r2 中的数据写入内存单元 (r3) 中 */– swp r1, r1, [r2] /* 将 r1 寄存器内容和内存单元 (r

2) 的内容互换 */

• 说明– swpb读取 8bit 数据到寄存器后会对高 24 位清零,写

到内存的 8bit 数来自寄存器低 8 位

Page 74: ARM 指令集与编程

ARM指令集与编程 74

7.1 信号量操作指令 ( 续 )

Page 75: ARM 指令集与编程

ARM指令集与编程 75

7.2 异常产生指令• 指令格式

• 语法– swi{<cond>} <immed_24>

• 说明– 主要用于用户程序调用操作系统的 API 。参数传递通

常有两种方法:• 指令中的 24bit 立即数指定 API 号,参数通过寄存器传递。• 忽略指令中的 24bit 立即数, r0 指定 API 号,其它参数通过其

它寄存器传递。

cond Immed_24

023

1 1 1 1

272831 24

Page 76: ARM 指令集与编程

ARM指令集与编程 76

7.3 中断产生指令• 语法

– bkpt <immed_16>

• 说明– 用于产生软件断点中断。–主要用于调试。– ARMv5及以上版本支持。

Page 77: ARM 指令集与编程

ARM指令集与编程 77

目录

1. 总体介绍:指令分类,特点,格式,条件码2. 数据处理指令:数据传输指令,算术指令,逻辑指令,比

较指令,乘法指令 ( 略 ) ,前导零计数 ( 略 )3. 程序状态访问指令4. 跳转指令5. 单数据访存指令6. 多数据访存指令7. 其它指令:信号量操作指令,异常中断产生指令,协处理

器指令 ( 略 )8. 伪指令 ( 略 )9. 基于 ARM 的编程

Page 78: ARM 指令集与编程

ARM指令集与编程 78

8 伪指令• 略

Page 79: ARM 指令集与编程

ARM指令集与编程 79

目录

1. 总体介绍:指令分类,特点,格式,条件码2. 数据处理指令:数据传输指令,算术指令,逻辑指令,比

较指令,乘法指令 ( 略 ) ,前导零计数 ( 略 )3. 程序状态访问指令4. 跳转指令5. 单数据访存指令6. 多数据访存指令7. 其它指令:信号量操作指令,异常中断产生指令,协处理

器指令 ( 略 )8. 伪指令 ( 略 )9. 基于 ARM 的编程

Page 80: ARM 指令集与编程

ARM指令集与编程 80

• 编程工具• 编程语言

9 基于 ARM 的编程

Page 81: ARM 指令集与编程

ARM指令集与编程 81

9.1 编程工具• 直接面向硬件的开发

– SDT 、 ADS (集成开发环境)– CodeWorrier

• 面向特定操作系统的应用– 面向WinCE 的 Embeded VC – 面向 Symbian 的 C/C++ 集成开发环境– 面向 Linux 的 GNU Tools (主要是 GCC/G++ )

• 操作系统开发– GCC/C++ ( 支持 uClinux, Linux, ECOS, uC/OS-II 等 )

• 其它– J2ME 等基于 JAVA 的编程

Page 82: ARM 指令集与编程

ARM指令集与编程 82

9.2 编程语言• 汇编语言• C/C++语言

– C 与汇编混合编程• Java语言

Page 83: ARM 指令集与编程

ARM指令集与编程 83

9.2.1 C 与汇编混合编程( 1 )

• C/ASM 相互调用基于 ATPCS(ARM/Thumb Procdure Call Standard) ,也可简称 APCS

• C 中内嵌汇编 基于 ADS__asm{ 指令 [; 指令 ] /* 注释 */ ….. [ 指令 ]}

基于 GNU C__asm__ __volatile__ (“ 指令 @ 注释 ….. [ 指令 ]:属性设置 1:属性设置 2)

Asm(“ 指令” :属性 1:属性 2)

Page 84: ARM 指令集与编程

ARM指令集与编程 84

• 内嵌汇编的语法– 操作数:作为操作数的寄存器和产量可以是 ch

ar\short\int型的 C 表达式。–物理寄存器:不要使用复杂的 C 表达式;一般

不要使用 R0~R3,R12(IP),R14(LR)– 不要使用寄存器代替变量

9.2.1 C 与汇编混合编程( 2 )

Page 85: ARM 指令集与编程

ARM指令集与编程 85

9.2.1 C 与汇编混合编程( 3 )

• 交互规则:– 寄存器规则: v1-v8 ( R4-R11 )用来保存局部变量– 堆栈规则: FD 类型(满递减)堆栈– 参数传递规则:如果参数个数小于等于 4 ,用 R0-R3保存参数;参数个数多于 4 的情况下,剩余的参数传入堆栈

– 子程序结果返回规则:• 结果为一个 32 位整数,通过 R0返回;• 结果为一个 64 位整数,通过 R0 、 R1返回;• 对于位数更多的结果,通过内存传递。

Page 86: ARM 指令集与编程

ARM指令集与编程 86

9.2.1 C 与汇编混合编程( 4 )• C调用汇编

C 代码

extern void scopy(char *d, char *s);

scopy(dststr,srcstr

汇编代码

AREA example, CODE, READONLY

EXPORT scopy

scopy

LDRB R2, [R1],#1

STRB R2, [R1], #1

CMP R2, #0

BNE scopy

MOV pc,lr

END

Page 87: ARM 指令集与编程

ARM指令集与编程 87

9.2.1 C 与汇编混合编程( 5 )• 汇编调用 C

汇编代码EXPORT callsum5

AREA example, CODE, READONLY

IMPORT sum5

callsum5

STMFD SP!,{LR} ;LR 入栈

ADD R1,R0,R0 ;R0=a,R1=b,R2=c

ADD R2,R1,R0

ADD R3,R1,R2

STR R3,[SP,#-4]! ;e in stack

ADD R3,R1,R1 ;R3=d

BL sum5 ;call R5, R0=result

ADD SP,SP,#4

LDMFD SP!,{PC}

END

C 代码

Int sum5(int a, int b ,int c, int d, int e)

{

return (a+b+c+d+e);

}