290. Controller definition
Define the pure NES Controller state object.
Lesson 290 of 356 · tests/chapter_07_controller_input/test_290_controller_definition.py
Files to create in this step
emulator/input/controller.pyWhy this step exists
Before connecting controller input to CpuBus address $4016, we need a pure data model for the standard NES controller. This keeps the controller mechanism easy to test without involving pygame, CpuBus, ROM execution, or frame timing.
What is a standard NES controller?
The standard controller has eight buttons
References
https://www.nesdev.org/wiki/Standard_controller
https://www.nesdev.org/wiki/Controller_reading_code
A, B, Select, Start, Up, Down, Left, RightThe hardware serial read order is
first read -> A
second read -> B
third read -> Select
fourth read -> Start
fifth read -> Up
sixth read -> Down
seventh read -> Left
eighth read -> RightImportant distinction
Some NES assembly routines shift these reads into RAM so A ends up in bit 7 of a game-owned byte. That does not mean the hardware sends Right first. The emulator should model the hardware serial order.
Suggested implementation example
from dataclasses import dataclass
BUTTON_A = 1 << 0
BUTTON_B = 1 << 1
BUTTON_SELECT = 1 << 2
BUTTON_START = 1 << 3
BUTTON_UP = 1 << 4
BUTTON_DOWN = 1 << 5
BUTTON_LEFT = 1 << 6
BUTTON_RIGHT = 1 << 7
@dataclass
class Controller:
a: bool = False
b: bool = False
select: bool = False
start: bool = False
up: bool = False
down: bool = False
left: bool = False
right: bool = False
strobe: bool = False
captured_buttons: int = 0
read_index: int = 0Out of scope
- CpuBus $4016 routing
- pygame keyboard mapping
- controller port 2
- Famicom expansion controllers
- DMC/controller read glitch behavior
Run this lesson
uv run pytest tests/chapter_07_controller_input/test_290_controller_definition.py -v