Implement halt, exception, fatal
This commit is contained in:
parent
7c25a4ac93
commit
bfc2254b9e
465
core/cpu.c
465
core/cpu.c
|
@ -125,6 +125,12 @@ static const uint8_t INST_LENGTHS[] = {
|
||||||
2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2
|
2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Highest interrupt level by IRQ bit mask value */
|
||||||
|
static const int8_t IRQ_LEVELS[] = {
|
||||||
|
-1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||||
|
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/********************************** Macros ***********************************/
|
/********************************** Macros ***********************************/
|
||||||
|
@ -195,6 +201,18 @@ static const uint8_t OPDEFS_FLOATENDO[] = {
|
||||||
|
|
||||||
/***************************** Callback Handlers *****************************/
|
/***************************** Callback Handlers *****************************/
|
||||||
|
|
||||||
|
/* Prepare to handle an exception */
|
||||||
|
#ifndef VB_DIRECT_EXCEPTION
|
||||||
|
#define VB_ON_EXCEPTION sim->onException
|
||||||
|
#else
|
||||||
|
extern int vbxOnException(VB *, uint16_t *);
|
||||||
|
#define VB_ON_EXCEPTION sim->onException
|
||||||
|
#endif
|
||||||
|
static int cpuOnException(VB *sim, uint16_t *cause) {
|
||||||
|
return sim->onException != NULL && VB_ON_EXCEPTION(sim, cause);
|
||||||
|
}
|
||||||
|
#undef VB_ON_EXCEPTION
|
||||||
|
|
||||||
/* Prepare to execute an instruction */
|
/* Prepare to execute an instruction */
|
||||||
#ifndef VB_DIRECT_EXECUTE
|
#ifndef VB_DIRECT_EXECUTE
|
||||||
#define VB_ON_EXECUTE sim->onExecute
|
#define VB_ON_EXECUTE sim->onExecute
|
||||||
|
@ -202,7 +220,7 @@ static const uint8_t OPDEFS_FLOATENDO[] = {
|
||||||
extern int vbxOnExecute(VB *, uint32_t, const uint16_t *, int);
|
extern int vbxOnExecute(VB *, uint32_t, const uint16_t *, int);
|
||||||
#define VB_ON_EXECUTE vbxOnExecute
|
#define VB_ON_EXECUTE vbxOnExecute
|
||||||
#endif
|
#endif
|
||||||
static int cpuExecute(VB *sim) {
|
static int cpuOnExecute(VB *sim) {
|
||||||
return
|
return
|
||||||
sim->onExecute != NULL &&
|
sim->onExecute != NULL &&
|
||||||
VB_ON_EXECUTE(sim, sim->cpu.pc, sim->cpu.code, sim->cpu.length)
|
VB_ON_EXECUTE(sim, sim->cpu.pc, sim->cpu.code, sim->cpu.length)
|
||||||
|
@ -289,160 +307,8 @@ static int cpuWrite(VB *sim, uint32_t address, int type, int32_t value) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/****************************** Pipeline Stages ******************************/
|
|
||||||
|
|
||||||
/* Fetch the code bits for the next instruction */
|
|
||||||
static int cpuFetch(VB *sim) {
|
|
||||||
int32_t value;
|
|
||||||
switch (sim->cpu.step) {
|
|
||||||
|
|
||||||
case 0:
|
|
||||||
sim->cpu.pc = sim->cpu.nextPC;
|
|
||||||
/* Fallthrough */
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
|
|
||||||
/* Retrieve the first code unit */
|
|
||||||
if (cpuReadFetch(sim, 0, sim->cpu.pc, &value)) {
|
|
||||||
sim->cpu.step = 1;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update state */
|
|
||||||
sim->cpu.code[0] = value;
|
|
||||||
sim->cpu.length = INST_LENGTHS[value >> 10 & 63];
|
|
||||||
sim->cpu.step = 3 - sim->cpu.length;
|
|
||||||
|
|
||||||
/* Wait any clocks taken */
|
|
||||||
if (sim->cpu.clocks != 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Skip fetching a second code unit */
|
|
||||||
if (sim->cpu.length == 1)
|
|
||||||
goto Step3;
|
|
||||||
|
|
||||||
/* Fallthrough */
|
|
||||||
case 2:
|
|
||||||
|
|
||||||
/* Retrieve the second code unit */
|
|
||||||
if (cpuReadFetch(sim, 1, sim->cpu.pc + 2, &value))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
/* Update state */
|
|
||||||
sim->cpu.code[1] = value;
|
|
||||||
sim->cpu.step = 3;
|
|
||||||
|
|
||||||
/* Wait any clocks taken */
|
|
||||||
if (sim->cpu.clocks != 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Fallthrough */
|
|
||||||
case 3: Step3:
|
|
||||||
|
|
||||||
/* Prepare to execute the instruction */
|
|
||||||
if (cpuExecute(sim))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
/* Select operation definition */
|
|
||||||
sim->cpu.operation = OPDEFS[sim->cpu.code[0] >> 10];
|
|
||||||
switch (sim->cpu.operation) {
|
|
||||||
case CPU_BITSTRING:
|
|
||||||
sim->cpu.operation =
|
|
||||||
OPDEFS_BITSTRING[sim->cpu.code[0] & 31];
|
|
||||||
break;
|
|
||||||
case CPU_FLOATENDO:
|
|
||||||
sim->cpu.operation =
|
|
||||||
OPDEFS_FLOATENDO[sim->cpu.code[1] >> 10];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update state */
|
|
||||||
sim->cpu.step = 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**************************** Instruction Helpers ****************************/
|
/**************************** Instruction Helpers ****************************/
|
||||||
|
|
||||||
/* Parse the immediate 4-bit condition value */
|
|
||||||
static int32_t cpuGetCond(VB *sim) {
|
|
||||||
return sim->cpu.code[0] >> 9 & 15;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Parse the 9-bit displacement value */
|
|
||||||
static int32_t cpuGetDisp9(VB *sim) {
|
|
||||||
return SignExtend(sim->cpu.code[0], 9);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Parse the 26-bit displacement value */
|
|
||||||
static int32_t cpuGetDisp26(VB *sim) {
|
|
||||||
return SignExtend((int32_t) sim->cpu.code[0] << 16 | sim->cpu.code[1], 26);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Parse the immediate 5-bit sign-extended value */
|
|
||||||
static int32_t cpuGetImm5S(VB *sim) {
|
|
||||||
return SignExtend(sim->cpu.code[0], 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Parse the immediate 5-bit zero-filled value */
|
|
||||||
static int32_t cpuGetImm5U(VB *sim) {
|
|
||||||
return sim->cpu.code[0] & 31;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Parse the immediate 16-bit sign-extended value */
|
|
||||||
static int32_t cpuGetImm16S(VB *sim) {
|
|
||||||
return SignExtend(sim->cpu.code[1], 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Parse the immediate 16-bit zero-filled value */
|
|
||||||
static int32_t cpuGetImm16U(VB *sim) {
|
|
||||||
return sim->cpu.code[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Resolve the operand value for reg1 */
|
|
||||||
static int32_t cpuGetReg1(VB *sim) {
|
|
||||||
return sim->cpu.program[sim->cpu.code[0] & 31];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Resolve the operand value for reg2 */
|
|
||||||
static int32_t cpuGetReg2(VB *sim) {
|
|
||||||
return sim->cpu.program[sim->cpu.code[0] >> 5 & 31];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Supply an operand value for reg2 */
|
|
||||||
static void cpuSetReg2(VB *sim, int32_t value) {
|
|
||||||
int reg2 = sim->cpu.code[0] >> 5 & 31;
|
|
||||||
if (reg2 != 0)
|
|
||||||
sim->cpu.program[reg2] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Advance to the next instruction */
|
|
||||||
static void cpuAdvance(VB *sim, uint32_t clocks) {
|
|
||||||
sim->cpu.clocks += clocks;
|
|
||||||
sim->cpu.operation = CPU_FETCH;
|
|
||||||
sim->cpu.nextPC = sim->cpu.pc + (sim->cpu.length << 1);
|
|
||||||
sim->cpu.step = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Interpret floating short bits as word integer bits */
|
|
||||||
static int32_t cpuFloatToWord(float x) {
|
|
||||||
return *(int32_t *) &x;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Raise an exception */
|
|
||||||
static int cpuThrow(VB *sim, uint16_t cause) {
|
|
||||||
sim->cpu.exception = cause;
|
|
||||||
sim->cpu.operation = CPU_EXCEPTION;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Interpret word integer bits as floating short bits */
|
|
||||||
static float cpuWordToFloat(int32_t x) {
|
|
||||||
return *(float *) &x;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Retrieve the value of a system register */
|
/* Retrieve the value of a system register */
|
||||||
static uint32_t cpuGetSystemRegister(VB *sim, int index) {
|
static uint32_t cpuGetSystemRegister(VB *sim, int index) {
|
||||||
switch (index) {
|
switch (index) {
|
||||||
|
@ -528,6 +394,260 @@ static uint32_t cpuSetSystemRegister(VB*sim,
|
||||||
return 0x00000000; /* All others */
|
return 0x00000000; /* All others */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Raise an exception */
|
||||||
|
static void cpuThrow(VB *sim, uint16_t cause) {
|
||||||
|
sim->cpu.exception = cause;
|
||||||
|
sim->cpu.operation = CPU_EXCEPTION;
|
||||||
|
sim->cpu.step = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for an interrupt request */
|
||||||
|
static int cpuIRQ(VB *sim) {
|
||||||
|
int level;
|
||||||
|
if (sim->cpu.psw.id | sim->cpu.psw.ep | sim->cpu.psw.np)
|
||||||
|
return 0;
|
||||||
|
level = IRQ_LEVELS[sim->cpu.irq];
|
||||||
|
if (level > sim->cpu.psw.i)
|
||||||
|
return 0;
|
||||||
|
cpuThrow(sim, 0xFE00 | level << 4);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/****************************** Pipeline Stages ******************************/
|
||||||
|
|
||||||
|
/* Handle an exception */
|
||||||
|
static int cpuException(VB *sim) {
|
||||||
|
uint16_t cause = sim->cpu.exception;
|
||||||
|
|
||||||
|
/* Invoke the exception callback */
|
||||||
|
if (sim->cpu.step == 0 && cpuOnException(sim, &cause))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* Fatal exception */
|
||||||
|
if (sim->cpu.psw.np) {
|
||||||
|
switch (sim->cpu.step) {
|
||||||
|
case 0:
|
||||||
|
auxData.value = 0xFFFF0000 | cause;
|
||||||
|
/* Fallthrough */
|
||||||
|
case 1:
|
||||||
|
if (cpuWrite(sim, 0x00000000, VB_S32, auxData.value)) {
|
||||||
|
sim->cpu.step = 1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
auxData.value = cpuGetSystemRegister(sim, VB_PSW);
|
||||||
|
/* Fallthrough */
|
||||||
|
case 2:
|
||||||
|
if (cpuWrite(sim, 0x00000004, VB_S32, auxData.value)) {
|
||||||
|
sim->cpu.step = 2;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/* Fallthrough */
|
||||||
|
case 3:
|
||||||
|
if (cpuWrite(sim, 0x00000008, VB_S32, sim->cpu.pc)) {
|
||||||
|
sim->cpu.step = 3;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enter fatal halting state */
|
||||||
|
sim->cpu.halt = 1;
|
||||||
|
sim->cpu.operation = CPU_FATAL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Duplexed exception */
|
||||||
|
if (sim->cpu.psw.ep) {
|
||||||
|
sim->cpu.ecr.fecc = cause;
|
||||||
|
sim->cpu.fepsw = cpuGetSystemRegister(sim, VB_PSW);
|
||||||
|
sim->cpu.fepc = sim->cpu.pc;
|
||||||
|
sim->cpu.psw.np = 1;
|
||||||
|
sim->cpu.nextPC = 0xFFFFFFD0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Regular exception */
|
||||||
|
else {
|
||||||
|
|
||||||
|
/* Interrupts only */
|
||||||
|
if ((cause & 0xFF00) == 0xFE00) {
|
||||||
|
sim->cpu.psw.i = (cause >> 4 & 7) + 1;
|
||||||
|
if (sim->cpu.halt) {
|
||||||
|
sim->cpu.halt = 0;
|
||||||
|
sim->cpu.pc += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* All exceptions */
|
||||||
|
sim->cpu.ecr.eicc = cause;
|
||||||
|
sim->cpu.eipsw = cpuGetSystemRegister(sim, VB_PSW);
|
||||||
|
sim->cpu.eipc = sim->cpu.pc;
|
||||||
|
sim->cpu.psw.ep = 1;
|
||||||
|
sim->cpu.nextPC = 0xFFFF0000 |
|
||||||
|
((cause & 0xFFF0) == 0xFF60 ? 0xFF60 : cause & 0xFFF0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* All exceptions */
|
||||||
|
sim->cpu.psw.ae = 0;
|
||||||
|
sim->cpu.psw.id = 1;
|
||||||
|
sim->cpu.operation = CPU_FETCH;
|
||||||
|
/* TODO: Research clocks */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fetch the code bits for the next instruction */
|
||||||
|
static int cpuFetch(VB *sim) {
|
||||||
|
int32_t value;
|
||||||
|
switch (sim->cpu.step) {
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
sim->cpu.pc = sim->cpu.nextPC;
|
||||||
|
if (cpuIRQ(sim))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Fallthrough */
|
||||||
|
case 1:
|
||||||
|
|
||||||
|
/* Retrieve the first code unit */
|
||||||
|
if (cpuReadFetch(sim, 0, sim->cpu.pc, &value)) {
|
||||||
|
sim->cpu.step = 1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update state */
|
||||||
|
sim->cpu.code[0] = value;
|
||||||
|
sim->cpu.length = INST_LENGTHS[value >> 10 & 63];
|
||||||
|
sim->cpu.step = 3 - sim->cpu.length;
|
||||||
|
|
||||||
|
/* Wait any clocks taken */
|
||||||
|
if (sim->cpu.clocks != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Skip fetching a second code unit */
|
||||||
|
if (sim->cpu.length == 1)
|
||||||
|
goto Step3;
|
||||||
|
|
||||||
|
/* Fallthrough */
|
||||||
|
case 2:
|
||||||
|
|
||||||
|
/* Retrieve the second code unit */
|
||||||
|
if (cpuReadFetch(sim, 1, sim->cpu.pc + 2, &value))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* Update state */
|
||||||
|
sim->cpu.code[1] = value;
|
||||||
|
sim->cpu.step = 3;
|
||||||
|
|
||||||
|
/* Wait any clocks taken */
|
||||||
|
if (sim->cpu.clocks != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Fallthrough */
|
||||||
|
case 3: Step3:
|
||||||
|
|
||||||
|
/* Prepare to execute the instruction */
|
||||||
|
if (cpuOnExecute(sim))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* Select operation definition */
|
||||||
|
sim->cpu.operation = OPDEFS[sim->cpu.code[0] >> 10];
|
||||||
|
switch (sim->cpu.operation) {
|
||||||
|
case CPU_BITSTRING:
|
||||||
|
sim->cpu.operation =
|
||||||
|
OPDEFS_BITSTRING[sim->cpu.code[0] & 31];
|
||||||
|
break;
|
||||||
|
case CPU_FLOATENDO:
|
||||||
|
sim->cpu.operation =
|
||||||
|
OPDEFS_FLOATENDO[sim->cpu.code[1] >> 10];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update state */
|
||||||
|
sim->cpu.step = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* HALT instruction is pending */
|
||||||
|
static int cpuHalt(VB *sim) {
|
||||||
|
/* TODO: Research clocks */
|
||||||
|
return !cpuIRQ(sim);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**************************** Instruction Helpers ****************************/
|
||||||
|
|
||||||
|
/* Parse the immediate 4-bit condition value */
|
||||||
|
static int32_t cpuGetCond(VB *sim) {
|
||||||
|
return sim->cpu.code[0] >> 9 & 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse the 9-bit displacement value */
|
||||||
|
static int32_t cpuGetDisp9(VB *sim) {
|
||||||
|
return SignExtend(sim->cpu.code[0], 9);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse the 26-bit displacement value */
|
||||||
|
static int32_t cpuGetDisp26(VB *sim) {
|
||||||
|
return SignExtend((int32_t) sim->cpu.code[0] << 16 | sim->cpu.code[1], 26);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse the immediate 5-bit sign-extended value */
|
||||||
|
static int32_t cpuGetImm5S(VB *sim) {
|
||||||
|
return SignExtend(sim->cpu.code[0], 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse the immediate 5-bit zero-filled value */
|
||||||
|
static int32_t cpuGetImm5U(VB *sim) {
|
||||||
|
return sim->cpu.code[0] & 31;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse the immediate 16-bit sign-extended value */
|
||||||
|
static int32_t cpuGetImm16S(VB *sim) {
|
||||||
|
return SignExtend(sim->cpu.code[1], 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse the immediate 16-bit zero-filled value */
|
||||||
|
static int32_t cpuGetImm16U(VB *sim) {
|
||||||
|
return sim->cpu.code[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Resolve the operand value for reg1 */
|
||||||
|
static int32_t cpuGetReg1(VB *sim) {
|
||||||
|
return sim->cpu.program[sim->cpu.code[0] & 31];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Resolve the operand value for reg2 */
|
||||||
|
static int32_t cpuGetReg2(VB *sim) {
|
||||||
|
return sim->cpu.program[sim->cpu.code[0] >> 5 & 31];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Supply an operand value for reg2 */
|
||||||
|
static void cpuSetReg2(VB *sim, int32_t value) {
|
||||||
|
int reg2 = sim->cpu.code[0] >> 5 & 31;
|
||||||
|
if (reg2 != 0)
|
||||||
|
sim->cpu.program[reg2] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Advance to the next instruction */
|
||||||
|
static void cpuAdvance(VB *sim, uint32_t clocks) {
|
||||||
|
sim->cpu.clocks += clocks;
|
||||||
|
sim->cpu.operation = CPU_FETCH;
|
||||||
|
sim->cpu.nextPC = sim->cpu.pc + (sim->cpu.length << 1);
|
||||||
|
sim->cpu.step = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Interpret floating short bits as word integer bits */
|
||||||
|
static int32_t cpuFloatToWord(float x) {
|
||||||
|
return *(int32_t *) &x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Interpret word integer bits as floating short bits */
|
||||||
|
static float cpuWordToFloat(int32_t x) {
|
||||||
|
return *(float *) &x;
|
||||||
|
}
|
||||||
|
|
||||||
/* Addition common processing */
|
/* Addition common processing */
|
||||||
static int32_t cpuAdd(VB *sim, int32_t a, int32_t b) {
|
static int32_t cpuAdd(VB *sim, int32_t a, int32_t b) {
|
||||||
int32_t c = a + b;
|
int32_t c = a + b;
|
||||||
|
@ -649,7 +769,8 @@ static int32_t cpuShiftLeft(VB *sim, int32_t b) {
|
||||||
/* Logical right shift common processing */
|
/* Logical right shift common processing */
|
||||||
static int32_t cpuShiftRight(VB *sim, int32_t b) {
|
static int32_t cpuShiftRight(VB *sim, int32_t b) {
|
||||||
int32_t a = cpuGetReg2(sim);
|
int32_t a = cpuGetReg2(sim);
|
||||||
int32_t c = a >> b & (uint32_t) 0xFFFFFFFF << (32 - b);
|
int32_t c = b == 0 ? (uint32_t) a :
|
||||||
|
a >> b & ~((uint32_t) 0xFFFFFFFF << (32 - b));
|
||||||
sim->cpu.psw.cy = b == 0 ? 0 : a >> (b - 1) & 1;
|
sim->cpu.psw.cy = b == 0 ? 0 : a >> (b - 1) & 1;
|
||||||
sim->cpu.psw.ov = 0;
|
sim->cpu.psw.ov = 0;
|
||||||
sim->cpu.psw.s = c < 0;
|
sim->cpu.psw.s = c < 0;
|
||||||
|
@ -1087,6 +1208,7 @@ static void cpuMOVHI(VB *sim) {
|
||||||
/* MPYHW */
|
/* MPYHW */
|
||||||
static void cpuMPYHW(VB *sim) {
|
static void cpuMPYHW(VB *sim) {
|
||||||
cpuSetReg2(sim, cpuGetReg2(sim) * SignExtend(cpuGetReg1(sim), 17));
|
cpuSetReg2(sim, cpuGetReg2(sim) * SignExtend(cpuGetReg1(sim), 17));
|
||||||
|
cpuAdvance(sim, cpuClocks(9));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* MUL */
|
/* MUL */
|
||||||
|
@ -1120,14 +1242,14 @@ static void cpuMULF_S(VB *sim) {
|
||||||
|
|
||||||
/* MULU */
|
/* MULU */
|
||||||
static void cpuMULU(VB *sim) {
|
static void cpuMULU(VB *sim) {
|
||||||
uint64_t a = cpuGetReg2(sim);
|
uint64_t a = (uint32_t) cpuGetReg2(sim);
|
||||||
uint64_t b = cpuGetReg1(sim);
|
uint64_t b = (uint32_t) cpuGetReg1(sim);
|
||||||
int64_t c = a * b;
|
uint64_t c = a * b;
|
||||||
int32_t d = c;
|
uint32_t d = c;
|
||||||
sim->cpu.program[30] = c >> 32;
|
sim->cpu.program[30] = c >> 32;
|
||||||
cpuSetReg2(sim, d);
|
cpuSetReg2(sim, d);
|
||||||
sim->cpu.psw.ov = d != c;
|
sim->cpu.psw.ov = d != c;
|
||||||
sim->cpu.psw.s = d < 0;
|
sim->cpu.psw.s = (int32_t) d < 0;
|
||||||
sim->cpu.psw.z = d == 0;
|
sim->cpu.psw.z = d == 0;
|
||||||
cpuAdvance(sim, 13);
|
cpuAdvance(sim, 13);
|
||||||
}
|
}
|
||||||
|
@ -1195,6 +1317,12 @@ static void cpuSARImm(VB *sim) {
|
||||||
cpuAdvance(sim, cpuClocks(1));
|
cpuAdvance(sim, cpuClocks(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* SAR register */
|
||||||
|
static void cpuSARReg(VB *sim) {
|
||||||
|
cpuSetReg2(sim, cpuShiftArithmetic(sim, cpuGetReg1(sim) & 31));
|
||||||
|
cpuAdvance(sim, cpuClocks(1));
|
||||||
|
}
|
||||||
|
|
||||||
/* SEI */
|
/* SEI */
|
||||||
static void cpuSEI(VB *sim) {
|
static void cpuSEI(VB *sim) {
|
||||||
sim->cpu.psw.id = 1;
|
sim->cpu.psw.id = 1;
|
||||||
|
@ -1207,19 +1335,13 @@ static void cpuSETF(VB *sim) {
|
||||||
cpuAdvance(sim, cpuClocks(1));
|
cpuAdvance(sim, cpuClocks(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* SHR register */
|
|
||||||
static void cpuSARReg(VB *sim) {
|
|
||||||
cpuSetReg2(sim, cpuShiftArithmetic(sim, cpuGetReg1(sim) & 31));
|
|
||||||
cpuAdvance(sim, cpuClocks(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* SHL immediate */
|
/* SHL immediate */
|
||||||
static void cpuSHLImm(VB *sim) {
|
static void cpuSHLImm(VB *sim) {
|
||||||
cpuSetReg2(sim, cpuShiftLeft(sim, cpuGetImm5U(sim)));
|
cpuSetReg2(sim, cpuShiftLeft(sim, cpuGetImm5U(sim)));
|
||||||
cpuAdvance(sim, cpuClocks(1));
|
cpuAdvance(sim, cpuClocks(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* SHR register */
|
/* SHL register */
|
||||||
static void cpuSHLReg(VB *sim) {
|
static void cpuSHLReg(VB *sim) {
|
||||||
cpuSetReg2(sim, cpuShiftLeft(sim, cpuGetReg1(sim) & 31));
|
cpuSetReg2(sim, cpuShiftLeft(sim, cpuGetReg1(sim) & 31));
|
||||||
cpuAdvance(sim, cpuClocks(1));
|
cpuAdvance(sim, cpuClocks(1));
|
||||||
|
@ -1282,8 +1404,7 @@ static void cpuSUBF_S(VB *sim) {
|
||||||
/* TRAP */
|
/* TRAP */
|
||||||
static void cpuTRAP(VB *sim) {
|
static void cpuTRAP(VB *sim) {
|
||||||
sim->cpu.clocks += cpuClocks(15);
|
sim->cpu.clocks += cpuClocks(15);
|
||||||
sim->cpu.exception = 0xFFA0 + cpuGetImm5U(sim);
|
cpuThrow(sim, 0xFFA0 + cpuGetImm5U(sim));
|
||||||
sim->cpu.operation = CPU_EXCEPTION;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TRNC.SW */
|
/* TRNC.SW */
|
||||||
|
@ -1361,7 +1482,10 @@ static int cpuEmulate(VB *sim, uint32_t clocks) {
|
||||||
|
|
||||||
/* Processing by operation ID */
|
/* Processing by operation ID */
|
||||||
switch (sim->cpu.operation) {
|
switch (sim->cpu.operation) {
|
||||||
case CPU_FETCH: brk = cpuFetch(sim); break;
|
case CPU_EXCEPTION: brk = cpuException(sim); break;
|
||||||
|
case CPU_FATAL : return 0;
|
||||||
|
case CPU_FETCH : brk = cpuFetch (sim); break;
|
||||||
|
case CPU_HALTING : if (cpuHalt(sim)) return 0; break;
|
||||||
|
|
||||||
case CPU_ADD_IMM: cpuADDImm (sim); break;
|
case CPU_ADD_IMM: cpuADDImm (sim); break;
|
||||||
case CPU_ADD_REG: cpuADDReg (sim); break;
|
case CPU_ADD_REG: cpuADDReg (sim); break;
|
||||||
|
@ -1441,7 +1565,8 @@ static int cpuEmulate(VB *sim, uint32_t clocks) {
|
||||||
|
|
||||||
/* Determine how many clocks are guaranteed to process */
|
/* Determine how many clocks are guaranteed to process */
|
||||||
static uint32_t cpuUntil(VB *sim, uint32_t clocks) {
|
static uint32_t cpuUntil(VB *sim, uint32_t clocks) {
|
||||||
return sim->cpu.clocks < clocks ? sim->cpu.clocks : clocks;
|
return sim->cpu.halt || sim->cpu.clocks > clocks ?
|
||||||
|
clocks : sim->cpu.clocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* VBAPI */
|
#endif /* VBAPI */
|
||||||
|
|
15
core/vb.c
15
core/vb.c
|
@ -75,6 +75,7 @@ struct VB {
|
||||||
uint32_t clocks; /* Master clocks to wait */
|
uint32_t clocks; /* Master clocks to wait */
|
||||||
uint16_t code[2]; /* Instruction code units */
|
uint16_t code[2]; /* Instruction code units */
|
||||||
uint16_t exception; /* Exception cause code */
|
uint16_t exception; /* Exception cause code */
|
||||||
|
int halt; /* CPU is halting */
|
||||||
uint16_t irq; /* Interrupt request lines */
|
uint16_t irq; /* Interrupt request lines */
|
||||||
int length; /* Instruction code length */
|
int length; /* Instruction code length */
|
||||||
uint32_t nextPC; /* Address of next instruction */
|
uint32_t nextPC; /* Address of next instruction */
|
||||||
|
@ -86,6 +87,7 @@ struct VB {
|
||||||
uint8_t wram[0x10000]; /* System RAM */
|
uint8_t wram[0x10000]; /* System RAM */
|
||||||
|
|
||||||
/* Application data */
|
/* Application data */
|
||||||
|
vbOnException onException; /* CPU exception */
|
||||||
vbOnExecute onExecute; /* CPU instruction execute */
|
vbOnExecute onExecute; /* CPU instruction execute */
|
||||||
vbOnFetch onFetch; /* CPU instruction fetch */
|
vbOnFetch onFetch; /* CPU instruction fetch */
|
||||||
vbOnRead onRead; /* CPU instruction read */
|
vbOnRead onRead; /* CPU instruction read */
|
||||||
|
@ -185,6 +187,11 @@ VBAPI void* vbGetCartROM(VB *sim, uint32_t *size) {
|
||||||
return sim->cart.rom;
|
return sim->cart.rom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Retrieve the exception callback handle */
|
||||||
|
VBAPI vbOnException vbGetExceptionCallback(VB *sim) {
|
||||||
|
return sim->onException;
|
||||||
|
}
|
||||||
|
|
||||||
/* Retrieve the execute callback handle */
|
/* Retrieve the execute callback handle */
|
||||||
VBAPI vbOnExecute vbGetExecuteCallback(VB *sim) {
|
VBAPI vbOnExecute vbGetExecuteCallback(VB *sim) {
|
||||||
return sim->onExecute;
|
return sim->onExecute;
|
||||||
|
@ -256,6 +263,7 @@ VBAPI VB* vbReset(VB *sim) {
|
||||||
|
|
||||||
/* CPU (normal) */
|
/* CPU (normal) */
|
||||||
sim->cpu.exception = 0;
|
sim->cpu.exception = 0;
|
||||||
|
sim->cpu.halt = 0;
|
||||||
sim->cpu.irq = 0;
|
sim->cpu.irq = 0;
|
||||||
sim->cpu.pc = 0xFFFFFFF0;
|
sim->cpu.pc = 0xFFFFFFF0;
|
||||||
cpuSetSystemRegister(sim, VB_ECR, 0x0000FFF0, 1);
|
cpuSetSystemRegister(sim, VB_ECR, 0x0000FFF0, 1);
|
||||||
|
@ -304,6 +312,13 @@ VBAPI int vbSetCartROM(VB *sim, void *rom, uint32_t size) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Specify a new exception callback handle */
|
||||||
|
VBAPI vbOnException vbSetExceptionCallback(VB *sim, vbOnException callback) {
|
||||||
|
vbOnException prev = sim->onException;
|
||||||
|
sim->onException = callback;
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
|
||||||
/* Specify a new execute callback handle */
|
/* Specify a new execute callback handle */
|
||||||
VBAPI vbOnExecute vbSetExecuteCallback(VB *sim, vbOnExecute callback) {
|
VBAPI vbOnExecute vbSetExecuteCallback(VB *sim, vbOnExecute callback) {
|
||||||
vbOnExecute prev = sim->onExecute;
|
vbOnExecute prev = sim->onExecute;
|
||||||
|
|
13
core/vb.h
13
core/vb.h
|
@ -52,7 +52,8 @@ extern "C" {
|
||||||
typedef struct VB VB;
|
typedef struct VB VB;
|
||||||
|
|
||||||
/* Callbacks */
|
/* Callbacks */
|
||||||
typedef int (*vbOnExecute)(VB *sim, uint32_t address, const uint16_t *code, int length);
|
typedef int (*vbOnException)(VB *sim, uint16_t *cause);
|
||||||
|
typedef int (*vbOnExecute )(VB *sim, uint32_t address, const uint16_t *code, int length);
|
||||||
typedef int (*vbOnFetch )(VB *sim, int fetch, uint32_t address, int32_t *value, uint32_t *cycles);
|
typedef int (*vbOnFetch )(VB *sim, int fetch, uint32_t address, int32_t *value, uint32_t *cycles);
|
||||||
typedef int (*vbOnRead )(VB *sim, uint32_t address, int type, int32_t *value, uint32_t *cycles);
|
typedef int (*vbOnRead )(VB *sim, uint32_t address, int type, int32_t *value, uint32_t *cycles);
|
||||||
typedef int (*vbOnWrite )(VB *sim, uint32_t address, int type, int32_t *value, uint32_t *cycles, int *cancel);
|
typedef int (*vbOnWrite )(VB *sim, uint32_t address, int type, int32_t *value, uint32_t *cycles, int *cancel);
|
||||||
|
@ -67,10 +68,11 @@ VBAPI int vbEmulateEx (VB **sims, int count, uint32_t *clocks);
|
||||||
VBAPI void* vbGetCallback (VB *sim, int id);
|
VBAPI void* vbGetCallback (VB *sim, int id);
|
||||||
VBAPI void* vbGetCartRAM (VB *sim, uint32_t *size);
|
VBAPI void* vbGetCartRAM (VB *sim, uint32_t *size);
|
||||||
VBAPI void* vbGetCartROM (VB *sim, uint32_t *size);
|
VBAPI void* vbGetCartROM (VB *sim, uint32_t *size);
|
||||||
VBAPI vbOnExecute vbGetExecuteCallback(VB *sim);
|
VBAPI vbOnException vbGetExceptionCallback(VB *sim);
|
||||||
|
VBAPI vbOnExecute vbGetExecuteCallback (VB *sim);
|
||||||
VBAPI vbOnFetch vbGetFetchCallback (VB *sim);
|
VBAPI vbOnFetch vbGetFetchCallback (VB *sim);
|
||||||
VBAPI uint32_t vbGetProgramCounter (VB *sim);
|
VBAPI uint32_t vbGetProgramCounter (VB *sim);
|
||||||
VBAPI int32_t vbGetProgramRegister(VB *sim, int index);
|
VBAPI int32_t vbGetProgramRegister (VB *sim, int index);
|
||||||
VBAPI vbOnRead vbGetReadCallback (VB *sim);
|
VBAPI vbOnRead vbGetReadCallback (VB *sim);
|
||||||
VBAPI uint32_t vbGetSystemRegister (VB *sim, int index);
|
VBAPI uint32_t vbGetSystemRegister (VB *sim, int index);
|
||||||
VBAPI void* vbGetUserData (VB *sim);
|
VBAPI void* vbGetUserData (VB *sim);
|
||||||
|
@ -80,10 +82,11 @@ VBAPI int32_t vbRead (VB *sim, uint32_t address, int type);
|
||||||
VBAPI VB* vbReset (VB *sim);
|
VBAPI VB* vbReset (VB *sim);
|
||||||
VBAPI int vbSetCartRAM (VB *sim, void *sram, uint32_t size);
|
VBAPI int vbSetCartRAM (VB *sim, void *sram, uint32_t size);
|
||||||
VBAPI int vbSetCartROM (VB *sim, void *rom, uint32_t size);
|
VBAPI int vbSetCartROM (VB *sim, void *rom, uint32_t size);
|
||||||
VBAPI vbOnExecute vbSetExecuteCallback(VB *sim, vbOnExecute callback);
|
VBAPI vbOnException vbSetExceptionCallback(VB *sim, vbOnException callback);
|
||||||
|
VBAPI vbOnExecute vbSetExecuteCallback (VB *sim, vbOnExecute callback);
|
||||||
VBAPI vbOnFetch vbSetFetchCallback (VB *sim, vbOnFetch callback);
|
VBAPI vbOnFetch vbSetFetchCallback (VB *sim, vbOnFetch callback);
|
||||||
VBAPI uint32_t vbSetProgramCounter (VB *sim, uint32_t value);
|
VBAPI uint32_t vbSetProgramCounter (VB *sim, uint32_t value);
|
||||||
VBAPI int32_t vbSetProgramRegister(VB *sim, int index, int32_t value);
|
VBAPI int32_t vbSetProgramRegister (VB *sim, int index, int32_t value);
|
||||||
VBAPI vbOnRead vbSetReadCallback (VB *sim, vbOnRead callback);
|
VBAPI vbOnRead vbSetReadCallback (VB *sim, vbOnRead callback);
|
||||||
VBAPI uint32_t vbSetSystemRegister (VB *sim, int index, uint32_t value);
|
VBAPI uint32_t vbSetSystemRegister (VB *sim, int index, uint32_t value);
|
||||||
VBAPI void* vbSetUserData (VB *sim, void *tag);
|
VBAPI void* vbSetUserData (VB *sim, void *tag);
|
||||||
|
|
Loading…
Reference in New Issue