#c64 #模拟器 #commodore

app zinc64

Commodore 64模拟器应用程序

10个版本 (破坏性更新)

0.8.0 2019年5月6日
0.7.0 2018年12月29日
0.6.0 2018年8月21日
0.5.2 2018年7月25日
0.1.0 2018年1月13日

#173 in 模拟器

每月下载量 29次
用于 zinc64-sdl

GPL-3.0+

480KB
12K 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 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 trait,因此芯片与其他组件之间的交互仅限于并通过提供给芯片构造函数的共享I/O线路/引脚来处理。这允许芯片的实现相互解耦。

状态

类别 组件 状态
芯片组 6510 CPU 完成
芯片组 内存 完成
芯片组 6526 CIA 完成
芯片组 6581 SID 完成
芯片组 6567 VIC 完成
设备 墨盒 完成
设备 软盘 未开始
设备 数据盒 完成
设备 键盘 完成
设备 游戏手柄 完成
设备 鼠标 未开始
调试器 遥控器 完成
调试器 Radare2 完成
格式 二进制 完成
格式 CRT 完成
格式 D64 未开始
格式 P00 完成
格式 程序 完成
格式 Tap 完成
格式 T64 未开始
客户端 SDL 进行中
客户端 Raspi3 进行中

路线图

  • v0.9 - rpi端口
  • v0.10 - 支持软盘

入门指南

  1. 安装Rust编译器或按照以下步骤操作:https://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++构建工具工作负载。

  2. 安装SDL2开发库

  3. 将所有SDL2库文件从

     SDL2-devel-2.0.x-VC\SDL2-2.0.x\lib\x64\
    

    复制到

     C:\Users\{Your Username}\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib
    
  4. 将SDL2.dll从

     SDL2-devel-2.0.x-VC\SDL2-2.0.x\lib\x64\
    

    复制到zinc64项目目录

调试器

要启动调试器,使用'-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处理器进行了CPU验证

    ./target/release/zinc64 --binary bin/6502_functional_test.bin --offset=1024 --console --loglevel trace

键盘快捷键

快捷键 功能
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为我提供了各种硬件组件的参考

依赖项

~22MB
~442K SLoC