romdevtools 0.71.1 → 0.84.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/AGENTS.md +19 -16
- package/CHANGELOG.md +175 -0
- package/README.md +5 -5
- package/examples/README.md +1 -0
- package/examples/gametank/templates/gt_draw.h +91 -0
- package/examples/gametank/templates/gt_hud.h +89 -0
- package/examples/gametank/templates/gt_palette.h +59 -0
- package/examples/gametank/templates/gt_sound.h +90 -0
- package/examples/gametank/templates/gt_sprites.h +53 -0
- package/examples/gametank/templates/platformer.c +318 -0
- package/examples/gametank/templates/puzzle.c +295 -0
- package/examples/gametank/templates/racing.c +139 -0
- package/examples/gametank/templates/shmup.c +277 -0
- package/examples/gametank/templates/sports.c +119 -0
- package/package.json +23 -22
- package/src/cores/capabilities.js +24 -0
- package/src/cores/registry.js +7 -1
- package/src/host/LibretroHost.js +90 -17
- package/src/host/callbacks.js +20 -2
- package/src/host/cpu-state.js +17 -0
- package/src/host/gametank-acp-state.js +53 -0
- package/src/http/skill-doc.js +10 -6
- package/src/mcp/tools/audio.js +1 -1
- package/src/mcp/tools/cart-parts.js +76 -0
- package/src/mcp/tools/lifecycle.js +1 -1
- package/src/mcp/tools/platform-tools.js +9 -1
- package/src/platforms/gametank/lib/gt/audio/acp_image.bin +0 -0
- package/src/platforms/gametank/lib/gt/audio/audio_coprocessor.c +55 -0
- package/src/platforms/gametank/lib/gt/audio/audio_coprocessor.h +34 -0
- package/src/platforms/gametank/lib/gt/audio/audio_fw.asm +223 -0
- package/src/platforms/gametank/lib/gt/audio/audio_fw_blob.s +8 -0
- package/src/platforms/gametank/lib/gt/audio/instruments.c +79 -0
- package/src/platforms/gametank/lib/gt/audio/instruments.h +25 -0
- package/src/platforms/gametank/lib/gt/audio/music.c +370 -0
- package/src/platforms/gametank/lib/gt/audio/music.h +35 -0
- package/src/platforms/gametank/lib/gt/audio/note_numbers.h +132 -0
- package/src/platforms/gametank/lib/gt/audio/scaled_sines.raw +0 -0
- package/src/platforms/gametank/lib/gt/audio/sine_256_-63_63.bin +0 -0
- package/src/platforms/gametank/lib/gt/banking.c +29 -0
- package/src/platforms/gametank/lib/gt/banking.h +8 -0
- package/src/platforms/gametank/lib/gt/banking2.s +41 -0
- package/src/platforms/gametank/lib/gt/crt0.s +102 -0
- package/src/platforms/gametank/lib/gt/draw_logo.s +55 -0
- package/src/platforms/gametank/lib/gt/feature/persist/persist.c +103 -0
- package/src/platforms/gametank/lib/gt/feature/persist/persist.h +13 -0
- package/src/platforms/gametank/lib/gt/feature/random/random.c +40 -0
- package/src/platforms/gametank/lib/gt/feature/random/random.h +18 -0
- package/src/platforms/gametank/lib/gt/feature/text/text.c +111 -0
- package/src/platforms/gametank/lib/gt/feature/text/text.h +25 -0
- package/src/platforms/gametank/lib/gt/gametank.c +12 -0
- package/src/platforms/gametank/lib/gt/gametank.h +80 -0
- package/src/platforms/gametank/lib/gt/gametank_logo.inc +393 -0
- package/src/platforms/gametank/lib/gt/gen/assets/assets_index.h +9 -0
- package/src/platforms/gametank/lib/gt/gen/assets/sdk_default.h +5 -0
- package/src/platforms/gametank/lib/gt/gen/bank_nums.h +11 -0
- package/src/platforms/gametank/lib/gt/gen/modules_enabled.h +4 -0
- package/src/platforms/gametank/lib/gt/gen/modules_enabled.inc +4 -0
- package/src/platforms/gametank/lib/gt/gfx/draw_direct.c +132 -0
- package/src/platforms/gametank/lib/gt/gfx/draw_direct.h +75 -0
- package/src/platforms/gametank/lib/gt/gfx/draw_queue.c +177 -0
- package/src/platforms/gametank/lib/gt/gfx/draw_queue.h +35 -0
- package/src/platforms/gametank/lib/gt/gfx/draw_util.s +157 -0
- package/src/platforms/gametank/lib/gt/gfx/gfx_sys.c +43 -0
- package/src/platforms/gametank/lib/gt/gfx/gfx_sys.h +46 -0
- package/src/platforms/gametank/lib/gt/gfx/sprites.c +216 -0
- package/src/platforms/gametank/lib/gt/gfx/sprites.h +41 -0
- package/src/platforms/gametank/lib/gt/init.c +9 -0
- package/src/platforms/gametank/lib/gt/input.c +26 -0
- package/src/platforms/gametank/lib/gt/input.h +20 -0
- package/src/platforms/gametank/lib/gt/interrupt.s +67 -0
- package/src/platforms/gametank/lib/gt/vectors.s +14 -0
- package/src/platforms/gametank/lib/gt/wait.s +53 -0
- package/src/playtest/playtest.js +174 -26
- package/src/playtest/resampler/build.sh +19 -0
- package/src/playtest/resampler/index.mjs +75 -0
- package/src/playtest/resampler/resampler.c +129 -0
- package/src/playtest/resampler/resampler.mjs +2 -0
- package/src/playtest/resampler/resampler.wasm +0 -0
- package/src/toolchains/arm-none-eabi-gcc/gcc.js +39 -188
- package/src/toolchains/asar/asar.js +10 -15
- package/src/toolchains/cc65/cc65.js +82 -92
- package/src/toolchains/cc65/da65.js +12 -17
- package/src/toolchains/cc65/preset-resolver.js +13 -2
- package/src/toolchains/cc65/presets/gametank/gametank.h +80 -0
- package/src/toolchains/cc65/presets/gametank/sdk.cfg +32 -0
- package/src/toolchains/cc65/presets/gametank/sdk.crt0.s +61 -0
- package/src/toolchains/cc65/presets/gametank/sdk.vectors.s +11 -0
- package/src/toolchains/cc65/presets/gametank/single-bank.cfg +28 -0
- package/src/toolchains/cc65/presets/gametank/single-bank.crt0.s +71 -0
- package/src/toolchains/cc65/presets/gametank/single-bank.vectors.s +12 -0
- package/src/toolchains/common/c-build.js +109 -0
- package/src/toolchains/common/gcc-toolchain.js +164 -0
- package/src/toolchains/common/wasm-tool.js +101 -0
- package/src/toolchains/dasm/dasm.js +12 -18
- package/src/toolchains/gba-c/gba-c.js +253 -305
- package/src/toolchains/genesis-c/genesis-c.js +196 -225
- package/src/toolchains/index.js +58 -4
- package/src/toolchains/m68k-elf-gcc/gcc.js +39 -202
- package/src/toolchains/mips-c/mips-c.js +68 -78
- package/src/toolchains/mips-elf-gcc/gcc.js +55 -118
- package/src/toolchains/rgbds/rgbds.js +7 -19
- package/src/toolchains/sdcc/sdcc.js +35 -26
- package/src/toolchains/sh-c/sh-c.js +44 -52
- package/src/toolchains/sh-elf-gcc/gcc.js +55 -110
- package/src/toolchains/sjasm/sjasm.js +10 -14
- package/src/toolchains/snes-c/snes-c.js +125 -150
- package/src/toolchains/tcc816/tcc816.js +10 -15
- package/src/toolchains/vasm68k/vasm68k.js +11 -16
- package/src/toolchains/wladx/wladx.js +5 -17
- package/src/toolchains/z80/binutils.js +5 -11
|
@@ -24,6 +24,7 @@ import { readFile } from "node:fs/promises";
|
|
|
24
24
|
|
|
25
25
|
import { runTcc816 } from "../tcc816/tcc816.js";
|
|
26
26
|
import { runWla65816, runWlalink } from "../wladx/wladx.js";
|
|
27
|
+
import { CBuild, BuildError } from "../common/c-build.js";
|
|
27
28
|
|
|
28
29
|
const __filename = fileURLToPath(import.meta.url);
|
|
29
30
|
const __dirname = path.dirname(__filename);
|
|
@@ -171,7 +172,7 @@ function normalizeSnesSources(args) {
|
|
|
171
172
|
* substitution fires. (We do that in wla-65816.js unconditionally.)
|
|
172
173
|
*/
|
|
173
174
|
async function buildWithPvSnesLib({ sources, headers, tccOptions, wlaOptions, binaryIncludes = {} }) {
|
|
174
|
-
|
|
175
|
+
const cb = new CBuild();
|
|
175
176
|
const pvsnesHeaders = await loadPvSnesLibHeaders();
|
|
176
177
|
const pvsnesHdr = await readFile(path.join(PVSNESLIB_DIR, "include", "hdr.asm"), "utf-8");
|
|
177
178
|
// wla can `.include "<sibling>.asm"` from same dir, so all sources need
|
|
@@ -186,102 +187,91 @@ async function buildWithPvSnesLib({ sources, headers, tccOptions, wlaOptions, bi
|
|
|
186
187
|
// map. tcc only looks in /work (we use `-I /work`) so a flat namespace works.
|
|
187
188
|
const tccHeaders = { ...pvsnesHeaders, ...headers };
|
|
188
189
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
190
|
+
try {
|
|
191
|
+
/** @type {Record<string, Uint8Array>} */
|
|
192
|
+
const userObjs = {};
|
|
193
|
+
// ── Stage 1: build each .c via tcc → .asm → .obj ────────────────
|
|
194
|
+
const cFiles = Object.keys(sources).filter((n) => /\.c$/i.test(n));
|
|
195
|
+
for (const cName of cFiles) {
|
|
196
|
+
const tcc = await cb.stage(`tcc-65816 (${cName})`, () => runTcc816({
|
|
197
|
+
source: sources[cName],
|
|
198
|
+
headers: tccHeaders,
|
|
199
|
+
options: tccOptions,
|
|
200
|
+
}), (r) => r.asmSource);
|
|
201
|
+
// KEEP tcc's `.include "hdr.asm"` — wla resolves it via the includes
|
|
202
|
+
// map below. (We strip it from library .obj builds where libc.asm
|
|
203
|
+
// already includes hdr.asm; user code includes hdr.asm directly.)
|
|
204
|
+
const wla = await cb.stage(`wla-65816 (${cName})`, () => runWla65816({
|
|
205
|
+
source: tcc.asmSource,
|
|
206
|
+
includes: { "hdr.asm": pvsnesHdr, ...asmSiblings },
|
|
207
|
+
options: wlaOptions,
|
|
208
|
+
}), (r) => r.object, { logName: `wla-65816 (${cName} → .obj)` });
|
|
209
|
+
const objName = cName.replace(/\.c$/i, ".obj");
|
|
210
|
+
userObjs[objName] = wla.object;
|
|
202
211
|
}
|
|
203
|
-
|
|
204
|
-
//
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
212
|
+
|
|
213
|
+
// ── Stage 2: assemble each user .asm / .s sibling directly ──────
|
|
214
|
+
for (const asmName of Object.keys(asmSiblings)) {
|
|
215
|
+
const wla = await cb.stage(`wla-65816 (${asmName})`, () => runWla65816({
|
|
216
|
+
source: asmSiblings[asmName],
|
|
217
|
+
includes: { "hdr.asm": pvsnesHdr, ...asmSiblings },
|
|
218
|
+
binaryIncludes,
|
|
219
|
+
options: wlaOptions,
|
|
220
|
+
}), (r) => r.object, { logName: `wla-65816 (${asmName} → .obj)` });
|
|
221
|
+
const objName = asmName.replace(/\.(asm|s)$/i, ".obj");
|
|
222
|
+
userObjs[objName] = wla.object;
|
|
214
223
|
}
|
|
215
|
-
const objName = cName.replace(/\.c$/i, ".obj");
|
|
216
|
-
userObjs[objName] = wla.object;
|
|
217
|
-
}
|
|
218
224
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
includes: { "hdr.asm": pvsnesHdr, ...asmSiblings },
|
|
224
|
-
binaryIncludes,
|
|
225
|
-
options: wlaOptions,
|
|
226
|
-
});
|
|
227
|
-
log += `--- wla-65816 (${asmName} → .obj) ---\n` + (wla.log || "(ok)") + "\n";
|
|
228
|
-
if (wla.exitCode !== 0 || !wla.object) {
|
|
229
|
-
return { ok: false, binary: null, log, exitCode: wla.exitCode || 1, stage: `wla-65816 (${asmName})`, ...(wla.crash ? { crash: wla.crash } : {}) };
|
|
225
|
+
// ── Stage 3: assemble PVSnesLib runtime FROM SOURCE, then link ──
|
|
226
|
+
const pvObjs = await assemblePvSnesLibObjs();
|
|
227
|
+
if (!pvObjs.ok) {
|
|
228
|
+
return { ok: false, binary: null, log: cb.log + (pvObjs.log || ""), exitCode: 1, stage: `pvsneslib runtime: ${pvObjs.stage}`, runtime: "pvsneslib" };
|
|
230
229
|
}
|
|
231
|
-
const
|
|
232
|
-
|
|
233
|
-
|
|
230
|
+
const crt0Obj = pvObjs.objs["crt0_snes.obj"];
|
|
231
|
+
const libmObj = pvObjs.objs["libm.obj"];
|
|
232
|
+
const libtccObj = pvObjs.objs["libtcc.obj"];
|
|
233
|
+
const libcObj = pvObjs.objs["libc.obj"];
|
|
234
234
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
235
|
+
// PVSnesLib's linkfile convention puts crt0 first (reset-vector tie-break),
|
|
236
|
+
// then libm/libtcc/libc, then user code. wlalink's order matters for which
|
|
237
|
+
// section "wins" when sections collide.
|
|
238
|
+
const userObjLines = Object.keys(userObjs).map((n) => `/work/${n}`).join("\n");
|
|
239
|
+
const linkfile =
|
|
240
|
+
"[objects]\n" +
|
|
241
|
+
"/work/crt0_snes.obj\n" +
|
|
242
|
+
"/work/libm.obj\n" +
|
|
243
|
+
"/work/libtcc.obj\n" +
|
|
244
|
+
"/work/libc.obj\n" +
|
|
245
|
+
userObjLines + "\n";
|
|
244
246
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
247
|
+
const link = await cb.stage("wlalink", () => runWlalink({
|
|
248
|
+
objects: {
|
|
249
|
+
"crt0_snes.obj": crt0Obj,
|
|
250
|
+
"libm.obj": libmObj,
|
|
251
|
+
"libtcc.obj": libtccObj,
|
|
252
|
+
"libc.obj": libcObj,
|
|
253
|
+
...userObjs,
|
|
254
|
+
},
|
|
255
|
+
linkfile,
|
|
256
|
+
// -d: disable label-arith opts (PVSnesLib's library .obj files were
|
|
257
|
+
// built with -d so user link must match). -A: cart-size check.
|
|
258
|
+
// -c: allow duplicate labels (PVSnesLib's libc has known dupes between
|
|
259
|
+
// consoles/input regs that they ship with -c). -b: program output.
|
|
260
|
+
options: ["-d", "-A", "-c", "-b"],
|
|
261
|
+
}), (r) => r.binary);
|
|
256
262
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
"
|
|
263
|
-
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
// -c: allow duplicate labels (PVSnesLib's libc has known dupes between
|
|
269
|
-
// consoles/input regs that they ship with -c). -b: program output.
|
|
270
|
-
options: ["-d", "-A", "-c", "-b"],
|
|
271
|
-
});
|
|
272
|
-
log += "--- wlalink ---\n" + (link.log || "(ok)") + "\n";
|
|
273
|
-
if (link.exitCode !== 0 || !link.binary) {
|
|
274
|
-
return { ok: false, binary: null, log, exitCode: link.exitCode || 1, stage: "wlalink", ...(link.crash ? { crash: link.crash } : {}) };
|
|
263
|
+
return {
|
|
264
|
+
ok: true,
|
|
265
|
+
binary: link.binary,
|
|
266
|
+
log: cb.log,
|
|
267
|
+
exitCode: 0,
|
|
268
|
+
stage: "done",
|
|
269
|
+
runtime: "pvsneslib",
|
|
270
|
+
};
|
|
271
|
+
} catch (e) {
|
|
272
|
+
if (e instanceof BuildError) return e.toResult();
|
|
273
|
+
throw e;
|
|
275
274
|
}
|
|
276
|
-
|
|
277
|
-
return {
|
|
278
|
-
ok: true,
|
|
279
|
-
binary: link.binary,
|
|
280
|
-
log,
|
|
281
|
-
exitCode: 0,
|
|
282
|
-
stage: "done",
|
|
283
|
-
runtime: "pvsneslib",
|
|
284
|
-
};
|
|
285
275
|
}
|
|
286
276
|
|
|
287
277
|
/**
|
|
@@ -289,7 +279,7 @@ async function buildWithPvSnesLib({ sources, headers, tccOptions, wlaOptions, bi
|
|
|
289
279
|
* bundled original crt0.asm + hdr.asm support a bare `int main()`.
|
|
290
280
|
*/
|
|
291
281
|
async function buildMinimal({ sources, headers, tccOptions, wlaOptions, _binaryIncludes = {} }) {
|
|
292
|
-
|
|
282
|
+
const cb = new CBuild();
|
|
293
283
|
const hdrAsm = await readFile(path.join(MINIMAL_LIB_DIR, "hdr.asm"), "utf-8");
|
|
294
284
|
const crt0Asm = await readFile(path.join(MINIMAL_LIB_DIR, "crt0.asm"), "utf-8");
|
|
295
285
|
|
|
@@ -300,73 +290,58 @@ async function buildMinimal({ sources, headers, tccOptions, wlaOptions, _binaryI
|
|
|
300
290
|
if (/\.(asm|s)$/i.test(name)) asmSiblings[name] = contents;
|
|
301
291
|
}
|
|
302
292
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
293
|
+
try {
|
|
294
|
+
/** @type {Record<string, Uint8Array>} */
|
|
295
|
+
const userObjs = {};
|
|
296
|
+
const cFiles = Object.keys(sources).filter((n) => /\.c$/i.test(n));
|
|
297
|
+
for (const cName of cFiles) {
|
|
298
|
+
const tcc = await cb.stage(`tcc-65816 (${cName})`, () => runTcc816({ source: sources[cName], headers, options: tccOptions }), (r) => r.asmSource);
|
|
299
|
+
const wla = await cb.stage(`wla-65816 (${cName})`, () => runWla65816({
|
|
300
|
+
source: tcc.asmSource,
|
|
301
|
+
includes: { "hdr.asm": hdrAsm, ...asmSiblings },
|
|
302
|
+
options: wlaOptions,
|
|
303
|
+
}), (r) => r.object, { logName: `wla-65816 (${cName} → .obj)` });
|
|
304
|
+
const objName = cName.replace(/\.c$/i, ".o");
|
|
305
|
+
userObjs[objName] = wla.object;
|
|
311
306
|
}
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
307
|
+
|
|
308
|
+
for (const asmName of Object.keys(asmSiblings)) {
|
|
309
|
+
const wla = await cb.stage(`wla-65816 (${asmName})`, () => runWla65816({
|
|
310
|
+
source: asmSiblings[asmName],
|
|
311
|
+
includes: { "hdr.asm": hdrAsm, ...asmSiblings },
|
|
312
|
+
options: wlaOptions,
|
|
313
|
+
}), (r) => r.object, { logName: `wla-65816 (${asmName} → .obj)` });
|
|
314
|
+
const objName = asmName.replace(/\.(asm|s)$/i, ".o");
|
|
315
|
+
userObjs[objName] = wla.object;
|
|
320
316
|
}
|
|
321
|
-
const objName = cName.replace(/\.c$/i, ".o");
|
|
322
|
-
userObjs[objName] = wla.object;
|
|
323
|
-
}
|
|
324
317
|
|
|
325
|
-
|
|
326
|
-
const
|
|
327
|
-
source:
|
|
328
|
-
includes: { "hdr.asm": hdrAsm
|
|
318
|
+
// crt0 from our minimum-viable runtime.
|
|
319
|
+
const wlaCrt0 = await cb.stage("wla-65816 (crt0)", () => runWla65816({
|
|
320
|
+
source: crt0Asm,
|
|
321
|
+
includes: { "hdr.asm": hdrAsm },
|
|
329
322
|
options: wlaOptions,
|
|
330
|
-
});
|
|
331
|
-
log += `--- wla-65816 (${asmName} → .obj) ---\n` + (wla.log || "(ok)") + "\n";
|
|
332
|
-
if (wla.exitCode !== 0 || !wla.object) {
|
|
333
|
-
return { ok: false, binary: null, log, exitCode: wla.exitCode || 1, stage: `wla-65816 (${asmName})`, ...(wla.crash ? { crash: wla.crash } : {}) };
|
|
334
|
-
}
|
|
335
|
-
const objName = asmName.replace(/\.(asm|s)$/i, ".o");
|
|
336
|
-
userObjs[objName] = wla.object;
|
|
337
|
-
}
|
|
323
|
+
}), (r) => r.object, { logName: "wla-65816 (crt0.asm)" });
|
|
338
324
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
if (wlaCrt0.exitCode !== 0 || !wlaCrt0.object) {
|
|
347
|
-
return { ok: false, binary: null, log, exitCode: wlaCrt0.exitCode || 1, stage: "wla-65816 (crt0)", ...(wlaCrt0.crash ? { crash: wlaCrt0.crash } : {}) };
|
|
348
|
-
}
|
|
325
|
+
const userObjLines = Object.keys(userObjs).map((n) => `/work/${n}`).join("\n");
|
|
326
|
+
const linkfile = "[objects]\n/work/crt0.o\n" + userObjLines + "\n";
|
|
327
|
+
const link = await cb.stage("wlalink", () => runWlalink({
|
|
328
|
+
objects: { "crt0.o": wlaCrt0.object, ...userObjs },
|
|
329
|
+
linkfile,
|
|
330
|
+
options: ["-d", "-b"],
|
|
331
|
+
}), (r) => r.binary);
|
|
349
332
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
333
|
+
return {
|
|
334
|
+
ok: true,
|
|
335
|
+
binary: link.binary,
|
|
336
|
+
log: cb.log,
|
|
337
|
+
exitCode: 0,
|
|
338
|
+
stage: "done",
|
|
339
|
+
runtime: "minimal",
|
|
340
|
+
};
|
|
341
|
+
} catch (e) {
|
|
342
|
+
if (e instanceof BuildError) return e.toResult();
|
|
343
|
+
throw e;
|
|
360
344
|
}
|
|
361
|
-
|
|
362
|
-
return {
|
|
363
|
-
ok: true,
|
|
364
|
-
binary: link.binary,
|
|
365
|
-
log,
|
|
366
|
-
exitCode: 0,
|
|
367
|
-
stage: "done",
|
|
368
|
-
runtime: "minimal",
|
|
369
|
-
};
|
|
370
345
|
}
|
|
371
346
|
|
|
372
347
|
/**
|
|
@@ -11,30 +11,25 @@
|
|
|
11
11
|
// NOT wired into buildSource yet.
|
|
12
12
|
|
|
13
13
|
import { fileURLToPath } from "node:url";
|
|
14
|
-
import { existsSync } from "node:fs";
|
|
15
14
|
import path from "node:path";
|
|
16
15
|
|
|
17
16
|
import { runIsolated, textFile, getOutputText } from "../_worker/run.js";
|
|
17
|
+
import { resolveGlueFile } from "../common/wasm-tool.js";
|
|
18
18
|
|
|
19
19
|
const __filename = fileURLToPath(import.meta.url);
|
|
20
20
|
const __dirname = path.dirname(__filename);
|
|
21
21
|
|
|
22
22
|
// tcc816's WASM ships in romdev-platform-snes (the SNES platform is the only
|
|
23
|
-
// consumer)
|
|
24
|
-
//
|
|
25
|
-
function resolveTcc816Glue() {
|
|
26
|
-
try {
|
|
27
|
-
const u = import.meta.resolve("romdev-platform-snes");
|
|
28
|
-
const p = path.join(path.dirname(fileURLToPath(u)), "wasm", "tcc816.js");
|
|
29
|
-
if (existsSync(p)) return p;
|
|
30
|
-
} catch { /* package not resolvable — fall through to local */ }
|
|
31
|
-
const local = path.join(__dirname, "wasm", "tcc816.js");
|
|
32
|
-
if (existsSync(local)) return local;
|
|
33
|
-
throw new Error("tcc816 WASM not found — install romdev-platform-snes");
|
|
34
|
-
}
|
|
35
|
-
// Lazy + memoized: resolve only on the first tcc816 (SNES C) build, not at boot.
|
|
23
|
+
// consumer); a local src/ copy is the dev fallback. Lazy + memoized: resolve
|
|
24
|
+
// only on the first tcc816 (SNES C) build, not at boot.
|
|
36
25
|
let _gluePath;
|
|
37
|
-
const gluePath = () =>
|
|
26
|
+
const gluePath = () =>
|
|
27
|
+
(_gluePath ??= resolveGlueFile({
|
|
28
|
+
pkg: "romdev-platform-snes",
|
|
29
|
+
file: "tcc816.js",
|
|
30
|
+
localDir: __dirname,
|
|
31
|
+
label: "tcc816",
|
|
32
|
+
}));
|
|
38
33
|
|
|
39
34
|
/**
|
|
40
35
|
* Compile a C source to 65816 assembly via tcc-65816.
|
|
@@ -1,30 +1,25 @@
|
|
|
1
1
|
// vasm68k_mot — bundled m68k assembler with Motorola syntax (Genesis dev).
|
|
2
2
|
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
|
-
import { existsSync } from "node:fs";
|
|
5
4
|
import path from "node:path";
|
|
6
5
|
|
|
7
6
|
import { runIsolated, textFile, binaryFile, getOutputBytes } from "../_worker/run.js";
|
|
7
|
+
import { resolveGlueFile } from "../common/wasm-tool.js";
|
|
8
8
|
|
|
9
9
|
const __filename = fileURLToPath(import.meta.url);
|
|
10
10
|
const __dirname = path.dirname(__filename);
|
|
11
11
|
|
|
12
|
-
// vasm68k's WASM ships in romdev-toolchain-vasm
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
function resolveVasm68kGlue() {
|
|
16
|
-
try {
|
|
17
|
-
const u = import.meta.resolve("romdev-toolchain-vasm");
|
|
18
|
-
const p = path.join(path.dirname(fileURLToPath(u)), "wasm", "vasm68k.js");
|
|
19
|
-
if (existsSync(p)) return p;
|
|
20
|
-
} catch { /* package not resolvable — fall through to local */ }
|
|
21
|
-
const local = path.join(__dirname, "wasm", "vasm68k.js");
|
|
22
|
-
if (existsSync(local)) return local;
|
|
23
|
-
throw new Error("vasm68k WASM not found — install romdev-toolchain-vasm");
|
|
24
|
-
}
|
|
25
|
-
// Lazy + memoized: resolve only on the first vasm (Genesis asm) build, not at boot.
|
|
12
|
+
// vasm68k's WASM ships in romdev-toolchain-vasm; a local src/ copy is the dev
|
|
13
|
+
// fallback. Lazy + memoized: resolve only on the first vasm (Genesis asm)
|
|
14
|
+
// build, not at boot.
|
|
26
15
|
let _gluePath;
|
|
27
|
-
const gluePath = () =>
|
|
16
|
+
const gluePath = () =>
|
|
17
|
+
(_gluePath ??= resolveGlueFile({
|
|
18
|
+
pkg: "romdev-toolchain-vasm",
|
|
19
|
+
file: "vasm68k.js",
|
|
20
|
+
localDir: __dirname,
|
|
21
|
+
label: "vasm68k",
|
|
22
|
+
}));
|
|
28
23
|
|
|
29
24
|
/**
|
|
30
25
|
* Static analyzer for known Genesis landmines. Mirrors asar preflight
|
|
@@ -12,31 +12,19 @@
|
|
|
12
12
|
// See `src/toolchains/index.js` SNES dispatch.
|
|
13
13
|
|
|
14
14
|
import { fileURLToPath } from "node:url";
|
|
15
|
-
import { existsSync } from "node:fs";
|
|
16
15
|
import path from "node:path";
|
|
17
16
|
|
|
18
17
|
import { runIsolated, textFile, binaryFile, getOutputBytes } from "../_worker/run.js";
|
|
18
|
+
import { makeGlueResolver } from "../common/wasm-tool.js";
|
|
19
19
|
|
|
20
20
|
const __filename = fileURLToPath(import.meta.url);
|
|
21
21
|
const __dirname = path.dirname(__filename);
|
|
22
22
|
|
|
23
23
|
// wla-dx's WASM ships in romdev-platform-snes (the SNES platform is the only
|
|
24
|
-
// consumer)
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const u = import.meta.resolve("romdev-platform-snes");
|
|
29
|
-
const p = path.join(path.dirname(fileURLToPath(u)), "wasm", file);
|
|
30
|
-
if (existsSync(p)) return p;
|
|
31
|
-
} catch { /* package not resolvable — fall through to local */ }
|
|
32
|
-
const local = path.join(__dirname, "wasm", file);
|
|
33
|
-
if (existsSync(local)) return local;
|
|
34
|
-
throw new Error(`wla-dx WASM (${file}) not found — install romdev-platform-snes`);
|
|
35
|
-
}
|
|
36
|
-
// Lazy + memoized per tool: resolve only on the first wla-dx (SNES asm) build
|
|
37
|
-
// that uses each tool, not at module load.
|
|
38
|
-
const _glue = {};
|
|
39
|
-
const wladxGlue = (file) => (_glue[file] ??= resolveWladxGlue(file));
|
|
24
|
+
// consumer); a local src/ copy is the dev fallback. Lazy + memoized per tool:
|
|
25
|
+
// resolve only on the first wla-dx (SNES asm) build that uses each tool, not at
|
|
26
|
+
// module load.
|
|
27
|
+
const wladxGlue = makeGlueResolver({ pkg: "romdev-platform-snes", localDir: __dirname, label: "wla-dx" });
|
|
40
28
|
|
|
41
29
|
/**
|
|
42
30
|
* Assemble a single .asm source with wla-65816.
|
|
@@ -5,22 +5,16 @@
|
|
|
5
5
|
// romdev-toolchain-sdcc alongside sdas/sdcc.
|
|
6
6
|
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
|
-
import { existsSync } from "node:fs";
|
|
9
8
|
import path from "node:path";
|
|
10
9
|
import { runIsolated, textFile, binaryFile, getOutputBytes } from "../_worker/run.js";
|
|
10
|
+
import { makeGlueResolver } from "../common/wasm-tool.js";
|
|
11
11
|
|
|
12
12
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
if (existsSync(p)) return p;
|
|
19
|
-
} catch { /* fall through to local */ }
|
|
20
|
-
const local = path.join(__dirname, "wasm", file);
|
|
21
|
-
if (existsSync(local)) return local;
|
|
22
|
-
throw new Error(`z80 binutils WASM (${file}) not found — install romdev-toolchain-sdcc`);
|
|
23
|
-
}
|
|
14
|
+
// z80-elf binutils ship in romdev-toolchain-sdcc (alongside sdas/sdcc); a local
|
|
15
|
+
// src/ copy is the dev fallback. Lazy + memoized: resolve each glue only on its
|
|
16
|
+
// first use, not at boot.
|
|
17
|
+
const z80Glue = makeGlueResolver({ pkg: "romdev-toolchain-sdcc", localDir: __dirname, label: "sdas" });
|
|
24
18
|
|
|
25
19
|
/** True if the z80 GNU assembler chain is available. */
|
|
26
20
|
export function z80GnuAvailable() {
|