Introducing CPU register lists
This commit is contained in:
parent
2e38c1fa49
commit
7d8d33158f
|
@ -10,6 +10,7 @@ app {
|
|||
debug {
|
||||
(menu) Debug
|
||||
console Console
|
||||
cpu CPU
|
||||
memory Memory
|
||||
}
|
||||
|
||||
|
@ -36,6 +37,16 @@ console {
|
|||
title Console
|
||||
}
|
||||
|
||||
# CPU window
|
||||
cpu {
|
||||
float Float
|
||||
hex Hex
|
||||
last_pc Last PC
|
||||
signed Signed
|
||||
title CPU
|
||||
unsigned Unsigned
|
||||
}
|
||||
|
||||
# Memory window
|
||||
memory {
|
||||
title Memory
|
||||
|
|
18
makefile
18
makefile
|
@ -69,7 +69,7 @@ core:
|
|||
desktop: clean_desktop
|
||||
@echo " Compiling Java desktop application"
|
||||
@javac -sourcepath src/desktop --release 10 -Xlint:unchecked \
|
||||
-h src/desktop/native -d . src/desktop/Main.java
|
||||
-h src/desktop/vue -d . src/desktop/Main.java
|
||||
|
||||
# Build all native modules
|
||||
.PHONY: native
|
||||
|
@ -103,7 +103,7 @@ clean_desktop:
|
|||
# Delete everything but the .jar
|
||||
.PHONY: clean_most
|
||||
clean_most: clean_desktop
|
||||
@rm -f src/desktop/native/vue_NativeVUE.h native/*.dll native/*.so
|
||||
@rm -f src/desktop/vue/vue_NativeVUE.h native/*.dll native/*.so
|
||||
|
||||
|
||||
|
||||
|
@ -112,14 +112,14 @@ clean_most: clean_desktop
|
|||
###############################################################################
|
||||
|
||||
# JNI header file
|
||||
src/desktop/native/vue_NativeVUE.h: src/desktop/vue/NativeVUE.java
|
||||
@javac -h src/desktop/native -sourcepath src/desktop -d . \
|
||||
src/desktop/vue/vue_NativeVUE.h: src/desktop/vue/NativeVUE.java
|
||||
@javac -h src/desktop/vue -sourcepath src/desktop -d . \
|
||||
src/desktop/vue/NativeVUE.java
|
||||
@sleep 3
|
||||
|
||||
# linux_x86
|
||||
.PHONY: lin32_pre
|
||||
lin32_pre: src/desktop/native/vue_NativeVUE.h
|
||||
lin32_pre: src/desktop/vue/vue_NativeVUE.h
|
||||
$(eval name = linux_x86)
|
||||
$(eval prefix = `uname -m`-linux-gnu-)
|
||||
$(eval include = -I$(include_linux) -I$(include_linux)/linux)
|
||||
|
@ -130,7 +130,7 @@ lin32: lin32_pre native_common
|
|||
|
||||
# linux_x86-64
|
||||
.PHONY: lin64_pre
|
||||
lin64_pre: src/desktop/native/vue_NativeVUE.h
|
||||
lin64_pre: src/desktop/vue/vue_NativeVUE.h
|
||||
$(eval name = linux_x86-64)
|
||||
$(eval prefix = `uname -m`-linux-gnu-)
|
||||
$(eval include = -I$(include_linux) -I$(include_linux)/linux)
|
||||
|
@ -141,7 +141,7 @@ lin64: lin64_pre native_common
|
|||
|
||||
# windows_x86
|
||||
.PHONY: win32_pre
|
||||
win32_pre: src/desktop/native/vue_NativeVUE.h
|
||||
win32_pre: src/desktop/vue/vue_NativeVUE.h
|
||||
$(eval name = windows_x86)
|
||||
$(eval prefix = i686-w64-mingw32-)
|
||||
$(eval include = -I$(include_windows) -I$(include_windows)/win32)
|
||||
|
@ -151,7 +151,7 @@ win32: win32_pre native_common
|
|||
|
||||
# windows_x86-64
|
||||
.PHONY: win64_pre
|
||||
win64_pre: src/desktop/native/vue_NativeVUE.h
|
||||
win64_pre: src/desktop/vue/vue_NativeVUE.h
|
||||
$(eval name = windows_x86-64)
|
||||
$(eval prefix = x86_64-w64-mingw32-)
|
||||
$(eval include = -I$(include_windows) -I$(include_windows)/win32)
|
||||
|
@ -165,4 +165,4 @@ native_common:
|
|||
@echo " Building native module $(name)"
|
||||
@$(prefix)gcc $(include) -Isrc/core/include $(gccargs) -s -shared -O2 \
|
||||
-fno-strict-aliasing -Werror \
|
||||
-o native/$(name)$(ext) src/desktop/native/native.c src/core/vue.c
|
||||
-o native/$(name)$(ext) src/desktop/vue/NativeVUE.c src/core/vue.c
|
||||
|
|
|
@ -69,6 +69,13 @@ static int32_t busReadValue(VUE *vue, uint32_t address, int type) {
|
|||
return 0; /* Unreachable */
|
||||
}
|
||||
|
||||
/* Perform a system reset */
|
||||
static void busReset(VUE *vue) {
|
||||
int x;
|
||||
for (x = 0; x < 0x10000; x++)
|
||||
vue->bus.wram[x] = 0;
|
||||
}
|
||||
|
||||
/* Write bytes to host memory */
|
||||
static void busWriteBytes(uint8_t *dest, uint8_t *src, uint32_t address,
|
||||
uint32_t size, uint32_t length) {
|
||||
|
|
|
@ -90,6 +90,13 @@ static int32_t cpuSetSystemRegister(VUE *vue, int index, int32_t value,
|
|||
|
||||
return vue->cpu.chcw_ice << 1;
|
||||
|
||||
case VUE_ECR:
|
||||
if (debug) {
|
||||
vue->cpu.ecr_fecc = value >> 16 & 0xFFFF;
|
||||
vue->cpu.ecr_eicc = value & 0xFFFF;
|
||||
}
|
||||
return vue->cpu.ecr_fecc << 16 | vue->cpu.ecr_eicc;
|
||||
|
||||
case VUE_PSW :
|
||||
vue->cpu.psw_i = value >> 16 & 15;
|
||||
vue->cpu.psw_np = value >> 15 & 1;
|
||||
|
@ -109,16 +116,16 @@ static int32_t cpuSetSystemRegister(VUE *vue, int index, int32_t value,
|
|||
return value & 0x000FF3FF;
|
||||
|
||||
/* Remaining cases to encourage tableswitch */
|
||||
case 4: case 6: case 7: case 8: case 9: case 10: case 11:
|
||||
case 12: case 13: case 14: case 15: case 16: case 17: case 18:
|
||||
case 19: case 20: case 21: case 22: case 23: case 26: case 27:
|
||||
case 28: case 30:
|
||||
case 6: case 7: case 8: case 9: case 10: case 11: case 12:
|
||||
case 13: case 14: case 15: case 16: case 17: case 18: case 19:
|
||||
case 20: case 21: case 22: case 23: case 26: case 27: case 28:
|
||||
case 30:
|
||||
return 0;
|
||||
}
|
||||
return 1; /* Unreachable */
|
||||
}
|
||||
|
||||
/* System reset */
|
||||
/* Perform a system reset */
|
||||
static void cpuReset(VUE *vue) {
|
||||
int x;
|
||||
|
||||
|
@ -127,15 +134,17 @@ static void cpuReset(VUE *vue) {
|
|||
vue->cpu.fetch = 0;
|
||||
vue->cpu.stage = CPU_FETCH;
|
||||
|
||||
/* Reset program counter */
|
||||
vue->cpu.pc = 0xFFFFFFF0;
|
||||
|
||||
/* Clear all registers (hardware only sets ECR, PC and PSW) */
|
||||
for (x = 0; x < 32; x++) {
|
||||
vue->cpu.program[x] = 0;
|
||||
cpuSetSystemRegister(vue, x, 0, VUE_TRUE);
|
||||
}
|
||||
|
||||
/* Configure registers */
|
||||
vue->cpu.ecr_eicc = 0xFFF0;
|
||||
vue->cpu.lastPC = 0xFFFFFFF0;
|
||||
vue->cpu.pc = 0xFFFFFFF0;
|
||||
vue->cpu.psw_np = 1;
|
||||
}
|
||||
|
||||
/* Test a condition */
|
||||
|
|
|
@ -43,6 +43,13 @@ extern "C" {
|
|||
#define VUE_PSW 5
|
||||
#define VUE_TKCW 7
|
||||
|
||||
/* Program register indexes */
|
||||
#define VUE_GP 4
|
||||
#define VUE_HP 2
|
||||
#define VUE_LP 31
|
||||
#define VUE_SP 3
|
||||
#define VUE_TP 5
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
|
@ -68,6 +75,7 @@ typedef struct {
|
|||
struct {
|
||||
uint32_t cycles; /* Cycles until next stage */
|
||||
int fetch; /* Fetch unit index */
|
||||
int32_t lastPC; /* Previous value of PC */
|
||||
int stage; /* Current processing stage */
|
||||
|
||||
/* Program registers */
|
||||
|
@ -101,17 +109,17 @@ typedef struct {
|
|||
int8_t psw_z; /* Zero */
|
||||
|
||||
/* Cache Control Word */
|
||||
int32_t chcw_cec; /* Clear Entry Count */
|
||||
int32_t chcw_cen; /* Clear Entry Number */
|
||||
int8_t chcw_icc; /* Instruction Cache Clear */
|
||||
int8_t chcw_icd; /* Instruction Cache Dump */
|
||||
int8_t chcw_ice; /* Instruction Cache Enable */
|
||||
int8_t chcw_icr; /* Instruction Cache Restore */
|
||||
int32_t chcw_sa; /* Spill-Out Base Address */
|
||||
uint16_t chcw_cec; /* Clear Entry Count */
|
||||
uint16_t chcw_cen; /* Clear Entry Number */
|
||||
int8_t chcw_icc; /* Instruction Cache Clear */
|
||||
int8_t chcw_icd; /* Instruction Cache Dump */
|
||||
int8_t chcw_ice; /* Instruction Cache Enable */
|
||||
int8_t chcw_icr; /* Instruction Cache Restore */
|
||||
int32_t chcw_sa; /* Spill-Out Base Address */
|
||||
|
||||
/* Exception Cause Register */
|
||||
int8_t ecr_eicc; /* Exception/Interrupt Cause Code */
|
||||
int8_t ecr_fecc; /* Fatal Error Cause Code */
|
||||
uint16_t ecr_eicc; /* Exception/Interrupt Cause Code */
|
||||
uint16_t ecr_fecc; /* Fatal Error Cause Code */
|
||||
} cpu;
|
||||
|
||||
} VUE;
|
||||
|
@ -125,6 +133,7 @@ typedef struct {
|
|||
VUEAPI int32_t vueGetRegister(VUE *vue, int index, vbool system);
|
||||
VUEAPI void vueInitialize (VUE *vue);
|
||||
VUEAPI vbool vueRead (VUE *vue, uint32_t address, uint8_t *dest, uint32_t length);
|
||||
VUEAPI void vueReset (VUE *vue);
|
||||
VUEAPI int32_t vueSetRegister(VUE *vue, int index, vbool system, int32_t value);
|
||||
VUEAPI vbool vueSetROM (VUE *vue, uint8_t *rom, uint32_t size);
|
||||
VUEAPI vbool vueWrite (VUE *vue, uint32_t address, uint8_t *src, uint32_t length);
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#include <vue.h>
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Constants *
|
||||
*****************************************************************************/
|
||||
|
@ -27,7 +26,7 @@ static const int TYPE_SIZES[] = { 1, 1, 2, 2, 4 };
|
|||
|
||||
/* Retrieve the value of a register */
|
||||
int32_t vueGetRegister(VUE *vue, int index, vbool system) {
|
||||
return
|
||||
return vue == NULL ? 0 :
|
||||
index == VUE_PC && system ? vue->cpu.pc :
|
||||
index < 0 || index > 31 ? 0 :
|
||||
system ? cpuGetSystemRegister(vue, index) :
|
||||
|
@ -37,6 +36,8 @@ int32_t vueGetRegister(VUE *vue, int index, vbool system) {
|
|||
|
||||
/* Prepare an emulation state context for use */
|
||||
void vueInitialize(VUE *vue) {
|
||||
if (vue == NULL)
|
||||
return;
|
||||
vue->bus.rom = NULL;
|
||||
vue->bus.sram = NULL;
|
||||
}
|
||||
|
@ -79,13 +80,21 @@ vbool vueRead(VUE *vue, uint32_t address, uint8_t *dest, uint32_t length) {
|
|||
return VUE_TRUE;
|
||||
}
|
||||
|
||||
/* Initialize all system components */
|
||||
void vueReset(VUE *vue) {
|
||||
if (vue == NULL)
|
||||
return;
|
||||
busReset(vue);
|
||||
cpuReset(vue);
|
||||
}
|
||||
|
||||
/* Specify a value for a register */
|
||||
int32_t vueSetRegister(VUE *vue, int index, vbool system, int32_t value) {
|
||||
return
|
||||
return vue == NULL ? 0 :
|
||||
index == VUE_PC && system ? vue->cpu.pc = value & 0xFFFFFFFE :
|
||||
index < 0 || index > 31 ? 0 :
|
||||
system ? cpuSetSystemRegister(vue, index, value, VUE_TRUE) :
|
||||
index == 0 ? 0 : vue->cpu.program[index]
|
||||
index == 0 ? 0 : (vue->cpu.program[index] = value)
|
||||
;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,255 @@
|
|||
package app;
|
||||
|
||||
// Java imports
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.util.*;
|
||||
import javax.swing.*;
|
||||
|
||||
// Project imports
|
||||
import util.*;
|
||||
import vue.*;
|
||||
|
||||
// CPU window
|
||||
class CPU extends ChildWindow {
|
||||
|
||||
// Instance fields
|
||||
private int expandWidth; // Width of expand buttons
|
||||
private Font font; // Display font
|
||||
private int fontHeight; // Font line height
|
||||
private int fontWidth; // Font maximum character width
|
||||
private boolean shown; // Window has been shown
|
||||
private int systemHeight; // Initial height of system register list
|
||||
|
||||
// UI components
|
||||
private JPanel dasm; // Disassembler
|
||||
private JPanel system; // System registers
|
||||
private JPanel program; // Program registers
|
||||
private ArrayList<Register> registers; // Register controls
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Constructors //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Default constructor
|
||||
CPU(MainWindow parent) {
|
||||
super(parent, "cpu.title");
|
||||
var client = getContentPane();
|
||||
|
||||
// Configure instance fields
|
||||
font = new Font(Util.fontFamily(new String[]
|
||||
{ "Consolas", Font.MONOSPACED } ), Font.PLAIN, 14);
|
||||
registers = new ArrayList<Register>();
|
||||
|
||||
dasm = new JPanel(null);
|
||||
dasm.setBackground(SystemColor.window);
|
||||
dasm.setFocusable(true);
|
||||
|
||||
var inner = initRegisters();
|
||||
var outer = Util.splitPane(JSplitPane.HORIZONTAL_SPLIT);
|
||||
outer.setLeftComponent(new JScrollPane(dasm,
|
||||
JScrollPane.VERTICAL_SCROLLBAR_NEVER,
|
||||
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED));
|
||||
outer.setRightComponent(inner);
|
||||
outer.setResizeWeight(1);
|
||||
|
||||
client.add(outer);
|
||||
client.setPreferredSize(new Dimension(640, 480));
|
||||
setFont2(font);
|
||||
pack();
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Register Constructors //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Initialize program register list
|
||||
private void initProgram() {
|
||||
Dimension target = null;
|
||||
|
||||
// Program register container
|
||||
var lst = program = new JPanel(new GridBagLayout()) {
|
||||
public Dimension getPreferredSize() {
|
||||
var ret = super.getPreferredSize();
|
||||
if (!shown)
|
||||
ret.height = 0;
|
||||
return ret;
|
||||
}
|
||||
public void paintComponent(Graphics g) {
|
||||
super.paintComponent(g);
|
||||
if (shown)
|
||||
return;
|
||||
shown = true;
|
||||
system.revalidate();
|
||||
program.revalidate();
|
||||
}
|
||||
};
|
||||
lst.setBackground(SystemColor.window);
|
||||
lst.setFocusable(true);
|
||||
lst.addMouseListener(Util.onMouse(e->lst.requestFocus(),null));
|
||||
|
||||
// Produce the list of program registers
|
||||
for (int x = 0; x < 32; x++) {
|
||||
String name = "r" + x;
|
||||
switch (x) {
|
||||
case VUE.GP: name = "gp"; break;
|
||||
case VUE.HP: name = "hp"; break;
|
||||
case VUE.LP: name = "lp"; break;
|
||||
case VUE.SP: name = "sp"; break;
|
||||
case VUE.TP: name = "tp"; break;
|
||||
}
|
||||
registers.add(new Register(parent,lst,name,x,Register.PROGRAM));
|
||||
}
|
||||
endList(lst);
|
||||
}
|
||||
|
||||
// Initialize register lists
|
||||
private JSplitPane initRegisters() {
|
||||
initSystem();
|
||||
initProgram();
|
||||
|
||||
var ret = Util.splitPane(JSplitPane.VERTICAL_SPLIT);
|
||||
ret.setTopComponent(new JScrollPane(system,
|
||||
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
|
||||
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED
|
||||
));
|
||||
ret.setBottomComponent(new JScrollPane(program,
|
||||
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
|
||||
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED
|
||||
));
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Initialize system register list
|
||||
private void initSystem() {
|
||||
|
||||
// System register container
|
||||
var lst = system = new JPanel(new GridBagLayout()) {
|
||||
public Dimension getPreferredSize() {
|
||||
var ret = super.getPreferredSize();
|
||||
if (!shown)
|
||||
ret.height = systemHeight;
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
system.setBackground(SystemColor.window);
|
||||
system.setFocusable(true);
|
||||
system.addMouseListener(Util.onMouse(e->system.requestFocus(), null));
|
||||
system.putClientProperty("shown", true);
|
||||
|
||||
// Add the first two system registers and expand PSW
|
||||
registers.add(new Register(parent, lst, "PC" , VUE.PC , VUE.PC ));
|
||||
Register psw =new Register(parent, lst, "PSW" , VUE.PSW , VUE.PSW );
|
||||
psw.setExpanded(true);
|
||||
registers.add(psw);
|
||||
shown = true;
|
||||
systemHeight = system.getPreferredSize().height + 6;
|
||||
shown = false;
|
||||
|
||||
// Add the remaining system registers
|
||||
registers.add(new Register(parent, lst, "EIPC" , VUE.EIPC , VUE.PC ));
|
||||
registers.add(new Register(parent, lst, "EIPSW", VUE.EIPSW, VUE.PSW ));
|
||||
registers.add(new Register(parent, lst, "FEPC" , VUE.FEPC , VUE.PC ));
|
||||
registers.add(new Register(parent, lst, "FEPSW", VUE.FEPSW, VUE.PSW ));
|
||||
registers.add(new Register(parent, lst, "ECR" , VUE.ECR , VUE.ECR ));
|
||||
registers.add(new Register(parent, lst, "ADTRE", VUE.ADTRE, VUE.PC ));
|
||||
registers.add(new Register(parent, lst, "CHCW" , VUE.CHCW , VUE.CHCW));
|
||||
registers.add(new Register(parent, lst, "PIR" , VUE.PIR , VUE.PIR ));
|
||||
registers.add(new Register(parent, lst, "TKCW" , VUE.TKCW , VUE.TKCW));
|
||||
registers.add(new Register(parent, lst, "29" , 29, VUE.PC ));
|
||||
registers.add(new Register(parent, lst, "30" , 30, VUE.PC ));
|
||||
registers.add(new Register(parent, lst, "31" , 31, VUE.PC ));
|
||||
endList(lst);
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Event Handlers //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Client resize
|
||||
private void onResize() {
|
||||
//refreshDasm();
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Package Methods //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Update the display
|
||||
void refresh() {
|
||||
|
||||
// The element is not ready
|
||||
if (registers == null)
|
||||
return;
|
||||
|
||||
// Refresh registers
|
||||
for (var reg : registers)
|
||||
reg.refresh();
|
||||
}
|
||||
|
||||
// Specify a new font
|
||||
void setFont2(Font font) {
|
||||
this.font = font;
|
||||
|
||||
// Configure the maximum font dimensions
|
||||
var fontMax = new JLabel("!");
|
||||
fontMax.setFont(font);
|
||||
fontHeight = Math.max(1, fontMax.getPreferredSize().height);
|
||||
fontWidth = -1;
|
||||
for (int x = 0; x < 16; x++) {
|
||||
fontMax.setText(Integer.toString(x, 16).toUpperCase());
|
||||
fontWidth = Math.max(fontWidth, fontMax.getPreferredSize().width);
|
||||
}
|
||||
|
||||
// Configure register list scrolling
|
||||
for (int x = 0; x < 2; x++) {
|
||||
Component ctrl = x == 0 ? system : program;
|
||||
while (!(ctrl instanceof JScrollPane))
|
||||
ctrl = ctrl.getParent();
|
||||
((JScrollPane) ctrl).getVerticalScrollBar()
|
||||
.setUnitIncrement(fontHeight);
|
||||
}
|
||||
|
||||
// Determine the width of the register expand buttons
|
||||
var expand = new JLabel("+");
|
||||
int width = expand.getPreferredSize().width;
|
||||
expand.setText("-");
|
||||
width = Math.max(width, expand.getPreferredSize().width) + 4;
|
||||
|
||||
// Configure registers
|
||||
for (var reg : registers) {
|
||||
reg.setExpandWidth(width);
|
||||
reg.setFont(font, fontWidth, fontHeight);
|
||||
}
|
||||
|
||||
onResize();
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Private Methods //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Terminate a register list
|
||||
private JPanel endList(JPanel list) {
|
||||
var spacer = new JPanel(null);
|
||||
spacer.setOpaque(false);
|
||||
spacer.setPreferredSize(new Dimension(1, 1));
|
||||
var gbc = new GridBagConstraints();
|
||||
gbc.gridheight = GridBagConstraints.REMAINDER;
|
||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
||||
gbc.weighty = 1;
|
||||
list.add(spacer, gbc);
|
||||
return spacer;
|
||||
}
|
||||
|
||||
}
|
|
@ -29,6 +29,7 @@ class MainWindow extends JFrame {
|
|||
// UI components
|
||||
private JPanel client; // Common client container
|
||||
private Console console; // Console window
|
||||
private CPU cpu; // CPU window
|
||||
private JDesktopPane desktop; // Container for child windows
|
||||
private Memory memory; // Memory window
|
||||
private JPanel video; // Video output
|
||||
|
@ -92,9 +93,11 @@ class MainWindow extends JFrame {
|
|||
desktop = new JDesktopPane();
|
||||
desktop.setBackground(SystemColor.controlShadow);
|
||||
desktop.add(console = new Console(this));
|
||||
desktop.add(cpu = new CPU (this));
|
||||
desktop.add(memory = new Memory (this));
|
||||
|
||||
// Display window
|
||||
refreshDebug();
|
||||
pack();
|
||||
setLocationRelativeTo(null);
|
||||
setVisible(true);
|
||||
|
@ -131,6 +134,11 @@ class MainWindow extends JFrame {
|
|||
mnuDebugMemory.addActionListener(e->memory.setVisible(true));
|
||||
mnuDebug.add(mnuDebugMemory);
|
||||
|
||||
var mnuDebugCPU = new JMenuItem();
|
||||
loc.add(mnuDebugCPU, "app.debug.cpu");
|
||||
mnuDebugCPU.addActionListener(e->cpu.setVisible(true));
|
||||
mnuDebug.add(mnuDebugCPU);
|
||||
|
||||
return mnuDebug;
|
||||
}
|
||||
|
||||
|
@ -178,6 +186,7 @@ class MainWindow extends JFrame {
|
|||
|
||||
// Refresh all debug views
|
||||
void refreshDebug() {
|
||||
cpu .refresh();
|
||||
memory.refresh();
|
||||
}
|
||||
|
||||
|
@ -283,6 +292,7 @@ class MainWindow extends JFrame {
|
|||
var bytes = rom.toByteArray();
|
||||
// Pause emulation
|
||||
vue.setROM(bytes, 0, bytes.length);
|
||||
vue.reset();
|
||||
refreshDebug();
|
||||
// Resume emulation
|
||||
}
|
||||
|
|
|
@ -13,12 +13,13 @@ import util.*;
|
|||
class Memory extends ChildWindow {
|
||||
|
||||
// Private fields
|
||||
private int address; // Address of top row
|
||||
private Font font; // Display font
|
||||
private int address; // Address of top row
|
||||
private Font font; // Display font
|
||||
private int fontHeight; // Font line height
|
||||
private int fontWidth; // Font maximum character width
|
||||
|
||||
// UI components
|
||||
private JPanel client; // Client area
|
||||
private JLabel fontHeight; // Font height proxy
|
||||
private JPanel client; // Client area
|
||||
private ArrayList<Row> rows; // Rows of text
|
||||
|
||||
|
||||
|
@ -44,23 +45,25 @@ class Memory extends ChildWindow {
|
|||
super(parent, "memory.title");
|
||||
|
||||
// Configure instance fields
|
||||
address = 0x00000000;
|
||||
font = new Font(Util.fontFamily(new String[]
|
||||
address = 0x00000000;
|
||||
font = new Font(Util.fontFamily(new String[]
|
||||
{ "Consolas", Font.MONOSPACED } ), Font.PLAIN, 14);
|
||||
fontHeight = new JLabel(".");
|
||||
rows = new ArrayList<Row>();
|
||||
rows = new ArrayList<Row>();
|
||||
|
||||
// Configure client area
|
||||
client = new JPanel(null);
|
||||
client.addComponentListener(Util.onResize(e->onResize()));
|
||||
client.addKeyListener(Util.onKey(e->onKeyDown(e), null));
|
||||
client.addMouseWheelListener(e->onWheel(e));
|
||||
client.setBackground(SystemColor.window);
|
||||
client.setFocusable(true);
|
||||
client.setPreferredSize(new Dimension(640, 480));
|
||||
client.setBackground(SystemColor.window);
|
||||
|
||||
// Configure component
|
||||
setContentPane(client);
|
||||
var content = new JPanel(new BorderLayout());
|
||||
content.setBorder(new JScrollPane().getBorder());
|
||||
content.add(client, BorderLayout.CENTER);
|
||||
setContentPane(content);
|
||||
setFont2(font);
|
||||
pack();
|
||||
}
|
||||
|
@ -79,11 +82,9 @@ class Memory extends ChildWindow {
|
|||
return;
|
||||
|
||||
// Configure working variables
|
||||
int height = client.getHeight();
|
||||
int lineHeight = fontHeight.getPreferredSize().height;
|
||||
int count = (height + lineHeight - 1) / lineHeight;
|
||||
var data = new byte[count * 16];
|
||||
var widths = new int[2];
|
||||
int height = client.getHeight();
|
||||
int count = (height + fontHeight - 1) / fontHeight;
|
||||
var data = new byte[count * 16];
|
||||
|
||||
// Retrieve all visible bytes from the emulation context
|
||||
parent.vue.read(address, data, 0, data.length);
|
||||
|
@ -91,26 +92,17 @@ class Memory extends ChildWindow {
|
|||
// Update visible rows
|
||||
for (int x = 0; x < count; x++) {
|
||||
Row row;
|
||||
|
||||
// Retrieve the row if it exists, make a new one otherwise
|
||||
if (x < rows.size())
|
||||
row = rows.get(x);
|
||||
else row = createRow();
|
||||
|
||||
// Configure the row
|
||||
update(row, address + x * 16, data, x * 16);
|
||||
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);
|
||||
setVisible(row, true);
|
||||
measure(row, widths);
|
||||
}
|
||||
|
||||
// Hide any rows that are not visible
|
||||
for (int x = count; x < rows.size(); x++)
|
||||
setVisible(rows.get(x), false);
|
||||
|
||||
// Position components
|
||||
for (int x = 0; x < rows.size(); x++)
|
||||
arrange(rows.get(x), x * lineHeight, widths, lineHeight);
|
||||
|
||||
// Finalize layout
|
||||
client.revalidate();
|
||||
client.repaint();
|
||||
|
@ -119,12 +111,24 @@ class Memory extends ChildWindow {
|
|||
// Specify a new font
|
||||
void setFont2(Font font) {
|
||||
this.font = font;
|
||||
fontHeight.setFont(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();
|
||||
}
|
||||
|
||||
|
@ -192,27 +196,9 @@ class Memory extends ChildWindow {
|
|||
// Private Methods //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Position the elements of a row
|
||||
private void arrange(Row row, int y, int[] widths, int height) {
|
||||
int spacing = (height + 1) / 2;
|
||||
|
||||
// Size and position the address header
|
||||
row.address.setSize(row.address.getPreferredSize());
|
||||
row.address.setLocation(0, y);
|
||||
|
||||
// Size and position the byte labels
|
||||
for (int z = 0, x = widths[0] + height; z < 16; z++) {
|
||||
var label = row.bytes[z];
|
||||
label.setBounds(x, y, widths[1], height);
|
||||
x += widths[1] + (z == 7 ? height : spacing);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Add a new row of output
|
||||
private Row createRow() {
|
||||
var row = new Row();
|
||||
row.address =
|
||||
|
||||
// Address label
|
||||
row.address = new JLabel();
|
||||
|
@ -260,16 +246,24 @@ class Memory extends ChildWindow {
|
|||
|
||||
// Determine how many rows of output are visible
|
||||
private int tall(boolean partial) {
|
||||
int lineHeight = fontHeight.getPreferredSize().height;
|
||||
return lineHeight == 0 ? 0 :
|
||||
(client.getHeight() + (partial ? lineHeight + 1 : 0)) / lineHeight;
|
||||
return (client.getHeight() + (partial?fontHeight-1:0)) / fontHeight;
|
||||
}
|
||||
|
||||
// Update the text of a row
|
||||
private void update(Row row, int address, byte[] data, int offset) {
|
||||
private void update(Row row, int y, int address, byte[] data, int offset) {
|
||||
|
||||
// Update address
|
||||
row.address.setBounds(0, y, 8 * fontWidth, fontHeight);
|
||||
row.address.setText(String.format("%08X", address));
|
||||
for (var label : row.bytes)
|
||||
|
||||
// Update bytes
|
||||
for (int z = 0, x = 10 * fontWidth; z < 16; z++) {
|
||||
var label = row.bytes[z];
|
||||
label.setBounds(x, y, 2 * fontWidth, fontHeight);
|
||||
label.setText(String.format("%02X", data[offset++] & 0xFF));
|
||||
x += fontWidth * (z == 7 ? 4 : 3);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,419 @@
|
|||
package app;
|
||||
|
||||
// Java imports
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.util.*;
|
||||
import javax.swing.*;
|
||||
|
||||
// Project imports
|
||||
import util.*;
|
||||
import vue.*;
|
||||
|
||||
// Register list item
|
||||
class Register {
|
||||
|
||||
// Instance fields
|
||||
boolean expanded; // The expanded area is being shown
|
||||
Font font; // Hexadecimal font
|
||||
int index; // Register index
|
||||
int mode; // Display mode for program registers
|
||||
MainWindow parent; // Containing window
|
||||
int type; // Expansion controls type
|
||||
int value; // Current register value
|
||||
|
||||
// UI components
|
||||
private JPanel expansion; // Expansion area
|
||||
private JLabel btnExpand; // Expand button
|
||||
private JLabel lblName; // Register name
|
||||
private JPanel list; // Containing element
|
||||
private JPanel spacer; // Expansion area spacer
|
||||
private JTextField txtValue; // Register value
|
||||
private ArrayList<JComponent> controls; // Expansion controls
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Constants //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Modes
|
||||
static final int FLOAT = 3;
|
||||
static final int HEX = 0;
|
||||
static final int SIGNED = 1;
|
||||
static final int UNSIGNED = 2;
|
||||
|
||||
// Types
|
||||
static final int PROGRAM = -2;
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Constructors //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Default constructor
|
||||
Register(MainWindow parent, JPanel list, String name, int index, int type){
|
||||
|
||||
// Configure instance fields
|
||||
controls = new ArrayList<JComponent>();
|
||||
this.index = index;
|
||||
this.list = list;
|
||||
this.mode = HEX;
|
||||
this.parent = parent;
|
||||
this.type = type;
|
||||
|
||||
// Click handler for expand and name controls
|
||||
MouseListener expand = type == VUE.PC ? null : Util.onMouse(
|
||||
e->{ if (e.getButton() == 1) setExpanded(!expanded); }, null);
|
||||
|
||||
// Expand button
|
||||
btnExpand = new JLabel(expand != null ? "+" : " ");
|
||||
btnExpand.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
if (expand != null)
|
||||
btnExpand.addMouseListener(expand);
|
||||
var gbc = new GridBagConstraints();
|
||||
gbc.anchor = GridBagConstraints.NORTH;
|
||||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
||||
list.add(btnExpand, gbc);
|
||||
|
||||
// Name label
|
||||
lblName = new JLabel(name);
|
||||
if (expand != null)
|
||||
lblName.addMouseListener(expand);
|
||||
gbc = new GridBagConstraints();
|
||||
gbc.anchor = GridBagConstraints.NORTH;
|
||||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
||||
gbc.weightx = 1;
|
||||
list.add(lblName, gbc);
|
||||
|
||||
// Value text box
|
||||
txtValue = new JTextField();
|
||||
txtValue.setBorder(null);
|
||||
txtValue.setOpaque(false);
|
||||
txtValue.setText("00000000");
|
||||
gbc = new GridBagConstraints();
|
||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
||||
gbc.insets = new Insets(0, 4, 0, 0);
|
||||
list.add(txtValue, gbc);
|
||||
|
||||
// Value changed
|
||||
txtValue.addActionListener(e->{
|
||||
String text = txtValue.getText();
|
||||
int val = value;
|
||||
try { switch (mode) {
|
||||
case HEX : val = (int) Long.parseLong(text, 16); break;
|
||||
case SIGNED : // Fallthrough
|
||||
case UNSIGNED: val = (int) Long.parseLong(text, 10); break;
|
||||
case FLOAT : val =
|
||||
Float.floatToIntBits(Float.parseFloat(text) ); break;
|
||||
}} catch (Exception x) { }
|
||||
setValue(val);
|
||||
});
|
||||
|
||||
// Expansion controls
|
||||
switch (type) {
|
||||
case PROGRAM : initProgram(); break;
|
||||
case VUE.CHCW: initCHCW (); break;
|
||||
case VUE.ECR : initECR (); break;
|
||||
case VUE.PIR : initPIR (); break;
|
||||
case VUE.PSW : initPSW (); break;
|
||||
case VUE.TKCW: initTKCW (); break;
|
||||
default: return;
|
||||
}
|
||||
|
||||
// Expansion spacer
|
||||
spacer = new JPanel(null);
|
||||
spacer.setOpaque(false);
|
||||
spacer.setPreferredSize(new Dimension(0, 0));
|
||||
spacer.setVisible(false);
|
||||
list.add(spacer, new GridBagConstraints());
|
||||
|
||||
// Expansion area
|
||||
expansion.setOpaque(false);
|
||||
expansion.setVisible(false);
|
||||
gbc = new GridBagConstraints();
|
||||
gbc.anchor = GridBagConstraints.WEST;
|
||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
||||
gbc.insets = new Insets(0, 4, 0, 0);
|
||||
list.add(expansion, gbc);
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Expansion Constructors //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Expansion controls for CHCW
|
||||
private void initCHCW() {
|
||||
expansion = new JPanel(new GridBagLayout());
|
||||
addCheckBox("ICE", 1, false); endRow();
|
||||
}
|
||||
|
||||
// Expansion controls for ECR
|
||||
private void initECR() {
|
||||
expansion = new JPanel(new GridBagLayout());
|
||||
addTextBox("EICC", 0, 16, false, true); endRow();
|
||||
addTextBox("FECC", 16, 16, false, true); endRow();
|
||||
}
|
||||
|
||||
// Expansion controls for program registers
|
||||
private void initProgram() {
|
||||
expansion = new JPanel(new GridBagLayout());
|
||||
var group = new ButtonGroup();
|
||||
group.add(addRadioButton("cpu.hex" , HEX ));
|
||||
group.add(addRadioButton("cpu.signed" , SIGNED ));
|
||||
group.add(addRadioButton("cpu.unsigned", UNSIGNED));
|
||||
group.add(addRadioButton("cpu.float" , FLOAT ));
|
||||
}
|
||||
|
||||
// Expansion controls for PSW
|
||||
private void initPSW() {
|
||||
expansion = new JPanel(new GridBagLayout());
|
||||
addCheckBox("Z" , 0, false);
|
||||
addCheckBox("FRO", 9, false); endRow();
|
||||
addCheckBox("S" , 1, false);
|
||||
addCheckBox("FIV", 8, false); endRow();
|
||||
addCheckBox("OV" , 2, false);
|
||||
addCheckBox("FZD", 7, false); endRow();
|
||||
addCheckBox("CY" , 3, false);
|
||||
addCheckBox("FOV", 6, false); endRow();
|
||||
addCheckBox("EP" , 14, false);
|
||||
addCheckBox("FUD", 5, false); endRow();
|
||||
addCheckBox("NP" , 15, false);
|
||||
addCheckBox("FPR", 4, false); endRow();
|
||||
addCheckBox("AE" , 13, false); endRow();
|
||||
addCheckBox("ID" , 12, false);
|
||||
addTextBox ("I" , 16, 4, false, false); endRow();
|
||||
}
|
||||
|
||||
// Expansion controls for PIR
|
||||
private void initPIR() {
|
||||
expansion = new JPanel(new GridBagLayout());
|
||||
addTextBox("PT", 0, 16, true, true); endRow();
|
||||
}
|
||||
|
||||
// Expansion controls for TKCW
|
||||
private void initTKCW() {
|
||||
expansion = new JPanel(new GridBagLayout());
|
||||
addCheckBox("OTM", 8, true);
|
||||
addCheckBox("FVT", 5, true); endRow();
|
||||
addCheckBox("FIT", 7, true);
|
||||
addCheckBox("FUT", 4, true); endRow();
|
||||
addCheckBox("FZT", 6, true);
|
||||
addCheckBox("FPT", 3, true); endRow();
|
||||
addCheckBox("RDI", 2, true);
|
||||
addTextBox ("RD", 0, 2, true, false); endRow();
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Package Methods //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Refresh controls
|
||||
void refresh() {
|
||||
|
||||
// Value text box
|
||||
value = parent.vue.getRegister(index, type != PROGRAM);
|
||||
txtValue.setText(
|
||||
type != PROGRAM || mode == HEX ?
|
||||
String.format("%08X", value) :
|
||||
mode == SIGNED ? Integer.toString(value) :
|
||||
mode == UNSIGNED ? Long.toString(value & 0xFFFFFFFFL) :
|
||||
Float.toString(Float.intBitsToFloat(value))
|
||||
);
|
||||
|
||||
// Expansion controls
|
||||
for (var control : controls) {
|
||||
|
||||
// Check box
|
||||
if (control instanceof JCheckBox) {
|
||||
var ctrl = (JCheckBox) control;
|
||||
int bit = (Integer) ctrl.getClientProperty("bit");
|
||||
ctrl.setSelected((value & 1 << bit) != 0);
|
||||
}
|
||||
|
||||
// Text box
|
||||
if (control instanceof JTextField) {
|
||||
var ctrl = (JTextField) control;
|
||||
int bit = (Integer) ctrl.getClientProperty("bit" );
|
||||
int digits = (Integer) ctrl.getClientProperty("digits");
|
||||
boolean hex = (Boolean) ctrl.getClientProperty("hex");
|
||||
int width = (Integer) ctrl.getClientProperty("width");
|
||||
int val = value >> bit & (1 << width) - 1;
|
||||
ctrl.setText(!hex ? Integer.toString(val) :
|
||||
String.format("%0" + digits + "X", val));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Specify whether the expansion area is expanded
|
||||
void setExpanded(boolean expanded) {
|
||||
|
||||
// Error checking
|
||||
if (type == VUE.PC)
|
||||
return;
|
||||
|
||||
// Update controls
|
||||
this.expanded = expanded;
|
||||
btnExpand.setText (expanded ? "-" : "+");
|
||||
expansion.setVisible(expanded);
|
||||
spacer .setVisible(expanded);
|
||||
list.revalidate();
|
||||
list.repaint();
|
||||
}
|
||||
|
||||
// Specify the width of the expand button
|
||||
void setExpandWidth(int width) {
|
||||
var size = btnExpand.getPreferredSize();
|
||||
size.width = width;
|
||||
btnExpand.setPreferredSize(size);
|
||||
}
|
||||
|
||||
// Specify a new font
|
||||
void setFont(Font font, int fontWidth, int fontHeight) {
|
||||
this.font = font;
|
||||
|
||||
// Value text box
|
||||
txtValue.setFont(font);
|
||||
txtValue.setPreferredSize(
|
||||
new Dimension(8 * fontWidth + 4, fontHeight));
|
||||
|
||||
// Expansion controls
|
||||
for (var ctrl : controls) {
|
||||
if (!(ctrl instanceof JTextField))
|
||||
continue;
|
||||
if ((Boolean) ctrl.getClientProperty("hex"))
|
||||
((JTextField) ctrl).setFont(font);
|
||||
int digits = (Integer) ctrl.getClientProperty("digits");
|
||||
var size = ctrl.getPreferredSize();
|
||||
size.width = digits * fontWidth + 4;
|
||||
ctrl.setPreferredSize(size);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Change the display mode of a program register
|
||||
void setMode(int mode) {
|
||||
this.mode = mode;
|
||||
txtValue.setFont(mode == HEX ? font : null);
|
||||
refresh();
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Private Methods //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Add a check box to the expansion area
|
||||
private void addCheckBox(String name, int bit, boolean readOnly) {
|
||||
int mask = 1 << bit;
|
||||
|
||||
// Configure control
|
||||
var ctrl = new JCheckBox(name);
|
||||
ctrl.putClientProperty("bit", bit);
|
||||
ctrl.setBorder(null);
|
||||
ctrl.setEnabled(!readOnly);
|
||||
ctrl.setFocusable(false);
|
||||
ctrl.setOpaque(false);
|
||||
controls.add(ctrl);
|
||||
|
||||
// Event handler
|
||||
ctrl.addItemListener(e->setValue(
|
||||
e.getStateChange() == ItemEvent.SELECTED ?
|
||||
value | mask : value & ~mask
|
||||
));
|
||||
|
||||
// Configure expansion area
|
||||
var gbc = new GridBagConstraints();
|
||||
gbc.anchor = GridBagConstraints.NORTHWEST;
|
||||
gbc.gridwidth = 2;
|
||||
gbc.insets = new Insets(0, 4, 0, 0);
|
||||
expansion.add(ctrl, gbc);
|
||||
}
|
||||
|
||||
// Add a radio button to the expansion area
|
||||
private JRadioButton addRadioButton(String key, int mode) {
|
||||
|
||||
// Configure control
|
||||
var ctrl = new JRadioButton();
|
||||
parent.app.getLocalizer().add(ctrl, key);
|
||||
ctrl.setBorder(null);
|
||||
ctrl.setFocusable(false);
|
||||
ctrl.setOpaque(false);
|
||||
ctrl.setSelected(mode == HEX);
|
||||
controls.add(ctrl);
|
||||
|
||||
// Event handler
|
||||
ctrl.addItemListener(e->{
|
||||
if (e.getStateChange() == ItemEvent.SELECTED) setMode(mode); });
|
||||
|
||||
// Configure expansion area
|
||||
var gbc = new GridBagConstraints();
|
||||
gbc.anchor = GridBagConstraints.NORTHWEST;
|
||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
||||
gbc.insets = new Insets(0, 4, 0, 0);
|
||||
expansion.add(ctrl, gbc);
|
||||
|
||||
return ctrl;
|
||||
}
|
||||
|
||||
// Add a text box to the expansion area
|
||||
private void addTextBox(String name, int bit, int width, boolean readOnly,
|
||||
boolean hex) {
|
||||
int mask = (1 << width) - 1;
|
||||
|
||||
// Configure control
|
||||
var ctrl = new JTextField();
|
||||
ctrl.putClientProperty("bit", bit);
|
||||
ctrl.putClientProperty("digits",
|
||||
Integer.toString(mask, hex ? 16 : 10).length());
|
||||
ctrl.putClientProperty("hex", hex);
|
||||
ctrl.putClientProperty("width", width);
|
||||
ctrl.setBorder(null);
|
||||
ctrl.setEnabled(!readOnly);
|
||||
ctrl.setOpaque(false);
|
||||
controls.add(ctrl);
|
||||
|
||||
// Event handlers
|
||||
ctrl.addActionListener(e->{
|
||||
int val = value >> bit & mask;
|
||||
try { val = Integer.parseInt(ctrl.getText(), hex ? 16 : 10); }
|
||||
catch (Exception x) { }
|
||||
setValue(value & ~(mask << bit) | (val & mask) << bit);
|
||||
});
|
||||
|
||||
// Configure expansion area
|
||||
var label = new JLabel(name);
|
||||
label.setEnabled(!readOnly);
|
||||
var gbc = new GridBagConstraints();
|
||||
gbc.anchor = GridBagConstraints.NORTHWEST;
|
||||
gbc.insets = new Insets(0, 4, 0, 4);
|
||||
expansion.add(label, gbc);
|
||||
expansion.add(ctrl , gbc);
|
||||
}
|
||||
|
||||
// Terminate a row of expansion controls
|
||||
private void endRow() {
|
||||
var spacer = new JPanel(null);
|
||||
spacer.setOpaque(false);
|
||||
spacer.setPreferredSize(new Dimension(0, 0));
|
||||
var gbc = new GridBagConstraints();
|
||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
||||
expansion.add(spacer, gbc);
|
||||
}
|
||||
|
||||
// Update the register value
|
||||
private void setValue(int value) {
|
||||
list.requestFocus();
|
||||
parent.vue.setRegister(index, type != PROGRAM, value);
|
||||
refresh();
|
||||
}
|
||||
|
||||
}
|
|
@ -28,12 +28,13 @@ public final class Util {
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Event listener interfaces
|
||||
public interface OnClose { void call(WindowEvent e); }
|
||||
public interface OnClose2 { void call(InternalFrameEvent e); }
|
||||
public interface OnFocus { void call(FocusEvent e); }
|
||||
public interface OnKey { void call(KeyEvent e); }
|
||||
public interface OnMouse { void call(MouseEvent e); }
|
||||
public interface OnResize { void call(ComponentEvent e); }
|
||||
public interface OnClose { void call(WindowEvent e); }
|
||||
public interface OnClose2 { void call(InternalFrameEvent e); }
|
||||
public interface OnFocus { void call(FocusEvent e); }
|
||||
public interface OnKey { void call(KeyEvent e); }
|
||||
public interface OnMouse { void call(MouseEvent e); }
|
||||
public interface OnResize { void call(ComponentEvent e); }
|
||||
public interface OnVisible { void call(AncestorEvent e); }
|
||||
|
||||
// Data class for byte-order marks
|
||||
private static class BOM {
|
||||
|
@ -310,6 +311,17 @@ public final class Util {
|
|||
};
|
||||
}
|
||||
|
||||
// Produce an AncestorListener using functional interfaces
|
||||
public static AncestorListener onVisible(OnVisible show, OnVisible hide) {
|
||||
return new AncestorListener() {
|
||||
public void ancestorMoved (AncestorEvent e) { }
|
||||
public void ancestorAdded (AncestorEvent e)
|
||||
{ if (show != null) show.call(e); }
|
||||
public void ancestorRemoved(AncestorEvent e)
|
||||
{ if (hide != null) hide.call(e); }
|
||||
};
|
||||
}
|
||||
|
||||
// Configure the Swing look-and-feel with the system theme
|
||||
public static boolean setSystemLAF() {
|
||||
try {
|
||||
|
|
|
@ -87,6 +87,11 @@ class Bus {
|
|||
return 0; // Unreachable
|
||||
}
|
||||
|
||||
// Perform a system reset
|
||||
public void reset() {
|
||||
Arrays.fill(wram, 0, 0x10000, (byte) 0);
|
||||
}
|
||||
|
||||
// Write bytes to host memory
|
||||
void writeBytes(byte[] dest,byte[] src,int address,int offset,int length) {
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ class CPU {
|
|||
// Package fields
|
||||
int cycles; // Cycles until next stage
|
||||
int fetch; // Fetch unit index
|
||||
int lastPC; // Previous value of PC
|
||||
int stage; // Current processing stage
|
||||
|
||||
// Program registers
|
||||
|
@ -113,7 +114,19 @@ class CPU {
|
|||
|
||||
// Remaining cases to encourage tableswitch
|
||||
case 8: case 9: case 10: case 11: case 12: case 13: case 14:
|
||||
case 15: case 16: case 17: case 18: case 19: case 20: case 21:
|
||||
case 15: case 16: case 17: case 18: case 19: case 20: case 21: // Configure instance fields
|
||||
cycles = 0;
|
||||
fetch = 0;
|
||||
stage = FETCH;
|
||||
|
||||
// Reset program counter
|
||||
pc = 0xFFFFFFF0;
|
||||
|
||||
// Clear all registers (hardware only sets ECR, PC and PSW)
|
||||
for (int x = 0; x < 32; x++) {
|
||||
program[x] = 0;
|
||||
setSystemRegister(x, 0, true);
|
||||
}
|
||||
case 22: case 23: case 26: case 27: case 28:
|
||||
return 0;
|
||||
}
|
||||
|
@ -128,15 +141,17 @@ class CPU {
|
|||
fetch = 0;
|
||||
stage = FETCH;
|
||||
|
||||
// Reset program counter
|
||||
pc = 0xFFFFFFF0;
|
||||
|
||||
// Clear all registers (hardware only sets ECR, PC and PSW)
|
||||
for (int x = 0; x < 32; x++) {
|
||||
program[x] = 0;
|
||||
setSystemRegister(x, 0, true);
|
||||
}
|
||||
|
||||
// Configure registers
|
||||
ecr_eicc = 0xFFF0;
|
||||
lastPC = 0xFFFFFFF0;
|
||||
pc = 0xFFFFFFF0;
|
||||
psw_np = 1;
|
||||
}
|
||||
|
||||
// Write a system register
|
||||
|
@ -150,6 +165,13 @@ class CPU {
|
|||
case 29 : return sr29 = value;
|
||||
case 31 : return sr31 = debug || value >= 0 ? value : -value;
|
||||
|
||||
case VUE.ECR:
|
||||
if (debug) {
|
||||
ecr_fecc = value >> 16 & 0xFFFF;
|
||||
ecr_eicc = value & 0xFFFF;
|
||||
}
|
||||
return ecr_fecc << 16 | ecr_eicc;
|
||||
|
||||
case VUE.CHCW :
|
||||
chcw_cen = value >> 20 & 0x00000FFF;
|
||||
chcw_cec = value >> 8 & 0x00000FFF;
|
||||
|
@ -181,10 +203,10 @@ class CPU {
|
|||
return value & 0x000FF3FF;
|
||||
|
||||
// Remaining cases to encourage tableswitch
|
||||
case 4: case 6: case 7: case 8: case 9: case 10: case 11:
|
||||
case 12: case 13: case 14: case 15: case 16: case 17: case 18:
|
||||
case 19: case 20: case 21: case 22: case 23: case 26: case 27:
|
||||
case 28: case 30:
|
||||
case 6: case 7: case 8: case 9: case 10: case 11: case 12:
|
||||
case 13: case 14: case 15: case 16: case 17: case 18: case 19:
|
||||
case 20: case 21: case 22: case 23: case 26: case 27: case 28:
|
||||
case 30:
|
||||
return 0;
|
||||
}
|
||||
return 1; // Unreachable
|
||||
|
|
|
@ -26,6 +26,7 @@ class JavaVUE extends VUE {
|
|||
JavaVUE() {
|
||||
bus = new Bus(this);
|
||||
cpu = new CPU(this);
|
||||
reset();
|
||||
}
|
||||
|
||||
|
||||
|
@ -108,13 +109,19 @@ class JavaVUE extends VUE {
|
|||
return true;
|
||||
}
|
||||
|
||||
// Initialize all system components
|
||||
public void reset() {
|
||||
bus.reset();
|
||||
cpu.reset();
|
||||
}
|
||||
|
||||
// Specify a register value
|
||||
public int setRegister(int index, boolean system, int value) {
|
||||
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]
|
||||
index == 0 ? 0 : (cpu.program[index] = value)
|
||||
;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// Native-backed emulation core implementation
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <jni.h>
|
||||
|
@ -21,7 +23,7 @@ static const int TYPE_SIZES[] = { 1, 1, 2, 2, 4 };
|
|||
|
||||
// Core context state type
|
||||
typedef struct {
|
||||
VUE vue;
|
||||
VUE vue; /* Context into the generic C library */
|
||||
} CORE;
|
||||
|
||||
|
||||
|
@ -59,6 +61,7 @@ JNIEXPORT void JNICALL Java_vue_NativeVUE_construct
|
|||
// Produce and initialize s new core context
|
||||
CORE *core = calloc(sizeof (CORE), 1);
|
||||
vueInitialize(&core->vue);
|
||||
vueReset(&core->vue);
|
||||
|
||||
// Encode the context handle into a byte array
|
||||
jbyteArray pointer = (*env)->NewByteArray(env, sizeof (void *));
|
||||
|
@ -83,7 +86,7 @@ JNIEXPORT void JNICALL Java_vue_NativeVUE_dispose
|
|||
JNIEXPORT jint JNICALL Java_vue_NativeVUE_getRegister
|
||||
(JNIEnv *env, jobject vue, jint index, jboolean system) {
|
||||
CORE *core = GetCore(env, vue);
|
||||
return vueGetRegister(&core->vue, index, system);
|
||||
return vueGetRegister(&core->vue, index, system);;
|
||||
}
|
||||
|
||||
// Retrieve a copy of the ROM data
|
||||
|
@ -130,6 +133,13 @@ JNIEXPORT jboolean JNICALL Java_vue_NativeVUE_read
|
|||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
// Initialize all system components
|
||||
JNIEXPORT void JNICALL Java_vue_NativeVUE_reset
|
||||
(JNIEnv *env, jobject vue) {
|
||||
CORE *core = GetCore(env, vue);
|
||||
vueReset(&core->vue);
|
||||
}
|
||||
|
||||
// Specify a register value
|
||||
JNIEXPORT jint JNICALL Java_vue_NativeVUE_setRegister
|
||||
(JNIEnv *env, jobject vue, jint index, jboolean system, jint value) {
|
|
@ -39,6 +39,9 @@ class NativeVUE extends VUE {
|
|||
public native boolean read(int address, byte[] dest, int offset,
|
||||
int length);
|
||||
|
||||
// Initialize all system components
|
||||
public native void reset();
|
||||
|
||||
// Specify a register value
|
||||
public native int setRegister(int index, boolean system, int value);
|
||||
|
||||
|
|
|
@ -32,6 +32,13 @@ public abstract class VUE {
|
|||
public static final int PSW = 5;
|
||||
public static final int TKCW = 7;
|
||||
|
||||
// Program register indexes
|
||||
public static final int GP = 4;
|
||||
public static final int HP = 2;
|
||||
public static final int LP = 31;
|
||||
public static final int SP = 3;
|
||||
public static final int TP = 5;
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
@ -81,6 +88,9 @@ public abstract class VUE {
|
|||
public abstract boolean read(int address, byte[] dest, int offset,
|
||||
int length);
|
||||
|
||||
// Initialize all system components
|
||||
public abstract void reset();
|
||||
|
||||
// Specify a register value
|
||||
public abstract int setRegister(int index, boolean system, int value);
|
||||
|
||||
|
|
Loading…
Reference in New Issue