Adding registers panes of CPU window

This commit is contained in:
2021-09-02 00:16:22 +00:00
parent 3dc8b93f94
commit ff07e1907f
32 changed files with 2437 additions and 444 deletions
+292
View File
@@ -0,0 +1,292 @@
"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();
+82 -50
View File
@@ -8,47 +8,68 @@ globalThis.MemoryWindow = class MemoryWindow extends Toolkit.Window {
super(debug.gui, options);
// Configure instance fields
this.address = 0xFFFFFFF0;
this.address = 0x05000000;
this.debug = debug;
this.rows = [new MemoryWindow.Row(this.client)];
this.rows = [];
// Configure element
this.element.setAttribute("window", "memory");
this.element.addEventListener("wheel", e=>this.onwheel(e));
// Configure body
this.body.element.setAttribute("filter", "");
// Configure client
this.client.setLayout("grid", { columns: "repeat(17, max-content)" });
this.client.element.style.gridAutoRows = "max-content";
this.client.setOverflow("auto", "hidden");
this.client.setLayout("grid");
this.client.addResizeListener(b=>this.refresh(b.height));
// Wrapping element to hide overflowing scrollbar
this.hexWrap = this.client.add(this.newPanel({
layout : "grid",
columns: "auto"
}));
this.hexWrap.element.setAttribute("name", "wrap-hex");
// Configure hex viewer
this.hex = this.hexWrap.add(this.client.newPanel({
focusable: true,
layout : "block",
hollow : false,
overflowX: "auto",
overflowY: "hidden"
}));
this.hex.element.setAttribute("role", "grid");
this.hex.element.setAttribute("name", "hex");
this.hex.element.addEventListener("wheel", e=>this.onwheel(e));
// Configure properties
this.setProperty("sim", "");
}
///////////////////////////// Public Methods //////////////////////////////
// The window is being displayed for the first time
firstShow() {
super.firstShow();
this.seek(this.address, Math.floor(this.lines(true) / 3));
this.rows.push(this.hex.add(new MemoryWindow.Row(this.hex)));
this.application.addComponent(this);
}
///////////////////////////// Package Methods /////////////////////////////
// Update display text with localized strings
localize() {
let hex = "";
if (this.application)
hex = this.application.translate("{memory.hexEditor}");
this.hex.element.setAttribute("aria-label", hex);
}
// Update the display with current emulation data
refresh(clientHeight, lineHeight) {
clientHeight = clientHeight || this.client.getBounds().height;
lineHeight = lineHeight || this.lineHeight();
let rowCount = this.lines(false, clientHeight, lineHeight);
// Showing for the first time
if (this.address < 0)
this.seek(-this.address, Math.floor(rowCount / 3));
refresh(gridHeight, lineHeight) {
// Do nothing while closed
if (!this.isVisible())
return;
// Working variables
gridHeight = gridHeight || this.hex.getBounds().height;
lineHeight = lineHeight || this.lineHeight();
let rowCount = this.lines(false, gridHeight, lineHeight);
// Request bus data from the WebAssembly core
this.debug.core.postMessage({
@@ -61,9 +82,9 @@ globalThis.MemoryWindow = class MemoryWindow extends Toolkit.Window {
// Configure elements
for (let y = this.rows.length; y < rowCount; y++)
this.rows[y] = new MemoryWindow.Row(this.client);
this.rows[y] = this.hex.add(new MemoryWindow.Row(this.hex));
for (let y = rowCount; y < this.rows.length; y++)
this.rows[y].remove();
this.hex.remove(this.rows[y]);
if (this.rows.length > rowCount)
this.rows.splice(rowCount, this.rows.length - rowCount);
}
@@ -93,17 +114,23 @@ globalThis.MemoryWindow = class MemoryWindow extends Toolkit.Window {
///////////////////////////// Private Methods /////////////////////////////
// The window is being displayed for the first time
firstShow() {
super.firstShow();
this.center();
}
// Determine the height in pixels of one row of output
lineHeight() {
return Math.max(1, this.rows[0].address.getBounds().height);
return Math.max(10, this.rows[0].address.getBounds().height);
}
// Determine the number of rows of output
lines(fullyVisible, clientHeight, lineHeight) {
clientHeight = clientHeight || this.client.getBounds().height;
lineHeight = lineHeight || this.lineHeight();
let ret = clientHeight / lineHeight;
ret = fullyVisible ? Math.floor(ret) : Math.ceil(ret);
lines(fullyVisible, gridHeight, lineHeight) {
gridHeight = gridHeight || this.client.getBounds().height;
lineHeight = lineHeight || this.lineHeight();
let ret = gridHeight / lineHeight;
ret = fullyVisible ? Math.floor(ret) : Math.ceil(ret);
return Math.max(1, ret);
}
@@ -127,29 +154,24 @@ globalThis.MemoryWindow = class MemoryWindow extends Toolkit.Window {
// Processing by key
else switch (e.key) {
case "ArrowDown":
this.address = (this.address + 16 & 0xFFFFFFFF) >>> 0;
this.refresh();
break;
case "ArrowUp":
this.address = (this.address - 16 & 0xFFFFFFFF) >>> 0;
this.refresh();
break;
case "PageUp":
this.address = (this.address - 16 * this.lines(true) &
0xFFFFFFFF) >>> 0;
this.refresh();
break;
case "PageDown":
this.address = (this.address + 16 * this.lines(true) &
0xFFFFFFFF) >>> 0;
this.refresh();
break;
default: return super.onkeydown(e);
}
@@ -165,6 +187,12 @@ globalThis.MemoryWindow = class MemoryWindow extends Toolkit.Window {
let mag = Math.abs (e.deltaY);
if (e.deltaMode == WheelEvent.DOM_DELTA_PIXEL)
mag = Math.max(1, Math.floor(mag / lineHeight));
// Configure element
e.preventDefault();
e.stopPropagation();
// Specify the new address
this.address = (this.address + sign * mag * 16 & 0xFFFFFFFF) >>> 0;
this.refresh(null, lineHeight);
}
@@ -177,23 +205,34 @@ globalThis.MemoryWindow = class MemoryWindow extends Toolkit.Window {
};
// One row of output
MemoryWindow.Row = class Row {
MemoryWindow.Row = class Row extends Toolkit.Panel {
// Object constructor
constructor(client) {
constructor(parent) {
super(parent.application, {
layout : "grid",
columns : "repeat(17, max-content)",
hollow : false,
overflowX: "visible",
overflowY: "visible"
});
// Configure instance fields
this.bytes = new Array(16);
this.client = client;
this.bytes = new Array(16);
// Configure element
this.element.setAttribute("role", "row");
// Address label
this.address = client.add(client.newLabel({ text: "\u00a0" }));
this.address = this.add(parent.newLabel({ text: "\u00a0" }));
this.address.element.setAttribute("role", "gridcell");
this.address.element.setAttribute("name", "address");
// Byte labels
for (let x = 0; x < 16; x++) {
let lbl = this.bytes[x] =
client.add(client.newLabel({ text: "\u00a0" }));
this.add(parent.newLabel({ text: "\u00a0" }));
lbl.element.setAttribute("role", "gridcell");
lbl.element.setAttribute("name", "byte");
}
@@ -203,13 +242,6 @@ MemoryWindow.Row = class Row {
///////////////////////////// Package Methods /////////////////////////////
// Remove components from the memory window
remove() {
this.client.remove(this.address);
for (let bytel of this.bytes)
this.client.remove(bytel);
}
// Update the output labels with emulation state content
update(address, bytes, offset) {
this.address.setText(
+496
View File
@@ -0,0 +1,496 @@
"use strict";
// List item for CPU window register lists
(CPUWindow.Register = class Register extends Toolkit.Panel {
// Static initializer
static initializer() {
let buffer = new ArrayBuffer(4);
this.F32 = new Float32Array(buffer);
this.S32 = new Int32Array (buffer);
this.U32 = new Uint32Array (buffer);
}
// Object constructor
constructor(debug, parent, system, id, name) {
super(parent.application, {
layout : "grid",
columns : "auto max-content",
overflowX: "visible",
overflowY: "visible"
});
// Configure instance fields
this.debug = debug;
this.expanded = false;
this.expansion = null;
this.fields = {};
this.format = "hex";
this.id = id;
this.name = name;
this.parent = parent;
this.system = system;
this.value = 0x00000000;
// Determine whether the register has expansion fields
this.expands = !system;
switch (id) {
case CPUWindow.CHCW:
case CPUWindow.ECR:
case CPUWindow.EIPSW:
case CPUWindow.FEPSW:
case CPUWindow.PC:
case CPUWindow.PIR:
case CPUWindow.PSW:
case CPUWindow.TKCW:
this.expands = true;
}
// Configure element
this.element.setAttribute("name", "register");
this.element.setAttribute("format", this.format);
// Name/expansion "check box"
this.chkExpand = this.add(this.newCheckBox({
enabled: this.expands,
text : name
}));
this.chkExpand.element.setAttribute("name", "expand");
this.chkExpand.element.setAttribute("aria-expanded", "false");
this.chkExpand.addChangeListener(e=>
this.setExpanded(this.chkExpand.isChecked()));
// Value text box
this.txtValue = this.add(this.newTextBox({ text: "00000000" }));
this.txtValue.element.setAttribute("name", "value");
this.txtValue.addCommitListener(e=>this.onvalue());
// Expansion controls
if (!system)
this.expansionProgram();
else switch (id) {
case CPUWindow.CHCW : this.expansionCHCW(); break;
case CPUWindow.ECR : this.expansionECR (); break;
case CPUWindow.EIPSW:
case CPUWindow.FEPSW:
case CPUWindow.PSW : this.expansionPSW (); break;
case CPUWindow.PC : this.expansionPC (); break;
case CPUWindow.PIR : this.expansionPIR (); break;
case CPUWindow.TKCW : this.expansionTKCW(); break;
}
if (this.expands) {
this.chkExpand.element.setAttribute(
"aria-controls", this.expansion.id);
}
}
///////////////////////////// Static Methods //////////////////////////////
// Force a 32-bit integer to be signed
static asSigned(value) {
this.U32[0] = value >>> 0;
return this.S32[0];
}
// Interpret a 32-bit integer as a float
static intBitsToFloat(value) {
this.U32[0] = value;
value = this.F32[0];
return Number.isFinite(value) ? value : 0;
}
// Interpret a float as a 32-bit integer
static floatToIntBits(value) {
if (!Number.isFinite(value))
return 0;
this.F32[0] = value;
return this.U32[0];
}
///////////////////////////// Package Methods /////////////////////////////
// Specify whether the expansion fields are visible
setExpanded(expanded) {
this.expanded = expanded = !!expanded;
this.expansion.setVisible(expanded);
this.chkExpand.setChecked(expanded);
this.chkExpand.element.setAttribute("aria-expanded", expanded);
}
// Specify the display mode of the register value
setFormat(format) {
this.format = format;
this.setValue(this.value);
this.element.setAttribute("format", format.replace("_", ""));
}
// Update the value of the register
setValue(value, pcFrom, pcTo) {
this.value = value;
// Value text box
let text;
switch (this.format) {
case "float":
text = CPUWindow.Register.intBitsToFloat(value).toString();
if (text.indexOf(".") == -1)
text += ".0";
break;
case "hex":
text = ("0000000" +
(value >>> 0).toString(16).toUpperCase()).slice(-8);
break;
case "signed":
text = CPUWindow.Register.asSigned(value).toString();
break;
case "unsigned":
text = (value >>> 0).toString();
}
this.txtValue.setText(text);
// Expansion fields
for (let field of Object.values(this.fields)) {
switch (field.type) {
case "bit":
field.setChecked(value >> field.bit & 1);
break;
case "decimal":
field.setText(value >> field.bit & field.mask);
break;
case "hex":
let digits = Math.max(1, Math.ceil(field.width / 4));
field.setText(("0".repeat(digits) +
(value >> field.bit & field.mask)
.toString(16).toUpperCase()
).slice(-digits));
}
}
// Special fields for PC
if (pcFrom === undefined)
return;
this.txtFrom.setText(("0000000" +
(pcFrom >>> 0).toString(16).toUpperCase()).slice(-8));
this.txtTo .setText(("0000000" +
(pcTo >>> 0).toString(16).toUpperCase()).slice(-8));
}
///////////////////////////// Private Methods /////////////////////////////
// Add a field component to the expansion area
addField(type, name, bit, width, readonly) {
let field, label, panel;
// Processing by type
switch (type) {
// Bit
case "bit":
field = this.newCheckBox({
enabled: !readonly,
text : name
});
field.addChangeListener(e=>this.onbit(field));
this.expansion.add(field);
break;
// Decimal number
case "decimal":
// Field
field = this.newTextBox({
enabled: !readonly,
name : name
});
field.addCommitListener(e=>this.onnumber(field));
label = this.newLabel({
label: true,
text : name
});
label.element.htmlFor = field.id;
if (readonly)
label.element.setAttribute("aria-disabled", "true");
// Enclose in a panel
panel = this.newPanel({
layout : "flex",
alignCross: "center",
alignMain : "start",
direction : "row"
});
panel.element.setAttribute("name", name);
panel.add(label);
panel.add(field);
this.expansion.add(panel);
break;
// Hexadecimal number
case "hex":
field = this.newTextBox({
enabled: !readonly,
name : name
});
field.addCommitListener(e=>this.onnumber(field));
label = this.newLabel({
label: true,
text : name
});
label.element.htmlFor = field.id;
if (readonly)
label.element.setAttribute("aria-disabled", "true");
this.expansion.add(label);
this.expansion.add(field);
}
// Configure field
field.bit = bit;
field.mask = (1 << width) - 1;
field.type = type;
field.width = width;
this.fields[name] = field;
}
// Expansion controls for CHCW
expansionCHCW() {
// Expansion area
this.expansion = this.newPanel({
layout : "block",
overflowX: "visible",
overflowY: "visible",
visible : false
});
this.expansion.element.setAttribute("name", "expansion");
this.expansion.element.setAttribute("register", "chcw");
// Fields
this.addField("bit", "ICE", 1, 1, false);
}
// Expansion controls for ECR
expansionECR() {
// Expansion area
this.expansion = this.newPanel({
layout : "grid",
columns : "max-content auto",
overflowX: "visible",
overflowY: "visible",
visible : false
});
this.expansion.element.setAttribute("name", "expansion");
this.expansion.element.setAttribute("register", "ecr");
this.expansion.element.style.justifyContent = "start";
// Fields
this.addField("hex", "FECC", 16, 16, false);
this.addField("hex", "EICC", 0, 16, false);
}
// Expansion controls for PC
expansionPC() {
// Expansion area
this.expansion = this.newPanel({
layout : "grid",
columns : "auto max-content",
overflowX: "visible",
overflowY: "visible",
visible : false
});
this.expansion.element.setAttribute("name", "expansion");
// From text box
let lbl = this.expansion.add(this.newLabel({
localized: true,
text : "{cpu.pcFrom}"
}));
lbl.element.setAttribute("name", "indent");
this.txtFrom = this.expansion.add(this.newTextBox());
this.txtFrom.element.setAttribute("name", "value");
// To text box
lbl = this.expansion.add(this.newLabel({
localized: true,
text : "{cpu.pcTo}"
}));
lbl.element.setAttribute("name", "indent");
this.txtTo = this.expansion.add(this.newTextBox());
this.txtTo.element.setAttribute("name", "value");
}
// Expansion controls for PIR
expansionPIR() {
// Expansion area
this.expansion = this.newPanel({
layout : "grid",
columns : "max-content auto",
overflowX: "visible",
overflowY: "visible",
visible : false
});
this.expansion.element.setAttribute("name", "expansion");
this.expansion.element.setAttribute("register", "pir");
// Fields
this.addField("hex", "PT", 0, 16, true);
}
// Expansion controls for program registers
expansionProgram() {
// Expansion area
this.expansion = this.newPanel({
layout : "grid",
columns : "auto",
overflowX: "visible",
overflowY: "visible",
visible : false
});
this.expansion.element.setAttribute("role", "radiogroup");
this.expansion.element.setAttribute("name", "expansion");
this.expansion.element.setAttribute("register", "program");
this.expansion.element.style.justifyContent = "start";
// Format selections
let group = new Toolkit.ButtonGroup();
for (let opt of [ "hex", "signed", "unsigned", "float_" ]) {
let fmt = group.add(this.expansion.add(this.newRadioButton({
checked: opt == "hex",
text : "{cpu." + opt + "}",
})));
fmt.addChangeListener(
(opt=>e=>this.setFormat(opt))
(opt.replace("_", ""))
);
}
}
// Expansion controls for EIPSW, FEPSW and PSW
expansionPSW() {
// Expansion area
this.expansion = this.newPanel({
layout : "grid",
columns : "max-content auto",
overflowX: "visible",
overflowY: "visible",
visible : false
});
this.expansion.element.setAttribute("name", "expansion");
this.expansion.element.setAttribute("register", "psw");
this.expansion.element.style.justifyContent = "start";
// Fields
this.addField("bit" , "CY" , 3, 1, false);
this.addField("bit" , "FRO", 9, 1, false);
this.addField("bit" , "OV" , 2, 1, false);
this.addField("bit" , "FIV", 8, 1, false);
this.addField("bit" , "S" , 1, 1, false);
this.addField("bit" , "FZD", 7, 1, false);
this.addField("bit" , "Z" , 0, 1, false);
this.addField("bit" , "FOV", 6, 1, false);
this.addField("bit" , "NP" , 15, 1, false);
this.addField("bit" , "FUD", 5, 1, false);
this.addField("bit" , "EP" , 14, 1, false);
this.addField("bit" , "FPR", 4, 1, false);
this.addField("bit" , "ID" , 12, 1, false);
this.addField("decimal", "I" , 16, 4, false);
this.addField("bit" , "AE" , 13, 1, false);
}
// Expansion controls for TKCW
expansionTKCW() {
// Expansion area
this.expansion = this.newPanel({
layout : "grid",
columns : "max-content auto",
overflowX: "visible",
overflowY: "visible",
visible : false
});
this.expansion.element.setAttribute("name", "expansion");
this.expansion.element.setAttribute("register", "tkcw");
this.expansion.element.style.justifyContent = "start";
// Fields
this.addField("bit" , "FIT", 7, 1, true);
this.addField("bit" , "FUT", 4, 1, true);
this.addField("bit" , "FZT", 6, 1, true);
this.addField("bit" , "FPT", 3, 1, true);
this.addField("bit" , "FVT", 5, 1, true);
this.addField("bit" , "OTM", 8, 1, true);
this.addField("bit" , "RDI", 2, 1, true);
this.addField("decimal", "RD" , 0, 2, true);
}
// Bit check box change event handler
onbit(field) {
let mask = 1 << field.bit;
let value = this.value;
if (field.isChecked())
value = (value | mask & 0xFFFFFFFF) >>> 0;
else value = (value & ~mask & 0xFFFFFFFF) >>> 0;
this.setRegister(value);
}
// Number text box commit event handler
onnumber(field) {
let value = parseInt(field.getText(),
field.type == "decimal" ? 10 : 16);
if (value == NaN)
value = this.value;
this.setRegister((
this.value & ~(field.mask << field.bit) |
(value & field.mask) << field.bit
) >>> 0);
}
// Value text box commit event handler
onvalue() {
// Process the entered value
let value = this.txtValue.getText();
switch (this.format) {
case "float":
value = parseFloat(value);
if (Number.isFinite(value))
value = CPUWindow.Register.floatToIntBits(value);
break;
case "hex":
value = parseInt(value, 16);
break;
case "signed":
case "unsigned":
value = parseInt(value);
}
// Update the value
if (!Number.isFinite(value))
this.setValue(this.value);
else this.setRegister((value & 0xFFFFFFFF) >>> 0);
}
// Update the value of the register
setRegister(value) {
this.debug.core.postMessage({
command: "SetRegister",
debug : "CPU",
id : this.id,
sim : this.debug.sim,
type : this.system ? this.id == -1 ? "pc" : "system" : "program",
value : value
});
}
}).initializer();