arm32: new vasm, new editor mode

This commit is contained in:
Steven Hugg 2021-06-08 12:49:37 -05:00
parent 76d29c6026
commit c99597ee28
10 changed files with 282 additions and 107 deletions

View File

@ -540,6 +540,7 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
<script src="src/codemirror/fastbasic.js"></script>
<script src="src/codemirror/basic.js"></script>
<script src="src/codemirror/wiz.js"></script>
<script src="src/codemirror/vasm.js"></script>
<link rel="stylesheet" href="css/codemirror.css">
<script src="codemirror/addon/edit/matchbrackets.js"></script>
<script src="codemirror/addon/search/search.js"></script>

98
src/codemirror/vasm.js Normal file
View File

@ -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");
});

View File

@ -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;
}
}

View File

@ -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) {

View File

@ -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 },

View File

@ -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;
}
}

View File

@ -231,13 +231,15 @@ export abstract class BaseARMMachinePlatform<T extends Machine> extends BaseMach
class ARM32Platform extends BaseARMMachinePlatform<ARM32Machine> 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<ARM32Machine> 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 {

View File

@ -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");

Binary file not shown.

View File

@ -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,