romdevtools 0.56.1 → 0.71.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +338 -0
- package/README.md +9 -7
- package/examples/dreamcast/hello/main.c +24 -0
- package/examples/dreamcast/platformer/main.c +31 -0
- package/examples/dreamcast/puzzle/main.c +44 -0
- package/examples/dreamcast/racing/main.c +39 -0
- package/examples/dreamcast/shmup/main.c +50 -0
- package/examples/dreamcast/sports/main.c +39 -0
- package/package.json +5 -3
- package/src/analysis/analyze.js +60 -5
- package/src/analysis/decompile.js +3 -0
- package/src/analysis/rizin.js +3 -1
- package/src/cores/capabilities.js +43 -7
- package/src/cores/registry.js +13 -8
- package/src/host/LibretroGL.js +26 -23
- package/src/host/LibretroHost.js +302 -24
- package/src/host/callbacks.js +72 -1
- package/src/host/coreLoader.js +17 -4
- package/src/host/cpu-state.js +32 -0
- package/src/host/dc-aica-state.js +67 -0
- package/src/mcp/tools/audio.js +1 -1
- package/src/mcp/tools/disasm.js +1 -1
- package/src/mcp/tools/index.js +1 -1
- package/src/mcp/tools/platform-docs.js +1 -1
- package/src/mcp/tools/platform-tools.js +9 -1
- package/src/mcp/tools/project.js +16 -0
- package/src/mcp/tools/toolchain.js +115 -10
- package/src/platforms/dreamcast/MENTAL_MODEL.md +87 -0
- package/src/platforms/dreamcast/TROUBLESHOOTING.md +55 -0
- package/src/platforms/dreamcast/UPSTREAM_SOURCES.md +57 -0
- package/src/platforms/n64/MENTAL_MODEL.md +84 -0
- package/src/platforms/n64/TROUBLESHOOTING.md +60 -0
- package/src/platforms/n64/UPSTREAM_SOURCES.md +52 -0
- package/src/platforms/n64/lib/c/n64.c +181 -80
- package/src/platforms/ps1/MENTAL_MODEL.md +85 -0
- package/src/platforms/ps1/TROUBLESHOOTING.md +55 -0
- package/src/platforms/ps1/UPSTREAM_SOURCES.md +54 -0
- package/src/platforms/snes/TROUBLESHOOTING.md +10 -0
- package/src/toolchains/asar/asar.js +84 -14
- package/src/toolchains/index.js +30 -0
- package/src/toolchains/mips-c/mips-c.js +35 -1
- package/src/toolchains/sh-c/lib/dc-crt0.s +23 -0
- package/src/toolchains/sh-c/lib/dc.h +152 -0
- package/src/toolchains/sh-c/lib/dc.ld +11 -0
- package/src/toolchains/sh-c/lib/libc.a +0 -0
- package/src/toolchains/sh-c/lib/libgcc.a +0 -0
- package/src/toolchains/sh-c/lib/libm.a +0 -0
- package/src/toolchains/sh-c/sh-c.js +104 -0
- package/src/toolchains/sh-elf-gcc/gcc.js +122 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,344 @@ All notable changes to `romdevtools`. Dates are release dates.
|
|
|
4
4
|
(Published as `romdev-mcp` through 0.11.0; renamed to `romdevtools` in 0.13.0 —
|
|
5
5
|
the `romdev-mcp` bin is kept as an alias.)
|
|
6
6
|
|
|
7
|
+
## 0.71.0 — 2026-06-28
|
|
8
|
+
|
|
9
|
+
### N64 / PS1 / Dreamcast reach full parity: cpuState + audioDebug + GPU-rendering helper libs + 5 examples each
|
|
10
|
+
|
|
11
|
+
The three next-gen 3D platforms are now first-class alongside the original 14.
|
|
12
|
+
|
|
13
|
+
**Live debugging (cpuState + audioDebug).** PS1 (beetle_psx_hw) and Dreamcast (flycast)
|
|
14
|
+
gained the romdev debug-reader exports, so `cpu({op:'read'})` and
|
|
15
|
+
`audioDebug({op:'inspect'})` light up (N64 already had them):
|
|
16
|
+
- **PS1** — `cpu({op:'read'})` returns the live R3000A register file; `audioDebug({chip:'spu'})`
|
|
17
|
+
decodes the SPU's 24 voices + main volume (read from the raw register mirror, not the
|
|
18
|
+
sweep-quantized `SPU_Read`).
|
|
19
|
+
- **Dreamcast** — `cpu({op:'read'})` returns the SH-4 registers (r0–r15, pc, pr, gbr, vbr,
|
|
20
|
+
sr + decoded flags, mac, fpul); `audioDebug({chip:'aica'})` decodes the AICA's 64
|
|
21
|
+
PCM/ADPCM channels + master volume. Full host plumbing + decoders added.
|
|
22
|
+
- The capability manifest now reports cpuState/audioDebug `true` for all three (verified by
|
|
23
|
+
probing real core exports; `breakpoint`/`watch` remain pending on PS1/DC).
|
|
24
|
+
|
|
25
|
+
**GPU-rendering helper libs (no software framebuffers).** Every 3D platform's helper now
|
|
26
|
+
draws through the GPU — a software rasterizer would be black on the GL cores and <1fps:
|
|
27
|
+
- **N64** — the `n64.h` helper was rewritten to emit a **GBI (F3DEX2) display list** that
|
|
28
|
+
glide64 HLEs onto the GPU (clear/rect as fill-rectangles, triangles scan-converted into
|
|
29
|
+
GPU fill-rect spans), instead of poking pixels into RDRAM (which rendered black on
|
|
30
|
+
glide64). No Nintendo microcode shipped — the OSTask CRC-bait trick selects F3DEX2.
|
|
31
|
+
- **PS1** — already correct (GP0 GPU primitives on beetle_psx_hw).
|
|
32
|
+
- **Dreamcast** — `dc.h` now sets **480i interlace** in `dc_video_init` (240p only showed
|
|
33
|
+
the top 240 of 480 lines), and added a Maple-DMA `dc_pad()` / `dc_pressed()`.
|
|
34
|
+
- `#include "n64.h"` / `#include "psx.h"` now auto-bundle (parity with `dc.h`).
|
|
35
|
+
|
|
36
|
+
**5 genre examples per platform.** N64, PS1, and Dreamcast each ship
|
|
37
|
+
shmup / platformer / puzzle / racing / sports examples — all verified building + rendering
|
|
38
|
+
on the GPU.
|
|
39
|
+
|
|
40
|
+
**Docs.** MENTAL_MODEL + TROUBLESHOOTING for N64, PS1, and Dreamcast (the render model,
|
|
41
|
+
boot story, debug surface, and what's N/A and why).
|
|
42
|
+
|
|
43
|
+
### asar (SNES) build-tool fixes
|
|
44
|
+
|
|
45
|
+
From real commercial-disassembly feedback:
|
|
46
|
+
- **`build({output:'project'|'run'})` honors `options` + a new `defines` map** (e.g. asar
|
|
47
|
+
`--define`) — they were silently dropped.
|
|
48
|
+
- **New `entry` param** so a project whose top file isn't `main.*` (e.g. an existing
|
|
49
|
+
`smw.asm` disassembly) builds without injecting glue.
|
|
50
|
+
- **Subdirectory assets are staged recursively** (a flat `readdir` missed nested
|
|
51
|
+
`incbin`/`incsrc` targets).
|
|
52
|
+
- **A clean asar error is no longer mislabeled** `[worker] Abort in WASM` (it exits errors
|
|
53
|
+
via a C++-exception path; the misleading heap-pointer line is stripped when real
|
|
54
|
+
diagnostics are present).
|
|
55
|
+
- **The LoROM-header bankcross preflight no longer false-positives** on banks $01+ (the
|
|
56
|
+
header is only in bank $00) and honors `check bankcross off`.
|
|
57
|
+
- **A readfile/filesize advisory** warns when a source reads many distinct files that way
|
|
58
|
+
(the asar-WASM resource limit), pointing at the pre-convert-to-`.bin` + `incbin`
|
|
59
|
+
workaround.
|
|
60
|
+
|
|
61
|
+
### Toolchain
|
|
62
|
+
|
|
63
|
+
- **sh-c (Dreamcast) defaults to `-O1`** — the sh-elf `cc1.wasm` has an `-O2`-only pass
|
|
64
|
+
that aborts on common control flow; `-O1` dodges it. A user-supplied `-O<level>` wins.
|
|
65
|
+
|
|
66
|
+
## 0.70.0 — 2026-06-26
|
|
67
|
+
|
|
68
|
+
### Dreamcast is ship-ready: verified build → run → screenshot, with a renderable example
|
|
69
|
+
|
|
70
|
+
The Dreamcast platform is now verified end-to-end and release-ready:
|
|
71
|
+
|
|
72
|
+
- **build → run → screenshot proven + regression-tested.** A C homebrew compiles via
|
|
73
|
+
sh-elf-gcc, boots DIRECTLY on Flycast's reios HLE BIOS (no GD-ROM image, no firmware),
|
|
74
|
+
and renders on the real GPU through native-gles at 640×480 — confirmed by the new
|
|
75
|
+
`test/dreamcast-runside.test.js`.
|
|
76
|
+
- **dc.h is now auto-bundled.** The PowerVR2 framebuffer helper (640×480 RGB565 bring-up:
|
|
77
|
+
FB_R_CTRL/SIZE/SOF1 + SPG) ships in the sh-c toolchain lib and is injected automatically,
|
|
78
|
+
so `#include "dc.h"` just works — a DC program is a single `main.c` with no glue. A
|
|
79
|
+
caller-supplied `dc.h` still overrides the bundled one.
|
|
80
|
+
- **A renderable example** — `examples/dreamcast/hello` (DCHELLO): the canonical starter
|
|
81
|
+
that paints a test pattern through the GPU pipeline. Registered with createProject /
|
|
82
|
+
scaffold like the other platforms.
|
|
83
|
+
|
|
84
|
+
(The 640×480 screenshot path was already correct — the GL FBO is sized to Flycast's
|
|
85
|
+
upscale bound and the host crops the readback to the core's reported geometry; a raw
|
|
86
|
+
readback without crop args was the only thing that looked oversized.)
|
|
87
|
+
|
|
88
|
+
## 0.69.0 — 2026-06-26
|
|
89
|
+
|
|
90
|
+
### PS1 renders on the REAL GPU via native-gles (Beetle PSX HW + OpenBIOS)
|
|
91
|
+
|
|
92
|
+
The PS1 core is now **Beetle PSX HW** (mednafen) with its GLES3/WebGL2 hardware renderer,
|
|
93
|
+
rendering the PS1 GPU on the real GPU through native-gles — the same path as glide64-N64
|
|
94
|
+
and Flycast-DC. It ships with **OpenBIOS embedded** (PCSX-Redux, MIT-licensed, region-free),
|
|
95
|
+
so there's NO copyrighted Sony firmware to ship and no BIOS file to supply. (Verified:
|
|
96
|
+
mod.GL exposed, SET_HW_RENDER fires, hwActive=true, the OpenBIOS 3D-cube boot animation
|
|
97
|
+
renders in shaded perspective through native-gles.)
|
|
98
|
+
|
|
99
|
+
- New package romdev-core-beetle-psx-hw (replaces romdev-core-pcsx-rearmed as the PS1
|
|
100
|
+
core); build-beetle-psx-hw.sh reuses the N64 GL recipe (all-.o link, -lGL +
|
|
101
|
+
GL_ENABLE_GET_PROC_ADDRESS + GL in EXPORTED_RUNTIME_METHODS, the libretro-common EXTRAS).
|
|
102
|
+
- Registry: ps1 → beetle_psx_hw, hwRender:true. Manifest: renderingKind 3d, run+screenshot
|
|
103
|
+
+disasm+decompile+build true; cpuState/audioDebug now false (beetle lacks the romdev
|
|
104
|
+
MIPS/SPU debug exports the old pcsx_rearmed-software build had — a future core patch;
|
|
105
|
+
pcsx had no WebGL2 GPU path).
|
|
106
|
+
|
|
107
|
+
NOTE (both MIPS platforms): the GL cores render RDP/GPU display lists, NOT raw CPU-written
|
|
108
|
+
framebuffers — so the romdev software-3D example libs (which rasterize into a framebuffer)
|
|
109
|
+
render black on them; REAL games with GPU geometry render correctly. SDK-based examples
|
|
110
|
+
(libdragon rdpq / PSn00bSDK GTE) are the renderable path. Suite 1059/1059.
|
|
111
|
+
|
|
112
|
+
## 0.68.0 — 2026-06-26
|
|
113
|
+
|
|
114
|
+
### N64 renders on the REAL GPU via native-gles (glide64), not software
|
|
115
|
+
|
|
116
|
+
parallel_n64 now renders the RDP through **glide64 → GLES2/WebGL2 → native-gles** (the
|
|
117
|
+
real GPU, headless EGL pbuffer), replacing the angrylion software-RDP build. SET_HW_RENDER
|
|
118
|
+
fires, the host's LibretroGL drives native-gles, and frames read back via glReadPixels —
|
|
119
|
+
the same GPU path as Flycast/Dreamcast. (Verified: hwActive=true, the GL context engages
|
|
120
|
+
from boot.)
|
|
121
|
+
|
|
122
|
+
The build + host fixes that made it work (every one was a real wall):
|
|
123
|
+
- **Link all .o directly**, not via a .bc/.a archive — the archive route drops the
|
|
124
|
+
GLSM/context_reset/glide64 objects (no externally-referenced symbol), so the core never
|
|
125
|
+
calls SET_HW_RENDER. (build-parallel-n64.sh)
|
|
126
|
+
- **`-lGL` + `GL_ENABLE_GET_PROC_ADDRESS=1` + `"GL"` in EXPORTED_RUNTIME_METHODS** — these
|
|
127
|
+
make Emscripten emit `Module["GL"]=GL`, so the returned module actually exposes the GL
|
|
128
|
+
context object the host needs. Without them, `mod.GL` is undefined and HW render never
|
|
129
|
+
initializes.
|
|
130
|
+
- **coreLoader: don't set `noInitialRun`/`wasmBinary` for GL (canvas) cores** — both
|
|
131
|
+
suppress the Emscripten GL runtime init; use `locateFile` so the .wasm loads the normal way.
|
|
132
|
+
- **Pre-seed PLATFORM_CORE_OPTIONS before `_retro_init`** (loadCore now infers the platform
|
|
133
|
+
from the core filename): the core picks its renderer (glide64 vs angrylion) from
|
|
134
|
+
`parallel-n64-gfxplugin` during retro_init, so the override must be set before then.
|
|
135
|
+
- Registry: n64 is now `hwRender:true` (glide64 GL).
|
|
136
|
+
|
|
137
|
+
## 0.67.0 — 2026-06-26
|
|
138
|
+
|
|
139
|
+
### Dreamcast examples + sh-c -O level fix
|
|
140
|
+
|
|
141
|
+
Four DC example programs (rom-games/dreamcast/): dchello (test card), bounce (animation),
|
|
142
|
+
starfield (shmup background), grid (puzzle/board) — all build via the WASM toolchain and
|
|
143
|
+
render distinct content through Flycast, exercising the dc.h helper (no-KOS PowerVR2
|
|
144
|
+
framebuffer + 2D primitives).
|
|
145
|
+
|
|
146
|
+
sh-c driver: a user-supplied `-O<level>` now wins over the default `-O2` (gcc honors the
|
|
147
|
+
LAST -O, so a default appended after the user's would clobber it — only add -O2 if absent).
|
|
148
|
+
This matters because the WASM cc1 hangs at -O2 on some sources (the interprocedural-
|
|
149
|
+
optimization phase; native sh-elf-gcc compiles them in <1s), and -O1 is the workaround.
|
|
150
|
+
Suite 1059/1059.
|
|
151
|
+
|
|
152
|
+
## 0.66.0 — 2026-06-26
|
|
153
|
+
|
|
154
|
+
### Dreamcast: build() works — full WASM toolchain + packaging
|
|
155
|
+
|
|
156
|
+
`build({platform:"dreamcast"})` now compiles SH-4 C to a bootable ELF entirely in WASM,
|
|
157
|
+
and the result boots + renders through Flycast — the complete zero-install pipeline
|
|
158
|
+
(build → run → screenshot), verified end-to-end via the public `buildForPlatform`.
|
|
159
|
+
|
|
160
|
+
- **sh-elf-gcc WASM toolchain** (cc1 + as + ld + objcopy + objdump): gcc 14.2.0 +
|
|
161
|
+
binutils 2.42 + newlib 4.4.0 for sh-elf (little-endian SH-4, m4-single-only). The cc1
|
|
162
|
+
build needed CC_FOR_BUILD forced native (emconfigure makes $(CC)=emcc, which would
|
|
163
|
+
build the gen tools as WASM) + the host-side libcpp/libiberty configured first.
|
|
164
|
+
- **sh-c build driver** + lib (dc-crt0.s zeroes .bss + calls main; dc.ld links at
|
|
165
|
+
0x8c010000; newlib libc/libm/libgcc). The ELF IS the deliverable — reios boots it.
|
|
166
|
+
- **Packages:** romdev-core-flycast (the DC core) + romdev-toolchain-sh-gcc (the WASM
|
|
167
|
+
compiler), both added as romdevtools deps; the registry resolves the DC core from the
|
|
168
|
+
package. Manifest `dreamcast.build` is now true.
|
|
169
|
+
|
|
170
|
+
Dreamcast core parity reached: disasm + decompile + build + run + screenshot. Suite
|
|
171
|
+
1059/1059.
|
|
172
|
+
|
|
173
|
+
## 0.65.0 — 2026-06-26
|
|
174
|
+
|
|
175
|
+
### Dreamcast: homebrew renders correct graphics + HW-frame crop-to-native
|
|
176
|
+
|
|
177
|
+
A minimal DC homebrew (no KallistiOS — a dependency-free `dc.h` helper that programs the
|
|
178
|
+
PowerVR2 FB_R_CTRL/FB_R_SIZE/FB_R_SOF1 + SPG for a 640x480 RGB565 framebuffer) builds with
|
|
179
|
+
the native sh-elf toolchain, boots via reios HLE, runs, and renders a test pattern that the
|
|
180
|
+
host captures **pixel-exact** (verified: dark-blue background + equal red/green/blue bars +
|
|
181
|
+
white frame, the program's exact colors). This closes the DC render-fidelity loop.
|
|
182
|
+
|
|
183
|
+
Host change (helps any HW-render core): the video_refresh callback now records the core's
|
|
184
|
+
reported active resolution, and the GL readback crops the FBO to it — so a 640x480 DC frame
|
|
185
|
+
no longer comes back as the full 853x853 GL viewport with a dead border. `readbackFrame`
|
|
186
|
+
takes optional (cropW, cropH); `_afterRun` passes the core's w/h. Suite 1059/1059.
|
|
187
|
+
|
|
188
|
+
## 0.64.0 — 2026-06-26
|
|
189
|
+
|
|
190
|
+
### Dreamcast: present-path verified — screenshot works
|
|
191
|
+
|
|
192
|
+
Flycast renders to the GL FBO and the host reads it back: a framebuffer-writing homebrew
|
|
193
|
+
program shows ~727k captured pixels through the host's normal frame path (hwFramePending →
|
|
194
|
+
readbackFrame). Manifest `dreamcast.screenshot` is now true. With the CPU executing
|
|
195
|
+
(0.63.0), the direct-framebuffer present path lights up.
|
|
196
|
+
|
|
197
|
+
Added `flycast_emulate_framebuffer: enabled` to the host's DC options — it scans the DC
|
|
198
|
+
framebuffer out on every VBlank (the 2D path, no PowerVR2 tile list), so simple homebrew
|
|
199
|
+
that writes RGB565 to VRAM presents reliably without authoring a full TA list. (Full
|
|
200
|
+
TA/3D fidelity + correct framebuffer addressing come with the KOS helper lib; the pipeline
|
|
201
|
+
itself — boot → run → render → host capture — is proven end-to-end.) Suite 1059/1059.
|
|
202
|
+
|
|
203
|
+
## 0.63.0 — 2026-06-26
|
|
204
|
+
|
|
205
|
+
### Dreamcast: HOMEBREW EXECUTES — run + memory introspection live
|
|
206
|
+
|
|
207
|
+
Custom Flycast core patches make the SH-4 actually execute guest code. A homebrew .elf
|
|
208
|
+
boots via reios HLE, the SH-4 runs it, and the guest's RAM writes are visible through the
|
|
209
|
+
host (verified: a 0xDC0DC0DC marker the test program writes appears in DC RAM). Manifest
|
|
210
|
+
`dreamcast.run` is now true.
|
|
211
|
+
|
|
212
|
+
Root cause (3 stacked bugs): (1) worker-thread aborts — fixed by single-thread +
|
|
213
|
+
`--wrap pthread_create` no-op (0.62.0); (2) HLE BIOS off — only the reios path loads a raw
|
|
214
|
+
.elf, and the option is latched at retro_init, so default `UseReios=true` in source for
|
|
215
|
+
emscripten; (3) THE BIG ONE — `ThreadedRendering` defaulted ON, which runs the CPU on a
|
|
216
|
+
`std::async` worker that our pthread no-op kills → the SH-4 never steps (PC stuck at the
|
|
217
|
+
reset vector, reios_boot never fires, RAM stays zero). Fixed by unconditionally
|
|
218
|
+
`config::ThreadedRendering.override(false)` for emscripten in update_variables.
|
|
219
|
+
|
|
220
|
+
`screenshot` stays false until the PowerVR2 present-path is verified with a TA-driving
|
|
221
|
+
program (the KOS helper lib — next phase). All patches reproducible in build-flycast.sh.
|
|
222
|
+
Suite 1059/1059.
|
|
223
|
+
|
|
224
|
+
## 0.62.0 — 2026-06-26
|
|
225
|
+
|
|
226
|
+
### Dreamcast run-side BREAKTHROUGH: Flycast boots + runs DC ELFs
|
|
227
|
+
|
|
228
|
+
The threading wall is solved. Flycast (the full DC emulator) now **boots a homebrew
|
|
229
|
+
.elf via reios HLE and runs frames** through the romdev host — `retro_init` /
|
|
230
|
+
`retro_load_game` / `retro_run` all succeed, av_info reports 640×480, and video_refresh
|
|
231
|
+
fires every frame. No abort, no `unwind`.
|
|
232
|
+
|
|
233
|
+
The fix (after trying PROXY_TO_PTHREAD + ASYNCIFY, which deadlocks in Node on the
|
|
234
|
+
GL↔proxy-thread dependency): build single-threaded and **`--wrap` pthread_create to a
|
|
235
|
+
no-op** (`scripts/patches/romdev-snippets/flycast-pthread-noop.c`). pthread_create
|
|
236
|
+
returns success but spawns nothing; join/detach are no-ops. So flycast's worker threads
|
|
237
|
+
(achievements/http/network/audio-async) never run, `std::thread`'s ctor doesn't abort
|
|
238
|
+
(no "thread constructor failed"), and — crucially — the main thread never blocks on a
|
|
239
|
+
worker, so there's no emscripten `unwind`. Emulation runs synchronously on retro_run
|
|
240
|
+
(ThreadedRendering defaulted false). This is far cleaner than stubbing thread sites
|
|
241
|
+
one-by-one (there were 4+ wrapper classes plus raw std::thread/std::async).
|
|
242
|
+
|
|
243
|
+
Also: the GL `get_proc_address` bridge fix (0.59.0) is what got context_reset past the
|
|
244
|
+
signature mismatch; the 512MB-mmap fallback (posix_vmem) got init past the trap.
|
|
245
|
+
|
|
246
|
+
NEXT: a DC program that actually renders via PowerVR2 (the KOS helper lib) to verify the
|
|
247
|
+
present path end-to-end, then flip run/screenshot true. Captured in build-flycast.sh.
|
|
248
|
+
Suite green.
|
|
249
|
+
|
|
250
|
+
## 0.60.0 — 2026-06-26
|
|
251
|
+
|
|
252
|
+
### Dreamcast: SuperH4 SLEIGH metadata shipped + Flycast threading progress
|
|
253
|
+
|
|
254
|
+
- **SuperH4 SLEIGH metadata committed** (`.ldefs`/`.pspec`/`.cspec`) — these ship
|
|
255
|
+
alongside the gitignored `.sla` (like every other CPU); without them the decompiler
|
|
256
|
+
couldn't load the SuperH4 spec at runtime. (0.57.0 shipped the wiring but missed the
|
|
257
|
+
metadata files. Now complete.)
|
|
258
|
+
- Flycast run-side threading: the single-threaded WASM build needs worker-thread
|
|
259
|
+
creation stubbed (emscripten can't spawn them without -pthread; with -pthread the
|
|
260
|
+
main thread can't block → unwind). Captured the patches in `build-flycast.sh`
|
|
261
|
+
(`cThread::Start` / `VPeriodicThread::start` no-op, `ThreadedRendering` defaults
|
|
262
|
+
false on emscripten) + the `flycast_threaded_rendering: disabled` host option.
|
|
263
|
+
|
|
264
|
+
KNOWN-OPEN: Flycast's load still aborts on a not-yet-located worker thread (no-pthread)
|
|
265
|
+
or unwinds (pthread). The thread/main-loop model integration is the remaining run-side
|
|
266
|
+
fight — see N64_PS1_LESSONS_FOR_DREAMCAST.md. DC analysis (disasm+decompile) is fully
|
|
267
|
+
shipped + tested. Suite 1059/1059.
|
|
268
|
+
|
|
269
|
+
## 0.59.0 — 2026-06-26
|
|
270
|
+
|
|
271
|
+
### Dreamcast run-side: Flycast loads ELFs + GL bridge fix (general)
|
|
272
|
+
|
|
273
|
+
Flycast WASM now boots a homebrew `.elf` (reios HLE — no BIOS/disc) and requests GL:
|
|
274
|
+
- threads: `-pthread -sPTHREAD_POOL_SIZE=8` (Flycast spawns std::threads; without
|
|
275
|
+
pthreads the ctor aborts). The pthread build bakes the module filename into the
|
|
276
|
+
worker bootstrap, so it MUST link with the final `flycast_libretro.js` name.
|
|
277
|
+
- **GL proc-address (general bridge fix in LibretroGL.js):** emscripten-WebGL cores
|
|
278
|
+
(Flycast) resolve GL via libretro `get_proc_address`. The bridge previously returned
|
|
279
|
+
a no-op 0-arg stub → the core called multi-arg GL fns through it → "null function or
|
|
280
|
+
function signature mismatch" in context_reset. Now the bridge returns the real
|
|
281
|
+
`emscripten_GetProcAddress` table pointer (built with `-sGL_ENABLE_GET_PROC_ADDRESS=1
|
|
282
|
+
-lGL`); the native-gles stub path stays as the glide64-N64 fallback. This fix helps
|
|
283
|
+
ANY future emscripten-WebGL core.
|
|
284
|
+
- `ROMDEV_CORE_LOG=1` env gates core stdout/stderr (was always suppressed) — found the
|
|
285
|
+
thread + mmap aborts with it.
|
|
286
|
+
|
|
287
|
+
KNOWN-OPEN: `retro_run` throws emscripten's `unwind` (Flycast yields via
|
|
288
|
+
emscripten_set_main_loop / Asyncify, incompatible with the host's synchronous
|
|
289
|
+
frame-step). That main-loop integration is the next run-side step. Suite 1059/1059.
|
|
290
|
+
|
|
291
|
+
## 0.58.0 — 2026-06-26
|
|
292
|
+
|
|
293
|
+
### Dreamcast run-side: Flycast WASM core builds + inits; sh-elf toolchain built
|
|
294
|
+
|
|
295
|
+
The two heaviest Dreamcast pieces, both landed (build infrastructure; host present-path
|
|
296
|
+
integration is the next step):
|
|
297
|
+
|
|
298
|
+
- **sh-elf-gcc toolchain** (SH-4): binutils 2.42 + gcc 14.2.0 + newlib 4.4.0, built
|
|
299
|
+
for `sh-elf` (m4-single-only, little-endian — the DC ABI). Compiles SH-4 C end to
|
|
300
|
+
end. `scripts/build-sh-toolchain.sh` (adapted from the mips one; SH-4 is single-
|
|
301
|
+
endian so no be/el split).
|
|
302
|
+
- **Flycast → WASM**: the full Dreamcast emulator (785 C++ files, GLES3/WebGL2)
|
|
303
|
+
compiled to a 5.9MB WASM module that instantiates with all libretro entry points
|
|
304
|
+
and `retro_init` succeeds. Flycast has no upstream emscripten build, so
|
|
305
|
+
`scripts/build-flycast.sh` applies the romdev WASM patches discovered here:
|
|
306
|
+
- a `CPU_GENERIC` host (no JIT) → the SH-4/ARM/DSP interpreters (`TARGET_NO_REC`);
|
|
307
|
+
CMake `DetectArchitecture` + `build.h` + the FPU-control / JIT-segfault-recovery
|
|
308
|
+
arch branches all get a generic no-op path.
|
|
309
|
+
- asio single-threaded (`ASIO_DISABLE_THREADS`) so it doesn't need POSIX
|
|
310
|
+
signal_blocker/tss_ptr (emscripten without -pthread isn't detected as POSIX).
|
|
311
|
+
- Vulkan OFF (WASM uses WebGL); networking/UPnP stubbed.
|
|
312
|
+
- **the key boot fix:** emscripten can't `mmap` a 512MB contiguous reservation (it
|
|
313
|
+
traps), so `posix_vmem::init` declines fast-vmem on emscripten → Flycast's
|
|
314
|
+
malloc-based memory fallback engages and `retro_init` succeeds.
|
|
315
|
+
- `dreamcast` registry entry (Flycast, hwRender — PowerVR2 is GPU-first, no software
|
|
316
|
+
framebuffer; HLE reios BIOS, no firmware to ship).
|
|
317
|
+
|
|
318
|
+
Suite 1059/1059. Next: the GL present-path (load_game + run + frame through the host's
|
|
319
|
+
WebGL2 bridge), then the helper lib + 5 example games + packaging.
|
|
320
|
+
|
|
321
|
+
## 0.57.0 — 2026-06-26
|
|
322
|
+
|
|
323
|
+
### Dreamcast (SH-4) analysis slice — disasm + decompile
|
|
324
|
+
|
|
325
|
+
First slice of Dreamcast support: the SH-4 (SuperH) reverse-engineering path, on the
|
|
326
|
+
same pattern as the PS1/N64 analysis slice.
|
|
327
|
+
|
|
328
|
+
- rizin's `sh` plugin (already in rizin.wasm) wired for disasm/cfg/xrefs/functions
|
|
329
|
+
(arch=sh, little-endian).
|
|
330
|
+
- Ghidra's **SuperH4** SLEIGH spec compiled (`SuperH4_le.sla`) + shipped in
|
|
331
|
+
romdev-analysis-decompiler → `decompile` produces real C (langid
|
|
332
|
+
`SuperH4:LE:32:default`). Verified: SH-4 bytes → disasm + decompiled C.
|
|
333
|
+
- analyze.js handles DC binaries: strips an ELF to its first PT_LOAD segment (vaddr =
|
|
334
|
+
loadBase 0x8c010000) or treats a raw image as flat; left-pads so flat offset ==
|
|
335
|
+
the VA's low bits + rebases the high bits (same trick PS1 needed for absolute-
|
|
336
|
+
addressed calls — SH-4's PC-relative + absolute addressing needs it too).
|
|
337
|
+
- `dreamcast` added to the capability manifest as the new `sh` tier (analysis-first;
|
|
338
|
+
run/build/etc. land in later phases). The 3D (PowerVR2) renderer's tile/sprite
|
|
339
|
+
inspectors are N/A by hardware with a stated reason. Excluded from the all-14
|
|
340
|
+
contract via the generalized NEXTGEN_TIER (mips + sh).
|
|
341
|
+
|
|
342
|
+
Suite 1059/1059. Run-side (Flycast WASM), build (sh-elf-gcc), the helper lib, and the
|
|
343
|
+
5 example games are the next phases.
|
|
344
|
+
|
|
7
345
|
## 0.56.1 — 2026-06-26
|
|
8
346
|
|
|
9
347
|
### ascii screenshot: legible default grid + lighter default color (0.44.0 feedback #1)
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# romdev
|
|
2
2
|
|
|
3
|
-
The entry point for **romdev** — vibe-code real retro games. Build, run, inspect, and reverse-engineer actual homebrew ROMs (NES, SNES, Game Boy, Genesis, Atari, C64, GBA, and
|
|
3
|
+
The entry point for **romdev** — vibe-code real retro games. Build, run, inspect, and reverse-engineer actual homebrew ROMs (NES, SNES, Game Boy, Genesis, Atari, C64, GBA, PC Engine, MSX — and the 3D consoles N64, PlayStation, and Dreamcast) with one command — drive it yourself or let a coding assistant do it.
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
6
|
npx romdevtools
|
|
@@ -9,7 +9,7 @@ npx romdevtools
|
|
|
9
9
|
**What you get:**
|
|
10
10
|
|
|
11
11
|
- **Build** — bundled per-platform toolchains (cc65, SDCC, RGBDS, asar, vasm, SGDK, PVSnesLib, libtonc, …) as WASM. Write source, compile, get a real ROM.
|
|
12
|
-
- **Run + see + drive** — load the ROM into an emulated console (libretro cores as WASM), step frames, screenshot, script controller input.
|
|
12
|
+
- **Run + see + drive** — load the ROM into an emulated console (libretro cores as WASM), step frames, screenshot, script controller input. The 2D consoles render in software; the 3D consoles (N64 via glide64, PlayStation via Beetle PSX HW, Dreamcast via Flycast) render on the **real GPU** through [`native-gles`](https://github.com/monteslu/native-gles) — headless OpenGL/EGL, no browser. PlayStation ships [OpenBIOS](https://github.com/grumpycoders/pcsx-redux) (MIT) embedded, so there's no proprietary firmware to supply.
|
|
13
13
|
- **Inspect + romhack** — read CPU/video/save RAM, watch memory, write-breakpoints, the Cheat-Engine value-search loop, a bundled cheat database, mapper-aware disassembly, and a byte-exact rebuildable-project disassembler.
|
|
14
14
|
- **Reverse-engineering analysis engine (all 14 platforms)** — control-flow graphs, deep cross-references, auto-detected functions (ranked real-code-first), a one-shot structural map, and a Ghidra **decompiler** (C-like pseudocode, with hardware registers named and 6502 SLEIGH clutter folded to readable C): `disasm({target:'cfg'|'xrefs'|'functions'|'decompile'})` and `symbols({op:'analyze'})`. And the piece no static tool has: **live computed-jumptable recovery** — `breakpoint({on:'jumptable'})` runs the emulator to resolve the `JMP (table,X)` / RTS-trick dispatchers (state machines, script/battle VMs) that static analysis collapses to "could not recover." Understand *how* a routine works before you touch it — no $3,000 IDA license, no install.
|
|
15
15
|
- **Convert assets** — PNG → platform tiles/tilemaps, quantize-to-palette, audio importers (BRR for SNES, XGM2 PCM for Genesis).
|
|
@@ -20,7 +20,7 @@ Point any coding agent at it three ways:
|
|
|
20
20
|
- **Agent Skill** — `GET /skills/romdev/SKILL.md` (the [Agent Skills](https://agentskills.io) standard; save it to your skills dir as `skills/romdev/SKILL.md`; ~100 tokens until invoked).
|
|
21
21
|
- **MCP** — it's also a [Model Context Protocol](https://modelcontextprotocol.io/) server at `/mcp` for clients that want it.
|
|
22
22
|
|
|
23
|
-
This package contains all the JavaScript — the tool surface, the WASM emulator host, the per-platform example games, runtime/library source, and debug helpers — but **no emulator or compiler WASM itself.** Those ship in the `romdev-*` binary packages it depends on
|
|
23
|
+
This package contains all the JavaScript — the tool surface, the WASM emulator host, the per-platform example games, runtime/library source, and debug helpers — but **no emulator or compiler WASM itself.** Those ship in the `romdev-*` binary packages it depends on; each platform's core/toolchain WASM is resolved (`import.meta.resolve`) and instantiated only the first time you build or run that platform, so memory stays proportional to what you actually use.
|
|
24
24
|
|
|
25
25
|
> For the full project — what romdev is, the supported-platform matrix, how the pieces fit together, and how to develop on it — see the [repository README](https://github.com/monteslu/romdev#readme).
|
|
26
26
|
|
|
@@ -34,11 +34,13 @@ This package contains all the JavaScript — the tool surface, the WASM emulator
|
|
|
34
34
|
|
|
35
35
|
## Dependencies
|
|
36
36
|
|
|
37
|
-
`romdevtools`
|
|
37
|
+
`romdevtools` depends on the binary/data packages it needs (exact-pinned), so a single install gets a matched, tested set:
|
|
38
38
|
|
|
39
|
-
-
|
|
40
|
-
-
|
|
41
|
-
-
|
|
39
|
+
- 2D cores: `romdev-core-{fceumm,gambatte,gpgx,vice,handy,prosystem,geargrafx,bluemsx}`
|
|
40
|
+
- 3D / GPU cores (rendered through `native-gles`): `romdev-core-{parallel-n64,beetle-psx-hw,flycast}`
|
|
41
|
+
- Platforms (core + dedicated toolchain bundled): `romdev-platform-{snes,gba,atari2600}`
|
|
42
|
+
- Toolchains: `romdev-toolchain-{cc65,sdcc,m68k-gcc,vasm,rgbds,mips-gcc,sh-gcc}` (mips-gcc = N64/PS1 C; sh-gcc = Dreamcast C)
|
|
43
|
+
- GPU deps (OPTIONAL — only the 3D cores need them; the 2D cores never touch GL): `native-gles` + `webgl-node`. A headless user without a GPU stack can still run all the 2D platforms.
|
|
42
44
|
- Analysis: `romdev-analysis` (Rizin → WASM: control-flow graphs, cross-references, function detection) and `romdev-analysis-decompiler` (Ghidra's C++ decompiler → WASM + SLEIGH processor specs for all 14 CPUs). Power `disasm({target:'cfg'|'xrefs'|'functions'|'decompile'})` and `symbols({op:'analyze'})`. Lazy-loaded on first use.
|
|
43
45
|
- Data: `romdev_game_codes` — the bundled game-code / cheat database (a free labeled RAM/code map for thousands of known ROMs), split out so it can grow independently. Lazy-loaded one platform at a time.
|
|
44
46
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/* dchello — a minimal Dreamcast homebrew that draws a recognizable test pattern,
|
|
2
|
+
* proving the romdev DC pipeline renders program-controlled graphics end-to-end. */
|
|
3
|
+
#include "dc.h"
|
|
4
|
+
|
|
5
|
+
void main(void) {
|
|
6
|
+
dc_video_init();
|
|
7
|
+
|
|
8
|
+
/* Clear to a dark blue background. */
|
|
9
|
+
dc_clear(dc_rgb(16, 24, 64));
|
|
10
|
+
|
|
11
|
+
/* Three solid bars (red, green, blue) — distinct, easy to verify in a screenshot. */
|
|
12
|
+
dc_rect(64, 80, 160, 320, dc_rgb(220, 40, 40)); /* red */
|
|
13
|
+
dc_rect(240, 80, 160, 320, dc_rgb(40, 200, 60)); /* green */
|
|
14
|
+
dc_rect(416, 80, 160, 320, dc_rgb(50, 90, 230)); /* blue */
|
|
15
|
+
|
|
16
|
+
/* A white frame around the screen. */
|
|
17
|
+
dc_rect(0, 0, DC_W, 4, dc_rgb(255, 255, 255));
|
|
18
|
+
dc_rect(0, DC_H - 4, DC_W, 4, dc_rgb(255, 255, 255));
|
|
19
|
+
dc_rect(0, 0, 4, DC_H, dc_rgb(255, 255, 255));
|
|
20
|
+
dc_rect(DC_W - 4, 0, 4, DC_H, dc_rgb(255, 255, 255));
|
|
21
|
+
|
|
22
|
+
/* Hold the frame. */
|
|
23
|
+
for (;;) { }
|
|
24
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/* Dreamcast PLATFORMER demo — a side-scrolling scene: a hero hops across platforms
|
|
2
|
+
* while the camera scrolls. Self-animating (no input). Renders on the PowerVR2 via
|
|
3
|
+
* the framebuffer path. */
|
|
4
|
+
#include "dc.h"
|
|
5
|
+
|
|
6
|
+
void main(void){
|
|
7
|
+
int frame = 0;
|
|
8
|
+
dc_video_init();
|
|
9
|
+
for (;;){
|
|
10
|
+
int scroll = (frame * 2) % (DC_W);
|
|
11
|
+
int t = frame % 90;
|
|
12
|
+
int jump = t < 45 ? t : (90 - t); /* 0..45..0 hop */
|
|
13
|
+
int hy = DC_H - 140 - jump * 2;
|
|
14
|
+
int hx = DC_W/2 - 16;
|
|
15
|
+
|
|
16
|
+
dc_clear(dc_rgb(80, 150, 230)); /* sky */
|
|
17
|
+
/* parallax hills */
|
|
18
|
+
{ int i; for (i = -1; i < 6; i++){ int x = i*140 - (scroll/2); dc_rect(x, DC_H-200, 120, 200, dc_rgb(60, 170, 90)); } }
|
|
19
|
+
/* ground */
|
|
20
|
+
dc_rect(0, DC_H-60, DC_W, 60, dc_rgb(120, 80, 40));
|
|
21
|
+
/* floating platforms (scrolling) */
|
|
22
|
+
{ int i; for (i = -1; i < 6; i++){ int x = i*180 - (scroll % 180); dc_rect(x, DC_H-160, 90, 18, dc_rgb(150, 110, 60)); } }
|
|
23
|
+
/* hero (head + body) */
|
|
24
|
+
dc_rect(hx, hy, 32, 32, dc_rgb(240, 90, 70));
|
|
25
|
+
dc_rect(hx+6, hy+6, 6, 6, dc_rgb(255,255,255)); /* eye */
|
|
26
|
+
dc_rect(hx, hy+32, 32, 20, dc_rgb(40, 60, 200)); /* legs */
|
|
27
|
+
/* a coin that bobs */
|
|
28
|
+
dc_rect(DC_W/2 + 120 - (scroll%240), DC_H-220 + (jump), 18, 18, dc_rgb(255, 220, 60));
|
|
29
|
+
frame++;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/* Dreamcast PUZZLE demo — a falling-block (Tetris-like) board that fills + clears
|
|
2
|
+
* rows on a loop. Self-animating (no input). Renders on the PowerVR2 framebuffer. */
|
|
3
|
+
#include "dc.h"
|
|
4
|
+
|
|
5
|
+
#define COLS 10
|
|
6
|
+
#define ROWS 16
|
|
7
|
+
#define CELL 24
|
|
8
|
+
|
|
9
|
+
static unsigned char board[ROWS][COLS];
|
|
10
|
+
static unsigned int rng = 0xACE1u;
|
|
11
|
+
static unsigned int rnd(void){ rng ^= rng << 7; rng ^= rng >> 9; rng ^= rng << 8; return rng; }
|
|
12
|
+
|
|
13
|
+
static const u16 PAL[7] = { 0, 0xF800, 0x07E0, 0x001F, 0xFFE0, 0xF81F, 0x07FF };
|
|
14
|
+
|
|
15
|
+
void main(void){
|
|
16
|
+
int frame = 0, px = COLS/2, py = 0, col = 1, i, r, c;
|
|
17
|
+
dc_video_init();
|
|
18
|
+
for (;;){
|
|
19
|
+
int ox = (DC_W - COLS*CELL)/2, oy = (DC_H - ROWS*CELL)/2;
|
|
20
|
+
|
|
21
|
+
if ((frame % 8) == 0){
|
|
22
|
+
/* drop the active block one row; lock + respawn at the bottom */
|
|
23
|
+
if (py+1 >= ROWS || board[py+1][px]){
|
|
24
|
+
board[py][px] = col;
|
|
25
|
+
/* clear full-ish rows occasionally to keep it moving */
|
|
26
|
+
for (r = 0; r < ROWS; r++){ int full=1; for (c=0;c<COLS;c++) if(!board[r][c]) full=0;
|
|
27
|
+
if (full){ for(c=0;c<COLS;c++) board[r][c]=0; } }
|
|
28
|
+
py = 0; px = rnd()%COLS; col = 1 + rnd()%6;
|
|
29
|
+
if (board[0][px]){ for(r=0;r<ROWS;r++)for(c=0;c<COLS;c++) board[r][c]=0; } /* reset if buried */
|
|
30
|
+
} else py++;
|
|
31
|
+
}
|
|
32
|
+
dc_clear(dc_rgb(18, 18, 30));
|
|
33
|
+
/* board frame */
|
|
34
|
+
dc_rect(ox-4, oy-4, COLS*CELL+8, ROWS*CELL+8, dc_rgb(90,90,120));
|
|
35
|
+
dc_rect(ox, oy, COLS*CELL, ROWS*CELL, dc_rgb(10,10,18));
|
|
36
|
+
/* settled cells */
|
|
37
|
+
for (r = 0; r < ROWS; r++) for (c = 0; c < COLS; c++) if (board[r][c])
|
|
38
|
+
dc_rect(ox + c*CELL+1, oy + r*CELL+1, CELL-2, CELL-2, PAL[board[r][c]]);
|
|
39
|
+
/* active block */
|
|
40
|
+
dc_rect(ox + px*CELL+1, oy + py*CELL+1, CELL-2, CELL-2, PAL[col]);
|
|
41
|
+
frame++;
|
|
42
|
+
(void)i;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/* Dreamcast RACING demo — a pseudo-3D road that curves + scrolls toward a horizon,
|
|
2
|
+
* with a car at the bottom that drifts side to side. Self-animating (no input).
|
|
3
|
+
* Renders on the PowerVR2 framebuffer. */
|
|
4
|
+
#include "dc.h"
|
|
5
|
+
|
|
6
|
+
/* tiny fixed sine via a 16-entry quarter table */
|
|
7
|
+
static const int SIN16[17] = {0,49,97,142,181,213,236,251,256,251,236,213,181,142,97,49,0};
|
|
8
|
+
static int isin(int a){ a &= 63; if(a<16) return SIN16[a]; if(a<32) return SIN16[32-a]; if(a<48) return -SIN16[a-32]; return -SIN16[64-a]; }
|
|
9
|
+
|
|
10
|
+
void main(void){
|
|
11
|
+
int frame = 0, y;
|
|
12
|
+
dc_video_init();
|
|
13
|
+
for (;;){
|
|
14
|
+
int horizon = DC_H/3;
|
|
15
|
+
dc_clear(dc_rgb(60, 140, 230)); /* sky */
|
|
16
|
+
dc_rect(0, horizon, DC_W, DC_H-horizon, dc_rgb(40, 120, 50)); /* grass */
|
|
17
|
+
|
|
18
|
+
/* road: for each scanline below the horizon, a trapezoid widening to the
|
|
19
|
+
bottom, shifted by a curve that scrolls. */
|
|
20
|
+
for (y = horizon; y < DC_H; y++){
|
|
21
|
+
int depth = y - horizon;
|
|
22
|
+
int half = depth * (DC_W/2 - 20) / (DC_H - horizon) + 12;
|
|
23
|
+
int curve = isin((frame/2 + depth/4)) * depth / 256;
|
|
24
|
+
int cx = DC_W/2 + curve;
|
|
25
|
+
/* road stripe alternation for motion */
|
|
26
|
+
u16 rc = (((depth + frame) / 12) & 1) ? dc_rgb(70,70,75) : dc_rgb(90,90,95);
|
|
27
|
+
dc_rect(cx - half, y, half*2, 1, rc);
|
|
28
|
+
/* center dashes */
|
|
29
|
+
if ((((depth + frame*2)/16) & 1)) dc_rect(cx-2, y, 4, 1, dc_rgb(240,240,120));
|
|
30
|
+
}
|
|
31
|
+
/* the car (drifts L/R) */
|
|
32
|
+
{ int carx = DC_W/2 + isin(frame/3) * 60 / 256 - 24;
|
|
33
|
+
dc_rect(carx, DC_H-70, 48, 40, dc_rgb(220, 40, 40));
|
|
34
|
+
dc_rect(carx+6, DC_H-64, 36, 14, dc_rgb(40,40,60)); /* windshield */
|
|
35
|
+
dc_rect(carx-4, DC_H-44, 10, 18, dc_rgb(20,20,20)); /* wheels */
|
|
36
|
+
dc_rect(carx+42, DC_H-44, 10, 18, dc_rgb(20,20,20)); }
|
|
37
|
+
frame++;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/* Dreamcast SHMUP demo — a vertical shooter scene rendered on the PowerVR2 via the
|
|
2
|
+
* framebuffer path. The ship weaves, bullets stream up, enemies descend + recycle.
|
|
3
|
+
* Self-animating (no input) — proves program-controlled graphics render on the GPU.
|
|
4
|
+
* (DC input via dc_pad() reads the resting controller state; full press wiring is a
|
|
5
|
+
* follow-up — see dc.h.) */
|
|
6
|
+
#include "dc.h"
|
|
7
|
+
|
|
8
|
+
#define NB 12
|
|
9
|
+
#define NE 6
|
|
10
|
+
|
|
11
|
+
static int frame;
|
|
12
|
+
static unsigned int rng = 0x1234567u;
|
|
13
|
+
static unsigned int rnd(void){ rng ^= rng << 13; rng ^= rng >> 17; rng ^= rng << 5; return rng; }
|
|
14
|
+
|
|
15
|
+
static int bx[NB], by[NB], ba[NB];
|
|
16
|
+
static int ex[NE], ey[NE];
|
|
17
|
+
|
|
18
|
+
void main(void){
|
|
19
|
+
int i;
|
|
20
|
+
dc_video_init();
|
|
21
|
+
for (i = 0; i < NE; i++){ ex[i] = 60 + i*90; ey[i] = -(int)(rnd()%300); }
|
|
22
|
+
for (;;){
|
|
23
|
+
int shipx = DC_W/2 + (int)(80.0 * ((frame % 120) < 60 ? (frame%60) : (60-(frame%60))) / 60.0 - 40);
|
|
24
|
+
int shipy = DC_H - 80;
|
|
25
|
+
|
|
26
|
+
/* spawn a bullet every 8 frames */
|
|
27
|
+
if ((frame & 7) == 0){
|
|
28
|
+
for (i = 0; i < NB; i++) if (!ba[i]){ ba[i]=1; bx[i]=shipx; by[i]=shipy; break; }
|
|
29
|
+
}
|
|
30
|
+
dc_clear(dc_rgb(8, 10, 28));
|
|
31
|
+
/* starfield */
|
|
32
|
+
for (i = 0; i < 24; i++){
|
|
33
|
+
int sx = (int)((rnd()%DC_W));
|
|
34
|
+
int sy = (int)((frame*2 + i*53) % DC_H);
|
|
35
|
+
dc_rect(sx, sy, 2, 2, dc_rgb(120,120,160));
|
|
36
|
+
}
|
|
37
|
+
/* enemies */
|
|
38
|
+
for (i = 0; i < NE; i++){
|
|
39
|
+
ey[i] += 2;
|
|
40
|
+
if (ey[i] > DC_H){ ey[i] = -(int)(rnd()%200); ex[i] = (int)(rnd()%(DC_W-40)); }
|
|
41
|
+
if (ey[i] >= 0) dc_rect(ex[i], ey[i], 36, 28, dc_rgb(220, 60, 60));
|
|
42
|
+
}
|
|
43
|
+
/* bullets */
|
|
44
|
+
for (i = 0; i < NB; i++) if (ba[i]){ by[i] -= 8; if (by[i] < 0) ba[i]=0; else dc_rect(bx[i]-2, by[i], 4, 12, dc_rgb(255,240,80)); }
|
|
45
|
+
/* player ship (a little arrow of rects) */
|
|
46
|
+
dc_rect(shipx-4, shipy, 8, 24, dc_rgb(80, 200, 255));
|
|
47
|
+
dc_rect(shipx-16, shipy+14, 32, 8, dc_rgb(60, 160, 230));
|
|
48
|
+
frame++;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/* Dreamcast SPORTS demo — a top-down pong/air-hockey rally: two paddles track a
|
|
2
|
+
* bouncing ball with a scoreboard. Self-animating (the CPU "AI" plays both sides).
|
|
3
|
+
* Renders on the PowerVR2 framebuffer. */
|
|
4
|
+
#include "dc.h"
|
|
5
|
+
|
|
6
|
+
void main(void){
|
|
7
|
+
int frame = 0;
|
|
8
|
+
int bx = DC_W/2, by = DC_H/2, vx = 5, vy = 3;
|
|
9
|
+
int p0 = DC_H/2, p1 = DC_H/2; /* paddle centers (y) */
|
|
10
|
+
int s0 = 0, s1 = 0, i;
|
|
11
|
+
dc_video_init();
|
|
12
|
+
for (;;){
|
|
13
|
+
/* ball physics */
|
|
14
|
+
bx += vx; by += vy;
|
|
15
|
+
if (by < 12 || by > DC_H-12) vy = -vy;
|
|
16
|
+
/* paddles track the ball (simple AI) */
|
|
17
|
+
if (p0 < by) p0 += 4; else p0 -= 4;
|
|
18
|
+
if (p1 < by) p1 += 4; else p1 -= 4;
|
|
19
|
+
/* bounce off paddles / score */
|
|
20
|
+
if (bx < 40){ if (by > p0-50 && by < p0+50) vx = -vx; else { s1++; bx=DC_W/2; by=DC_H/2; vx=5; } }
|
|
21
|
+
if (bx > DC_W-40){ if (by > p1-50 && by < p1+50) vx = -vx; else { s0++; bx=DC_W/2; by=DC_H/2; vx=-5; } }
|
|
22
|
+
|
|
23
|
+
dc_clear(dc_rgb(15, 60, 30)); /* court green */
|
|
24
|
+
/* center line (dashed) */
|
|
25
|
+
for (i = 0; i < DC_H; i += 32) dc_rect(DC_W/2-2, i+8, 4, 16, dc_rgb(200,200,200));
|
|
26
|
+
/* top/bottom rails */
|
|
27
|
+
dc_rect(0, 0, DC_W, 8, dc_rgb(220,220,220));
|
|
28
|
+
dc_rect(0, DC_H-8, DC_W, 8, dc_rgb(220,220,220));
|
|
29
|
+
/* paddles */
|
|
30
|
+
dc_rect(24, p0-50, 14, 100, dc_rgb(80, 160, 255));
|
|
31
|
+
dc_rect(DC_W-38, p1-50, 14, 100, dc_rgb(255, 160, 80));
|
|
32
|
+
/* ball */
|
|
33
|
+
dc_rect(bx-8, by-8, 16, 16, dc_rgb(255, 240, 80));
|
|
34
|
+
/* scoreboard (score as stacked pips) */
|
|
35
|
+
for (i = 0; i < s0 && i < 9; i++) dc_rect(DC_W/2 - 60 - i*10, 16, 8, 8, dc_rgb(80,160,255));
|
|
36
|
+
for (i = 0; i < s1 && i < 9; i++) dc_rect(DC_W/2 + 56 + i*10, 16, 8, 8, dc_rgb(255,160,80));
|
|
37
|
+
frame++; (void)frame;
|
|
38
|
+
}
|
|
39
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "romdevtools",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Tool server giving coding agents full control of homebrew ROM development AND reverse-engineering/romhacking across
|
|
3
|
+
"version": "0.71.0",
|
|
4
|
+
"description": "Tool server giving coding agents full control of homebrew ROM development AND reverse-engineering/romhacking across 17 retro platforms (NES, SNES, GB, Genesis, Atari, C64, PC Engine, MSX, PlayStation, N64, Dreamcast, ...) via WASM toolchains + emulator cores. Use over plain HTTP, as an Agent Skill, or as an MCP server.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/mcp/server.js",
|
|
7
7
|
"bin": {
|
|
@@ -58,8 +58,9 @@
|
|
|
58
58
|
"romdev-core-geargrafx": "0.7.0",
|
|
59
59
|
"romdev-core-gpgx": "0.12.0",
|
|
60
60
|
"romdev-core-handy": "0.7.0",
|
|
61
|
+
"romdev-core-flycast": "0.1.1",
|
|
61
62
|
"romdev-core-parallel-n64": "0.1.0",
|
|
62
|
-
"romdev-core-
|
|
63
|
+
"romdev-core-beetle-psx-hw": "0.1.1",
|
|
63
64
|
"romdev-core-prosystem": "0.8.0",
|
|
64
65
|
"romdev-core-vice": "0.9.0",
|
|
65
66
|
"romdev-famitone": "0.1.0",
|
|
@@ -72,6 +73,7 @@
|
|
|
72
73
|
"romdev-toolchain-mips-gcc": "0.1.0",
|
|
73
74
|
"romdev-toolchain-rgbds": "0.1.0",
|
|
74
75
|
"romdev-toolchain-sdcc": "0.2.0",
|
|
76
|
+
"romdev-toolchain-sh-gcc": "0.1.0",
|
|
75
77
|
"romdev-toolchain-vasm": "0.1.0",
|
|
76
78
|
"romdev-xgm2": "0.1.0",
|
|
77
79
|
"romdev_game_codes": "0.1.0",
|