Implementing disassembler back-end, yet more adjustments to CPU window

This commit is contained in:
Guy Perfect 2020-08-08 18:40:22 -05:00
parent b7c2545ea7
commit 76c95b0523
14 changed files with 952 additions and 431 deletions

View File

@ -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 This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages

View File

@ -79,7 +79,6 @@ static void cpuDecode(VUE_INST *inst, int32_t bits) {
/* Decode by format */ /* Decode by format */
switch (inst->format) { switch (inst->format) {
case 0: return; /* Illegal opcode */
case 1: case 1:
inst->reg2 = bits >> 21 & 31; inst->reg2 = bits >> 21 & 31;
inst->reg1 = bits >> 16 & 31; inst->reg1 = bits >> 16 & 31;

View File

@ -159,6 +159,7 @@ typedef struct {
/* Emulation state */ /* Emulation state */
typedef struct { typedef struct {
VUE_INST inst; /* Instruction state */
/* Memory bus */ /* Memory bus */
struct { struct {
@ -221,8 +222,6 @@ typedef struct {
uint16_t ecr_fecc; /* Fatal Error Cause Code */ uint16_t ecr_fecc; /* Fatal Error Cause Code */
} cpu; } cpu;
/* Additional fields */
VUE_INST inst; /* Instruction state */
} VUE; } VUE;

View File

@ -11,7 +11,7 @@ import vue.*;
public class App { public class App {
// Instance fields // Instance fields
private boolean useNative; // Produce native core contexts private boolean useNative; // Produce native core contexts
private Localizer.Locale[] locales; // Language translations private Localizer.Locale[] locales; // Language translations
private ArrayList<MainWindow> windows; // Application windows private ArrayList<MainWindow> windows; // Application windows

View File

@ -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<Register> 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<Register>();
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;
}
}

View File

@ -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<CPUWindow> instances; // Spawned instances
// Static initializer
static {
setDefaults();
instances = new HashSet<CPUWindow>();
}
///////////////////////////////////////////////////////////////////////////
// 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);
}
}

View File

@ -5,7 +5,7 @@ import java.awt.*;
import javax.swing.*; import javax.swing.*;
// Console window // Console window
class Console extends ChildWindow { class ConsoleWindow extends ChildWindow {
// Instance fields // Instance fields
private boolean shown; // Component has been visible private boolean shown; // Component has been visible
@ -17,7 +17,7 @@ class Console extends ChildWindow {
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// Default constructor // Default constructor
Console(MainWindow parent) { ConsoleWindow(MainWindow parent) {
super(parent, "console.title"); super(parent, "console.title");
getContentPane().setPreferredSize(new Dimension(384, 224)); getContentPane().setPreferredSize(new Dimension(384, 224));
pack(); pack();

View File

@ -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" : ""
);
}
}

View File

@ -27,13 +27,13 @@ class MainWindow extends JFrame {
private File romFile; // Currently loaded ROM file private File romFile; // Currently loaded ROM file
// UI components // UI components
private JPanel client; // Common client container private JPanel client; // Common client container
private Console console; // Console window private ConsoleWindow console; // Console window
private CPU cpu; // CPU window private CPUWindow cpu; // CPU window
private JDesktopPane desktop; // Container for child windows private JDesktopPane desktop; // Container for child windows
private Memory memory; // Memory window private MemoryWindow memory; // Memory window
private JPanel video; // Video output private JMenu mnuDebug; // Debug menu
private JMenu mnuDebug; // Debug menu private JPanel video; // Video output
private JMenuItem mnuFileDebugMode; // File -> Debug mode private JMenuItem mnuFileDebugMode; // File -> Debug mode
private JMenuItem mnuFileGameMode; // File -> Game mode private JMenuItem mnuFileGameMode; // File -> Game mode
@ -92,9 +92,9 @@ class MainWindow extends JFrame {
// Configure child windows // Configure child windows
desktop = new JDesktopPane(); desktop = new JDesktopPane();
desktop.setBackground(SystemColor.controlShadow); desktop.setBackground(SystemColor.controlShadow);
desktop.add(console = new Console(this)); desktop.add(console = new ConsoleWindow(this));
desktop.add(cpu = new CPU (this)); desktop.add(cpu = new CPUWindow (this));
desktop.add(memory = new Memory (this)); desktop.add(memory = new MemoryWindow (this));
// Display window // Display window
refreshDebug(); refreshDebug();
@ -207,6 +207,7 @@ class MainWindow extends JFrame {
// Window close, File -> Exit // Window close, File -> Exit
private void onClose() { private void onClose() {
app.removeWindow(this); app.removeWindow(this);
cpu.dispose();
dispose(); dispose();
vue.dispose(); vue.dispose();
} }

View File

@ -10,7 +10,7 @@ import javax.swing.*;
import util.*; import util.*;
// Memory viewer and hex editor window // Memory viewer and hex editor window
class Memory extends ChildWindow { class MemoryWindow extends ChildWindow {
// Private fields // Private fields
private int address; // Address of top row private int address; // Address of top row
@ -41,7 +41,7 @@ class Memory extends ChildWindow {
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// Default constructor // Default constructor
Memory(MainWindow parent) { MemoryWindow(MainWindow parent) {
super(parent, "memory.title"); super(parent, "memory.title");
// Configure instance fields // Configure instance fields

View File

@ -14,26 +14,22 @@ import vue.*;
class Register { class Register {
// Instance fields // Instance fields
boolean expandable; // The expansion area can be shown private boolean expandable; // The expansion area can be shown
boolean expanded; // The expanded area is being shown private boolean expanded; // The expanded area is being shown
Font font; // Hexadecimal font private int index; // Register index
int index; // Register index private int mode; // Display mode for program registers
int mode; // Display mode for program registers private String name; // Register name
MainWindow parent; // Containing window private RegisterList parent; // Containing register list
int type; // Expansion controls type private int type; // Expansion controls type
int value; // Current register value private int value; // Current register value
// UI components // UI components
private JPanel expansion; // Expansion area JPanel expansion; // Expansion container
private JLabel btnExpand; // Expand button JLabel btnExpand; // Expand button
private JLabel lblLastPC; // Last PC name JPanel indent; // Expansion area indentation
private JLabel lblName; // Register name JLabel lblName; // Register name
private JPanel list; // Containing element JTextField txtValue; // Register value
private JPanel spacer; // Expansion area spacer ArrayList<JComponent> controls; // Expansion controls
private JTextField txtJumpFrom; // Jump-from value
private JTextField txtJumpTo; // Jump-to value
private JTextField txtValue; // Register value
private ArrayList<JComponent> controls; // Expansion controls
@ -48,8 +44,8 @@ class Register {
static final int UNSIGNED = 2; static final int UNSIGNED = 2;
// Types // Types
static final int PLAIN = -1; static final int PLAIN = -2;
static final int PROGRAM = -2; static final int PROGRAM = -3;
@ -58,20 +54,21 @@ class Register {
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// Default constructor // 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 // Configure instance fields
controls = new ArrayList<JComponent>(); controls = new ArrayList<JComponent>();
expandable = type != PLAIN && index != 0 || index == VUE.PC; expandable = type != PLAIN && index != 0;
this.index = index; this.index = index;
this.list = list; mode = HEX;
this.mode = HEX; this.name = name;
this.parent = parent; this.parent = parent;
this.type = type; this.type = type;
// Click handler for expand and name controls // Click handler for expand and name controls
MouseListener expand = !expandable ? null : Util.onMouse(e->{ MouseListener expand = !expandable ? null : Util.onMouse(e->{
if (e.getButton() == 1) setExpanded(!expanded); }, null); if (e.getButton() == 1) setExpanded(!expanded); }, null);
// Expand button // Expand button
btnExpand = new JLabel(expandable ? "+" : " "); btnExpand = new JLabel(expandable ? "+" : " ");
@ -81,17 +78,17 @@ class Register {
var gbc = new GridBagConstraints(); var gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.NORTH; gbc.anchor = GridBagConstraints.NORTH;
gbc.fill = GridBagConstraints.HORIZONTAL; gbc.fill = GridBagConstraints.HORIZONTAL;
list.add(btnExpand, gbc); parent.add(gbc, btnExpand);
// Name label // Name label
lblName = new JLabel(name); lblName = new JLabel(" ");
if (expandable) if (expandable)
lblName.addMouseListener(expand); lblName.addMouseListener(expand);
gbc = new GridBagConstraints(); gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.NORTH; gbc.anchor = GridBagConstraints.NORTH;
gbc.fill = GridBagConstraints.HORIZONTAL; gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1; gbc.weightx = 1;
list.add(lblName, gbc); parent.add(gbc, lblName);
// Value text box // Value text box
txtValue = new JTextField(); txtValue = new JTextField();
@ -101,7 +98,7 @@ class Register {
gbc = new GridBagConstraints(); gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.insets = new Insets(0, 4, 0, 0); gbc.insets = new Insets(0, 4, 0, 0);
list.add(txtValue, gbc); parent.add(gbc, txtValue);
// Value changed // Value changed
txtValue.addActionListener(e->{ txtValue.addActionListener(e->{
@ -129,14 +126,14 @@ class Register {
default: return; default: return;
} }
// Expansion spacer // Expansion indentation
if (index != VUE.PC) { if (index != VUE.PC) {
spacer = new JPanel(null); indent = new JPanel(null);
spacer.setOpaque(false); indent.setOpaque(false);
spacer.setPreferredSize(new Dimension(0, 0)); indent.setPreferredSize(new Dimension(0, 0));
spacer.setVisible(false); indent.setVisible(false);
gbc = new GridBagConstraints(); gbc = new GridBagConstraints();
list.add(spacer, gbc); parent.add(gbc, indent);
} }
// Expansion area // Expansion area
@ -149,7 +146,11 @@ class Register {
gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.insets = new Insets(0, 4, 0, 0); gbc.insets = new Insets(0, 4, 0, 0);
gbc.weightx = 1; 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 // Expansion controls for CHCW
private void initCHCW() { private void initCHCW() {
expansion = new JPanel(new GridBagLayout()); expansion = new JPanel(new GridBagLayout());
addCheckBox("ICE", 1, false); endRow(); addCheckBox("ICE", 1, false, true);
} }
// Expansion controls for ECR // Expansion controls for ECR
private void initECR() { private void initECR() {
expansion = new JPanel(new GridBagLayout()); expansion = new JPanel(new GridBagLayout());
addTextBox("EICC", 0, 16, false, true); endRow(); addTextBox("EICC", 0, 16, false, true);
addTextBox("FECC", 16, 16, false, true); endRow(); addTextBox("FECC", 16, 16, false, true);
} }
// Expansion controls for program registers // Expansion controls for program registers
@ -189,38 +190,37 @@ class Register {
for (int x = 0; x < 2; x++) { for (int x = 0; x < 2; x++) {
// Indentation // Indentation
var spacer = new JPanel(null); indent = new JPanel(null);
spacer.setOpaque(false); indent.setOpaque(false);
spacer.setPreferredSize(new Dimension(0, 0)); indent.setPreferredSize(new Dimension(0, 0));
var gbc = new GridBagConstraints(); var gbc = new GridBagConstraints();
gbc.weightx = 1; gbc.weightx = 1;
expansion.add(spacer, gbc); expansion.add(indent, gbc);
// Name label // Name label
var label = new JLabel(); var label = new JLabel();
parent.app.localizer.add(label, parent.parent.parent.app.localizer.add(label,
x == 0 ? "cpu.jump_from" : "cpu.jump_to" ); x == 0 ? "cpu.jump_from" : "cpu.jump_to" );
gbc = new GridBagConstraints(); gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.NORTHWEST; gbc.anchor = GridBagConstraints.NORTHWEST;
expansion.add(label, gbc); expansion.add(label, gbc);
controls.add(label);
// Value text box // Value text box
var txt = new JTextField(); var txt = new JTextField();
txt.addActionListener(e->{ txt.addActionListener(e->{
txt.setText((String) txt.getClientProperty("text")); 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.setBorder(null);
txt.setOpaque(false); txt.setOpaque(false);
gbc = new GridBagConstraints(); gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.insets = new Insets(0, 4, 0, 0); gbc.insets = new Insets(0, 4, 0, 0);
expansion.add(txt, gbc); expansion.add(txt, gbc);
controls.add(txt);
// Initialize the corresponding component field
if (x == 0)
txtJumpFrom = txt;
else txtJumpTo = txt;
} }
} }
@ -228,40 +228,40 @@ class Register {
// Expansion controls for PSW // Expansion controls for PSW
private void initPSW() { private void initPSW() {
expansion = new JPanel(new GridBagLayout()); expansion = new JPanel(new GridBagLayout());
addCheckBox("Z" , 0, false); addCheckBox("Z" , 0, false, false);
addCheckBox("FRO", 9, false); endRow(); addCheckBox("FRO", 9, false, true );
addCheckBox("S" , 1, false); addCheckBox("S" , 1, false, false);
addCheckBox("FIV", 8, false); endRow(); addCheckBox("FIV", 8, false, true );
addCheckBox("OV" , 2, false); addCheckBox("OV" , 2, false, false);
addCheckBox("FZD", 7, false); endRow(); addCheckBox("FZD", 7, false, true );
addCheckBox("CY" , 3, false); addCheckBox("CY" , 3, false, false);
addCheckBox("FOV", 6, false); endRow(); addCheckBox("FOV", 6, false, true );
addCheckBox("EP" , 14, false); addCheckBox("EP" , 14, false, false);
addCheckBox("FUD", 5, false); endRow(); addCheckBox("FUD", 5, false, true );
addCheckBox("NP" , 15, false); addCheckBox("NP" , 15, false, false);
addCheckBox("FPR", 4, false); endRow(); addCheckBox("FPR", 4, false, true );
addCheckBox("AE" , 13, false); endRow(); addCheckBox("AE" , 13, false, true );
addCheckBox("ID" , 12, false); addCheckBox("ID" , 12, false, false);
addTextBox ("I" , 16, 4, false, false); endRow(); addTextBox ("I" , 16, 4, false, false);
} }
// Expansion controls for PIR // Expansion controls for PIR
private void initPIR() { private void initPIR() {
expansion = new JPanel(new GridBagLayout()); expansion = new JPanel(new GridBagLayout());
addTextBox("PT", 0, 16, true, true); endRow(); addTextBox("PT", 0, 16, true, true);
} }
// Expansion controls for TKCW // Expansion controls for TKCW
private void initTKCW() { private void initTKCW() {
expansion = new JPanel(new GridBagLayout()); expansion = new JPanel(new GridBagLayout());
addCheckBox("OTM", 8, true); addCheckBox("OTM", 8, true, false);
addCheckBox("FVT", 5, true); endRow(); addCheckBox("FVT", 5, true, true );
addCheckBox("FIT", 7, true); addCheckBox("FIT", 7, true, false);
addCheckBox("FUT", 4, true); endRow(); addCheckBox("FUT", 4, true, true );
addCheckBox("FZT", 6, true); addCheckBox("FZT", 6, true, false);
addCheckBox("FPT", 3, true); endRow(); addCheckBox("FPT", 3, true, true );
addCheckBox("RDI", 2, true); addCheckBox("RDI", 2, true, false);
addTextBox ("RD", 0, 2, true, false); endRow(); addTextBox ("RD", 0, 2, true, false);
} }
@ -270,11 +270,61 @@ class Register {
// Package Methods // // Package Methods //
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// Refresh controls // Apply configuration settings
void refresh() { 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 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( txtValue.setText(
type != PROGRAM || mode == HEX ? type != PROGRAM || mode == HEX ?
String.format("%08X", value) : String.format("%08X", value) :
@ -283,18 +333,8 @@ class Register {
Float.toString(Float.intBitsToFloat(value)) Float.toString(Float.intBitsToFloat(value))
); );
// PC expansion controls // Expansion controls
if (index == VUE.PC) for (int x = 0; x < 2; x++) { for (var control : controls) {
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) {
// Check box // Check box
if (control instanceof JCheckBox) { if (control instanceof JCheckBox) {
@ -306,13 +346,32 @@ class Register {
// Text box // Text box
if (control instanceof JTextField) { if (control instanceof JTextField) {
var ctrl = (JTextField) control; var ctrl = (JTextField) control;
int bit = (Integer) ctrl.getClientProperty("bit" ); int digits; // Maximum digits that can be displayed
int digits = (Integer) ctrl.getClientProperty("digits"); boolean hex; // The value is hexadecimal
boolean hex = (Boolean) ctrl.getClientProperty("hex"); int val; // The value to be displayed
int width = (Integer) ctrl.getClientProperty("width");
int val = value >> bit & (1 << width) - 1; // Jump history
ctrl.setText(!hex ? Integer.toString(val) : if (type == VUE.PC) {
String.format("%0" + digits + "X", val)); 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 // Update controls
this.expanded = expanded; this.expanded = expanded;
btnExpand.setText(expanded ? "-" : "+"); btnExpand.setText(expanded ? "-" : "+");
if (index != VUE.PC) if (type != VUE.PC)
spacer.setVisible(expanded); indent.setVisible(expanded);
expansion.setVisible(expanded); expansion.setVisible(expanded);
list.revalidate(); parent.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);
}
} }
// Change the display mode of a program register // Change the display mode of a program register
void setMode(int mode) { void setMode(int mode) {
this.mode = mode; this.mode = mode;
txtValue.setFont(mode == HEX ? font : null); txtValue.setFont(mode == HEX ? CPUWindow.regHexFont : null);
refresh(); refresh();
} }
@ -385,7 +408,8 @@ class Register {
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// Add a check box to the expansion area // 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; int mask = 1 << bit;
// Configure control // Configure control
@ -406,7 +430,7 @@ class Register {
// Configure expansion area // Configure expansion area
var gbc = new GridBagConstraints(); var gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.NORTHWEST; gbc.anchor = GridBagConstraints.NORTHWEST;
gbc.gridwidth = 2; gbc.gridwidth = last ? GridBagConstraints.REMAINDER : 2;
gbc.insets = new Insets(0, 4, 0, 4); gbc.insets = new Insets(0, 4, 0, 4);
expansion.add(ctrl, gbc); expansion.add(ctrl, gbc);
} }
@ -416,7 +440,7 @@ class Register {
// Configure control // Configure control
var ctrl = new JRadioButton(); var ctrl = new JRadioButton();
parent.app.localizer.add(ctrl, key); parent.parent.parent.app.localizer.add(ctrl, key);
ctrl.setBorder(null); ctrl.setBorder(null);
ctrl.setFocusable(false); ctrl.setFocusable(false);
ctrl.setOpaque(false); ctrl.setOpaque(false);
@ -465,27 +489,20 @@ class Register {
// Configure expansion area // Configure expansion area
var label = new JLabel(name); var label = new JLabel(name);
label.setEnabled(!readOnly); label.setEnabled(!readOnly);
var gbc = new GridBagConstraints(); var gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.NORTHWEST; gbc.anchor = GridBagConstraints.NORTHWEST;
gbc.insets = new Insets(0, 4, 0, 4); gbc.insets = new Insets(0, 4, 0, 4);
expansion.add(label, gbc); expansion.add(label, gbc);
expansion.add(ctrl , gbc); gbc = new GridBagConstraints();
}
// 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.gridwidth = GridBagConstraints.REMAINDER; gbc.gridwidth = GridBagConstraints.REMAINDER;
expansion.add(spacer, gbc); gbc.insets = new Insets(0, 4, 0, 4);
expansion.add(ctrl , gbc);
} }
// Update the register value // Update the register value
private void setValue(int value) { private void setValue(int value) {
list.requestFocus(); parent.requestFocus();
parent.vue.setRegister(index, type != PROGRAM, value); parent.parent.parent.vue.setRegister(index, type != PROGRAM, value);
refresh(); refresh();
} }

View File

@ -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<Integer, Register> 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<Integer, Register>();
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;
}
}

View File

@ -104,7 +104,6 @@ public class Instruction {
// Decode by format // Decode by format
switch (format) { switch (format) {
case 0: return; // Illegal opcode
case 1: case 1:
reg2 = bits >> 21 & 31; reg2 = bits >> 21 & 31;
reg1 = bits >> 16 & 31; reg1 = bits >> 16 & 31;

View File

@ -3,6 +3,9 @@ package vue;
// Java emulation core implementation // Java emulation core implementation
class JavaVUE extends VUE { class JavaVUE extends VUE {
// Instance fields
Instruction inst; // Instruction state
// Components // Components
Bus bus; // Memory bus Bus bus; // Memory bus
CPU cpu; // Processor CPU cpu; // Processor
@ -24,8 +27,9 @@ class JavaVUE extends VUE {
// Default constructor // Default constructor
JavaVUE() { JavaVUE() {
bus = new Bus(this); bus = new Bus(this);
cpu = new CPU(this); cpu = new CPU(this);
inst = new Instruction();
reset(); reset();
} }