基于ARM Cortex-M3微控制器(STM32系列)基础知识(三)——ARM指令集

指令概述

在这里插入图片描述

ARM指令

在这里插入图片描述

STR与LDR概述(详细在本文的数据加载与存储指令中)

在这里插入图片描述

数据操作指令

数据操作指令是指对存放在寄存器中的数据进行操作的指令。主要包括数据传送指令、算术指令、逻辑指令、比较与测试指令及乘法指令。如果在数据处理指令后使用“S”后缀,指令的执行结果将会影响CPSR中的标志位。数据处理指令的基本语法格式如下:

< opcode > {< cond >} {S} < Rd >,< Rn >,< shifter_operand >

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

指令的可选后缀

S后缀

在这里插入图片描述
在这里插入图片描述

!后缀

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
即该指令相当于
在这里插入图片描述

指令的条件执行

在这里插入图片描述

条件码

在这里插入图片描述
在这里插入图片描述

两种后缀同时存在时,S排后面

在这里插入图片描述
在这里插入图片描述

其他后缀

(1)字长后缀

在这里插入图片描述

(2)索引后缀和堆栈后缀

在这里插入图片描述

T后缀

在这里插入图片描述

cortex-M3指令

在这里插入图片描述

“统一汇编语言(UAL)”语法机制

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
解析:

LDR命令,将存储器地址所指地址处连续的4个字节(1个字)的数据传送到目的寄存器中。内存中的值是不会改变的。 故C

ARM寻址方式

所谓寻址,就是要找存放某个东西的位置
在这里插入图片描述
数据处理指令寻址方式可以分为以下几种:

  • (1)立即数寻址方式。
  • (2)寄存器寻址方式。
  • (3)寄存器移位寻址方式。

立即寻址:就是在让你做事的时候,同时把你要用的东西也给你,也是不用你忙活着去找。

指令中的立即数是由一个8bit的常数移动4bit偶数位(0,2,4,…,26,28,30)得到的,所以,每一条指令都包含一个8bit的常数X和移位值Y,得到的立即数=X循环右移(2×Y)
在这里插入图片描述
下面列举了一些有效的立即数:
0xFF、0x104、0xFF0、0xFF00、0xFF000、0xFF000000、0xF000000F。

下面是一些无效的立即数:
0x101、0x102、0xFF1、0xFF04、0xFF003、0xFFFFFFFF、0xF000001F。
在这里插入图片描述
在以下两条指令中,第二个源操作数即为立即数,要求以“#”为前缀,对于以十六进制表示的立即数,还要求在“#”后加上“0x”或“&”。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

立即数生成方式(循环左移右移)

在这里插入图片描述
在这里插入图片描述

直接寻址:就是告诉你储物柜的号码,你自己去该储物柜里把东西拿出来用。

mov 寄存器,[偏移地址]
mov [偏移地址],寄存器

在这里插入图片描述

寄存器寻址:就是有几个固定的门房收发室,你找门房问,就能告诉你储物柜的号码,然后就能从储物柜拿到东西。

寄存器的值可以被直接用于数据操作指令,这种寻址方式是各类处理器经常采用的方式,利用寄存器中的数值作为操作数,也是一种执行效率较高的寻址方式。例如以下指令:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

寄存器间接寻址:还是去找门房,问到储物柜号码,然后去打开储物柜一看,里面是个纸条,纸条上说东西在另一个储物柜,号码是XXX。

在这里插入图片描述
在这里插入图片描述
寄存器间接寻址就是以寄存器中的值作为操作数的地址,而操作数本身存放在存储器中。例如以下指令:
在这里插入图片描述
在第一条指令中,以寄存器R2的值作为操作数的地址,在存储器中取得一个操作数后与R1相加,结果存入寄存器R0中。

第二条指令将以R1的值为地址的存储器中的数据传送到R0中。

第三条指令将R0的值传送到以R1的值为地址的存储器中。
在这里插入图片描述

寄存器移位寻址方式

寄存器的值在被送到ALU之前,可以事先经过桶形移位寄存器的处理。预处理和移位发生在同一周期内,所以有效地使用移位寄存器,可以增加代码的执行效率。下面是一些在指令中使用了移位操作的例子:
在这里插入图片描述
在这里插入图片描述
Rm,shift—寄存器移位方式
将寄存器的移位结果作为操作数(移位操作不消 耗额外的时间),但Rm值保持不变。
在这里插入图片描述
逻辑右移和算术右移的区别:
在这里插入图片描述

基址变址寻址

基址变址寻址就是将寄存器(该寄存器一般称为基址寄存器)的内容与指令中给出的地址偏移量相加,从而得到一个操作数的有效地址。变址寻址方式常用于访问某基地址附近的地址单元。采用变址寻址方式的指令常见有以下几种形式,如下指令所示:

重要!!!

在这里插入图片描述
在第一条指令中,将寄存器R1的内容加上4形成操作数的有效地址,从而取得操作数存入寄存器R0中。

在第二条指令中,将寄存器R1的内容加上4形成操作数的有效地址,从而取得操作数存入寄存器R0中,然后,R1的内容自增4个字节。

在第三条指令中,以寄存器R1的内容作为操作数的有效地址,从而取得操作数存入寄存器R0中,然后,R1的内容自增4个字节。

在第四条指令中,将寄存器R1的内容加上寄存器R2的内容形成操作数的有效地址,从而取得操作数存入寄存器R0中。
在这里插入图片描述

多寄存器寻址

采用多寄存器寻址方式,一条指令可以完成多个寄存器值的传送。这种寻址方式可以用一条指令完成传送最多16个通用寄存器的值。例如以下指令:
在这里插入图片描述
该指令的后缀IA表示在每次执行完加载/存储操作后,R0按字长度增加,因此,指令可将连续存储单元的值传送到R1~R4。

多寄存器寻址一次可传送几个寄存器值,该寻址方 式中一条指令最多可传送16个通用寄存器的值。连 续的寄存器间用“-”连接,否则用“,”分隔
在这里插入图片描述
在这里插入图片描述

相对寻址

与基址变址寻址方式相类似,相对寻址以程序计数器PC的当前值为基地址,指令中的地址标号作为偏移量,将两者相加之后得到操作数的有效地址。以下程序段完成子程序的调用和返回,跳转指令BL采用了相对寻址方式:
在这里插入图片描述
在这里插入图片描述

堆栈寻址

在这里插入图片描述
在这里插入图片描述

Cortex-M3支持的Thumb-2指令集

在这里插入图片描述

数据处理指令

在这里插入图片描述

数据传送指令

在这里插入图片描述

MOV指令

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

MVN指令

MVN是反相传送(Move Negative)指令,它将操作数的反码传送到目的寄存器,多用于向寄存器传送一个负数或生成位掩码。
在这里插入图片描述
在这里插入图片描述

移位指令(包括5种)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.LSL逻辑左移(无符号)

在这里插入图片描述
在这里插入图片描述

例题(第二题是进位)

在这里插入图片描述
分析:
R1 = 0x80000004,而LSL #1就是左移一位,那么把R1由十六进制数转换为二进制数,即R1 = 1000 … 0100,左移一位,则R1 = 0000 … 1000,所以R0 = 0x00000008,R1保持不变
在这里插入图片描述

2.LSR逻辑右移(无符号)

在这里插入图片描述
在这里插入图片描述

例题

在这里插入图片描述

3.ASR算术右移

在这里插入图片描述
在这里插入图片描述

4.ROR循环右移

在这里插入图片描述

算术指令

在这里插入图片描述

1. ADD 加法指令

在这里插入图片描述

例题

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2. ADC带进位加法指令

在这里插入图片描述

3. SUB减法指令

在这里插入图片描述

4. SBC 带借位减法指令

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5. RSB 逆向减法指令

在这里插入图片描述

逻辑运算指令

在这里插入图片描述

1. AND 逻辑与指令

在这里插入图片描述

2. ORR 逻辑或指令

在这里插入图片描述
在这里插入图片描述

3. EOR 逻辑异或指令

在这里插入图片描述
在这里插入图片描述

4. BIC 位清除指令

BIC(Bit Clear)位清零指令将寄存器Rn的值与第二个源操作数shifter_operand的值的反码按位做逻辑与操作,并将结果保存到目标寄存器Rd中。
在这里插入图片描述
在这里插入图片描述

比较指令

在这里插入图片描述

1. CMP比较指令

在这里插入图片描述

2. CMN反值比较指令

在这里插入图片描述

3. TST位测试指令

在这里插入图片描述
与CMP指令一样,该指令不需要指定S后缀。

4. TEQ相等测试指令

在这里插入图片描述
使用TEQ进行相等测试,常与EQ和NE条件码配合使用,当两个数据相等时,条件码EQ有效;否则条件码NE有效。

乘法和乘加指令

在这里插入图片描述

注意事项

在这里插入图片描述

1. MUL 32位乘法指令

在这里插入图片描述

2. MLA 32位乘加指令

在这里插入图片描述

3. SMULL 64位有符号数乘法指令

在这里插入图片描述

4. SMLAL 64位有符号数乘加指令

在这里插入图片描述

5. UMULL 64位无符号数乘法指令

在这里插入图片描述

6. UMLAL 64位无符号数乘加指令

在这里插入图片描述

乘法指令–注意事项

在这里插入图片描述
在这里插入图片描述

数据加载与存储指令

在这里插入图片描述
ARM处理器对存储器的访问只能通过加载和存储指令。

1. 数据加载与存储的方向

在这里插入图片描述

2. 数据加载/存储指令的寻址(LDR和STR)

在这里插入图片描述
在这里插入图片描述

LDR指令

LDR指令用于从指定地址的内存中读取一个32位的字到目标寄存器。
在这里插入图片描述

STR指令

STR指令用于将一个32位的字数据写入到指令中指定的内存单元。

3. 地址索引(前索引、自动索引、后索引)

在这里插入图片描述
在这里插入图片描述

不同索引方式的区别

在这里插入图片描述

单数据访存指令

在这里插入图片描述
在这里插入图片描述

单寄存器加载与存储指令

在这里插入图片描述
在这里插入图片描述

例题

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

【注意事项】

在这里插入图片描述
在这里插入图片描述

多寄存器加载与存储指令

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

例题★

在这里插入图片描述

堆栈操作

在这里插入图片描述
在这里插入图片描述
堆栈是一种数据结构,按先进后出(First In Last Out,FILO)的方式工作,使用一个称为堆栈指针的专用寄存器指示当前的操作位置,堆栈指针总是指向栈顶。

ARM微处理器所支持的批量数据加载/存储指令可以一次在一片连续的存储器单元和多个寄存器之间传送数据,批量加载指令用于将一片连续的存储器中的数据传送到多个寄存器,批量数据存储指令则完成相反的操作。

LDM(或STM)指令的格式为:
在这里插入图片描述
LDM(或STM)指令用于从基址寄存器所指示的一片连续存储器到寄存器列表所指示的多个寄存器之间传送数据,该指令的常见用途是将多个寄存器的内容入栈或出栈。

堆栈的操作包括: 建栈、进栈、出栈三种基本操作。

(1)建栈

在这里插入图片描述

(2)进栈

在这里插入图片描述
当堆栈指针指向最后压入堆栈的数据时,称为满堆栈(Full Stack),而当堆栈指针指向下一个将要放入数据的空位置时,称为空堆栈(Empty Stack)。

同时,根据堆栈的生成方式,又可分为递增堆栈(Ascending Stack)和递减堆栈(Decending Stack),当堆栈由低地址向高地址生成时,称为递增堆栈当堆栈由高地址向低地址生成时,称为递减堆栈。

这样就有4种类型的堆栈工作方式,ARM微处理器是支持基于堆栈操作的,其Rn寄存器为R13(SP)栈指针寄存器4种类型的堆栈工作方式,即:

堆栈寻址(满递增堆栈、满递减堆栈、空递增堆栈、空递减堆栈)

  • 满递增堆栈(FA):堆栈指针指向最后压入的数据,且由低地址向高地址生成。
  • 满递减堆栈(FD):堆栈指针指向最后压入的数据,且由高地址向低地址生成。
  • 空递增堆栈(EA):堆栈指针指向下一个将要放入数据的空位置,且由低地址向高地址生成。
  • 空递减堆栈(ED):堆栈指针指向下一个将要放入数据的空位置,且由高地址向低地址生成。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

STMFD SP!,{R0-R7,LR}
在这里插入图片描述
先是sp = sp - 4,然后LR进栈,然后sp = sp - 8,R7进栈,接下来依次类推

提示

在这里插入图片描述
{!}为可选后缀,若选用该后缀,则当数据传送完毕之后,将最后的地址写入基址寄存器,否则基址寄存器的内容不改变。

基址寄存器不允许为R15,寄存器列表可以为R0~R15的任意组合。{∧}为可选后缀,当指令为LDM且寄存器列表中包含R15,选用该后缀时表示:除了正常的数据传送之外,还将SPSR复制到CPSR。同时,该后缀还表示传入或传出的是用户模式下的寄存器,而不是当前模式下的寄存器。

STMFD (Push) 块存储- Full Descending stack [STMDB]
LDMFD (Pop) 块装载- Full Descending stack [LDMIA]

(3)出栈

例题★

在这里插入图片描述
在这里插入图片描述
小案例:
在这里插入图片描述

分支指令(B、BL、BX、BLX)

在这里插入图片描述
在这里插入图片描述

分支指令B(B、BEQ、NE)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

带返回的分支指令BL

BL是另一个跳转指令,但在跳转之前,会在寄存器R14中保存PC的当前内容,因此,可以通过将R14的内容重新加载到PC中,来返回到跳转指令之后的那个指令处执行。该指令是实现子程序调用的一个基本但常用的手段。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

例题

在这里插入图片描述
顺序为:ACDEGHIFBJ

带返回和状态切换的分支指令BLX

BLX指令从ARM指令集跳转到指令中所指定的目标地址,并将处理器的工作状态由ARM状态切换到Thumb状态,该指令同时将PC的当前内容保存到寄存器R14中。因此,当子程序使用Thumb指令集,而调用者使用ARM指令集时,可以通过BLX指令实现子程序的调用和处理器工作状态的切换。同时,子程序的返回可以通过将寄存器R14值复制到PC中来完成。
在这里插入图片描述
在这里插入图片描述

程序状态寄存器访问指令

在这里插入图片描述

1、状态寄存器到通用寄存器的传送指令(MRS)

在这里插入图片描述
在这里插入图片描述

2、通用寄存器到状态寄存器的传送指令(MSR)

在这里插入图片描述
在这里插入图片描述

例题

在这里插入图片描述

课后测试一

1、

在这里插入图片描述
解析:

由于ADD没有S,所以CPSR的Z不变,Z = 0,
R4 = R3 + 1 = 7

故答案为7;0

2、

在这里插入图片描述
因为Z = 1,所以数为0,执行ADDEQ R4,R3, #1

所以R4 = R3 + 1 = 7

故答案为7;1

3、

在这里插入图片描述
R4 = R3 + 1 = 0
Z = 1

故答案为0;1

4、

在这里插入图片描述
R4 = R0 + R2 = -1 + 4 = 3
Z = 0

故答案为3;0

课后测试二

1、

在这里插入图片描述
解析:

(1)LDR R3,[R4,#8]
前索引,寄存器间接寻址,所以R3 = [0x2008] = 0x55667788,R4 = 0x2000

(2)LDR R3,[R4,#8]!
自动索引,因为有!后缀,所以基址寄存器的地址发生变化,R3 = 0x55667788,R4 = 0x2008

(3)LDR R3,[R4],#8
后索引,所以R3 = 0x11223344,R4 = 0x2008

2、

在这里插入图片描述
解析:

(1)
BD
(2)
R2左移2位,我们先将R2的十六进制转化为二进制,0001左移后变为0100(就针对1那个值看,不然我前面要写好多个0,给你们看也不够直观),所以R2 = 0x0004
在这里插入图片描述
而这个加法指令对应第二种格式,所以R1 = 0x1000 + 0x0004 = 0x1004

3、

在这里插入图片描述
答案:BE

4、

在这里插入图片描述
解析:

(1)
LDMIA为出栈,所以R2 = [原R1(0x2000)] = 0x11
R3 = [原R1 + 4] = 0x22
R1 = 原R1(0x2000) + 8 = 0x2008

(2)
STMIA为进栈,R2和R3依次进栈,所以R2和R3不变,分别为R2 = 0x3000,R3 = 0x3004,R1 = 0x2000 + 4 * 2 = 0x2008,

乘法指令

1、

在这里插入图片描述
解析:

目的寄存器Rd和操作数Rm必须是不同的寄存器

故选CD

2、

在这里插入图片描述
解析:

Rs必须是通用寄存器,而不是立即数

故选E

3、

在这里插入图片描述
答案F

4、

在这里插入图片描述
解析:

两种后缀同时存在时,S排后面

故选B

5、

在这里插入图片描述
解析:

因为Rdlo、Rdhi和Rm必须使用不同的寄存器

故选DE

6、

在这里插入图片描述
故选F

7、

在这里插入图片描述

解析:

因为不能对操作数使用立即数

故选E

指令系统测试

1、

在这里插入图片描述
解析:

MOV R8, #0x05
//R8 = 0x05
MOV R5,#0x08
//R5 = 0x08
CMP R8,#10
//R8 - 10 < 0所以执行ADDMI语句
//R6 = R5 + 0x07 = 0x0F
MOVS R3,#0
//R3 = 0,且Z = 1
MOV R2,#0x20
//R2 = 0x20
SUB R3,R2,R8
//R3 = R2 - R8 = 0x20 - 0x05 = 0x1B
//因为Z = 1,所以执行ADDEQ语句
R3 = R2 + R5 = 0x20 + 0x08 = 0x28

故答案为0x05,0x0F,0x1B,0x28

2、

在这里插入图片描述
解析:

MOV R1,#0x08
MOV R3,#0x10
//R1 = 0x08,R3 = 0x10
CMP R1,#10
//R1 - 10 < 0所以执行SUBMI指令
R3 = R3 - 0x07 = 0x09
MOVS R0,#0
//R0 = 0,Z = 1
MOV R4,#0x20
//R4 = 0x20
SUB R3,R4,R1
//R3 = R4 - R1 = 0x20 - 0x08 = 0x18
//因为Z = 1,所以ADDNE不执行

故答案为0x08;0x09;0x18;0x0

判断题

在这里插入图片描述
解析:

(1)错,自动索引[R4,…]
(2)错,去掉!
(3)错,!放在R6
(4)对,满递减堆栈出栈
(5)对
(6)错,循环右移不是偶数位
(7)对
(8)错,立即数超出限定范围
(9)错,操作数只能是两个
(10)错,不能用程序计数器R15,还有应该是四个操作数(因为有移位寻址),否则就应是三个操作数
(11)错,
(12)对
(13)错,因为#0x001应该改为通用寄存器
(14)错,因为Rd不能同时为Rm
(15)错,不能使用立即数,应用寄存器
(16)错,应该去掉!
在这里插入图片描述
(17)错,R6去掉
(18)错,R15换掉
(19)错,PC换为其他寄存器
(20)错,#0x101非法
(21)错,无STRSH,把SH删掉

如果喜欢我的文章,请记得三连哦,点赞关注收藏,你的每一个赞每一份关注每一次收藏都将是我前进路上的无限动力 !!!↖(▔▽▔)↗感谢支持,下期更精彩!!!

猜你喜欢

转载自blog.csdn.net/qq_44631615/article/details/118471289