【ARMday02】

ARM的7种工作模式:

  • User:非特权模式(用户模式),大部分任务执行在这种模式
  • FIQ:(快速中断模式)当一个高优先级(fast)中断产生时将会进入这种模式
  • IRQ:(普通中断模式)当一个低优先级(normal)中断产生时将会进入这种模
  • Supervisor:当复位或软中断指令执行时将会进入这种模式
  • Abort:(终止模式)当存取异常时将会进入这种模式
  • Undef:(未定义模式)当执行未定义指令时会进入这种模式
  • System:使用和User模式相同寄存器集的特权模式

切换情况

  • 硬件触发:中断、异常(比如 IRQ/FIQ/Abort/Undefined)会自动切换模式;

  • 软件触发 :执行 SWI 指令进入 SVC;

  • 手动切换:通过修改 CPSR 模式位。

启动代码的主要任务:

  • 初始化异常向量表;
  • 初始化各工作模式的栈指针寄存器;
  • 开启arm内核中断允许;
  • 将工作模式设置为user模式;
  • 完成上述工作后,引导程序进入c语言主函数执行;

格式:

  • area: 这是最重要的一个伪操作,用于定义一个段。程序、数据、堆栈等都需要被组织在不同的段中。
  • reset: 这是你为这个段起的名字。名字 reset 具有很强的暗示性,通常用于表示复位向量段,即CPU上电或复位后首先执行的第一段代码所在的位置。
  • code: 指定该段的属性为代码,意味着这个段包含可执行的指令。
  • readonly: 指定该段的属性为只读。对于代码段来说,这通常是默认且必须的。
  • code32: 表示后续指令使用 32位的 ARM 指令集。
  • thumb: 表示后续指令使用 16位的 Thumb 指令集。

指令:

mov

MOV{S}<c> <Rd>, #<const>

MOV{S}<c> <Rd>, <Rm>

MOV instruction Canonical form

  • MOV{S} <Rd>, <Rm>, ASR #<n> ASR{S} <Rd>, <Rm>, #<n>
    • ASR算数右移n位
  • MOV{S} <Rd>, <Rm>, LSL #<n> LSL{S} <Rd>, <Rm>, #<n>
    • LSL逻辑左移n位
  • MOV{S} <Rd>, <Rm>, LSR #<n> LSR{S} <Rd>, <Rm>, #<n>
    • LSR逻辑右移n位
  • MOV{S} <Rd>, <Rm>, ROR #<n> ROR{S} <Rd>, <Rm>, #<n>
    • ROR循环右移n位

移位量来自寄存器Rs

  • MOV{S} <Rd>, <Rm>, ASR <Rs> ASR{S} <Rd>, <Rm>, <Rs>
  • MOV{S} <Rd>, <Rm>, LSL <Rs> LSL{S} <Rd>, <Rm>, <Rs>
  • MOV{S} <Rd>, <Rm>, LSR <Rs> LSR{S} <Rd>, <Rm>, <Rs>
  • MOV{S} <Rd>, <Rm>, ROR**<Rs>** ROR{S} <Rd>, <Rm>,<Rs>
  • MOV{S} <Rd>, <Rm>, RRX RRX{S} <Rd>, <Rm>

基本概念:

  • <Rd>:目的寄存器(左值,类似 C 里赋值号左边)
  • <Rm> / <Rs>:源寄存器(右值,来自谁)
  • #<const> / #<n>:立即数(写死在指令里的常数)
  • {S}:可选的 S 后缀,写成 MOVS。带 S 会更新标志位(APSR 里的 N/Z/C/V)。不带 S 不改标志位。
  • <c>:可选 条件码 (如 EQ/NE/GT/...),满足条件才执行
  • 移位量#<n>/<Rs> 取值范围 (0 - 31)

lsl:逻辑左移:低位补0,高位丢弃(相当于乘以2)

lsr:逻辑右移:高位补0,低位丢弃(相当于除以2)

ror:循环右移,移出的位从左边绕回

asr:算数右移:往右补符号位,常用于有符号数除以2

ADD(加法指令)

ADD{S}<c> <Rd>, <Rn>, <operand2>

  • <Rd>:目的寄存器(结果放哪)。

  • <Rn>:第一个操作数(通常是寄存器)。

  • <operand2>:第二操作数(可以是立即数或寄存器,寄存器可带移位)。

    • 立即数作为第二操作数:

      • ADD{S}<c> <Rd>, <Rn>, #<const>
    • 寄存器作为第二操作数寄存器:

      • ADD{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
    • 寄存器作为第二操作数移位量:

      • ADD{S}<c> <Rd>, <Rn>, <Rm>, <type> <Rs>
  • {S}:可选,写成 ADDS更新条件标志位(N/Z/C/V)。

  • <c>:可选条件码(如 EQ/NE/...),指令只有在满足条件时才执行。

ADDS 会更新 APSR 的 N/Z/C/V:

  • N(Negative):结果的最高位(bit31)。

  • Z(Zero):结果是否为 0(是则 Z=1)。

  • C(Carry):无符号加法时的进位(即 32-bit 加法是否有向 33 位进位产生)。

  • V(Overflow):有符号加法时溢出(例如正数+正数变成负数,或负数+负数变成正数)。

sub(减法指令)

  • 立即数作为第二操作数:
    • SUB{S}<c> <Rd>, <Rn>, #<const>
  • 寄存器作为第二操作数寄存器:
    • SUB{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
  • 寄存器作为第二操作数移位量:
    • SUB{S}<c> <Rd>, <Rn>, <Rm>, <type> <Rs>

SUBS,会更新 APSR 四个标志:

  • N(Negative)= 结果的最高位(bit31)。

  • Z(Zero)= 结果是否为 0(是则 Z=1)。

  • C (Carry)= 对减法来说,C = 1 当且仅当 没有借位 (也就是 Rn ≥ operand2 按无符号比较);如果产生借位,则 C = 0。

    • 举例:0x00000005 - 0x00000003 → 没有借位 → C=1

    • 0x00000003 - 0x00000005 → 需要借位 → C=0

  • V(Overflow)= 有符号减法溢出标志(例如正数减负数等导致符号变化的不合理情况)。

什么是立即数?如何判断某数是否合法为 12 位立即数?

在 ARM 数据处理指令中,第二操作数可以是寄存器,也可以是 立即数。立即数就是直接写在指令里的常量。

**12位立即数imm12:**把某个数转为2进制,该数必须存在一种循环右移(偶数位),使得移位后高24位全0,低8位即为有效imm8;任何能表示成"一个 8-bit 值向右循环旋转偶数位"的 32-bit 数都能编码成这个 imm12。

  • 0xFF → 可表示(imm8=0xFF, rotate=0)

  • 0x80000000 → 可表示(imm8=0x80, rotate=8)

  • 0xFFFFFFFF → 不能表示(需要 MVN r0, #0 或 LDR 伪指令)。

LDR(加载指令)

LDR<c> <Rt>, <label>,用来把内存内容装到寄存器

SDR(存放指令)

将寄存器内容写到内存,与LDR对称

MVN(按位取反移动指令)

  • MVN{S}<c> <Rd>, #<const>
  • MVN{S}<c> <Rd>, <Rm>{, <shift>}
  • MVN{S}<c> <Rd>, <Rm>, <type> <Rs>

bic(bit clear):指定位置清0

  • BIC{S}<c> <Rd>, <Rn>, #<const>
  • BIC{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
  • BIC{S}<c> <Rd>, <Rn>, <Rm>, <type> <Rs>

orr(or):指定位置1

  • ORR{S}<c> <Rd>, <Rn>, #<const>
  • ORR{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
  • ORR{S}<c> <Rd>, <Rn>, <Rm>, <type> <Rs>

条件判断标志NZCV

CPSR寄存器中条件判断标志位

N: 符号标志位:上条指令执行结果最高位bit31为1,则 N = 1, 当结果作为有符号解释时为负值;

Z: 零值标志位:上条指令执行结果为0(即bit0 - bit31 均为0),则 Z = 1;

C: 进位标志位:进行无符号解读,如果在加法过程中进位或者减法时没有借位,则为 C = 1,否则 C = 0

V: 溢出标志位:进行有符号解读,是否发生溢出 -2^31 - 2^31-1(两个正数加得负数,两个负数加得正数)

条件码:eq ge gt le lt al(无条件执行)

equal:等于

not equal:不等于

cmp(compare):比较指令

CMP<c> <Rn>, #<const>

CMP<c> <Rn>, <Rm>{, <shift>}

CMP<c> <Rn>, <Rm>, <type> <Rs>

b bl bx :(跳转指令)

B<c> <label>

b fun <==> ldr pc, =fun

B <label> :无条件跳转到 label,相当于 pc = label,不保存返回地址。

BL<c> <label>

bl fun
BL <label>调用时把返回地址写入链接寄存器 LR(R14),然后跳到目标。常用于函数调用

BX<c> <Rm>

bx lr <==> mov pc, lr

BX <Rm>BX Rm 从寄存器 Rm 读取目标地址并跳转,跳转到寄存器 Rm 的值,可以用于从函数返回(bx lr),也可以实现 ARM/Thumb 状态切换。

常见用法:

  • b fun→ 死循环跳转,不返回;

  • bl fun → 调用函数,返回地址存在 lr

  • bx lr→ 从函数返回。

ARM内核采用的栈是哪种栈?

使用的是满减栈,即栈向低地址方向增长,SP指向当前栈顶位置,每次压栈(push)会使SP减小,出栈(pop)会使SP增大。

"满":SP始终指向当前已经使用的栈顶元素,而不是下一个空闲位置

"递减"栈向低地址方向增长(高地址➡低地址)

在 ARM 的过程调用标准(AAPCS)中,还有一个约定:进入函数接口时,SP 必须保持 8 字节对齐,保证数据访问高效。

ARM 汇编调用 C 函数,或者 C 调用汇编函数时,参数和返回值如何处理?

ARM 遵循 AAPCS(ARM Procedure Call Standard) 约定:

  1. 参数传递规则

    • 前四个参数依次放在 r0、r1、r2、r3

    • 如果参数超过四个,多余的参数会从 右到左 依次压入栈中,由调用者负责分配。

    • 栈在函数入口时必须保持 8 字节对齐

  2. 返回值规则

    • 如果返回值是 32 位整型或指针,放在 r0

    • 如果是 64 位整型或 double,放在 r0:r1

    • 如果返回值是一个较大的结构体,通常由调用者传入一个隐藏指针,返回值写到该内存地址中。

  3. 寄存器保存约定

    • 调用者需要保存 易变寄存器(caller-saved)r0--r3, r12, lr

    • 被调用者需要保存 非易变寄存器(callee-saved)r4--r11

举个例子

如果 C 调用一个汇编函数 int add3(int a, int b, int c)

  • 编译器会把 a, b, c 放到 r0, r1, r2

  • 汇编里直接用 r0, r1, r2 做加法,结果放回 r0

  • 最后 bx lr 返回。

反过来,如果汇编里要调用一个 C 函数:

  • 把参数准备好放在 r0--r3 或栈中。

  • bl func 调用,返回值自动在 r0

1、什么是RISC、CISC;

RISC 和 CISC 是两种指令集设计理念:

  • RISC(精简指令集计算机):指令集简单,每条指令执行时间短,寻求"硬件简单 + 软件优化",代表是 ARM、MIPS。

  • CISC(复杂指令集计算机):指令集复杂,指令功能丰富,单条指令可以完成复杂操作,代表是 x86。

  • ARM 作为 RISC 架构,特点是指令长度固定(大多数是 32 位,Thumb 是 16 位),流水线容易优化,功耗低。

2、冯.诺伊曼架构和哈佛架构有何区别?ARM内核属于哪一种?

  • 冯·诺伊曼架构:指令和数据共享一条总线,存储空间统一。优点是硬件简单,缺点是容易产生"瓶颈"。

  • 哈佛架构:指令和数据分开存储、分开总线,可以同时取指和访存,效率更高。

ARM 内核一般采用 改进型哈佛架构:内部取指和数据访问分离(提高并行度),但在外部存储器接口上可以统一成一个总线,兼顾效率和灵活性。

3、ARM内核中都有什么?

ARM 内核主要包括:

  • 通用寄存器:R0--R12;

  • 堆栈指针 SP (R13)、链接寄存器 LR (R14)、程序计数器 PC(R15);

  • CPSR(当前程序状态寄存器),保存标志位和工作模式;

  • SPSR(保存程序状态寄存器),用于异常返回时恢复现场;

  • 流水线(典型 3 级:取指、译码、执行);

  • 异常向量表 和 模式切换机制。

可以简单概括为:寄存器文件 + 状态寄存器 + 流水线 + 异常机制

4、ARM有几种工作模式?

ARM 有 7 种主要工作模式:

  1. User(用户模式):普通应用程序运行;

  2. FIQ(快速中断模式)

  3. IRQ(普通中断模式)

  4. Supervisor(管理模式,操作系统用)

  5. Abort(异常模式,存储器访问错误)

  6. Undefined(未定义指令模式)

  7. System(系统模式,特权模式,运行内核任务)

其中 User 模式权限最低,其余为特权模式。

5、什么是异常向量表?

异常向量表是 ARM 处理器在发生异常或中断时,跳转执行的入口地址表

  • 它一般存放在地址 0x000000000xFFFF0000

  • 每种异常都有固定入口,比如:

    • Reset:0x00

    • Undefined:0x04

    • SWI:0x08

    • Prefetch Abort:0x0C

    • Data Abort:0x10

    • IRQ:0x18

    • FIQ:0x1C

这样 CPU 在异常发生时,就能根据异常类型跳转到对应入口地址去执行服务例程。

相关推荐
世微 如初8 小时前
无需外部补偿的同步降压方案:AP3471在分布式供电系统中的应用
单片机·嵌入式硬件·芯片·led驱动·led电源驱动
云山工作室9 小时前
基于单片机的声光控制楼道灯(论文+源码)
单片机·嵌入式硬件
humingling9 小时前
单片机的bin、exe、elf、hex文件差异
单片机·嵌入式硬件
神仙别闹12 小时前
基于单片机的六足机器人控制系统设计
单片机·嵌入式硬件·机器人
MilesShi13 小时前
从 scheduler_tick 到上下文切换:深入解析 Linux 内核的 TIF_NEED_RESCHED 标志设置流程
linux·运维·单片机
阿让啊15 小时前
C语言strtol 函数使用方法
c语言·数据结构·c++·单片机·嵌入式硬件
DebugKitty19 小时前
硬件开发1-51单片机4-DS18B20
单片机·嵌入式硬件·51单片机·ds18b20
Hello_Embed19 小时前
STM32HAL 快速入门(十九):UART 编程(二)—— 中断方式实现收发及局限分析
笔记·stm32·单片机·嵌入式硬件·学习
沐欣工作室_lvyiyi19 小时前
基于单片机的可燃性气体泄漏智能报警系统
stm32·单片机·嵌入式硬件·毕业设计