2021-09-02 00:16:22 +00:00
|
|
|
"use strict";
|
|
|
|
|
|
|
|
// CPU register and disassembler display
|
|
|
|
(globalThis.CPUWindow = class CPUWindow extends Toolkit.Window {
|
|
|
|
|
|
|
|
// Static initializer
|
|
|
|
static initializer() {
|
|
|
|
|
|
|
|
// System register IDs
|
|
|
|
this.ADTRE = 25;
|
|
|
|
this.CHCW = 24;
|
|
|
|
this.ECR = 4;
|
|
|
|
this.EIPC = 0;
|
|
|
|
this.EIPSW = 1;
|
|
|
|
this.FEPC = 2;
|
|
|
|
this.FEPSW = 3;
|
|
|
|
this.PC = -1;
|
|
|
|
this.PIR = 6;
|
|
|
|
this.PSW = 5;
|
|
|
|
this.TKCW = 7;
|
|
|
|
|
|
|
|
// Program register names
|
|
|
|
this.PROGRAM = {
|
|
|
|
[ 2]: "hp",
|
|
|
|
[ 3]: "sp",
|
|
|
|
[ 4]: "gp",
|
|
|
|
[ 5]: "tp",
|
|
|
|
[31]: "lp"
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Object constructor
|
|
|
|
constructor(debug, options) {
|
|
|
|
super(debug.gui, options);
|
|
|
|
|
|
|
|
// Configure instance fields
|
2021-09-06 00:09:15 +00:00
|
|
|
this.address = 0xFFFFFFF0;
|
|
|
|
this.columns = [ 0, 0, 0, 0 ];
|
|
|
|
this.debug = debug;
|
|
|
|
this.pendingDasm = { mode: null };
|
|
|
|
this.pendingRegs = { mode: null };
|
|
|
|
this.rows = [];
|
2021-09-02 00:16:22 +00:00
|
|
|
|
|
|
|
// Configure properties
|
|
|
|
this.setProperty("sim", "");
|
|
|
|
|
|
|
|
// Configure elements
|
|
|
|
this.initDisassembler();
|
|
|
|
this.initSystemRegisters();
|
|
|
|
this.initProgramRegisters();
|
|
|
|
this.initWindow();
|
|
|
|
|
|
|
|
// Disassembler on the left
|
|
|
|
this.mainWrap.add(this.dasmWrap);
|
|
|
|
|
|
|
|
// Registers on the right
|
|
|
|
this.regs = this.newPanel({
|
|
|
|
layout: "grid",
|
|
|
|
rows : "max-content max-content auto"
|
|
|
|
});
|
|
|
|
this.regs.element.setAttribute("name", "wrap-registers");
|
|
|
|
|
|
|
|
// Splitter between disassembler and registers
|
|
|
|
this.mainSplit = this.newSplitter({
|
|
|
|
component : this.regs,
|
|
|
|
orientation: "vertical",
|
|
|
|
edge : "right",
|
|
|
|
name : "{cpu.mainSplit}"
|
|
|
|
});
|
|
|
|
this.mainSplit.element.setAttribute("name", "split-main");
|
|
|
|
this.mainSplit.element.style.width = "3px";
|
|
|
|
this.mainSplit.element.style.minWidth = "3px";
|
|
|
|
this.mainSplit.element.style.cursor = "ew-resize";
|
|
|
|
this.mainWrap.add(this.mainSplit);
|
|
|
|
|
|
|
|
// Registers on the right
|
|
|
|
this.mainWrap.add(this.regs);
|
|
|
|
|
|
|
|
// System registers on top
|
|
|
|
this.regs.add(this.sysWrap);
|
|
|
|
|
|
|
|
// Splitter between system registers and program registers
|
|
|
|
this.regsSplit = this.regs.add(this.newSplitter({
|
|
|
|
component : this.sysWrap,
|
|
|
|
orientation: "horizontal",
|
|
|
|
edge : "top",
|
|
|
|
name : "{cpu.regsSplit}"
|
|
|
|
}));
|
|
|
|
this.regsSplit.element.style.height = "3px";
|
|
|
|
this.regsSplit.element.style.minHeight = "3px";
|
|
|
|
this.regsSplit.element.style.cursor = "ns-resize";
|
|
|
|
|
|
|
|
// Program registers on the bottom
|
|
|
|
this.regs.add(this.proWrap);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize disassembler pane
|
|
|
|
initDisassembler() {
|
|
|
|
|
|
|
|
// Wrapping element to hide overflowing scrollbar
|
|
|
|
this.dasmWrap = this.newPanel({
|
|
|
|
layout : "grid",
|
|
|
|
overflowX: "hidden",
|
|
|
|
overflowY: "hidden"
|
|
|
|
});
|
|
|
|
this.dasmWrap.element.setAttribute("name", "wrap-disassembler");
|
|
|
|
|
|
|
|
// Main element
|
|
|
|
this.dasm = this.dasmWrap.add(this.newPanel({
|
|
|
|
focusable: true,
|
|
|
|
name : "{cpu.disassembler}",
|
|
|
|
overflowX: "auto",
|
|
|
|
overflowY: "hidden"
|
|
|
|
}));
|
|
|
|
this.dasm.element.setAttribute("name", "disassembler");
|
2021-09-06 00:09:15 +00:00
|
|
|
this.dasm.addResizeListener(b=>this.onresize(b));
|
|
|
|
this.dasm.element.addEventListener("keydown", e=>this.onkeydasm(e));
|
|
|
|
this.dasm.element.addEventListener("wheel" , e=>this.onwheel (e));
|
|
|
|
|
|
|
|
this.rows.push(this.dasm.add(new CPUWindow.Row(this.dasm)));
|
2021-09-02 00:16:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize program registers pane
|
|
|
|
initProgramRegisters() {
|
|
|
|
|
|
|
|
// Wrapping element to hide overflowing scrollbar
|
|
|
|
this.proWrap = this.newPanel({
|
|
|
|
layout : "grid",
|
|
|
|
overflow: "hidden"
|
|
|
|
});
|
|
|
|
this.proWrap.element.setAttribute("name", "wrap-program-registers");
|
|
|
|
|
|
|
|
// Main element
|
|
|
|
this.proRegs = this.proWrap.add(this.newPanel({
|
|
|
|
overflowX: "auto",
|
|
|
|
overflowY: "scroll"
|
|
|
|
}));
|
|
|
|
this.proRegs.element.setAttribute("name", "program-registers");
|
|
|
|
|
|
|
|
// List of registers
|
|
|
|
this.proRegs.registers = {};
|
|
|
|
for (let x = 0; x <= 31; x++)
|
|
|
|
this.addRegister(false, x, CPUWindow.PROGRAM[x] || "r" + x);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize system registers pane
|
|
|
|
initSystemRegisters() {
|
|
|
|
|
|
|
|
// Wrapping element to hide overflowing scrollbar
|
|
|
|
this.sysWrap = this.newPanel({
|
|
|
|
layout : "grid",
|
|
|
|
overflow: "hidden"
|
|
|
|
});
|
|
|
|
this.sysWrap.element.setAttribute("name", "wrap-system-registers");
|
|
|
|
|
|
|
|
// Main element
|
|
|
|
this.sysRegs = this.sysWrap.add(this.newPanel({
|
|
|
|
overflowX: "auto",
|
|
|
|
overflowY: "scroll"
|
|
|
|
}));
|
|
|
|
this.sysRegs.element.setAttribute("name", "system-registers");
|
|
|
|
|
|
|
|
// List of registers
|
|
|
|
this.sysRegs.registers = {};
|
|
|
|
this.addRegister(true, CPUWindow.PC , "PC" );
|
|
|
|
this.addRegister(true, CPUWindow.PSW , "PSW" );
|
|
|
|
this.addRegister(true, CPUWindow.ADTRE, "ADTRE");
|
|
|
|
this.addRegister(true, CPUWindow.CHCW , "CHCW" );
|
|
|
|
this.addRegister(true, CPUWindow.ECR , "ECR" );
|
|
|
|
this.addRegister(true, CPUWindow.EIPC , "EIPC" );
|
|
|
|
this.addRegister(true, CPUWindow.EIPSW, "EIPSW");
|
|
|
|
this.addRegister(true, CPUWindow.FEPC , "FEPC" );
|
|
|
|
this.addRegister(true, CPUWindow.FEPSW, "FEPSW");
|
|
|
|
this.addRegister(true, CPUWindow.PIR , "PIR" );
|
|
|
|
this.addRegister(true, CPUWindow.TKCW , "TKCW" );
|
|
|
|
this.addRegister(true, 29 , "29" );
|
|
|
|
this.addRegister(true, 30 , "30" );
|
|
|
|
this.addRegister(true, 31 , "31" );
|
|
|
|
this.sysRegs.registers[CPUWindow.PSW].setExpanded(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize window and client
|
|
|
|
initWindow() {
|
|
|
|
|
|
|
|
// Configure element
|
|
|
|
this.element.setAttribute("window", "cpu");
|
|
|
|
|
|
|
|
// Configure body
|
|
|
|
this.body.element.setAttribute("filter", "");
|
|
|
|
|
|
|
|
// Configure client
|
|
|
|
this.client.setLayout("grid", {
|
|
|
|
columns: "auto"
|
|
|
|
});
|
|
|
|
|
|
|
|
// Configure main wrapper
|
|
|
|
this.mainWrap = this.client.add(this.newPanel({
|
|
|
|
layout : "grid",
|
|
|
|
columns: "auto max-content max-content"
|
|
|
|
}));
|
|
|
|
this.mainWrap.element.setAttribute("name", "wrap-main");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////// Public Methods //////////////////////////////
|
|
|
|
|
2021-09-06 00:09:15 +00:00
|
|
|
// Update the display with current emulation data
|
2021-09-19 19:36:30 +00:00
|
|
|
refresh(seekToPC, dasm, regs) {
|
|
|
|
if (dasm || dasm === undefined)
|
|
|
|
this.refreshDasm(this.address, 0, !!seekToPC);
|
|
|
|
if (regs || regs === undefined)
|
|
|
|
this.refreshRegs();
|
2021-09-02 00:16:22 +00:00
|
|
|
}
|
|
|
|
|
2021-09-06 00:09:15 +00:00
|
|
|
// Specify whether the component is visible
|
|
|
|
setVisible(visible, focus) {
|
|
|
|
let prev = this.visible
|
|
|
|
visible = !!visible;
|
|
|
|
super.setVisible(visible, focus);
|
|
|
|
if (visible && !prev)
|
|
|
|
this.refresh();
|
2021-09-02 00:16:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////// Message Methods /////////////////////////////
|
|
|
|
|
|
|
|
// Message received
|
|
|
|
message(msg) {
|
|
|
|
switch (msg.command) {
|
|
|
|
case "GetRegisters": this.getRegisters(msg); break;
|
2021-09-06 00:09:15 +00:00
|
|
|
case "ReadBuffer" : this.readBuffer (msg); break;
|
2021-09-02 00:16:22 +00:00
|
|
|
case "SetRegister" : this.setRegister (msg); break;
|
2021-09-19 19:36:30 +00:00
|
|
|
case "RunNext": case "SingleStep":
|
|
|
|
this.refresh(true); break;
|
2021-09-02 00:16:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Retrieved all register values
|
|
|
|
getRegisters(msg) {
|
2021-09-10 16:24:02 +00:00
|
|
|
|
|
|
|
// Update controls
|
2021-09-02 00:16:22 +00:00
|
|
|
this.sysRegs.registers[CPUWindow.PC ]
|
|
|
|
.setValue(msg.pc, msg.pcFrom, msg.pcTo);
|
|
|
|
this.sysRegs.registers[CPUWindow.PSW ].setValue(msg.psw );
|
|
|
|
this.sysRegs.registers[CPUWindow.ADTRE].setValue(msg.adtre);
|
|
|
|
this.sysRegs.registers[CPUWindow.CHCW ].setValue(msg.chcw );
|
|
|
|
this.sysRegs.registers[CPUWindow.ECR ].setValue(msg.ecr );
|
|
|
|
this.sysRegs.registers[CPUWindow.EIPC ].setValue(msg.eipc );
|
|
|
|
this.sysRegs.registers[CPUWindow.EIPSW].setValue(msg.eipsw);
|
|
|
|
this.sysRegs.registers[CPUWindow.FEPC ].setValue(msg.fepc );
|
|
|
|
this.sysRegs.registers[CPUWindow.FEPSW].setValue(msg.fepsw);
|
|
|
|
this.sysRegs.registers[CPUWindow.PIR ].setValue(msg.pir );
|
|
|
|
this.sysRegs.registers[CPUWindow.TKCW ].setValue(msg.tkcw );
|
|
|
|
this.sysRegs.registers[29 ].setValue(msg.sr29 );
|
|
|
|
this.sysRegs.registers[30 ].setValue(msg.sr30 );
|
|
|
|
this.sysRegs.registers[31 ].setValue(msg.sr31 );
|
|
|
|
for (let x = 0; x <= 31; x++)
|
|
|
|
this.proRegs.registers[x].setValue(msg.program[x]);
|
2021-09-06 00:09:15 +00:00
|
|
|
|
|
|
|
// Check for pending display updates
|
|
|
|
let mode = this.pendingDasm.mode;
|
|
|
|
this.pendingRegs.mode = null;
|
|
|
|
switch (mode) {
|
|
|
|
case "first":
|
|
|
|
case null :
|
|
|
|
return;
|
|
|
|
case "refresh":
|
|
|
|
this.refreshRegs();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Retrieved data for disassembly
|
|
|
|
readBuffer(msg) {
|
|
|
|
let lines = Math.min(msg.lines, this.rows.length);
|
|
|
|
|
|
|
|
// Disassemble the visible instructions
|
|
|
|
let dasm = Disassembler.disassemble(
|
|
|
|
new Uint8Array(msg.buffer), 0, msg.address, msg.target,
|
|
|
|
msg.pc, msg.line, lines);
|
|
|
|
|
2021-09-19 19:36:30 +00:00
|
|
|
// Ensure PC is visible if requested
|
|
|
|
let reseeking = false;
|
|
|
|
if (msg.seekToPC) {
|
|
|
|
let visible = this.lines(true);
|
|
|
|
let count = Math.min(msg.lines, visible);
|
|
|
|
let x;
|
2021-09-06 00:09:15 +00:00
|
|
|
|
2021-09-19 19:36:30 +00:00
|
|
|
// Ensure PC is visible in the disassembly
|
|
|
|
for (x = 0; x < count; x++)
|
|
|
|
if (dasm[x].address == msg.pc)
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Seek to display PC in the view
|
|
|
|
if (x == count) {
|
|
|
|
reseeking = true;
|
|
|
|
this.seek(msg.pc, Math.floor(visible / 3));
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Not seeking to PC
|
|
|
|
if (!reseeking) {
|
|
|
|
|
|
|
|
// Configure instance fields
|
|
|
|
this.address = dasm[0].address;
|
|
|
|
|
|
|
|
// Configure elements
|
|
|
|
for (let x = 0; x < lines; x++)
|
|
|
|
this.rows[x].update(dasm[x], this.columns, msg.pc);
|
|
|
|
for (let x = 0; x < lines; x++)
|
|
|
|
this.rows[x].setWidths(this.columns);
|
|
|
|
}
|
2021-09-06 00:09:15 +00:00
|
|
|
|
|
|
|
// Check for pending display updates
|
|
|
|
let address = this.pendingDasm.address === null ?
|
|
|
|
this.address : this.pendingDasm.address;
|
|
|
|
let line = this.pendingDasm.line === null ?
|
|
|
|
0 : this.pendingDasm.line ;
|
|
|
|
let mode = this.pendingDasm.mode;
|
|
|
|
this.pendingDasm.mode = null;
|
|
|
|
switch (mode) {
|
|
|
|
case "first":
|
|
|
|
case null :
|
|
|
|
return;
|
|
|
|
case "refresh":
|
|
|
|
case "scroll" :
|
|
|
|
case "seek" :
|
|
|
|
this.refreshDasm(address, line);
|
|
|
|
}
|
2021-09-10 16:24:02 +00:00
|
|
|
|
2021-09-02 00:16:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Modified a register value
|
|
|
|
setRegister(msg) {
|
|
|
|
(msg.type == "program" ? this.proRegs : this.sysRegs)
|
|
|
|
.registers[msg.id].setValue(msg.value);
|
2021-09-19 19:36:30 +00:00
|
|
|
this.refreshDasm(this.address, 0);
|
2021-09-02 00:16:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////// Private Methods /////////////////////////////
|
|
|
|
|
|
|
|
// Insert a register control to a register list
|
|
|
|
addRegister(system, id, name) {
|
|
|
|
let list = system ? this.sysRegs : this.proRegs;
|
|
|
|
let reg = new CPUWindow.Register(this.debug, list, system, id, name);
|
|
|
|
list.registers[id] = reg;
|
|
|
|
list.add(reg);
|
|
|
|
if (reg.expands)
|
|
|
|
list.add(reg.expansion);
|
|
|
|
}
|
|
|
|
|
2021-09-06 00:09:15 +00:00
|
|
|
// The window is being displayed for the first time
|
|
|
|
firstShow() {
|
|
|
|
super.firstShow();
|
|
|
|
this.center();
|
|
|
|
this.mainSplit.measure();
|
|
|
|
this.regsSplit.measure();
|
|
|
|
this.seek(this.address, Math.floor(this.lines(true) / 3));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Determine the height in pixels of one row of output
|
|
|
|
lineHeight() {
|
|
|
|
return Math.max(10, this.rows[0].address.getBounds().height);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Determine the number of rows of output
|
|
|
|
lines(fullyVisible) {
|
|
|
|
let gridHeight = this.dasm.getBounds().height;
|
|
|
|
let lineHeight = this.lineHeight();
|
|
|
|
let ret = gridHeight / lineHeight;
|
|
|
|
ret = fullyVisible ? Math.floor(ret) : Math.ceil(ret);
|
|
|
|
return Math.max(1, ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Key down event handler
|
|
|
|
onkeydasm(e) {
|
|
|
|
|
|
|
|
// Control is pressed
|
|
|
|
if (e.ctrlKey) switch (e.key) {
|
2021-09-10 16:24:02 +00:00
|
|
|
|
|
|
|
// Auto-fit
|
|
|
|
case "f": case "F":
|
|
|
|
for (let x = 0; x < this.columns.length; x++)
|
|
|
|
this.columns[x] = 0;
|
|
|
|
for (let row of this.rows)
|
|
|
|
row.setWidths(this.columns);
|
|
|
|
for (let row of this.rows)
|
|
|
|
row.measure(this.columns);
|
|
|
|
for (let row of this.rows)
|
|
|
|
row.setWidths(this.columns);
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Goto
|
2021-09-06 00:09:15 +00:00
|
|
|
case "g": case "G":
|
|
|
|
let addr = prompt(this.application.translate("{app.goto_}"));
|
|
|
|
if (addr === null)
|
|
|
|
break;
|
|
|
|
this.seek(
|
|
|
|
(parseInt(addr, 16) & 0xFFFFFFFE) >>> 0,
|
|
|
|
Math.floor(this.lines(true) / 3)
|
|
|
|
);
|
|
|
|
break;
|
2021-09-10 16:24:02 +00:00
|
|
|
|
2021-09-06 00:09:15 +00:00
|
|
|
default: return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Processing by key
|
|
|
|
else switch (e.key) {
|
2021-09-19 19:36:30 +00:00
|
|
|
case "ArrowDown": this.scroll( 1); break;
|
|
|
|
case "ArrowUp" : this.scroll(-1); break;
|
2021-09-06 00:09:15 +00:00
|
|
|
case "PageDown" : this.scroll( this.lines(true)); break;
|
|
|
|
case "PageUp" : this.scroll(-this.lines(true)); break;
|
2021-09-19 19:36:30 +00:00
|
|
|
default: return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Configure event
|
|
|
|
e.preventDefault();
|
|
|
|
e.stopPropagation();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Key down event handler
|
|
|
|
onkeydown(e) {
|
|
|
|
|
|
|
|
// Processing by key
|
|
|
|
switch (e.key) {
|
|
|
|
|
|
|
|
// Run next
|
|
|
|
case "F10":
|
|
|
|
this.debug.core.postMessage({
|
|
|
|
command : "RunNext",
|
|
|
|
dbgwnd : "CPU",
|
|
|
|
sim : this.debug.sim,
|
|
|
|
seekToPC: true
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Single step
|
|
|
|
case "F11":
|
|
|
|
this.debug.core.postMessage({
|
|
|
|
command : "SingleStep",
|
|
|
|
dbgwnd : "CPU",
|
|
|
|
sim : this.debug.sim,
|
|
|
|
seekToPC: true
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
|
|
|
|
default: return super.onkeydown(e);
|
2021-09-06 00:09:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Configure event
|
|
|
|
e.preventDefault();
|
|
|
|
e.stopPropagation();
|
|
|
|
}
|
|
|
|
|
2021-09-02 00:16:22 +00:00
|
|
|
// Resize event handler
|
|
|
|
onresize(bounds) {
|
2021-09-06 00:09:15 +00:00
|
|
|
|
|
|
|
// Update Splitters
|
2021-09-02 00:16:22 +00:00
|
|
|
this.mainSplit.measure();
|
|
|
|
this.regsSplit.measure();
|
2021-09-06 00:09:15 +00:00
|
|
|
|
|
|
|
// Configure disassembler elements
|
|
|
|
let lines = this.lines(false);
|
|
|
|
for (let y = this.rows.length; y < lines; y++)
|
|
|
|
this.rows[y] = this.dasm.add(new CPUWindow.Row(this.dasm));
|
|
|
|
for (let y = lines; y < this.rows.length; y++)
|
|
|
|
this.dasm.remove(this.rows[y]);
|
|
|
|
if (this.rows.length > lines)
|
|
|
|
this.rows.splice(lines, this.rows.length - lines);
|
|
|
|
this.refreshDasm();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Mouse wheel event handler
|
|
|
|
onwheel(e) {
|
|
|
|
let sign = Math.sign(e.deltaY);
|
|
|
|
let mag = Math.abs (e.deltaY);
|
|
|
|
if (e.deltaMode == WheelEvent.DOM_DELTA_PIXEL)
|
|
|
|
mag = Math.max(1, Math.floor(mag / this.lineHeight()));
|
|
|
|
|
|
|
|
// Configure element
|
|
|
|
e.preventDefault();
|
|
|
|
e.stopPropagation();
|
|
|
|
|
|
|
|
// Configure display
|
|
|
|
this.scroll(sign * mag);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update the disassembler with current emulation data
|
2021-09-19 19:36:30 +00:00
|
|
|
refreshDasm(address, line, seekToPC) {
|
2021-09-06 00:09:15 +00:00
|
|
|
|
|
|
|
// Do nothing while closed or already waiting to refresh
|
|
|
|
if (!this.isVisible() || this.pendingDasm.mode != null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Working variables
|
|
|
|
address = address !== undefined ?
|
|
|
|
(address & 0xFFFFFFFE) >>> 0 : this.address;
|
|
|
|
line = line || 0;
|
|
|
|
let lines = this.lines(false);
|
|
|
|
let start = -10 - Math.max(0, line);
|
|
|
|
let end = lines - Math.min(0, line);
|
|
|
|
|
|
|
|
// Configure pending state
|
|
|
|
this.pendingDasm.mode = "first";
|
|
|
|
this.pendingDasm.address = null;
|
|
|
|
this.pendingDasm.line = null;
|
|
|
|
|
|
|
|
// Request bus data from the WebAssembly core
|
|
|
|
this.debug.core.postMessage({
|
2021-09-19 19:36:30 +00:00
|
|
|
command : "ReadBuffer",
|
|
|
|
sim : this.debug.sim,
|
|
|
|
dbgwnd : "CPU",
|
|
|
|
address : (address + start * 4 & 0xFFFFFFFE) >>> 0,
|
|
|
|
line : line,
|
|
|
|
lines : lines,
|
|
|
|
target : address,
|
|
|
|
seekToPC: seekToPC,
|
|
|
|
size : (end - start + 1) * 4
|
2021-09-06 00:09:15 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update the register list with current emulation data
|
|
|
|
refreshRegs() {
|
|
|
|
|
|
|
|
// Schedule another refresh
|
|
|
|
if (this.pendingRegs.mode != null)
|
|
|
|
this.pendingRegs.mode = "refresh";
|
|
|
|
|
|
|
|
// Do nothing while closed or already waiting to refresh
|
|
|
|
if (!this.isVisible() || this.pendingRegs.mode != null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Configure pending state
|
|
|
|
this.pendingRegs.mode = "first";
|
|
|
|
this.pendingRegs.address = null;
|
|
|
|
this.pendingRegs.line = null;
|
|
|
|
|
|
|
|
// Request bus data from the WebAssembly core
|
|
|
|
this.debug.core.postMessage({
|
|
|
|
command: "GetRegisters",
|
2021-09-19 19:36:30 +00:00
|
|
|
dbgwnd : "CPU",
|
2021-09-06 00:09:15 +00:00
|
|
|
sim : this.debug.sim
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// Move to a new address relative to the current address
|
|
|
|
scroll(lines) {
|
|
|
|
switch (this.pendingDasm.mode) {
|
|
|
|
case "first" :
|
|
|
|
case "refresh":
|
|
|
|
this.pendingDasm.mode = "scroll";
|
|
|
|
this.pendingDasm.line = -lines;
|
|
|
|
break;
|
|
|
|
case "seek" :
|
|
|
|
case "scroll":
|
|
|
|
this.pendingDasm.mode = "scroll";
|
|
|
|
this.pendingDasm.line -= lines;
|
|
|
|
break;
|
|
|
|
case null:
|
|
|
|
this.refreshDasm(this.address, -lines);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Move to a new address positioned at a particular row of output
|
|
|
|
seek(address, line) {
|
|
|
|
switch (this.pendingDasm.mode) {
|
|
|
|
case "first" :
|
|
|
|
case "refresh":
|
|
|
|
this.pendingDasm.mode = "seek";
|
|
|
|
this.pendingDasm.address = address;
|
|
|
|
this.pendingDasm.line = line;
|
|
|
|
break;
|
|
|
|
case "seek" :
|
|
|
|
case "scroll":
|
|
|
|
this.pendingDasm.mode = "seek";
|
|
|
|
this.pendingDasm.address = address;
|
|
|
|
this.pendingDasm.line += line;
|
|
|
|
break;
|
|
|
|
case null:
|
|
|
|
this.refreshDasm(address, line);
|
|
|
|
}
|
2021-09-02 00:16:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}).initializer();
|
2021-09-06 00:09:15 +00:00
|
|
|
|
|
|
|
// One row of disassembly
|
|
|
|
CPUWindow.Row = class Row extends Toolkit.Panel {
|
|
|
|
|
|
|
|
// Object constructor
|
|
|
|
constructor(parent) {
|
|
|
|
super(parent.application, {
|
|
|
|
layout : "grid",
|
|
|
|
columns : "repeat(4, max-content)",
|
|
|
|
hollow : false,
|
|
|
|
overflowX: "visible",
|
|
|
|
overflowY: "visible"
|
|
|
|
});
|
|
|
|
|
|
|
|
// Configure element
|
|
|
|
this.element.style.justifyContent = "start";
|
|
|
|
this.element.setAttribute("name", "row");
|
|
|
|
|
|
|
|
// Address column
|
|
|
|
this.address = this.add(parent.newLabel({ text: "\u00a0" }));
|
|
|
|
this.address.element.setAttribute("name", "address");
|
|
|
|
|
|
|
|
// Bytes column
|
|
|
|
this.bytes = this.add(parent.newLabel({ text: "\u00a0" }));
|
|
|
|
this.bytes.element.setAttribute("name", "bytes");
|
|
|
|
|
|
|
|
// Mnemonic column
|
|
|
|
this.mnemonic = this.add(parent.newLabel({ text: "\u00a0" }));
|
|
|
|
this.mnemonic.element.setAttribute("name", "mnemonic");
|
|
|
|
|
|
|
|
// Operands column
|
|
|
|
this.operands = this.add(parent.newLabel({ text: "\u00a0" }));
|
|
|
|
this.operands.element.setAttribute("name", "operands");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////// Package Methods /////////////////////////////
|
|
|
|
|
2021-09-10 16:24:02 +00:00
|
|
|
// Measure the content widths of each column of output
|
|
|
|
measure(columns) {
|
|
|
|
columns[0] = Math.max(columns[0], this.address .getBounds().width);
|
|
|
|
columns[1] = Math.max(columns[1], this.bytes .getBounds().width);
|
|
|
|
columns[2] = Math.max(columns[2], this.mnemonic.getBounds().width);
|
|
|
|
columns[3] = Math.max(columns[3], this.operands.getBounds().width);
|
|
|
|
}
|
|
|
|
|
2021-09-06 00:09:15 +00:00
|
|
|
// Specify the column widths
|
|
|
|
setWidths(columns) {
|
|
|
|
this.address .element.style.minWidth = columns[0] + "px";
|
|
|
|
this.bytes .element.style.minWidth = columns[1] + "px";
|
|
|
|
this.mnemonic.element.style.minWidth = columns[2] + "px";
|
|
|
|
this.operands.element.style.minWidth = columns[3] + "px";
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update the output labels with emulation state content
|
2021-09-19 19:36:30 +00:00
|
|
|
update(line, columns, pc) {
|
|
|
|
if (pc == line.address)
|
|
|
|
this.element.setAttribute("pc", "");
|
|
|
|
else this.element.removeAttribute("pc");
|
|
|
|
|
2021-09-06 00:09:15 +00:00
|
|
|
this.address.setText(
|
|
|
|
("0000000" + line.address.toString(16).toUpperCase()).slice(-8));
|
|
|
|
|
|
|
|
let bytes = new Array(line.bytes.length);
|
|
|
|
for (let x = 0; x < bytes.length; x++)
|
|
|
|
bytes[x] =
|
2021-09-10 16:24:02 +00:00
|
|
|
("0" + line.bytes[x].toString(16).toUpperCase()).slice(-2);
|
2021-09-06 00:09:15 +00:00
|
|
|
this.bytes.setText(bytes.join(" "));
|
|
|
|
|
|
|
|
this.mnemonic.setText(line.mnemonic);
|
|
|
|
this.operands.setText(line.operands);
|
|
|
|
|
2021-09-10 16:24:02 +00:00
|
|
|
this.measure(columns);
|
2021-09-06 00:09:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
};
|