Implementing disassembler back-end, yet more adjustments to CPU window
This commit is contained in:
parent
b7c2545ea7
commit
76c95b0523
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
@ -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<MainWindow> windows; // Application windows
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -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();
|
|
@ -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" : ""
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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<JComponent> 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<JComponent> 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<JComponent>();
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue