#c64 #emulator #commodore #no-std

no-std zinc64-emu

包含电池但可替换的 Commodore 64 模拟器工具包

1 个不稳定版本

0.8.0 2019 年 5 月 6 日

#317 in 模拟器


3 个 crate 中使用

GPL-3.0+

280KB
7K SLoC

Zinc64

Build Status Crates.io

** 注意: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 - 软盘支持

入门指南

  1. 安装 Rust 编译器或遵循以下步骤 @ https://www.rust-lang.net.cn/en-US/install.html.

     curl https://sh.rustup.rs -sSf | sh
    
  2. 克隆此存储库。

     git clone https://github.com/digitalstreamio/zinc64
    

    或下载 zip 存档

     https://github.com/digitalstreamio/zinc64/archive/master.zip
    
  3. 构建模拟器。

     cd zinc64
     cargo build --release --all
    
  4. 运行模拟器。

     ./target/release/zinc64
    

    或启动程序

     ./target/release/zinc64 --autostart path
    

Windows 注意事项

  1. 安装 Microsoft Visual C++ Build Tools 2017. 选择 Visual C++ build tools 工作负载。

  2. 安装 SDL2 开发库.

  3.  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
    
  4.  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