1 个不稳定版本
0.8.0 | 2019 年 5 月 6 日 |
---|
#317 in 模拟器
在 3 个 crate 中使用
280KB
7K SLoC
Zinc64
** 注意:zinc64 crate 已重命名为 zinc64-emu **
概述
zinc64 是一个包含电池但可替换的 Commodore 64 模拟器工具包。它被设计为可以作为一个独立的模拟器,或者作为一个库用来构建新的模拟器。设计哲学允许每个组件被替换为不同的实现。因此,特别考虑了芯片之间的交互而无需将它们耦合在一起。
它实现了 MOS 6510 CPU、MOS 6526 CIA、MOS 6581 SID、MOS 6567/6569 VIC 套片,以及 C64 所有的设备和外围设备。
故事
zinc64 是作为一个学习 Rust 和更详细地探索 Commodore 64 硬件的练习开始的。大约在 2016 年中旬,为了满足我的 8 位怀旧情绪,我买了一台工作正常的 Commodore 64(实体版)并开始收集将其上软件安装到其上的各种配件。很快,我就买了一本 C64 程序员参考指南,其余的就是历史了。
2019 年带来了支持修订的 SDL 端口,具有控制台支持和裸机环境,特别是裸机 Raspberry Pi 3 端口。参见 zinc64-rpi 以获得早期预览。
设计
功能 std
zinc64-emu crate 不使用标准库,例如在裸机环境中。要在 #[no_std] 环境中使用 zinc64-emu,请使用
[dependencies]
zinc64-emu = { version = "0.8.0", default-features = false }
可扩展性
可以通过提供自定义 core::ChipFactory 特征实现来替换模拟器组件。core::ChipFactory 特征的默认实现是通过 system::C64Factory 完成的。芯片工厂对象被传递到 system::C64 组件中,该组件提供核心模拟器功能。
以下是如何一起使用这些组件的示例
let config = Rc::new(Config::new(SystemModel::from("pal")));
let chip_factory = Box::new(C64Factory::new(config.clone()));
let mut c64 = C64::new(config.clone(), chip_factory).unwrap();
c64.reset(true);
用于模拟系统操作的四个核心特征是 Chip、Cpu、Mmu 和 Addressable。
/// A chip represents a system component that is driven by clock signal.
pub trait Chip {
/// The core method of the chip, emulates one clock cycle of the chip.
fn clock(&mut self);
/// Process delta cycles at once.
fn clock_delta(&mut self, delta: u32);
/// Handle vsync event.
fn process_vsync(&mut self);
/// Handle reset signal.
fn reset(&mut self);
// I/O
/// Read value from the specified register.
fn read(&mut self, reg: u8) -> u8;
/// Write value to the specified register.
fn write(&mut self, reg: u8, value: u8);
}
/// CPU is responsible for decoding and executing instructions.
pub trait Cpu {
...
/// The core method of the cpu, decodes and executes one instruction. Tick callback is invoked
/// for each elapsed clock cycle.
fn step(&mut self, tick_fn: &TickFn);
// I/O
/// Read byte from the specified address.
fn read(&self, address: u16) -> u8;
/// Write byte to the specified address.
fn write(&mut self, address: u16, value: u8);
}
/// Represents memory management unit which controls visible memory banks
/// and is used by CPU to read from and write to memory locations.
pub trait Mmu {
/// Change bank configuration based on the specified mode.
fn switch_banks(&mut self, mode: u8);
// I/O
/// Read byte from the specified address.
fn read(&self, address: u16) -> u8;
/// Write byte to the specified address.
fn write(&mut self, address: u16, value: u8);
}
/// Addressable represents a bank of memory.
pub trait Addressable {
/// Read byte from the specified address.
fn read(&self, address: u16) -> u8;
/// Write byte to the specified address.
fn write(&mut self, address: u16, value: u8);
}
由于所有系统组件(除了 Cpu 和 Mmu)都实现了 Chip 特征,芯片和其他组件之间的交互仅限于并通过提供给芯片构造函数的共享 I/O 线/引脚来处理。这允许芯片的实现相互解耦。
状态
类 | 组件 | 状态 |
---|---|---|
芯片组 | 6510 CPU | 完成 |
芯片组 | 内存 | 完成 |
芯片组 | 6526 CIA | 完成 |
芯片组 | 6581 SID | 完成 |
芯片组 | 6567 VIC | 完成 |
设备 | 卡带 | 完成 |
设备 | 软盘 | 未开始 |
设备 | 数据磁带 | 完成 |
设备 | 键盘 | 完成 |
设备 | 游戏手柄 | 完成 |
设备 | 鼠标 | 未开始 |
调试器 | 遥控器 | 完成 |
调试器 | Radare2 | 完成 |
格式 | 二进制 | 完成 |
格式 | 创建 | 完成 |
格式 | D64 | 未开始 |
格式 | P00 | 完成 |
格式 | Prg | 完成 |
格式 | Tap | 完成 |
格式 | T64 | 未开始 |
客户端 | SDL | 进行中 |
客户端 | Raspi3 | 进行中 |
路线图
- v0.9 - rpi 端口
- v0.10 - 软盘支持
入门指南
-
安装 Rust 编译器或遵循以下步骤 @ https://www.rust-lang.net.cn/en-US/install.html.
curl https://sh.rustup.rs -sSf | sh
-
克隆此存储库。
git clone https://github.com/digitalstreamio/zinc64
或下载 zip 存档
https://github.com/digitalstreamio/zinc64/archive/master.zip
-
构建模拟器。
cd zinc64 cargo build --release --all
-
运行模拟器。
./target/release/zinc64
或启动程序
./target/release/zinc64 --autostart path
Windows 注意事项
-
安装 Microsoft Visual C++ Build Tools 2017. 选择 Visual C++ build tools 工作负载。
-
安装 SDL2 开发库.
-
从
SDL2-devel-2.0.x-VC\SDL2-2.0.x\lib\x64\
复制所有 SDL2 库文件到
C:\Users\{Your Username}\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib
-
从
SDL2-devel-2.0.x-VC\SDL2-2.0.x\lib\x64\
到 zinc64 项目目录复制 SDL2.dll
调试器
要启动调试器,请使用 '-d' 或 '--debug' 选项运行模拟器。可选地,您可以使用 '--debugaddress' 绑定到特定地址。
./target/release/zinc64 --debug
要连接到调试器,请使用 telnet 连接到调试器使用的地址和端口。
telnet localhost 9999
调试器命令和语法模仿 Vice 模拟器。要查看可用命令列表,请在调试会话中输入
help
或要获取特定命令的帮助
help <command>
Radare2
Radare2 的初始支持已合并到版本 0.3 中。要使用 RAP 服务器支持启动模拟器,请运行
./target/release/zinc64 --rap 127.0.0.1:9999
并连接到
radare2 -a 6502 -d rap://localhost:9999/1
示例
我包含了一些来自 Kick Assembler 的示例,我使用这些示例测试了模拟器的各个组件。它们可以在存储库的 bin 文件夹中找到,并可以通过模拟器的自动启动选项启动。
./target/release/zinc64 --autostart bin/SineAndGraphics.prg
程序 | 状态 |
---|---|
6502_functional_test.bin | 通过 |
FloydSteinberg.prg | 通过 |
KoalaShower.prg | 通过 |
Message.prg | 通过 |
MusicIrq.prg | 通过 |
Scroll.prg | 通过 |
SID_Player.prg | 通过 |
SimpleSplits.prg | 失败 |
SineAndGraphics.prg | 通过 |
测试
使用 Klaus2m5 为 6502 处理器提供的Klaus2m5 功能测试帮助进行了 CPU 验证
./target/release/zinc64 --binary bin/6502_functional_test.bin --offset=1024 --console --loglevel trace
键盘快捷键
快捷键 | 功能 |
---|---|
Esc | 控制台 |
Alt-Enter | 切换全屏 |
Alt-F9 | 重置 |
Alt-H | 激活调试器 |
Alt-M | 切换静音 |
Alt-P | 切换暂停 |
Alt-Q | 退出 |
Alt-W | 快速模式 |
Ctrl-F1 | 磁带播放/停止 |
数字键盘2 | 摇杆向下 |
数字键盘4 | 摇杆向左 |
数字键盘5 | 摇杆开火 |
数字键盘6 | 摇杆向右 |
数字键盘8 | 摇杆向上 |
致谢
- 感谢 Commodore 团队打造了一个标志性的 8 位机器
- 感谢 Rust 开发者为开发提供了不可思议的语言
- 感谢 Rafal Wiosna 将他对 8 位机器的热情传递给我 ;)
- 感谢 Klaus Dormann 提供的 6502_65C02_functional_tests,没有它我将迷失方向
- 感谢 Dag Lem 提供的 reSID 实现
- 感谢 Christian Bauer 提供的关于 MOS 6567/6569 视频控制器 (VIC-II) 及其在 Commodore 64 中的应用的论文
- 感谢 Peter Schepers 提供的“各种模拟器文件格式介绍”
- 感谢 c64-wiki.com 为我提供了各种硬件组件的参考资料
依赖项
~605KB
~10K SLoC