1 个不稳定版本

使用旧的Rust 2015

0.6.0 2018年8月21日

#362 in 模拟器

GPL-3.0+

260KB
7K SLoC

Zinc64

Build Status Crates.io

概述

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程序员参考指南,其余的就是历史了。

2020年将带来对改进的OpenGL端口的支持,包括控制台支持和裸机环境,特别是裸机Raspberry Pi 3端口。请参阅zinc64-rpi以获取早期预览。

设计

功能 std

zinc64-system crate可以在没有标准库的情况下工作,例如在裸机环境中。要在#[no_std]环境中使用zinc64-system,请使用

[dependencies]
zinc64-system = { version = "0.9.0", default-features = false }

可扩展性

可以通过提供自定义core::ChipFactory trait实现来替换模拟器组件。core::ChipFactory trait的默认实现是通过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 完成
格式 二进制 完成
格式 CRT 完成
格式 D64 未启动
格式 P00 完成
格式 Prg 完成
格式 Tap 完成
格式 T64 未启动
客户端 OpenGL 进行中
客户端 Raspi3 进行中

路线图

  • v0.9 - OpenGL客户端
  • v0.10 - 树莓派端口
  • v0.11 - 软盘支持

开始使用

  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/binaryfields/zinc64
    

    或下载zip存档

     https://github.com/binaryfields/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++构建工具工作负载。

调试器

要启动调试器,以'-d'或'--debug'选项运行仿真器。可选地,您可以指定'--debugaddress'以绑定到特定地址。

    ./target/release/zinc64 --debug

要连接到调试器,通过telnet连接到调试器使用的地址和端口。

    telnet localhost 9999

调试器命令和语法仿照Vice仿真器。要查看可用命令列表,在调试会话中输入

    help

或要获取特定命令的帮助

    help <command>

Radare2

版本0.3已合并对Radare2的初始支持。要以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功能测试帮助执行了CPU验证,该测试针对6502处理器

    ./target/release/zinc64 --console --loglevel trace bin/6502_functional_test.bin 

键盘快捷键

快捷键 功能
Escape 控制台
Alt-Enter 切换全屏
Alt-F9 重置
Alt-H 激活调试器
Alt-M 切换静音
Alt-P 切换暂停
Alt-Q 退出
Alt-W 时间跳跃模式
Ctrl-F1 磁带播放/停止
NumPad-2 游戏杆下
NumPad-4 游戏杆左
NumPad-5 游戏杆开火
NumPad-6 游戏杆右
NumPad-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,它是我关于各种硬件组件的参考指南

依赖项

~19MB
~385K SLoC