Appearance
内存模型概念 (Memory Model Concepts)
256MB 内存布局总览
pokeemerald-wasm 在 WebAssembly 中模拟了 GBA 的完整 256MB 地址空间。这块内存通过 WebAssembly.Memory 创建,初始大小恰好为 256MB(268,435,456 字节)。
线性内存模型
WebAssembly 采用平坦线性内存模型——内存是一块连续的字节数组,通过偏移量(offset)访问。没有虚拟内存、没有分页、没有内存保护。这与 GBA 的硬件设计高度契合:
在 C 源码中,GBA 硬件通过内存映射 I/O (MMIO) 访问——读写特定地址即控制硬件。编译为 WebAssembly 后,这些地址访问变成了对线性内存对应偏移量的读写。app.js 中的 JavaScript 代码则监控这些内存区域的变化,模拟硬件行为。
为什么是 256MB?
GBA 的 32 位地址总线理论上可寻址 4GB,但实际硬件只使用了低 256MB。initial-memory=268435456(即 0x10000000 = 256 * 1024 * 1024)这个值确保 WASM 内存覆盖所有 GBA 地址空间:
| 地址范围 | 用途 | 实际大小 |
|---|---|---|
0x00000000 | BIOS ROM | 16KB |
0x02000000 | EWRAM(外部工作 RAM) | 256KB |
0x03000000 | IWRAM(内部工作 RAM) | 32KB |
0x04000000 | I/O 寄存器 | ~1KB |
0x05000000 | 调色板 RAM | 1KB |
0x06000000 | VRAM(视频 RAM) | 96KB |
0x07000000 | OAM(精灵属性内存) | 1KB |
0x08000000 | 游戏 ROM | 最大 32MB |
0x0E000000 | Flash 存档 | 128KB |
SharedArrayBuffer 与内存共享
使用 SharedArrayBuffer 而非普通 ArrayBuffer 的原因:
- 线程共享:
SharedArrayBuffer可以在主线程和 Web Worker 之间共享,为将来将 WASM 执行移至 Worker 留下空间。 - 零拷贝访问:WASM 模块和 JavaScript 通过同一个底层缓冲区操作,无需数据拷贝。
- 实时同步:JavaScript 对内存视图的修改立即可被 WASM 代码感知,反之亦然。
注意:使用
SharedArrayBuffer要求服务器设置Cross-Origin-Opener-Policy: same-origin和Cross-Origin-Embedder-Policy: require-corpHTTP 头。
地址映射策略
pokeemerald-wasm 采用直接映射策略——GBA 地址就是 WASM 线性内存的偏移量:
javascript
// GBA 地址 0x06000000 (VRAM) 对应:
memoryBuffer[0x06000000] // Uint8Array 中的字节偏移
// 等价于 WASM 内存中的 i32.load offset=0x06000000这种直接映射意味着:
- C 源码中的指针地址无需转换即可在 WASM 中使用
- JavaScript 通过类型化数组视图直接操作对应地址
- 硬件模拟代码只需关注特定地址范围的变化
关键地址的 JavaScript 监控
app.js 通过定期检查(polling)或写入拦截来监控关键地址:
| 监控区域 | JavaScript 行为 |
|---|---|
0x04000000 (DISPCNT 等) | 解析显示控制寄存器,更新渲染模式 |
0x04000130 (REG_KEYINPUT) | 写入按键状态供游戏读取 |
0x05000000 (Palette) | 读取调色板颜色用于渲染 |
0x06000000 (VRAM) | 读取图块数据渲染背景和精灵 |
0x07000000 (OAM) | 读取精灵位置、大小等属性 |
0x0E000000 (Flash) | 监控存档写入,序列化到 localStorage |
内存初始化流程
初始化时,JavaScript 先创建 256MB 的 SharedArrayBuffer,以此构造 WebAssembly.Memory 对象。随后将 GBA ROM 数据复制到 0x08000000 起始位置。WASM 模块实例化时接收这块共享内存,C 代码中的指针操作直接作用于此。
相关概念
- WebAssembly -- WebAssembly 基础与线性内存模型
- VRAM -- 视频内存的详细结构与渲染作用
- 输入系统 -- I/O 寄存器中的按键输入部分
- 存档系统 -- Flash 存档区域的读写机制
- 渲染管线 -- VRAM 数据如何变为屏幕像素