016. Refactorización de la tabla de opcodes

Sustituir las ramas de CPU.step por una tabla de opcodes.

Lección 16 de 356 · tests/chapter_01_cpu/test_016_opcode_table_refactor.py

Archivo a crear

emulator/cpu/opcodes.py

Archivo a actualizar

emulator/cpu/cpu.py

Ubicaciones

opcodes.lda_immediate
opcodes.lda_zero_page
opcodes.lda_absolute
opcodes.OPCODE_TABLE
CPU.step

Por qué existe este paso

Las ramas directas funcionan para tres opcodes, pero escalan mal a lo largo de todo el conjunto de instrucciones del 6502. Una tabla hace que el despacho de byte a handler esté dirigido por datos, a la vez que conserva los límites existentes entre direccionamiento e instrucción.

Implementación de ejemplo completa

# 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)

Límite importante

CPU.step despacha; un handler de opcode coordina el direccionamiento, el acceso a memoria y la instrucción; lda realiza la transición de estado de registros y flags.

Error común

Un handler de opcode no es lo mismo que una instrucción. Tres opcodes de LDA comparten una única instrucción lda, pero usan mecanismos distintos de adquisición del operando.

Fuera de alcance

  • handlers de LDA indexada
  • valores de retorno del número de ciclos
  • un objeto decodificador de instrucciones genérico

Ejecutar esta lección

uv run pytest tests/chapter_01_cpu/test_016_opcode_table_refactor.py -v