292. CpuBus 控制器 4016
将 CpuBus $4016 的读写路由到控制器端口 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