Implementing remaining CPU instructions except bit string

This commit is contained in:
Guy Perfect 2020-08-12 11:49:32 -05:00
parent 2d380460a6
commit fa1728b424
5 changed files with 439 additions and 75 deletions

View File

@ -94,7 +94,7 @@ static void cpuBitwise(VUE *vue, int32_t result) {
#define cpuFloat(x) ((double) *(float *)&(x))
/* Determine whether the floating-point operands are reserved values */
static vbool cpuFloatReserved(VUE *vue) {
static vbool cpuFloatReserved(VUE *vue, vbool left) {
int32_t exponent; /* Operand exponent */
int32_t operand; /* Current operand */
int x; /* Iterator */
@ -105,7 +105,7 @@ static vbool cpuFloatReserved(VUE *vue) {
operands[1] = vue->cpu.program[vue->cpu.inst.reg1];
/* Process both operands */
for (x = 0; x < 2; x++) {
for (x = left ^ 1; x < 2; x++) {
operand = operands[x];
exponent = operand & 0x7F800000;
@ -125,8 +125,69 @@ static vbool cpuFloatReserved(VUE *vue) {
return VUE_FALSE;
}
/* Convert a floating short to word */
static void cpuFloatConvert(VUE *vue, vbool round) {
int32_t bits; /* Number of bits to shift */
int32_t digits; /* Significant digits */
int32_t result; /* Output value */
int32_t sign; /* Sign of the result */
/* Reserved operand */
if (cpuFloatReserved(vue, VUE_FALSE))
return;
/* Parse the floating-point value */
result = vue->cpu.program[vue->cpu.inst.reg1];
bits = (result >> 23 & 0xFF) - 150;
digits = (result & 0x007FFFFF) | 0x00800000;
sign = result & 0x80000000;
/* Maximum negative word value */
if (result == (int32_t) 0xCF000000) {
digits = (int32_t) 0x80000000;
sign = 0;
}
/* Invalid operation (word overflow) */
else if (bits >= 8) {
vue->cpu.exception.code = 0xFF70;
return;
}
/* Zero */
else if ((result & 0x7FFFFFFF) == 0)
digits = 0;
/* No significant digits are shifted out */
else if (bits >= 0)
digits <<= bits;
/* All significant digits are shifted out */
else if (bits < -24) {
vue->cpu.psw_fpr = 1; /* The implicit leading 1 was lost */
digits = 0;
}
/* Some significant digits are shifted out */
else {
result = 1 << (-bits - 1); /* Position of the "one half" bit */
if (digits & ((result << 1) - 1)) /* The lost bits are not all zero */
vue->cpu.psw_fpr = 1;
if (round && (digits & result)) /* The "one half" bit is set */
digits += result;
digits = digits >> -bits;
}
/* Common processing */
result = sign ? -digits : digits;
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;
}
/* Floating-point result */
static void cpuFloatResult(VUE *vue, double full) {
static void cpuFloatResult(VUE *vue, vbool compare, double full) {
int32_t bits = 0x7F7FFFFF; /* Binary representation of result */
float result = *(float *)&bits; /* Operation output */
@ -148,12 +209,14 @@ static void cpuFloatResult(VUE *vue, double full) {
vue->cpu.psw_fud = 1;
}
/* Precision degradation */
if (result != full)
vue->cpu.psw_fpr = 1;
/* Operations other than compare */
if (!compare) {
vue->cpu.program[vue->cpu.inst.reg2] = bits;
if (result != full) /* Precision degradation */
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;
@ -194,6 +257,25 @@ static int32_t cpuGetSystemRegister(VUE *vue, int32_t index) {
return 1; /* Unreachable */
}
/* 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
/* Transfer program to another address */
static void cpuJump(VUE *vue, int32_t address) {
int level = vue->cpu.psw_np ? 2 : vue->cpu.psw_ep;
vue->cpu.jumpFrom[level] = vue->cpu.pc;
vue->cpu.jumpTo [level] = address;
vue->cpu.pc = address - vue->cpu.inst.size;
}
/* 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])
/* Perform a bus read */
static vbool cpuRead(VUE *vue, int32_t address, int8_t type, int8_t fetch) {
@ -384,17 +466,6 @@ static vbool cpuWrite(VUE *vue, int32_t address, int8_t type, int32_t 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])
/*****************************************************************************
@ -414,7 +485,7 @@ static vbool cpuWrite(VUE *vue, int32_t address, int8_t type, int32_t value) {
/* Add Floating Short */
#define cpuADDF_S(vue) \
if (!cpuFloatReserved(vue)) cpuFloatResult(vue, \
if (!cpuFloatReserved(vue, VUE_TRUE)) cpuFloatResult(vue, VUE_FALSE, \
cpuFloat(vue->cpu.program[vue->cpu.inst.reg2]) + \
cpuFloat(vue->cpu.program[vue->cpu.inst.reg1]))
@ -435,10 +506,37 @@ static vbool cpuWrite(VUE *vue, int32_t address, int8_t type, int32_t value) {
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;
cpuJump(vue, vue->cpu.pc + vue->cpu.inst.disp);
}
/* Compare and Exchange Interlocked */
static void cpuCAXI(VUE *vue) {
int32_t address =
vue->cpu.program[vue->cpu.inst.reg1] + vue->cpu.inst.disp;
int32_t left = vue->cpu.program[vue->cpu.inst.reg2];
int32_t lock; /* Value of lock word */
/* Retrieve the lock word */
if (cpuRead(vue, address, VUE_S32, -1))
return;
lock = vue->cpu.access.value;
/* Compare and exchange */
if (lock == left)
vue->cpu.access.value = vue->cpu.program[30];
if (cpuWrite(vue, address, VUE_S32, vue->cpu.access.value))
return;
/* Update CPU state */
cpuSubtract(vue, left, lock);
vue->cpu.program[vue->cpu.inst.reg2] = lock;
}
/* Clear Interrupt Disable Flag */
#define cpuCLI(vue) \
vue->cpu.psw_id = 0
/* Compare Immediate */
#define cpuCMP_IMM(vue) \
cpuSubtract(vue, \
@ -450,6 +548,28 @@ static void cpuBCOND(VUE *vue) {
vue->cpu.program[vue->cpu.inst.reg2], \
vue->cpu.program[vue->cpu.inst.reg1])
/* Compare Floating Short */
#define cpuCMPF_S(vue) \
if (!cpuFloatReserved(vue, VUE_TRUE)) cpuFloatResult(vue, VUE_TRUE, \
cpuFloat(vue->cpu.program[vue->cpu.inst.reg2]) - \
cpuFloat(vue->cpu.program[vue->cpu.inst.reg1]))
/* Convert Short Floating to Word */
#define cpuCVT_SW(vue) \
cpuFloatConvert(vue, VUE_TRUE)
/* Convert Word Integer to Short */
static void cpuCVT_WS(VUE *vue) {
int32_t bits = vue->cpu.program[vue->cpu.inst.reg1];
float result = (float) bits;
vue->cpu.program[vue->cpu.inst.reg2] = *(int32_t *)&result;
if (result != bits) /* Precision degradation */
vue->cpu.psw_fpr = 1;
vue->cpu.psw_cy = vue->cpu.psw_s = bits >> 31 & 1;
vue->cpu.psw_ov = 0;
vue->cpu.psw_z = bits ? 0 : 1;
}
/* Divide */
static void cpuDIV(VUE *vue) {
int32_t left = vue->cpu.program[vue->cpu.inst.reg2];
@ -481,6 +601,25 @@ static void cpuDIV(VUE *vue) {
vue->cpu.psw_z = result ? 0 : 1;
}
/* Divide Floating Short */
static void cpuDIVF_S(VUE *vue) {
int32_t left = vue->cpu.program[vue->cpu.inst.reg2];
int32_t right = vue->cpu.program[vue->cpu.inst.reg1];
/* Reserved operand */
if (cpuFloatReserved(vue, VUE_TRUE))
return;
/* An exception has occurred */
if (!right) {
vue->cpu.exception.code = left ? 0xFF68 : 0xFF70;
return;
}
/* Perform the operation */
cpuFloatResult(vue, VUE_FALSE, cpuFloat(left) / cpuFloat(right));
}
/* Divide Unsigned */
static void cpuDIVU(VUE *vue) {
uint32_t left = vue->cpu.program[vue->cpu.inst.reg2];
@ -518,15 +657,15 @@ static void cpuDIVU(VUE *vue) {
/* Jump and Link */
#define cpuJAL(vue) \
vue->cpu.program[31] = vue->cpu.pc + 4, \
vue->cpu.pc += vue->cpu.inst.disp - 4
cpuJump(vue, vue->cpu.pc + vue->cpu.inst.disp)
/* Jump Register */
#define cpuJMP(vue) \
vue->cpu.pc = vue->cpu.program[vue->cpu.inst.reg1] - 2
cpuJump(vue, vue->cpu.program[vue->cpu.inst.reg1])
/* Jump Relative */
#define cpuJR(vue) \
vue->cpu.pc += vue->cpu.inst.disp - 4
cpuJump(vue, vue->cpu.pc + vue->cpu.inst.disp)
/* Load Byte */
#define cpuLD_B(vue) cpuIN_LD(vue, VUE_S8)
@ -551,6 +690,12 @@ static void cpuDIVU(VUE *vue) {
vue->cpu.program[vue->cpu.inst.reg2] = \
vue->cpu.program[vue->cpu.inst.reg1]
/* Multiply Halfword */
static void cpuMPYHW(VUE *vue) {
int32_t right = vue->cpu.program[vue->cpu.inst.reg1];
vue->cpu.program[vue->cpu.inst.reg2] *= SIGN_EXTEND(17, right);
}
/* Multiply */
static void cpuMUL(VUE *vue) {
int64_t full = (int64_t) vue->cpu.program[vue->cpu.inst.reg2] *
@ -563,6 +708,12 @@ static void cpuMUL(VUE *vue) {
vue->cpu.psw_z = lower ? 0 : 1;
}
/* Multiply Floating Short */
#define cpuMULF_S(vue) \
if (!cpuFloatReserved(vue, VUE_TRUE)) cpuFloatResult(vue, VUE_FALSE, \
cpuFloat(vue->cpu.program[vue->cpu.inst.reg2]) * \
cpuFloat(vue->cpu.program[vue->cpu.inst.reg1]))
/* Multiply Unsigned */
static void cpuMULU(VUE *vue) {
uint64_t full = (uint64_t)(uint32_t) vue->cpu.program[vue->cpu.inst.reg2] *
@ -629,6 +780,15 @@ static void cpuRETI(VUE *vue) {
cpuShiftArithmetic(vue, vue->cpu.program[vue->cpu.inst.reg2], \
vue->cpu.program[vue->cpu.inst.reg1])
/* Set Interrupt Disable Flag */
#define cpuSEI(vue) \
vue->cpu.psw_id = 1
/* Set Flag Condition */
#define cpuSETF(vue) \
vue->cpu.program[vue->cpu.inst.reg2] = \
cpuTestCondition(vue, vue->cpu.inst.imm & 15)
/* Shift Logical Left by Immediate */
#define cpuSHL_IMM(vue) \
cpuShiftLeft(vue, vue->cpu.program[vue->cpu.inst.reg2], \
@ -649,6 +809,17 @@ static void cpuRETI(VUE *vue) {
cpuShiftRight(vue, vue->cpu.program[vue->cpu.inst.reg2], \
vue->cpu.program[vue->cpu.inst.reg1])
/* Reverse Bits in Word */
static void cpuREV(VUE *vue) {
int32_t value = vue->cpu.program[vue->cpu.inst.reg1];
value = (value >> 16 & 0x0000FFFF) | value << 16;
value = (value >> 8 & 0x00FF00FF) | (value << 8 & 0xFF00FF00);
value = (value >> 4 & 0x0F0F0F0F) | (value << 4 & 0xF0F0F0F0);
value = (value >> 2 & 0x33333333) | (value << 2 & 0xCCCCCCCC);
value = (value >> 1 & 0x55555555) | (value << 1 & 0xAAAAAAAA);
vue->cpu.program[vue->cpu.inst.reg2] = value;
}
/* Store Byte */
#define cpuST_B(vue) cpuOUT_ST(vue, VUE_S8)
@ -669,11 +840,35 @@ static void cpuRETI(VUE *vue) {
vue->cpu.program[vue->cpu.inst.reg2], \
vue->cpu.program[vue->cpu.inst.reg1])
/* Subtract Floating Short */
#define cpuSUBF_S(vue) \
if (!cpuFloatReserved(vue, VUE_TRUE)) cpuFloatResult(vue, VUE_FALSE, \
cpuFloat(vue->cpu.program[vue->cpu.inst.reg2]) - \
cpuFloat(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
/* Truncate Short Floating to Word */
#define cpuTRNC_SW(vue) \
cpuFloatConvert(vue, VUE_FALSE)
/* Exchange Byte */
static void cpuXB(VUE *vue) {
int32_t value = vue->cpu.program[vue->cpu.inst.reg2];
vue->cpu.program[vue->cpu.inst.reg2] =
(value & 0xFFFF0000) | (value >> 8 & 0xFF) | (value & 0xFF) << 8;
}
/* Exchange Halfword */
static void cpuXH(VUE *vue) {
int32_t value = vue->cpu.program[vue->cpu.inst.reg2];
vue->cpu.program[vue->cpu.inst.reg2] =
(value >> 16 & 0xFFFF) | value << 16;
}
/* Exclusive Or */
#define cpuXOR(vue) \
cpuBitwise(vue, vue->cpu.program[vue->cpu.inst.reg2] ^ \
@ -795,15 +990,15 @@ static vbool cpuExecute(VUE *vue) {
case VUE_ANDI : cpuANDI (vue); break;
/*case VUE_ANDNBSU: cpuANDNBSU(vue); break;*/
case VUE_BCOND : cpuBCOND (vue); break;
/*case VUE_CAXI : cpuCAXI (vue); break;*/
/*case VUE_CLI : cpuCLI (vue); break;*/
case VUE_CAXI : cpuCAXI (vue); break;
case VUE_CLI : cpuCLI (vue); break;
case VUE_CMP_IMM: cpuCMP_IMM(vue); break;
case VUE_CMP_REG: cpuCMP_REG(vue); break;
/*case VUE_CMPF_S : cpuCMPF_S (vue); break;*/
/*case VUE_CVT_SW : cpuCVT_SW (vue); break;*/
/*case VUE_CVT_WS : cpuCVT_WS (vue); break;*/
case VUE_CMPF_S : cpuCMPF_S (vue); break;
case VUE_CVT_SW : cpuCVT_SW (vue); break;
case VUE_CVT_WS : cpuCVT_WS (vue); break;
case VUE_DIV : cpuDIV (vue); break;
/*case VUE_DIVF_S : cpuDIVF_S (vue); break;*/
case VUE_DIVF_S : cpuDIVF_S (vue); break;
case VUE_DIVU : cpuDIVU (vue); break;
case VUE_HALT : cpuHALT (vue); break;
case VUE_IN_B : cpuIN_B (vue); break;
@ -821,9 +1016,9 @@ static vbool cpuExecute(VUE *vue) {
/*case VUE_MOVBSU : cpuMOVBSU (vue); break;*/
case VUE_MOVEA : cpuMOVEA (vue); break;
case VUE_MOVHI : cpuMOVHI (vue); break;
/*case VUE_MPYHW : cpuMPYHW (vue); break;*/
case VUE_MPYHW : cpuMPYHW (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_NOT : cpuNOT (vue); break;
/*case VUE_NOTBSU : cpuNOTBSU (vue); break;*/
@ -835,15 +1030,15 @@ static vbool cpuExecute(VUE *vue) {
case VUE_OUT_H : cpuOUT_H (vue); break;
case VUE_OUT_W : cpuOUT_W (vue); break;
case VUE_RETI : cpuRETI (vue); break;
/*case VUE_REV : cpuREV (vue); break;*/
case VUE_REV : cpuREV (vue); break;
case VUE_SAR_IMM: cpuSAR_IMM(vue); break;
case VUE_SAR_REG: cpuSAR_REG(vue); break;
/*case VUE_SCH0BSD: cpuSCH0BSD(vue); break;*/
/*case VUE_SCH0BSU: cpuSCH0BSU(vue); break;*/
/*case VUE_SCH1BSD: cpuSCH1BSD(vue); break;*/
/*case VUE_SCH1BSU: cpuSCH1BSU(vue); break;*/
/*case VUE_SEI : cpuSEI (vue); break;*/
/*case VUE_SETF : cpuSETF (vue); break;*/
case VUE_SEI : cpuSEI (vue); break;
case VUE_SETF : cpuSETF (vue); break;
case VUE_SHL_IMM: cpuSHL_IMM(vue); break;
case VUE_SHL_REG: cpuSHL_REG(vue); break;
case VUE_SHR_IMM: cpuSHR_IMM(vue); break;
@ -853,11 +1048,11 @@ static vbool cpuExecute(VUE *vue) {
case VUE_ST_W : cpuST_W (vue); break;
case VUE_STSR : cpuSTSR (vue); break;
case VUE_SUB : cpuSUB (vue); break;
/*case VUE_SUBF_S : cpuSUBF_S (vue); break;*/
case VUE_SUBF_S : cpuSUBF_S (vue); break;
case VUE_TRAP : cpuTRAP (vue); break;
/*case VUE_TRNC_SW: cpuTRNC_SW(vue); break;*/
/*case VUE_XB : cpuXB (vue); break;*/
/*case VUE_XH : cpuXH (vue); break;*/
case VUE_TRNC_SW: cpuTRNC_SW(vue); break;
case VUE_XB : cpuXB (vue); break;
case VUE_XH : cpuXH (vue); break;
case VUE_XOR : cpuXOR (vue); break;
/*case VUE_XORBSU : cpuXORBSU (vue); break;*/
case VUE_XORI : cpuXORI (vue); break;

View File

@ -116,11 +116,11 @@ static void writeBuffer(uint8_t *data, uint32_t datlen, uint32_t address,
#ifdef VUE_BIGENDIAN
switch (type) {
case VUE_S32:
value = (value & 0xFFFF0000) >> 16 | value << 16;
value = (value >> 16 & 0x0000FFFF) | value << 16;
/* Fallthrough */
case VUE_S16: /* Fallthrough */
case VUE_U16:
value = (value & 0xFF00FF00) >> 8 | (value & 0x00FF00FF) << 8;
value = (value >> 8 & 0x00FF00FF) | (value << 8 & 0xFF00FF00);
}
#endif

View File

@ -480,6 +480,7 @@ class Register {
// Event handlers
ctrl.addActionListener(e->{
parent.requestFocus();
int val = value >> bit & mask;
try { val = Integer.parseInt(ctrl.getText(), hex ? 16 : 10); }
catch (Exception x) { }
@ -501,9 +502,10 @@ class Register {
// Update the register value
private void setValue(int value) {
parent.requestFocus();
parent.parent.parent.vue.setRegister(index, type != PROGRAM, value);
refresh();
if (index == VUE.PSW && type == VUE.PSW)
parent.registers.get(VUE.PC).refresh();
}
}

View File

@ -14,10 +14,10 @@ class RegisterList extends JScrollPane {
// Package fields
CPUWindow parent; // Containing CPU window
HashMap<Integer, Register> registers; // Register items
// Private fields
private boolean shown; // Component has been shown
private HashMap<Integer, Register> registers; // Register items
// UI components
private JPanel client; // Client area

View File

@ -350,15 +350,15 @@ this.cycles = 0; // DEBUG: Stop processing after execute
case VUE.ANDI : ANDI (); break;
//case VUE.ANDNBSU: ANDNBSU(); break;
case VUE.BCOND : BCOND (); break;
//case VUE.CAXI : CAXI (); break;
//case VUE.CLI : CLI (); break;
case VUE.CAXI : CAXI (); break;
case VUE.CLI : CLI (); break;
case VUE.CMP_IMM: CMP_IMM(); break;
case VUE.CMP_REG: CMP_REG(); break;
//case VUE.CMPF_S : CMPF_S (); break;
//case VUE.CVT_SW : CVT_SW (); break;
//case VUE.CVT_WS : CVT_WS (); break;
case VUE.CMPF_S : CMPF_S (); break;
case VUE.CVT_SW : CVT_SW (); break;
case VUE.CVT_WS : CVT_WS (); 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.HALT : HALT (); break;
case VUE.IN_B : IN_B (); break;
@ -376,9 +376,9 @@ this.cycles = 0; // DEBUG: Stop processing after execute
//case VUE.MOVBSU : MOVBSU (); break;
case VUE.MOVEA : MOVEA (); break;
case VUE.MOVHI : MOVHI (); break;
//case VUE.MPYHW : MPYHW (); break;
case VUE.MPYHW : MPYHW (); 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.NOT : NOT (); break;
//case VUE.NOTBSU : NOTBSU (); break;
@ -390,29 +390,29 @@ this.cycles = 0; // DEBUG: Stop processing after execute
case VUE.OUT_H : OUT_H (); break;
case VUE.OUT_W : OUT_W (); break;
case VUE.RETI : RETI (); break;
//case VUE.REV : REV (); break;
//case VUE.SAR_IMM: SAR_IMM(); break;
//case VUE.SAR_REG: SAR_REG(); break;
case VUE.REV : REV (); break;
case VUE.SAR_IMM: SAR_IMM(); break;
case VUE.SAR_REG: SAR_REG(); break;
//case VUE.SCH0BSD: SCH0BSD(); break;
//case VUE.SCH0BSU: SCH0BSU(); break;
//case VUE.SCH1BSD: SCH1BSD(); break;
//case VUE.SCH1BSU: SCH1BSU(); break;
//case VUE.SEI : SEI (); break;
//case VUE.SETF : SETF (); break;
//case VUE.SHL_IMM: SHL_IMM(); break;
//case VUE.SHL_REG: SHL_REG(); break;
//case VUE.SHR_IMM: SHR_IMM(); break;
//case VUE.SHR_REG: SHR_REG(); break;
case VUE.SEI : SEI (); break;
case VUE.SETF : SETF (); break;
case VUE.SHL_IMM: SHL_IMM(); break;
case VUE.SHL_REG: SHL_REG(); break;
case VUE.SHR_IMM: SHR_IMM(); break;
case VUE.SHR_REG: SHR_REG(); break;
case VUE.ST_B : ST_B (); break;
case VUE.ST_H : ST_H (); break;
case VUE.ST_W : ST_W (); break;
case VUE.STSR : STSR (); 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.TRNC_SW: TRNC_SW(); break;
//case VUE.XB : XB (); break;
//case VUE.XH : XH (); break;
case VUE.TRNC_SW: TRNC_SW(); break;
case VUE.XB : XB (); break;
case VUE.XH : XH (); break;
case VUE.XOR : XOR (); break;
//case VUE.XORBSU : XORBSU (); break;
case VUE.XORI : XORI (); break;
@ -567,9 +567,37 @@ this.cycles = 0; // DEBUG: Stop processing after execute
psw_z = result == 0 ? 1 : 0;
}
// Convert a floating short to word
private void floatConvert(boolean round) {
// Reserved operand
if (floatReserved(false))
return;
// Determine the value to convert
float value = Float.intBitsToFloat(program[inst.reg1]);
value = (float) (round ? Math.round(value) :
value < 0 ? Math.ceil(value) : Math.floor(value));
// Invalid operation
if (value > 0x7FFFFFFF || value < 0x80000000) {
exception.code = 0xFF70;
return;
}
// Common processing
int result = (int) value;
if (result != value) // Precision degradation
psw_fpr = 1;
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++) {
private boolean floatReserved(boolean left) {
for (int x = left ? 0 : 1; x < 2; x++) {
int operand = program[x == 0 ? inst.reg2 : inst.reg1];
int exponent = operand & 0x7F800000;
@ -588,7 +616,7 @@ this.cycles = 0; // DEBUG: Stop processing after execute
}
// Floating-point result
private void floatResult(double full) {
private void floatResult(boolean compare, double full) {
// Overflow
if (full > Float.MAX_VALUE || full < -Float.MAX_VALUE) {
@ -608,12 +636,14 @@ this.cycles = 0; // DEBUG: Stop processing after execute
psw_fud = 1;
}
// Precision degradation
if (result != full)
psw_fpr = 1;
// Operations other than compare
if (!compare) {
program[inst.reg2] = bits;
if (result != full) // Precision degradation
psw_fpr = 1;
}
// Common processing
program[inst.reg2] = bits;
psw_cy = psw_s = bits >>> 31;
psw_ov = 0;
psw_z = bits == 0 ? 1 : 0;
@ -625,6 +655,14 @@ this.cycles = 0; // DEBUG: Stop processing after execute
program[inst.reg2] = access.value;
}
// Transfer program to another address
private void jump(int address) {
int level = psw_np != 0 ? 2 : psw_ep;
jumpFrom[level] = pc;
jumpTo [level] = address;
pc = address - inst.size;
}
// Proxy for OUT and ST
private void OUT_ST(int type) {
write(program[inst.reg1] + inst.disp, type, program[inst.reg2]);
@ -679,7 +717,7 @@ this.cycles = 0; // DEBUG: Stop processing after execute
// Add Floating Short
private void ADDF_S() {
if (!floatReserved()) floatResult(
if (!floatReserved(true)) floatResult(false,
(double) Float.intBitsToFloat(program[inst.reg2]) +
(double) Float.intBitsToFloat(program[inst.reg1]));
}
@ -703,8 +741,34 @@ this.cycles = 0; // DEBUG: Stop processing after execute
private void BCOND() {
if (testCondition(inst.cond) == 0)
return;
pc += inst.disp - 2;
cycles = 2;
jump(pc + inst.disp);
}
// Compare and Exchange Interlocked
private void CAXI() {
int address = program[inst.reg1] + inst.disp;
int left = program[inst.reg2];
// Retrieve the lock word
if (read(address, VUE.S32, -1))
return;
int lock = access.value;
// Compare and exchange
if (lock == left)
access.value = program[30];
if (write(address, VUE.S32, access.value))
return;
// Update CPU state
subtract(left, lock);
program[inst.reg2] = lock;
}
// Clear Interrupt Disable Flag
private void CLI() {
psw_id = 0;
}
// Compare Immediate
@ -717,6 +781,30 @@ this.cycles = 0; // DEBUG: Stop processing after execute
subtract(program[inst.reg2], program[inst.reg1]);
}
// Compare Floating Short
private void CMPF_S() {
if (!floatReserved(true)) floatResult(true,
(double) Float.intBitsToFloat(program[inst.reg2]) -
(double) Float.intBitsToFloat(program[inst.reg1]));
}
// Convert Short Floating to Word
private void CVT_SW() {
floatConvert(true);
}
// Convert Word Integer to Short
private void CVT_WS() {
int bits = program[inst.reg1];
float result = (float) bits;
program[inst.reg2] = Float.floatToRawIntBits(result);
if (result != bits) // Precision degradation
psw_fpr = 1;
psw_cy = psw_s = bits >>> 31;
psw_ov = 0;
psw_z = bits == 0 ? 1 : 0;
}
// Divide
private void DIV() {
int left = program[inst.reg2];
@ -747,6 +835,27 @@ this.cycles = 0; // DEBUG: Stop processing after execute
psw_z = result == 0 ? 1 : 0;
}
// Divide Floating Short
private void DIVF_S() {
int left = program[inst.reg2];
int right = program[inst.reg1];
// Reserved operand
if (floatReserved(true))
return;
// An exception has occurred
if (right == 0) {
exception.code = left == 0 ? 0xFF70 : 0xFF68;
return;
}
// Perform the operation
floatResult(false,
(double) Float.intBitsToFloat(left) /
(double) Float.intBitsToFloat(right));
}
// Divide Unsigned
private void DIVU() {
long left = program[inst.reg2] & 0xFFFFFFFFL;
@ -791,17 +900,17 @@ this.cycles = 0; // DEBUG: Stop processing after execute
// Jump and Link
private void JAL() {
program[31] = pc + 4;
pc += inst.disp - 4;
jump(pc + inst.disp);
}
// Jump Register
private void JMP() {
pc = program[inst.reg1] - 2;
jump(program[inst.reg1]);
}
// Jump Relative
private void JR() {
pc += inst.disp - 4;
jump(pc + inst.disp);
}
// Load Byte
@ -844,6 +953,11 @@ this.cycles = 0; // DEBUG: Stop processing after execute
program[inst.reg2] = program[inst.reg1] + (inst.imm << 16);
}
// Multiply Halfword
private void MPYHW() {
program[inst.reg2] *= program[inst.reg1] << 15 >> 15;
}
// Multiply
private void MUL() {
long full = (long) program[inst.reg2] * (long) program[inst.reg1];
@ -855,6 +969,13 @@ this.cycles = 0; // DEBUG: Stop processing after execute
psw_z = result == 0 ? 1 : 0;
}
// Multiply Floating Short
private void MULF_S() {
if (!floatReserved(true)) floatResult(false,
(double) Float.intBitsToFloat(program[inst.reg2]) *
(double) Float.intBitsToFloat(program[inst.reg1]));
}
// Multiply Unsigned
private void MULU() {
long full = (program[inst.reg2] & 0xFFFFFFFFL) *
@ -908,6 +1029,17 @@ this.cycles = 0; // DEBUG: Stop processing after execute
}
}
// Reverse Bits in Word
private void REV() {
int value = program[inst.reg1];
value = value >> 16 & 0x0000FFFF | value << 16;
value = value >> 8 & 0x00FF00FF | value << 8 & 0xFF00FF00;
value = value >> 4 & 0x0F0F0F0F | value << 4 & 0xF0F0F0F0;
value = value >> 2 & 0x33333333 | value << 2 & 0xCCCCCCCC;
value = value >> 1 & 0x55555555 | value << 1 & 0xAAAAAAAA;
program[inst.reg2] = value;
}
// Shift Arithmetic Right by Immediate
private void SAR_IMM() {
shiftArithmetic(program[inst.reg2], inst.imm);
@ -918,6 +1050,16 @@ this.cycles = 0; // DEBUG: Stop processing after execute
shiftArithmetic(program[inst.reg2], program[inst.reg1]);
}
// Set Interrupt Disable Flag
private void SEI() {
psw_id = 1;
}
// Set Flag Condition
private void SETF() {
program[inst.reg2] = testCondition(inst.imm & 15);
}
// Shift Logical Left by Immediate
private void SHL_IMM() {
shiftLeft(program[inst.reg2], inst.imm);
@ -963,12 +1105,37 @@ this.cycles = 0; // DEBUG: Stop processing after execute
program[inst.reg2] = subtract(program[inst.reg2], program[inst.reg1]);
}
// Subtract Floating Short
private void SUBF_S() {
if (!floatReserved(true)) floatResult(false,
(double) Float.intBitsToFloat(program[inst.reg2]) -
(double) Float.intBitsToFloat(program[inst.reg1]));
}
// Trap
private void TRAP() {
exception.code = 0xFFA0 | inst.imm & 15;
pc += 2;
}
// Truncate Short Floating to Word
private void TRNC_SW() {
floatConvert(false);
}
// Exchange Byte
private void XB() {
int value = program[inst.reg2];
program[inst.reg2] = value & 0xFFFF0000 |
value >> 8 & 0xFF | (value & 0xFF) << 8;
}
// Exchange Halfword
private void XH() {
int value = program[inst.reg2];
program[inst.reg2] = value >> 16 & 0xFFFF | value << 16;
}
// Exclusive Or
private void XOR() {
bitwise(program[inst.reg2] ^ program[inst.reg1]);