Laying the groundwork for the CPU
This commit is contained in:
+11
-12
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+156
@@ -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
|
||||
+79
-9
@@ -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);
|
||||
|
||||
|
||||
|
||||
|
||||
+37
-16
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user