1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2026-03-10 21:25:31 +00:00

cli: added --symbols, --save flags

gb: use codeseg_start parameter
This commit is contained in:
Steven Hugg
2026-03-07 11:30:12 +01:00
parent 43303a3a06
commit f50aa23d24
5 changed files with 93 additions and 33 deletions

View File

@@ -1,7 +1,7 @@
import { SM83, SM83State } from "../common/cpu/SM83";
import { BasicScanlineMachine, Bus } from "../common/devices";
import { newAddressDecoder, padBytes, Keys, makeKeycodeMap, newKeyboardHandler } from "../common/emu";
import { newAddressDecoder, padBytes, Keys, makeKeycodeMap, newKeyboardHandler, EmuHalt } from "../common/emu";
import { hex } from "../common/util";
// Game Boy DMG palette: 4 shades of green (darkest to lightest)
@@ -1246,9 +1246,9 @@ export class GameBoyMachine extends BasicScanlineMachine {
switch (cartType) {
case 0x00: this.mbcType = 0; break; // ROM only
case 0x01: case 0x02: case 0x03: this.mbcType = 1; break; // MBC1
default: this.mbcType = 1; break; // Default to MBC1 for other types
default: console.log(`Invalid cartridge type @ 0x147: ${data[0x147]}`); break;
}
}
} else throw new EmuHalt("ROM not long enough for header");
// Determine ROM size and bank mask
this.rom = new Uint8Array(Math.max(data.length, 0x8000));
@@ -1257,15 +1257,14 @@ export class GameBoyMachine extends BasicScanlineMachine {
this.romBankMask = numBanks - 1;
// Determine RAM size from header
if (data.length > 0x149) {
switch (data[0x149]) {
case 0x00: break; // No RAM
case 0x01: this.extram = new Uint8Array(0x800); break; // 2KB
case 0x02: this.extram = new Uint8Array(0x2000); break; // 8KB
case 0x03: this.extram = new Uint8Array(0x8000); break; // 32KB
case 0x04: this.extram = new Uint8Array(0x20000); break; // 128KB
case 0x05: this.extram = new Uint8Array(0x10000); break; // 64KB
}
switch (data[0x149]) {
case 0x00: break; // No RAM
case 0x01: this.extram = new Uint8Array(0x800); break; // 2KB
case 0x02: this.extram = new Uint8Array(0x2000); break; // 8KB
case 0x03: this.extram = new Uint8Array(0x8000); break; // 32KB
case 0x04: this.extram = new Uint8Array(0x20000); break; // 128KB
case 0x05: this.extram = new Uint8Array(0x10000); break; // 64KB
default: console.log(`Invalid RAM size code @ 0x149: ${data[0x149]}`); break;
}
this.reset();

View File

@@ -3,7 +3,8 @@
// 8bws - 8bitworkshop CLI tool for compilation, ROM execution, and platform info
import * as fs from 'fs';
import { initialize, compile, compileSourceFile, preload, listTools, listPlatforms, getToolForFilename, PLATFORM_PARAMS, TOOLS, TOOL_PRELOADFS } from './testlib';
import * as path from 'path';
import { initialize, compile, compileSourceFile, preload, listTools, listPlatforms, getToolForFilename, PLATFORM_PARAMS, TOOLS, TOOL_PRELOADFS, store } from './testlib';
import { isDebuggable } from '../common/baseplatform';
import { hex } from '../common/util';
@@ -91,7 +92,8 @@ function formatHelp(data: any): void {
console.log(` ${c.green}${cmd}${c.reset}${c.dim} - ${usage}${c.reset}`);
}
console.log(`\n${c.bold}Global options:${c.reset}`);
console.log(` ${c.yellow}--json${c.reset}${c.dim} Output raw JSON instead of formatted text${c.reset}`);
console.log(` ${c.yellow}--json${c.reset}${c.dim} Output raw JSON instead of formatted text${c.reset}`);
console.log(` ${c.yellow}--save${c.reset}${c.dim} Save all intermediate build files to /tmp/8bws-<name>${c.reset}`);
console.log();
}
}
@@ -114,6 +116,31 @@ function formatCompile(data: any): void {
if (data.outputFile) console.log(` ${c.dim}Output:${c.reset} ${c.cyan}${data.outputFile}${c.reset}`);
if (data.hasListings) console.log(` ${c.dim}Listings:${c.reset} ${c.green}yes${c.reset}`);
if (data.hasSymbolmap) console.log(` ${c.dim}Symbols:${c.reset} ${c.green}yes${c.reset}`);
// --symbols: dump symbol map
if (data.symbolmap) {
console.log(`\n${c.bold}Symbols${c.reset} ${c.dim}(${Object.keys(data.symbolmap).length})${c.reset}`);
var sorted = Object.entries(data.symbolmap).sort((a: any, b: any) => a[1] - b[1]);
for (var [name, addr] of sorted) {
console.log(` ${c.cyan}$${hex(addr as number, 4)}${c.reset} ${name}`);
}
}
// --save: show saved files
if (data.saveDir) {
console.log(`\n${c.bold}Saved to${c.reset} ${c.cyan}${data.saveDir}${c.reset} ${c.dim}(${data.savedFiles.length} files)${c.reset}`);
for (var f of data.savedFiles) {
console.log(` ${c.dim}${c.reset} ${f}`);
}
}
// --symbols: dump segments
if (data.segments) {
console.log(`\n${c.bold}Segments${c.reset} ${c.dim}(${data.segments.length})${c.reset}`);
for (var seg of data.segments) {
console.log(` ${c.green}${seg.name.padEnd(16)}${c.reset} ${c.cyan}$${hex(seg.start, 4)}${c.reset} ${c.dim}size${c.reset} ${c.yellow}${seg.size}${c.reset}`);
}
}
}
function formatListTools(data: any): void {
@@ -152,7 +179,7 @@ function formatGeneric(data: any): void {
}
}
var BOOLEAN_FLAGS = new Set(['json', 'info']);
var BOOLEAN_FLAGS = new Set(['json', 'info', 'symbols', 'save']);
function parseArgs(argv: string[]): { command: string; args: { [key: string]: string }; positional: string[] } {
var command = argv[2];
@@ -183,7 +210,7 @@ function usage(): void {
command: 'help',
data: {
commands: {
'compile': 'compile --platform <platform> [--tool <tool>] [--output <file>] <source>',
'compile': 'compile --platform <platform> [--tool <tool>] [--output <file>] [--symbols] [--save] <source>',
'check': 'check --platform <platform> [--tool <tool>] <source>',
'run': 'run (--platform <id> | --machine <module:ClassName>) [--frames N] [--output <file.png>] [--memdump start,end] [--info] <rom>',
'list-tools': 'list-tools',
@@ -273,18 +300,45 @@ async function doCompile(args: { [key: string]: string }, positional: string[],
outputSize = result.output.code ? result.output.code.length : result.output.length;
}
var compileData: any = {
tool: tool,
platform: platform,
source: sourceFile,
outputSize: outputSize,
outputFile: outputFile || null,
hasListings: result.listings ? Object.keys(result.listings).length > 0 : false,
hasSymbolmap: !!result.symbolmap,
};
if (args['symbols'] === 'true') {
if (result.symbolmap) compileData.symbolmap = result.symbolmap;
if (result.segments) compileData.segments = result.segments;
}
// --save: write all intermediate build files to /tmp/<dirname>
if (args['save'] === 'true') {
var baseName = path.basename(sourceFile, path.extname(sourceFile));
var saveDir = path.join('/tmp', `8bws-${baseName}`);
fs.mkdirSync(saveDir, { recursive: true });
var savedFiles: string[] = [];
for (var [filePath, entry] of Object.entries(store.workfs)) {
var outPath = path.join(saveDir, filePath);
fs.mkdirSync(path.dirname(outPath), { recursive: true });
if (entry.data instanceof Uint8Array) {
fs.writeFileSync(outPath, entry.data);
} else {
fs.writeFileSync(outPath, entry.data);
}
savedFiles.push(filePath);
}
compileData.saveDir = saveDir;
compileData.savedFiles = savedFiles;
}
output({
success: true,
command: 'compile',
data: {
tool: tool,
platform: platform,
source: sourceFile,
outputSize: outputSize,
outputFile: outputFile || null,
hasListings: result.listings ? Object.keys(result.listings).length > 0 : false,
hasSymbolmap: !!result.symbolmap,
}
data: compileData,
});
}

View File

@@ -30,6 +30,7 @@ export interface CompileResult {
errors?: { line: number; msg: string; path?: string }[];
listings?: any;
symbolmap?: any;
segments?: any;
params?: any;
unchanged?: boolean;
}
@@ -381,6 +382,7 @@ function workerResultToCompileResult(result: WorkerResult): CompileResult {
output: result.output,
listings: (result as any).listings,
symbolmap: (result as any).symbolmap,
segments: (result as any).segments,
params: (result as any).params,
};
}

View File

@@ -364,7 +364,8 @@ export var PLATFORM_PARAMS = {
},
'gb': {
arch: 'gbz80',
code_start: 0x0,
code_start: 0x0, // ROM starts @ 0x0, header @ 0x100, etc.
codeseg_start: 0x200, // _CODE area starts here
rom_size: 0x8000,
data_start: 0xc0a0,
data_size: 0x1f60,

View File

@@ -14,22 +14,25 @@ function hexToArray(s, ofs) {
return arr;
}
function parseIHX(ihx, rom_start, rom_size, errors) {
function parseIHX(ihx: string, rom_start: number, rom_size: number, errors: WorkerError[]) {
var output = new Uint8Array(new ArrayBuffer(rom_size));
var high_size = 0;
for (var s of ihx.split("\n")) {
if (s[0] == ':') {
var arr = hexToArray(s, 1);
var count = arr[0];
var address = (arr[1] << 8) + arr[2] - rom_start;
var offset = (arr[1] << 8) + arr[2] - rom_start;
var rectype = arr[3];
//console.log(rectype,address.toString(16),count,arr);
if (rectype == 0) {
if (output[offset] !== 0) {
errors.push({line:0,msg:`IHX overlap offset 0x${(offset).toString(16)}`});
}
for (var i = 0; i < count; i++) {
var b = arr[4 + i];
output[i + address] = b;
output[i + offset] = b;
}
if (i + address > high_size) high_size = i + address;
if (i + offset > high_size) high_size = i + offset;
} else if (rectype == 1) {
break;
} else {
@@ -144,6 +147,7 @@ export async function assembleSDASGB(step: BuildStep): Promise<BuildStepResult>
export function linkSDLDZ80(step: BuildStep) {
loadNative("sdldz80");
const arch = step.params.arch || 'z80';
var errors = [];
gatherFiles(step);
var binpath = "main.ihx";
@@ -177,10 +181,10 @@ export function linkSDLDZ80(step: BuildStep) {
FS.writeFile('crt0.lst', '\n'); // TODO: needed so -u flag works
}
var args = ['-mjwxyu',
'-i', 'main.ihx', // TODO: main?
'-b', '_CODE=0x' + params.code_start.toString(16),
'-i', 'main.ihx',
'-b', '_CODE=0x' + (params.codeseg_start||params.code_start).toString(16),
'-b', '_DATA=0x' + params.data_start.toString(16),
'-k', '/share/lib/z80',
'-k', `/share/lib/z80`, // TODO: $arch for gbz80
'-l', 'z80'];
if (params.extra_link_args)
args.push.apply(args, params.extra_link_args);