started cc65/ca65 support
This commit is contained in:
parent
5e8cf0f71f
commit
3239dd6a19
|
@ -241,6 +241,10 @@ function updateSelector() {
|
|||
function setCode(text) {
|
||||
if (current_preset_id.endsWith(".pla"))
|
||||
worker.postMessage({code:text, tool:'plasm'});
|
||||
else if (current_preset_id.endsWith(".c"))
|
||||
worker.postMessage({code:text, tool:'cc65'});
|
||||
else if (current_preset_id.endsWith(".s"))
|
||||
worker.postMessage({code:text, tool:'ca65'});
|
||||
else
|
||||
worker.postMessage({code:text, tool:'dasm'});
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,221 @@
|
|||
|
||||
var Module;
|
||||
|
||||
if (typeof Module === 'undefined') Module = eval('(function() { try { return Module || {} } catch(e) { return {} } })()');
|
||||
|
||||
if (!Module.expectedDataFileDownloads) {
|
||||
Module.expectedDataFileDownloads = 0;
|
||||
Module.finishedDataFileDownloads = 0;
|
||||
}
|
||||
Module.expectedDataFileDownloads++;
|
||||
(function() {
|
||||
var loadPackage = function(metadata) {
|
||||
|
||||
var PACKAGE_PATH;
|
||||
if (typeof window === 'object') {
|
||||
PACKAGE_PATH = window['encodeURIComponent'](window.location.pathname.toString().substring(0, window.location.pathname.toString().lastIndexOf('/')) + '/');
|
||||
} else if (typeof location !== 'undefined') {
|
||||
// worker
|
||||
PACKAGE_PATH = encodeURIComponent(location.pathname.toString().substring(0, location.pathname.toString().lastIndexOf('/')) + '/');
|
||||
} else {
|
||||
throw 'using preloaded data can only be done on a web page or in a web worker';
|
||||
}
|
||||
var PACKAGE_NAME = 'js/fs65.data';
|
||||
var REMOTE_PACKAGE_BASE = 'fs65.data';
|
||||
if (typeof Module['locateFilePackage'] === 'function' && !Module['locateFile']) {
|
||||
Module['locateFile'] = Module['locateFilePackage'];
|
||||
Module.printErr('warning: you defined Module.locateFilePackage, that has been renamed to Module.locateFile (using your locateFilePackage for now)');
|
||||
}
|
||||
var REMOTE_PACKAGE_NAME = typeof Module['locateFile'] === 'function' ?
|
||||
Module['locateFile'](REMOTE_PACKAGE_BASE) :
|
||||
((Module['filePackagePrefixURL'] || '') + REMOTE_PACKAGE_BASE);
|
||||
|
||||
var REMOTE_PACKAGE_SIZE = metadata.remote_package_size;
|
||||
var PACKAGE_UUID = metadata.package_uuid;
|
||||
|
||||
function fetchRemotePackage(packageName, packageSize, callback, errback) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', packageName, true);
|
||||
xhr.responseType = 'arraybuffer';
|
||||
xhr.onprogress = function(event) {
|
||||
var url = packageName;
|
||||
var size = packageSize;
|
||||
if (event.total) size = event.total;
|
||||
if (event.loaded) {
|
||||
if (!xhr.addedTotal) {
|
||||
xhr.addedTotal = true;
|
||||
if (!Module.dataFileDownloads) Module.dataFileDownloads = {};
|
||||
Module.dataFileDownloads[url] = {
|
||||
loaded: event.loaded,
|
||||
total: size
|
||||
};
|
||||
} else {
|
||||
Module.dataFileDownloads[url].loaded = event.loaded;
|
||||
}
|
||||
var total = 0;
|
||||
var loaded = 0;
|
||||
var num = 0;
|
||||
for (var download in Module.dataFileDownloads) {
|
||||
var data = Module.dataFileDownloads[download];
|
||||
total += data.total;
|
||||
loaded += data.loaded;
|
||||
num++;
|
||||
}
|
||||
total = Math.ceil(total * Module.expectedDataFileDownloads/num);
|
||||
if (Module['setStatus']) Module['setStatus']('Downloading data... (' + loaded + '/' + total + ')');
|
||||
} else if (!Module.dataFileDownloads) {
|
||||
if (Module['setStatus']) Module['setStatus']('Downloading data...');
|
||||
}
|
||||
};
|
||||
xhr.onerror = function(event) {
|
||||
throw new Error("NetworkError for: " + packageName);
|
||||
}
|
||||
xhr.onload = function(event) {
|
||||
if (xhr.status == 200 || xhr.status == 304 || xhr.status == 206 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0
|
||||
var packageData = xhr.response;
|
||||
callback(packageData);
|
||||
} else {
|
||||
throw new Error(xhr.statusText + " : " + xhr.responseURL);
|
||||
}
|
||||
};
|
||||
xhr.send(null);
|
||||
};
|
||||
|
||||
function handleError(error) {
|
||||
console.error('package error:', error);
|
||||
};
|
||||
|
||||
var fetched = null, fetchedCallback = null;
|
||||
fetchRemotePackage(REMOTE_PACKAGE_NAME, REMOTE_PACKAGE_SIZE, function(data) {
|
||||
if (fetchedCallback) {
|
||||
fetchedCallback(data);
|
||||
fetchedCallback = null;
|
||||
} else {
|
||||
fetched = data;
|
||||
}
|
||||
}, handleError);
|
||||
|
||||
function runWithFS() {
|
||||
|
||||
function assert(check, msg) {
|
||||
if (!check) throw msg + new Error().stack;
|
||||
}
|
||||
Module['FS_createPath']('/', 'include', true, true);
|
||||
Module['FS_createPath']('/include', 'joystick', true, true);
|
||||
Module['FS_createPath']('/include', 'tgi', true, true);
|
||||
Module['FS_createPath']('/include', 'geos', true, true);
|
||||
Module['FS_createPath']('/include', 'em', true, true);
|
||||
Module['FS_createPath']('/include', 'sys', true, true);
|
||||
Module['FS_createPath']('/include', 'mouse', true, true);
|
||||
Module['FS_createPath']('/', 'asminc', true, true);
|
||||
Module['FS_createPath']('/', 'cfg', true, true);
|
||||
Module['FS_createPath']('/', 'lib', true, true);
|
||||
Module['FS_createPath']('/', 'target', true, true);
|
||||
Module['FS_createPath']('/target', 'apple2', true, true);
|
||||
Module['FS_createPath']('/target/apple2', 'drv', true, true);
|
||||
Module['FS_createPath']('/target/apple2/drv', 'tgi', true, true);
|
||||
Module['FS_createPath']('/target/apple2/drv', 'joy', true, true);
|
||||
Module['FS_createPath']('/target/apple2/drv', 'emd', true, true);
|
||||
Module['FS_createPath']('/target/apple2/drv', 'mou', true, true);
|
||||
Module['FS_createPath']('/target/apple2/drv', 'ser', true, true);
|
||||
Module['FS_createPath']('/target/apple2', 'util', true, true);
|
||||
|
||||
function DataRequest(start, end, crunched, audio) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.crunched = crunched;
|
||||
this.audio = audio;
|
||||
}
|
||||
DataRequest.prototype = {
|
||||
requests: {},
|
||||
open: function(mode, name) {
|
||||
this.name = name;
|
||||
this.requests[name] = this;
|
||||
Module['addRunDependency']('fp ' + this.name);
|
||||
},
|
||||
send: function() {},
|
||||
onload: function() {
|
||||
var byteArray = this.byteArray.subarray(this.start, this.end);
|
||||
|
||||
this.finish(byteArray);
|
||||
|
||||
},
|
||||
finish: function(byteArray) {
|
||||
var that = this;
|
||||
|
||||
Module['FS_createDataFile'](this.name, null, byteArray, true, true, true); // canOwn this data in the filesystem, it is a slide into the heap that will never change
|
||||
Module['removeRunDependency']('fp ' + that.name);
|
||||
|
||||
this.requests[this.name] = null;
|
||||
}
|
||||
};
|
||||
|
||||
var files = metadata.files;
|
||||
for (i = 0; i < files.length; ++i) {
|
||||
new DataRequest(files[i].start, files[i].end, files[i].crunched, files[i].audio).open('GET', files[i].filename);
|
||||
}
|
||||
|
||||
|
||||
function processPackageData(arrayBuffer) {
|
||||
Module.finishedDataFileDownloads++;
|
||||
assert(arrayBuffer, 'Loading data file failed.');
|
||||
assert(arrayBuffer instanceof ArrayBuffer, 'bad input to processPackageData');
|
||||
var byteArray = new Uint8Array(arrayBuffer);
|
||||
var curr;
|
||||
|
||||
// copy the entire loaded file into a spot in the heap. Files will refer to slices in that. They cannot be freed though
|
||||
// (we may be allocating before malloc is ready, during startup).
|
||||
if (Module['SPLIT_MEMORY']) Module.printErr('warning: you should run the file packager with --no-heap-copy when SPLIT_MEMORY is used, otherwise copying into the heap may fail due to the splitting');
|
||||
var ptr = Module['getMemory'](byteArray.length);
|
||||
Module['HEAPU8'].set(byteArray, ptr);
|
||||
DataRequest.prototype.byteArray = Module['HEAPU8'].subarray(ptr, ptr+byteArray.length);
|
||||
|
||||
var files = metadata.files;
|
||||
for (i = 0; i < files.length; ++i) {
|
||||
DataRequest.prototype.requests[files[i].filename].onload();
|
||||
}
|
||||
Module['removeRunDependency']('datafile_js/fs65.data');
|
||||
|
||||
};
|
||||
Module['addRunDependency']('datafile_js/fs65.data');
|
||||
|
||||
if (!Module.preloadResults) Module.preloadResults = {};
|
||||
|
||||
Module.preloadResults[PACKAGE_NAME] = {fromCache: false};
|
||||
if (fetched) {
|
||||
processPackageData(fetched);
|
||||
fetched = null;
|
||||
} else {
|
||||
fetchedCallback = processPackageData;
|
||||
}
|
||||
|
||||
}
|
||||
if (Module['calledRun']) {
|
||||
runWithFS();
|
||||
} else {
|
||||
if (!Module['preRun']) Module['preRun'] = [];
|
||||
Module["preRun"].push(runWithFS); // FS is not initialized yet, wait for it
|
||||
}
|
||||
|
||||
Module['removeRunDependency']('fs65.js.metadata');
|
||||
}
|
||||
|
||||
var REMOTE_METADATA_NAME = typeof Module['locateFile'] === 'function' ?
|
||||
Module['locateFile']('fs65.js.metadata') :
|
||||
((Module['filePackagePrefixURL'] || '') + 'fs65.js.metadata');
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState === 4 && xhr.status === 200) {
|
||||
loadPackage(JSON.parse(xhr.responseText));
|
||||
}
|
||||
}
|
||||
xhr.open('GET', REMOTE_METADATA_NAME, true);
|
||||
xhr.overrideMimeType('application/json');
|
||||
xhr.send(null);
|
||||
|
||||
if (!Module['preRun']) Module['preRun'] = [];
|
||||
Module["preRun"].push(function() {
|
||||
Module['addRunDependency']('fs65.js.metadata');
|
||||
});
|
||||
|
||||
})();
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,9 +1,34 @@
|
|||
"use strict";
|
||||
|
||||
"use strict";
|
||||
// set up require.js for worker
|
||||
importScripts("../../js/dasm.js");
|
||||
importScripts("../../js/acme.js");
|
||||
importScripts("../../js/plasm.js");
|
||||
importScripts("dasm.js");
|
||||
importScripts("acme.js");
|
||||
importScripts("plasm.js");
|
||||
importScripts("cc65.js");
|
||||
importScripts("ca65.js");
|
||||
importScripts("ld65.js");
|
||||
|
||||
var fsMeta, fsBlob;
|
||||
{
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.responseType = 'blob';
|
||||
xhr.open("GET", "fs65.data", false); // synchronous request
|
||||
xhr.send(null);
|
||||
fsBlob = xhr.response;
|
||||
xhr = new XMLHttpRequest();
|
||||
xhr.responseType = 'json';
|
||||
xhr.open("GET", "fs65.js.metadata", false); // synchronous request
|
||||
xhr.send(null);
|
||||
fsMeta = xhr.response;
|
||||
console.log("Fetched", fsMeta, fsBlob);
|
||||
}
|
||||
|
||||
function setupFS(FS) {
|
||||
FS.mkdir('/share');
|
||||
FS.mount(FS.filesystems['WORKERFS'], {
|
||||
packages: [{ metadata: fsMeta, blob: fsBlob }]
|
||||
}, '/share');
|
||||
}
|
||||
|
||||
// shim out window and document objects
|
||||
// https://github.com/mbostock/d3/issues/1053
|
||||
|
@ -25,6 +50,8 @@ var DASM_MAIN_FILENAME = "main.a";
|
|||
var DASM_PREAMBLE = "\tprocessor 6502\n";
|
||||
var DASM_PREAMBLE_LINES = 1;
|
||||
|
||||
var print_fn = function(s) { console.log(s); }
|
||||
|
||||
function parseDASMListing(code, unresolved) {
|
||||
var errorMatch = /main.a [(](\d+)[)]: error: (.+)/;
|
||||
// 4 08ee a9 00 start lda #01workermain.js:23:5
|
||||
|
@ -88,7 +115,7 @@ function parseDASMListing(code, unresolved) {
|
|||
function assembleDASM(code) {
|
||||
var re_usl = /(\w+)\s+0000\s+[?][?][?][?]/;
|
||||
var unresolved = {};
|
||||
function print_fn(s) {
|
||||
function match_fn(s) {
|
||||
var matches = re_usl.exec(s);
|
||||
if (matches) {
|
||||
unresolved[matches[1]] = 0;
|
||||
|
@ -96,7 +123,7 @@ function assembleDASM(code) {
|
|||
}
|
||||
var Module = DASM({
|
||||
noInitialRun:true,
|
||||
print:print_fn
|
||||
print:match_fn
|
||||
});
|
||||
var FS = Module['FS'];
|
||||
FS.writeFile(DASM_MAIN_FILENAME, DASM_PREAMBLE + code);
|
||||
|
@ -109,10 +136,11 @@ function assembleDASM(code) {
|
|||
return {exitstatus:Module.EXITSTATUS, output:aout, listing:listing};
|
||||
}
|
||||
|
||||
// TODO: not quite done
|
||||
function assembleACME(code) {
|
||||
var re_usl = /(\w+)\s+0000\s+[?][?][?][?]/;
|
||||
var re_usl = /(\w+)\s+0000\s+[?][?][?][?]/; // TODO: modify for acme
|
||||
var unresolved = {};
|
||||
function print_fn(s) {
|
||||
function match_fn(s) {
|
||||
var matches = re_usl.exec(s);
|
||||
if (matches) {
|
||||
unresolved[matches[1]] = 0;
|
||||
|
@ -120,14 +148,14 @@ function assembleACME(code) {
|
|||
}
|
||||
var Module = ACME({
|
||||
noInitialRun:true,
|
||||
print:print_fn
|
||||
print:match_fn
|
||||
});
|
||||
var FS = Module['FS'];
|
||||
FS.writeFile("main.a", code);
|
||||
Module.callMain(["-o", "a.out", "-r", "a.rpt", "-l", "a.sym", "--setpc", "24576", "main.a"]);
|
||||
var aout = FS.readFile("a.out");
|
||||
var alst = FS.readFile("a.rpt", {'encoding':'utf8'});
|
||||
var asym = FS.readFile("a.sym", {'encoding':'utf8'});
|
||||
var alst = FS.readFile("a.rpt", {'encoding':'utf8'}); // TODO
|
||||
var asym = FS.readFile("a.sym", {'encoding':'utf8'}); // TODO
|
||||
console.log("acme", code.length, "->", aout.length);
|
||||
console.log(alst);
|
||||
console.log(asym);
|
||||
|
@ -136,7 +164,6 @@ function assembleACME(code) {
|
|||
}
|
||||
|
||||
function compilePLASMA(code) {
|
||||
function print_fn(s) { console.log(s); }
|
||||
var outstr = "";
|
||||
function out_fn(s) { outstr += s; outstr += "\n"; }
|
||||
var Module = PLASM({
|
||||
|
@ -152,13 +179,95 @@ function compilePLASMA(code) {
|
|||
);
|
||||
FS.writeFile("main.pla", code);
|
||||
Module.callMain(["-A"]);
|
||||
console.log("plasm", code.length, "->", outstr.length);
|
||||
//console.log("plasm", code.length, "->", outstr.length);
|
||||
return assembleACME(outstr);
|
||||
}
|
||||
|
||||
function parseCA65Listing(code, unresolved) {
|
||||
// .dbg line, "main.c", 1
|
||||
var dbgLineMatch = /([0-9a-fA-F]+)([r]?)\s+(\d+)\s+[.]dbg\s+line,\s+\S+,\s+(\d+)/;
|
||||
var errors = [];
|
||||
var lines = [];
|
||||
var lastlinenum = 0;
|
||||
for (var line of code.split(/\r?\n/)) {
|
||||
var linem = dbgLineMatch.exec(line);
|
||||
if (linem && linem[1]) {
|
||||
var offset = parseInt(linem[1], 16);
|
||||
var linenum = parseInt(linem[4]);
|
||||
lines.push({
|
||||
line:linenum,
|
||||
offset:offset + 0x6000, //TODO
|
||||
insns:null
|
||||
});
|
||||
//console.log(linem, lastlinenum, lines[lines.length-1]);
|
||||
}
|
||||
}
|
||||
return {lines:lines, errors:errors};
|
||||
}
|
||||
|
||||
function assemblelinkCA65(code, platform) {
|
||||
if (!platform)
|
||||
platform = 'apple2'; // TODO
|
||||
var objout, lstout;
|
||||
{
|
||||
var CA65 = ca65({
|
||||
noInitialRun:true,
|
||||
logReadFiles:true,
|
||||
print:print_fn,
|
||||
printErr:print_fn,
|
||||
//locateFile: function(s) { return "" + s; },
|
||||
});
|
||||
var FS = CA65['FS'];
|
||||
setupFS(FS);
|
||||
FS.writeFile("main.s", code, {encoding:'utf8'});
|
||||
CA65.callMain(['-v', '-g', '-I', '/share/asminc', '-l', 'main.lst', "main.s"]);
|
||||
objout = FS.readFile("main.o", {encoding:'binary'});
|
||||
lstout = FS.readFile("main.lst", {encoding:'utf8'});
|
||||
}{
|
||||
var LD65 = ld65({
|
||||
noInitialRun:true,
|
||||
logReadFiles:true,
|
||||
print:print_fn,
|
||||
printErr:print_fn,
|
||||
//locateFile: function(s) { return "" + s; },
|
||||
});
|
||||
var FS = LD65['FS'];
|
||||
setupFS(FS);
|
||||
FS.writeFile("main.o", objout, {encoding:'binary'});
|
||||
LD65.callMain(['--cfg-path', '/share/cfg', '--lib-path', '/share/lib',
|
||||
'--start-addr', '0x6000', // TODO
|
||||
'-t', platform, '-o', 'main', '-m', 'main.map', 'main.o', platform+'.lib']);
|
||||
var aout = FS.readFile("main", {encoding:'binary'});
|
||||
var mapout = FS.readFile("main.map", {encoding:'utf8'});
|
||||
console.log(lstout);
|
||||
console.log(mapout);
|
||||
return {exitstatus:LD65.EXITSTATUS, output:aout.slice(4), listing:parseCA65Listing(lstout)};
|
||||
}
|
||||
}
|
||||
|
||||
function compileCC65(code, platform) {
|
||||
if (!platform)
|
||||
platform = 'apple2'; // TODO
|
||||
var CC65 = cc65({
|
||||
noInitialRun:true,
|
||||
logReadFiles:true,
|
||||
print:print_fn,
|
||||
printErr:print_fn,
|
||||
//locateFile: function(s) { return "" + s; },
|
||||
});
|
||||
var FS = CC65['FS'];
|
||||
setupFS(FS);
|
||||
FS.writeFile("main.c", code, {encoding:'utf8'});
|
||||
CC65.callMain(['-v', '-T', '-g', '-I', '/share/include', '-t', platform, "main.c"]);
|
||||
var asmout = FS.readFile("main.s", {encoding:'utf8'});
|
||||
return assemblelinkCA65(asmout, platform);
|
||||
}
|
||||
|
||||
var tools = {
|
||||
'dasm': assembleDASM,
|
||||
'plasm': compilePLASMA,
|
||||
'cc65': compileCC65,
|
||||
'ca65': assemblelinkCA65,
|
||||
}
|
||||
|
||||
onmessage = function(e) {
|
||||
|
@ -167,5 +276,7 @@ onmessage = function(e) {
|
|||
if (!toolfn) throw "no tool named " + e.data.tool;
|
||||
var result = toolfn(code);
|
||||
//console.log("RESULT", result);
|
||||
postMessage(result);
|
||||
if (result) {
|
||||
postMessage(result);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue