mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2024-06-12 18:42:14 +00:00
Compare commits
4 Commits
4cd000d70d
...
ed700af6bb
Author | SHA1 | Date | |
---|---|---|---|
|
ed700af6bb | ||
|
312cb3d025 | ||
|
bd63ef1268 | ||
|
2e0382b0a6 |
|
@ -61,8 +61,6 @@ typedef enum { false, true } bool; // boolean
|
||||||
// default screen base address on startup
|
// default screen base address on startup
|
||||||
#define DEFAULT_SCREEN ((void*)0x400)
|
#define DEFAULT_SCREEN ((void*)0x400)
|
||||||
|
|
||||||
// wait until next frame, same as waitvsync()
|
|
||||||
#define wait_vblank waitvsync
|
|
||||||
// is raster line > 255?
|
// is raster line > 255?
|
||||||
#define RASTER_HIBIT (VIC.ctrl1 & 0x80)
|
#define RASTER_HIBIT (VIC.ctrl1 & 0x80)
|
||||||
|
|
||||||
|
|
54
src/common/wasi/libretro.ts
Normal file
54
src/common/wasi/libretro.ts
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
import { WASIRunner } from "./wasishim";
|
||||||
|
|
||||||
|
export class LibRetroRunner extends WASIRunner {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
getEnv() {
|
||||||
|
return {
|
||||||
|
...super.getEnv(),
|
||||||
|
retro_environment_callback: (cmd: number, data: number) => {
|
||||||
|
console.log(`retro_environment_callback: ${cmd}, ${data}`);
|
||||||
|
return 0;
|
||||||
|
},
|
||||||
|
retro_video_refresh_callback: (data: number, width: number, height: number, pitch: number) => {
|
||||||
|
console.log(`retro_video_refresh_callback: ${data}, ${width}, ${height}, ${pitch}`);
|
||||||
|
},
|
||||||
|
retro_audio_sample_batch_callback: (data: number, frames: number) => {
|
||||||
|
console.log(`retro_audio_sample_batch_callback: ${data}, ${frames}`);
|
||||||
|
},
|
||||||
|
retro_audio_sample_callback: (left: number, right: number) => {
|
||||||
|
console.log(`retro_audio_sample_callback: ${left}, ${right}`);
|
||||||
|
return 0;
|
||||||
|
},
|
||||||
|
retro_input_poll_callback: () => {
|
||||||
|
console.log(`retro_input_poll_callback`);
|
||||||
|
},
|
||||||
|
retro_input_state_callback: (port: number, device: number, index: number, id: number) => {
|
||||||
|
console.log(`retro_input_state_callback: ${port}, ${device}, ${index}, ${id}`);
|
||||||
|
return 0;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
retro_init() {
|
||||||
|
let errno = this.initialize();
|
||||||
|
// TODO: if (errno) throw new Error(`retro_init failed: ${errno}`);
|
||||||
|
this.exports().retro_init_callbacks();
|
||||||
|
this.exports().retro_init();
|
||||||
|
this.exports().retro_set_controller_port_device(0,1);
|
||||||
|
this.exports().retro_set_controller_port_device(1,1);
|
||||||
|
}
|
||||||
|
retro_api_version() {
|
||||||
|
return this.exports().retro_api_version();
|
||||||
|
}
|
||||||
|
load_rom(path: string, data: Uint8Array) {
|
||||||
|
const meta = '';
|
||||||
|
this.exports().retro_load_rom(path, data, data.length, meta);
|
||||||
|
}
|
||||||
|
reset() {
|
||||||
|
this.exports().retro_reset();
|
||||||
|
}
|
||||||
|
advance() {
|
||||||
|
this.exports().retro_run();
|
||||||
|
}
|
||||||
|
}
|
|
@ -264,7 +264,7 @@ export class WASIMemoryFilesystem implements WASIFilesystem {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WASIRunner {
|
export class WASIRunner {
|
||||||
#instance; // TODO
|
#instance : any; // TODO
|
||||||
#memarr8: Uint8Array;
|
#memarr8: Uint8Array;
|
||||||
#memarr32: Int32Array;
|
#memarr32: Int32Array;
|
||||||
#args: Uint8Array[] = [];
|
#args: Uint8Array[] = [];
|
||||||
|
@ -282,6 +282,9 @@ export class WASIRunner {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.createStdioBrowser();
|
this.createStdioBrowser();
|
||||||
}
|
}
|
||||||
|
exports() {
|
||||||
|
return this.#instance.exports;
|
||||||
|
}
|
||||||
createStdioNode() {
|
createStdioNode() {
|
||||||
this.stdin = new WASIStreamingFileDescriptor(0, '<stdin>', FDType.CHARACTER_DEVICE, FDRights.FD_READ, process.stdin);
|
this.stdin = new WASIStreamingFileDescriptor(0, '<stdin>', FDType.CHARACTER_DEVICE, FDRights.FD_READ, process.stdin);
|
||||||
this.stdout = new WASIStreamingFileDescriptor(1, '<stdout>', FDType.CHARACTER_DEVICE, FDRights.FD_WRITE, process.stdout);
|
this.stdout = new WASIStreamingFileDescriptor(1, '<stdout>', FDType.CHARACTER_DEVICE, FDRights.FD_WRITE, process.stdout);
|
||||||
|
@ -373,6 +376,10 @@ export class WASIRunner {
|
||||||
}
|
}
|
||||||
return this.getErrno();
|
return this.getErrno();
|
||||||
}
|
}
|
||||||
|
initialize() {
|
||||||
|
this.#instance.exports._initialize();
|
||||||
|
return this.getErrno();
|
||||||
|
}
|
||||||
getImportObject() {
|
getImportObject() {
|
||||||
return {
|
return {
|
||||||
"wasi_snapshot_preview1": this.getWASISnapshotPreview1(),
|
"wasi_snapshot_preview1": this.getWASISnapshotPreview1(),
|
||||||
|
@ -485,7 +492,8 @@ export class WASIRunner {
|
||||||
}
|
}
|
||||||
fd_seek(fd: number, offset: number, whence: number, newoffset_ptr: number) {
|
fd_seek(fd: number, offset: number, whence: number, newoffset_ptr: number) {
|
||||||
const file = this.fds[fd];
|
const file = this.fds[fd];
|
||||||
debug("fd_seek", fd, offset, whence, file);
|
if (typeof offset == 'bigint') offset = Number(offset);
|
||||||
|
debug("fd_seek", fd, offset, whence, file+"");
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
file.llseek(offset, whence);
|
file.llseek(offset, whence);
|
||||||
this.poke64(newoffset_ptr, file.offset);
|
this.poke64(newoffset_ptr, file.offset);
|
||||||
|
@ -603,11 +611,12 @@ export class WASIRunner {
|
||||||
fd_readdir() { warning("TODO: fd_readdir"); return WASIErrors.NOTSUP; },
|
fd_readdir() { warning("TODO: fd_readdir"); return WASIErrors.NOTSUP; },
|
||||||
path_unlink_file() { warning("TODO: path_unlink_file"); return WASIErrors.NOTSUP; },
|
path_unlink_file() { warning("TODO: path_unlink_file"); return WASIErrors.NOTSUP; },
|
||||||
clock_time_get() { warning("TODO: clock_time_get"); return WASIErrors.NOTSUP; },
|
clock_time_get() { warning("TODO: clock_time_get"); return WASIErrors.NOTSUP; },
|
||||||
|
fd_tell() { warning("TODO: fd_tell"); return WASIErrors.NOTSUP; },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getEnv() {
|
getEnv() {
|
||||||
return {
|
return {
|
||||||
__syscall_unlinkat() { warning('TODO: unlink'); return 0; },
|
__syscall_unlinkat() { warning('TODO: unlink'); return WASIErrors.NOTSUP; },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
24
src/test/testlibretro.ts
Normal file
24
src/test/testlibretro.ts
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import assert from "assert";
|
||||||
|
import * as fs from "fs";
|
||||||
|
import { LibRetroRunner } from "../common/wasi/libretro";
|
||||||
|
|
||||||
|
async function loadLibretro() {
|
||||||
|
const wasmdata = fs.readFileSync(`./wasi/stella2014_libretro_2.wasm`);
|
||||||
|
let shim = new LibRetroRunner();
|
||||||
|
await shim.loadAsync(wasmdata);
|
||||||
|
return shim;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
describe('test WASI libretro', function () {
|
||||||
|
it('libretro init', async function () {
|
||||||
|
let shim = await loadLibretro();
|
||||||
|
assert.strictEqual(1, shim.retro_api_version());
|
||||||
|
shim.retro_init();
|
||||||
|
let romdata = fs.readFileSync(`./test/roms/vcs/brickgame.rom`);
|
||||||
|
shim.load_rom('brickgame.rom', romdata);
|
||||||
|
shim.reset();
|
||||||
|
shim.advance();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
*/
|
|
@ -77,3 +77,4 @@ describe('test WASI cc7800', function () {
|
||||||
assert.ok(stdout.indexOf('Usage: cc7800') >= 0);
|
assert.ok(stdout.indexOf('Usage: cc7800') >= 0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
416
src/worker/builder.ts
Normal file
416
src/worker/builder.ts
Normal file
|
@ -0,0 +1,416 @@
|
||||||
|
import { getBasePlatform } from "../common/util";
|
||||||
|
import { WorkerBuildStep, WorkerError, WorkerErrorResult, WorkerMessage, WorkerResult, WorkingStore } from "../common/workertypes";
|
||||||
|
import { PLATFORM_PARAMS } from "./platforms";
|
||||||
|
import { TOOLS } from "./workertools";
|
||||||
|
|
||||||
|
/// working file store and build steps
|
||||||
|
|
||||||
|
const PSRC = "../../src/";
|
||||||
|
export const PWORKER = PSRC + "worker/";
|
||||||
|
|
||||||
|
export type FileData = string | Uint8Array;
|
||||||
|
|
||||||
|
export type FileEntry = {
|
||||||
|
path: string
|
||||||
|
encoding: string
|
||||||
|
data: FileData
|
||||||
|
ts: number
|
||||||
|
};
|
||||||
|
|
||||||
|
export type BuildOptions = {
|
||||||
|
mainFilePath: string,
|
||||||
|
processFn?: (s: string, d: FileData) => FileData
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
export type BuildStepResult = WorkerResult | WorkerNextToolResult;
|
||||||
|
|
||||||
|
export interface WorkerNextToolResult {
|
||||||
|
nexttool?: string
|
||||||
|
linktool?: string
|
||||||
|
path?: string
|
||||||
|
args: string[]
|
||||||
|
files: string[]
|
||||||
|
bblines?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BuildStep extends WorkerBuildStep {
|
||||||
|
files?: string[]
|
||||||
|
args?: string[]
|
||||||
|
nextstep?: BuildStep
|
||||||
|
linkstep?: BuildStep
|
||||||
|
params?
|
||||||
|
result?: BuildStepResult
|
||||||
|
code?
|
||||||
|
prefix?
|
||||||
|
maxts?
|
||||||
|
debuginfo?
|
||||||
|
};
|
||||||
|
|
||||||
|
///
|
||||||
|
|
||||||
|
export class FileWorkingStore implements WorkingStore {
|
||||||
|
workfs: { [path: string]: FileEntry } = {};
|
||||||
|
workerseq: number = 0;
|
||||||
|
items: {};
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.reset();
|
||||||
|
}
|
||||||
|
reset() {
|
||||||
|
this.workfs = {};
|
||||||
|
this.newVersion();
|
||||||
|
}
|
||||||
|
currentVersion() {
|
||||||
|
return this.workerseq;
|
||||||
|
}
|
||||||
|
newVersion() {
|
||||||
|
let ts = new Date().getTime();
|
||||||
|
if (ts <= this.workerseq)
|
||||||
|
ts = ++this.workerseq;
|
||||||
|
return ts;
|
||||||
|
}
|
||||||
|
putFile(path: string, data: FileData): FileEntry {
|
||||||
|
var encoding = (typeof data === 'string') ? 'utf8' : 'binary';
|
||||||
|
var entry = this.workfs[path];
|
||||||
|
if (!entry || !compareData(entry.data, data) || entry.encoding != encoding) {
|
||||||
|
this.workfs[path] = entry = { path: path, data: data, encoding: encoding, ts: this.newVersion() };
|
||||||
|
console.log('+++', entry.path, entry.encoding, entry.data.length, entry.ts);
|
||||||
|
}
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
hasFile(path: string) {
|
||||||
|
return this.workfs[path] != null;
|
||||||
|
}
|
||||||
|
getFileData(path: string): FileData {
|
||||||
|
return this.workfs[path] && this.workfs[path].data;
|
||||||
|
}
|
||||||
|
getFileAsString(path: string): string {
|
||||||
|
let data = this.getFileData(path);
|
||||||
|
if (data != null && typeof data !== 'string')
|
||||||
|
throw new Error(`${path}: expected string`)
|
||||||
|
return data as string; // TODO
|
||||||
|
}
|
||||||
|
getFileEntry(path: string): FileEntry {
|
||||||
|
return this.workfs[path];
|
||||||
|
}
|
||||||
|
setItem(key: string, value: object) {
|
||||||
|
this.items[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export var store = new FileWorkingStore();
|
||||||
|
|
||||||
|
///
|
||||||
|
|
||||||
|
export function errorResult(msg: string): WorkerErrorResult {
|
||||||
|
return { errors: [{ line: 0, msg: msg }] };
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Builder {
|
||||||
|
steps: BuildStep[] = [];
|
||||||
|
startseq: number = 0;
|
||||||
|
|
||||||
|
// returns true if file changed during this build step
|
||||||
|
wasChanged(entry: FileEntry): boolean {
|
||||||
|
return entry.ts > this.startseq;
|
||||||
|
}
|
||||||
|
async executeBuildSteps(): Promise<WorkerResult> {
|
||||||
|
this.startseq = store.currentVersion();
|
||||||
|
var linkstep: BuildStep = null;
|
||||||
|
while (this.steps.length) {
|
||||||
|
var step = this.steps.shift(); // get top of array
|
||||||
|
var platform = step.platform;
|
||||||
|
var [tool, remoteTool] = step.tool.split(':', 2);
|
||||||
|
var toolfn = TOOLS[tool];
|
||||||
|
if (!toolfn) {
|
||||||
|
throw Error(`no tool named "${tool}"`);
|
||||||
|
}
|
||||||
|
if (remoteTool) {
|
||||||
|
step.tool = remoteTool;
|
||||||
|
}
|
||||||
|
step.params = PLATFORM_PARAMS[getBasePlatform(platform)];
|
||||||
|
try {
|
||||||
|
step.result = await toolfn(step);
|
||||||
|
} catch (e) {
|
||||||
|
console.log("EXCEPTION", e, e.stack);
|
||||||
|
return errorResult(e + ""); // TODO: catch errors already generated?
|
||||||
|
}
|
||||||
|
if (step.result) {
|
||||||
|
(step.result as any).params = step.params; // TODO: type check
|
||||||
|
if (step.debuginfo) {
|
||||||
|
let r = step.result as any; // TODO
|
||||||
|
if (!r.debuginfo) r.debuginfo = {};
|
||||||
|
Object.assign(r.debuginfo, step.debuginfo);
|
||||||
|
}
|
||||||
|
// errors? return them
|
||||||
|
if ('errors' in step.result && step.result.errors.length) {
|
||||||
|
applyDefaultErrorPath(step.result.errors, step.path);
|
||||||
|
return step.result;
|
||||||
|
}
|
||||||
|
// if we got some output, return it immediately
|
||||||
|
if ('output' in step.result && step.result.output) {
|
||||||
|
return step.result;
|
||||||
|
}
|
||||||
|
// combine files with a link tool?
|
||||||
|
if ('linktool' in step.result) {
|
||||||
|
// add to existing link step
|
||||||
|
if (linkstep) {
|
||||||
|
linkstep.files = linkstep.files.concat(step.result.files);
|
||||||
|
linkstep.args = linkstep.args.concat(step.result.args);
|
||||||
|
} else {
|
||||||
|
linkstep = {
|
||||||
|
tool: step.result.linktool,
|
||||||
|
platform: platform,
|
||||||
|
files: step.result.files,
|
||||||
|
args: step.result.args
|
||||||
|
};
|
||||||
|
}
|
||||||
|
linkstep.debuginfo = step.debuginfo; // TODO: multiple debuginfos
|
||||||
|
}
|
||||||
|
// process with another tool?
|
||||||
|
if ('nexttool' in step.result) {
|
||||||
|
var asmstep: BuildStep = {
|
||||||
|
tool: step.result.nexttool,
|
||||||
|
platform: platform,
|
||||||
|
...step.result
|
||||||
|
}
|
||||||
|
this.steps.push(asmstep);
|
||||||
|
}
|
||||||
|
// process final step?
|
||||||
|
if (this.steps.length == 0 && linkstep) {
|
||||||
|
this.steps.push(linkstep);
|
||||||
|
linkstep = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async handleMessage(data: WorkerMessage): Promise<WorkerResult> {
|
||||||
|
this.steps = [];
|
||||||
|
// file updates
|
||||||
|
if (data.updates) {
|
||||||
|
data.updates.forEach((u) => store.putFile(u.path, u.data));
|
||||||
|
}
|
||||||
|
// object update
|
||||||
|
if (data.setitems) {
|
||||||
|
data.setitems.forEach((i) => store.setItem(i.key, i.value));
|
||||||
|
}
|
||||||
|
// build steps
|
||||||
|
if (data.buildsteps) {
|
||||||
|
this.steps.push.apply(this.steps, data.buildsteps);
|
||||||
|
}
|
||||||
|
// single-file
|
||||||
|
if (data.code) {
|
||||||
|
this.steps.push(data as BuildStep); // TODO: remove cast
|
||||||
|
}
|
||||||
|
// execute build steps
|
||||||
|
if (this.steps.length) {
|
||||||
|
var result = await this.executeBuildSteps();
|
||||||
|
return result ? result : { unchanged: true };
|
||||||
|
}
|
||||||
|
// TODO: cache results
|
||||||
|
// message not recognized
|
||||||
|
console.log("Unknown message", data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyDefaultErrorPath(errors: WorkerError[], path: string) {
|
||||||
|
if (!path) return;
|
||||||
|
for (var i = 0; i < errors.length; i++) {
|
||||||
|
var err = errors[i];
|
||||||
|
if (!err.path && err.line) err.path = path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function compareData(a: FileData, b: FileData): boolean {
|
||||||
|
if (a.length != b.length) return false;
|
||||||
|
if (typeof a === 'string' && typeof b === 'string') {
|
||||||
|
return a == b;
|
||||||
|
} else {
|
||||||
|
for (var i = 0; i < a.length; i++) {
|
||||||
|
//if (a[i] != b[i]) console.log('differ at byte',i,a[i],b[i]);
|
||||||
|
if (a[i] != b[i]) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const builder = new Builder();
|
||||||
|
|
||||||
|
var _t1;
|
||||||
|
export function starttime() { _t1 = new Date(); }
|
||||||
|
export function endtime(msg) { var _t2 = new Date(); console.log(msg, _t2.getTime() - _t1.getTime(), "ms"); }
|
||||||
|
|
||||||
|
///
|
||||||
|
|
||||||
|
export function putWorkFile(path: string, data: FileData) {
|
||||||
|
return store.putFile(path, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getWorkFileAsString(path: string): string {
|
||||||
|
return store.getFileAsString(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function populateEntry(fs, path: string, entry: FileEntry, options: BuildOptions) {
|
||||||
|
var data = entry.data;
|
||||||
|
if (options && options.processFn) {
|
||||||
|
data = options.processFn(path, data);
|
||||||
|
}
|
||||||
|
// create subfolders
|
||||||
|
var toks = path.split('/');
|
||||||
|
if (toks.length > 1) {
|
||||||
|
for (var i = 0; i < toks.length - 1; i++)
|
||||||
|
try {
|
||||||
|
fs.mkdir(toks[i]);
|
||||||
|
} catch (e) { }
|
||||||
|
}
|
||||||
|
// write file
|
||||||
|
fs.writeFile(path, data, { encoding: entry.encoding });
|
||||||
|
var time = new Date(entry.ts);
|
||||||
|
fs.utime(path, time, time);
|
||||||
|
console.log("<<<", path, entry.data.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
// can call multiple times (from populateFiles)
|
||||||
|
export function gatherFiles(step: BuildStep, options?: BuildOptions): number {
|
||||||
|
var maxts = 0;
|
||||||
|
if (step.files) {
|
||||||
|
for (var i = 0; i < step.files.length; i++) {
|
||||||
|
var path = step.files[i];
|
||||||
|
var entry = store.workfs[path];
|
||||||
|
if (!entry) {
|
||||||
|
throw new Error("No entry for path '" + path + "'");
|
||||||
|
} else {
|
||||||
|
maxts = Math.max(maxts, entry.ts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (step.code) {
|
||||||
|
var path = step.path ? step.path : options.mainFilePath; // TODO: what if options null
|
||||||
|
if (!path) throw Error("need path or mainFilePath");
|
||||||
|
var code = step.code;
|
||||||
|
var entry = putWorkFile(path, code);
|
||||||
|
step.path = path;
|
||||||
|
step.files = [path];
|
||||||
|
maxts = entry.ts;
|
||||||
|
}
|
||||||
|
else if (step.path) {
|
||||||
|
var path = step.path;
|
||||||
|
var entry = store.workfs[path];
|
||||||
|
maxts = entry.ts;
|
||||||
|
step.files = [path];
|
||||||
|
}
|
||||||
|
if (step.path && !step.prefix) {
|
||||||
|
step.prefix = getPrefix(step.path);
|
||||||
|
}
|
||||||
|
step.maxts = maxts;
|
||||||
|
return maxts;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPrefix(s: string): string {
|
||||||
|
var pos = s.lastIndexOf('.');
|
||||||
|
return (pos > 0) ? s.substring(0, pos) : s;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function populateFiles(step: BuildStep, fs, options?: BuildOptions) {
|
||||||
|
gatherFiles(step, options);
|
||||||
|
if (!step.files) throw Error("call gatherFiles() first");
|
||||||
|
for (var i = 0; i < step.files.length; i++) {
|
||||||
|
var path = step.files[i];
|
||||||
|
populateEntry(fs, path, store.workfs[path], options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function populateExtraFiles(step: BuildStep, fs, extrafiles) {
|
||||||
|
if (extrafiles) {
|
||||||
|
for (var i = 0; i < extrafiles.length; i++) {
|
||||||
|
var xfn = extrafiles[i];
|
||||||
|
// is this file cached?
|
||||||
|
if (store.workfs[xfn]) {
|
||||||
|
fs.writeFile(xfn, store.workfs[xfn].data, { encoding: 'binary' });
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// fetch from network
|
||||||
|
var xpath = "lib/" + getBasePlatform(step.platform) + "/" + xfn;
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
xhr.responseType = 'arraybuffer';
|
||||||
|
xhr.open("GET", PWORKER + xpath, false); // synchronous request
|
||||||
|
xhr.send(null);
|
||||||
|
if (xhr.response && xhr.status == 200) {
|
||||||
|
var data = new Uint8Array(xhr.response);
|
||||||
|
fs.writeFile(xfn, data, { encoding: 'binary' });
|
||||||
|
putWorkFile(xfn, data);
|
||||||
|
console.log(":::", xfn, data.length);
|
||||||
|
} else {
|
||||||
|
throw Error("Could not load extra file " + xpath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function staleFiles(step: BuildStep, targets: string[]) {
|
||||||
|
if (!step.maxts) throw Error("call populateFiles() first");
|
||||||
|
// see if any target files are more recent than inputs
|
||||||
|
for (var i = 0; i < targets.length; i++) {
|
||||||
|
var entry = store.workfs[targets[i]];
|
||||||
|
if (!entry || step.maxts > entry.ts)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
console.log("unchanged", step.maxts, targets);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function anyTargetChanged(step: BuildStep, targets: string[]) {
|
||||||
|
if (!step.maxts) throw Error("call populateFiles() first");
|
||||||
|
// see if any target files are more recent than inputs
|
||||||
|
for (var i = 0; i < targets.length; i++) {
|
||||||
|
var entry = store.workfs[targets[i]];
|
||||||
|
if (!entry || entry.ts > step.maxts)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
console.log("unchanged", step.maxts, targets);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fixParamsWithDefines(path: string, params) {
|
||||||
|
var libargs = params.libargs;
|
||||||
|
if (path && libargs) {
|
||||||
|
var code = getWorkFileAsString(path);
|
||||||
|
if (code) {
|
||||||
|
var oldcfgfile = params.cfgfile;
|
||||||
|
var ident2index = {};
|
||||||
|
// find all lib args "IDENT=VALUE"
|
||||||
|
for (var i = 0; i < libargs.length; i++) {
|
||||||
|
var toks = libargs[i].split('=');
|
||||||
|
if (toks.length == 2) {
|
||||||
|
ident2index[toks[0]] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// find #defines and replace them
|
||||||
|
var re = /^[;]?#define\s+(\w+)\s+(\S+)/gmi; // TODO: empty string?
|
||||||
|
var m;
|
||||||
|
while (m = re.exec(code)) {
|
||||||
|
var ident = m[1];
|
||||||
|
var value = m[2];
|
||||||
|
var index = ident2index[ident];
|
||||||
|
if (index >= 0) {
|
||||||
|
libargs[index] = ident + "=" + value;
|
||||||
|
console.log('Using libargs', index, libargs[index]);
|
||||||
|
// TODO: MMC3 mapper switch
|
||||||
|
if (ident == 'NES_MAPPER' && value == '4') {
|
||||||
|
params.cfgfile = 'nesbanked.cfg';
|
||||||
|
console.log("using config file", params.cfgfile);
|
||||||
|
}
|
||||||
|
} else if (ident == 'CFGFILE' && value) {
|
||||||
|
params.cfgfile = value;
|
||||||
|
} else if (ident == 'LIBARGS' && value) {
|
||||||
|
params.libargs = value.split(',').filter((s) => { return s != ''; });
|
||||||
|
console.log('Using libargs', params.libargs);
|
||||||
|
} else if (ident == 'CC65_FLAGS' && value) {
|
||||||
|
params.extra_compiler_args = value.split(',').filter((s) => { return s != ''; });
|
||||||
|
console.log('Using compiler flags', params.extra_compiler_args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
129
src/worker/listingutils.ts
Normal file
129
src/worker/listingutils.ts
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
|
||||||
|
// test.c(6) : warning 85: in function main unreferenced local variable : 'x'
|
||||||
|
// main.a (4): error: Unknown Mnemonic 'xxx'.
|
||||||
|
|
||||||
|
import { SourceLine, WorkerError } from "../common/workertypes";
|
||||||
|
|
||||||
|
// at 2: warning 190: ISO C forbids an empty source file
|
||||||
|
export const re_msvc = /[/]*([^( ]+)\s*[(](\d+)[)]\s*:\s*(.+?):\s*(.*)/;
|
||||||
|
export const re_msvc2 = /\s*(at)\s+(\d+)\s*(:)\s*(.*)/;
|
||||||
|
|
||||||
|
export function msvcErrorMatcher(errors: WorkerError[]) {
|
||||||
|
return function (s: string) {
|
||||||
|
var matches = re_msvc.exec(s) || re_msvc2.exec(s);
|
||||||
|
if (matches) {
|
||||||
|
var errline = parseInt(matches[2]);
|
||||||
|
errors.push({
|
||||||
|
line: errline,
|
||||||
|
path: matches[1],
|
||||||
|
//type:matches[3],
|
||||||
|
msg: matches[4]
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.log(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function makeErrorMatcher(errors: WorkerError[], regex, iline: number, imsg: number, mainpath: string, ifilename?: number) {
|
||||||
|
return function (s) {
|
||||||
|
var matches = regex.exec(s);
|
||||||
|
if (matches) {
|
||||||
|
errors.push({
|
||||||
|
line: parseInt(matches[iline]) || 1,
|
||||||
|
msg: matches[imsg],
|
||||||
|
path: ifilename ? matches[ifilename] : mainpath
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.log("??? " + s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function extractErrors(regex, strings: string[], path: string, iline, imsg, ifilename) {
|
||||||
|
var errors = [];
|
||||||
|
var matcher = makeErrorMatcher(errors, regex, iline, imsg, path, ifilename);
|
||||||
|
for (var i = 0; i < strings.length; i++) {
|
||||||
|
matcher(strings[i]);
|
||||||
|
}
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const re_crlf = /\r?\n/;
|
||||||
|
// 1 %line 16+1 hello.asm
|
||||||
|
export const re_lineoffset = /\s*(\d+)\s+[%]line\s+(\d+)\+(\d+)\s+(.+)/;
|
||||||
|
|
||||||
|
export function parseListing(code: string,
|
||||||
|
lineMatch, iline: number, ioffset: number, iinsns: number, icycles?: number,
|
||||||
|
funcMatch?, segMatch?): SourceLine[] {
|
||||||
|
var lines: SourceLine[] = [];
|
||||||
|
var lineofs = 0;
|
||||||
|
var segment = '';
|
||||||
|
var func = '';
|
||||||
|
var funcbase = 0;
|
||||||
|
code.split(re_crlf).forEach((line, lineindex) => {
|
||||||
|
let segm = segMatch && segMatch.exec(line);
|
||||||
|
if (segm) { segment = segm[1]; }
|
||||||
|
let funcm = funcMatch && funcMatch.exec(line);
|
||||||
|
if (funcm) { funcbase = parseInt(funcm[1], 16); func = funcm[2]; }
|
||||||
|
|
||||||
|
var linem = lineMatch.exec(line);
|
||||||
|
if (linem && linem[1]) {
|
||||||
|
var linenum = iline < 0 ? lineindex : parseInt(linem[iline]);
|
||||||
|
var offset = parseInt(linem[ioffset], 16);
|
||||||
|
var insns = linem[iinsns];
|
||||||
|
var cycles: number = icycles ? parseInt(linem[icycles]) : null;
|
||||||
|
var iscode = cycles > 0;
|
||||||
|
if (insns) {
|
||||||
|
lines.push({
|
||||||
|
line: linenum + lineofs,
|
||||||
|
offset: offset - funcbase,
|
||||||
|
insns,
|
||||||
|
cycles,
|
||||||
|
iscode,
|
||||||
|
segment,
|
||||||
|
func
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let m = re_lineoffset.exec(line);
|
||||||
|
// TODO: check filename too
|
||||||
|
if (m) {
|
||||||
|
lineofs = parseInt(m[2]) - parseInt(m[1]) - parseInt(m[3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseSourceLines(code: string, lineMatch, offsetMatch, funcMatch?, segMatch?) {
|
||||||
|
var lines = [];
|
||||||
|
var lastlinenum = 0;
|
||||||
|
var segment = '';
|
||||||
|
var func = '';
|
||||||
|
var funcbase = 0;
|
||||||
|
for (var line of code.split(re_crlf)) {
|
||||||
|
let segm = segMatch && segMatch.exec(line);
|
||||||
|
if (segm) { segment = segm[1]; }
|
||||||
|
let funcm = funcMatch && funcMatch.exec(line);
|
||||||
|
if (funcm) { funcbase = parseInt(funcm[1], 16); func = funcm[2]; }
|
||||||
|
|
||||||
|
var linem = lineMatch.exec(line);
|
||||||
|
if (linem && linem[1]) {
|
||||||
|
lastlinenum = parseInt(linem[1]);
|
||||||
|
} else if (lastlinenum) {
|
||||||
|
var linem = offsetMatch.exec(line);
|
||||||
|
if (linem && linem[1]) {
|
||||||
|
var offset = parseInt(linem[1], 16);
|
||||||
|
lines.push({
|
||||||
|
line: lastlinenum,
|
||||||
|
offset: offset - funcbase,
|
||||||
|
segment,
|
||||||
|
func
|
||||||
|
});
|
||||||
|
lastlinenum = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lines;
|
||||||
|
}
|
334
src/worker/platforms.ts
Normal file
334
src/worker/platforms.ts
Normal file
|
@ -0,0 +1,334 @@
|
||||||
|
|
||||||
|
export var PLATFORM_PARAMS = {
|
||||||
|
'vcs': {
|
||||||
|
arch: '6502',
|
||||||
|
code_start: 0x1000,
|
||||||
|
code_size: 0xf000,
|
||||||
|
data_start: 0x80,
|
||||||
|
data_size: 0x80,
|
||||||
|
wiz_rom_ext: '.a26',
|
||||||
|
wiz_inc_dir: '2600',
|
||||||
|
cfgfile: 'atari2600.cfg',
|
||||||
|
libargs: ['crt0.o', 'atari2600.lib'],
|
||||||
|
extra_link_files: ['crt0.o', 'atari2600.cfg'],
|
||||||
|
define: ['__ATARI2600__'],
|
||||||
|
},
|
||||||
|
'mw8080bw': {
|
||||||
|
arch: 'z80',
|
||||||
|
code_start: 0x0,
|
||||||
|
rom_size: 0x2000,
|
||||||
|
data_start: 0x2000,
|
||||||
|
data_size: 0x400,
|
||||||
|
stack_end: 0x2400,
|
||||||
|
},
|
||||||
|
'vicdual': {
|
||||||
|
arch: 'z80',
|
||||||
|
code_start: 0x0,
|
||||||
|
rom_size: 0x4020,
|
||||||
|
data_start: 0xe400,
|
||||||
|
data_size: 0x400,
|
||||||
|
stack_end: 0xe800,
|
||||||
|
},
|
||||||
|
'galaxian': {
|
||||||
|
arch: 'z80',
|
||||||
|
code_start: 0x0,
|
||||||
|
rom_size: 0x4000,
|
||||||
|
data_start: 0x4000,
|
||||||
|
data_size: 0x400,
|
||||||
|
stack_end: 0x4800,
|
||||||
|
},
|
||||||
|
'galaxian-scramble': {
|
||||||
|
arch: 'z80',
|
||||||
|
code_start: 0x0,
|
||||||
|
rom_size: 0x5020,
|
||||||
|
data_start: 0x4000,
|
||||||
|
data_size: 0x400,
|
||||||
|
stack_end: 0x4800,
|
||||||
|
},
|
||||||
|
'williams': {
|
||||||
|
arch: '6809',
|
||||||
|
code_start: 0x0,
|
||||||
|
rom_size: 0xc000,
|
||||||
|
data_start: 0x9800,
|
||||||
|
data_size: 0x2800,
|
||||||
|
stack_end: 0xc000,
|
||||||
|
set_stack_end: 0xc000,
|
||||||
|
extra_link_files: ['williams.scr', 'libcmoc-crt-vec.a', 'libcmoc-std-vec.a'],
|
||||||
|
extra_link_args: ['-swilliams.scr', '-lcmoc-crt-vec', '-lcmoc-std-vec'],
|
||||||
|
extra_compile_files: ['assert.h','cmoc.h','stdarg.h','stdlib.h'],
|
||||||
|
//extra_compile_args: ['--vectrex'],
|
||||||
|
},
|
||||||
|
'williams-defender': {
|
||||||
|
arch: '6809',
|
||||||
|
code_start: 0x0,
|
||||||
|
rom_size: 0xc000,
|
||||||
|
data_start: 0x9800,
|
||||||
|
data_size: 0x2800,
|
||||||
|
stack_end: 0xc000,
|
||||||
|
},
|
||||||
|
'williams-z80': {
|
||||||
|
arch: 'z80',
|
||||||
|
code_start: 0x0,
|
||||||
|
rom_size: 0x9800,
|
||||||
|
data_start: 0x9800,
|
||||||
|
data_size: 0x2800,
|
||||||
|
stack_end: 0xc000,
|
||||||
|
},
|
||||||
|
'vector-z80color': {
|
||||||
|
arch: 'z80',
|
||||||
|
code_start: 0x0,
|
||||||
|
rom_size: 0x8000,
|
||||||
|
data_start: 0xe000,
|
||||||
|
data_size: 0x2000,
|
||||||
|
stack_end: 0x0,
|
||||||
|
},
|
||||||
|
'vector-ataricolor': { //TODO
|
||||||
|
arch: '6502',
|
||||||
|
define: ['__VECTOR__'],
|
||||||
|
cfgfile: 'vector-color.cfg',
|
||||||
|
libargs: ['crt0.o', 'none.lib'],
|
||||||
|
extra_link_files: ['crt0.o', 'vector-color.cfg'],
|
||||||
|
},
|
||||||
|
'sound_williams-z80': {
|
||||||
|
arch: 'z80',
|
||||||
|
code_start: 0x0,
|
||||||
|
rom_size: 0x4000,
|
||||||
|
data_start: 0x4000,
|
||||||
|
data_size: 0x400,
|
||||||
|
stack_end: 0x8000,
|
||||||
|
},
|
||||||
|
'base_z80': {
|
||||||
|
arch: 'z80',
|
||||||
|
code_start: 0x0,
|
||||||
|
rom_size: 0x8000,
|
||||||
|
data_start: 0x8000,
|
||||||
|
data_size: 0x8000,
|
||||||
|
stack_end: 0x0,
|
||||||
|
},
|
||||||
|
'coleco': {
|
||||||
|
arch: 'z80',
|
||||||
|
rom_start: 0x8000,
|
||||||
|
code_start: 0x8100,
|
||||||
|
rom_size: 0x8000,
|
||||||
|
data_start: 0x7000,
|
||||||
|
data_size: 0x400,
|
||||||
|
stack_end: 0x8000,
|
||||||
|
extra_preproc_args: ['-I', '/share/include/coleco', '-D', 'CV_CV'],
|
||||||
|
extra_link_args: ['-k', '/share/lib/coleco', '-l', 'libcv', '-l', 'libcvu', 'crt0.rel'],
|
||||||
|
},
|
||||||
|
'msx': {
|
||||||
|
arch: 'z80',
|
||||||
|
rom_start: 0x4000,
|
||||||
|
code_start: 0x4000,
|
||||||
|
rom_size: 0x8000,
|
||||||
|
data_start: 0xc000,
|
||||||
|
data_size: 0x3000,
|
||||||
|
stack_end: 0xffff,
|
||||||
|
extra_link_args: ['crt0-msx.rel'],
|
||||||
|
extra_link_files: ['crt0-msx.rel', 'crt0-msx.lst'],
|
||||||
|
wiz_sys_type: 'z80',
|
||||||
|
wiz_inc_dir: 'msx',
|
||||||
|
},
|
||||||
|
'msx-libcv': {
|
||||||
|
arch: 'z80',
|
||||||
|
rom_start: 0x4000,
|
||||||
|
code_start: 0x4000,
|
||||||
|
rom_size: 0x8000,
|
||||||
|
data_start: 0xc000,
|
||||||
|
data_size: 0x3000,
|
||||||
|
stack_end: 0xffff,
|
||||||
|
extra_preproc_args: ['-I', '.', '-D', 'CV_MSX'],
|
||||||
|
extra_link_args: ['-k', '.', '-l', 'libcv-msx', '-l', 'libcvu-msx', 'crt0-msx.rel'],
|
||||||
|
extra_link_files: ['libcv-msx.lib', 'libcvu-msx.lib', 'crt0-msx.rel', 'crt0-msx.lst'],
|
||||||
|
extra_compile_files: ['cv.h','cv_graphics.h','cv_input.h','cv_sound.h','cv_support.h','cvu.h','cvu_c.h','cvu_compression.h','cvu_f.h','cvu_graphics.h','cvu_input.h','cvu_sound.h'],
|
||||||
|
},
|
||||||
|
'sms-sg1000-libcv': {
|
||||||
|
arch: 'z80',
|
||||||
|
rom_start: 0x0000,
|
||||||
|
code_start: 0x0100,
|
||||||
|
rom_size: 0xc000,
|
||||||
|
data_start: 0xc000,
|
||||||
|
data_size: 0x400,
|
||||||
|
stack_end: 0xe000,
|
||||||
|
extra_preproc_args: ['-I', '.', '-D', 'CV_SMS'],
|
||||||
|
extra_link_args: ['-k', '.', '-l', 'libcv-sms', '-l', 'libcvu-sms', 'crt0-sms.rel'],
|
||||||
|
extra_link_files: ['libcv-sms.lib', 'libcvu-sms.lib', 'crt0-sms.rel', 'crt0-sms.lst'],
|
||||||
|
extra_compile_files: ['cv.h','cv_graphics.h','cv_input.h','cv_sound.h','cv_support.h','cvu.h','cvu_c.h','cvu_compression.h','cvu_f.h','cvu_graphics.h','cvu_input.h','cvu_sound.h'],
|
||||||
|
},
|
||||||
|
'nes': { //TODO
|
||||||
|
arch: '6502',
|
||||||
|
define: ['__NES__'],
|
||||||
|
cfgfile: 'neslib2.cfg',
|
||||||
|
libargs: ['crt0.o', 'nes.lib', 'neslib2.lib',
|
||||||
|
'-D', 'NES_MAPPER=0', // NROM
|
||||||
|
'-D', 'NES_PRG_BANKS=2', // 2 16K PRG banks
|
||||||
|
'-D', 'NES_CHR_BANKS=1', // 1 CHR bank
|
||||||
|
'-D', 'NES_MIRRORING=0', // horizontal mirroring
|
||||||
|
],
|
||||||
|
extra_link_files: ['crt0.o', 'neslib2.lib', 'neslib2.cfg', 'nesbanked.cfg'],
|
||||||
|
wiz_rom_ext: '.nes',
|
||||||
|
},
|
||||||
|
'apple2': {
|
||||||
|
arch: '6502',
|
||||||
|
define: ['__APPLE2__'],
|
||||||
|
cfgfile: 'apple2.cfg',
|
||||||
|
libargs: [ '--lib-path', '/share/target/apple2/drv', 'apple2.lib'],
|
||||||
|
__CODE_RUN__: 16384,
|
||||||
|
code_start: 0x803,
|
||||||
|
acmeargs: ['-f', 'apple'],
|
||||||
|
},
|
||||||
|
'apple2-e': {
|
||||||
|
arch: '6502',
|
||||||
|
define: ['__APPLE2__'],
|
||||||
|
cfgfile: 'apple2.cfg',
|
||||||
|
libargs: ['apple2.lib'],
|
||||||
|
acmeargs: ['-f', 'apple'],
|
||||||
|
},
|
||||||
|
'atari8-800xl.disk': {
|
||||||
|
arch: '6502',
|
||||||
|
define: ['__ATARI__'],
|
||||||
|
cfgfile: 'atari.cfg',
|
||||||
|
libargs: ['atari.lib'],
|
||||||
|
fastbasic_cfgfile: 'fastbasic-cart.cfg',
|
||||||
|
},
|
||||||
|
'atari8-800xl': {
|
||||||
|
arch: '6502',
|
||||||
|
define: ['__ATARI__'],
|
||||||
|
cfgfile: 'atari-cart.cfg',
|
||||||
|
libargs: ['atari.lib', '-D', '__CARTFLAGS__=4'],
|
||||||
|
fastbasic_cfgfile: 'fastbasic-cart.cfg',
|
||||||
|
},
|
||||||
|
'atari8-800': {
|
||||||
|
arch: '6502',
|
||||||
|
define: ['__ATARI__'],
|
||||||
|
cfgfile: 'atari-cart.cfg',
|
||||||
|
libargs: ['atari.lib', '-D', '__CARTFLAGS__=4'],
|
||||||
|
fastbasic_cfgfile: 'fastbasic-cart.cfg',
|
||||||
|
},
|
||||||
|
'atari8-5200': {
|
||||||
|
arch: '6502',
|
||||||
|
define: ['__ATARI5200__'],
|
||||||
|
cfgfile: 'atari5200.cfg',
|
||||||
|
libargs: ['atari5200.lib', '-D', '__CARTFLAGS__=255'],
|
||||||
|
fastbasic_cfgfile: 'fastbasic-cart.cfg',
|
||||||
|
},
|
||||||
|
'verilog': {
|
||||||
|
arch: 'verilog',
|
||||||
|
extra_compile_files: ['8bitworkshop.v'],
|
||||||
|
},
|
||||||
|
'astrocade': {
|
||||||
|
arch: 'z80',
|
||||||
|
code_start: 0x2000,
|
||||||
|
rom_size: 0x2000,
|
||||||
|
data_start: 0x4e10,
|
||||||
|
data_size: 0x1f0,
|
||||||
|
stack_end: 0x5000,
|
||||||
|
},
|
||||||
|
'astrocade-arcade': {
|
||||||
|
arch: 'z80',
|
||||||
|
code_start: 0x0000,
|
||||||
|
rom_size: 0x4000,
|
||||||
|
data_start: 0x7de0,
|
||||||
|
data_size: 0x220,
|
||||||
|
stack_end: 0x8000,
|
||||||
|
},
|
||||||
|
'astrocade-bios': {
|
||||||
|
arch: 'z80',
|
||||||
|
code_start: 0x0000,
|
||||||
|
rom_size: 0x2000,
|
||||||
|
data_start: 0x4fce,
|
||||||
|
data_size: 50,
|
||||||
|
stack_end: 0x4fce,
|
||||||
|
},
|
||||||
|
'atari7800': {
|
||||||
|
arch: '6502',
|
||||||
|
define: ['__ATARI7800__'],
|
||||||
|
cfgfile: 'atari7800.cfg',
|
||||||
|
libargs: ['crt0.o', 'none.lib'],
|
||||||
|
extra_link_files: ['crt0.o', 'atari7800.cfg'],
|
||||||
|
},
|
||||||
|
'c64': {
|
||||||
|
arch: '6502',
|
||||||
|
define: ['__CBM__', '__C64__'],
|
||||||
|
cfgfile: 'c64.cfg', // SYS 2061
|
||||||
|
libargs: ['c64.lib'],
|
||||||
|
acmeargs: ['-f', 'cbm'],
|
||||||
|
//extra_link_files: ['c64-cart.cfg'],
|
||||||
|
},
|
||||||
|
'vic20': {
|
||||||
|
arch: '6502',
|
||||||
|
define: ['__CBM__', '__VIC20__'],
|
||||||
|
cfgfile: 'vic20.cfg',
|
||||||
|
libargs: ['vic20.lib'],
|
||||||
|
acmeargs: ['-f', 'cbm'],
|
||||||
|
//extra_link_files: ['c64-cart.cfg'],
|
||||||
|
},
|
||||||
|
'kim1': {
|
||||||
|
arch: '6502',
|
||||||
|
},
|
||||||
|
'vectrex': {
|
||||||
|
arch: '6809',
|
||||||
|
code_start: 0x0,
|
||||||
|
rom_size: 0x8000,
|
||||||
|
data_start: 0xc880,
|
||||||
|
data_size: 0x380,
|
||||||
|
stack_end: 0xcc00,
|
||||||
|
extra_compile_files: ['assert.h','cmoc.h','stdarg.h','vectrex.h','stdlib.h','bios.h'],
|
||||||
|
extra_link_files: ['vectrex.scr', 'libcmoc-crt-vec.a', 'libcmoc-std-vec.a'],
|
||||||
|
extra_compile_args: ['--vectrex'],
|
||||||
|
extra_link_args: ['-svectrex.scr', '-lcmoc-crt-vec', '-lcmoc-std-vec'],
|
||||||
|
},
|
||||||
|
'x86': {
|
||||||
|
arch: 'x86',
|
||||||
|
},
|
||||||
|
'zx': {
|
||||||
|
arch: 'z80',
|
||||||
|
code_start: 0x5ccb,
|
||||||
|
rom_size: 0xff58-0x5ccb,
|
||||||
|
data_start: 0xf000,
|
||||||
|
data_size: 0xfe00-0xf000,
|
||||||
|
stack_end: 0xff58,
|
||||||
|
extra_link_args: ['crt0-zx.rel'],
|
||||||
|
extra_link_files: ['crt0-zx.rel', 'crt0-zx.lst'],
|
||||||
|
},
|
||||||
|
'devel-6502': {
|
||||||
|
arch: '6502',
|
||||||
|
cfgfile: 'devel-6502.cfg',
|
||||||
|
libargs: ['crt0.o', 'none.lib'],
|
||||||
|
extra_link_files: ['crt0.o', 'devel-6502.cfg'],
|
||||||
|
},
|
||||||
|
// https://github.com/cpcitor/cpc-dev-tool-chain
|
||||||
|
'cpc.rslib': {
|
||||||
|
arch: 'z80',
|
||||||
|
code_start: 0x4000,
|
||||||
|
rom_size: 0xb100-0x4000,
|
||||||
|
data_start: 0xb100,
|
||||||
|
data_size: 0xb100-0xc000,
|
||||||
|
stack_end: 0xc000,
|
||||||
|
extra_compile_files: ['cpcrslib.h'],
|
||||||
|
extra_link_args: ['crt0-cpc.rel', 'cpcrslib.lib'],
|
||||||
|
extra_link_files: ['crt0-cpc.rel', 'crt0-cpc.lst', 'cpcrslib.lib', 'cpcrslib.lst'],
|
||||||
|
},
|
||||||
|
// https://lronaldo.github.io/cpctelera/ (TODO)
|
||||||
|
'cpc': {
|
||||||
|
arch: 'z80',
|
||||||
|
code_start: 0x4000,
|
||||||
|
rom_size: 0xb100-0x4000,
|
||||||
|
data_start: 0xb100,
|
||||||
|
data_size: 0xb100-0xc000,
|
||||||
|
stack_end: 0xc000,
|
||||||
|
extra_compile_files: ['cpctelera.h'],
|
||||||
|
extra_link_args: ['crt0-cpc.rel', 'cpctelera.lib'],
|
||||||
|
extra_link_files: ['crt0-cpc.rel', 'crt0-cpc.lst', 'cpctelera.lib', 'cpctelera.lst'],
|
||||||
|
},
|
||||||
|
'pce': {
|
||||||
|
arch: 'huc6280',
|
||||||
|
define: ['__PCE__'],
|
||||||
|
cfgfile: 'pce.cfg',
|
||||||
|
libargs: ['pce.lib', '-D', '__CARTSIZE__=0x8000'],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
PLATFORM_PARAMS['sms-sms-libcv'] = PLATFORM_PARAMS['sms-sg1000-libcv'];
|
||||||
|
PLATFORM_PARAMS['sms-gg-libcv'] = PLATFORM_PARAMS['sms-sms-libcv'];
|
||||||
|
|
|
@ -2,10 +2,11 @@
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { spawn } from 'child_process';
|
import { spawn } from 'child_process';
|
||||||
import { CodeListingMap, WorkerBuildStep, WorkerError, WorkerErrorResult, WorkerFileUpdate, WorkerResult, isOutputResult } from '../../common/workertypes';
|
import { WorkerBuildStep, WorkerErrorResult, WorkerFileUpdate, WorkerResult, isOutputResult } from '../../common/workertypes';
|
||||||
import { getBasePlatform, getRootBasePlatform, replaceAll } from '../../common/util';
|
import { getRootBasePlatform, replaceAll } from '../../common/util';
|
||||||
import { BuildStep, makeErrorMatcher } from '../workermain';
|
|
||||||
import { parseObjDump } from './clang';
|
import { parseObjDump } from './clang';
|
||||||
|
import { BuildStep } from '../builder';
|
||||||
|
import { makeErrorMatcher } from '../listingutils';
|
||||||
|
|
||||||
|
|
||||||
const LLVM_MOS_TOOL: ServerBuildTool = {
|
const LLVM_MOS_TOOL: ServerBuildTool = {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { CodeListing, CodeListingMap } from "../../common/workertypes";
|
import { CodeListing, CodeListingMap } from "../../common/workertypes";
|
||||||
import { BuildStep, BuildStepResult, emglobal, execMain, fixParamsWithDefines, gatherFiles, loadNative, makeErrorMatcher, moduleInstFn, msvcErrorMatcher, populateFiles, print_fn, putWorkFile, setupFS, staleFiles } from "../workermain";
|
import { BuildStep, BuildStepResult, gatherFiles, staleFiles, populateFiles, fixParamsWithDefines, putWorkFile } from "../builder";
|
||||||
import { EmscriptenModule } from "../workermain"
|
import { msvcErrorMatcher } from "../listingutils";
|
||||||
|
import { loadNative, moduleInstFn, print_fn, setupFS, execMain, emglobal, EmscriptenModule } from "../wasmutils";
|
||||||
|
|
||||||
function parseACMESymbolTable(text: string) {
|
function parseACMESymbolTable(text: string) {
|
||||||
var symbolmap = {};
|
var symbolmap = {};
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
|
|
||||||
import { hex } from "../../common/util";
|
import { hex } from "../../common/util";
|
||||||
import { WorkerResult, CodeListingMap, WorkerError, SourceLine } from "../../common/workertypes";
|
import { CodeListingMap, SourceLine, WorkerError, WorkerResult } from "../../common/workertypes";
|
||||||
import { anyTargetChanged, BuildStep, BuildStepResult, emglobal, EmscriptenModule, execMain, gatherFiles, getPrefix, getWorkFileAsString, loadNative, makeErrorMatcher, moduleInstFn, populateFiles, putWorkFile, re_crlf, staleFiles } from "../workermain"
|
import { BuildStep, BuildStepResult, gatherFiles, staleFiles, populateFiles, putWorkFile, anyTargetChanged, getPrefix, getWorkFileAsString } from "../builder";
|
||||||
|
import { makeErrorMatcher, re_crlf } from "../listingutils";
|
||||||
|
import { loadNative, moduleInstFn, execMain, emglobal, EmscriptenModule } from "../wasmutils";
|
||||||
|
|
||||||
export function assembleARMIPS(step: BuildStep): WorkerResult {
|
export function assembleARMIPS(step: BuildStep): WorkerResult {
|
||||||
loadNative("armips");
|
loadNative("armips");
|
||||||
|
|
100
src/worker/tools/bataribasic.ts
Normal file
100
src/worker/tools/bataribasic.ts
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
import { BuildStep, BuildStepResult, gatherFiles, getWorkFileAsString, populateFiles, putWorkFile, staleFiles } from "../builder";
|
||||||
|
import { EmscriptenModule, emglobal, execMain, load, print_fn, setupFS, setupStdin } from "../wasmutils";
|
||||||
|
|
||||||
|
function preprocessBatariBasic(code: string): string {
|
||||||
|
load("bbpreprocess");
|
||||||
|
var bbout = "";
|
||||||
|
function addbbout_fn(s) {
|
||||||
|
bbout += s;
|
||||||
|
bbout += "\n";
|
||||||
|
}
|
||||||
|
var BBPRE: EmscriptenModule = emglobal.preprocess({
|
||||||
|
noInitialRun: true,
|
||||||
|
//logReadFiles:true,
|
||||||
|
print: addbbout_fn,
|
||||||
|
printErr: print_fn,
|
||||||
|
noFSInit: true,
|
||||||
|
});
|
||||||
|
var FS = BBPRE.FS;
|
||||||
|
setupStdin(FS, code);
|
||||||
|
BBPRE.callMain([]);
|
||||||
|
console.log("preprocess " + code.length + " -> " + bbout.length + " bytes");
|
||||||
|
return bbout;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function compileBatariBasic(step: BuildStep): BuildStepResult {
|
||||||
|
load("bb2600basic");
|
||||||
|
var params = step.params;
|
||||||
|
// stdout
|
||||||
|
var asmout = "";
|
||||||
|
function addasmout_fn(s) {
|
||||||
|
asmout += s;
|
||||||
|
asmout += "\n";
|
||||||
|
}
|
||||||
|
// stderr
|
||||||
|
var re_err1 = /[(](\d+)[)]:?\s*(.+)/;
|
||||||
|
var errors = [];
|
||||||
|
var errline = 0;
|
||||||
|
function match_fn(s) {
|
||||||
|
console.log(s);
|
||||||
|
var matches = re_err1.exec(s);
|
||||||
|
if (matches) {
|
||||||
|
errline = parseInt(matches[1]);
|
||||||
|
errors.push({
|
||||||
|
line: errline,
|
||||||
|
msg: matches[2]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gatherFiles(step, { mainFilePath: "main.bas" });
|
||||||
|
var destpath = step.prefix + '.asm';
|
||||||
|
if (staleFiles(step, [destpath])) {
|
||||||
|
var BB: EmscriptenModule = emglobal.bb2600basic({
|
||||||
|
noInitialRun: true,
|
||||||
|
//logReadFiles:true,
|
||||||
|
print: addasmout_fn,
|
||||||
|
printErr: match_fn,
|
||||||
|
noFSInit: true,
|
||||||
|
TOTAL_MEMORY: 64 * 1024 * 1024,
|
||||||
|
});
|
||||||
|
var FS = BB.FS;
|
||||||
|
populateFiles(step, FS);
|
||||||
|
// preprocess, pipe file to stdin
|
||||||
|
var code = getWorkFileAsString(step.path);
|
||||||
|
code = preprocessBatariBasic(code);
|
||||||
|
setupStdin(FS, code);
|
||||||
|
setupFS(FS, '2600basic');
|
||||||
|
execMain(step, BB, ["-i", "/share", step.path]);
|
||||||
|
if (errors.length)
|
||||||
|
return { errors: errors };
|
||||||
|
// build final assembly output from include file list
|
||||||
|
var includesout = FS.readFile("includes.bB", { encoding: 'utf8' });
|
||||||
|
var redefsout = FS.readFile("2600basic_variable_redefs.h", { encoding: 'utf8' });
|
||||||
|
var includes = includesout.trim().split("\n");
|
||||||
|
var combinedasm = "";
|
||||||
|
var splitasm = asmout.split("bB.asm file is split here");
|
||||||
|
for (var incfile of includes) {
|
||||||
|
var inctext;
|
||||||
|
if (incfile == "bB.asm")
|
||||||
|
inctext = splitasm[0];
|
||||||
|
else if (incfile == "bB2.asm")
|
||||||
|
inctext = splitasm[1];
|
||||||
|
else
|
||||||
|
inctext = FS.readFile("/share/includes/" + incfile, { encoding: 'utf8' });
|
||||||
|
console.log(incfile, inctext.length);
|
||||||
|
combinedasm += "\n\n;;;" + incfile + "\n\n";
|
||||||
|
combinedasm += inctext;
|
||||||
|
}
|
||||||
|
// TODO: ; bB.asm file is split here
|
||||||
|
putWorkFile(destpath, combinedasm);
|
||||||
|
putWorkFile("2600basic.h", FS.readFile("/share/includes/2600basic.h"));
|
||||||
|
putWorkFile("2600basic_variable_redefs.h", redefsout);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
nexttool: "dasm",
|
||||||
|
path: destpath,
|
||||||
|
args: [destpath],
|
||||||
|
files: [destpath, "2600basic.h", "2600basic_variable_redefs.h"],
|
||||||
|
bblines: true,
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,8 +1,9 @@
|
||||||
|
|
||||||
import { convertDataToUint8Array, getFilenamePrefix, getRootBasePlatform, safeident } from "../../common/util";
|
import { convertDataToUint8Array, getFilenamePrefix, getRootBasePlatform, safeident } from "../../common/util";
|
||||||
import { CodeListingMap, WorkerError } from "../../common/workertypes";
|
import { CodeListingMap, WorkerError } from "../../common/workertypes";
|
||||||
import { re_crlf, BuildStepResult, anyTargetChanged, execMain, gatherFiles, msvcErrorMatcher, populateEntry, populateExtraFiles, populateFiles, print_fn, putWorkFile, setupFS, staleFiles, BuildStep, emglobal, loadNative, moduleInstFn, fixParamsWithDefines, store, makeErrorMatcher, getWorkFileAsString } from "../workermain";
|
import { BuildStep, BuildStepResult, gatherFiles, staleFiles, populateFiles, fixParamsWithDefines, putWorkFile, populateExtraFiles, store, populateEntry, anyTargetChanged } from "../builder";
|
||||||
import { EmscriptenModule } from "../workermain"
|
import { re_crlf, makeErrorMatcher } from "../listingutils";
|
||||||
|
import { loadNative, moduleInstFn, print_fn, setupFS, execMain, emglobal, EmscriptenModule } from "../wasmutils";
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1,42 +1,12 @@
|
||||||
import { WASIFilesystem, WASIMemoryFilesystem, WASIRunner } from "../../common/wasi/wasishim";
|
import { WASIFilesystem, WASIMemoryFilesystem, WASIRunner } from "../../common/wasi/wasishim";
|
||||||
import { BuildStep, BuildStepResult, gatherFiles, getWASMBinary, loadNative, loadWASMBinary, makeErrorMatcher, putWorkFile, staleFiles, store } from "../workermain";
|
import { BuildStep, BuildStepResult, gatherFiles, staleFiles, store, putWorkFile } from "../builder";
|
||||||
import JSZip from 'jszip';
|
import { makeErrorMatcher } from "../listingutils";
|
||||||
|
import { loadWASIFilesystemZip } from "../wasiutils";
|
||||||
|
import { loadWASMBinary } from "../wasmutils";
|
||||||
|
|
||||||
let cc7800_fs: WASIFilesystem | null = null;
|
let cc7800_fs: WASIFilesystem | null = null;
|
||||||
let wasiModule: WebAssembly.Module | null = null;
|
let wasiModule: WebAssembly.Module | null = null;
|
||||||
|
|
||||||
function loadBlobSync(path: string) {
|
|
||||||
var xhr = new XMLHttpRequest();
|
|
||||||
xhr.responseType = 'blob';
|
|
||||||
xhr.open("GET", path, false); // synchronous request
|
|
||||||
xhr.send(null);
|
|
||||||
return xhr.response;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function loadWASIFilesystemZip(zippath: string) {
|
|
||||||
const jszip = new JSZip();
|
|
||||||
const path = '../../src/worker/fs/' + zippath;
|
|
||||||
const zipdata = loadBlobSync(path);
|
|
||||||
console.log(zippath, zipdata);
|
|
||||||
await jszip.loadAsync(zipdata);
|
|
||||||
let fs = new WASIMemoryFilesystem();
|
|
||||||
let promises = [];
|
|
||||||
jszip.forEach(async (relativePath, zipEntry) => {
|
|
||||||
if (zipEntry.dir) {
|
|
||||||
fs.putDirectory(relativePath);
|
|
||||||
} else {
|
|
||||||
let path = './' + relativePath;
|
|
||||||
let prom = zipEntry.async("uint8array").then((data) => {
|
|
||||||
fs.putFile(path, data);
|
|
||||||
});
|
|
||||||
promises.push(prom);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
await Promise.all(promises);
|
|
||||||
return fs;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export async function compileCC7800(step: BuildStep): Promise<BuildStepResult> {
|
export async function compileCC7800(step: BuildStep): Promise<BuildStepResult> {
|
||||||
const errors = [];
|
const errors = [];
|
||||||
gatherFiles(step, { mainFilePath: "main.c" });
|
gatherFiles(step, { mainFilePath: "main.c" });
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
import { WASIRunner } from "../../common/wasi/wasishim";
|
||||||
import { CodeListingMap, WorkerError } from "../../common/workertypes";
|
import { CodeListingMap, WorkerError } from "../../common/workertypes";
|
||||||
import { re_crlf, BuildStep, BuildStepResult, load, msvcErrorMatcher, emglobal, populateFiles, execMain, putWorkFile, anyTargetChanged, re_msvc, gatherFiles, getWorkFileAsString, print_fn, setupFS, setupStdin, staleFiles } from "../workermain";
|
import { BuildStep, BuildStepResult, populateFiles, putWorkFile, anyTargetChanged, store } from "../builder";
|
||||||
import { EmscriptenModule } from "../workermain"
|
import { msvcErrorMatcher, re_crlf, re_msvc } from "../listingutils";
|
||||||
|
import { execMain, emglobal, EmscriptenModule, load, loadWASMBinary } from "../wasmutils";
|
||||||
|
|
||||||
function parseDASMListing(lstpath: string, lsttext: string, listings: CodeListingMap, errors: WorkerError[], unresolved: {}) {
|
function parseDASMListing(lstpath: string, lsttext: string, listings: CodeListingMap, errors: WorkerError[], unresolved: {}) {
|
||||||
// TODO: this gets very slow
|
// TODO: this gets very slow
|
||||||
|
@ -118,9 +120,21 @@ function parseDASMListing(lstpath: string, lsttext: string, listings: CodeListin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var re_usl = /(\w+)\s+0000\s+[?][?][?][?]/;
|
||||||
|
|
||||||
|
function parseSymbolMap(asym: string) {
|
||||||
|
var symbolmap = {};
|
||||||
|
for (var s of asym.split("\n")) {
|
||||||
|
var toks = s.split(/\s+/);
|
||||||
|
if (toks && toks.length >= 2 && !toks[0].startsWith('-')) {
|
||||||
|
symbolmap[toks[0]] = parseInt(toks[1], 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return symbolmap;
|
||||||
|
}
|
||||||
|
|
||||||
export function assembleDASM(step: BuildStep): BuildStepResult {
|
export function assembleDASM(step: BuildStep): BuildStepResult {
|
||||||
load("dasm");
|
load("dasm");
|
||||||
var re_usl = /(\w+)\s+0000\s+[?][?][?][?]/;
|
|
||||||
var unresolved = {};
|
var unresolved = {};
|
||||||
var errors = [];
|
var errors = [];
|
||||||
var errorMatcher = msvcErrorMatcher(errors);
|
var errorMatcher = msvcErrorMatcher(errors);
|
||||||
|
@ -187,13 +201,7 @@ export function assembleDASM(step: BuildStep): BuildStepResult {
|
||||||
// TODO: what if listing or symbols change?
|
// TODO: what if listing or symbols change?
|
||||||
if (!anyTargetChanged(step, [binpath/*, lstpath, sympath*/]))
|
if (!anyTargetChanged(step, [binpath/*, lstpath, sympath*/]))
|
||||||
return;
|
return;
|
||||||
var symbolmap = {};
|
const symbolmap = parseSymbolMap(asym);
|
||||||
for (var s of asym.split("\n")) {
|
|
||||||
var toks = s.split(/\s+/);
|
|
||||||
if (toks && toks.length >= 2 && !toks[0].startsWith('-')) {
|
|
||||||
symbolmap[toks[0]] = parseInt(toks[1], 16);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// for bataribasic (TODO)
|
// for bataribasic (TODO)
|
||||||
if (step['bblines']) {
|
if (step['bblines']) {
|
||||||
let lst = listings[step.path];
|
let lst = listings[step.path];
|
||||||
|
@ -211,101 +219,55 @@ export function assembleDASM(step: BuildStep): BuildStepResult {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let wasiModule: WebAssembly.Module | null = null;
|
||||||
|
|
||||||
function preprocessBatariBasic(code: string): string {
|
export function assembleDASM2(step: BuildStep): BuildStepResult {
|
||||||
load("bbpreprocess");
|
const errors = [];
|
||||||
var bbout = "";
|
if (!wasiModule) {
|
||||||
function addbbout_fn(s) {
|
wasiModule = new WebAssembly.Module(loadWASMBinary("dasm-wasisdk"));
|
||||||
bbout += s;
|
|
||||||
bbout += "\n";
|
|
||||||
}
|
}
|
||||||
var BBPRE: EmscriptenModule = emglobal.preprocess({
|
const binpath = 'a.out';
|
||||||
noInitialRun: true,
|
const lstpath = step.prefix + '.lst';
|
||||||
//logReadFiles:true,
|
const sympath = step.prefix + '.sym';
|
||||||
print: addbbout_fn,
|
const wasi = new WASIRunner();
|
||||||
printErr: print_fn,
|
wasi.initSync(wasiModule);
|
||||||
noFSInit: true,
|
for (let file of step.files) {
|
||||||
});
|
wasi.fs.putFile("./" + file, store.getFileData(file));
|
||||||
var FS = BBPRE.FS;
|
|
||||||
setupStdin(FS, code);
|
|
||||||
BBPRE.callMain([]);
|
|
||||||
console.log("preprocess " + code.length + " -> " + bbout.length + " bytes");
|
|
||||||
return bbout;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function compileBatariBasic(step: BuildStep): BuildStepResult {
|
|
||||||
load("bb2600basic");
|
|
||||||
var params = step.params;
|
|
||||||
// stdout
|
|
||||||
var asmout = "";
|
|
||||||
function addasmout_fn(s) {
|
|
||||||
asmout += s;
|
|
||||||
asmout += "\n";
|
|
||||||
}
|
}
|
||||||
// stderr
|
wasi.addPreopenDirectory(".");
|
||||||
var re_err1 = /[(](\d+)[)]:?\s*(.+)/;
|
wasi.setArgs(['dasm', step.path, '-f3', "-l" + lstpath, "-s" + sympath]);
|
||||||
var errors = [];
|
try {
|
||||||
var errline = 0;
|
wasi.run();
|
||||||
function match_fn(s) {
|
} catch (e) {
|
||||||
console.log(s);
|
errors.push(e);
|
||||||
var matches = re_err1.exec(s);
|
}
|
||||||
if (matches) {
|
const stdout = wasi.fds[1].getBytesAsString();
|
||||||
errline = parseInt(matches[1]);
|
//const stderr = wasi.fds[2].getBytesAsString();
|
||||||
errors.push({
|
const matcher = msvcErrorMatcher(errors);
|
||||||
line: errline,
|
const unresolved = {};
|
||||||
msg: matches[2]
|
for (let line of stdout.split("\n")) {
|
||||||
});
|
matcher(line);
|
||||||
|
let m = re_usl.exec(line);
|
||||||
|
if (m) {
|
||||||
|
unresolved[m[1]] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gatherFiles(step, { mainFilePath: "main.bas" });
|
const alst = wasi.fs.getFile("./" + lstpath).getBytesAsString();
|
||||||
var destpath = step.prefix + '.asm';
|
const listings: CodeListingMap = {};
|
||||||
if (staleFiles(step, [destpath])) {
|
for (let path of step.files) {
|
||||||
var BB: EmscriptenModule = emglobal.bb2600basic({
|
listings[path] = { lines: [] };
|
||||||
noInitialRun: true,
|
|
||||||
//logReadFiles:true,
|
|
||||||
print: addasmout_fn,
|
|
||||||
printErr: match_fn,
|
|
||||||
noFSInit: true,
|
|
||||||
TOTAL_MEMORY: 64 * 1024 * 1024,
|
|
||||||
});
|
|
||||||
var FS = BB.FS;
|
|
||||||
populateFiles(step, FS);
|
|
||||||
// preprocess, pipe file to stdin
|
|
||||||
var code = getWorkFileAsString(step.path);
|
|
||||||
code = preprocessBatariBasic(code);
|
|
||||||
setupStdin(FS, code);
|
|
||||||
setupFS(FS, '2600basic');
|
|
||||||
execMain(step, BB, ["-i", "/share", step.path]);
|
|
||||||
if (errors.length)
|
|
||||||
return { errors: errors };
|
|
||||||
// build final assembly output from include file list
|
|
||||||
var includesout = FS.readFile("includes.bB", { encoding: 'utf8' });
|
|
||||||
var redefsout = FS.readFile("2600basic_variable_redefs.h", { encoding: 'utf8' });
|
|
||||||
var includes = includesout.trim().split("\n");
|
|
||||||
var combinedasm = "";
|
|
||||||
var splitasm = asmout.split("bB.asm file is split here");
|
|
||||||
for (var incfile of includes) {
|
|
||||||
var inctext;
|
|
||||||
if (incfile == "bB.asm")
|
|
||||||
inctext = splitasm[0];
|
|
||||||
else if (incfile == "bB2.asm")
|
|
||||||
inctext = splitasm[1];
|
|
||||||
else
|
|
||||||
inctext = FS.readFile("/share/includes/" + incfile, { encoding: 'utf8' });
|
|
||||||
console.log(incfile, inctext.length);
|
|
||||||
combinedasm += "\n\n;;;" + incfile + "\n\n";
|
|
||||||
combinedasm += inctext;
|
|
||||||
}
|
|
||||||
// TODO: ; bB.asm file is split here
|
|
||||||
putWorkFile(destpath, combinedasm);
|
|
||||||
putWorkFile("2600basic.h", FS.readFile("/share/includes/2600basic.h"));
|
|
||||||
putWorkFile("2600basic_variable_redefs.h", redefsout);
|
|
||||||
}
|
}
|
||||||
|
parseDASMListing(lstpath, alst, listings, errors, unresolved);
|
||||||
|
if (errors.length) {
|
||||||
|
return { errors: errors };
|
||||||
|
}
|
||||||
|
const asym = wasi.fs.getFile("./" + sympath).getBytesAsString();
|
||||||
|
const symbolmap = parseSymbolMap(asym);
|
||||||
|
const output = wasi.fs.getFile("./" + binpath).getBytes();
|
||||||
return {
|
return {
|
||||||
nexttool: "dasm",
|
output,
|
||||||
path: destpath,
|
errors,
|
||||||
args: [destpath],
|
listings,
|
||||||
files: [destpath, "2600basic.h", "2600basic_variable_redefs.h"],
|
symbolmap
|
||||||
bblines: true,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { ECSCompiler } from "../../common/ecs/compiler";
|
||||||
import { Dialect_CA65, ECSError, EntityManager } from "../../common/ecs/ecs";
|
import { Dialect_CA65, ECSError, EntityManager } from "../../common/ecs/ecs";
|
||||||
import { CompileError } from "../../common/tokenizer";
|
import { CompileError } from "../../common/tokenizer";
|
||||||
import { CodeListingMap } from "../../common/workertypes";
|
import { CodeListingMap } from "../../common/workertypes";
|
||||||
import { BuildStep, BuildStepResult, fixParamsWithDefines, gatherFiles, getWorkFileAsString, putWorkFile, staleFiles } from "../workermain";
|
import { BuildStep, BuildStepResult, getWorkFileAsString, gatherFiles, staleFiles, fixParamsWithDefines, putWorkFile } from "../builder";
|
||||||
|
|
||||||
export function assembleECS(step: BuildStep): BuildStepResult {
|
export function assembleECS(step: BuildStep): BuildStepResult {
|
||||||
let em = new EntityManager(new Dialect_CA65()); // TODO
|
let em = new EntityManager(new Dialect_CA65()); // TODO
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
|
|
||||||
import { WorkerError, CodeListingMap } from "../../common/workertypes";
|
import { WorkerError, CodeListingMap } from "../../common/workertypes";
|
||||||
import { anyTargetChanged, BuildStep, BuildStepResult, emglobal, EmscriptenModule, execMain, gatherFiles, loadNative, makeErrorMatcher, moduleInstFn, parseListing, populateFiles, print_fn, putWorkFile, staleFiles } from "../workermain"
|
import { BuildStep, BuildStepResult, populateFiles, putWorkFile, anyTargetChanged, gatherFiles, staleFiles } from "../builder";
|
||||||
|
import { parseListing, makeErrorMatcher } from "../listingutils";
|
||||||
|
import { loadNative, emglobal, moduleInstFn, execMain, print_fn } from "../wasmutils";
|
||||||
|
import { EmscriptenModule } from "../wasmutils";
|
||||||
|
|
||||||
// http://www.nespowerpak.com/nesasm/
|
// http://www.nespowerpak.com/nesasm/
|
||||||
export function assembleNESASM(step: BuildStep): BuildStepResult {
|
export function assembleNESASM(step: BuildStep): BuildStepResult {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import { CodeListingMap, WorkerError } from "../../common/workertypes";
|
import { CodeListingMap, WorkerError } from "../../common/workertypes";
|
||||||
import { BuildStep, BuildStepResult, load, emglobal, print_fn, populateFiles, execMain, putWorkFile, parseListing, loadNative, gatherFiles, staleFiles, moduleInstFn, getWorkFileAsString, preprocessMCPP, fixParamsWithDefines, msvcErrorMatcher, populateExtraFiles, anyTargetChanged, parseSourceLines } from "../workermain";
|
import { BuildStep, BuildStepResult, populateFiles, putWorkFile, gatherFiles, staleFiles, getWorkFileAsString, fixParamsWithDefines, populateExtraFiles, anyTargetChanged } from "../builder";
|
||||||
import { EmscriptenModule } from "../workermain";
|
import { parseListing, msvcErrorMatcher, parseSourceLines } from "../listingutils";
|
||||||
|
import { EmscriptenModule, emglobal, execMain, load, loadNative, moduleInstFn, print_fn } from "../wasmutils";
|
||||||
|
import { preprocessMCPP } from "./mcpp";
|
||||||
|
|
||||||
// http://datapipe-blackbeltsystems.com/windows/flex/asm09.html
|
// http://datapipe-blackbeltsystems.com/windows/flex/asm09.html
|
||||||
export function assembleXASM6809(step: BuildStep): BuildStepResult {
|
export function assembleXASM6809(step: BuildStep): BuildStepResult {
|
||||||
|
|
64
src/worker/tools/mcpp.ts
Normal file
64
src/worker/tools/mcpp.ts
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
import { getBasePlatform } from "../../common/util";
|
||||||
|
import { BuildStep, populateFiles, populateExtraFiles, errorResult } from "../builder";
|
||||||
|
import { makeErrorMatcher, extractErrors } from "../listingutils";
|
||||||
|
import { PLATFORM_PARAMS } from "../platforms";
|
||||||
|
import { load, print_fn, setupFS, execMain, emglobal, EmscriptenModule } from "../wasmutils";
|
||||||
|
|
||||||
|
function makeCPPSafe(s: string): string {
|
||||||
|
return s.replace(/[^A-Za-z0-9_]/g, '_');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function preprocessMCPP(step: BuildStep, filesys: string) {
|
||||||
|
load("mcpp");
|
||||||
|
var platform = step.platform;
|
||||||
|
var params = PLATFORM_PARAMS[getBasePlatform(platform)];
|
||||||
|
if (!params) throw Error("Platform not supported: " + platform);
|
||||||
|
// <stdin>:2: error: Can't open include file "foo.h"
|
||||||
|
var errors = [];
|
||||||
|
var match_fn = makeErrorMatcher(errors, /<stdin>:(\d+): (.+)/, 1, 2, step.path);
|
||||||
|
var MCPP: EmscriptenModule = emglobal.mcpp({
|
||||||
|
noInitialRun: true,
|
||||||
|
noFSInit: true,
|
||||||
|
print: print_fn,
|
||||||
|
printErr: match_fn,
|
||||||
|
});
|
||||||
|
var FS = MCPP.FS;
|
||||||
|
if (filesys) setupFS(FS, filesys);
|
||||||
|
populateFiles(step, FS);
|
||||||
|
populateExtraFiles(step, FS, params.extra_compile_files);
|
||||||
|
// TODO: make configurable by other compilers
|
||||||
|
var args = [
|
||||||
|
"-D", "__8BITWORKSHOP__",
|
||||||
|
"-D", "__SDCC_z80",
|
||||||
|
"-D", makeCPPSafe(platform.toUpperCase()),
|
||||||
|
"-I", "/share/include",
|
||||||
|
"-Q",
|
||||||
|
step.path, "main.i"];
|
||||||
|
if (step.mainfile) {
|
||||||
|
args.unshift.apply(args, ["-D", "__MAIN__"]);
|
||||||
|
}
|
||||||
|
let platform_def = (platform.toUpperCase() as any).replaceAll(/[^a-zA-Z0-9]/g, '_');
|
||||||
|
args.unshift.apply(args, ["-D", `__PLATFORM_${platform_def}__`]);
|
||||||
|
if (params.extra_preproc_args) {
|
||||||
|
args.push.apply(args, params.extra_preproc_args);
|
||||||
|
}
|
||||||
|
execMain(step, MCPP, args);
|
||||||
|
if (errors.length)
|
||||||
|
return { errors: errors };
|
||||||
|
var iout = FS.readFile("main.i", { encoding: 'utf8' });
|
||||||
|
iout = iout.replace(/^#line /gm, '\n# ');
|
||||||
|
try {
|
||||||
|
var errout = FS.readFile("mcpp.err", { encoding: 'utf8' });
|
||||||
|
if (errout.length) {
|
||||||
|
// //main.c:2: error: Can't open include file "stdiosd.h"
|
||||||
|
var errors = extractErrors(/([^:]+):(\d+): (.+)/, errout.split("\n"), step.path, 2, 3, 1);
|
||||||
|
if (errors.length == 0) {
|
||||||
|
errors = errorResult(errout).errors;
|
||||||
|
}
|
||||||
|
return { errors: errors };
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
return { code: iout };
|
||||||
|
}
|
|
@ -1,8 +1,10 @@
|
||||||
import { Segment, CodeListingMap, WorkerResult, WorkerError } from "../../common/workertypes";
|
import { Segment, CodeListingMap, WorkerResult, WorkerError } from "../../common/workertypes";
|
||||||
import { BuildStep, BuildStepResult, setupRequireFunction, load, emglobal, getWorkFileAsString, loadNative, gatherFiles, staleFiles, msvcErrorMatcher, moduleInstFn, setupFS, populateFiles, execMain, putWorkFile, anyTargetChanged, parseListing, print_fn, makeErrorMatcher, populateExtraFiles } from "../workermain";
|
|
||||||
import { EmscriptenModule } from "../workermain"
|
|
||||||
import * as basic_compiler from '../../common/basic/compiler';
|
import * as basic_compiler from '../../common/basic/compiler';
|
||||||
import { getRootBasePlatform, parseXMLPoorly } from "../../common/util";
|
import { getRootBasePlatform, parseXMLPoorly } from "../../common/util";
|
||||||
|
import { EmscriptenModule, emglobal, execMain, load, loadNative, moduleInstFn, print_fn, setupFS } from "../wasmutils";
|
||||||
|
import { BuildStep, BuildStepResult, getWorkFileAsString, gatherFiles, staleFiles, populateFiles, putWorkFile, anyTargetChanged, populateExtraFiles } from "../builder";
|
||||||
|
import { msvcErrorMatcher, parseListing, makeErrorMatcher } from "../listingutils";
|
||||||
|
import { setupRequireFunction } from "../workermain";
|
||||||
|
|
||||||
export function translateShowdown(step: BuildStep): BuildStepResult {
|
export function translateShowdown(step: BuildStep): BuildStepResult {
|
||||||
setupRequireFunction();
|
setupRequireFunction();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { byteArrayToString, stringToByteArray } from "../../common/util";
|
import { byteArrayToString, stringToByteArray } from "../../common/util";
|
||||||
import { WorkerFileUpdate, isErrorResult, isOutputResult, isUnchanged } from "../../common/workertypes";
|
import { WorkerFileUpdate, isErrorResult, isOutputResult, isUnchanged } from "../../common/workertypes";
|
||||||
import { BuildStep, BuildStepResult, gatherFiles, staleFiles, store } from "../workermain";
|
import { BuildStep, BuildStepResult, gatherFiles, staleFiles, store } from "../builder";
|
||||||
|
|
||||||
// create random UID
|
// create random UID
|
||||||
const sessionID = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
|
const sessionID = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import { CodeListingMap } from "../../common/workertypes";
|
import { CodeListingMap } from "../../common/workertypes";
|
||||||
import { BuildStep, BuildStepResult, loadNative, gatherFiles, staleFiles, emglobal, moduleInstFn, populateFiles, execMain, putWorkFile, setupFS, populateExtraFiles, anyTargetChanged, parseListing, print_fn, msvcErrorMatcher, getWorkFileAsString, setupStdin, preprocessMCPP, parseSourceLines } from "../workermain";
|
import { BuildStep, BuildStepResult, gatherFiles, staleFiles, populateFiles, putWorkFile, populateExtraFiles, anyTargetChanged, getWorkFileAsString } from "../builder";
|
||||||
import { EmscriptenModule } from "../workermain"
|
import { parseListing, parseSourceLines, msvcErrorMatcher } from "../listingutils";
|
||||||
|
import { EmscriptenModule, emglobal, execMain, loadNative, moduleInstFn, print_fn, setupFS, setupStdin } from "../wasmutils";
|
||||||
|
import { preprocessMCPP } from "./mcpp";
|
||||||
|
|
||||||
function hexToArray(s, ofs) {
|
function hexToArray(s, ofs) {
|
||||||
var buf = new ArrayBuffer(s.length / 2);
|
var buf = new ArrayBuffer(s.length / 2);
|
||||||
|
|
|
@ -4,8 +4,9 @@
|
||||||
import { WorkerError, CodeListingMap, SourceLocation } from "../../common/workertypes";
|
import { WorkerError, CodeListingMap, SourceLocation } from "../../common/workertypes";
|
||||||
import { Assembler } from "../assembler";
|
import { Assembler } from "../assembler";
|
||||||
import * as vxmlparser from '../../common/hdl/vxmlparser';
|
import * as vxmlparser from '../../common/hdl/vxmlparser';
|
||||||
import { getWorkFileAsString, BuildStep, BuildStepResult, gatherFiles, loadNative, staleFiles, makeErrorMatcher, emglobal, moduleInstFn, print_fn, populateFiles, execMain, putWorkFile, anyTargetChanged, endtime, getWASMMemory, starttime, populateExtraFiles, setupFS } from "../workermain";
|
import { EmscriptenModule, emglobal, execMain, getWASMMemory, loadNative, moduleInstFn, print_fn, setupFS } from "../wasmutils";
|
||||||
import { EmscriptenModule } from "../workermain"
|
import { getWorkFileAsString, BuildStep, BuildStepResult, gatherFiles, staleFiles, populateFiles, starttime, endtime, putWorkFile, anyTargetChanged, populateExtraFiles } from "../builder";
|
||||||
|
import { makeErrorMatcher } from "../listingutils";
|
||||||
|
|
||||||
function detectModuleName(code: string) {
|
function detectModuleName(code: string) {
|
||||||
var m = /^\s*module\s+(\w+_top)\b/m.exec(code)
|
var m = /^\s*module\s+(\w+_top)\b/m.exec(code)
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import { WorkerError, CodeListingMap } from "../../common/workertypes";
|
import { WorkerError, CodeListingMap } from "../../common/workertypes";
|
||||||
import { BuildStep, BuildStepResult, loadNative, gatherFiles, staleFiles, emglobal, moduleInstFn, getWorkFileAsString, preprocessMCPP, populateFiles, fixParamsWithDefines, execMain, putWorkFile, print_fn, msvcErrorMatcher, anyTargetChanged, parseListing } from "../workermain";
|
import { BuildStep, BuildStepResult, gatherFiles, staleFiles, getWorkFileAsString, populateFiles, fixParamsWithDefines, putWorkFile, anyTargetChanged } from "../builder";
|
||||||
import { EmscriptenModule } from "../workermain"
|
import { msvcErrorMatcher, parseListing } from "../listingutils";
|
||||||
|
import { EmscriptenModule, emglobal, execMain, loadNative, moduleInstFn, print_fn } from "../wasmutils";
|
||||||
|
import { preprocessMCPP } from "./mcpp";
|
||||||
|
|
||||||
// http://www.techhelpmanual.com/829-program_startup___exit.html
|
// http://www.techhelpmanual.com/829-program_startup___exit.html
|
||||||
export function compileSmallerC(step: BuildStep): BuildStepResult {
|
export function compileSmallerC(step: BuildStep): BuildStepResult {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
|
||||||
import { CodeListingMap } from "../../common/workertypes";
|
import { CodeListingMap } from "../../common/workertypes";
|
||||||
import { anyTargetChanged, BuildStep, BuildStepResult, emglobal, EmscriptenModule, execMain, gatherFiles, loadNative, makeErrorMatcher, moduleInstFn, parseListing, populateFiles, print_fn, putWorkFile, staleFiles } from "../workermain"
|
import { BuildStep, BuildStepResult, gatherFiles, staleFiles, populateFiles, putWorkFile, anyTargetChanged } from "../builder";
|
||||||
|
import { makeErrorMatcher, parseListing } from "../listingutils";
|
||||||
|
import { EmscriptenModule, emglobal, execMain, loadNative, moduleInstFn, print_fn } from "../wasmutils";
|
||||||
|
|
||||||
|
|
||||||
export function assembleZMAC(step: BuildStep): BuildStepResult {
|
export function assembleZMAC(step: BuildStep): BuildStepResult {
|
||||||
|
|
33
src/worker/wasiutils.ts
Normal file
33
src/worker/wasiutils.ts
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
import JSZip from 'jszip';
|
||||||
|
import { WASIMemoryFilesystem } from "../common/wasi/wasishim";
|
||||||
|
|
||||||
|
export function loadBlobSync(path: string) {
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
xhr.responseType = 'blob';
|
||||||
|
xhr.open("GET", path, false); // synchronous request
|
||||||
|
xhr.send(null);
|
||||||
|
return xhr.response;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function loadWASIFilesystemZip(zippath: string) {
|
||||||
|
const jszip = new JSZip();
|
||||||
|
const path = '../../src/worker/fs/' + zippath;
|
||||||
|
const zipdata = loadBlobSync(path);
|
||||||
|
console.log(zippath, zipdata);
|
||||||
|
await jszip.loadAsync(zipdata);
|
||||||
|
let fs = new WASIMemoryFilesystem();
|
||||||
|
let promises = [];
|
||||||
|
jszip.forEach(async (relativePath, zipEntry) => {
|
||||||
|
if (zipEntry.dir) {
|
||||||
|
fs.putDirectory(relativePath);
|
||||||
|
} else {
|
||||||
|
let path = './' + relativePath;
|
||||||
|
let prom = zipEntry.async("uint8array").then((data) => {
|
||||||
|
fs.putFile(path, data);
|
||||||
|
});
|
||||||
|
promises.push(prom);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await Promise.all(promises);
|
||||||
|
return fs;
|
||||||
|
}
|
188
src/worker/wasmutils.ts
Normal file
188
src/worker/wasmutils.ts
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
|
||||||
|
// WebAssembly module cache
|
||||||
|
// for Emscripten-compiled functions
|
||||||
|
|
||||||
|
import { BuildStep, PWORKER, endtime, starttime } from "./builder";
|
||||||
|
|
||||||
|
/// <reference types="emscripten" />
|
||||||
|
export interface EmscriptenModule {
|
||||||
|
callMain: (args: string[]) => void;
|
||||||
|
FS: any; // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
declare function importScripts(path: string);
|
||||||
|
|
||||||
|
const ENVIRONMENT_IS_WEB = typeof window === 'object';
|
||||||
|
const ENVIRONMENT_IS_WORKER = typeof importScripts === 'function';
|
||||||
|
export const emglobal: any = ENVIRONMENT_IS_WORKER ? self : ENVIRONMENT_IS_WEB ? window : global;
|
||||||
|
|
||||||
|
// simple CommonJS module loader
|
||||||
|
// TODO: relative paths for dependencies
|
||||||
|
if (!emglobal['require']) {
|
||||||
|
emglobal['require'] = (modpath: string) => {
|
||||||
|
if (modpath.endsWith('.js')) modpath = modpath.slice(-3);
|
||||||
|
var modname = modpath.split('/').slice(-1)[0];
|
||||||
|
var hasNamespace = emglobal[modname] != null;
|
||||||
|
console.log('@@@ require', modname, modpath, hasNamespace);
|
||||||
|
if (!hasNamespace) {
|
||||||
|
exports = {};
|
||||||
|
importScripts(`${modpath}.js`);
|
||||||
|
}
|
||||||
|
if (emglobal[modname] == null) {
|
||||||
|
emglobal[modname] = exports; // TODO: always put in global scope?
|
||||||
|
}
|
||||||
|
return emglobal[modname]; // TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: leaks memory even when disabled...
|
||||||
|
var _WASM_module_cache = {};
|
||||||
|
var CACHE_WASM_MODULES = true; // if false, use asm.js only
|
||||||
|
|
||||||
|
// TODO: which modules need this?
|
||||||
|
var wasmMemory;
|
||||||
|
export function getWASMMemory() {
|
||||||
|
if (wasmMemory == null) {
|
||||||
|
wasmMemory = new WebAssembly.Memory({
|
||||||
|
'initial': 1024, // 64MB
|
||||||
|
'maximum': 16384, // 1024MB
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return wasmMemory;
|
||||||
|
}
|
||||||
|
export function getWASMBinary(module_id: string) {
|
||||||
|
return wasmBlob[module_id];
|
||||||
|
}
|
||||||
|
function getWASMModule(module_id: string) {
|
||||||
|
var module = _WASM_module_cache[module_id];
|
||||||
|
if (!module) {
|
||||||
|
starttime();
|
||||||
|
module = new WebAssembly.Module(wasmBlob[module_id]);
|
||||||
|
if (CACHE_WASM_MODULES) {
|
||||||
|
_WASM_module_cache[module_id] = module;
|
||||||
|
delete wasmBlob[module_id];
|
||||||
|
}
|
||||||
|
endtime("module creation " + module_id);
|
||||||
|
}
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
// function for use with instantiateWasm
|
||||||
|
export function moduleInstFn(module_id: string) {
|
||||||
|
return function (imports, ri) {
|
||||||
|
var mod = getWASMModule(module_id);
|
||||||
|
var inst = new WebAssembly.Instance(mod, imports);
|
||||||
|
ri(inst);
|
||||||
|
return inst.exports;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function execMain(step: BuildStep, mod, args: string[]) {
|
||||||
|
starttime();
|
||||||
|
var run = mod.callMain || mod.run; // TODO: run?
|
||||||
|
run(args);
|
||||||
|
endtime(step.tool);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// asm.js / WASM / filesystem loading
|
||||||
|
|
||||||
|
export var fsMeta = {};
|
||||||
|
var fsBlob = {};
|
||||||
|
var wasmBlob = {};
|
||||||
|
|
||||||
|
// load filesystems for CC65 and others asynchronously
|
||||||
|
export function loadFilesystem(name: string) {
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
xhr.responseType = 'blob';
|
||||||
|
xhr.open("GET", PWORKER + "fs/fs" + name + ".data", false); // synchronous request
|
||||||
|
xhr.send(null);
|
||||||
|
fsBlob[name] = xhr.response;
|
||||||
|
xhr = new XMLHttpRequest();
|
||||||
|
xhr.responseType = 'json';
|
||||||
|
xhr.open("GET", PWORKER + "fs/fs" + name + ".js.metadata", false); // synchronous request
|
||||||
|
xhr.send(null);
|
||||||
|
fsMeta[name] = xhr.response;
|
||||||
|
console.log("Loaded " + name + " filesystem", fsMeta[name].files.length, 'files', fsBlob[name].size, 'bytes');
|
||||||
|
}
|
||||||
|
|
||||||
|
var loaded = {};
|
||||||
|
export function load(modulename: string, debug?: boolean) {
|
||||||
|
if (!loaded[modulename]) {
|
||||||
|
importScripts(PWORKER + 'asmjs/' + modulename + (debug ? "." + debug + ".js" : ".js"));
|
||||||
|
loaded[modulename] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export function loadWASMBinary(modulename: string) {
|
||||||
|
if (!loaded[modulename]) {
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
xhr.responseType = 'arraybuffer';
|
||||||
|
xhr.open("GET", PWORKER + "wasm/" + modulename + ".wasm", false); // synchronous request
|
||||||
|
xhr.send(null);
|
||||||
|
if (xhr.response) {
|
||||||
|
wasmBlob[modulename] = new Uint8Array(xhr.response);
|
||||||
|
console.log("Loaded " + modulename + ".wasm (" + wasmBlob[modulename].length + " bytes)");
|
||||||
|
loaded[modulename] = 1;
|
||||||
|
} else {
|
||||||
|
throw Error("Could not load WASM file " + modulename + ".wasm");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return wasmBlob[modulename];
|
||||||
|
}
|
||||||
|
export function loadWASM(modulename: string, debug?: boolean) {
|
||||||
|
if (!loaded[modulename]) {
|
||||||
|
importScripts(PWORKER + "wasm/" + modulename + (debug ? "." + debug + ".js" : ".js"));
|
||||||
|
loadWASMBinary(modulename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export function loadNative(modulename: string) {
|
||||||
|
// detect WASM
|
||||||
|
if (CACHE_WASM_MODULES && typeof WebAssembly === 'object') {
|
||||||
|
loadWASM(modulename);
|
||||||
|
} else {
|
||||||
|
load(modulename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// mount the filesystem at /share
|
||||||
|
export function setupFS(FS, name: string) {
|
||||||
|
var WORKERFS = FS.filesystems['WORKERFS'];
|
||||||
|
if (name === '65-vector') name = '65-none'; // TODO
|
||||||
|
if (name === '65-atari7800') name = '65-none'; // TODO
|
||||||
|
if (name === '65-devel') name = '65-none'; // TODO
|
||||||
|
if (name === '65-vcs') name = '65-atari2600'; // TODO
|
||||||
|
if (!fsMeta[name]) throw Error("No filesystem for '" + name + "'");
|
||||||
|
FS.mkdir('/share');
|
||||||
|
FS.mount(WORKERFS, {
|
||||||
|
packages: [{ metadata: fsMeta[name], blob: fsBlob[name] }]
|
||||||
|
}, '/share');
|
||||||
|
// fix for slow Blob operations by caching typed arrays
|
||||||
|
// https://github.com/kripken/emscripten/blob/incoming/src/library_workerfs.js
|
||||||
|
// https://bugs.chromium.org/p/chromium/issues/detail?id=349304#c30
|
||||||
|
var reader = WORKERFS.reader;
|
||||||
|
var blobcache = {};
|
||||||
|
WORKERFS.stream_ops.read = function (stream, buffer, offset, length, position) {
|
||||||
|
if (position >= stream.node.size) return 0;
|
||||||
|
var contents = blobcache[stream.path];
|
||||||
|
if (!contents) {
|
||||||
|
var ab = reader.readAsArrayBuffer(stream.node.contents);
|
||||||
|
contents = blobcache[stream.path] = new Uint8Array(ab);
|
||||||
|
}
|
||||||
|
if (position + length > contents.length)
|
||||||
|
length = contents.length - position;
|
||||||
|
for (var i = 0; i < length; i++) {
|
||||||
|
buffer[offset + i] = contents[position + i];
|
||||||
|
}
|
||||||
|
return length;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export var print_fn = function (s: string) {
|
||||||
|
console.log(s);
|
||||||
|
//console.log(new Error().stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setupStdin(fs, code: string) {
|
||||||
|
var i = 0;
|
||||||
|
fs.init(
|
||||||
|
function () { return i < code.length ? code.charCodeAt(i++) : null; }
|
||||||
|
);
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
90
src/worker/workertools.ts
Normal file
90
src/worker/workertools.ts
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
|
||||||
|
import * as misc from './tools/misc'
|
||||||
|
import * as cc65 from './tools/cc65'
|
||||||
|
import * as dasm from './tools/dasm'
|
||||||
|
import * as sdcc from './tools/sdcc'
|
||||||
|
import * as verilog from './tools/verilog'
|
||||||
|
import * as m6809 from './tools/m6809'
|
||||||
|
import * as m6502 from './tools/m6502'
|
||||||
|
import * as z80 from './tools/z80'
|
||||||
|
import * as x86 from './tools/x86'
|
||||||
|
import * as arm from './tools/arm'
|
||||||
|
import * as ecs from './tools/ecs'
|
||||||
|
import * as remote from './tools/remote'
|
||||||
|
import * as acme from './tools/acme'
|
||||||
|
import * as cc7800 from './tools/cc7800'
|
||||||
|
import * as bataribasic from './tools/bataribasic'
|
||||||
|
import { PLATFORM_PARAMS } from "./platforms";
|
||||||
|
|
||||||
|
export const TOOLS = {
|
||||||
|
'dasm': dasm.assembleDASM,
|
||||||
|
'acme': acme.assembleACME,
|
||||||
|
'cc65': cc65.compileCC65,
|
||||||
|
'ca65': cc65.assembleCA65,
|
||||||
|
'ld65': cc65.linkLD65,
|
||||||
|
//'z80asm': assembleZ80ASM,
|
||||||
|
//'sccz80': compileSCCZ80,
|
||||||
|
'sdasz80': sdcc.assembleSDASZ80,
|
||||||
|
'sdldz80': sdcc.linkSDLDZ80,
|
||||||
|
'sdcc': sdcc.compileSDCC,
|
||||||
|
'xasm6809': m6809.assembleXASM6809,
|
||||||
|
'cmoc': m6809.compileCMOC,
|
||||||
|
'lwasm': m6809.assembleLWASM,
|
||||||
|
'lwlink': m6809.linkLWLINK,
|
||||||
|
//'naken': assembleNAKEN,
|
||||||
|
'verilator': verilog.compileVerilator,
|
||||||
|
'yosys': verilog.compileYosys,
|
||||||
|
'jsasm': verilog.compileJSASMStep,
|
||||||
|
'zmac': z80.assembleZMAC,
|
||||||
|
'nesasm': m6502.assembleNESASM,
|
||||||
|
'smlrc': x86.compileSmallerC,
|
||||||
|
'yasm': x86.assembleYASM,
|
||||||
|
'bataribasic': bataribasic.compileBatariBasic,
|
||||||
|
'markdown': misc.translateShowdown,
|
||||||
|
'inform6': misc.compileInform6,
|
||||||
|
'merlin32': m6502.assembleMerlin32,
|
||||||
|
'fastbasic': m6502.compileFastBasic,
|
||||||
|
'basic': misc.compileBASIC,
|
||||||
|
'silice': verilog.compileSilice,
|
||||||
|
'wiz': misc.compileWiz,
|
||||||
|
'armips': arm.assembleARMIPS,
|
||||||
|
'vasmarm': arm.assembleVASMARM,
|
||||||
|
'ecs': ecs.assembleECS,
|
||||||
|
'remote': remote.buildRemote,
|
||||||
|
'cc7800': cc7800.compileCC7800,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TOOL_PRELOADFS = {
|
||||||
|
'cc65-apple2': '65-apple2',
|
||||||
|
'ca65-apple2': '65-apple2',
|
||||||
|
'cc65-c64': '65-c64',
|
||||||
|
'ca65-c64': '65-c64',
|
||||||
|
'cc65-vic20': '65-vic20',
|
||||||
|
'ca65-vic20': '65-vic20',
|
||||||
|
'cc65-nes': '65-nes',
|
||||||
|
'ca65-nes': '65-nes',
|
||||||
|
'cc65-atari8': '65-atari8',
|
||||||
|
'ca65-atari8': '65-atari8',
|
||||||
|
'cc65-vector': '65-none',
|
||||||
|
'ca65-vector': '65-none',
|
||||||
|
'cc65-atari7800': '65-none',
|
||||||
|
'ca65-atari7800': '65-none',
|
||||||
|
'cc65-devel': '65-none',
|
||||||
|
'ca65-devel': '65-none',
|
||||||
|
'cc65-vcs': '65-atari2600',
|
||||||
|
'ca65-vcs': '65-atari2600',
|
||||||
|
'cc65-pce': '65-pce',
|
||||||
|
'ca65-pce': '65-pce',
|
||||||
|
'sdasz80': 'sdcc',
|
||||||
|
'sdcc': 'sdcc',
|
||||||
|
'sccz80': 'sccz80',
|
||||||
|
'bataribasic': '2600basic',
|
||||||
|
'inform6': 'inform',
|
||||||
|
'fastbasic': '65-atari8',
|
||||||
|
'silice': 'Silice',
|
||||||
|
'wiz': 'wiz',
|
||||||
|
'ecs-vcs': '65-atari2600', // TODO: support multiple platforms
|
||||||
|
'ecs-nes': '65-nes', // TODO: support multiple platforms
|
||||||
|
'ecs-c64': '65-c64', // TODO: support multiple platforms
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user