65XX 系列 CPU,特别是经典的 MOS 6502 处理器,是 20 世纪 70-80 年代计算机和游戏机的核心,如 Apple II、Atari 800 和 NES 红白机。尽管官方文档仅定义了 151 条指令,但其 8 位操作码空间总计 256 种,其中约 100 种未文档化指令(illegal opcodes)因硬件布线侧效应对仿真至关重要。这些指令往往组合已知操作的行为,如 LAX(LDA + TAX),在游戏中用于加速或特殊效果。忽略它们会导致兼容性问题,例如某些 NES 游戏依赖 DCP(DEC + CMP)指令的 dummy 读写周期来脉冲硬件端口。
反向工程这些指令的核心在于理解 NMOS 6502 的硬件实现。早期逆向方法依赖逻辑分析仪捕获真实芯片的时序信号:将测试 ROM 加载到 6502 开发板,执行每个操作码,记录寄存器变化、标志位更新和内存访问模式。例如,操作码 0x0B(ANC #imm)执行 AND 立即数后,将 N 标志设为 C 标志,这在官方文档中无对应,但通过示波器或 LA 可确认其行为为 AND imm 后 N=C。这类测试需覆盖所有寻址模式(零页、绝对、间接等),并注意变体如 65C02 CMOS 版移除多数 illegal ops,导致 Apple IIc 兼容性问题。
在现代仿真器中,实现精确行为需构建完整 256 操作码表。使用 switch 语句或函数指针数组 dispatch,每条指令记录周期数(2-7 周期)和内存访问(read-modify-write 的 dummy 读)。关键参数:为 RMW 指令(如 ISC、RLC)模拟额外读周期,即使无副作用;分支指令处理页面跨越额外 1 周期;非法指令如 0x02/0x22/0x42 等 KIL(JAM)导致 fetch 循环,仿真器须检测避免死锁。测试套件如 6502_functional_tests 验证寄存器 / 标志一致性,nestest.nes 专测 NES 2A03 变体(无 BCD)。优化阈值:dispatch 循环目标 < 10ns / 指令,使用 JIT 预编译非法路径减少分支预测失败。
性能优化聚焦周期精确仿真(cycle-accurate)。传统解释器(interpreter)速度瓶颈在 dispatch 和内存模拟;解决方案:固定时钟比(CPU:3 周期 / PPU:1 像素)下批量执行指令,直至 PPU DMA 中断。参数设定:内存访问延迟 1 周期,BRK/IRQ 延迟 7 周期;使用位打包寄存器(P 标志 7 位)节省空间。针对非法指令,优化为 NOP 变体加速非关键代码,但保留精确标志更新。基准:Altirra 仿真器通过微码式 dispatch 实现 > 100MHz 有效速度,支持 undocumented 6502 行为如 mid-scanline 寄存器变更。
现代复古项目中,这些知识直接落地 FPGA 软核和加速器。MiSTer 框架的 6502 核心需实现全 illegal 表以兼容原始 ROM;优化清单:1)Verilog 中用 casez 覆盖 256 码,非法路径映射官方等价;2)时序约束 <10ns/clk,支持 65C816 扩展(WDC 变体);3)回滚策略:若测试失败,fallback 到 NMOS 行为表;4)监控点:周期计数器溢出阈值 0xFFFF,非法率> 5% 触发警告。参数示例:DMA 冲突延迟 2 周期,IRQ 优先级高于 NMI。项目如 Analogue Nt Mini 复刻机利用此提升帧率稳定性。
实际落地清单:
- 逆向工具:Saleae Logic Pro(捕获 > 100MHz),6502singleboard 电脑。
- 仿真框架:Rust/Verilog 模板,集成 nesdev wiki opcode 表。
- 测试向量:100% 覆盖 illegal,阈值:标志匹配率 > 99.9%。
- 优化参数:dispatch LUT 大小 256*8B,JIT 缓存命中 > 95%。
- 风险缓解:版本检测(6502/65C02/2A03),动态切换行为表。
通过上述实践,不仅实现精确仿真,还能在 FPGA 项目中优化至原生速度,推动复古计算复兴。(约 1250 字)
资料来源:
- NESDev Wiki: CPU unofficial opcodes。
- Altirra Atari Emulator 文档,精确 undocumented 行为。
- FFD2.com(65XX 参考)。