diff --git a/src/core/cpu.c b/src/core/cpu.c index 4ed4e35..f9a7370 100644 --- a/src/core/cpu.c +++ b/src/core/cpu.c @@ -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; diff --git a/src/core/vue.c b/src/core/vue.c index 5d84c9a..e18de25 100644 --- a/src/core/vue.c +++ b/src/core/vue.c @@ -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 diff --git a/src/desktop/app/Register.java b/src/desktop/app/Register.java index daf0ee8..dc92a15 100644 --- a/src/desktop/app/Register.java +++ b/src/desktop/app/Register.java @@ -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(); } } \ No newline at end of file diff --git a/src/desktop/app/RegisterList.java b/src/desktop/app/RegisterList.java index d599b90..0109f58 100644 --- a/src/desktop/app/RegisterList.java +++ b/src/desktop/app/RegisterList.java @@ -14,10 +14,10 @@ class RegisterList extends JScrollPane { // Package fields CPUWindow parent; // Containing CPU window + HashMap registers; // Register items // Private fields private boolean shown; // Component has been shown - private HashMap registers; // Register items // UI components private JPanel client; // Client area diff --git a/src/desktop/vue/CPU.java b/src/desktop/vue/CPU.java index e1bfa84..ed3e623 100644 --- a/src/desktop/vue/CPU.java +++ b/src/desktop/vue/CPU.java @@ -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]);