Published on

计算机小教程:冯诺曼依架构

Authors
  • Name
    lzray
    Twitter

冯诺依曼计算机概述

冯诺依曼计算机(又称普林斯顿体系结构)的核心思想是存储程序:将指令与数据以同样的形式存放在可寻址的存储器中,由控制单元按地址顺序取出并执行。该思想形成于 1940 年代中期,标志性文献是 1945 年的 First Draft of a Report on the EDVAC。与此前以插线板或手工设置完成运算流程的电子计算装置相比,存储程序让计算过程可通过修改内存内容来改变,从而奠定了现代通用计算机的软件与硬件分层。

简单理解:?
可以理解为把“做事的方法(指令)”和“需要处理的东西(数据)”都装进一本可随机翻页的“笔记本(内存)”。控制器像读菜单一样按页码(地址)取出要做的步骤,运算器照做,结果再写回笔记本或端口。
易混淆点:“存储程序”不是指“把程序放硬盘”,而是强调在内存里指令与数据地位等同、统一编码。

五大功能部件与工作分工

经典模型将一台计算机抽象为五大部件:输入、输出、存储器、运算器(算术逻辑单元,ALU)、控制器(包括程序计数器 PC、指令寄存器 IR、状态寄存器等)。它们通过总线互连并按照时序协同工作。

冯诺依曼模型的五大部件与要点

部件职责与要点常见实例关键性能指标
输入将外界信息编码为二进制并送入系统。需配合缓冲和中断/DMA 降低 CPU 轮询开销。键鼠、网卡、传感器、摄像头吞吐、端到端延迟、错误率
存储器统一存放指令与数据,按地址随机访问。层次结构由小而快到大而慢。寄存器、L1/L2/L3 Cache、主存、二级存储容量、带宽、平均访问延迟(AMAT)、命中率
运算器执行定点/浮点、逻辑、移位、比较等微操作。ALU、FPU、向量/矩阵单元吞吐(每拍操作数)、时钟频率、位宽
控制器维护程序顺序,完成取指、译码、发射、提交,中断/异常处理,访存控制。PC、IR、解码/重命名、乱序窗口、提交队列指令发射宽度、分支预测精度、窗口深度
输出将计算结果转换为外设可识别的形式并输出。显示、打印、存盘、网络发送吞吐、抖动、接口协议效率

术语 & 误区
PC(程序计数器):指向下一条将要取的指令地址;IR:当前正在执行/译码的指令副本。
误区 1:“CPU=运算器”。其实 CPU 还包含控制层级缓存等;误区 2:“有显卡就不需要输出部件”。显卡本身就是一种输出相关部件(显示适配器)。
推荐:Windows 打开任务管理器看“内存”和“GPU”;Linux 可试 lscpufree -hlspci | grep -i vga 理解部件分工。

指令、数据与寻址方式

在存储程序机中,内存为一维字节或字的线性空间。指令通常由操作码与若干操作数/地址字段构成,寻址方式决定有效地址(Effective Address, EA)的形成。常见方式如下。

常见寻址方式与有效地址计算

方式含义典型 EA 计算或示例
立即数操作数即指令中给出常量,不涉及访存。ADD R1, #5
寄存器直接操作数在寄存器中。ADD R1, R2
直接寻址指令给出内存绝对地址。EA=Addr\mathrm{EA}=\text{Addr}
间接寻址指令给出一个指针的地址,取其内容作为 EA。EA=[Addr]\mathrm{EA}=[\text{Addr}]
基址/变址以寄存器为基,加位移或索引。EA=Rb+disp\mathrm{EA}=R_b + \text{disp}EA=Rb+Ri×s+disp\mathrm{EA}=R_b + R_i \times s + \text{disp}
PC 相对以当前 PC 为基,便于位置无关代码与分支。EA=PC+offset\mathrm{EA}=PC+\text{offset}

基址/变址好比像“仓库地址 + 第几层货架 ×\times 每层间距 + 偏移”。C 语言里的 a[i] 常在硬件上实现为 EA=base(a)+i×sizeof(a)\text{EA}=\text{base}(a)+i\times \text{sizeof}(*a)
间接寻址像“先拿到联系人电话号码(指针),再打电话问对方住哪(解引用)”。
易错点:PC 相对与源代码行号无关,它只与“当前指令的地址”有关。
练习:已知 EA=Rb+Ri×4+12\text{EA}=R_b + R_i \times 4 + 12,若 Rb=1000R_b=1000, Ri=3R_i=3,则 EA 是多少?(答:1000+3×4+12=10241000+3\times4+12=1024

指令周期与微操作

一次完整的指令处理可分为若干阶段(不同体系可能合并/细分):

  1. 取指:IRMem[PC]\text{IR}\gets \text{Mem}[PC],随后 PCPC+len(IR)\text{PC}\gets \text{PC}+\text{len(IR)}
  2. 译码:解析操作码与操作数位置,生成控制信号。
  3. 取数:按寻址方式形成 EA,必要时访存或读寄存器。
  4. 执行:ALU/FPU/向量单元完成运算,或触发分支、系统调用等。
  5. 访存与写回:将结果写寄存器或内存,更新标志/状态。
  6. 中断/异常:在精确不精确语义下保存现场并转移到服务例程。

为了提高吞吐,现代处理器在保持顺序语义的前提下采用流水线、超标量、乱序执行与寄存器重命名等技术,将上述阶段重叠并行。程序提交顺序仍与架构可观察顺序一致。

装配线类比:流水线为何更快?
串行是一份做完再做下一份;流水线是每个工位并发处理不同三明治的不同环节。
注意:分支跳转像“突然换单”,需要分支预测减少返工(流水线清空)。
练习:在 5 级流水线中,若每级 1 拍、无冲突,第一条指令完成需几拍?稳态下每几拍完成一条?(答:首条 5 拍;稳态每拍 1 条)

总线与带宽

冯诺依曼结构使用统一的地址空间与通用总线(或互连网络)在指令与数据之间复用带宽。基本信号包括数据线、地址线与控制线(读/写、有效、就绪、中断等)。理想带宽的上界近似为

BW数据位宽8×f总线×每拍传输次数\text{BW} \approx \frac{\text{数据位宽}}{8}\times f_\text{总线}\times \text{每拍传输次数}

但实际有效带宽受握手、等待状态、仲裁、突发长度与一致性协议影响。

带宽 vs 延迟:
带宽像“每分钟能过桥多少辆车”;延迟像“单辆车过桥所花的时间”。高速而高延迟的链路(如远端内存)可能“单次很慢,但一旦排起长队,总吞吐不低”。
小算例:64 位数据线,双沿传输(每拍 2 次),时钟 1600MHz1600\,\text{MHz},理想上界 8B×2×1600M=25.6GB/s\approx 8\,\text{B}\times 2\times 1600\,\text{M}=25.6\,\text{GB/s}

冯诺依曼瓶颈与工程对策

所谓冯诺依曼瓶颈指处理器算力与存储子系统带宽/延迟之间的不匹配,表现为取指和访存争用同一通路、指令/数据局部性不足导致的缓存未命中、以及 I/O 带宽/延迟限制。典型缓解手段:

  • 存储层次:多级缓存(分离的 L1I/L1D、统一的 L2/L3)、预取器、写缓冲;平均访存时间 AMAT=tL1+mL1(tL2+mL2())\mathrm{AMAT}=t_\text{L1}+m_\text{L1}(t_\text{L2}+m_\text{L2}(\cdots))
  • 指令层面:分支预测、投机执行、指令融合、宏/微指令解码与缓存。
  • 执行层面:超标量发射、乱序调度、重命名消除假相关;向量/SIMD、矩阵单元提升数据并行。
  • 访存与 I/O:非阻塞缓存、合并写、页表与 TLB、NUMA 亲和性;DMA 与中断降低 CPU 参与度。
  • 软件配合:数据结构与访问模式的局部性优化、阻塞/分块、流水/并行算法、restrict/对齐、cache-friendly 的布局。

为什么“多用局部性”就能更快?
时间局部性:刚访问过的数据很可能马上又用;空间局部性:邻近地址常被一同访问。缓存正是为这两点设计。
微实验:顺序遍历数组通常显著快于随机访问同大小的数组,因为前者更容易命中缓存和触发硬件预取。

与哈佛结构的比较

哈佛结构将指令与数据的存储与通路物理分离,可并行取指与取数,天然减轻带宽争用。现代通用 CPU 广泛采用改良哈佛:在小而快的一级缓存分离指令/数据,而在更高层与主存保持统一地址空间,既兼顾并行性也保留编程灵活性。

冯诺依曼与(改良)哈佛结构的要点对比

方面冯诺依曼(统一存储)哈佛/改良哈佛(分离通路)
取指/取数共享带宽,易产生争用可并行,提升吞吐
编程模型单一地址空间,加载/自修改代码更自然物理分离,但现代改良方案对软件透明
硬件复杂度互连简单需要两套端口/Cache,一致性与回写更复杂
应用典型早期通用机、许多微控制器数字信号处理、嵌入式、当代 CPU 的 L1 层

冯诺依曼像一条双向单车道:指令车与数据车需要错峰通过;哈佛像两条独立车道:互不干扰并行通行;改良哈佛是在路口附近分道(L1I/L1D),远处再汇合(统一的更高层/主存)。

ISA 与微架构、虚拟存储与一致性

指令集架构(ISA)规定了程序员可见的寄存器、指令与语义;微架构则是实现方式(流水线深度、缓存层次、执行端口等)。同一 ISA 可有多种微架构。现代系统提供分页式虚拟内存与 TLB 加速,实现进程隔离、按需调页与共享库;在多核场景下通过一致性协议(如 MESI 派生族)维护对共享内存的可观察顺序,配合内存模型与屏障指令保证并发正确性。

最小抽象机的一段伪代码

while (running) {
  IR = M[PC]; PC += len(IR);           // 取指
  decode(IR, &op, &dst, &src, &mode);  // 译码
  EA  = calc_EA(mode, src, PC, R);     // 形成有效地址
  V   = read_operand(mode, EA, R, M);  // 取数
  R[dst] = execute(op, R[dst], V);     // 执行与写回
  handle_traps_and_interrupts();       // 异常/中断
}

IR = M[PC]:把下一条指令从内存读入 IR;随后 PC += len(IR) 跳到下一条指令的地址decode(...):从比特串中解析出“做什么(op)”“对谁做(dst/src)”“怎么找(mode)”。 calc_EA(...):依据寻址方式算出“收货地址”(EA)。 read_operand(...):按 EA 或寄存器位置把真正数据取出来。 execute(...):用 ALU/FPU/向量单元做事,并把结果写回寄存器/内存。 handle_traps_and_interrupts():若有异常/中断,保存现场并跳到对应服务例程。

学习与实验建议

  • 在模拟器中观察指令逐步执行与寄存器/内存变化,体会 PC 相对寻址、栈调用约定与中断的现场保存。
  • 通过更换内存访问模式(顺序/跳跃/随机)测量 AMAT 与带宽利用,验证缓存层次的影响。
  • 采用矩阵乘法的分块实现或卷积的向量化实现,对比流水线、SIMD 与预取的收益与限制。

新手路线 可视化单步调试:选任意汇编教学模拟器(如 MIPS/ARM 的教学工具),单步运行,看 PC、IR、寄存器、内存变化。 缓存体感实验:写两段代码(顺序遍历 vs 随机访问),比较运行耗时,感受局部性和预取的威力。 并行:用向量化库或编译器自动向量化跑一次矩阵乘法,对比标量版。

小结

冯诺依曼体系以存储程序思想统一了“指令—数据—状态”三者的表示,使计算机得以通过软件灵活重构功能。围绕该模型产生的瓶颈促成了存储层次、流水线、乱序、并行与虚拟化等一系列改良。理解这一抽象及其工程化演进,是学习后续 CPU 架构、内存管理、操作系统与编译器的基础。

—— 追加:术语速查表(便于回看)——

术语简单解释
PC(程序计数器)指向下一条将被取出的指令地址
IR(指令寄存器)当前正被处理的那条指令的副本
ALU/FPU算术逻辑单元/浮点单元,做“算术与逻辑”/“浮点数”工作
EA(有效地址)真正去内存拿数据时使用的“收货地址”
AMAT平均访存时间,越小越好;由多级缓存命中/未命中叠加出来
TLB地址翻译的“加速表”,把虚拟地址快速映射成物理地址
SIMD/向量化一条指令同时处理多个数据(数据并行)
一致性协议(MESI)多核间对同一数据副本的“行为准则”,防止读到旧值