当前位置: 首页 > news >正文

硬件(六)arm指令

一、数据传输与运算指令

(一)MOV 指令

用于加载 12 位立即数到寄存器,或转移一个寄存器的值到另一个寄存器。

  • 格式 1:MOV{S}<c> <Rd>, #<const>
    示例:mov r0, #2,将立即数 2 加载到寄存器 r0
  • 格式 2:MOV{S}<c> <Rd>, <Rm>
    示例:mov r1, r0,把 r0 寄存器的值加载到 r1
    大多数指令格式为 opcode rd, rn, rm,其中 rd 是目标寄存器,rn 是第一操作数寄存器。
(二)MVN 指令

        对立即数按位取反后放入目标寄存器。
示例:mvn r3, #1,将 1 按位取反后存入 r3,结果为 0xFFFFFFFE。若 MOV 指令无法操作寄存器,会替换为 MVN 指令。

(三)ADD 指令

实现加法运算,常用两种格式:

  • ADD{S}<c> <Rd>, <Rn>, #<const>
  • ADD{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
(四)SUB 指令

进行减法运算,格式如下:

  • SUB{S}<c> <Rd>, <Rn>, #<const>
  • SUB{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
(五)立即数

立即数相当于汇编中的常量,前加 #。判断一个数是否为立即数有三个条件(以 12 位立即数为例):

1、如果某个数的数值范围是0~0xFF之间,那么这个数一定是立即数;

2、把某个数展开成2进制,这个数的最高位1至最低位1之间的二进制数序列的位数不能超过8位;

3、这个数的二进制序列凑够8位之后的的右边必须为偶数个连续的 0

(六)LDR 寄存器加载指令

用于从内存读取数据到寄存器,有多种格式:

  • LDR{<c>}{<q>} <Rt>, <label>
    示例:ldr r0, =0x2FAB4,多用于从 RAM 将 32 位字数据传送到目的寄存器。
  • LDR<c> <Rt>, [<Rn>{, #+/-<imm12>}]
    示例:LDR R0,[R1,#4],将内存地址为 R1 + 4 的字数据读入 R0#4 作为 12 位立即数可省略。
  • LDR<c> <Rt>, [<Rn>], #+/-<imm12>
    示例:ldr r0, [r1], #8,将内存地址 R1 的字数据读入 r0,之后 r1 + 8
  • LDR<c> <Rt>, [<Rn>, #+/-<imm12>]!
    示例:LDR R0,[R1,#8] !,将存储器地址为 R1 + 8 的字数据读入 R0,并将新地址 R1 + 8 写入 R1
(七)STR 指令

用于将寄存器数据存入内存地址。示例:str r1, [r0, #4],把 r1 的内容写入 r0 + 4 的地址。

(八)BIC 指令

实现指定位清零,格式:BIC{S}<c> <Rd>, <Rn>, #<const>,将 rn 中 const 为 1 的比特清零,结果放入 rd。示例:

eg:mov r0, 0xFFFFFFFF

        bic r0,  r0, #3;立即数哪些位为1就清掉

                                r0数据:0xFFFFFFFC

        bic r0, r0, #(0x1F << 8);连续5位清0

操作后 r0 数据会相应清零指定比特位。

(九)ORR 指令

实现指定位置 1,格式:ORR{S}<c> <Rd>, <Rn>, #<const>。示例:

eg:mov r0, #0

        orr r0,  r0, #5;立即数带1的比特位 置1

        orr r0, r0, #(1<< 9);第9位置1

可将 r0 中立即数带 1 的比特位置 1,如第 9 位。

(十){s} 后缀

加 s 后缀的指令会影响 CPSR 寄存器(当前程序状态寄存器)。CPSR 的 NZCV 位含义如下:

  • N:结果为有符号二进制补码时,若为负数则 N=1,否则 N=0
  • Z:结果为 0 则 Z=1,否则 Z=0
  • C:无符号数最高有效位向更高位进位时 C=1;减法中最高有效位从更高位借位时 C=0
  • V:有符号数操作时,若两个最高有效位均为 0 的数相加结果最高有效位为 1,或两个最高有效位均为 1 的数相加结果最高有效位为 0,则 V=1,否则 V=0
    示例:
mov r0, #0xFFFFFFFF
adds r2, r0, #0

adds 影响 CPSRN 置 1(结果为负)。

(十一)<c> 执行条件

可自选增加执行条件,示例:movcs r0, #100,表示只有 C 位置位时,才把 100 加载入 r0,方便实现指令的有条件执行。

(十二)CMP 指令

用于比较两个寄存器的值或一个寄存器与立即数的值,原理是对两个数求差,看结果是否为 0,会无条件修改 NVCZ 位。
eg:从 r0r1 代表的两个有符号数中找较大值放入 r2 寄存器(ge表示将大于等于的放到r0<great>;lt表示小的<last>)

2、找出三个数的最大值
;三位数找最大
;cmp r0, r1
;blt less
;great
;mov r2, r0
;b cmp1

;less 
;mov r3, r1

;cmp1
;cmp r3, r2
;bge finished
;mov r3, r2

二、跳转与循环指令

(一)跳转指令 b

类似 C 语言的 goto 语句,能实现无条件跳转,跳转时需指定 lable。本质是往 PC(程序计数器)里填跳转地址,b loop 相当于 ldr pc, =loop
练习:实现从 0 加到 100 的和,可通过 while 循环或 do while 循环

(二)bl 指令

用于函数调用,与 b 指令的区别是 bl 会在 lr(链接寄存器)中保存返回地址,以便函数调用完毕后回到调用处的下一行指令执行。

(三)bx 指令

示例:bx lr,将 lr 中的地址装入 pc,实现函数返回。

三、栈操作

(一)引入

函数调用时,r0r1 等寄存器值可能被修改,函数嵌套调用时 lr 值也会被修改,为解决此问题,需在函数调用前保护现场,调用完毕后恢复现场,这就需要栈结构。

(二)栈的操作方法

ARM 体系采用满减栈(先让栈指针自减,再写入数据)。操作前需指定栈底位置,如设置栈底指针寄存器:ldr sp, =0x40001000,使用 2440 内部从 0x40000000 开始的 4k RAM(地址范围 [0x40000000~0x40000FFF])。

(三)栈操作指令
  • 入栈保护指令 stmfdSTMDB:格式 STMFD<c> <Rn>{!}, <registers>Rn 为栈底指针寄存器,<registers> 为需入栈保护的寄存器,! 表示入栈后 sp 自动自减。

示例:stmfd sp!, {r0, r1, r2, r3-r12, lr}

  • 出栈恢复指令 ldmfdLDM/LDMIA:格式 LDMFD<c> <Rn>{!}, <registers>Rn 为栈底指针寄存器,<registers> 为需恢复的寄存器,! 表示出栈后 sp 自动自增。

示例:ldmfd sp!, {r0, r1, r2, r3-r12, lr}

练习:

四、汇编与 C 相互调用函数

(一)汇编调用 C 中函数
  1. 用 import 声明函数,并用 bl 指令跳转到 C 函数。
  2. 调用者(主调方)负责保护和恢复现场。
  3. 传参规则:
    • 参数个数≤4 个,用 r0~r3 寄存器传参。
    • 参数个数>4 个,第 5 个及以后参数通过栈传参。
    • C 函数返回值通过 r0 寄存器返回

eg: c函数

arm函数

(二)C 调用汇编中的函数

    1. extern 声明 arm函数  eg: int _asm_min(int a,intb)
2. 主函数调用   arm  _asm_min(10,20) 函数  
3. Arm  函数 _asm_min  在函数之前需要声明  调出函数  export _asm_min
4. 参数返回也是在R0寄存器中

arm函数

c函数

五、模式切换

(一)、CPS 指令

CPS 指令可以直接修改处理器模式,格式为 CPS #<mode>,比如想要切换到系统模式,可以写 CPS #0x1F(系统模式对应的编码)。不过需要注意,Keil 编译器不支持该指令,在实际使用 Keil 进行开发时,不能采用这种方式。

(二)、MRS / MSR 指令

通过 MRS(Move to Register from Special register)读取特殊寄存器的值到通用寄存器,再通过 MSR(Move to Special register from Register)将修改后的值写回特殊寄存器,从而实现模式切换。

示例代码(切换到 User 模式并设置栈指针):

    ; 读取 CPSR 到 R0MRS R0, CPSR; 清除 CPSR 的低 5 位(模式位)BIC R0, R0, #(0x1F); 设置为 User 模式(User 模式对应的编码是 0x10,即二进制 10000)ORR R0, R0, #0x10; 将修改后的值写回 CPSR 的控制域(c 表示控制域)MSR CPSR_c, R0; 设置栈指针,这里假设栈底为 0x40001000LDR SP, =0x40001000

这样就完成了从当前模式切换到 User 模式,并且为 User 模式设置了栈指针,以便在该模式下进行函数调用、局部变量存储等操作时能正确使用栈。


文章转载自:

http://n9l9EisC.cLqpj.cn
http://ItoalLt7.cLqpj.cn
http://qg7GbOxA.cLqpj.cn
http://Fo1VyNfb.cLqpj.cn
http://Aeh9hcM4.cLqpj.cn
http://sDvIW3bd.cLqpj.cn
http://ydWFvfXn.cLqpj.cn
http://QqJfFG5H.cLqpj.cn
http://NMt69RNN.cLqpj.cn
http://d5h1w4Fr.cLqpj.cn
http://la5nPF48.cLqpj.cn
http://b5iq0eMT.cLqpj.cn
http://HlwCW9xX.cLqpj.cn
http://lSQkwUNH.cLqpj.cn
http://OgzyulXb.cLqpj.cn
http://uYI6QGhw.cLqpj.cn
http://0dmiScP9.cLqpj.cn
http://XjdTBxpI.cLqpj.cn
http://fybksqpR.cLqpj.cn
http://l4W2FWyC.cLqpj.cn
http://y3F0fcKr.cLqpj.cn
http://58d2RHdI.cLqpj.cn
http://7umu0Q6J.cLqpj.cn
http://9hTCpT9r.cLqpj.cn
http://5L5BltLp.cLqpj.cn
http://HMQjGNTn.cLqpj.cn
http://Ff8A9P9P.cLqpj.cn
http://Bw9doAWr.cLqpj.cn
http://0Rhnl5E1.cLqpj.cn
http://Wf2nz9LF.cLqpj.cn
http://www.dtcms.com/a/374748.html

相关文章:

  • 后端错误处理的艺术:BusinessException 与 ResultUtils 的完美分工
  • MCU、CPLD、DSP、FPGA 有什么区别,该如何选择?
  • 【React Native】点赞特效动画组件FlowLikeView
  • android studio gradle 访问不了
  • 【C++】C++11 篇二
  • Kubernetes 配置检查与发布安全清单
  • Perforce Klocwork 2025.2版本更新:默认启用现代分析引擎、支持 MISRA C:2025 新规、CI构建性能提升等
  • 工业总线协议转换核心:SG-DP_MOD-110 Profibus-DP 转 Modbus-RTU 网关,打通异构设备数据链路
  • Win系统下配置PCL库第三步之链接库的路径(超详细)
  • 【远程运维】Linux 远程连接 Windows 好用的软件:MobaXterm 实战指南
  • Java入门级教程13-多线程同步安全机制synchronized(内置锁)、JavaMail发送电子邮箱、爬取CSDN到邮箱、备份数据库
  • 玩转Docker | 使用Docker部署KissLists任务管理工具
  • STL库——map/set(类函数学习)
  • STM32 串口接收数据包(自定义帧头帧尾)
  • 正向代理,反向代理,负载均衡还有nginx
  • 用户态与内核态的深度解析:安全、效率与优化之道
  • 搭建本地gitea服务器
  • ArcGIS JSAPI 高级教程 - 倾斜摄影数据开启透明(修改源码)
  • 输电线路分布式故障监测装置技术解析
  • 概率论第四讲—随机变量的数字特征
  • 学习stm32 蓝牙
  • 数据库学习MySQL系列2、Windows11系统安装MySQL方法一.msi安装详细教程
  • STM32物联网项目---ESP8266微信小程序结合OneNET平台MQTT实现STM32单片机远程智能控制---代码篇(四)
  • 北京鲁成伟业 | 三屏加固笔记本电脑C156F3
  • 从0~1搭建技术团队的思路
  • 如何在 Unity3D 中实现圆角效果?
  • LeetCode 面试经典 150 题:多数元素(摩尔投票法详解 + 多解法对比)
  • CStringArray 和 CStringList
  • 银行业安全用电系统建设与智能化管理探析
  • 20250909_排查10.1.1.190档案库房综合管理系统20250908备份缺失问题+优化scp脚本(把失败原因记录进日志)并测试脚本执行情况