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