欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

常见的ARM指令集和汇编技术

最编程 2024-01-18 13:16:26
...

ARM7TDMI(-S)指令集及汇编

ARM 处理器是基于精简指令集计算机(RISC)原理设计的,指令集和相关译码机制 较为简单,ARM7TDMI(-S)具有 32 位 ARM 指令集和 16 位 Thumb 指令集,ARM 指令集效率 高,但是代码密度低,而 Thumb 指令集具有更好的代码密度,却仍然保持 ARM 的大多数 性能上的优势,它是 ARM 指令集的子集。所有 ARM 指令都是可以有条件执行的,而 Thumb 指令仅有一条指令具备条件执行功能。ARM 程序和 Thumb 程序可相互调用,相互之间的 状态切换开销几乎为零。

ARM 处理器寻址方式

寻址方式是根据指令中给出的地址码字段来实现寻找真实操作数地址的方式,ARM 处理器有 9 种基本寻址方式。

寄存器寻址

操作数的值在寄存器中,指令中的地址码字段指出的是寄存器编号,指令执行时直 接取出寄存器值操作。

寄存器寻址指令举例如下:

MOV

R1,R2

;R2 -> R1

SUB

R0,R1,R2

;R1 - R2 -> R0

立即寻址

立即寻址指令中的操作码字段后面的地址码部分就是操作数本身,也就是说,数据就包含在指令当中,取出指令也就取出了可以立即使用的操作数(立即数)。

立即寻址指令举例如下:

SUBS R0,R0,#1 ;R0 – 1 -> R0

MOV R0,#0xff00 ;0xff00 -> R0 立即数要以“#”为前缀,表示 16 进制数值时以“0x”表示。

寄存器偏移寻址

寄存器偏移寻址是ARM指令集特有的寻址方式,当第2操作数是寄存器偏移方式时, 第 2 个寄存器操作数在与第 1 个操作数结合之前,选择进行移位操作。

寄存器偏移寻址方式指令举例如下:

MOV R0,R2,LSL #3 ;R2 的值左移 3 位,结果放入 R0,即 R0 = R2 * 8

ANDS R1,R1,R2,LSL R3 ;R2 的值左移 R3 位,然后和 R1 相与操作,结果放入 R1 可采用的移位操作如下:

LSL:逻辑左移(Logical Shift Left),寄存器中字的低端空出的位补 0

LSR:逻辑右移(Logical Shift Right),寄存器中字的高端空出的位补 0

ASR:算术右移(Arithmetic Shift Right),移位过程中保持符号位不变,即如 果源操作数为正数,则字的高端空出的位补 0,否则补 1

ROR:循环右移(Rotate Right),由字的低端移出的位填入字的高端空出的位 RRX:带扩展的循环右移(Rotate Right eXtended by 1place),操作数右移一位,

高端空出的位用原 C 标志值填充。

各移位操作如下图所示。

0 LSL 移位操作

0 LSR 移位操作

ASR 移位操作

ROR 移位操作

C RRX 移位操作

寄存器间接寻址

寄存器间接寻址指令中的地址码给出的是一个通用寄存器编号,所需要的操作数保 存在寄存器指定地址的存储单元中,即寄存器为操作数的地址指针。

寄存器间接寻址指令举例如下:

LDR R1,[R2] ;将 R2 中的数值作为地址,取出此地址中的数据保存在 R1 中 SWP R1,R1,[R2];将如中的数值作为地址,取出此地址中的数值与 R1 中的值交换

基址寻址

基址寻址是将基址寄存器的内容与指令中给出的偏移量相加,形成操作数的有效地

址,基址寻址用于访问基址附近的存储单元,常用于查表,数组操作,功能部件寄存器

访问等。 基址寻址指令举例如下:

LDR R2,[R3,#0x0F] ;将 R3 中的数值加 0x0F 作为地址,取出此地址的数值保存在 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

使用多寄存器寻址指令时,寄存器子集的顺序时由小到大的顺序排列,连续的寄存 器可用“-”连接,否则,用“,”分隔书写。

堆栈寻址

堆栈是特定顺序进行存取的存储区,操作顺序分为“后进先出”和“先进后出”, 堆栈寻址时隐含的,它使用一个专门的寄存器(堆栈指针)指向一块存储区域(堆栈), 指针所指向的存储单元就是堆栈的栈顶。存储器堆栈可分为两种:

向上生长:向高地址方向生长,称为递增堆栈 向下生长:向低地址方向生长,称为递减堆栈 堆栈指针指向最后压入的堆栈的有效数据项,称为满堆栈;堆栈指针指向下一个要

放入的空位置,称为空堆栈。这样就有 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 寄存器。满递减堆栈。

块拷贝寻址

多寄存器传送指令用于一块数据从存储器的某一位置拷贝到另一位置。 块拷贝寻址指令举例如下:

STMIA

R0!,{R1-R7}

;将 R1~R7 的数据保存到存储器中,存储器指针在保存第一

;个值之后增加,增长方向为向上增长。

STMIB

R0!,{R1-R7}

;将 R1~R7 的数据保存到存储器中,存储器指针在保存第一

;个值之前增加,增长方向为向上增长。

STMDA

R0!,{R1-R7}

;将 R1~R7 的数据保存到存储器中,存储器指针在保存第一

;个值之后增加,增长方向为向下增长。

STMDB

R0!,{R1-R7}

;将 R1~R7 的数据保存到存储器中,存储器指针在保存第一

;个值之前增加,增长方向为向下增长。

相对寻址

相对寻址是基址寻址的一种变通,由程序计数器 PC 提供基准地址,指令中的地址码字段作为偏移量,两者相加后得到的地址即为操作数的有效地址。

相对寻址指令举例如下:

BL ROUTE1 ;调用到 ROUTE1 子程序 BEQ LOOP ;条件跳转到 LOOP 标号处

LOOP MOV R2,#2

ROUTE1

指令集介绍

ARM 指令集

指令格式

基本格式

<opcode>{<cond>}{S} <Rd>,<Rn>{,<opcode2>} 其中,<>内的项是必须的,{}内的项是可选的,如<opcode>是指令助记符,是必须

的,而{<cond>}为指令执行条件,是可选的,如果不写则使用默认条件 AL(无条件执行)。

opcode 指令助记符,如 LDR,STR 等

cond 执行条件,如 EQ,NE 等

S 是否影响 CPSR 寄存器的值,书写时影响 CPSR,否则不影响 Rd 目标寄存器

Rn 第一个操作数的寄存器

operand2 第二个操作数

指令格式举例如下:

LDR R0,[R1] ;读取 R1 地址上的存储器单元内容,执行条件 AL BEQ DATAEVEN ;跳转指令,执行条件 EQ,即相等跳转到 DATAEVEN ADDS R1,R1,#1 ;加法指令,R1+1=R1 影响 CPSR 寄存器,带有 S

SUBNES R1,R1,#0xD;条件执行减法运算(NE),R1-0xD=>R1,影响 CPSR 寄存器,带有 S

2 个操作数

在 ARM 指令中,灵活的使用第 2 个操作数能提高代码效率,第 2 个操作数的形式如 下:

immed_8r

常数表达式,该常数必须对应 8 位位图,即常数是由一个 8 位的常数循环移位偶数

位得到。

合法常量:

0x3FC、0、0xF0000000、200,0xF0000001 非法常量:

0x1FE、511、0xFFFF、0x1010、0xF0000010 常数表达式应用举例如下:

MOV R0,#1 ;R0=1

AND R1,R2,#0x0F ;R2 与 0x0F,结果保存在 R1

LDR R0,[R1],#-4 ;读取 R1 地址上的存储器单元内容,且 R1=R1-4

Rm

寄存器方式,在寄存器方式下操作数即为寄存器的数值。 寄存器方式应用举例:

SUB

R1,R1,R2

;R1-R2=>R1

MOV

PC,R0

;PC=R0,程序跳转到指定地址

LDR

R0,[R1],-R2

;读取 R1 地址上的存储器单元内容并存入 R0,且 R1=R1-R2

Rm,shift

寄存器移位方式。将寄存器的移位结果作为操作数,但 RM 值保存不变,移位方法 如下:

ASR #n 算术右移 n 位(1≤n≤32) LSL #n 逻辑左移 n 位(1≤n≤31) LSR #n 逻辑左移 n 位(1≤n≤32) ROR #n 循环右移 n 位(1≤n≤31) RRX 带扩展的循环右移 1 位

type Rs 其中,type 为 ASR,LSL,和 ROR 中的一种;Rs 偏移量寄存器,低 8 位有效,若其值大于或等于 32,则第 2 个操作数的结果为 0(ASR、ROR 例外)。

寄存器偏移方式应用举例:

ADD R1,R1,R1,LSL #3 ;R1=R1*9

SUB R1,R1,R2,LSR#2 ;R1=R1-R2*4

R15 为处理器的程序计数器 PC,一般不要对其进行操作,而且有些指令是不允许使 用 R15,如 UMULL 指令。

条件码

使用指令条件码,可实现高效的逻辑操作,提高代码效率。 条件码表

条件码助记符

标志

含义

EQ

Z=1

相等

NE

Z=0

不相等

CS/HS

C=1

无符号数大于或等于

CC/LO

C=0

无符号数小于

MI

N=1

负数

PL

N=0

正数或零

VS

V=1

溢出

VC

V=0

没有溢出

HI

C=1,Z=0

无符号数大于

LS

C=0,Z=1

无符号数小于或等于

GE

N=V

带符号数大于或等于

LT

N!=V

带符号数小于

GT

Z=0,N=V

带符号数大于

LE

Z=1,N!=V

带符号数小于或等于

AL

任何

无条件执行(指令默认条件)

对于 Thumb 指令集,只有 B 指令具有条件码执行功能,此指令条件码同表 2.1,但

如果为无条件执行时,条件码助记符“AL”不能在指令中书写。 条件码应用举例如下:

比较两个值大小,并进行相应加 1 处理,C 代码为

if(a>b)a++;

else b++;

对应的 ARM 指令如下。其 R0 为 a,R1 为 b。 CMP R0,R1 ;R0 与 R1 比较

ADDHI R0,R0,#1 ;若 R0>R1,则 R0=R0+1

ADDLS R1,R1,#1 ;若 R0<=R1,则 R1=R1+1 若两个条件均成立,则将这两个数值相加,C 代码为

If((a!=10)&&(b!=20)) a=a+b;

对应的 ARM 指令如下.其中 R0 为 a,R1 为 b. CMP R0,#10 ;比较 R0 是否为 10

CMPNE R1,#20 ;若 R0 不为 10,则比较 R1 是否 20

ADDNE R0,R0,R1 ;若 R0 不为 10 且 R1 不为 20,指令执行,R0=R0+R1

ARM 存储器访问指令

ARM 处理是加载/存储体系结构的典型的 RISC 处理器,对存储器的访问只能使用加 载和存储指令实现。ARM 的加载/存储指令是可以实现字、半字、,无符/有符字节操作; 批量加载/存储指令可实现一条指令加载/存储多个寄存器的内容,大大提高效率;SWP 指令是一条寄存器和存储器内容交换的指令,可用于信号量操作等。ARM 处理器是冯. 诺依曼存储结构,程序空间、RAM 空间及 IO 映射空间统一编址,除对对 RAM 操作以外, 对外围 IO、程序数据的访问均要通过加载/存储指令进行。

ARM 存储访问指令表

助记符

说明

操作

条件码位置

LDR Rd,addressing

加载字数据

Rd←[addressing],addressing 索引

LDR{cond}

LDRB Rd,addressing

加载无符字节数据

Rd←[addressing],addressing 索引

LDR{cond}B

LDRT Rd,addressing

以用户模式加载字数据

Rd←[addressing],addressing 索引

LDR{cond}T

LDRBT Rd,addressing

以用户模式加载无符号字数据

Rd←[addressing],addressing 索引

LDR{cond}BT

LDRH Rd,addressing

加载无符半字数据

Rd←[addressing],addressing 索引

LDR{cond}H

LDRSB Rd,addressing

加载有符字节数据

Rd←[addressing],addressing 索引

LDR{cond}SB

LDRSH Rd,addressing

加载有符半字数据

Rd←[addressing],addressing 索引

LDR{cond}SH

STR Rd,addressing

存储字数据

[addressing]←Rd,addressing 索引

STR{cond}

STRB Rd,addressing

存储字节数据

[addressing]←Rd,addressing 索引

STR{cond}B

STRT Rd,addressing

以用户模式存储字数据

[addressing]←Rd,addressing 索引

STR{cond}T

SRTBT Rd,addressing

以用户模式存储字节数据

[addressing]←Rd,addressing 索引

STR{cond}BT

STRH Rd,addressing

存储半字数据

[addressing]←Rd,addressing 索引

STR{cond}H

LDM{mode} Rn{!},reglist

批量(寄存器)加载

reglist←[Rn…],Rn 回存等

LDM{cond}{more}

STM{mode} Rn{!},rtglist

批量(寄存器)存储

[Rn…]← reglist,Rn 回存等

STM{cond}{more}

SWP Rd,Rm,Rn

寄存器和存储器字数据交换

Rd←[Rd],[Rn]←[Rm](Rn≠Rd 或 Rm)

SWP{cond}

SWPB Rd,Rm,Rn

寄存器和存储器字节数据交换

Rd←[Rd],[Rn]←[Rm](Rn≠Rd 或 Rm)

SWP{cond}B

X LDR STR

加载/存储字和无符号字节指令.使用单一数据传送指令(STR 和 LDR)来装载和存储 单一字节或字的数据从/到内存.LDR 指令用于从内存中读取数据放入寄存器中;STR 指 令用于将寄存器中的数据保存到内存.指令格式如下:

LDR{cond}{T} Rd,<地址>;加载指定地址上的数据(字),放入 Rd 中 STR{cond}{T} Rd,<地址>;存储数据(字)到指定地址的存储单元,要存储的数据在 Rd 中 LDR{cond}B{T} Rd,<地址>;加载字节数据,放入 Rd 中,即 Rd 最低字节有效,高 24 位清零

STR{cond}B{T} Rd,<地址>;存储字节数据,要存储的数据在 Rd,最低字节有效

其中,T 为可选后缀,若指令有 T,那么即使处理器是在特权模式下,存储系统也将访 问看成是处理器是在用户模式下.T 在用户模式下无效,不能与前索引偏移一起使用 T. LDR/STR 指令寻址是非常灵活的,由两部分组成,一部分为一个基址寄存器,可以为任一 个通用寄存器,另一部分为一个地址偏移量.地址偏移量有以下 3 种格式:

(1) 立即数.立即数可以是一个无符号数值,这个数据可以加到基址寄存器,也可 以从基址寄存器中减去这个数值.指令举例如下:

LDR R1,[R0,#0x12] ;将 R0+0x12 地址处的数据读出,保存到 R1 中(R0 的值不变) LDR R1,[R0,#-0x12];将 R0-0x12 地址处的数据读出,保存到 R1 中(R0 的值不变) LDR R1,[R0] ;将 R0 地址处的数据读出,保存到 R1 中(零偏移) (2)寄存器.寄存器中的数值可以加到基址寄存器,也可以从基址寄存器中减去这

个数值.指令举例值.指令举例如下:

LDR R1,[R0,R2] ;将 R0+R2 地址的数据计读出,保存到 R1 中(R0 的值不变) LDR R1,[R0,-R2] ;将 R0-R2 地址处的数据计读出,保存到 R1 中(R0 的值不变) (3)寄存器及移位常数.寄存器移位后的值可以加到基址寄存器,也可以从基址寄

存器中减去这个数值.指令举例如下:

LDR R1,[R0,R2,LSL #2] ;将 R0+R2*4 地址处的数据读出,保存到 R1 中(R0,R2 的值不变) LDR R1,[R0,-R2,LSL #2];将 R0-R2*4 地址处的数据计读出,保存到 R1 中(R0,R2 的值不变) 从寻址方式的地址计算方法分,加载/存储指令有以下 4 种形式:

(1)零偏移.Rn 的值作为传送数据的地址,即地址偏移量为 0.指令举例如下: LDR Rd,[Rn]

(2)前索引偏移.在数据传送之前,将偏移量加到 Rn 中,其结果作为传送数据的存储地址.若使用后缀“!”,则结果写回到 Rn 中,且 Rn 值不允许为 R15.指令举例如下:

LDR Rd,[Rn,#0x04]! LDR Rd,[Rn,#-0x04] (3)程序相对偏移.程序相对偏移是索引形式的另一个版本.汇编器由 PC 寄存器计

算偏移量,并将 PC 寄存器作为 Rn 生成前索引指令.不能使用后缀“!”.指令举例如下: LDR Rd,label ;label 为程序标号,label 必须是在当前指令的±4KB 范围内 (4) 后索引偏移.Rn 的值用做传送数据的存储地址.在数据传送后,将偏移量与 Rn

相加,结果写回到 Rn 中.Rn 不允许是 R15.指令举例如下:

LDR Rd,[Rn],#0x04

地址对准--大多数情况下,必须保证用于 32 位传送的地址是 32 位对准的. 加载/存储字和无符号字节指令举例如下:

LDR R2,[R5] ;加载 R5 指定地址上的数据(字),放入 R2 中

STR R1,[R0,#0x04] ;将 R1 的数据存储到 R0+0x04 存储单元,R0 值不变

LDRB R3,[R2],#1 ;读取 R2 地址上的一字节数据,并保存到 R3 中,R2=R3+1

STRB R6,[R7] ;读R6的数据保存到R7指定的地址中,只存储一字节数据 加载/存储半字和带符号字节.这类 LDR/STR 指令可能加载带符字节\加载带符号半字、加载/存储无符号半字.偏移量格式、寻址方式与加载/存储字和无符号字节指令相

同.指令格式如下:

LDR{cond}SB Rd,<地址> ;加载指定地址上的数据(带符号字节),放入 Rd 中 LDR{cond}SH Rd,<地址> ;加载指定地址上的数据(带符号字节),放入 Rd 中 LDR{cond}H Rd,<地址> ;加载半字数据,放入 Rd 中,即 Rd 最低 16 位有效,高 16 位清零 STR{cond}H Rd,<地址> ;存储半字数据,要存储的数据在 Rd,最低 16 位有效 说明:带符号位半字/字节加载是指带符号位加载扩展到 32 位;无符号位半字加载

是指零扩展到 32 位.

地址对准--对半字传送的地址必须为偶数.非半字对准的半字加载将使 Rd 内容不 可靠,非半字对准的半字存储将使指定地址的 2 字节存储内容不可靠.

加载/存储半字和带符号字节指令举例如下:

LDRSB R1[R0,R3] ;将 R0+R3 地址上的字节数据读出到 R1,高 24 位用符号位扩展 LDRSH R1,[R9] ;将 R9 地址上的半字数据读出到 R1,高 16 位用符号位扩展 LDRH R6,[R2],#2 ;将 R2 地址上的半字数据读出到 R6,高 16 位用零扩展,,R2=R2+1

SHRH R1,[R0,#2]!;将 R1 的数据保存到 R2+2 地址中,只存储低 2 字节数据,R0=R0+2

LDR/STR 指令用于对内存变量的访问,内存缓冲区数据的访问、查表、外围部件的 控制操作等等,若使用 LDR 指令加载数据到 PC 寄存器,则实现程序跳转功能,这样也就实现了程序散转。

变量的访问

NumCount EQU 0x40003000 ;定义变量 NumCount

GPIO 设置

LDR R0,=NumCount ;使用 LDR 伪指令装载 NumCount 的地址到 R0

LDR R1,[R0] ;取出变量值

ADD R1,R1,#1 ;NumCount=NumCount+1

STR R1,[R0] ;保存变量值

GPIO-BASE EQU 0Xe0028000 ;定义 GPIO 寄存器的基地址

LDR R0,=GPIO-BASE

LDR R1,=0x00FFFF00 ;装载 32 位立即数,即设置值

STR R1,[R0,#0x0C] ;IODIR=0x00FFFF00, IODIR 的地址为 0xE002800C

MOV R1,#0x00F00000

STR R1,[R0,#0x04] ;IOSET=0x00F00000,IOSET 的地址为 0xE0028004

程序散转

MOV R2,R2,LSL #2 ;功能号乘上 4,以便查表

LDR PC,[PC,R2] ;查表取得对应功能子程序地址,并跳转 NOP

FUN-TAB DCD FUN-SUB0

DCD FUN-SUB1

DCD FUN-SUB2

X LDM STM

批量加载/存储指令可以实现在一组寄存器和一块连续的内存单元之间传输数 据.LDM 为加载多个寄存器,STM 为存储多个寄存器.允许一条指令传送 16 个寄存器的任 何子集或所有寄存器.指令格式如下:

LDM{cond}<模式> Rn{!},reglist{^}

STM{cond}<模式> Rn{!},reglist{^}

LDM /STM 的主要用途是现场保护、数据复制、参数传送等。其模式有 8 种,如下:(前 面 4 种用于数据块的传输,后面 4 种是堆栈操作)

(1) IA:每次传送后地址加 4 (2) IB:每次传送前地址加 4 (3) DA:每次传送后地址减 4 (4) DB:每次传送前地址减 4 (5) FD:满递减堆栈

(6) ED:空递增堆栈 (7) FA:满递增堆栈 (8) EA:空递增堆栈

其中,寄存器Rn为基址寄存器,装有传送数据的初始地址,Rn不允许为R15;后缀“!” 表示最后的地址写回到Rn中;寄存器列表reglist可包含多于一个寄存器或寄存器范围, 使用“,”分开,如{R1,R2,R6-R9},寄存器排列由小到大排列;“^”后缀不允许在用户 模式呈系统模式下使用,若在 LDM 指令用寄存器列表中包含有 PC 时使用,那么除了正 常的多寄存器传送外,将 SPSR 拷贝到 CPSR 中,这可用于异常处理返回;使用“^”后 缀进行数据传送且寄存器列表不包含 PC 时,加载/存储的是用户模式的寄存器,而不是 当前模式的寄存器。

地址对准――这些指令忽略地址的位[1:0] 批量加载/存储指令举例如下:

LDMIA R0!,{R3-R9} ;加载 R0 指向的地址上的多字数据,保存到 R3~R9 中,R0 值更新 STMIA R1!,{R3-R9} ;将 R3~R9 的数据存储到 R1 指向的地址上,R1 值更新 STMFD SP!,{R0-R7,LR} ;现场保存,将 R0~R7、LR 入栈

LDMFD SP!,{R0-R7,PC}^;恢复现场,异常处理返回 在进行数据复制时,先设置好源数据指针,然后使用块拷贝寻址指令 LDMIA/STMIA、

LDMIB/STMIB、LDMDA/STMDA、LDMDB/STMDB 进行读取和存储。而进行堆栈操作时,则要先设置堆栈指针,一般使用 SP 然后使用堆栈寻址指令 STMFD/LDMFD、STMED。LDMED、 STMFA/LDMFA、STMEA/LDMEA 实现堆栈操作。

多寄存器传送指令示意图如图所示,其中 R1 为指令执行前的基址寄存器,R1 则为指

令执行完后的基址寄存器. R1’

R7

R6

R1 R5 4008H

4004H

4000H

a)指令 STMIA R1!,{R5-R7}

R1’

R1

R7

R6

R5 4008H

4004H

4000H

b)指令 STMIB R1!,{R5-R7}

R1

R1’

R7

R6

R5 4008H

4004H

4000H

c)指令 STMDA R1!, {R5-R7}

R1

R1’

R7

R6 4008H R5 4004H

4000H

d)指令 STMDB R1!,{R5-R7}

数据是存储在基址寄存器的地址之上还是之下,地址是在存储第一个值之前还是之后增加还是减少.

多寄存器传送指令映射

向上生长

向下生长

增加

之前

STMIB

LDMIB

STMFA

LDMED

之后

STMIA

LDMIA

STMEA

LDMFD

增加

之前

LDMDB

STMDB

LDMEA

STMFD

之后

LDMDA

STMDA

LDMFA

STMED

使用 LDM/STM 进行数据复制:

LDR R0,=SrcData ;设置源数据地址 LDR R1,=DstData ;设置目标地址

LDMIA R0,{R2-R9} ;加载 8 字数据到寄存器 R2~R9

STMIA R1,{R2~R9} ;存储寄存器 R2~R9 到目标地址 使用 LDM/STM 进行现场寄存器保护,常在子程序中或异常处理使用: SENDBYTE

STMFD SP!,{R0-R7,LR} ;寄存器入堆

BL DELAY ;调用 DELAY 子程序

LDMFD SP!,{R0-R7,PC} ;恢复寄存器,并返回

X SWP

寄存器和存储器交换指令.SWP 指令用于将一个内存单元(该单元地址放在寄存器 Rn 中)的内容读取到一个寄存器 Rd 中,同时将另一个寄存器 Rm 的内容写入到该内存单 元中.使用 SWP 可实现信号量操作.

指令格式如下: SWP{cond}{B} Rd,Rm,[Rn]

其中,B 为可选后缀,若有 B,则交换字节,否则交换 32 位字:Rd 为数据从存储器加载

到的寄存器;Rm 的数据用于存储到存储器中,若 Rm 与 Rn 相同,则为寄存器与存储器内容 进行交换;Rn 为要进行数据交换的存储器地址,Rn 不能与 Rd 和 Rm 相同.

SWP 指令举例如下:

SWP R1,R1,[R0] ;将 R1 的内容与 R0 指向的存储单元的内容进行交换

SWP R1,R2,,[R0] ;将R0指向的存储单元内容读取一字节数据到R1中(高

24 位清零),并将 R2 的内容写入到该内存单元中(最低字节有效) 使用 SWP 指令可以方便地进行信号量的操作:

12C_SEM EQU 0x40003000

12C_SEM_WAIT

MOV R0,#0

LDR R0,=12C_SEM

SWP R1,R1,[R0] ;取出信号量,并设置其为 0

CMP R1,#0 ;判断是否有信号

BEQ 12C_SEM_WAIT ;若没有信号,则等待

ARM 数据处理指令

数据处理指令大致可分为 3 类;数据传送指令(如 MOV、MVN),算术逻辑运算指令 (如 ADD,SUM,AND),比较指令(如 CMP,TST).数据处理指令只能对寄存器的内容进行操作. 所有 ARM 数据处理指令均可选择使用 S 后缀,以影响状态标志.比较指令 CMP,CMN,TST 和 TEQ 不需要后缀 S,它们会直接影响状态标志.

ARM 数据处理指令

助记符号

说明

操作

条件码位置

MOV Rd ,operand2

数据转送

Rd←operand2

MOV {cond}{S}

MVN Rd ,operand2

数据非转送

Rd←(operand2)

MVN {cond}{S}

ADD Rd,Rn operand2

加法运算指令

Rd←Rn+operand2

ADD {cond}{S}

SUB Rd,Rn operand2

减法运算指令

Rd←Rn-operand2

SUB {cond}{S}

RSB Rd,Rn operand2

逆向减法指令

Rd←operand2-Rn

RSB {cond}{S}

ADC Rd,Rn operand2

带进位加法

Rd←Rn+operand2+carry

ADC {cond}{S}

SBC Rd,Rn operand2

带进位减法指令

Rd←Rn-operand2-(NOT)Carry

SBC {cond}{S}

RSC Rd,Rn operand2

带进位逆向减法指令

Rd←operand2-Rn-(NOT)Carry

RSC {cond}{S}

AND Rd,Rn operand2

逻辑与操作指令

Rd←Rn&operand2

AND {cond}{S}

ORR Rd,Rn operand2

逻辑或操作指令

Rd←Rn|operand2

ORR {cond}{S}

EOR Rd,Rn operand2

逻辑异或操作指令

Rd←Rn^operand2

EOR {cond}{S}

BIC Rd,Rn operand2

位清除指令

Rd←Rn&(~operand2)

BIC {cond}{S}

CMP Rn,operand2

比较指令

标志 N、Z、C、V←Rn-operand2

CMP {cond}

CMN Rn,operand2

负数比较指令

标志 N、Z、C、V←Rn+operand2

CMN {cond}

TST Rn,operand2

位测试指令

标志 N、Z、C、V←Rn&operand2

TST {cond}

TEQ Rn,operand2

相等测试指令

标志 N、Z、C、V←Rn^operand2

TEQ {cond}

数据传送指令

X MOV

数据传送指令.将 8 位图立即数或寄存器(operant2)传送到目标寄存器 Rd,可用于 移位运算等操作.指令格式如下:

MOV{cond}{S} Rd,operand2

MOV 指令举例如下:

MOV

R1#0x10

;R1=0x10

MOV

R0,R1

;R0=R1

MOVS

R3,R1,LSL

#2

;R3=R1<<2,并影响标志位

MOV

PC,LR

;PC=LR ,子程序返回

X MVN

数据非传送指令.将 8 位图立即数或寄存器(operand2)按位取反后传送到目标寄存 器(Rd),因为其具有取反功能,所以可以装载范围更广的立即数.指令格式如下:

MVN{cond}{S} Rd,operand2

MVN 指令举例如下:

MVN

R1,#0xFF

;R1=0xFFFFFF00

MVN

R1,R2

;将 R2 取反,结果存到 R1

算术逻辑运算指令

X ADD

加法运算指令.将 operand2 数据与 Rn 的值相加,结果保存到 Rd 寄存器.指令格式如

下:

ADD{cond}{S} Rd,Rn,operand2

ADD 指令举例如下:

ADDS R1,R1,#1 ;R1=R1+1

ADD R1,R1,R2 ;R1=R1+R2

ADDS R3,R1,R2,LSL #2 ;R3=R1+R2<<2

X SUB

减法运算指令.用寄存器 Rn 减去 operand2.结果保存到 Rd 中.指令格式如下: SUB{cond}{S} Rd,Rn,operand2

SUB 指令举例如下

SUBS R0,R0,#1 ;R0=R0-1

SUBS R2,R1,R2 ;R2=R1-R2

SUB R6,R7,#0x10 ;R6=R7-0x10

X RSB

逆向减法指令.用寄存器 operand2 减法 Rn,结果保存到 Rd 中.指令格式如下: RSB{cond}{S} Rd,Rn,operand2

SUB 指令举例如下

RSB R3,R1,#0xFF00 ;R3=0xFF00-R1

RSBS R1,R2,R2,LSL #2 ;R1=R2<<2-R2=R2×3

RSB R0,R1,#0 ;R0=-R1

X ADC

带进位加法指令.将 operand2 的数据与 Rn 的值相加,再加上 CPSR 中的 C 条件标志位.结果保存到 Rd 寄存器.指令格式如下;

ADC{cond}{S} Rd,Rn,operand2

ADC 指令举例如下:

ADDS

R0,R0,R2

ADC

R1,R1,R3

;使用 ADC 实现 64 位加法,(R1、R0)=(R1、R0)+(R3、R2)

X SBC

带进位减法指令。用寄存器 Rn 减去 operand2,再减去 CPSR 中的 C 条件标志位的非(即若 C 标志清零,则结果减去 1),结果保存到 Rd 中。指令格式如下:

SCB{cond}{S}Rd,Rn,operand2

SBC 指令举例如下

推荐阅读