处理器微架构
1. 概述
微架构(Microarchitecture)是 ISA 的具体硬件实现方案。同一 ISA 可以有多种微架构实现,在性能、功耗、面积之间做不同取舍。
核心目标:在给定功耗和面积约束下,最大化指令吞吐量(IPC)。
2. 经典五级流水线
2.1 流水线阶段
将指令执行分为五个阶段,每个阶段由独立硬件完成,不同指令的不同阶段可以重叠执行:
graph LR
IF[IF<br/>取指] --> ID[ID<br/>译码/读寄存器]
ID --> EX[EX<br/>执行/计算地址]
EX --> MEM[MEM<br/>访存]
MEM --> WB[WB<br/>写回]
| 阶段 | 全称 | 功能 |
|---|---|---|
| IF | Instruction Fetch | 从 I-Cache 取指令,PC += 4 |
| ID | Instruction Decode | 译码指令,读取源寄存器 |
| EX | Execute | ALU 运算或地址计算 |
| MEM | Memory Access | Load/Store 访问 D-Cache |
| WB | Write Back | 将结果写回目标寄存器 |
2.2 流水线加速比
理想情况下,\(k\) 级流水线执行 \(n\) 条指令:
当 \(n \gg k\) 时,\(S \approx k\),即加速比趋近于流水线级数。
数值示例
5 级流水线执行 100 条指令:
接近理想加速比 5。
实际中,由于冒险(Hazards)的存在,流水线无法总是满载运行。
3. 流水线冒险
3.1 数据冒险(Data Hazard)
后续指令依赖前序指令的结果,但结果尚未产生。
类型(按数据依赖分类):
| 类型 | 含义 | 示例 |
|---|---|---|
| RAW(Read After Write) | 写后读,真依赖 | add x1,x2,x3; sub x4,x1,x5 |
| WAR(Write After Read) | 读后写,反依赖 | 乱序执行中可能出现 |
| WAW(Write After Write) | 写后写,输出依赖 | 乱序执行中可能出现 |
解决方案:
- 转发/旁路(Forwarding/Bypassing):将 EX 或 MEM 阶段的结果直接送给需要的指令,无需等待 WB
- 流水线暂停(Stalling):插入气泡(bubble),等待数据就绪
- 编译器调度:重排指令顺序避免冒险
3.2 控制冒险(Control Hazard)
分支指令的跳转方向未确定时,后续取指不知道取哪条路径。
影响:分支指令可能导致 1-3 个周期的流水线气泡。
解决方案:
- 延迟槽(Branch Delay Slot):分支后的指令总是执行(MIPS 方案,已过时)
- 分支预测(Branch Prediction):预测分支方向,投机执行
3.3 结构冒险(Structural Hazard)
多条指令同时需要同一硬件资源。
解决方案:
- 硬件资源复制(如分离 I-Cache 和 D-Cache)
- 流水线暂停
4. 分支预测
分支预测是现代处理器的关键技术,预测准确率直接影响 IPC。
4.1 静态预测
- Always Not Taken:假设不跳转
- Always Taken:假设跳转
- BTFN(Backward Taken, Forward Not Taken):向后跳转预测为taken(循环场景)
4.2 动态预测
分支历史表(BHT / Branch History Table)
使用 PC 低位索引,记录过去的分支行为:
- 1-bit 预测器:记录上次是否跳转。嵌套循环性能差(每次循环边界错两次)
- 2-bit 饱和计数器:需要连续两次预测错误才改变预测方向
预测 Taken
┌──────────────┐
│ │
▼ Taken │ Not Taken
[11] ────────► [11] ────────► [10]
ST ST WT
│
Taken │ Not Taken
┌──── [01] ◄───┘
│ WN
▼
[00]
SN
状态:ST(Strongly Taken)、WT(Weakly Taken)、WN(Weakly Not Taken)、SN(Strongly Not Taken)
分支目标缓冲器(BTB / Branch Target Buffer)
- 缓存分支指令地址 → 跳转目标地址的映射
- 在 IF 阶段就能知道跳转目标,减少 penalty
竞赛预测器(Tournament Predictor)
组合多个预测器,用 meta-predictor 选择当前更准确的那个:
- 局部预测器:基于单条分支的历史模式
- 全局预测器:基于所有分支的全局历史
- Meta 选择器:跟踪哪个预测器对当前分支更准确
现代处理器(如 Intel Alder Lake)分支预测准确率超过 97%。
4.3 间接跳转预测
- 函数指针、虚函数调用、switch-case → 目标地址不固定
- 使用 Indirect Branch Target Array 记录历史目标
5. 乱序执行(Out-of-Order Execution)
5.1 动机
顺序执行中,一条长延迟指令(如 cache miss)会阻塞后续所有无关指令。乱序执行允许就绪的指令先执行。
5.2 Tomasulo 算法
IBM 360/91 首创(1967),核心思想:寄存器重命名 + 保留站分布式调度。
关键组件:
| 组件 | 功能 |
|---|---|
| 保留站(Reservation Station) | 缓存等待操作数的指令,操作数就绪即发射 |
| 公共数据总线(CDB) | 广播计算结果,所有等待该结果的保留站同时获取 |
| 重排序缓冲区(ROB) | 保证指令按程序顺序提交(精确异常) |
执行流程:
- 发射(Issue):指令进入保留站,寄存器重命名消除 WAR/WAW
- 执行(Execute):操作数就绪后在功能单元执行
- 写结果(Write Result):结果通过 CDB 广播
- 提交(Commit):ROB 头部指令按序提交到寄存器文件
graph TB
A[指令队列] --> B[发射 Issue]
B --> C[保留站 RS]
C --> D{操作数就绪?}
D -->|是| E[功能单元执行]
D -->|否| F[等待 CDB 广播]
F --> D
E --> G[CDB 广播结果]
G --> C
G --> H[重排序缓冲区 ROB]
H --> I[按序提交 Commit]
5.3 寄存器重命名
物理寄存器数 >> 架构寄存器数,通过重命名消除假依赖:
原始代码(WAW 依赖): 重命名后:
add x1, x2, x3 add p10, p2, p3
sub x4, x1, x5 sub p11, p10, p5
mul x1, x6, x7 mul p12, p6, p7 ← x1 重命名为 p12,与 p10 无关
6. 超标量处理器(Superscalar)
6.1 基本概念
每个时钟周期取指、译码、发射、执行多条指令。
实际 IPC 受限于数据依赖、分支预测错误、cache miss。
典型配置:
| 处理器 | 发射宽度 | 实际 IPC |
|---|---|---|
| ARM Cortex-A78 | 4-wide | ~3 |
| Intel Golden Cove | 6-wide | ~4-5 |
| Apple Firestorm (M1) | 8-wide | ~5-6 |
6.2 SMT(Simultaneous Multithreading)
在同一物理核心上同时执行多个硬件线程:
- Intel 称为 Hyper-Threading
- 共享执行单元、Cache,各线程有独立架构状态(寄存器、PC)
- 提升功能单元利用率(一个线程 stall 时另一个线程可利用空闲单元)
- 典型收益:单核 +20-30% 吞吐量
7. VLIW(Very Long Instruction Word)
7.1 设计理念
将指令级并行的发现工作交给编译器而非硬件:
- 编译器将多个可并行操作打包进一条「超长指令」
- 硬件无需复杂的乱序调度逻辑 → 更简单、更省功耗
7.2 优劣势
| 优势 | 劣势 |
|---|---|
| 硬件简单 | 二进制兼容性差 |
| 功耗低 | 编译器优化难度大 |
| 确定性延迟 | NOP 填充浪费带宽 |
代表:Intel Itanium(IA-64,商业失败)、TI DSP(嵌入式领域成功)
8. 现代微架构实例
Apple M 系列(Firestorm + Icestorm)
- 大核 Firestorm:8 发射、630+ ROB、192 KB L1I、128 KB L1D
- 小核 Icestorm:4 发射、低功耗
- big.LITTLE 异构:高性能核 + 高能效核
AMD Zen 系列
- 前端:分支预测→取指→译码(4-wide)→ micro-op cache
- 后端:整数执行单元 × 6 + 浮点/SIMD × 4
- 6 发射宽度,256 项 ROB
9. 性能分析:CPI 堆栈
性能优化思路
- \(\text{CPI}_{\text{cache miss}}\):优化数据局部性、预取 → 见 存储层次设计
- \(\text{CPI}_{\text{branch mispredict}}\):改进分支预测器、减少分支(branchless 编程)
- \(\text{CPI}_{\text{data hazard}}\):编译器指令调度
- 整体提升发射宽度和乱序窗口大小 → 更高 IPC