Implementing another 40 CPU instructions
This commit is contained in:
parent
e31a5080c4
commit
2d380460a6
2
makefile
2
makefile
|
@ -10,7 +10,7 @@ default:
|
||||||
@echo
|
@echo
|
||||||
@echo "Planet Virtual Boy Emulator"
|
@echo "Planet Virtual Boy Emulator"
|
||||||
@echo " https://www.planetvb.com/"
|
@echo " https://www.planetvb.com/"
|
||||||
@echo " August 5, 2020"
|
@echo " August 11, 2020"
|
||||||
@echo
|
@echo
|
||||||
@echo "Intended build environment: Debian i386 or amd64"
|
@echo "Intended build environment: Debian i386 or amd64"
|
||||||
@echo " gcc-multilib"
|
@echo " gcc-multilib"
|
||||||
|
|
888
src/core/cpu.c
888
src/core/cpu.c
|
@ -68,27 +68,622 @@ static const int8_t CYCLES[] = {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Instruction Helpers *
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
/* Integer addition */
|
||||||
|
static int32_t cpuAdd(VUE *vue, int left, int right) {
|
||||||
|
int32_t result = left + right;
|
||||||
|
vue->cpu.psw_cy = (uint32_t) result < (uint32_t) left ? 1 : 0;
|
||||||
|
vue->cpu.psw_s = result >> 31 & 1;
|
||||||
|
vue->cpu.psw_ov = (~(left ^ right) & (left ^ result)) >> 31 & 1;
|
||||||
|
vue->cpu.psw_z = result ? 0 : 1;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Bitwise operation */
|
||||||
|
static void cpuBitwise(VUE *vue, int32_t result) {
|
||||||
|
vue->cpu.program[vue->cpu.inst.reg2] = result;
|
||||||
|
vue->cpu.psw_ov = 0;
|
||||||
|
vue->cpu.psw_s = result >> 31 & 1;
|
||||||
|
vue->cpu.psw_z = result ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reinterpret integer bits as a float promoted to double */
|
||||||
|
#define cpuFloat(x) ((double) *(float *)&(x))
|
||||||
|
|
||||||
|
/* Determine whether the floating-point operands are reserved values */
|
||||||
|
static vbool cpuFloatReserved(VUE *vue) {
|
||||||
|
int32_t exponent; /* Operand exponent */
|
||||||
|
int32_t operand; /* Current operand */
|
||||||
|
int x; /* Iterator */
|
||||||
|
|
||||||
|
/* Operands */
|
||||||
|
int32_t operands[2];
|
||||||
|
operands[0] = vue->cpu.program[vue->cpu.inst.reg2];
|
||||||
|
operands[1] = vue->cpu.program[vue->cpu.inst.reg1];
|
||||||
|
|
||||||
|
/* Process both operands */
|
||||||
|
for (x = 0; x < 2; x++) {
|
||||||
|
operand = operands[x];
|
||||||
|
exponent = operand & 0x7F800000;
|
||||||
|
|
||||||
|
/* Check for a reserved operand */
|
||||||
|
if (!(
|
||||||
|
exponent == 0x7F800000 || /* Indefinite */
|
||||||
|
(exponent == 0 && (operand & 0x007FFFFF) != 0) /* Denormal */
|
||||||
|
)) continue;
|
||||||
|
|
||||||
|
/* The value is a reserved operand */
|
||||||
|
vue->cpu.exception.code = 0xFF60;
|
||||||
|
vue->cpu.psw_fro = 1;
|
||||||
|
return VUE_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Neither operand is a reserved value */
|
||||||
|
return VUE_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Floating-point result */
|
||||||
|
static void cpuFloatResult(VUE *vue, double full) {
|
||||||
|
int32_t bits = 0x7F7FFFFF; /* Binary representation of result */
|
||||||
|
float result = *(float *)&bits; /* Operation output */
|
||||||
|
|
||||||
|
/* Overflow */
|
||||||
|
if (full > result || full < -result) {
|
||||||
|
vue->cpu.exception.code = 0xFF64;
|
||||||
|
vue->cpu.psw_fov = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process the result */
|
||||||
|
result = (float) full;
|
||||||
|
bits = *(int32_t *)&result;
|
||||||
|
|
||||||
|
/* Underflow */
|
||||||
|
if ((bits & 0x7F800000) == 0 && (bits & 0x007FFFFF) != 0) {
|
||||||
|
bits = 0;
|
||||||
|
result = 0;
|
||||||
|
vue->cpu.psw_fud = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Precision degradation */
|
||||||
|
if (result != full)
|
||||||
|
vue->cpu.psw_fpr = 1;
|
||||||
|
|
||||||
|
/* Common processing */
|
||||||
|
vue->cpu.program[vue->cpu.inst.reg2] = bits;
|
||||||
|
vue->cpu.psw_cy = vue->cpu.psw_s = bits >> 31 & 1;
|
||||||
|
vue->cpu.psw_ov = 0;
|
||||||
|
vue->cpu.psw_z = bits ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read a system register */
|
||||||
|
static int32_t cpuGetSystemRegister(VUE *vue, int32_t 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 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Perform a bus read */
|
||||||
|
static vbool cpuRead(VUE *vue, int32_t address, int8_t type, int8_t fetch) {
|
||||||
|
|
||||||
|
/* Perform the operation */
|
||||||
|
vue->cpu.access.address = address;
|
||||||
|
vue->cpu.access.fetch = fetch;
|
||||||
|
vue->cpu.access.type = type;
|
||||||
|
vue->cpu.access.value = vueRead(vue, address, type);
|
||||||
|
|
||||||
|
/* There is no application callback */
|
||||||
|
if (vue->onRead == NULL)
|
||||||
|
return VUE_FALSE;
|
||||||
|
|
||||||
|
/* Call the application callback */
|
||||||
|
vue->breakCode = vue->onRead(vue, &vue->cpu.access);
|
||||||
|
return vue->breakCode != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write a system register */
|
||||||
|
static int32_t cpuSetSystemRegister(VUE *vue, int32_t 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 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Arithmetic shift right */
|
||||||
|
static void cpuShiftArithmetic(VUE *vue, int32_t value, int32_t bits) {
|
||||||
|
bits &= 31;
|
||||||
|
|
||||||
|
/* Nothing to do */
|
||||||
|
if (bits == 0)
|
||||||
|
vue->cpu.psw_cy = 0;
|
||||||
|
|
||||||
|
/* Perform the operation */
|
||||||
|
else {
|
||||||
|
vue->cpu.psw_cy = value >> (bits - 1) & 1;
|
||||||
|
value >>= bits;
|
||||||
|
bits = 32 - bits;
|
||||||
|
value = SIGN_EXTEND(bits, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Common processing */
|
||||||
|
cpuBitwise(vue, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Logical shift left */
|
||||||
|
static void cpuShiftLeft(VUE *vue, int32_t value, int32_t bits) {
|
||||||
|
bits &= 31;
|
||||||
|
|
||||||
|
/* Nothing to do */
|
||||||
|
if (bits == 0)
|
||||||
|
vue->cpu.psw_cy = 0;
|
||||||
|
|
||||||
|
/* Perform the operation */
|
||||||
|
else {
|
||||||
|
vue->cpu.psw_cy = value >> (32 - bits) & 1;
|
||||||
|
value <<= bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Commmon processing */
|
||||||
|
cpuBitwise(vue, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Logical shift right */
|
||||||
|
static void cpuShiftRight(VUE *vue, int32_t value, int32_t bits) {
|
||||||
|
bits &= 31;
|
||||||
|
|
||||||
|
/* Nothing to do */
|
||||||
|
if (bits == 0)
|
||||||
|
vue->cpu.psw_cy = 0;
|
||||||
|
|
||||||
|
/* Perform the operation */
|
||||||
|
else {
|
||||||
|
vue->cpu.psw_cy = value >> (bits - 1) & 1;
|
||||||
|
value = value >> bits & ~((uint32_t) 0xFFFFFFFF << (32 - bits));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Commmon processing */
|
||||||
|
cpuBitwise(vue, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Integer subtraction */
|
||||||
|
static int32_t cpuSubtract(VUE *vue, int left, int right) {
|
||||||
|
int32_t result = left - right;
|
||||||
|
vue->cpu.psw_cy = (uint32_t) result > (uint32_t) left ? 1 : 0;
|
||||||
|
vue->cpu.psw_s = result >> 31 & 1;
|
||||||
|
vue->cpu.psw_ov = ((left ^ right) & (left ^ result)) >> 31 & 1;
|
||||||
|
vue->cpu.psw_z = result ? 0 : 1;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test a condition */
|
||||||
|
static int8_t cpuTestCondition(VUE *vue, int32_t 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 cpuTestCondition(vue, condition & 7) ^ 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Perform a bus write */
|
||||||
|
static vbool cpuWrite(VUE *vue, int32_t address, int8_t type, int32_t value) {
|
||||||
|
|
||||||
|
/* Prepare the operation */
|
||||||
|
vue->cpu.access.address = address;
|
||||||
|
vue->cpu.access.fetch = -1;
|
||||||
|
vue->cpu.access.type = type;
|
||||||
|
vue->cpu.access.value = value;
|
||||||
|
|
||||||
|
/* Application callback */
|
||||||
|
if (vue->onWrite != NULL) {
|
||||||
|
vue->breakCode = vue->onWrite(vue, &vue->cpu.access);
|
||||||
|
if (vue->breakCode != 0)
|
||||||
|
return VUE_TRUE;
|
||||||
|
if (vue->cpu.access.type == VUE_CANCEL)
|
||||||
|
return VUE_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Perform the operation */
|
||||||
|
vueWrite(vue, vue->cpu.access.address,
|
||||||
|
vue->cpu.access.type, vue->cpu.access.value);
|
||||||
|
return VUE_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Proxy for IN and LD */
|
||||||
|
#define cpuIN_LD(vue, type) \
|
||||||
|
if (!cpuRead(vue, vue->cpu.program[vue->cpu.inst.reg1] + \
|
||||||
|
vue->cpu.inst.disp, type, -1)) \
|
||||||
|
vue->cpu.program[vue->cpu.inst.reg2] = vue->cpu.access.value
|
||||||
|
|
||||||
|
/* Proxy for OUT and ST */
|
||||||
|
#define cpuOUT_ST(vue, type) \
|
||||||
|
cpuWrite(vue, vue->cpu.program[vue->cpu.inst.reg1] + \
|
||||||
|
vue->cpu.inst.disp, type, vue->cpu.program[vue->cpu.inst.reg2])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Instruction Functions *
|
* Instruction Functions *
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
/* JMP */
|
/* Add Immediate */
|
||||||
static void cpuJMP(VUE *vue) {
|
#define cpuADD_IMM(vue) \
|
||||||
vue->cpu.pc = vue->cpu.program[vue->cpu.inst.reg1] - 2;
|
vue->cpu.program[vue->cpu.inst.reg2] = cpuAdd(vue, \
|
||||||
|
vue->cpu.program[vue->cpu.inst.reg2], vue->cpu.inst.imm)
|
||||||
|
|
||||||
|
/* Add Register */
|
||||||
|
#define cpuADD_REG(vue) \
|
||||||
|
vue->cpu.program[vue->cpu.inst.reg2] = cpuAdd(vue, \
|
||||||
|
vue->cpu.program[vue->cpu.inst.reg2], \
|
||||||
|
vue->cpu.program[vue->cpu.inst.reg1])
|
||||||
|
|
||||||
|
/* Add Floating Short */
|
||||||
|
#define cpuADDF_S(vue) \
|
||||||
|
if (!cpuFloatReserved(vue)) cpuFloatResult(vue, \
|
||||||
|
cpuFloat(vue->cpu.program[vue->cpu.inst.reg2]) + \
|
||||||
|
cpuFloat(vue->cpu.program[vue->cpu.inst.reg1]))
|
||||||
|
|
||||||
|
/* Add Immediate */
|
||||||
|
#define cpuADDI(vue) cpuADD_IMM(vue)
|
||||||
|
|
||||||
|
/* And */
|
||||||
|
#define cpuAND(vue) \
|
||||||
|
cpuBitwise(vue, vue->cpu.program[vue->cpu.inst.reg2] & \
|
||||||
|
vue->cpu.program[vue->cpu.inst.reg1])
|
||||||
|
|
||||||
|
/* And Immediate */
|
||||||
|
#define cpuANDI(vue) \
|
||||||
|
cpuBitwise(vue, vue->cpu.program[vue->cpu.inst.reg2] & \
|
||||||
|
vue->cpu.inst.imm)
|
||||||
|
|
||||||
|
/* Branch on Condition */
|
||||||
|
static void cpuBCOND(VUE *vue) {
|
||||||
|
if (!cpuTestCondition(vue, vue->cpu.inst.cond & 15))
|
||||||
|
return;
|
||||||
|
vue->cpu.pc += vue->cpu.inst.disp - 2;
|
||||||
|
vue->cpu.cycles = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* MOVEA */
|
/* Compare Immediate */
|
||||||
static void cpuMOVEA(VUE *vue) {
|
#define cpuCMP_IMM(vue) \
|
||||||
vue->cpu.program[vue->cpu.inst.reg2] =
|
cpuSubtract(vue, \
|
||||||
vue->cpu.program[vue->cpu.inst.reg1] + vue->cpu.inst.imm;
|
vue->cpu.program[vue->cpu.inst.reg2], vue->cpu.inst.imm)
|
||||||
|
|
||||||
|
/* Compare Register */
|
||||||
|
#define cpuCMP_REG(vue) \
|
||||||
|
cpuSubtract(vue, \
|
||||||
|
vue->cpu.program[vue->cpu.inst.reg2], \
|
||||||
|
vue->cpu.program[vue->cpu.inst.reg1])
|
||||||
|
|
||||||
|
/* Divide */
|
||||||
|
static void cpuDIV(VUE *vue) {
|
||||||
|
int32_t left = vue->cpu.program[vue->cpu.inst.reg2];
|
||||||
|
int32_t right = vue->cpu.program[vue->cpu.inst.reg1];
|
||||||
|
int32_t result;
|
||||||
|
|
||||||
|
/* Zero division */
|
||||||
|
if (right == 0) {
|
||||||
|
vue->cpu.exception.code = 0xFF80;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* MOVHI */
|
/* Special case */
|
||||||
static void cpuMOVHI(VUE *vue) {
|
if ((left == (int32_t) 0x80000000) && (right == (int32_t) 0xFFFFFFFF)) {
|
||||||
vue->cpu.program[vue->cpu.inst.reg2] =
|
vue->cpu.program[30] = 0;
|
||||||
vue->cpu.program[vue->cpu.inst.reg1] + (vue->cpu.inst.imm << 16);
|
vue->cpu.program[vue->cpu.inst.reg2] = 0x80000000;
|
||||||
|
vue->cpu.psw_ov = 1;
|
||||||
|
vue->cpu.psw_s = 1;
|
||||||
|
vue->cpu.psw_z = 0;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Regular case */
|
||||||
|
result = left / right;
|
||||||
|
vue->cpu.program[30] = left % right;
|
||||||
|
vue->cpu.program[vue->cpu.inst.reg2] = result;
|
||||||
|
vue->cpu.psw_ov = 0;
|
||||||
|
vue->cpu.psw_s = result >> 31 & 1;
|
||||||
|
vue->cpu.psw_z = result ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Divide Unsigned */
|
||||||
|
static void cpuDIVU(VUE *vue) {
|
||||||
|
uint32_t left = vue->cpu.program[vue->cpu.inst.reg2];
|
||||||
|
uint32_t right = vue->cpu.program[vue->cpu.inst.reg1];
|
||||||
|
uint32_t result;
|
||||||
|
|
||||||
|
/* Zero division */
|
||||||
|
if (right == 0) {
|
||||||
|
vue->cpu.exception.code = 0xFF80;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Regular case */
|
||||||
|
result = left / right;
|
||||||
|
vue->cpu.program[30] = left % right;
|
||||||
|
vue->cpu.program[vue->cpu.inst.reg2] = result;
|
||||||
|
vue->cpu.psw_ov = 0;
|
||||||
|
vue->cpu.psw_s = result >> 31 & 1;
|
||||||
|
vue->cpu.psw_z = result ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Halt */
|
||||||
|
#define cpuHALT(vue) \
|
||||||
|
vue->cpu.stage = CPU_HALT, vue->cpu.inst.size = 0
|
||||||
|
|
||||||
|
/* Input Byte from Port */
|
||||||
|
#define cpuIN_B(vue) cpuIN_LD(vue, VUE_U8)
|
||||||
|
|
||||||
|
/* Input Halfword from Port */
|
||||||
|
#define cpuIN_H(vue) cpuIN_LD(vue, VUE_U16)
|
||||||
|
|
||||||
|
/* Input Word from Port */
|
||||||
|
#define cpuIN_W(vue) cpuIN_LD(vue, VUE_S32)
|
||||||
|
|
||||||
|
/* Jump and Link */
|
||||||
|
#define cpuJAL(vue) \
|
||||||
|
vue->cpu.program[31] = vue->cpu.pc + 4, \
|
||||||
|
vue->cpu.pc += vue->cpu.inst.disp - 4
|
||||||
|
|
||||||
|
/* Jump Register */
|
||||||
|
#define cpuJMP(vue) \
|
||||||
|
vue->cpu.pc = vue->cpu.program[vue->cpu.inst.reg1] - 2
|
||||||
|
|
||||||
|
/* Jump Relative */
|
||||||
|
#define cpuJR(vue) \
|
||||||
|
vue->cpu.pc += vue->cpu.inst.disp - 4
|
||||||
|
|
||||||
|
/* Load Byte */
|
||||||
|
#define cpuLD_B(vue) cpuIN_LD(vue, VUE_S8)
|
||||||
|
|
||||||
|
/* Load Halfword */
|
||||||
|
#define cpuLD_H(vue) cpuIN_LD(vue, VUE_S16)
|
||||||
|
|
||||||
|
/* Load Word */
|
||||||
|
#define cpuLD_W(vue) cpuIN_LD(vue, VUE_S32)
|
||||||
|
|
||||||
|
/* Load to System Register */
|
||||||
|
#define cpuLDSR(vue) \
|
||||||
|
cpuSetSystemRegister(vue, vue->cpu.inst.imm & 31, \
|
||||||
|
vue->cpu.program[vue->cpu.inst.reg2], VUE_FALSE)
|
||||||
|
|
||||||
|
/* Move Immediate */
|
||||||
|
#define cpuMOV_IMM(vue) \
|
||||||
|
vue->cpu.program[vue->cpu.inst.reg2] = vue->cpu.inst.imm
|
||||||
|
|
||||||
|
/* Move Register */
|
||||||
|
#define cpuMOV_REG(vue) \
|
||||||
|
vue->cpu.program[vue->cpu.inst.reg2] = \
|
||||||
|
vue->cpu.program[vue->cpu.inst.reg1]
|
||||||
|
|
||||||
|
/* Multiply */
|
||||||
|
static void cpuMUL(VUE *vue) {
|
||||||
|
int64_t full = (int64_t) vue->cpu.program[vue->cpu.inst.reg2] *
|
||||||
|
(int64_t) vue->cpu.program[vue->cpu.inst.reg1];
|
||||||
|
int32_t lower = (int32_t) full;
|
||||||
|
vue->cpu.program[30] = (int32_t) (full >> 32);
|
||||||
|
vue->cpu.program[vue->cpu.inst.reg2] = lower;
|
||||||
|
vue->cpu.psw_ov = (int64_t) lower != full ? 1 : 0;
|
||||||
|
vue->cpu.psw_s = lower >> 31 & 1;
|
||||||
|
vue->cpu.psw_z = lower ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Multiply Unsigned */
|
||||||
|
static void cpuMULU(VUE *vue) {
|
||||||
|
uint64_t full = (uint64_t)(uint32_t) vue->cpu.program[vue->cpu.inst.reg2] *
|
||||||
|
(uint64_t)(uint32_t) vue->cpu.program[vue->cpu.inst.reg1];
|
||||||
|
int32_t lower = (int32_t) full;
|
||||||
|
vue->cpu.program[30] = (int32_t) (full >> 32);
|
||||||
|
vue->cpu.program[vue->cpu.inst.reg2] = lower;
|
||||||
|
vue->cpu.psw_ov = full > (uint32_t) 0xFFFFFFFF ? 1 : 0;
|
||||||
|
vue->cpu.psw_s = lower >> 31 & 1;
|
||||||
|
vue->cpu.psw_z = lower ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add */
|
||||||
|
#define cpuMOVEA(vue) \
|
||||||
|
vue->cpu.program[vue->cpu.inst.reg2] = \
|
||||||
|
vue->cpu.program[vue->cpu.inst.reg1] + vue->cpu.inst.imm
|
||||||
|
|
||||||
|
/* Add */
|
||||||
|
#define cpuMOVHI(vue) \
|
||||||
|
vue->cpu.program[vue->cpu.inst.reg2] = \
|
||||||
|
vue->cpu.program[vue->cpu.inst.reg1] + (vue->cpu.inst.imm << 16)
|
||||||
|
|
||||||
|
/* Not */
|
||||||
|
#define cpuNOT(vue) \
|
||||||
|
cpuBitwise(vue, ~vue->cpu.program[vue->cpu.inst.reg1])
|
||||||
|
|
||||||
|
/* Output Byte to Port */
|
||||||
|
#define cpuOUT_B(vue) cpuOUT_ST(vue, VUE_U8)
|
||||||
|
|
||||||
|
/* Output Halfword to Port */
|
||||||
|
#define cpuOUT_H(vue) cpuOUT_ST(vue, VUE_U16)
|
||||||
|
|
||||||
|
/* Output Word to Port */
|
||||||
|
#define cpuOUT_W(vue) cpuOUT_ST(vue, VUE_S32)
|
||||||
|
|
||||||
|
/* Or */
|
||||||
|
#define cpuOR(vue) \
|
||||||
|
cpuBitwise(vue, vue->cpu.program[vue->cpu.inst.reg2] | \
|
||||||
|
vue->cpu.program[vue->cpu.inst.reg1])
|
||||||
|
|
||||||
|
/* Or Immediate */
|
||||||
|
#define cpuORI(vue) \
|
||||||
|
cpuBitwise(vue, vue->cpu.program[vue->cpu.inst.reg2] | \
|
||||||
|
vue->cpu.inst.imm)
|
||||||
|
|
||||||
|
/* Return from Trap or Interrupt */
|
||||||
|
static void cpuRETI(VUE *vue) {
|
||||||
|
if (vue->cpu.psw_np) {
|
||||||
|
vue->cpu.pc = vue->cpu.fepc;
|
||||||
|
cpuSetSystemRegister(vue, VUE_PSW, vue->cpu.fepsw, VUE_FALSE);
|
||||||
|
} else {
|
||||||
|
vue->cpu.pc = vue->cpu.eipc;
|
||||||
|
cpuSetSystemRegister(vue, VUE_PSW, vue->cpu.eipsw, VUE_FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shift Arithmetic Right by Immediate */
|
||||||
|
#define cpuSAR_IMM(vue) \
|
||||||
|
cpuShiftArithmetic(vue, vue->cpu.program[vue->cpu.inst.reg2], \
|
||||||
|
vue->cpu.inst.imm)
|
||||||
|
|
||||||
|
/* Shift Arithmetic Right by Register */
|
||||||
|
#define cpuSAR_REG(vue) \
|
||||||
|
cpuShiftArithmetic(vue, vue->cpu.program[vue->cpu.inst.reg2], \
|
||||||
|
vue->cpu.program[vue->cpu.inst.reg1])
|
||||||
|
|
||||||
|
/* Shift Logical Left by Immediate */
|
||||||
|
#define cpuSHL_IMM(vue) \
|
||||||
|
cpuShiftLeft(vue, vue->cpu.program[vue->cpu.inst.reg2], \
|
||||||
|
vue->cpu.inst.imm)
|
||||||
|
|
||||||
|
/* Shift Logical Left by Register */
|
||||||
|
#define cpuSHL_REG(vue) \
|
||||||
|
cpuShiftLeft(vue, vue->cpu.program[vue->cpu.inst.reg2], \
|
||||||
|
vue->cpu.program[vue->cpu.inst.reg1])
|
||||||
|
|
||||||
|
/* Shift Logical Right by Immediate */
|
||||||
|
#define cpuSHR_IMM(vue) \
|
||||||
|
cpuShiftRight(vue, vue->cpu.program[vue->cpu.inst.reg2], \
|
||||||
|
vue->cpu.inst.imm)
|
||||||
|
|
||||||
|
/* Shift Logical Right by Register */
|
||||||
|
#define cpuSHR_REG(vue) \
|
||||||
|
cpuShiftRight(vue, vue->cpu.program[vue->cpu.inst.reg2], \
|
||||||
|
vue->cpu.program[vue->cpu.inst.reg1])
|
||||||
|
|
||||||
|
/* Store Byte */
|
||||||
|
#define cpuST_B(vue) cpuOUT_ST(vue, VUE_S8)
|
||||||
|
|
||||||
|
/* Store Halfword */
|
||||||
|
#define cpuST_H(vue) cpuOUT_ST(vue, VUE_S16)
|
||||||
|
|
||||||
|
/* Store Word */
|
||||||
|
#define cpuST_W(vue) cpuOUT_ST(vue, VUE_S32)
|
||||||
|
|
||||||
|
/* Store Contents of System Register */
|
||||||
|
#define cpuSTSR(vue) \
|
||||||
|
vue->cpu.program[vue->cpu.inst.reg2] = \
|
||||||
|
cpuGetSystemRegister(vue, vue->cpu.inst.imm & 31)
|
||||||
|
|
||||||
|
/* Subtract */
|
||||||
|
#define cpuSUB(vue) \
|
||||||
|
vue->cpu.program[vue->cpu.inst.reg2] = cpuSubtract(vue, \
|
||||||
|
vue->cpu.program[vue->cpu.inst.reg2], \
|
||||||
|
vue->cpu.program[vue->cpu.inst.reg1])
|
||||||
|
|
||||||
|
/* Trap */
|
||||||
|
#define cpuTRAP(vue) \
|
||||||
|
vue->cpu.exception.code = 0xFFA0 | (vue->cpu.inst.imm & 15), \
|
||||||
|
vue->cpu.pc += 2
|
||||||
|
|
||||||
|
/* Exclusive Or */
|
||||||
|
#define cpuXOR(vue) \
|
||||||
|
cpuBitwise(vue, vue->cpu.program[vue->cpu.inst.reg2] ^ \
|
||||||
|
vue->cpu.program[vue->cpu.inst.reg1])
|
||||||
|
|
||||||
|
/* Exclusive Or Immediate */
|
||||||
|
#define cpuXORI(vue) \
|
||||||
|
cpuBitwise(vue, vue->cpu.program[vue->cpu.inst.reg2] ^ \
|
||||||
|
vue->cpu.inst.imm)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
@ -185,97 +780,97 @@ static vbool cpuExecute(VUE *vue) {
|
||||||
vue->breakCode = vue->onExecute(vue, &vue->cpu.inst);
|
vue->breakCode = vue->onExecute(vue, &vue->cpu.inst);
|
||||||
if (vue->breakCode != 0)
|
if (vue->breakCode != 0)
|
||||||
return VUE_TRUE;
|
return VUE_TRUE;
|
||||||
|
vue->cpu.inst.reg1 &= 31;
|
||||||
|
vue->cpu.inst.reg2 &= 31;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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 */
|
/* Processing by instruction ID */
|
||||||
switch (vue->cpu.inst.id) {
|
switch (vue->cpu.inst.id) {
|
||||||
/*case VUE_ADD_IMM: cpuADD_IMM(vue); break;*/
|
case VUE_ADD_IMM: cpuADD_IMM(vue); break;
|
||||||
/*case VUE_ADD_REG: cpuADD_REG(vue); break;*/
|
case VUE_ADD_REG: cpuADD_REG(vue); break;
|
||||||
/*case VUE_ADDF_S : cpuADDF_S (vue); break;*/
|
case VUE_ADDF_S : cpuADDF_S (vue); break;
|
||||||
/*case VUE_ADDI : cpuADDI (vue); break;*/
|
case VUE_ADDI : cpuADDI (vue); break;
|
||||||
/*case VUE_AND : cpuAND (vue); break;*/
|
case VUE_AND : cpuAND (vue); break;
|
||||||
/*case VUE_ANDBSU : cpuANDBSU (vue); break;*/
|
/*case VUE_ANDBSU : cpuANDBSU (vue); break;*/
|
||||||
/*case VUE_ANDI : cpuANDI (vue); break;*/
|
case VUE_ANDI : cpuANDI (vue); break;
|
||||||
/*case VUE_ANDNBSU: cpuANDNBSU(vue); break;*/
|
/*case VUE_ANDNBSU: cpuANDNBSU(vue); break;*/
|
||||||
/*case VUE_BCOND : cpuBCOND (vue); break;*/
|
case VUE_BCOND : cpuBCOND (vue); break;
|
||||||
/*case VUE_CAXI : cpuCAXI (vue); break;*/
|
/*case VUE_CAXI : cpuCAXI (vue); break;*/
|
||||||
/*case VUE_CLI : cpuCLI (vue); break;*/
|
/*case VUE_CLI : cpuCLI (vue); break;*/
|
||||||
/*case VUE_CMP_IMM: cpuCMP_IMM(vue); break;*/
|
case VUE_CMP_IMM: cpuCMP_IMM(vue); break;
|
||||||
/*case VUE_CMP_REG: cpuCMP_REG(vue); break;*/
|
case VUE_CMP_REG: cpuCMP_REG(vue); break;
|
||||||
/*case VUE_CMPF_S : cpuCMPF_S (vue); break;*/
|
/*case VUE_CMPF_S : cpuCMPF_S (vue); break;*/
|
||||||
/*case VUE_CVT_SW : cpuCVT_SW (vue); break;*/
|
/*case VUE_CVT_SW : cpuCVT_SW (vue); break;*/
|
||||||
/*case VUE_CVT_WS : cpuCVT_WS (vue); break;*/
|
/*case VUE_CVT_WS : cpuCVT_WS (vue); break;*/
|
||||||
/*case VUE_DIV : cpuDIV (vue); break;*/
|
case VUE_DIV : cpuDIV (vue); break;
|
||||||
/*case VUE_DIVF_S : cpuDIVF_S (vue); break;*/
|
/*case VUE_DIVF_S : cpuDIVF_S (vue); break;*/
|
||||||
/*case VUE_DIVU : cpuDIVU (vue); break;*/
|
case VUE_DIVU : cpuDIVU (vue); break;
|
||||||
/*case VUE_HALT : cpuHALT (vue); break;*/
|
case VUE_HALT : cpuHALT (vue); break;
|
||||||
/*case VUE_IN_B : cpuIN_B (vue); break;*/
|
case VUE_IN_B : cpuIN_B (vue); break;
|
||||||
/*case VUE_IN_H : cpuIN_H (vue); break;*/
|
case VUE_IN_H : cpuIN_H (vue); break;
|
||||||
/*case VUE_IN_W : cpuIN_W (vue); break;*/
|
case VUE_IN_W : cpuIN_W (vue); break;
|
||||||
/*case VUE_JAL : cpuJAL (vue); break;*/
|
case VUE_JAL : cpuJAL (vue); break;
|
||||||
case VUE_JMP : cpuJMP (vue); break;
|
case VUE_JMP : cpuJMP (vue); break;
|
||||||
/*case VUE.JR : cpuJR (vue); break;*/
|
case VUE_JR : cpuJR (vue); break;
|
||||||
/*case VUE.LD_B : cpuLD_B (vue); break;*/
|
case VUE_LD_B : cpuLD_B (vue); break;
|
||||||
/*case VUE.LD_H : cpuLD_H (vue); break;*/
|
case VUE_LD_H : cpuLD_H (vue); break;
|
||||||
/*case VUE.LD_W : cpuLD_W (vue); break;*/
|
case VUE_LD_W : cpuLD_W (vue); break;
|
||||||
/*case VUE.LDSR : cpuLDSR (vue); break;*/
|
case VUE_LDSR : cpuLDSR (vue); break;
|
||||||
/*case VUE.MOV_IMM: cpuMOV_IMM(vue); break;*/
|
case VUE_MOV_IMM: cpuMOV_IMM(vue); break;
|
||||||
/*case VUE.MOV_REG: cpuMOV_REG(vue); break;*/
|
case VUE_MOV_REG: cpuMOV_REG(vue); break;
|
||||||
/*case VUE.MOVBSU : cpuMOVBSU (vue); break;*/
|
/*case VUE_MOVBSU : cpuMOVBSU (vue); break;*/
|
||||||
case VUE_MOVEA : cpuMOVEA (vue); break;
|
case VUE_MOVEA : cpuMOVEA (vue); break;
|
||||||
case VUE_MOVHI : cpuMOVHI (vue); break;
|
case VUE_MOVHI : cpuMOVHI (vue); break;
|
||||||
/*case VUE.MPYHW : cpuMPYHW (vue); break;*/
|
/*case VUE_MPYHW : cpuMPYHW (vue); break;*/
|
||||||
/*case VUE.MUL : cpuMUL (vue); break;*/
|
case VUE_MUL : cpuMUL (vue); break;
|
||||||
/*case VUE.MULF_S : cpuMULF_S (vue); break;*/
|
/*case VUE_MULF_S : cpuMULF_S (vue); break;*/
|
||||||
/*case VUE.MULU : cpuMULU (vue); break;*/
|
case VUE_MULU : cpuMULU (vue); break;
|
||||||
/*case VUE.NOT : cpuNOT (vue); break;*/
|
case VUE_NOT : cpuNOT (vue); break;
|
||||||
/*case VUE.NOTBSU : cpuNOTBSU (vue); break;*/
|
/*case VUE_NOTBSU : cpuNOTBSU (vue); break;*/
|
||||||
/*case VUE.OR : cpuOR (vue); break;*/
|
case VUE_OR : cpuOR (vue); break;
|
||||||
/*case VUE.ORBSU : cpuORBSU (vue); break;*/
|
/*case VUE_ORBSU : cpuORBSU (vue); break;*/
|
||||||
/*case VUE.ORI : cpuORI (vue); break;*/
|
case VUE_ORI : cpuORI (vue); break;
|
||||||
/*case VUE.ORNBSU : cpuORNBSU (vue); break;*/
|
/*case VUE_ORNBSU : cpuORNBSU (vue); break;*/
|
||||||
/*case VUE.OUT_B : cpuOUT_B (vue); break;*/
|
case VUE_OUT_B : cpuOUT_B (vue); break;
|
||||||
/*case VUE.OUT_H : cpuOUT_H (vue); break;*/
|
case VUE_OUT_H : cpuOUT_H (vue); break;
|
||||||
/*case VUE.OUT_W : cpuOUT_W (vue); break;*/
|
case VUE_OUT_W : cpuOUT_W (vue); break;
|
||||||
/*case VUE.RETI : cpuRETI (vue); break;*/
|
case VUE_RETI : cpuRETI (vue); break;
|
||||||
/*case VUE.REV : cpuREV (vue); break;*/
|
/*case VUE_REV : cpuREV (vue); break;*/
|
||||||
/*case VUE.SAR_IMM: cpuSAR_IMM(vue); break;*/
|
case VUE_SAR_IMM: cpuSAR_IMM(vue); break;
|
||||||
/*case VUE.SAR_REG: cpuSAR_REG(vue); break;*/
|
case VUE_SAR_REG: cpuSAR_REG(vue); break;
|
||||||
/*case VUE.SCH0BSD: cpuSCH0BSD(vue); break;*/
|
/*case VUE_SCH0BSD: cpuSCH0BSD(vue); break;*/
|
||||||
/*case VUE.SCH0BSU: cpuSCH0BSU(vue); break;*/
|
/*case VUE_SCH0BSU: cpuSCH0BSU(vue); break;*/
|
||||||
/*case VUE.SCH1BSD: cpuSCH1BSD(vue); break;*/
|
/*case VUE_SCH1BSD: cpuSCH1BSD(vue); break;*/
|
||||||
/*case VUE.SCH1BSU: cpuSCH1BSU(vue); break;*/
|
/*case VUE_SCH1BSU: cpuSCH1BSU(vue); break;*/
|
||||||
/*case VUE.SEI : cpuSEI (vue); break;*/
|
/*case VUE_SEI : cpuSEI (vue); break;*/
|
||||||
/*case VUE.SETF : cpuSETF (vue); break;*/
|
/*case VUE_SETF : cpuSETF (vue); break;*/
|
||||||
/*case VUE.SHL_IMM: cpuSHL_IMM(vue); break;*/
|
case VUE_SHL_IMM: cpuSHL_IMM(vue); break;
|
||||||
/*case VUE.SHL_REG: cpuSHL_REG(vue); break;*/
|
case VUE_SHL_REG: cpuSHL_REG(vue); break;
|
||||||
/*case VUE.SHR_IMM: cpuSHR_IMM(vue); break;*/
|
case VUE_SHR_IMM: cpuSHR_IMM(vue); break;
|
||||||
/*case VUE.SHR_REG: cpuSHR_REG(vue); break;*/
|
case VUE_SHR_REG: cpuSHR_REG(vue); break;
|
||||||
/*case VUE.ST_B : cpuST_B (vue); break;*/
|
case VUE_ST_B : cpuST_B (vue); break;
|
||||||
/*case VUE.ST_H : cpuST_H (vue); break;*/
|
case VUE_ST_H : cpuST_H (vue); break;
|
||||||
/*case VUE.ST_W : cpuST_W (vue); break;*/
|
case VUE_ST_W : cpuST_W (vue); break;
|
||||||
/*case VUE.STSR : cpuSTSR (vue); break;*/
|
case VUE_STSR : cpuSTSR (vue); break;
|
||||||
/*case VUE.SUB : cpuSUB (vue); break;*/
|
case VUE_SUB : cpuSUB (vue); break;
|
||||||
/*case VUE.SUBF_S : cpuSUBF_S (vue); break;*/
|
/*case VUE_SUBF_S : cpuSUBF_S (vue); break;*/
|
||||||
/*case VUE.TRAP : cpuTRAP (vue); break;*/
|
case VUE_TRAP : cpuTRAP (vue); break;
|
||||||
/*case VUE.TRNC_SW: cpuTRNC_SW(vue); break;*/
|
/*case VUE_TRNC_SW: cpuTRNC_SW(vue); break;*/
|
||||||
/*case VUE.XB : cpuXB (vue); break;*/
|
/*case VUE_XB : cpuXB (vue); break;*/
|
||||||
/*case VUE.XH : cpuXH (vue); break;*/
|
/*case VUE_XH : cpuXH (vue); break;*/
|
||||||
/*case VUE.XOR : cpuXOR (vue); break;*/
|
case VUE_XOR : cpuXOR (vue); break;
|
||||||
/*case VUE.XORBSU : cpuXORBSU (vue); break;*/
|
/*case VUE_XORBSU : cpuXORBSU (vue); break;*/
|
||||||
/*case VUE.XORI : cpuXORI (vue); break;*/
|
case VUE_XORI : cpuXORI (vue); break;
|
||||||
/*case VUE.XORNBSU: cpuXORNBSU(vue); break;*/
|
/*case VUE_XORNBSU: cpuXORNBSU(vue); break;*/
|
||||||
default: /* Invalid instruction */
|
default: /* Invalid instruction */
|
||||||
vue->cpu.exception.code = 0xFF90;
|
vue->cpu.exception.code = 0xFF90;
|
||||||
vue->cpu.inst.size = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Common processing */
|
/* Common processing */
|
||||||
|
if (vue->cpu.exception.code == 0) {
|
||||||
|
vue->cpu.cycles += CYCLES[vue->cpu.inst.id];
|
||||||
vue->cpu.pc += vue->cpu.inst.size;
|
vue->cpu.pc += vue->cpu.inst.size;
|
||||||
|
}
|
||||||
vue->cpu.program[0] = 0;
|
vue->cpu.program[0] = 0;
|
||||||
cpuTestException(vue);
|
cpuTestException(vue);
|
||||||
if (vue->cpu.stage == CPU_EXECUTE)
|
if (vue->cpu.stage == CPU_EXECUTE)
|
||||||
|
@ -293,17 +888,9 @@ static int32_t cpuSize(int32_t opcode) {
|
||||||
static vbool cpuFetch(VUE *vue) {
|
static vbool cpuFetch(VUE *vue) {
|
||||||
|
|
||||||
/* Read the bits from the bus */
|
/* Read the bits from the bus */
|
||||||
vue->cpu.access.address = vue->cpu.pc + (vue->cpu.fetch << 1);
|
if (cpuRead(vue, vue->cpu.pc + (vue->cpu.fetch << 1),
|
||||||
vue->cpu.access.fetch = vue->cpu.fetch;
|
VUE_U16, 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;
|
return VUE_TRUE;
|
||||||
}
|
|
||||||
|
|
||||||
/* First unit */
|
/* First unit */
|
||||||
if (vue->cpu.fetch == 0) {
|
if (vue->cpu.fetch == 0) {
|
||||||
|
@ -326,41 +913,6 @@ static vbool cpuFetch(VUE *vue) {
|
||||||
return VUE_FALSE;
|
return VUE_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read a system register */
|
|
||||||
static int32_t cpuGetSystemRegister(VUE *vue, int32_t 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 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Operations for exception stage */
|
/* Operations for exception stage */
|
||||||
static vbool cpuException(VUE *vue) {
|
static vbool cpuException(VUE *vue) {
|
||||||
vbool isIRQ; /* The exception is an interrupt */
|
vbool isIRQ; /* The exception is an interrupt */
|
||||||
|
@ -411,6 +963,8 @@ static vbool cpuException(VUE *vue) {
|
||||||
if (isIRQ) {
|
if (isIRQ) {
|
||||||
psw = vue->cpu.exception.code >> 4 & 15;
|
psw = vue->cpu.exception.code >> 4 & 15;
|
||||||
vue->cpu.psw_i = psw < 15 ? psw : 15;
|
vue->cpu.psw_i = psw < 15 ? psw : 15;
|
||||||
|
if (vue->cpu.stage == CPU_HALT)
|
||||||
|
vue->cpu.pc += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Common processing */
|
/* Common processing */
|
||||||
|
@ -452,73 +1006,6 @@ vue->cpu.cycles = 0; /* DEBUG: Stop processing after execute */
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write a system register */
|
|
||||||
static int32_t cpuSetSystemRegister(VUE *vue, int32_t 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 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* System reset */
|
/* System reset */
|
||||||
static void cpuReset(VUE *vue) {
|
static void cpuReset(VUE *vue) {
|
||||||
int32_t x;
|
int32_t x;
|
||||||
|
@ -546,21 +1033,6 @@ static void cpuReset(VUE *vue) {
|
||||||
vue->cpu.psw_np = 1;
|
vue->cpu.psw_np = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Test a condition */
|
|
||||||
static int8_t cpuTestCondition(VUE *vue, int32_t 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 cpuTestCondition(vue, condition & 7) ^ 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Determine the number of CPU cycles until something can happen */
|
/* Determine the number of CPU cycles until something can happen */
|
||||||
static int32_t cpuUntil(VUE *vue, int32_t cycles) {
|
static int32_t cpuUntil(VUE *vue, int32_t cycles) {
|
||||||
if (vue->cpu.stage == CPU_FATAL || vue->cpu.stage == CPU_HALT)
|
if (vue->cpu.stage == CPU_FATAL || vue->cpu.stage == CPU_HALT)
|
||||||
|
|
|
@ -29,6 +29,7 @@ extern "C" {
|
||||||
#define VUE_S16 2
|
#define VUE_S16 2
|
||||||
#define VUE_U16 3
|
#define VUE_U16 3
|
||||||
#define VUE_S32 4
|
#define VUE_S32 4
|
||||||
|
#define VUE_CANCEL 5
|
||||||
|
|
||||||
/* System register indexes */
|
/* System register indexes */
|
||||||
#define VUE_ADTRE 25
|
#define VUE_ADTRE 25
|
||||||
|
|
|
@ -112,8 +112,19 @@ static void writeBuffer(uint8_t *data, uint32_t datlen, uint32_t address,
|
||||||
/* Common processing */
|
/* Common processing */
|
||||||
address &= (~size + 1) & (datlen - 1);
|
address &= (~size + 1) & (datlen - 1);
|
||||||
|
|
||||||
/* The host is little-endian */
|
/* The host is big-endian */
|
||||||
#ifndef VUE_BIGENDIAN
|
#ifdef VUE_BIGENDIAN
|
||||||
|
switch (type) {
|
||||||
|
case VUE_S32:
|
||||||
|
value = (value & 0xFFFF0000) >> 16 | value << 16;
|
||||||
|
/* Fallthrough */
|
||||||
|
case VUE_S16: /* Fallthrough */
|
||||||
|
case VUE_U16:
|
||||||
|
value = (value & 0xFF00FF00) >> 8 | (value & 0x00FF00FF) << 8;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Processing by data type */
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case VUE_S8 : /* Fallthrough */
|
case VUE_S8 : /* Fallthrough */
|
||||||
case VUE_U8 : *(int8_t *)&data[address] = (int8_t ) value; break;
|
case VUE_U8 : *(int8_t *)&data[address] = (int8_t ) value; break;
|
||||||
|
@ -122,22 +133,6 @@ static void writeBuffer(uint8_t *data, uint32_t datlen, uint32_t address,
|
||||||
case VUE_S32: *(int32_t *)&data[address] = (int32_t ) value; break;
|
case VUE_S32: *(int32_t *)&data[address] = (int32_t ) value; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The host is big-endian */
|
|
||||||
#else
|
|
||||||
switch (type) {
|
|
||||||
case VUE_S32:
|
|
||||||
data[address + 3] = (uint8_t) (value >> 24);
|
|
||||||
data[address + 2] = (uint8_t) (value >> 16);
|
|
||||||
/* Fallthrough */
|
|
||||||
case VUE_S16: /* Fallthrough */
|
|
||||||
case VUE_U16:
|
|
||||||
data[address + 1] = (uint8_t) (value >> 8);
|
|
||||||
/* Fallthrough */
|
|
||||||
case VUE_S8 : /* Fallthrough */
|
|
||||||
case VUE_U8 : value |=
|
|
||||||
data[address ] = (uint8_t) value;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write bytes to a byte buffer */
|
/* Write bytes to a byte buffer */
|
||||||
|
|
|
@ -256,21 +256,6 @@ this.cycles = 0; // DEBUG: Stop processing after execute
|
||||||
return 1; // Unreachable
|
return 1; // Unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test a condition
|
|
||||||
int test(int condition) {
|
|
||||||
switch (condition) {
|
|
||||||
case 0: return psw_ov;
|
|
||||||
case 1: return psw_cy;
|
|
||||||
case 2: return psw_z;
|
|
||||||
case 3: return psw_cy | psw_z;
|
|
||||||
case 4: return psw_s;
|
|
||||||
case 5: return 1;
|
|
||||||
case 6: return psw_ov | psw_s;
|
|
||||||
case 7: return psw_ov ^ psw_s | psw_z;
|
|
||||||
}
|
|
||||||
return test(condition & 7) ^ 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine the number of CPU cycles until something can happen
|
// Determine the number of CPU cycles until something can happen
|
||||||
int until(int cycles) {
|
int until(int cycles) {
|
||||||
if (stage == FATAL || stage == HALT)
|
if (stage == FATAL || stage == HALT)
|
||||||
|
@ -294,8 +279,6 @@ this.cycles = 0; // DEBUG: Stop processing after execute
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
System.out.printf("Exception %04X %d %d\n", exception.code, psw_ep, psw_np);
|
|
||||||
|
|
||||||
// Configure working variables
|
// Configure working variables
|
||||||
exception.code &= 0xFFFF;
|
exception.code &= 0xFFFF;
|
||||||
boolean isIRQ = (exception.code & 0xFF00) == 0xFE00;
|
boolean isIRQ = (exception.code & 0xFF00) == 0xFE00;
|
||||||
|
@ -331,8 +314,11 @@ System.out.printf("Exception %04X %d %d\n", exception.code, psw_ep, psw_np);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interrupt
|
// Interrupt
|
||||||
if (isIRQ)
|
if (isIRQ) {
|
||||||
psw_i = Math.min(15, exception.code >> 4 & 15);
|
psw_i = Math.min(15, exception.code >> 4 & 15);
|
||||||
|
if (stage == HALT)
|
||||||
|
pc += 2;
|
||||||
|
}
|
||||||
|
|
||||||
// Common processing
|
// Common processing
|
||||||
cycles = 0; // TODO: Determine the actual number
|
cycles = 0; // TODO: Determine the actual number
|
||||||
|
@ -353,63 +339,57 @@ System.out.printf("Exception %04X %d %d\n", exception.code, psw_ep, psw_np);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
System.out.printf("Execute %08X %d\n", pc, inst.id);
|
|
||||||
|
|
||||||
// Determine the default number of cycles for the instruction
|
|
||||||
if (inst.id >= 0 && inst.id <= 75)
|
|
||||||
cycles = CYCLES[inst.id];
|
|
||||||
|
|
||||||
// Processing by instruction ID
|
// Processing by instruction ID
|
||||||
switch (inst.id) {
|
switch (inst.id) {
|
||||||
//case VUE.ADD_IMM: ADD_IMM(); break;
|
case VUE.ADD_IMM: ADD_IMM(); break;
|
||||||
//case VUE.ADD_REG: ADD_REG(); break;
|
case VUE.ADD_REG: ADD_REG(); break;
|
||||||
//case VUE.ADDF_S : ADDF_S (); break;
|
case VUE.ADDF_S : ADDF_S (); break;
|
||||||
//case VUE.ADDI : ADDI (); break;
|
case VUE.ADDI : ADDI (); break;
|
||||||
//case VUE.AND : AND (); break;
|
case VUE.AND : AND (); break;
|
||||||
//case VUE.ANDBSU : ANDBSU (); break;
|
//case VUE.ANDBSU : ANDBSU (); break;
|
||||||
//case VUE.ANDI : ANDI (); break;
|
case VUE.ANDI : ANDI (); break;
|
||||||
//case VUE.ANDNBSU: ANDNBSU(); break;
|
//case VUE.ANDNBSU: ANDNBSU(); break;
|
||||||
//case VUE.BCOND : BCOND (); break;
|
case VUE.BCOND : BCOND (); break;
|
||||||
//case VUE.CAXI : CAXI (); break;
|
//case VUE.CAXI : CAXI (); break;
|
||||||
//case VUE.CLI : CLI (); break;
|
//case VUE.CLI : CLI (); break;
|
||||||
//case VUE.CMP_IMM: CMP_IMM(); break;
|
case VUE.CMP_IMM: CMP_IMM(); break;
|
||||||
//case VUE.CMP_REG: CMP_REG(); break;
|
case VUE.CMP_REG: CMP_REG(); break;
|
||||||
//case VUE.CMPF_S : CMPF_S (); break;
|
//case VUE.CMPF_S : CMPF_S (); break;
|
||||||
//case VUE.CVT_SW : CVT_SW (); break;
|
//case VUE.CVT_SW : CVT_SW (); break;
|
||||||
//case VUE.CVT_WS : CVT_WS (); break;
|
//case VUE.CVT_WS : CVT_WS (); break;
|
||||||
//case VUE.DIV : DIV (); break;
|
case VUE.DIV : DIV (); break;
|
||||||
//case VUE.DIVF_S : DIVF_S (); break;
|
//case VUE.DIVF_S : DIVF_S (); break;
|
||||||
//case VUE.DIVU : DIVU (); break;
|
case VUE.DIVU : DIVU (); break;
|
||||||
//case VUE.HALT : HALT (); break;
|
case VUE.HALT : HALT (); break;
|
||||||
//case VUE.IN_B : IN_B (); break;
|
case VUE.IN_B : IN_B (); break;
|
||||||
//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;
|
||||||
//case VUE.LD_W : LD_W (); break;
|
case VUE.LD_W : LD_W (); break;
|
||||||
//case VUE.LDSR : LDSR (); break;
|
case VUE.LDSR : LDSR (); break;
|
||||||
//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;
|
||||||
//case VUE.MULU : MULU (); break;
|
case VUE.MULU : MULU (); break;
|
||||||
//case VUE.NOT : NOT (); break;
|
case VUE.NOT : NOT (); break;
|
||||||
//case VUE.NOTBSU : NOTBSU (); break;
|
//case VUE.NOTBSU : NOTBSU (); break;
|
||||||
//case VUE.OR : OR (); break;
|
case VUE.OR : OR (); break;
|
||||||
//case VUE.ORBSU : ORBSU (); break;
|
//case VUE.ORBSU : ORBSU (); break;
|
||||||
//case VUE.ORI : ORI (); break;
|
case VUE.ORI : ORI (); break;
|
||||||
//case VUE.ORNBSU : ORNBSU (); break;
|
//case VUE.ORNBSU : ORNBSU (); break;
|
||||||
//case VUE.OUT_B : OUT_B (); break;
|
case VUE.OUT_B : OUT_B (); break;
|
||||||
//case VUE.OUT_H : OUT_H (); break;
|
case VUE.OUT_H : OUT_H (); break;
|
||||||
//case VUE.OUT_W : OUT_W (); break;
|
case VUE.OUT_W : OUT_W (); break;
|
||||||
//case VUE.RETI : RETI (); break;
|
case VUE.RETI : RETI (); break;
|
||||||
//case VUE.REV : REV (); break;
|
//case VUE.REV : REV (); break;
|
||||||
//case VUE.SAR_IMM: SAR_IMM(); break;
|
//case VUE.SAR_IMM: SAR_IMM(); break;
|
||||||
//case VUE.SAR_REG: SAR_REG(); break;
|
//case VUE.SAR_REG: SAR_REG(); break;
|
||||||
|
@ -423,27 +403,33 @@ System.out.printf("Execute %08X %d\n", pc, inst.id);
|
||||||
//case VUE.SHL_REG: SHL_REG(); break;
|
//case VUE.SHL_REG: SHL_REG(); break;
|
||||||
//case VUE.SHR_IMM: SHR_IMM(); break;
|
//case VUE.SHR_IMM: SHR_IMM(); break;
|
||||||
//case VUE.SHR_REG: SHR_REG(); break;
|
//case VUE.SHR_REG: SHR_REG(); break;
|
||||||
//case VUE.ST_B : ST_B (); break;
|
case VUE.ST_B : ST_B (); break;
|
||||||
//case VUE.ST_H : ST_H (); break;
|
case VUE.ST_H : ST_H (); break;
|
||||||
//case VUE.ST_W : ST_W (); break;
|
case VUE.ST_W : ST_W (); break;
|
||||||
//case VUE.STSR : STSR (); break;
|
case VUE.STSR : STSR (); break;
|
||||||
//case VUE.SUB : SUB (); break;
|
case VUE.SUB : SUB (); break;
|
||||||
//case VUE.SUBF_S : SUBF_S (); break;
|
//case VUE.SUBF_S : SUBF_S (); break;
|
||||||
//case VUE.TRAP : TRAP (); break;
|
case VUE.TRAP : TRAP (); break;
|
||||||
//case VUE.TRNC_SW: TRNC_SW(); break;
|
//case VUE.TRNC_SW: TRNC_SW(); break;
|
||||||
//case VUE.XB : XB (); break;
|
//case VUE.XB : XB (); break;
|
||||||
//case VUE.XH : XH (); break;
|
//case VUE.XH : XH (); break;
|
||||||
//case VUE.XOR : XOR (); break;
|
case VUE.XOR : XOR (); break;
|
||||||
//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: // Invalid instruction
|
default: // Invalid instruction
|
||||||
exception.code = 0xFF90;
|
exception.code = 0xFF90;
|
||||||
inst.size = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// An application break was requested
|
||||||
|
if (vue.breakCode != 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
// Common processing
|
// Common processing
|
||||||
|
if (exception.code == 0) {
|
||||||
|
cycles += CYCLES[inst.id];
|
||||||
pc += inst.size;
|
pc += inst.size;
|
||||||
|
}
|
||||||
program[0] = 0;
|
program[0] = 0;
|
||||||
testException();
|
testException();
|
||||||
if (stage == EXECUTE)
|
if (stage == EXECUTE)
|
||||||
|
@ -455,19 +441,8 @@ System.out.printf("Execute %08X %d\n", pc, inst.id);
|
||||||
private boolean fetch() {
|
private boolean fetch() {
|
||||||
|
|
||||||
// Read the bits from the bus
|
// Read the bits from the bus
|
||||||
access.address = pc + (fetch << 1);
|
if (read(pc + (fetch << 1), VUE.U16, fetch))
|
||||||
access.fetch = fetch;
|
|
||||||
access.type = VUE.U16;
|
|
||||||
access.value = vue.read(access.address, VUE.U16);
|
|
||||||
|
|
||||||
System.out.printf("Fetch %08X %04X\n", access.address, access.value);
|
|
||||||
|
|
||||||
// Application callback
|
|
||||||
if (vue.onRead != null) {
|
|
||||||
vue.breakCode = vue.onRead.call(vue, access);
|
|
||||||
if (vue.breakCode != 0)
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
// First unit
|
// First unit
|
||||||
if (fetch == 0) {
|
if (fetch == 0) {
|
||||||
|
@ -490,6 +465,39 @@ System.out.printf("Fetch %08X %04X\n", access.address, access.value);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Perform a bus read
|
||||||
|
private boolean read(int address, int type, int fetch) {
|
||||||
|
|
||||||
|
// Perform the operation
|
||||||
|
access.address = address;
|
||||||
|
access.fetch = fetch;
|
||||||
|
access.type = type;
|
||||||
|
access.value = vue.read(address, type);
|
||||||
|
|
||||||
|
// There is no application callback
|
||||||
|
if (vue.onRead == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Call the application callback
|
||||||
|
vue.breakCode = vue.onRead.call(vue, access);
|
||||||
|
return vue.breakCode != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test a condition
|
||||||
|
private int testCondition(int condition) {
|
||||||
|
switch (condition) {
|
||||||
|
case 0: return psw_ov;
|
||||||
|
case 1: return psw_cy;
|
||||||
|
case 2: return psw_z;
|
||||||
|
case 3: return psw_cy | psw_z;
|
||||||
|
case 4: return psw_s;
|
||||||
|
case 5: return 1;
|
||||||
|
case 6: return psw_ov | psw_s;
|
||||||
|
case 7: return psw_ov ^ psw_s | psw_z;
|
||||||
|
}
|
||||||
|
return testCondition(condition & 7) ^ 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Check for an exception or interrupt
|
// Check for an exception or interrupt
|
||||||
private boolean testException() {
|
private boolean testException() {
|
||||||
|
|
||||||
|
@ -512,25 +520,463 @@ System.out.printf("Fetch %08X %04X\n", access.address, access.value);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Perform a bus write
|
||||||
|
private boolean write(int address, int type, int value) {
|
||||||
|
|
||||||
|
// Prepare the operation
|
||||||
|
access.address = address;
|
||||||
|
access.fetch = -1;
|
||||||
|
access.type = type;
|
||||||
|
access.value = value;
|
||||||
|
|
||||||
|
// Application callback
|
||||||
|
if (vue.onWrite != null) {
|
||||||
|
vue.breakCode = vue.onWrite.call(vue, access);
|
||||||
|
if (vue.breakCode != 0)
|
||||||
|
return true;
|
||||||
|
if (access.type == VUE.CANCEL)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform the operation
|
||||||
|
vue.write(access.address, access.type, access.value);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Instruction Helpers //
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Integer addition
|
||||||
|
private int add(int left, int right) {
|
||||||
|
int result = left + right;
|
||||||
|
psw_cy = Integer.compareUnsigned(result, left) < 0 ? 1 : 0;
|
||||||
|
psw_s = result >>> 31;
|
||||||
|
psw_ov = (~(left ^ right) & (left ^ result)) >>> 31;
|
||||||
|
psw_z = result == 0 ? 1 : 0;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bitwise operation
|
||||||
|
private void bitwise(int result) {
|
||||||
|
program[inst.reg2] = result;
|
||||||
|
psw_ov = 0;
|
||||||
|
psw_s = result >>> 31;
|
||||||
|
psw_z = result == 0 ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine whether the floating-point operands are reserved values
|
||||||
|
private boolean floatReserved() {
|
||||||
|
for (int x = 0; x < 2; x++) {
|
||||||
|
int operand = program[x == 0 ? inst.reg2 : inst.reg1];
|
||||||
|
int exponent = operand & 0x7F800000;
|
||||||
|
|
||||||
|
// Check for a reserved operand
|
||||||
|
if (!(
|
||||||
|
exponent == 0x7F800000 || // Indefinite
|
||||||
|
exponent == 0 && (operand & 0x007FFFFF) != 0 // Denormal
|
||||||
|
)) continue;
|
||||||
|
|
||||||
|
// The value is a reserved operand
|
||||||
|
exception.code = 0xFF60;
|
||||||
|
psw_fro = 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Floating-point result
|
||||||
|
private void floatResult(double full) {
|
||||||
|
|
||||||
|
// Overflow
|
||||||
|
if (full > Float.MAX_VALUE || full < -Float.MAX_VALUE) {
|
||||||
|
exception.code = 0xFF64;
|
||||||
|
psw_fov = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the result
|
||||||
|
float result = (float) full;
|
||||||
|
int bits = Float.floatToRawIntBits(result);
|
||||||
|
|
||||||
|
// Underflow
|
||||||
|
if ((bits & 0x7F800000) == 0 && (bits & 0x007FFFFF) != 0) {
|
||||||
|
bits = 0;
|
||||||
|
result = 0;
|
||||||
|
psw_fud = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Precision degradation
|
||||||
|
if (result != full)
|
||||||
|
psw_fpr = 1;
|
||||||
|
|
||||||
|
// Common processing
|
||||||
|
program[inst.reg2] = bits;
|
||||||
|
psw_cy = psw_s = bits >>> 31;
|
||||||
|
psw_ov = 0;
|
||||||
|
psw_z = bits == 0 ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proxy for IN and LD
|
||||||
|
private void IN_LD(int type) {
|
||||||
|
if (!read(program[inst.reg1] + inst.disp, type, -1))
|
||||||
|
program[inst.reg2] = access.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proxy for OUT and ST
|
||||||
|
private void OUT_ST(int type) {
|
||||||
|
write(program[inst.reg1] + inst.disp, type, program[inst.reg2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Arithmetic shift right
|
||||||
|
private void shiftArithmetic(int value, int bits) {
|
||||||
|
bits &= 31;
|
||||||
|
psw_cy = bits == 0 ? 0 : value >> bits - 1 & 1;
|
||||||
|
bitwise(value >> bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logical shift left
|
||||||
|
private void shiftLeft(int value, int bits) {
|
||||||
|
bits &= 31;
|
||||||
|
psw_cy = bits == 0 ? 0 : value >> 32 - bits & 1;
|
||||||
|
bitwise(value << bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logical shift right
|
||||||
|
private void shiftRight(int value, int bits) {
|
||||||
|
bits &= 31;
|
||||||
|
psw_cy = bits == 0 ? 0 : value >> bits - 1 & 1;
|
||||||
|
bitwise(value >>> bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Integer subtraction
|
||||||
|
private int subtract(int left, int right) {
|
||||||
|
int result = left - right;
|
||||||
|
psw_cy = Integer.compareUnsigned(result, left) > 0 ? 1 : 0;
|
||||||
|
psw_s = result >>> 31;
|
||||||
|
psw_ov = ((left ^ right) & (left ^ result)) >>> 31;
|
||||||
|
psw_z = result == 0 ? 1 : 0;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Instruction Methods //
|
// Instruction Methods //
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// JMP
|
// Add Immediate
|
||||||
|
private void ADD_IMM() {
|
||||||
|
program[inst.reg2] = add(program[inst.reg2], inst.imm);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add Register
|
||||||
|
private void ADD_REG() {
|
||||||
|
program[inst.reg2] = add(program[inst.reg2], program[inst.reg1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add Floating Short
|
||||||
|
private void ADDF_S() {
|
||||||
|
if (!floatReserved()) floatResult(
|
||||||
|
(double) Float.intBitsToFloat(program[inst.reg2]) +
|
||||||
|
(double) Float.intBitsToFloat(program[inst.reg1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add Immediate
|
||||||
|
private void ADDI() {
|
||||||
|
program[inst.reg2] = add(program[inst.reg2], inst.imm);
|
||||||
|
}
|
||||||
|
|
||||||
|
// And
|
||||||
|
private void AND() {
|
||||||
|
bitwise(program[inst.reg2] & program[inst.reg1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// And Immediate
|
||||||
|
private void ANDI() {
|
||||||
|
bitwise(program[inst.reg2] & inst.imm);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Branch on Condition
|
||||||
|
private void BCOND() {
|
||||||
|
if (testCondition(inst.cond) == 0)
|
||||||
|
return;
|
||||||
|
pc += inst.disp - 2;
|
||||||
|
cycles = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare Immediate
|
||||||
|
private void CMP_IMM() {
|
||||||
|
subtract(program[inst.reg2], inst.imm);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare Register
|
||||||
|
private void CMP_REG() {
|
||||||
|
subtract(program[inst.reg2], program[inst.reg1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Divide
|
||||||
|
private void DIV() {
|
||||||
|
int left = program[inst.reg2];
|
||||||
|
int right = program[inst.reg1];
|
||||||
|
|
||||||
|
// Zero division
|
||||||
|
if (right == 0) {
|
||||||
|
exception.code = 0xFF80;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special case
|
||||||
|
if (left == 0x80000000 && right == 0xFFFFFFFF) {
|
||||||
|
program[30] = 0;
|
||||||
|
program[inst.reg2] = 0x80000000;
|
||||||
|
psw_ov = 1;
|
||||||
|
psw_s = 1;
|
||||||
|
psw_z = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regular case
|
||||||
|
int result = left / right;
|
||||||
|
program[30] = left % right;
|
||||||
|
program[inst.reg2] = result;
|
||||||
|
psw_ov = 0;
|
||||||
|
psw_s = result >>> 31;
|
||||||
|
psw_z = result == 0 ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Divide Unsigned
|
||||||
|
private void DIVU() {
|
||||||
|
long left = program[inst.reg2] & 0xFFFFFFFFL;
|
||||||
|
long right = program[inst.reg1] & 0xFFFFFFFFL;
|
||||||
|
|
||||||
|
// Zero division
|
||||||
|
if (right == 0) {
|
||||||
|
exception.code = 0xFF80;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regular case
|
||||||
|
int result = (int) (left / right);
|
||||||
|
program[30] = (int) (left % right);
|
||||||
|
program[inst.reg2] = result;
|
||||||
|
psw_ov = 0;
|
||||||
|
psw_s = result >>> 31;
|
||||||
|
psw_z = result == 0 ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Halt
|
||||||
|
private void HALT() {
|
||||||
|
stage = HALT;
|
||||||
|
inst.size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Input Byte from Port
|
||||||
|
private void IN_B() {
|
||||||
|
IN_LD(VUE.U8);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Input Halfword from Port
|
||||||
|
private void IN_H() {
|
||||||
|
IN_LD(VUE.U16);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Input Word from Port
|
||||||
|
private void IN_W() {
|
||||||
|
IN_LD(VUE.S32);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jump and Link
|
||||||
|
private void JAL() {
|
||||||
|
program[31] = pc + 4;
|
||||||
|
pc += inst.disp - 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jump Register
|
||||||
private void JMP() {
|
private void JMP() {
|
||||||
pc = program[inst.reg1] - 2;
|
pc = program[inst.reg1] - 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// MOVEA
|
// Jump Relative
|
||||||
|
private void JR() {
|
||||||
|
pc += inst.disp - 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load Byte
|
||||||
|
private void LD_B() {
|
||||||
|
IN_LD(VUE.S8);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load Halfword
|
||||||
|
private void LD_H() {
|
||||||
|
IN_LD(VUE.S16);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load Word
|
||||||
|
private void LD_W() {
|
||||||
|
IN_LD(VUE.S32);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load to System Register
|
||||||
|
private void LDSR() {
|
||||||
|
setSystemRegister(inst.imm & 31, program[inst.reg2], false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move Immediate
|
||||||
|
private void MOV_IMM() {
|
||||||
|
program[inst.reg2] = inst.imm;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move Register
|
||||||
|
private void MOV_REG() {
|
||||||
|
program[inst.reg2] = program[inst.reg1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add
|
||||||
private void MOVEA() {
|
private void MOVEA() {
|
||||||
program[inst.reg2] = program[inst.reg1] + inst.imm;
|
program[inst.reg2] = program[inst.reg1] + inst.imm;
|
||||||
}
|
}
|
||||||
|
|
||||||
// MOVHI
|
// Add
|
||||||
private void MOVHI() {
|
private void MOVHI() {
|
||||||
program[inst.reg2] = program[inst.reg1] + (inst.imm << 16);
|
program[inst.reg2] = program[inst.reg1] + (inst.imm << 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Multiply
|
||||||
|
private void MUL() {
|
||||||
|
long full = (long) program[inst.reg2] * (long) program[inst.reg1];
|
||||||
|
int result = (int) full;
|
||||||
|
program[30] = (int) (full >> 32);
|
||||||
|
program[inst.reg2] = result;
|
||||||
|
psw_ov = (long) result != full ? 1 : 0;
|
||||||
|
psw_s = result >>> 31;
|
||||||
|
psw_z = result == 0 ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiply Unsigned
|
||||||
|
private void MULU() {
|
||||||
|
long full = (program[inst.reg2] & 0xFFFFFFFFL) *
|
||||||
|
(program[inst.reg1] & 0xFFFFFFFFL);
|
||||||
|
int result = (int) full;
|
||||||
|
program[30] = (int) (full >> 32);
|
||||||
|
program[inst.reg2] = result;
|
||||||
|
psw_ov = full > 0xFFFFFFFFL ? 1 : 0;
|
||||||
|
psw_s = result >>> 31;
|
||||||
|
psw_z = result == 0 ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not
|
||||||
|
private void NOT() {
|
||||||
|
bitwise(~program[inst.reg1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Or
|
||||||
|
private void OR() {
|
||||||
|
bitwise(program[inst.reg2] | program[inst.reg1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Or Immediate
|
||||||
|
private void ORI() {
|
||||||
|
bitwise(program[inst.reg2] | inst.imm);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output Byte to Port
|
||||||
|
private void OUT_B() {
|
||||||
|
OUT_ST(VUE.U8);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output Halfword to Port
|
||||||
|
private void OUT_H() {
|
||||||
|
OUT_ST(VUE.U16);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output Word to Port
|
||||||
|
private void OUT_W() {
|
||||||
|
OUT_ST(VUE.S32);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return from Trap or Interrupt
|
||||||
|
private void RETI() {
|
||||||
|
if (psw_np == 1) {
|
||||||
|
pc = fepc;
|
||||||
|
setSystemRegister(VUE.PSW, fepsw, false);
|
||||||
|
} else {
|
||||||
|
pc = eipc;
|
||||||
|
setSystemRegister(VUE.PSW, eipsw, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shift Arithmetic Right by Immediate
|
||||||
|
private void SAR_IMM() {
|
||||||
|
shiftArithmetic(program[inst.reg2], inst.imm);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shift Arithmetic Right by Register
|
||||||
|
private void SAR_REG() {
|
||||||
|
shiftArithmetic(program[inst.reg2], program[inst.reg1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shift Logical Left by Immediate
|
||||||
|
private void SHL_IMM() {
|
||||||
|
shiftLeft(program[inst.reg2], inst.imm);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shift Logical Left by Register
|
||||||
|
private void SHL_REG() {
|
||||||
|
shiftLeft(program[inst.reg2], program[inst.reg1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shift Logical Right by Immediate
|
||||||
|
private void SHR_IMM() {
|
||||||
|
shiftRight(program[inst.reg2], inst.imm);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shift Logical Right by Register
|
||||||
|
private void SHR_REG() {
|
||||||
|
shiftRight(program[inst.reg2], program[inst.reg1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store Byte
|
||||||
|
private void ST_B() {
|
||||||
|
OUT_ST(VUE.S8);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store Halfword
|
||||||
|
private void ST_H() {
|
||||||
|
OUT_ST(VUE.S16);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store Word
|
||||||
|
private void ST_W() {
|
||||||
|
OUT_ST(VUE.S32);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store Contents of System Register
|
||||||
|
private void STSR() {
|
||||||
|
program[inst.reg2] = getSystemRegister(inst.imm & 31);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subtract
|
||||||
|
private void SUB() {
|
||||||
|
program[inst.reg2] = subtract(program[inst.reg2], program[inst.reg1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trap
|
||||||
|
private void TRAP() {
|
||||||
|
exception.code = 0xFFA0 | inst.imm & 15;
|
||||||
|
pc += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exclusive Or
|
||||||
|
private void XOR() {
|
||||||
|
bitwise(program[inst.reg2] ^ program[inst.reg1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exclusive Or Immediate
|
||||||
|
private void XORI() {
|
||||||
|
bitwise(program[inst.reg2] ^ inst.imm);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue