pvbemu/app/windows/CPUWindow.js

293 lines
9.1 KiB
JavaScript

"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
this.address = 0xFFFFFFF0;
this.debug = debug;
// Configure properties
this.setProperty("sim", "");
// Configure elements
this.initDisassembler();
this.initSystemRegisters();
this.initProgramRegisters();
this.initWindow();
// Layout components
// 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");
}
// 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");
this.proWrap.element.style.flexGrow = "1";
// 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"
});
this.client.addResizeListener(b=>this.onresize(b));
// 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 //////////////////////////////
// The window is being displayed for the first time
firstShow() {
super.firstShow();
this.center();
this.mainSplit.measure();
this.regsSplit.measure();
this.refresh();
}
///////////////////////////// Package Methods /////////////////////////////
// Update the display with current emulation data
refresh(clientHeight, lineHeight, registers) {
if (!registers) {
this.debug.core.postMessage({
command: "GetRegisters",
debug : "CPU",
sim : this.debug.sim
});
}
}
///////////////////////////// Message Methods /////////////////////////////
// Message received
message(msg) {
switch (msg.command) {
case "GetRegisters": this.getRegisters(msg); break;
case "SetRegister" : this.setRegister (msg); break;
}
}
// Retrieved all register values
getRegisters(msg) {
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]);
}
// Modified a register value
setRegister(msg) {
(msg.type == "program" ? this.proRegs : this.sysRegs)
.registers[msg.id].setValue(msg.value);
}
///////////////////////////// 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);
}
// Resize event handler
onresize(bounds) {
if (!this.isVisible())
return;
//this.regs.setHeight(bounds.height);
this.mainSplit.measure();
this.regsSplit.measure();
}
}).initializer();