Introducing VIP memory controller and Characters window, fixing Format V instructions, adjusting JNI includes

This commit is contained in:
2020-12-25 17:59:08 -06:00
parent 9f5a5233ea
commit 8192fb6960
36 changed files with 7343 additions and 178 deletions
+18 -7
View File
@@ -265,9 +265,12 @@ static int32_t cpuGetSystemRegister(Vue *vue, int32_t index) {
/* Transfer program to another address */
static void cpuJump(Vue *vue, int32_t address) {
int level = vue->cpu.psw_np ? 2 : vue->cpu.psw_ep;
vue->cpu.jumpFrom[level] = vue->cpu.pc;
vue->cpu.jumpTo [level] = address;
int level;
if (address != vue->cpu.pc) {
level = vue->cpu.psw_np ? 2 : vue->cpu.psw_ep;
vue->cpu.jumpFrom[level] = vue->cpu.pc;
vue->cpu.jumpTo [level] = address;
}
vue->cpu.pc = address - vue->cpu.inst.size;
}
@@ -490,7 +493,9 @@ static vbool cpuWrite(Vue *vue, int32_t address, int8_t type, int32_t value) {
cpuFloat(vue->cpu.program[vue->cpu.inst.reg1]))
/* Add Immediate */
#define cpuADDI(vue) cpuADD_IMM(vue)
#define cpuADDI(vue) \
vue->cpu.program[vue->cpu.inst.reg2] = cpuAdd(vue, \
vue->cpu.program[vue->cpu.inst.reg1], vue->cpu.inst.imm)
/* And */
#define cpuAND(vue) \
@@ -499,7 +504,7 @@ static vbool cpuWrite(Vue *vue, int32_t address, int8_t type, int32_t value) {
/* And Immediate */
#define cpuANDI(vue) \
cpuBitwise(vue, vue->cpu.program[vue->cpu.inst.reg2] & \
cpuBitwise(vue, vue->cpu.program[vue->cpu.inst.reg1] & \
vue->cpu.inst.imm)
/* Branch on Condition */
@@ -756,7 +761,7 @@ static void cpuMULU(Vue *vue) {
/* Or Immediate */
#define cpuORI(vue) \
cpuBitwise(vue, vue->cpu.program[vue->cpu.inst.reg2] | \
cpuBitwise(vue, vue->cpu.program[vue->cpu.inst.reg1] | \
vue->cpu.inst.imm)
/* Return from Trap or Interrupt */
@@ -876,7 +881,7 @@ static void cpuXH(Vue *vue) {
/* Exclusive Or Immediate */
#define cpuXORI(vue) \
cpuBitwise(vue, vue->cpu.program[vue->cpu.inst.reg2] ^ \
cpuBitwise(vue, vue->cpu.program[vue->cpu.inst.reg1] ^ \
vue->cpu.inst.imm)
@@ -1182,6 +1187,12 @@ static vbool cpuFetch(Vue *vue) {
return VUE_FALSE;
}
/*****************************************************************************
* Internal Functions *
******************************************************************************/
/* Process the simulation */
static void cpuEmulate(Vue *vue, uint32_t cycles) {
+6 -1
View File
@@ -244,7 +244,7 @@ struct Vue {
uint16_t ecr_fecc; /* Fatal Error Cause Code */
} cpu;
/* Game pak */
/* Game pak state */
struct {
uint8_t *ram; /* Cartridge SRAM */
uint32_t ramSize; /* Number of bytes in cartridge SRAM */
@@ -254,6 +254,11 @@ struct Vue {
int8_t wcr_rom1w; /* ROM one-wait mode */
} pak;
/* VIP state */
struct {
uint8_t vram[0x40000]; /* Video memory */
} vip;
};
+298
View File
@@ -0,0 +1,298 @@
/* This file is included through vue.c and cannot be built directly. */
#ifdef VUEAPI
/*****************************************************************************
* Internal Functions *
******************************************************************************/
/* Process the simulation */
static void vipEmulate(Vue *vue, uint32_t cycles) {
vue = vue;
cycles = cycles;
}
/* Read an I/O register */
static int32_t vipReadRegister(Vue *vue, int32_t address) {
vue=vue;
/* Process by register */
switch (address & ~1) {
case 0x0005F800: break; /* INTPND */
case 0x0005F802: break; /* INTENB */
case 0x0005F804: break; /* INTCLR */
case 0x0005F820: break; /* DPSTTS */
case 0x0005F822: break; /* DPCTRL */
case 0x0005F824: break; /* BRTA */
case 0x0005F826: break; /* BRTB */
case 0x0005F828: break; /* BRTC */
case 0x0005F82A: break; /* REST */
case 0x0005F82E: break; /* FRMCYC */
case 0x0005F830: break; /* CTA */
case 0x0005F840: break; /* XPSTTS */
case 0x0005F842: break; /* XPCTRL */
case 0x0005F844: break; /* VER */
case 0x0005F848: break; /* SPT0 */
case 0x0005F84A: break; /* SPT1 */
case 0x0005F84C: break; /* SPT2 */
case 0x0005F84E: break; /* SPT3 */
case 0x0005F860: break; /* GPLT0 */
case 0x0005F862: break; /* GPLT1 */
case 0x0005F864: break; /* GPLT2 */
case 0x0005F866: break; /* GPLT3 */
case 0x0005F868: break; /* JPLT0 */
case 0x0005F86A: break; /* JPLT1 */
case 0x0005F86C: break; /* JPLT2 */
case 0x0005F86E: break; /* JPLT3 */
case 0x0005F870: break; /* BKCOL */
}
/* Unmapped */
return 0;
}
/* Read an I/O register */
static void vipWriteRegister(Vue *vue, int32_t address, int32_t value) {
vue=vue;
value=value;
/* Process by register */
switch (address & ~1) {
case 0x0005F800: break; /* INTPND */
case 0x0005F802: break; /* INTENB */
case 0x0005F804: break; /* INTCLR */
case 0x0005F820: break; /* DPSTTS */
case 0x0005F822: break; /* DPCTRL */
case 0x0005F824: break; /* BRTA */
case 0x0005F826: break; /* BRTB */
case 0x0005F828: break; /* BRTC */
case 0x0005F82A: break; /* REST */
case 0x0005F82E: break; /* FRMCYC */
case 0x0005F830: break; /* CTA */
case 0x0005F840: break; /* XPSTTS */
case 0x0005F842: break; /* XPCTRL */
case 0x0005F844: break; /* VER */
case 0x0005F848: break; /* SPT0 */
case 0x0005F84A: break; /* SPT1 */
case 0x0005F84C: break; /* SPT2 */
case 0x0005F84E: break; /* SPT3 */
case 0x0005F860: break; /* GPLT0 */
case 0x0005F862: break; /* GPLT1 */
case 0x0005F864: break; /* GPLT2 */
case 0x0005F866: break; /* GPLT3 */
case 0x0005F868: break; /* JPLT0 */
case 0x0005F86A: break; /* JPLT1 */
case 0x0005F86C: break; /* JPLT2 */
case 0x0005F86E: break; /* JPLT3 */
case 0x0005F870: break; /* BKCOL */
}
}
/* Read a value from the CPU bus */
static int32_t vipRead(Vue *vue, int32_t address, int32_t type) {
int32_t value; /* Register value */
address &= 0x0007FFFF;
/* VRAM */
if (address < 0x00040000)
return readBuffer(vue->vip.vram, 0x40000, address, type);
/* Mirrors of character memory */
if (address >= 0x00078000)
return readBuffer(vue->vip.vram, 0x40000,
(address - 0x00078000) >> 13 << 15 | 0x00006000 |
(address & 0x00001FFF),
type);
/* I/O register or unmapped */
value = vipReadRegister(vue, address);
if (type < 2 && (address & 1) == 1)
value >>= 8;
switch (type) {
case VUE_S8 : return SIGN_EXTEND(value, 8);
case VUE_U8 : return value & 0x000000FF;
case VUE_S16: return SIGN_EXTEND(value, 16);
case VUE_S32: return value | vipReadRegister(vue, address + 2) << 16;
}
return value; /* U16 */
}
/* Read bytes from the CPU bus */
static void vipReadBytes(Vue *vue, int address, uint8_t *dest, int length) {
int32_t count, size, value; /* Working variables */
address &= 0x0007FFFF;
/* Perform the operation */
while (length > 0) {
/* VRAM */
if (address < 0x00040000) {
count = 0x00040000 - address;
if (length < count)
count = length;
readBytes(vue->vip.vram, 0x40000, address, dest, count);
}
/* Mirrors of character memory */
else if (address >= 0x00078000) {
count = 0x2000 - (address & 0x1FFF);
if (length < count)
count = length;
readBytes(vue->vip.vram, 0x40000,
(address - 0x00078000) >> 13 << 15 | 0x00006000 |
(address & 0x00001FFF),
dest, count);
}
/* I/O register or unmapped */
else {
count = 0x00078000 - address;
if (length < count)
count = length;
/* Read all registers in the range */
while (count > 0) {
value = vipReadRegister(vue, address);
/* Odd address */
if ((address & 1) == 1) {
*dest = value >> 8;
address++;
count --;
length --;
dest ++;
continue;
}
/* Even address */
size = count == 1 ? 1 : 2;
*dest = value;
if (size == 2)
dest[1] = value >> 8;
address += size;
count -= size;
length -= size;
dest += size;
}
continue;
}
/* Advance to the next region */
address += count;
length -= count;
dest += count;
}
}
/* System reset */
static void vipReset(Vue *vue) {
vue = vue;
}
/* Determine the number of CPU cycles until a breakpoint could trigger */
static uint32_t vipUntil(Vue *vue, uint32_t cycles) {
vue = vue;
return cycles;
}
/* Write a value to the CPU bus */
static void vipWrite(Vue *vue, int32_t address, int32_t type, int32_t value) {
address &= 0x0007FFFF;
/* VRAM */
if (address < 0x00040000) {
writeBuffer(vue->vip.vram, 0x40000, address, type, value);
return;
}
/* Mirrors of character memory */
if (address >= 0x00078000) {
writeBuffer(vue->vip.vram, 0x40000,
(address - 0x00078000) >> 13 << 15 | 0x00006000 |
(address & 0x00001FFF),
type, value);
return;
}
/* I/O register or unmapped */
if (type < 2 && (address & 1) == 1)
value <<= 8;
vipWriteRegister(vue, address, value);
if (type == VUE_S32)
vipWriteRegister(vue, address + 2, value >> 16);
}
/* Write bytes to the CPU bus */
static void vipWriteBytes(Vue *vue, int address, uint8_t *src, int length) {
int32_t count, size, value; /* Working variables */
address &= 0x0007FFFF;
/* Perform the operation */
while (length > 0) {
/* VRAM */
if (address < 0x00040000) {
count = 0x00040000 - address;
if (length < count)
count = length;
writeBytes(vue->vip.vram, 0x40000, address, src, count);
}
/* Mirrors of character memory */
else if (address >= 0x00078000) {
count = 0x2000 - (address & 0x1FFF);
if (length < count)
count = length;
writeBytes(vue->vip.vram, 0x40000,
(address - 0x00078000) >> 13 << 15 | 0x00006000 |
(address & 0x00001FFF),
src, count);
}
/* I/O register or unmapped */
else {
count = 0x00078000 - address;
if (length < count)
count = length;
/* Read all registers in the range */
while (count > 0) {
value = *src;
/* Odd address */
if ((address & 1) == 1) {
vipWriteRegister(vue, address, value << 8);
address++;
count --;
length --;
src ++;
continue;
}
/* Even address */
size = count == 1 ? 1 : 2;
if (size == 2)
value |= src[1] << 8;
vipWriteRegister(vue, address, value);
address += size;
count -= size;
length -= size;
src += size;
}
continue;
}
/* Advance to the next region */
address += count;
length -= count;
src += count;
}
}
#endif
+45 -23
View File
@@ -22,15 +22,6 @@ static const uint32_t TYPE_SIZES[] = { 1, 1, 2, 2, 4 };
/*****************************************************************************
* Component Includes *
*****************************************************************************/
#include "cpu.c"
#include "gamepak.c"
/*****************************************************************************
* Module Functions *
*****************************************************************************/
@@ -150,6 +141,16 @@ static void writeBytes(uint8_t *data, uint32_t datlen, uint32_t address,
/*****************************************************************************
* Component Includes *
*****************************************************************************/
#include "cpu.c"
#include "gamepak.c"
#include "vip.c"
/*****************************************************************************
* Library Functions *
*****************************************************************************/
@@ -167,7 +168,7 @@ uint32_t vueEmulate(Vue *vue, uint32_t maxCycles) {
/*cycles = padUntil (vue, cycles);*/
/*cycles = linkUntil (vue, cycles);*/
/*cycles = timerUntil(vue, cycles);*/
/*cycles = vipUntil (vue, cycles);*/
cycles = vipUntil (vue, cycles);
/* Process all system components */
vue->breakCode = 0;
@@ -176,7 +177,7 @@ uint32_t vueEmulate(Vue *vue, uint32_t maxCycles) {
/*pakEmulate (vue, cycles);*/
/*linkEmulate (vue, cycles);*/
/*timerEmulate(vue, cycles);*/
/*vipEmulate (vue, cycles);*/
vipEmulate (vue, cycles);
/*vsuEmulate (vue, cycles);*/
maxCycles -= cycles;
} while (vue->breakCode == 0 && maxCycles != 0);
@@ -288,16 +289,6 @@ VueOnAccess vueOnWrite(Vue *vue, VueOnAccess callback) {
return ret;
}
/* Specify a new application reference */
void* vueSetTag(Vue *vue, void *tag) {
void *ret;
if (vue == NULL)
return NULL;
ret = vue->tag;
vue->tag = tag;
return ret;
}
/* Read a value from the CPU bus */
int32_t vueRead(Vue *vue, uint32_t address, int32_t type) {
@@ -307,6 +298,7 @@ int32_t vueRead(Vue *vue, uint32_t address, int32_t type) {
/* Perform the operation */
switch (address >> 24 & 7) {
case 0: return vipRead (vue , address,type);
case 5: return readBuffer(vue->wram , 0x10000,address,type);
case 6: return readBuffer(vue->pak.ram,vue->pak.ramSize,address,type);
case 7: return readBuffer(vue->pak.rom,vue->pak.romSize,address,type);
@@ -328,6 +320,8 @@ vbool vueReadBytes(Vue *vue, uint32_t address, uint8_t *dest, uint32_t length){
if (length < count)
count = length;
switch (address >> 24 & 7) {
case 0: vipReadBytes(vue ,
address, dest, count); break;
case 5: readBytes(vue->wram , 0x10000,
address, dest, count); break;
case 6: readBytes(vue->pak.ram, vue->pak.ramSize,
@@ -363,8 +357,22 @@ void vueReset(Vue *vue) {
/* Specify a value for a register */
int32_t vueSetRegister(Vue *vue, int32_t index, vbool system, int32_t value) {
return vue == NULL ? 0 :
index == VUE_PC && system ? vue->cpu.pc = value & 0xFFFFFFFE :
/* Error checking */
if (vue == NULL)
return 0;
/* PC */
if (index == VUE_PC && system) {
if (vue->cpu.stage == CPU_EXECUTE || vue->cpu.stage == CPU_FETCH) {
vue->cpu.fetch = -1;
vue->cpu.stage = CPU_FETCH;
}
return vue->cpu.pc = value & 0xFFFFFFFE;
}
/* Other */
return
index < 0 || index > 31 ? 0 :
system ? cpuSetSystemRegister(vue, index, value, VUE_TRUE) :
index == 0 ? 0 : (vue->cpu.program[index] = value)
@@ -388,6 +396,16 @@ vbool vueSetROM(Vue *vue, uint8_t *rom, uint32_t size) {
return VUE_TRUE;
}
/* Specify a new application reference */
void* vueSetTag(Vue *vue, void *tag) {
void *ret;
if (vue == NULL)
return NULL;
ret = vue->tag;
vue->tag = tag;
return ret;
}
/* Write a value to the CPU bus */
void vueWrite(Vue *vue, uint32_t address, int32_t type, int32_t value) {
@@ -397,6 +415,8 @@ void vueWrite(Vue *vue, uint32_t address, int32_t type, int32_t value) {
/* Perform the operation */
switch (address >> 24 & 7) {
case 0: vipWrite(vue ,
address, type, value); break;
case 5: writeBuffer(vue->wram , 0x10000,
address, type, value); break;
case 6: writeBuffer(vue->pak.ram, vue->pak.ramSize,
@@ -421,6 +441,8 @@ vbool vueWriteBytes(Vue *vue, uint32_t address, uint8_t *src, uint32_t length){
if (length < count)
count = length;
switch (address >> 24 & 7) {
case 0: vipWriteBytes(vue ,
address, src, count); break;
case 5: writeBytes(vue->wram , 0x10000,
address, src, count); break;
case 6: writeBytes(vue->pak.ram, vue->pak.ramSize,
+2 -5
View File
@@ -23,6 +23,7 @@ public class App {
int hexDigitWidth; // Width in pixels of one hex digit
Localizer localizer; // UI localization manager
int[][] rgbBase; // Base anaglyph filter colors
int rgbClear; // Transparent pixel color
@@ -36,11 +37,6 @@ public class App {
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;
///////////////////////////////////////////////////////////////////////////
@@ -60,6 +56,7 @@ public class App {
{ "Consolas", Font.MONOSPACED } ), Font.PLAIN, 14));
hexDigitWidth = hexDigitWidth();
rgbBase = new int[][] { GREEN, MAGENTA, RED };
rgbClear = 0x003050;
// Additional processing
setUseNative(useNative);
+17 -19
View File
@@ -25,11 +25,11 @@ class BreakpointsWindow extends ChildWindow {
private JCheckBox chkExecute; // Execute check box
private JCheckBox chkRead; // Read check box
private JCheckBox chkWrite; // Write check box
private JPanel client; // Client area
private UPanel client; // Client area
private JLabel errAddress; // Address error text
private JLabel errCondition; // Condition error text
private JPanel lstBreakpoints; // Breakpoint list
private JPanel spacer; // List termination spacer
private UPanel lstBreakpoints; // Breakpoint list
private UPanel spacer; // List termination spacer
private JTextField txtAddress; // Address text box
private JTextField txtCondition; // Condition text box
private JTextField txtName; // Name text box
@@ -161,31 +161,29 @@ class BreakpointsWindow extends ChildWindow {
selectedIndex = -1;
// Configure client area
client = new JPanel(new BorderLayout());
client = new UPanel(new BorderLayout());
client.setBackground(SystemColor.control);
client.setFocusable(true);
client.setPreferredSize(new Dimension(320, 240));
// Configure breakpoint list
lstBreakpoints = new JPanel(new GridBagLayout()) {
public void paintComponent(Graphics g) {
super.paintComponent(g);
onPaint((Graphics2D) g, getWidth(), getHeight());
}
};
lstBreakpoints = new UPanel(new GridBagLayout());
lstBreakpoints.setFocusable(true);
lstBreakpoints.setBackground(SystemColor.window);
lstBreakpoints.addFocusListener(Util.onFocus(
e->lstBreakpoints.repaint(), e->lstBreakpoints.repaint()));
lstBreakpoints.addMouseListener(Util.onMouse(e->onMouseDown(e), null));
lstBreakpoints.addPaintListener((g,w,h)->onPaint(g, w, h));
var scr = new JScrollPane(lstBreakpoints);
scr.getVerticalScrollBar().setUnitIncrement(
parent.app.fntDialog.metrics.getHeight());
client.add(scr, BorderLayout.CENTER);
spacer = new JPanel();
spacer = new UPanel();
spacer.setOpaque(false);
lstBreakpoints.add(spacer, SPACER);
// Configure properties pane
var props = new JPanel(new GridBagLayout());
var props = new UPanel(new GridBagLayout());
props.setBackground(SystemColor.control);
props.addMouseListener(
Util.onMouse(e->client.requestFocus(), null));
@@ -215,12 +213,12 @@ class BreakpointsWindow extends ChildWindow {
errCondition = error(props);
// Configure buttons
var buttons = new JPanel(new GridBagLayout());
var buttons = new UPanel(new GridBagLayout());
var gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.gridwidth = GridBagConstraints.REMAINDER;
props.add(buttons, gbc);
var fill = new JPanel();
var fill = new UPanel();
fill.setOpaque(false);
fill.addMouseListener(Util.onMouse(e->onDebug(e), null));
gbc = new GridBagConstraints();
@@ -448,7 +446,7 @@ class BreakpointsWindow extends ChildWindow {
///////////////////////////////////////////////////////////////////////////
// Add a button to the form
private JButton button(JPanel panel, String key, boolean last) {
private JButton button(UPanel panel, String key, boolean last) {
var btn = new JButton();
if (key != null)
parent.app.localizer.add(btn, key);
@@ -462,7 +460,7 @@ class BreakpointsWindow extends ChildWindow {
}
// Add a check box to the form
private JCheckBox checkBox(JPanel panel, String key, boolean last) {
private JCheckBox checkBox(UPanel panel, String key, boolean last) {
var chk = new JCheckBox();
if (key != null)
parent.app.localizer.add(chk, key);
@@ -509,7 +507,7 @@ class BreakpointsWindow extends ChildWindow {
}
// Add an error label to the form
private JLabel error(JPanel panel) {
private JLabel error(UPanel panel) {
var lbl = new JLabel();
lbl.setForeground(Color.red);
lbl.setVisible(false);
@@ -524,7 +522,7 @@ class BreakpointsWindow extends ChildWindow {
}
// Add a label to the form
private void label(JPanel panel, String key, int top) {
private void label(UPanel panel, String key, int top) {
var lbl = new JLabel();
if (key != null)
parent.app.localizer.add(lbl, key);
@@ -594,7 +592,7 @@ class BreakpointsWindow extends ChildWindow {
}
// Add a text box to the form
private JTextField textBox(JPanel panel, boolean mono, int top,
private JTextField textBox(UPanel panel, boolean mono, int top,
Commit handler) {
var txt = new JTextField();
txt.setEnabled(false);
+367 -51
View File
@@ -13,14 +13,29 @@ import util.*;
class CharactersWindow extends ChildWindow {
// Instance fields
private int color; // Selected color index
private int color; // Selected color index
private Point dragging; // Most recent pattern mouse position
private int index; // Current character index
private boolean grid; // Draw a grid around characters
private int palette; // Palette index
private int scale; // Display scale
private int wide; // Number of characters per row
// UI components
private JPanel client; // Client area
private JPanel panCharacters; // Characters panel
private JPanel panPalette; // Palette panel
private JPanel panPattern; // Pattern panel
private JCheckBox chkGrid; // Grid check box
private UPanel client; // Client area
private UPanel panCharacters; // Characters panel
private UPanel panPalette; // Palette panel
private UPanel panPattern; // Pattern panel
private JScrollPane scrCharacters; // Characters container
private JScrollPane scrControls; // Controls panel
private JScrollBar scrWidth; // Width template scroll bar
private JSlider sldScale; // Scale slider
private JSpinner spnIndex; // Index spinner
private JSpinner spnWide; // Wide spinner
private JTextField txtAddress; // Address text box
private JTextField txtMirror; // Mirror text box
private JComboBox<String> cmbPalette; // Palette drop-down
@@ -34,16 +49,21 @@ class CharactersWindow extends ChildWindow {
// Configure instance fields
color = 0;
grid = true;
scale = 3;
// Template scroll bar to check control width in the current LAF
scrWidth = new JScrollBar(JScrollBar.VERTICAL);
// Configure client area
client = new JPanel(new BorderLayout());
client = new UPanel(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());
var ctrls = new UPanel(new GridBagLayout());
ctrls.setBackground(SystemColor.control);
ctrls.addMouseListener(
Util.onMouse(e->client.requestFocus(), null));
@@ -54,17 +74,29 @@ class CharactersWindow extends ChildWindow {
scrControls.getVerticalScrollBar().setUnitIncrement(20);
client.add(scrControls, BorderLayout.WEST);
// Character controls
label(ctrls, "characters.index", true);
spinner(ctrls, 0, 2047, 0, true);
spnIndex = spinner(ctrls, 0, 2047, 0, true);
spnIndex.addChangeListener(e->{
setIndex((Integer) spnIndex.getValue()); });
label(ctrls, "characters.address", false);
textBox(ctrls);
txtAddress = textBox(ctrls);
txtAddress.addFocusListener(Util.onFocus(null,
e->onAddress(txtAddress)));
label(ctrls, "characters.mirror", false);
textBox(ctrls);
txtMirror = textBox(ctrls);
txtMirror.addFocusListener(Util.onFocus(null,
e->onAddress(txtMirror)));
// Pattern panel
var panPattern = new JPanel();
panPattern.setBackground(Color.black);
panPattern = new UPanel();
panPattern.setOpaque(false);
panPattern.setPreferredSize(new Dimension(96, 96));
panPattern.addMouseListener(
Util.onMouse(e->onMousePattern(e), e->onMousePattern(e)));
panPattern.addMouseMotionListener(
Util.onMouseMove(null, e->onMousePattern(e)));
panPattern.addPaintListener((g,w,h)->onPaintPattern(g, w, h));
var gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.CENTER;
gbc.gridwidth = GridBagConstraints.REMAINDER;
@@ -72,16 +104,12 @@ class CharactersWindow extends ChildWindow {
ctrls.add(panPattern, gbc);
// Palette panel
panPalette = new JPanel() {
public void paintComponent(Graphics g) {
super.paintComponent(g);
onPaintPalette((Graphics2D) g, getWidth(), getHeight());
}
};
panPalette = new UPanel();
panPalette.setOpaque(false);
panPalette.setPreferredSize(new Dimension(0, 20 + 6));
panPalette.addMouseListener(
Util.onMouse(e->onMouseDownPalette(e), null));
panPalette.addPaintListener((g,w,h)->onPaintPalette(g, w, h));
gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.gridwidth = GridBagConstraints.REMAINDER;
@@ -89,27 +117,37 @@ class CharactersWindow extends ChildWindow {
ctrls.add(panPalette, gbc);
// Fill the extra space above the view controls
var spacer = new JPanel();
var spacer = new UPanel();
spacer.setOpaque(false);
gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.weighty = 1;
ctrls.add(spacer, gbc);
// View controls
label(ctrls, "characters.grid", false);
checkBox(ctrls).setSelected(true);
chkGrid = checkBox(ctrls);
chkGrid.setSelected(grid);
chkGrid.addActionListener(e->{
grid = chkGrid.isSelected(); onView(); });
label(ctrls, "characters.wide", false);
spinner(ctrls, 0, 2048, 0, false);
spnWide = spinner(ctrls, 0, 2048, 0, false);
spnWide.addChangeListener(e->{
wide = (Integer) spnWide.getValue(); onView(); });
label(ctrls, "characters.palette", false);
select(ctrls, new String[] { "palette.generic",
cmbPalette = select(ctrls, new String[] { "palette.generic",
"palette.gplt0", "palette.gplt1", "palette.gplt2", "palette.gplt3",
"palette.jplt0", "palette.jplt1", "palette.jplt2", "palette.jplt3"
});
cmbPalette.addActionListener(e->{
palette = cmbPalette.getSelectedIndex(); repaint(); });
label(ctrls, "characters.scale", false);
slider(ctrls, 1, 10, 1);
sldScale = slider(ctrls, 1, 10, scale);
sldScale.addChangeListener(e->{
scale = sldScale.getValue(); onView(); });
// Terminate the list of controls
spacer = new JPanel();
spacer = new UPanel();
spacer.setOpaque(false);
spacer.setPreferredSize(new Dimension(0, 0));
gbc = new GridBagConstraints();
@@ -118,20 +156,17 @@ class CharactersWindow extends ChildWindow {
ctrls.add(spacer, gbc);
// Configure characters panel
panCharacters = new JPanel() {
public void paintComponent(Graphics g) {
super.paintComponent(g);
onPaintCharacters((Graphics2D) g, getWidth(), getHeight());
}
};
panCharacters = new UPanel();
panCharacters.setBackground(SystemColor.control);
panCharacters.addMouseListener(
Util.onMouse(e->client.requestFocus(), null));
var scr = new JScrollPane(panCharacters);
client.add(scr, BorderLayout.CENTER);
Util.onMouse(e->onMouseDownCharacters(e), null));
panCharacters.addPaintListener((g,w,h)->onPaintCharacters(g, w, h));
scrCharacters = new JScrollPane(panCharacters);
client.add(scrCharacters, BorderLayout.CENTER);
// Configure component
setContentPane(client);
setIndex(0);
pack();
}
@@ -152,6 +187,64 @@ class CharactersWindow extends ChildWindow {
// Event Handlers //
///////////////////////////////////////////////////////////////////////////
// Address and Mirror text box commit
private void onAddress(JTextField src) {
int address;
// Parse the given address
try { address = (int) Long.parseLong(src.getText(), 16); }
catch (Exception e) {
setIndex(index);
return;
}
// Restrict address range
if ((address >> 24 & 7) != 0) {
setIndex(index);
return;
}
address &= 0x0007FFFF;
// Character memory
if ((address & 0x00066000) == 0x00006000)
index = address >> 15 << 9 | address >> 4 & 511;
// Mirror of character memory
else if (address >= 0x00078000)
index = address - 0x00078000 >> 4;
// Common processing
setIndex(index);
}
// Characters mouse button press
private void onMouseDownCharacters(MouseEvent e) {
// Common processing
client.requestFocus();
// Only consider left clicks
if (e.getButton() != MouseEvent.BUTTON1)
return;
// Working variables
int grid = this.grid ? 1 : 0;
int size = 8 * scale + grid;
int wide = this.wide != 0 ? this.wide :
Math.max(1, (panCharacters.getWidth() + grid) / size);
int col = e.getX() / size;
int row = e.getY() / size;
// The pixel is not within a character
if (col >= wide || row >= (2047 + wide) / wide)
return;
// Calculate the index of the selected character
int index = row * wide + col;
if (index < 2048)
setIndex(index);
}
// Palette mouse button press
private void onMouseDownPalette(MouseEvent e) {
@@ -183,16 +276,154 @@ class CharactersWindow extends ChildWindow {
panPalette.repaint();
}
// Pattern mouse
private void onMousePattern(MouseEvent e) {
int id = e.getID();
// Mouse release
if (id == MouseEvent.MOUSE_RELEASED) {
if (e.getButton() == MouseEvent.BUTTON1)
dragging = null;
return;
}
// Mouse press
if (id == MouseEvent.MOUSE_PRESSED) {
if (e.getButton() != MouseEvent.BUTTON1)
return;
dragging = e.getPoint();
}
// Not dragging
if (dragging == null)
return;
// Configure working variables
var pix = parent.chrs[index];
var pos = e.getPoint();
int scale = Math.max(1, Math.min(
panPattern.getWidth() / 8, panPattern.getHeight() / 8));
// Determine the bounds of the line segment
int left = Math.min(dragging.x, pos.x) / scale;
int right = (Math.max(dragging.x, pos.x) - 1) / scale;
int top = Math.min(dragging.y, pos.y) / scale;
int bottom = (Math.max(dragging.y, pos.y) - 1) / scale;
if (left >= 8 || right < 0 || top >= 8 || bottom < 0) {
dragging = pos;
return;
}
// The line segment occupies a single column of pixels
if (left == right) {
top = Math.max(0, top );
bottom = Math.min(7, bottom);
// Draw the column
for (
int y = top, dest = left + top * 8;
y <= bottom;
y++, dest += 8
) pix[dest] = (byte) color;
// Update the current VRAM state
parent.encode(index);
dragging = pos;
return;
}
// Calculate and order the vertex coordinates
float v0x = (float) dragging.x / scale;
float v0y = (float) dragging.y / scale;
float v1x = (float) pos .x / scale;
float v1y = (float) pos .y / scale;
if (v0x > v1x) {
float t = v0x; v0x = v1x; v1x = t;
t = v0y; v0y = v1y; v1y = t;
}
// Determine the starting position of the line segment
float slope = (v1y - v0y) / (v1x - v0x);
float cur, next;
if (v0x < 0) {
left = 0;
cur = v0y - slope * v0x;
next = cur + slope;
} else {
cur = v0y;
next = v0y + slope * (1 - v0x % 1);
}
// Draw all columns of pixels
int last = Math.min(7, right);
for (int x = left; x <= last; x++) {
// The column is the final column in the line segment
if (x == right)
next = v1y;
// Determine the top and bottom rows of pixels
v0y = Math.max(cur, next);
if (v0y % 1 == 0)
v0y--;
top = Math.max(0, (int) Math.floor(Math.min(cur, next)));
bottom = Math.min(7, (int) Math.floor(v0y ));
// Draw the column
for (
int y = top, dest = x + top * 8;
y <= bottom;
y++, dest += 8
) pix[dest] = (byte) color;
// Advance to the next column
cur = next;
next += slope;
}
// Update the current VRAM state
parent.encode(index);
dragging = pos;
}
// Characters paint
private void onPaintCharacters(Graphics2D g, int width, int height) {
g.setColor(new Color(0x001830));
g.fillRect(0, 0, 256, 512);
var clear = new Color(parent.app.rgbClear);
int grid = this.grid ? 1 : 0;
var pal = parent.palettes[palette][MainWindow.RED];
var pix = new byte[64];
int size = scale * 8 + grid;
int wide = this.wide != 0 ? this.wide :
Math.max(1, (width + grid) / size);
int tall = (2047 + wide) / wide;
// Draw all characters
for (int Y = 0, y = 0, z = 0; y < tall; y++, Y += size)
for (int X = 0, x = 0; x < wide; x++, z++, X += size) {
if (z == 2048)
break;
g.setColor(clear);
g.fillRect(X, Y, size - grid, size - grid);
drawCharacter(g, X, Y, scale, z, pal);
}
// Highlight the selected character
int X = index % wide * size;
int Y = index / wide * size;
int light = SystemColor.textHighlight.getRGB() & 0x00FFFFFF;
g.setColor(new Color(0xD0000000 | light, true));
g.drawRect(X , Y , 8 * scale - 1, 8 * scale - 1);
g.setColor(new Color(0x90000000 | light, true));
g.drawRect(X + 1, Y + 1, 8 * scale - 3, 8 * scale - 3);
g.setColor(new Color(0x50000000 | light, true));
g.fillRect(X + 2, Y + 2, 8 * scale - 4, 8 * scale - 4);
}
// 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;
var pal = parent.palettes[palette][MainWindow.RED];
int top = (height - size - 6) / 2;
// Draw the color picker
@@ -207,27 +438,85 @@ class CharactersWindow extends ChildWindow {
}
// Draw the color area
g.setColor(Color.black);
g.setColor(x == 0 ? new Color(parent.app.rgbClear) : pal[x]);
g.fillRect(left + 3, top + 3, size , size );
}
}
// Pattern paint
private void onPaintPattern(Graphics2D g, int width, int height) {
int scale = Math.max(1, Math.min(width >> 3, height >> 3));
int x = (width - (scale << 3) + 1) >> 1;
int y = (height - (scale << 3) + 1) >> 1;
g.setColor(new Color(parent.app.rgbClear));
g.fillRect(x, y, scale * 8, scale * 8);
drawCharacter(g, x, y, scale, index,
parent.palettes[palette][MainWindow.RED]);
}
// 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();
if (inner != outer) {
scrControls.setPreferredSize(new Dimension(
scrControls.getPreferredSize().width + inner - outer, 0));
scrControls.revalidate();
scrControls.repaint();
}
// The number of characters per row is dynamic
if (wide == 0) {
var bar = scrWidth.getPreferredSize().width;
var border = scrCharacters.getBorder();
int grid = this.grid ? 1 : 0;
var insets = border == null ? new Insets(0, 0, 0, 0) :
border.getBorderInsets(scrCharacters);
var size = new Dimension(
scrCharacters.getWidth () - insets.left - insets.right,
scrCharacters.getHeight() - insets.top - insets.bottom
);
// Calculate the dimensions without the vertical scroll bar
int wide = Math.max(1, (size.width + grid) / (8 * scale + grid));
int height = (2047 + wide) / wide * (8 * scale + grid) - grid;
// Calculate the dimensions with the vertical scroll bar
if (height > size.height) {
wide = Math.max(1, (size.width-bar+grid) / (8 * scale + grid));
height = (2047 + wide) / wide * (8 * scale + grid) - grid;
}
// Configure the component
panCharacters.setPreferredSize(
new Dimension(wide * (8 * scale + grid) - grid, height));
panCharacters.revalidate();
panCharacters.repaint();
}
}
// View control changed
private void onView() {
// Number of characters per row is dynamic: defer to resize processing
if (wide == 0) {
onResize();
return;
}
// Calculate the space occupied by the character images
int grid = this.grid ? 1 : 0;
panCharacters.setPreferredSize(new Dimension(
wide * (scale * 8 + grid) - grid,
(2047 + wide) / wide * (scale * 8 + grid) - grid
));
panCharacters.revalidate();
panCharacters.repaint();
}
@@ -237,7 +526,7 @@ class CharactersWindow extends ChildWindow {
///////////////////////////////////////////////////////////////////////////
// Add a check box to the controls panel
private JCheckBox checkBox(JPanel panel) {
private JCheckBox checkBox(UPanel panel) {
var chk = new JCheckBox();
chk.setBorder(null);
chk.setFocusable(false);
@@ -249,8 +538,21 @@ class CharactersWindow extends ChildWindow {
return chk;
}
// Draw a character
private void drawCharacter(Graphics2D g, int X, int Y, int scale,
int index, Color[] pal) {
var pix = parent.chrs[index];
for (int y = 0, src = 0; y < 8; y++)
for (int x = 0; x < 8; x++, src++) {
if (pix[src] == 0)
continue;
g.setColor(pal[pix[src]]);
g.fillRect(X + x * scale, Y + y * scale, scale, scale);
}
}
// Add a label to the controls panel
private void label(JPanel panel, String key, boolean top) {
private void label(UPanel panel, String key, boolean top) {
var lbl = new JLabel();
parent.app.localizer.add(lbl, key);
var gbc = new GridBagConstraints();
@@ -260,7 +562,7 @@ class CharactersWindow extends ChildWindow {
}
// Add a combo box to the controls panel
private JComboBox<String> select(JPanel panel, String[] options) {
private JComboBox<String> select(UPanel panel, String[] options) {
var cmb = new JComboBox<String>();
parent.app.localizer.add(cmb, options);
cmb.setSelectedIndex(0);
@@ -272,8 +574,19 @@ class CharactersWindow extends ChildWindow {
return cmb;
}
// Specify the current character index
private void setIndex(int index) {
this.index = index;
spnIndex.setValue(index);
txtAddress.setText(String.format("%08X",
index >> 9 << 15 | 0x00006000 | (index & 511) << 4));
txtMirror .setText(String.format("%08X",
index << 4 | 0x00078000));
repaint();
}
// Add a slider to the controls panel
private JSlider slider(JPanel panel, int min, int max, int value) {
private JSlider slider(UPanel 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));
@@ -286,10 +599,12 @@ class CharactersWindow extends ChildWindow {
}
// Add a spinner to the controls panel
private JSpinner spinner(JPanel panel, int min, int max, int value,
private JSpinner spinner(UPanel 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 txt = new JSpinner.NumberEditor(spn, "#");
txt.getTextField().addActionListener(e->client.requestFocus());
spn.setEditor(txt);
var gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.BOTH;
gbc.gridwidth = GridBagConstraints.REMAINDER;
@@ -300,9 +615,10 @@ class CharactersWindow extends ChildWindow {
}
// Add a text box to the controls panel
private JTextField textBox(JPanel panel) {
private JTextField textBox(UPanel panel) {
var txt = new JTextField();
txt.setFont(parent.app.fntMono);
txt.addActionListener(e->client.requestFocus());
var size = txt.getPreferredSize();
txt.setPreferredSize(new Dimension(
parent.app.hexDigitWidth * 8 + 2 + size.width, size.height));
+3 -7
View File
@@ -21,7 +21,7 @@ class DisassemblerPane extends JScrollPane {
private int[] widths; // Column widths
// UI components
private JPanel client; // Client area
private UPanel client; // Client area
private ArrayList<Row> rows; // Disassembler output
@@ -53,12 +53,7 @@ class DisassemblerPane extends JScrollPane {
widths = new int[5];
// Configure client area
client = new JPanel() {
public void paintComponent(Graphics g) {
super.paintComponent(g);
onPaint((Graphics2D) g, getWidth(), getHeight());
}
};
client = new UPanel();
client.setBackground(SystemColor.window);
client.setFocusable(true);
client.addFocusListener(
@@ -66,6 +61,7 @@ class DisassemblerPane extends JScrollPane {
client.addKeyListener(Util.onKey(e->onKeyDown(e), null));
client.addMouseListener(Util.onMouse(e->client.requestFocus(), null));
client.addMouseWheelListener(e->onMouseWheel(e));
client.addPaintListener((g,w,h)->onPaint(g, w, h));
// Configure component
setViewportView(client);
+52 -30
View File
@@ -15,11 +15,12 @@ import vue.*;
class MainWindow extends JFrame {
// Instance fields
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
App app; // Containing application
Breakpoint brkStep; // Single step internal breakpoint
byte[][] chrs; // Decoded pixel patterns
Color[][][] palettes; // Raster palettes
byte[] vram; // Snapshot of VIP memory
Vue vue; // Emulation core context
// Private fields
private boolean debugMode; // Window is in debug mode
@@ -30,10 +31,10 @@ class MainWindow extends JFrame {
private File romFile; // Currently loaded ROM file
// UI components
private JPanel client; // Common client container
private UPanel client; // Common client container
private JDesktopPane desktop; // Container for child windows
private JMenu mnuDebug; // Debug menu
private JPanel video; // Video output
private UPanel video; // Video output
private JMenuItem mnuFileDebugMode; // File -> Debug mode
private JMenuItem mnuFileGameMode; // File -> Game mode
@@ -74,17 +75,6 @@ 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 //
///////////////////////////////////////////////////////////////////////////
@@ -95,26 +85,29 @@ class MainWindow extends JFrame {
// Configure instance fields
this.app = app;
palettes = new int[9][3][4];
chrs = new byte[2048][64];
palettes = new Color[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);
// Initialize palettes
var invis = new Color(0, true);
for (int x = 0; x < 9; x++)
for (int y = 0; y < 3; y++)
for (int z = 0; z < 4; z++)
palettes[x][y][z] = invis;
// Configure video pane
video = new JPanel() {
public void paintComponent(Graphics g) {
super.paintComponent(g);
onPaintVideo((Graphics2D) g, getWidth(), getHeight());
}
};
video = new UPanel();
video.setPreferredSize(new Dimension(384, 224));
video.setFocusable(true);
video.addPaintListener((g,w,h)->onPaintVideo(g, w, h));
// Configure client area
client = new JPanel(new BorderLayout());
client = new UPanel(new BorderLayout());
client.add(video, BorderLayout.CENTER);
// Configure window
@@ -258,12 +251,28 @@ class MainWindow extends JFrame {
// Package Methods //
///////////////////////////////////////////////////////////////////////////
// Encode a character graphic
void encode(int index) {
int dest = index >> 9 << 15 | 0x00006000 | (index & 511) << 4;
var pix = chrs[index];
for (int y = 0, src = 0; y < 8; y++)
for (int b = 0, bits = 0; b < 2; b++, vram[dest++] = (byte) bits)
for (int x = 0; x < 4; x++, src++)
bits = bits >> 2 | pix[src] << 6;
vue.writeBytes(dest - 16, pix, dest - 16, 16);
refreshDebugLite(false);
}
// Refresh all debug views
void refreshDebug(boolean seekToPC) {
vue.readBytes(0x00000000, vram, 0, vram.length);
refreshCharacters();
refreshPalettes();
refreshDebugLite(seekToPC);
}
// Refresh all debug views without retrieving video memory
void refreshDebugLite(boolean seekToPC) {
breakpoints.refresh();
characters .refresh();
cpu .refresh(seekToPC);
@@ -403,6 +412,18 @@ class MainWindow extends JFrame {
// Private Methods //
///////////////////////////////////////////////////////////////////////////
// Update the character patterns
private void refreshCharacters() {
for (int index = 0; index < 2048; index++) {
var pix = chrs[index];
int src = index >> 9 << 15 | 0x00006000 | (index & 511) << 4;
for (int y = 0, dest = 0; y < 8; y++)
for (int b = 0; b < 2; b++, src++)
for (int x = 0, bits = vram[src]; x < 4; x++, dest++, bits >>= 2)
pix[dest] = (byte) (bits & 3);
}
}
// Update the palette composites
private void refreshPalettes() {
@@ -440,9 +461,10 @@ class MainWindow extends JFrame {
var base = app.rgbBase[y];
var dest = palettes[x][y];
for (int z = 1; z < 4; z++) {
dest[z] = 0xFF000000;
int argb = 0xFF000000;
for (int w = 0, bits = 16; w < 3; w++, bits -= 8)
dest[z] |= (pal[z] * base[w] + 255) / 510 << bits;
argb |= (pal[z] * base[w] + 255) / 510 << bits;
dest[z] = new Color(argb);
}
}
+3 -3
View File
@@ -16,7 +16,7 @@ class MemoryWindow extends ChildWindow {
private int address; // Address of top row
// UI components
private JPanel client; // Client area
private UPanel client; // Client area
private ArrayList<Row> rows; // Rows of text
@@ -46,7 +46,7 @@ class MemoryWindow extends ChildWindow {
rows = new ArrayList<Row>();
// Configure client area
client = new JPanel(null);
client = new UPanel();
client.addComponentListener(Util.onResize(e->onResize()));
client.addKeyListener(Util.onKey(e->onKeyDown(e), null));
client.addMouseWheelListener(e->onWheel(e));
@@ -55,7 +55,7 @@ class MemoryWindow extends ChildWindow {
client.setPreferredSize(new Dimension(480, 360));
// Configure component
var content = new JPanel(new BorderLayout());
var content = new UPanel(new BorderLayout());
content.setBorder(new JScrollPane().getBorder());
content.add(client, BorderLayout.CENTER);
setContentPane(content);
+11 -11
View File
@@ -24,9 +24,9 @@ class Register {
private int value; // Current register value
// UI components
JPanel expansion; // Expansion container
UPanel expansion; // Expansion container
JLabel btnExpand; // Expand button
JPanel indent; // Expansion area indentation
UPanel indent; // Expansion area indentation
JLabel lblName; // Register name
JTextField txtValue; // Register value
ArrayList<JComponent> controls; // Expansion controls
@@ -133,7 +133,7 @@ class Register {
// Expansion indentation
if (index != Vue.PC) {
indent = new JPanel();
indent = new UPanel();
indent.setOpaque(false);
indent.setPreferredSize(new Dimension(0, 0));
indent.setVisible(false);
@@ -169,20 +169,20 @@ class Register {
// Expansion controls for CHCW
private void initCHCW() {
expansion = new JPanel(new GridBagLayout());
expansion = new UPanel(new GridBagLayout());
addCheckBox("ICE", 1, false, true);
}
// Expansion controls for ECR
private void initECR() {
expansion = new JPanel(new GridBagLayout());
expansion = new UPanel(new GridBagLayout());
addTextBox("EICC", 0, 16, false, true);
addTextBox("FECC", 16, 16, false, true);
}
// Expansion controls for program registers
private void initProgram() {
expansion = new JPanel(new GridBagLayout());
expansion = new UPanel(new GridBagLayout());
var group = new ButtonGroup();
group.add(addRadioButton("cpu.hex" , HEX ));
group.add(addRadioButton("cpu.signed" , SIGNED ));
@@ -192,13 +192,13 @@ class Register {
// Expansion controls for PC
private void initPC() {
expansion = new JPanel(new GridBagLayout());
expansion = new UPanel(new GridBagLayout());
// Configure controls
for (int x = 0; x < 2; x++) {
// Indentation
indent = new JPanel();
indent = new UPanel();
indent.setOpaque(false);
indent.setPreferredSize(new Dimension(0, 0));
var gbc = new GridBagConstraints();
@@ -234,7 +234,7 @@ class Register {
// Expansion controls for PSW
private void initPSW() {
expansion = new JPanel(new GridBagLayout());
expansion = new UPanel(new GridBagLayout());
addCheckBox("Z" , 0, false, false);
addCheckBox("FRO", 9, false, true );
addCheckBox("S" , 1, false, false);
@@ -254,13 +254,13 @@ class Register {
// Expansion controls for PIR
private void initPIR() {
expansion = new JPanel(new GridBagLayout());
expansion = new UPanel(new GridBagLayout());
addTextBox("PT", 0, 16, true, true);
}
// Expansion controls for TKCW
private void initTKCW() {
expansion = new JPanel(new GridBagLayout());
expansion = new UPanel(new GridBagLayout());
addCheckBox("OTM", 8, true, false);
addCheckBox("FVT", 5, true, true );
addCheckBox("FIT", 7, true, false);
+3 -3
View File
@@ -20,7 +20,7 @@ class RegisterList extends JScrollPane {
private boolean shown; // Component has been shown
// UI components
private JPanel client; // Client area
private UPanel client; // Client area
@@ -38,7 +38,7 @@ class RegisterList extends JScrollPane {
shown = true;
// Configure client area
client = new JPanel(new GridBagLayout()) {
client = new UPanel(new GridBagLayout()) {
public Dimension getPreferredSize() {
var ret = super.getPreferredSize();
if (!shown) ret.height = system ? getInitialHeight() : 0;
@@ -85,7 +85,7 @@ class RegisterList extends JScrollPane {
}
// List terminator
var spacer = new JPanel();
var spacer = new UPanel();
spacer.setOpaque(false);
spacer.setPreferredSize(new Dimension(0, 0));
var gbc = new GridBagConstraints();
+93
View File
@@ -0,0 +1,93 @@
package util;
// Java imports
import java.awt.*;
import java.util.*;
import javax.swing.*;
// Wrapper around JPanel to work around a bug in GridBagLayout
public class UPanel extends JPanel {
// Instance fields
private HashSet<PaintListener> paintListeners;
///////////////////////////////////////////////////////////////////////////
// Classes //
///////////////////////////////////////////////////////////////////////////
// Functional interface for paint events
public interface PaintListener {
void paint(Graphics2D g, int width, int height);
}
///////////////////////////////////////////////////////////////////////////
// Constructors //
///////////////////////////////////////////////////////////////////////////
// Default constructor
public UPanel() {
this(null);
}
// Layout manager constructor
public UPanel(LayoutManager layout) {
super(layout);
paintListeners = new HashSet<PaintListener>();
}
///////////////////////////////////////////////////////////////////////////
// Public Methods //
///////////////////////////////////////////////////////////////////////////
// Add a listener to receive paint events
public void addPaintListener(PaintListener l) {
if (l != null)
paintListeners.add(l);
}
// Retrieve a list of the current paint listeners
public PaintListener[] getPaintListeners() {
return paintListeners.toArray(
new PaintListener[paintListeners.size()]);
}
// Retrieve the maximum size of the component
public Dimension getMaximumSize() {
var ret = super.getMaximumSize();
return ret != null ? ret : new Dimension();
}
// Retrieve the minimum size of the component
public Dimension getMinimumSize() {
var ret = super.getMinimumSize();
return ret != null ? ret : new Dimension();
}
// Retrieve the preferred size of the component
public Dimension getPreferredSize() {
var ret = super.getPreferredSize();
return ret != null ? ret : new Dimension();
}
// Draw the component
public void paintComponent(Graphics g) {
super.paintComponent(g);
var G = (Graphics2D) g;
int width = getWidth();
int height = getHeight();
for (var lst : paintListeners)
lst.paint(G, width, height);
}
// Remove a paint listener from the collection
public void removePaintListener(PaintListener l) {
paintListeners.remove(l);
}
}
+9 -7
View File
@@ -645,9 +645,11 @@ class CPU {
// Transfer program to another address
private void jump(int address) {
int level = psw_np != 0 ? 2 : psw_ep;
jumpFrom[level] = pc;
jumpTo [level] = address;
if (address != pc) {
int level = psw_np != 0 ? 2 : psw_ep;
jumpFrom[level] = pc;
jumpTo [level] = address;
}
pc = address - inst.size;
}
@@ -712,7 +714,7 @@ class CPU {
// Add Immediate
private void ADDI() {
program[inst.reg2] = add(program[inst.reg2], inst.imm);
program[inst.reg2] = add(program[inst.reg1], inst.imm);
}
// And
@@ -722,7 +724,7 @@ class CPU {
// And Immediate
private void ANDI() {
bitwise(program[inst.reg2] & inst.imm);
bitwise(program[inst.reg1] & inst.imm);
}
// Branch on Condition
@@ -988,7 +990,7 @@ class CPU {
// Or Immediate
private void ORI() {
bitwise(program[inst.reg2] | inst.imm);
bitwise(program[inst.reg1] | inst.imm);
}
// Output Byte to Port
@@ -1131,7 +1133,7 @@ class CPU {
// Exclusive Or Immediate
private void XORI() {
bitwise(program[inst.reg2] ^ inst.imm);
bitwise(program[inst.reg1] ^ inst.imm);
}
}
+31 -7
View File
@@ -9,11 +9,14 @@ class JavaVue extends Vue {
// Package fields
int breakCode; // Application breakpoint code
int breakType; // Most recent breakpoint scenario
CPU cpu; // Processor
GamePak pak; // Game pak
int[] stack; // Breakpoint condition evaluation stack
byte[] wram; // System WRAM
// System components
CPU cpu; // Processor
GamePak pak; // Game pak
VIP vip; // Video unit
///////////////////////////////////////////////////////////////////////////
@@ -31,10 +34,17 @@ class JavaVue extends Vue {
// Default constructor
JavaVue() {
cpu = new CPU (this);
pak = new GamePak(this);
// Configure instance fields
stack = new int[0];
wram = new byte[0x10000];
// Configure system components
cpu = new CPU (this);
pak = new GamePak(this);
vip = new VIP (this);
// Initialize state
reset();
}
@@ -59,7 +69,7 @@ class JavaVue extends Vue {
//cycles = pad .until(cycles);
//cycles = link .until(cycles);
//cycles = timer.until(cycles);
//cycles = vip .until(cycles);
cycles = vip .until(cycles);
// Process all system components
breakCode = 0;
@@ -67,7 +77,7 @@ class JavaVue extends Vue {
//pad .emulate(cycles);
//link .emulate(cycles);
//timer.emulate(cycles);
//vip .emulate(cycles);
vip .emulate(cycles);
//vsu .emulate(cycles);
maxCycles -= cycles;
} while (breakCode == 0 && maxCycles != 0);
@@ -133,6 +143,7 @@ class JavaVue extends Vue {
// Perform the operation
switch (address >> 24 & 7) {
case 0: return vip.read ( address, type);
case 5: return readBuffer(wram , address, type);
case 6: return readBuffer(pak.ram, address, type);
case 7: return readBuffer(pak.rom, address, type);
@@ -155,6 +166,7 @@ class JavaVue extends Vue {
while (length > 0) {
int count = Math.min(length, 0x01000000 - (address & 0x00FFFFFF));
switch (address >> 24 & 7) {
case 0: vip.readBytes( address,dest,offset,count); break;
case 5: readBytes(wram ,address,dest,offset,count); break;
case 6: readBytes(pak.ram,address,dest,offset,count); break;
case 7: readBytes(pak.rom,address,dest,offset,count); break;
@@ -176,8 +188,18 @@ class JavaVue extends Vue {
// Specify a register value
public int setRegister(int index, boolean system, int value) {
// PC
if (index == Vue.PC && system) {
if (cpu.stage == CPU.EXECUTE || cpu.stage == CPU.FETCH) {
cpu.fetch = -1;
cpu.stage = CPU.FETCH;
}
return cpu.pc = value & 0xFFFFFFFE;
}
// Other
return
index == Vue.PC && system ? cpu.pc = value & 0xFFFFFFFE :
index < 0 || index > 31 ? 0 :
system ? cpu.setSystemRegister(index, value, true) :
index == 0 ? 0 : (cpu.program[index] = value)
@@ -205,6 +227,7 @@ class JavaVue extends Vue {
// Write a value to the CPU bus
public void write(int address, int type, int value) {
switch (address >> 24 & 7) {
case 0: vip.write ( address, type, value); break;
case 5: writeBuffer(wram , address, type, value); break;
case 6: writeBuffer(pak.ram, address, type, value); break;
case 7: writeBuffer(pak.rom, address, type, value); break;
@@ -226,6 +249,7 @@ class JavaVue extends Vue {
while (length > 0) {
int count = Math.min(length, 0x01000000 - (address & 0x00FFFFFF));
switch (address >> 24 & 7) {
case 0: vip.writeBytes( address,src,offset,count); break;
case 5: writeBytes(wram ,address,src,offset,count); break;
case 6: writeBytes(pak.ram,address,src,offset,count); break;
case 7: writeBytes(pak.rom,address,src,offset,count); break;
+309
View File
@@ -0,0 +1,309 @@
package vue;
// Java imports
import java.util.*;
// VIP state
class VIP {
// Instance fields
byte[] vram; // Video memory
// Private fields
private JavaVue vue; // Emulation state
///////////////////////////////////////////////////////////////////////////
// Constructors //
///////////////////////////////////////////////////////////////////////////
// Default constructor
VIP(JavaVue vue) {
vram = new byte[0x40000];
this.vue = vue;
}
///////////////////////////////////////////////////////////////////////////
// Package Methods //
///////////////////////////////////////////////////////////////////////////
// Process the simulation
void emulate(int cycles) {
}
// Read a value from the CPU bus
int read(int address, int type) {
address &= 0x0007FFFF;
// VRAM
if (address < 0x00040000)
return JavaVue.readBuffer(vram, address, type);
// Mirrors of character memory
if (address >= 0x00078000)
return JavaVue.readBuffer(vram,
address - 0x00078000 >> 13 << 15 | 0x00006000 |
address & 0x00001FFF,
type);
// I/O register or unmapped
int value = readRegister(address);
if (type < 2 && (address & 1) == 1)
value >>= 8;
switch (type) {
case Vue.S8 : return value << 24 >> 24;
case Vue.U8 : return value & 0x000000FF;
case Vue.S16: return value << 16 >> 16;
case Vue.S32: return value | readRegister(address + 2) << 16;
}
return value; // U16
}
// Read bytes from the CPU bus
void readBytes(int address, byte[] dest, int offset, int length) {
address &= 0x0007FFFF;
// Perform the operation
while (length > 0) {
int count;
// VRAM
if (address < 0x00040000) {
count = Math.min(length, 0x00040000 - address);
JavaVue.readBytes(vram, address, dest, offset, count);
}
// Mirrors of character memory
else if (address >= 0x00078000) {
count = Math.min(length, 0x2000 - (address & 0x1FFF));
JavaVue.readBytes(vram,
address - 0x00078000 >> 13 << 15 | 0x00006000 |
address & 0x00001FFF,
dest, offset, count);
}
// I/O register or unmapped
else {
count = Math.min(length, 0x00078000 - address);
// Read all registers in the range
while (count > 0) {
int value = readRegister(address);
// Odd address
if ((address & 1) == 1) {
dest[offset] = (byte) (value >> 8);
address++;
count --;
length --;
offset ++;
continue;
}
// Even address
int size = count == 1 ? 1 : 2;
dest[offset] = (byte) value;
if (size == 2)
dest[offset + 1] = (byte) (value >> 8);
address += size;
count -= size;
length -= size;
offset += size;
}
continue;
}
// Advance to the next region
address += count;
length -= count;
offset += count;
}
}
// System reset
void reset() {
}
// Determine the number of CPU cycles until a breakpoint could trigger
int until(int cycles) {
return cycles;
}
// Write a value to the CPU bus
void write(int address, int type, int value) {
address &= 0x0007FFFF;
// VRAM
if (address < 0x00040000) {
JavaVue.writeBuffer(vram, address, type, value);
return;
}
// Mirrors of character memory
if (address >= 0x00078000) {
JavaVue.writeBuffer(vram,
address - 0x00078000 >> 13 << 15 | 0x00006000 |
address & 0x00001FFF,
type, value);
return;
}
// I/O register or unmapped
if (type < 2 && (address & 1) == 1)
value <<= 8;
writeRegister(address, value);
if (type == Vue.S32)
writeRegister(address + 2, value >> 16);
}
// Write bytes to the CPU bus
void writeBytes(int address, byte[] src, int offset, int length) {
address &= 0x0007FFFF;
// Perform the operation
while (length > 0) {
int count;
// VRAM
if (address < 0x00040000) {
count = Math.min(length, 0x00040000 - address);
JavaVue.writeBytes(vram, address, src, offset, count);
}
// Mirrors of character memory
else if (address >= 0x00078000) {
count = Math.min(length, 0x2000 - (address & 0x1FFF));
JavaVue.writeBytes(vram,
address - 0x00078000 >> 13 << 15 | 0x00006000 |
address & 0x00001FFF,
src, offset, count);
}
// I/O register or unmapped
else {
count = Math.min(length, 0x00078000 - address);
// Write all registers in the range
while (count > 0) {
int value = src[offset] & 0xFF;
// Odd address
if ((address & 1) == 1) {
writeRegister(address, value << 8);
address++;
count --;
length --;
offset ++;
continue;
}
// Even address
int size = count == 1 ? 1 : 2;
if (size == 2)
value |= src[offset + 1] << 8;
writeRegister(address, value);
address += size;
count -= size;
length -= size;
offset += size;
}
continue;
}
// Advance to the next region
address += count;
length -= count;
offset += count;
}
}
///////////////////////////////////////////////////////////////////////////
// Private Methods //
///////////////////////////////////////////////////////////////////////////
// Read an I/O register
private int readRegister(int address) {
// Process by register
switch (address & ~1) {
case 0x0005F800: break; // INTPND
case 0x0005F802: break; // INTENB
case 0x0005F804: break; // INTCLR
case 0x0005F820: break; // DPSTTS
case 0x0005F822: break; // DPCTRL
case 0x0005F824: break; // BRTA
case 0x0005F826: break; // BRTB
case 0x0005F828: break; // BRTC
case 0x0005F82A: break; // REST
case 0x0005F82E: break; // FRMCYC
case 0x0005F830: break; // CTA
case 0x0005F840: break; // XPSTTS
case 0x0005F842: break; // XPCTRL
case 0x0005F844: break; // VER
case 0x0005F848: break; // SPT0
case 0x0005F84A: break; // SPT1
case 0x0005F84C: break; // SPT2
case 0x0005F84E: break; // SPT3
case 0x0005F860: break; // GPLT0
case 0x0005F862: break; // GPLT1
case 0x0005F864: break; // GPLT2
case 0x0005F866: break; // GPLT3
case 0x0005F868: break; // JPLT0
case 0x0005F86A: break; // JPLT1
case 0x0005F86C: break; // JPLT2
case 0x0005F86E: break; // JPLT3
case 0x0005F870: break; // BKCOL
}
// Unmapped
return 0;
}
// Write an I/O register
private void writeRegister(int address, int value) {
// Process by register
switch (address & ~1) {
case 0x0005F800: break; // INTPND
case 0x0005F802: break; // INTENB
case 0x0005F804: break; // INTCLR
case 0x0005F820: break; // DPSTTS
case 0x0005F822: break; // DPCTRL
case 0x0005F824: break; // BRTA
case 0x0005F826: break; // BRTB
case 0x0005F828: break; // BRTC
case 0x0005F82A: break; // REST
case 0x0005F82E: break; // FRMCYC
case 0x0005F830: break; // CTA
case 0x0005F840: break; // XPSTTS
case 0x0005F842: break; // XPCTRL
case 0x0005F844: break; // VER
case 0x0005F848: break; // SPT0
case 0x0005F84A: break; // SPT1
case 0x0005F84C: break; // SPT2
case 0x0005F84E: break; // SPT3
case 0x0005F860: break; // GPLT0
case 0x0005F862: break; // GPLT1
case 0x0005F864: break; // GPLT2
case 0x0005F866: break; // GPLT3
case 0x0005F868: break; // JPLT0
case 0x0005F86A: break; // JPLT1
case 0x0005F86C: break; // JPLT2
case 0x0005F86E: break; // JPLT3
case 0x0005F870: break; // BKCOL
}
}
}