两名开发者从逻辑门开始,设计了一颗五级流水线CPU,再把它部署到FPGA上跑。他们给这颗处理器接上DDR3内存、自制的指令缓存和数据缓存,又装了显示、键盘、定时器等外设,最后把1993年发布的《DOOM》移植了上去。两周前,这台“玩具处理器”第一次把游戏画面吐了出来。作者自己的说法是“crawled”——勉强爬起来,不是流畅运行。
这不是一次追求性能的突破。DOOM能在微控制器、烤面包机上运行早就不是新闻。这次真正的看点是:两人验证了自己从零搭建的CPU、内存系统和工具链,第一次扛住了一款成熟的商业级软件,这比自己写个Pong难得多。
从Pong到DOOM,考验的是系统全不全
在这次移植之前,这颗CPU只跑过作者自己写的小程序:Pong、曼德勃罗集分形。这些程序体积以几十KB计,逻辑简单,几乎碰不到边界情况。
DOOM不一样。它由id Software在1993年发布,基础共享版体积约14MB,涉及文件系统、渲染管线和大量分支跳转。这颗CPU原本可用的FPGA片上BRAM却不到1MB。
| 对比项 | 此前:Pong/曼德勃罗 | 现在:DOOM |
|---|---|---|
| 程序体积 | 几十KB | 约14MB(基础共享版) |
| 逻辑复杂度 | 简单,少分支 | 完整渲染管线、文件系统、大量跳转 |
| 片上BRAM是否够用 | 完全够用 | 不到1MB,远远不够 |
两个开发者把问题拆开做。一人研究乱序执行,想给流水线补上并行度;另一人扎进内存系统,解决“14MB的游戏怎么塞进不到1MB片上内存”这个问题。这不是多接一块内存芯片那么简单。
缺的不是缓存,是一整套内存系统
FPGA自带的BRAM延迟固定为1个周期,读写按字寻址。原来的流水线设计就是照着这个假设搭的。
DDR3完全不是这么回事。延迟可变,单次访问动辄要30到100个周期。如果每条指令都直接找DDR3要数据,CPU基本瘫痪。
| 存储层级 | 访问延迟 | 说明 |
|---|---|---|
| BRAM直连 | 1周期 | 原设计假设,地址位宽固定 |
| 自制缓存命中 | 约2周期 | 单路直接映射,指令/数据缓存各2048行 |
| DDR3直接访问 | 30-100周期 | 需仲裁排队,不能挂在每条指令上 |
团队自己造了两套缓存,单路直接映射,各挂2048行。取指和执行两个流水级可能同一周期抢内存,团队加了一个仲裁器排队处理,优先让数据缓存过队,避免死锁。
DDR3接口本身很难对付,团队借用了Xilinx的MIG(内存接口生成器),还要处理MIG时钟域和主处理器时钟域不同步的问题,靠时钟域交叉和FIFO缓冲接起来。原来那块板子的MIG始终跑不通,团队中途换成了朋友的64位总线板子继续做。
外设也是将就出来的。显示靠自制VGA控制器接HDMI;键盘本该走板子上的USB主机芯片,结果那个USB口不供电,插键盘没反应,最后改成用笔记本通过UART转发按键。
游戏移植借助了开源项目doomgeneric做适配层,省了不少事。真正麻烦的是调试——程序出错时分不清是DOOM代码的问题,还是CPU本身有毛病。
团队把游戏拆成一段段小程序逐步验证,才找出死循环、乱跳转、写回请求被吞、数据缓存覆盖指令数据等一堆错误。其中一些错误可以追溯到他们更早的单周期处理器,只是此前从没被真正踩到过。能暴露出潜伏多年的CPU错误,恰恰说明简单程序测试不够用,系统完整性只能靠足够复杂的软件来验证。
能跑起来,不等于能用
作者自己承认,这套单路直接映射缓存设计低效。缓存行只有4字宽,是为了迁就早期那块128位MIG接口,换板子后就成了历史包袱,没来得及重新优化。文中也没有给出主频、帧率这类可验证的性能数据,“crawled”这个词已经说明了跑起来的状态。
对CPU和FPGA学习者来说,这条路线值得照着走一遍:流水线、自制缓存、内存仲裁、时钟域交叉、外设集成,每一步都比单纯读教材有用。
对普通玩家来说,不用惦记这套东西能不能玩——键盘靠笔记本转发,USB供电都没解决,这是一个验证平台,不是一台游戏机。
接下来值得盯的,是团队提到的乱序执行能不能真正合入流水线,以及这套单路缓存会不会被重新设计成组相联结构,提高命中率。
