FPGA上的CHIP-8游戏机模拟器
这是一个在FPGA芯片(具体为TinyFPGA BX)上运行的CHIP-8游戏机模拟器。


实现注释与思考
编写单元测试(见cpu,gpu,bcd)对我的帮助极大,使我能够对大部分指令进行仿真测试。我还编写了一些简单的汇编程序,并使用Tortilla-8项目将其编译为CHIP-8格式。
为了使屏幕和键盘功能正常工作,还需要一些手动测试。我为芯片编写了简单程序运行,并修正了对CHIP-8行为的一些误解(例如,内存读写涉及多个寄存器,以及图形绘制可以环绕边界)。在这个过程中,我也修正了我的Rust语言编写的CHIP-8模拟器,有趣的是,尽管之前的理解有误,它仍能运行许多游戏。
CHIP-8规范包括16个一字节寄存器(V0到VF)和20个两字节栈空间。最初我想让它们成为独立数组,但很难协调访问以实现为RAM合成,因此我决定将它们映射到内存中(参见[cpu.v]顶部描述的内存映射)。
屏幕内容也被映射到了系统内存中,这意味着CPU和屏幕模块需要竞争内存访问。我决定,在读取屏幕内容时暂停CPU(即不执行下一条指令)。
处理屏幕显示是令人烦恼的,我按行存储帧数据(每个字节代表8像素的水平条),而我使用的屏幕期待的是8像素的垂直条,因此需要额外逻辑来旋转这些数据。
BCD指令(将字节转换为三个十进制数字)在电路中实现较为困难,因为它涉及到除以10的操作。我采用了Hacker's Delight一书中描述的方法,该方法涉及位移操作和手动调整。详细可见[bcd.v]。
向内存加载游戏很有趣。IceStorm工具提供了icebram
实用程序,可以在已准备好的比特流中替换内存内容,这样就不必每次想玩不同的游戏时都重复整个漫长的(约30秒)构建过程。
TinyFPGA BX的默认时钟速度为16MHz,这对CHIP-8游戏来说太快了。所以我将整体速度限制为每秒500条指令。
我还添加了一个“调试模式”,同时按下1和F键激活。这时,我会渲染寄存器、堆栈和部分程序内存而不是屏幕缓冲区,观看其运作十分有趣。
随机数生成使用了Xorshift算法,每一周期计算一次新值,若检测到按键则迭代计算两次,确保结果受用户输入影响。
最后,由于我是Verilog的新手,项目在某些方面显得笨拙:
- 单条指令大约需20个周期。
- 内存访问遵循“读-确认”循环,其间有一个不必要的单周期暂停。
- iCE40内存是双端口的,理论上可同时读写,但我并未利用这一点。
- 整个项目占用1600多个LUT,我相信可以优化至少于1000个LUT,以便能适应更小的iCEstick。
硬件配置
我使用了以下硬件:
- TinyFPGA BX,搭载Lattice iCE40-LP8K芯片
- SparkFun的16按钮键盘
- WaveShare的128x64像素单色OLED屏幕
源码概述
Verilog模块:
chip8.v
—— 专为TinyFPGA BX设计的顶层模块cpu.v
—— 包含内存控制器的CPUmem.v
—— 系统内存gpu.v
—— 图形精灵绘制bcd.v
—— BCD转换电路rng.v
—— 虚拟随机数生成器screen_bridge.v
—— OLED屏幕与CPU之间的桥接,以访问帧缓冲区
测试文件:
*_tb.v
—— 模块的测试平台(见下方如何运行)asm/
—— 各种汇编程序
"愿我的文字能带给您一丝美好"
分享海报

FPGA上的CHIP-8游戏机模拟器
这是一个在FPGA芯片(具体为TinyFPGABX)上运行的CHIP-8游戏机模拟器。…
FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训
FPGA在线学习平台
评论
A 为本文作者,G 为游客总数:0