【机器学习智能硬件开发全解】(六)—— 政安晨:通过ARM-Linux掌握基本技能【认知准备:体系结构与汇编指令】

本文主要是介绍【机器学习智能硬件开发全解】(六)—— 政安晨:通过ARM-Linux掌握基本技能【认知准备:体系结构与汇编指令】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

ARM-Linux体系是指基于ARM架构的Linux操作系统体系,其它常见的体系还有x86-Linux体系等。ARM架构是一种常用于移动设备和嵌入式系统的处理器架构,如手机、平板电脑、智能手表等都广泛使用ARM处理器。

ARM-Linux体系基于Linux开源操作系统,并针对ARM架构进行了优化和适配。它包括了Linux内核和一系列基于Linux的工具和库,提供了完整的操作系统功能和开发环境,可以运行在各种ARM架构的设备上。

ARM-Linux体系具有以下特点:

  1. 轻量化:ARM-Linux体系针对嵌入式设备进行了优化,具有较小的内存和存储需求,可以运行在资源受限的设备上。
  2. 开源:ARM-Linux体系基于Linux开源操作系统,具有强大的社区支持和生态系统,开发者可以通过共享和交流获得更多资源和技术支持。
  3. 易于开发:ARM-Linux提供了完善的开发工具链和开发环境,开发者可以使用C/C++等常用编程语言进行开发,并且可以方便地移植和调试应用程序。
  4. 广泛应用:ARM架构在移动设备、智能家居、工业控制、自动驾驶等领域具有广泛应用,ARM-Linux体系可以满足各种不同应用场景的需求。

总结起来ARM-Linux体系是一种适用于ARM架构设备的Linux操作系统体系,具有轻量化、开源、易于开发和广泛应用等特点。它为开发者提供了一个强大的开发平台,可以快速构建和部署各种ARM设备上的应用程序。


政安晨的个人主页政安晨

欢迎 👍点赞✍评论⭐收藏

收录专栏机器学习智能硬件开发全解

希望政安晨的博客能够对您有所裨益,如有不足之处,欢迎在评论区提出指正!



在嵌入式开发领域,ARM架构的处理器占了80%以上的市场份额,大多数人学习嵌入式都是从ARM开始的。

目标

一是以ARM汇编指令为媒介,深入了解ARM体系结构和工作流程

二是掌握ARM汇编程序的编写技巧,能看懂反汇编代码,为后面基于C语言的ARM-Linux人工智能编程实践打下基础

基于这个现实背景,咱们这篇文章将带领大家在了解ARM体系结构的基础上,学习一下ARM常用的一些汇编指令。

ARM体系结构

计算机的指令集一般可分为4种

复杂指令集(CISC)、

精简指令集(RISC)、

显式并行指令集(EPIC)、

超长指令字指令集(VLIW)。

我们在嵌入式学习和工作中需要经常打交道的是RISC指令集

RISC指令集相对于CISC指令集主要有以下特点

● Load/Store架构,CPU不能直接处理内存中的数据,要先将内存中的数据Load(加载)到寄存器中才能操作,然后将处理结果Store(存储)到内存中。

● 固定的指令长度、单周期指令。

● 倾向于使用更多的寄存器来存储数据,而不是使用内存中的堆栈,效率更高。

ARM指令集虽然属于RISC,但是和原汁原味的RISC相比,还是有一些差异的,具体如下。

ARM指令集虽然属于RISC,但是和原汁原味的RISC相比,还是有一些差异的,具体如下:

● ARM有桶型移位寄存器,单周期内可以完成数据的各种移位操作。

● 并不是所有的ARM指令都是单周期的。

● ARM有16位的Thumb指令集,是32位ARM指令集的压缩形式,提高了代码密度。

● 条件执行:通过指令组合,减少了分支指令数目,提高了代码密度。

● 增加了DSP、SIMD/NEON等指令。

ARM处理器有多种工作模式,如下表所示:

ARM处理器的不同工作模式

应用程序正常运行时,ARM处理器工作在用户模式(User mode),当程序运行出错或有中断发生时,ARM处理器就会切换到对应的特权工作模式。用户模式属于普通模式,有些特权指令是运行不了的,需要切换到特权模式下才能运行。在ARM处理器中,除了用户模式是普通模式,剩下的几种工作模式都属于特权模式。

为了保证计算机能长期安全稳定地运行,CPU提供了多种工作模式和权限管理。应用程序正常运行时,处理器处于普通模式,没有权限对内存和底层硬件进行操作。应用程序如果要读写磁盘上的音频数据,驱动声卡播放音乐,往屏幕写数据显示歌词,则要首先通过系统调用或软中断进入处理器特权模式,运行操作系统内核或硬件驱动代码,才能对底层的硬件设备进行读写操作。

在ARM处理器内部,除了基本的算术运算单元、逻辑运算单元、浮点运算单元和控制单元,还有一系列寄存器,包括各种通用寄存器、状态寄存器、控制寄存器,用来控制处理器的运行,保存程序运行时的各种状态和临时结果,如下图所示(ARM处理器中的寄存器):

ARM处理器中的寄存器可分为通用寄存器和专用寄存器两种。

寄存器R0~R12属于通用寄存器,除了FIQ工作模式,在其他工作模式下这些寄存器都是共用、共享的R0~R3通常用来传递函数参数,R4~R11用来保存程序运算的中间结果或函数的局部变量等,R12常用来作为函数调用过程中的临时寄存器。

ARM处理器有多种工作模式除了这些在各个模式下通用的寄存器,还有一些寄存器在各自的工作模式下是独立存在的:

如R13、R14、R15、CPSP、SPSR寄存器在每个工作模式下都有自己单独的寄存器

R13寄存器又称为堆栈指针寄存器(Stack Pointer,SP),用来维护和管理函数调用过程中的栈帧变化,R13总是指向当前正在运行的函数的栈帧,一般不能再用作其他用途。

R14寄存器又称为链接寄存器(Link Register,LR),在函数调用过程中主要用来保存上一级函数调用者的返回地址。

寄存器R15又称为程序计数器(Program Counter,PC),CPU从内存取指令执行,就是默认从PC保存的地址中取的,每取一次指令,PC寄存器的地址值自动增加。CPU一条一条不停地取指令,程序也就源源不断地一直运行下去。在ARM三级流水线中,PC指针的值等于当前正在运行的指令地址+8,后续的32位处理器虽然流水线的级数不断增加,但为了简化编程,PC指针的值继续延续了这种计算方式。

当前处理器状态寄存器(Current Processor State Register,CPSR)主要用来表征当前处理器的运行状态。除了各种状态位、标志位,CPSR寄存器里也有一些控制位,用来切换处理器的工作模式和中断使能控制。CPSR寄存器各个标志位、控制位的详细说明如下图所示:

CPSR寄存器的标志位、控制位的详细说明

在每种工作模式下,都有一个单独的程序状态保存寄存器(Saved Processor State Register,SPSR)。

当ARM处理器切换工作模式或发生异常时,SPSR用来保存当前工作模式下的处理器现场,即将CPSR寄存器的值保存到当前工作模式下的SPSR寄存器。

当ARM处理器从异常返回时,就可以从SPSR寄存器中恢复原先的处理器状态,切换到原来的工作模式继续运行。

在ARM所有的工作模式中,有一种工作模式比较特殊,即FIQ模式。为了快速响应中断,减少中断现场保护带来的时间开销,在FIQ工作模式下,ARM处理器有自己独享的R8~R12寄存器。

ARM汇编指令

咱们接下来了解一些ARM常用的汇编指令。

如存储器访问指令、数据传送指令、算术逻辑运算指令、跳转指令等。

一个完整的ARM指令通常由操作码+操作数组成,指令的编码格式如下:

这是一个完整的ARM指令需要遵循的格式规则,指令格式的具体说明如下:

● 使用<>标起来的是必选项,使用{}标起来的是可选项。

● <opcode>是二进制机器指令的操作码助记符,如MOV、ADD这些汇编指令都是操作码的指令助记符。

● cond:执行条件,ARM为减少分支跳转指令个数,允许类似BEQ、BNE等形式的组合指令。

● S:是否影响CPSR寄存器中的标志位,如SUBS指令会影响CPSR寄存器中的N、Z、C、V标志位,而SUB指令不会。

● Rd:目标寄存器。

● Rn:第一个操作数的寄存器。

● operand2:第二个可选操作数,灵活使用第二个操作数可以提高代码效率。

在熟悉了ARM指令的基本格式后,我们接下来就开始了解ARM常用的一些汇编指令:

存储访问指令

ARM指令集属于RISC指令集,RISC处理器采用典型的加载/存储体系结构,CPU无法对内存里的数据直接操作,只能通过Load/Store指令来实现

当我们需要对内存中的数据进行操作时,要首先将这个数据从内存加载到寄存器,然后在寄存器中对数据进行处理,最后将结果重新存储到内存中。ARM处理器属于冯·诺依曼架构,程序和数据都存储在同一存储器上,内存空间和I/O空间统一编址,ARM处理器对程序指令、数据、I/O空间中外设寄存器的访问都要通过Load/Store指令来完成。

ARM处理器中经常使用的Load/Store指令的使用方法如下

在ARM存储访问指令中,我们经常使用的是LDR/STR、LDM/STM这两对指令。

LDR/STR指令是ARM汇编程序中使用频率最高的一对指令,每一次数据的处理基本上都离不开它们。LDM/STM指令常用来加载或存储一组寄存器到一片连续的内存,通过和堆栈格式符组合使用,LDM/STM指令还可以用来模拟堆栈操作。

LDM/STM指令常和下表的堆栈格式组合使用

不同类型的堆栈

如下图所示:

在一个堆栈内存结构中,如果堆栈指针SP总是指向栈顶元素,那么这个栈就是满栈;如果堆栈指针SP指向的是栈顶元素的下一个空闲的存储单元,那么这个栈就是空栈。

每入栈一个元素,栈指针SP都会往栈增长的方向移动一个存储单元:

如果栈指针SP从高地址往低地址移动,那么这个栈就是递减栈

如果栈指针SP从低地址往高地址移动,那么这个栈就是递增栈。

ARM处理器使用的一般都是满递减堆栈,在将一组寄存器入栈,或者从栈中弹出一组寄存器时,我们可以使用下面的指令。

这里需要注意的一个细节是,在入栈和出栈过程中要留意栈中各个元素的入栈出栈顺序。

栈的特点是先入后出(First In Last Out,FILO),栈元素在入栈操作时,STMFD会根据大括号{}中寄存器列表中各个寄存器的顺序,从左往右依次压入堆栈。在上面的例子中,R0会先入栈,接着R1、R2入栈,最后R14入栈,入栈操作完成后,栈指针SP在内存中的位置如下图左侧所示:

栈元素在出栈操作时,顺序刚好相反,栈中的元素先弹出到R14寄存器中,接着是R2、R1、R0。将栈中的元素依次弹出到R14、R2寄存器后,堆栈指针在内存中的位置如上图右侧所示。

除此之外,ARM还专门提供了PUSH和POP指令来执行栈元素的入栈和出栈操作。PUSH和POP指令的使用方法如下:

数据传送指令

LDR/STR指令用来在寄存器和内存之间输送数据。如果我们想要在寄存器之间传送数据,则可以使用MOV指令。MOV指令的格式如下:

其中,{cond}为条件指令可选项,{S}用来表示是否影响CPSR寄存器的值,如MOVS指令就会影响寄存器CPSR的值,而MOV则不会。

MVN指令用来将操作数operand2按位取反后传送到目标寄存器Rd。

操作数operand2可以是一个立即数,也可以是一个寄存器。

MOV和MVN指令的一般使用方法如下

算术逻辑运算指令

算术运算指令包括基本的加、减、乘、除,逻辑运算指令包括与、或、非、异或、清除等。

指令格式如下:

算术逻辑运算指令的基本使用方法及说明如下:

操作数:operand2详解

ARM指令的可选项很多,操作数也很灵活。

很多ARM指令会使用第二个参数operand2可以是一个常数,也可以是寄存器+偏移的形式。操作数operand2在汇编程序中经常出现的两种格式如下。

第一种格式比较简单,操作数是一个立即数,第二种格式可以直接使用寄存器的值作为操作数。

在咱们刚才的ADD、SUB、AND指令示例中,第二个操作数要么是一个常数,要么是一个寄存器。在第二种格式中,通过{,shift}可选项,我们还可以通过多种移位或循环移位的方式,构建更加灵活的操作数

可选项{,shift}可以选择的移位方式如下

可选性指令的使用示例及说明如下:

比较指令

比较指令用来比较两个数的大小,或比较两个数是否相等。

比较指令的运算结果会影响CPSR寄存器的N、Z、C、V标志位,具体的标志位说明可参考前面的CPSR寄存器介绍。

比较指令的格式如下:

比较指令的使用示例及说明如下:

比较指令的运行结果Z=1时,表示运算结果为零,两个数相等;

N=1表示运算结果为负,N=0表示运算结果为非负,即运算结果为正或者为零。

条件执行指令

为了提高代码密度,减少ARM指令的数量,几乎所有的ARM指令都可以根据CPSR寄存器中的标志位,通过指令组合实现条件执行。

如无条件跳转指令B,我们可以在后面加上条件码组成BEQ、BNE组合指令。

BEQ指令表示两个数比较,结果相等时跳转;

BNE指令则表示结果不相等时跳转。

CPSR寄存器中的标志位根据需要可以任意搭配成不同的条件码,和ARM指令一起组合使用。ARM指令的条件码如下表所示( ARM指令的条件码):

条件执行经常出现在跳转或循环的程序结构中。

如下面的汇编程序,通过循环结构,我们可以实现数据块的搬运功能。我们可以将无条件跳转指令B和条件码NE组合在一起使用,构成一个循环程序结构。

跳转指令

在函数调用的场合,以及循环结构、分支结构的程序中经常会用到跳转指令。

ARM指令集提供了B、BL、BX、BLX等跳转指令,每个指令都有各自的用武之地和使用场景。跳转指令的格式如下。

1.B label

跳转到标号label处,B跳转指令的跳转范围大小为[0,32MB],可以往前跳,也可以往后跳。

无条件跳转指令B主要用在循环、分支结构的汇编程序中,使用示例如下:

2.BL label

BL跳转指令表示带链接的跳转。

在跳转之前,BL指令会先将当前指令的下一条指令地址(即返回地址)保存到LR寄存器中,然后跳转到label处执行。

BL指令一般用在函数调用的场合,主函数在跳转到子函数执行之前,会先将返回地址,即当前跳转指令的下一条指令地址保存到LR寄存器中

子函数执行结束后,LR寄存器中的地址被赋值给PC,处理器就可以返回到原来的主函数中继续运行了。

3.BX Rm

BX表示带状态切换的跳转。Rm寄存器中保存的是跳转地址,要跳转的目标地址处可能是ARM指令,也可能是Thumb指令。

处理器根据Rm[0]位决定是切换到ARM状态还是切换到Thumb状态。

● 0:表示目标地址处是ARM指令,在跳转之前要先切换至ARM状态。

● 1:表示目标地址处是Thumb指令,在跳转之前要先切换至Thumb状态。

BLX指令是BL指令和BX指令的综合,表示带链接和状态切换的跳转,使用方法和上面相同。


我们对ARM体系结构与汇编指令有个基本认知即可,未来咱们会在实践中,从更高层次来理解。

这篇关于【机器学习智能硬件开发全解】(六)—— 政安晨:通过ARM-Linux掌握基本技能【认知准备:体系结构与汇编指令】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/819631

相关文章

Linux换行符的使用方法详解

《Linux换行符的使用方法详解》本文介绍了Linux中常用的换行符LF及其在文件中的表示,展示了如何使用sed命令替换换行符,并列举了与换行符处理相关的Linux命令,通过代码讲解的非常详细,需要的... 目录简介检测文件中的换行符使用 cat -A 查看换行符使用 od -c 检查字符换行符格式转换将

Linux系统配置NAT网络模式的详细步骤(附图文)

《Linux系统配置NAT网络模式的详细步骤(附图文)》本文详细指导如何在VMware环境下配置NAT网络模式,包括设置主机和虚拟机的IP地址、网关,以及针对Linux和Windows系统的具体步骤,... 目录一、配置NAT网络模式二、设置虚拟机交换机网关2.1 打开虚拟机2.2 管理员授权2.3 设置子

Linux系统中卸载与安装JDK的详细教程

《Linux系统中卸载与安装JDK的详细教程》本文详细介绍了如何在Linux系统中通过Xshell和Xftp工具连接与传输文件,然后进行JDK的安装与卸载,安装步骤包括连接Linux、传输JDK安装包... 目录1、卸载1.1 linux删除自带的JDK1.2 Linux上卸载自己安装的JDK2、安装2.1

Spring Boot + MyBatis Plus 高效开发实战从入门到进阶优化(推荐)

《SpringBoot+MyBatisPlus高效开发实战从入门到进阶优化(推荐)》本文将详细介绍SpringBoot+MyBatisPlus的完整开发流程,并深入剖析分页查询、批量操作、动... 目录Spring Boot + MyBATis Plus 高效开发实战:从入门到进阶优化1. MyBatis

Python基于wxPython和FFmpeg开发一个视频标签工具

《Python基于wxPython和FFmpeg开发一个视频标签工具》在当今数字媒体时代,视频内容的管理和标记变得越来越重要,无论是研究人员需要对实验视频进行时间点标记,还是个人用户希望对家庭视频进行... 目录引言1. 应用概述2. 技术栈分析2.1 核心库和模块2.2 wxpython作为GUI选择的优

Mysql表的简单操作(基本技能)

《Mysql表的简单操作(基本技能)》在数据库中,表的操作主要包括表的创建、查看、修改、删除等,了解如何操作这些表是数据库管理和开发的基本技能,本文给大家介绍Mysql表的简单操作,感兴趣的朋友一起看... 目录3.1 创建表 3.2 查看表结构3.3 修改表3.4 实践案例:修改表在数据库中,表的操作主要

Linux卸载自带jdk并安装新jdk版本的图文教程

《Linux卸载自带jdk并安装新jdk版本的图文教程》在Linux系统中,有时需要卸载预装的OpenJDK并安装特定版本的JDK,例如JDK1.8,所以本文给大家详细介绍了Linux卸载自带jdk并... 目录Ⅰ、卸载自带jdkⅡ、安装新版jdkⅠ、卸载自带jdk1、输入命令查看旧jdkrpm -qa

Linux samba共享慢的原因及解决方案

《Linuxsamba共享慢的原因及解决方案》:本文主要介绍Linuxsamba共享慢的原因及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux samba共享慢原因及解决问题表现原因解决办法总结Linandroidux samba共享慢原因及解决

新特性抢先看! Ubuntu 25.04 Beta 发布:Linux 6.14 内核

《新特性抢先看!Ubuntu25.04Beta发布:Linux6.14内核》Canonical公司近日发布了Ubuntu25.04Beta版,这一版本被赋予了一个活泼的代号——“Plu... Canonical 昨日(3 月 27 日)放出了 Beta 版 Ubuntu 25.04 系统镜像,代号“Pluc

利用Python开发Markdown表格结构转换为Excel工具

《利用Python开发Markdown表格结构转换为Excel工具》在数据管理和文档编写过程中,我们经常使用Markdown来记录表格数据,但它没有Excel使用方便,所以本文将使用Python编写一... 目录1.完整代码2. 项目概述3. 代码解析3.1 依赖库3.2 GUI 设计3.3 解析 Mark