逻辑门与加法器
AND、OR、NOT 操作位,XOR 在输入不同时为一。半加器的和为异或、进位为与。有输入进位的全加器产生和与输出进位,链接后处理多位。组合电路依赖当前输入,时序电路保存状态,通常按时钟更新。真值表规定功能,实际硬件还有传播延迟与物理约束。
a=b=1 时半加器和与进位?
完整解答
和零、进位一,即二进制 10。
指令与体系结构状态
指令集规定机器可见操作。寄存器保存工作值,程序计数器指向下一指令。模型有累加器、计数器、八个数据槽和 SET、ADD、STORE、HALT。逻辑周期取指、译码、更新状态。真实处理器可通过流水线重叠工作,但可观察结果需遵守体系结构规则。本模型不模拟流水线或机器编码。
哪个状态标识下一指令?
完整解答
程序计数器。
内存、地址与表示
内存关联地址与保存值,加载读取,存储写入。地址不同于该地址的值。STORE 0 把累加器写入零号槽,不是把累加器设零。真实按字节寻址机器读取多字节值需规定宽度、对齐与字节序。模型使用 Python 列表槽,八槽不等同完整物理内存系统。
累加器七后 STORE 2,改变什么?
完整解答
槽二变七,累加器仍七。
缓存与局部性
存储层次权衡容量与延迟。缓存保存近期块,时间局部性复用数据,空间局部性访问邻近数据。直接映射模型用地址取模选行、整除得标记,相同有效标记命中,否则替换。四行中地址零和四冲突。真实缓存还有多字节块、关联度与写策略,单字读取模型只突出映射冲突。
反复访问仍可能因冲突未命中吗?
完整解答
可以,零与四交替互相替换。
性能与抽象边界
耗时依赖指令数、每指令平均工作与时钟周期,因素相互影响,频率更高不保证整体更快。分支、内存等待与依赖影响吞吐。若九成运行不变,即使其余一成无限加速,总加速最多 1/0.9≈1.11。优化前先分析瓶颈,明确模型假设。
仅优化一成能整体十倍吗?
完整解答
不能,剩余九成把加速限制约 1.11 倍。
常见误解
- 模拟器是教学模型,不是真实指令集实现。
- 缓存命中次数本身不能确定运行时间。
实验准备
下载脚本,在终端中使用 Python 3.11 或更新版本运行:python m09_cpu.py. Windows 也可使用 py -3;部分系统使用 python3。实验仅用标准库。先预测结果,再运行并完成变体。不要使用 -O,以保留断言。下方输出由构建器实际运行捕获,两种语言使用相同代码与输出。
实验 1 — 跟踪微型 CPU
预测累加器与计数器,模型在执行操作前递增计数器。
"""A tiny 8-bit accumulator machine, not an emulator of a real CPU."""
def run(program):
pc, acc, memory, steps = 0, 0, [0] * 8, 0
while steps < 100:
if not 0 <= pc < len(program):
raise ValueError("program counter out of bounds")
op, operand = program[pc]
print(f"pc={pc} acc={acc:3} execute={op} {operand}")
pc += 1; steps += 1
if op == "SET": acc = operand % 256
elif op == "ADD": acc = (acc + operand) % 256
elif op == "STORE":
if not 0 <= operand < len(memory): raise ValueError("invalid address")
memory[operand] = acc
elif op == "HALT": return memory
else: raise ValueError("unknown instruction")
raise RuntimeError("step limit exceeded")
result = run([("SET", 250), ("ADD", 10), ("STORE", 0), ("HALT", 0)])
print("memory[0]:", result[0])
assert result[0] == 4
pc=0 acc= 0 execute=SET 250
pc=1 acc=250 execute=ADD 10
pc=2 acc= 4 execute=STORE 0
pc=3 acc= 4 execute=HALT 0
memory[0]: 4
- 把三加四写入槽一。
- 尝试 STORE 9 和未知指令。
- 删除 HALT,解释边界错误。
完整解答
使用 SET 3、ADD 4、STORE 1、HALT。无效地址或操作抛 ValueError。无 HALT 时计数器超出指令列表,模型明确拒绝。
实验 2 — 缓存访问模式
独立于耗时统计命中,初始标记 None 表示无效。
"""A direct-mapped, one-word-per-line read cache with no timing simulation."""
def access_trace(addresses, lines=4):
tags, hits = [None] * lines, 0
for address in addresses:
index, tag = address % lines, address // lines
hit = tags[index] == tag
hits += int(hit)
tags[index] = tag
print(f"address={address} line={index} tag={tag} {'hit' if hit else 'miss'}")
return hits
print("local reuse")
assert access_trace([0, 1, 0, 1]) == 2
print("conflicting reuse")
assert access_trace([0, 4, 0, 4]) == 0
local reuse
address=0 line=0 tag=0 miss
address=1 line=1 tag=0 miss
address=0 line=0 tag=0 hit
address=1 line=1 tag=0 hit
conflicting reuse
address=0 line=0 tag=0 miss
address=4 line=0 tag=1 miss
address=0 line=0 tag=0 miss
address=4 line=0 tag=1 miss
- 八行运行零四交替。
- 预测零至三重复访问。
- 解释更大块会改变什么。
完整解答
八行分离零和四,得到两命中。四行重复零至三在四次初次未命中后四命中。更大块增加空间复用,也改变索引标记计算与冲突。
练习与完整解答
先尝试,再展开解答。★ 应用概念;★★ 结合概念;★★★ 进行设计或证明。
二进制一加一。
完整解答
10,和零进位一。
八位回绕的 250+10?
完整解答
260 对 256 取余为四。
跟踪 SET 2、ADD 3、STORE 0、HALT。
完整解答
累加器二、五,零槽为五,HALT 返回内存。
地址九映射到四行缓存哪里?
完整解答
行一,标记二。
区分时间与空间局部性。
完整解答
重复读同记录是时间,连续扫描邻接记录是空间。
一半程序四倍加速,整体加速?
完整解答
新相对时间 0.625,加速 1.6 倍。
模拟器缺少哪些真实 CPU 行为?
完整解答
缺少指令编码、流水线、中断、虚拟内存、可变延迟与缓存一致性,只展示逻辑状态变化。
STORE 0 与 SET 0 有何不同?
完整解答
STORE 选地址并写当前值,SET 设置累加器值。
自测
选择答案查看反馈,重置后可重做。无需 JavaScript 也可阅读答案表。
一与一异或?
下一指令位置?
STORE 改变什么?
时间局部性?
四行中零和四怎样?
更高频率单独保证快吗?
答案表
- A — 相同位给零。
- B — 计数器记录控制位置。
- C — 向地址写值。
- A — 空间局部性关注邻近。
- B — 索引为地址模四。
- C — 工作量与等待也重要。
引导阅读
- Nand2Tetris 项目路线 — 查看逻辑门至 CPU 项目,指出各阶段抽象。
复习与下一步
跟踪四指令并解释冲突未命中。模块 10 将介绍操作系统如何共享并保护资源。
关键术语
| 术语 | 含义 |
|---|---|
| 寄存器 | 小型体系结构可见工作存储。 |
| 缓存未命中 | 请求数据不在对应缓存项。 |
| 指令集体系结构 | 机器可见指令与状态约定。 |