用Python手搓一个简易CPU:从零模拟TOY计算机指令集(附完整代码)
理解计算机如何工作,最直接的方式莫过于亲手构建一个简化版的CPU。TOY计算机作为教学用简化架构,完美平衡了复杂度与可理解性。本文将带你用Python从零实现一个完整的TOY计算机模拟器,通过200行代码揭示CPU执行指令的核心原理。
1. TOY计算机架构解析
TOY计算机由哈佛架构简化而来,包含三个核心组件:
- 内存单元:1000个存储位置,每个可存放16位数据或指令
- 寄存器组:10个通用寄存器(R0-R9)加4个特殊寄存器
- 控制单元:实现取指-译码-执行循环
用Python类表示这个结构:
class ToyCPU: def __init__(self): self.memory = [0] * 1000 # 主存储器 self.registers = [0] * 10 # R0-R9 self.pc = 0 # 程序计数器 self.ir = None # 指令寄存器 self.cf = 0 # 状态标志位2. 指令集设计与编码
TOY采用定长16位指令,典型格式如下:
[操作码4位][操作数1 6位][操作数2 6位]基础指令集包含12种操作:
| 操作码 | 助记符 | 功能描述 |
|---|---|---|
| 0001 | MOV1 | 内存→寄存器 |
| 0010 | MOV2 | 寄存器→内存 |
| 0011 | MOV3 | 立即数→寄存器 |
| 0100 | ADD | 寄存器加法 |
| 0101 | SUB | 寄存器减法 |
| 0110 | JMP | 无条件跳转 |
指令编码示例:
def encode_mov3(reg, value): opcode = 0b0011 << 12 reg_part = (reg & 0b1111) << 6 val_part = value & 0b111111 return opcode | reg_part | val_part3. 核心执行循环实现
CPU工作流程遵循经典的三阶段模型:
- 取指阶段:
def fetch(self): self.ir = self.memory[self.pc] self.pc += 1- 译码阶段:
def decode(self): opcode = (self.ir >> 12) & 0xF op1 = (self.ir >> 6) & 0x3F op2 = self.ir & 0x3F return opcode, op1, op2- 执行阶段(以ADD为例):
def execute(self, opcode, op1, op2): if opcode == 0b0100: # ADD self.registers[op1] += self.registers[op2] self.registers[op1] &= 0xFFFF # 16位截断4. 完整模拟器实现
整合各组件后的核心循环:
def run(self, start_addr): self.pc = start_addr while True: self.fetch() opcode, op1, op2 = self.decode() if opcode == 0b0000: # HALT break self.execute(opcode, op1, op2) # 处理跳转指令的特殊情况 if opcode not in [0b0110, 0b0111]: self.pc += 1典型程序执行流程示例:
MOV3 R1, 5 # R1 = 5 MOV3 R2, 7 # R2 = 7 ADD R1, R2 # R1 = R1 + R2 OUT R1 # 输出12 HALT5. 调试与可视化增强
为提升教学价值,可添加执行跟踪功能:
def print_state(self): print(f"PC:{self.pc:04X} IR:{self.ir:04X} ", end="") print("Regs:[", end="") for r in self.registers[:4]: print(f"{r:04X}", end=" ") print("...]")在run()方法中添加:
print(f"Executing: {self.disassemble(self.ir)}") self.print_state()6. 扩展指令集实践
在基础指令集上增加乘法指令:
elif opcode == 0b1100: # MUL self.registers[op1] *= self.registers[op2] self.registers[op1] &= 0xFFFF对应的汇编语法:
MUL R1, R2 # R1 = R1 * R27. 从模拟器学到的计算机原理
通过这个项目,可以直观理解:
- 程序如何转化为指令序列
- 时钟周期与流水线概念
- 寄存器暂存数据的必要性
- 内存与CPU的交互方式
例如,当执行ADD R1,R2时,CPU内部实际发生:
- 从内存获取操作数
- ALU执行加法运算
- 结果写回寄存器
- 更新程序计数器
完整项目代码已托管在GitHub,包含测试程序和可视化界面。建议尝试修改指令集或添加中断机制来深化理解。