0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何编写ARM指令集中的基本汇编指令

嵌入式星球 2020-10-10 09:24 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

了解用于编程ARM内核的ARM指令集中使用的一些基本指令。
本文旨在帮助您了解有关ARM核心编程的基本汇编指令。
我们将从上一篇有关ARM寄存器文件的文章中摘录-请在继续之前考虑一下该信息,因为我们将在下面的说明中引用寄存器符号和寄存器标志。
下一篇文章将使用此信息来编程使用32位ARM内核的Raspberry Pi。在本文中,我们将重点放在32位ARMv7指令和32位寄存器上。
注意:运行Raspbian的Raspberry Pi的更高版本使用64位ARMv8处理器,但与旧版v7一样,以32位模式运行。我们可能会在以后的文章中介绍ARMv8。

机器码

指令由处理器使用-让我们看一下指令所代表的机器代码。由于我们要讲的大部分指令都是关于数据操作的,因此我从ARMV7手册中获取了数据处理指令。


图1.ARM数据处理指令

图1显示了ARM数据处理指令中的32位;每个位都有特定的用途,可以单独使用,也可以作为一组使用。

条件字段为4位宽,因为大约有十五个条件代码。操作码为4位宽,位于立即信号和条件设置标志之间,该信号指示操作数2保持一个立即值,而条件设置标志可用于在操作期间更新状态寄存器(稍后会详细介绍)。注意,由操作码确定处理器将执行的操作(例如加法,减法或异或)。

当您浏览下面的指令时,我们将参考图1并尝试查看汇编指令如何被编码为二进制。并且不要害怕深入阅读ARM手册以获取更多信息。

如何阅读汇编说明:助记符和操作数

每条指令均以代表操作的助记符开头。助记符后面是将要操作的操作数。这些通常是目标操作数和源操作数,如下所示。


MNEMONIC DEST, SRC1, SRC2


ADD指令(在下面的部分中介绍)将R2加到R1并将结果放入寄存器R0中(有关这些符号的说明,请参见上一篇文章)。这是读取汇编指令的典型方法。将R2加到R1并将其(结果)放入R0。将在ADD指令旁边显示将在处理器上执行的等效机器代码。

“条件”字段包含始终执行的“ 1110”。这些位在使用附加到ADD操作的条件后缀时起作用。下一个字段未使用且设置为零。“ I”字段为零,因为“ Op2”是一个寄存器,而不是立即数。“ S”字段为零,因为我们没有将S附加到ADD操作上,也就是说,我们不希望该指令更新状态寄存器标志(如上所述的N,Z,C和V)。

如果您再次参考图1,请注意要添加的操作码。0100b。这告诉处理器设置ADD操作的数据路径。最后三个字段是R1(0001b),R0(0000b)和R2(….0010b)。


Cond I OpCd SRn Rd Op2

ADD R0,R1, R2 @ 1110|00|0|0100|0|0001|0000|000000000010


指令中的操作数通常是寄存器,但它们也可以是内存地址或立即数。立即值是要使用的确切数字。这些前缀有#符号。例如,我们可以使用立即数42代替上面的R2。该指令如下所示:


Cond I OpCd SRn Rd Op2

ADDS R4, R6, #42 @ 1110|00|1|0100|1|0110|0100|000000101010


该指令将42加到R6并将结果放入R4。这次围绕“ I”设置为1的原因是,我们将立即数用于操作数2。操作码保持不变,因为我们仍在进行加法运算。请注意,“ S”字段为1;因此,我们希望此ADD操作在执行期间更新状态寄存器标志。

下一条指令可以使用“条件”字段检查状态标志,并根据结果有条件地执行。'Rn'是0110b,代表R6,而'Rd'是0100b对于R4。“ Op2”中的立即数是数字42的12位二进制表示形式。本节的其余部分列出了最基本的ARM指令的子集,并提供了简短说明和示例。

数据处理说明以下说明处理数据。这可以是执行数学功能的算术运算,比较运算或数据移动。

加法(ADD)加法(ADD)将R2加到R1并将结果放入R0。带进位加法(ADC)将R2与进位标志一起加到R1。在处理大于单个32位字的数字时使用此功能。

ADD R0, R1, R2
ADC R0, R1, R2

减法(SUB减法(SUB)从R1减去R2并将结果放入R0。进位减法(SBC)从R1中减去R2,如果清除了进位标志,则从结果中减去1。这等效于算术借用,并确保多字减法正确工作。

SUB R0,R1,R2
SBC R0,R1,R2

比较(CMP)和比较负数(CMN)比较(CMP)和比较负数(CMN)比较两个操作数。CMP从R0中减去R1,CMN将R2与R1相加,然后根据加法或减法的结果更新状态标志。

CMP R0,R1
CMN R1,R2

移动(MOV)“移动(MOV)”操作确实像听起来那样。它将数据从一个地方移到另一个地方。下面,将R1复制到R0。第二行将立即数8放入R0。

MOV R0,R1
MOV R0,#8

移负(MVN)负向移动(MVN)执行类似的操作,但先对数据进行补充(取反)。当执行带有负数的操作时,尤其是使用二进制补码时,这很有用。以下指令将NOT 8(通常称为–9)放入R0。将一个加到该结果中,您便完成了两个的补数并获得了-8。

MVN R0,#8

AND执行R2和R1的按位与运算,并将结果放入R0。可以使用立即数代替R2。

AND R0,R1,R2

ORR和EORORR和EOR分别执行R2和R1的按位OR和XOR。

ORR R0,R1,R2
EOR R0,R1,R2

位清除(BIC)位清除(BIC)对R2和R1执行按位与,但首先对R2中的位进行补充。此操作通常与立即数一起使用,如第二行所示,立即数0xFF取反,然后与R1进行“与”运算。将八个零与R1的第一个字节进行“与”运算将清除这些位,即,将它们设置为零,然后将结果放入R0。

BIC R0,R1,R2
BIC R0,R1,#0xFF

测试位(TST)和测试当量(TEQ)存在TeST位(TST)和测试等效项(TEQ)以测试位于寄存器中的位。这些指令不使用目标寄存器,而只是根据结果更新状态寄存器。TST本质上执行两个操作数的按位与。通过为操作数2使用掩码,我们可以测试R0中是否设置了单个位。
在这种情况下,我们检查第3位(位掩码= 1000b = 8),然后根据结果设置Z标志。TEQ与排他或执行类似的功能,非常适合检查两个寄存器是否相等。这将更新N和Z标志,因此它也适用于带符号的数字。如果它们的符号不同,则将N设置为1。

TST R0, #8
TEQ R1, R2

乘法(MUL)乘法(MUL)将R1乘以R2并将结果存入R0。乘法不能与立即数一起使用。

MUL R0,R1,R2
移位和旋转说明逻辑左移(LSL)逻辑左移(LSL)将R1中的位移位一个移位值。在这种情况下,立即数为3,并丢弃最高有效位。移出的最后一位放入进位标志,最低有效位用零填充。在下面,R1向左移动立即数3,即R2中的0到31之间的一个值,然后放入R0。逻辑左移一个值乘以2。这是进行简单乘法的廉价方法。

LSL R0,R1,#3
LSL R0,R1,R2

逻辑右移(LSR)逻辑右移(LSR)与LSL以相反的方式工作,并且有效地将一个值除以2。最高有效位用零填充,最后最低有效位放入进位标志。

LSR R0,R1,#2

算术右移(ASR)算术右移(ASR)执行与LSR相同的工作,但设计用于带符号的数字。它将符号位复制回左侧的最后一个位置。

ASR R0,R1,#4

向右旋转(ROR)向右旋转(ROR)将一个单词中的所有位旋转一个值。无需将左侧的位填充零,只需将移出的位放回另一端即可。

ROR R0,R1,#5
分支操作说明处理器的一项重要功能是能够基于一组输入在两个代码路径之间进行选择的能力。这正是分支操作所要做的。处理器通常通过将程序计数器(PC)R15递增四个字节(即,一条指令的长度)来执行一条指令。分支将PC更改为另一个标签,该标签表示代表汇编代码的那部分。

支(B)分支(B)将PC移至标签指定的地址。标签(下面的示例中的“循环”)代表您希望处理器接下来执行的一段代码。标签只是文本,通常是一个有意义的词。

B loop

分支链接(BL)分支链接(BL)执行类似的操作,但是它将下一条指令的地址复制到链接寄存器(LR)R14中。这在执行子例程/过程调用时非常有用,因为一旦标签上的代码部分完成,我们就可以使用LR返回分支。在下面,我们跳转到标签“子例程”,然后使用链接寄存器返回下一条指令。

BL subroutine



subroutine:


MOV PC, LR

我们使用mov指令将链接寄存器放回程序计数器。这将使程序返回到我们子程序调用之后的位置,此处标记为。注意上面的LR和PC的使用。ARM汇编器分别将它们识别为R14和R15。这样可以方便地提醒程序员有关正在执行的操作。
加载和存储说明计算机的内存存储处理器所需的数据。通过使用地址访问此数据。首先将地址放入寄存器,然后我们可以访问该地址的数据。这就是为什么我们使用加载和存储操作。

加载寄存器(LDR)加载寄存器(LDR)将位于某个地址的数据加载到目标寄存器中。R1周围的括号表示该寄存器包含一个地址。通过使用括号,我们将位于该地址的数据(而不是地址本身)放入R0。我们还可以使用这种表示法来定位与某个地址的数据偏移量,如第二行所示。R0将包含与地址R1所包含的内容相距两个字的数据。

LDR R0,[R1]
LDR R0,[R1,#8]

我们还可以使用标签表示地址,然后可以将相应的数据加载到寄存器中。下面的第一行将标签“ info”的地址加载到R0中。然后访问存储在该地址的值,并将其放入第二行的R1中。

LDR R0, =info
LDR R1, [R0]

商店(STR)存储(STR)执行补充操作以加载。STR将寄存器的内容放入存储位置。下面的代码将数据存储在R1中R0的地址处。同样,方括号表示R0拥有一个地址,我们希望修改该地址上的数据。

STR R1,[R0]

加载和存储类型:字节(B),半字(H),字(略),有符号(SB),无符号(B)加载和存储都可以使用附加的类型编写。此类型表示指令将操作字节(B),半字(H)还是字(忽略),以及数据是带符号的(SB)还是无符号的(B)。
一个方便的地方是用于字符串操作,因为ASCII字符的长度为一个字节。这些操作还允许在加载或存储时使用偏移量,如最后一行所示。

LDR R0, =text @ load a 32 bit address into R0
STRB R1, [R0] @ store byte at address in memory

STRB R1, [R0, + R2] @ store byte at address + offset R2

如前所述,指令中使用的助记符可以附加可选的条件代码。这允许条件执行。
请记住,这些标志(如前面的文章中布局)是Z(ŽERO),C(ÇARRY),N(Ñegative)和V(OveRFlow)。
为了强制指令更新状态寄存器,可以将一个可选的S附加到迄今为止提到的大多数助记符中。更新状态寄存器后,可以使用以下条件后缀(如下所示)来控制指令是否执行。这些后缀的二进制代码对应于上面显示的数据处理指令的前四位(请参见图1)。


图2.条件后缀
在编写汇编时,这些后缀将附加到助记符。下面的清单显示了前面提到的说明中使用的一些条件后缀。
由于我们将在下一篇文章中使用GNU汇编器进行汇编,因此我们需要使用@符号表示注释。

.global _start

start:
MOV R0, #3 @ Put the value 3 into R0
MOV R1, #0 @ Put the value 0 into R1

loop:
CMP R0, R1 @ Compare R1 to R0 (effectively R0 minus R1)
BEQ done @ If they are equal (Z=1) branch to done label
ADDGT R1, #1 @ If R0 is greater than R1 add 1 to R1
SUBLT R1, #1 @ If R0 is less than R1 subtract 1 from R1
B loop @ Branch back and re-run loop

done:

@ do other stuff




希望本文能使你对用于编程ARM内核的基本指令有基本的了解。在下一篇文章中,我们将在一个使用Raspberry Pi编程内核的简单示例中使用此知识。


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • ARM
    ARM
    +关注

    关注

    135

    文章

    9499

    浏览量

    388663
  • 汇编指令
    +关注

    关注

    0

    文章

    38

    浏览量

    11795
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    采用汇编指示符来使用自定义指令

    具体实现 1、采用.word .half .dword等汇编指示符直接插入自定义指令,这种方法需要自己指定寄存器。其中.word为插入一个字的数据即32位,.half为插入半字即16位
    发表于 10-28 06:02

    指令集测试的一种纠错方法

    本文描述在进行指令集测试的一种纠错方法 1.打开测试指令集对应的dump文件 dump文件是指由汇编文件进行反汇编之后,可以供人阅读指令
    发表于 10-24 14:04

    浮点扩展指令集中定义的五种舍入模式

    本文主要描述浮点扩展指令集中定义的五种舍入模式,并介绍一些实现时要注意的地方。 舍入模式介绍 首先,在riscv-spec-v2.2的浮点指令集扩展部分一共定义了五种不同的舍入模式,如下
    发表于 10-24 10:25

    通过内联汇编调用乘法指令mulh\\mulhsu\\mulhu

    1.蜂鸟E203内核支持的乘法指令有四种(不含融合指令),分别为mul、mulh、mulhu与mulhsu。它们的汇编语言格式如下: mulrd,rs1, rs2 将两个32位整数相乘,取低
    发表于 10-24 06:52

    Vector向量指令集简介(一)

    3位标识数据位宽,高两位指示数据类型。 指令的类型由vetype的值进行标记,如果将vetype设为00000则会禁用向量寄存器。 对于vector指令集来说,有一些必须要明白的名词需要搞懂
    发表于 10-23 08:28

    risc-v P扩展(一) P指令集简介

    解码、医学成像、计算机视觉、嵌入式控制、机器人技术、人机界面等。 P指令集扩展提高了RISC-V CPU IP产品的DSP算法处理能力。随着RISC-V P指令集扩展的增加,RISC-Vcpu现在可以以
    发表于 10-23 07:40

    RISCV-K指令集扩展分享

    RISC-V K扩展指的是RISC-V用于提升密码学算法的速度、减小应用程序大小的一个扩展指令集。主要包含了:AES加密算法的加速指令、SHA算法的加速指令,SM3、SM4算法的加速指令
    发表于 10-23 06:12

    Whetstone代码涉及的浮点指令汇编分析

    对benchmark中的whetstone进行代码分析,通过反汇编统计所出现的浮点指令,共有26种,如下 特点是只涉及单精度的浮点指令,并且存在有浮点Load/Store的压缩指令
    发表于 10-22 08:11

    RVF单精度浮点指令集扩展介绍(2)

    RVF单精度浮点指令集扩展 RVF扩展了26条浮点指令。 浮点乘加指令 浮点比较、最大最小值、转移、符号注入、分类指令 浮点除、开方
    发表于 10-22 07:26

    指令集P扩展的主要内容

    1. 指令集P扩展的主要内容 新指令的添加,在蜂鸟E203原有指令集的基础上,可以添加一些新的指令,以满足新的应用需求;指令集扩展,在原有
    发表于 10-21 10:50

    基于蜂鸟E203架构的指令集K扩展

    需要硬件支持,因此需要对蜂鸟E203架构进行一定的修改和升级。此外,还需要编写相应的编译器和工具链,以支持K扩展指令集的编译和调试。
    发表于 10-21 09:38

    TMS320C54x DSP助记指令集参考集第2卷

    电子发烧友网站提供《TMS320C54x DSP助记指令集参考集第2卷.pdf》资料免费下载
    发表于 12-24 16:58 0次下载
    TMS320C54x DSP助记<b class='flag-5'>指令集</b>参考集第2卷

    TMS320C55x DSP代数指令集参考指南

    电子发烧友网站提供《TMS320C55x DSP代数指令集参考指南.pdf》资料免费下载
    发表于 12-24 16:20 0次下载
    TMS320C55x DSP代数<b class='flag-5'>指令集</b>参考指南

    《RISC-V 体系结构编程与实践(第2版)》指令集

    本书的指令集基于rv64i mafdcsiu 属于精简指令集。 阅读本章可以指令集不多,都是最基础的功能点。 分为6个部分 加载保存指令 跳转指令
    发表于 12-07 18:36

    TAS3108/TAS3108IA音频DSP指令集

    电子发烧友网站提供《TAS3108/TAS3108IA音频DSP指令集.pdf》资料免费下载
    发表于 12-07 14:32 0次下载
    TAS3108/TAS3108IA音频DSP<b class='flag-5'>指令集</b>