计算机体系结构
冯·诺依曼体系结构、CPU工作原理、指令周期、存储层次与总线系统。
1. 冯·诺依曼体系结构
现代计算机的理论基础来自1945年约翰·冯·诺依曼提出的”存储程序”思想。其核心观点是:程序和数据以同等地位存储在同一存储器中,由控制器按顺序从存储器中取出指令并执行。
1.1 五大组成部分
冯·诺依曼体系结构将计算机划分为五个功能部件:
| 部件 | 功能 | 类比 |
|---|---|---|
| 控制器 | 从存储器取指令、译码、控制各部件协调工作 | 乐队指挥 |
| 运算器 | 执行算术运算和逻辑运算 | 计算器 |
| 存储器 | 存放程序和数据 | 书架 |
| 输入设备 | 将外部信息转换为计算机能识别的数据 | 眼睛/耳朵 |
| 输出设备 | 将计算结果转换为人类可感知的形式 | 嘴巴/手 |
控制器和运算器合称为中央处理器(CPU)。
1.2 存储程序原理
存储程序是冯·诺依曼体系结构最核心的思想:
- 程序和数据以二进制形式存放在存储器中
- 计算机运行时,从存储器中依次取出指令并执行
- 指令的执行顺序可以通过跳转指令改变
- 存储器中的内容既可以被读取也可以被修改
┌─────────────────────────────────────────────┐
│ 存储器 │
│ ┌──────┬──────┬──────┬──────┬──────┐ │
│ │指令1 │指令2 │指令3 │数据1 │数据2 │ ... │
│ └──────┴──────┴──────┴──────┴──────┘ │
└──────────┬──────────────────┬───────────────┘
│ 取指令 │ 读/写数据
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ 控制器 │ │ 运算器 │
│ ┌───────────┐ │ │ ┌───────────┐ │
│ │ 指令寄存器 │ │ │ │ 累加器 │ │
│ │ 程序计数器│ │ │ │ ALU │ │
│ └───────────┘ │ │ └───────────┘ │
└─────────────────┘ └─────────────────┘
1.3 冯·诺依曼瓶颈
由于指令和数据共享同一条总线,CPU与存储器之间的数据传输速率成为系统性能的瓶颈,这被称为冯·诺依曼瓶颈。现代计算机通过缓存、流水线等技术缓解此问题。
2. CPU 工作原理
CPU是计算机的”大脑”,由控制器和运算器两部分组成。
2.1 控制器
控制器负责协调计算机各部件的工作,主要包含以下寄存器:
| 寄存器 | 作用 |
|---|---|
| PC(程序计数器) | 存放下一条要执行的指令地址 |
| IR(指令寄存器) | 存放当前正在执行的指令 |
| MAR(地址寄存器) | 存放要访问的存储器地址 |
| MDR(数据寄存器) | 存放从存储器读出或要写入的数据 |
2.2 运算器
运算器(ALU,算术逻辑单元)执行具体的计算:
- 算术运算:加、减、乘、除
- 逻辑运算:与、或、非、异或
- 移位操作:左移、右移
- 比较操作:等于、大于、小于
// ALU 的简化模型
int ALU(int operand1, int operand2, int opcode) {
switch (opcode) {
case ADD: return operand1 + operand2;
case SUB: return operand1 - operand2;
case AND: return operand1 & operand2;
case OR: return operand1 | operand2;
case XOR: return operand1 ^ operand2;
case SHL: return operand1 << operand2;
case SHR: return operand1 >> operand2;
default: return 0;
}
}
2.3 CPU 内部结构示意
┌──────────────────────────────────┐
│ CPU │
│ │
│ ┌──────────┐ ┌──────────┐ │
│ │ 控制器 │ │ 运算器 │ │
│ │ │ │ │ │
│ │ PC IR │◄──│ ALU │ │
│ │ MAR MDR │──►│ 累加器 │ │
│ │ 时序发生器│ │ 标志寄存器│ │
│ └──────────┘ └──────────┘ │
│ │ │ │
│ └──────┬───────┘ │
│ │ 内部总线 │
└───────────────┼──────────────────┘
│
外部总线
│
┌───────┴───────┐
│ 存储器 │
└───────────────┘
3. 指令周期
CPU执行一条指令的过程称为指令周期,通常分为以下几个阶段:
3.1 取指(Fetch)
- 将 PC 中的地址送入 MAR
- 通过地址总线将 MAR 中的地址发送给存储器
- 存储器将对应地址的数据通过数据总线送入 MDR
- 将 MDR 中的指令送入 IR
- PC 自增,指向下一条指令
3.2 译码(Decode)
- 分析 IR 中指令的操作码
- 确定要执行的操作类型
- 识别操作数地址
3.3 执行(Execute)
- 根据译码结果执行相应操作
- 可能需要从存储器读取操作数
- ALU 执行计算
- 将结果写回寄存器或存储器
3.4 指令周期流程
取指 ──► 译码 ──► 执行 ──► 写回
│ │
└──────────────────────────────┘
重复执行
3.5 用代码理解指令周期
// 模拟简化的指令周期
void cpu_run() {
while (running) {
// 取指:从存储器取出PC指向的指令
int instruction = memory[PC];
// 译码:分离操作码和操作数
int opcode = (instruction >> 12) & 0xF; // 高4位为操作码
int operand = instruction & 0xFFF; // 低12位为操作数
// 执行:根据操作码执行对应操作
switch (opcode) {
case LOAD: // 加载数据到累加器
accumulator = memory[operand];
break;
case STORE: // 将累加器数据存入存储器
memory[operand] = accumulator;
break;
case ADD: // 加法
accumulator += memory[operand];
break;
case SUB: // 减法
accumulator -= memory[operand];
break;
case JUMP: // 无条件跳转
PC = operand;
continue; // 跳过PC自增
case HALT: // 停机
running = 0;
break;
}
PC++; // 程序计数器自增
}
}
3.6 时钟周期与指令周期
| 概念 | 定义 | 关系 |
|---|---|---|
| 时钟周期 | CPU 时钟脉冲的一个周期,最小时间单位 | 基本单位 |
| 机器周期 | 完成一个基本操作所需的时间 | 通常 = 若干时钟周期 |
| 指令周期 | 执行一条指令所需的时间 | = 若干机器周期 |
现代CPU通过流水线技术让多条指令的不同阶段重叠执行,大幅提升吞吐量。例如五级流水线:取指→译码→执行→访存→写回,五条指令可以同时在不同阶段运行。
4. 存储层次
计算机的存储系统按照速度、容量和价格形成层次结构,从快到慢、从小到大:
4.1 存储层次结构
速度 ↑ ┌──────────────┐
│ CPU寄存器 │ ~1ns | ~几百B
├──────────────┤
│ 高速缓存 │ ~几ns | ~几MB
│ (L1/L2/L3) │
├──────────────┤
│ 主存(内存) │ ~100ns | ~几GB~几TB
├──────────────┤
│ 辅存(外存) │ ~ms级 | ~几TB~几PB
│ SSD / HDD │
└──────────────┘
容量 ↑
4.2 各级存储详细对比
| 层次 | 典型容量 | 访问时间 | 是否易失 | 典型用途 |
|---|---|---|---|---|
| 寄存器 | 几十~几百B | < 1ns | 是 | 指令执行中的临时数据 |
| L1 缓存 | 32~64 KB | 1~2 ns | 是 | 最频繁使用的数据 |
| L2 缓存 | 256 KB~1 MB | 3~10 ns | 是 | 较频繁使用的数据 |
| L3 缓存 | 4~64 MB | 10~30 ns | 是 | 多核共享数据 |
| 主存(DRAM) | 8~128 GB | 50~100 ns | 是 | 运行中的程序和数据 |
| SSD | 256 GB~4 TB | 0.1~0.5 ms | 否 | 持久化存储 |
| HDD | 1~20 TB | 5~15 ms | 否 | 大容量归档存储 |
4.3 缓存工作原理
缓存利用了局部性原理:
- 时间局部性:最近被访问的数据,很可能在不久后再次被访问
- 空间局部性:被访问数据附近的数据,很可能也会被访问
// 缓存命中与未命中的概念
int data[1000];
// 时间局部性:sum 被反复读写
int sum = 0;
for (int i = 0; i < 1000; i++) {
sum += data[i]; // sum 会被缓存
}
// 空间局部性:顺序访问数组
// data[0] 被访问后,data[1], data[2]... 也会被预取到缓存
for (int i = 0; i < 1000; i++) {
process(data[i]);
}
4.4 缓存命中率
缓存命中率是衡量缓存效率的关键指标:
命中率 = 缓存命中次数 / 总访问次数 × 100%
| 场景 | 典型命中率 | 说明 |
|---|---|---|
| L1 缓存 | 90%~95% | 大多数指令和数据在L1命中 |
| L2 缓存 | 80%~90% | L1未命中的大部分在L2命中 |
| L3 缓存 | 70%~85% | L2未命中的大部分在L3命中 |
缓存每提升1%的命中率,程序性能可能有数个百分点的提升。编写缓存友好的代码是性能优化的重要手段。
5. 总线系统
总线是计算机各部件之间传送信息的公共通道。
5.1 总线分类
按功能划分,总线分为三类:
| 总线类型 | 传输内容 | 方向 | 宽度 |
|---|---|---|---|
| 地址总线 | 内存地址/IO端口地址 | CPU→存储器/IO | 决定寻址空间 |
| 数据总线 | 数据 | 双向 | 决定一次传输量 |
| 控制总线 | 控制信号 | 双向 | 读写/中断等 |
5.2 总线工作示例:读内存
CPU 存储器
│ │
│ ── 地址(0x1000) ──────────► │ 1. CPU通过地址总线发送地址
│ │
│ ── 读信号 ────────────────► │ 2. CPU通过控制总线发送读信号
│ │
│ ◄── 数据(0x5A) ─────────── │ 3. 存储器通过数据总线返回数据
│ │
5.3 地址总线与寻址空间
地址总线的宽度决定了CPU能直接寻址的内存空间大小:
| 地址总线宽度 | 寻址空间 | 计算 |
|---|---|---|
| 16 位 | 64 KB | 2^16 = 65,536 B |
| 20 位 | 1 MB | 2^20 = 1,048,576 B |
| 32 位 | 4 GB | 2^32 ≈ 4.3×10^9 B |
| 64 位 | 16 EB | 2^64 ≈ 1.8×10^19 B |
// 32位系统的寻址空间计算
// 地址总线32根,每根线0或1
// 可表示地址数 = 2^32 = 4,294,967,296
// 每个地址对应1字节
// 总寻址空间 = 4,294,967,296 字节 = 4 GB
#include <stdio.h>
int main() {
// 32位指针的大小
printf("指针大小: %zu 字节\n", sizeof(void*)); // 4 (32位) 或 8 (64位)
// 理论寻址空间
unsigned long long addr_space = 1ULL << 32;
printf("32位寻址空间: %llu 字节 = %llu GB\n",
addr_space, addr_space / (1024*1024*1024));
return 0;
}
5.4 数据总线与传输效率
数据总线的宽度决定了CPU一次能传输的数据量:
| 数据总线宽度 | 一次传输 | 说明 |
|---|---|---|
| 8 位 | 1 字节 | 早期8位机 |
| 16 位 | 2 字节 | 8086等16位机 |
| 32 位 | 4 字节 | 80386等32位机 |
| 64 位 | 8 字节 | 现代64位处理器 |
5.5 总线仲裁
当多个设备同时请求使用总线时,需要通过总线仲裁决定优先级:
- 链式查询:设备串行连接,离仲裁器越近优先级越高
- 计数器定时:从某个起始地址开始计数,被计数的设备获得总线
- 独立请求:每个设备有独立的请求线和授权线,响应最快
6. 哈佛架构与冯·诺依曼架构对比
| 特性 | 冯·诺依曼架构 | 哈佛架构 |
|---|---|---|
| 指令与数据 | 共用存储器和总线 | 分开存储,独立总线 |
| 总线数量 | 1套 | 2套 |
| 取指与取数据 | 不能同时进行 | 可以同时进行 |
| 实现复杂度 | 较低 | 较高 |
| 典型应用 | 通用计算机 | DSP、嵌入式、ARM |
现代CPU通常采用改进型哈佛架构:在CPU内部(L1缓存层)使用哈佛架构(指令缓存和数据缓存分离),在外部使用冯·诺依曼架构(统一主存),兼顾两者优势。
7. 小结
| 概念 | 要点 |
|---|---|
| 冯·诺依曼架构 | 五大部件、存储程序原理、指令数据共享总线 |
| CPU | 控制器+运算器,通过寄存器暂存中间结果 |
| 指令周期 | 取指→译码→执行→写回,流水线提升吞吐量 |
| 存储层次 | 寄存器→缓存→内存→外存,速度递减容量递增 |
| 总线系统 | 地址总线定寻址空间,数据总线定传输宽度 |
理解计算机体系结构是学习操作系统、编译原理和性能优化的基础。后续章节将在此基础上深入探讨数据表示和程序设计。