pvbemu/src/core/cpu.c

167 lines
6.0 KiB
C

/* 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_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;
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 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 */
}
/* Perform a 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;
/* 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.jumpFrom = 0xFFFFFFF0;
vue->cpu.jumpTo = 0xFFFFFFF0;
vue->cpu.pc = 0xFFFFFFF0;
vue->cpu.psw_np = 1;
}
/* 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