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/fastbasic.js"></script>
<script src="src/codemirror/basic.js"></script> <script src="src/codemirror/basic.js"></script>
<script src="src/codemirror/wiz.js"></script> <script src="src/codemirror/wiz.js"></script>
<script src="src/codemirror/vasm.js"></script>
<link rel="stylesheet" href="css/codemirror.css"> <link rel="stylesheet" href="css/codemirror.css">
<script src="codemirror/addon/edit/matchbrackets.js"></script> <script src="codemirror/addon/edit/matchbrackets.js"></script>
<script src="codemirror/addon/search/search.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[][], bankedRegisters: number[][],
spsr: number, spsr: number,
bankedSPSRs: number[], bankedSPSRs: number[],
cycles: number cycles: number,
instructionWidth: 2 | 4
} }
interface ARMCoreType { interface ARMCoreType {
@ -122,6 +123,7 @@ interface ARMCoreType {
spsr: number; spsr: number;
mmu: ARMMMUInterface; mmu: ARMMMUInterface;
irq : ARMIRQInterface; irq : ARMIRQInterface;
instructionWidth: 2 | 4;
hasSPSR() : boolean; hasSPSR() : boolean;
unpackCPSR(v : number) : void; unpackCPSR(v : number) : void;
@ -148,6 +150,33 @@ export enum ARMMode {
MODE_SYSTEM = 0x1F 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 UNALLOC_MASK = 0x0FFFFF00;
const USER_MASK = 0xF0000000; const USER_MASK = 0xF0000000;
const PRIV_MASK = 0x000000CF; // This is out of spec, but it seems to be what's done in other implementations 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) { 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[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.loadInstruction = this.loadInstructionArm;
this.execMode = ARMMode.MODE_ARM; this.execMode = ARMMode.MODE_ARM;
this.instructionWidth = this.WORD_SIZE_ARM; this.instructionWidth = ARMConstants.WORD_SIZE_ARM;
this.mode = ARMMode.MODE_SYSTEM; this.mode = ARMMode.MODE_SYSTEM;
@ -2674,21 +2703,21 @@ ARMCore.prototype.resetCPU = function(startOffset) {
var mmu = this.mmu as ARMMMUInterface; var mmu = this.mmu as ARMMMUInterface;
this.step = function() { this.step = function() {
var instruction = this.instruction || (this.instruction = this.loadInstruction(gprs[this.PC] - this.instructionWidth)); var instruction = this.instruction || (this.instruction = this.loadInstruction(gprs[ARMRegs.PC] - this.instructionWidth));
gprs[this.PC] += this.instructionWidth; gprs[ARMRegs.PC] += this.instructionWidth;
this.conditionPassed = true; this.conditionPassed = true;
instruction(); instruction();
if (!instruction.writesPC) { if (!instruction.writesPC) {
if (this.instruction != null) { // We might have gotten an interrupt from the instruction if (this.instruction != null) { // We might have gotten an interrupt from the instruction
if (instruction.next == null || instruction.next.page.invalid) { 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; this.instruction = instruction.next;
} }
} else { } else {
if (this.conditionPassed) { if (this.conditionPassed) {
var pc = gprs[this.PC] &= 0xFFFFFFFE; var pc = gprs[ARMRegs.PC] &= 0xFFFFFFFE;
if (this.execMode == ARMMode.MODE_ARM) { if (this.execMode == ARMMode.MODE_ARM) {
mmu.wait32(pc); mmu.wait32(pc);
mmu.waitPrefetch32(pc); mmu.waitPrefetch32(pc);
@ -2696,12 +2725,12 @@ ARMCore.prototype.resetCPU = function(startOffset) {
mmu.wait(pc); mmu.wait(pc);
mmu.waitPrefetch(pc); mmu.waitPrefetch(pc);
} }
gprs[this.PC] += this.instructionWidth; gprs[ARMRegs.PC] += this.instructionWidth;
if (!instruction.fixedJump) { if (!instruction.fixedJump) {
this.instruction = null; this.instruction = null;
} else if (this.instruction != null) { } else if (this.instruction != null) {
if (instruction.next == null || instruction.next.page.invalid) { 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; this.instruction = instruction.next;
} }
@ -2787,7 +2816,8 @@ ARMCore.prototype.freeze = function() : ARMCoreState {
this.bankedSPSRs[4], this.bankedSPSRs[4],
this.bankedSPSRs[5] 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.bankedSPSRs[5] = frost.bankedSPSRs[5];
this.cycles = frost.cycles; 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) { ARMCore.prototype.fetchPage = function(address : number) {
@ -2921,17 +2955,17 @@ ARMCore.prototype.selectBank = function(mode : ARMMode) {
case ARMMode.MODE_USER: case ARMMode.MODE_USER:
case ARMMode.MODE_SYSTEM: case ARMMode.MODE_SYSTEM:
// No banked registers // No banked registers
return this.BANK_NONE; return ARMConstants.BANK_NONE;
case ARMMode.MODE_FIQ: case ARMMode.MODE_FIQ:
return this.BANK_FIQ; return ARMConstants.BANK_FIQ;
case ARMMode.MODE_IRQ: case ARMMode.MODE_IRQ:
return this.BANK_IRQ; return ARMConstants.BANK_IRQ;
case ARMMode.MODE_SUPERVISOR: case ARMMode.MODE_SUPERVISOR:
return this.BANK_SUPERVISOR; return ARMConstants.BANK_SUPERVISOR;
case ARMMode.MODE_ABORT: case ARMMode.MODE_ABORT:
return this.BANK_ABORT; return ARMConstants.BANK_ABORT;
case ARMMode.MODE_UNDEFINED: case ARMMode.MODE_UNDEFINED:
return this.BANK_UNDEFINED; return ARMConstants.BANK_UNDEFINED;
default: default:
throw new EmuHalt("Invalid user mode passed to selectBank"); throw new EmuHalt("Invalid user mode passed to selectBank");
} }
@ -2941,10 +2975,10 @@ ARMCore.prototype.switchExecMode = function(newMode) {
if (this.execMode != newMode) { if (this.execMode != newMode) {
this.execMode = newMode; this.execMode = newMode;
if (newMode == ARMMode.MODE_ARM) { if (newMode == ARMMode.MODE_ARM) {
this.instructionWidth = this.WORD_SIZE_ARM; this.instructionWidth = ARMConstants.WORD_SIZE_ARM;
this.loadInstruction = this.loadInstructionArm; this.loadInstruction = this.loadInstructionArm;
} else { } else {
this.instructionWidth = this.WORD_SIZE_THUMB; this.instructionWidth = ARMConstants.WORD_SIZE_THUMB;
this.loadInstruction = this.loadInstructionThumb; this.loadInstruction = this.loadInstructionThumb;
} }
} }
@ -2963,8 +2997,8 @@ ARMCore.prototype.switchMode = function(newMode) {
if (newBank != oldBank) { if (newBank != oldBank) {
// TODO: support FIQ // TODO: support FIQ
if (newMode == ARMMode.MODE_FIQ || this.mode == ARMMode.MODE_FIQ) { if (newMode == ARMMode.MODE_FIQ || this.mode == ARMMode.MODE_FIQ) {
var oldFiqBank = (oldBank == this.BANK_FIQ) ? 1 : 0; var oldFiqBank = (oldBank == ARMConstants.BANK_FIQ) ? 1 : 0;
var newFiqBank = (newBank == this.BANK_FIQ) ? 1 : 0; var newFiqBank = (newBank == ARMConstants.BANK_FIQ) ? 1 : 0;
this.bankedRegisters[oldFiqBank][2] = this.gprs[8]; this.bankedRegisters[oldFiqBank][2] = this.gprs[8];
this.bankedRegisters[oldFiqBank][3] = this.gprs[9]; this.bankedRegisters[oldFiqBank][3] = this.gprs[9];
this.bankedRegisters[oldFiqBank][4] = this.gprs[10]; 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[11] = this.bankedRegisters[newFiqBank][5];
this.gprs[12] = this.bankedRegisters[newFiqBank][6]; this.gprs[12] = this.bankedRegisters[newFiqBank][6];
} }
this.bankedRegisters[oldBank][0] = this.gprs[this.SP]; this.bankedRegisters[oldBank][0] = this.gprs[ARMRegs.SP];
this.bankedRegisters[oldBank][1] = this.gprs[this.LR]; this.bankedRegisters[oldBank][1] = this.gprs[ARMRegs.LR];
this.gprs[this.SP] = this.bankedRegisters[newBank][0]; this.gprs[ARMRegs.SP] = this.bankedRegisters[newBank][0];
this.gprs[this.LR] = this.bankedRegisters[newBank][1]; this.gprs[ARMRegs.LR] = this.bankedRegisters[newBank][1];
this.bankedSPSRs[oldBank] = this.spsr; this.bankedSPSRs[oldBank] = this.spsr;
this.spsr = this.bankedSPSRs[newBank]; this.spsr = this.bankedSPSRs[newBank];
@ -3018,8 +3052,8 @@ ARMCore.prototype.raiseIRQ = function() {
var instructionWidth = this.instructionWidth; var instructionWidth = this.instructionWidth;
this.switchMode(ARMMode.MODE_IRQ); this.switchMode(ARMMode.MODE_IRQ);
this.spsr = cpsr; this.spsr = cpsr;
this.gprs[this.LR] = this.gprs[this.PC] - instructionWidth + 4; this.gprs[ARMRegs.LR] = this.gprs[ARMRegs.PC] - instructionWidth + 4;
this.gprs[this.PC] = this.BASE_IRQ + this.WORD_SIZE_ARM; this.gprs[ARMRegs.PC] = this.BASE_IRQ + ARMConstants.WORD_SIZE_ARM;
this.instruction = null; this.instruction = null;
this.switchExecMode(ARMMode.MODE_ARM); this.switchExecMode(ARMMode.MODE_ARM);
this.cpsrI = true; this.cpsrI = true;
@ -3030,8 +3064,8 @@ ARMCore.prototype.raiseTrap = function() {
var instructionWidth = this.instructionWidth; var instructionWidth = this.instructionWidth;
this.switchMode(ARMMode.MODE_SUPERVISOR); this.switchMode(ARMMode.MODE_SUPERVISOR);
this.spsr = cpsr; this.spsr = cpsr;
this.gprs[this.LR] = this.gprs[this.PC] - instructionWidth; this.gprs[ARMRegs.LR] = this.gprs[ARMRegs.PC] - instructionWidth;
this.gprs[this.PC] = this.BASE_SWI + this.WORD_SIZE_ARM; this.gprs[ARMRegs.PC] = this.BASE_SWI + ARMConstants.WORD_SIZE_ARM;
this.instruction = null; this.instruction = null;
this.switchExecMode(ARMMode.MODE_ARM); this.switchExecMode(ARMMode.MODE_ARM);
this.cpsrI = true; this.cpsrI = true;
@ -3213,7 +3247,7 @@ ARMCore.prototype.compileArm = function(instruction) {
// MRS // MRS
var rd = (instruction & 0x0000F000) >> 12; var rd = (instruction & 0x0000F000) >> 12;
op = this.armCompiler.constructMRS(rd, r, condOp); op = this.armCompiler.constructMRS(rd, r, condOp);
op.writesPC = rd == this.PC; op.writesPC = rd == ARMRegs.PC;
} }
} else { } else {
// Data processing/FSR transfer // Data processing/FSR transfer
@ -3374,7 +3408,7 @@ ARMCore.prototype.compileArm = function(instruction) {
} }
break; break;
} }
op.writesPC = rd == this.PC; op.writesPC = rd == ARMRegs.PC;
} }
} else if ((instruction & 0x0FB00FF0) == 0x01000090) { } else if ((instruction & 0x0FB00FF0) == 0x01000090) {
// Single data swap // Single data swap
@ -3386,7 +3420,7 @@ ARMCore.prototype.compileArm = function(instruction) {
} else { } else {
op = this.armCompiler.constructSWP(rd, rn, rm, condOp); op = this.armCompiler.constructSWP(rd, rn, rm, condOp);
} }
op.writesPC = rd == this.PC; op.writesPC = rd == ARMRegs.PC;
} else { } else {
switch (i) { switch (i) {
case 0x00000000: case 0x00000000:
@ -3446,7 +3480,7 @@ ARMCore.prototype.compileArm = function(instruction) {
op = this.armCompiler.constructSMLALS(rd, rn, rs, rm, condOp); op = this.armCompiler.constructSMLALS(rd, rn, rs, rm, condOp);
break; break;
} }
op.writesPC = rd == this.PC; op.writesPC = rd == ARMRegs.PC;
} else { } else {
// Halfword and signed byte data transfer // Halfword and signed byte data transfer
var load = instruction & 0x00100000; var load = instruction & 0x00100000;
@ -3465,7 +3499,7 @@ ARMCore.prototype.compileArm = function(instruction) {
} else { } else {
address = this.armCompiler.constructAddressingMode23Register(instruction, rm, condOp); address = this.armCompiler.constructAddressingMode23Register(instruction, rm, condOp);
} }
address.writesPC = !!w && rn == this.PC; address.writesPC = !!w && rn == ARMRegs.PC;
if ((instruction & 0x00000090) == 0x00000090) { if ((instruction & 0x00000090) == 0x00000090) {
if (load) { if (load) {
@ -3489,7 +3523,7 @@ ARMCore.prototype.compileArm = function(instruction) {
op = this.armCompiler.constructSTRH(rd, address, condOp); op = this.armCompiler.constructSTRH(rd, address, condOp);
} }
} }
op.writesPC = rd == this.PC || address.writesPC; op.writesPC = rd == ARMRegs.PC || address.writesPC;
} }
break; break;
case 0x04000000: case 0x04000000:
@ -3541,7 +3575,7 @@ ARMCore.prototype.compileArm = function(instruction) {
op = this.armCompiler.constructSTR(rd, address, condOp); op = this.armCompiler.constructSTR(rd, address, condOp);
} }
} }
op.writesPC = rd == this.PC || address.writesPC; op.writesPC = rd == ARMRegs.PC || address.writesPC;
break; break;
case 0x08000000: case 0x08000000:
// Block data transfer // Block data transfer
@ -3733,7 +3767,7 @@ ARMCore.prototype.compileThumb = function(instruction) {
case 0x0000: case 0x0000:
// ADD(4) // ADD(4)
op = this.thumbCompiler.constructADD4(rd, rm) op = this.thumbCompiler.constructADD4(rd, rm)
op.writesPC = rd == this.PC; op.writesPC = rd == ARMRegs.PC;
break; break;
case 0x0100: case 0x0100:
// CMP(3) // CMP(3)
@ -3743,7 +3777,7 @@ ARMCore.prototype.compileThumb = function(instruction) {
case 0x0200: case 0x0200:
// MOV(3) // MOV(3)
op = this.thumbCompiler.constructMOV3(rd, rm); op = this.thumbCompiler.constructMOV3(rd, rm);
op.writesPC = rd == this.PC; op.writesPC = rd == ARMRegs.PC;
break; break;
case 0x0300: case 0x0300:
// BX // BX
@ -4198,4 +4232,7 @@ export class ARM32CPU implements CPU, InstructionBased, ARMMMUInterface, ARMIRQI
} }
updateTimers() : void { updateTimers() : void {
} }
isThumb() : boolean {
return this.core.instructionWidth == 2;
}
} }

View File

@ -84,7 +84,7 @@ var TOOL_TO_SOURCE_STYLE = {
'basic': 'basic', 'basic': 'basic',
'silice': 'verilog', 'silice': 'verilog',
'wiz': 'text/x-wiz', 'wiz': 'text/x-wiz',
'vasmarm': '6502' 'vasmarm': 'vasm'
} }
function gaEvent(category:string, action:string, label?:string, value?:string) { function gaEvent(category:string, action:string, label?:string, value?:string) {

View File

@ -71,6 +71,7 @@ const MODEDEFS = {
z80: { isAsm: true }, z80: { isAsm: true },
jsasm: { isAsm: true }, jsasm: { isAsm: true },
gas: { isAsm: true }, gas: { isAsm: true },
vasm: { isAsm: true },
inform6: { theme: 'cobalt' }, inform6: { theme: 'cobalt' },
markdown: { lineWrap: true }, markdown: { lineWrap: true },
fastbasic: { noGutters: true }, fastbasic: { noGutters: true },

View File

@ -89,12 +89,12 @@ export class ARM32Machine extends BasicScanlineMachine implements Debuggable {
getDebugInfo?(category: string, state: EmuState) : string { getDebugInfo?(category: string, state: EmuState) : string {
var s = ''; var s = '';
var c = state.c as ARMCoreState; var c = state.c as ARMCoreState;
for (var i=0; i<13; i++) { const EXEC_MODE = {2:'Thumb',4:'ARM'};
s += lpad('r'+i, 3) + ' ' + hex(c.gprs[i],8) + '\n'; 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 += 'Flags ';
s += ' LR ' + hex(c.gprs[14],8) + '\n';
s += ' PC ' + hex(c.PC,8) + '\n';
s += c.cpsrN ? " N" : " -"; s += c.cpsrN ? " N" : " -";
s += c.cpsrV ? " V" : " -"; s += c.cpsrV ? " V" : " -";
s += c.cpsrF ? " F" : " -"; s += c.cpsrF ? " F" : " -";
@ -102,10 +102,9 @@ export class ARM32Machine extends BasicScanlineMachine implements Debuggable {
s += c.cpsrC ? " C" : " -"; s += c.cpsrC ? " C" : " -";
s += c.cpsrI ? " I" : " -"; s += c.cpsrI ? " I" : " -";
s += '\n'; s += '\n';
s += 'MODE ' + MODE_NAMES[c.mode]; s += 'MODE ' + EXEC_MODE[c.instructionWidth] + ' ' + MODE_NAMES[c.mode] + '\n';
s += '\n'; s += 'SPSR ' + hex(c.spsr,8) + '\n';
s += 'cycl ' + c.cycles; s += 'cycl ' + c.cycles + '\n';
s += '\n';
return s; return s;
} }
} }

View File

@ -231,13 +231,15 @@ export abstract class BaseARMMachinePlatform<T extends Machine> extends BaseMach
class ARM32Platform extends BaseARMMachinePlatform<ARM32Machine> implements Platform { class ARM32Platform extends BaseARMMachinePlatform<ARM32Machine> implements Platform {
capstone : any; capstone_arm : any;
capstone_thumb : any;
async start() { async start() {
super.start(); super.start();
console.log("Loading Capstone"); console.log("Loading Capstone");
await loadScript('./lib/capstone-arm.min.js'); 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(); } newMachine() { return new ARM32Machine(); }
@ -250,11 +252,13 @@ class ARM32Platform extends BaseARMMachinePlatform<ARM32Machine> implements Plat
{name:'Video RAM',start:0x40000000,size:0x20000,type:'ram'}, {name:'Video RAM',start:0x40000000,size:0x20000,type:'ram'},
] } }; ] } };
disassemble(pc:number, read:(addr:number)=>number) : DisasmLine { 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 = []; var buf = [];
for (var i=0; i<4; i++) { for (var i=0; i<4; i++) {
buf[i] = read(pc+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]; var i0 = insns && insns[0];
if (i0) { if (i0) {
return { return {

View File

@ -750,8 +750,8 @@ var wasmMemory;
// so this creates a (non-native-wasm) table for us. // so this creates a (non-native-wasm) table for us.
var wasmTable = new WebAssembly.Table({ var wasmTable = new WebAssembly.Table({
'initial': 109, 'initial': 111,
'maximum': 109, 'maximum': 111,
'element': 'anyfunc' 'element': 'anyfunc'
}); });
@ -1372,11 +1372,11 @@ function updateGlobalBufferAndViews(buf) {
} }
var STATIC_BASE = 1024, var STATIC_BASE = 1024,
STACK_BASE = 5270320, STACK_BASE = 5270912,
STACKTOP = STACK_BASE, STACKTOP = STACK_BASE,
STACK_MAX = 27440, STACK_MAX = 28032,
DYNAMIC_BASE = 5270320, DYNAMIC_BASE = 5270912,
DYNAMICTOP_PTR = 27280; DYNAMICTOP_PTR = 27872;
assert(STACK_BASE % 16 === 0, 'stack must start aligned'); assert(STACK_BASE % 16 === 0, 'stack must start aligned');
assert(DYNAMIC_BASE % 16 === 0, 'heap 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() } }); /* global initializers */ __ATINIT__.push({ func: function() { ___wasm_call_ctors() } });
@ -4678,7 +4678,7 @@ var ASM_CONSTS = {
} }
function _emscripten_get_sbrk_ptr() { function _emscripten_get_sbrk_ptr() {
return 27280; return 27872;
} }
function _emscripten_memcpy_big(dest, src, num) { function _emscripten_memcpy_big(dest, src, num) {
@ -4871,6 +4871,12 @@ var stackRestore = Module["stackRestore"] = createExportWrapper("stackRestore");
/** @type {function(...*):?} */ /** @type {function(...*):?} */
var stackAlloc = Module["stackAlloc"] = createExportWrapper("stackAlloc"); 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(...*):?} */ /** @type {function(...*):?} */
var dynCall_vi = Module["dynCall_vi"] = createExportWrapper("dynCall_vi"); var dynCall_vi = Module["dynCall_vi"] = createExportWrapper("dynCall_vi");
@ -4889,18 +4895,12 @@ var dynCall_vijjiii = Module["dynCall_vijjiii"] = createExportWrapper("dynCall_v
/** @type {function(...*):?} */ /** @type {function(...*):?} */
var dynCall_vjjjj = Module["dynCall_vjjjj"] = createExportWrapper("dynCall_vjjjj"); var dynCall_vjjjj = Module["dynCall_vjjjj"] = createExportWrapper("dynCall_vjjjj");
/** @type {function(...*):?} */
var dynCall_iii = Module["dynCall_iii"] = createExportWrapper("dynCall_iii");
/** @type {function(...*):?} */ /** @type {function(...*):?} */
var dynCall_iiii = Module["dynCall_iiii"] = createExportWrapper("dynCall_iiii"); var dynCall_iiii = Module["dynCall_iiii"] = createExportWrapper("dynCall_iiii");
/** @type {function(...*):?} */ /** @type {function(...*):?} */
var dynCall_iidiiii = Module["dynCall_iidiiii"] = createExportWrapper("dynCall_iidiiii"); var dynCall_iidiiii = Module["dynCall_iidiiii"] = createExportWrapper("dynCall_iidiiii");
/** @type {function(...*):?} */
var dynCall_vii = Module["dynCall_vii"] = createExportWrapper("dynCall_vii");
/** @type {function(...*):?} */ /** @type {function(...*):?} */
var dynCall_jiji = Module["dynCall_jiji"] = createExportWrapper("dynCall_jiji"); 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 /// TODO: match undefined symbols
var re_err1 = /^(fatal error|error|warning)? (\d+) in line (\d+) of "(.+)": (.+)/; var re_err1 = /^(fatal error|error|warning)? (\d+) in line (\d+) of "(.+)": (.+)/;
var re_err2 = /^(fatal error|error|warning)? (\d+): (.+)/; var re_err2 = /^(fatal error|error|warning)? (\d+): (.+)/;
var re_undefsym = /symbol <(.+?)>/;
var errors : WorkerError[] = []; 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) { function match_fn(s) {
var matches = re_err1.exec(s); let matches = re_err1.exec(s);
if (matches) { if (matches) {
errors.push({ errors.push({
line:parseInt(matches[3]), line:parseInt(matches[3]),
path:matches[2], path:matches[4],
msg:matches[5], msg:matches[5],
}); });
console.log(matches);
} else { } else {
matches = re_err2.exec(s); matches = re_err2.exec(s);
if (matches) { if (matches) {
errors.push({ let m = re_undefsym.exec(matches[3]);
line:0, if (m) {
msg:s, undefsyms.push(m[1]);
}); } else {
errors.push({
line:0,
msg:s,
});
}
} else { } else {
console.log(s); console.log(s);
} }
@ -2937,7 +2958,7 @@ function assembleVASMARM(step:BuildStep) {
var lstpath = step.prefix+".lst"; var lstpath = step.prefix+".lst";
if (staleFiles(step, [objpath])) { 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({ var vasm = emglobal.vasm({
instantiateWasm: moduleInstFn('vasmarm_std'), instantiateWasm: moduleInstFn('vasmarm_std'),
noInitialRun:true, noInitialRun:true,
@ -2952,60 +2973,74 @@ function assembleVASMARM(step:BuildStep) {
return {errors:errors}; return {errors:errors};
} }
var objout = FS.readFile(objpath, {encoding:'binary'}); if (undefsyms.length == 0) {
putWorkFile(objpath, objout); var objout = FS.readFile(objpath, {encoding:'binary'});
if (!anyTargetChanged(step, [objpath])) putWorkFile(objpath, objout);
return; if (!anyTargetChanged(step, [objpath]))
return;
}
var lstout = FS.readFile(lstpath, {encoding:'utf8'}); var lstout = FS.readFile(lstpath, {encoding:'utf8'});
//console.log(lstout); // 00:00000018 023020E0 14: eor r3, r0, r2
// F00:0001 mov r0, #0x884400 ; RGB value // Source: "vidfill.vasm"
// S01:00000000: 11 0B A0 E3 22 07 80 E3 // 00: ".text" (0-40)
// S01 .text // LOOP 00:00000018
// F00 vidfill.vasm // STACK S:20010000
// LOOP LAB (0x10) sec=.text
var symbolmap = {}; var symbolmap = {};
var segments = []; var segments = []; // TODO
var listings : CodeListingMap = {}; var listings : CodeListingMap = {};
// TODO: parse listings // TODO: parse listings
var re_lstline = /^F(\d+):(\d+)\s+(.+)/; var re_asmline = /^(\d+):([0-9A-F]+)\s+([0-9A-F ]+)\s+(\d+)([:M])/;
var re_secline = /^\s+S(\d+):([0-9A-F]+):\s*([0-9A-F ]+)/; var re_secline = /^(\d+):\s+"(.+)"/;
var re_nameline = /^([SF])(\d+)\s+(.+)/; var re_nameline = /^Source:\s+"(.+)"/;
var files = {}; var re_symline = /^(\w+)\s+(\d+):([0-9A-F]+)/;
var re_emptyline = /^\s+(\d+)([:M])/;
var curpath = step.path;
var curline = 0;
var sections = {}; var sections = {};
// map file and section indices -> names // map file and section indices -> names
var lines = lstout.split(re_crlf); var lines : string[] = 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);
// parse lines // parse lines
var lstlines : SourceLine[] = []; var lstlines : SourceLine[] = [];
var linenum = 0;
for (var line of lines) { for (var line of lines) {
var m; var m;
if (m = re_lstline.exec(line)) { if (m = re_secline.exec(line)) {
linenum = parseInt(m[2]); sections[m[1]] = m[2];
} else if (m = re_secline.exec(line)) { } 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({ lstlines.push({
line: linenum, path: curpath,
line: curline,
offset: parseInt(m[2], 16), offset: parseInt(m[2], 16),
path: step.path,
insns: m[3].replaceAll(' ','') 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 { return {
output:objout, //.slice(0), output:objout, //.slice(0x34),
listings:listings, listings:listings,
errors:errors, errors:errors,
symbolmap:symbolmap, symbolmap:symbolmap,