Precursor to VIP introduction
This commit is contained in:
parent
d636719775
commit
9f5a5233ea
|
@ -135,7 +135,7 @@
|
|||
border-width: 0 1px 1px 0;
|
||||
}
|
||||
|
||||
.bordered tr > :first-child {
|
||||
.bordered tr > :first-child, .op1 {
|
||||
padding: 1px 12px 1px 12px;
|
||||
text-align: center;
|
||||
}
|
||||
|
@ -245,12 +245,12 @@
|
|||
</p>
|
||||
<p>
|
||||
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
|
||||
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.
|
||||
Float values in the expression evaluator are subjected to the same
|
||||
restrictions as on the Virtual Boy's CPU: if the result of any float
|
||||
Float values in the expression evaluator are subjected to the following
|
||||
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
|
||||
changed to positive zero.
|
||||
</p>
|
||||
|
@ -259,7 +259,7 @@
|
|||
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
|
||||
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.
|
||||
</p>
|
||||
<p>
|
||||
|
@ -298,13 +298,13 @@
|
|||
<td class="mono">disp</td>
|
||||
<td>Displacement offset for jumps and memory accesses.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<!--tr>
|
||||
<td class="mono">fetch</td>
|
||||
<td>
|
||||
Data unit index during a fetch operation, or <code>-1</code> if the read
|
||||
operation is not a fetch.
|
||||
</td>
|
||||
</tr>
|
||||
</tr-->
|
||||
<tr>
|
||||
<td class="mono">format</td>
|
||||
<td>Current instruction's encoding format.</td>
|
||||
|
@ -354,7 +354,7 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<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>
|
||||
<td class="mono">vector</td>
|
||||
|
@ -434,15 +434,14 @@
|
|||
<p>
|
||||
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
|
||||
operator). Binary operators appear between the values they modify. Each
|
||||
operator considers the types of its operands in order to produce a new value
|
||||
of the appropriate type.
|
||||
operator). Binary operators appear between the values they modify.
|
||||
</p>
|
||||
<p>
|
||||
If the operands of a binary operator have different types, one of the values
|
||||
will be converted to the other type before performing the operation. The
|
||||
conversion depends on the "greater" of the two types, in the following order
|
||||
(higher is "greater"):
|
||||
Each operator considers the types of its operands in order to produce a new
|
||||
value of the appropriate type. If the operands of a binary operator have
|
||||
different types, one of the values will be converted to the other type before
|
||||
performing the operation. The conversion selects the "greater" of the two
|
||||
types, in the following order (higher is "greater"):
|
||||
</p>
|
||||
<table class="indent">
|
||||
<tr><td class="center narrow">↑</td><td>Float</td></tr>
|
||||
|
@ -452,7 +451,7 @@
|
|||
</table>
|
||||
<p>
|
||||
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>
|
||||
Operators have assigned precedence that specifies the order of operations.
|
||||
|
@ -467,12 +466,14 @@
|
|||
<p>
|
||||
The following operators may be used in expressions. Groups listed higher have
|
||||
higher precedence and happen before groups listed lower. Operators within
|
||||
groups have the same precedence and are processed in the order they appear in
|
||||
the expression from left to right.
|
||||
groups have the same precedence and are processed according to the order in
|
||||
which they appear in the expression: right-to-left for unary operators,
|
||||
left-to-right for binary operators.
|
||||
</p>
|
||||
<table class="indent bordered">
|
||||
<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">Cannot be used with a float value.</td>
|
||||
</tr>
|
||||
|
@ -562,7 +563,8 @@
|
|||
<td>The binary value is not modified.</td>
|
||||
</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">Zero divisor yields zero as result.</td>
|
||||
</tr>
|
||||
|
@ -589,17 +591,17 @@
|
|||
<tr>
|
||||
<td class="mono open"><<</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>
|
||||
<td class="mono open">>></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>
|
||||
<td class="mono">>>></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>
|
||||
<td class="mono open">></td>
|
||||
|
@ -634,17 +636,17 @@
|
|||
<tr>
|
||||
<td class="mono">&</td>
|
||||
<td>And Bitwise</td>
|
||||
<td>Cannot be used with a float value.</td>
|
||||
<td>Cannot be used with float values.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="mono">^</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>
|
||||
<td class="mono">|</td>
|
||||
<td>Or Bitwise</td>
|
||||
<td>Cannot be used with a float value.</td>
|
||||
<td>Cannot be used with float values.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="mono">&&</td>
|
||||
|
@ -691,6 +693,13 @@
|
|||
<td>Performs a halfword read of the specified signedness.</td>
|
||||
</tr>
|
||||
</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>
|
||||
</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 {
|
||||
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 {
|
||||
float Float
|
||||
|
@ -84,21 +106,6 @@ cpu {
|
|||
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
|
||||
dialog {
|
||||
ext_isx ISX modules (*.isx)
|
||||
|
@ -108,3 +115,21 @@ dialog {
|
|||
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.
|
||||
}
|
||||
|
||||
# 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 */
|
||||
if (vue->cpu.fetch == 0) {
|
||||
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;
|
||||
return VUE_FALSE;
|
||||
}
|
||||
|
@ -1172,7 +1172,7 @@ static vbool cpuFetch(Vue *vue) {
|
|||
|
||||
/* Second unit */
|
||||
else {
|
||||
vue->cpu.inst.bits |= vue->cpu.access.value & 0xFFFF;
|
||||
vue->cpu.inst.bits |= vue->cpu.access.value;
|
||||
vue->cpu.fetch = -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package app;
|
||||
|
||||
// Java imports
|
||||
import java.awt.*;
|
||||
import java.util.*;
|
||||
import javax.swing.*;
|
||||
|
||||
// Project imports
|
||||
import util.*;
|
||||
|
@ -16,7 +18,28 @@ public class App {
|
|||
private ArrayList<MainWindow> windows; // Application windows
|
||||
|
||||
// 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
|
||||
public App(boolean useNative) {
|
||||
|
||||
// Instance fields
|
||||
// Configure instance fields
|
||||
localizer = new Localizer();
|
||||
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
|
||||
setUseNative(useNative);
|
||||
initLocales();
|
||||
|
@ -83,6 +113,14 @@ public class App {
|
|||
// 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
|
||||
private void initLocales() {
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@ import vue.*;
|
|||
class BreakpointsWindow extends ChildWindow {
|
||||
|
||||
// Private fields
|
||||
private Font font; // Display font
|
||||
private ArrayList<Item> items; // List items
|
||||
private int selectedIndex; // Selected list item
|
||||
|
||||
|
@ -133,7 +132,7 @@ class BreakpointsWindow extends ChildWindow {
|
|||
else if (breakpoint.any() && breakpoint.evaluate(inst, acc))
|
||||
lblStatus.setText("\u2605"); // Star
|
||||
else lblStatus.setText(" ");
|
||||
int lineHeight = lblStatus.getPreferredSize().height;
|
||||
int lineHeight = parent.app.fntDialog.metrics.getHeight();
|
||||
lblStatus.setPreferredSize(new Dimension(lineHeight, lineHeight));
|
||||
}
|
||||
|
||||
|
@ -158,8 +157,6 @@ class BreakpointsWindow extends ChildWindow {
|
|||
super(parent, "breakpoints.title");
|
||||
|
||||
// Configure instance fields
|
||||
font = new Font(Util.fontFamily(new String[]
|
||||
{ "Consolas", Font.MONOSPACED } ), Font.PLAIN, 14);
|
||||
items = new ArrayList<Item>();
|
||||
selectedIndex = -1;
|
||||
|
||||
|
@ -183,7 +180,7 @@ class BreakpointsWindow extends ChildWindow {
|
|||
lstBreakpoints.addMouseListener(Util.onMouse(e->onMouseDown(e), null));
|
||||
var scr = new JScrollPane(lstBreakpoints);
|
||||
client.add(scr, BorderLayout.CENTER);
|
||||
spacer = new JPanel(null);
|
||||
spacer = new JPanel();
|
||||
spacer.setOpaque(false);
|
||||
lstBreakpoints.add(spacer, SPACER);
|
||||
|
||||
|
@ -223,7 +220,7 @@ class BreakpointsWindow extends ChildWindow {
|
|||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
||||
props.add(buttons, gbc);
|
||||
var fill = new JPanel(null);
|
||||
var fill = new JPanel();
|
||||
fill.setOpaque(false);
|
||||
fill.addMouseListener(Util.onMouse(e->onDebug(e), null));
|
||||
gbc = new GridBagConstraints();
|
||||
|
@ -602,7 +599,7 @@ class BreakpointsWindow extends ChildWindow {
|
|||
var txt = new JTextField();
|
||||
txt.setEnabled(false);
|
||||
if (mono)
|
||||
txt.setFont(font);
|
||||
txt.setFont(parent.app.fntMono);
|
||||
txt.addActionListener(e->client.requestFocus());
|
||||
txt.addFocusListener (Util.onFocus(null, e->handler.run()));
|
||||
var gbc = new GridBagConstraints();
|
||||
|
|
|
@ -13,7 +13,7 @@ import vue.*;
|
|||
// CPU window
|
||||
class CPUWindow extends ChildWindow {
|
||||
|
||||
// Package fields
|
||||
// Instance fields
|
||||
MainWindow parent; // Containing window
|
||||
|
||||
// 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 //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
@ -94,7 +30,6 @@ class CPUWindow extends ChildWindow {
|
|||
// Default constructor
|
||||
CPUWindow(MainWindow parent) {
|
||||
super(parent, "cpu.title");
|
||||
instances.add(this);
|
||||
|
||||
// Configure instance fields
|
||||
this.parent = parent;
|
||||
|
@ -117,34 +52,15 @@ class CPUWindow extends ChildWindow {
|
|||
var client = getContentPane();
|
||||
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() {
|
||||
panDasm .configure();
|
||||
lstProgram.configure();
|
||||
lstSystem .configure();
|
||||
}
|
||||
|
||||
// Update the display
|
||||
void refresh(boolean seekToPC) {
|
||||
panDasm .refresh(seekToPC);
|
||||
|
@ -152,42 +68,4 @@ class CPUWindow extends ChildWindow {
|
|||
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
|
||||
|
||||
// UI components
|
||||
private JPanel client; // Client area
|
||||
private ArrayList<Row> rows; // Disassembler output
|
||||
private JPanel client; // Client area
|
||||
private ArrayList<Row> rows; // Disassembler output
|
||||
|
||||
|
||||
|
||||
|
@ -53,23 +53,22 @@ class DisassemblerPane extends JScrollPane {
|
|||
widths = new int[5];
|
||||
|
||||
// Configure client area
|
||||
client = new JPanel(null) {
|
||||
client = new JPanel() {
|
||||
public void paintComponent(Graphics g) {
|
||||
super.paintComponent(g);
|
||||
onPaint((Graphics2D) g, getWidth(), getHeight());
|
||||
}
|
||||
};
|
||||
client.setBackground(SystemColor.window);
|
||||
client.setFocusable(true);
|
||||
client.addFocusListener(
|
||||
Util.onFocus(e->client.repaint(), e->client.repaint()));
|
||||
client.addKeyListener(Util.onKey(e->onKeyDown(e), null));
|
||||
client.addMouseListener(Util.onMouse(e->client.requestFocus(), null));
|
||||
client.addMouseWheelListener(e->onMouseWheel(e));
|
||||
client.setBackground(SystemColor.window);
|
||||
client.setFocusable(true);
|
||||
|
||||
// Configure component
|
||||
setViewportView(client);
|
||||
configure();
|
||||
}
|
||||
|
||||
|
||||
|
@ -78,17 +77,14 @@ class DisassemblerPane extends JScrollPane {
|
|||
// Package Methods //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Apply configuration settings
|
||||
void configure() {
|
||||
client.repaint();
|
||||
}
|
||||
|
||||
// Update the display
|
||||
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();
|
||||
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
|
||||
int address = this.address;
|
||||
int count = tall(true);
|
||||
var data = new byte[count * 4];
|
||||
int offset = 0;
|
||||
int address = this.address;
|
||||
int count = tall(true);
|
||||
var data = new byte[count * 4];
|
||||
int lineHeight = parent.parent.app.fntMono.metrics.getHeight();
|
||||
int offset = 0;
|
||||
|
||||
// Disassemble from the current address
|
||||
vue.readBytes(address, data, 0, data.length);
|
||||
|
@ -202,8 +199,8 @@ class DisassemblerPane extends JScrollPane {
|
|||
}
|
||||
g.setColor(bg);
|
||||
g.fillRect(
|
||||
0, y * CPUWindow.dasmFontHeight,
|
||||
width, CPUWindow.dasmFontHeight
|
||||
0, y * lineHeight,
|
||||
width, lineHeight
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -220,7 +217,7 @@ class DisassemblerPane extends JScrollPane {
|
|||
// Configure all rows
|
||||
for (int y = 0; y < rows.size(); y++) {
|
||||
var row = rows.get(y);
|
||||
int top = y * CPUWindow.dasmFontHeight;
|
||||
int top = y * lineHeight;
|
||||
|
||||
// Configure all labels
|
||||
for (int z = 0, x = 0; z < 5; z++) {
|
||||
|
@ -235,17 +232,17 @@ class DisassemblerPane extends JScrollPane {
|
|||
// Configure the label
|
||||
label.setLocation(x, top);
|
||||
label.setSize(label.getPreferredSize());
|
||||
x += widths[z] + CPUWindow.dasmFontHeight;
|
||||
x += widths[z] + lineHeight;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Update the client's size
|
||||
var size = client.getPreferredSize();
|
||||
width = -CPUWindow.dasmFontHeight + 1;
|
||||
width = -lineHeight + 1;
|
||||
for (int x = 0; x < 5; x++)
|
||||
if (widths[x] != 0 && (x != 2 || showBytes))
|
||||
width += CPUWindow.dasmFontHeight + widths[x];
|
||||
width += lineHeight + widths[x];
|
||||
if (width == size.width)
|
||||
return;
|
||||
client.setPreferredSize(new Dimension(width, 0));
|
||||
|
@ -268,7 +265,7 @@ class DisassemblerPane extends JScrollPane {
|
|||
for (int x = 0; x < 5; x++) {
|
||||
var label = row.labels[x] = new JLabel();
|
||||
if (x != 4)
|
||||
label.setFont(CPUWindow.dasmFont);
|
||||
label.setFont(parent.parent.app.fntMono);
|
||||
client.add(label);
|
||||
}
|
||||
|
||||
|
@ -380,9 +377,10 @@ class DisassemblerPane extends JScrollPane {
|
|||
|
||||
// Determine how many rows of output are visible
|
||||
private int tall(boolean partial) {
|
||||
int lineHeight = parent.parent.app.fntMono.metrics.getHeight();
|
||||
return Math.max(1, (client.getHeight() +
|
||||
(partial ? CPUWindow.dasmFontHeight - 1 : 0)
|
||||
) / CPUWindow.dasmFontHeight);
|
||||
(partial ? lineHeight - 1 : 0)
|
||||
) / lineHeight);
|
||||
}
|
||||
|
||||
// Update a row with its text and measure the column widths
|
||||
|
|
|
@ -15,9 +15,11 @@ import vue.*;
|
|||
class MainWindow extends JFrame {
|
||||
|
||||
// Instance fields
|
||||
App app; // Containing application
|
||||
Breakpoint brkStep; // Single step internal breakpoint
|
||||
Vue vue; // Emulation core context
|
||||
App app; // Containing application
|
||||
Breakpoint brkStep; // Single step internal breakpoint
|
||||
int[][][] palettes; // Raster palettes
|
||||
byte[] vram; // Snapshot of VIP memory
|
||||
Vue vue; // Emulation core context
|
||||
|
||||
// Private fields
|
||||
private boolean debugMode; // Window is in debug mode
|
||||
|
@ -28,23 +30,40 @@ class MainWindow extends JFrame {
|
|||
private File romFile; // Currently loaded ROM file
|
||||
|
||||
// UI components
|
||||
private BreakpointsWindow breakpoints; // Breakpoints window
|
||||
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 JPanel client; // Common client container
|
||||
private JDesktopPane desktop; // Container for child windows
|
||||
private JMenu mnuDebug; // Debug menu
|
||||
private JPanel video; // Video output
|
||||
private JMenuItem mnuFileDebugMode; // File -> Debug 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 //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// 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
|
||||
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 //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
@ -65,13 +95,16 @@ class MainWindow extends JFrame {
|
|||
|
||||
// Configure instance fields
|
||||
this.app = app;
|
||||
palettes = new int[9][3][4];
|
||||
pwd = Util.PWD;
|
||||
vram = new byte[0x40000];
|
||||
vue = Vue.create(app.getUseNative());
|
||||
System.out.println("Native: " +
|
||||
(vue.isNative() ? Vue.getNativeID() : "No"));
|
||||
//vue.write(0x00078000, Vue.S32, -1);
|
||||
|
||||
// Configure video pane
|
||||
video = new JPanel(null) {
|
||||
video = new JPanel() {
|
||||
public void paintComponent(Graphics g) {
|
||||
super.paintComponent(g);
|
||||
onPaintVideo((Graphics2D) g, getWidth(), getHeight());
|
||||
|
@ -96,6 +129,7 @@ class MainWindow extends JFrame {
|
|||
desktop = new JDesktopPane();
|
||||
desktop.setBackground(SystemColor.controlShadow);
|
||||
desktop.add(breakpoints = new BreakpointsWindow(this));
|
||||
desktop.add(characters = new CharactersWindow (this));
|
||||
desktop.add(console = new ConsoleWindow (this));
|
||||
desktop.add(cpu = new CPUWindow (this));
|
||||
desktop.add(memory = new MemoryWindow (this));
|
||||
|
@ -160,8 +194,8 @@ class MainWindow extends JFrame {
|
|||
mnuDebug.add(mnuDebugBackgrounds);
|
||||
|
||||
var mnuDebugCharacters = new JMenuItem();
|
||||
mnuDebugCharacters.setEnabled(false);
|
||||
loc.add(mnuDebugCharacters, "app.debug.characters");
|
||||
mnuDebugCharacters.addActionListener(e->characters.setVisible(true));
|
||||
mnuDebug.add(mnuDebugCharacters);
|
||||
|
||||
var mnuDebugFrameBuffers = new JMenuItem();
|
||||
|
@ -226,7 +260,12 @@ class MainWindow extends JFrame {
|
|||
|
||||
// Refresh all debug views
|
||||
void refreshDebug(boolean seekToPC) {
|
||||
|
||||
vue.readBytes(0x00000000, vram, 0, vram.length);
|
||||
refreshPalettes();
|
||||
|
||||
breakpoints.refresh();
|
||||
characters .refresh();
|
||||
cpu .refresh(seekToPC);
|
||||
memory .refresh();
|
||||
}
|
||||
|
@ -364,6 +403,58 @@ class MainWindow extends JFrame {
|
|||
// 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
|
||||
private void updateTitle() {
|
||||
app.localizer.add(this,
|
||||
|
|
|
@ -13,10 +13,7 @@ import util.*;
|
|||
class MemoryWindow extends ChildWindow {
|
||||
|
||||
// Private fields
|
||||
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
|
||||
private int address; // Address of top row
|
||||
|
||||
// UI components
|
||||
private JPanel client; // Client area
|
||||
|
@ -46,8 +43,6 @@ class MemoryWindow extends ChildWindow {
|
|||
|
||||
// Configure instance fields
|
||||
address = 0x00000000;
|
||||
font = new Font(Util.fontFamily(new String[]
|
||||
{ "Consolas", Font.MONOSPACED } ), Font.PLAIN, 14);
|
||||
rows = new ArrayList<Row>();
|
||||
|
||||
// Configure client area
|
||||
|
@ -64,7 +59,6 @@ class MemoryWindow extends ChildWindow {
|
|||
content.setBorder(new JScrollPane().getBorder());
|
||||
content.add(client, BorderLayout.CENTER);
|
||||
setContentPane(content);
|
||||
setFont2(font);
|
||||
pack();
|
||||
}
|
||||
|
||||
|
@ -82,9 +76,10 @@ class MemoryWindow extends ChildWindow {
|
|||
return;
|
||||
|
||||
// Configure working variables
|
||||
int height = client.getHeight();
|
||||
int count = (height + fontHeight - 1) / fontHeight;
|
||||
var data = new byte[count * 16];
|
||||
int height = client.getHeight();
|
||||
int lineHeight = parent.app.fntMono.metrics.getHeight();
|
||||
int count = (height + lineHeight - 1) / lineHeight;
|
||||
var data = new byte[count * 16];
|
||||
|
||||
// Retrieve all visible bytes from the emulation context
|
||||
parent.vue.readBytes(address, data, 0, data.length);
|
||||
|
@ -95,7 +90,7 @@ class MemoryWindow extends ChildWindow {
|
|||
if (x < rows.size())
|
||||
row = rows.get(x); // Retrieve row from collection
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -108,30 +103,6 @@ class MemoryWindow extends ChildWindow {
|
|||
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
|
||||
private Row createRow() {
|
||||
var row = new Row();
|
||||
var font = parent.app.fntMono;
|
||||
var row = new Row();
|
||||
|
||||
// Address label
|
||||
row.address = new JLabel();
|
||||
|
@ -250,22 +222,25 @@ class MemoryWindow extends ChildWindow {
|
|||
|
||||
// Determine how many rows of output are visible
|
||||
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
|
||||
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
|
||||
row.address.setBounds(0, y, 8 * fontWidth, fontHeight);
|
||||
row.address.setBounds(0, y, 8 * hexDigitWidth, lineHeight);
|
||||
row.address.setText(String.format("%08X", address));
|
||||
|
||||
// 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];
|
||||
label.setBounds(x, y, 2 * fontWidth, fontHeight);
|
||||
label.setBounds(x, y, 2 * hexDigitWidth, lineHeight);
|
||||
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 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);
|
||||
|
||||
// Expand button
|
||||
btnExpand = new JLabel(expandable ? "+" : " ");
|
||||
btnExpand = new JLabel(expandable ? EXPAND : "");
|
||||
btnExpand.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
if (expandable)
|
||||
btnExpand.addMouseListener(expand);
|
||||
|
@ -124,12 +128,12 @@ class Register {
|
|||
case Vue.PIR : initPIR (); break;
|
||||
case Vue.PSW : initPSW (); break;
|
||||
case Vue.TKCW: initTKCW (); break;
|
||||
default: return;
|
||||
default: configure(); return;
|
||||
}
|
||||
|
||||
// Expansion indentation
|
||||
if (index != Vue.PC) {
|
||||
indent = new JPanel(null);
|
||||
indent = new JPanel();
|
||||
indent.setOpaque(false);
|
||||
indent.setPreferredSize(new Dimension(0, 0));
|
||||
indent.setVisible(false);
|
||||
|
@ -152,6 +156,9 @@ class Register {
|
|||
// Handling for PSW
|
||||
if (index == Vue.PSW && type == Vue.PSW)
|
||||
setExpanded(true);
|
||||
|
||||
// Apply application settings
|
||||
configure();
|
||||
}
|
||||
|
||||
|
||||
|
@ -191,7 +198,7 @@ class Register {
|
|||
for (int x = 0; x < 2; x++) {
|
||||
|
||||
// Indentation
|
||||
indent = new JPanel(null);
|
||||
indent = new JPanel();
|
||||
indent.setOpaque(false);
|
||||
indent.setPreferredSize(new Dimension(0, 0));
|
||||
var gbc = new GridBagConstraints();
|
||||
|
@ -295,26 +302,29 @@ class Register {
|
|||
lblName.setText(name);
|
||||
|
||||
// Expand button
|
||||
var size = btnExpand.getPreferredSize();
|
||||
size.width = CPUWindow.regExpandWidth;
|
||||
var size = btnExpand.getPreferredSize();
|
||||
var metrics = parent.parent.parent.app.fntDialog.metrics;
|
||||
size.width = 4 + Math.max(
|
||||
metrics.stringWidth(EXPAND), metrics.stringWidth(COLLAPSE));
|
||||
btnExpand.setPreferredSize(size);
|
||||
|
||||
// Value text box
|
||||
var fontSize = CPUWindow.regHexFontSize;
|
||||
size = new Dimension(8 * fontSize.width + 4, fontSize.height);
|
||||
txtValue.setFont(CPUWindow.regHexFont);
|
||||
txtValue.setPreferredSize(size);
|
||||
var fntMono = parent.parent.parent.app.fntMono;
|
||||
int hexDigitWidth = parent.parent.parent.app.hexDigitWidth;
|
||||
txtValue.setFont(fntMono);
|
||||
txtValue.setPreferredSize(new Dimension(
|
||||
hexDigitWidth * 8 + 4, fntMono.metrics.getHeight()));
|
||||
|
||||
// Expansion controls
|
||||
for (var ctrl : controls) {
|
||||
if (!(ctrl instanceof JTextField))
|
||||
continue;
|
||||
if (type == Vue.PC || (Boolean) ctrl.getClientProperty("hex"))
|
||||
((JTextField) ctrl).setFont(CPUWindow.regHexFont);
|
||||
((JTextField) ctrl).setFont(fntMono);
|
||||
int digits = type == Vue.PC ? 8 :
|
||||
(Integer) ctrl.getClientProperty("digits");
|
||||
size = ctrl.getPreferredSize();
|
||||
size.width = digits * fontSize.width + 4;
|
||||
size.width = digits * hexDigitWidth + 4;
|
||||
ctrl.setPreferredSize(size);
|
||||
}
|
||||
}
|
||||
|
@ -397,7 +407,7 @@ class Register {
|
|||
// Change the display mode of a program register
|
||||
void setMode(int mode) {
|
||||
this.mode = mode;
|
||||
txtValue.setFont(mode == HEX ? CPUWindow.regHexFont : null);
|
||||
txtValue.setFont(mode!=HEX ? null : parent.parent.parent.app.fntMono);
|
||||
refresh();
|
||||
}
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ class RegisterList extends JScrollPane {
|
|||
}
|
||||
|
||||
// List terminator
|
||||
var spacer = new JPanel(null);
|
||||
var spacer = new JPanel();
|
||||
spacer.setOpaque(false);
|
||||
spacer.setPreferredSize(new Dimension(0, 0));
|
||||
var gbc = new GridBagConstraints();
|
||||
|
@ -144,7 +144,7 @@ class RegisterList extends JScrollPane {
|
|||
}
|
||||
|
||||
// Apply configuration settings
|
||||
void configure() {
|
||||
void configure2() {
|
||||
|
||||
// Configure registers
|
||||
for (var reg : registers.values())
|
||||
|
@ -152,7 +152,7 @@ class RegisterList extends JScrollPane {
|
|||
|
||||
// Configure component
|
||||
getVerticalScrollBar().setUnitIncrement(
|
||||
CPUWindow.regHexFontSize.height);
|
||||
parent.parent.app.fntMono.metrics.getHeight());
|
||||
}
|
||||
|
||||
// Update the display
|
||||
|
|
|
@ -24,7 +24,7 @@ public final class Util {
|
|||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Types //
|
||||
// Classes //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Event listener interfaces
|
||||
|
@ -43,6 +43,16 @@ public final class Util {
|
|||
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 COND : sym = inst.cond ; 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 ID : sym = inst.id ; break;
|
||||
case OPCODE : sym = inst.opcode ; break;
|
||||
|
|
|
@ -443,8 +443,8 @@ class CPU {
|
|||
|
||||
// First unit
|
||||
if (fetch == 0) {
|
||||
inst.bits = access.value & 0xFFFF;
|
||||
if (Instruction.size(access.value >> 10 & 0x3F) == 4) {
|
||||
inst.bits = access.value;
|
||||
if (Instruction.size(access.value >> 10) == 4) {
|
||||
fetch = 1;
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -114,6 +114,7 @@ public class Instruction {
|
|||
boolean read = false;
|
||||
var ret = new Access();
|
||||
ret.address = vue.getRegister(reg1, false) + disp;
|
||||
ret.fetch = vue.getFetch();
|
||||
ret.type = Vue.S32;
|
||||
|
||||
// Configure descriptor by ID
|
||||
|
@ -139,10 +140,17 @@ public class Instruction {
|
|||
if (read)
|
||||
ret.value = vue.read(ret.address, ret.type);
|
||||
|
||||
// Select the value to write to the bus
|
||||
else ret.value = vue.getRegister(id == Vue.CAXI &&
|
||||
vue.getRegister(reg2, false) == vue.read(ret.address, Vue.S32) ?
|
||||
30 : reg2, false);
|
||||
// Write a register to the bus
|
||||
else if (id != Vue.CAXI)
|
||||
vue.getRegister(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;
|
||||
}
|
||||
|
|
|
@ -76,11 +76,6 @@ class JavaVue extends Vue {
|
|||
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
|
||||
public int getBreakCode() {
|
||||
return breakCode;
|
||||
|
@ -91,11 +86,6 @@ class JavaVue extends Vue {
|
|||
return cpu.exception;
|
||||
}
|
||||
|
||||
// Retrieve a snapshot of the current state's instruction
|
||||
public Instruction getInstruction() {
|
||||
return cpu.inst;
|
||||
}
|
||||
|
||||
// Retrieve a register value
|
||||
public int getRegister(int index, boolean system) {
|
||||
|
||||
|
|
|
@ -141,22 +141,6 @@ JNIEXPORT jint JNICALL Java_vue_NativeVue_emulate
|
|||
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
|
||||
JNIEXPORT jint JNICALL Java_vue_NativeVue_getBreakCode
|
||||
(JNIEnv *env, jobject vue, jlong handle) {
|
||||
|
@ -171,36 +155,6 @@ JNIEXPORT jint JNICALL Java_vue_NativeVue_getExceptionCode
|
|||
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
|
||||
JNIEXPORT jint JNICALL Java_vue_NativeVue_getRegister
|
||||
(JNIEnv *env, jobject vue, jlong handle, jint index, jboolean system) {
|
||||
|
|
|
@ -42,12 +42,6 @@ class NativeVue extends Vue {
|
|||
public int emulate(int 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
|
||||
private native int getBreakCode(long handle);
|
||||
public int getBreakCode() { return getBreakCode(handle); }
|
||||
|
@ -58,12 +52,6 @@ class NativeVue extends Vue {
|
|||
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
|
||||
private native int getRegister(long handle, int index, boolean system);
|
||||
public int getRegister(int index, boolean system)
|
||||
|
|
Loading…
Reference in New Issue