import { WorkerError, CodeListingMap } from "../../common/workertypes"; 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/ export function assembleNESASM(step: BuildStep): BuildStepResult { loadNative("nesasm"); var re_filename = /\#\[(\d+)\]\s+(\S+)/; var re_insn = /\s+(\d+)\s+([0-9A-F]+):([0-9A-F]+)/; var re_error = /\s+(.+)/; var errors: WorkerError[] = []; var state = 0; var lineno = 0; var filename; function match_fn(s) { var m; switch (state) { case 0: m = re_filename.exec(s); if (m) { filename = m[2]; } m = re_insn.exec(s); if (m) { lineno = parseInt(m[1]); state = 1; } break; case 1: m = re_error.exec(s); if (m) { errors.push({ path: filename, line: lineno, msg: m[1] }); state = 0; } break; } } var Module: EmscriptenModule = emglobal.nesasm({ instantiateWasm: moduleInstFn('nesasm'), noInitialRun: true, print: match_fn }); var FS = Module.FS; populateFiles(step, FS, { mainFilePath: 'main.a' }); var binpath = step.prefix + '.nes'; var lstpath = step.prefix + '.lst'; var sympath = step.prefix + '.fns'; execMain(step, Module, [step.path, '-s', "-l", "2"]); // parse main listing, get errors and listings for each file var listings: CodeListingMap = {}; try { var alst = FS.readFile(lstpath, { 'encoding': 'utf8' }); // 16 00:C004 8E 17 40 STX $4017 ; disable APU frame IRQ var asmlines = parseListing(alst, /^\s*(\d+)\s+([0-9A-F]+):([0-9A-F]+)\s+([0-9A-F ]+?) (.*)/i, 1, 3, 4); putWorkFile(lstpath, alst); listings[lstpath] = { lines: asmlines, text: alst }; } catch (e) { // } if (errors.length) { return { errors: errors }; } // read binary rom output and symbols var aout, asym; aout = FS.readFile(binpath); try { asym = FS.readFile(sympath, { 'encoding': 'utf8' }); } catch (e) { console.log(e); errors.push({ line: 0, msg: "No symbol table generated, maybe missing ENDM or segment overflow?" }); return { errors: errors } } putWorkFile(binpath, aout); putWorkFile(sympath, asym); if (alst) putWorkFile(lstpath, alst); // listing optional (use LIST) // return unchanged if no files changed if (!anyTargetChanged(step, [binpath, sympath])) return; // parse symbols var symbolmap = {}; for (var s of asym.split("\n")) { if (!s.startsWith(';')) { var m = /(\w+)\s+=\s+[$]([0-9A-F]+)/.exec(s); if (m) { symbolmap[m[1]] = parseInt(m[2], 16); } } } return { output: aout, listings: listings, errors: errors, symbolmap: symbolmap, }; } /* ------+-------------------+-------------+----+---------+------+-----------------------+------------------------------------------------------------------- Line | # File Line | Line Type | MX | Reloc | Size | Address Object Code | Source Code ------+-------------------+-------------+----+---------+------+-----------------------+------------------------------------------------------------------- 1 | 1 zap.asm 1 | Unknown | ?? | | -1 | 00/FFFF | broak 2 | 1 zap.asm 2 | Comment | ?? | | -1 | 00/FFFF | * SPACEGAME => [Error] Impossible to decode address mode for instruction 'BNE KABOOM!' (line 315, file 'zap.asm') : The number of element in 'KABOOM!' is even (should be value [operator value [operator value]...]). => [Error] Unknown line 'foo' in source file 'zap.asm' (line 315) => Creating Object file 'pcs.bin' => Creating Output file 'pcs.bin_S01__Output.txt' */ export function assembleMerlin32(step: BuildStep): BuildStepResult { loadNative("merlin32"); var errors = []; var lstfiles = []; gatherFiles(step, { mainFilePath: "main.lnk" }); var objpath = step.prefix + ".bin"; if (staleFiles(step, [objpath])) { var args = ['-v', step.path]; var merlin32: EmscriptenModule = emglobal.merlin32({ instantiateWasm: moduleInstFn('merlin32'), noInitialRun: true, print: (s: string) => { var m = /\s*=>\s*Creating Output file '(.+?)'/.exec(s); if (m) { lstfiles.push(m[1]); } var errpos = s.indexOf('Error'); if (errpos >= 0) { s = s.slice(errpos + 6).trim(); var mline = /\bline (\d+)\b/.exec(s); var mpath = /\bfile '(.+?)'/.exec(s); errors.push({ line: parseInt(mline[1]) || 0, msg: s, path: mpath[1] || step.path, }); } }, printErr: print_fn, }); var FS = merlin32.FS; populateFiles(step, FS); execMain(step, merlin32, args); if (errors.length) return { errors: errors }; var errout = null; try { errout = FS.readFile("error_output.txt", { encoding: 'utf8' }); } catch (e) { // } var objout = FS.readFile(objpath, { encoding: 'binary' }); putWorkFile(objpath, objout); if (!anyTargetChanged(step, [objpath])) return; var symbolmap = {}; var segments = []; var listings: CodeListingMap = {}; lstfiles.forEach((lstfn) => { var lst = FS.readFile(lstfn, { encoding: 'utf8' }) as string; lst.split('\n').forEach((line) => { var toks = line.split(/\s*\|\s*/); if (toks && toks[6]) { var toks2 = toks[1].split(/\s+/); var toks3 = toks[6].split(/[:/]/, 4); var path = toks2[1]; if (path && toks2[2] && toks3[1]) { var lstline = { line: parseInt(toks2[2]), offset: parseInt(toks3[1].trim(), 16), insns: toks3[2], cycles: null, iscode: false // TODO }; var lst = listings[path]; if (!lst) listings[path] = lst = { lines: [] }; lst.lines.push(lstline); //console.log(path,toks2,toks3); } } }); }); return { output: objout, //.slice(0), listings: listings, errors: errors, symbolmap: symbolmap, segments: segments }; } } // README.md:2:5: parse error, expected: statement or variable assignment, integer variable, variable assignment export function compileFastBasic(step: BuildStep): BuildStepResult { // TODO: fastbasic-fp? loadNative("fastbasic-int"); var params = step.params; gatherFiles(step, { mainFilePath: "main.fb" }); var destpath = step.prefix + '.s'; var errors = []; if (staleFiles(step, [destpath])) { var fastbasic: EmscriptenModule = emglobal.fastbasic({ instantiateWasm: moduleInstFn('fastbasic-int'), noInitialRun: true, print: print_fn, printErr: makeErrorMatcher(errors, /(.+?):(\d+):(\d+):\s*(.+)/, 2, 4, step.path, 1), }); var FS = fastbasic.FS; populateFiles(step, FS); var libfile = 'fastbasic-int.lib' params.libargs = [libfile]; params.cfgfile = params.fastbasic_cfgfile; //params.extra_compile_args = ["--asm-define", "NO_SMCODE"]; params.extra_link_files = [libfile, params.cfgfile]; //fixParamsWithDefines(step.path, params); var args = [step.path, destpath]; execMain(step, fastbasic, args); if (errors.length) return { errors: errors }; var asmout = FS.readFile(destpath, { encoding: 'utf8' }); putWorkFile(destpath, asmout); } return { nexttool: "ca65", path: destpath, args: [destpath], files: [destpath], }; }