diff --git a/index.html b/index.html index 4a5faf6f..5a1eb910 100644 --- a/index.html +++ b/index.html @@ -540,6 +540,7 @@ if (window.location.host.endsWith('8bitworkshop.com')) { + diff --git a/src/codemirror/vasm.js b/src/codemirror/vasm.js new file mode 100644 index 00000000..af9ad68c --- /dev/null +++ b/src/codemirror/vasm.js @@ -0,0 +1,98 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +// vasm DASM syntax + +CodeMirror.defineMode('vasm', function(_config, parserConfig) { + var keywords1, keywords2; + + var directives_list = [ + ]; + var directives = new Map(); + directives_list.forEach(function(s) { directives.set(s, 'keyword'); }); + + var opcodes = /^[a-z]+\b/; + var numbers = /^([\da-f]+h|[0-7]+o|[01]+b|\d+d?)\b/i; + + return { + startState: function() { + return { + context: 0 + }; + }, + token: function(stream, state) { + if (!stream.column()) { + state.context = 0; + } + if (stream.eatSpace()) { + if (!state.context) state.context = 1; + return null; + } + + var w; + if (stream.eatWhile(/\w/)) { + w = stream.current(); + var cur = w.toLowerCase(); + var style = directives.get(cur); + if (style) + return style; + if (stream.eat(':')) { + state.context = 1; + return 'tag'; + } + if (state.context == 1 && opcodes.test(w)) { + state.context = 4; + return 'keyword'; + } else if (state.context == 4 && numbers.test(w)) { + return 'number'; + } else if (stream.match(numbers)) { + return 'number'; + } else { + return null; + } + } else if (stream.eat('.')) { + if (stream.eatWhile(/[\w]/)) { + return 'meta'; + } + } else if (stream.eat(';')) { + stream.skipToEnd(); + return 'comment'; + } else if (stream.eat('"')) { + while (w = stream.next()) { + if (w == '"') + break; + + if (w == '\\') + stream.next(); + } + return 'string'; + } else if (stream.eat('\'')) { + if (stream.match(/\\?.'/)) + return 'number'; + } else if (stream.eat('$') || stream.eat('#')) { + if (stream.eatWhile(/[^;]/i)) + return 'number'; + } else if (stream.eat('%')) { + if (stream.eatWhile(/[01]/)) + return 'number'; + } else { + stream.next(); + } + return null; + } + }; +}); + +CodeMirror.defineMIME("text/x-vasm", "vasm"); + +}); diff --git a/src/common/cpu/ARM.ts b/src/common/cpu/ARM.ts index 9221793b..2a42a615 100644 --- a/src/common/cpu/ARM.ts +++ b/src/common/cpu/ARM.ts @@ -101,7 +101,8 @@ export interface ARMCoreState { bankedRegisters: number[][], spsr: number, bankedSPSRs: number[], - cycles: number + cycles: number, + instructionWidth: 2 | 4 } interface ARMCoreType { @@ -122,6 +123,7 @@ interface ARMCoreType { spsr: number; mmu: ARMMMUInterface; irq : ARMIRQInterface; + instructionWidth: 2 | 4; hasSPSR() : boolean; unpackCPSR(v : number) : void; @@ -148,6 +150,33 @@ export enum ARMMode { MODE_SYSTEM = 0x1F } +export enum ARMRegs { + SP = 13, + LR = 14, + PC = 15, +} + +export enum ARMConstants { + + BANK_NONE = 0, + BANK_FIQ = 1, + BANK_IRQ = 2, + BANK_SUPERVISOR = 3, + BANK_ABORT = 4, + BANK_UNDEFINED = 5, + + WORD_SIZE_ARM = 4, + WORD_SIZE_THUMB = 2, + + BASE_RESET = 0x00000000, + BASE_UNDEF = 0x00000004, + BASE_SWI = 0x00000008, + BASE_PABT = 0x0000000C, + BASE_DABT = 0x00000010, + BASE_IRQ = 0x00000018, + BASE_FIQ = 0x0000001C, +} + const UNALLOC_MASK = 0x0FFFFF00; const USER_MASK = 0xF0000000; const PRIV_MASK = 0x000000CF; // This is out of spec, but it seems to be what's done in other implementations @@ -2627,14 +2656,14 @@ function ARMCore() { }; ARMCore.prototype.resetCPU = function(startOffset) { - for (var i = 0; i < this.PC; ++i) { + for (var i = 0; i < ARMRegs.PC; ++i) { this.gprs[i] = 0; } - this.gprs[this.PC] = startOffset + this.WORD_SIZE_ARM; + this.gprs[ARMRegs.PC] = startOffset + ARMConstants.WORD_SIZE_ARM; this.loadInstruction = this.loadInstructionArm; this.execMode = ARMMode.MODE_ARM; - this.instructionWidth = this.WORD_SIZE_ARM; + this.instructionWidth = ARMConstants.WORD_SIZE_ARM; this.mode = ARMMode.MODE_SYSTEM; @@ -2674,21 +2703,21 @@ ARMCore.prototype.resetCPU = function(startOffset) { var mmu = this.mmu as ARMMMUInterface; this.step = function() { - var instruction = this.instruction || (this.instruction = this.loadInstruction(gprs[this.PC] - this.instructionWidth)); - gprs[this.PC] += this.instructionWidth; + var instruction = this.instruction || (this.instruction = this.loadInstruction(gprs[ARMRegs.PC] - this.instructionWidth)); + gprs[ARMRegs.PC] += this.instructionWidth; this.conditionPassed = true; instruction(); if (!instruction.writesPC) { if (this.instruction != null) { // We might have gotten an interrupt from the instruction if (instruction.next == null || instruction.next.page.invalid) { - instruction.next = this.loadInstruction(gprs[this.PC] - this.instructionWidth); + instruction.next = this.loadInstruction(gprs[ARMRegs.PC] - this.instructionWidth); } this.instruction = instruction.next; } } else { if (this.conditionPassed) { - var pc = gprs[this.PC] &= 0xFFFFFFFE; + var pc = gprs[ARMRegs.PC] &= 0xFFFFFFFE; if (this.execMode == ARMMode.MODE_ARM) { mmu.wait32(pc); mmu.waitPrefetch32(pc); @@ -2696,12 +2725,12 @@ ARMCore.prototype.resetCPU = function(startOffset) { mmu.wait(pc); mmu.waitPrefetch(pc); } - gprs[this.PC] += this.instructionWidth; + gprs[ARMRegs.PC] += this.instructionWidth; if (!instruction.fixedJump) { this.instruction = null; } else if (this.instruction != null) { if (instruction.next == null || instruction.next.page.invalid) { - instruction.next = this.loadInstruction(gprs[this.PC] - this.instructionWidth); + instruction.next = this.loadInstruction(gprs[ARMRegs.PC] - this.instructionWidth); } this.instruction = instruction.next; } @@ -2787,7 +2816,8 @@ ARMCore.prototype.freeze = function() : ARMCoreState { this.bankedSPSRs[4], this.bankedSPSRs[5] ], - 'cycles': this.cycles + 'cycles': this.cycles, + 'instructionWidth': this.instructionWidth, }; }; @@ -2860,6 +2890,10 @@ ARMCore.prototype.defrost = function(frost: ARMCoreState) { this.bankedSPSRs[5] = frost.bankedSPSRs[5]; this.cycles = frost.cycles; + + this.instructionWidth = frost.instructionWidth; + this.loadInstruction = frost.instructionWidth == 2 ? this.loadInstructionThumb : this.loadInstructionArm; + this.execMode = frost.instructionWidth == 2 ? ARMMode.MODE_THUMB : ARMMode.MODE_ARM; }; ARMCore.prototype.fetchPage = function(address : number) { @@ -2921,17 +2955,17 @@ ARMCore.prototype.selectBank = function(mode : ARMMode) { case ARMMode.MODE_USER: case ARMMode.MODE_SYSTEM: // No banked registers - return this.BANK_NONE; + return ARMConstants.BANK_NONE; case ARMMode.MODE_FIQ: - return this.BANK_FIQ; + return ARMConstants.BANK_FIQ; case ARMMode.MODE_IRQ: - return this.BANK_IRQ; + return ARMConstants.BANK_IRQ; case ARMMode.MODE_SUPERVISOR: - return this.BANK_SUPERVISOR; + return ARMConstants.BANK_SUPERVISOR; case ARMMode.MODE_ABORT: - return this.BANK_ABORT; + return ARMConstants.BANK_ABORT; case ARMMode.MODE_UNDEFINED: - return this.BANK_UNDEFINED; + return ARMConstants.BANK_UNDEFINED; default: throw new EmuHalt("Invalid user mode passed to selectBank"); } @@ -2941,10 +2975,10 @@ ARMCore.prototype.switchExecMode = function(newMode) { if (this.execMode != newMode) { this.execMode = newMode; if (newMode == ARMMode.MODE_ARM) { - this.instructionWidth = this.WORD_SIZE_ARM; + this.instructionWidth = ARMConstants.WORD_SIZE_ARM; this.loadInstruction = this.loadInstructionArm; } else { - this.instructionWidth = this.WORD_SIZE_THUMB; + this.instructionWidth = ARMConstants.WORD_SIZE_THUMB; this.loadInstruction = this.loadInstructionThumb; } } @@ -2963,8 +2997,8 @@ ARMCore.prototype.switchMode = function(newMode) { if (newBank != oldBank) { // TODO: support FIQ if (newMode == ARMMode.MODE_FIQ || this.mode == ARMMode.MODE_FIQ) { - var oldFiqBank = (oldBank == this.BANK_FIQ) ? 1 : 0; - var newFiqBank = (newBank == this.BANK_FIQ) ? 1 : 0; + var oldFiqBank = (oldBank == ARMConstants.BANK_FIQ) ? 1 : 0; + var newFiqBank = (newBank == ARMConstants.BANK_FIQ) ? 1 : 0; this.bankedRegisters[oldFiqBank][2] = this.gprs[8]; this.bankedRegisters[oldFiqBank][3] = this.gprs[9]; this.bankedRegisters[oldFiqBank][4] = this.gprs[10]; @@ -2976,10 +3010,10 @@ ARMCore.prototype.switchMode = function(newMode) { this.gprs[11] = this.bankedRegisters[newFiqBank][5]; this.gprs[12] = this.bankedRegisters[newFiqBank][6]; } - this.bankedRegisters[oldBank][0] = this.gprs[this.SP]; - this.bankedRegisters[oldBank][1] = this.gprs[this.LR]; - this.gprs[this.SP] = this.bankedRegisters[newBank][0]; - this.gprs[this.LR] = this.bankedRegisters[newBank][1]; + this.bankedRegisters[oldBank][0] = this.gprs[ARMRegs.SP]; + this.bankedRegisters[oldBank][1] = this.gprs[ARMRegs.LR]; + this.gprs[ARMRegs.SP] = this.bankedRegisters[newBank][0]; + this.gprs[ARMRegs.LR] = this.bankedRegisters[newBank][1]; this.bankedSPSRs[oldBank] = this.spsr; this.spsr = this.bankedSPSRs[newBank]; @@ -3018,8 +3052,8 @@ ARMCore.prototype.raiseIRQ = function() { var instructionWidth = this.instructionWidth; this.switchMode(ARMMode.MODE_IRQ); this.spsr = cpsr; - this.gprs[this.LR] = this.gprs[this.PC] - instructionWidth + 4; - this.gprs[this.PC] = this.BASE_IRQ + this.WORD_SIZE_ARM; + this.gprs[ARMRegs.LR] = this.gprs[ARMRegs.PC] - instructionWidth + 4; + this.gprs[ARMRegs.PC] = this.BASE_IRQ + ARMConstants.WORD_SIZE_ARM; this.instruction = null; this.switchExecMode(ARMMode.MODE_ARM); this.cpsrI = true; @@ -3030,8 +3064,8 @@ ARMCore.prototype.raiseTrap = function() { var instructionWidth = this.instructionWidth; this.switchMode(ARMMode.MODE_SUPERVISOR); this.spsr = cpsr; - this.gprs[this.LR] = this.gprs[this.PC] - instructionWidth; - this.gprs[this.PC] = this.BASE_SWI + this.WORD_SIZE_ARM; + this.gprs[ARMRegs.LR] = this.gprs[ARMRegs.PC] - instructionWidth; + this.gprs[ARMRegs.PC] = this.BASE_SWI + ARMConstants.WORD_SIZE_ARM; this.instruction = null; this.switchExecMode(ARMMode.MODE_ARM); this.cpsrI = true; @@ -3213,7 +3247,7 @@ ARMCore.prototype.compileArm = function(instruction) { // MRS var rd = (instruction & 0x0000F000) >> 12; op = this.armCompiler.constructMRS(rd, r, condOp); - op.writesPC = rd == this.PC; + op.writesPC = rd == ARMRegs.PC; } } else { // Data processing/FSR transfer @@ -3374,7 +3408,7 @@ ARMCore.prototype.compileArm = function(instruction) { } break; } - op.writesPC = rd == this.PC; + op.writesPC = rd == ARMRegs.PC; } } else if ((instruction & 0x0FB00FF0) == 0x01000090) { // Single data swap @@ -3386,7 +3420,7 @@ ARMCore.prototype.compileArm = function(instruction) { } else { op = this.armCompiler.constructSWP(rd, rn, rm, condOp); } - op.writesPC = rd == this.PC; + op.writesPC = rd == ARMRegs.PC; } else { switch (i) { case 0x00000000: @@ -3446,7 +3480,7 @@ ARMCore.prototype.compileArm = function(instruction) { op = this.armCompiler.constructSMLALS(rd, rn, rs, rm, condOp); break; } - op.writesPC = rd == this.PC; + op.writesPC = rd == ARMRegs.PC; } else { // Halfword and signed byte data transfer var load = instruction & 0x00100000; @@ -3465,7 +3499,7 @@ ARMCore.prototype.compileArm = function(instruction) { } else { address = this.armCompiler.constructAddressingMode23Register(instruction, rm, condOp); } - address.writesPC = !!w && rn == this.PC; + address.writesPC = !!w && rn == ARMRegs.PC; if ((instruction & 0x00000090) == 0x00000090) { if (load) { @@ -3489,7 +3523,7 @@ ARMCore.prototype.compileArm = function(instruction) { op = this.armCompiler.constructSTRH(rd, address, condOp); } } - op.writesPC = rd == this.PC || address.writesPC; + op.writesPC = rd == ARMRegs.PC || address.writesPC; } break; case 0x04000000: @@ -3541,7 +3575,7 @@ ARMCore.prototype.compileArm = function(instruction) { op = this.armCompiler.constructSTR(rd, address, condOp); } } - op.writesPC = rd == this.PC || address.writesPC; + op.writesPC = rd == ARMRegs.PC || address.writesPC; break; case 0x08000000: // Block data transfer @@ -3733,7 +3767,7 @@ ARMCore.prototype.compileThumb = function(instruction) { case 0x0000: // ADD(4) op = this.thumbCompiler.constructADD4(rd, rm) - op.writesPC = rd == this.PC; + op.writesPC = rd == ARMRegs.PC; break; case 0x0100: // CMP(3) @@ -3743,7 +3777,7 @@ ARMCore.prototype.compileThumb = function(instruction) { case 0x0200: // MOV(3) op = this.thumbCompiler.constructMOV3(rd, rm); - op.writesPC = rd == this.PC; + op.writesPC = rd == ARMRegs.PC; break; case 0x0300: // BX @@ -4198,4 +4232,7 @@ export class ARM32CPU implements CPU, InstructionBased, ARMMMUInterface, ARMIRQI } updateTimers() : void { } + isThumb() : boolean { + return this.core.instructionWidth == 2; + } } diff --git a/src/ide/ui.ts b/src/ide/ui.ts index bb88bd3d..8e0bb0db 100644 --- a/src/ide/ui.ts +++ b/src/ide/ui.ts @@ -84,7 +84,7 @@ var TOOL_TO_SOURCE_STYLE = { 'basic': 'basic', 'silice': 'verilog', 'wiz': 'text/x-wiz', - 'vasmarm': '6502' + 'vasmarm': 'vasm' } function gaEvent(category:string, action:string, label?:string, value?:string) { diff --git a/src/ide/views.ts b/src/ide/views.ts index d172a817..04737284 100644 --- a/src/ide/views.ts +++ b/src/ide/views.ts @@ -71,6 +71,7 @@ const MODEDEFS = { z80: { isAsm: true }, jsasm: { isAsm: true }, gas: { isAsm: true }, + vasm: { isAsm: true }, inform6: { theme: 'cobalt' }, markdown: { lineWrap: true }, fastbasic: { noGutters: true }, diff --git a/src/machine/arm32.ts b/src/machine/arm32.ts index 648b9f45..d415d539 100644 --- a/src/machine/arm32.ts +++ b/src/machine/arm32.ts @@ -89,12 +89,12 @@ export class ARM32Machine extends BasicScanlineMachine implements Debuggable { getDebugInfo?(category: string, state: EmuState) : string { var s = ''; var c = state.c as ARMCoreState; - for (var i=0; i<13; i++) { - s += lpad('r'+i, 3) + ' ' + hex(c.gprs[i],8) + '\n'; + const EXEC_MODE = {2:'Thumb',4:'ARM'}; + const REGNAMES = {15:'PC',14:'LR',13:'SP',12:'IP',11:'FP',9:'SB'}; + for (var i=0; i<16; i++) { + s += lpad(REGNAMES[i]||'',3) + lpad('r'+i, 5) + ' ' + hex(c.gprs[i],8) + '\n'; } - s += ' SP ' + hex(c.SP,8) + '\n'; - s += ' LR ' + hex(c.gprs[14],8) + '\n'; - s += ' PC ' + hex(c.PC,8) + '\n'; + s += 'Flags '; s += c.cpsrN ? " N" : " -"; s += c.cpsrV ? " V" : " -"; s += c.cpsrF ? " F" : " -"; @@ -102,10 +102,9 @@ export class ARM32Machine extends BasicScanlineMachine implements Debuggable { s += c.cpsrC ? " C" : " -"; s += c.cpsrI ? " I" : " -"; s += '\n'; - s += 'MODE ' + MODE_NAMES[c.mode]; - s += '\n'; - s += 'cycl ' + c.cycles; - s += '\n'; + s += 'MODE ' + EXEC_MODE[c.instructionWidth] + ' ' + MODE_NAMES[c.mode] + '\n'; + s += 'SPSR ' + hex(c.spsr,8) + '\n'; + s += 'cycl ' + c.cycles + '\n'; return s; } } diff --git a/src/platform/arm32.ts b/src/platform/arm32.ts index 351c0b17..68557e19 100644 --- a/src/platform/arm32.ts +++ b/src/platform/arm32.ts @@ -231,13 +231,15 @@ export abstract class BaseARMMachinePlatform extends BaseMach class ARM32Platform extends BaseARMMachinePlatform implements Platform { - capstone : any; + capstone_arm : any; + capstone_thumb : any; async start() { super.start(); console.log("Loading Capstone"); await loadScript('./lib/capstone-arm.min.js'); - this.capstone = new cs.Capstone(cs.ARCH_ARM, cs.MODE_ARM); + this.capstone_arm = new cs.Capstone(cs.ARCH_ARM, cs.MODE_ARM); + this.capstone_thumb = new cs.Capstone(cs.ARCH_ARM, cs.MODE_THUMB); } newMachine() { return new ARM32Machine(); } @@ -250,11 +252,13 @@ class ARM32Platform extends BaseARMMachinePlatform implements Plat {name:'Video RAM',start:0x40000000,size:0x20000,type:'ram'}, ] } }; disassemble(pc:number, read:(addr:number)=>number) : DisasmLine { + var is_thumb = this.machine.cpu.isThumb(); + var capstone = is_thumb ? this.capstone_thumb : this.capstone_arm; var buf = []; for (var i=0; i<4; i++) { buf[i] = read(pc+i); } - var insns = this.capstone.disasm(buf, pc, 4); + var insns = capstone.disasm(buf, pc, 4); var i0 = insns && insns[0]; if (i0) { return { diff --git a/src/worker/wasm/vasmarm_std.js b/src/worker/wasm/vasmarm_std.js index 8fa72141..3a77d013 100644 --- a/src/worker/wasm/vasmarm_std.js +++ b/src/worker/wasm/vasmarm_std.js @@ -750,8 +750,8 @@ var wasmMemory; // so this creates a (non-native-wasm) table for us. var wasmTable = new WebAssembly.Table({ - 'initial': 109, - 'maximum': 109, + 'initial': 111, + 'maximum': 111, 'element': 'anyfunc' }); @@ -1372,11 +1372,11 @@ function updateGlobalBufferAndViews(buf) { } var STATIC_BASE = 1024, - STACK_BASE = 5270320, + STACK_BASE = 5270912, STACKTOP = STACK_BASE, - STACK_MAX = 27440, - DYNAMIC_BASE = 5270320, - DYNAMICTOP_PTR = 27280; + STACK_MAX = 28032, + DYNAMIC_BASE = 5270912, + DYNAMICTOP_PTR = 27872; assert(STACK_BASE % 16 === 0, 'stack must start aligned'); assert(DYNAMIC_BASE % 16 === 0, 'heap must start aligned'); @@ -1940,7 +1940,7 @@ var ASM_CONSTS = { -// STATICTOP = STATIC_BASE + 26416; +// STATICTOP = STATIC_BASE + 27008; /* global initializers */ __ATINIT__.push({ func: function() { ___wasm_call_ctors() } }); @@ -4678,7 +4678,7 @@ var ASM_CONSTS = { } function _emscripten_get_sbrk_ptr() { - return 27280; + return 27872; } function _emscripten_memcpy_big(dest, src, num) { @@ -4871,6 +4871,12 @@ var stackRestore = Module["stackRestore"] = createExportWrapper("stackRestore"); /** @type {function(...*):?} */ var stackAlloc = Module["stackAlloc"] = createExportWrapper("stackAlloc"); +/** @type {function(...*):?} */ +var dynCall_iii = Module["dynCall_iii"] = createExportWrapper("dynCall_iii"); + +/** @type {function(...*):?} */ +var dynCall_vii = Module["dynCall_vii"] = createExportWrapper("dynCall_vii"); + /** @type {function(...*):?} */ var dynCall_vi = Module["dynCall_vi"] = createExportWrapper("dynCall_vi"); @@ -4889,18 +4895,12 @@ var dynCall_vijjiii = Module["dynCall_vijjiii"] = createExportWrapper("dynCall_v /** @type {function(...*):?} */ var dynCall_vjjjj = Module["dynCall_vjjjj"] = createExportWrapper("dynCall_vjjjj"); -/** @type {function(...*):?} */ -var dynCall_iii = Module["dynCall_iii"] = createExportWrapper("dynCall_iii"); - /** @type {function(...*):?} */ var dynCall_iiii = Module["dynCall_iiii"] = createExportWrapper("dynCall_iiii"); /** @type {function(...*):?} */ var dynCall_iidiiii = Module["dynCall_iidiiii"] = createExportWrapper("dynCall_iidiiii"); -/** @type {function(...*):?} */ -var dynCall_vii = Module["dynCall_vii"] = createExportWrapper("dynCall_vii"); - /** @type {function(...*):?} */ var dynCall_jiji = Module["dynCall_jiji"] = createExportWrapper("dynCall_jiji"); diff --git a/src/worker/wasm/vasmarm_std.wasm b/src/worker/wasm/vasmarm_std.wasm index ae4771a2..ac010d6f 100644 Binary files a/src/worker/wasm/vasmarm_std.wasm and b/src/worker/wasm/vasmarm_std.wasm differ diff --git a/src/worker/workermain.ts b/src/worker/workermain.ts index c74b6a66..be8dbed2 100644 --- a/src/worker/workermain.ts +++ b/src/worker/workermain.ts @@ -2910,22 +2910,43 @@ function assembleVASMARM(step:BuildStep) { /// TODO: match undefined symbols var re_err1 = /^(fatal error|error|warning)? (\d+) in line (\d+) of "(.+)": (.+)/; var re_err2 = /^(fatal error|error|warning)? (\d+): (.+)/; + var re_undefsym = /symbol <(.+?)>/; var errors : WorkerError[] = []; + var undefsyms = []; + function findUndefinedSymbols(line:string) { + // find undefined symbols in line + undefsyms.forEach((sym) => { + if (line.indexOf(sym) >= 0) { + console.log(sym,line); + errors.push({ + path:curpath, + line:curline, + msg:"Undefined symbol: " + sym, + }) + } + }); + } function match_fn(s) { - var matches = re_err1.exec(s); + let matches = re_err1.exec(s); if (matches) { errors.push({ line:parseInt(matches[3]), - path:matches[2], + path:matches[4], msg:matches[5], }); + console.log(matches); } else { matches = re_err2.exec(s); if (matches) { - errors.push({ - line:0, - msg:s, - }); + let m = re_undefsym.exec(matches[3]); + if (m) { + undefsyms.push(m[1]); + } else { + errors.push({ + line:0, + msg:s, + }); + } } else { console.log(s); } @@ -2937,7 +2958,7 @@ function assembleVASMARM(step:BuildStep) { var lstpath = step.prefix+".lst"; if (staleFiles(step, [objpath])) { - var args = [ '-Fbin', '-x', '-wfail', step.path, '-o', objpath, '-L', lstpath ]; + var args = [ '-Fbin', '-m7tdmi', '-x', '-wfail', step.path, '-o', objpath, '-L', lstpath ]; var vasm = emglobal.vasm({ instantiateWasm: moduleInstFn('vasmarm_std'), noInitialRun:true, @@ -2952,60 +2973,74 @@ function assembleVASMARM(step:BuildStep) { return {errors:errors}; } - var objout = FS.readFile(objpath, {encoding:'binary'}); - putWorkFile(objpath, objout); - if (!anyTargetChanged(step, [objpath])) - return; + if (undefsyms.length == 0) { + var objout = FS.readFile(objpath, {encoding:'binary'}); + putWorkFile(objpath, objout); + if (!anyTargetChanged(step, [objpath])) + return; + } var lstout = FS.readFile(lstpath, {encoding:'utf8'}); - //console.log(lstout); - // F00:0001 mov r0, #0x884400 ; RGB value - // S01:00000000: 11 0B A0 E3 22 07 80 E3 - // S01 .text - // F00 vidfill.vasm - // LOOP LAB (0x10) sec=.text + // 00:00000018 023020E0 14: eor r3, r0, r2 + // Source: "vidfill.vasm" + // 00: ".text" (0-40) + // LOOP 00:00000018 + // STACK S:20010000 var symbolmap = {}; - var segments = []; + var segments = []; // TODO var listings : CodeListingMap = {}; // TODO: parse listings - var re_lstline = /^F(\d+):(\d+)\s+(.+)/; - var re_secline = /^\s+S(\d+):([0-9A-F]+):\s*([0-9A-F ]+)/; - var re_nameline = /^([SF])(\d+)\s+(.+)/; - var files = {}; + var re_asmline = /^(\d+):([0-9A-F]+)\s+([0-9A-F ]+)\s+(\d+)([:M])/; + var re_secline = /^(\d+):\s+"(.+)"/; + var re_nameline = /^Source:\s+"(.+)"/; + var re_symline = /^(\w+)\s+(\d+):([0-9A-F]+)/; + var re_emptyline = /^\s+(\d+)([:M])/; + var curpath = step.path; + var curline = 0; var sections = {}; // map file and section indices -> names - var lines = lstout.split(re_crlf); - for (var line of lines) { - var m; - if (m = re_nameline.exec(line)) { - if (m[1] == 'F') { - files[m[2]] = m[3]; - } else { - sections[m[2]] = m[3]; - } - } - } - //console.log(files, sections); + var lines : string[] = lstout.split(re_crlf); // parse lines var lstlines : SourceLine[] = []; - var linenum = 0; for (var line of lines) { var m; - if (m = re_lstline.exec(line)) { - linenum = parseInt(m[2]); - } else if (m = re_secline.exec(line)) { + if (m = re_secline.exec(line)) { + sections[m[1]] = m[2]; + } else if (m = re_nameline.exec(line)) { + curpath = m[1]; + } else if (m = re_symline.exec(line)) { + symbolmap[m[1]] = parseInt(m[3], 16); + } else if (m = re_asmline.exec(line)) { + if (m[5] == ':') { + curline = parseInt(m[4]); + } else { + // TODO: macro line + } lstlines.push({ - line: linenum, + path: curpath, + line: curline, offset: parseInt(m[2], 16), - path: step.path, insns: m[3].replaceAll(' ','') }); + findUndefinedSymbols(line); + } else if (m = re_emptyline.exec(line)) { + curline = parseInt(m[1]); + findUndefinedSymbols(line); + } else { + //console.log(line); } } - listings[lstpath] = {lines:lstlines}; + listings[lstpath] = {lines:lstlines, text:lstout}; + // catch-all if no error generated + if (undefsyms.length && errors.length == 0) { + errors.push({ + line: 0, + msg: 'Undefined symbols: ' + undefsyms.join(', ') + }) + } return { - output:objout, //.slice(0), + output:objout, //.slice(0x34), listings:listings, errors:errors, symbolmap:symbolmap,