【物联网】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 label | Z == 1 | 相等(Rn == Rm)时跳转 |
BNE label | Z == 0 | 不相等(Rn ≠ Rm)时跳转 |
BGT label | Z == 0 且 N == V | 大于(Rn > Rm,有符号)时跳转 |
BGE label | N == V | 大于等于(Rn ≥ Rm,有符号)时跳转 |
BLT label | N ≠ V | 小于(Rn < Rm,有符号)时跳转 |
BLE label | Z == 1 或 N ≠ V | 小于等于(Rn ≤ Rm,有符号)时跳转 |
BHI label | C == 1 且 Z == 0 | 大于(Rn > Rm,无符号)时跳转 |
BHS label | C == 1 | 大于等于(Rn ≥ Rm,无符号)时跳转 |
BLO label | C == 0 | 小于(Rn < Rm,无符号)时跳转 |
BLS label | C == 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就已经确定值是什么了
如果是ADRA内存的0x0008 和B内存的0x0008 是不一样的
有点难理解

ADR R0,Label指令表示根据当前的PC的值 +/-偏移量,动态获取当前Label所表示的内存地址
(5)如何判别代码在实际内存中运行的地址?
ADR r0,_start可以知道,因为他是根据pc的值,动态获取
LDR r0,=_start无法知道,这条指令不论在哪里运行,r0的值都是固定(取决于指定的链接地址)
相关文章:
【物联网】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. l…...
Jackson中@JsonTypeId的妙用与实例解析
在日常的Java开发中,Jackson库是处理JSON数据的常用工具。其中,JsonTypeId注解是一个非常实用的功能,它可以帮助我们更好地控制多态类型信息在序列化过程中的表现。今天,我们就来深入探讨一下JsonTypeId的用法,并通过具…...
Ubuntu 顶部状态栏 配置,gnu扩展程序
顶部状态栏 默认没有配置、隐藏的地方 安装使用Hide Top Bar 或Just Perfection等进行配置 1 安装 sudo apt install gnome-shell-extension-manager2 打开 安装的“扩展管理器” 3. 对顶部状态栏进行配置 使用Hide Top Bar 智能隐藏,或者使用Just Perfection 直…...
Java---入门基础篇(上)
前言 本片文章主要讲了刚学Java的一些基础内容,例如注释,标识符,数据类型和变量,运算符,还有逻辑控制等,记录的很详细,带你从简单的知识点再到练习题.如果学习了c语言的小伙伴会发现,这篇文章的内容和c语言大致相同. 而在下一篇文章里,我会讲解方法和数组的使用,也是Java中基础…...
Linux C++
一、引言 冯诺依曼架构是现代计算机系统的基础,它的提出为计算机的发展奠定了理论基础。在学习 C 和 Linux 系统时,理解冯诺依曼架构有助于我们更好地理解程序是如何在计算机中运行的,包括程序的存储、执行和资源管理。这对于编写高效、可靠的…...
gradio 合集
知识点 1:基本 Chatbot 创建 import gradio as gr 定义历史记录 history [gr.ChatMessage(role“assistant”, content“How can I help you?”), gr.ChatMessage(role“user”, content“What is the weather today?”)] 使用历史记录创建 Chatbot 组件 ch…...
996引擎 - NPC-动态创建NPC
996引擎 - NPC-动态创建NPC 创建脚本服务端脚本客户端脚本添加自定义音效添加音效文件修改配置参考资料有个小问题,创建NPC时没有控制朝向的参数。所以。。。自己考虑怎么找补吧。 多重影分身 创建脚本 服务端脚本 Mir200\Envir\Market_Def\test\test001-3.lua -- NPC八门名…...
论文阅读(十三):复杂表型关联的贝叶斯、基于系统的多层次分析:从解释到决策
1.论文链接:Bayesian, Systems-based, Multilevel Analysis of Associations for Complex Phenotypes: from Interpretation to Decision 摘要: 遗传关联研究(GAS)报告的结果相对稀缺,促使许多研究方向。尽管关联概念…...
代码随想录算法训练营第三十九天-动态规划-198. 打家劫舍
动规五部曲 dp[i]表示在下标为i的房间偷或不偷与前面所偷之和所能获得的最大价值递推公式:dp[i] std::max(dp[i - 2] nums[i], dp[i - 1])初始化:要给dp[0]与dp[1]来给定初始值,因为递推公式有-1与-2。dp[0] nums[0], dp[1] std::max(num…...
CF1098F Ж-function
【题意】 给你一个字符串 s s s,每次询问给你 l , r l, r l,r,让你输出 s s s l , r sss_{l,r} sssl,r中 ∑ i 1 r − l 1 L C P ( s s i , s s 1 ) \sum_{i1}^{r-l1}LCP(ss_i,ss_1) ∑i1r−l1LCP(ssi,ss1)。 【思路】 和前一道题一样&#…...
Python 函数魔法书:基础、范例、避坑、测验与项目实战
Python 函数魔法书:基础、范例、避坑、测验与项目实战 内容简介 本系列文章是为 Python3 学习者精心设计的一套全面、实用的学习指南,旨在帮助读者从基础入门到项目实战,全面提升编程能力。文章结构由 5 个版块组成,内容层层递进…...
vim交换文件的作用
1.数据恢复:因为vim异常的退出,使用交换文件可以恢复之前的修改内容。 2.防止多人同时编辑:vim检测到交换文件的存在,会给出提示,以避免一个文件同时被多人编辑。 (vim交换文件的工作原理:vim交换文件的工作…...
[NOI1995] 石子合并
[NOI1995] 石子合并 题目描述 在一个圆形操场的四周摆放 N N N 堆石子,现要将石子有次序地合并成一堆,规定每次只能选相邻的 2 2 2 堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。 试设计出一个算法,计算出将 …...
真正的智能与那只蝴蝶
“蝴蝶效应”可以展开为对智能本质与大算力关系的追问,其中“蝴蝶”作为隐喻可能指向多重维度——从混沌理论的“蝴蝶效应”到庄子“物我两忘”的蝴蝶之梦。这种并置本身暗示了智能与宇宙秩序、认知边界之间的深刻张力。以下从三个层面展开分析:一、混沌…...
C++小病毒-1.0勒索(更新次数:2)
内容供学习使用,不得转卖,代码复制后请1小时内删除,此代码会危害计算机安全,谨慎操作 在C20环境下,并在虚拟机里运行此代码!,病毒带来后果自负! 使用时请删除在main()里的注释,并修改位置至C:\\(看我代码注释)//可以改成WIN Main() #include <iostream> #i…...
Node.js 的底层原理
Node.js 的底层原理 1. 事件驱动和非阻塞 I/O Node.js 基于 Chrome V8 引擎,使用 JavaScript 作为开发语言。它采用事件驱动和非阻塞 I/O 模型,使其轻量且高效。通过 libuv 库实现跨平台的异步 I/O,包括文件操作、网络请求等。 2. 单线程事…...
基于Django的豆瓣影视剧推荐系统的设计与实现
【Django】基于Django的豆瓣影视剧推荐系统的设计与实现(完整系统源码开发笔记详细部署教程)✅ 目录 一、项目简介二、项目界面展示三、项目视频展示 一、项目简介 该系统采用了Python作为后端开发语言,采用Django作为后端架构,结…...
P10638 BZOJ4355 Play with sequence Solution
Description 给定 a ( a 1 , a 2 , ⋯ , a n ) a(a_1,a_2,\cdots,a_n) a(a1,a2,⋯,an),有 m m m 个操作,分以下三种: assign ( l , r , k ) \operatorname{assign}(l,r,k) assign(l,r,k):对每个 i ∈ [ l , r ] i \…...
MySQL误删数据怎么办?
文章目录 1. 从备份恢复数据2. 通过二进制日志恢复数据3. 使用数据恢复工具4. 利用事务回滚恢复数据5. 预防误删数据的策略总结 在使用MySQL进行数据管理时,误删数据是一个常见且具有高风险的操作。无论是因为操作失误、系统故障,还是不小心执行了删除命…...
项目测试之MockMvc
文章目录 基础基础概念Mockxxx一般实现文件位置 实战MockMvc与Test注解不兼容RequestParams参数RequestBody参数 基础 基础概念 定义:是Spring框架提供的一种用于测试Spring MVC控制器的工具,它允许开发者在不启动完整的web服务器的情况下,…...
Prompt Tuning、P-Tuning、Prefix Tuning的区别
一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法
深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...
【笔记】WSL 中 Rust 安装与测试完整记录
#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统:Ubuntu 24.04 LTS (WSL2)架构:x86_64 (GNU/Linux)Rust 版本:rustc 1.87.0 (2025-05-09)Cargo 版本:cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...
轻量级Docker管理工具Docker Switchboard
简介 什么是 Docker Switchboard ? Docker Switchboard 是一个轻量级的 Web 应用程序,用于管理 Docker 容器。它提供了一个干净、用户友好的界面来启动、停止和监控主机上运行的容器,使其成为本地开发、家庭实验室或小型服务器设置的理想选择…...
第14节 Node.js 全局对象
JavaScript 中有一个特殊的对象,称为全局对象(Global Object),它及其所有属性都可以在程序的任何地方访问,即全局变量。 在浏览器 JavaScript 中,通常 window 是全局对象, 而 Node.js 中的全局…...
更新 Docker 容器中的某一个文件
🔄 如何更新 Docker 容器中的某一个文件 以下是几种在 Docker 中更新单个文件的常用方法,适用于不同场景。 ✅ 方法一:使用 docker cp 拷贝文件到容器中(最简单) 🧰 命令格式: docker cp <…...
【AI News | 20250609】每日AI进展
AI Repos 1、OpenHands-Versa OpenHands-Versa 是一个通用型 AI 智能体,通过结合代码编辑与执行、网络搜索、多模态网络浏览和文件访问等通用工具,在软件工程、网络导航和工作流自动化等多个领域展现出卓越性能。它在 SWE-Bench Multimodal、GAIA 和 Th…...
