#opcode #emulator #processor #compatible #instructions #test-suite #environments

nmos6502

适用于嵌入式环境的符合 no_std 规范的 NMOS6502 模拟器

2 个稳定版本

1.0.1 2023年3月31日
1.0.0 2023年3月29日

#647嵌入式开发

MIT 许可证

73KB
1.5K SLoC

Rust 中的 NMOS 6502

另一个 6502 模拟器吗?

是的!但等等,这是你为什么可能想要这个的原因

  • no_std 兼容
  • 最小依赖(仅 num_enum 作为操作码的预处理器)
  • 在 Big Endian 和 Little Endian 环境中均能工作
  • 通过了 Klaus2m5 6502 处理器功能测试套件
  • 支持 IRQNMI 中断
  • 在包括 Mac、PC 和嵌入式 RP2040 在内的各种系统上进行了测试
  • 每条指令执行后都会公开准确的周期计数

此实现涵盖了所有标准 NMOS 6502 操作码以及所有 "非法" NOP 等效操作码。未识别的操作码公开用于调试目的,将在以后实现。

快速入门

此库仅是 CPU。在 6502 系统中,CPU 始终负责总线当前地址。基本用法如下

let cpu = Nmos6502::new();

loop {
    // "bus" is any struct
    // that implements: BusInterface
    cpu.tick(&mut bus); 
}

CPU 通过 BusInterface 发送和接收数据,该接口由包用户自行实现。在最基本的情况下,实现可以简单地分配一个空的 64k u8 数组,并返回/写入索引值。

BusInterface 必须基本提供

fn get_byte_at(&mut self, addr:u16) -> u8;
fn set_byte_at(&mut self, addr:u16, byte: u8);

更多细节

6502 将使用默认的 RESET 向量 0xFFFC-0xFFFD。也就是说,BusInterface 为该地址返回的任何值都将被 cpu 设置为程序计数器。

在更复杂的系统中,例如 Apple][ 模拟器,您可能可以实施任何您喜欢的系统,通过 BusInterface 来拦截/分配任何请求到各种子系统。

为了效率/速度,您可以可选地覆盖

fn get_pipelined_bytes(&mut self, addr:u16) -> (u8, u8, u8)

这用于检索当前操作码和下两个字节作为可能的操作数。这仅在您有实际管道这些字节的方法(例如,一个可以在一条指令中发送 24 位 + 单词的系统)或您需要避免可能触发例如软开关的外部内存访问时才有用。默认实现简单地使用 get_byte_at 并在地址上循环增加。

依赖项

~1.5MB
~36K SLoC