硬件(六)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>,将 rnconst 为 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 寄存器(当前程序状态寄存器)。CPSRNZCV 位含义如下:

  • 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 到 R0
    MRS R0, CPSR
    ; 清除 CPSR 的低 5 位(模式位)
    BIC R0, R0, #(0x1F)
    ; 设置为 User 模式(User 模式对应的编码是 0x10,即二进制 10000)
    ORR R0, R0, #0x10
    ; 将修改后的值写回 CPSR 的控制域(c 表示控制域)
    MSR CPSR_c, R0
    ; 设置栈指针,这里假设栈底为 0x40001000
    LDR SP, =0x40001000

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

相关推荐
默默敲代码的徐哥儿7 小时前
八股文整理——后端
java·开发语言·spring boot·后端·学习
matlab代码7 小时前
基于matlab人脸门禁识别系统(可增加其它人脸图像)源码40期】
开发语言·matlab·人脸识别·人脸门禁
池塘的蜗牛7 小时前
AFDM波形基于DFT的通感一体化
算法
李少兄8 小时前
Java CompletableFuture 解析(含常见面试题)
java·开发语言
147API8 小时前
Claude global workspace 研究给智能体测试提了一个醒
人工智能·算法·机器学习
葫三生8 小时前
《论三生原理》与模糊数学的关联、异同、互补关系?
人工智能·科技·算法·机器学习·开源
KaifuZeng8 小时前
通信与接口协议面试十一、网口
嵌入式硬件·面试·通信与接口协议
ACP广源盛139246256738 小时前
破局 PCIe 4.0 交换瓶颈@ACP#IX8024 / ASM58024参数及应用对比
大数据·人工智能·分布式·嵌入式硬件
我命由我123458 小时前
方差(实例实操、与标准差的区别)
java·数据结构·算法·数据分析·java-ee·intellij-idea·idea
闲研随记8 小时前
【文献阅读 ICML 2026】RL算法:Critique-GRPO
论文阅读·算法·llm·强化学习·rl·icml·grpo