From 18b9892bc750fecc67c7a71c6086fe104b5e4d39 Mon Sep 17 00:00:00 2001 From: zilmar Date: Mon, 5 Sep 2022 16:35:13 +0930 Subject: [PATCH] Core: Add handling of overflow exception --- .../N64System/Interpreter/InterpreterOps.cpp | 70 +++- .../N64System/Interpreter/InterpreterOps.h | 1 + .../Interpreter/InterpreterOps32.cpp | 31 +- .../N64System/Mips/Register.cpp | 16 + .../Project64-core/N64System/Mips/Register.h | 1 + .../N64System/Recompiler/ExitInfo.h | 1 + .../Recompiler/x86/x86RecompilerOps.cpp | 314 ++++++++++-------- .../N64System/Recompiler/x86/x86ops.cpp | 7 + .../N64System/Recompiler/x86/x86ops.h | 1 + 9 files changed, 298 insertions(+), 144 deletions(-) diff --git a/Source/Project64-core/N64System/Interpreter/InterpreterOps.cpp b/Source/Project64-core/N64System/Interpreter/InterpreterOps.cpp index 0284de802..eb436f5a0 100644 --- a/Source/Project64-core/N64System/Interpreter/InterpreterOps.cpp +++ b/Source/Project64-core/N64System/Interpreter/InterpreterOps.cpp @@ -816,7 +816,15 @@ void R4300iOp::ADDI() StackValue += (int16_t)m_Opcode.immediate; } #endif - _GPR[m_Opcode.rt].DW = (_GPR[m_Opcode.rs].W[0] + ((int16_t)m_Opcode.immediate)); + int32_t rs = _GPR[m_Opcode.rs].W[0]; + int32_t imm = (int16_t)m_Opcode.immediate; + int32_t sum = rs + imm; + if ((~(rs ^ imm) & (rs ^ sum)) & 0x80000000) + { + GenerateOverflowException(); + return; + } + _GPR[m_Opcode.rt].DW = sum; #ifdef Interpreter_StackTest if (m_Opcode.rt == 29 && m_Opcode.rs != 29) { @@ -979,7 +987,16 @@ void R4300iOp::BGTZL() void R4300iOp::DADDI() { - _GPR[m_Opcode.rt].DW = _GPR[m_Opcode.rs].DW + (int64_t)((int16_t)m_Opcode.immediate); + int64_t rs = _GPR[m_Opcode.rs].DW; + int64_t imm = (int64_t)((int16_t)m_Opcode.immediate); + int64_t sum = rs + imm; + if ((~(rs ^ imm) & (rs ^ sum)) & 0x8000000000000000) + { + GenerateOverflowException(); + return; + } + _GPR[m_Opcode.rt].DW = sum; + } void R4300iOp::DADDIU() @@ -1499,7 +1516,15 @@ void R4300iOp::SPECIAL_DDIVU() void R4300iOp::SPECIAL_ADD() { - _GPR[m_Opcode.rd].DW = _GPR[m_Opcode.rs].W[0] + _GPR[m_Opcode.rt].W[0]; + int32_t rs = _GPR[m_Opcode.rs].W[0]; + int32_t rt = _GPR[m_Opcode.rt].W[0]; + int32_t sum = rs + rt; + if ((~(rs ^ rt) & (rs ^ sum)) & 0x80000000) + { + GenerateOverflowException(); + return; + } + _GPR[m_Opcode.rd].DW = sum; } void R4300iOp::SPECIAL_ADDU() @@ -1509,7 +1534,16 @@ void R4300iOp::SPECIAL_ADDU() void R4300iOp::SPECIAL_SUB() { - _GPR[m_Opcode.rd].DW = _GPR[m_Opcode.rs].W[0] - _GPR[m_Opcode.rt].W[0]; + int32_t rs = _GPR[m_Opcode.rs].W[0]; + int32_t rt = _GPR[m_Opcode.rt].W[0]; + int32_t sub = rs - rt; + + if (((rs ^ rt) & (rs ^ sub)) & 0x80000000) + { + GenerateOverflowException(); + return; + } + _GPR[m_Opcode.rd].DW = sub; } void R4300iOp::SPECIAL_SUBU() @@ -1569,7 +1603,15 @@ void R4300iOp::SPECIAL_SLTU() void R4300iOp::SPECIAL_DADD() { - _GPR[m_Opcode.rd].DW = _GPR[m_Opcode.rs].DW + _GPR[m_Opcode.rt].DW; + int64_t rs = _GPR[m_Opcode.rs].DW; + int64_t rt = _GPR[m_Opcode.rt].DW; + int64_t sum = rs + rt; + if ((~(rs ^ rt) & (rs ^ sum)) & 0x8000000000000000) + { + GenerateOverflowException(); + return; + } + _GPR[m_Opcode.rd].DW = sum; } void R4300iOp::SPECIAL_DADDU() @@ -1579,7 +1621,16 @@ void R4300iOp::SPECIAL_DADDU() void R4300iOp::SPECIAL_DSUB() { - _GPR[m_Opcode.rd].DW = _GPR[m_Opcode.rs].DW - _GPR[m_Opcode.rt].DW; + int64_t rs = _GPR[m_Opcode.rs].DW; + int64_t rt = _GPR[m_Opcode.rt].DW; + int64_t sub = rs - rt; + + if (((rs ^ rt) & (rs ^ sub)) & 0x8000000000000000) + { + GenerateOverflowException(); + return; + } + _GPR[m_Opcode.rd].DW = sub; } void R4300iOp::SPECIAL_DSUBU() @@ -2688,6 +2739,13 @@ void R4300iOp::GenerateAddressErrorException(uint32_t VAddr, bool FromRead) g_System->m_JumpToLocation = (*_PROGRAM_COUNTER); } +void R4300iOp::GenerateOverflowException(void) +{ + g_Reg->DoOverflowException(g_System->m_PipelineStage == PIPELINE_STAGE_JUMP); + g_System->m_PipelineStage = PIPELINE_STAGE_JUMP; + g_System->m_JumpToLocation = (*_PROGRAM_COUNTER); +} + void R4300iOp::GenerateTLBReadException(uint32_t VAddr, const char * function) { if (bShowTLBMisses()) diff --git a/Source/Project64-core/N64System/Interpreter/InterpreterOps.h b/Source/Project64-core/N64System/Interpreter/InterpreterOps.h index 85ee8a363..c36d4c185 100644 --- a/Source/Project64-core/N64System/Interpreter/InterpreterOps.h +++ b/Source/Project64-core/N64System/Interpreter/InterpreterOps.h @@ -241,6 +241,7 @@ protected: static Func Jump_CoP1_L[64]; static void GenerateAddressErrorException(uint32_t VAddr, bool FromRead); + static void GenerateOverflowException(void); static void GenerateTLBReadException(uint32_t VAddr, const char * function); static void GenerateTLBWriteException(uint32_t VAddr, const char * function); diff --git a/Source/Project64-core/N64System/Interpreter/InterpreterOps32.cpp b/Source/Project64-core/N64System/Interpreter/InterpreterOps32.cpp index d13105788..299cff9d4 100644 --- a/Source/Project64-core/N64System/Interpreter/InterpreterOps32.cpp +++ b/Source/Project64-core/N64System/Interpreter/InterpreterOps32.cpp @@ -715,7 +715,15 @@ void R4300iOp32::ADDI() StackValue += (int16_t)m_Opcode.immediate; } #endif - _GPR[m_Opcode.rt].W[0] = (_GPR[m_Opcode.rs].W[0] + ((int16_t)m_Opcode.immediate)); + int32_t rs = _GPR[m_Opcode.rs].W[0]; + int32_t imm = (int16_t)m_Opcode.immediate; + int32_t sum = rs + imm; + if ((~(rs ^ imm) & (rs ^ sum)) & 0x80000000) + { + GenerateOverflowException(); + return; + } + _GPR[m_Opcode.rt].W[0] = sum; #ifdef Interpreter_StackTest if (m_Opcode.rt == 29 && m_Opcode.rs != 29) { @@ -1001,7 +1009,15 @@ void R4300iOp32::SPECIAL_JALR() void R4300iOp32::SPECIAL_ADD() { - _GPR[m_Opcode.rd].W[0] = _GPR[m_Opcode.rs].W[0] + _GPR[m_Opcode.rt].W[0]; + int32_t rs = _GPR[m_Opcode.rs].W[0]; + int32_t rt = _GPR[m_Opcode.rt].W[0]; + int32_t sum = rs + rt; + if ((~(rs ^ rt) & (rs ^ sum)) & 0x80000000) + { + GenerateOverflowException(); + return; + } + _GPR[m_Opcode.rd].W[0] = sum; } void R4300iOp32::SPECIAL_ADDU() @@ -1011,7 +1027,16 @@ void R4300iOp32::SPECIAL_ADDU() void R4300iOp32::SPECIAL_SUB() { - _GPR[m_Opcode.rd].W[0] = _GPR[m_Opcode.rs].W[0] - _GPR[m_Opcode.rt].W[0]; + int32_t rs = _GPR[m_Opcode.rs].W[0]; + int32_t rt = _GPR[m_Opcode.rt].W[0]; + int32_t sub = rs - rt; + + if (((rs ^ rt) & (rs ^ sub)) & 0x80000000) + { + GenerateOverflowException(); + return; + } + _GPR[m_Opcode.rd].W[0] = sub; } void R4300iOp32::SPECIAL_SUBU() diff --git a/Source/Project64-core/N64System/Mips/Register.cpp b/Source/Project64-core/N64System/Mips/Register.cpp index 1aed3e1be..eaeabc596 100644 --- a/Source/Project64-core/N64System/Mips/Register.cpp +++ b/Source/Project64-core/N64System/Mips/Register.cpp @@ -367,6 +367,22 @@ bool CRegisters::DoIntrException(bool DelaySlot) return true; } +void CRegisters::DoOverflowException(bool DelaySlot) +{ + CAUSE_REGISTER = EXC_OV; + if (DelaySlot) + { + CAUSE_REGISTER |= CAUSE_BD; + EPC_REGISTER = m_PROGRAM_COUNTER - 4; + } + else + { + EPC_REGISTER = m_PROGRAM_COUNTER; + } + m_PROGRAM_COUNTER = 0x80000180; + STATUS_REGISTER |= STATUS_EXL; +} + void CRegisters::DoTLBReadMiss(bool DelaySlot, uint32_t BadVaddr) { CAUSE_REGISTER = EXC_RMISS; diff --git a/Source/Project64-core/N64System/Mips/Register.h b/Source/Project64-core/N64System/Mips/Register.h index 23828392f..7093b77a1 100644 --- a/Source/Project64-core/N64System/Mips/Register.h +++ b/Source/Project64-core/N64System/Mips/Register.h @@ -269,6 +269,7 @@ public: void DoTrapException( bool DelaySlot ); void DoCopUnusableException( bool DelaySlot, int32_t Coprocessor ); bool DoIntrException( bool DelaySlot ); + void DoOverflowException(bool DelaySlot); void DoTLBReadMiss(bool DelaySlot, uint32_t BadVaddr); void DoTLBWriteMiss(bool DelaySlot, uint32_t BadVaddr); void DoSysCallException ( bool DelaySlot); diff --git a/Source/Project64-core/N64System/Recompiler/ExitInfo.h b/Source/Project64-core/N64System/Recompiler/ExitInfo.h index d1100bbed..b6937daa9 100644 --- a/Source/Project64-core/N64System/Recompiler/ExitInfo.h +++ b/Source/Project64-core/N64System/Recompiler/ExitInfo.h @@ -19,6 +19,7 @@ struct CExitInfo TLBReadMiss = 5, TLBWriteMiss = 6, ExitResetRecompCode = 8, + Exit_ExceptionOverflow, }; std::string Name; diff --git a/Source/Project64-core/N64System/Recompiler/x86/x86RecompilerOps.cpp b/Source/Project64-core/N64System/Recompiler/x86/x86RecompilerOps.cpp index baa89f056..e1250de90 100644 --- a/Source/Project64-core/N64System/Recompiler/x86/x86RecompilerOps.cpp +++ b/Source/Project64-core/N64System/Recompiler/x86/x86RecompilerOps.cpp @@ -473,6 +473,7 @@ void CX86RecompilerOps::Compile_Branch(RecompilerBranchCompare CompareType, bool } if (m_CompilePC + ((int16_t)m_Opcode.offset << 2) + 4 == m_CompilePC + 8) { + m_PipelineStage = PIPELINE_STAGE_DO_DELAY_SLOT; return; } @@ -2218,8 +2219,6 @@ void CX86RecompilerOps::JAL() void CX86RecompilerOps::ADDI() { - if (m_Opcode.rt == 0) { return; } - if (g_System->bFastSP() && m_Opcode.rs == 29 && m_Opcode.rt == 29) { m_Assembler.AddConstToX86Reg(Map_MemoryStack(CX86Ops::x86_Any, true), (int16_t)m_Opcode.immediate); @@ -2227,17 +2226,36 @@ void CX86RecompilerOps::ADDI() if (IsConst(m_Opcode.rs)) { - if (IsMapped(m_Opcode.rt)) + int32_t rs = GetMipsRegLo(m_Opcode.rs); + int32_t imm = (int16_t)m_Opcode.immediate; + int32_t sum = rs + imm; + if ((~(rs ^ imm) & (rs ^ sum)) & 0x80000000) { - UnMap_GPR(m_Opcode.rt, false); + m_RegWorkingSet.SetBlockCycleCount(m_RegWorkingSet.GetBlockCycleCount() + g_System->CountPerOp()); + CompileExit(m_CompilePC, m_CompilePC, m_RegWorkingSet, CExitInfo::Exit_ExceptionOverflow, true, nullptr); + m_PipelineStage = PIPELINE_STAGE_END_BLOCK; + } + else if (m_Opcode.rt != 0) + { + if (IsMapped(m_Opcode.rt)) + { + UnMap_GPR(m_Opcode.rt, false); + } + m_RegWorkingSet.SetMipsRegLo(m_Opcode.rt, sum); + m_RegWorkingSet.SetMipsRegState(m_Opcode.rt, CRegInfo::STATE_CONST_32_SIGN); } - m_RegWorkingSet.SetMipsRegLo(m_Opcode.rt, GetMipsRegLo(m_Opcode.rs) + (int16_t)m_Opcode.immediate); - m_RegWorkingSet.SetMipsRegState(m_Opcode.rt, CRegInfo::STATE_CONST_32_SIGN); } else { - Map_GPR_32bit(m_Opcode.rt, true, m_Opcode.rs); - m_Assembler.AddConstToX86Reg(GetMipsRegMapLo(m_Opcode.rt), (int16_t)m_Opcode.immediate); + ProtectGPR(m_Opcode.rt); + CX86Ops::x86Reg Reg = Map_TempReg(CX86Ops::x86_Any, m_Opcode.rs, false); + m_Assembler.AddConstToX86Reg(Reg, (int16_t)m_Opcode.immediate); + CompileExit(m_CompilePC, m_CompilePC, m_RegWorkingSet, CExitInfo::Exit_ExceptionOverflow, false, &CX86Ops::JoLabel32); + if (m_Opcode.rt != 0) + { + Map_GPR_32bit(m_Opcode.rt, true, -1); + m_Assembler.MoveX86RegToX86Reg(Reg, GetMipsRegMapLo(m_Opcode.rt)); + } } if (g_System->bFastSP() && m_Opcode.rt == 29 && m_Opcode.rs != 29) { @@ -2619,7 +2637,7 @@ void CX86RecompilerOps::DADDI() UnMap_GPR(m_Opcode.rs, true); } - if (m_Opcode.rs != 0) + if (m_Opcode.rt != 0) { UnMap_GPR(m_Opcode.rt, true); } @@ -4523,13 +4541,6 @@ void CX86RecompilerOps::SPECIAL_DSLLV() { return; } - - if (IsConst(m_Opcode.rs)) - { - //uint32_t Shift = (GetMipsRegLo(m_Opcode.rs) & 0x3F); - CX86RecompilerOps::UnknownOpcode(); - return; - } Map_TempReg(CX86Ops::x86_ECX, m_Opcode.rs, false); m_Assembler.AndConstToX86Reg(CX86Ops::x86_ECX, 0x3F); Map_GPR_64bit(m_Opcode.rd, m_Opcode.rt); @@ -4591,12 +4602,6 @@ void CX86RecompilerOps::SPECIAL_DSRLV() } return; } - if (m_Opcode.rd == m_Opcode.rt) - { - CX86RecompilerOps::UnknownOpcode(); - return; - } - Map_TempReg(CX86Ops::x86_ECX, -1, false); m_Assembler.MoveConstToX86reg(Shift, CX86Ops::x86_ECX); Map_GPR_64bit(m_Opcode.rd, m_Opcode.rt); @@ -4650,13 +4655,6 @@ void CX86RecompilerOps::SPECIAL_DSRAV() { return; } - - if (IsConst(m_Opcode.rs)) - { - //uint32_t Shift = (GetMipsRegLo(m_Opcode.rs) & 0x3F); - CX86RecompilerOps::UnknownOpcode(); - return; - } Map_TempReg(CX86Ops::x86_ECX, m_Opcode.rs, false); m_Assembler.AndConstToX86Reg(CX86Ops::x86_ECX, 0x3F); Map_GPR_64bit(m_Opcode.rd, m_Opcode.rt); @@ -5127,44 +5125,56 @@ void CX86RecompilerOps::SPECIAL_DDIVU() void CX86RecompilerOps::SPECIAL_ADD() { - if (m_Opcode.rd == 0) - { - return; - } - int source1 = m_Opcode.rd == m_Opcode.rt ? m_Opcode.rt : m_Opcode.rs; int source2 = m_Opcode.rd == m_Opcode.rt ? m_Opcode.rs : m_Opcode.rt; if (IsConst(source1) && IsConst(source2)) { - uint32_t temp = GetMipsRegLo(source1) + GetMipsRegLo(source2); - if (IsMapped(m_Opcode.rd)) + int32_t Val1 = GetMipsRegLo(source1); + int32_t Val2 = GetMipsRegLo(source2); + int32_t Sum = Val1 + Val2; + if ((~(Val1 ^ Val2) & (Val1 ^ Sum)) & 0x80000000) { - UnMap_GPR(m_Opcode.rd, false); + m_RegWorkingSet.SetBlockCycleCount(m_RegWorkingSet.GetBlockCycleCount() + g_System->CountPerOp()); + CompileExit(m_CompilePC, m_CompilePC, m_RegWorkingSet, CExitInfo::Exit_ExceptionOverflow, true, nullptr); + m_PipelineStage = PIPELINE_STAGE_END_BLOCK; + } + else if (m_Opcode.rd != 0) + { + if (IsMapped(m_Opcode.rd)) + { + UnMap_GPR(m_Opcode.rd, false); + } + m_RegWorkingSet.SetMipsRegLo(m_Opcode.rd, Sum); + m_RegWorkingSet.SetMipsRegState(m_Opcode.rd, CRegInfo::STATE_CONST_32_SIGN); } - - m_RegWorkingSet.SetMipsRegLo(m_Opcode.rd, temp); - m_RegWorkingSet.SetMipsRegState(m_Opcode.rd, CRegInfo::STATE_CONST_32_SIGN); return; } - Map_GPR_32bit(m_Opcode.rd, true, source1); + ProtectGPR(m_Opcode.rd); + CX86Ops::x86Reg Reg = Map_TempReg(CX86Ops::x86_Any, source1, false); if (IsConst(source2)) { - m_Assembler.AddConstToX86Reg(GetMipsRegMapLo(m_Opcode.rd), GetMipsRegLo(source2)); + m_Assembler.AddConstToX86Reg(Reg, GetMipsRegLo(source2)); } else if (IsKnown(source2) && IsMapped(source2)) { - m_Assembler.AddX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rd), GetMipsRegMapLo(source2)); + m_Assembler.AddX86RegToX86Reg(Reg, GetMipsRegMapLo(source2)); } else { - m_Assembler.AddVariableToX86reg(GetMipsRegMapLo(m_Opcode.rd), &_GPR[source2].W[0], CRegName::GPR_Lo[source2]); + m_Assembler.AddVariableToX86reg(Reg, &_GPR[source2].W[0], CRegName::GPR_Lo[source2]); } if (g_System->bFastSP() && m_Opcode.rd == 29) { ResetMemoryStack(); } + CompileExit(m_CompilePC, m_CompilePC, m_RegWorkingSet, CExitInfo::Exit_ExceptionOverflow, false, &CX86Ops::JoLabel32); + if (m_Opcode.rd != 0) + { + Map_GPR_32bit(m_Opcode.rd, true, -1); + m_Assembler.MoveX86RegToX86Reg(Reg, GetMipsRegMapLo(m_Opcode.rd)); + } } void CX86RecompilerOps::SPECIAL_ADDU() @@ -5210,44 +5220,49 @@ void CX86RecompilerOps::SPECIAL_ADDU() void CX86RecompilerOps::SPECIAL_SUB() { - if (m_Opcode.rd == 0) - { - return; - } - if (IsConst(m_Opcode.rt) && IsConst(m_Opcode.rs)) { - uint32_t temp = GetMipsRegLo(m_Opcode.rs) - GetMipsRegLo(m_Opcode.rt); + int32_t rs = GetMipsRegLo(m_Opcode.rs); + int32_t rt = GetMipsRegLo(m_Opcode.rt); + int32_t sub = rs - rt; - if (IsMapped(m_Opcode.rd)) + if (((rs ^ rt) & (rs ^ sub)) & 0x80000000) { - UnMap_GPR(m_Opcode.rd, false); + m_RegWorkingSet.SetBlockCycleCount(m_RegWorkingSet.GetBlockCycleCount() + g_System->CountPerOp()); + CompileExit(m_CompilePC, m_CompilePC, m_RegWorkingSet, CExitInfo::Exit_ExceptionOverflow, true, nullptr); + m_PipelineStage = PIPELINE_STAGE_END_BLOCK; + } + else if (m_Opcode.rd != 0) + { + if (IsMapped(m_Opcode.rd)) + { + UnMap_GPR(m_Opcode.rd, false); + } + m_RegWorkingSet.SetMipsRegLo(m_Opcode.rd, sub); + m_RegWorkingSet.SetMipsRegState(m_Opcode.rd, CRegInfo::STATE_CONST_32_SIGN); } - - m_RegWorkingSet.SetMipsRegLo(m_Opcode.rd, temp); - m_RegWorkingSet.SetMipsRegState(m_Opcode.rd, CRegInfo::STATE_CONST_32_SIGN); } else { - if (m_Opcode.rd == m_Opcode.rt) - { - CX86Ops::x86Reg Reg = Map_TempReg(CX86Ops::x86_Any, m_Opcode.rt, false); - Map_GPR_32bit(m_Opcode.rd, true, m_Opcode.rs); - m_Assembler.SubX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rd), Reg); - return; - } - Map_GPR_32bit(m_Opcode.rd, true, m_Opcode.rs); + ProtectGPR(m_Opcode.rd); + CX86Ops::x86Reg Reg = Map_TempReg(CX86Ops::x86_Any, m_Opcode.rs, false); if (IsConst(m_Opcode.rt)) { - m_Assembler.SubConstFromX86Reg(GetMipsRegMapLo(m_Opcode.rd), GetMipsRegLo(m_Opcode.rt)); + m_Assembler.SubConstFromX86Reg(Reg, GetMipsRegLo(m_Opcode.rt)); } else if (IsMapped(m_Opcode.rt)) { - m_Assembler.SubX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rd), GetMipsRegMapLo(m_Opcode.rt)); + m_Assembler.SubX86RegToX86Reg(Reg, GetMipsRegMapLo(m_Opcode.rt)); } else { - m_Assembler.SubVariableFromX86reg(GetMipsRegMapLo(m_Opcode.rd), &_GPR[m_Opcode.rt].W[0], CRegName::GPR_Lo[m_Opcode.rt]); + m_Assembler.SubVariableFromX86reg(Reg, &_GPR[m_Opcode.rt].W[0], CRegName::GPR_Lo[m_Opcode.rt]); + } + CompileExit(m_CompilePC, m_CompilePC, m_RegWorkingSet, CExitInfo::Exit_ExceptionOverflow, false, &CX86Ops::JoLabel32); + if (m_Opcode.rd != 0) + { + Map_GPR_32bit(m_Opcode.rd, true, -1); + m_Assembler.MoveX86RegToX86Reg(Reg, GetMipsRegMapLo(m_Opcode.rd)); } } if (g_System->bFastSP() && m_Opcode.rd == 29) @@ -6597,33 +6612,36 @@ void CX86RecompilerOps::SPECIAL_SLTU() void CX86RecompilerOps::SPECIAL_DADD() { - if (m_Opcode.rd == 0) - { - return; - } - if (IsConst(m_Opcode.rt) && IsConst(m_Opcode.rs)) { - if (IsMapped(m_Opcode.rd)) + int64_t rs = Is64Bit(m_Opcode.rs) ? GetMipsReg(m_Opcode.rs) : (int64_t)GetMipsRegLo_S(m_Opcode.rs); + int64_t rt = Is64Bit(m_Opcode.rt) ? GetMipsReg(m_Opcode.rt) : (int64_t)GetMipsRegLo_S(m_Opcode.rt); + int64_t sum = rs + rt; + if ((~(rs ^ rt) & (rs ^ sum)) & 0x8000000000000000) { - UnMap_GPR(m_Opcode.rd, false); - } - - m_RegWorkingSet.SetMipsReg(m_Opcode.rd, - Is64Bit(m_Opcode.rs) ? GetMipsReg(m_Opcode.rs) : (int64_t)GetMipsRegLo_S(m_Opcode.rs) + - Is64Bit(m_Opcode.rt) ? GetMipsReg(m_Opcode.rt) : (int64_t)GetMipsRegLo_S(m_Opcode.rt) - ); - if (GetMipsRegLo_S(m_Opcode.rd) < 0 && GetMipsRegHi_S(m_Opcode.rd) == -1) - { - m_RegWorkingSet.SetMipsRegState(m_Opcode.rd, CRegInfo::STATE_CONST_32_SIGN); - } - else if (GetMipsRegLo_S(m_Opcode.rd) >= 0 && GetMipsRegHi_S(m_Opcode.rd) == 0) - { - m_RegWorkingSet.SetMipsRegState(m_Opcode.rd, CRegInfo::STATE_CONST_32_SIGN); + m_RegWorkingSet.SetBlockCycleCount(m_RegWorkingSet.GetBlockCycleCount() + g_System->CountPerOp()); + CompileExit(m_CompilePC, m_CompilePC, m_RegWorkingSet, CExitInfo::Exit_ExceptionOverflow, true, nullptr); + m_PipelineStage = PIPELINE_STAGE_END_BLOCK; } else { - m_RegWorkingSet.SetMipsRegState(m_Opcode.rd, CRegInfo::STATE_CONST_64); + if (IsMapped(m_Opcode.rd)) + { + UnMap_GPR(m_Opcode.rd, false); + } + m_RegWorkingSet.SetMipsReg(m_Opcode.rd, sum); + if (GetMipsRegLo_S(m_Opcode.rd) < 0 && GetMipsRegHi_S(m_Opcode.rd) == -1) + { + m_RegWorkingSet.SetMipsRegState(m_Opcode.rd, CRegInfo::STATE_CONST_32_SIGN); + } + else if (GetMipsRegLo_S(m_Opcode.rd) >= 0 && GetMipsRegHi_S(m_Opcode.rd) == 0) + { + m_RegWorkingSet.SetMipsRegState(m_Opcode.rd, CRegInfo::STATE_CONST_32_SIGN); + } + else + { + m_RegWorkingSet.SetMipsRegState(m_Opcode.rd, CRegInfo::STATE_CONST_64); + } } } else @@ -6631,23 +6649,35 @@ void CX86RecompilerOps::SPECIAL_DADD() int source1 = m_Opcode.rd == m_Opcode.rt ? m_Opcode.rt : m_Opcode.rs; int source2 = m_Opcode.rd == m_Opcode.rt ? m_Opcode.rs : m_Opcode.rt; - if (IsMapped(source2)) { ProtectGPR(source2); } - Map_GPR_64bit(m_Opcode.rd, source1); + ProtectGPR(source1); + ProtectGPR(source2); + CX86Ops::x86Reg RegLo = Map_TempReg(CX86Ops::x86_Any, source1, false); + CX86Ops::x86Reg RegHi = Map_TempReg(CX86Ops::x86_Any, source1, true); + if (IsConst(source2)) { - m_Assembler.AddConstToX86Reg(GetMipsRegMapLo(m_Opcode.rd), GetMipsRegLo(source2)); - m_Assembler.AddConstToX86Reg(GetMipsRegMapHi(m_Opcode.rd), GetMipsRegHi(source2)); + m_Assembler.AddConstToX86Reg(RegLo, GetMipsRegLo(source2)); + m_Assembler.AdcConstToX86Reg(RegHi, GetMipsRegHi(source2)); } else if (IsMapped(source2)) { CX86Ops::x86Reg HiReg = Is64Bit(source2) ? GetMipsRegMapHi(source2) : Map_TempReg(CX86Ops::x86_Any, source2, true); - m_Assembler.AddX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rd), GetMipsRegMapLo(source2)); - m_Assembler.AdcX86RegToX86Reg(GetMipsRegMapHi(m_Opcode.rd), HiReg); + m_Assembler.AddX86RegToX86Reg(RegLo, GetMipsRegMapLo(source2)); + m_Assembler.AdcX86RegToX86Reg(RegHi, HiReg); } else { - m_Assembler.AddVariableToX86reg(GetMipsRegMapLo(m_Opcode.rd), &_GPR[source2].W[0], CRegName::GPR_Lo[source2]); - m_Assembler.AdcVariableToX86reg(GetMipsRegMapHi(m_Opcode.rd), &_GPR[source2].W[1], CRegName::GPR_Hi[source2]); + m_Assembler.AddVariableToX86reg(RegLo, &_GPR[source2].W[0], CRegName::GPR_Lo[source2]); + m_Assembler.AdcVariableToX86reg(RegHi, &_GPR[source2].W[1], CRegName::GPR_Hi[source2]); + } + CompileExit(m_CompilePC, m_CompilePC, m_RegWorkingSet, CExitInfo::Exit_ExceptionOverflow, false, &CX86Ops::JoLabel32); + if (m_Opcode.rd != 0) + { + UnProtectGPR(source1); + UnProtectGPR(source2); + Map_GPR_64bit(m_Opcode.rd, source1); + m_Assembler.MoveX86RegToX86Reg(RegLo, GetMipsRegMapLo(m_Opcode.rd)); + m_Assembler.MoveX86RegToX86Reg(RegHi, GetMipsRegMapHi(m_Opcode.rd)); } } } @@ -6716,64 +6746,73 @@ void CX86RecompilerOps::SPECIAL_DADDU() void CX86RecompilerOps::SPECIAL_DSUB() { - if (m_Opcode.rd == 0) - { - return; - } - if (IsConst(m_Opcode.rt) && IsConst(m_Opcode.rs)) { - if (IsMapped(m_Opcode.rd)) - { - UnMap_GPR(m_Opcode.rd, false); - } + int64_t rs = Is64Bit(m_Opcode.rs) ? GetMipsReg(m_Opcode.rs) : (int64_t)GetMipsRegLo_S(m_Opcode.rs); + int64_t rt = Is64Bit(m_Opcode.rt) ? GetMipsReg(m_Opcode.rt) : (int64_t)GetMipsRegLo_S(m_Opcode.rt); + int64_t sub = rs - rt; - m_RegWorkingSet.SetMipsReg(m_Opcode.rd, - Is64Bit(m_Opcode.rs) ? GetMipsReg(m_Opcode.rs) : (int64_t)GetMipsRegLo_S(m_Opcode.rs) - - Is64Bit(m_Opcode.rt) ? GetMipsReg(m_Opcode.rt) : (int64_t)GetMipsRegLo_S(m_Opcode.rt) - ); - if (GetMipsRegLo_S(m_Opcode.rd) < 0 && GetMipsRegHi_S(m_Opcode.rd) == -1) + if (((rs ^ rt) & (rs ^ sub)) & 0x8000000000000000) { - m_RegWorkingSet.SetMipsRegState(m_Opcode.rd, CRegInfo::STATE_CONST_32_SIGN); - } - else if (GetMipsRegLo_S(m_Opcode.rd) >= 0 && GetMipsRegHi_S(m_Opcode.rd) == 0) - { - m_RegWorkingSet.SetMipsRegState(m_Opcode.rd, CRegInfo::STATE_CONST_32_SIGN); + m_RegWorkingSet.SetBlockCycleCount(m_RegWorkingSet.GetBlockCycleCount() + g_System->CountPerOp()); + CompileExit(m_CompilePC, m_CompilePC, m_RegWorkingSet, CExitInfo::Exit_ExceptionOverflow, true, nullptr); + m_PipelineStage = PIPELINE_STAGE_END_BLOCK; } else { - m_RegWorkingSet.SetMipsRegState(m_Opcode.rd, CRegInfo::STATE_CONST_64); + if (IsMapped(m_Opcode.rd)) + { + UnMap_GPR(m_Opcode.rd, false); + } + m_RegWorkingSet.SetMipsReg(m_Opcode.rd, sub); + if (GetMipsRegLo_S(m_Opcode.rd) < 0 && GetMipsRegHi_S(m_Opcode.rd) == -1) + { + m_RegWorkingSet.SetMipsRegState(m_Opcode.rd, CRegInfo::STATE_CONST_32_SIGN); + } + else if (GetMipsRegLo_S(m_Opcode.rd) >= 0 && GetMipsRegHi_S(m_Opcode.rd) == 0) + { + m_RegWorkingSet.SetMipsRegState(m_Opcode.rd, CRegInfo::STATE_CONST_32_SIGN); + } + else + { + m_RegWorkingSet.SetMipsRegState(m_Opcode.rd, CRegInfo::STATE_CONST_64); + } } } else { - if (m_Opcode.rd == m_Opcode.rt) - { - CX86Ops::x86Reg HiReg = Map_TempReg(CX86Ops::x86_Any, m_Opcode.rt, true); - CX86Ops::x86Reg LoReg = Map_TempReg(CX86Ops::x86_Any, m_Opcode.rt, false); - Map_GPR_64bit(m_Opcode.rd, m_Opcode.rs); - m_Assembler.SubX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rd), LoReg); - m_Assembler.SbbX86RegToX86Reg(GetMipsRegMapHi(m_Opcode.rd), HiReg); - return; - } + int source1 = m_Opcode.rd == m_Opcode.rt ? m_Opcode.rt : m_Opcode.rs; + int source2 = m_Opcode.rd == m_Opcode.rt ? m_Opcode.rs : m_Opcode.rt; - if (IsMapped(m_Opcode.rt)) { ProtectGPR(m_Opcode.rt); } - Map_GPR_64bit(m_Opcode.rd, m_Opcode.rs); - if (IsConst(m_Opcode.rt)) + ProtectGPR(source1); + ProtectGPR(source2); + CX86Ops::x86Reg RegLo = Map_TempReg(CX86Ops::x86_Any, source1, false); + CX86Ops::x86Reg RegHi = Map_TempReg(CX86Ops::x86_Any, source1, true); + + if (IsConst(source2)) { - m_Assembler.SubConstFromX86Reg(GetMipsRegMapLo(m_Opcode.rd), GetMipsRegLo(m_Opcode.rt)); - m_Assembler.SbbConstFromX86Reg(GetMipsRegMapHi(m_Opcode.rd), GetMipsRegHi(m_Opcode.rt)); + m_Assembler.SubConstFromX86Reg(RegLo, GetMipsRegLo(source2)); + m_Assembler.SbbConstFromX86Reg(RegHi, GetMipsRegHi(source2)); } - else if (IsMapped(m_Opcode.rt)) + else if (IsMapped(source2)) { - CX86Ops::x86Reg HiReg = Is64Bit(m_Opcode.rt) ? GetMipsRegMapHi(m_Opcode.rt) : Map_TempReg(CX86Ops::x86_Any, m_Opcode.rt, true); - m_Assembler.SubX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rd), GetMipsRegMapLo(m_Opcode.rt)); - m_Assembler.SbbX86RegToX86Reg(GetMipsRegMapHi(m_Opcode.rd), HiReg); + CX86Ops::x86Reg HiReg = Is64Bit(source2) ? GetMipsRegMapHi(source2) : Map_TempReg(CX86Ops::x86_Any, source2, true); + m_Assembler.SubX86RegToX86Reg(RegLo, GetMipsRegMapLo(source2)); + m_Assembler.SbbX86RegToX86Reg(RegHi, HiReg); } else { - m_Assembler.SubVariableFromX86reg(GetMipsRegMapLo(m_Opcode.rd), &_GPR[m_Opcode.rt].W[0], CRegName::GPR_Lo[m_Opcode.rt]); - m_Assembler.SbbVariableFromX86reg(GetMipsRegMapHi(m_Opcode.rd), &_GPR[m_Opcode.rt].W[1], CRegName::GPR_Hi[m_Opcode.rt]); + m_Assembler.SubVariableFromX86reg(RegLo, &_GPR[source2].W[0], CRegName::GPR_Lo[source2]); + m_Assembler.SbbVariableFromX86reg(RegHi, &_GPR[source2].W[1], CRegName::GPR_Hi[source2]); + } + CompileExit(m_CompilePC, m_CompilePC, m_RegWorkingSet, CExitInfo::Exit_ExceptionOverflow, false, &CX86Ops::JoLabel32); + if (m_Opcode.rd != 0) + { + UnProtectGPR(source1); + UnProtectGPR(source2); + Map_GPR_64bit(m_Opcode.rd, source1); + m_Assembler.MoveX86RegToX86Reg(RegLo, GetMipsRegMapLo(m_Opcode.rd)); + m_Assembler.MoveX86RegToX86Reg(RegHi, GetMipsRegMapHi(m_Opcode.rd)); } } } @@ -9513,6 +9552,11 @@ void CX86RecompilerOps::CompileExit(uint32_t JumpPC, uint32_t TargetPC, CRegInfo m_Assembler.X86BreakPoint(__FILE__, __LINE__); ExitCodeBlock(); break; + case CExitInfo::Exit_ExceptionOverflow: + m_Assembler.PushImm32(m_PipelineStage == PIPELINE_STAGE_JUMP || m_PipelineStage == PIPELINE_STAGE_DELAY_SLOT); + m_Assembler.CallThis((uint32_t)g_Reg, AddressOf(&CRegisters::DoOverflowException), "CRegisters::DoOverflowException", 12); + ExitCodeBlock(); + break; default: WriteTrace(TraceRecompiler, TraceError, "How did you want to exit on reason (%d) ???", reason); g_Notify->BreakPoint(__FILE__, __LINE__); diff --git a/Source/Project64-core/N64System/Recompiler/x86/x86ops.cpp b/Source/Project64-core/N64System/Recompiler/x86/x86ops.cpp index a94632afd..36a61a7ee 100644 --- a/Source/Project64-core/N64System/Recompiler/x86/x86ops.cpp +++ b/Source/Project64-core/N64System/Recompiler/x86/x86ops.cpp @@ -630,6 +630,13 @@ void CX86Ops::JsLabel32(const char *Label, uint32_t Value) AddCode32(Value); } +void CX86Ops::JoLabel32(const char *Label, uint32_t Value) +{ + CodeLog(" jo $%s", Label); + AddCode16(0x800F); + AddCode32(Value); +} + void CX86Ops::JzLabel8(const char *Label, uint8_t Value) { CodeLog(" jz $%s", Label); diff --git a/Source/Project64-core/N64System/Recompiler/x86/x86ops.h b/Source/Project64-core/N64System/Recompiler/x86/x86ops.h index b07eb6741..1470f67eb 100644 --- a/Source/Project64-core/N64System/Recompiler/x86/x86ops.h +++ b/Source/Project64-core/N64System/Recompiler/x86/x86ops.h @@ -114,6 +114,7 @@ public: void JnsLabel32(const char * Label, uint32_t Value); void JnzLabel8(const char * Label, uint8_t Value); void JnzLabel32(const char * Label, uint32_t Value); + void JoLabel32(const char * Label, uint32_t Value); void JsLabel32(const char * Label, uint32_t Value); void JzLabel8(const char * Label, uint8_t Value); void JzLabel32(const char * Label, uint32_t Value);