Precursor to VIP introduction
This commit is contained in:
parent
d636719775
commit
9f5a5233ea
|
@ -135,7 +135,7 @@
|
||||||
border-width: 0 1px 1px 0;
|
border-width: 0 1px 1px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bordered tr > :first-child {
|
.bordered tr > :first-child, .op1 {
|
||||||
padding: 1px 12px 1px 12px;
|
padding: 1px 12px 1px 12px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
@ -245,12 +245,12 @@
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Floats, like words, are represented as sequences of character digits. They
|
Floats, like words, are represented as sequences of character digits. They
|
||||||
are differentiated from words by the presence of a dot <code>.</code>
|
are distinguished from words by the presence of a dot <code>.</code>
|
||||||
character somewhere within the sequence. Only one dot may be present in a
|
character somewhere within the sequence. Only one dot may be present in a
|
||||||
float literal, and dots cannot be used in hexadecimal literals. If the given
|
float literal, and dots cannot be used in hexadecimal literals. If the given
|
||||||
value cannot be represented in the float data type, a parsing error occurs.
|
value cannot be represented in the float data type, a parsing error occurs.
|
||||||
Float values in the expression evaluator are subjected to the same
|
Float values in the expression evaluator are subjected to the following
|
||||||
restrictions as on the Virtual Boy's CPU: if the result of any float
|
restrictions: if the value of any float literal or the result of any float
|
||||||
operation is NaN, an infinity, a denormal number or negative zero, it will be
|
operation is NaN, an infinity, a denormal number or negative zero, it will be
|
||||||
changed to positive zero.
|
changed to positive zero.
|
||||||
</p>
|
</p>
|
||||||
|
@ -259,7 +259,7 @@
|
||||||
slightly different. When used in a numeric operation, a boolean will use the
|
slightly different. When used in a numeric operation, a boolean will use the
|
||||||
value <code>0</code> if false or the value <code>1</code> if true. Boolean
|
value <code>0</code> if false or the value <code>1</code> if true. Boolean
|
||||||
literals are specified with the named values <code>true</code> and
|
literals are specified with the named values <code>true</code> and
|
||||||
<code>false</code> within the expression. In a boolean operation, any result
|
<code>false</code> within the expression. In a boolean operation, any value
|
||||||
that is zero is considered false, and any non-zero value is considered true.
|
that is zero is considered false, and any non-zero value is considered true.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
|
@ -298,13 +298,13 @@
|
||||||
<td class="mono">disp</td>
|
<td class="mono">disp</td>
|
||||||
<td>Displacement offset for jumps and memory accesses.</td>
|
<td>Displacement offset for jumps and memory accesses.</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<!--tr>
|
||||||
<td class="mono">fetch</td>
|
<td class="mono">fetch</td>
|
||||||
<td>
|
<td>
|
||||||
Data unit index during a fetch operation, or <code>-1</code> if the read
|
Data unit index during a fetch operation, or <code>-1</code> if the read
|
||||||
operation is not a fetch.
|
operation is not a fetch.
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr-->
|
||||||
<tr>
|
<tr>
|
||||||
<td class="mono">format</td>
|
<td class="mono">format</td>
|
||||||
<td>Current instruction's encoding format.</td>
|
<td>Current instruction's encoding format.</td>
|
||||||
|
@ -354,7 +354,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="mono">value</td>
|
<td class="mono">value</td>
|
||||||
<td>Value read by the current memory access.</td>
|
<td>Value read or to be written by the current memory access.</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="mono">vector</td>
|
<td class="mono">vector</td>
|
||||||
|
@ -434,15 +434,14 @@
|
||||||
<p>
|
<p>
|
||||||
Operators may apply to one (unary) or two (binary) values. All unary
|
Operators may apply to one (unary) or two (binary) values. All unary
|
||||||
operators appear to the left of the value they modify (or another unary
|
operators appear to the left of the value they modify (or another unary
|
||||||
operator). Binary operators appear between the values they modify. Each
|
operator). Binary operators appear between the values they modify.
|
||||||
operator considers the types of its operands in order to produce a new value
|
|
||||||
of the appropriate type.
|
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
If the operands of a binary operator have different types, one of the values
|
Each operator considers the types of its operands in order to produce a new
|
||||||
will be converted to the other type before performing the operation. The
|
value of the appropriate type. If the operands of a binary operator have
|
||||||
conversion depends on the "greater" of the two types, in the following order
|
different types, one of the values will be converted to the other type before
|
||||||
(higher is "greater"):
|
performing the operation. The conversion selects the "greater" of the two
|
||||||
|
types, in the following order (higher is "greater"):
|
||||||
</p>
|
</p>
|
||||||
<table class="indent">
|
<table class="indent">
|
||||||
<tr><td class="center narrow">↑</td><td>Float</td></tr>
|
<tr><td class="center narrow">↑</td><td>Float</td></tr>
|
||||||
|
@ -452,7 +451,7 @@
|
||||||
</table>
|
</table>
|
||||||
<p>
|
<p>
|
||||||
For example, if an operation contains both a signed word and a float, the
|
For example, if an operation contains both a signed word and a float, the
|
||||||
signed word value is first converted to float.
|
signed word value is converted to float before performing the operation.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Operators have assigned precedence that specifies the order of operations.
|
Operators have assigned precedence that specifies the order of operations.
|
||||||
|
@ -467,12 +466,14 @@
|
||||||
<p>
|
<p>
|
||||||
The following operators may be used in expressions. Groups listed higher have
|
The following operators may be used in expressions. Groups listed higher have
|
||||||
higher precedence and happen before groups listed lower. Operators within
|
higher precedence and happen before groups listed lower. Operators within
|
||||||
groups have the same precedence and are processed in the order they appear in
|
groups have the same precedence and are processed according to the order in
|
||||||
the expression from left to right.
|
which they appear in the expression: right-to-left for unary operators,
|
||||||
|
left-to-right for binary operators.
|
||||||
</p>
|
</p>
|
||||||
<table class="indent bordered">
|
<table class="indent bordered">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="mono open">~</td>
|
<td rowSpan="18" class="middle">Unary</td>
|
||||||
|
<td class="mono open op1">~</td>
|
||||||
<td class="open">Not Bitwise</td>
|
<td class="open">Not Bitwise</td>
|
||||||
<td class="open">Cannot be used with a float value.</td>
|
<td class="open">Cannot be used with a float value.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -562,7 +563,8 @@
|
||||||
<td>The binary value is not modified.</td>
|
<td>The binary value is not modified.</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="mono open">/</td>
|
<td rowSpan="20" class="middle">Binary</td>
|
||||||
|
<td class="mono open op1">/</td>
|
||||||
<td class="open">Divide</td>
|
<td class="open">Divide</td>
|
||||||
<td class="open">Zero divisor yields zero as result.</td>
|
<td class="open">Zero divisor yields zero as result.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -589,17 +591,17 @@
|
||||||
<tr>
|
<tr>
|
||||||
<td class="mono open"><<</td>
|
<td class="mono open"><<</td>
|
||||||
<td class="open">Shift Left</td>
|
<td class="open">Shift Left</td>
|
||||||
<td class="open">Cannot be used with a float value.</td>
|
<td class="open">Cannot be used with float values.</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="mono open">>></td>
|
<td class="mono open">>></td>
|
||||||
<td class="open">Shift Right Arithmetic</td>
|
<td class="open">Shift Right Arithmetic</td>
|
||||||
<td class="open">Cannot be used with a float value.</td>
|
<td class="open">Cannot be used with float values.</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="mono">>>></td>
|
<td class="mono">>>></td>
|
||||||
<td>Shift Right Logical</td>
|
<td>Shift Right Logical</td>
|
||||||
<td>Cannot be used with a float value.</td>
|
<td>Cannot be used with float values.</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="mono open">></td>
|
<td class="mono open">></td>
|
||||||
|
@ -634,17 +636,17 @@
|
||||||
<tr>
|
<tr>
|
||||||
<td class="mono">&</td>
|
<td class="mono">&</td>
|
||||||
<td>And Bitwise</td>
|
<td>And Bitwise</td>
|
||||||
<td>Cannot be used with a float value.</td>
|
<td>Cannot be used with float values.</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="mono">^</td>
|
<td class="mono">^</td>
|
||||||
<td>Exclusive Or Bitwise</td>
|
<td>Exclusive Or Bitwise</td>
|
||||||
<td>Cannot be used with a float value.</td>
|
<td>Cannot be used with float values.</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="mono">|</td>
|
<td class="mono">|</td>
|
||||||
<td>Or Bitwise</td>
|
<td>Or Bitwise</td>
|
||||||
<td>Cannot be used with a float value.</td>
|
<td>Cannot be used with float values.</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="mono">&&</td>
|
<td class="mono">&&</td>
|
||||||
|
@ -691,6 +693,13 @@
|
||||||
<td>Performs a halfword read of the specified signedness.</td>
|
<td>Performs a halfword read of the specified signedness.</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
<p>
|
||||||
|
Reads are subjected to the alginment restrictions of the Virtual Boy's CPU:
|
||||||
|
the lowest bit of the address is ignored for halfword reads, and the lowest
|
||||||
|
two bits of the address are ignored for word reads.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h1> </h1>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -68,11 +68,33 @@ breakpoints {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Characters window
|
||||||
|
characters {
|
||||||
|
address Address
|
||||||
|
grid Grid
|
||||||
|
index Index
|
||||||
|
mirror Mirror
|
||||||
|
Palette Palette
|
||||||
|
scale Scale
|
||||||
|
title Characters
|
||||||
|
wide Wide
|
||||||
|
}
|
||||||
|
|
||||||
# Console window
|
# Console window
|
||||||
console {
|
console {
|
||||||
title Console
|
title Console
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Emulation core
|
||||||
|
core {
|
||||||
|
java Java
|
||||||
|
linux-x86 Linux (32-bit)
|
||||||
|
linux-x86_64 Linux (64-bit)
|
||||||
|
native Native
|
||||||
|
windows-x86 Windows (32-bit)
|
||||||
|
windows-x86_64 Windows (64-bit)
|
||||||
|
}
|
||||||
|
|
||||||
# CPU window
|
# CPU window
|
||||||
cpu {
|
cpu {
|
||||||
float Float
|
float Float
|
||||||
|
@ -84,21 +106,6 @@ cpu {
|
||||||
unsigned Unsigned
|
unsigned Unsigned
|
||||||
}
|
}
|
||||||
|
|
||||||
# Memory window
|
|
||||||
memory {
|
|
||||||
title Memory
|
|
||||||
}
|
|
||||||
|
|
||||||
# Emulation core
|
|
||||||
core {
|
|
||||||
java Java
|
|
||||||
linux-x86 Linux (32-bit)
|
|
||||||
linux-x86_64 Linux (64-bit)
|
|
||||||
native Native
|
|
||||||
windows-x86 Windows (32-bit)
|
|
||||||
windows-x86_64 Windows (64-bit)
|
|
||||||
}
|
|
||||||
|
|
||||||
# File dialog
|
# File dialog
|
||||||
dialog {
|
dialog {
|
||||||
ext_isx ISX modules (*.isx)
|
ext_isx ISX modules (*.isx)
|
||||||
|
@ -108,3 +115,21 @@ dialog {
|
||||||
load_rom_error Unable to load the selected ROM file.
|
load_rom_error Unable to load the selected ROM file.
|
||||||
load_rom_notvb The selected file does not appear to be a Virtual Boy ROM.
|
load_rom_notvb The selected file does not appear to be a Virtual Boy ROM.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Memory window
|
||||||
|
memory {
|
||||||
|
title Memory
|
||||||
|
}
|
||||||
|
|
||||||
|
# Palettes
|
||||||
|
palette {
|
||||||
|
Generic Generic
|
||||||
|
gplt0 BG 0
|
||||||
|
gplt1 BG 1
|
||||||
|
gplt2 BG 2
|
||||||
|
gplt3 BG 3
|
||||||
|
jplt0 OBJ 0
|
||||||
|
jplt1 OBJ 1
|
||||||
|
jplt2 OBJ 2
|
||||||
|
jplt3 OBJ 3
|
||||||
|
}
|
||||||
|
|
|
@ -1164,7 +1164,7 @@ static vbool cpuFetch(Vue *vue) {
|
||||||
/* First unit */
|
/* First unit */
|
||||||
if (vue->cpu.fetch == 0) {
|
if (vue->cpu.fetch == 0) {
|
||||||
vue->cpu.inst.bits = vue->cpu.access.value << 16;
|
vue->cpu.inst.bits = vue->cpu.access.value << 16;
|
||||||
if (cpuSize(vue->cpu.access.value >> 10 & 0x3F) == 4) {
|
if (cpuSize(vue->cpu.access.value >> 10) == 4) {
|
||||||
vue->cpu.fetch = 1;
|
vue->cpu.fetch = 1;
|
||||||
return VUE_FALSE;
|
return VUE_FALSE;
|
||||||
}
|
}
|
||||||
|
@ -1172,7 +1172,7 @@ static vbool cpuFetch(Vue *vue) {
|
||||||
|
|
||||||
/* Second unit */
|
/* Second unit */
|
||||||
else {
|
else {
|
||||||
vue->cpu.inst.bits |= vue->cpu.access.value & 0xFFFF;
|
vue->cpu.inst.bits |= vue->cpu.access.value;
|
||||||
vue->cpu.fetch = -1;
|
vue->cpu.fetch = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
package app;
|
package app;
|
||||||
|
|
||||||
// Java imports
|
// Java imports
|
||||||
|
import java.awt.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import javax.swing.*;
|
||||||
|
|
||||||
// Project imports
|
// Project imports
|
||||||
import util.*;
|
import util.*;
|
||||||
|
@ -16,7 +18,28 @@ public class App {
|
||||||
private ArrayList<MainWindow> windows; // Application windows
|
private ArrayList<MainWindow> windows; // Application windows
|
||||||
|
|
||||||
// Configuration fields
|
// Configuration fields
|
||||||
Localizer localizer; // UI localization manager
|
Util.Font fntDialog; // Dialog font
|
||||||
|
Util.Font fntMono; // Monospaced font
|
||||||
|
int hexDigitWidth; // Width in pixels of one hex digit
|
||||||
|
Localizer localizer; // UI localization manager
|
||||||
|
int[][] rgbBase; // Base anaglyph filter colors
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constants //
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Anaglyph presets
|
||||||
|
static final int[] RED = { 0xFF, 0x00, 0x00 };
|
||||||
|
static final int[] CYAN = { 0x00, 0xC6, 0xF0 };
|
||||||
|
static final int[] GREEN = { 0x00, 0xB4, 0x00 };
|
||||||
|
static final int[] MAGENTA = { 0xC8, 0x00, 0xFF };
|
||||||
|
|
||||||
|
// Eyes
|
||||||
|
static final int LEFT = 0;
|
||||||
|
static final int RIGHT = 1;
|
||||||
|
static final int CHR = 2;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,10 +50,17 @@ public class App {
|
||||||
// Default constructor
|
// Default constructor
|
||||||
public App(boolean useNative) {
|
public App(boolean useNative) {
|
||||||
|
|
||||||
// Instance fields
|
// Configure instance fields
|
||||||
localizer = new Localizer();
|
localizer = new Localizer();
|
||||||
windows = new ArrayList<MainWindow>();
|
windows = new ArrayList<MainWindow>();
|
||||||
|
|
||||||
|
// Configure config fields
|
||||||
|
fntDialog = new Util.Font(new JLabel().getFont());
|
||||||
|
fntMono = new Util.Font(new Font(Util.fontFamily(new String[]
|
||||||
|
{ "Consolas", Font.MONOSPACED } ), Font.PLAIN, 14));
|
||||||
|
hexDigitWidth = hexDigitWidth();
|
||||||
|
rgbBase = new int[][] { GREEN, MAGENTA, RED };
|
||||||
|
|
||||||
// Additional processing
|
// Additional processing
|
||||||
setUseNative(useNative);
|
setUseNative(useNative);
|
||||||
initLocales();
|
initLocales();
|
||||||
|
@ -83,6 +113,14 @@ public class App {
|
||||||
// Private Methods //
|
// Private Methods //
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Calculate the maximum hexadecimal digit width
|
||||||
|
private int hexDigitWidth() {
|
||||||
|
int width = 0;
|
||||||
|
for (var digit : "0123456789ABCDEFabcdef".toCharArray())
|
||||||
|
width = Math.max(width, fntMono.metrics.charWidth(digit));
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
// Load and parse all locale translations
|
// Load and parse all locale translations
|
||||||
private void initLocales() {
|
private void initLocales() {
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,6 @@ import vue.*;
|
||||||
class BreakpointsWindow extends ChildWindow {
|
class BreakpointsWindow extends ChildWindow {
|
||||||
|
|
||||||
// Private fields
|
// Private fields
|
||||||
private Font font; // Display font
|
|
||||||
private ArrayList<Item> items; // List items
|
private ArrayList<Item> items; // List items
|
||||||
private int selectedIndex; // Selected list item
|
private int selectedIndex; // Selected list item
|
||||||
|
|
||||||
|
@ -133,7 +132,7 @@ class BreakpointsWindow extends ChildWindow {
|
||||||
else if (breakpoint.any() && breakpoint.evaluate(inst, acc))
|
else if (breakpoint.any() && breakpoint.evaluate(inst, acc))
|
||||||
lblStatus.setText("\u2605"); // Star
|
lblStatus.setText("\u2605"); // Star
|
||||||
else lblStatus.setText(" ");
|
else lblStatus.setText(" ");
|
||||||
int lineHeight = lblStatus.getPreferredSize().height;
|
int lineHeight = parent.app.fntDialog.metrics.getHeight();
|
||||||
lblStatus.setPreferredSize(new Dimension(lineHeight, lineHeight));
|
lblStatus.setPreferredSize(new Dimension(lineHeight, lineHeight));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,8 +157,6 @@ class BreakpointsWindow extends ChildWindow {
|
||||||
super(parent, "breakpoints.title");
|
super(parent, "breakpoints.title");
|
||||||
|
|
||||||
// Configure instance fields
|
// Configure instance fields
|
||||||
font = new Font(Util.fontFamily(new String[]
|
|
||||||
{ "Consolas", Font.MONOSPACED } ), Font.PLAIN, 14);
|
|
||||||
items = new ArrayList<Item>();
|
items = new ArrayList<Item>();
|
||||||
selectedIndex = -1;
|
selectedIndex = -1;
|
||||||
|
|
||||||
|
@ -183,7 +180,7 @@ class BreakpointsWindow extends ChildWindow {
|
||||||
lstBreakpoints.addMouseListener(Util.onMouse(e->onMouseDown(e), null));
|
lstBreakpoints.addMouseListener(Util.onMouse(e->onMouseDown(e), null));
|
||||||
var scr = new JScrollPane(lstBreakpoints);
|
var scr = new JScrollPane(lstBreakpoints);
|
||||||
client.add(scr, BorderLayout.CENTER);
|
client.add(scr, BorderLayout.CENTER);
|
||||||
spacer = new JPanel(null);
|
spacer = new JPanel();
|
||||||
spacer.setOpaque(false);
|
spacer.setOpaque(false);
|
||||||
lstBreakpoints.add(spacer, SPACER);
|
lstBreakpoints.add(spacer, SPACER);
|
||||||
|
|
||||||
|
@ -223,7 +220,7 @@ class BreakpointsWindow extends ChildWindow {
|
||||||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
gbc.fill = GridBagConstraints.HORIZONTAL;
|
||||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
||||||
props.add(buttons, gbc);
|
props.add(buttons, gbc);
|
||||||
var fill = new JPanel(null);
|
var fill = new JPanel();
|
||||||
fill.setOpaque(false);
|
fill.setOpaque(false);
|
||||||
fill.addMouseListener(Util.onMouse(e->onDebug(e), null));
|
fill.addMouseListener(Util.onMouse(e->onDebug(e), null));
|
||||||
gbc = new GridBagConstraints();
|
gbc = new GridBagConstraints();
|
||||||
|
@ -602,7 +599,7 @@ class BreakpointsWindow extends ChildWindow {
|
||||||
var txt = new JTextField();
|
var txt = new JTextField();
|
||||||
txt.setEnabled(false);
|
txt.setEnabled(false);
|
||||||
if (mono)
|
if (mono)
|
||||||
txt.setFont(font);
|
txt.setFont(parent.app.fntMono);
|
||||||
txt.addActionListener(e->client.requestFocus());
|
txt.addActionListener(e->client.requestFocus());
|
||||||
txt.addFocusListener (Util.onFocus(null, e->handler.run()));
|
txt.addFocusListener (Util.onFocus(null, e->handler.run()));
|
||||||
var gbc = new GridBagConstraints();
|
var gbc = new GridBagConstraints();
|
||||||
|
|
|
@ -13,7 +13,7 @@ import vue.*;
|
||||||
// CPU window
|
// CPU window
|
||||||
class CPUWindow extends ChildWindow {
|
class CPUWindow extends ChildWindow {
|
||||||
|
|
||||||
// Package fields
|
// Instance fields
|
||||||
MainWindow parent; // Containing window
|
MainWindow parent; // Containing window
|
||||||
|
|
||||||
// UI components
|
// UI components
|
||||||
|
@ -23,70 +23,6 @@ class CPUWindow extends ChildWindow {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Global Settings //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
static Font dasmFont; // Disassembler font
|
|
||||||
static int dasmFontHeight; // Disassembler font line height
|
|
||||||
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) + 4;
|
|
||||||
|
|
||||||
// Disassembler font
|
|
||||||
setDasmFont(new Font(Util.fontFamily(new String[]
|
|
||||||
{ "Consolas", Font.MONOSPACED } ), Font.PLAIN, 14));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Specify a font to use as the disassembler font
|
|
||||||
static void setDasmFont(Font font) {
|
|
||||||
dasmFont = font;
|
|
||||||
var label = new JLabel("!");
|
|
||||||
label.setFont(font);
|
|
||||||
dasmFontHeight = label.getPreferredSize().height;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Specify a font to use as the register list hex font
|
|
||||||
static void setRegHexFont(Font font) {
|
|
||||||
regHexFont = font;
|
|
||||||
regHexFontSize = measureHex(font);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Constructors //
|
// Constructors //
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -94,7 +30,6 @@ class CPUWindow extends ChildWindow {
|
||||||
// Default constructor
|
// Default constructor
|
||||||
CPUWindow(MainWindow parent) {
|
CPUWindow(MainWindow parent) {
|
||||||
super(parent, "cpu.title");
|
super(parent, "cpu.title");
|
||||||
instances.add(this);
|
|
||||||
|
|
||||||
// Configure instance fields
|
// Configure instance fields
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
|
@ -117,34 +52,15 @@ class CPUWindow extends ChildWindow {
|
||||||
var client = getContentPane();
|
var client = getContentPane();
|
||||||
client.add(outer);
|
client.add(outer);
|
||||||
client.setPreferredSize(new Dimension(480, 300));
|
client.setPreferredSize(new Dimension(480, 300));
|
||||||
configure();
|
|
||||||
pack();
|
pack();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Public Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// The window is closing
|
|
||||||
public void dispose() {
|
|
||||||
instances.remove(this);
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Package Methods //
|
// Package Methods //
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Apply configuration settings
|
|
||||||
void configure() {
|
|
||||||
panDasm .configure();
|
|
||||||
lstProgram.configure();
|
|
||||||
lstSystem .configure();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the display
|
// Update the display
|
||||||
void refresh(boolean seekToPC) {
|
void refresh(boolean seekToPC) {
|
||||||
panDasm .refresh(seekToPC);
|
panDasm .refresh(seekToPC);
|
||||||
|
@ -152,42 +68,4 @@ class CPUWindow extends ChildWindow {
|
||||||
lstProgram.refresh();
|
lstProgram.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Event Handlers //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Client resize
|
|
||||||
private void onResize() {
|
|
||||||
//refreshDasm();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Private Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Determine the maximum 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,317 @@
|
||||||
|
package app;
|
||||||
|
|
||||||
|
// Java imports
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.*;
|
||||||
|
import java.util.*;
|
||||||
|
import javax.swing.*;
|
||||||
|
|
||||||
|
// Project imports
|
||||||
|
import util.*;
|
||||||
|
|
||||||
|
// VIP characters window
|
||||||
|
class CharactersWindow extends ChildWindow {
|
||||||
|
|
||||||
|
// Instance fields
|
||||||
|
private int color; // Selected color index
|
||||||
|
|
||||||
|
// UI components
|
||||||
|
private JPanel client; // Client area
|
||||||
|
private JPanel panCharacters; // Characters panel
|
||||||
|
private JPanel panPalette; // Palette panel
|
||||||
|
private JPanel panPattern; // Pattern panel
|
||||||
|
private JScrollPane scrControls; // Controls panel
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructors //
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Default constructor
|
||||||
|
CharactersWindow(MainWindow parent) {
|
||||||
|
super(parent, "characters.title");
|
||||||
|
|
||||||
|
// Configure instance fields
|
||||||
|
color = 0;
|
||||||
|
|
||||||
|
// Configure client area
|
||||||
|
client = new JPanel(new BorderLayout());
|
||||||
|
client.setBackground(SystemColor.control);
|
||||||
|
client.setFocusable(true);
|
||||||
|
client.setPreferredSize(new Dimension(480, 360));
|
||||||
|
client.addComponentListener(Util.onResize(e->onResize()));
|
||||||
|
|
||||||
|
// Configure controls panel
|
||||||
|
var ctrls = new JPanel(new GridBagLayout());
|
||||||
|
ctrls.setBackground(SystemColor.control);
|
||||||
|
ctrls.addMouseListener(
|
||||||
|
Util.onMouse(e->client.requestFocus(), null));
|
||||||
|
scrControls = new JScrollPane(ctrls,
|
||||||
|
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
|
||||||
|
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
|
||||||
|
scrControls.setBorder(null);
|
||||||
|
scrControls.getVerticalScrollBar().setUnitIncrement(20);
|
||||||
|
client.add(scrControls, BorderLayout.WEST);
|
||||||
|
|
||||||
|
label(ctrls, "characters.index", true);
|
||||||
|
spinner(ctrls, 0, 2047, 0, true);
|
||||||
|
label(ctrls, "characters.address", false);
|
||||||
|
textBox(ctrls);
|
||||||
|
label(ctrls, "characters.mirror", false);
|
||||||
|
textBox(ctrls);
|
||||||
|
|
||||||
|
// Pattern panel
|
||||||
|
var panPattern = new JPanel();
|
||||||
|
panPattern.setBackground(Color.black);
|
||||||
|
panPattern.setPreferredSize(new Dimension(96, 96));
|
||||||
|
var gbc = new GridBagConstraints();
|
||||||
|
gbc.anchor = GridBagConstraints.CENTER;
|
||||||
|
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
||||||
|
gbc.insets = new Insets(4, 2, 2, 2);
|
||||||
|
ctrls.add(panPattern, gbc);
|
||||||
|
|
||||||
|
// Palette panel
|
||||||
|
panPalette = new JPanel() {
|
||||||
|
public void paintComponent(Graphics g) {
|
||||||
|
super.paintComponent(g);
|
||||||
|
onPaintPalette((Graphics2D) g, getWidth(), getHeight());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
panPalette.setOpaque(false);
|
||||||
|
panPalette.setPreferredSize(new Dimension(0, 20 + 6));
|
||||||
|
panPalette.addMouseListener(
|
||||||
|
Util.onMouse(e->onMouseDownPalette(e), null));
|
||||||
|
gbc = new GridBagConstraints();
|
||||||
|
gbc.fill = GridBagConstraints.HORIZONTAL;
|
||||||
|
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
||||||
|
gbc.insets = new Insets(0, 2, 4, 2);
|
||||||
|
ctrls.add(panPalette, gbc);
|
||||||
|
|
||||||
|
// Fill the extra space above the view controls
|
||||||
|
var spacer = new JPanel();
|
||||||
|
spacer.setOpaque(false);
|
||||||
|
gbc = new GridBagConstraints();
|
||||||
|
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
||||||
|
gbc.weighty = 1;
|
||||||
|
ctrls.add(spacer, gbc);
|
||||||
|
|
||||||
|
label(ctrls, "characters.grid", false);
|
||||||
|
checkBox(ctrls).setSelected(true);
|
||||||
|
label(ctrls, "characters.wide", false);
|
||||||
|
spinner(ctrls, 0, 2048, 0, false);
|
||||||
|
label(ctrls, "characters.palette", false);
|
||||||
|
select(ctrls, new String[] { "palette.generic",
|
||||||
|
"palette.gplt0", "palette.gplt1", "palette.gplt2", "palette.gplt3",
|
||||||
|
"palette.jplt0", "palette.jplt1", "palette.jplt2", "palette.jplt3"
|
||||||
|
});
|
||||||
|
label(ctrls, "characters.scale", false);
|
||||||
|
slider(ctrls, 1, 10, 1);
|
||||||
|
|
||||||
|
// Terminate the list of controls
|
||||||
|
spacer = new JPanel();
|
||||||
|
spacer.setOpaque(false);
|
||||||
|
spacer.setPreferredSize(new Dimension(0, 0));
|
||||||
|
gbc = new GridBagConstraints();
|
||||||
|
gbc.gridheight = GridBagConstraints.REMAINDER;
|
||||||
|
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
||||||
|
ctrls.add(spacer, gbc);
|
||||||
|
|
||||||
|
// Configure characters panel
|
||||||
|
panCharacters = new JPanel() {
|
||||||
|
public void paintComponent(Graphics g) {
|
||||||
|
super.paintComponent(g);
|
||||||
|
onPaintCharacters((Graphics2D) g, getWidth(), getHeight());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
panCharacters.setBackground(SystemColor.control);
|
||||||
|
panCharacters.addMouseListener(
|
||||||
|
Util.onMouse(e->client.requestFocus(), null));
|
||||||
|
var scr = new JScrollPane(panCharacters);
|
||||||
|
client.add(scr, BorderLayout.CENTER);
|
||||||
|
|
||||||
|
// Configure component
|
||||||
|
setContentPane(client);
|
||||||
|
pack();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Package Methods //
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Update the display
|
||||||
|
void refresh() {
|
||||||
|
repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Event Handlers //
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Palette mouse button press
|
||||||
|
private void onMouseDownPalette(MouseEvent e) {
|
||||||
|
|
||||||
|
// Common processing
|
||||||
|
client.requestFocus();
|
||||||
|
|
||||||
|
// Only consider left clicks
|
||||||
|
if (e.getButton() != MouseEvent.BUTTON1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Working variables
|
||||||
|
int height = panPalette.getHeight();
|
||||||
|
int width = panPalette.getWidth();
|
||||||
|
int size = Math.max(1, Math.min((width - 18) / 4, height - 6));
|
||||||
|
int left = (width - size * 4 - 18) / 2;
|
||||||
|
int top = (height - size - 6) / 2;
|
||||||
|
int x = e.getX() - left - 3;
|
||||||
|
int y = e.getY() - top - 3;
|
||||||
|
|
||||||
|
// The click was not on top of a color
|
||||||
|
if (
|
||||||
|
x < 0 || x >= (size + 4) * 4 ||
|
||||||
|
x % (size + 4) >= size ||
|
||||||
|
y < 0 || y >= size
|
||||||
|
) return;
|
||||||
|
|
||||||
|
// Select the clicked color
|
||||||
|
color = x / (size + 4);
|
||||||
|
panPalette.repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Characters paint
|
||||||
|
private void onPaintCharacters(Graphics2D g, int width, int height) {
|
||||||
|
g.setColor(new Color(0x001830));
|
||||||
|
g.fillRect(0, 0, 256, 512);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Palette paint
|
||||||
|
private void onPaintPalette(Graphics2D g, int width, int height) {
|
||||||
|
int size = Math.max(1, Math.min((width - 18) / 4, height - 6));
|
||||||
|
int left = (width - size * 4 - 18) / 2;
|
||||||
|
int top = (height - size - 6) / 2;
|
||||||
|
|
||||||
|
// Draw the color picker
|
||||||
|
for (int x = 0; x < 4; x++, left += size + 4) {
|
||||||
|
|
||||||
|
// The current color is selected
|
||||||
|
if (x == color) {
|
||||||
|
g.setColor(SystemColor.textHighlight);
|
||||||
|
g.fillRect(left , top , size + 6, size + 6);
|
||||||
|
g.setColor(SystemColor.control);
|
||||||
|
g.fillRect(left + 2, top + 2, size + 2, size + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw the color area
|
||||||
|
g.setColor(Color.black);
|
||||||
|
g.fillRect(left + 3, top + 3, size , size );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Window resize
|
||||||
|
private void onResize() {
|
||||||
|
var viewport = scrControls.getViewport();
|
||||||
|
int inner = viewport.getView().getPreferredSize().width;
|
||||||
|
int outer = viewport.getExtentSize().width;
|
||||||
|
|
||||||
|
// The controls container does not need to be resized
|
||||||
|
if (inner == outer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Size the controls container to match the inner component
|
||||||
|
scrControls.setPreferredSize(new Dimension(
|
||||||
|
scrControls.getPreferredSize().width + inner - outer, 0));
|
||||||
|
scrControls.revalidate();
|
||||||
|
scrControls.repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Private Methods //
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Add a check box to the controls panel
|
||||||
|
private JCheckBox checkBox(JPanel panel) {
|
||||||
|
var chk = new JCheckBox();
|
||||||
|
chk.setBorder(null);
|
||||||
|
chk.setFocusable(false);
|
||||||
|
var gbc = new GridBagConstraints();
|
||||||
|
gbc.anchor = GridBagConstraints.WEST;
|
||||||
|
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
||||||
|
gbc.insets = new Insets(0, 0, 2, 2);
|
||||||
|
panel.add(chk, gbc);
|
||||||
|
return chk;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a label to the controls panel
|
||||||
|
private void label(JPanel panel, String key, boolean top) {
|
||||||
|
var lbl = new JLabel();
|
||||||
|
parent.app.localizer.add(lbl, key);
|
||||||
|
var gbc = new GridBagConstraints();
|
||||||
|
gbc.anchor = GridBagConstraints.WEST;
|
||||||
|
gbc.insets = new Insets(top ? 2 : 0, 2, 2, 2);
|
||||||
|
panel.add(lbl, gbc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a combo box to the controls panel
|
||||||
|
private JComboBox<String> select(JPanel panel, String[] options) {
|
||||||
|
var cmb = new JComboBox<String>();
|
||||||
|
parent.app.localizer.add(cmb, options);
|
||||||
|
cmb.setSelectedIndex(0);
|
||||||
|
var gbc = new GridBagConstraints();
|
||||||
|
gbc.fill = GridBagConstraints.BOTH;
|
||||||
|
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
||||||
|
gbc.insets = new Insets(0, 0, 1, 2);
|
||||||
|
panel.add(cmb, gbc);
|
||||||
|
return cmb;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a slider to the controls panel
|
||||||
|
private JSlider slider(JPanel panel, int min, int max, int value) {
|
||||||
|
var sld = new JSlider(min, max, value);
|
||||||
|
sld.setFocusable(false);
|
||||||
|
sld.setPreferredSize(new Dimension(0, sld.getPreferredSize().height));
|
||||||
|
var gbc = new GridBagConstraints();
|
||||||
|
gbc.fill = GridBagConstraints.BOTH;
|
||||||
|
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
||||||
|
gbc.insets = new Insets(0, 0, 1, 2);
|
||||||
|
panel.add(sld, gbc);
|
||||||
|
return sld;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a spinner to the controls panel
|
||||||
|
private JSpinner spinner(JPanel panel, int min, int max, int value,
|
||||||
|
boolean top) {
|
||||||
|
var spn = new JSpinner(new SpinnerNumberModel(value, min, max, 1));
|
||||||
|
spn.setEditor(new JSpinner.NumberEditor(spn, "#"));
|
||||||
|
var gbc = new GridBagConstraints();
|
||||||
|
gbc.fill = GridBagConstraints.BOTH;
|
||||||
|
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
||||||
|
gbc.insets = new Insets(top ? 2 : 0, 0, 2, 2);
|
||||||
|
gbc.weightx = 1;
|
||||||
|
panel.add(spn, gbc);
|
||||||
|
return spn;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a text box to the controls panel
|
||||||
|
private JTextField textBox(JPanel panel) {
|
||||||
|
var txt = new JTextField();
|
||||||
|
txt.setFont(parent.app.fntMono);
|
||||||
|
var size = txt.getPreferredSize();
|
||||||
|
txt.setPreferredSize(new Dimension(
|
||||||
|
parent.app.hexDigitWidth * 8 + 2 + size.width, size.height));
|
||||||
|
var gbc = new GridBagConstraints();
|
||||||
|
gbc.fill = GridBagConstraints.BOTH;
|
||||||
|
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
||||||
|
gbc.insets = new Insets(0, 0, 2, 2);
|
||||||
|
panel.add(txt, gbc);
|
||||||
|
return txt;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -21,8 +21,8 @@ class DisassemblerPane extends JScrollPane {
|
||||||
private int[] widths; // Column widths
|
private int[] widths; // Column widths
|
||||||
|
|
||||||
// UI components
|
// UI components
|
||||||
private JPanel client; // Client area
|
private JPanel client; // Client area
|
||||||
private ArrayList<Row> rows; // Disassembler output
|
private ArrayList<Row> rows; // Disassembler output
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -53,23 +53,22 @@ class DisassemblerPane extends JScrollPane {
|
||||||
widths = new int[5];
|
widths = new int[5];
|
||||||
|
|
||||||
// Configure client area
|
// Configure client area
|
||||||
client = new JPanel(null) {
|
client = new JPanel() {
|
||||||
public void paintComponent(Graphics g) {
|
public void paintComponent(Graphics g) {
|
||||||
super.paintComponent(g);
|
super.paintComponent(g);
|
||||||
onPaint((Graphics2D) g, getWidth(), getHeight());
|
onPaint((Graphics2D) g, getWidth(), getHeight());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
client.setBackground(SystemColor.window);
|
||||||
|
client.setFocusable(true);
|
||||||
client.addFocusListener(
|
client.addFocusListener(
|
||||||
Util.onFocus(e->client.repaint(), e->client.repaint()));
|
Util.onFocus(e->client.repaint(), e->client.repaint()));
|
||||||
client.addKeyListener(Util.onKey(e->onKeyDown(e), null));
|
client.addKeyListener(Util.onKey(e->onKeyDown(e), null));
|
||||||
client.addMouseListener(Util.onMouse(e->client.requestFocus(), null));
|
client.addMouseListener(Util.onMouse(e->client.requestFocus(), null));
|
||||||
client.addMouseWheelListener(e->onMouseWheel(e));
|
client.addMouseWheelListener(e->onMouseWheel(e));
|
||||||
client.setBackground(SystemColor.window);
|
|
||||||
client.setFocusable(true);
|
|
||||||
|
|
||||||
// Configure component
|
// Configure component
|
||||||
setViewportView(client);
|
setViewportView(client);
|
||||||
configure();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -78,17 +77,14 @@ class DisassemblerPane extends JScrollPane {
|
||||||
// Package Methods //
|
// Package Methods //
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Apply configuration settings
|
|
||||||
void configure() {
|
|
||||||
client.repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the display
|
// Update the display
|
||||||
void refresh(boolean seekToPC) {
|
void refresh(boolean seekToPC) {
|
||||||
|
if (seekToPC) {
|
||||||
|
int pc = parent.parent.vue.getRegister(Vue.PC, true);
|
||||||
|
if (!isVisible(pc))
|
||||||
|
seek(pc, tall(false) / 3);
|
||||||
|
}
|
||||||
client.repaint();
|
client.repaint();
|
||||||
int pc = parent.parent.vue.getRegister(Vue.PC, true);
|
|
||||||
if (!isVisible(pc))
|
|
||||||
seek(pc, tall(false) / 3);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -176,10 +172,11 @@ class DisassemblerPane extends JScrollPane {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure working variables
|
// Configure working variables
|
||||||
int address = this.address;
|
int address = this.address;
|
||||||
int count = tall(true);
|
int count = tall(true);
|
||||||
var data = new byte[count * 4];
|
var data = new byte[count * 4];
|
||||||
int offset = 0;
|
int lineHeight = parent.parent.app.fntMono.metrics.getHeight();
|
||||||
|
int offset = 0;
|
||||||
|
|
||||||
// Disassemble from the current address
|
// Disassemble from the current address
|
||||||
vue.readBytes(address, data, 0, data.length);
|
vue.readBytes(address, data, 0, data.length);
|
||||||
|
@ -202,8 +199,8 @@ class DisassemblerPane extends JScrollPane {
|
||||||
}
|
}
|
||||||
g.setColor(bg);
|
g.setColor(bg);
|
||||||
g.fillRect(
|
g.fillRect(
|
||||||
0, y * CPUWindow.dasmFontHeight,
|
0, y * lineHeight,
|
||||||
width, CPUWindow.dasmFontHeight
|
width, lineHeight
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,7 +217,7 @@ class DisassemblerPane extends JScrollPane {
|
||||||
// Configure all rows
|
// Configure all rows
|
||||||
for (int y = 0; y < rows.size(); y++) {
|
for (int y = 0; y < rows.size(); y++) {
|
||||||
var row = rows.get(y);
|
var row = rows.get(y);
|
||||||
int top = y * CPUWindow.dasmFontHeight;
|
int top = y * lineHeight;
|
||||||
|
|
||||||
// Configure all labels
|
// Configure all labels
|
||||||
for (int z = 0, x = 0; z < 5; z++) {
|
for (int z = 0, x = 0; z < 5; z++) {
|
||||||
|
@ -235,17 +232,17 @@ class DisassemblerPane extends JScrollPane {
|
||||||
// Configure the label
|
// Configure the label
|
||||||
label.setLocation(x, top);
|
label.setLocation(x, top);
|
||||||
label.setSize(label.getPreferredSize());
|
label.setSize(label.getPreferredSize());
|
||||||
x += widths[z] + CPUWindow.dasmFontHeight;
|
x += widths[z] + lineHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the client's size
|
// Update the client's size
|
||||||
var size = client.getPreferredSize();
|
var size = client.getPreferredSize();
|
||||||
width = -CPUWindow.dasmFontHeight + 1;
|
width = -lineHeight + 1;
|
||||||
for (int x = 0; x < 5; x++)
|
for (int x = 0; x < 5; x++)
|
||||||
if (widths[x] != 0 && (x != 2 || showBytes))
|
if (widths[x] != 0 && (x != 2 || showBytes))
|
||||||
width += CPUWindow.dasmFontHeight + widths[x];
|
width += lineHeight + widths[x];
|
||||||
if (width == size.width)
|
if (width == size.width)
|
||||||
return;
|
return;
|
||||||
client.setPreferredSize(new Dimension(width, 0));
|
client.setPreferredSize(new Dimension(width, 0));
|
||||||
|
@ -268,7 +265,7 @@ class DisassemblerPane extends JScrollPane {
|
||||||
for (int x = 0; x < 5; x++) {
|
for (int x = 0; x < 5; x++) {
|
||||||
var label = row.labels[x] = new JLabel();
|
var label = row.labels[x] = new JLabel();
|
||||||
if (x != 4)
|
if (x != 4)
|
||||||
label.setFont(CPUWindow.dasmFont);
|
label.setFont(parent.parent.app.fntMono);
|
||||||
client.add(label);
|
client.add(label);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -380,9 +377,10 @@ class DisassemblerPane extends JScrollPane {
|
||||||
|
|
||||||
// Determine how many rows of output are visible
|
// Determine how many rows of output are visible
|
||||||
private int tall(boolean partial) {
|
private int tall(boolean partial) {
|
||||||
|
int lineHeight = parent.parent.app.fntMono.metrics.getHeight();
|
||||||
return Math.max(1, (client.getHeight() +
|
return Math.max(1, (client.getHeight() +
|
||||||
(partial ? CPUWindow.dasmFontHeight - 1 : 0)
|
(partial ? lineHeight - 1 : 0)
|
||||||
) / CPUWindow.dasmFontHeight);
|
) / lineHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update a row with its text and measure the column widths
|
// Update a row with its text and measure the column widths
|
||||||
|
|
|
@ -15,9 +15,11 @@ import vue.*;
|
||||||
class MainWindow extends JFrame {
|
class MainWindow extends JFrame {
|
||||||
|
|
||||||
// Instance fields
|
// Instance fields
|
||||||
App app; // Containing application
|
App app; // Containing application
|
||||||
Breakpoint brkStep; // Single step internal breakpoint
|
Breakpoint brkStep; // Single step internal breakpoint
|
||||||
Vue vue; // Emulation core context
|
int[][][] palettes; // Raster palettes
|
||||||
|
byte[] vram; // Snapshot of VIP memory
|
||||||
|
Vue vue; // Emulation core context
|
||||||
|
|
||||||
// Private fields
|
// Private fields
|
||||||
private boolean debugMode; // Window is in debug mode
|
private boolean debugMode; // Window is in debug mode
|
||||||
|
@ -28,23 +30,40 @@ class MainWindow extends JFrame {
|
||||||
private File romFile; // Currently loaded ROM file
|
private File romFile; // Currently loaded ROM file
|
||||||
|
|
||||||
// UI components
|
// UI components
|
||||||
private BreakpointsWindow breakpoints; // Breakpoints window
|
private JPanel client; // Common client container
|
||||||
private JPanel client; // Common client container
|
private JDesktopPane desktop; // Container for child windows
|
||||||
private ConsoleWindow console; // Console window
|
private JMenu mnuDebug; // Debug menu
|
||||||
private CPUWindow cpu; // CPU window
|
private JPanel video; // Video output
|
||||||
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 mnuFileDebugMode; // File -> Debug mode
|
||||||
private JMenuItem mnuFileGameMode; // File -> Game mode
|
private JMenuItem mnuFileGameMode; // File -> Game mode
|
||||||
|
|
||||||
|
// Child windows
|
||||||
|
private BreakpointsWindow breakpoints;
|
||||||
|
private CharactersWindow characters;
|
||||||
|
private ConsoleWindow console;
|
||||||
|
private CPUWindow cpu;
|
||||||
|
private MemoryWindow memory;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Constants //
|
// Constants //
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Palette indexes
|
||||||
|
static final int GENERIC = 0;
|
||||||
|
static final int GPLT0 = 1;
|
||||||
|
static final int GPLT1 = 2;
|
||||||
|
static final int GPLT2 = 3;
|
||||||
|
static final int GPLT3 = 4;
|
||||||
|
static final int JPLT0 = 5;
|
||||||
|
static final int JPLT1 = 6;
|
||||||
|
static final int JPLT2 = 7;
|
||||||
|
static final int JPLT3 = 8;
|
||||||
|
static final int LEFT = 0;
|
||||||
|
static final int RIGHT = 1;
|
||||||
|
static final int RED = 2;
|
||||||
|
|
||||||
// Application icon
|
// Application icon
|
||||||
private static final BufferedImage APPICON;
|
private static final BufferedImage APPICON;
|
||||||
|
|
||||||
|
@ -55,6 +74,17 @@ class MainWindow extends JFrame {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Static Methods //
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Calculate the address of a character by index
|
||||||
|
static int chrAddress(int index) {
|
||||||
|
return index >> 9 << 15 | (index & 511) << 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Constructors //
|
// Constructors //
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -65,13 +95,16 @@ class MainWindow extends JFrame {
|
||||||
|
|
||||||
// Configure instance fields
|
// Configure instance fields
|
||||||
this.app = app;
|
this.app = app;
|
||||||
|
palettes = new int[9][3][4];
|
||||||
pwd = Util.PWD;
|
pwd = Util.PWD;
|
||||||
|
vram = new byte[0x40000];
|
||||||
vue = Vue.create(app.getUseNative());
|
vue = Vue.create(app.getUseNative());
|
||||||
System.out.println("Native: " +
|
System.out.println("Native: " +
|
||||||
(vue.isNative() ? Vue.getNativeID() : "No"));
|
(vue.isNative() ? Vue.getNativeID() : "No"));
|
||||||
|
//vue.write(0x00078000, Vue.S32, -1);
|
||||||
|
|
||||||
// Configure video pane
|
// Configure video pane
|
||||||
video = new JPanel(null) {
|
video = new JPanel() {
|
||||||
public void paintComponent(Graphics g) {
|
public void paintComponent(Graphics g) {
|
||||||
super.paintComponent(g);
|
super.paintComponent(g);
|
||||||
onPaintVideo((Graphics2D) g, getWidth(), getHeight());
|
onPaintVideo((Graphics2D) g, getWidth(), getHeight());
|
||||||
|
@ -96,6 +129,7 @@ class MainWindow extends JFrame {
|
||||||
desktop = new JDesktopPane();
|
desktop = new JDesktopPane();
|
||||||
desktop.setBackground(SystemColor.controlShadow);
|
desktop.setBackground(SystemColor.controlShadow);
|
||||||
desktop.add(breakpoints = new BreakpointsWindow(this));
|
desktop.add(breakpoints = new BreakpointsWindow(this));
|
||||||
|
desktop.add(characters = new CharactersWindow (this));
|
||||||
desktop.add(console = new ConsoleWindow (this));
|
desktop.add(console = new ConsoleWindow (this));
|
||||||
desktop.add(cpu = new CPUWindow (this));
|
desktop.add(cpu = new CPUWindow (this));
|
||||||
desktop.add(memory = new MemoryWindow (this));
|
desktop.add(memory = new MemoryWindow (this));
|
||||||
|
@ -160,8 +194,8 @@ class MainWindow extends JFrame {
|
||||||
mnuDebug.add(mnuDebugBackgrounds);
|
mnuDebug.add(mnuDebugBackgrounds);
|
||||||
|
|
||||||
var mnuDebugCharacters = new JMenuItem();
|
var mnuDebugCharacters = new JMenuItem();
|
||||||
mnuDebugCharacters.setEnabled(false);
|
|
||||||
loc.add(mnuDebugCharacters, "app.debug.characters");
|
loc.add(mnuDebugCharacters, "app.debug.characters");
|
||||||
|
mnuDebugCharacters.addActionListener(e->characters.setVisible(true));
|
||||||
mnuDebug.add(mnuDebugCharacters);
|
mnuDebug.add(mnuDebugCharacters);
|
||||||
|
|
||||||
var mnuDebugFrameBuffers = new JMenuItem();
|
var mnuDebugFrameBuffers = new JMenuItem();
|
||||||
|
@ -226,7 +260,12 @@ class MainWindow extends JFrame {
|
||||||
|
|
||||||
// Refresh all debug views
|
// Refresh all debug views
|
||||||
void refreshDebug(boolean seekToPC) {
|
void refreshDebug(boolean seekToPC) {
|
||||||
|
|
||||||
|
vue.readBytes(0x00000000, vram, 0, vram.length);
|
||||||
|
refreshPalettes();
|
||||||
|
|
||||||
breakpoints.refresh();
|
breakpoints.refresh();
|
||||||
|
characters .refresh();
|
||||||
cpu .refresh(seekToPC);
|
cpu .refresh(seekToPC);
|
||||||
memory .refresh();
|
memory .refresh();
|
||||||
}
|
}
|
||||||
|
@ -364,6 +403,58 @@ class MainWindow extends JFrame {
|
||||||
// Private Methods //
|
// Private Methods //
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Update the palette composites
|
||||||
|
private void refreshPalettes() {
|
||||||
|
|
||||||
|
// Process brightness levels
|
||||||
|
int[] brt = { 0,
|
||||||
|
vue.read(0x0005F824, Vue.U8),
|
||||||
|
vue.read(0x0005F826, Vue.U8),
|
||||||
|
vue.read(0x0005F828, Vue.U8)
|
||||||
|
};
|
||||||
|
brt[3] += brt[0] + brt[1];
|
||||||
|
for (int x = 1; x < 4; x++)
|
||||||
|
brt[x] = (Math.min(127, brt[x]) * 510 + 127) / 254 << 1;
|
||||||
|
|
||||||
|
// Process all palettes
|
||||||
|
var pal = new int[4];
|
||||||
|
for (int x = 0; x < 9; x++) {
|
||||||
|
|
||||||
|
// Generic palette
|
||||||
|
if (x == GENERIC) {
|
||||||
|
pal[1] = 0x55 << 1;
|
||||||
|
pal[2] = 0xAA << 1;
|
||||||
|
pal[3] = 0xFF << 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Palette from emulation state
|
||||||
|
else {
|
||||||
|
int bits = vue.read(0x0005F860 + (x - 1 << 1), Vue.U8);
|
||||||
|
pal[1] = brt[bits >> 2 & 3];
|
||||||
|
pal[2] = brt[bits >> 4 & 3];
|
||||||
|
pal[3] = brt[bits >> 6 ];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process colors
|
||||||
|
for (int y = 0; y < 3; y++) {
|
||||||
|
var base = app.rgbBase[y];
|
||||||
|
var dest = palettes[x][y];
|
||||||
|
for (int z = 1; z < 4; z++) {
|
||||||
|
dest[z] = 0xFF000000;
|
||||||
|
for (int w = 0, bits = 16; w < 3; w++, bits -= 8)
|
||||||
|
dest[z] |= (pal[z] * base[w] + 255) / 510 << bits;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Separate the RGB components of a color
|
||||||
|
private static int[] split(int rgb) {
|
||||||
|
return new int[] { rgb >> 16 & 0xFF, rgb >> 8 & 0xFF, rgb & 0xFF };
|
||||||
|
}
|
||||||
|
|
||||||
// Update the window title
|
// Update the window title
|
||||||
private void updateTitle() {
|
private void updateTitle() {
|
||||||
app.localizer.add(this,
|
app.localizer.add(this,
|
||||||
|
|
|
@ -13,10 +13,7 @@ import util.*;
|
||||||
class MemoryWindow extends ChildWindow {
|
class MemoryWindow extends ChildWindow {
|
||||||
|
|
||||||
// Private fields
|
// Private fields
|
||||||
private int address; // Address of top row
|
private int address; // Address of top row
|
||||||
private Font font; // Display font
|
|
||||||
private int fontHeight; // Font line height
|
|
||||||
private int fontWidth; // Font maximum character width
|
|
||||||
|
|
||||||
// UI components
|
// UI components
|
||||||
private JPanel client; // Client area
|
private JPanel client; // Client area
|
||||||
|
@ -46,8 +43,6 @@ class MemoryWindow extends ChildWindow {
|
||||||
|
|
||||||
// Configure instance fields
|
// Configure instance fields
|
||||||
address = 0x00000000;
|
address = 0x00000000;
|
||||||
font = new Font(Util.fontFamily(new String[]
|
|
||||||
{ "Consolas", Font.MONOSPACED } ), Font.PLAIN, 14);
|
|
||||||
rows = new ArrayList<Row>();
|
rows = new ArrayList<Row>();
|
||||||
|
|
||||||
// Configure client area
|
// Configure client area
|
||||||
|
@ -64,7 +59,6 @@ class MemoryWindow extends ChildWindow {
|
||||||
content.setBorder(new JScrollPane().getBorder());
|
content.setBorder(new JScrollPane().getBorder());
|
||||||
content.add(client, BorderLayout.CENTER);
|
content.add(client, BorderLayout.CENTER);
|
||||||
setContentPane(content);
|
setContentPane(content);
|
||||||
setFont2(font);
|
|
||||||
pack();
|
pack();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,9 +76,10 @@ class MemoryWindow extends ChildWindow {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Configure working variables
|
// Configure working variables
|
||||||
int height = client.getHeight();
|
int height = client.getHeight();
|
||||||
int count = (height + fontHeight - 1) / fontHeight;
|
int lineHeight = parent.app.fntMono.metrics.getHeight();
|
||||||
var data = new byte[count * 16];
|
int count = (height + lineHeight - 1) / lineHeight;
|
||||||
|
var data = new byte[count * 16];
|
||||||
|
|
||||||
// Retrieve all visible bytes from the emulation context
|
// Retrieve all visible bytes from the emulation context
|
||||||
parent.vue.readBytes(address, data, 0, data.length);
|
parent.vue.readBytes(address, data, 0, data.length);
|
||||||
|
@ -95,7 +90,7 @@ class MemoryWindow extends ChildWindow {
|
||||||
if (x < rows.size())
|
if (x < rows.size())
|
||||||
row = rows.get(x); // Retrieve row from collection
|
row = rows.get(x); // Retrieve row from collection
|
||||||
else row = createRow(); // Produce a new row
|
else row = createRow(); // Produce a new row
|
||||||
update(row, x * fontHeight, address + x * 16, data, x * 16);
|
update(row, x * lineHeight, address + x * 16, data, x * 16);
|
||||||
setVisible(row, true);
|
setVisible(row, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,30 +103,6 @@ class MemoryWindow extends ChildWindow {
|
||||||
client.repaint();
|
client.repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 rows
|
|
||||||
for (var row : rows) {
|
|
||||||
row.address.setFont(font);
|
|
||||||
for (var label : row.bytes)
|
|
||||||
label.setFont(font);
|
|
||||||
}
|
|
||||||
|
|
||||||
onResize();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -202,7 +173,8 @@ class MemoryWindow extends ChildWindow {
|
||||||
|
|
||||||
// Add a new row of output
|
// Add a new row of output
|
||||||
private Row createRow() {
|
private Row createRow() {
|
||||||
var row = new Row();
|
var font = parent.app.fntMono;
|
||||||
|
var row = new Row();
|
||||||
|
|
||||||
// Address label
|
// Address label
|
||||||
row.address = new JLabel();
|
row.address = new JLabel();
|
||||||
|
@ -250,22 +222,25 @@ class MemoryWindow extends ChildWindow {
|
||||||
|
|
||||||
// Determine how many rows of output are visible
|
// Determine how many rows of output are visible
|
||||||
private int tall(boolean partial) {
|
private int tall(boolean partial) {
|
||||||
return (client.getHeight() + (partial?fontHeight-1:0)) / fontHeight;
|
int lineHeight = parent.app.fntMono.metrics.getHeight();
|
||||||
|
return (client.getHeight() + (partial?lineHeight-1:0)) / lineHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the text of a row
|
// Update the text of a row
|
||||||
private void update(Row row, int y, int address, byte[] data, int offset) {
|
private void update(Row row, int y, int address, byte[] data, int offset) {
|
||||||
|
int hexDigitWidth = parent.app.hexDigitWidth;
|
||||||
|
int lineHeight = parent.app.fntMono.metrics.getHeight();
|
||||||
|
|
||||||
// Update address
|
// Update address
|
||||||
row.address.setBounds(0, y, 8 * fontWidth, fontHeight);
|
row.address.setBounds(0, y, 8 * hexDigitWidth, lineHeight);
|
||||||
row.address.setText(String.format("%08X", address));
|
row.address.setText(String.format("%08X", address));
|
||||||
|
|
||||||
// Update bytes
|
// Update bytes
|
||||||
for (int z = 0, x = 10 * fontWidth; z < 16; z++) {
|
for (int z = 0, x = 10 * hexDigitWidth; z < 16; z++) {
|
||||||
var label = row.bytes[z];
|
var label = row.bytes[z];
|
||||||
label.setBounds(x, y, 2 * fontWidth, fontHeight);
|
label.setBounds(x, y, 2 * hexDigitWidth, lineHeight);
|
||||||
label.setText(String.format("%02X", data[offset++] & 0xFF));
|
label.setText(String.format("%02X", data[offset++] & 0xFF));
|
||||||
x += fontWidth * (z == 7 ? 4 : 3);
|
x += hexDigitWidth * (z == 7 ? 4 : 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,10 @@ class Register {
|
||||||
static final int PLAIN = -2;
|
static final int PLAIN = -2;
|
||||||
static final int PROGRAM = -3;
|
static final int PROGRAM = -3;
|
||||||
|
|
||||||
|
// Expand button labels
|
||||||
|
static final String COLLAPSE = "-";
|
||||||
|
static final String EXPAND = "+";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -71,7 +75,7 @@ class Register {
|
||||||
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 ? EXPAND : "");
|
||||||
btnExpand.setHorizontalAlignment(SwingConstants.CENTER);
|
btnExpand.setHorizontalAlignment(SwingConstants.CENTER);
|
||||||
if (expandable)
|
if (expandable)
|
||||||
btnExpand.addMouseListener(expand);
|
btnExpand.addMouseListener(expand);
|
||||||
|
@ -124,12 +128,12 @@ class Register {
|
||||||
case Vue.PIR : initPIR (); break;
|
case Vue.PIR : initPIR (); break;
|
||||||
case Vue.PSW : initPSW (); break;
|
case Vue.PSW : initPSW (); break;
|
||||||
case Vue.TKCW: initTKCW (); break;
|
case Vue.TKCW: initTKCW (); break;
|
||||||
default: return;
|
default: configure(); return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expansion indentation
|
// Expansion indentation
|
||||||
if (index != Vue.PC) {
|
if (index != Vue.PC) {
|
||||||
indent = new JPanel(null);
|
indent = new JPanel();
|
||||||
indent.setOpaque(false);
|
indent.setOpaque(false);
|
||||||
indent.setPreferredSize(new Dimension(0, 0));
|
indent.setPreferredSize(new Dimension(0, 0));
|
||||||
indent.setVisible(false);
|
indent.setVisible(false);
|
||||||
|
@ -152,6 +156,9 @@ class Register {
|
||||||
// Handling for PSW
|
// Handling for PSW
|
||||||
if (index == Vue.PSW && type == Vue.PSW)
|
if (index == Vue.PSW && type == Vue.PSW)
|
||||||
setExpanded(true);
|
setExpanded(true);
|
||||||
|
|
||||||
|
// Apply application settings
|
||||||
|
configure();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -191,7 +198,7 @@ class Register {
|
||||||
for (int x = 0; x < 2; x++) {
|
for (int x = 0; x < 2; x++) {
|
||||||
|
|
||||||
// Indentation
|
// Indentation
|
||||||
indent = new JPanel(null);
|
indent = new JPanel();
|
||||||
indent.setOpaque(false);
|
indent.setOpaque(false);
|
||||||
indent.setPreferredSize(new Dimension(0, 0));
|
indent.setPreferredSize(new Dimension(0, 0));
|
||||||
var gbc = new GridBagConstraints();
|
var gbc = new GridBagConstraints();
|
||||||
|
@ -295,26 +302,29 @@ class Register {
|
||||||
lblName.setText(name);
|
lblName.setText(name);
|
||||||
|
|
||||||
// Expand button
|
// Expand button
|
||||||
var size = btnExpand.getPreferredSize();
|
var size = btnExpand.getPreferredSize();
|
||||||
size.width = CPUWindow.regExpandWidth;
|
var metrics = parent.parent.parent.app.fntDialog.metrics;
|
||||||
|
size.width = 4 + Math.max(
|
||||||
|
metrics.stringWidth(EXPAND), metrics.stringWidth(COLLAPSE));
|
||||||
btnExpand.setPreferredSize(size);
|
btnExpand.setPreferredSize(size);
|
||||||
|
|
||||||
// Value text box
|
// Value text box
|
||||||
var fontSize = CPUWindow.regHexFontSize;
|
var fntMono = parent.parent.parent.app.fntMono;
|
||||||
size = new Dimension(8 * fontSize.width + 4, fontSize.height);
|
int hexDigitWidth = parent.parent.parent.app.hexDigitWidth;
|
||||||
txtValue.setFont(CPUWindow.regHexFont);
|
txtValue.setFont(fntMono);
|
||||||
txtValue.setPreferredSize(size);
|
txtValue.setPreferredSize(new Dimension(
|
||||||
|
hexDigitWidth * 8 + 4, fntMono.metrics.getHeight()));
|
||||||
|
|
||||||
// Expansion controls
|
// Expansion controls
|
||||||
for (var ctrl : controls) {
|
for (var ctrl : controls) {
|
||||||
if (!(ctrl instanceof JTextField))
|
if (!(ctrl instanceof JTextField))
|
||||||
continue;
|
continue;
|
||||||
if (type == Vue.PC || (Boolean) ctrl.getClientProperty("hex"))
|
if (type == Vue.PC || (Boolean) ctrl.getClientProperty("hex"))
|
||||||
((JTextField) ctrl).setFont(CPUWindow.regHexFont);
|
((JTextField) ctrl).setFont(fntMono);
|
||||||
int digits = type == Vue.PC ? 8 :
|
int digits = type == Vue.PC ? 8 :
|
||||||
(Integer) ctrl.getClientProperty("digits");
|
(Integer) ctrl.getClientProperty("digits");
|
||||||
size = ctrl.getPreferredSize();
|
size = ctrl.getPreferredSize();
|
||||||
size.width = digits * fontSize.width + 4;
|
size.width = digits * hexDigitWidth + 4;
|
||||||
ctrl.setPreferredSize(size);
|
ctrl.setPreferredSize(size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -397,7 +407,7 @@ class Register {
|
||||||
// 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 ? CPUWindow.regHexFont : null);
|
txtValue.setFont(mode!=HEX ? null : parent.parent.parent.app.fntMono);
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -85,7 +85,7 @@ class RegisterList extends JScrollPane {
|
||||||
}
|
}
|
||||||
|
|
||||||
// List terminator
|
// List terminator
|
||||||
var spacer = new JPanel(null);
|
var spacer = new JPanel();
|
||||||
spacer.setOpaque(false);
|
spacer.setOpaque(false);
|
||||||
spacer.setPreferredSize(new Dimension(0, 0));
|
spacer.setPreferredSize(new Dimension(0, 0));
|
||||||
var gbc = new GridBagConstraints();
|
var gbc = new GridBagConstraints();
|
||||||
|
@ -144,7 +144,7 @@ class RegisterList extends JScrollPane {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply configuration settings
|
// Apply configuration settings
|
||||||
void configure() {
|
void configure2() {
|
||||||
|
|
||||||
// Configure registers
|
// Configure registers
|
||||||
for (var reg : registers.values())
|
for (var reg : registers.values())
|
||||||
|
@ -152,7 +152,7 @@ class RegisterList extends JScrollPane {
|
||||||
|
|
||||||
// Configure component
|
// Configure component
|
||||||
getVerticalScrollBar().setUnitIncrement(
|
getVerticalScrollBar().setUnitIncrement(
|
||||||
CPUWindow.regHexFontSize.height);
|
parent.parent.app.fntMono.metrics.getHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the display
|
// Update the display
|
||||||
|
|
|
@ -24,7 +24,7 @@ public final class Util {
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Types //
|
// Classes //
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Event listener interfaces
|
// Event listener interfaces
|
||||||
|
@ -43,6 +43,16 @@ public final class Util {
|
||||||
BOM(byte[] m, Charset s) { mark = m; set = s; }
|
BOM(byte[] m, Charset s) { mark = m; set = s; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Font metrics wrapper
|
||||||
|
public static class Font extends java.awt.Font {
|
||||||
|
public final FontMetrics metrics;
|
||||||
|
public Font(java.awt.Font font) {
|
||||||
|
super(font);
|
||||||
|
metrics = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB)
|
||||||
|
.getGraphics().getFontMetrics(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -1537,7 +1537,7 @@ public class Breakpoint {
|
||||||
case CODE : sym = vue.getExceptionCode(); break;
|
case CODE : sym = vue.getExceptionCode(); break;
|
||||||
case COND : sym = inst.cond ; break;
|
case COND : sym = inst.cond ; break;
|
||||||
case DISP : sym = inst.disp ; break;
|
case DISP : sym = inst.disp ; break;
|
||||||
case FETCH : sym = vue.getFetch (); break;
|
case FETCH : sym = acc.fetch ; break;
|
||||||
case FORMAT : sym = inst.format ; break;
|
case FORMAT : sym = inst.format ; break;
|
||||||
case ID : sym = inst.id ; break;
|
case ID : sym = inst.id ; break;
|
||||||
case OPCODE : sym = inst.opcode ; break;
|
case OPCODE : sym = inst.opcode ; break;
|
||||||
|
|
|
@ -443,8 +443,8 @@ class CPU {
|
||||||
|
|
||||||
// First unit
|
// First unit
|
||||||
if (fetch == 0) {
|
if (fetch == 0) {
|
||||||
inst.bits = access.value & 0xFFFF;
|
inst.bits = access.value;
|
||||||
if (Instruction.size(access.value >> 10 & 0x3F) == 4) {
|
if (Instruction.size(access.value >> 10) == 4) {
|
||||||
fetch = 1;
|
fetch = 1;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,6 +114,7 @@ public class Instruction {
|
||||||
boolean read = false;
|
boolean read = false;
|
||||||
var ret = new Access();
|
var ret = new Access();
|
||||||
ret.address = vue.getRegister(reg1, false) + disp;
|
ret.address = vue.getRegister(reg1, false) + disp;
|
||||||
|
ret.fetch = vue.getFetch();
|
||||||
ret.type = Vue.S32;
|
ret.type = Vue.S32;
|
||||||
|
|
||||||
// Configure descriptor by ID
|
// Configure descriptor by ID
|
||||||
|
@ -139,10 +140,17 @@ public class Instruction {
|
||||||
if (read)
|
if (read)
|
||||||
ret.value = vue.read(ret.address, ret.type);
|
ret.value = vue.read(ret.address, ret.type);
|
||||||
|
|
||||||
// Select the value to write to the bus
|
// Write a register to the bus
|
||||||
else ret.value = vue.getRegister(id == Vue.CAXI &&
|
else if (id != Vue.CAXI)
|
||||||
vue.getRegister(reg2, false) == vue.read(ret.address, Vue.S32) ?
|
vue.getRegister(reg2, false);
|
||||||
30 : reg2, false);
|
|
||||||
|
// CAXI processing
|
||||||
|
else {
|
||||||
|
int value = vue.read(ret.address, Vue.S32);
|
||||||
|
int compare = vue.getRegister(reg2, false);
|
||||||
|
int exchange = vue.getRegister( 30, false);
|
||||||
|
ret.value = value == compare ? value : exchange;
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,11 +76,6 @@ class JavaVue extends Vue {
|
||||||
return maxCycles;
|
return maxCycles;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve a snapshot of the current state's memory access
|
|
||||||
public Access getAccess() {
|
|
||||||
return cpu.access;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the most recent applicaiton break code
|
// Retrieve the most recent applicaiton break code
|
||||||
public int getBreakCode() {
|
public int getBreakCode() {
|
||||||
return breakCode;
|
return breakCode;
|
||||||
|
@ -91,11 +86,6 @@ class JavaVue extends Vue {
|
||||||
return cpu.exception;
|
return cpu.exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve a snapshot of the current state's instruction
|
|
||||||
public Instruction getInstruction() {
|
|
||||||
return cpu.inst;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve a register value
|
// Retrieve a register value
|
||||||
public int getRegister(int index, boolean system) {
|
public int getRegister(int index, boolean system) {
|
||||||
|
|
||||||
|
|
|
@ -141,22 +141,6 @@ JNIEXPORT jint JNICALL Java_vue_NativeVue_emulate
|
||||||
return vueEmulate(&core->vue, maxCycles);
|
return vueEmulate(&core->vue, maxCycles);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve a snapshot of the current state's memory access
|
|
||||||
JNIEXPORT jobject JNICALL Java_vue_NativeVue_getAccess
|
|
||||||
(JNIEnv *env, jobject vue, jlong handle, jobject acc) {
|
|
||||||
Core *core = *(Core **)&handle;
|
|
||||||
jclass cls = (*env)->GetObjectClass(env, acc);
|
|
||||||
(*env)->SetIntField(env, acc, (*env)->GetFieldID(env, cls, "address", "I"),
|
|
||||||
core->vue.cpu.access.address);
|
|
||||||
(*env)->SetIntField(env, acc, (*env)->GetFieldID(env, cls, "fetch", "I"),
|
|
||||||
core->vue.cpu.fetch);
|
|
||||||
(*env)->SetIntField(env, acc, (*env)->GetFieldID(env, cls, "type", "I"),
|
|
||||||
core->vue.cpu.access.type);
|
|
||||||
(*env)->SetIntField(env, acc, (*env)->GetFieldID(env, cls, "value", "I"),
|
|
||||||
core->vue.cpu.access.value);
|
|
||||||
return acc;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the most recent exception code
|
// Retrieve the most recent exception code
|
||||||
JNIEXPORT jint JNICALL Java_vue_NativeVue_getBreakCode
|
JNIEXPORT jint JNICALL Java_vue_NativeVue_getBreakCode
|
||||||
(JNIEnv *env, jobject vue, jlong handle) {
|
(JNIEnv *env, jobject vue, jlong handle) {
|
||||||
|
@ -171,36 +155,6 @@ JNIEXPORT jint JNICALL Java_vue_NativeVue_getExceptionCode
|
||||||
return vueGetExceptionCode(&core->vue);
|
return vueGetExceptionCode(&core->vue);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve a snapshot of the current state's instruction
|
|
||||||
JNIEXPORT jobject JNICALL Java_vue_NativeVue_getInstruction
|
|
||||||
(JNIEnv *env, jobject vue, jlong handle, jobject inst) {
|
|
||||||
Core *core = *(Core **)&handle;
|
|
||||||
jclass cls = (*env)->GetObjectClass(env, inst);
|
|
||||||
(*env)->SetIntField(env, inst, (*env)->GetFieldID(env, cls, "bits", "I"),
|
|
||||||
core->vue.cpu.inst.bits);
|
|
||||||
(*env)->SetIntField(env, inst, (*env)->GetFieldID(env, cls, "cond", "I"),
|
|
||||||
core->vue.cpu.inst.cond);
|
|
||||||
(*env)->SetIntField(env, inst, (*env)->GetFieldID(env, cls, "disp", "I"),
|
|
||||||
core->vue.cpu.inst.disp);
|
|
||||||
(*env)->SetIntField(env, inst, (*env)->GetFieldID(env, cls, "format", "I"),
|
|
||||||
core->vue.cpu.inst.format);
|
|
||||||
(*env)->SetIntField(env, inst, (*env)->GetFieldID(env, cls, "id", "I"),
|
|
||||||
core->vue.cpu.inst.id);
|
|
||||||
(*env)->SetIntField(env, inst, (*env)->GetFieldID(env, cls, "imm", "I"),
|
|
||||||
core->vue.cpu.inst.imm);
|
|
||||||
(*env)->SetIntField(env, inst, (*env)->GetFieldID(env, cls, "opcode", "I"),
|
|
||||||
core->vue.cpu.inst.opcode);
|
|
||||||
(*env)->SetIntField(env, inst, (*env)->GetFieldID(env, cls, "reg1", "I"),
|
|
||||||
core->vue.cpu.inst.reg1);
|
|
||||||
(*env)->SetIntField(env, inst, (*env)->GetFieldID(env, cls, "reg2", "I"),
|
|
||||||
core->vue.cpu.inst.reg2);
|
|
||||||
(*env)->SetIntField(env, inst, (*env)->GetFieldID(env, cls, "size", "I"),
|
|
||||||
core->vue.cpu.inst.size);
|
|
||||||
(*env)->SetIntField(env, inst, (*env)->GetFieldID(env,cls,"subopcode","I"),
|
|
||||||
core->vue.cpu.inst.subopcode);
|
|
||||||
return inst;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve a register value
|
// Retrieve a register value
|
||||||
JNIEXPORT jint JNICALL Java_vue_NativeVue_getRegister
|
JNIEXPORT jint JNICALL Java_vue_NativeVue_getRegister
|
||||||
(JNIEnv *env, jobject vue, jlong handle, jint index, jboolean system) {
|
(JNIEnv *env, jobject vue, jlong handle, jint index, jboolean system) {
|
||||||
|
|
|
@ -42,12 +42,6 @@ class NativeVue extends Vue {
|
||||||
public int emulate(int maxCycles)
|
public int emulate(int maxCycles)
|
||||||
{ return emulate(handle, maxCycles); }
|
{ return emulate(handle, maxCycles); }
|
||||||
|
|
||||||
// Retrieve a snapshot of the current state's memory access
|
|
||||||
private native Access getAccess(long handle, Access access);
|
|
||||||
public Access getAccess() {
|
|
||||||
return getAccess(handle, new Access());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the most recent application break code
|
// Retrieve the most recent application break code
|
||||||
private native int getBreakCode(long handle);
|
private native int getBreakCode(long handle);
|
||||||
public int getBreakCode() { return getBreakCode(handle); }
|
public int getBreakCode() { return getBreakCode(handle); }
|
||||||
|
@ -58,12 +52,6 @@ class NativeVue extends Vue {
|
||||||
return getExceptionCode(handle);
|
return getExceptionCode(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve a snapshot of the current state's instruction
|
|
||||||
private native Instruction getInstruction(long handle, Instruction inst);
|
|
||||||
public Instruction getInstruction() {
|
|
||||||
return getInstruction(handle, new Instruction());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve a register value
|
// Retrieve a register value
|
||||||
private native int getRegister(long handle, int index, boolean system);
|
private native int getRegister(long handle, int index, boolean system);
|
||||||
public int getRegister(int index, boolean system)
|
public int getRegister(int index, boolean system)
|
||||||
|
|
Loading…
Reference in New Issue