Play-/Source/COP_FPU.cpp
2010-10-08 00:27:22 +00:00

497 lines
14 KiB
C++

#include <string.h>
#include <stdio.h>
#include "COP_FPU.h"
#include "MIPS.h"
#include "Jitter.h"
#include "offsetof_def.h"
#include "MemoryUtils.h"
uint32 CCOP_FPU::m_nCCMask[8] =
{
0x00800000,
0x02000000,
0x04000000,
0x08000000,
0x10000000,
0x20000000,
0x40000000,
0x80000000
};
CCOP_FPU::CCOP_FPU(MIPS_REGSIZE nRegSize) :
CMIPSCoprocessor(nRegSize),
m_nFT(0),
m_nFS(0),
m_nFD(0)
{
SetupReflectionTables();
}
void CCOP_FPU::CompileInstruction(uint32 nAddress, CMipsJitter* codeGen, CMIPS* pCtx)
{
SetupQuickVariables(nAddress, codeGen, pCtx);
m_nFT = (uint8)((m_nOpcode >> 16) & 0x1F);
m_nFS = (uint8)((m_nOpcode >> 11) & 0x1F);
m_nFD = (uint8)((m_nOpcode >> 6) & 0x1F);
switch((m_nOpcode >> 26) & 0x3F)
{
case 0x11:
//COP1
((this)->*(m_pOpGeneral[(m_nOpcode >> 21) & 0x1F]))();
break;
case 0x31:
LWC1();
break;
case 0x39:
SWC1();
break;
default:
Illegal();
break;
}
}
void CCOP_FPU::SetCCBit(bool nCondition, uint32 nMask)
{
m_codeGen->PushCst(0);
m_codeGen->BeginIf(nCondition ? Jitter::CONDITION_NE : Jitter::CONDITION_EQ);
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nFCSR));
m_codeGen->PushCst(nMask);
m_codeGen->Or();
m_codeGen->PullRel(offsetof(CMIPS, m_State.nFCSR));
}
m_codeGen->Else();
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nFCSR));
m_codeGen->PushCst(~nMask);
m_codeGen->And();
m_codeGen->PullRel(offsetof(CMIPS, m_State.nFCSR));
}
m_codeGen->EndIf();
}
void CCOP_FPU::PushCCBit(uint32 nMask)
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nFCSR));
m_codeGen->PushCst(nMask);
m_codeGen->And();
}
//////////////////////////////////////////////////
//General Opcodes
//////////////////////////////////////////////////
//00
void CCOP_FPU::MFC1()
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nCOP10[m_nFS * 2]));
if(m_regSize == MIPS_REGSIZE_64)
{
m_codeGen->PushTop();
m_codeGen->SignExt();
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nFT].nV[1]));
}
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nFT].nV[0]));
}
//02
void CCOP_FPU::CFC1()
{
if(m_nFS == 31)
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nFCSR));
m_codeGen->SignExt();
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nFT].nV[1]));
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nFT].nV[0]));
}
else
{
assert(0);
}
}
//04
void CCOP_FPU::MTC1()
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nFT].nV[0]));
m_codeGen->PullRel(offsetof(CMIPS, m_State.nCOP10[m_nFS * 2]));
}
//06
void CCOP_FPU::CTC1()
{
if(m_nFS == 31)
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nFT].nV[0]));
m_codeGen->PullRel(offsetof(CMIPS, m_State.nFCSR));
}
else
{
assert(0);
}
}
//08
void CCOP_FPU::BC1()
{
switch((m_nOpcode >> 16) & 0x03)
{
case 0x00:
BC1F();
break;
case 0x01:
BC1T();
break;
case 0x02:
BC1FL();
break;
case 0x03:
BC1TL();
break;
default:
Illegal();
break;
}
}
//10
void CCOP_FPU::S()
{
((this)->*(m_pOpSingle[(m_nOpcode & 0x3F)]))();
}
//14
void CCOP_FPU::W()
{
((this)->*(m_pOpWord[(m_nOpcode & 0x3F)]))();
}
//////////////////////////////////////////////////
//Branch Opcodes
//////////////////////////////////////////////////
//00
void CCOP_FPU::BC1F()
{
PushCCBit(m_nCCMask[(m_nOpcode >> 18) & 0x07]);
m_codeGen->PushCst(0);
Branch(Jitter::CONDITION_EQ);
}
//01
void CCOP_FPU::BC1T()
{
PushCCBit(m_nCCMask[(m_nOpcode >> 18) & 0x07]);
m_codeGen->PushCst(0);
Branch(Jitter::CONDITION_NE);
}
//02
void CCOP_FPU::BC1FL()
{
PushCCBit(m_nCCMask[(m_nOpcode >> 18) & 0x07]);
m_codeGen->PushCst(0);
BranchLikely(Jitter::CONDITION_EQ);
}
//03
void CCOP_FPU::BC1TL()
{
PushCCBit(m_nCCMask[(m_nOpcode >> 18) & 0x07]);
m_codeGen->PushCst(0);
BranchLikely(Jitter::CONDITION_NE);
}
//////////////////////////////////////////////////
//Single Precision Floating Point Opcodes
//////////////////////////////////////////////////
//00
void CCOP_FPU::ADD_S()
{
m_codeGen->FP_PushSingle(offsetof(CMIPS, m_State.nCOP10[m_nFS * 2]));
m_codeGen->FP_PushSingle(offsetof(CMIPS, m_State.nCOP10[m_nFT * 2]));
m_codeGen->FP_Add();
m_codeGen->FP_PullSingle(offsetof(CMIPS, m_State.nCOP10[m_nFD * 2]));
}
//01
void CCOP_FPU::SUB_S()
{
m_codeGen->FP_PushSingle(offsetof(CMIPS, m_State.nCOP10[m_nFS * 2]));
m_codeGen->FP_PushSingle(offsetof(CMIPS, m_State.nCOP10[m_nFT * 2]));
m_codeGen->FP_Sub();
m_codeGen->FP_PullSingle(offsetof(CMIPS, m_State.nCOP10[m_nFD * 2]));
}
//02
void CCOP_FPU::MUL_S()
{
m_codeGen->FP_PushSingle(offsetof(CMIPS, m_State.nCOP10[m_nFS * 2]));
m_codeGen->FP_PushSingle(offsetof(CMIPS, m_State.nCOP10[m_nFT * 2]));
m_codeGen->FP_Mul();
m_codeGen->FP_PullSingle(offsetof(CMIPS, m_State.nCOP10[m_nFD * 2]));
}
//03
void CCOP_FPU::DIV_S()
{
//Check if FT equals to 0
m_codeGen->PushRel(offsetof(CMIPS, m_State.nCOP10[m_nFT * 2]));
m_codeGen->PushCst(0);
m_codeGen->BeginIf(Jitter::CONDITION_EQ);
{
m_codeGen->PushCst(0x7F7FFFFF);
m_codeGen->PullRel(offsetof(CMIPS, m_State.nCOP10[m_nFD * 2]));
}
m_codeGen->Else();
{
m_codeGen->FP_PushSingle(offsetof(CMIPS, m_State.nCOP10[m_nFS * 2]));
m_codeGen->FP_PushSingle(offsetof(CMIPS, m_State.nCOP10[m_nFT * 2]));
m_codeGen->FP_Div();
m_codeGen->FP_PullSingle(offsetof(CMIPS, m_State.nCOP10[m_nFD * 2]));
}
m_codeGen->EndIf();
}
//04
void CCOP_FPU::SQRT_S()
{
m_codeGen->FP_PushSingle(offsetof(CMIPS, m_State.nCOP10[m_nFT * 2]));
m_codeGen->FP_Sqrt();
m_codeGen->FP_PullSingle(offsetof(CMIPS, m_State.nCOP10[m_nFD * 2]));
}
//05
void CCOP_FPU::ABS_S()
{
m_codeGen->FP_PushSingle(offsetof(CMIPS, m_State.nCOP10[m_nFS * 2]));
m_codeGen->FP_Abs();
m_codeGen->FP_PullSingle(offsetof(CMIPS, m_State.nCOP10[m_nFD * 2]));
}
//06
void CCOP_FPU::MOV_S()
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nCOP10[m_nFS * 2]));
m_codeGen->PullRel(offsetof(CMIPS, m_State.nCOP10[m_nFD * 2]));
}
//07
void CCOP_FPU::NEG_S()
{
m_codeGen->FP_PushSingle(offsetof(CMIPS, m_State.nCOP10[m_nFS * 2]));
m_codeGen->FP_Neg();
m_codeGen->FP_PullSingle(offsetof(CMIPS, m_State.nCOP10[m_nFD * 2]));
}
//0D
void CCOP_FPU::TRUNC_W_S()
{
m_codeGen->FP_PushSingle(offsetof(CMIPS, m_State.nCOP10[m_nFS * 2]));
m_codeGen->FP_PullWordTruncate(offsetof(CMIPS, m_State.nCOP10[m_nFD * 2]));
}
//18
void CCOP_FPU::ADDA_S()
{
m_codeGen->FP_PushSingle(offsetof(CMIPS, m_State.nCOP10[m_nFS * 2]));
m_codeGen->FP_PushSingle(offsetof(CMIPS, m_State.nCOP10[m_nFT * 2]));
m_codeGen->FP_Add();
m_codeGen->FP_PullSingle(offsetof(CMIPS, m_State.nCOP1A));
}
//1A
void CCOP_FPU::MULA_S()
{
m_codeGen->FP_PushSingle(offsetof(CMIPS, m_State.nCOP10[m_nFS * 2]));
m_codeGen->FP_PushSingle(offsetof(CMIPS, m_State.nCOP10[m_nFT * 2]));
m_codeGen->FP_Mul();
m_codeGen->FP_PullSingle(offsetof(CMIPS, m_State.nCOP1A));
}
//1C
void CCOP_FPU::MADD_S()
{
m_codeGen->FP_PushSingle(offsetof(CMIPS, m_State.nCOP1A));
m_codeGen->FP_PushSingle(offsetof(CMIPS, m_State.nCOP10[m_nFS * 2]));
m_codeGen->FP_PushSingle(offsetof(CMIPS, m_State.nCOP10[m_nFT * 2]));
m_codeGen->FP_Mul();
m_codeGen->FP_Add();
m_codeGen->FP_PullSingle(offsetof(CMIPS, m_State.nCOP10[m_nFD * 2]));
}
//1D
void CCOP_FPU::MSUB_S()
{
m_codeGen->FP_PushSingle(offsetof(CMIPS, m_State.nCOP1A));
m_codeGen->FP_PushSingle(offsetof(CMIPS, m_State.nCOP10[m_nFS * 2]));
m_codeGen->FP_PushSingle(offsetof(CMIPS, m_State.nCOP10[m_nFT * 2]));
m_codeGen->FP_Mul();
m_codeGen->FP_Sub();
m_codeGen->FP_PullSingle(offsetof(CMIPS, m_State.nCOP10[m_nFD * 2]));
}
//24
void CCOP_FPU::CVT_W_S()
{
//Load the rounding mode from FCSR?
//PS2 only supports truncate rounding mode
m_codeGen->FP_PushSingle(offsetof(CMIPS, m_State.nCOP10[m_nFS * 2]));
m_codeGen->FP_PullWordTruncate(offsetof(CMIPS, m_State.nCOP10[m_nFD * 2]));
}
//28
void CCOP_FPU::MAX_S()
{
m_codeGen->FP_PushSingle(offsetof(CMIPS, m_State.nCOP10[m_nFS * 2]));
m_codeGen->FP_PushSingle(offsetof(CMIPS, m_State.nCOP10[m_nFT * 2]));
m_codeGen->FP_Max();
m_codeGen->FP_PullSingle(offsetof(CMIPS, m_State.nCOP10[m_nFD * 2]));
}
//29
void CCOP_FPU::MIN_S()
{
m_codeGen->FP_PushSingle(offsetof(CMIPS, m_State.nCOP10[m_nFS * 2]));
m_codeGen->FP_PushSingle(offsetof(CMIPS, m_State.nCOP10[m_nFT * 2]));
m_codeGen->FP_Min();
m_codeGen->FP_PullSingle(offsetof(CMIPS, m_State.nCOP10[m_nFD * 2]));
}
//32
void CCOP_FPU::C_EQ_S()
{
m_codeGen->FP_PushSingle(offsetof(CMIPS, m_State.nCOP10[m_nFS * 2]));
m_codeGen->FP_PushSingle(offsetof(CMIPS, m_State.nCOP10[m_nFT * 2]));
m_codeGen->FP_Cmp(Jitter::CONDITION_EQ);
SetCCBit(true, m_nCCMask[((m_nOpcode >> 8) & 0x07)]);
}
//34
void CCOP_FPU::C_LT_S()
{
m_codeGen->FP_PushSingle(offsetof(CMIPS, m_State.nCOP10[m_nFS * 2]));
m_codeGen->FP_PushSingle(offsetof(CMIPS, m_State.nCOP10[m_nFT * 2]));
m_codeGen->FP_Cmp(Jitter::CONDITION_BL);
SetCCBit(true, m_nCCMask[((m_nOpcode >> 8) & 0x07)]);
}
//36
void CCOP_FPU::C_LE_S()
{
m_codeGen->FP_PushSingle(offsetof(CMIPS, m_State.nCOP10[m_nFS * 2]));
m_codeGen->FP_PushSingle(offsetof(CMIPS, m_State.nCOP10[m_nFT * 2]));
m_codeGen->FP_Cmp(Jitter::CONDITION_BE);
SetCCBit(true, m_nCCMask[((m_nOpcode >> 8) & 0x07)]);
}
//////////////////////////////////////////////////
//Word Sized Integer Opcodes
//////////////////////////////////////////////////
//20
void CCOP_FPU::CVT_S_W()
{
m_codeGen->FP_PushWord(offsetof(CMIPS, m_State.nCOP10[m_nFS * 2]));
m_codeGen->FP_PullSingle(offsetof(CMIPS, m_State.nCOP10[m_nFD * 2]));
}
//////////////////////////////////////////////////
//Miscellanous Opcodes
//////////////////////////////////////////////////
//31
void CCOP_FPU::LWC1()
{
ComputeMemAccessAddr();
m_codeGen->PushCtx();
m_codeGen->PushIdx(1);
m_codeGen->Call(reinterpret_cast<void*>(&CMemoryUtils::GetWordProxy), 2, true);
m_codeGen->PullRel(offsetof(CMIPS, m_State.nCOP10[m_nFT * 2]));
m_codeGen->PullTop();
}
//39
void CCOP_FPU::SWC1()
{
ComputeMemAccessAddr();
m_codeGen->PushCtx();
m_codeGen->PushRel(offsetof(CMIPS, m_State.nCOP10[m_nFT * 2]));
m_codeGen->PushIdx(2);
m_codeGen->Call(reinterpret_cast<void*>(&CMemoryUtils::SetWordProxy), 3, false);
m_codeGen->PullTop();
}
//////////////////////////////////////////////////
//Opcode Tables
//////////////////////////////////////////////////
CCOP_FPU::InstructionFuncConstant CCOP_FPU::m_pOpGeneral[0x20] =
{
//0x00
&CCOP_FPU::MFC1, &CCOP_FPU::Illegal, &CCOP_FPU::CFC1, &CCOP_FPU::Illegal, &CCOP_FPU::MTC1, &CCOP_FPU::Illegal, &CCOP_FPU::CTC1, &CCOP_FPU::Illegal,
//0x08
&CCOP_FPU::BC1, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal,
//0x10
&CCOP_FPU::S, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::W, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal,
//0x18
&CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal,
};
CCOP_FPU::InstructionFuncConstant CCOP_FPU::m_pOpSingle[0x40] =
{
//0x00
&CCOP_FPU::ADD_S, &CCOP_FPU::SUB_S, &CCOP_FPU::MUL_S, &CCOP_FPU::DIV_S, &CCOP_FPU::SQRT_S, &CCOP_FPU::ABS_S, &CCOP_FPU::MOV_S, &CCOP_FPU::NEG_S,
//0x08
&CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::TRUNC_W_S, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal,
//0x10
&CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal,
//0x18
&CCOP_FPU::ADDA_S, &CCOP_FPU::Illegal, &CCOP_FPU::MULA_S, &CCOP_FPU::Illegal, &CCOP_FPU::MADD_S, &CCOP_FPU::MSUB_S, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal,
//0x20
&CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::CVT_W_S, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal,
//0x28
&CCOP_FPU::MAX_S, &CCOP_FPU::MIN_S, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal,
//0x30
&CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::C_EQ_S, &CCOP_FPU::Illegal, &CCOP_FPU::C_LT_S, &CCOP_FPU::Illegal, &CCOP_FPU::C_LE_S, &CCOP_FPU::Illegal,
//0x38
&CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::C_LT_S, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal,
};
CCOP_FPU::InstructionFuncConstant CCOP_FPU::m_pOpWord[0x40] =
{
//0x00
&CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal,
//0x08
&CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal,
//0x10
&CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal,
//0x18
&CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal,
//0x20
&CCOP_FPU::CVT_S_W, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal,
//0x28
&CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal,
//0x30
&CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal,
//0x38
&CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal, &CCOP_FPU::Illegal,
};