ARM内核与寄存器

ARM内核与寄存器详解

目录

ARM架构概述

ARM(Advanced RISC Microprocessor)是一种RISC(精简指令集计算机)处理器架构,最初由Acorn计算机公司设计,现在由ARM公司开发和授权。由于其低功耗和高性能特性,ARM处理器广泛应用于移动设备、嵌入式系统和物联网设备。

ARM架构已经发展了多个版本,从ARMv1到最新的ARMv9,不同版本引入了不同的功能和改进。主要的架构系列包括:

  • Cortex-A系列:应用处理器,用于高性能系统
  • Cortex-R系列:实时处理器,用于需要快速响应的系统
  • Cortex-M系列:微控制器,用于低功耗嵌入式设备

ARM处理器模式

ARM处理器有多种操作模式,每种模式有不同的寄存器可见性和权限级别:

模式 描述 进入方式
用户模式 普通程序执行 程序正常运行
系统模式 特权操作系统任务 软件切换
管理模式 系统保护模式 软件中断
中止模式 处理内存访问违例 数据或指令预取中止
未定义模式 处理未定义指令 遇到未定义指令
快速中断模式 高优先级中断处理 FIQ中断
中断模式 中断处理 IRQ中断

Cortex-M3内核的处理器模式

注意:Cortex-M3内核采用了简化的处理器模式系统,与传统ARM架构不同。Cortex-M3主要有两种运行模式:

  1. 线程模式(Thread Mode) - 用于运行应用程序代码
  2. 处理器模式(Handler Mode) - 用于处理所有异常

Cortex-M3还引入了特权级别的概念:

  • 特权访问 - 可访问所有系统资源
  • 非特权访问 - 受限制的资源访问

以下是Cortex-M3中不同情况的模式对应关系:

传统ARM模式 Cortex-M3对应情况 实际例子
用户模式 线程模式(非特权) 运行普通应用程序代码,如循环计算任务
系统模式 线程模式(特权) 操作系统执行特权操作,如初始化外设、配置MPU
管理模式 通过SVC异常进入Handler模式 应用程序调用SVC指令请求操作系统服务,如SVC #0切换任务
中止模式 MemManage异常进入Handler模式 程序访问MPU禁止的内存区域;设置了只读区域但尝试写入
未定义模式 UsageFault异常进入Handler模式 执行了未支持的浮点指令;除零操作;未对齐的内存访问
快速中断模式 没有直接对应,所有中断进入Handler模式 EXTI外部中断;高优先级的ADC转换完成中断
中断模式 没有直接对应,所有中断进入Handler模式 UART接收完成中断;SysTick系统定时器中断
Cortex-M3异常处理示例:
  1. 硬故障(HardFault)例子

    • 程序尝试执行未映射内存区域的代码
    • 访问了未对齐的内存地址
    • 在中断处理过程中出现嵌套错误
  2. SVC(管理模式)例子

    c 复制代码
    // 通过SVC调用请求操作系统服务
    __asm("SVC #42");  // 调用42号系统服务,例如RTOS切换任务
  3. BusFault例子

    c 复制代码
    // 访问无效的外设地址
    volatile uint32_t *ptr = (uint32_t *)0x60000000; // 假设这是无效总线地址
    *ptr = 0x1234;  // 触发BusFault异常
  4. 使用故障例子

    c 复制代码
    // 未对齐的访问(如果启用了对齐检查)
    volatile uint32_t *ptr = (uint32_t *)0x20000001; // 非4字节对齐地址
    *ptr = 0x1234;  // 触发UsageFault异常

Cortex-A系列处理器模式

Cortex-A系列处理器保留了传统ARM架构的7种处理器模式,并增加了安全扩展和虚拟化扩展模式。以下是Cortex-A核在不同情况下的模式例子:

模式 Cortex-A对应情况 实际例子
用户模式 低特权应用程序 手机上运行的普通APP;Linux用户空间程序
系统模式 高特权操作系统代码 操作系统内核执行特权任务;驱动程序操作硬件
管理模式 系统调用处理 应用程序通过SWI/SVC请求系统服务;Android的Binder调用
中止模式 内存访问违例处理 程序访问受MMU保护的内存区域;Linux中的段错误(SIGSEGV)
未定义模式 处理未识别指令 程序执行平台不支持的指令;尝试执行NEON指令但硬件不支持
快速中断模式 高优先级外设中断 DMA传输完成;高速存储器控制器中断;显示刷新中断
中断模式 普通外设中断处理 触摸屏输入;按键中断;传感器数据就绪中断
监视模式 TrustZone安全世界 安全认证;指纹处理;支付系统隔离
虚拟机模式 虚拟化支持(ARMv7-A) 虚拟机管理程序;Docker容器环境切换
Cortex-A与Cortex-M主要区别:
  1. 处理器模式实现:

    • Cortex-A: 完整的7种模式+扩展模式,通过CPSR控制
    • Cortex-M: 简化为线程模式和处理器模式两种,通过异常入口管理
  2. 特权级别:

    • Cortex-A: 通过处理器模式区分特权
    • Cortex-M: 明确的特权/非特权状态区分
  3. 异常处理:

    • Cortex-A: 使用向量表+模式切换
    • Cortex-M: 统一的异常机制,自动保存/恢复上下文
Cortex-A异常处理示例:
c 复制代码
// Cortex-A中的异常向量表设置
// 通常在汇编启动文件中定义
void vectors(void) __attribute__((section("vectors")));
void vectors(void) {
    asm("b reset_handler");      // 复位处理
    asm("b undefined_handler");  // 未定义指令
    asm("b svc_handler");        // 软件中断(SVC)
    asm("b prefetch_handler");   // 取指中止
    asm("b data_handler");       // 数据中止
    asm("b unused_handler");     // 未使用
    asm("b irq_handler");        // 中断
    asm("b fiq_handler");        // 快速中断
}

// SVC示例 - Linux系统调用
int main() {
    int result;
    // 调用write系统调用(4号)
    asm("mov r0, #1");          // 文件描述符1(stdout)
    asm("ldr r1, =message");    // 消息缓冲区
    asm("mov r2, #13");         // 消息长度
    asm("mov r7, #4");          // write系统调用号
    asm("swi #0");              // 执行系统调用
    asm("mov %0, r0" : "=r" (result));
    return 0;
}

ARM寄存器集

通用寄存器

ARM架构提供16个32位通用寄存器(R0-R15),其中R13-R15有特殊用途:

寄存器 别名 描述 使用约定
R0 - 通用寄存器 第一个函数参数,函数返回值
R1-R3 - 通用寄存器 函数参数
R4-R11 - 通用寄存器 需在函数调用间保存
R12 IP 程序内部暂存寄存器 过程调用中临时使用
R13 SP 堆栈指针 指向当前堆栈顶部
R14 LR 链接寄存器 保存子程序返回地址
R15 PC 程序计数器 指向当前执行指令

程序计数器(PC)

PC寄存器(R15)保存当前执行指令的地址。在ARM状态下,PC指向当前指令地址+8;在Thumb状态下,PC指向当前指令地址+4。

使用方法:

  • 读取PC获得当前指令附近的地址
  • 向PC写入值实现跳转
assembly 复制代码
MOV R0, PC      @ 获取当前PC值
MOV PC, LR      @ 从子程序返回

链接寄存器(LR)

LR寄存器(R14)用于存储子程序返回地址。当执行BL(分支并链接)指令时,返回地址被自动保存到LR中。

使用方法:

  • 调用子程序前保存LR(如果子程序内还会调用其他函数)
  • 子程序返回时将LR的值复制到PC
assembly 复制代码
PUSH {LR}       @ 保存返回地址
BL subroutine   @ 调用子程序
POP {PC}        @ 恢复返回地址并返回

堆栈指针(SP)

SP寄存器(R13)指向当前堆栈顶部。ARM通常采用满递减(Full Descending)堆栈,即SP指向最后一个已入栈的数据项。

使用方法:

  • PUSH操作前先减少SP,再存储
  • POP操作先加载,再增加SP
assembly 复制代码
PUSH {R0-R3}    @ 将R0-R3压入堆栈
POP {R0-R3}     @ 从堆栈弹出到R0-R3

状态寄存器(CPSR/SPSR)

当前程序状态寄存器(CPSR)和保存的程序状态寄存器(SPSR)包含处理器状态信息。

CPSR字段:

  • 条件标志(N,Z,C,V):用于条件执行
  • 控制位:处理器模式、中断禁用标志、指令集状态等

条件标志:

  • N(负数):结果为负
  • Z(零):结果为零
  • C(进位):产生进位
  • V(溢出):有符号溢出
assembly 复制代码
CMP R0, R1      @ 比较R0和R1,设置条件标志
ADDPL R0, R0, #1 @ 如果结果非负(N=0)则执行加法

协处理器寄存器

ARM架构支持协处理器扩展,包括CP15系统控制协处理器。CP15寄存器控制缓存、MMU、系统控制和配置。

访问方法:

assembly 复制代码
MRC p15, 0, R0, c1, c0, 0  @ 读取CP15 c1寄存器到R0
MCR p15, 0, R0, c1, c0, 0  @ 写入R0到CP15 c1寄存器

NEON和VFP寄存器

现代ARM架构包含NEON和VFP(向量浮点)扩展,提供额外的寄存器用于SIMD和浮点运算:

  • 32个64位寄存器(D0-D31)
  • 也可视为16个128位寄存器(Q0-Q15)
assembly 复制代码
VMOV.F32 S0, #1.0        @ 加载浮点常量到S0
VADD.F32 S0, S0, S1      @ 浮点加法
VLDM R0, {D0-D3}         @ 加载多个64位寄存器

寄存器使用规范

ARM架构定义了AAPCS(ARM架构过程调用标准)规范:

  • R0-R3:参数传递和结果返回,调用者保存
  • R4-R11:局部变量,被调用者保存
  • R12(IP):内部过程调用暂存,调用者保存
  • R13(SP):堆栈指针,被调用者保存
  • R14(LR):链接寄存器,被调用者保存
  • R15(PC):程序计数器

参数传递机制

当函数参数超过4个时,ARM采用以下策略:

  • 前4个参数通过R0-R3寄存器传递
  • 额外的参数通过栈传递,从右到左入栈
  • 参数在栈上按照4字节对齐
  • 被调用者负责从栈上获取额外参数

示例:调用有6个参数的函数func(a, b, c, d, e, f)

assembly 复制代码
MOV R0, #1          @ 第一个参数 a
MOV R1, #2          @ 第二个参数 b
MOV R2, #3          @ 第三个参数 c
MOV R3, #4          @ 第四个参数 d
PUSH {R5, R6}       @ 将第五和第六个参数入栈 (f先入栈,e后入栈)
MOV R5, #6          @ 第六个参数 f (先入栈)
MOV R6, #5          @ 第五个参数 e (后入栈)
PUSH {R5, R6}
BL func             @ 调用函数
ADD SP, SP, #8      @ 调用完成后恢复栈(清理参数)

对于返回值:

  • 32位或更小的返回值保存在R0中
  • 64位返回值使用R0和R1
  • 更大的结构体通过引用返回,调用者提供内存地址作为隐式第一个参数

常见ARM指令与寄存器操作

数据处理指令:

assembly 复制代码
MOV R0, R1          @ R0 = R1
ADD R0, R1, R2      @ R0 = R1 + R2
SUB R0, R1, #1      @ R0 = R1 - 1
AND R0, R1, #0xFF   @ R0 = R1 & 0xFF

内存访问指令:

assembly 复制代码
LDR R0, [R1]        @ 从R1指向的地址加载到R0
STR R0, [R1, #4]    @ 存储R0到R1+4指向的地址
LDMIA R1!, {R0-R4}  @ 多寄存器加载,递增后更新R1
STMDB R13!, {R0-R3} @ 多寄存器存储,递减前更新R13

分支指令:

assembly 复制代码
B label             @ 无条件分支
BL function         @ 分支并链接(调用子程序)
BX LR               @ 分支并切换状态(常用于返回)
CMP R0, #0          @ 比较R0与0
BEQ zero_label      @ 相等时分支

条件执行:

assembly 复制代码
ADDEQ R0, R0, R1    @ 当Z=1时执行加法
MOVNE R0, #0        @ 当Z=0时执行赋值
相关推荐
zd8451015001 小时前
STM32 HAL DHT11驱动程序
stm32·单片机·嵌入式硬件
lzb7591 小时前
蓝桥杯单片机刷题——ADC测量电位器的电压
单片机·蓝桥杯
_She0011 小时前
硬件知识积累 单片机+ 光耦 + 继电器需要注意的地方
单片机·嵌入式硬件
南梦也要学习4 小时前
STM32江科大-----SPI
stm32·单片机·嵌入式硬件
willhu20084 小时前
Keil调试STM32:未定义OS_EVENT以及停在“BEAB BKPT 0xAB”处等问题
stm32·单片机·嵌入式硬件
卡尔曼的BD SLAMer4 小时前
问题 | 对于初学者来说,esp32和stm32哪个比较适合?
stm32·单片机·嵌入式硬件
不脱发的程序猿4 小时前
ESP32与STM32哪种更适合初学者?
arm开发·stm32·嵌入式硬件
lzb7596 小时前
蓝桥杯单片机刷题——通过按键触发串口传输电压值
单片机·蓝桥杯
鑫—萍6 小时前
数据结构与算法——链表OJ题详解(2)
c语言·开发语言·数据结构·学习·算法·链表
小百小摆7 小时前
合并2(K)个链表、排序链表
数据结构·链表