demake:一份源码工程编译出任意复古主机的 ROM

查看原文 HN 讨论

文章摘要

demake 是英国伦敦的技术主管 George Stephenson(HN 用户名 gste)的业余项目,目标听上去有点狂:写一份源码工程,编译出几乎所有主流 8/16 位时代游戏机和掌机能真正跑起来的 ROM。项目遵循 MIT 协议开源,同时提供网页应用、命令行工具和 NPM 包,网页版完全在浏览器本地运行,不上传任何素材。

按作者在 Show HN 里的自述,这个项目最初并不是奔着”跨主机游戏引擎”去的,而是为解决一个很具体的图形问题:生成式 AI 已经能画出复古风格的像素精灵图,但它没法遵守真实硬件在像素与颜色上的硬约束——主调色板、每格图块的颜色数上限、属性网格、图块预算等等。demake 要补的就是这块缺口,让 AI Agent 能端到端地做一款复古游戏:生成美术素材、把它转成符合硬件规格的数据和显示代码、再构建出一个能启动的 ROM。做着做着作者发现,既然规格是数据驱动的,那就可以”扇出”到任意主机和掌机的规格上去。

项目按输入类型分成四个”demaker”:art 吃任意图片,产出合规美术、调色板、图块映射、汇编/C/二进制数据乃至可启动 ROM;game 吃一份 Demotic 脚本加美术,产出”一款游戏、每台主机各一份”;music 吃 MIDI 轨道,产出芯片音乐;sound 吃 WAV 音效,产出经过排布和优先级安排的芯片音效。四者共用同一套引擎、同一份确定性保证,以及同一种验证方式——真实 ROM 在真实模拟器里启动,与工具声称的输出逐像素、逐 tick、逐寄存器写入地比对。目前 prepinspect 覆盖从 Game Boy 到任天堂 DS 的 21 台机器,--format rom 的逐像素模拟器验证覆盖十余台,其中 Virtual Boy 是双眼都验证(它的显示是两组 LED 阵列,视频处理器把每一帧按场景声明的景深画两遍)。

真正的核心创新是作者自创的声明式语言 Demotic.dmt 文件)。名字取自罗塞塔石碑上的”世俗体”——同一段文本以圣书体、希腊文和世俗体三种书写并存,Demotic 也要把同一款游戏带到每台主机上,而且是用人(或者模型)真正写得出来的语言层级。它的中心原则是一条铁律:Demotic 描述游戏,Demakefile 描述构建.dmt 文件里不出现任何主机名、任何调色板、任何像素;游戏中的距离和速度全部用相对单位表达(vw、vh、vmin、vmax),这正是它能跨屏幕尺寸移植的原因。作者在 CI 里把这条原则做成了可验证的属性:删掉 Demakefile 游戏必须玩法完全一致,只是产物变了;Demakefile 里的任何东西都不能改变玩法。

实现层面有三个关键决策。其一是”约束地模拟,自由地渲染”:游戏状态一律以 16.16 定点数、按固定逻辑 tick 推进,浏览器预览和真实硬件上完全一致,只有渲染是自由的(SVG 美术、任意分辨率、tick 之间插值)。因此预览不是第二套会漂移的实现,预览本身就是规格。代价是刻意的:模拟里没有浮点数、没有墙上时钟、没有宿主随机数(random 走语言自己的带种子生成器),全局只有一条取整规则——向下取整,也就是 6502 或 Z80 上算术右移的行为。其二是先把语言前端编译成一个中间的 Program(场景、对象、控制、规则的解析表,常量全部折叠成定点数),再由后端把 Program 编译成目标机器的原生代码。作者坦承这推翻了文档里更早的一个决定——原本打算让 Program 本身就是交付物,每台主机配一个小型固定引擎去解释它,理由是 N+M 的工作量优于 N×M。这个账算工作量是对的,算机器是错的:解释器每条规则、每个对象、每个 tick 都要取规则记录、按触发器分发、用栈式求值器走一遍表达式树、再通过指针寻址每个属性,光一个 Pong 就要吃掉大约三个 Game Boy 帧。其三是 .test.dmt 测试套件,能一次性断言游戏在每台主机上都还玩得对。

作者刻意把 Demotic 和 Demakefile 都设计得又小又扁平、按行组织,正是为了让模型能可靠地写和改。目前 demake build pong.dmt -o pong.gb 能把游戏编译成 32KiB 的 Game Boy 卡带机器码,顺手把它引用的美术也 demake 掉;换成 -c nes-c sms-c gg-c md 就编译到 6502、Z80 和 68000。构建甚至不需要你装汇编器,因为汇编器是项目自带的——这也是网页版能在页面里直接编译并玩到与命令行完全相同字节的原因。Demotic 明确划定了范围:11 台带多色硬件精灵和可比按键集的图块机器。被刻意排除的机器各有各的理由——SG-1000/TMS9918 每扫描线只有 4 个精灵且每精灵单色,没有滚动寄存器所以摄像机编译不出来,1KB 工作 RAM 也顶不住游戏需要的 700–950 字节;Supervision、Game.com、Lynx 这类纯帧缓冲掌机根本没有硬件精灵;Neo Geo 没有图块背景层,它的背景就是精灵;Atari 2600、Virtual Boy、Intellivision 则各自以不同方式打破模型。作者对此的表述很诚实:所谓”每一台主机”实际形状是若干 profile,而不是一个最小公分母。

HN 评论精华

这条 Show HN 拿到 40 分,讨论量不大但含金量高,作者本人在串里逐条回应。