1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2024-11-18 03:05:35 +00:00
8bitworkshop/gen/worker/tools/cc65.js

332 lines
13 KiB
JavaScript
Raw Normal View History

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.compileCC65 = exports.linkLD65 = exports.assembleCA65 = void 0;
const util_1 = require("../../common/util");
const workermain_1 = require("../workermain");
/*
000000r 1 .segment "CODE"
000000r 1 .proc _rasterWait: near
000000r 1 ; int main() { return mul2(2); }
000000r 1 .dbg line, "main.c", 3
000014r 1 .dbg func, "main", "00", extern, "_main"
000000r 1 A2 00 ldx #$00
00B700 1 BOOT2:
00B700 1 A2 01 ldx #1 ;track
00B725 1 00 IBLASTDRVN: .byte 0
00B726 1 xx xx IBSECSZ: .res 2
00BA2F 1 2A 2B E8 2C HEX "2A2BE82C2D2E2F303132F0F133343536"
*/
function parseCA65Listing(code, symbols, params, dbg, listings) {
var segofs = 0;
var offset = 0;
var dbgLineMatch = /^([0-9A-F]+)([r]?)\s+(\d+)\s+[.]dbg\s+(\w+), "([^"]+)", (.+)/;
var funcLineMatch = /"(\w+)", (\w+), "(\w+)"/;
var insnLineMatch = /^([0-9A-F]+)([r]?)\s{1,2}(\d+)\s{1,2}([0-9A-Frx ]{11})\s+(.*)/;
var segMatch = /[.]segment\s+"(\w+)"/i;
var origlines = [];
var lines = origlines;
var linenum = 0;
let curpath = '';
// TODO: only does .c functions, not all .s files
for (var line of code.split(workermain_1.re_crlf)) {
var dbgm = dbgLineMatch.exec(line);
if (dbgm && dbgm[1]) {
var dbgtype = dbgm[4];
offset = parseInt(dbgm[1], 16);
curpath = dbgm[5];
// new file?
if (curpath && listings) {
let l = listings[curpath];
if (!l)
l = listings[curpath] = { lines: [] };
lines = l.lines;
}
if (dbgtype == 'func') {
var funcm = funcLineMatch.exec(dbgm[6]);
if (funcm) {
var funcofs = symbols[funcm[3]];
if (typeof funcofs === 'number') {
segofs = funcofs - offset;
//console.log(funcm[3], funcofs, '-', offset);
}
}
}
}
if (dbg && dbgm && dbgtype == 'line') {
//console.log(dbgm[5], dbgm[6], offset, segofs);
lines.push({
path: dbgm[5],
line: parseInt(dbgm[6]),
offset: offset + segofs,
insns: null
});
}
var linem = insnLineMatch.exec(line);
var topfile = linem && linem[3] == '1';
if (topfile)
linenum++;
if (topfile && linem[1]) {
var offset = parseInt(linem[1], 16);
var insns = linem[4].trim();
if (insns.length) {
// take back one to honor the long .byte line
if (linem[5].length == 0) {
linenum--;
}
else if (!dbg) {
lines.push({
path: curpath,
line: linenum,
offset: offset + segofs,
insns: insns,
iscode: true // TODO: can't really tell unless we parse it
});
}
}
else {
var sym = linem[5];
var segm = sym && segMatch.exec(sym);
if (segm && segm[1]) {
var symofs = symbols['__' + segm[1] + '_RUN__'];
if (typeof symofs === 'number') {
segofs = symofs;
//console.log(sym, segofs, symofs, '-', offset);
}
}
else if (sym.endsWith(':') && !sym.startsWith('@')) {
var symofs = symbols[sym.substring(0, sym.length - 1)];
if (typeof symofs === 'number') {
segofs = symofs - offset;
//console.log(sym, segofs, symofs, '-', offset);
}
}
}
}
}
return origlines;
}
function assembleCA65(step) {
(0, workermain_1.loadNative)("ca65");
var errors = [];
(0, workermain_1.gatherFiles)(step, { mainFilePath: "main.s" });
var objpath = step.prefix + ".o";
var lstpath = step.prefix + ".lst";
if ((0, workermain_1.staleFiles)(step, [objpath, lstpath])) {
var objout, lstout;
var CA65 = workermain_1.emglobal.ca65({
instantiateWasm: (0, workermain_1.moduleInstFn)('ca65'),
noInitialRun: true,
//logReadFiles:true,
print: workermain_1.print_fn,
printErr: (0, workermain_1.makeErrorMatcher)(errors, /(.+?):(\d+): (.+)/, 2, 3, step.path, 1),
});
var FS = CA65.FS;
(0, workermain_1.setupFS)(FS, '65-' + (0, util_1.getRootBasePlatform)(step.platform));
(0, workermain_1.populateFiles)(step, FS);
(0, workermain_1.fixParamsWithDefines)(step.path, step.params);
var args = ['-v', '-g', '-I', '/share/asminc', '-o', objpath, '-l', lstpath, step.path];
args.unshift.apply(args, ["-D", "__8BITWORKSHOP__=1"]);
if (step.mainfile) {
args.unshift.apply(args, ["-D", "__MAIN__=1"]);
}
(0, workermain_1.execMain)(step, CA65, args);
if (errors.length) {
// TODO?
let listings = {};
listings[step.path] = { lines: [], text: (0, workermain_1.getWorkFileAsString)(step.path) };
return { errors, listings };
}
objout = FS.readFile(objpath, { encoding: 'binary' });
lstout = FS.readFile(lstpath, { encoding: 'utf8' });
(0, workermain_1.putWorkFile)(objpath, objout);
(0, workermain_1.putWorkFile)(lstpath, lstout);
}
return {
linktool: "ld65",
files: [objpath, lstpath],
args: [objpath]
};
}
exports.assembleCA65 = assembleCA65;
function linkLD65(step) {
var _a;
(0, workermain_1.loadNative)("ld65");
var params = step.params;
(0, workermain_1.gatherFiles)(step);
var binpath = "main";
if ((0, workermain_1.staleFiles)(step, [binpath])) {
var errors = [];
var LD65 = workermain_1.emglobal.ld65({
instantiateWasm: (0, workermain_1.moduleInstFn)('ld65'),
noInitialRun: true,
//logReadFiles:true,
print: workermain_1.print_fn,
printErr: function (s) { errors.push({ msg: s, line: 0 }); }
});
var FS = LD65.FS;
(0, workermain_1.setupFS)(FS, '65-' + (0, util_1.getRootBasePlatform)(step.platform));
(0, workermain_1.populateFiles)(step, FS);
(0, workermain_1.populateExtraFiles)(step, FS, params.extra_link_files);
// populate .cfg file, if it is a custom one
if (workermain_1.store.hasFile(params.cfgfile)) {
(0, workermain_1.populateEntry)(FS, params.cfgfile, workermain_1.store.getFileEntry(params.cfgfile), null);
}
var libargs = params.libargs || [];
var cfgfile = params.cfgfile;
var args = ['--cfg-path', '/share/cfg',
'--lib-path', '/share/lib',
'-C', cfgfile,
'-Ln', 'main.vice',
//'--dbgfile', 'main.dbg', // TODO: get proper line numbers
'-o', 'main', '-m', 'main.map'].concat(step.args, libargs);
//console.log(args);
(0, workermain_1.execMain)(step, LD65, args);
if (errors.length)
return { errors: errors };
var aout = FS.readFile("main", { encoding: 'binary' });
var mapout = FS.readFile("main.map", { encoding: 'utf8' });
var viceout = FS.readFile("main.vice", { encoding: 'utf8' });
//var dbgout = FS.readFile("main.dbg", {encoding:'utf8'});
(0, workermain_1.putWorkFile)("main", aout);
(0, workermain_1.putWorkFile)("main.map", mapout);
(0, workermain_1.putWorkFile)("main.vice", viceout);
// return unchanged if no files changed
if (!(0, workermain_1.anyTargetChanged)(step, ["main", "main.map", "main.vice"]))
return;
// parse symbol map (TODO: omit segments, constants)
var symbolmap = {};
for (var s of viceout.split("\n")) {
var toks = s.split(" ");
if (toks[0] == 'al') {
let ident = toks[2].substr(1);
if (ident.length != 5 || !ident.startsWith('L')) { // no line numbers
let ofs = parseInt(toks[1], 16);
symbolmap[ident] = ofs;
}
}
}
// build segment map
var seg_re = /^__(\w+)_SIZE__$/;
// TODO: move to Platform class
var segments = [];
segments.push({ name: 'CPU Stack', start: 0x100, size: 0x100, type: 'ram' });
segments.push({ name: 'CPU Vectors', start: 0xfffa, size: 0x6, type: 'rom' });
// TODO: CHR, banks, etc
for (let ident in symbolmap) {
let m = seg_re.exec(ident);
if (m) {
let seg = m[1];
let segstart = symbolmap['__' + seg + '_RUN__'] || symbolmap['__' + seg + '_START__'];
let segsize = symbolmap['__' + seg + '_SIZE__'];
let seglast = symbolmap['__' + seg + '_LAST__'];
if (segstart >= 0 && segsize > 0 && !seg.startsWith('PRG') && seg != 'RAM') { // TODO
var type = null;
if (seg.startsWith('CODE') || seg == 'STARTUP' || seg == 'RODATA' || seg.endsWith('ROM'))
type = 'rom';
else if (seg == 'ZP' || seg == 'DATA' || seg == 'BSS' || seg.endsWith('RAM'))
type = 'ram';
segments.push({ name: seg, start: segstart, size: segsize, last: seglast, type: type });
}
}
}
// build listings
var listings = {};
for (var fn of step.files) {
if (fn.endsWith('.lst')) {
var lstout = FS.readFile(fn, { encoding: 'utf8' });
lstout = lstout.split('\n\n')[1] || lstout; // remove header
(0, workermain_1.putWorkFile)(fn, lstout);
console.log(step);
let isECS = ((_a = step.debuginfo) === null || _a === void 0 ? void 0 : _a.entities) != null; // TODO
if (isECS) {
var asmlines = [];
var srclines = parseCA65Listing(lstout, symbolmap, params, true, listings);
listings[fn] = {
lines: [],
text: lstout
};
}
else {
var asmlines = parseCA65Listing(lstout, symbolmap, params, false);
var srclines = parseCA65Listing(lstout, symbolmap, params, true); // TODO: listings param for ecs
listings[fn] = {
asmlines: srclines.length ? asmlines : null,
lines: srclines.length ? srclines : asmlines,
text: lstout
};
}
}
}
return {
output: aout,
listings: listings,
errors: errors,
symbolmap: symbolmap,
segments: segments
};
}
}
exports.linkLD65 = linkLD65;
function compileCC65(step) {
(0, workermain_1.loadNative)("cc65");
var params = step.params;
// stderr
var re_err1 = /(.*?):(\d+): (.+)/;
var errors = [];
var errline = 0;
function match_fn(s) {
console.log(s);
var matches = re_err1.exec(s);
if (matches) {
errline = parseInt(matches[2]);
errors.push({
line: errline,
msg: matches[3],
path: matches[1]
});
}
}
(0, workermain_1.gatherFiles)(step, { mainFilePath: "main.c" });
var destpath = step.prefix + '.s';
if ((0, workermain_1.staleFiles)(step, [destpath])) {
var CC65 = workermain_1.emglobal.cc65({
instantiateWasm: (0, workermain_1.moduleInstFn)('cc65'),
noInitialRun: true,
//logReadFiles:true,
print: workermain_1.print_fn,
printErr: match_fn,
});
var FS = CC65.FS;
(0, workermain_1.setupFS)(FS, '65-' + (0, util_1.getRootBasePlatform)(step.platform));
(0, workermain_1.populateFiles)(step, FS);
(0, workermain_1.fixParamsWithDefines)(step.path, params);
var args = [
'-I', '/share/include',
'-I', '.',
"-D", "__8BITWORKSHOP__",
];
if (params.define) {
params.define.forEach((x) => args.push('-D' + x));
}
if (step.mainfile) {
args.unshift.apply(args, ["-D", "__MAIN__"]);
}
var customArgs = params.extra_compiler_args || ['-T', '-g', '-Oirs', '-Cl', '-W', '-pointer-sign,-no-effect'];
args = args.concat(customArgs, args);
args.push(step.path);
//console.log(args);
(0, workermain_1.execMain)(step, CC65, args);
if (errors.length)
return { errors: errors };
var asmout = FS.readFile(destpath, { encoding: 'utf8' });
(0, workermain_1.putWorkFile)(destpath, asmout);
}
return {
nexttool: "ca65",
path: destpath,
args: [destpath],
files: [destpath],
};
}
exports.compileCC65 = compileCC65;
//# sourceMappingURL=cc65.js.map