Skip to content

Commit f50aa23

Browse files
committed
cli: added --symbols, --save flags
gb: use codeseg_start parameter
1 parent 43303a3 commit f50aa23

5 files changed

Lines changed: 93 additions & 33 deletions

File tree

src/machine/gb.ts

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
import { SM83, SM83State } from "../common/cpu/SM83";
33
import { BasicScanlineMachine, Bus } from "../common/devices";
4-
import { newAddressDecoder, padBytes, Keys, makeKeycodeMap, newKeyboardHandler } from "../common/emu";
4+
import { newAddressDecoder, padBytes, Keys, makeKeycodeMap, newKeyboardHandler, EmuHalt } from "../common/emu";
55
import { hex } from "../common/util";
66

77
// Game Boy DMG palette: 4 shades of green (darkest to lightest)
@@ -1246,9 +1246,9 @@ export class GameBoyMachine extends BasicScanlineMachine {
12461246
switch (cartType) {
12471247
case 0x00: this.mbcType = 0; break; // ROM only
12481248
case 0x01: case 0x02: case 0x03: this.mbcType = 1; break; // MBC1
1249-
default: this.mbcType = 1; break; // Default to MBC1 for other types
1249+
default: console.log(`Invalid cartridge type @ 0x147: ${data[0x147]}`); break;
12501250
}
1251-
}
1251+
} else throw new EmuHalt("ROM not long enough for header");
12521252

12531253
// Determine ROM size and bank mask
12541254
this.rom = new Uint8Array(Math.max(data.length, 0x8000));
@@ -1257,15 +1257,14 @@ export class GameBoyMachine extends BasicScanlineMachine {
12571257
this.romBankMask = numBanks - 1;
12581258

12591259
// Determine RAM size from header
1260-
if (data.length > 0x149) {
1261-
switch (data[0x149]) {
1262-
case 0x00: break; // No RAM
1263-
case 0x01: this.extram = new Uint8Array(0x800); break; // 2KB
1264-
case 0x02: this.extram = new Uint8Array(0x2000); break; // 8KB
1265-
case 0x03: this.extram = new Uint8Array(0x8000); break; // 32KB
1266-
case 0x04: this.extram = new Uint8Array(0x20000); break; // 128KB
1267-
case 0x05: this.extram = new Uint8Array(0x10000); break; // 64KB
1268-
}
1260+
switch (data[0x149]) {
1261+
case 0x00: break; // No RAM
1262+
case 0x01: this.extram = new Uint8Array(0x800); break; // 2KB
1263+
case 0x02: this.extram = new Uint8Array(0x2000); break; // 8KB
1264+
case 0x03: this.extram = new Uint8Array(0x8000); break; // 32KB
1265+
case 0x04: this.extram = new Uint8Array(0x20000); break; // 128KB
1266+
case 0x05: this.extram = new Uint8Array(0x10000); break; // 64KB
1267+
default: console.log(`Invalid RAM size code @ 0x149: ${data[0x149]}`); break;
12691268
}
12701269

12711270
this.reset();

src/tools/8bws.ts

Lines changed: 67 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
// 8bws - 8bitworkshop CLI tool for compilation, ROM execution, and platform info
44

55
import * as fs from 'fs';
6-
import { initialize, compile, compileSourceFile, preload, listTools, listPlatforms, getToolForFilename, PLATFORM_PARAMS, TOOLS, TOOL_PRELOADFS } from './testlib';
6+
import * as path from 'path';
7+
import { initialize, compile, compileSourceFile, preload, listTools, listPlatforms, getToolForFilename, PLATFORM_PARAMS, TOOLS, TOOL_PRELOADFS, store } from './testlib';
78
import { isDebuggable } from '../common/baseplatform';
89
import { hex } from '../common/util';
910

@@ -91,7 +92,8 @@ function formatHelp(data: any): void {
9192
console.log(` ${c.green}${cmd}${c.reset}${c.dim} - ${usage}${c.reset}`);
9293
}
9394
console.log(`\n${c.bold}Global options:${c.reset}`);
94-
console.log(` ${c.yellow}--json${c.reset}${c.dim} Output raw JSON instead of formatted text${c.reset}`);
95+
console.log(` ${c.yellow}--json${c.reset}${c.dim} Output raw JSON instead of formatted text${c.reset}`);
96+
console.log(` ${c.yellow}--save${c.reset}${c.dim} Save all intermediate build files to /tmp/8bws-<name>${c.reset}`);
9597
console.log();
9698
}
9799
}
@@ -114,6 +116,31 @@ function formatCompile(data: any): void {
114116
if (data.outputFile) console.log(` ${c.dim}Output:${c.reset} ${c.cyan}${data.outputFile}${c.reset}`);
115117
if (data.hasListings) console.log(` ${c.dim}Listings:${c.reset} ${c.green}yes${c.reset}`);
116118
if (data.hasSymbolmap) console.log(` ${c.dim}Symbols:${c.reset} ${c.green}yes${c.reset}`);
119+
120+
// --symbols: dump symbol map
121+
if (data.symbolmap) {
122+
console.log(`\n${c.bold}Symbols${c.reset} ${c.dim}(${Object.keys(data.symbolmap).length})${c.reset}`);
123+
var sorted = Object.entries(data.symbolmap).sort((a: any, b: any) => a[1] - b[1]);
124+
for (var [name, addr] of sorted) {
125+
console.log(` ${c.cyan}$${hex(addr as number, 4)}${c.reset} ${name}`);
126+
}
127+
}
128+
129+
// --save: show saved files
130+
if (data.saveDir) {
131+
console.log(`\n${c.bold}Saved to${c.reset} ${c.cyan}${data.saveDir}${c.reset} ${c.dim}(${data.savedFiles.length} files)${c.reset}`);
132+
for (var f of data.savedFiles) {
133+
console.log(` ${c.dim}${c.reset} ${f}`);
134+
}
135+
}
136+
137+
// --symbols: dump segments
138+
if (data.segments) {
139+
console.log(`\n${c.bold}Segments${c.reset} ${c.dim}(${data.segments.length})${c.reset}`);
140+
for (var seg of data.segments) {
141+
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}`);
142+
}
143+
}
117144
}
118145

119146
function formatListTools(data: any): void {
@@ -152,7 +179,7 @@ function formatGeneric(data: any): void {
152179
}
153180
}
154181

155-
var BOOLEAN_FLAGS = new Set(['json', 'info']);
182+
var BOOLEAN_FLAGS = new Set(['json', 'info', 'symbols', 'save']);
156183

157184
function parseArgs(argv: string[]): { command: string; args: { [key: string]: string }; positional: string[] } {
158185
var command = argv[2];
@@ -183,7 +210,7 @@ function usage(): void {
183210
command: 'help',
184211
data: {
185212
commands: {
186-
'compile': 'compile --platform <platform> [--tool <tool>] [--output <file>] <source>',
213+
'compile': 'compile --platform <platform> [--tool <tool>] [--output <file>] [--symbols] [--save] <source>',
187214
'check': 'check --platform <platform> [--tool <tool>] <source>',
188215
'run': 'run (--platform <id> | --machine <module:ClassName>) [--frames N] [--output <file.png>] [--memdump start,end] [--info] <rom>',
189216
'list-tools': 'list-tools',
@@ -273,18 +300,45 @@ async function doCompile(args: { [key: string]: string }, positional: string[],
273300
outputSize = result.output.code ? result.output.code.length : result.output.length;
274301
}
275302

303+
var compileData: any = {
304+
tool: tool,
305+
platform: platform,
306+
source: sourceFile,
307+
outputSize: outputSize,
308+
outputFile: outputFile || null,
309+
hasListings: result.listings ? Object.keys(result.listings).length > 0 : false,
310+
hasSymbolmap: !!result.symbolmap,
311+
};
312+
313+
if (args['symbols'] === 'true') {
314+
if (result.symbolmap) compileData.symbolmap = result.symbolmap;
315+
if (result.segments) compileData.segments = result.segments;
316+
}
317+
318+
// --save: write all intermediate build files to /tmp/<dirname>
319+
if (args['save'] === 'true') {
320+
var baseName = path.basename(sourceFile, path.extname(sourceFile));
321+
var saveDir = path.join('/tmp', `8bws-${baseName}`);
322+
fs.mkdirSync(saveDir, { recursive: true });
323+
var savedFiles: string[] = [];
324+
for (var [filePath, entry] of Object.entries(store.workfs)) {
325+
var outPath = path.join(saveDir, filePath);
326+
fs.mkdirSync(path.dirname(outPath), { recursive: true });
327+
if (entry.data instanceof Uint8Array) {
328+
fs.writeFileSync(outPath, entry.data);
329+
} else {
330+
fs.writeFileSync(outPath, entry.data);
331+
}
332+
savedFiles.push(filePath);
333+
}
334+
compileData.saveDir = saveDir;
335+
compileData.savedFiles = savedFiles;
336+
}
337+
276338
output({
277339
success: true,
278340
command: 'compile',
279-
data: {
280-
tool: tool,
281-
platform: platform,
282-
source: sourceFile,
283-
outputSize: outputSize,
284-
outputFile: outputFile || null,
285-
hasListings: result.listings ? Object.keys(result.listings).length > 0 : false,
286-
hasSymbolmap: !!result.symbolmap,
287-
}
341+
data: compileData,
288342
});
289343
}
290344

src/tools/testlib.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export interface CompileResult {
3030
errors?: { line: number; msg: string; path?: string }[];
3131
listings?: any;
3232
symbolmap?: any;
33+
segments?: any;
3334
params?: any;
3435
unchanged?: boolean;
3536
}
@@ -381,6 +382,7 @@ function workerResultToCompileResult(result: WorkerResult): CompileResult {
381382
output: result.output,
382383
listings: (result as any).listings,
383384
symbolmap: (result as any).symbolmap,
385+
segments: (result as any).segments,
384386
params: (result as any).params,
385387
};
386388
}

src/worker/platforms.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,8 @@ export var PLATFORM_PARAMS = {
364364
},
365365
'gb': {
366366
arch: 'gbz80',
367-
code_start: 0x0,
367+
code_start: 0x0, // ROM starts @ 0x0, header @ 0x100, etc.
368+
codeseg_start: 0x200, // _CODE area starts here
368369
rom_size: 0x8000,
369370
data_start: 0xc0a0,
370371
data_size: 0x1f60,

src/worker/tools/sdcc.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,25 @@ function hexToArray(s, ofs) {
1414
return arr;
1515
}
1616

17-
function parseIHX(ihx, rom_start, rom_size, errors) {
17+
function parseIHX(ihx: string, rom_start: number, rom_size: number, errors: WorkerError[]) {
1818
var output = new Uint8Array(new ArrayBuffer(rom_size));
1919
var high_size = 0;
2020
for (var s of ihx.split("\n")) {
2121
if (s[0] == ':') {
2222
var arr = hexToArray(s, 1);
2323
var count = arr[0];
24-
var address = (arr[1] << 8) + arr[2] - rom_start;
24+
var offset = (arr[1] << 8) + arr[2] - rom_start;
2525
var rectype = arr[3];
2626
//console.log(rectype,address.toString(16),count,arr);
2727
if (rectype == 0) {
28+
if (output[offset] !== 0) {
29+
errors.push({line:0,msg:`IHX overlap offset 0x${(offset).toString(16)}`});
30+
}
2831
for (var i = 0; i < count; i++) {
2932
var b = arr[4 + i];
30-
output[i + address] = b;
33+
output[i + offset] = b;
3134
}
32-
if (i + address > high_size) high_size = i + address;
35+
if (i + offset > high_size) high_size = i + offset;
3336
} else if (rectype == 1) {
3437
break;
3538
} else {
@@ -144,6 +147,7 @@ export async function assembleSDASGB(step: BuildStep): Promise<BuildStepResult>
144147

145148
export function linkSDLDZ80(step: BuildStep) {
146149
loadNative("sdldz80");
150+
const arch = step.params.arch || 'z80';
147151
var errors = [];
148152
gatherFiles(step);
149153
var binpath = "main.ihx";
@@ -177,10 +181,10 @@ export function linkSDLDZ80(step: BuildStep) {
177181
FS.writeFile('crt0.lst', '\n'); // TODO: needed so -u flag works
178182
}
179183
var args = ['-mjwxyu',
180-
'-i', 'main.ihx', // TODO: main?
181-
'-b', '_CODE=0x' + params.code_start.toString(16),
184+
'-i', 'main.ihx',
185+
'-b', '_CODE=0x' + (params.codeseg_start||params.code_start).toString(16),
182186
'-b', '_DATA=0x' + params.data_start.toString(16),
183-
'-k', '/share/lib/z80',
187+
'-k', `/share/lib/z80`, // TODO: $arch for gbz80
184188
'-l', 'z80'];
185189
if (params.extra_link_args)
186190
args.push.apply(args, params.extra_link_args);

0 commit comments

Comments
 (0)