【物联网】ARM核常用指令(详解):数据传送、计算、位运算、比较、跳转、内存访问、CPSR/SPSR、流水线及伪指令

文章目录

  • 指令格式(重点)
    • 1. 立即数
    • 2. 寄存器位移
  • 一、数据传送指令
    • 1. MOV指令
    • 2. MVN指令
    • 3. LDR指令
  • 二、数据计算指令
    • 1. ADD指令
    • 1. SUB指令
    • 1. MUL指令
  • 三、位运算指令
    • 1. AND指令
    • 2. ORR指令
    • 3. EOR指令
    • 4. BIC指令
  • 四、比较指令
  • 五、跳转指令
    • 1. B/BL指令
    • 2. ldr指令
    • 练习
  • 六、内存访问指令
    • 1. 单内存访问指令
      • 练习
    • 2. 多内存访问指令
      • 示例
    • 3. 栈操作指令
      • 示例
  • 七、CPSR/SPSR操作指令
      • 练习
  • 八、ARM指令流水线分析及伪指令
    • 1. 最佳流水线
    • 2. 内存访问指令流水线
    • 3. 分支流水线
    • 4. ARM伪指令、汇编与C混合编程、Volatile关键字
      • (1)LDR R0,=0x12345678分析
      • (2)LDR R0,=Label 分析
      • (3)LDR R0,Label
      • (4)ADR R0,Label分析
      • (5)如何判别代码在实际内存中运行的地址?


指令格式(重点)

在这里插入图片描述

1. 立即数

一个常数,该常数必须对应8位位图,即一个8位的常数通过,循环右移偶数位得到该数,该数
数为合法立即数。

在指令中表示方法:#数字,例如:#100

快速判定是否是合法立即数:

  • 首先将这个数转换为32bit的16进制形式,例如218=0xDA=0x000000DA
  • 除零外,仅有一位数为合法立即数
  • 除零外,仅有二位数,并且相邻(包括首尾,如0x1000000A)的为合法立即数。
  • 除零外,仅有三位数,并且相邻(包括中间有0相间,例如0x10800000,包括首尾相邻
    如:0x14000003),这三位数中,最高位取值仅能为1、2、3,最低位取值仅能为4、8、C
    中间位0x0~0xF。
    这种组合的为合法立即数。

2. 寄存器位移

将寄存器值读取之后,进行移位运算后,作为操作数2参与运算。支持的移位方式如下:

  • LSL(Logical shift Left)逻辑右移
  • LSR(Logical shift Right)逻辑左移
  • ASR(Arithmetic shift Right)算术右移
r0,lsr #4 表示r0 >>4
r0,lsr r1 表示r0 >>r1
#3,LsL #4 错误,只能是寄存器移位,不能是立即数移位

一、数据传送指令

1. MOV指令

格式:mov 目标寄存器,操作数2
功能:将操作数2的值赋值给目标寄存器

在这里插入图片描述

2. MVN指令

格式:mvn 目标寄存器,操作数2
功能:将操作2取反的值给目标寄存器

在这里插入图片描述

3. LDR指令

格式: LDR 目标寄存器,= 数据
功能: 完成任意的数据传送到目标寄存器
注意: 数据前面不能加#,因为此时数据不按立即数来处理

在这里插入图片描述

二、数据计算指令

1. ADD指令

格式: add 目标寄存器,操作数1操作数2
功能: 将操作数1加上操作数2的结果给目标寄存器
在这里插入图片描述

1. SUB指令

格式: sub 目标寄存器,操作数1操作数2
功能: 将操作数1减去操作数2的结果给目标寄存器

在这里插入图片描述

1. MUL指令

格式: mul 目标寄存器,操作1操作2
功能: 将操作数1乘以操作数2的结果存放在目标寄存器

注意:操作数1操作2必须都是寄存器,并且操作1的寄存器编号不能和目标寄存器一样

在这里插入图片描述

三、位运算指令

1. AND指令

格式: and 目标寄存器,操作数1操作数2
功能: 将操作数1按位与操作数2的结果存放在目标寄存器
在这里插入图片描述

2. ORR指令

格式: orr 目标寄存器,操作数1操作数2
功能: 将操作1按位或操作2的结果存放在目标寄存器

3. EOR指令

格式: eor 目标寄存器,操作1操作2
功能: 将操作数1按位异或操作数2的结果存放在目标寄存器

在这里插入图片描述

4. BIC指令

格式: bic 目标寄存器,操作1操作2
功能: 将操作数1按位与操作数2取反的结果存放在目标寄存器
目标寄存器 = 操作数1 & ~操作数2

在这里插入图片描述

四、比较指令

格式: cmp 寄存器,操作数2
等于寄存器减去操作数2
功能: 将寄存器的值与操作2比较,比较的结果会自动影响CPSR的NZCV

在这里插入图片描述

答案

在这里插入图片描述

五、跳转指令

1. B/BL指令

格式: B/BL 标签
功能: 跳到一个指定的标签,BL 跳转之前,将跳转前的PC的值保存在LR,跳转范围+/- 32M
在这里插入图片描述

NZCV 标志位

标志位含义
N (Negative)结果为负数(Rn < Rm)
Z (Zero)结果为 0(Rn == Rm)
C (Carry)发生借位(无符号比较时 Rn < Rm)
V (Overflow)溢出(有符号计算超出范围)

比较指令 + B 条件跳转

指令条件说明
BEQ labelZ == 1相等(Rn == Rm)时跳转
BNE labelZ == 0不相等(Rn ≠ Rm)时跳转
BGT labelZ == 0 且 N == V大于(Rn > Rm,有符号)时跳转
BGE labelN == V大于等于(Rn ≥ Rm,有符号)时跳转
BLT labelN ≠ V小于(Rn < Rm,有符号)时跳转
BLE labelZ == 1 或 N ≠ V小于等于(Rn ≤ Rm,有符号)时跳转
BHI labelC == 1 且 Z == 0大于(Rn > Rm,无符号)时跳转
BHS labelC == 1大于等于(Rn ≥ Rm,无符号)时跳转
BLO labelC == 0小于(Rn < Rm,无符号)时跳转
BLS labelC == 0 或 Z == 1小于等于(Rn ≤ Rm,无符号)时跳转

2. ldr指令

格式: ldr pc,= 标签名
功能: 将PC指针指闻标签表示的地址
在这里插入图片描述

练习

在这里插入图片描述

答案

在这里插入图片描述

六、内存访问指令

1. 单内存访问指令

LDR 将内存中的值加载到寄存器(读内存)
STR 将寄存器的内容写入内存(写内存)

寄存器间接寻址:寄存器的值是一个地址

LDR ro,[r1 ]     //r0 = *r1
STR ro,[ r1 ] //*r1 = ro

基址变址寻址:将基地址寄存器加上指令中给出的偏移量,得到数据存放的地址

  • A. 前索引
STR r0,[r1,#4] //*(r1 + 4)= r0
LDR r0,[r1,#4] //r0 =*(r1+ 4)
  • B. 后索引
STR r0,[r1],#4   //*r1=r0 &&r1=r1 + 4
LDR r0,[r1],#4   //r0=*r1 &&r1=r1 + 4
  • C. 自动索引
STR r0,[r1,#4]!    //*(r1+4)=r0&&r1=r1+4
LDR r0,[r1,#4]!    //r0=*(r1+4)&&r1 =r1+4

示范:

在这里插入图片描述

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

练习

将1-10数据存放在基地址为0x4000,0000,将0x4000,0000起始地址的值拷贝到0x4000,0100

答案
在这里插入图片描述

将0x1234写到0x4000,0000,将0xabcd写到0x4000,0004,然后从这两个地址读取数据做案加,最终结果存放在r0

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

2. 多内存访问指令

LDM 将一块内存的数据,加载到多个寄存器中
STM 将多个寄存器的值,存储到一块内存

格式:

LDM{条件}{s}<MODE>基址寄存器{!},{Reglist}^
STM{条件}{s}<MODE>基址寄存器{!},{Reglist}^

mode说明
IA后增加地址
IB先增加地址
DA后减少地址
DB先减少地址

基址寄存器
用于放内存的起始地址

!
最后更新基址寄存器的值

Reglist

  • 多个寄存器,从小到大,中间用 , 隔开,如 {r0,r2,r3}{r0-r7,r10}
  • 寄存器号大的对应内存的高地址,寄存器号小的对应内存的低地址

^

  • 它存在,如果 Reglist 没有 pc 的时候,这个时候操作的寄存器是用户模式下的寄存器
  • LDM 指令中,有 PC 的时候,在数据传送的时候,会将 SPSR 的值拷贝到 CPSR,用于异常的返回

流程图:
在这里插入图片描述
在这里插入图片描述

示例

在这里插入图片描述

3. 栈操作指令

A. 进栈

stmfd sp!,{寄存器列表}

B. 出栈

Idmfd sp!,{寄存器列表}

注意
在对栈操作之前,必须先设置sp的值,进栈和出栈的方式一样,ATPCS标准规定满减栈

流程图:
在这里插入图片描述

堆栈指针指向最后压入的堆栈的有效数据项,称为满堆栈
堆栈指针指向下一个待压入数据的空位置,称为空堆栈

在这里插入图片描述

示例

在这里插入图片描述

七、CPSR/SPSR操作指令

A. 读操作

MRS Rn,CPSR/SPSR
将状态寄存器的值,读到通用寄存器中

B. 写操作

MSR CPSR/SPSR,Rn
将通用寄存器的值,写到状态寄存器

练习

A.写一段代码,将CPSR的第I(7)位清0,其他位不变(使能IRQ异常)
B.写一段代码,将CPSR的第I(7)位置1,其他位不变(禁用IRQ异常)

答案
在这里插入图片描述

八、ARM指令流水线分析及伪指令

在ARM核中,为增加处理器指令流的速度,ARM7系列使用3级流水线。允许多个操作同时处理,而非顺序执行。不同的ARM核,流水线的级数是不一样的,ARM核版本越高,流水线级数越多。对于软件工程师编程而言,统一按照三级流水线来分析就可以了。

PC指向正被取指的指令,而非正在执行的指令

在这里插入图片描述

1. 最佳流水线

在这里插入图片描述

该例中用5个时钟周期执行了5条指令,所有的操作都在寄存器中(单周期执行)
指令周期数(CPI)=1

2. 内存访问指令流水线

在这里插入图片描述

该例中,用6周期执行了4条指令,指令周期数(CPI)=1.5

3. 分支流水线

在这里插入图片描述

4. ARM伪指令、汇编与C混合编程、Volatile关键字

伪指令定义:
为了方便程序员使用,编译器设计的指令,这个指令ARM核无法直接识别,需要编译器对他翻译成ARM核所能识别的指令。

(1)LDR R0,=0x12345678分析

再次强调:PC指向正被取指的指令,而非正在执行的指令

如何看内存中的12345678
正在读取的LDR内存是0x0008 加上 PC所在的地址(因为LDR正在执行 所以pc等于0x0000000C预取的值)
也就是0x0008加上pc的值0x0000000C等于0x00000014

在这里插入图片描述

总结

编译器在编译的时候,将Idr r0,=0x12345678翻译成了ldr r0,[pc,#0x0008]这一条读内存的指令。根据PC的值加上偏移量算出0x12345678这个数据在内存的地址,然后使用Idr指令读取这个地址的数据。

(2)LDR R0,=Label 分析

1) 链接地址指定为0x0情况分析

0x00000018等于0x000C加上pc的值0x000C

注意 0x00000018的值是14 这是个值 是编译器算出来的一个值

在这里插入图片描述

在这里插入图片描述

2) 链接地址指定为0x2000情况分析

修改链接地址
在这里插入图片描述

再运行

label的地址也就是0x000c+pc的值0x0000200c=0x00002018

在这里插入图片描述

3) 总结

LDR r0,=Label指令表示将Label的值写入r0,Label的值由指定的代码段运行地址(-Ttext=地址值)来决定。

编译器做法:

  • 首先根据指定的代码段开始的地址,算出Label标签对应的地址值
  • 然后将这个表示的地址值存放在一个位置
  • 生成内存访问指令,根据pc +固定偏移量,找到标签对应值存放的位置

注意
当代码编译结束的时候,标签表示的地址值(根据指定的代码段地址)已经编译死存放在程序文件中了。

(3)LDR R0,Label

LDR R0,Label 表示读取Label表示的地址对应数据

不带=的时候 存的是标签里的内容

在这里插入图片描述

(4)ADR R0,Label分析

动态方式 根据pc的值+0x00000008

之前是静态的 在编译完的时候 label就已经确定值是什么了
这个是动态

举个例子:如果是用LDR我把这个代码放到A内存和B内存运行
这两块内存的值是一模一样的 因为在编译完的时候 label就已经确定值是什么了
如果是ADR A内存的0x0008 和B内存的0x0008 是不一样的
有点难理解

在这里插入图片描述

ADR R0,Label指令表示根据当前的PC的值 +/-偏移量,动态获取当前Label所表示的内存地址

(5)如何判别代码在实际内存中运行的地址?

ADR r0,_start 可以知道,因为他是根据pc的值,动态获取
LDR r0,=_start 无法知道,这条指令不论在哪里运行,r0的值都是固定(取决于指定的链接地址)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/68430.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

过年之无用知识研究:std::is_assignable到底怎么个事?

下面是gcc的std::is_assignable相关源码&#xff1a;template<typename _Tp, typename _Up>class __is_assignable_helper{template< typename _Tp1, typename _Up1,typename decltype(declval<_Tp1>() declval<_Up1>()) //注意这行 >static true_ty…

单链表算法实战:解锁数据结构核心谜题——链表的回文结构

题目如下&#xff1a; 解题过程如下&#xff1a; 回文结构举例&#xff1a; 回文数字&#xff1a;12521、12321、1221…… 回文字符串&#xff1a;“abcba”、“abba”…… 并不是所有的循环嵌套的时间复杂度都是O(n^2) 可以用C写C程序&#xff1a; C里可以直接使用ListNode…

C++ 包装器与绑定器的应用之回调函数的实现

回调函数的实现 在消息队列和网络库的框架中&#xff0c;当接收到消息&#xff08;报文&#xff09;时&#xff0c;回调用户自定义的函数对象&#xff0c;把消息&#xff08;报文&#xff09;参数传给它&#xff0c;由它决定如何处理。 queue参考文章:C queue(STL queue&…

除了layui.js还有什么比较好的纯JS组件WEB UI?在谷歌浏览上显示

以下是一些比较好的纯JS组件WEB UI&#xff0c;可以在谷歌浏览器上良好显示&#xff1a; 1. Sencha 特点&#xff1a;提供超过140个高性能UI组件&#xff0c;用于构建现代应用程序。支持与Angular和React集成&#xff0c;提供企业级网格解决方案。 适用场景&#xff1a;适用于…

计算机网络 (58)无线局域网WLAN

前言 无线局域网WLAN&#xff08;Wireless Local Area Network&#xff09;是一种利用无线通信技术将计算机设备互联起来&#xff0c;构成可以互相通信和实现资源共享的网络体系。 一、定义与特点 定义&#xff1a; WLAN通过无线信道代替有线传输介质连接两个或多个设备形成一个…

AIP-132 标准方法:List

编号132原文链接AIP-132: Standard methods: List状态批准创建日期2019-01-21更新日期2022-06-02 在许多API中&#xff0c;通常会向集合URI&#xff08;例如 /v1/publishers/1/books &#xff09;发出GET请求&#xff0c;获取集合中资源的列表。 面向资源设计&#xff08;AIP…

Vue.js组件开发-Vue实现上传word模版打印设置自定义样式和布局

要使用 Vue 实现上传 Word 模板、打印并设置自定义样式和布局&#xff0c;可以借助一些工具和库来完成这个任务。 实现步骤 创建 Vue 项目&#xff1a;使用 Vue CLI 创建一个新的 Vue 项目。安装依赖&#xff1a;安装 docx-templates 库来处理 Word 模板&#xff0c;file-sav…

算法随笔_28:最大宽度坡_方法2

上一篇:算法随笔_27:最大宽度坡-CSDN博客 题目描述如下: 给定一个整数数组 nums&#xff0c;坡是元组 (i, j)&#xff0c;其中 i < j 且 nums[i] < nums[j]。这样的坡的宽度为 j - i。 找出 nums 中的坡的最大宽度&#xff0c;如果不存在&#xff0c;返回 0 。 示例 …

C++中函数返回值当引用

文章目录 一、概述二、返回值当引用的基本语法三、返回局部变量的引用四、返回引用的常见用途五、返回右值引用六、总结 一、概述 在 C 中&#xff0c;函数返回值当引用&#xff08;即返回引用&#xff09;是一个常见的编程技巧。它可以让你返回一个函数内部的局部变量或对象的…

10 款《医学数据库和期刊》查阅网站

在毕业设计过程中,需要查阅到关于医学的相关文献和图片作为参考,发现下面10款非常的好用,作为分享。 1. PubMed: PubMed 搜索关键词如“lung cancer CT images”或“lung cancer CT scan”。 Radiopaedia: https://radiopaedia.org/ 这是一个放射学专业网站,有大量肺癌的CT…

OpenCV:形态学梯度

目录 简述 1. 用图像运算和腐蚀实现形态学梯度 1.1 代码示例 1.2 运行结果 2. 形态学梯度接口 2.1 参数解释 2.2 代码示例 2.3 运行结果 3. 形态学梯度与边缘检测 4. 形态学梯度的应用场景 5. 注意事项 相关阅读 OpenCV&#xff1a;图像的腐蚀与膨胀-CSDN博客 简述…

Java 大视界 -- Java 大数据在生物信息学中的应用与挑战(67)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…

MySQL中InnoDB逻辑存储结构

在MySQL中&#xff0c;InnoDB是最常用的存储引擎之一&#xff0c;它具有高度的事务支持、行级锁、ACID特性以及自动崩溃恢复等特性。InnoDB的逻辑存储结构可以分为多个层次&#xff0c;下面是详细的解析。 1. 表空间 (Tablespace) InnoDB的物理存储结构以表空间为基础。表空间…

字符设备驱动模版-中断

字符设备驱动模版-中断 思维导图在线高清查看&#xff1a;https://www.helloimg.com/i/2025/01/27/679791b5257c0.png 修改设备树 1添加pinctrl节点 1创建对应的节点 在 iomuxc 节点的 imx6ul-evk 子节点下 2添加“fsl,pins”属性 3在“fsl,pins”属性中添加PIN配置信息 …

【SH】Windows禁用Alt+F4关机、重启、注销等功能,只保留关闭应用的功能

文章目录 组策略编辑器参考文档 组策略编辑器 亲测有效&#xff01; 1、按winr&#xff0c;输入gpedit.msc&#xff0c;回车。 2、找到》用户配置》管理模板》“开始”菜单和任务栏。 3、在右侧找到删除并阻止访问“关机”、“重新启动”、“睡眠”和“休眠”命令&#xff0c…

AndroidCompose Navigation导航精通2-过渡动画与路由切换

目录 前言路由切换NavControllerBackStackEntry过渡动画过渡原理缩放动画渐隐动画滑动动画动画过渡实战前言 在当今的移动应用开发中,导航是用户与应用交互的核心环节。随着 Android Compose 的兴起,它为开发者提供了一种全新的、声明式的方式来构建用户界面,同时也带来了更…

分库分表后如何进行join操作

在分库分表后的系统中&#xff0c;进行表之间的 JOIN 操作比在单一数据库表中复杂得多&#xff0c;因为涉及的数据可能位于不同的物理节点或分片中。此时&#xff0c;传统的 SQL JOIN 语句不能直接用于不同分片的数据&#xff0c;以下是几种处理这样的跨分片 JOIN 操作的方法&a…

【深度学习】线性回归的简洁实现

线性回归的简洁实现 在过去的几年里&#xff0c;出于对深度学习强烈的兴趣&#xff0c;许多公司、学者和业余爱好者开发了各种成熟的开源框架。 这些框架可以自动化基于梯度的学习算法中重复性的工作。 目前&#xff0c;我们只会运用&#xff1a; &#xff08;1&#xff09;通…

C++中的显式构造和隐式构造

文章目录 一、概述二、显式构造函数的使用三、隐式构造函数的使用四、显式和隐式的适用场景 一、概述 在 C 中&#xff0c;构造函数可以分为 显式构造 和 隐式构造&#xff0c;它们的区别主要体现在构造函数的调用方式上。 1.显式构造&#xff08;Explicit Constructor&#…

【YOLOv11改进- 主干网络】YOLOv11+MobileNetV3(2019): 更快,更精准;

YOLOV11目标检测-主干网络改进实例与创新改进专栏 目录 YOLOV11目标检测-主干网络改进实例与创新改进专栏 本文介绍 1.完整代码获取 2.MobileNetv3介绍 文章摘要 3. MobileNetv3网络结构图 4. yolov11-MobileNetv3 yaml文件 5.MobileNetv3代码实现 6.MobileNetv3添加方…