第五章 计算机体系结构
导读
前四章我们构建了计算机的所有硬件组件:逻辑门、ALU、寄存器和内存,并学习了机器语言编程。本章将把这些组件整合在一起,构建一台完整的计算机——Hack计算机。
计算机体系结构是计算机科学的基石。理解计算机体系结构不仅帮助我们理解计算机如何工作,还培养了系统化设计复杂工程系统的能力。本章将展示如何通过精心设计的架构,将简单的组件组合成功能强大的计算系统。
通过本章的学习,你将理解计算机各组件如何协同工作,掌握计算机体系结构的设计原则,并亲手构建一台完整的计算机。这是从硬件到软件的关键桥梁,也是理解整个计算机系统的基础。
核心概念详解
5.1 冯·诺依曼架构
Hack计算机基于经典的冯·诺依曼架构,其核心特点是:
存储程序概念
程序和数据存储在同一内存中,可以被同等对待。这意味着:
- 程序可以像数据一样被处理
- 程序可以修改自身(自修改代码)
- 简化了硬件设计
五大组件
冯·诺依曼架构包含五个基本组件:
运算器(ALU):执行算术和逻辑运算
控制器(Control Unit):协调各组件工作,控制指令执行
存储器(Memory):存储程序和数据
输入设备(Input):接收外部输入
输出设备(Output):向外部输出结果
在Hack计算机中,这些组件通过系统总线连接,形成一个完整的计算系统。
5.2 Hack计算机架构
Hack计算机是一个16位计算机,具有以下特性:
硬件组成
Hack计算机 = ALU + 寄存器 + 内存 + 控制逻辑具体包括:
- ALU:16位算术逻辑单元
- 寄存器:D寄存器、A寄存器
- 内存:统一的16位内存空间,包括RAM、屏幕内存和键盘内存
- 程序计数器(PC):15位程序计数器
- 控制逻辑:解码指令并控制各组件工作
内存映射
Hack计算机的内存空间分为三个区域:
RAM(0-16383):
- 24K字的通用内存
- 用于存储程序和数据
- 包括变量、数组、堆栈等
屏幕内存(16384-24575):
- 8K字的内存
- 映射到512×256像素的黑白屏幕
- 每个字控制32个水平像素
键盘内存(24576):
- 1个字的内存
- 映射到键盘
- 存储当前按下的键的ASCII码
指令执行流程
Hack计算机的指令执行遵循以下步骤:
取指:PC提供地址,从内存读取指令
解码:控制单元解码指令,确定操作类型
执行:
- A指令:将值加载到A寄存器
- C指令:控制ALU执行操作,存储结果,可能跳转
更新PC:如果跳转,PC=A;否则PC递增
重复:回到步骤1
5.3 CPU设计
CPU(中央处理单元)是计算机的核心,负责执行指令。
CPU的功能
CPU需要完成以下任务:
从内存获取指令
解码指令
执行指令
更新程序计数器
CPU的内部结构
Hack CPU包含以下组件:
- ALU:执行算术和逻辑运算
- D寄存器:存储操作数
- A寄存器:存储地址/操作数
- 控制逻辑:解码指令并控制各组件
CPU的工作原理
CPU根据当前指令类型执行不同的操作:
A指令执行:
将指令的低15位加载到A寄存器
不执行ALU操作
不存储结果
不跳转
PC递增
C指令执行:
根据a字段选择ALU的y输入(A或M)
根据c字段设置ALU控制信号
ALU执行计算
根据d字段存储结果到D、A或M
根据j字段和ALU输出决定是否跳转
如果跳转,PC=A;否则PC递增
5.4 内存设计
Hack计算机使用统一的内存空间,包括RAM、屏幕和键盘。
RAM设计
Hack RAM由多个层次的RAM芯片组成:
- RAM8:8个寄存器
- RAM64:8个RAM8
- RAM512:8个RAM64
- RAM4K:8个RAM512
- RAM16K:4个RAM4K
最终构建24K RAM(地址0-16383)。
屏幕内存
屏幕内存是8K RAM(地址16384-24575):
- 直接映射到屏幕显示
- 每个内存字对应32个像素
- 写入内存立即反映到屏幕
键盘内存
键盘内存是1个字的内存(地址24576):
- 只读内存
- 存储当前按下的键
- 硬件自动更新
5.5 计算机集成
将所有组件集成在一起形成完整的计算机。
组件连接
CPU <--> 内存
| |
| +-- RAM (0-16383)
| +-- 屏幕 (16384-24575)
| +-- 键盘 (24576)
|
+-- 控制逻辑信号流
地址信号:从PC或A寄存器到内存
数据信号:双向在CPU和内存之间
控制信号:从控制单元到各组件
读写信号:控制内存读写操作
5.6 计算机工作过程
理解计算机的工作过程对于编写高效程序至关重要。
启动过程
PC初始化为0
从地址0开始取指
执行第一条指令
继续执行后续指令
指令循环
计算机不断重复取指-执行循环,直到遇到停机指令或断电。
中断处理
虽然Hack计算机没有实现中断机制,但实际计算机通常支持中断:
- 外部设备可以请求CPU注意
- CPU暂停当前程序,执行中断处理程序
- 处理完成后恢复原程序
5.7 性能考虑
计算机性能受多个因素影响。
时钟频率
时钟频率决定了指令执行的速度。更高的频率意味着更快的执行速度,但也带来功耗和散热问题。
指令周期
每条指令需要一定数量的时钟周期:
- 简单指令:1个周期
- 复杂指令:多个周期
内存访问
内存访问通常是性能瓶颈:
- 内存速度远慢于CPU速度
- 使用高速缓存缓解
- 优化内存访问模式
流水线
现代CPU使用流水线技术提高性能:
- 将指令执行分为多个阶段
- 不同指令的不同阶段可以并行执行
- 提高指令吞吐量
重要知识点
知识点1:哈佛架构vs冯·诺依曼架构
冯·诺依曼架构:
- 程序和数据共享同一内存
- 简化硬件设计
- 可能存在冯·诺依曼瓶颈
哈佛架构:
- 程序和数据使用独立内存
- 可以同时访问程序和数据
- 硬件设计更复杂
现代计算机通常采用改进的哈佛架构,在缓存级别分离程序和数据。
知识点2:总线设计
总线是连接计算机各组件的通信通道:
数据总线:传输数据,宽度决定一次传输的数据量
地址总线:传输地址,宽度决定可寻址的内存空间
控制总线:传输控制信号
知识点3:存储层次
现代计算机使用多级存储层次:
- 寄存器:最快,容量最小
- L1缓存:较快,容量较小
- L2/L3缓存:较慢,容量较大
- 主存(RAM):慢,容量大
- 辅存(磁盘):最慢,容量最大
知识点4:指令流水线
流水线将指令执行分为多个阶段:
取指(IF):从内存获取指令
解码(ID):解码指令
执行(EX):执行操作
访存(MEM):访问内存
写回(WB):写回结果
流水线可以提高指令吞吐量,但需要处理数据冒险和控制冒险。
知识点5:并行处理
现代计算机使用多种并行技术:
- 指令级并行:同时执行多条指令
- 数据级并行:同时处理多个数据
- 任务级并行:同时执行多个任务
常见误区
误区1:认为计算机一次只能做一件事
实际上,现代计算机通过流水线、多核等技术可以同时执行多个操作。但在Hack计算机中,确实是顺序执行的。
误区2:忽视内存访问延迟
内存访问比CPU操作慢得多。频繁访问内存会严重影响性能。优化内存访问模式是编写高效程序的关键。
误区3:认为更大的寄存器文件总是更好
更大的寄存器文件增加了硬件复杂度和访问延迟。需要在寄存器数量和使用便利性之间取得平衡。
误区4:不理解控制单元的作用
控制单元是CPU的"大脑",负责解码指令并控制各组件工作。没有控制单元,CPU无法正确执行指令。
误区5:认为计算机架构是一成不变的
计算机架构在不断演进。从单核到多核,从顺序执行到并行处理,架构设计在不断发展。
实践应用
实践1:实现CPU
CHIP CPU {
IN inM[16], instruction[16], reset;
OUT outM[16], writeM, addressM[15];
PARTS:
// A指令处理
// 如果是A指令,将指令低15位加载到A寄存器
// 如果是C指令,根据指令字段控制ALU
// 1. 解码指令
// instruction[15] = 0: A指令
// instruction[15] = 1: C指令
// 2. A寄存器控制
Mux16(a=aluOut, b=instruction, sel=notC, out=aIn);
Mux(a=dOut, b=true, sel=notC, out=aLoad);
Register(in=aIn, load=aLoad, out=aOut);
// 3. D寄存器
Register(in=aluOut, load=dLoad, out=dOut);
// 4. ALU控制
// 根据C指令字段设置ALU
// 5. PC控制
// 根据跳转条件和ALU输出控制PC
}实践2:实现内存
CHIP Memory {
IN in[16], load, address[15];
OUT out[16];
PARTS:
// 地址解码
// address < 16384: RAM
// 16384 <= address < 24576: 屏幕
// address = 24576: 键盘
// RAM访问
RAM16K(in=in, load=ramLoad, address=address[0..13], out=ramOut);
// 屏幕访问
Screen(in=in, load=screenLoad, address=address[0..12], out=screenOut);
// 键盘访问(只读)
Keyboard(out=keyboardOut);
// 输出选择
Mux16(a=ramOut, b=screenOut, sel=screenSel, out=m1);
Mux16(a=m1, b=keyboardOut, sel=keyboardSel, out=out);
}实践3:实现完整的计算机
CHIP Computer {
IN reset;
PARTS:
// 连接CPU和内存
CPU(inM=memoryOut, instruction=instruction, reset=reset,
outM=cpuOut, writeM=write, addressM=address);
Memory(in=cpuOut, load=write, address=address, out=memoryOut);
// 指令就是内存输出
instruction = memoryOut;
}实践4:测试计算机
测试完整的计算机需要加载程序并验证执行结果:
// 加载程序到内存
load RAM16K, file=program.hack;
// 运行计算机
tick, tock;
tick, tock;
// ...
// 验证结果
// 检查特定内存位置的值实践5:编写测试程序
编写简单的测试程序验证计算机功能:
// 程序:计算1+2+...+10
@10
D=A
@0
M=0
(LOOP)
@0
D=D+M
M=D
@1
D=M-1
M=D
@1
D=M
@LOOP
D;JGT
@END
0;JMP
(END)
@END
0;JMP实践6:性能分析
分析程序性能:
- 计算指令数量
- 估算执行时间
- 识别性能瓶颈
- 优化关键代码
本章小结
本章我们将所有硬件组件整合在一起,构建了完整的Hack计算机。
核心要点回顾
冯·诺依曼架构:存储程序概念,五大组件协同工作。
Hack架构:16位计算机,统一内存空间,简单的指令集。
CPU设计:包含ALU、寄存器和控制逻辑,负责执行指令。
内存设计:统一的内存空间,包括RAM、屏幕和键盘。
计算机集成:将所有组件连接成完整的系统。
工作过程:取指-执行循环,不断重复直到停机。
关键技能掌握
- 理解冯·诺依曼架构的原理
- 掌握Hack计算机的架构设计
- 理解CPU的工作原理
- 掌握内存映射I/O的概念
- 能够分析和优化计算机性能
与后续章节的联系
本章构建的计算机是后续章节的基础:
- 第六章将构建汇编器,将汇编语言转换为机器语言
- 第七章和第八章将介绍虚拟机,提供更高级的抽象
- 后续章节将在此基础上构建完整的软件栈
学习建议
理解整体架构:从宏观角度理解计算机各组件如何协同工作
关注细节:深入理解每个组件的工作原理
动手实践:亲手构建和测试计算机
思考设计决策:理解为什么这样设计,有什么优缺点
通过本章的学习,你已经完成了一台完整计算机的构建。从最基本的逻辑门到完整的计算机系统,这是一个了不起的成就。这台计算机虽然简单,但它包含了现代计算机的所有基本概念。理解这台计算机的工作原理,为理解更复杂的计算机系统奠定了坚实基础。
现在,我们有了硬件平台,下一步是让它更容易编程。直接编写机器语言非常繁琐,第六章我们将构建汇编器,使编程变得更加容易。