8bitworkshop/src/worker/tools/m6809.ts

278 lines
9.9 KiB
TypeScript

import { CodeListingMap, WorkerError } from "../../common/workertypes";
import { BuildStep, BuildStepResult, populateFiles, putWorkFile, gatherFiles, staleFiles, getWorkFileAsString, fixParamsWithDefines, populateExtraFiles, anyTargetChanged } from "../builder";
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
export function assembleXASM6809(step: BuildStep): BuildStepResult {
load("xasm6809");
var alst = "";
var lasterror = null;
var errors = [];
function match_fn(s) {
alst += s;
alst += "\n";
if (lasterror) {
var line = parseInt(s.slice(0, 5)) || 0;
errors.push({
line: line,
msg: lasterror
});
lasterror = null;
}
else if (s.startsWith("***** ")) {
lasterror = s.slice(6);
}
}
var Module: EmscriptenModule = emglobal.xasm6809({
noInitialRun: true,
//logReadFiles:true,
print: match_fn,
printErr: print_fn
});
var FS = Module.FS;
//setupFS(FS);
populateFiles(step, FS, {
mainFilePath: 'main.asm'
});
var binpath = step.prefix + '.bin';
var lstpath = step.prefix + '.lst'; // in stdout
execMain(step, Module, ["-c", "-l", "-s", "-y", "-o=" + binpath, step.path]);
if (errors.length)
return { errors: errors };
var aout = FS.readFile(binpath, { encoding: 'binary' });
if (aout.length == 0) {
errors.push({ line: 0, msg: "Empty output file" });
return { errors: errors };
}
putWorkFile(binpath, aout);
putWorkFile(lstpath, alst);
// TODO: symbol map
//mond09 0000
var symbolmap = {};
//00005 W 0003 [ 8] A6890011 lda >PALETTE,x
//00012 0011 0C0203 fcb 12,2,3
var asmlines = parseListing(alst, /^\s*([0-9]+) .+ ([0-9A-F]+)\s+\[([0-9 ]+)\]\s+([0-9A-F]+) (.*)/i, 1, 2, 4, 3);
var listings: CodeListingMap = {};
listings[step.prefix + '.lst'] = { lines: asmlines, text: alst };
return {
output: aout,
listings: listings,
errors: errors,
symbolmap: symbolmap,
};
}
export function compileCMOC(step: BuildStep): BuildStepResult {
loadNative("cmoc");
var params = step.params;
// stderr
var re_err1 = /^[/]*([^:]*):(\d+): (.+)$/;
var errors: WorkerError[] = [];
var errline = 0;
function match_fn(s) {
var matches = re_err1.exec(s);
if (matches) {
errors.push({
line: parseInt(matches[2]),
msg: matches[3],
path: matches[1] || step.path
});
} else {
console.log(s);
}
}
gatherFiles(step, { mainFilePath: "main.c" });
var destpath = step.prefix + '.s';
if (staleFiles(step, [destpath])) {
var args = ['-S', '-Werror', '-V',
'-I/share/include',
'-I.',
step.path];
var CMOC: EmscriptenModule = emglobal.cmoc({
instantiateWasm: moduleInstFn('cmoc'),
noInitialRun: true,
//logReadFiles:true,
print: match_fn,
printErr: match_fn,
});
// load source file and preprocess
var code = getWorkFileAsString(step.path);
var preproc = preprocessMCPP(step, null);
if (preproc.errors) {
return { errors: preproc.errors }
}
else code = preproc.code;
// set up filesystem
var FS = CMOC.FS;
//setupFS(FS, '65-'+getRootBasePlatform(step.platform));
populateFiles(step, FS);
FS.writeFile(step.path, code);
fixParamsWithDefines(step.path, params);
if (params.extra_compile_args) {
args.unshift.apply(args, params.extra_compile_args);
}
execMain(step, CMOC, args);
if (errors.length)
return { errors: errors };
var asmout = FS.readFile(destpath, { encoding: 'utf8' });
if (step.params.set_stack_end)
asmout = asmout.replace('stack space in bytes', `\n lds #${step.params.set_stack_end}\n`)
putWorkFile(destpath, asmout);
}
return {
nexttool: "lwasm",
path: destpath,
args: [destpath],
files: [destpath],
};
}
export function assembleLWASM(step: BuildStep): BuildStepResult {
loadNative("lwasm");
var errors = [];
gatherFiles(step, { mainFilePath: "main.s" });
var objpath = step.prefix + ".o";
var lstpath = step.prefix + ".lst";
const isRaw = step.path.endsWith('.asm');
if (staleFiles(step, [objpath, lstpath])) {
var objout, lstout;
var args = ['-9', '-I/share/asminc', '-o' + objpath, '-l' + lstpath, step.path];
args.push(isRaw ? '-r' : '--obj');
var LWASM: EmscriptenModule = emglobal.lwasm({
instantiateWasm: moduleInstFn('lwasm'),
noInitialRun: true,
//logReadFiles:true,
print: print_fn,
printErr: msvcErrorMatcher(errors),
});
var FS = LWASM.FS;
//setupFS(FS, '65-'+getRootBasePlatform(step.platform));
populateFiles(step, FS);
fixParamsWithDefines(step.path, step.params);
execMain(step, LWASM, args);
if (errors.length)
return { errors: errors };
objout = FS.readFile(objpath, { encoding: 'binary' });
lstout = FS.readFile(lstpath, { encoding: 'utf8' });
putWorkFile(objpath, objout);
putWorkFile(lstpath, lstout);
if (isRaw) {
return {
output: objout
};
}
}
return {
linktool: "lwlink",
files: [objpath, lstpath],
args: [objpath]
};
}
export function linkLWLINK(step: BuildStep): BuildStepResult {
loadNative("lwlink");
var params = step.params;
gatherFiles(step);
var binpath = "main";
if (staleFiles(step, [binpath])) {
var errors = [];
var LWLINK: EmscriptenModule = emglobal.lwlink({
instantiateWasm: moduleInstFn('lwlink'),
noInitialRun: true,
//logReadFiles:true,
print: print_fn,
printErr: function (s) {
if (s.startsWith("Warning:"))
console.log(s);
else
errors.push({ msg: s, line: 0 });
}
});
var FS = LWLINK.FS;
//setupFS(FS, '65-'+getRootBasePlatform(step.platform));
populateFiles(step, FS);
populateExtraFiles(step, FS, params.extra_link_files);
var libargs = params.extra_link_args || [];
var args = [
'-L.',
'--entry=program_start',
'--raw',
'--output=main',
'--map=main.map'].concat(libargs, step.args);
console.log(args);
execMain(step, LWLINK, args);
if (errors.length)
return { errors: errors };
var aout = FS.readFile("main", { encoding: 'binary' });
var mapout = FS.readFile("main.map", { encoding: 'utf8' });
putWorkFile("main", aout);
putWorkFile("main.map", mapout);
// return unchanged if no files changed
if (!anyTargetChanged(step, ["main", "main.map"]))
return;
// parse symbol map
//console.log(mapout);
var symbolmap = {};
var segments = [];
for (var s of mapout.split("\n")) {
var toks = s.split(" ");
// TODO: use regex
if (toks[0] == 'Symbol:') {
let ident = toks[1];
let ofs = parseInt(toks[4], 16);
if (ident && ofs >= 0
&& !ident.startsWith("l_")
//&& !/^L\d+$/.test(ident)
&& !ident.startsWith('funcsize_')
&& !ident.startsWith('funcend_')) {
symbolmap[ident] = ofs;
}
}
else if (toks[0] == 'Section:') {
let seg = toks[1];
let segstart = parseInt(toks[5], 16);
let segsize = parseInt(toks[7], 16);
segments.push({ name: seg, start: segstart, size: segsize });
}
}
// build listings
const re_segment = /\s*SECTION\s+(\w+)/i;
const re_function = /\s*([0-9a-f]+).+?(\w+)\s+EQU\s+[*]/i;
var listings: CodeListingMap = {};
for (var fn of step.files) {
if (fn.endsWith('.lst')) {
// TODO
var lstout = FS.readFile(fn, { encoding: 'utf8' });
var asmlines = parseListing(lstout, /^([0-9A-F]+)\s+([0-9A-F]+)\s+[(]\s*(.+?)[)]:(\d+) (.*)/i, 4, 1, 2, 3, re_function, re_segment);
for (let l of asmlines) {
l.offset += symbolmap[l.func] || 0;
}
// * Line //threed.c:117: init of variable e
var srclines = parseSourceLines(lstout, /Line .+?:(\d+)/i, /^([0-9A-F]{4})/i, re_function, re_segment);
for (let l of srclines) {
l.offset += symbolmap[l.func] || 0;
}
putWorkFile(fn, lstout);
// strip out left margin
lstout = lstout.split('\n').map(l => l.substring(0,15) + l.substring(56)).join('\n')
// TODO: you have to get rid of all source lines to get asm listing
listings[fn] = {
asmlines: srclines.length ? asmlines : null,
lines: srclines.length ? srclines : asmlines,
text: lstout
};
}
}
return {
output: aout, //.slice(0),
listings: listings,
errors: errors,
symbolmap: symbolmap,
segments: segments
};
}
}