1. ARMv7架构概述:从ARM公司到指令集家族

各位同学,咱们今天正式开讲ARMv7。在开始之前,我想先聊聊ARM这家公司。很多人以为ARM是芯片制造商,其实不是。ARM只做一件事——卖IP授权。你买它的指令集架构和微架构设计,然后自己找代工厂生产。我当年第一次接触这个模式时也挺惊讶的,后来做项目多了才明白,正是这种轻资产模式,让ARM几乎统治了嵌入式世界。

1.1 ARM公司简史:从Acorn到软银

ARM的故事要从1985年说起。英国Acorn电脑公司想搞一颗自己的CPU,当时Intel的80286太贵,Motorola的68000又不好用。Acorn的工程师们一合计,干脆自己设计一个精简指令集处理器——这就是ARM1的原型。

有意思的是,ARM这个名字最初是Acorn RISC Machine的缩写。后来Acorn把芯片部门独立出来,改名为Advanced RISC Machines,简称ARM。1998年ARM在伦敦证交所上市,之后一路高歌猛进。2016年软银以320亿美元收购ARM,2023年又再次上市——这中间的故事够写一本书了。

我个人觉得,ARM成功的关键在于抓住了两个风口:低功耗移动设备和嵌入式系统。你想想看,90年代Intel和AMD在PC市场打得不可开交,ARM却悄悄在手机、PDA、路由器这些领域扎根。等到智能手机爆发时,ARM已经成了事实标准。

年份 里程碑 我的备注
1985 ARM1诞生(Acorn RISC Machine) 26位地址总线,现在看来很原始
1990 ARM公司正式成立 从Acorn独立出来
1993 ARM7发布 经典的三级流水线架构
2002 ARMv5架构(ARM9E系列) 开始支持DSP指令扩展
2005 ARMv7架构发布 我们今天课程的核心
2011 ARMv8架构(64位) AArch64来了

1.2 ARMv7架构家族:Cortex-A/R/M三兄弟

ARMv7是一个分水岭。在它之前,ARM的命名体系比较混乱——ARM7、ARM9、ARM11这些名字既代表架构也代表处理器。到了ARMv7,ARM终于把产品线理清楚了,推出了三个明确的系列:Cortex-A、Cortex-R、Cortex-M。

这三个系列的设计哲学完全不同。我打个比方你就明白了:

  • Cortex-A —— 像跑车,追求极致性能,适合跑Linux/Android
  • Cortex-R —— 像赛车,追求实时响应,适合汽车、工业控制
  • Cortex-M —— 像自行车,追求低功耗低成本,适合单片机

核心要点:三个系列共享ARMv7指令集,但微架构和系统特性完全不同。选型时一定要搞清楚你的应用场景——是做实时控制还是跑操作系统?是追求性能还是省电?

Cortex-A系列(应用处理器)

这是性能担当。支持MMU(内存管理单元),可以跑Linux、Android这些复杂操作系统。我在项目中用过Cortex-A8(单核)、A9(多核)、A15(乱序执行),每个都有鲜明的特点。A9的Snoop Control Unit(SCU)在多核一致性上做得不错,但A15的功耗确实有点高——嗯,性能的代价。

Cortex-R系列(实时处理器)

这是可靠性担当。支持MPU(内存保护单元),不支持MMU。它的强项是低延迟中断响应和硬件错误检测。我曾经在一个汽车刹车控制项目中用过Cortex-R4,中断延迟可以做到几十个纳秒级别——这个数字对安全关键系统来说太重要了。

Cortex-M系列(微控制器)

这是性价比担当。没有MMU也没有MPU,但有一个简单的NVIC(嵌套向量中断控制器)。Cortex-M3/M4是嵌入式工程师最熟悉的,M0则把面积和功耗压到了极致。我记得有个传感器节点项目,用M0跑在32MHz,整机功耗不到1mW——这种场景下A系列根本没法比。

特性 Cortex-A Cortex-R Cortex-M
典型频率 500MHz ~ 2.5GHz 200MHz ~ 1GHz 16MHz ~ 400MHz
内存管理 MMU(页表) MPU(区域保护) 无(直接寻址)
中断延迟 数百纳秒 数十纳秒 数十纳秒(NVIC)
典型OS Linux, Android FreeRTOS, VxWorks 裸机, RTOS
应用场景 手机, 平板, 网关 汽车, 工业, 医疗 传感器, 家电, 玩具
ARMv7架构家族总览 ARMv7 架构 Cortex-A 系列 Cortex-R 系列 Cortex-M 系列 MMU · 乱序执行 · 多核 MPU · 低延迟 · 错误检测 NVIC · 位带 · 低功耗 手机 · 平板 · 网关 汽车 · 工业 · 医疗 传感器 · 家电 · 玩具 共享ARMv7指令集,但微架构和系统特性完全不同 选型时务必根据应用场景匹配对应系列

1.3 指令集架构对比:ARM、Thumb、Thumb-2

ARMv7支持三种指令集模式:ARM(32位)、Thumb(16位)、Thumb-2(16/32位混合)。你可能会问:为什么搞这么复杂?直接一种指令集不好吗?

原因很简单——代码密度和性能的权衡。ARM指令每条32位,功能强大但占空间;Thumb指令每条16位,代码密度高但功能受限;Thumb-2则试图取两者的长处。

ARM指令集(32位)

这是ARM的"完全体"。所有寄存器都可以访问,所有寻址模式都支持,条件执行(Conditional Execution)是它的标志性特性。每条指令前面可以加条件码——比如ADDEQ R0, R1, R2只在相等时才执行。这个特性在编译优化时很有用,可以减少分支跳转。

我在一个视频编解码项目中用过这个特性。当时有个关键循环,用条件执行替代了if-else分支,性能提升了大约15%。不过要注意,条件执行在Cortex-A上效率高,在Cortex-M上就别用了——M系列没有分支预测,条件执行反而可能拖慢速度。

Thumb指令集(16位)

Thumb是ARM的"精简版"。指令长度固定16位,只能访问R0-R7这8个低寄存器,不支持条件执行(除了BEQ/BNE等分支指令)。它的优势是代码密度高——同样的C代码,Thumb编译出来的体积比ARM小30%左右。

你想想看,在Cortex-M0这种只有几KB Flash的芯片上,代码密度就是命。我做过一个BLE Beacon项目,Flash总共8KB,用Thumb编译刚好塞下,换成ARM模式直接超了——嗯,这就是Thumb存在的意义。

Thumb-2指令集(16/32位混合)

Thumb-2是ARMv7引入的重大改进。它不再区分ARM模式和Thumb模式,而是统一使用Thumb-2指令集——指令长度可以是16位也可以是32位,由编码决定。这样既保留了Thumb的高代码密度,又恢复了ARM的大部分功能(比如访问所有寄存器、使用大部分寻址模式)。

我的建议:在Cortex-M3/M4/M7上,直接用Thumb-2模式。编译器会自动选择最合适的指令长度,你不需要手动干预。在Cortex-A上,如果你跑Linux,用户态程序用Thumb-2,内核用ARM模式——这是性能最优的搭配。

特性 ARM Thumb Thumb-2
指令长度 固定32位 固定16位 16/32位混合
寄存器访问 R0-R15(全部) R0-R7(受限) R0-R15(全部)
条件执行 全部指令支持 仅分支指令 部分指令支持
代码密度 低 高 高
性能 高 中 高
适用架构 Cortex-A/R Cortex-M0/M1 Cortex-M3+ / A / R

1.4 模式切换与互操作性

ARMv7允许在运行时切换指令集模式。切换方式很简单——通过BX或BLX指令跳转时,目标地址的最低位(LSB)决定模式:

  • LSB = 0:切换到ARM模式
  • LSB = 1:切换到Thumb/Thumb-2模式

举个例子:

; 从ARM模式跳转到Thumb函数
LDR R0, =thumb_func
BX  R0          ; 如果thumb_func地址最低位为1,则切换到Thumb模式

; 从Thumb模式跳转到ARM函数
LDR R0, =arm_func
BX  R0          ; 如果arm_func地址最低位为0,则切换到ARM模式

避坑指南:我曾经在一个项目中遇到过一个bug——函数指针调用时系统崩溃。查了两天才发现,问题出在函数指针的最低位没有正确设置。在ARMv7上,如果你用函数指针调用Thumb函数,必须确保指针的最低位为1。编译器通常会自动处理,但如果你手写汇编或者做函数指针转换,一定要小心这个细节。

1.5 本章小结

好了,第一讲的内容就到这里。我们梳理了ARM公司的发展脉络,搞清楚了Cortex-A/R/M三个系列各自的特点和适用场景,也对比了ARM、Thumb、Thumb-2三种指令集的差异。这些是ARMv7架构的基础知识,后面的章节会在此基础上深入展开。

最后留个思考题:为什么Cortex-M系列不支持MMU?如果你在设计一个低功耗微控制器,MMU会带来哪些问题?想明白了,你对嵌入式系统的理解会更深一层。