NES TDD

292. Геймпад в CpuBus по адресу 4016

Маршрутизация чтения/записи $4016 в CpuBus к порту геймпада 1.

Урок 292 из 356 · tests/chapter_07_controller_input/test_292_cpubus_controller_4016.py

Файл для обновления

emulator/bus/cpu_bus.py

Зачем нужен этот шаг

На предыдущих шагах, посвящённых геймпаду, был создан чистый объект Controller. Теперь шина CPU должна предоставлять этот геймпад через порт геймпада, отображённый в память NES:

$4016 = controller port 1

Обычная последовательность опроса NES

write 1 to $4016
write 0 to $4016
read $4016 eight times

Эти восемь чтений возвращают

A, B, Select, Start, Up, Down, Left, Right

Ссылки

https://www.nesdev.org/wiki/Standard_controller
https://www.nesdev.org/wiki/Controller_reading_code

Пример предполагаемой реализации

from emulator.input.controller import Controller


@dataclass
class CpuBus:
    ...
    controller_1: Controller = field(default_factory=Controller)

    def read(self, addr: int) -> int:
        ...

        # Controller port 1
        if addr == 0x4016:
            return self.controller_1.read_bit()

        # Controller port 2 / expansion input is out of scope for now.
        if addr == 0x4017:
            return 0

        ...

    def write(self, addr: int, value: int) -> None:
        ...

        # Controller port 1 strobe
        if addr == 0x4016:
            self.controller_1.write_strobe(value)
            return

        # $4017 writes are APU frame-counter writes, no-op for now.
        if addr == 0x4017:
            return

        ...

Важное различие

$4016 read/write belongs to controller port 1.
$4017 read is controller port 2 / expansion input, out of scope for now.
$4017 write is APU frame counter, out of scope for now.

Распространённое заблуждение

"Controller input should be handled by pygame directly in CpuBus."

Нет. CpuBus должна взаимодействовать только с чистым объектом Controller. Сопоставление клавиш pygame позже будет обновлять булевы значения кнопок Controller из ручной/фронтенд точки входа.

Вне рамок этого шага

  • сопоставление клавиш pygame
  • реализация порта геймпада 2
  • контроллеры расширения Famicom
  • поведение сбоя чтения DMC/геймпада
  • поведение верхних бит открытой шины

Запустить этот урок

uv run pytest tests/chapter_07_controller_input/test_292_cpubus_controller_4016.py -v