Additional work on emulation/CPU logic, implementing in C code
This commit is contained in:
parent
d1b8e293c3
commit
e31a5080c4
2
makefile
2
makefile
|
@ -164,5 +164,5 @@ win64: win64_pre native_common
|
||||||
native_common:
|
native_common:
|
||||||
@echo " Building native module $(name)"
|
@echo " Building native module $(name)"
|
||||||
@$(prefix)gcc $(include) -Isrc/core/include $(gccargs) -s -shared -O2 \
|
@$(prefix)gcc $(include) -Isrc/core/include $(gccargs) -s -shared -O2 \
|
||||||
-fno-strict-aliasing -Werror \
|
-fno-strict-aliasing -fPIC -Werror \
|
||||||
-o native/$(name)$(ext) src/desktop/vue/NativeVUE.c src/core/vue.c
|
-o native/$(name)$(ext) src/desktop/vue/NativeVUE.c src/core/vue.c
|
||||||
|
|
372
src/core/cpu.c
372
src/core/cpu.c
|
@ -8,14 +8,14 @@
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
/* Stages */
|
/* Stages */
|
||||||
#define CPU_FETCH 0
|
#define CPU_FATAL -1
|
||||||
#define CPU_EXECUTE 1
|
#define CPU_FETCH 0
|
||||||
#define CPU_HALT 2
|
#define CPU_EXECUTE 1
|
||||||
#define CPU_EXCEPTION 3
|
#define CPU_EXCEPTION 2
|
||||||
#define CPU_FATAL 4
|
#define CPU_HALT 3
|
||||||
#define CPU_CLEAR 5
|
#define CPU_CLEAR 4
|
||||||
#define CPU_DUMP 6
|
#define CPU_DUMP 5
|
||||||
#define CPU_RESTORE 7
|
#define CPU_RESTORE 6
|
||||||
|
|
||||||
/* Intermediate instruction IDs */
|
/* Intermediate instruction IDs */
|
||||||
#define BITSTRING -2
|
#define BITSTRING -2
|
||||||
|
@ -57,20 +57,51 @@ static const int8_t LOOKUP_FLOATENDO[] = {
|
||||||
VUE_MPYHW , VUE_ILLEGAL, VUE_ILLEGAL, VUE_ILLEGAL
|
VUE_MPYHW , VUE_ILLEGAL, VUE_ILLEGAL, VUE_ILLEGAL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Instruction cycle counts */
|
||||||
|
static const int8_t CYCLES[] = {
|
||||||
|
1, 1, 28, 1, 1, 1, 1, 1, 1, 26, 12, 1, 1, 10, 14, 16,
|
||||||
|
38, 44, 36, 1, 5, 5, 5, 3, 3, 3, 5, 5, 5, 8, 1, 1,
|
||||||
|
1, 1, 1, 9, 13, 30, 13, 1, 1, 1, 1, 1, 1, 4, 4, 4,
|
||||||
|
10, 22, 1, 1, 1, 1, 1, 1, 12, 1, 1, 1, 1, 1, 4, 4,
|
||||||
|
4, 8, 1, 28, 15, 14, 6, 1, 1, 1, 1, 1
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Module Functions *
|
* Instruction Functions *
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
/* JMP */
|
||||||
|
static void cpuJMP(VUE *vue) {
|
||||||
|
vue->cpu.pc = vue->cpu.program[vue->cpu.inst.reg1] - 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MOVEA */
|
||||||
|
static void cpuMOVEA(VUE *vue) {
|
||||||
|
vue->cpu.program[vue->cpu.inst.reg2] =
|
||||||
|
vue->cpu.program[vue->cpu.inst.reg1] + vue->cpu.inst.imm;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MOVHI */
|
||||||
|
static void cpuMOVHI(VUE *vue) {
|
||||||
|
vue->cpu.program[vue->cpu.inst.reg2] =
|
||||||
|
vue->cpu.program[vue->cpu.inst.reg1] + (vue->cpu.inst.imm << 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Stage Functions *
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
/* Decode an instruction from its binary encoding */
|
/* Decode an instruction from its binary encoding */
|
||||||
static void cpuDecode(VUE_INST *inst, int32_t bits) {
|
static void cpuDecode(VUE_INSTRUCTION *inst) {
|
||||||
int8_t extend; /* Sign-extend the immediate operand */
|
int8_t extend; /* Sign-extend the immediate operand */
|
||||||
int32_t x; /* Working variable */
|
int32_t x; /* Working variable */
|
||||||
|
|
||||||
/* Configure instance fields */
|
/* Configure instance fields */
|
||||||
inst->bits = bits;
|
inst->opcode = inst->bits >> 26 & 63;
|
||||||
inst->opcode = bits >> 26 & 63;
|
|
||||||
x = inst->opcode << 1;
|
x = inst->opcode << 1;
|
||||||
inst->id = LOOKUP_OPCODE[x ];
|
inst->id = LOOKUP_OPCODE[x ];
|
||||||
extend = LOOKUP_OPCODE[x + 1];
|
extend = LOOKUP_OPCODE[x + 1];
|
||||||
|
@ -80,42 +111,42 @@ static void cpuDecode(VUE_INST *inst, int32_t bits) {
|
||||||
/* Decode by format */
|
/* Decode by format */
|
||||||
switch (inst->format) {
|
switch (inst->format) {
|
||||||
case 1:
|
case 1:
|
||||||
inst->reg2 = bits >> 21 & 31;
|
inst->reg2 = inst->bits >> 21 & 31;
|
||||||
inst->reg1 = bits >> 16 & 31;
|
inst->reg1 = inst->bits >> 16 & 31;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
x = bits >> 16 & 31;
|
x = inst->bits >> 16 & 31;
|
||||||
inst->reg2 = bits >> 21 & 31;
|
inst->reg2 = inst->bits >> 21 & 31;
|
||||||
inst->imm = extend < 0 ? SIGN_EXTEND(5, x) : x;
|
inst->imm = extend < 0 ? SIGN_EXTEND(5, x) : x;
|
||||||
if (inst->id == BITSTRING)
|
if (inst->id == BITSTRING)
|
||||||
inst->id = x >= 16 ? VUE_ILLEGAL : LOOKUP_BITSTRING[x];
|
inst->id = x >= 16 ? VUE_ILLEGAL : LOOKUP_BITSTRING[x];
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
x = bits >> 16 & 0x1FF;
|
x = inst->bits >> 16 & 0x1FF;
|
||||||
inst->opcode = 0x20;
|
inst->opcode = 0x20;
|
||||||
inst->cond = bits >> 25 & 15;
|
inst->cond = inst->bits >> 25 & 15;
|
||||||
inst->disp = SIGN_EXTEND(9, x);
|
inst->disp = SIGN_EXTEND(9, x);
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
x = bits & 0x3FFFFFF;
|
x = inst->bits & 0x3FFFFFF;
|
||||||
inst->disp = SIGN_EXTEND(26, x);
|
inst->disp = SIGN_EXTEND(26, x);
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
x = bits & 0xFFFF;
|
x = inst->bits & 0xFFFF;
|
||||||
inst->reg2 = bits >> 21 & 31;
|
inst->reg2 = inst->bits >> 21 & 31;
|
||||||
inst->reg1 = bits >> 16 & 31;
|
inst->reg1 = inst->bits >> 16 & 31;
|
||||||
inst->imm = extend < 0 ? SIGN_EXTEND(16, x) : x;
|
inst->imm = extend < 0 ? SIGN_EXTEND(16, x) : x;
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
x = bits & 0xFFFF;
|
x = inst->bits & 0xFFFF;
|
||||||
inst->reg2 = bits >> 21 & 31;
|
inst->reg2 = inst->bits >> 21 & 31;
|
||||||
inst->reg1 = bits >> 16 & 31;
|
inst->reg1 = inst->bits >> 16 & 31;
|
||||||
inst->disp = SIGN_EXTEND(16, x);
|
inst->disp = SIGN_EXTEND(16, x);
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
inst->reg2 = bits >> 21 & 31;
|
inst->reg2 = inst->bits >> 21 & 31;
|
||||||
inst->reg1 = bits >> 16 & 31;
|
inst->reg1 = inst->bits >> 16 & 31;
|
||||||
inst->subopcode = bits >> 10 & 63;
|
inst->subopcode = inst->bits >> 10 & 63;
|
||||||
inst->id = inst->subopcode >= 16 ? VUE_ILLEGAL :
|
inst->id = inst->subopcode >= 16 ? VUE_ILLEGAL :
|
||||||
LOOKUP_FLOATENDO[inst->subopcode];
|
LOOKUP_FLOATENDO[inst->subopcode];
|
||||||
break;
|
break;
|
||||||
|
@ -123,6 +154,178 @@ static void cpuDecode(VUE_INST *inst, int32_t bits) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check for an exception or interrupt */
|
||||||
|
static vbool cpuTestException(VUE *vue) {
|
||||||
|
int32_t level; /* Interrupt level */
|
||||||
|
|
||||||
|
/* Check for an interrupt */
|
||||||
|
if (vue->cpu.irq != 0 && (vue->cpu.exception.code |
|
||||||
|
vue->cpu.psw_id | vue->cpu.psw_ep | vue->cpu.psw_np) == 0) {
|
||||||
|
for (level = 4; level >= 0; level--)
|
||||||
|
if ((vue->cpu.irq >> level & 1) != 0)
|
||||||
|
break;
|
||||||
|
vue->cpu.exception.code = 0xFE00 | level << 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* There is no exception */
|
||||||
|
if (vue->cpu.exception.code == 0) /* No further processing */
|
||||||
|
return vue->cpu.stage == CPU_HALT && vue->cpu.cycles == 0;
|
||||||
|
|
||||||
|
/* An exception has occurred */
|
||||||
|
vue->cpu.cycles = 0;
|
||||||
|
vue->cpu.stage = CPU_EXCEPTION;
|
||||||
|
return VUE_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Operations for execute stage */
|
||||||
|
static vbool cpuExecute(VUE *vue) {
|
||||||
|
|
||||||
|
/* Application callback */
|
||||||
|
if (vue->onExecute != NULL) {
|
||||||
|
vue->breakCode = vue->onExecute(vue, &vue->cpu.inst);
|
||||||
|
if (vue->breakCode != 0)
|
||||||
|
return VUE_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Determine the default number of cycles for the instruction */
|
||||||
|
if (vue->cpu.inst.id >= 0 && vue->cpu.inst.id <= 75)
|
||||||
|
vue->cpu.cycles = CYCLES[vue->cpu.inst.id];
|
||||||
|
|
||||||
|
/* Processing by instruction ID */
|
||||||
|
switch (vue->cpu.inst.id) {
|
||||||
|
/*case VUE_ADD_IMM: cpuADD_IMM(vue); break;*/
|
||||||
|
/*case VUE_ADD_REG: cpuADD_REG(vue); break;*/
|
||||||
|
/*case VUE_ADDF_S : cpuADDF_S (vue); break;*/
|
||||||
|
/*case VUE_ADDI : cpuADDI (vue); break;*/
|
||||||
|
/*case VUE_AND : cpuAND (vue); break;*/
|
||||||
|
/*case VUE_ANDBSU : cpuANDBSU (vue); break;*/
|
||||||
|
/*case VUE_ANDI : cpuANDI (vue); break;*/
|
||||||
|
/*case VUE_ANDNBSU: cpuANDNBSU(vue); break;*/
|
||||||
|
/*case VUE_BCOND : cpuBCOND (vue); break;*/
|
||||||
|
/*case VUE_CAXI : cpuCAXI (vue); break;*/
|
||||||
|
/*case VUE_CLI : cpuCLI (vue); break;*/
|
||||||
|
/*case VUE_CMP_IMM: cpuCMP_IMM(vue); break;*/
|
||||||
|
/*case VUE_CMP_REG: cpuCMP_REG(vue); break;*/
|
||||||
|
/*case VUE_CMPF_S : cpuCMPF_S (vue); break;*/
|
||||||
|
/*case VUE_CVT_SW : cpuCVT_SW (vue); break;*/
|
||||||
|
/*case VUE_CVT_WS : cpuCVT_WS (vue); break;*/
|
||||||
|
/*case VUE_DIV : cpuDIV (vue); break;*/
|
||||||
|
/*case VUE_DIVF_S : cpuDIVF_S (vue); break;*/
|
||||||
|
/*case VUE_DIVU : cpuDIVU (vue); break;*/
|
||||||
|
/*case VUE_HALT : cpuHALT (vue); break;*/
|
||||||
|
/*case VUE_IN_B : cpuIN_B (vue); break;*/
|
||||||
|
/*case VUE_IN_H : cpuIN_H (vue); break;*/
|
||||||
|
/*case VUE_IN_W : cpuIN_W (vue); break;*/
|
||||||
|
/*case VUE_JAL : cpuJAL (vue); break;*/
|
||||||
|
case VUE_JMP : cpuJMP (vue); break;
|
||||||
|
/*case VUE.JR : cpuJR (vue); break;*/
|
||||||
|
/*case VUE.LD_B : cpuLD_B (vue); break;*/
|
||||||
|
/*case VUE.LD_H : cpuLD_H (vue); break;*/
|
||||||
|
/*case VUE.LD_W : cpuLD_W (vue); break;*/
|
||||||
|
/*case VUE.LDSR : cpuLDSR (vue); break;*/
|
||||||
|
/*case VUE.MOV_IMM: cpuMOV_IMM(vue); break;*/
|
||||||
|
/*case VUE.MOV_REG: cpuMOV_REG(vue); break;*/
|
||||||
|
/*case VUE.MOVBSU : cpuMOVBSU (vue); break;*/
|
||||||
|
case VUE_MOVEA : cpuMOVEA (vue); break;
|
||||||
|
case VUE_MOVHI : cpuMOVHI (vue); break;
|
||||||
|
/*case VUE.MPYHW : cpuMPYHW (vue); break;*/
|
||||||
|
/*case VUE.MUL : cpuMUL (vue); break;*/
|
||||||
|
/*case VUE.MULF_S : cpuMULF_S (vue); break;*/
|
||||||
|
/*case VUE.MULU : cpuMULU (vue); break;*/
|
||||||
|
/*case VUE.NOT : cpuNOT (vue); break;*/
|
||||||
|
/*case VUE.NOTBSU : cpuNOTBSU (vue); break;*/
|
||||||
|
/*case VUE.OR : cpuOR (vue); break;*/
|
||||||
|
/*case VUE.ORBSU : cpuORBSU (vue); break;*/
|
||||||
|
/*case VUE.ORI : cpuORI (vue); break;*/
|
||||||
|
/*case VUE.ORNBSU : cpuORNBSU (vue); break;*/
|
||||||
|
/*case VUE.OUT_B : cpuOUT_B (vue); break;*/
|
||||||
|
/*case VUE.OUT_H : cpuOUT_H (vue); break;*/
|
||||||
|
/*case VUE.OUT_W : cpuOUT_W (vue); break;*/
|
||||||
|
/*case VUE.RETI : cpuRETI (vue); break;*/
|
||||||
|
/*case VUE.REV : cpuREV (vue); break;*/
|
||||||
|
/*case VUE.SAR_IMM: cpuSAR_IMM(vue); break;*/
|
||||||
|
/*case VUE.SAR_REG: cpuSAR_REG(vue); break;*/
|
||||||
|
/*case VUE.SCH0BSD: cpuSCH0BSD(vue); break;*/
|
||||||
|
/*case VUE.SCH0BSU: cpuSCH0BSU(vue); break;*/
|
||||||
|
/*case VUE.SCH1BSD: cpuSCH1BSD(vue); break;*/
|
||||||
|
/*case VUE.SCH1BSU: cpuSCH1BSU(vue); break;*/
|
||||||
|
/*case VUE.SEI : cpuSEI (vue); break;*/
|
||||||
|
/*case VUE.SETF : cpuSETF (vue); break;*/
|
||||||
|
/*case VUE.SHL_IMM: cpuSHL_IMM(vue); break;*/
|
||||||
|
/*case VUE.SHL_REG: cpuSHL_REG(vue); break;*/
|
||||||
|
/*case VUE.SHR_IMM: cpuSHR_IMM(vue); break;*/
|
||||||
|
/*case VUE.SHR_REG: cpuSHR_REG(vue); break;*/
|
||||||
|
/*case VUE.ST_B : cpuST_B (vue); break;*/
|
||||||
|
/*case VUE.ST_H : cpuST_H (vue); break;*/
|
||||||
|
/*case VUE.ST_W : cpuST_W (vue); break;*/
|
||||||
|
/*case VUE.STSR : cpuSTSR (vue); break;*/
|
||||||
|
/*case VUE.SUB : cpuSUB (vue); break;*/
|
||||||
|
/*case VUE.SUBF_S : cpuSUBF_S (vue); break;*/
|
||||||
|
/*case VUE.TRAP : cpuTRAP (vue); break;*/
|
||||||
|
/*case VUE.TRNC_SW: cpuTRNC_SW(vue); break;*/
|
||||||
|
/*case VUE.XB : cpuXB (vue); break;*/
|
||||||
|
/*case VUE.XH : cpuXH (vue); break;*/
|
||||||
|
/*case VUE.XOR : cpuXOR (vue); break;*/
|
||||||
|
/*case VUE.XORBSU : cpuXORBSU (vue); break;*/
|
||||||
|
/*case VUE.XORI : cpuXORI (vue); break;*/
|
||||||
|
/*case VUE.XORNBSU: cpuXORNBSU(vue); break;*/
|
||||||
|
default: /* Invalid instruction */
|
||||||
|
vue->cpu.exception.code = 0xFF90;
|
||||||
|
vue->cpu.inst.size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Common processing */
|
||||||
|
vue->cpu.pc += vue->cpu.inst.size;
|
||||||
|
vue->cpu.program[0] = 0;
|
||||||
|
cpuTestException(vue);
|
||||||
|
if (vue->cpu.stage == CPU_EXECUTE)
|
||||||
|
vue->cpu.stage = CPU_FETCH;
|
||||||
|
return VUE_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Determine the size of an instruction given its opcode */
|
||||||
|
static int32_t cpuSize(int32_t opcode) {
|
||||||
|
int32_t ret = LOOKUP_OPCODE[opcode << 1 | 1];
|
||||||
|
return (ret < 0 ? -ret : ret) < 4 ? 2 : 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Operations for fetch stage */
|
||||||
|
static vbool cpuFetch(VUE *vue) {
|
||||||
|
|
||||||
|
/* Read the bits from the bus */
|
||||||
|
vue->cpu.access.address = vue->cpu.pc + (vue->cpu.fetch << 1);
|
||||||
|
vue->cpu.access.fetch = vue->cpu.fetch;
|
||||||
|
vue->cpu.access.type = VUE_U16;
|
||||||
|
vue->cpu.access.value = vueRead(vue, vue->cpu.access.address, VUE_U16);
|
||||||
|
|
||||||
|
/* Application callback */
|
||||||
|
if (vue->onRead != NULL) {
|
||||||
|
vue->breakCode = vue->onRead(vue, &vue->cpu.access);
|
||||||
|
if (vue->breakCode != 0)
|
||||||
|
return VUE_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* First unit */
|
||||||
|
if (vue->cpu.fetch == 0) {
|
||||||
|
vue->cpu.inst.bits = vue->cpu.access.value << 16;
|
||||||
|
if (cpuSize(vue->cpu.access.value >> 10 & 0x3F) == 4) {
|
||||||
|
vue->cpu.fetch = 1;
|
||||||
|
return VUE_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Second unit */
|
||||||
|
else {
|
||||||
|
vue->cpu.inst.bits |= vue->cpu.access.value & 0xFFFF;
|
||||||
|
vue->cpu.fetch = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decode the instruction and advance to execute stage */
|
||||||
|
cpuDecode(&vue->cpu.inst);
|
||||||
|
vue->cpu.stage = CPU_EXECUTE;
|
||||||
|
return VUE_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/* Read a system register */
|
/* Read a system register */
|
||||||
static int32_t cpuGetSystemRegister(VUE *vue, int32_t index) {
|
static int32_t cpuGetSystemRegister(VUE *vue, int32_t index) {
|
||||||
switch (index) {
|
switch (index) {
|
||||||
|
@ -158,6 +361,97 @@ static int32_t cpuGetSystemRegister(VUE *vue, int32_t index) {
|
||||||
return 1; /* Unreachable */
|
return 1; /* Unreachable */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Operations for exception stage */
|
||||||
|
static vbool cpuException(VUE *vue) {
|
||||||
|
vbool isIRQ; /* The exception is an interrupt */
|
||||||
|
int32_t psw; /* Current value of PSW */
|
||||||
|
|
||||||
|
/* Application callback */
|
||||||
|
if (vue->onException != NULL) {
|
||||||
|
vue->breakCode = vue->onException(vue, &vue->cpu.exception);
|
||||||
|
if (vue->breakCode != 0)
|
||||||
|
return VUE_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Configure working variables */
|
||||||
|
vue->cpu.exception.code &= 0xFFFF;
|
||||||
|
isIRQ = (vue->cpu.exception.code & 0xFF00) == 0xFE00;
|
||||||
|
psw = cpuGetSystemRegister(vue, VUE_PSW);
|
||||||
|
|
||||||
|
/* Fatal exception */
|
||||||
|
if (vue->cpu.psw_np != 0) {
|
||||||
|
vueWrite(vue, 0x00000000, VUE_S32, 0xFFFF0000|vue->cpu.exception.code);
|
||||||
|
vueWrite(vue, 0x00000004, VUE_S32, psw);
|
||||||
|
vueWrite(vue, 0x00000008, VUE_S32, vue->cpu.pc);
|
||||||
|
vue->cpu.stage = CPU_FATAL;
|
||||||
|
return VUE_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Duplexed exception */
|
||||||
|
if (vue->cpu.psw_ep != 0) {
|
||||||
|
vue->cpu.ecr_fecc = vue->cpu.exception.code;
|
||||||
|
vue->cpu.fepc = vue->cpu.pc;
|
||||||
|
vue->cpu.fepsw = psw;
|
||||||
|
vue->cpu.psw_np = 1;
|
||||||
|
vue->cpu.pc = 0xFFFFFFD0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Regular exception */
|
||||||
|
else {
|
||||||
|
vue->cpu.ecr_eicc = vue->cpu.exception.code;
|
||||||
|
vue->cpu.eipc = vue->cpu.pc;
|
||||||
|
vue->cpu.eipsw = psw;
|
||||||
|
vue->cpu.psw_ep = 1;
|
||||||
|
vue->cpu.pc = 0xFFFF0000 | (vue->cpu.exception.code & 0xFFF0);
|
||||||
|
if (vue->cpu.pc == (int32_t) 0xFFFFFF70) /* FIV */
|
||||||
|
vue->cpu.pc = 0xFFFFFF60;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Interrupt */
|
||||||
|
if (isIRQ) {
|
||||||
|
psw = vue->cpu.exception.code >> 4 & 15;
|
||||||
|
vue->cpu.psw_i = psw < 15 ? psw : 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Common processing */
|
||||||
|
vue->cpu.cycles = 0; /* TODO: Determine the actual number */
|
||||||
|
vue->cpu.exception.code = 0;
|
||||||
|
vue->cpu.psw_ae = 0;
|
||||||
|
vue->cpu.psw_id = 1;
|
||||||
|
vue->cpu.stage = CPU_FETCH;
|
||||||
|
return VUE_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process the simulation */
|
||||||
|
static void cpuEmulate(VUE *vue, int32_t cycles) {
|
||||||
|
|
||||||
|
/* The CPU is in permanent halt */
|
||||||
|
if (vue->cpu.stage == CPU_FATAL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
vue->cpu.cycles = 0; /* DEBUG: Stop processing after execute */
|
||||||
|
|
||||||
|
/* Process for the given number of cycles */
|
||||||
|
for (;;) {
|
||||||
|
|
||||||
|
/* The next event occurs after the given number of cycles */
|
||||||
|
if (vue->cpu.cycles > cycles) {
|
||||||
|
vue->cpu.cycles -= cycles;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Processing by stage */
|
||||||
|
switch (vue->cpu.stage) {
|
||||||
|
case CPU_EXCEPTION: if (cpuException (vue)) return; break;
|
||||||
|
case CPU_EXECUTE : if (cpuExecute (vue)) return; break;
|
||||||
|
case CPU_FETCH : if (cpuFetch (vue)) return; break;
|
||||||
|
case CPU_HALT : if (cpuTestException(vue)) return; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/* Write a system register */
|
/* Write a system register */
|
||||||
static int32_t cpuSetSystemRegister(VUE *vue, int32_t index, int32_t value,
|
static int32_t cpuSetSystemRegister(VUE *vue, int32_t index, int32_t value,
|
||||||
vbool debug) {
|
vbool debug) {
|
||||||
|
@ -230,9 +524,11 @@ static void cpuReset(VUE *vue) {
|
||||||
int32_t x;
|
int32_t x;
|
||||||
|
|
||||||
/* Configure instance fields */
|
/* Configure instance fields */
|
||||||
vue->cpu.cycles = 0; /* Duration of first fetch */
|
vue->cpu.cycles = 0;
|
||||||
vue->cpu.fetch = 0;
|
vue->cpu.exception.code = 0;
|
||||||
vue->cpu.stage = CPU_FETCH;
|
vue->cpu.fetch = 0;
|
||||||
|
vue->cpu.irq = 0;
|
||||||
|
vue->cpu.stage = CPU_FETCH;
|
||||||
|
|
||||||
/* Clear all registers (hardware only sets ECR, PC and PSW) */
|
/* Clear all registers (hardware only sets ECR, PC and PSW) */
|
||||||
for (x = 0; x < 32; x++) {
|
for (x = 0; x < 32; x++) {
|
||||||
|
@ -251,7 +547,7 @@ static void cpuReset(VUE *vue) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Test a condition */
|
/* Test a condition */
|
||||||
static int8_t cpuTest(VUE *vue, int32_t condition) {
|
static int8_t cpuTestCondition(VUE *vue, int32_t condition) {
|
||||||
switch (condition) {
|
switch (condition) {
|
||||||
case 0: return vue->cpu.psw_ov;
|
case 0: return vue->cpu.psw_ov;
|
||||||
case 1: return vue->cpu.psw_cy;
|
case 1: return vue->cpu.psw_cy;
|
||||||
|
@ -262,7 +558,17 @@ static int8_t cpuTest(VUE *vue, int32_t condition) {
|
||||||
case 6: return vue->cpu.psw_ov | vue->cpu.psw_s;
|
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;
|
case 7: return (vue->cpu.psw_ov ^ vue->cpu.psw_s) | vue->cpu.psw_z;
|
||||||
}
|
}
|
||||||
return cpuTest(vue, condition & 7) ^ 1;
|
return cpuTestCondition(vue, condition & 7) ^ 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Determine the number of CPU cycles until something can happen */
|
||||||
|
static int32_t cpuUntil(VUE *vue, int32_t cycles) {
|
||||||
|
if (vue->cpu.stage == CPU_FATAL || vue->cpu.stage == CPU_HALT)
|
||||||
|
return cycles;
|
||||||
|
return cycles < 0 ? vue->cpu.cycles :
|
||||||
|
cycles < vue->cpu.cycles ? cycles : vue->cpu.cycles;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -139,9 +139,25 @@ extern "C" {
|
||||||
* Types *
|
* Types *
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
|
/* Forward references */
|
||||||
|
typedef struct VUE VUE;
|
||||||
|
|
||||||
/* Boolean */
|
/* Boolean */
|
||||||
typedef int vbool;
|
typedef int vbool;
|
||||||
|
|
||||||
|
/* Access state */
|
||||||
|
typedef struct {
|
||||||
|
uint32_t address; /* CPU bus address */
|
||||||
|
int32_t value; /* Value read/to write */
|
||||||
|
int8_t fetch; /* Index of machine code unit */
|
||||||
|
int8_t type; /* Data type */
|
||||||
|
} VUE_ACCESS;
|
||||||
|
|
||||||
|
/* Exception state */
|
||||||
|
typedef struct {
|
||||||
|
uint16_t code; /* Exception code */
|
||||||
|
} VUE_EXCEPTION;
|
||||||
|
|
||||||
/* Instruction state */
|
/* Instruction state */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int32_t bits; /* Binary encoding */
|
int32_t bits; /* Binary encoding */
|
||||||
|
@ -155,21 +171,36 @@ typedef struct {
|
||||||
uint8_t reg2; /* Destination/left register */
|
uint8_t reg2; /* Destination/left register */
|
||||||
uint8_t size; /* Number of bytes in encoding */
|
uint8_t size; /* Number of bytes in encoding */
|
||||||
uint8_t subopcode; /* Instruction subopcode */
|
uint8_t subopcode; /* Instruction subopcode */
|
||||||
} VUE_INST;
|
} VUE_INSTRUCTION;
|
||||||
|
|
||||||
|
/* Callbacks */
|
||||||
|
typedef int32_t (*VUE_ONEXCEPTION)(VUE *, VUE_EXCEPTION *);
|
||||||
|
typedef int32_t (*VUE_ONEXECUTE )(VUE *, VUE_INSTRUCTION *);
|
||||||
|
typedef int32_t (*VUE_ONREAD )(VUE *, VUE_ACCESS *);
|
||||||
|
typedef int32_t (*VUE_ONWRITE )(VUE *, VUE_ACCESS *);
|
||||||
|
|
||||||
/* Emulation state */
|
/* Emulation state */
|
||||||
typedef struct {
|
struct VUE {
|
||||||
int32_t breakCode; /* Application break code */
|
int32_t breakCode; /* Application break code */
|
||||||
uint8_t wram[0x10000]; /* System memory */
|
uint8_t wram[0x10000]; /* System memory */
|
||||||
|
|
||||||
|
/* Callback handlers */
|
||||||
|
VUE_ONEXCEPTION onException;
|
||||||
|
VUE_ONEXECUTE onExecute;
|
||||||
|
VUE_ONREAD onRead;
|
||||||
|
VUE_ONWRITE onWrite;
|
||||||
|
|
||||||
/* CPU state */
|
/* CPU state */
|
||||||
struct {
|
struct {
|
||||||
VUE_INST inst; /* Instruction state */
|
VUE_ACCESS access; /* Access state */
|
||||||
uint32_t cycles; /* Cycles until next stage */
|
VUE_EXCEPTION exception; /* Exception state */
|
||||||
int32_t jumpFrom[3]; /* Source PCs of most recent jumps */
|
VUE_INSTRUCTION inst; /* Instruction state */
|
||||||
int32_t jumpTo [3]; /* Destination PCs of most recent jumps */
|
int32_t cycles; /* Cycles until next stage */
|
||||||
int fetch; /* Fetch unit index */
|
int32_t jumpFrom[3]; /* Source PCs of most recent jumps */
|
||||||
int stage; /* Current processing stage */
|
int32_t jumpTo [3]; /* Destination PCs of most recent jumps */
|
||||||
|
uint16_t irq; /* Interrupt lines */
|
||||||
|
int fetch; /* Fetch unit index */
|
||||||
|
int stage; /* Current processing stage */
|
||||||
|
|
||||||
/* Program registers */
|
/* Program registers */
|
||||||
int32_t program[32];
|
int32_t program[32];
|
||||||
|
@ -225,7 +256,7 @@ typedef struct {
|
||||||
int8_t wcr_rom1w; /* ROM one-wait mode */
|
int8_t wcr_rom1w; /* ROM one-wait mode */
|
||||||
} pak;
|
} pak;
|
||||||
|
|
||||||
} VUE;
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -240,8 +271,12 @@ VUEAPI void vueInitialize (VUE *vue);
|
||||||
VUEAPI int32_t vueRead (VUE *vue, uint32_t address, int32_t type);
|
VUEAPI int32_t vueRead (VUE *vue, uint32_t address, int32_t type);
|
||||||
VUEAPI vbool vueReadBytes (VUE *vue, uint32_t address, uint8_t *dest, uint32_t length);
|
VUEAPI vbool vueReadBytes (VUE *vue, uint32_t address, uint8_t *dest, uint32_t length);
|
||||||
VUEAPI void vueReset (VUE *vue);
|
VUEAPI void vueReset (VUE *vue);
|
||||||
|
VUEAPI void vueSetException(VUE *vue, VUE_ONEXCEPTION callback);
|
||||||
|
VUEAPI void vueSetExecute (VUE *vue, VUE_ONEXECUTE callback);
|
||||||
|
VUEAPI void vueSetRead (VUE *vue, VUE_ONREAD callback);
|
||||||
VUEAPI int32_t vueSetRegister (VUE *vue, int32_t index, vbool system, int32_t value);
|
VUEAPI int32_t vueSetRegister (VUE *vue, int32_t index, vbool system, int32_t value);
|
||||||
VUEAPI vbool vueSetROM (VUE *vue, uint8_t *rom, uint32_t size);
|
VUEAPI vbool vueSetROM (VUE *vue, uint8_t *rom, uint32_t size);
|
||||||
|
VUEAPI void vueSetWrite (VUE *vue, VUE_ONWRITE callback);
|
||||||
VUEAPI void vueWrite (VUE *vue, uint32_t address, int32_t type, int32_t value);
|
VUEAPI void vueWrite (VUE *vue, uint32_t address, int32_t type, int32_t value);
|
||||||
VUEAPI vbool vueWriteBytes (VUE *vue, uint32_t address, uint8_t *src, uint32_t length);
|
VUEAPI vbool vueWriteBytes (VUE *vue, uint32_t address, uint8_t *src, uint32_t length);
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ static int32_t readBuffer(uint8_t *data, uint32_t datlen, uint32_t address,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sign-extend the value if appropriate */
|
/* Sign-extend the value if appropriate */
|
||||||
if (type & 1) {
|
if ((type & 1) == 0) {
|
||||||
size <<= 3;
|
size <<= 3;
|
||||||
value = SIGN_EXTEND(size, value);
|
value = SIGN_EXTEND(size, value);
|
||||||
}
|
}
|
||||||
|
@ -167,23 +167,29 @@ int32_t vueEmulate(VUE *vue, int32_t maxCycles) {
|
||||||
do {
|
do {
|
||||||
|
|
||||||
/* Determine the number of cycles during which nothing will happen */
|
/* Determine the number of cycles during which nothing will happen */
|
||||||
cycles = maxCycles;
|
cycles = -1;
|
||||||
/*cycles = cpuUntil (vue, cycles);*/
|
|
||||||
/*cycles = padUntil (vue, cycles);*/
|
/*cycles = padUntil (vue, cycles);*/
|
||||||
/*cycles = linkUntil (vue, cycles);*/
|
/*cycles = linkUntil (vue, cycles);*/
|
||||||
/*cycles = timerUntil(vue, cycles);*/
|
/*cycles = timerUntil(vue, cycles);*/
|
||||||
/*cycles = vipUntil (vue, cycles);*/
|
/*cycles = vipUntil (vue, cycles);*/
|
||||||
/*cycles = vsuUntil (vue, cycles);*/
|
/*cycles = vsuUntil (vue, cycles);*/
|
||||||
|
cycles = cpuUntil (vue, cycles);
|
||||||
|
|
||||||
|
/* Range checking */
|
||||||
|
if (cycles == -1) /* No activity on any component */
|
||||||
|
break;
|
||||||
|
if (maxCycles >= 0) /* Restrict to given number of cycles */
|
||||||
|
cycles = cycles < maxCycles ? cycles : maxCycles;
|
||||||
|
|
||||||
/* Process all system components */
|
/* Process all system components */
|
||||||
vue->breakCode = 0;
|
vue->breakCode = 0;
|
||||||
/*gamePad.emulate(cycles);*/
|
/*padEmulate (vue, cycles);*/
|
||||||
/*gamePak.emulate(cycles);*/
|
/*pakEmulate (vue, cycles);*/
|
||||||
/*link .emulate(cycles);*/
|
/*linkEmulate (vue, cycles);*/
|
||||||
/*timer .emulate(cycles);*/
|
/*timerEmulate(vue, cycles);*/
|
||||||
/*vip .emulate(cycles);*/
|
/*vipEmulate (vue, cycles);*/
|
||||||
/*vsu .emulate(cycles);*/
|
/*vsuEmulate (vue, cycles);*/
|
||||||
/*cpu .emulate(cycles);*/
|
cpuEmulate (vue, cycles);
|
||||||
|
|
||||||
/* An application break was requested */
|
/* An application break was requested */
|
||||||
if (vue->breakCode != 0)
|
if (vue->breakCode != 0)
|
||||||
|
@ -231,12 +237,22 @@ int32_t vueGetRegister(VUE *vue, int32_t index, vbool system) {
|
||||||
void vueInitialize(VUE *vue) {
|
void vueInitialize(VUE *vue) {
|
||||||
if (vue == NULL)
|
if (vue == NULL)
|
||||||
return;
|
return;
|
||||||
vue->pak.ram = NULL;
|
vue->onException = NULL;
|
||||||
vue->pak.rom = NULL;
|
vue->onExecute = NULL;
|
||||||
|
vue->onRead = NULL;
|
||||||
|
vue->onWrite = NULL;
|
||||||
|
vue->pak.ram = NULL;
|
||||||
|
vue->pak.rom = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read a value from the CPU bus */
|
/* Read a value from the CPU bus */
|
||||||
int32_t vueRead(VUE *vue, uint32_t address, int32_t type) {
|
int32_t vueRead(VUE *vue, uint32_t address, int32_t type) {
|
||||||
|
|
||||||
|
/* Error checking */
|
||||||
|
if (vue == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Perform the operation */
|
||||||
switch (address >> 24 & 7) {
|
switch (address >> 24 & 7) {
|
||||||
case 5: return readBuffer(vue->wram , 0x10000,address,type);
|
case 5: return readBuffer(vue->wram , 0x10000,address,type);
|
||||||
case 6: return readBuffer(vue->pak.ram,vue->pak.ramSize,address,type);
|
case 6: return readBuffer(vue->pak.ram,vue->pak.ramSize,address,type);
|
||||||
|
@ -292,6 +308,24 @@ void vueReset(VUE *vue) {
|
||||||
vue->wram[x] = 0;
|
vue->wram[x] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Specify an exception breakpoint callback */
|
||||||
|
void vueSetException(VUE *vue, VUE_ONEXCEPTION callback) {
|
||||||
|
if (vue != NULL)
|
||||||
|
vue->onException = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Specify an execute breakpoint callback */
|
||||||
|
void vueSetExecute(VUE *vue, VUE_ONEXECUTE callback) {
|
||||||
|
if (vue != NULL)
|
||||||
|
vue->onExecute = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Specify a read breakpoint callback */
|
||||||
|
void vueSetRead(VUE *vue, VUE_ONREAD callback) {
|
||||||
|
if (vue != NULL)
|
||||||
|
vue->onRead = callback;
|
||||||
|
}
|
||||||
|
|
||||||
/* Specify a value for a register */
|
/* Specify a value for a register */
|
||||||
int32_t vueSetRegister(VUE *vue, int32_t index, vbool system, int32_t value) {
|
int32_t vueSetRegister(VUE *vue, int32_t index, vbool system, int32_t value) {
|
||||||
return vue == NULL ? 0 :
|
return vue == NULL ? 0 :
|
||||||
|
@ -319,8 +353,20 @@ vbool vueSetROM(VUE *vue, uint8_t *rom, uint32_t size) {
|
||||||
return VUE_TRUE;
|
return VUE_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Specify a write breakpoint callback */
|
||||||
|
void vueSetWrite(VUE *vue, VUE_ONREAD callback) {
|
||||||
|
if (vue != NULL)
|
||||||
|
vue->onWrite = callback;
|
||||||
|
}
|
||||||
|
|
||||||
/* Write a value to the CPU bus */
|
/* Write a value to the CPU bus */
|
||||||
void vueWrite(VUE *vue, uint32_t address, int32_t type, int32_t value) {
|
void vueWrite(VUE *vue, uint32_t address, int32_t type, int32_t value) {
|
||||||
|
|
||||||
|
/* Error checking */
|
||||||
|
if (vue == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Perform the operation */
|
||||||
switch (address >> 24 & 7) {
|
switch (address >> 24 & 7) {
|
||||||
case 5: writeBuffer(vue->wram , 0x1000,
|
case 5: writeBuffer(vue->wram , 0x1000,
|
||||||
address, type, value); break;
|
address, type, value); break;
|
||||||
|
@ -329,6 +375,7 @@ void vueWrite(VUE *vue, uint32_t address, int32_t type, int32_t value) {
|
||||||
case 7: writeBuffer(vue->pak.rom, vue->pak.romSize,
|
case 7: writeBuffer(vue->pak.rom, vue->pak.romSize,
|
||||||
address, type, value); break;
|
address, type, value); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write bytes to the CPU bus */
|
/* Write bytes to the CPU bus */
|
||||||
|
|
|
@ -115,12 +115,20 @@ class DisassemblerPane extends JScrollPane {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Seek
|
// Processing by key code
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case KeyEvent.VK_UP : seek(address, 1); break;
|
case KeyEvent.VK_UP : seek(address, 1); break;
|
||||||
case KeyEvent.VK_DOWN : seek(address, -1); break;
|
case KeyEvent.VK_DOWN : seek(address, -1); break;
|
||||||
case KeyEvent.VK_PAGE_UP : seek(address, count); break;
|
case KeyEvent.VK_PAGE_UP : seek(address, count); break;
|
||||||
case KeyEvent.VK_PAGE_DOWN: seek(address, -count); break;
|
case KeyEvent.VK_PAGE_DOWN: seek(address, -count); break;
|
||||||
|
|
||||||
|
case KeyEvent.VK_F11:
|
||||||
|
parent.parent.vue.emulate(0);
|
||||||
|
parent.parent.refreshDebug();
|
||||||
|
int pc = parent.parent.vue.getRegister(VUE.PC, true);
|
||||||
|
if (!isVisible(pc))
|
||||||
|
seek(pc, count / 3);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ class CPU {
|
||||||
// Package fields
|
// Package fields
|
||||||
Access access; // Access state
|
Access access; // Access state
|
||||||
int cycles; // Cycles until next stage
|
int cycles; // Cycles until next stage
|
||||||
int exception; // Exception code
|
Ecxeption exception; // Exception code
|
||||||
int fetch; // Fetch unit index
|
int fetch; // Fetch unit index
|
||||||
Instruction inst; // Instruction state
|
Instruction inst; // Instruction state
|
||||||
int irq; // Interrupt lines
|
int irq; // Interrupt lines
|
||||||
|
@ -96,12 +96,13 @@ class CPU {
|
||||||
|
|
||||||
// Default constructor
|
// Default constructor
|
||||||
CPU(JavaVUE vue) {
|
CPU(JavaVUE vue) {
|
||||||
access = new Access();
|
access = new Access();
|
||||||
inst = new Instruction();
|
exception = new Ecxeption();
|
||||||
jumpFrom = new int[3];
|
inst = new Instruction();
|
||||||
jumpTo = new int[3];
|
jumpFrom = new int[3];
|
||||||
program = new int[32];
|
jumpTo = new int[3];
|
||||||
this.vue = vue;
|
program = new int[32];
|
||||||
|
this.vue = vue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -117,8 +118,10 @@ class CPU {
|
||||||
if (stage == FATAL)
|
if (stage == FATAL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
this.cycles = 0; // DEBUG: Stop processing after execute
|
||||||
|
|
||||||
// Process for the given number of cycles
|
// Process for the given number of cycles
|
||||||
do {
|
for (;;) {
|
||||||
|
|
||||||
// The next event occurs after the given number of cycles
|
// The next event occurs after the given number of cycles
|
||||||
if (this.cycles > cycles) {
|
if (this.cycles > cycles) {
|
||||||
|
@ -128,13 +131,14 @@ class CPU {
|
||||||
|
|
||||||
// Processing by stage
|
// Processing by stage
|
||||||
switch (stage) {
|
switch (stage) {
|
||||||
case FETCH : if (fetch ()) return;
|
case EXCEPTION: if (exception ()) return; break;
|
||||||
case EXECUTE : if (execute ()) return;
|
case EXECUTE : if (execute ()) return; break;
|
||||||
case HALT : testException(); break;
|
case FETCH : if (fetch ()) return; break;
|
||||||
case EXCEPTION: if (exception()) return;
|
case HALT : if (testException()) return; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
} while (cycles > 0);
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read a system register
|
// Read a system register
|
||||||
|
@ -172,11 +176,11 @@ class CPU {
|
||||||
void reset() {
|
void reset() {
|
||||||
|
|
||||||
// Configure instance fields
|
// Configure instance fields
|
||||||
cycles = 0; // Duration of first fetch
|
cycles = 0;
|
||||||
exception = 0;
|
exception.code = 0;
|
||||||
fetch = 0;
|
fetch = 0;
|
||||||
irq = 0;
|
irq = 0;
|
||||||
stage = FETCH;
|
stage = FETCH;
|
||||||
|
|
||||||
// Clear all registers (hardware only sets ECR, PC and PSW)
|
// Clear all registers (hardware only sets ECR, PC and PSW)
|
||||||
for (int x = 0; x < 32; x++) {
|
for (int x = 0; x < 32; x++) {
|
||||||
|
@ -290,44 +294,52 @@ class CPU {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
exception &= 0xFFFF;
|
System.out.printf("Exception %04X %d %d\n", exception.code, psw_ep, psw_np);
|
||||||
boolean isIRQ = (exception & 0xFF00) == 0xFE00;
|
|
||||||
int psw = getSystemRegister(VUE.PSW);
|
// Configure working variables
|
||||||
|
exception.code &= 0xFFFF;
|
||||||
|
boolean isIRQ = (exception.code & 0xFF00) == 0xFE00;
|
||||||
|
int psw = getSystemRegister(VUE.PSW);
|
||||||
|
|
||||||
// Fatal exception
|
// Fatal exception
|
||||||
if (psw_np != 0) {
|
if (psw_np != 0) {
|
||||||
vue.write(0x00000000, VUE.S32, 0xFFFF0000 | exception);
|
vue.write(0x00000000, VUE.S32, 0xFFFF0000 | exception.code);
|
||||||
vue.write(0x00000004, VUE.S32, psw);
|
vue.write(0x00000004, VUE.S32, psw);
|
||||||
vue.write(0x00000008, VUE.S32, pc);
|
vue.write(0x00000008, VUE.S32, pc);
|
||||||
|
stage = FATAL;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Duplexed exception
|
// Duplexed exception
|
||||||
if (psw_ep != 0) {
|
if (psw_ep != 0) {
|
||||||
ecr_fecc = exception;
|
ecr_fecc = exception.code;
|
||||||
fepc = pc;
|
fepc = pc;
|
||||||
fepsw = psw;
|
fepsw = psw;
|
||||||
|
psw_np = 1;
|
||||||
pc = 0xFFFFFFD0;
|
pc = 0xFFFFFFD0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Regular exception
|
// Regular exception
|
||||||
else {
|
else {
|
||||||
ecr_eicc = exception;
|
ecr_eicc = exception.code;
|
||||||
eipc = pc;
|
eipc = pc;
|
||||||
eipsw = psw;
|
eipsw = psw;
|
||||||
pc = 0xFFFF0000 | exception & 0xFFF0;
|
psw_ep = 1;
|
||||||
|
pc = 0xFFFF0000 | exception.code & 0xFFF0;
|
||||||
if (pc == 0xFFFFFF70) // FIV
|
if (pc == 0xFFFFFF70) // FIV
|
||||||
pc = 0xFFFFFF60;
|
pc = 0xFFFFFF60;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interrupt
|
// Interrupt
|
||||||
if (isIRQ)
|
if (isIRQ)
|
||||||
psw_i = Math.min(15, exception >> 4 & 15);
|
psw_i = Math.min(15, exception.code >> 4 & 15);
|
||||||
|
|
||||||
// Common processing
|
// Common processing
|
||||||
exception = 0;
|
cycles = 0; // TODO: Determine the actual number
|
||||||
psw_ae = 0;
|
exception.code = 0;
|
||||||
psw_id = 1;
|
psw_ae = 0;
|
||||||
stage = FETCH;
|
psw_id = 1;
|
||||||
|
stage = FETCH;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -341,6 +353,8 @@ class CPU {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
System.out.printf("Execute %08X %d\n", pc, inst.id);
|
||||||
|
|
||||||
// Determine the default number of cycles for the instruction
|
// Determine the default number of cycles for the instruction
|
||||||
if (inst.id >= 0 && inst.id <= 75)
|
if (inst.id >= 0 && inst.id <= 75)
|
||||||
cycles = CYCLES[inst.id];
|
cycles = CYCLES[inst.id];
|
||||||
|
@ -371,7 +385,7 @@ class CPU {
|
||||||
//case VUE.IN_H : IN_H (); break;
|
//case VUE.IN_H : IN_H (); break;
|
||||||
//case VUE.IN_W : IN_W (); break;
|
//case VUE.IN_W : IN_W (); break;
|
||||||
//case VUE.JAL : JAL (); break;
|
//case VUE.JAL : JAL (); break;
|
||||||
//case VUE.JMP : JMP (); break;
|
case VUE.JMP : JMP (); break;
|
||||||
//case VUE.JR : JR (); break;
|
//case VUE.JR : JR (); break;
|
||||||
//case VUE.LD_B : LD_B (); break;
|
//case VUE.LD_B : LD_B (); break;
|
||||||
//case VUE.LD_H : LD_H (); break;
|
//case VUE.LD_H : LD_H (); break;
|
||||||
|
@ -380,8 +394,8 @@ class CPU {
|
||||||
//case VUE.MOV_IMM: MOV_IMM(); break;
|
//case VUE.MOV_IMM: MOV_IMM(); break;
|
||||||
//case VUE.MOV_REG: MOV_REG(); break;
|
//case VUE.MOV_REG: MOV_REG(); break;
|
||||||
//case VUE.MOVBSU : MOVBSU (); break;
|
//case VUE.MOVBSU : MOVBSU (); break;
|
||||||
//case VUE.MOVEA : MOVEA (); break;
|
case VUE.MOVEA : MOVEA (); break;
|
||||||
//case VUE.MOVHI : MOVHI (); break;
|
case VUE.MOVHI : MOVHI (); break;
|
||||||
//case VUE.MPYHW : MPYHW (); break;
|
//case VUE.MPYHW : MPYHW (); break;
|
||||||
//case VUE.MUL : MUL (); break;
|
//case VUE.MUL : MUL (); break;
|
||||||
//case VUE.MULF_S : MULF_S (); break;
|
//case VUE.MULF_S : MULF_S (); break;
|
||||||
|
@ -423,13 +437,17 @@ class CPU {
|
||||||
//case VUE.XORBSU : XORBSU (); break;
|
//case VUE.XORBSU : XORBSU (); break;
|
||||||
//case VUE.XORI : XORI (); break;
|
//case VUE.XORI : XORI (); break;
|
||||||
//case VUE.XORNBSU: XORNBSU(); break;
|
//case VUE.XORNBSU: XORNBSU(); break;
|
||||||
default: exception = 0xFF90; // Invalid instruction
|
default: // Invalid instruction
|
||||||
|
exception.code = 0xFF90;
|
||||||
|
inst.size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Common processing
|
// Common processing
|
||||||
pc += inst.size;
|
pc += inst.size;
|
||||||
program[0] = 0;
|
program[0] = 0;
|
||||||
testException();
|
testException();
|
||||||
|
if (stage == EXECUTE)
|
||||||
|
stage = FETCH;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -442,6 +460,8 @@ class CPU {
|
||||||
access.type = VUE.U16;
|
access.type = VUE.U16;
|
||||||
access.value = vue.read(access.address, VUE.U16);
|
access.value = vue.read(access.address, VUE.U16);
|
||||||
|
|
||||||
|
System.out.printf("Fetch %08X %04X\n", access.address, access.value);
|
||||||
|
|
||||||
// Application callback
|
// Application callback
|
||||||
if (vue.onRead != null) {
|
if (vue.onRead != null) {
|
||||||
vue.breakCode = vue.onRead.call(vue, access);
|
vue.breakCode = vue.onRead.call(vue, access);
|
||||||
|
@ -452,7 +472,7 @@ class CPU {
|
||||||
// First unit
|
// First unit
|
||||||
if (fetch == 0) {
|
if (fetch == 0) {
|
||||||
inst.bits = access.value << 16;
|
inst.bits = access.value << 16;
|
||||||
if (Instruction.size(access.value & 0x3F) == 4) {
|
if (Instruction.size(access.value >> 10 & 0x3F) == 4) {
|
||||||
fetch = 1;
|
fetch = 1;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -471,23 +491,46 @@ class CPU {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for an exception or interrupt
|
// Check for an exception or interrupt
|
||||||
private void testException() {
|
private boolean testException() {
|
||||||
|
|
||||||
// Check for an interrupt
|
// Check for an interrupt
|
||||||
if (irq != 0 && (exception | psw_id | psw_ep | psw_np) == 0) {
|
if (irq != 0 && (exception.code | psw_id | psw_ep | psw_np) == 0) {
|
||||||
int level;
|
int level;
|
||||||
for (level = 4; level >= 0; level--)
|
for (level = 4; level >= 0; level--)
|
||||||
if ((irq >> level & 1) != 0)
|
if ((irq >> level & 1) != 0)
|
||||||
break;
|
break;
|
||||||
exception = 0xFE00 | level << 4;
|
exception.code = 0xFE00 | level << 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for an exception
|
// There is no exception
|
||||||
if (exception != 0) {
|
if (exception.code == 0)
|
||||||
cycles = 0;
|
return stage == HALT && cycles == 0; // No further processing
|
||||||
stage = EXCEPTION;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// An exception has occurred
|
||||||
|
cycles = 0;
|
||||||
|
stage = EXCEPTION;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Instruction Methods //
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// JMP
|
||||||
|
private void JMP() {
|
||||||
|
pc = program[inst.reg1] - 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// MOVEA
|
||||||
|
private void MOVEA() {
|
||||||
|
program[inst.reg2] = program[inst.reg1] + inst.imm;
|
||||||
|
}
|
||||||
|
|
||||||
|
// MOVHI
|
||||||
|
private void MOVHI() {
|
||||||
|
program[inst.reg2] = program[inst.reg1] + (inst.imm << 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
package vue;
|
||||||
|
|
||||||
|
// Intentionally misspelled to avoid ambiguity with java.lang.Exception
|
||||||
|
|
||||||
|
// Exception state
|
||||||
|
public class Ecxeption {
|
||||||
|
|
||||||
|
// Instance fields
|
||||||
|
public int code; // Exception code
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructors //
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Default constructor
|
||||||
|
Ecxeption() { }
|
||||||
|
|
||||||
|
}
|
|
@ -178,6 +178,21 @@ class JavaVUE extends VUE {
|
||||||
Arrays.fill(wram, 0, 0x10000, (byte) 0);
|
Arrays.fill(wram, 0, 0x10000, (byte) 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Specify an exception breakpoint callback
|
||||||
|
public void setException(OnException callback) {
|
||||||
|
onException = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Specify an execute breakpoint callback
|
||||||
|
public void setExecute(OnExecute callback) {
|
||||||
|
onExecute = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Specify a read breakpoint callback
|
||||||
|
public void setRead(OnRead callback) {
|
||||||
|
onRead = callback;
|
||||||
|
}
|
||||||
|
|
||||||
// Specify a register value
|
// Specify a register value
|
||||||
public int setRegister(int index, boolean system, int value) {
|
public int setRegister(int index, boolean system, int value) {
|
||||||
return
|
return
|
||||||
|
@ -206,6 +221,11 @@ class JavaVUE extends VUE {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Specify a write breakpoint callback
|
||||||
|
public void setWrite(OnWrite callback) {
|
||||||
|
onWrite = callback;
|
||||||
|
}
|
||||||
|
|
||||||
// Write a value to the CPU bus
|
// Write a value to the CPU bus
|
||||||
public void write(int address, int type, int value) {
|
public void write(int address, int type, int value) {
|
||||||
switch (address >> 24 & 7) {
|
switch (address >> 24 & 7) {
|
||||||
|
@ -273,7 +293,7 @@ class JavaVUE extends VUE {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sign-extend the value if appropriate
|
// Sign-extend the value if appropriate
|
||||||
if ((type & 1) == 1) {
|
if ((type & 1) == 0) {
|
||||||
size = 32 - (size << 3);
|
size = 32 - (size << 3);
|
||||||
value = value << size >> size;
|
value = value << size >> size;
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,7 +90,7 @@ JNIEXPORT jint JNICALL Java_vue_NativeVUE_emulate
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve the application break code
|
// Retrieve the application break code
|
||||||
JNIEXPORT jint JNICALL Java_vue_NativeVUE_getRegister
|
JNIEXPORT jint JNICALL Java_vue_NativeVUE_getBreakCode
|
||||||
(JNIEnv *env, jobject vue) {
|
(JNIEnv *env, jobject vue) {
|
||||||
CORE *core = GetCore(env, vue);
|
CORE *core = GetCore(env, vue);
|
||||||
return vueGetBreakCode(&core->vue);
|
return vueGetBreakCode(&core->vue);
|
||||||
|
@ -161,6 +161,24 @@ JNIEXPORT void JNICALL Java_vue_NativeVUE_reset
|
||||||
vueReset(&core->vue);
|
vueReset(&core->vue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Specify an exception breakpoint callback
|
||||||
|
JNIEXPORT void JNICALL Java_vue_NativeVUE_setException
|
||||||
|
(JNIEnv *env, jobject vue, jobject onException) {
|
||||||
|
CORE *core = GetCore(env, vue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Specify an execute breakpoint callback
|
||||||
|
JNIEXPORT void JNICALL Java_vue_NativeVUE_setExecute
|
||||||
|
(JNIEnv *env, jobject vue, jobject onExecute) {
|
||||||
|
CORE *core = GetCore(env, vue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Specify a read breakpoint callback
|
||||||
|
JNIEXPORT void JNICALL Java_vue_NativeVUE_setRead
|
||||||
|
(JNIEnv *env, jobject vue, jobject onRead) {
|
||||||
|
CORE *core = GetCore(env, vue);
|
||||||
|
}
|
||||||
|
|
||||||
// Specify a register value
|
// Specify a register value
|
||||||
JNIEXPORT jint JNICALL Java_vue_NativeVUE_setRegister
|
JNIEXPORT jint JNICALL Java_vue_NativeVUE_setRegister
|
||||||
(JNIEnv *env, jobject vue, jint index, jboolean system, jint value) {
|
(JNIEnv *env, jobject vue, jint index, jboolean system, jint value) {
|
||||||
|
@ -195,6 +213,12 @@ JNIEXPORT jboolean JNICALL Java_vue_NativeVUE_setROM
|
||||||
return JNI_TRUE;
|
return JNI_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Specify a write breakpoint callback
|
||||||
|
JNIEXPORT void JNICALL Java_vue_NativeVUE_setWrite
|
||||||
|
(JNIEnv *env, jobject vue, jobject onWrite) {
|
||||||
|
CORE *core = GetCore(env, vue);
|
||||||
|
}
|
||||||
|
|
||||||
// Write a value to the CPU bus
|
// Write a value to the CPU bus
|
||||||
JNIEXPORT void JNICALL Java_vue_NativeVUE_write
|
JNIEXPORT void JNICALL Java_vue_NativeVUE_write
|
||||||
(JNIEnv *env, jobject vue, jint address, jint type, jint value) {
|
(JNIEnv *env, jobject vue, jint address, jint type, jint value) {
|
||||||
|
|
|
@ -51,12 +51,24 @@ class NativeVUE extends VUE {
|
||||||
// Initialize all system components
|
// Initialize all system components
|
||||||
public native void reset();
|
public native void reset();
|
||||||
|
|
||||||
|
// Specify an exception breakpoint callback
|
||||||
|
public native void setException(OnException callback);
|
||||||
|
|
||||||
|
// Specify an execute breakpoint callback
|
||||||
|
public native void setExecute(OnExecute callback);
|
||||||
|
|
||||||
|
// Specify a read breakpoint callback
|
||||||
|
public native void setRead(OnRead callback);
|
||||||
|
|
||||||
// Specify a register value
|
// Specify a register value
|
||||||
public native int setRegister(int index, boolean system, int value);
|
public native int setRegister(int index, boolean system, int value);
|
||||||
|
|
||||||
// Provide new ROM data
|
// Provide new ROM data
|
||||||
public native boolean setROM(byte[] data, int offset, int length);
|
public native boolean setROM(byte[] data, int offset, int length);
|
||||||
|
|
||||||
|
// Specify a write breakpoint callback
|
||||||
|
public native void setWrite(OnWrite callback);
|
||||||
|
|
||||||
// Write a value to the CPU bus
|
// Write a value to the CPU bus
|
||||||
public native void write(int address, int type, int value);
|
public native void write(int address, int type, int value);
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ public abstract class VUE {
|
||||||
// Types //
|
// Types //
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public interface OnException { int call(VUE vue, int code ); }
|
public interface OnException { int call(VUE vue, Ecxeption exp ); }
|
||||||
public interface OnExecute { int call(VUE vue, Instruction inst ); }
|
public interface OnExecute { int call(VUE vue, Instruction inst ); }
|
||||||
public interface OnRead { int call(VUE vue, Access access); }
|
public interface OnRead { int call(VUE vue, Access access); }
|
||||||
public interface OnWrite { int call(VUE vue, Access access); }
|
public interface OnWrite { int call(VUE vue, Access access); }
|
||||||
|
@ -24,11 +24,12 @@ public abstract class VUE {
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Memory access types
|
// Memory access types
|
||||||
public static final int S8 = 0;
|
public static final int S8 = 0;
|
||||||
public static final int U8 = 1;
|
public static final int U8 = 1;
|
||||||
public static final int S16 = 2;
|
public static final int S16 = 2;
|
||||||
public static final int U16 = 3;
|
public static final int U16 = 3;
|
||||||
public static final int S32 = 4;
|
public static final int S32 = 4;
|
||||||
|
public static final int CANCEL = 5;
|
||||||
|
|
||||||
// System register indexes
|
// System register indexes
|
||||||
public static final int ADTRE = 25;
|
public static final int ADTRE = 25;
|
||||||
|
@ -194,12 +195,24 @@ public abstract class VUE {
|
||||||
// Initialize all system components
|
// Initialize all system components
|
||||||
public abstract void reset();
|
public abstract void reset();
|
||||||
|
|
||||||
|
// Specify an exception breakpoint callback
|
||||||
|
public abstract void setException(OnException callback);
|
||||||
|
|
||||||
|
// Specify an execute breakpoint callback
|
||||||
|
public abstract void setExecute(OnExecute callback);
|
||||||
|
|
||||||
|
// Specify a read breakpoint callback
|
||||||
|
public abstract void setRead(OnRead callback);
|
||||||
|
|
||||||
// Specify a register value
|
// Specify a register value
|
||||||
public abstract int setRegister(int index, boolean system, int value);
|
public abstract int setRegister(int index, boolean system, int value);
|
||||||
|
|
||||||
// Provide new ROM data
|
// Provide new ROM data
|
||||||
public abstract boolean setROM(byte[] data, int offset, int length);
|
public abstract boolean setROM(byte[] data, int offset, int length);
|
||||||
|
|
||||||
|
// Specify a write breakpoint callback
|
||||||
|
public abstract void setWrite(OnWrite callback);
|
||||||
|
|
||||||
// Write a value to the CPU bus
|
// Write a value to the CPU bus
|
||||||
public abstract void write(int address, int type, int value);
|
public abstract void write(int address, int type, int value);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue