Show HN:Pokémon Emerald 移植到 Raspberry Pi Pico 2
摘要
一位开发者将 Pokémon Emerald 移植到 Raspberry Pi Pico 2 (RP2350) 微控制器上原生运行,通过将 GBA 游戏重新编译为 Cortex-M33,并在第二个核心上重新实现 PPU,实现了 60 fps 的 HDMI 输出。
查看缓存全文
缓存时间: 2026/08/06 23:05
mattdeeds/pokeemerald-rp2350
来源:https://github.com/mattdeeds/pokeemerald-rp2350
pokeemerald-rp2350
在 6 美元的微控制器上原生运行《宝可梦 绿宝石》 — 完整游戏、60 fps、 HDMI 输出、实体按键、断电后依然存在的存档。没有模拟器: pret 反编译项目(https://github.com/pret/pokeemerald)从 ARMv4T 重新编译为 Cortex-M33,Game Boy Advance 的视频硬件在第二个核心上以软件方式重新实现。
目标板卡是 WeAct Studio Core2350B(RP2350B,16 MB QSPI 闪存)。 整个游戏 — 代码、图形、地图、音乐 — 是一个 11.7 MB 的镜像,直接从闪存中原地执行(XIP)。
RP2350B @ 252 MHz ┌──────────────┬──────────────┐ │ 核心 0 │ 核心 1 │ │ 游戏逻辑 │ PPU 渲染 │──▶ 240×160 RGB565 帧缓冲 │ ~0.3 毫秒/帧 │ ~12 毫秒/帧 │ │ └──────────────┴──────────────┘ ▼ ▲ HSTX ──▶ DVI/HDMI 640×480p60 GP0–GP9 按键 (2× 放大,DMA 控制块环)
状态
截至目前测试所及,可以从头玩到尾 — 开机、播放开场动画、开始新游戏、 在野外行走、战斗、存档。除 OBJ 窗口开场动画外,所有场景都保持锁定 60 fps。 它不是成品;请参阅 限制。
| 视频 | ✅ 完整 PPU:模式 0–4、仿射、精灵、窗口、混合。与参考实现逐字节一致。 |
| 帧率 | ✅ 锁定 60 fps,无撕裂,与扫描光束垂直同步锁定 |
| 输入 | ✅ 10 个 GPIO 按键 |
| 存档 | ✅ 持久化到 QSPI 闪存,重启和重新刷写后依然存在 |
| 音频 | ⚠️ 音乐会播放;部分乐器类别静音(见下文) |
| 联机线 / RFU | ❌ 未实现 |
硬件
完整的引脚定义、物料清单和接线说明请参阅 docs/HARDWARE.md。 简而言之:一块 RP2350B 板卡、一个按 Pico DVI Sock 引脚顺序接线的 HSTX 转 HDMI 分线板、十个接地按键,以及可选的一个 PCM5102A I2S DAC 用于发声。
构建
先决条件和完整流程请参阅 docs/BUILD.md。 从仓库根目录开始的简略版本:
sh make tools && make modern # 第一步:反编译工具 + 生成资源 rp2350/gen_sound_assets.sh # 一次性:wav→bin,mid→歌曲 .s rp2350/build_objs.sh # 游戏源码 → rp2350/build/libpokeemerald.a cmake -B rp2350/hw/build -S rp2350/hw -G Ninja # 必须设置 PICO_SDK_PATH ninja -C rp2350/hw/build emerald picotool load -f rp2350/hw/build/emerald.uf2
rp2350/hw/CMakeLists.txt 还构建了独立的 Bring-Up 目标,用于在集成之前
在真硅片上验证每个子系统,并且是调试新板卡的最快方式:
hstx_test(彩条)、psram_test、
i2s_test(440 Hz 正弦波)、display_test、ppu_display_test、emerald_hwtest。
工作原理
完整的工程日志 — 每个阶段、做出继续/停止判断所依据的测量数据、 以及最耗时的 bug — 都在 docs/PORTING.md 中。 简而言之:
它借助了一个 WASM 移植版。 tripplyons/pokeemerald-wasm(https://github.com/tripplyons/pokeemerald-wasm)
已经把所有对真实 GBA 硬件的依赖用 #if WASM 隔离起来。
复用这些接缝作为 #if WASM || RP2350,意味着“去除硬件依赖”的工作已经完成;
本移植只需要添加面向 MCU 的那一半。
GBA 内存映射得以保留。 游戏仍然在原始地址写入 DISPCNT、VRAM、OAM 和
调色板 RAM — 这些现在只是普通的 SRAM。运行态 RAM 约为 RP2350 520 KB 中的
378 KB。ROM 通过 XIP 位于 QSPI 闪存中,游戏的 0x08000000 基地址被重映射到
0x10000000。
PPU 是核心 1 上的一个软件光栅化器。 从 WASM 宿主端的 web/app.js 移植而来,
并与它进行了逐字节验证。第一个可用版本运行速度为 909 毫秒/帧;
每帧调色板 LUT、每扫描线窗口掩码、8 像素瓦片跨度以及增量仿射步进
将其提升到 60 fps — 大约快了 45 倍。随后专门的内部循环将典型场景缩短到约 12 毫秒。
扫描输出完全不需要 CPU。 一个 DMA 控制块环将完整的 525 线帧送入 HSTX 串行器,CPU 从不接触重新装备路径。中断只是通告性的。这就是为什么显示在存档期间 闪存写入导致的多毫秒停顿下依然不受影响 — 为此付出了消除约每 0.8 分钟一次 HDMI 掉信号的代价。
限制
以下是关于哪些功能是桩、缺失或错误的诚实清单:
- 音频不完整。 m4a 引擎已移植,音乐也能播放,但 DPCM(压缩)和反向播放 乐器是静音桩。混音与帧率耦合,因此任何低于 60 fps 的场景都会欠载。 它还没有经过仔细的听感正确性检查。
- 没有联机线或无线。 RFU 和 multiboot 路径都是桩。交换、对战以及 神秘礼物的下载代码路径无法工作。(神秘礼物的运行下载代码路径会将数据 重定位为 Thumb 代码,这按原样无法在 M33 上工作。)
- RTC 是一块死掉的卡带时钟。 真正的绿宝石通过卡带 GPIO 比特碰撞读取 RTC, 而这里不存在该 GPIO。时间读数为零,游戏内的时钟设置界面显示“时钟已停止”。 树果生长和其他时间段相关事件会受影响。
- OBJ 窗口开场动画运行在 20–25 毫秒/帧,低于 60 fps。这是唯一一个没有 快速路径的场景。
- 音频硬件是可选的,但尚未完善。 如果没有接 I2S DAC,游戏会静默且正确地运行。
仓库布局
这是 pokeemerald-wasm 的一个分支,而 pokeemerald-wasm 又是 pret/pokeemerald 的 分支。这里几乎一切都是上游内容;移植只集中在一个目录中。
| 路径 | 内容 |
|---|---|
rp2350/ | 移植部分。 PPU、HSTX 显示驱动、BIOS 调用、m4a 引擎、构建脚本。 |
rp2350/hw/ | Pico SDK 工程:game_main.c、链接脚本、闪存存档、I2S、测试目标。 |
docs/ | 硬件、构建和移植文档。 |
src/、data/、graphics/、sound/ | 上游 pokeemerald 游戏源码和资源。 |
web/、tools/wasm_* | WASM 构建,保留作为 PPU 参考(见下文)。 |
WASM 构建被有意保留。 rp2350/ppu_validate.sh 在浏览器中运行游戏,
从 JavaScript 光栅化器转储 GBA 内存和参考帧,用 rp2350/ppu.c 渲染相同状态,
并对两者进行像素差异比较。这个工具链是 PPU 可以被称作逐字节一致的唯一原因,
并且在每次优化过程中都捕获了真实 bug。上游的 Cloudflare 部署配置已被移除,
但 make wasm 和 make serve-wasm 仍然可用。
许可证
rp2350/ 是原创作品,以 MIT 许可证(rp2350/LICENSE)发布。
仓库其余部分是 pret 反编译项目,本工程不为其添加任何许可证。遵循 pret 惯例, 不需要也不包含任何 ROM — 反编译项目从自身提交的源码构建游戏。宝可梦和宝可梦角色名称 是 Nintendo、Creatures Inc. 和 GAME FREAK Inc. 的商标。 本项目与它们没有任何关联,也未获得它们认可。
致谢
- pret/pokeemerald(https://github.com/pret/pokeemerald) — 本工程所基于的反编译项目。 这是许多人多年的工作;没有它,这一切都不可能。
- tripplyons/pokeemerald-wasm(https://github.com/tripplyons/pokeemerald-wasm) —
WebAssembly 移植版,本移植直接依赖它的
#if WASM接缝和参考光栅化器。 - 原始的 pokeemerald README 保存在 docs/original-pokeemerald-readme.md。
相似文章
GameBoy Emulator on ESP32 + Eink
作者成功在M5 Paper S3(ESP32 S3+电子墨水屏)上实现可玩的Gameboy模拟器,通过高刷新率驱动、优化模拟核心和创新的伪复音声音方案,使经典游戏在电子墨水屏上流畅运行。
我打造了一个袖珍Macintosh
使用运行Pico Micro Mac固件的Raspberry Pi Pico打造了一个袖珍Macintosh,具备VGA输出和USB键盘/鼠标。
CGA上的60fps视频?– GlyphBlaster
GlyphBlaster是一款基于Raspberry Pi Pico的设备,它替换了CGA显卡上的字模ROM,通过将字模ROM读取作为像素可寻址帧缓冲区,在文本模式下实现了60fps的视频播放。
用RP2350监视Z80
一篇博客文章,探讨如何使用带PIO的Raspberry Pi Pico RP2350来监视Z80微处理器的地址和数据总线,包括时序考虑和时钟速度限制。
PS3 模拟现在在 ARM 上运行很快
RPCS3 的 ARM 移植版现在运行速度快了 60%,功耗降低了 25%,这是因为修复了一个忙等待定时器 bug、用 ARM ISB 替换了 x86 pause,并重写了 LLVM 代码生成。这些改进源于由一台廉价 Android 掌上测试设备推动的低层 ARM 优化。