From 76c95b0523e8ae409567e00d44986bccc2d1c798 Mon Sep 17 00:00:00 2001 From: Guy Perfect Date: Sat, 8 Aug 2020 18:40:22 -0500 Subject: [PATCH] Implementing disassembler back-end, yet more adjustments to CPU window --- license.txt | 2 +- src/core/cpu.c | 1 - src/core/include/vue.h | 3 +- src/desktop/app/App.java | 2 +- src/desktop/app/CPU.java | 257 ------------ src/desktop/app/CPUWindow.java | 179 +++++++++ .../app/{Console.java => ConsoleWindow.java} | 4 +- src/desktop/app/Disassembler.java | 379 ++++++++++++++++++ src/desktop/app/MainWindow.java | 21 +- .../app/{Memory.java => MemoryWindow.java} | 4 +- src/desktop/app/Register.java | 321 ++++++++------- src/desktop/app/RegisterList.java | 201 ++++++++++ src/desktop/vue/Instruction.java | 1 - src/desktop/vue/JavaVUE.java | 8 +- 14 files changed, 952 insertions(+), 431 deletions(-) delete mode 100644 src/desktop/app/CPU.java create mode 100644 src/desktop/app/CPUWindow.java rename src/desktop/app/{Console.java => ConsoleWindow.java} (92%) create mode 100644 src/desktop/app/Disassembler.java rename src/desktop/app/{Memory.java => MemoryWindow.java} (99%) create mode 100644 src/desktop/app/RegisterList.java diff --git a/license.txt b/license.txt index d9258e2..003a32a 100644 --- a/license.txt +++ b/license.txt @@ -1,4 +1,4 @@ -Copyright (C) 2019 Planet Virtual Boy +Copyright (C) 2020 Planet Virtual Boy This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/src/core/cpu.c b/src/core/cpu.c index 33169b3..f76cc42 100644 --- a/src/core/cpu.c +++ b/src/core/cpu.c @@ -79,7 +79,6 @@ static void cpuDecode(VUE_INST *inst, int32_t bits) { /* Decode by format */ switch (inst->format) { - case 0: return; /* Illegal opcode */ case 1: inst->reg2 = bits >> 21 & 31; inst->reg1 = bits >> 16 & 31; diff --git a/src/core/include/vue.h b/src/core/include/vue.h index aa0f864..fc43eb1 100644 --- a/src/core/include/vue.h +++ b/src/core/include/vue.h @@ -159,6 +159,7 @@ typedef struct { /* Emulation state */ typedef struct { + VUE_INST inst; /* Instruction state */ /* Memory bus */ struct { @@ -221,8 +222,6 @@ typedef struct { uint16_t ecr_fecc; /* Fatal Error Cause Code */ } cpu; - /* Additional fields */ - VUE_INST inst; /* Instruction state */ } VUE; diff --git a/src/desktop/app/App.java b/src/desktop/app/App.java index 021495a..49a1fa8 100644 --- a/src/desktop/app/App.java +++ b/src/desktop/app/App.java @@ -11,7 +11,7 @@ import vue.*; public class App { // Instance fields - private boolean useNative; // Produce native core contexts + private boolean useNative; // Produce native core contexts private Localizer.Locale[] locales; // Language translations private ArrayList windows; // Application windows diff --git a/src/desktop/app/CPU.java b/src/desktop/app/CPU.java deleted file mode 100644 index 77d3fea..0000000 --- a/src/desktop/app/CPU.java +++ /dev/null @@ -1,257 +0,0 @@ -package app; - -// Java imports -import java.awt.*; -import java.awt.event.*; -import java.util.*; -import javax.swing.*; - -// Project imports -import util.*; -import vue.*; - -// CPU window -class CPU extends ChildWindow { - - // Instance fields - private int expandWidth; // Width of expand buttons - private Font font; // Display font - private int fontHeight; // Font line height - private int fontWidth; // Font maximum character width - private boolean shown; // Window has been shown - private int systemHeight; // Initial height of system register list - - // UI components - private JPanel dasm; // Disassembler - private JPanel system; // System registers - private JPanel program; // Program registers - private ArrayList registers; // Register controls - - - - /////////////////////////////////////////////////////////////////////////// - // Constructors // - /////////////////////////////////////////////////////////////////////////// - - // Default constructor - CPU(MainWindow parent) { - super(parent, "cpu.title"); - var client = getContentPane(); - - // Configure instance fields - font = new Font(Util.fontFamily(new String[] - { "Consolas", Font.MONOSPACED } ), Font.PLAIN, 14); - registers = new ArrayList(); - - dasm = new JPanel(null); - dasm.setBackground(SystemColor.window); - dasm.setFocusable(true); - - var inner = initRegisters(); - var outer = Util.splitPane(JSplitPane.HORIZONTAL_SPLIT); - outer.setLeftComponent(new JScrollPane(dasm, - JScrollPane.VERTICAL_SCROLLBAR_NEVER, - JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED)); - outer.setRightComponent(inner); - outer.setResizeWeight(1); - - client.add(outer); - client.setPreferredSize(new Dimension(480, 300)); - setFont2(font); - pack(); - } - - - - /////////////////////////////////////////////////////////////////////////// - // Register Constructors // - /////////////////////////////////////////////////////////////////////////// - - // Initialize program register list - private void initProgram() { - Dimension target = null; - - // Program register container - var lst = program = new JPanel(new GridBagLayout()) { - public Dimension getPreferredSize() { - var ret = super.getPreferredSize(); - if (!shown) - ret.height = 0; - return ret; - } - public void paintComponent(Graphics g) { - super.paintComponent(g); - if (shown) - return; - shown = true; - system.revalidate(); - program.revalidate(); - } - }; - lst.setBackground(SystemColor.window); - lst.setFocusable(true); - lst.addMouseListener(Util.onMouse(e->lst.requestFocus(),null)); - - // Produce the list of program registers - for (int x = 0; x < 32; x++) { - String name = "r" + x; - switch (x) { - case VUE.GP: name = "gp"; break; - case VUE.HP: name = "hp"; break; - case VUE.LP: name = "lp"; break; - case VUE.SP: name = "sp"; break; - case VUE.TP: name = "tp"; break; - } - registers.add(new Register( - parent, lst, name, x, Register.PROGRAM)); - } - endList(lst); - } - - // Initialize register lists - private JSplitPane initRegisters() { - initSystem(); - initProgram(); - - var ret = Util.splitPane(JSplitPane.VERTICAL_SPLIT); - ret.setTopComponent(new JScrollPane(system, - JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, - JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED - )); - ret.setBottomComponent(new JScrollPane(program, - JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, - JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED - )); - return ret; - } - - // Initialize system register list - private void initSystem() { - - // System register container - var lst = system = new JPanel(new GridBagLayout()) { - public Dimension getPreferredSize() { - var ret = super.getPreferredSize(); - if (!shown) - ret.height = systemHeight; - return ret; - } - }; - system.setBackground(SystemColor.window); - system.setFocusable(true); - system.addMouseListener(Util.onMouse(e->system.requestFocus(), null)); - system.putClientProperty("shown", true); - - // Add the first two system registers and expand PSW - int plain = Register.PLAIN; - registers.add(new Register(parent, lst, "PC" , VUE.PC , plain )); - Register psw =new Register(parent, lst, "PSW" , VUE.PSW , VUE.PSW ); - psw.setExpanded(true); - registers.add(psw); - shown = true; - systemHeight = system.getPreferredSize().height + 6; - shown = false; - - // Add the remaining system registers - registers.add(new Register(parent, lst, "EIPC" , VUE.EIPC , plain )); - registers.add(new Register(parent, lst, "EIPSW", VUE.EIPSW, VUE.PSW )); - registers.add(new Register(parent, lst, "FEPC" , VUE.FEPC , plain )); - registers.add(new Register(parent, lst, "FEPSW", VUE.FEPSW, VUE.PSW )); - registers.add(new Register(parent, lst, "ECR" , VUE.ECR , VUE.ECR )); - registers.add(new Register(parent, lst, "ADTRE", VUE.ADTRE, plain )); - registers.add(new Register(parent, lst, "CHCW" , VUE.CHCW , VUE.CHCW)); - registers.add(new Register(parent, lst, "PIR" , VUE.PIR , VUE.PIR )); - registers.add(new Register(parent, lst, "TKCW" , VUE.TKCW , VUE.TKCW)); - registers.add(new Register(parent, lst, "29" , 29, plain )); - registers.add(new Register(parent, lst, "30" , 30, plain )); - registers.add(new Register(parent, lst, "31" , 31, plain )); - endList(lst); - } - - - - /////////////////////////////////////////////////////////////////////////// - // Event Handlers // - /////////////////////////////////////////////////////////////////////////// - - // Client resize - private void onResize() { - //refreshDasm(); - } - - - - /////////////////////////////////////////////////////////////////////////// - // Package Methods // - /////////////////////////////////////////////////////////////////////////// - - // Update the display - void refresh() { - - // The element is not ready - if (registers == null) - return; - - // Refresh registers - for (var reg : registers) - reg.refresh(); - } - - // Specify a new font - void setFont2(Font font) { - this.font = font; - - // Configure the maximum font dimensions - var fontMax = new JLabel("!"); - fontMax.setFont(font); - fontHeight = Math.max(1, fontMax.getPreferredSize().height); - fontWidth = -1; - for (int x = 0; x < 16; x++) { - fontMax.setText(Integer.toString(x, 16).toUpperCase()); - fontWidth = Math.max(fontWidth, fontMax.getPreferredSize().width); - } - - // Configure register list scrolling - for (int x = 0; x < 2; x++) { - Component ctrl = x == 0 ? system : program; - while (!(ctrl instanceof JScrollPane)) - ctrl = ctrl.getParent(); - ((JScrollPane) ctrl).getVerticalScrollBar() - .setUnitIncrement(fontHeight); - } - - // Determine the width of the register expand buttons - var expand = new JLabel("+"); - int width = expand.getPreferredSize().width; - expand.setText("-"); - width = Math.max(width, expand.getPreferredSize().width) + 4; - - // Configure registers - for (var reg : registers) { - reg.setExpandWidth(width); - reg.setFont(font, fontWidth, fontHeight); - } - - onResize(); - } - - - - /////////////////////////////////////////////////////////////////////////// - // Private Methods // - /////////////////////////////////////////////////////////////////////////// - - // Terminate a register list - private JPanel endList(JPanel list) { - var spacer = new JPanel(null); - spacer.setOpaque(false); - spacer.setPreferredSize(new Dimension(1, 1)); - var gbc = new GridBagConstraints(); - gbc.gridheight = GridBagConstraints.REMAINDER; - gbc.gridwidth = GridBagConstraints.REMAINDER; - gbc.weighty = 1; - list.add(spacer, gbc); - return spacer; - } - -} diff --git a/src/desktop/app/CPUWindow.java b/src/desktop/app/CPUWindow.java new file mode 100644 index 0000000..7d283b1 --- /dev/null +++ b/src/desktop/app/CPUWindow.java @@ -0,0 +1,179 @@ +package app; + +// Java imports +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import javax.swing.*; + +// Project imports +import util.*; +import vue.*; + +// CPU window +class CPUWindow extends ChildWindow { + + // Instance fields + private int expandWidth; // Width of expand buttons + private boolean shown; // Window has been shown + private int systemHeight; // Initial height of system register list + + // UI components + private JPanel dasm; // Disassembler + private RegisterList lstProgram; // Program register list + private RegisterList lstSystem; // System register list + + + + /////////////////////////////////////////////////////////////////////////// + // Global Settings // + /////////////////////////////////////////////////////////////////////////// + + static int regExpandWidth; // Width of register list expand button + static Font regHexFont; // Register list hex font + static Dimension regHexFontSize; // Max dimensions + static HashSet instances; // Spawned instances + + // Static initializer + static { + setDefaults(); + instances = new HashSet(); + } + + + + /////////////////////////////////////////////////////////////////////////// + // Static Methods // + /////////////////////////////////////////////////////////////////////////// + + // Apply configuration settings to all instances + static void configureAll() { + for (var inst : instances) + inst.configure(); + } + + // Reset all settings to their default values + static void setDefaults() { + + // Register list hex font + setRegHexFont(new Font(Util.fontFamily(new String[] + { "Consolas", Font.MONOSPACED } ), Font.PLAIN, 14)); + + // Width of register list expand button + var label = new JLabel("+"); + regExpandWidth = label.getPreferredSize().width; + label.setText("-"); + regExpandWidth = Math.max(regExpandWidth, + label.getPreferredSize().width); + } + + // Specify a font to use as the register list hex font + static void setRegHexFont(Font font) { + regHexFont = font; + regHexFontSize = measureHex(font); + } + + + + /////////////////////////////////////////////////////////////////////////// + // Constructors // + /////////////////////////////////////////////////////////////////////////// + + // Default constructor + CPUWindow(MainWindow parent) { + super(parent, "cpu.title"); + instances.add(this); + + var client = getContentPane(); + + dasm = new JPanel(null); + dasm.setBackground(SystemColor.window); + dasm.setFocusable(true); + + lstSystem = new RegisterList(this, true); + lstProgram = new RegisterList(this, false); + var inner = Util.splitPane(JSplitPane.VERTICAL_SPLIT); + inner.setTopComponent(lstSystem); + inner.setBottomComponent(lstProgram); + + var outer = Util.splitPane(JSplitPane.HORIZONTAL_SPLIT); + outer.setLeftComponent(new JScrollPane(dasm, + JScrollPane.VERTICAL_SCROLLBAR_NEVER, + JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED)); + outer.setRightComponent(inner); + outer.setResizeWeight(1); + + client.add(outer); + client.setPreferredSize(new Dimension(480, 300)); + configure(); + pack(); + } + + + /////////////////////////////////////////////////////////////////////////// + // Public Methods // + /////////////////////////////////////////////////////////////////////////// + + // The window is closing + public void dispose() { + instances.remove(this); + super.dispose(); + } + + + + /////////////////////////////////////////////////////////////////////////// + // Package Methods // + /////////////////////////////////////////////////////////////////////////// + + // Apply configuration settings + void configure() { + lstProgram.configure(); + lstSystem .configure(); + } + + // Update the display + void refresh() { + lstSystem.refresh(); + lstProgram.refresh(); + } + + + + /////////////////////////////////////////////////////////////////////////// + // Event Handlers // + /////////////////////////////////////////////////////////////////////////// + + // Client resize + private void onResize() { + //refreshDasm(); + } + + + + /////////////////////////////////////////////////////////////////////////// + // Private Methods // + /////////////////////////////////////////////////////////////////////////// + + // Determine the maximum character width of a hex character in a font + private static Dimension measureHex(Font font) { + int ret = 0; + Dimension size = null; + + // Process all digits + var label = new JLabel(); + label.setFont(font); + for (int x = 0; x < 16; x++) { + label.setText(String.format( + "%" + (Disassembler.hexCaps ? "X" : "x" + ), x)); + size = label.getPreferredSize(); + ret = Math.max(ret, size.width); + } + + return new Dimension(ret, size.height); + } + + + +} diff --git a/src/desktop/app/Console.java b/src/desktop/app/ConsoleWindow.java similarity index 92% rename from src/desktop/app/Console.java rename to src/desktop/app/ConsoleWindow.java index 65b11e2..9c6391e 100644 --- a/src/desktop/app/Console.java +++ b/src/desktop/app/ConsoleWindow.java @@ -5,7 +5,7 @@ import java.awt.*; import javax.swing.*; // Console window -class Console extends ChildWindow { +class ConsoleWindow extends ChildWindow { // Instance fields private boolean shown; // Component has been visible @@ -17,7 +17,7 @@ class Console extends ChildWindow { /////////////////////////////////////////////////////////////////////////// // Default constructor - Console(MainWindow parent) { + ConsoleWindow(MainWindow parent) { super(parent, "console.title"); getContentPane().setPreferredSize(new Dimension(384, 224)); pack(); diff --git a/src/desktop/app/Disassembler.java b/src/desktop/app/Disassembler.java new file mode 100644 index 0000000..1bb60cb --- /dev/null +++ b/src/desktop/app/Disassembler.java @@ -0,0 +1,379 @@ +package app; + +// Project imports +import vue.*; + +// Instruction disassembler +class Disassembler { + private Disassembler() { } // Cannot be instantiated + static { setDefaults(); } // Initialize to default settings + + + + /////////////////////////////////////////////////////////////////////////// + // Global Settings // + /////////////////////////////////////////////////////////////////////////// + + static boolean bcondCombine; // Merge Bcond condition into mnemonic + static boolean bcondNames; // Use symbolic condition names for Bcond + static boolean condCaps; // Uppercase condition mnemonics + static boolean destLast; // Destination register last + static boolean dispDest; // Resolve jump destination addresses + static boolean dispInside; // Load/store displacement inside brackets + static boolean hexCaps; // Upercase hexadecimal + static int hexMode; // Hexadecimal decoration + static boolean immNumber; // Use number sign with immediate values + static boolean jmpBrackets; // Square brackets around JMP + static boolean jumpAddress; // Use jump destination addresses + static boolean lower; // Use L instead of C in conditions + static boolean mnemonicCaps; // Uppercase mnemonics + static boolean programCaps; // Uppercase program register names + static boolean programNames; // Use symbolic program register names + static boolean setfCombine; // Merge SETF condition into mnemonic + static boolean setfNames; // Use symbolic condition names for SETF + static boolean systemCaps; // Uppercase system register names + static boolean systemNames; // Use symbolic system register names + static boolean zero; // Use Z instead of E in conditions + + + + /////////////////////////////////////////////////////////////////////////// + // Constants // + /////////////////////////////////////////////////////////////////////////// + + // Hexadecimal decorations + static final int DOLLAR = 0; + static final int H = 1; + static final int ZEROX = 2; + + // Condition mneonics + static final String[] CONDITIONS = { + "V" , "C" , "E" , "NH", "N", "T", "LT", "LE", + "NV", "NC", "NE", "H" , "P", "F", "GE", "GT" + }; + + // Mnemonics + static final String[] MNEMONICS = { + "---" , "ADD" , "ADD" , "ADDF.S", "ADDI" , "AND" , + "ANDBSU" , "ANDI" , "ANDNBSU", "Bcond" , "CAXI" , "CLI" , + "CMP" , "CMP" , "CMPF.S" , "CVT.SW", "CVT.WS" , "DIV" , + "DIVF.S" , "DIVU" , "HALT" , "IN.B" , "IN.H" , "IN.W" , + "JAL" , "JMP" , "JR" , "LD.B" , "LD.H" , "LD.W" , + "LDSR" , "MOV" , "MOV" , "MOVBSU", "MOVEA" , "MOVHI" , + "MPYHW" , "MUL" , "MULF.S" , "MULU" , "NOT" , "NOTBSU" , + "OR" , "ORBSU" , "ORI" , "ORNBSU", "OUT.B" , "OUT.H" , + "OUT.W" , "RETI" , "REV" , "SAR" , "SAR" , "SCH0BSD", + "SCH0BSU", "SCH1BSD", "SCH1BSU", "SEI" , "SETF" , "SHL" , + "SHL" , "SHR" , "SHR" , "ST.B" , "ST.H" , "ST.W" , + "STSR" , "SUB" , "SUBF.S" , "TRAP" , "TRNC.SW", "XB" , + "XH" , "XOR" , "XORBSU" , "XORI" , "XORNBSU" + }; + + // Program register names + private static final String[] PROGRAMS = { + null, null, "hp", "sp", "gp", "tp", null, null, + null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, "lp" + }; + + // System register names + private static final String[] SYSTEMS = { + "EIPC", "EIPSW", "FEPC", "FEPSW", "ECR", "PSW", "PIR", "TKCW", + null , null , null , null , null , null , null , null , + null , null , null , null , null , null , null , null , + "CHCW", "ADTRE", null , null , null , null , null , null + }; + + + + /////////////////////////////////////////////////////////////////////////// + // Classes // + /////////////////////////////////////////////////////////////////////////// + + // One row of output + static class Row { + String address; // Bus address + String bytes; // Encoded bytes in bus order + String mnemonic; // Instruction mnemonic + String operands; // Instruction operands, if any + } + + + + /////////////////////////////////////////////////////////////////////////// + // Static Methods // + /////////////////////////////////////////////////////////////////////////// + + // Reset all settings to their default values + static void setDefaults() { + bcondCombine = true; + bcondNames = true; + condCaps = true; + destLast = true; + dispDest = true; + dispInside = false; + hexCaps = true; + hexMode = ZEROX; + immNumber = false; + jmpBrackets = true; + jumpAddress = true; + lower = true; + mnemonicCaps = true; + programCaps = false; + programNames = true; + setfCombine = false; + setfNames = true; + systemCaps = true; + systemNames = true; + zero = false; + } + + + + /////////////////////////////////////////////////////////////////////////// + // Package Methods // + /////////////////////////////////////////////////////////////////////////// + + // Represent an instruction as text fields + static void disassemble(int address, Instruction inst, Row row) { + + // Address + String x = hexCaps ? "X" : "x"; + row.address = String.format("%08" + x, address); + + // Bytes + x = "%02" + x; + row.bytes = inst.size == 2 ? + String.format(x + " " + x, + inst.bits >> 16 & 0xFF, + inst.bits >> 24 & 0xFF + ) : String.format(x + " " + x + " " + x + " " + x, + inst.bits >> 16 & 0xFF, + inst.bits >> 24 & 0xFF, + inst.bits & 0xFF, + inst.bits >> 8 & 0xFF + ) + ; + + // Bcond mnemonic + if (inst.id == VUE.BCOND && bcondCombine) { + row.mnemonic = "B" + CONDITIONS[inst.cond]; + if (lower && (inst.cond & 7) == 1) + row.mnemonic = inst.cond == 1 ? "BL" : "BNL"; + if (zero && (inst.cond & 7) == 2) + row.mnemonic = inst.cond == 2 ? "BZ" : "BNZ"; + if ( (inst.cond & 7) == 5) + row.mnemonic = inst.cond == 5 ? "BR" : "NOP"; + } + + // SETF mnemonic + else if (inst.id == VUE.SETF && setfCombine) + row.mnemonic = "SETF" + CONDITIONS[inst.imm]; + + // All other mnemonics + else row.mnemonic = MNEMONICS[inst.id]; + + // Adjust mnemonic case + if (!mnemonicCaps) + row.mnemonic = row.mnemonic.toLowerCase(); + + // Operands by format + row.operands = null; + if (inst.id != VUE.ILLEGAL) switch (inst.format) { + case 1: // Fallthrough + case 7: row.operands = formatI_VII(inst ); break; + case 2: row.operands = formatII (inst ); break; + case 3: row.operands = formatIII (inst, address); break; + case 4: row.operands = destination(inst, address); break; + case 5: row.operands = formatV (inst ); break; + case 6: row.operands = formatVI (inst ); break; + } + + } + + + + /////////////////////////////////////////////////////////////////////////// + // Private Methods // + /////////////////////////////////////////////////////////////////////////// + + // Format the destination of a branch or jump + private static String destination(Instruction inst, int address) { + return !dispDest ? toHex(inst.disp, 1, immNumber) : + String.format("%08" + (hexCaps ? "X" : "x"), address + inst.disp); + } + + // Operands for Format I and Format VII + private static String formatI_VII(Instruction inst) { + String reg1 = program(inst.reg1); + String reg2 = program(inst.reg2); + + // One-operand instructions + switch (inst.id) { + case VUE.JMP: + return String.format(jmpBrackets ? "[%s]" : "%s", reg1); + case VUE.XB: // Fallthrough + case VUE.XH: + return reg2; + } + + // Generic + return String.format("%s, %s", + destLast ? reg1 : reg2, + destLast ? reg2 : reg1 + ); + } + + // Operands for Format II + private static String formatII(Instruction inst) { + + // Bit string + if (inst.opcode == 0b011111) + return null; + + // Zero- or one-operand instructions + switch (inst.id) { + + // Zero-operand + case VUE.CLI : // Fallthrough + case VUE.HALT: // Fallthrough + case VUE.RETI: // Fallthrough + case VUE.SEI : + return null; + + // One-operand + case VUE.TRAP: + return Integer.toString(inst.imm); + } + + // Combined SETF + String reg2 = program(inst.reg2); + if (inst.id == VUE.SETF && setfCombine) + return reg2; + + // Two-operand instructions + String imm = String.format("%s%d", immNumber ? "#" : "", inst.imm); + switch (inst.id) { + case VUE.LDSR: // Fallthrough + case VUE.STSR: + if (!systemNames || SYSTEMS[inst.imm] == null) + break; + imm = SYSTEMS[inst.imm]; + if (!systemCaps) + imm = imm.toLowerCase(); + break; + case VUE.SETF: + if (!setfNames) + break; + imm = CONDITIONS[inst.imm]; + if (!condCaps) + imm = imm.toLowerCase(); + break; + } + + // Generic + return String.format("%s, %s", + destLast ? imm : reg2, + destLast ? reg2 : imm + ); + } + + // Operands for Format III + private static String formatIII(Instruction inst, int address) { + + // NOP + if (bcondCombine && inst.cond == 13) + return null; + + // Format destination + String dest = destination(inst, address); + + // One-operand notation + if (bcondCombine) + return dest; + + // Two-operand notation + String cond = bcondNames ? + CONDITIONS[inst.cond] : Integer.toString(inst.cond); + if (bcondNames && !condCaps) + cond = cond.toLowerCase(); + return String.format("%s, %s", cond, dest); + } + + // Operands for Format V + private static String formatV(Instruction inst) { + String reg1 = program(inst.reg1); + String reg2 = program(inst.reg2); + String imm = toHex( + inst.id == VUE.MOVEA ? inst.imm & 0xFFFF : inst.imm, + inst.id == VUE.ADDI ? 1 : 4, + immNumber + ); + return String.format("%s, %s, %s", + destLast ? imm : reg2, + reg1, + destLast ? reg2 : imm + ); + } + + // Operands for Format VI + private static String formatVI(Instruction inst) { + String src = program(inst.reg1); + String dest = program(inst.reg2); + + // Data operand + src = inst.disp == 0 ? String.format("[%s]", src) : + dispInside ? String.format( + "[%s %s %s]", + src, + inst.disp < 0 ? "-" : "+", + toHex(Math.abs(inst.disp), 1, immNumber) + ) : String.format( + "%s[%s]", + toHex(inst.disp, 1, immNumber), + src + ) + ; + + // Write instruction + switch (inst.id) { + case VUE.OUT_B: // Fallthrough + case VUE.OUT_H: // Fallthrough + case VUE.OUT_W: // Fallthrough + case VUE.ST_B : // Fallthrough + case VUE.ST_H : // Fallthrough + case VUE.ST_W : + String temp = src; + src = dest; + dest = temp; + } + + // Format operands + return String.format("%s, %s", + destLast ? src : dest, + destLast ? dest : src + ); + } + + // Format a program register + private static String program(int index) { + String ret = programNames ? PROGRAMS[index] : null; + if (ret == null) + ret = "r" + index; + return programCaps ? ret.toUpperCase() : ret; + } + + // Represent an immediate value as hexadecimal + private static String toHex(int value, int digits, boolean number) { + return String.format( + "%s%s%s%0" + digits + (hexCaps ? "X" : "x") + "%s", + number ? "#" : "", + value < 0 ? "-" : "", + hexMode == DOLLAR ? "$" : hexMode == ZEROX ? "0x" : "", + value < 0 ? -value : value, + hexMode == H ? "h" : "" + ); + } + +} diff --git a/src/desktop/app/MainWindow.java b/src/desktop/app/MainWindow.java index bfacae1..1bc143d 100644 --- a/src/desktop/app/MainWindow.java +++ b/src/desktop/app/MainWindow.java @@ -27,13 +27,13 @@ class MainWindow extends JFrame { private File romFile; // Currently loaded ROM file // UI components - private JPanel client; // Common client container - private Console console; // Console window - private CPU cpu; // CPU window - private JDesktopPane desktop; // Container for child windows - private Memory memory; // Memory window - private JPanel video; // Video output - private JMenu mnuDebug; // Debug menu + private JPanel client; // Common client container + private ConsoleWindow console; // Console window + private CPUWindow cpu; // CPU window + private JDesktopPane desktop; // Container for child windows + private MemoryWindow memory; // Memory window + private JMenu mnuDebug; // Debug menu + private JPanel video; // Video output private JMenuItem mnuFileDebugMode; // File -> Debug mode private JMenuItem mnuFileGameMode; // File -> Game mode @@ -92,9 +92,9 @@ class MainWindow extends JFrame { // Configure child windows desktop = new JDesktopPane(); desktop.setBackground(SystemColor.controlShadow); - desktop.add(console = new Console(this)); - desktop.add(cpu = new CPU (this)); - desktop.add(memory = new Memory (this)); + desktop.add(console = new ConsoleWindow(this)); + desktop.add(cpu = new CPUWindow (this)); + desktop.add(memory = new MemoryWindow (this)); // Display window refreshDebug(); @@ -207,6 +207,7 @@ class MainWindow extends JFrame { // Window close, File -> Exit private void onClose() { app.removeWindow(this); + cpu.dispose(); dispose(); vue.dispose(); } diff --git a/src/desktop/app/Memory.java b/src/desktop/app/MemoryWindow.java similarity index 99% rename from src/desktop/app/Memory.java rename to src/desktop/app/MemoryWindow.java index 97380c3..f32e3b4 100644 --- a/src/desktop/app/Memory.java +++ b/src/desktop/app/MemoryWindow.java @@ -10,7 +10,7 @@ import javax.swing.*; import util.*; // Memory viewer and hex editor window -class Memory extends ChildWindow { +class MemoryWindow extends ChildWindow { // Private fields private int address; // Address of top row @@ -41,7 +41,7 @@ class Memory extends ChildWindow { /////////////////////////////////////////////////////////////////////////// // Default constructor - Memory(MainWindow parent) { + MemoryWindow(MainWindow parent) { super(parent, "memory.title"); // Configure instance fields diff --git a/src/desktop/app/Register.java b/src/desktop/app/Register.java index 639c66e..daf0ee8 100644 --- a/src/desktop/app/Register.java +++ b/src/desktop/app/Register.java @@ -14,26 +14,22 @@ import vue.*; class Register { // Instance fields - boolean expandable; // The expansion area can be shown - boolean expanded; // The expanded area is being shown - Font font; // Hexadecimal font - int index; // Register index - int mode; // Display mode for program registers - MainWindow parent; // Containing window - int type; // Expansion controls type - int value; // Current register value + private boolean expandable; // The expansion area can be shown + private boolean expanded; // The expanded area is being shown + private int index; // Register index + private int mode; // Display mode for program registers + private String name; // Register name + private RegisterList parent; // Containing register list + private int type; // Expansion controls type + private int value; // Current register value // UI components - private JPanel expansion; // Expansion area - private JLabel btnExpand; // Expand button - private JLabel lblLastPC; // Last PC name - private JLabel lblName; // Register name - private JPanel list; // Containing element - private JPanel spacer; // Expansion area spacer - private JTextField txtJumpFrom; // Jump-from value - private JTextField txtJumpTo; // Jump-to value - private JTextField txtValue; // Register value - private ArrayList controls; // Expansion controls + JPanel expansion; // Expansion container + JLabel btnExpand; // Expand button + JPanel indent; // Expansion area indentation + JLabel lblName; // Register name + JTextField txtValue; // Register value + ArrayList controls; // Expansion controls @@ -48,8 +44,8 @@ class Register { static final int UNSIGNED = 2; // Types - static final int PLAIN = -1; - static final int PROGRAM = -2; + static final int PLAIN = -2; + static final int PROGRAM = -3; @@ -58,20 +54,21 @@ class Register { /////////////////////////////////////////////////////////////////////////// // Default constructor - Register(MainWindow parent, JPanel list, String name, int index, int type){ + Register(RegisterList parent, String name, int index, int type) { + parent.add(index, this); // Configure instance fields controls = new ArrayList(); - expandable = type != PLAIN && index != 0 || index == VUE.PC; + expandable = type != PLAIN && index != 0; this.index = index; - this.list = list; - this.mode = HEX; + mode = HEX; + this.name = name; this.parent = parent; this.type = type; // Click handler for expand and name controls MouseListener expand = !expandable ? null : Util.onMouse(e->{ - if (e.getButton() == 1) setExpanded(!expanded); }, null); + if (e.getButton() == 1) setExpanded(!expanded); }, null); // Expand button btnExpand = new JLabel(expandable ? "+" : " "); @@ -81,17 +78,17 @@ class Register { var gbc = new GridBagConstraints(); gbc.anchor = GridBagConstraints.NORTH; gbc.fill = GridBagConstraints.HORIZONTAL; - list.add(btnExpand, gbc); + parent.add(gbc, btnExpand); // Name label - lblName = new JLabel(name); + lblName = new JLabel(" "); if (expandable) lblName.addMouseListener(expand); gbc = new GridBagConstraints(); gbc.anchor = GridBagConstraints.NORTH; gbc.fill = GridBagConstraints.HORIZONTAL; gbc.weightx = 1; - list.add(lblName, gbc); + parent.add(gbc, lblName); // Value text box txtValue = new JTextField(); @@ -101,7 +98,7 @@ class Register { gbc = new GridBagConstraints(); gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.insets = new Insets(0, 4, 0, 0); - list.add(txtValue, gbc); + parent.add(gbc, txtValue); // Value changed txtValue.addActionListener(e->{ @@ -129,14 +126,14 @@ class Register { default: return; } - // Expansion spacer + // Expansion indentation if (index != VUE.PC) { - spacer = new JPanel(null); - spacer.setOpaque(false); - spacer.setPreferredSize(new Dimension(0, 0)); - spacer.setVisible(false); + indent = new JPanel(null); + indent.setOpaque(false); + indent.setPreferredSize(new Dimension(0, 0)); + indent.setVisible(false); gbc = new GridBagConstraints(); - list.add(spacer, gbc); + parent.add(gbc, indent); } // Expansion area @@ -149,7 +146,11 @@ class Register { gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.insets = new Insets(0, 4, 0, 0); gbc.weightx = 1; - list.add(expansion, gbc); + parent.add(gbc, expansion); + + // Handling for PSW + if (index == VUE.PSW && type == VUE.PSW) + setExpanded(true); } @@ -161,14 +162,14 @@ class Register { // Expansion controls for CHCW private void initCHCW() { expansion = new JPanel(new GridBagLayout()); - addCheckBox("ICE", 1, false); endRow(); + addCheckBox("ICE", 1, false, true); } // Expansion controls for ECR private void initECR() { expansion = new JPanel(new GridBagLayout()); - addTextBox("EICC", 0, 16, false, true); endRow(); - addTextBox("FECC", 16, 16, false, true); endRow(); + addTextBox("EICC", 0, 16, false, true); + addTextBox("FECC", 16, 16, false, true); } // Expansion controls for program registers @@ -189,38 +190,37 @@ class Register { for (int x = 0; x < 2; x++) { // Indentation - var spacer = new JPanel(null); - spacer.setOpaque(false); - spacer.setPreferredSize(new Dimension(0, 0)); + indent = new JPanel(null); + indent.setOpaque(false); + indent.setPreferredSize(new Dimension(0, 0)); var gbc = new GridBagConstraints(); gbc.weightx = 1; - expansion.add(spacer, gbc); + expansion.add(indent, gbc); // Name label var label = new JLabel(); - parent.app.localizer.add(label, + parent.parent.parent.app.localizer.add(label, x == 0 ? "cpu.jump_from" : "cpu.jump_to" ); gbc = new GridBagConstraints(); gbc.anchor = GridBagConstraints.NORTHWEST; expansion.add(label, gbc); + controls.add(label); // Value text box var txt = new JTextField(); txt.addActionListener(e->{ txt.setText((String) txt.getClientProperty("text")); - list.requestFocus(); + parent.requestFocus(); }); + txt.putClientProperty("index", + x == 0 ? VUE.JUMP_FROM : VUE.JUMP_TO); txt.setBorder(null); txt.setOpaque(false); gbc = new GridBagConstraints(); gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.insets = new Insets(0, 4, 0, 0); expansion.add(txt, gbc); - - // Initialize the corresponding component field - if (x == 0) - txtJumpFrom = txt; - else txtJumpTo = txt; + controls.add(txt); } } @@ -228,40 +228,40 @@ class Register { // Expansion controls for PSW private void initPSW() { expansion = new JPanel(new GridBagLayout()); - addCheckBox("Z" , 0, false); - addCheckBox("FRO", 9, false); endRow(); - addCheckBox("S" , 1, false); - addCheckBox("FIV", 8, false); endRow(); - addCheckBox("OV" , 2, false); - addCheckBox("FZD", 7, false); endRow(); - addCheckBox("CY" , 3, false); - addCheckBox("FOV", 6, false); endRow(); - addCheckBox("EP" , 14, false); - addCheckBox("FUD", 5, false); endRow(); - addCheckBox("NP" , 15, false); - addCheckBox("FPR", 4, false); endRow(); - addCheckBox("AE" , 13, false); endRow(); - addCheckBox("ID" , 12, false); - addTextBox ("I" , 16, 4, false, false); endRow(); + addCheckBox("Z" , 0, false, false); + addCheckBox("FRO", 9, false, true ); + addCheckBox("S" , 1, false, false); + addCheckBox("FIV", 8, false, true ); + addCheckBox("OV" , 2, false, false); + addCheckBox("FZD", 7, false, true ); + addCheckBox("CY" , 3, false, false); + addCheckBox("FOV", 6, false, true ); + addCheckBox("EP" , 14, false, false); + addCheckBox("FUD", 5, false, true ); + addCheckBox("NP" , 15, false, false); + addCheckBox("FPR", 4, false, true ); + addCheckBox("AE" , 13, false, true ); + addCheckBox("ID" , 12, false, false); + addTextBox ("I" , 16, 4, false, false); } // Expansion controls for PIR private void initPIR() { expansion = new JPanel(new GridBagLayout()); - addTextBox("PT", 0, 16, true, true); endRow(); + addTextBox("PT", 0, 16, true, true); } // Expansion controls for TKCW private void initTKCW() { expansion = new JPanel(new GridBagLayout()); - addCheckBox("OTM", 8, true); - addCheckBox("FVT", 5, true); endRow(); - addCheckBox("FIT", 7, true); - addCheckBox("FUT", 4, true); endRow(); - addCheckBox("FZT", 6, true); - addCheckBox("FPT", 3, true); endRow(); - addCheckBox("RDI", 2, true); - addTextBox ("RD", 0, 2, true, false); endRow(); + addCheckBox("OTM", 8, true, false); + addCheckBox("FVT", 5, true, true ); + addCheckBox("FIT", 7, true, false); + addCheckBox("FUT", 4, true, true ); + addCheckBox("FZT", 6, true, false); + addCheckBox("FPT", 3, true, true ); + addCheckBox("RDI", 2, true, false); + addTextBox ("RD", 0, 2, true, false); } @@ -270,11 +270,61 @@ class Register { // Package Methods // /////////////////////////////////////////////////////////////////////////// - // Refresh controls - void refresh() { + // Apply configuration settings + void configure() { + String name = null; + + // System register + if (type != PROGRAM) { + name = this.name; + if (!Disassembler.systemCaps) + name = name.toLowerCase(); + } + + // Program register + else { + if (Disassembler.programNames) + name = this.name; + if (name == null) + name = "r" + index; + if (Disassembler.programCaps) + name = name.toUpperCase(); + } + + // Name label + lblName.setText(name); + + // Expand button + var size = btnExpand.getPreferredSize(); + size.width = CPUWindow.regExpandWidth; + btnExpand.setPreferredSize(size); // Value text box - value = parent.vue.getRegister(index, type != PROGRAM); + var fontSize = CPUWindow.regHexFontSize; + size = new Dimension(8 * fontSize.width + 4, fontSize.height); + txtValue.setFont(CPUWindow.regHexFont); + txtValue.setPreferredSize(size); + + // Expansion controls + for (var ctrl : controls) { + if (!(ctrl instanceof JTextField)) + continue; + if (type == VUE.PC || (Boolean) ctrl.getClientProperty("hex")) + ((JTextField) ctrl).setFont(CPUWindow.regHexFont); + int digits = type == VUE.PC ? 8 : + (Integer) ctrl.getClientProperty("digits"); + size = ctrl.getPreferredSize(); + size.width = digits * fontSize.width + 4; + ctrl.setPreferredSize(size); + } + } + + // Refresh controls + void refresh() { + var vue = parent.parent.parent.vue; + + // Value text box + value = vue.getRegister(index, type != PROGRAM); txtValue.setText( type != PROGRAM || mode == HEX ? String.format("%08X", value) : @@ -283,18 +333,8 @@ class Register { Float.toString(Float.intBitsToFloat(value)) ); - // PC expansion controls - if (index == VUE.PC) for (int x = 0; x < 2; x++) { - JTextField txt = x == 0 ? txtJumpFrom : txtJumpTo; - int index = x == 0 ? VUE.JUMP_FROM : VUE.JUMP_TO; - int value = parent.vue.getRegister(index, true); - String text = String.format("%08X", value); - txt.putClientProperty("text", text); - txt.setText(text); - } - - // Other expansion controls - else for (var control : controls) { + // Expansion controls + for (var control : controls) { // Check box if (control instanceof JCheckBox) { @@ -306,13 +346,32 @@ class Register { // Text box if (control instanceof JTextField) { var ctrl = (JTextField) control; - int bit = (Integer) ctrl.getClientProperty("bit" ); - int digits = (Integer) ctrl.getClientProperty("digits"); - boolean hex = (Boolean) ctrl.getClientProperty("hex"); - int width = (Integer) ctrl.getClientProperty("width"); - int val = value >> bit & (1 << width) - 1; - ctrl.setText(!hex ? Integer.toString(val) : - String.format("%0" + digits + "X", val)); + int digits; // Maximum digits that can be displayed + boolean hex; // The value is hexadecimal + int val; // The value to be displayed + + // Jump history + if (type == VUE.PC) { + digits = 8; + hex = true; + val = vue.getRegister((Integer) + ctrl.getClientProperty("index"), true); + } + + // All other values + else { + int bit = (Integer) ctrl.getClientProperty("bit" ); + digits = (Integer) ctrl.getClientProperty("digits"); + hex = (Boolean) ctrl.getClientProperty("hex"); + int width = (Integer) ctrl.getClientProperty("width"); + val = value >> bit & (1 << width) - 1; + } + + // Update the text + String text = !hex ? Integer.toString(val) : String.format( + "%0" + digits + (Disassembler.hexCaps ? "X" : "x"), val); + ctrl.putClientProperty("text", text); + ctrl.setText(text); } } @@ -329,52 +388,16 @@ class Register { // Update controls this.expanded = expanded; btnExpand.setText(expanded ? "-" : "+"); - if (index != VUE.PC) - spacer.setVisible(expanded); + if (type != VUE.PC) + indent.setVisible(expanded); expansion.setVisible(expanded); - list.revalidate(); - } - - // Specify the width of the expand button - void setExpandWidth(int width) { - var size = btnExpand.getPreferredSize(); - size.width = width; - btnExpand.setPreferredSize(size); - } - - // Specify a new font - void setFont(Font font, int fontWidth, int fontHeight) { - this.font = font; - - // Value text box - var size = new Dimension(8 * fontWidth + 4, fontHeight); - txtValue.setFont(font); - txtValue.setPreferredSize(size); - if (index == VUE.PC) { - txtJumpFrom.setFont(font); - txtJumpFrom.setPreferredSize(size); - txtJumpTo .setFont(font); - txtJumpTo .setPreferredSize(size); - } - - // Expansion controls - for (var ctrl : controls) { - if (!(ctrl instanceof JTextField)) - continue; - if ((Boolean) ctrl.getClientProperty("hex")) - ((JTextField) ctrl).setFont(font); - int digits = (Integer) ctrl.getClientProperty("digits"); - size = ctrl.getPreferredSize(); - size.width = digits * fontWidth + 4; - ctrl.setPreferredSize(size); - } - + parent.revalidate(); } // Change the display mode of a program register void setMode(int mode) { this.mode = mode; - txtValue.setFont(mode == HEX ? font : null); + txtValue.setFont(mode == HEX ? CPUWindow.regHexFont : null); refresh(); } @@ -385,7 +408,8 @@ class Register { /////////////////////////////////////////////////////////////////////////// // Add a check box to the expansion area - private void addCheckBox(String name, int bit, boolean readOnly) { + private void addCheckBox(String name, int bit, boolean readOnly, + boolean last) { int mask = 1 << bit; // Configure control @@ -406,7 +430,7 @@ class Register { // Configure expansion area var gbc = new GridBagConstraints(); gbc.anchor = GridBagConstraints.NORTHWEST; - gbc.gridwidth = 2; + gbc.gridwidth = last ? GridBagConstraints.REMAINDER : 2; gbc.insets = new Insets(0, 4, 0, 4); expansion.add(ctrl, gbc); } @@ -416,7 +440,7 @@ class Register { // Configure control var ctrl = new JRadioButton(); - parent.app.localizer.add(ctrl, key); + parent.parent.parent.app.localizer.add(ctrl, key); ctrl.setBorder(null); ctrl.setFocusable(false); ctrl.setOpaque(false); @@ -465,27 +489,20 @@ class Register { // Configure expansion area var label = new JLabel(name); label.setEnabled(!readOnly); - var gbc = new GridBagConstraints(); + var gbc = new GridBagConstraints(); gbc.anchor = GridBagConstraints.NORTHWEST; gbc.insets = new Insets(0, 4, 0, 4); expansion.add(label, gbc); - expansion.add(ctrl , gbc); - } - - // Terminate a row of expansion controls - private void endRow() { - var spacer = new JPanel(null); - spacer.setOpaque(false); - spacer.setPreferredSize(new Dimension(0, 0)); - var gbc = new GridBagConstraints(); + gbc = new GridBagConstraints(); gbc.gridwidth = GridBagConstraints.REMAINDER; - expansion.add(spacer, gbc); + gbc.insets = new Insets(0, 4, 0, 4); + expansion.add(ctrl , gbc); } // Update the register value private void setValue(int value) { - list.requestFocus(); - parent.vue.setRegister(index, type != PROGRAM, value); + parent.requestFocus(); + parent.parent.parent.vue.setRegister(index, type != PROGRAM, value); refresh(); } diff --git a/src/desktop/app/RegisterList.java b/src/desktop/app/RegisterList.java new file mode 100644 index 0000000..7b1da29 --- /dev/null +++ b/src/desktop/app/RegisterList.java @@ -0,0 +1,201 @@ +package app; + +// Java imports +import java.awt.*; +import java.util.*; +import javax.swing.*; + +// Project imports +import vue.*; + +// List of CPU registers +class RegisterList extends JScrollPane { + + // Package fields + CPUWindow parent; // Containing CPU window + + // Private fields + private boolean shown; // Component has been shown + private HashMap registers; // Register items + + // UI components + private JPanel client; // Client area + + + + /////////////////////////////////////////////////////////////////////////// + // Constructors // + /////////////////////////////////////////////////////////////////////////// + + // Default constructor + RegisterList(CPUWindow parent, boolean system) { + super(VERTICAL_SCROLLBAR_ALWAYS, HORIZONTAL_SCROLLBAR_AS_NEEDED); + + // Configure instance fields + this.parent = parent; + registers = new HashMap(); + shown = true; + + // Configure client area + client = new JPanel(new GridBagLayout()) { + public Dimension getPreferredSize() { + var ret = super.getPreferredSize(); + if (!shown) ret.height = system ? getInitialHeight() : 0; + return ret; + } + public void paintComponent(Graphics g) { + shown = true; + super.paintComponent(g); + } + }; + client.setBackground(SystemColor.window); + client.setFocusable(true); + + // Initialize system registers + if (system) { + new Register(this, "PC" , VUE.PC , VUE.PC ); + new Register(this, "PSW" , VUE.PSW , VUE.PSW ); + new Register(this, "EIPC" , VUE.EIPC , Register.PLAIN); + new Register(this, "EIPSW", VUE.EIPSW, VUE.PSW ); + new Register(this, "FEPC" , VUE.FEPC , Register.PLAIN); + new Register(this, "FEPSW", VUE.FEPSW, VUE.PSW ); + new Register(this, "ECR" , VUE.ECR , VUE.ECR ); + new Register(this, "ADTRE", VUE.ADTRE, Register.PLAIN); + new Register(this, "CHCW" , VUE.CHCW , VUE.CHCW ); + new Register(this, "PIR" , VUE.PIR , VUE.PIR ); + new Register(this, "TKCW" , VUE.TKCW , VUE.TKCW ); + new Register(this, "29" , 29, Register.PLAIN); + new Register(this, "30" , 30, Register.PLAIN); + new Register(this, "31" , 31, Register.PLAIN); + } + + // Initialize program registers + else for (int x = 0; x < 32; x++) { + String name = null; + switch (x) { + case VUE.GP: name = "gp"; break; + case VUE.HP: name = "hp"; break; + case VUE.LP: name = "lp"; break; + case VUE.SP: name = "sp"; break; + case VUE.TP: name = "tp"; break; + } + new Register(this, name, x, Register.PROGRAM); + } + + // List terminator + var spacer = new JPanel(null); + spacer.setOpaque(false); + spacer.setPreferredSize(new Dimension(0, 0)); + var gbc = new GridBagConstraints(); + gbc.gridheight = GridBagConstraints.REMAINDER; + gbc.gridwidth = GridBagConstraints.REMAINDER; + gbc.weighty = 1; + client.add(spacer, gbc); + + // Configure component + shown = false; + setViewportView(client); + } + + + + /////////////////////////////////////////////////////////////////////////// + // Public Methods // + /////////////////////////////////////////////////////////////////////////// + + // Draw the component + public void paintComponent(Graphics g) { + if (!shown) { + shown = true; + revalidate(); + } + super.paintComponent(g); + } + + // Transfer focus to the client area + public void requestFocus() { + client.requestFocus(); + } + + // Recalculate layout + public void revalidate() { + if (client != null) + client.revalidate(); + super.revalidate(); + repaint(); + } + + + + /////////////////////////////////////////////////////////////////////////// + // Package Methods // + /////////////////////////////////////////////////////////////////////////// + + // Add a register component to the client area + void add(GridBagConstraints gbc, JComponent comp) { + client.add(comp, gbc); + } + + // Associate a register with its index + void add(int index, Register register) { + registers.put(index, register); + } + + // Apply configuration settings + void configure() { + + // Configure registers + for (var reg : registers.values()) + reg.configure(); + + // Configure component + getVerticalScrollBar().setUnitIncrement( + CPUWindow.regHexFontSize.height); + } + + // Update the display + void refresh() { + for (var reg : registers.values()) + reg.refresh(); + } + + + + /////////////////////////////////////////////////////////////////////////// + // Private Methods // + /////////////////////////////////////////////////////////////////////////// + + // Determine the initial height upon first show + private int getInitialHeight() { + int height = 0; + var layout = (GridBagLayout) client.getLayout(); + int ret = 0; + int row = 0; + + // Process controls until the target row is found + for (var control : client.getComponents()) { + var ctrl = (JComponent) control; + + // Track the tallest control on the row + if (ctrl.isVisible()) + height = Math.max(height, ctrl.getPreferredSize().height); + + // This is not the last control on the row + if (layout.getConstraints(control).gridwidth != + GridBagConstraints.REMAINDER) + continue; + + // Advance to the next row + ret += height; + height = 0; + row++; + + // The target row has been reached + if (row == 4) + break; + } + + return ret; + } + +} diff --git a/src/desktop/vue/Instruction.java b/src/desktop/vue/Instruction.java index b1461dd..e53a4bb 100644 --- a/src/desktop/vue/Instruction.java +++ b/src/desktop/vue/Instruction.java @@ -104,7 +104,6 @@ public class Instruction { // Decode by format switch (format) { - case 0: return; // Illegal opcode case 1: reg2 = bits >> 21 & 31; reg1 = bits >> 16 & 31; diff --git a/src/desktop/vue/JavaVUE.java b/src/desktop/vue/JavaVUE.java index 995f41b..a28b21e 100644 --- a/src/desktop/vue/JavaVUE.java +++ b/src/desktop/vue/JavaVUE.java @@ -3,6 +3,9 @@ package vue; // Java emulation core implementation class JavaVUE extends VUE { + // Instance fields + Instruction inst; // Instruction state + // Components Bus bus; // Memory bus CPU cpu; // Processor @@ -24,8 +27,9 @@ class JavaVUE extends VUE { // Default constructor JavaVUE() { - bus = new Bus(this); - cpu = new CPU(this); + bus = new Bus(this); + cpu = new CPU(this); + inst = new Instruction(); reset(); }