preload for worker FS, z80.lib + mcpp includes, font tools

This commit is contained in:
Steven Hugg 2017-01-23 16:21:45 -05:00
parent 7eae2e9274
commit f9c9fc91aa
10 changed files with 46470 additions and 49 deletions

View File

@ -157,12 +157,13 @@ function updatePreset(current_preset_id, text) {
}
function loadCode(text, fileid) {
var tool = platform.getToolForFilename(fileid);
editor.setOption("mode", tool && TOOL_TO_SOURCE_STYLE[tool]);
editor.setValue(text);
editor.clearHistory();
current_output = null;
setCode(text);
setLastPreset(fileid);
var tool = platform.getToolForFilename(fileid);
editor.setOption("mode", tool && TOOL_TO_SOURCE_STYLE[tool]);
}
function loadFile(fileid, filename, index) {
@ -887,12 +888,18 @@ var qs = (function (a) {
return b;
})(window.location.search.substr(1).split('&'));
function preloadWorker(fileid) {
var tool = platform.getToolForFilename(fileid);
if (tool) worker.postMessage({preload:tool});
}
function startPlatform() {
platform = new PLATFORMS[platform_id]($("#emulator")[0]);
store = new FileStore(localStorage, platform_id + '/');
PRESETS = platform.getPresets();
if (qs['file']) {
// start platform and load file
preloadWorker(qs['file']);
setupDebugControls();
platform.start();
loadPreset(qs['file']);

42212
src/worker/fssdcc.data Normal file

File diff suppressed because it is too large Load Diff

223
src/worker/fssdcc.js Normal file
View File

@ -0,0 +1,223 @@
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/fssdcc.data';
var REMOTE_PACKAGE_BASE = 'fssdcc.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', 'ds390', true, true);
Module['FS_createPath']('/include', 'asm', true, true);
Module['FS_createPath']('/include/asm', 'default', true, true);
Module['FS_createPath']('/include/asm', 'tlcs90', true, true);
Module['FS_createPath']('/include/asm', 'pic16', true, true);
Module['FS_createPath']('/include/asm', 'r3ka', true, true);
Module['FS_createPath']('/include/asm', 'ds390', true, true);
Module['FS_createPath']('/include/asm', 'mcs51', true, true);
Module['FS_createPath']('/include/asm', 'stm8', true, true);
Module['FS_createPath']('/include/asm', 'z180', true, true);
Module['FS_createPath']('/include/asm', 'pic14', true, true);
Module['FS_createPath']('/include/asm', 'gbz80', true, true);
Module['FS_createPath']('/include/asm', 'r2k', true, true);
Module['FS_createPath']('/include/asm', 'z80', true, true);
Module['FS_createPath']('/include', 'mcs51', true, true);
Module['FS_createPath']('/include', 'hc08', true, true);
Module['FS_createPath']('/include', 'z180', true, true);
Module['FS_createPath']('/include', 'ds400', true, true);
Module['FS_createPath']('/', 'lib', true, true);
Module['FS_createPath']('/lib', 'z80', 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/fssdcc.data');
};
Module['addRunDependency']('datafile_js/fssdcc.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']('fssdcc.js.metadata');
}
var REMOTE_METADATA_NAME = typeof Module['locateFile'] === 'function' ?
Module['locateFile']('fssdcc.js.metadata') :
((Module['filePackagePrefixURL'] || '') + 'fssdcc.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']('fssdcc.js.metadata');
});
})();

File diff suppressed because one or more lines are too long

View File

@ -21,46 +21,32 @@ var document = noop();
document.documentElement = noop();
document.documentElement.style = noop();
var fsMeta = {};
var fsBlob = {};
// load filesystems for CC65 and others asynchronously
var fsMeta, fsBlob;
{
function loadFilesystem(name) {
var xhr = new XMLHttpRequest();
xhr.responseType = 'blob';
xhr.open("GET", "fs65.data", false); // synchronous request
xhr.open("GET", "fs"+name+".data", false); // synchronous request
xhr.send(null);
fsBlob = xhr.response;
fsBlob[name] = xhr.response;
xhr = new XMLHttpRequest();
xhr.responseType = 'json';
xhr.open("GET", "fs65.js.metadata", false); // synchronous request
xhr.open("GET", "fs"+name+".js.metadata", false); // synchronous request
xhr.send(null);
fsMeta = xhr.response;
console.log("Loaded filesystem", fsMeta.files.length, 'files', fsBlob.size, 'bytes');
fsMeta[name] = xhr.response;
console.log("Loaded "+name+" filesystem", fsMeta[name].files.length, 'files', fsBlob[name].size, 'bytes');
}
// mount the filesystem at /share
function setupFS(FS) {
function setupFS(FS, name) {
FS.mkdir('/share');
FS.mount(FS.filesystems['WORKERFS'], {
packages: [{ metadata: fsMeta, blob: fsBlob }]
packages: [{ metadata: fsMeta[name], blob: fsBlob[name] }]
}, '/share');
}
function extractErrors(strings, regex) {
var errors = [];
for (var i=0; i<strings.length; i++) {
var m = regex.exec(strings[i]);
if (m) {
errors.push({
line: m[1],
msg: m[2]
});
}
}
return errors;
}
// main worker start
var DASM_MAIN_FILENAME = "main.a";
var DASM_PREAMBLE = "\tprocessor 6502\n";
var DASM_PREAMBLE_LINES = 1;
@ -88,6 +74,27 @@ function match_msvc(s) {
}
}
function makeErrorMatcher(errors, regex, iline, imsg) {
return function(s) {
var matches = regex.exec(s);
if (matches) {
errors.push({
line:parseInt(matches[iline]),
msg:matches[imsg]
});
}
}
}
function extractErrors(regex, strings) {
var errors = [];
var matcher = makeErrorMatcher(errors, regex, 1, 2);
for (var i=0; i<strings.length; i++) {
matcher(strings[i]);
}
return errors;
}
function parseListing(code, lineMatch, iline, ioffset, iinsns) {
var lines = [];
for (var line of code.split(/\r?\n/)) {
@ -346,7 +353,7 @@ function assemblelinkCA65(code, platform, warnings) {
printErr:print_fn,
});
var FS = CA65['FS'];
setupFS(FS);
setupFS(FS, '65');
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'});
@ -359,7 +366,7 @@ function assemblelinkCA65(code, platform, warnings) {
printErr:print_fn,
});
var FS = LD65['FS'];
setupFS(FS);
setupFS(FS, '65');
FS.writeFile("main.o", objout, {encoding:'binary'});
LD65.callMain(['--cfg-path', '/share/cfg', '--lib-path', '/share/lib',
'--start-addr', '0x6000', // TODO
@ -399,7 +406,7 @@ function compileCC65(code, platform) {
printErr:match_fn,
});
var FS = CC65['FS'];
setupFS(FS);
setupFS(FS, '65');
FS.writeFile("main.c", code, {encoding:'utf8'});
CC65.callMain(['-v', '-T', '-g', /*'-Cl',*/ '-Oirs', '-I', '/share/include', '-t', platform, "main.c"]);
try {
@ -433,7 +440,7 @@ function assembleZ80ASM(code, platform) {
try {
var aerr = FS.readFile("main.err", {'encoding':'utf8'}); // TODO
if (aerr.length) {
return {errors:extractErrors(aerr.split("\n"), /.+? line (\d+): (.+)/)};
return {errors:extractErrors(/.+? line (\d+): (.+)/, aerr.split("\n"))};
}
// Warning at file 'test.asm' line 9: 'XREF' is deprecated, use 'EXTERN' instead
} catch (e) {
@ -556,16 +563,18 @@ function assemblelinkSDASZ80(code, platform) {
printErr:match_aslink_fn,
});
var FS = LDZ80['FS'];
setupFS(FS, 'sdcc');
FS.writeFile("main.rel", objout, {encoding:'utf8'});
//FS.writeFile("main.lst", lstout, {encoding:'utf8'});
LDZ80.callMain(['-mjwx', '-i', 'main.ihx', '-y',
FS.writeFile("main.lst", lstout, {encoding:'utf8'});
LDZ80.callMain(['-mjwxyu', '-i', 'main.ihx',
'-b', '_CODE=0x'+params.code_start.toString(16),
'-b', '_DATA=0x'+params.data_start.toString(16),
//'-k', '/usr/share/sdcc/lib/z80',
//'-l', 'z80',
'-k', '/share/lib/z80',
'-l', 'z80',
'main.rel']);
var hexout = FS.readFile("main.ihx", {encoding:'utf8'});
var mapout = FS.readFile("main.noi", {encoding:'utf8'});
var rstout = FS.readFile("main.rst", {encoding:'utf8'});
//var dbgout = FS.readFile("main.cdb", {encoding:'utf8'});
// 0000 21 02 00 [10] 52 ld hl, #2
// TODO: offset by start address?
@ -585,7 +594,7 @@ function assemblelinkSDASZ80(code, platform) {
srclines:srclines,
errors:msvc_errors, // TODO?
symbolmap:symbolmap,
intermediate:{listing:lstout},
intermediate:{listing:rstout},
};
}
}
@ -606,7 +615,7 @@ function compileSDCC(code, platform) {
});
var FS = SDCC['FS'];
setupStdin(FS, code);
setupFS(FS);
setupFS(FS, 'sdcc');
//FS.writeFile("main.c", code, {encoding:'utf8'});
msvc_errors = [];
SDCC.callMain(['--vc', '--std-sdcc99', '-mz80', '-Wall',
@ -676,27 +685,38 @@ function assembleXASM6809(code, platform) {
function preprocessMCPP(code, platform) {
load("mcpp");
// <stdin>:2: error: Can't open include file "foo.h"
var errors = [];
var match_fn = makeErrorMatcher(errors, /<stdin>:(\d+): (.+)/, 1, 2);
var MCPP = mcpp({
noInitialRun:true,
noFSInit:true,
print:print_fn,
printErr:print_fn,
printErr:match_fn,
});
var FS = MCPP['FS'];
setupFS(FS, 'sdcc');
FS.writeFile("main.c", code, {encoding:'utf8'});
msvc_errors = [];
MCPP.callMain([
"-D", "__8BITWORKSHOP__",
"-D", platform.toUpperCase(),
"-I", "/share/include",
"-Q",
"main.c", "main.i"]);
try {
MCPP.callMain([
"-D", "__8BITWORKSHOP__",
"-D", platform.toUpperCase(),
"-W", "31",
"main.c", "main.i"]);
var iout = FS.readFile("main.i", {encoding:'utf8'});
var iout = FS.readFile("main.i", {encoding:'utf8'});
iout = iout.replace(/^#line /gm,'\n# ');
} catch (e) {
msvc_errors.push({line:1, msg:e+""});
errors.push({line:1, msg:e+""});
}
if (msvc_errors.length) {
return {errors:msvc_errors};
try {
var errout = FS.readFile("mcpp.err", {encoding:'utf8'});
if (errout.length) {
// //main.c:2: error: Can't open include file "stdiosd.h"
return {errors: extractErrors(/[^:]+:(\d+): (.+)/, errout.split("\n"))};
}
} catch (e) {
//
}
return {code:iout};
}
@ -713,7 +733,21 @@ var TOOLS = {
'xasm6809': assembleXASM6809,
}
var TOOL_PRELOADFS = {
'cc65': '65',
'ca65': '65',
'sdasz80': 'sdcc',
'sdcc': 'sdcc',
}
onmessage = function(e) {
// (preload)
if (e.data.preload) {
var fs = TOOL_PRELOADFS[e.data.preload];
if (fs && !fsMeta[fs]) loadFilesystem(fs);
return;
}
// (code,platform,tool)
var code = e.data.code;
var platform = e.data.platform;
var toolfn = TOOLS[e.data.tool];

View File

@ -59,6 +59,11 @@ global.postMessage = null;
includeInThisContext("src/worker/workermain.js");
global.onmessage({data:{preload:'cc65'}});
global.onmessage({data:{preload:'sdcc'}});
//
function compile(tool, code, platform, callback, outlen, nlines, nerrors) {
global.postMessage = function(msg) {
if (msg.errors && msg.errors.length) {
@ -117,7 +122,10 @@ describe('Worker', function() {
compile('sdasz80', '\tcall divxxx\n', 'mw8080bw', done, 0, 0, 1);
});
it('should compile SDCC', function(done) {
compile('sdcc', 'int foo=0; // comment\nint main(int argc) {\nint x=1;\nint y=2+argc;\nreturn x+y+argc;\n}', 'mw8080bw', done, 8192, 3, 0);
compile('sdcc', 'int foo=0; // comment\nint main(int argc) {\nint x=1;\nint y=2+argc;\nreturn x+y+argc;\n}\n', 'mw8080bw', done, 8192, 3, 0);
});
it('should compile SDCC w/ include', function(done) {
compile('sdcc', '#include <string.h>\nvoid main() {\nstrlen(0);\n}\n', 'mw8080bw', done, 8192, 2, 0);
});
it('should NOT compile SDCC', function(done) {
compile('sdcc', 'foobar', 'mw8080bw', done, 0, 0, 1);

1437
tools/c64.bdf Normal file

File diff suppressed because it is too large Load Diff

65
tools/parsebdf3x5.py Normal file
View File

@ -0,0 +1,65 @@
#!/usr/bin/python
import sys,string
height = 5
lochar = 41
hichar = 90
chars = {}
inbitmap = 0
with open(sys.argv[1],'r') as f:
lines = f.readlines()
for l in lines:
l = l.strip()
toks = l.split()
#print l,toks
if toks[0] == 'ENCODING':
chord = int(toks[1])
elif toks[0] == 'BITMAP':
inbitmap = True
bytes = []
elif toks[0] == 'ENDCHAR':
inbitmap = False
if chord >= lochar and chord <= hichar:
while len(bytes) < height:
bytes.insert(0,0)
assert(len(bytes) == height)
bytes.reverse()
print chord,bytes
chars[chord] = bytes
elif inbitmap and len(toks) == 1:
byte = int(toks[0],16)
assert((byte&15)==0)
assert((byte&1)==0)
byte = byte / 32
bytes.append(byte)
# output font table
x = 0
output = []
outputlo = []
outputhi = []
for ch in range(lochar,hichar+1):
bytes = chars.get(ch)
#bytes = bytes + [0]
if not bytes:
bytes = [0] * height
for b in bytes:
if not x:
v = b
else:
v = v | (b<<4)
output.append(v)
x ^= 1
outputlo.append(b)
outputhi.append(b<<4)
def tohex(v):
return '%02x'%v
print '\thex ' + string.join(map(tohex,output),'')
print '\thex ' + string.join(map(tohex,outputlo),'')
print '\thex ' + string.join(map(tohex,outputhi),'')
print len(output),len(outputlo),len(outputhi)

69
tools/parsebdf8.py Normal file
View File

@ -0,0 +1,69 @@
#!/usr/bin/python
import sys,string
height = 8
lochar = 0x20 #48
hichar = 0x5e #57
chars = {}
inbitmap = 0
with open(sys.argv[1],'r') as f:
lines = f.readlines()
for l in lines:
l = l.strip()
toks = l.split()
#print l,toks
if toks[0] == 'ENCODING':
chord = int(toks[1])
elif toks[0] == 'BITMAP':
inbitmap = True
bytes = []
elif toks[0] == 'ENDCHAR':
inbitmap = False
if chord >= lochar and chord <= hichar:
while len(bytes) < height:
bytes.insert(0,0)
assert(len(bytes) == height)
bytes.reverse()
print chord,bytes
chars[chord] = bytes
elif inbitmap and len(toks) == 1:
byte = int(toks[0],16)
bytes.append(byte)
# output font table
x = 0
output = []
invoutput = []
rotoutput = []
rot2output = []
for ch in range(lochar,hichar+1):
bytes = chars.get(ch)
#bytes = bytes + [0]
if not bytes:
bytes = [0] * height
for b in bytes:
output.append(b)
invoutput.append(b ^ 0xff)
rotoutput.append(0)
rot2output.append(0)
for x in range(0,height):
for y in range(0,height):
rotoutput[-7+x] |= (((output[-1-y]>>x)&1)<<y)
rot2output[-1-x] |= (((output[-7+y]>>x)&1)<<y)
def tohex(v):
return '%02x'%v
def tohex2(v):
return '0x%02x'%v
for arr in [output,invoutput,rotoutput,rot2output]:
print '\thex ' + string.join(map(tohex,arr),'')
for i in range(0,len(output),height):
print '{', string.join(map(tohex2,arr[i:i+height]),','), '},',
print
print
print len(output),len(invoutput),len(rotoutput),len(rot2output)

2365
tools/tom-thumb.bdf Normal file

File diff suppressed because it is too large Load Diff