Python 模拟 TOY 计算机:5 大部件 1000 单元内存的冯·诺伊曼架构实现
Python 模拟 TOY 计算机:5 大部件 1000 单元内存的冯·诺伊曼架构实现
1. 冯·诺伊曼架构的核心原理
1945年,约翰·冯·诺伊曼在《EDVAC报告书的第一份草案》中提出了现代计算机的基础架构。这个架构的核心思想可以用三个关键原则概括:
- 二进制编码:所有指令和数据都采用二进制形式表示
- 存储程序:程序指令与数据共同存储在内存中
- 五大部件:运算器、控制器、存储器、输入设备和输出设备
# 冯·诺伊曼架构的简化表示 class VonNeumannArchitecture: def __init__(self): self.memory = [0] * 1000 # 存储器 self.registers = [0] * 10 # 寄存器组 self.pc = 0 # 程序计数器(控制器) self.alu = ALU() # 运算器 self.io = IODevice() # 输入输出设备现代计算机虽然性能提升了数百万倍,但基本架构依然遵循这一设计。我们的TOY计算机模拟器将完整实现这五大组件:
| 组件 | 功能描述 | 模拟实现方式 |
|---|---|---|
| 运算器 | 执行算术逻辑运算 | Python算术运算符 |
| 控制器 | 指令读取与流程控制 | 程序计数器与指令循环 |
| 存储器 | 存储指令和数据 | Python列表 |
| 输入设备 | 接收外部数据 | Python input()函数 |
| 输出设备 | 显示计算结果 | Python print()函数 |
2. TOY计算机的内存与寄存器设计
我们的模拟器采用1000个单元的内存和10个通用寄存器,这种规模既足够演示完整计算流程,又保持足够简洁。
内存组织方式:
- 每个内存单元存储一条指令或一个数据值
- 地址范围:000-999(三位十进制表示)
- 指令格式:
操作码 操作数1 操作数2
# 初始化TOY计算机硬件 def init_toy_computer(): # 1000单元内存,初始化为0 memory = [''] * 1000 # 10个通用寄存器(R0-R9) registers = [0] * 10 # 特殊寄存器 program_counter = 0 # 程序计数器 instruction_register = '' # 指令寄存器 return memory, registers, program_counter, instruction_register寄存器设计对性能至关重要。TOY计算机的寄存器使用方案:
寄存器编号 | 常规用途 | 特殊说明 ----------|-------------------|------------------ R0 | 通用/累加器 | 常用作默认目标寄存器 R1-R8 | 通用寄存器 | 无特殊限制 R9 | 状态标志寄存器 | 存储比较结果等状态3. 指令集设计与实现
TOY计算机支持基础指令集,涵盖数据处理、算术运算、流程控制和I/O操作:
3.1 数据移动指令
def execute_mov(opcode, op1, op2, reg, mem): if opcode == 'mov1': # 内存到寄存器 reg[op1] = int(mem[op2]) elif opcode == 'mov2': # 寄存器到内存 mem[op1] = str(reg[op2]) elif opcode == 'mov3': # 立即数到寄存器 reg[op1] = op2 return reg, mem3.2 算术运算指令
def execute_arithmetic(opcode, op1, op2, reg): if opcode == 'add': reg[op1] += reg[op2] elif opcode == 'sub': reg[op1] -= reg[op2] elif opcode == 'mul': reg[op1] *= reg[op2] elif opcode == 'div': reg[op1] = reg[op1] // reg[op2] return reg3.3 流程控制指令
def execute_flow_control(opcode, op1, op2, reg, pc): if opcode == 'jmp': return op1 # 直接跳转 elif opcode == 'jz': return op2 if reg[op1] == 0 else pc + 1 return pc + 13.4 I/O指令
def execute_io(opcode, op1, reg): if opcode == 'in': reg[op1] = int(input("输入: ")) elif opcode == 'out': print(f"输出: {reg[op1]}") return reg4. 完整的指令执行周期
冯·诺伊曼架构的核心是指令的连续自动执行,这个过程分为四个阶段:
- 取指(Fetch):从内存获取指令
- 译码(Decode):解析指令操作码和操作数
- 执行(Execute):执行指令操作
- 回写(Writeback):更新寄存器或内存
def fetch(memory, pc): """从内存中取出指令""" return memory[pc], pc + 1 def decode(instruction): """解析指令为操作码和操作数""" parts = instruction.split() opcode = parts[0] op1 = int(parts[1]) if len(parts) > 1 else None op2 = int(parts[2]) if len(parts) > 2 else None return opcode, op1, op2 def execute(opcode, op1, op2, reg, mem, pc): """执行指令并返回更新后的状态""" if opcode.startswith('mov'): reg, mem = execute_mov(opcode, op1, op2, reg, mem) elif opcode in ['add', 'sub', 'mul', 'div']: reg = execute_arithmetic(opcode, op1, op2, reg) elif opcode in ['jmp', 'jz']: pc = execute_flow_control(opcode, op1, op2, reg, pc) elif opcode in ['in', 'out']: reg = execute_io(opcode, op1, reg) return reg, mem, pc def run_program(memory, start_addr): """执行完整的取指-译码-执行循环""" pc = start_addr reg = [0] * 10 while True: instruction, pc = fetch(memory, pc) if instruction == 'halt': break opcode, op1, op2 = decode(instruction) reg, memory, pc = execute(opcode, op1, op2, reg, memory, pc)5. 实战:编写并运行TOY程序
让我们编写一个计算1+2+...+100的程序:
000 mov3 1 0 # R1 = 0 (总和) 001 mov3 2 1 # R2 = 1 (当前数) 002 mov3 3 101 # R3 = 101 (终止条件) 003 add 1 2 # R1 += R2 004 add 2 1 # R2 += 1 005 sub 3 2 # R3 - R2 006 jz 3 008 # if R3==R2, jump to 008 007 jmp 003 # loop back 008 out 1 # print result 009 halt在Python模拟器中加载并运行:
# 加载程序到内存 program = [ "mov3 1 0", "mov3 2 1", "mov3 3 101", "add 1 2", "add 2 1", "sub 3 2", "jz 3 8", "jmp 3", "out 1", "halt" ] memory = [''] * 1000 for addr, instr in enumerate(program): memory[addr] = instr # 运行程序 run_program(memory, 0)这个程序演示了TOY计算机的核心能力:
- 寄存器操作
- 算术运算
- 条件分支
- 循环结构
- 输入输出
6. 扩展指令集实现
为增强TOY计算机的功能,我们可以添加三条实用指令:
- add2 Rx n:寄存器Rx加立即数n
- cmp Rx n:比较Rx与n,设置标志位
- ble addr:若比较结果为≤,跳转到addr
def execute_extended(opcode, op1, op2, reg, pc, cf): if opcode == 'add2': reg[op1] += op2 elif opcode == 'cmp': cf = 1 if reg[op1] <= op2 else 0 elif opcode == 'ble' and cf: pc = op1 return reg, pc, cf使用扩展指令重写求和程序:
000 mov3 1 0 # R1 = 0 001 mov3 2 1 # R2 = 1 002 add2 1 2 # R1 += R2 003 add2 2 1 # R2 += 1 004 cmp 2 100 # 比较R2与100 005 ble 2 # 若R2<=100则循环 006 out 1 # 输出结果 007 halt这种设计展示了如何通过合理扩展指令集来提高编程效率。