01-CPU架构基础¶
重要性:⭐⭐⭐⭐⭐ 实用度:⭐⭐⭐⭐⭐ 学习时间:2天 必须掌握:是
为什么学这一章?¶
CPU是计算机的核心,理解CPU架构能帮助你: - 理解程序是如何真正执行的 - 写出CPU友好的高效代码 - 理解性能瓶颈所在 - 为学习汇编语言和优化打下基础
学完这一章,你将能够: - ✅ 解释CPU的基本组成部分和工作原理 - ✅ 理解寄存器的作用和分类 - ✅ 掌握CPU执行指令的基本流程 - ✅ 了解现代CPU的核心技术
📖 核心概念¶
1. CPU的基本组成¶
Text Only
┌─────────────────────────────────────────────────────────────────────┐
│ CPU架构全景图 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ 控制单元(CU) │ │
│ │ ┌─────────────────────────────────────────────────────┐ │ │
│ │ │ • 指令译码器(Instruction Decoder) │ │ │
│ │ │ • 控制信号生成器(Control Signal Generator) │ │ │
│ │ │ • 程序计数器(PC) │ │ │
│ │ │ • 时序发生器(Clock) │ │ │
│ │ └─────────────────────────────────────────────────────┘ │ │
│ │ 功能:控制协调CPU各部件工作 │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ 运算单元(ALU) │ │
│ │ ┌─────────────────────────────────────────────────────┐ │ │
│ │ │ • 算术运算:加、减、乘、除 │ │ │
│ │ │ • 逻辑运算:与、或、非、异或 │ │ │
│ │ │ • 比较运算:等于、大于、小于 │ │ │
│ │ │ • 移位运算:左移、右移 │ │ │
│ │ └─────────────────────────────────────────────────────┘ │ │
│ │ 功能:执行算术和逻辑运算 │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ 寄存器组(Registers) │ │
│ │ ┌─────────────────────────────────────────────────────┐ │ │
│ │ │ • 通用寄存器:RAX, RBX, RCX, RDX, RSI, RDI, RBP, RSP│ │ │
│ │ │ • 段寄存器:CS, DS, SS, ES, FS, GS │ │ │
│ │ │ • 特殊寄存器:PC(RIP), FLAGS(RFLAGS) │ │ │
│ │ └─────────────────────────────────────────────────────┘ │ │
│ │ 功能:高速数据存储 │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ 缓存系统(Cache) │ │
│ │ ┌─────────────────────────────────────────────────────┐ │ │
│ │ │ • L1 Cache:32-64KB,分为指令缓存和数据缓存 │ │ │
│ │ │ • L2 Cache:256KB-512KB │ │ │
│ │ │ • L3 Cache:8-64MB(多核共享) │ │ │
│ │ └─────────────────────────────────────────────────────┘ │ │
│ │ 功能:缓解CPU与内存的速度差异 │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ 内存接口(Memory Interface) │ │
│ │ • 内存管理单元(MMU) │ │
│ │ • 总线接口(Bus Interface) │ │
│ │ • 预取单元(Prefetcher) │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
2. x86-64寄存器详解¶
通用寄存器¶
Text Only
┌─────────────────────────────────────────────────────────────────────┐
│ x86-64通用寄存器(64位) │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ RAX(Accumulator)累加器 │ │
│ │ ├── 用途:函数返回值、算术运算 │ │
│ │ ├── 32位:EAX │ │
│ │ ├── 16位:AX │ │
│ │ └── 8位:AH/AL │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ RBX(Base)基址寄存器 │ │
│ │ └── 用途:数据指针(较少使用) │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ RCX(Counter)计数器 │ │
│ │ └── 用途:循环计数、字符串操作 │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ RDX(Data)数据寄存器 │ │
│ │ └── 用途:I/O操作、乘除法辅助 │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ RSI(Source Index)源索引 │ │
│ │ └── 用途:字符串/数组操作的源地址 │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ RDI(Destination Index)目的索引 │ │
│ │ └── 用途:字符串/数组操作的目的地址 │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ RBP(Base Pointer)基址指针 │ │
│ │ └── 用途:栈帧基址,访问局部变量和参数 │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ RSP(Stack Pointer)栈指针 │ │
│ │ └── 用途:指向栈顶,push/pop操作 │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ R8-R15(扩展寄存器) │ │
│ │ └── 用途:通用,函数参数(RDI, RSI, RDX, RCX, R8, R9) │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
特殊寄存器¶
Text Only
┌─────────────────────────────────────────────────────────────────────┐
│ x86-64特殊寄存器 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ RIP(Instruction Pointer)指令指针 │
│ ├── 存储下一条要执行的指令地址 │
│ ├── 自动递增(顺序执行) │
│ └── 跳转/调用时改变 │
│ │
│ RFLAGS(Flags Register)标志寄存器 │
│ ├── CF(Carry Flag):进位标志 │
│ ├── ZF(Zero Flag):零标志 │
│ ├── SF(Sign Flag):符号标志 │
│ ├── OF(Overflow Flag):溢出标志 │
│ ├── PF(Parity Flag):奇偶标志 │
│ └── AF(Auxiliary Carry):辅助进位 │
│ │
│ 段寄存器(现代操作系统中作用有限) │
│ ├── CS(Code Segment):代码段 │
│ ├── DS(Data Segment):数据段 │
│ ├── SS(Stack Segment):栈段 │
│ └── FS/GS:线程本地存储 │
│ │
└─────────────────────────────────────────────────────────────────────┘
寄存器的历史演变¶
Text Only
8086(16位) 80386(32位) x86-64(64位)
┌───┐ ┌─────┐ ┌───────┐
│AX │─────────────→│ EAX │───────────→│ RAX │
└───┘ └─────┘ └───────┘
┌───┐ ┌─────┐ ┌───────┐
│BX │─────────────→│ EBX │───────────→│ RBX │
└───┘ └─────┘ └───────┘
... ... ...
新增:R8-R15(64位特有)
3. CPU执行指令的过程¶
指令周期(Instruction Cycle)¶
Text Only
┌─────────────────────────────────────────────────────────────────────┐
│ CPU指令执行周期 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 取指 │───→│ 译码 │───→│ 执行 │───→│ 访存 │ │
│ │ Fetch │ │ Decode │ │Execute │ │ Memory │ │
│ └────┬────┘ └─────────┘ └─────────┘ └────┬────┘ │
│ │ │ │
│ │ ┌─────────┐ │ │
│ └────────→│ 写回 │←──────────────────────┘ │
│ │Writeback│ │
│ └────┬────┘ │
│ │ │
│ ↓ │
│ 下一条指令 │
│ │
└─────────────────────────────────────────────────────────────────────┘
各阶段详解¶
1. 取指(Fetch)
Text Only
操作:
1. PC(RIP)指向内存中的指令地址
2. 从内存读取指令到指令寄存器(IR)
3. PC = PC + 指令长度(指向下一条指令)
示例:
RIP = 0x400500
从地址0x400500读取指令 "mov eax, 42"
RIP = 0x400506(假设指令长度6字节)
2. 译码(Decode)
Text Only
操作:
1. 解析指令的操作码(Opcode)
2. 确定操作类型(mov, add, jmp等)
3. 确定操作数(寄存器、内存、立即数)
4. 从寄存器读取操作数
示例:
指令:mov eax, 42
译码结果:
- 操作:mov(数据传送)
- 目的:EAX寄存器
- 源:立即数42
3. 执行(Execute)
Text Only
操作:
1. ALU执行运算(如果是运算指令)
2. 计算内存地址(如果是访存指令)
3. 比较操作数,设置标志位(如果是比较指令)
4. 计算跳转地址(如果是跳转指令)
示例:
指令:add eax, ebx
执行:EAX = EAX + EBX
设置ZF/SF/CF/OF标志位
4. 访存(Memory)
Text Only
操作:
1. 如果是load指令:从内存读取数据
2. 如果是store指令:准备写入内存的数据
3. 如果不是访存指令:跳过此阶段
示例:
指令:mov eax, [rbx]
访存:从RBX指向的内存地址读取4字节到EAX
5. 写回(Writeback)
4. 现代CPU的核心技术¶
流水线(Pipeline)¶
Text Only
┌─────────────────────────────────────────────────────────────────────┐
│ 5级流水线示例 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 时钟周期 → T1 T2 T3 T4 T5 T6 T7 │
│ │
│ 指令1 [F]────→[D]────→[E]────→[M]────→[W] │
│ 指令2 [F]────→[D]────→[E]────→[M]────→[W] │
│ 指令3 [F]────→[D]────→[E]────→[M]────→[W] │
│ 指令4 [F]────→[D]────→[E]────→[M] │
│ │
│ F=Fetch, D=Decode, E=Execute, M=Memory, W=Writeback │
│ │
│ 理想情况:每个时钟周期完成一条指令(CPI = 1) │
│ │
└─────────────────────────────────────────────────────────────────────┘
超标量(Superscalar)¶
Text Only
┌─────────────────────────────────────────────────────────────────────┐
│ 超标量执行(每周期多条指令) │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 单发射(Scalar) 超标量(Superscalar 4-way) │
│ │
│ 周期1: 取指1 ──→ 执行1 ──→ 写回1 │
│ 周期2: 取指2 ──→ 执行2 ──→ 写回2 │
│ 周期3: 取指3 ──→ 执行3 ──→ 写回3 │
│ │
│ 周期1: 取指1,2,3,4 ──→ 执行1,2,3,4 ──→ 写回1,2,3,4 │
│ 周期2: 取指5,6,7,8 ──→ 执行5,6,7,8 ──→ 写回5,6,7,8 │
│ │
│ 现代CPU:每周期可执行4-8条指令 │
│ │
└─────────────────────────────────────────────────────────────────────┘
乱序执行(Out-of-Order Execution)¶
Text Only
┌─────────────────────────────────────────────────────────────────────┐
│ 乱序执行示例 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 原始程序顺序: │
│ 1. load r1, [a] ; 从内存加载(耗时100周期) │
│ 2. add r2, r3, r4 ; 寄存器加法(耗时1周期) │
│ 3. mul r5, r6, r7 ; 寄存器乘法(耗时3周期) │
│ 4. add r8, r1, r2 ; 依赖r1的结果 │
│ │
│ 顺序执行: │
│ 周期1-100: load r1(等待内存) │
│ 周期101: add r2(r1完成后才能执行) │
│ 周期102: mul r5 │
│ 周期105: add r8 │
│ 总时间:105周期 │
│ │
│ 乱序执行: │
│ 周期1: load r1(开始执行,但结果未就绪) │
│ 周期2: add r2(不依赖r1,提前执行) │
│ 周期3: mul r5(不依赖r1,提前执行) │
│ 周期100: load r1完成 │
│ 周期101: add r8(现在可以执行了) │
│ 总时间:101周期 │
│ │
└─────────────────────────────────────────────────────────────────────┘
🧪 动手实验¶
实验1:观察寄存器¶
目的:使用GDB观察寄存器的值
步骤:
-
创建测试程序
-
编译并调试
-
在GDB中观察寄存器
实验2:查看汇编代码¶
目的:理解C代码如何对应到汇编
步骤:
-
生成汇编代码
-
分析关键部分
- 找到函数prologue(保存rbp,设置栈帧)
- 找到参数传递(rdi, rsi寄存器)
- 找到函数epilogue(恢复rbp,返回)
实验3:使用perf观察CPU性能¶
目的:学习使用性能分析工具
步骤:
-
安装perf(Linux)
-
创建计算密集型程序
-
使用perf分析
-
观察输出
- 指令数(instructions)
- 时钟周期(cycles)
- CPI(Cycles Per Instruction)
💡 核心要点总结¶
CPU核心组件¶
| 组件 | 功能 | 关键概念 |
|---|---|---|
| 控制单元(CU) | 控制协调 | PC、指令译码、控制信号 |
| 运算单元(ALU) | 执行运算 | 算术、逻辑、比较、移位 |
| 寄存器 | 高速存储 | 通用寄存器、特殊寄存器 |
| 缓存 | 缓解速度差异 | L1/L2/L3 Cache |
x86-64寄存器速查¶
| 寄存器 | 用途 | 说明 |
|---|---|---|
| RAX | 累加器 | 返回值、算术运算 |
| RBX | 基址 | 数据指针 |
| RCX | 计数器 | 循环计数 |
| RDX | 数据 | I/O、乘除法 |
| RSI | 源索引 | 字符串操作源 |
| RDI | 目的索引 | 字符串操作目的 |
| RBP | 基址指针 | 栈帧基址 |
| RSP | 栈指针 | 栈顶 |
| RIP | 指令指针 | 下条指令地址 |
| RFLAGS | 标志寄存器 | 状态标志 |
指令执行周期¶
❓ 常见问题¶
Q1:为什么64位CPU的寄存器是64位,但int还是32位?
A:为了保持向后兼容性。C/C++的int类型大小由ABI(应用程序二进制接口)定义,在x86-64 Linux上int是32位,long和指针是64位。
Q2:RAX和EAX是什么关系?
A:EAX是RAX的低32位。写入EAX会清零RAX的高32位,这是x86-64架构的设计。
Q3:为什么需要这么多寄存器?
A:寄存器比内存快得多(快100倍以上)。更多的寄存器可以减少内存访问,提高程序性能。
Q4:现代CPU的CPI(每指令周期数)是多少?
A:理想情况下CPI可以小于1(超标量)。但由于缓存未命中、分支预测失败等原因,实际CPI通常在1-4之间。
📚 扩展阅读¶
- 《深入理解计算机系统》 - 第4章:处理器体系结构
- 《计算机体系结构:量化研究方法》 - 第1-3章
- Intel手册:Intel 64 and IA-32 Architectures Software Developer's Manual
🎯 下一步¶
学习 02-指令集与汇编语言,掌握x86-64汇编编程。