016. 操作码表重构
用操作码表替换 CPU.step 中的分支。
第 16 / 356 · tests/chapter_01_cpu/test_016_opcode_table_refactor.py
要创建的文件
emulator/cpu/opcodes.py要更新的文件
emulator/cpu/cpu.py位置
opcodes.lda_immediate
opcodes.lda_zero_page
opcodes.lda_absolute
opcodes.OPCODE_TABLE
CPU.step为什么需要这一步
对三个操作码而言,直接分支尚可胜任,但面对整个 6502 指令集时扩展性很差。一张表使字节到处理函数的分发变为数据驱动,同时保留现有的寻址与指令边界。
完整示例实现
# emulator/cpu/opcodes.py
from emulator.cpu.addressing_modes import absolute, immediate, zero_page
from emulator.cpu.instructions import lda
def lda_immediate(cpu) -> None:
lda(cpu, immediate(cpu))
def lda_zero_page(cpu) -> None:
address = zero_page(cpu)
lda(cpu, cpu.bus.read(address))
def lda_absolute(cpu) -> None:
address = absolute(cpu)
lda(cpu, cpu.bus.read(address))
OPCODE_TABLE = {
0xA9: lda_immediate,
0xA5: lda_zero_page,
0xAD: lda_absolute,
}
# emulator/cpu/cpu.py
from emulator.cpu.opcodes import OPCODE_TABLE
class CPU:
def step(self) -> None:
opcode = self.fetch_byte()
handler = OPCODE_TABLE.get(opcode)
if handler is None:
raise NotImplementedError(
f"Opcode {opcode:02X} not implemented"
)
return handler(self)重要边界
CPU.step 负责分发;操作码处理函数协调寻址、内存访问和指令;lda 执行寄存器与标志位的状态转换。
常见误解
操作码处理函数并不等同于指令。三个 LDA 操作码共享同一个 lda 指令,但使用不同的操作数获取机制。
范围之外
- 变址 LDA 的处理函数
- 周期计数返回值
- 通用的指令解码器对象
运行本课
uv run pytest tests/chapter_01_cpu/test_016_opcode_table_refactor.py -v