Core: get COP1_D_CMP to work in recompiler

This commit is contained in:
zilmar 2024-04-11 18:14:44 +09:30
parent 9272ac05f6
commit 0cf4c7dc11
1 changed files with 158 additions and 71 deletions

View File

@ -8586,6 +8586,92 @@ void CX86RecompilerOps::COP1_D_CVT_L()
} }
void CX86RecompilerOps::COP1_D_CMP() void CX86RecompilerOps::COP1_D_CMP()
{
if (FpuExceptionInRecompiler())
{
CompileInitFpuOperation(CRegBase::RoundUnknown);
if (m_RegWorkingSet.RegInStack(m_Opcode.fs, CRegInfo::FPU_Any) || m_RegWorkingSet.RegInStack(m_Opcode.fd, CRegInfo::FPU_Any))
{
g_Notify->BreakPoint(__FILE__, __LINE__);
return;
}
if (m_RegWorkingSet.IsFPStatusRegMapped())
{
m_Assembler.and_(m_RegWorkingSet.Map_FPStatusReg(), (uint32_t)~FPCSR_C);
}
else
{
m_Assembler.AndConstToVariable(&m_Reg.m_FPCR[31], "_FPCR[31]", (uint32_t)~FPCSR_C);
}
m_RegWorkingSet.Map_TempReg(asmjit::x86::eax, 0, false, false);
asmjit::x86::Gp StatusReg = m_RegWorkingSet.Map_FPStatusReg();
asmjit::x86::Gp TempRegValue = m_RegWorkingSet.Map_TempReg(x86Reg_Unknown, -1, false, true);
asmjit::x86::Gp FsPtr = m_RegWorkingSet.FPRValuePointer(m_Opcode.fs, CRegInfo::FPU_Double);
asmjit::x86::Gp FtPtr = m_RegWorkingSet.FPRValuePointer(m_Opcode.ft, CRegInfo::FPU_UnsignedDoubleWord);
m_Assembler.fpuLoadQwordFromX86Reg(m_RegWorkingSet.StackTopPos(), FtPtr);
m_Assembler.fpuLoadQwordFromX86Reg(m_RegWorkingSet.StackTopPos(), FsPtr);
m_Assembler.fucompp();
m_Assembler.fstsw(asmjit::x86::ax);
m_Assembler.sahf();
asmjit::Label NotNanLabel = m_Assembler.newLabel();
m_Assembler.JnpLabel("NotNan", NotNanLabel);
//is Nan
asmjit::Label NotQuietNanLabel;
if ((m_Opcode.funct & 8) == 0)
{
//check QuietNan
NotQuietNanLabel = m_Assembler.newLabel();
asmjit::Label FsIsQuietNan = m_Assembler.newLabel();
m_Assembler.mov(TempRegValue, asmjit::x86::dword_ptr(FsPtr));
m_Assembler.cmp(TempRegValue, 0x7FC00000);
m_Assembler.JgeLabel("FsIsQuietNan", FsIsQuietNan);
m_Assembler.mov(TempRegValue, asmjit::x86::dword_ptr(FtPtr));
m_Assembler.cmp(TempRegValue, 0x7FC00000);
m_Assembler.JlLabel("FsIsQuietNan", NotQuietNanLabel);
m_Assembler.bind(FsIsQuietNan);
}
m_Assembler.or_(StatusReg, (uint32_t)FPCSR_CV);
m_Assembler.test(StatusReg, FPCSR_EV);
CRegInfo ExitRegSet = m_RegWorkingSet;
ExitRegSet.SetBlockCycleCount(ExitRegSet.GetBlockCycleCount() + g_System->CountPerOp());
CompileExit((uint32_t)-1, (uint32_t)-1, ExitRegSet, ExitReason_ExceptionFloatingPoint, false, &CX86Ops::JnzLabel);
m_Assembler.or_(StatusReg, (uint32_t)FPCSR_FV);
if ((m_Opcode.funct & 8) == 0)
{
m_Assembler.bind(NotQuietNanLabel);
}
if ((m_Opcode.funct & 1) != 0)
{
m_Assembler.or_(StatusReg, (uint32_t)FPCSR_C);
}
uint32_t cmp = 0;
if ((m_Opcode.funct & 2) != 0)
{
cmp |= 0x4000;
}
if ((m_Opcode.funct & 4) != 0)
{
cmp |= 0x0100;
}
asmjit::Label IsNanSkipCompare = m_Assembler.newLabel();
if (cmp != 0)
{
m_Assembler.JmpLabel("IsNanSkipCompare", IsNanSkipCompare);
}
m_Assembler.bind(NotNanLabel);
if (cmp != 0)
{
m_Assembler.xor_(TempRegValue, TempRegValue);
m_Assembler.test(asmjit::x86::eax, cmp);
m_Assembler.setnz(TempRegValue);
m_Assembler.shl(TempRegValue, 23);
m_Assembler.or_(StatusReg, TempRegValue);
m_Assembler.bind(IsNanSkipCompare);
}
}
else
{ {
uint32_t Reg1 = m_Opcode.fs; uint32_t Reg1 = m_Opcode.fs;
uint32_t Reg2 = m_Opcode.ft; uint32_t Reg2 = m_Opcode.ft;
@ -8668,6 +8754,7 @@ void CX86RecompilerOps::COP1_D_CMP()
m_Assembler.OrX86RegToVariable(&m_Reg.m_FPCR[31], "_FPCR[31]", Reg); m_Assembler.OrX86RegToVariable(&m_Reg.m_FPCR[31], "_FPCR[31]", Reg);
} }
} }
}
// COP1: W functions // COP1: W functions
void CX86RecompilerOps::COP1_W_CVT_S() void CX86RecompilerOps::COP1_W_CVT_S()