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