#chip8 #debugging #interpreter #emulation #dissassembler

app c8

🎮 CHIP-8 / S-CHIP / XO-CHIP 带有虚拟机、调试器和反汇编器的 tui 工具包

2 个稳定版本

1.0.1 2024 年 3 月 26 日
1.0.0 2024 年 3 月 24 日

#31模拟器

Download history 27/week @ 2024-04-01 5/week @ 2024-04-08 1/week @ 2024-05-20 5/week @ 2024-06-10

每月 55 次下载

MIT 许可证

365KB
7.5K SLoC

C8

CHIP-8 / S-CHIP / XO-CHIP 带有虚拟机、调试器和反汇编器的 tui 工具包

关于功能安装使用动机


C8 Screenshot


目录

关于

C8 是一个终端用户界面工具包,用于运行、调试和反汇编 CHIP-8S-CHIPXO-CHIP 游戏。其核心功能包括:

  • 运行 rom: c8 run [ROM_PATH]
    • 添加 --debug 启用调试模式
    • 添加 --kind 后跟 classicchip8schipxochip 以在自动选择失败时强制使用其他 CHIP-8 变体
    • 添加 --hz 后跟所需的每秒目标指令数(如果需要)
  • 使用 c8 dasm [ROM_PATH] > [OUTPUT_FILE_PATH] 将 rom 反汇编到文件
  • 使用 c8 check [ROM_PATH] 检查 rom 是否存在潜在问题*

功能概览

功能 C8
全功能 Chip-8 + Classic、S-CHIP 和 XO-Chip 支持
全功能声音支持
全功能 4 位颜色支持
debug 撤销、重做和执行步骤
debug 虚拟机状态检查
debug 寄存器和地址观察点
debug 指令断点
debug 程序执行历史
debug 修改键盘状态
debug 导出当前程序内存状态
静态跟踪反汇编器
可配置的执行速度
兼容性配置文件
预定义和自定义调色板 🚧
可单独配置的怪癖 🚧
标记为 debug 的功能仅在调试模式下可用

安装

C8 主要在 Windows 上进行测试,但应能在 Mac 和 Linux 上运行。如果在 Linux 上,请在继续之前查看以下内容以获取所需的系统包。

目前 C8 只能从 cargo 安装或从源代码构建。

使用 Cargo 安装

C8 已发布在 crates.io,可以使用 cargo 安装。需要 Rust 1.70.0 或更高版本。

cargo install c8

从源代码构建

可以使用 cargo 从源代码构建 C8。需要 Rust 1.70.0 或更高版本。

git clone https://github.com/tochiu/c8.git
cd c8
cargo install --path ./

为确保已安装 C8,请从存储库目录运行经典 IBM Logo ROM。

c8 run roms/c8/ibm_logo.ch8

安装注意事项

在 Linux 上,由于终端通常不支持按键事件,因此需要 X11 开发库来查询键盘状态。此外,系统上还需要高级 Linux 声音架构(ALSA)开发库。

在 Ubuntu/Debian 上

sudo apt install libx11-dev
sudo apt install librust-alsa-sys-dev

在 Fedora/RHEL/CentOS 上

sudo dnf install xorg-x11-server-devel
sudo dnf install alsa-lib-devel

在 MacOS 的新版本中,您可能会遇到只有元键(如 shift、退格等)的问题。这是由于权限问题。为了解决这个问题

  • 打开 MacOS 系统偏好设置
  • 转到 安全 -> 隐私
  • 向下滚动到可访问性并解锁它
  • 将您的终端添加到列表中

使用

运行

要运行 CHIP-8 程序,请使用 c8 run 命令,后跟程序路径。

  • 如果需要程序以指定的频率运行,请添加 --hz 标志,后跟每秒目标指令数(IPS)值。
  • 要指定 CHIP-8 变体,请添加 --kind 标志,后跟 chip8classicschipxochip 之一。
    • 如果没有指定 --kind,c8 将对 CHIP-8 变体进行最佳猜测。
  • 要将程序加载到调试器中,请添加 --debug 标志。

[!重要] classic 变体不是完整的 COSMAC VIP 模拟器,而只是在 VIP 上 CHIP-8 的怪癖设置。

例如

c8 run roms/xo/super_neatboy.ch8 --hz 50000 --kind xochip

将在 XO-CHIP 变体上以 50000 IPS 运行 Super Neatboy rom。在上面的例子中,由于 C8 将自动选择 XO-CHIP 变体,因此不需要 --kind 标志。

反汇编

C8反汇编器是一个静态追踪反汇编器。它不会执行程序来反汇编它,而是从起始地址开始追踪程序,经过所有可能的分支,以确定哪些内存区域是代码,哪些是数据。然后,它将输出一个程序内存视图,其中包含反汇编指令和原始内存数据。因为这是对程序进行的静态分析,自修改代码的反汇编效果可能不好。反汇编器并不总是确定给定的地址是否为指令(见:停止问题)。每个地址都附有一个标签,指示该地址为指令的置信度。标签如下

符号 标签 描述
' ' NOT 该地址不是指令
'?' PARSABLE 该地址可以解析为有效的指令
'*' REACHABLE 该地址可以解析为有效的指令,并且理论上可以由程序执行
'O' VALID 该地址可以解析为有效的指令,并且理论上可以由程序执行,并且可以至少属于一个静态执行路径
'X' PROVEN 该地址是至少属于一个静态执行路径的指令

A static execution path 是从起始指令地址(0x200)开始的指令序列,可以在不依赖于虚拟机状态的情况下由程序执行。

例如,从起始地址跳转到内存中特定位置的指令将创建一个新的静态(X 标签)执行路径,从该位置开始。反汇编器将遵循所有可能的静态执行路径以确定每个地址的置信度。

但如果指令跳转到由寄存器中的值等确定的内存位置,反汇编器将创建一个新的可达(* 标签)执行路径,从所有可能的跳转位置开始。这是因为反汇编器无法确定反汇编时的寄存器值。从那里,反汇编器将遵循所有可能的执行路径以确定每个地址的置信度。如果某个地址至少属于一个静态执行路径,它将被提升为有效(O 标签)。

要反汇编CHIP-8程序,请使用c8 dasm命令,后跟程序的路径。这将打印反汇编程序到标准输出。添加--kind标志以指定CHIP-8变体。例如

c8 dasm roms/ch8/ibm_logo.ch8

将反汇编ibm_logo rom并输出以下内容

0x200 cls                    # X 00E0     clear
0x202 ld   i 0x22A           # X A22A     i = 0x22A
0x204 ld   v0 12             # X 600C     v0 = 12
0x206 ld   v1 8              # X 6108     v1 = 8
0x208 drw  v0 v1 15          # X D01F     draw 8x15 @ v0,v1
0x20A add  v0 9              # X 7009     v0 += 9
0x20C ld   i 0x239           # X A239     i = 0x239
0x20E drw  v0 v1 15          # X D01F     draw 8x15 @ v0,v1
0x210 ld   i 0x248           # X A248     i = 0x248
0x212 add  v0 8              # X 7008     v0 += 8
0x214 drw  v0 v1 15          # X D01F     draw 8x15 @ v0,v1
0x216 add  v0 4              # X 7004     v0 += 4
0x218 ld   i 0x257           # X A257     i = 0x257
0x21A drw  v0 v1 15          # X D01F     draw 8x15 @ v0,v1
0x21C add  v0 8              # X 7008     v0 += 8
0x21E ld   i 0x266           # X A266     i = 0x266
0x220 drw  v0 v1 15          # X D01F     draw 8x15 @ v0,v1
0x222 add  v0 8              # X 7008     v0 += 8
0x224 ld   i 0x275           # X A275     i = 0x275
0x226 drw  v0 v1 15          # X D01F     draw 8x15 @ v0,v1
0x228 jp   0x228             # X 1228
0x22A                        #   FF       2X GRAPHIC @@@@@@@@@@@@@@@@
0x22B                        #   00       2X GRAPHIC ................
0x22C                        #   FF       2X GRAPHIC @@@@@@@@@@@@@@@@
0x22D                        #   00       2X GRAPHIC ................
0x22E                        # ? 3C00     2X GRAPHIC ....@@@@@@@@....
0x22F                        #   00       2X GRAPHIC ................
0x230                        # ? 3C00     2X GRAPHIC ....@@@@@@@@....
0x231                        #   00       2X GRAPHIC ................
0x232                        # ? 3C00     2X GRAPHIC ....@@@@@@@@....
0x233                        #   00       2X GRAPHIC ................
0x234                        # ? 3C00     2X GRAPHIC ....@@@@@@@@....
0x235                        #   00       2X GRAPHIC ................
0x236                        #   FF       2X GRAPHIC @@@@@@@@@@@@@@@@
0x237                        #   00       2X GRAPHIC ................
0x238                        #   FF       2X GRAPHIC @@@@@@@@@@@@@@@@
0x239                        #   FF       2X GRAPHIC @@@@@@@@@@@@@@@@
0x23A                        #   00       2X GRAPHIC ................
0x23B                        #   FF       2X GRAPHIC @@@@@@@@@@@@@@@@
0x23C                        #   00       2X GRAPHIC ................
0x23D                        # ? 3800     2X GRAPHIC ....@@@@@@......
0x23E                        #   00       2X GRAPHIC ................
0x23F                        # ? 3F00     2X GRAPHIC ....@@@@@@@@@@@@
0x240                        #   00       2X GRAPHIC ................
0x241                        # ? 3F00     2X GRAPHIC ....@@@@@@@@@@@@
0x242                        #   00       2X GRAPHIC ................
0x243                        # ? 3800     2X GRAPHIC ....@@@@@@......
0x244                        #   00       2X GRAPHIC ................
0x245                        #   FF       2X GRAPHIC @@@@@@@@@@@@@@@@
0x246                        #   00       2X GRAPHIC ................
0x247                        #   FF       2X GRAPHIC @@@@@@@@@@@@@@@@
0x248                        # ? 8000     2X GRAPHIC @@..............
0x249                        # ? 00E0     2X GRAPHIC ................
0x24A                        #   E0       2X GRAPHIC @@@@@@..........
0x24B                        # ? 00E0     2X GRAPHIC ................
0x24C                        #   E0       2X GRAPHIC @@@@@@..........
0x24D                        #   00       2X GRAPHIC ................
0x24E                        # ? 8000     2X GRAPHIC @@..............
0x24F                        #   00       2X GRAPHIC ................
0x250                        # ? 8000     2X GRAPHIC @@..............
0x251                        # ? 00E0     2X GRAPHIC ................
0x252                        #   E0       2X GRAPHIC @@@@@@..........
0x253                        # ? 00E0     2X GRAPHIC ................
0x254                        #   E0       2X GRAPHIC @@@@@@..........
0x255                        #   00       2X GRAPHIC ................
0x256                        #   80       2X GRAPHIC @@..............
0x257                        #   F8       2X GRAPHIC @@@@@@@@@@......
0x258                        #   00       2X GRAPHIC ................
0x259                        #   FC       2X GRAPHIC @@@@@@@@@@@@....
0x25A                        #   00       2X GRAPHIC ................
0x25B                        # ? 3E00     2X GRAPHIC ....@@@@@@@@@@..
0x25C                        #   00       2X GRAPHIC ................
0x25D                        # ? 3F00     2X GRAPHIC ....@@@@@@@@@@@@
0x25E                        #   00       2X GRAPHIC ................
0x25F                        # ? 3B00     2X GRAPHIC ....@@@@@@..@@@@
0x260                        #   00       2X GRAPHIC ................
0x261                        # ? 3900     2X GRAPHIC ....@@@@@@....@@
0x262                        #   00       2X GRAPHIC ................
0x263                        #   F8       2X GRAPHIC @@@@@@@@@@......
0x264                        #   00       2X GRAPHIC ................
0x265                        #   F8       2X GRAPHIC @@@@@@@@@@......
0x266                        #   03       2X GRAPHIC ............@@@@
0x267                        #   00       2X GRAPHIC ................
0x268                        #   07       2X GRAPHIC ..........@@@@@@
0x269                        #   00       2X GRAPHIC ................
0x26A                        #   0F       2X GRAPHIC ........@@@@@@@@
0x26B                        #   00       2X GRAPHIC ................
0x26C                        # ? BF00     2X GRAPHIC @@..@@@@@@@@@@@@
0x26D                        #   00       2X GRAPHIC ................
0x26E                        #   FB       2X GRAPHIC @@@@@@@@@@..@@@@
0x26F                        #   00       2X GRAPHIC ................
0x270                        #   F3       2X GRAPHIC @@@@@@@@....@@@@
0x271                        #   00       2X GRAPHIC ................
0x272                        #   E3       2X GRAPHIC @@@@@@......@@@@
0x273                        #   00       2X GRAPHIC ................
0x274                        # ? 43E0     2X GRAPHIC ..@@........@@@@
0x275                        #   E0       2X GRAPHIC @@@@@@..........
0x276                        # ? 00E0     2X GRAPHIC ................
0x277                        #   E0       2X GRAPHIC @@@@@@..........
0x278                        #   00       2X GRAPHIC ................
0x279                        # ? 8000     2X GRAPHIC @@..............
0x27A                        #   00       2X GRAPHIC ................
0x27B                        # ? 8000     2X GRAPHIC @@..............
0x27C                        #   00       2X GRAPHIC ................
0x27D                        # ? 8000     2X GRAPHIC @@..............
0x27E                        #   00       2X GRAPHIC ................
0x27F                        # ? 8000     2X GRAPHIC @@..............
0x280                        # ? 00E0     2X GRAPHIC ................
0x281                        #   E0       2X GRAPHIC @@@@@@..........
0x282                        # ? 00E0     2X GRAPHIC ................
0x283                        #   E0       2X GRAPHIC @@@@@@..........

如果需要,每个相关的地址将打印出相应的指令。

#符号之后是该地址的标签。因为ibm_logo是一个简单的程序,每个地址要么被标记为已证明的指令(X 标签),要么是数据,偶尔会有? 标签,如果它意外地可以解析为指令。

标签之后是该地址的十六进制值

  • 如果地址是指令,这将与重叠地址的合并一样长
  • 如果地址是数据,这是一个字节

最后是指令或数据的描述

  • 如果地址是指令,则打印指令的描述
  • 如果地址是数据,则打印字节数据的可视表示

在这种情况下,数据区域的视觉表示展示了保存在rom中的IBM图形。

[注意] 这个反汇编器还可以作为内存查看器。调试器中的内存面板只是程序内存的最新反汇编。

c8 check 是在反汇编器之上构建的一个工具,用于检查 ROM 中的不良执行分支。它通过在程序上运行反汇编器并记录可能执行无效指令的已验证(X 标签)或有效(O 标签)指令的区域来完成此操作。

调试

启动调试器

要调试 CHIP-8 程序,运行

c8 run [PATH_TO_PROGRAM] --debug

这将启动调试器,程序在执行第一条指令之前以暂停状态加载。使用 help 命令查看命令列表。在任何时候,按 Ctrl+C 退出。

导航调试器

下面是调试器第一次启动时的样子

C8 Debugger Screenshot

[提示] 确保终端窗口尽可能大,以确保每个面板都可见。

一眼就能看到

  • 带有输出的命令行界面
    • 要扩展输出面板,请使用 output 命令
  • 程序显示
    • 要切换程序显示,请使用 show displayhide display 命令
  • 程序键盘状态、寄存器状态、计时器状态和堆栈
  • 程序内存布局
    • 要扩展内存面板,请使用 memory 命令
    • 要切换内存布局的详细视图,请使用 show memory -vhide memory -v 命令
    • 要导航到特定内存地址,请使用 goto 命令后跟 pci 或特定地址
    • 要跟踪内存中的指针,请使用 follow 命令后跟一个指针(例如 pci
    • 要取消跟踪当前跟踪的指针,请使用 unfollow 命令
    • 要将整个内存视图导出到文件,请使用 dump memory 命令后跟文件路径
  • 程序历史记录
    • 要关注历史面板,请使用 history 命令

[提示] 当关注一个面板(例如内存)时,您可以使用 HomeEnd 键跳转到开始或结束。使用 Esc 键返回到命令行界面。

在 SCHIP 和 XOCHIP 程序上,高分辨率图形模式会更改 UI 布局,如下所示

C8 Debugger Screenshot (Hi-Res Display)

控制程序执行

运行程序

使用 continue 命令启动您程序的执行

(c8db) continue

这将最小化调试器并运行程序,直到触发调试事件或执行暂停。按 Esc 暂停执行并返回到调试器。

[重要] 调试事件是中断程序执行并进入调试器窗口的触发器。C8DB 中触发调试事件的功能是监视点和断点。

  • 断点设置为在指定地址的指令执行之前触发
  • 监视点设置为在指定寄存器或地址修改后触发

逐条执行程序

使用 step 执行下一条指令。后面跟一个整数 n 以执行下 n 条指令。如果触发调试事件,则将中断。例如

(c8db) step 50

将执行下 50 条指令。

![注意] 如果您使用 stepcontinue 与过去程序状态(可以使用 undo 获取)一起,所有未来的程序状态将被清除,执行将前进。如果您想重新播放这些未来状态,请使用 redo

![提示] 如果您因为正在轮询按键事件而卡在指令上,请使用 key 命令来模拟按键事件。输入 key --help 获取更多信息。

通过执行历史记录进行搜索

使用 undoredo 来浏览程序执行历史。后面跟一个整数 n,以回放或快进到最后 n 个程序状态。

或者,使用 history 命令将焦点集中到程序历史面板。使用 W/S 或 上/下 键来浏览程序执行。这只是在 undoredo 命令之上的图形层。

redo 是一个特别特殊的命令。技术上,它并不简单地执行下一个指令,因为某些指令的执行与程序状态的非确定性相关,例如用户输入或 RNG。如果需要,某些属性会在执行指令之间存储,以便正确回放。这就是 redo 所利用的。

如果您处于特定程序状态,并希望从该点执行程序而不是回放,请使用 stepcontinue

设置执行速度

使用 hertz 后跟 n,其中 n 是每秒目标指令数,以设置程序执行速度。例如

(c8db) hertz 60

将以每秒 60 指令的速度执行程序。

![重要] C8 以固定的帧率 60Hz 运行。 如果您的目标执行速度以每帧周期数表示,请将其乘以 60 以获得等效的每秒指令数。

断点和观察点

有时在满足特定条件时暂停执行是有用的。这是断点和监视点的用武之地。一个 断点 设置在指定地址的指令执行之前触发。一个 监视点 设置在指定的寄存器或地址被修改之后触发。

设置断点

使用 break 后跟一个地址来设置断点。例如

(c8db) break 0x200

将在地址 0x200 设置断点。一旦程序到达此地址,执行将暂停并进入调试器。要列出所有断点,请输入 info break。要删除断点,请使用 clear 命令。在这个例子中

(c8db) clear break 0x200

将删除地址 0x200 的断点。要清除所有断点,请输入 clear all break

设置监视点

使用 watch 后跟一个寄存器或地址来设置监视点。例如

(c8db) watch i

将在寄存器 i 上设置断点。一旦修改该寄存器,执行将暂停并进入调试器。如果我们在地址上设置断点,则在写入该地址时执行将暂停。要列出所有断点,请输入 info watch。要删除断点,请使用 clear 命令。在这个例子中

(c8db) clear watch i

将删除寄存器 i 上的断点。要清除所有断点,请输入 clear all watch

动机

这是我第一个 完成的 Rust 项目(哈哈)。我的一个朋友给我发了一篇关于如何用 CHIP-8 编写模拟器的文章。这是一篇非常有趣的阅读,也是学习 Rust 的好借口!在我完成模拟器后,我觉得我可以更进一步。所以,我们就在这里了。如果你在考虑编写自己的 CHIP-8 模拟器,你应该试试!它是仿真开发的一个很好的起点,并且在此基础上构建其他 CHIP-8 变种是编写可扩展软件的极好练习。

依赖项

~15–49MB
~581K SLoC