Laying the groundwork for the CPU
This commit is contained in:
parent
61bee38e3d
commit
2e38c1fa49
|
@ -59,12 +59,12 @@ static int32_t busReadValue(VUE *vue, uint32_t address, int type) {
|
|||
case 3: /* Fallthrough */ /* Unmapped */
|
||||
case 4: /* Cartridge expansion (not supported) */
|
||||
return 0;
|
||||
case 5: return /* System WRAM */
|
||||
busReadMemory(vue->wram, address & 0xFFFF , type);
|
||||
case 6: return /* Cartridge RAM */
|
||||
busReadMemory(vue->sram, address & (vue->sram_size - 1), type);
|
||||
case 7: return /* Cartridge ROM */
|
||||
busReadMemory(vue->rom , address & (vue->rom_size - 1), type);
|
||||
case 5: /* System WRAM */
|
||||
return busReadMemory(vue->bus.wram, address & 0xFFFF, type);
|
||||
case 6: return busReadMemory(vue->bus.sram, /* Cartridge RAM */
|
||||
address & (vue->bus.sram_size - 1), type);
|
||||
case 7: return busReadMemory(vue->bus.rom , /* Cartridge ROM */
|
||||
address & (vue->bus.rom_size - 1), type);
|
||||
}
|
||||
return 0; /* Unreachable */
|
||||
}
|
||||
|
@ -117,16 +117,15 @@ static void busWriteValue(VUE *vue, uint32_t address, int type, int32_t value){
|
|||
address &= -TYPE_SIZES[type];
|
||||
switch (address >> 24 & 7) {
|
||||
case 5: /* System WRAM */
|
||||
busWriteMemory(vue->wram,
|
||||
address & 0xFFFF , type, value);
|
||||
busWriteMemory(vue->bus.wram, address & 0xFFFF, type, value);
|
||||
break;
|
||||
case 6: /* Cartridge RAM */
|
||||
busWriteMemory(vue->sram,
|
||||
address & (vue->sram_size - 1), type, value);
|
||||
busWriteMemory(vue->bus.sram,
|
||||
address & (vue->bus.sram_size - 1), type, value);
|
||||
break;
|
||||
case 7: /* Cartridge ROM */
|
||||
busWriteMemory(vue->rom ,
|
||||
address & (vue->rom_size - 1), type, value);
|
||||
busWriteMemory(vue->bus.rom ,
|
||||
address & (vue->bus.rom_size - 1), type, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,156 @@
|
|||
/* This file is included through vue.c and cannot be built directly. */
|
||||
#ifdef VUEAPI
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Constants *
|
||||
*****************************************************************************/
|
||||
|
||||
/* Stages */
|
||||
#define CPU_FETCH 0
|
||||
#define CPU_EXECUTE 1
|
||||
#define CPU_HALT 2
|
||||
#define CPU_EXCEPTION 3
|
||||
#define CPU_FATAL 4
|
||||
#define CPU_CLEAR 5
|
||||
#define CPU_DUMP 6
|
||||
#define CPU_RESTORE 7
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Module Functions *
|
||||
*****************************************************************************/
|
||||
|
||||
/* Read a system register */
|
||||
static int32_t cpuGetSystemRegister(VUE *vue, int index) {
|
||||
switch (index) {
|
||||
case VUE_ADTRE: return vue->cpu.adtre;
|
||||
case VUE_EIPC : return vue->cpu.eipc;
|
||||
case VUE_EIPSW: return vue->cpu.eipsw;
|
||||
case VUE_FEPC : return vue->cpu.fepc;
|
||||
case VUE_FEPSW: return vue->cpu.fepsw;
|
||||
case VUE_ECR : return vue->cpu.ecr_fecc << 16 | vue->cpu.ecr_eicc;
|
||||
case VUE_PIR : return 0x00005346;
|
||||
case VUE_TKCW : return 0x000000E0;
|
||||
case VUE_CHCW : return vue->cpu.chcw_ice << 1;
|
||||
case 29 : return vue->cpu.sr29;
|
||||
case 30 : return 0x00000004;
|
||||
case 31 : return vue->cpu.sr31;
|
||||
case VUE_PSW : return
|
||||
vue->cpu.psw_i << 16 | vue->cpu.psw_fov << 6 |
|
||||
vue->cpu.psw_np << 15 | vue->cpu.psw_fud << 5 |
|
||||
vue->cpu.psw_ep << 14 | vue->cpu.psw_fpr << 4 |
|
||||
vue->cpu.psw_ae << 13 | vue->cpu.psw_cy << 3 |
|
||||
vue->cpu.psw_id << 12 | vue->cpu.psw_ov << 2 |
|
||||
vue->cpu.psw_fro << 9 | vue->cpu.psw_s << 1 |
|
||||
vue->cpu.psw_fiv << 8 | vue->cpu.psw_z |
|
||||
vue->cpu.psw_fzd << 7
|
||||
;
|
||||
|
||||
/* 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 22: case 23: case 26: case 27: case 28:
|
||||
return 0;
|
||||
}
|
||||
return 1; /* Unreachable */
|
||||
}
|
||||
|
||||
/* Write a system register */
|
||||
static int32_t cpuSetSystemRegister(VUE *vue, int index, int32_t value,
|
||||
vbool debug) {
|
||||
switch (index) {
|
||||
case VUE_ADTRE: return vue->cpu.adtre = value & 0xFFFFFFFE;
|
||||
case VUE_EIPC : return vue->cpu.eipc = value & 0xFFFFFFFE;
|
||||
case VUE_EIPSW: return vue->cpu.eipsw = value & 0x000FF3FF;
|
||||
case VUE_FEPC : return vue->cpu.fepc = value & 0xFFFFFFFE;
|
||||
case VUE_FEPSW: return vue->cpu.fepsw = value & 0x000FF3FF;
|
||||
case 29 : return vue->cpu.sr29 = value;
|
||||
case 31 : return vue->cpu.sr31 =
|
||||
debug || value >= 0 ? value : -value;
|
||||
|
||||
case VUE_CHCW :
|
||||
vue->cpu.chcw_cen = value >> 20 & 0x00000FFF;
|
||||
vue->cpu.chcw_cec = value >> 8 & 0x00000FFF;
|
||||
vue->cpu.chcw_sa = value >> 8 & 0x00FFFFFF;
|
||||
vue->cpu.chcw_icr = value >> 5 & 1;
|
||||
vue->cpu.chcw_icd = value >> 4 & 1;
|
||||
vue->cpu.chcw_ice = value >> 1 & 1;
|
||||
vue->cpu.chcw_icc = value & 1;
|
||||
|
||||
/* Only one of ICC, ICD or ICR is set */
|
||||
value &= 0x00000031;
|
||||
if ((value & (value - 1)) == 0) {
|
||||
/* Clear */
|
||||
/* Dump */
|
||||
/* Restore */
|
||||
}
|
||||
|
||||
return vue->cpu.chcw_ice << 1;
|
||||
|
||||
case VUE_PSW :
|
||||
vue->cpu.psw_i = value >> 16 & 15;
|
||||
vue->cpu.psw_np = value >> 15 & 1;
|
||||
vue->cpu.psw_ep = value >> 14 & 1;
|
||||
vue->cpu.psw_ae = value >> 13 & 1;
|
||||
vue->cpu.psw_id = value >> 12 & 1;
|
||||
vue->cpu.psw_fro = value >> 9 & 1;
|
||||
vue->cpu.psw_fiv = value >> 8 & 1;
|
||||
vue->cpu.psw_fzd = value >> 7 & 1;
|
||||
vue->cpu.psw_fov = value >> 6 & 1;
|
||||
vue->cpu.psw_fud = value >> 5 & 1;
|
||||
vue->cpu.psw_fpr = value >> 4 & 1;
|
||||
vue->cpu.psw_cy = value >> 3 & 1;
|
||||
vue->cpu.psw_ov = value >> 2 & 1;
|
||||
vue->cpu.psw_s = value >> 1 & 1;
|
||||
vue->cpu.psw_z = value & 1;
|
||||
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:
|
||||
return 0;
|
||||
}
|
||||
return 1; /* Unreachable */
|
||||
}
|
||||
|
||||
/* System reset */
|
||||
static void cpuReset(VUE *vue) {
|
||||
int x;
|
||||
|
||||
/* Configure instance fields */
|
||||
vue->cpu.cycles = 0;
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Test a condition */
|
||||
static int8_t cpuTest(VUE *vue, int condition) {
|
||||
switch (condition) {
|
||||
case 0: return vue->cpu.psw_ov;
|
||||
case 1: return vue->cpu.psw_cy;
|
||||
case 2: return vue->cpu.psw_z;
|
||||
case 3: return vue->cpu.psw_cy | vue->cpu.psw_z;
|
||||
case 4: return vue->cpu.psw_s;
|
||||
case 5: return 1;
|
||||
case 6: return vue->cpu.psw_ov | vue->cpu.psw_s;
|
||||
case 7: return (vue->cpu.psw_ov ^ vue->cpu.psw_s) | vue->cpu.psw_z;
|
||||
}
|
||||
return cpuTest(vue, condition & 7) ^ 1;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -30,6 +30,19 @@ extern "C" {
|
|||
#define VUE_U16 3
|
||||
#define VUE_S32 4
|
||||
|
||||
/* System register indexes */
|
||||
#define VUE_ADTRE 25
|
||||
#define VUE_CHCW 24
|
||||
#define VUE_ECR 4
|
||||
#define VUE_EIPC 0
|
||||
#define VUE_EIPSW 1
|
||||
#define VUE_FEPC 2
|
||||
#define VUE_FEPSW 3
|
||||
#define VUE_PC -1
|
||||
#define VUE_PIR 6
|
||||
#define VUE_PSW 5
|
||||
#define VUE_TKCW 7
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
|
@ -41,11 +54,66 @@ typedef int vbool;
|
|||
|
||||
/* Emulation state */
|
||||
typedef struct {
|
||||
uint8_t *rom; /* Cartridge ROM */
|
||||
uint32_t rom_size; /* Number of bytes in cartridge ROM */
|
||||
uint8_t *sram; /* Cartridge RAM */
|
||||
uint32_t sram_size; /* Number of bytes in cartridge RAM */
|
||||
uint8_t wram[0x10000]; /* System memory */
|
||||
|
||||
/* Memory bus */
|
||||
struct {
|
||||
uint8_t *rom; /* Cartridge ROM */
|
||||
uint32_t rom_size; /* Number of bytes in cartridge ROM */
|
||||
uint8_t *sram; /* Cartridge RAM */
|
||||
uint32_t sram_size; /* Number of bytes in cartridge RAM */
|
||||
uint8_t wram[0x10000]; /* System memory */
|
||||
} bus;
|
||||
|
||||
/* CPU state */
|
||||
struct {
|
||||
uint32_t cycles; /* Cycles until next stage */
|
||||
int fetch; /* Fetch unit index */
|
||||
int stage; /* Current processing stage */
|
||||
|
||||
/* Program registers */
|
||||
int32_t program[32];
|
||||
|
||||
/* System registers */
|
||||
int32_t adtre; /* Address Trap Register for Execution */
|
||||
int32_t eipc; /* Exception/interrupt PC */
|
||||
int32_t eipsw; /* Exception/interrupt PSW */
|
||||
int32_t fepc; /* Duplexed exception PC */
|
||||
int32_t fepsw; /* Duplexed exception PSW */
|
||||
int32_t pc; /* Program Counter */
|
||||
int32_t sr29; /* System register 29 */
|
||||
int32_t sr31; /* System register 31 */
|
||||
|
||||
/* Program Status Word */
|
||||
int8_t psw_ae; /* Address Trap Enable */
|
||||
int8_t psw_ep; /* Exception Pending */
|
||||
int8_t psw_id; /* Interrupt Disable */
|
||||
int8_t psw_cy; /* Carry */
|
||||
int8_t psw_fiv; /* Floating Reserved Operand */
|
||||
int8_t psw_fov; /* Floating Overflow */
|
||||
int8_t psw_fpr; /* Floating Precision */
|
||||
int8_t psw_fro; /* Floating Reserved Operand */
|
||||
int8_t psw_fud; /* Floating Underflow */
|
||||
int8_t psw_fzd; /* Floating Zero Divide */
|
||||
int8_t psw_i; /* Interrupt Level */
|
||||
int8_t psw_np; /* NMI Pending */
|
||||
int8_t psw_ov; /* Overflow */
|
||||
int8_t psw_s; /* Sign */
|
||||
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 */
|
||||
|
||||
/* Exception Cause Register */
|
||||
int8_t ecr_eicc; /* Exception/Interrupt Cause Code */
|
||||
int8_t ecr_fecc; /* Fatal Error Cause Code */
|
||||
} cpu;
|
||||
|
||||
} VUE;
|
||||
|
||||
|
||||
|
@ -54,10 +122,12 @@ typedef struct {
|
|||
* Function Prototypes *
|
||||
*****************************************************************************/
|
||||
|
||||
VUEAPI void vueInitialize(VUE *vue);
|
||||
VUEAPI vbool vueRead (VUE *vue, uint32_t address, uint8_t *dest, uint32_t length);
|
||||
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);
|
||||
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 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);
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ static const int TYPE_SIZES[] = { 1, 1, 2, 2, 4 };
|
|||
*****************************************************************************/
|
||||
|
||||
#include "bus.c"
|
||||
#include "cpu.c"
|
||||
|
||||
|
||||
|
||||
|
@ -24,10 +25,20 @@ static const int TYPE_SIZES[] = { 1, 1, 2, 2, 4 };
|
|||
* Library Functions *
|
||||
*****************************************************************************/
|
||||
|
||||
/* Retrieve the value of a register */
|
||||
int32_t vueGetRegister(VUE *vue, int index, vbool system) {
|
||||
return
|
||||
index == VUE_PC && system ? vue->cpu.pc :
|
||||
index < 0 || index > 31 ? 0 :
|
||||
system ? cpuGetSystemRegister(vue, index) :
|
||||
vue->cpu.program[index]
|
||||
;
|
||||
}
|
||||
|
||||
/* Prepare an emulation state context for use */
|
||||
void vueInitialize(VUE *vue) {
|
||||
vue->rom = NULL;
|
||||
vue->sram = NULL;
|
||||
vue->bus.rom = NULL;
|
||||
vue->bus.sram = NULL;
|
||||
}
|
||||
|
||||
/* Read bytes from the CPU bus */
|
||||
|
@ -51,16 +62,16 @@ vbool vueRead(VUE *vue, uint32_t address, uint8_t *dest, uint32_t length) {
|
|||
case 1: /* Fallthrough */ /* VSU (write-only) */
|
||||
case 3: /* Fallthrough */ /* Unmapped */
|
||||
case 4: /* Cartridge expansion (not supported) */
|
||||
busReadBytes(NULL , dest, address, 0 , count);
|
||||
busReadBytes(NULL, dest, address, 0, count);
|
||||
break;
|
||||
case 5: /* System WRAM */
|
||||
busReadBytes(vue->wram, dest, address, 0x10000 , count);
|
||||
case 5: busReadBytes(vue->bus.wram, dest, /* System WRAM */
|
||||
address, 0x10000 , count);
|
||||
break;
|
||||
case 6: /* Cartridge RAM */
|
||||
busReadBytes(vue->sram, dest, address, vue->sram_size, count);
|
||||
case 6: busReadBytes(vue->bus.sram, dest, /* Cartridge RAM */
|
||||
address, vue->bus.sram_size, count);
|
||||
break;
|
||||
case 7: /* Cartridge ROM */
|
||||
busReadBytes(vue->rom , dest, address, vue->rom_size , count);
|
||||
case 7: busReadBytes(vue->bus.rom , dest, /* Cartridge ROM */
|
||||
address, vue->bus.rom_size , count);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -68,6 +79,16 @@ vbool vueRead(VUE *vue, uint32_t address, uint8_t *dest, uint32_t length) {
|
|||
return VUE_TRUE;
|
||||
}
|
||||
|
||||
/* Specify a value for a register */
|
||||
int32_t vueSetRegister(VUE *vue, int index, vbool system, int32_t value) {
|
||||
return
|
||||
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]
|
||||
;
|
||||
}
|
||||
|
||||
/* Specify a new ROM buffer */
|
||||
vbool vueSetROM(VUE *vue, uint8_t *rom, uint32_t size) {
|
||||
|
||||
|
@ -80,8 +101,8 @@ vbool vueSetROM(VUE *vue, uint8_t *rom, uint32_t size) {
|
|||
) return VUE_FALSE;
|
||||
|
||||
/* Accept the new ROM buffer */
|
||||
vue->rom = rom;
|
||||
vue->rom_size = size;
|
||||
vue->bus.rom = rom;
|
||||
vue->bus.rom_size = size;
|
||||
return VUE_TRUE;
|
||||
}
|
||||
|
||||
|
@ -104,13 +125,13 @@ vbool vueWrite(VUE *vue, uint32_t address, uint8_t *src, uint32_t length) {
|
|||
/* Process by component */
|
||||
switch (address >> 24 & 7) {
|
||||
case 5: /* System WRAM */
|
||||
busWriteBytes(vue->wram, src, address, 0x10000 , count);
|
||||
busWriteBytes(vue->bus.wram, src, address, 0x10000, count);
|
||||
break;
|
||||
case 6: /* Cartridge RAM */
|
||||
busWriteBytes(vue->sram, src, address, vue->sram_size, count);
|
||||
case 6: busWriteBytes(vue->bus.sram, src, /* Cartridge RAM */
|
||||
address, vue->bus.sram_size, count);
|
||||
break;
|
||||
case 7: /* Cartridge ROM */
|
||||
busWriteBytes(vue->rom , src, address, vue->rom_size , count);
|
||||
case 7: busWriteBytes(vue->bus.rom , src, /* Cartridge ROM */
|
||||
address, vue->bus.rom_size , count);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -87,9 +87,7 @@ public class App {
|
|||
|
||||
// Specify whether using the native module
|
||||
boolean setUseNative(boolean useNative) {
|
||||
this.useNative = useNative && VUE.isNativeLoaded();
|
||||
System.out.println("Native: " + (this.useNative ? "Yes" : "No"));
|
||||
return this.useNative;
|
||||
return this.useNative = useNative && VUE.isNativeLoaded();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ class ChildWindow extends JInternalFrame {
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Show or hide the component
|
||||
public void setVisible(boolean visible) {
|
||||
public void setVisible(boolean visible) {
|
||||
|
||||
// Making visible
|
||||
if (visible) {
|
||||
|
@ -56,7 +56,11 @@ class ChildWindow extends JInternalFrame {
|
|||
}
|
||||
|
||||
// Already visible: bring to front
|
||||
else moveToFront();
|
||||
else {
|
||||
moveToFront();
|
||||
try { setSelected(true); } catch (Exception e) { }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Change visibility
|
||||
|
|
|
@ -64,6 +64,7 @@ class MainWindow extends JFrame {
|
|||
this.app = app;
|
||||
pwd = Util.PWD;
|
||||
vue = VUE.create(app.getUseNative());
|
||||
System.out.println("Native: " + (vue.isNative() ? "Yes" : "No"));
|
||||
|
||||
// Configure video pane
|
||||
video = new JPanel(null) {
|
||||
|
@ -109,7 +110,6 @@ class MainWindow extends JFrame {
|
|||
private JMenuBar initMenus() {
|
||||
var bar = new JMenuBar();
|
||||
var loc = app.getLocalizer();
|
||||
bar.setBorder(null);
|
||||
bar.add(initMenuFile (loc));
|
||||
bar.add(initMenuDebug(loc));
|
||||
return bar;
|
||||
|
|
|
@ -227,6 +227,7 @@ class Memory extends ChildWindow {
|
|||
var label = row.bytes[x] = new JLabel();
|
||||
label.setFont(font);
|
||||
label.setForeground(SystemColor.windowText);
|
||||
label.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
label.setVisible(false);
|
||||
client.add(label);
|
||||
}
|
||||
|
|
|
@ -59,7 +59,6 @@ JNIEXPORT void JNICALL Java_vue_NativeVUE_construct
|
|||
// Produce and initialize s new core context
|
||||
CORE *core = calloc(sizeof (CORE), 1);
|
||||
vueInitialize(&core->vue);
|
||||
vueSetROM(&core->vue, calloc(1024, 1), 1024);
|
||||
|
||||
// Encode the context handle into a byte array
|
||||
jbyteArray pointer = (*env)->NewByteArray(env, sizeof (void *));
|
||||
|
@ -73,19 +72,33 @@ JNIEXPORT void JNICALL Java_vue_NativeVUE_construct
|
|||
JNIEXPORT void JNICALL Java_vue_NativeVUE_dispose
|
||||
(JNIEnv *env, jobject vue) {
|
||||
CORE *core = GetCore(env, vue);
|
||||
free(core->vue.rom);
|
||||
if (core->vue.sram != NULL)
|
||||
free(core->vue.sram);
|
||||
if (core->vue.bus.rom != NULL)
|
||||
free(core->vue.bus.rom);
|
||||
if (core->vue.bus.sram != NULL)
|
||||
free(core->vue.bus.sram);
|
||||
free(core);
|
||||
}
|
||||
|
||||
// Retrieve a register value
|
||||
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);
|
||||
}
|
||||
|
||||
// Retrieve a copy of the ROM data
|
||||
JNIEXPORT jbyteArray JNICALL Java_vue_NativeVUE_getROM
|
||||
(JNIEnv *env, jobject vue) {
|
||||
CORE *core = GetCore(env, vue);
|
||||
jbyteArray ret = (*env)->NewByteArray(env, (jint) core->vue.rom_size);
|
||||
|
||||
// No ROM data
|
||||
if (core->vue.bus.rom == NULL)
|
||||
return NULL;
|
||||
|
||||
// Copy the ROM data
|
||||
jbyteArray ret = (*env)->NewByteArray(env, (jint)core->vue.bus.rom_size);
|
||||
jbyte *elems = (*env)->GetByteArrayElements(env, ret, NULL);
|
||||
memcpy(elems, core->vue.rom, core->vue.rom_size);
|
||||
memcpy(elems, core->vue.bus.rom, core->vue.bus.rom_size);
|
||||
(*env)->ReleaseByteArrayElements(env, ret, elems, 0);
|
||||
return ret;
|
||||
}
|
||||
|
@ -117,6 +130,13 @@ JNIEXPORT jboolean JNICALL Java_vue_NativeVUE_read
|
|||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
// Specify a register value
|
||||
JNIEXPORT jint JNICALL Java_vue_NativeVUE_setRegister
|
||||
(JNIEnv *env, jobject vue, jint index, jboolean system, jint value) {
|
||||
CORE *core = GetCore(env, vue);
|
||||
return vueSetRegister(&core->vue, index, system, value);
|
||||
}
|
||||
|
||||
// Provide new ROM data
|
||||
JNIEXPORT jboolean JNICALL Java_vue_NativeVUE_setROM
|
||||
(JNIEnv *env, jobject vue, jbyteArray data, jint offset, jint length) {
|
||||
|
@ -138,7 +158,8 @@ JNIEXPORT jboolean JNICALL Java_vue_NativeVUE_setROM
|
|||
|
||||
// Transfer the ROM data to the emulation state
|
||||
CORE *core = GetCore(env, vue);
|
||||
free(core->vue.rom);
|
||||
if (core->vue.bus.rom != NULL)
|
||||
free(core->vue.bus.rom);
|
||||
vueSetROM(&core->vue, rom, length);
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
|
|
@ -6,9 +6,14 @@ import java.util.*;
|
|||
// Simulation of the CPU bus
|
||||
class Bus {
|
||||
|
||||
// Instance fields
|
||||
// Private fields
|
||||
private JavaVUE vue; // Emulation state
|
||||
|
||||
// Package fields
|
||||
byte[] rom; // Cartridge ROM
|
||||
byte[] sram; // Cartridge SRAM
|
||||
byte[] wram; // System WRAM
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
@ -18,6 +23,7 @@ class Bus {
|
|||
// Default constructor
|
||||
Bus(JavaVUE vue) {
|
||||
this.vue = vue;
|
||||
wram = new byte[0x10000];
|
||||
}
|
||||
|
||||
// Read bytes from host memory
|
||||
|
@ -40,23 +46,24 @@ class Bus {
|
|||
}
|
||||
|
||||
// Read a value directly from host memory
|
||||
int readMemory(byte[] data, int offset, int type) {
|
||||
int readMemory(byte[] data, int address, int type) {
|
||||
|
||||
// There is no source data
|
||||
if (data == null)
|
||||
return 0;
|
||||
|
||||
// Processing by type
|
||||
address &= data.length - 1;
|
||||
switch (type) {
|
||||
case VUE.S8 : return data[offset];
|
||||
case VUE.U8 : return data[offset] & 0xFF;
|
||||
case VUE.S8 : return data[address];
|
||||
case VUE.U8 : return data[address] & 0xFF;
|
||||
case VUE.S16: return
|
||||
data[offset+1] << 8 | data[offset ] & 0xFF;
|
||||
data[address+1] << 8 | data[address ] & 0xFF;
|
||||
case VUE.U16: return
|
||||
(data[offset+1] & 0xFF) << 8 | data[offset ] & 0xFF;
|
||||
(data[address+1] & 0xFF)<< 8 | data[address ] & 0xFF;
|
||||
case VUE.S32: return
|
||||
data[offset+3] << 24 | (data[offset+2] & 0xFF) << 16 |
|
||||
(data[offset+1] & 0xFF) << 8 | (data[offset ] & 0xFF);
|
||||
data[address+3] <<24 | (data[address+2] & 0xFF)<<16 |
|
||||
(data[address+1] & 0xFF)<< 8 | (data[address ] & 0xFF);
|
||||
}
|
||||
|
||||
return 0; // Unreachable
|
||||
|
@ -71,11 +78,11 @@ class Bus {
|
|||
case 4: // Cartridge expansion (not supported)
|
||||
return 0;
|
||||
case 5: return
|
||||
readMemory(vue.wram, address & 0xFFFF , type);
|
||||
readMemory(wram, address & 0xFFFF , type);
|
||||
case 6: return
|
||||
readMemory(vue.sram, address & vue.sram.length - 1, type);
|
||||
readMemory(sram, address & sram.length - 1, type);
|
||||
case 7: return
|
||||
readMemory(vue.rom , address & vue.rom .length - 1, type);
|
||||
readMemory(rom , address & rom .length - 1, type);
|
||||
}
|
||||
return 0; // Unreachable
|
||||
}
|
||||
|
@ -98,25 +105,26 @@ class Bus {
|
|||
}
|
||||
|
||||
// Write a value directly to host memory
|
||||
void writeMemory(byte[] data, int offset, int type, int value) {
|
||||
void writeMemory(byte[] data, int address, int type, int value) {
|
||||
|
||||
// There is no source data
|
||||
if (data == null)
|
||||
return;
|
||||
|
||||
// Processing by type
|
||||
address &= data.length - 1;
|
||||
switch (type) {
|
||||
case VUE.S32:
|
||||
data[offset + 3] = (byte) (value >> 24);
|
||||
data[offset + 2] = (byte) (value >> 16);
|
||||
data[address + 3] = (byte) (value >> 24);
|
||||
data[address + 2] = (byte) (value >> 16);
|
||||
// Fallthrough
|
||||
case VUE.S16: // Fallthrough
|
||||
case VUE.U16:
|
||||
data[offset + 1] = (byte) (value >> 8);
|
||||
data[address + 1] = (byte) (value >> 8);
|
||||
// Fallthrough
|
||||
case VUE.S8 : // Fallthrough
|
||||
case VUE.U8 :
|
||||
data[offset ] = (byte) value ;
|
||||
data[address ] = (byte) value ;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -125,18 +133,9 @@ class Bus {
|
|||
void writeValue(int address, int type, int value) {
|
||||
address &= ~JavaVUE.TYPE_SIZES[type] + 1;
|
||||
switch (address >> 24 & 7) {
|
||||
case 5:
|
||||
writeMemory(vue.wram,
|
||||
address & 0xFFFF , type, value);
|
||||
break;
|
||||
case 6:
|
||||
writeMemory(vue.sram,
|
||||
address & vue.sram.length - 1, type, value);
|
||||
break;
|
||||
case 7:
|
||||
writeMemory(vue.rom ,
|
||||
address & vue.rom .length - 1, type, value);
|
||||
break;
|
||||
case 5: writeMemory(wram, address, type, value); break;
|
||||
case 6: writeMemory(sram, address, type, value); break;
|
||||
case 7: writeMemory(rom , address, type, value); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,208 @@
|
|||
package vue;
|
||||
|
||||
// CPU state
|
||||
class CPU {
|
||||
|
||||
// Private fields
|
||||
private JavaVUE vue; // Emulation state
|
||||
|
||||
// Package fields
|
||||
int cycles; // Cycles until next stage
|
||||
int fetch; // Fetch unit index
|
||||
int stage; // Current processing stage
|
||||
|
||||
// Program registers
|
||||
int[] program;
|
||||
|
||||
// System registers
|
||||
int adtre; // Address Trap Register for Execution
|
||||
int eipc; // Exception/interrupt PC
|
||||
int eipsw; // Exception/interrupt PSW
|
||||
int fepc; // Duplexed exception PC
|
||||
int fepsw; // Duplexed exception PSW
|
||||
int pc; // Program Counter
|
||||
int sr29; // System register 29
|
||||
int sr31; // System register 31
|
||||
|
||||
// Program Status Word
|
||||
int psw_ae; // Address Trap Enable
|
||||
int psw_ep; // Exception Pending
|
||||
int psw_id; // Interrupt Disable
|
||||
int psw_cy; // Carry
|
||||
int psw_fiv; // Floating Reserved Operand
|
||||
int psw_fov; // Floating Overflow
|
||||
int psw_fpr; // Floating Precision
|
||||
int psw_fro; // Floating Reserved Operand
|
||||
int psw_fud; // Floating Underflow
|
||||
int psw_fzd; // Floating Zero Divide
|
||||
int psw_i; // Interrupt Level
|
||||
int psw_np; // NMI Pending
|
||||
int psw_ov; // Overflow
|
||||
int psw_s; // Sign
|
||||
int psw_z; // Zero
|
||||
|
||||
// Cache Control Word
|
||||
int chcw_cec; // Clear Entry Count
|
||||
int chcw_cen; // Clear Entry Number
|
||||
int chcw_icc; // Instruction Cache Clear
|
||||
int chcw_icd; // Instruction Cache Dump
|
||||
int chcw_ice; // Instruction Cache Enable
|
||||
int chcw_icr; // Instruction Cache Restore
|
||||
int chcw_sa; // Spill-Out Base Address
|
||||
|
||||
// Exception Cause Register
|
||||
int ecr_eicc; // Exception/Interrupt Cause Code
|
||||
int ecr_fecc; // Fatal Error Cause Code
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Constants //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Stages
|
||||
static final int FETCH = 0;
|
||||
static final int EXECUTE = 1;
|
||||
static final int HALT = 2;
|
||||
static final int EXCEPTION = 3;
|
||||
static final int FATAL = 4;
|
||||
static final int CLEAR = 5;
|
||||
static final int DUMP = 6;
|
||||
static final int RESTORE = 7;
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Constructors //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Default constructor
|
||||
CPU(JavaVUE vue) {
|
||||
program = new int[32];
|
||||
this.vue = vue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Package Methods //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Read a system register
|
||||
int getSystemRegister(int index) {
|
||||
switch (index) {
|
||||
case VUE.ADTRE: return adtre;
|
||||
case VUE.EIPC : return eipc;
|
||||
case VUE.EIPSW: return eipsw;
|
||||
case VUE.FEPC : return fepc;
|
||||
case VUE.FEPSW: return fepsw;
|
||||
case VUE.ECR : return ecr_fecc << 16 | ecr_eicc;
|
||||
case VUE.PIR : return 0x00005346;
|
||||
case VUE.TKCW : return 0x000000E0;
|
||||
case VUE.CHCW : return chcw_ice << 1;
|
||||
case 29 : return sr29;
|
||||
case 30 : return 0x00000004;
|
||||
case 31 : return sr31;
|
||||
case VUE.PSW : return
|
||||
psw_i << 16 | psw_fro << 9 | psw_fpr << 4 |
|
||||
psw_np << 15 | psw_fiv << 8 | psw_cy << 3 |
|
||||
psw_ep << 14 | psw_fzd << 7 | psw_ov << 2 |
|
||||
psw_ae << 13 | psw_fov << 6 | psw_s << 1 |
|
||||
psw_id << 12 | psw_fud << 5 | psw_z
|
||||
;
|
||||
|
||||
// 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 22: case 23: case 26: case 27: case 28:
|
||||
return 0;
|
||||
}
|
||||
return 1; // Unreachable
|
||||
}
|
||||
|
||||
// System reset
|
||||
void reset() {
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Write a system register
|
||||
int setSystemRegister(int index, int value, boolean debug) {
|
||||
switch (index) {
|
||||
case VUE.ADTRE: return adtre = value & 0xFFFFFFFE;
|
||||
case VUE.EIPC : return eipc = value & 0xFFFFFFFE;
|
||||
case VUE.EIPSW: return eipsw = value & 0x000FF3FF;
|
||||
case VUE.FEPC : return fepc = value & 0xFFFFFFFE;
|
||||
case VUE.FEPSW: return fepsw = value & 0x000FF3FF;
|
||||
case 29 : return sr29 = value;
|
||||
case 31 : return sr31 = debug || value >= 0 ? value : -value;
|
||||
|
||||
case VUE.CHCW :
|
||||
chcw_cen = value >> 20 & 0x00000FFF;
|
||||
chcw_cec = value >> 8 & 0x00000FFF;
|
||||
chcw_sa = value >> 8 & 0x00FFFFFF;
|
||||
chcw_icr = value >> 5 & 1;
|
||||
chcw_icd = value >> 4 & 1;
|
||||
chcw_ice = value >> 1 & 1;
|
||||
chcw_icc = value & 1;
|
||||
|
||||
// Only one of ICC, ICD or ICR is set
|
||||
value &= 0x00000031;
|
||||
if ((value & value - 1) == 0) {
|
||||
// Clear
|
||||
// Dump
|
||||
// Restore
|
||||
}
|
||||
|
||||
return chcw_ice << 1;
|
||||
|
||||
case VUE.PSW :
|
||||
psw_i = value >> 16 & 15; psw_fov = value >> 6 & 1;
|
||||
psw_np = value >> 15 & 1; psw_fud = value >> 5 & 1;
|
||||
psw_ep = value >> 14 & 1; psw_fpr = value >> 4 & 1;
|
||||
psw_ae = value >> 13 & 1; psw_cy = value >> 3 & 1;
|
||||
psw_id = value >> 12 & 1; psw_ov = value >> 2 & 1;
|
||||
psw_fro = value >> 9 & 1; psw_s = value >> 1 & 1;
|
||||
psw_fiv = value >> 8 & 1; psw_z = value & 1;
|
||||
psw_fzd = value >> 7 & 1;
|
||||
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:
|
||||
return 0;
|
||||
}
|
||||
return 1; // Unreachable
|
||||
}
|
||||
|
||||
// Test a condition
|
||||
int test(int condition) {
|
||||
switch (condition) {
|
||||
case 0: return psw_ov;
|
||||
case 1: return psw_cy;
|
||||
case 2: return psw_z;
|
||||
case 3: return psw_cy | psw_z;
|
||||
case 4: return psw_s;
|
||||
case 5: return 1;
|
||||
case 6: return psw_ov | psw_s;
|
||||
case 7: return psw_ov ^ psw_s | psw_z;
|
||||
}
|
||||
return test(condition & 7) ^ 1;
|
||||
}
|
||||
|
||||
}
|
|
@ -3,13 +3,9 @@ package vue;
|
|||
// Java emulation core implementation
|
||||
class JavaVUE extends VUE {
|
||||
|
||||
// Instance fields
|
||||
byte[] rom; // Cartridge ROM
|
||||
byte[] sram; // Cartridge SRAM
|
||||
byte[] wram; // System WRAM
|
||||
|
||||
// Components
|
||||
Bus bus; // Memory bus
|
||||
CPU cpu; // Processor
|
||||
|
||||
|
||||
|
||||
|
@ -28,8 +24,8 @@ class JavaVUE extends VUE {
|
|||
|
||||
// Default constructor
|
||||
JavaVUE() {
|
||||
bus = new Bus(this);
|
||||
wram = new byte[0x10000];
|
||||
bus = new Bus(this);
|
||||
cpu = new CPU(this);
|
||||
}
|
||||
|
||||
|
||||
|
@ -41,10 +37,26 @@ class JavaVUE extends VUE {
|
|||
// Release any used resources
|
||||
public void dispose() { }; // No action needed
|
||||
|
||||
// Retrieve a register value
|
||||
public int getRegister(int index, boolean system) {
|
||||
return
|
||||
index == VUE.PC && system ? cpu.pc :
|
||||
index < 0 || index > 31 ? 0 :
|
||||
system ? cpu.getSystemRegister(index) :
|
||||
cpu.program[index]
|
||||
;
|
||||
}
|
||||
|
||||
// Retrieve a copy of the ROM data
|
||||
public byte[] getROM() {
|
||||
var ret = new byte[rom.length];
|
||||
System.arraycopy(rom, 0, ret, 0, ret.length);
|
||||
|
||||
// No ROM data
|
||||
if (bus.rom == null)
|
||||
return null;
|
||||
|
||||
// Copy the ROM data
|
||||
var ret = new byte[bus.rom.length];
|
||||
System.arraycopy(bus.rom, 0, ret, 0, ret.length);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -79,16 +91,16 @@ class JavaVUE extends VUE {
|
|||
break;
|
||||
case 3: // Fallthrough, unmapped
|
||||
case 4: // Cartridge expansion (not supported)
|
||||
bus.readBytes(null, dest, address, 0 , count);
|
||||
bus.readBytes(null , dest, address, 0 , count);
|
||||
break;
|
||||
case 5: /* System WRAM */
|
||||
bus.readBytes(wram, dest, address, offset, count);
|
||||
bus.readBytes(bus.wram, dest, address, offset, count);
|
||||
break;
|
||||
case 6: /* Cartridge RAM */
|
||||
bus.readBytes(sram, dest, address, offset, count);
|
||||
bus.readBytes(bus.sram, dest, address, offset, count);
|
||||
break;
|
||||
case 7: /* Cartridge ROM */
|
||||
bus.readBytes(rom , dest, address, offset, count);
|
||||
bus.readBytes(bus.rom , dest, address, offset, count);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -96,6 +108,16 @@ class JavaVUE extends VUE {
|
|||
return true;
|
||||
}
|
||||
|
||||
// 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]
|
||||
;
|
||||
}
|
||||
|
||||
// Provide new ROM data
|
||||
public boolean setROM(byte[] data, int offset, int length) {
|
||||
|
||||
|
@ -109,8 +131,8 @@ class JavaVUE extends VUE {
|
|||
) return false;
|
||||
|
||||
// Accept the new ROM data
|
||||
rom = new byte[length];
|
||||
System.arraycopy(data, offset, rom, 0, length);
|
||||
bus.rom = new byte[length];
|
||||
System.arraycopy(data, offset, bus.rom, 0, length);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -135,13 +157,13 @@ class JavaVUE extends VUE {
|
|||
// Process by component
|
||||
switch (address >> 24 & 7) {
|
||||
case 5: /* System WRAM */
|
||||
bus.writeBytes(wram, src, address, offset, count);
|
||||
bus.writeBytes(bus.wram, src, address, offset, count);
|
||||
break;
|
||||
case 6: /* Cartridge RAM */
|
||||
bus.writeBytes(sram, src, address, offset, count);
|
||||
bus.writeBytes(bus.sram, src, address, offset, count);
|
||||
break;
|
||||
case 7: /* Cartridge ROM */
|
||||
bus.writeBytes(rom , src, address, offset, count);
|
||||
bus.writeBytes(bus.rom , src, address, offset, count);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,9 @@ class NativeVUE extends VUE {
|
|||
// Release any used resources
|
||||
public native void dispose();
|
||||
|
||||
// Retrieve a register value
|
||||
public native int getRegister(int index, boolean system);
|
||||
|
||||
// Retrieve a copy of the ROM data
|
||||
public native byte[] getROM();
|
||||
|
||||
|
@ -36,6 +39,9 @@ class NativeVUE extends VUE {
|
|||
public native boolean read(int address, byte[] dest, int offset,
|
||||
int length);
|
||||
|
||||
// Specify a register value
|
||||
public native int setRegister(int index, boolean system, int value);
|
||||
|
||||
// Provide new ROM data
|
||||
public native boolean setROM(byte[] data, int offset, int length);
|
||||
|
||||
|
|
|
@ -19,6 +19,19 @@ public abstract class VUE {
|
|||
public static final int U16 = 3;
|
||||
public static final int S32 = 4;
|
||||
|
||||
// System register indexes
|
||||
public static final int ADTRE = 25;
|
||||
public static final int CHCW = 24;
|
||||
public static final int ECR = 4;
|
||||
public static final int EIPC = 0;
|
||||
public static final int EIPSW = 1;
|
||||
public static final int FEPC = 2;
|
||||
public static final int FEPSW = 3;
|
||||
public static final int PC = -1;
|
||||
public static final int PIR = 6;
|
||||
public static final int PSW = 5;
|
||||
public static final int TKCW = 7;
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
@ -55,6 +68,9 @@ public abstract class VUE {
|
|||
// Release any used resources
|
||||
public abstract void dispose();
|
||||
|
||||
// Retrieve a register value
|
||||
public abstract int getRegister(int index, boolean system);
|
||||
|
||||
// Retrieve a copy of the ROM data
|
||||
public abstract byte[] getROM();
|
||||
|
||||
|
@ -65,6 +81,9 @@ public abstract class VUE {
|
|||
public abstract boolean read(int address, byte[] dest, int offset,
|
||||
int length);
|
||||
|
||||
// Specify a register value
|
||||
public abstract int setRegister(int index, boolean system, int value);
|
||||
|
||||
// Provide new ROM data
|
||||
public abstract boolean setROM(byte[] data, int offset, int length);
|
||||
|
||||
|
|
Loading…
Reference in New Issue