mirror of
https://github.com/izzy2lost/WeeU.git
synced 2026-07-06 00:19:59 -07:00
Merge branch 'main' into android
This commit is contained in:
Vendored
+1
@@ -24,3 +24,4 @@ Comment[it]=Software per emulare giochi e applicazioni per Wii U su PC
|
||||
Categories=Game;Emulator;
|
||||
Keywords=Nintendo;
|
||||
MimeType=application/x-wii-u-rom;
|
||||
StartupWMClass=Cemu
|
||||
|
||||
@@ -55,7 +55,6 @@ add_subdirectory(audio)
|
||||
add_subdirectory(util)
|
||||
add_subdirectory(imgui)
|
||||
add_subdirectory(resource)
|
||||
add_subdirectory(asm)
|
||||
|
||||
if(ANDROID)
|
||||
add_library(CemuBin STATIC
|
||||
|
||||
@@ -468,6 +468,10 @@ add_library(CemuCafe
|
||||
OS/libs/nsyshid/Infinity.h
|
||||
OS/libs/nsyshid/Skylander.cpp
|
||||
OS/libs/nsyshid/Skylander.h
|
||||
OS/libs/nsyshid/SkylanderXbox360.cpp
|
||||
OS/libs/nsyshid/SkylanderXbox360.h
|
||||
OS/libs/nsyshid/g721/g721.cpp
|
||||
OS/libs/nsyshid/g721/g721.h
|
||||
OS/libs/nsyskbd/nsyskbd.cpp
|
||||
OS/libs/nsyskbd/nsyskbd.h
|
||||
OS/libs/nsysnet/nsysnet.cpp
|
||||
@@ -565,7 +569,6 @@ else()
|
||||
endif()
|
||||
|
||||
target_link_libraries(CemuCafe PRIVATE
|
||||
CemuAsm
|
||||
CemuAudio
|
||||
CemuCommon
|
||||
CemuComponents
|
||||
|
||||
@@ -863,7 +863,7 @@ namespace CafeSystem
|
||||
module->TitleStart();
|
||||
cemu_initForGame();
|
||||
// enter scheduler
|
||||
if (ActiveSettings::GetCPUMode() == CPUMode::MulticoreRecompiler && !LaunchSettings::ForceInterpreter())
|
||||
if ((ActiveSettings::GetCPUMode() == CPUMode::MulticoreRecompiler || LaunchSettings::ForceMultiCoreInterpreter()) && !LaunchSettings::ForceInterpreter())
|
||||
coreinit::OSSchedulerBegin(3);
|
||||
else
|
||||
coreinit::OSSchedulerBegin(1);
|
||||
|
||||
@@ -10,6 +10,18 @@ namespace Espresso
|
||||
CR_BIT_INDEX_SO = 3,
|
||||
};
|
||||
|
||||
enum class PSQ_LOAD_TYPE
|
||||
{
|
||||
TYPE_F32 = 0,
|
||||
TYPE_UNUSED1 = 1,
|
||||
TYPE_UNUSED2 = 2,
|
||||
TYPE_UNUSED3 = 3,
|
||||
TYPE_U8 = 4,
|
||||
TYPE_U16 = 5,
|
||||
TYPE_S8 = 6,
|
||||
TYPE_S16 = 7,
|
||||
};
|
||||
|
||||
enum class PrimaryOpcode
|
||||
{
|
||||
// underscore at the end of the name means that this instruction always updates CR0 (as if RC bit is set)
|
||||
|
||||
@@ -51,12 +51,10 @@ struct PPCInterpreter_t
|
||||
uint8 xer_ca; // carry from xer
|
||||
uint8 xer_so;
|
||||
uint8 xer_ov;
|
||||
uint8 LSQE;
|
||||
uint8 PSE;
|
||||
// thread remaining cycles
|
||||
sint32 remainingCycles; // if this value goes below zero, the next thread is scheduled
|
||||
sint32 skippedCycles; // number of skipped cycles
|
||||
struct
|
||||
struct
|
||||
{
|
||||
uint32 LR;
|
||||
uint32 CTR;
|
||||
@@ -72,7 +70,7 @@ struct PPCInterpreter_t
|
||||
uint32 temporaryGPR[4]; // deprecated, refactor backend dependency on this away
|
||||
uint32 temporaryGPR_reg[4];
|
||||
// values below this are not used by Cafe OS usermode
|
||||
struct
|
||||
struct
|
||||
{
|
||||
uint32 fpecr; // is this the same register as fpscr ?
|
||||
uint32 DEC;
|
||||
@@ -87,7 +85,7 @@ struct PPCInterpreter_t
|
||||
// DMA
|
||||
uint32 dmaU;
|
||||
uint32 dmaL;
|
||||
// MMU
|
||||
// MMU
|
||||
uint32 dbatU[8];
|
||||
uint32 dbatL[8];
|
||||
uint32 ibatU[8];
|
||||
@@ -95,6 +93,8 @@ struct PPCInterpreter_t
|
||||
uint32 sr[16];
|
||||
uint32 sdr1;
|
||||
}sprExtended;
|
||||
uint8 LSQE;
|
||||
uint8 PSE;
|
||||
// global CPU values
|
||||
PPCInterpreterGlobal_t* global;
|
||||
// interpreter control
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "Cafe/HW/Espresso/Const.h"
|
||||
#include "asm/x64util.h"
|
||||
#include "config/ActiveSettings.h"
|
||||
#include "util/helpers/fspinlock.h"
|
||||
#include "util/highresolutiontimer/HighResolutionTimer.h"
|
||||
|
||||
@@ -609,7 +609,7 @@ bool PPCRecompilerX64Gen_imlInstruction_r_r(PPCRecFunction_t* PPCRecFunction, pp
|
||||
}
|
||||
else
|
||||
{
|
||||
debug_printf("PPCRecompilerX64Gen_imlInstruction_r_r(): Unsupported operation 0x%x\n", imlInstruction->operation);
|
||||
cemuLog_logDebug(LogType::Force, "PPCRecompilerX64Gen_imlInstruction_r_r(): Unsupported operation 0x%x\n", imlInstruction->operation);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -635,7 +635,7 @@ bool PPCRecompilerX64Gen_imlInstruction_r_s32(PPCRecFunction_t* PPCRecFunction,
|
||||
}
|
||||
else
|
||||
{
|
||||
debug_printf("PPCRecompilerX64Gen_imlInstruction_r_s32(): Unsupported operation 0x%x\n", imlInstruction->operation);
|
||||
cemuLog_logDebug(LogType::Force, "PPCRecompilerX64Gen_imlInstruction_r_s32(): Unsupported operation 0x%x\n", imlInstruction->operation);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -894,7 +894,7 @@ bool PPCRecompilerX64Gen_imlInstruction_r_r_r(PPCRecFunction_t* PPCRecFunction,
|
||||
}
|
||||
else
|
||||
{
|
||||
debug_printf("PPCRecompilerX64Gen_imlInstruction_r_r_r(): Unsupported operation 0x%x\n", imlInstruction->operation);
|
||||
cemuLog_logDebug(LogType::Force, "PPCRecompilerX64Gen_imlInstruction_r_r_r(): Unsupported operation 0x%x\n", imlInstruction->operation);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -1204,9 +1204,11 @@ void PPCRecompilerX64Gen_imlInstruction_r_name(PPCRecFunction_t* PPCRecFunction,
|
||||
else if (imlInstruction->op_r_name.regR.GetBaseFormat() == IMLRegFormat::F64)
|
||||
{
|
||||
auto regR = _regF64(imlInstruction->op_r_name.regR);
|
||||
if (name >= PPCREC_NAME_FPR0 && name < (PPCREC_NAME_FPR0 + 32))
|
||||
if (name >= PPCREC_NAME_FPR_HALF && name < (PPCREC_NAME_FPR_HALF + 64))
|
||||
{
|
||||
x64Gen_movupd_xmmReg_memReg128(x64GenContext, regR, REG_RESV_HCPU, offsetof(PPCInterpreter_t, fpr) + sizeof(FPR_t) * (name - PPCREC_NAME_FPR0));
|
||||
sint32 regIndex = (name - PPCREC_NAME_FPR_HALF) / 2;
|
||||
sint32 pairIndex = (name - PPCREC_NAME_FPR_HALF) % 2;
|
||||
x64Gen_movsd_xmmReg_memReg64(x64GenContext, regR, REG_RESV_HCPU, offsetof(PPCInterpreter_t, fpr) + sizeof(FPR_t) * regIndex + pairIndex * sizeof(double));
|
||||
}
|
||||
else if (name >= PPCREC_NAME_TEMPORARY_FPR0 || name < (PPCREC_NAME_TEMPORARY_FPR0 + 8))
|
||||
{
|
||||
@@ -1281,9 +1283,11 @@ void PPCRecompilerX64Gen_imlInstruction_name_r(PPCRecFunction_t* PPCRecFunction,
|
||||
{
|
||||
auto regR = _regF64(imlInstruction->op_r_name.regR);
|
||||
uint32 name = imlInstruction->op_r_name.name;
|
||||
if (name >= PPCREC_NAME_FPR0 && name < (PPCREC_NAME_FPR0 + 32))
|
||||
if (name >= PPCREC_NAME_FPR_HALF && name < (PPCREC_NAME_FPR_HALF + 64))
|
||||
{
|
||||
x64Gen_movupd_memReg128_xmmReg(x64GenContext, regR, REG_RESV_HCPU, offsetof(PPCInterpreter_t, fpr) + sizeof(FPR_t) * (name - PPCREC_NAME_FPR0));
|
||||
sint32 regIndex = (name - PPCREC_NAME_FPR_HALF) / 2;
|
||||
sint32 pairIndex = (name - PPCREC_NAME_FPR_HALF) % 2;
|
||||
x64Gen_movsd_memReg64_xmmReg(x64GenContext, regR, REG_RESV_HCPU, offsetof(PPCInterpreter_t, fpr) + sizeof(FPR_t) * regIndex + (pairIndex ? sizeof(double) : 0));
|
||||
}
|
||||
else if (name >= PPCREC_NAME_TEMPORARY_FPR0 && name < (PPCREC_NAME_TEMPORARY_FPR0 + 8))
|
||||
{
|
||||
|
||||
@@ -205,6 +205,7 @@ void x64Gen_movddup_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegi
|
||||
void x64Gen_movhlps_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc);
|
||||
void x64Gen_movsd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc);
|
||||
void x64Gen_movsd_memReg64_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegister, sint32 memRegister, uint32 memImmU32);
|
||||
void x64Gen_movsd_xmmReg_memReg64(x64GenContext_t* x64GenContext, sint32 xmmRegister, sint32 memRegister, uint32 memImmU32);
|
||||
void x64Gen_movlpd_xmmReg_memReg64(x64GenContext_t* x64GenContext, sint32 xmmRegister, sint32 memRegister, uint32 memImmU32);
|
||||
void x64Gen_unpcklpd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc);
|
||||
void x64Gen_unpckhpd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc);
|
||||
@@ -230,6 +231,7 @@ void x64Gen_andps_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegist
|
||||
void x64Gen_pcmpeqd_xmmReg_mem128Reg64(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, uint32 memReg, uint32 memImmS32);
|
||||
void x64Gen_cvttpd2dq_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc);
|
||||
void x64Gen_cvttsd2si_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 registerDest, sint32 xmmRegisterSrc);
|
||||
void x64Gen_cvtsi2sd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 registerSrc);
|
||||
void x64Gen_cvtsd2ss_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc);
|
||||
void x64Gen_cvtpd2ps_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc);
|
||||
void x64Gen_cvtss2sd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -213,6 +213,37 @@ void x64Gen_movsd_memReg64_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegi
|
||||
}
|
||||
}
|
||||
|
||||
void x64Gen_movsd_xmmReg_memReg64(x64GenContext_t* x64GenContext, sint32 xmmRegister, sint32 memRegister, uint32 memImmU32)
|
||||
{
|
||||
// SSE2
|
||||
if( memRegister == X86_REG_RSP )
|
||||
{
|
||||
// MOVSD <xmm>, [RSP+<imm>]
|
||||
x64Gen_writeU8(x64GenContext, 0xF2);
|
||||
x64Gen_genSSEVEXPrefix2(x64GenContext, 0, xmmRegister, false);
|
||||
x64Gen_writeU8(x64GenContext, 0x0F);
|
||||
x64Gen_writeU8(x64GenContext, 0x10);
|
||||
x64Gen_writeU8(x64GenContext, 0x84+(xmmRegister&7)*8);
|
||||
x64Gen_writeU8(x64GenContext, 0x24);
|
||||
x64Gen_writeU32(x64GenContext, memImmU32);
|
||||
}
|
||||
else if( memRegister == 15 )
|
||||
{
|
||||
// MOVSD <xmm>, [R15+<imm>]
|
||||
x64Gen_writeU8(x64GenContext, 0x36);
|
||||
x64Gen_writeU8(x64GenContext, 0xF2);
|
||||
x64Gen_genSSEVEXPrefix2(x64GenContext, memRegister, xmmRegister, false);
|
||||
x64Gen_writeU8(x64GenContext, 0x0F);
|
||||
x64Gen_writeU8(x64GenContext, 0x10);
|
||||
x64Gen_writeU8(x64GenContext, 0x87+(xmmRegister&7)*8);
|
||||
x64Gen_writeU32(x64GenContext, memImmU32);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert_dbg();
|
||||
}
|
||||
}
|
||||
|
||||
void x64Gen_movlpd_xmmReg_memReg64(x64GenContext_t* x64GenContext, sint32 xmmRegister, sint32 memRegister, uint32 memImmU32)
|
||||
{
|
||||
// SSE3
|
||||
@@ -561,6 +592,16 @@ void x64Gen_cvttsd2si_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 regis
|
||||
x64Gen_writeU8(x64GenContext, 0xC0+(registerDest&7)*8+(xmmRegisterSrc&7));
|
||||
}
|
||||
|
||||
void x64Gen_cvtsi2sd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 registerSrc)
|
||||
{
|
||||
// SSE2
|
||||
x64Gen_writeU8(x64GenContext, 0xF2);
|
||||
x64Gen_genSSEVEXPrefix2(x64GenContext, registerSrc, xmmRegisterDest, false);
|
||||
x64Gen_writeU8(x64GenContext, 0x0F);
|
||||
x64Gen_writeU8(x64GenContext, 0x2A);
|
||||
x64Gen_writeU8(x64GenContext, 0xC0+(xmmRegisterDest&7)*8+(registerSrc&7));
|
||||
}
|
||||
|
||||
void x64Gen_cvtsd2ss_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc)
|
||||
{
|
||||
// SSE2
|
||||
|
||||
@@ -189,9 +189,13 @@ void IMLDebug_DisassembleInstruction(const IMLInstruction& inst, std::string& di
|
||||
{
|
||||
strOutput.addFmt("r{}", inst.op_r_name.name - PPCREC_NAME_R0);
|
||||
}
|
||||
else if (inst.op_r_name.name >= PPCREC_NAME_FPR0 && inst.op_r_name.name < (PPCREC_NAME_FPR0 + 999))
|
||||
if (inst.op_r_name.name >= PPCREC_NAME_FPR_HALF && inst.op_r_name.name < (PPCREC_NAME_FPR_HALF + 32*2))
|
||||
{
|
||||
strOutput.addFmt("f{}", inst.op_r_name.name - PPCREC_NAME_FPR0);
|
||||
strOutput.addFmt("f{}", inst.op_r_name.name - ((PPCREC_NAME_FPR_HALF - inst.op_r_name.name)/2));
|
||||
if ((inst.op_r_name.name-PPCREC_NAME_FPR_HALF)&1)
|
||||
strOutput.add(".ps1");
|
||||
else
|
||||
strOutput.add(".ps0");
|
||||
}
|
||||
else if (inst.op_r_name.name >= PPCREC_NAME_SPR0 && inst.op_r_name.name < (PPCREC_NAME_SPR0 + 999))
|
||||
{
|
||||
|
||||
@@ -226,35 +226,6 @@ void IMLInstruction::CheckRegisterUsage(IMLUsedRegisters* registersUsed) const
|
||||
// address is in gpr register
|
||||
if (op_storeLoad.registerMem.IsValid())
|
||||
registersUsed->readGPR1 = op_storeLoad.registerMem;
|
||||
// determine partially written result
|
||||
switch (op_storeLoad.mode)
|
||||
{
|
||||
case PPCREC_FPR_LD_MODE_PSQ_GENERIC_PS0:
|
||||
case PPCREC_FPR_LD_MODE_PSQ_GENERIC_PS0_PS1:
|
||||
cemu_assert_debug(op_storeLoad.registerGQR.IsValid());
|
||||
registersUsed->readGPR2 = op_storeLoad.registerGQR;
|
||||
break;
|
||||
case PPCREC_FPR_LD_MODE_DOUBLE_INTO_PS0:
|
||||
// PS1 remains the same
|
||||
cemu_assert_debug(op_storeLoad.registerGQR.IsInvalid());
|
||||
registersUsed->readGPR2 = op_storeLoad.registerData;
|
||||
break;
|
||||
case PPCREC_FPR_LD_MODE_SINGLE_INTO_PS0_PS1:
|
||||
case PPCREC_FPR_LD_MODE_PSQ_FLOAT_PS0_PS1:
|
||||
case PPCREC_FPR_LD_MODE_PSQ_FLOAT_PS0:
|
||||
case PPCREC_FPR_LD_MODE_PSQ_S16_PS0:
|
||||
case PPCREC_FPR_LD_MODE_PSQ_S16_PS0_PS1:
|
||||
case PPCREC_FPR_LD_MODE_PSQ_U16_PS0_PS1:
|
||||
case PPCREC_FPR_LD_MODE_PSQ_U16_PS0:
|
||||
case PPCREC_FPR_LD_MODE_PSQ_S8_PS0_PS1:
|
||||
case PPCREC_FPR_LD_MODE_PSQ_U8_PS0_PS1:
|
||||
case PPCREC_FPR_LD_MODE_PSQ_U8_PS0:
|
||||
case PPCREC_FPR_LD_MODE_PSQ_S8_PS0:
|
||||
cemu_assert_debug(op_storeLoad.registerGQR.IsInvalid());
|
||||
break;
|
||||
default:
|
||||
cemu_assert_unimplemented();
|
||||
}
|
||||
}
|
||||
else if (type == PPCREC_IML_TYPE_FPR_LOAD_INDEXED)
|
||||
{
|
||||
@@ -265,34 +236,6 @@ void IMLInstruction::CheckRegisterUsage(IMLUsedRegisters* registersUsed) const
|
||||
registersUsed->readGPR1 = op_storeLoad.registerMem;
|
||||
if (op_storeLoad.registerMem2.IsValid())
|
||||
registersUsed->readGPR2 = op_storeLoad.registerMem2;
|
||||
// determine partially written result
|
||||
switch (op_storeLoad.mode)
|
||||
{
|
||||
case PPCREC_FPR_LD_MODE_PSQ_GENERIC_PS0:
|
||||
case PPCREC_FPR_LD_MODE_PSQ_GENERIC_PS0_PS1:
|
||||
cemu_assert_debug(op_storeLoad.registerGQR.IsValid());
|
||||
registersUsed->readGPR3 = op_storeLoad.registerGQR;
|
||||
break;
|
||||
case PPCREC_FPR_LD_MODE_DOUBLE_INTO_PS0:
|
||||
// PS1 remains the same
|
||||
cemu_assert_debug(op_storeLoad.registerGQR.IsInvalid());
|
||||
registersUsed->readGPR3 = op_storeLoad.registerData;
|
||||
break;
|
||||
case PPCREC_FPR_LD_MODE_SINGLE_INTO_PS0_PS1:
|
||||
case PPCREC_FPR_LD_MODE_PSQ_FLOAT_PS0_PS1:
|
||||
case PPCREC_FPR_LD_MODE_PSQ_FLOAT_PS0:
|
||||
case PPCREC_FPR_LD_MODE_PSQ_S16_PS0:
|
||||
case PPCREC_FPR_LD_MODE_PSQ_S16_PS0_PS1:
|
||||
case PPCREC_FPR_LD_MODE_PSQ_U16_PS0_PS1:
|
||||
case PPCREC_FPR_LD_MODE_PSQ_U16_PS0:
|
||||
case PPCREC_FPR_LD_MODE_PSQ_S8_PS0_PS1:
|
||||
case PPCREC_FPR_LD_MODE_PSQ_U8_PS0_PS1:
|
||||
case PPCREC_FPR_LD_MODE_PSQ_U8_PS0:
|
||||
cemu_assert_debug(op_storeLoad.registerGQR.IsInvalid());
|
||||
break;
|
||||
default:
|
||||
cemu_assert_unimplemented();
|
||||
}
|
||||
}
|
||||
else if (type == PPCREC_IML_TYPE_FPR_STORE)
|
||||
{
|
||||
@@ -300,18 +243,6 @@ void IMLInstruction::CheckRegisterUsage(IMLUsedRegisters* registersUsed) const
|
||||
registersUsed->readGPR1 = op_storeLoad.registerData;
|
||||
if (op_storeLoad.registerMem.IsValid())
|
||||
registersUsed->readGPR2 = op_storeLoad.registerMem;
|
||||
// PSQ generic stores also access GQR
|
||||
switch (op_storeLoad.mode)
|
||||
{
|
||||
case PPCREC_FPR_ST_MODE_PSQ_GENERIC_PS0:
|
||||
case PPCREC_FPR_ST_MODE_PSQ_GENERIC_PS0_PS1:
|
||||
cemu_assert_debug(op_storeLoad.registerGQR.IsValid());
|
||||
registersUsed->readGPR3 = op_storeLoad.registerGQR;
|
||||
break;
|
||||
default:
|
||||
cemu_assert_debug(op_storeLoad.registerGQR.IsInvalid());
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (type == PPCREC_IML_TYPE_FPR_STORE_INDEXED)
|
||||
{
|
||||
@@ -322,72 +253,34 @@ void IMLInstruction::CheckRegisterUsage(IMLUsedRegisters* registersUsed) const
|
||||
registersUsed->readGPR2 = op_storeLoad.registerMem;
|
||||
if (op_storeLoad.registerMem2.IsValid())
|
||||
registersUsed->readGPR3 = op_storeLoad.registerMem2;
|
||||
// PSQ generic stores also access GQR
|
||||
switch (op_storeLoad.mode)
|
||||
{
|
||||
case PPCREC_FPR_ST_MODE_PSQ_GENERIC_PS0:
|
||||
case PPCREC_FPR_ST_MODE_PSQ_GENERIC_PS0_PS1:
|
||||
cemu_assert_debug(op_storeLoad.registerGQR.IsValid());
|
||||
registersUsed->readGPR4 = op_storeLoad.registerGQR;
|
||||
break;
|
||||
default:
|
||||
cemu_assert_debug(op_storeLoad.registerGQR.IsInvalid());
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (type == PPCREC_IML_TYPE_FPR_R_R)
|
||||
{
|
||||
// fpr operation
|
||||
if (operation == PPCREC_IML_OP_FPR_COPY_BOTTOM_TO_BOTTOM_AND_TOP ||
|
||||
operation == PPCREC_IML_OP_FPR_COPY_TOP_TO_BOTTOM_AND_TOP ||
|
||||
operation == PPCREC_IML_OP_FPR_COPY_BOTTOM_AND_TOP_SWAPPED ||
|
||||
operation == PPCREC_IML_OP_ASSIGN ||
|
||||
operation == PPCREC_IML_OP_FPR_NEGATE_PAIR ||
|
||||
operation == PPCREC_IML_OP_FPR_ABS_PAIR ||
|
||||
operation == PPCREC_IML_OP_FPR_FRES_PAIR ||
|
||||
operation == PPCREC_IML_OP_FPR_FRSQRTE_PAIR)
|
||||
{
|
||||
// operand read, result written
|
||||
registersUsed->readGPR1 = op_fpr_r_r.regA;
|
||||
registersUsed->writtenGPR1 = op_fpr_r_r.regR;
|
||||
}
|
||||
else if (
|
||||
operation == PPCREC_IML_OP_FPR_COPY_BOTTOM_TO_BOTTOM ||
|
||||
operation == PPCREC_IML_OP_FPR_COPY_BOTTOM_TO_TOP ||
|
||||
operation == PPCREC_IML_OP_FPR_COPY_TOP_TO_TOP ||
|
||||
operation == PPCREC_IML_OP_FPR_COPY_TOP_TO_BOTTOM ||
|
||||
operation == PPCREC_IML_OP_FPR_EXPAND_BOTTOM32_TO_BOTTOM64_AND_TOP64 ||
|
||||
operation == PPCREC_IML_OP_FPR_BOTTOM_FCTIWZ ||
|
||||
operation == PPCREC_IML_OP_FPR_BOTTOM_RECIPROCAL_SQRT
|
||||
if (
|
||||
operation == PPCREC_IML_OP_FPR_ASSIGN ||
|
||||
operation == PPCREC_IML_OP_FPR_EXPAND_F32_TO_F64 ||
|
||||
operation == PPCREC_IML_OP_FPR_FCTIWZ
|
||||
)
|
||||
{
|
||||
// operand read, result read and (partially) written
|
||||
registersUsed->readGPR1 = op_fpr_r_r.regA;
|
||||
registersUsed->readGPR2 = op_fpr_r_r.regR;
|
||||
registersUsed->writtenGPR1 = op_fpr_r_r.regR;
|
||||
}
|
||||
else if (operation == PPCREC_IML_OP_FPR_MULTIPLY_BOTTOM ||
|
||||
operation == PPCREC_IML_OP_FPR_MULTIPLY_PAIR ||
|
||||
operation == PPCREC_IML_OP_FPR_DIVIDE_BOTTOM ||
|
||||
operation == PPCREC_IML_OP_FPR_DIVIDE_PAIR ||
|
||||
operation == PPCREC_IML_OP_FPR_ADD_BOTTOM ||
|
||||
operation == PPCREC_IML_OP_FPR_ADD_PAIR ||
|
||||
operation == PPCREC_IML_OP_FPR_SUB_PAIR ||
|
||||
operation == PPCREC_IML_OP_FPR_SUB_BOTTOM)
|
||||
else if (operation == PPCREC_IML_OP_FPR_MULTIPLY ||
|
||||
operation == PPCREC_IML_OP_FPR_DIVIDE ||
|
||||
operation == PPCREC_IML_OP_FPR_ADD ||
|
||||
operation == PPCREC_IML_OP_FPR_SUB)
|
||||
{
|
||||
// operand read, result read and written
|
||||
registersUsed->readGPR1 = op_fpr_r_r.regA;
|
||||
registersUsed->readGPR2 = op_fpr_r_r.regR;
|
||||
registersUsed->writtenGPR1 = op_fpr_r_r.regR;
|
||||
|
||||
}
|
||||
else if (operation == PPCREC_IML_OP_FPR_FCMPU_BOTTOM ||
|
||||
operation == PPCREC_IML_OP_FPR_FCMPU_TOP ||
|
||||
operation == PPCREC_IML_OP_FPR_FCMPO_BOTTOM)
|
||||
else if (operation == PPCREC_IML_OP_FPR_FLOAT_TO_INT ||
|
||||
operation == PPCREC_IML_OP_FPR_INT_TO_FLOAT)
|
||||
{
|
||||
// operand read, result read
|
||||
registersUsed->writtenGPR1 = op_fpr_r_r.regR;
|
||||
registersUsed->readGPR1 = op_fpr_r_r.regA;
|
||||
registersUsed->readGPR2 = op_fpr_r_r.regR;
|
||||
}
|
||||
else
|
||||
cemu_assert_unimplemented();
|
||||
@@ -398,19 +291,6 @@ void IMLInstruction::CheckRegisterUsage(IMLUsedRegisters* registersUsed) const
|
||||
registersUsed->readGPR1 = op_fpr_r_r_r.regA;
|
||||
registersUsed->readGPR2 = op_fpr_r_r_r.regB;
|
||||
registersUsed->writtenGPR1 = op_fpr_r_r_r.regR;
|
||||
// handle partially written result
|
||||
switch (operation)
|
||||
{
|
||||
case PPCREC_IML_OP_FPR_MULTIPLY_BOTTOM:
|
||||
case PPCREC_IML_OP_FPR_ADD_BOTTOM:
|
||||
case PPCREC_IML_OP_FPR_SUB_BOTTOM:
|
||||
registersUsed->readGPR3 = op_fpr_r_r_r.regR;
|
||||
break;
|
||||
case PPCREC_IML_OP_FPR_SUB_PAIR:
|
||||
break;
|
||||
default:
|
||||
cemu_assert_unimplemented();
|
||||
}
|
||||
}
|
||||
else if (type == PPCREC_IML_TYPE_FPR_R_R_R_R)
|
||||
{
|
||||
@@ -419,33 +299,23 @@ void IMLInstruction::CheckRegisterUsage(IMLUsedRegisters* registersUsed) const
|
||||
registersUsed->readGPR2 = op_fpr_r_r_r_r.regB;
|
||||
registersUsed->readGPR3 = op_fpr_r_r_r_r.regC;
|
||||
registersUsed->writtenGPR1 = op_fpr_r_r_r_r.regR;
|
||||
// handle partially written result
|
||||
switch (operation)
|
||||
{
|
||||
case PPCREC_IML_OP_FPR_SELECT_BOTTOM:
|
||||
registersUsed->readGPR4 = op_fpr_r_r_r_r.regR;
|
||||
break;
|
||||
case PPCREC_IML_OP_FPR_SUM0:
|
||||
case PPCREC_IML_OP_FPR_SUM1:
|
||||
case PPCREC_IML_OP_FPR_SELECT_PAIR:
|
||||
break;
|
||||
default:
|
||||
cemu_assert_unimplemented();
|
||||
}
|
||||
}
|
||||
else if (type == PPCREC_IML_TYPE_FPR_R)
|
||||
{
|
||||
// fpr operation
|
||||
if (operation == PPCREC_IML_OP_FPR_NEGATE_BOTTOM ||
|
||||
operation == PPCREC_IML_OP_FPR_ABS_BOTTOM ||
|
||||
operation == PPCREC_IML_OP_FPR_NEGATIVE_ABS_BOTTOM ||
|
||||
operation == PPCREC_IML_OP_FPR_EXPAND_BOTTOM32_TO_BOTTOM64_AND_TOP64 ||
|
||||
operation == PPCREC_IML_OP_FPR_ROUND_TO_SINGLE_PRECISION_BOTTOM ||
|
||||
operation == PPCREC_IML_OP_FPR_ROUND_TO_SINGLE_PRECISION_PAIR)
|
||||
if (operation == PPCREC_IML_OP_FPR_NEGATE ||
|
||||
operation == PPCREC_IML_OP_FPR_ABS ||
|
||||
operation == PPCREC_IML_OP_FPR_NEGATIVE_ABS ||
|
||||
operation == PPCREC_IML_OP_FPR_EXPAND_F32_TO_F64 ||
|
||||
operation == PPCREC_IML_OP_FPR_ROUND_TO_SINGLE_PRECISION_BOTTOM)
|
||||
{
|
||||
registersUsed->readGPR1 = op_fpr_r.regR;
|
||||
registersUsed->writtenGPR1 = op_fpr_r.regR;
|
||||
}
|
||||
else if (operation == PPCREC_IML_OP_FPR_LOAD_ONE)
|
||||
{
|
||||
registersUsed->writtenGPR1 = op_fpr_r.regR;
|
||||
}
|
||||
else
|
||||
cemu_assert_unimplemented();
|
||||
}
|
||||
@@ -608,27 +478,23 @@ void IMLInstruction::RewriteGPR(const std::unordered_map<IMLRegID, IMLRegID>& tr
|
||||
{
|
||||
op_storeLoad.registerData = replaceRegisterIdMultiple(op_storeLoad.registerData, translationTable);
|
||||
op_storeLoad.registerMem = replaceRegisterIdMultiple(op_storeLoad.registerMem, translationTable);
|
||||
op_storeLoad.registerGQR = replaceRegisterIdMultiple(op_storeLoad.registerGQR, translationTable);
|
||||
}
|
||||
else if (type == PPCREC_IML_TYPE_FPR_LOAD_INDEXED)
|
||||
{
|
||||
op_storeLoad.registerData = replaceRegisterIdMultiple(op_storeLoad.registerData, translationTable);
|
||||
op_storeLoad.registerMem = replaceRegisterIdMultiple(op_storeLoad.registerMem, translationTable);
|
||||
op_storeLoad.registerMem2 = replaceRegisterIdMultiple(op_storeLoad.registerMem2, translationTable);
|
||||
op_storeLoad.registerGQR = replaceRegisterIdMultiple(op_storeLoad.registerGQR, translationTable);
|
||||
}
|
||||
else if (type == PPCREC_IML_TYPE_FPR_STORE)
|
||||
{
|
||||
op_storeLoad.registerData = replaceRegisterIdMultiple(op_storeLoad.registerData, translationTable);
|
||||
op_storeLoad.registerMem = replaceRegisterIdMultiple(op_storeLoad.registerMem, translationTable);
|
||||
op_storeLoad.registerGQR = replaceRegisterIdMultiple(op_storeLoad.registerGQR, translationTable);
|
||||
}
|
||||
else if (type == PPCREC_IML_TYPE_FPR_STORE_INDEXED)
|
||||
{
|
||||
op_storeLoad.registerData = replaceRegisterIdMultiple(op_storeLoad.registerData, translationTable);
|
||||
op_storeLoad.registerMem = replaceRegisterIdMultiple(op_storeLoad.registerMem, translationTable);
|
||||
op_storeLoad.registerMem2 = replaceRegisterIdMultiple(op_storeLoad.registerMem2, translationTable);
|
||||
op_storeLoad.registerGQR = replaceRegisterIdMultiple(op_storeLoad.registerGQR, translationTable);
|
||||
}
|
||||
else if (type == PPCREC_IML_TYPE_FPR_R)
|
||||
{
|
||||
|
||||
@@ -126,46 +126,22 @@ enum
|
||||
PPCREC_IML_OP_SRW, // SRW (shift based on register by up to 63 bits)
|
||||
PPCREC_IML_OP_CNTLZW,
|
||||
// FPU
|
||||
PPCREC_IML_OP_FPR_ADD_BOTTOM,
|
||||
PPCREC_IML_OP_FPR_ADD_PAIR,
|
||||
PPCREC_IML_OP_FPR_SUB_PAIR,
|
||||
PPCREC_IML_OP_FPR_SUB_BOTTOM,
|
||||
PPCREC_IML_OP_FPR_MULTIPLY_BOTTOM,
|
||||
PPCREC_IML_OP_FPR_MULTIPLY_PAIR,
|
||||
PPCREC_IML_OP_FPR_DIVIDE_BOTTOM,
|
||||
PPCREC_IML_OP_FPR_DIVIDE_PAIR,
|
||||
PPCREC_IML_OP_FPR_COPY_BOTTOM_TO_BOTTOM_AND_TOP,
|
||||
PPCREC_IML_OP_FPR_COPY_TOP_TO_BOTTOM_AND_TOP,
|
||||
PPCREC_IML_OP_FPR_COPY_BOTTOM_TO_BOTTOM,
|
||||
PPCREC_IML_OP_FPR_COPY_BOTTOM_TO_TOP, // leave bottom of destination untouched
|
||||
PPCREC_IML_OP_FPR_COPY_TOP_TO_TOP, // leave bottom of destination untouched
|
||||
PPCREC_IML_OP_FPR_COPY_TOP_TO_BOTTOM, // leave top of destination untouched
|
||||
PPCREC_IML_OP_FPR_COPY_BOTTOM_AND_TOP_SWAPPED,
|
||||
PPCREC_IML_OP_FPR_EXPAND_BOTTOM32_TO_BOTTOM64_AND_TOP64, // expand bottom f32 to f64 in bottom and top half
|
||||
PPCREC_IML_OP_FPR_FCMPO_BOTTOM, // deprecated
|
||||
PPCREC_IML_OP_FPR_FCMPU_BOTTOM, // deprecated
|
||||
PPCREC_IML_OP_FPR_FCMPU_TOP, // deprecated
|
||||
PPCREC_IML_OP_FPR_NEGATE_BOTTOM,
|
||||
PPCREC_IML_OP_FPR_NEGATE_PAIR,
|
||||
PPCREC_IML_OP_FPR_ABS_BOTTOM, // abs(fp0)
|
||||
PPCREC_IML_OP_FPR_ABS_PAIR,
|
||||
PPCREC_IML_OP_FPR_FRES_PAIR, // 1.0/fp approx (Espresso accuracy)
|
||||
PPCREC_IML_OP_FPR_FRSQRTE_PAIR, // 1.0/sqrt(fp) approx (Espresso accuracy)
|
||||
PPCREC_IML_OP_FPR_NEGATIVE_ABS_BOTTOM, // -abs(fp0)
|
||||
PPCREC_IML_OP_FPR_ASSIGN,
|
||||
PPCREC_IML_OP_FPR_LOAD_ONE, // load constant 1.0 into register
|
||||
PPCREC_IML_OP_FPR_ADD,
|
||||
PPCREC_IML_OP_FPR_SUB,
|
||||
PPCREC_IML_OP_FPR_MULTIPLY,
|
||||
PPCREC_IML_OP_FPR_DIVIDE,
|
||||
PPCREC_IML_OP_FPR_EXPAND_F32_TO_F64, // expand f32 to f64 in-place
|
||||
PPCREC_IML_OP_FPR_NEGATE,
|
||||
PPCREC_IML_OP_FPR_ABS, // abs(fpr)
|
||||
PPCREC_IML_OP_FPR_NEGATIVE_ABS, // -abs(fpr)
|
||||
PPCREC_IML_OP_FPR_ROUND_TO_SINGLE_PRECISION_BOTTOM, // round 64bit double to 64bit double with 32bit float precision (in bottom half of xmm register)
|
||||
PPCREC_IML_OP_FPR_ROUND_TO_SINGLE_PRECISION_PAIR, // round two 64bit doubles to 64bit double with 32bit float precision
|
||||
PPCREC_IML_OP_FPR_BOTTOM_RECIPROCAL_SQRT,
|
||||
PPCREC_IML_OP_FPR_BOTTOM_FCTIWZ,
|
||||
PPCREC_IML_OP_FPR_SELECT_BOTTOM, // selectively copy bottom value from operand B or C based on value in operand A
|
||||
PPCREC_IML_OP_FPR_SELECT_PAIR, // selectively copy top/bottom from operand B or C based on value in top/bottom of operand A
|
||||
// PS
|
||||
PPCREC_IML_OP_FPR_SUM0,
|
||||
PPCREC_IML_OP_FPR_SUM1,
|
||||
|
||||
|
||||
// R_R_R only
|
||||
|
||||
// R_R_S32 only
|
||||
PPCREC_IML_OP_FPR_FCTIWZ,
|
||||
PPCREC_IML_OP_FPR_SELECT, // selectively copy bottom value from operand B or C based on value in operand A
|
||||
// Conversion (FPR_R_R)
|
||||
PPCREC_IML_OP_FPR_INT_TO_FLOAT, // convert integer value in gpr to floating point value in fpr
|
||||
PPCREC_IML_OP_FPR_FLOAT_TO_INT, // convert floating point value in fpr to integer value in gpr
|
||||
|
||||
// R_R_R + R_R_S32
|
||||
PPCREC_IML_OP_ADD, // also R_R_R_CARRY
|
||||
@@ -275,7 +251,7 @@ enum // IMLName
|
||||
PPCREC_NAME_TEMPORARY = 1000,
|
||||
PPCREC_NAME_R0 = 2000,
|
||||
PPCREC_NAME_SPR0 = 3000,
|
||||
PPCREC_NAME_FPR0 = 4000,
|
||||
PPCREC_NAME_FPR_HALF = 4800, // Counts PS0 and PS1 separately. E.g. fp3.ps1 is at offset 3 * 2 + 1
|
||||
PPCREC_NAME_TEMPORARY_FPR0 = 5000, // 0 to 7
|
||||
PPCREC_NAME_XER_CA = 6000, // carry bit from XER
|
||||
PPCREC_NAME_XER_OV = 6001, // overflow bit from XER
|
||||
@@ -291,39 +267,14 @@ enum // IMLName
|
||||
enum
|
||||
{
|
||||
// fpr load
|
||||
PPCREC_FPR_LD_MODE_SINGLE_INTO_PS0,
|
||||
PPCREC_FPR_LD_MODE_SINGLE_INTO_PS0_PS1,
|
||||
PPCREC_FPR_LD_MODE_DOUBLE_INTO_PS0,
|
||||
PPCREC_FPR_LD_MODE_PSQ_GENERIC_PS0,
|
||||
PPCREC_FPR_LD_MODE_PSQ_GENERIC_PS0_PS1,
|
||||
PPCREC_FPR_LD_MODE_PSQ_FLOAT_PS0,
|
||||
PPCREC_FPR_LD_MODE_PSQ_FLOAT_PS0_PS1,
|
||||
PPCREC_FPR_LD_MODE_PSQ_S16_PS0,
|
||||
PPCREC_FPR_LD_MODE_PSQ_S16_PS0_PS1,
|
||||
PPCREC_FPR_LD_MODE_PSQ_U16_PS0,
|
||||
PPCREC_FPR_LD_MODE_PSQ_U16_PS0_PS1,
|
||||
PPCREC_FPR_LD_MODE_PSQ_S8_PS0,
|
||||
PPCREC_FPR_LD_MODE_PSQ_S8_PS0_PS1,
|
||||
PPCREC_FPR_LD_MODE_PSQ_U8_PS0,
|
||||
PPCREC_FPR_LD_MODE_PSQ_U8_PS0_PS1,
|
||||
PPCREC_FPR_LD_MODE_SINGLE,
|
||||
PPCREC_FPR_LD_MODE_DOUBLE,
|
||||
|
||||
// fpr store
|
||||
PPCREC_FPR_ST_MODE_SINGLE_FROM_PS0, // store 1 single precision float from ps0
|
||||
PPCREC_FPR_ST_MODE_DOUBLE_FROM_PS0, // store 1 double precision float from ps0
|
||||
PPCREC_FPR_ST_MODE_SINGLE,
|
||||
PPCREC_FPR_ST_MODE_DOUBLE,
|
||||
|
||||
PPCREC_FPR_ST_MODE_UI32_FROM_PS0, // store raw low-32bit of PS0
|
||||
|
||||
PPCREC_FPR_ST_MODE_PSQ_GENERIC_PS0_PS1,
|
||||
PPCREC_FPR_ST_MODE_PSQ_GENERIC_PS0,
|
||||
PPCREC_FPR_ST_MODE_PSQ_FLOAT_PS0_PS1,
|
||||
PPCREC_FPR_ST_MODE_PSQ_FLOAT_PS0,
|
||||
PPCREC_FPR_ST_MODE_PSQ_S8_PS0,
|
||||
PPCREC_FPR_ST_MODE_PSQ_S8_PS0_PS1,
|
||||
PPCREC_FPR_ST_MODE_PSQ_U8_PS0,
|
||||
PPCREC_FPR_ST_MODE_PSQ_U8_PS0_PS1,
|
||||
PPCREC_FPR_ST_MODE_PSQ_U16_PS0,
|
||||
PPCREC_FPR_ST_MODE_PSQ_U16_PS0_PS1,
|
||||
PPCREC_FPR_ST_MODE_PSQ_S16_PS0,
|
||||
PPCREC_FPR_ST_MODE_PSQ_S16_PS0_PS1,
|
||||
};
|
||||
|
||||
struct IMLUsedRegisters
|
||||
@@ -463,7 +414,6 @@ struct IMLInstruction
|
||||
IMLReg registerData;
|
||||
IMLReg registerMem;
|
||||
IMLReg registerMem2;
|
||||
IMLReg registerGQR;
|
||||
uint8 copyWidth;
|
||||
struct
|
||||
{
|
||||
@@ -471,7 +421,7 @@ struct IMLInstruction
|
||||
bool signExtend : 1;
|
||||
bool notExpanded : 1; // for floats
|
||||
}flags2;
|
||||
uint8 mode; // transfer mode (copy width, ps0/ps1 behavior)
|
||||
uint8 mode; // transfer mode
|
||||
sint32 immS32;
|
||||
}op_storeLoad;
|
||||
struct
|
||||
@@ -752,6 +702,56 @@ struct IMLInstruction
|
||||
this->op_call_imm.regReturn = regReturn;
|
||||
}
|
||||
|
||||
// FPR
|
||||
|
||||
// load from memory
|
||||
void make_fpr_r_memory(IMLReg registerDestination, IMLReg registerMemory, sint32 immS32, uint32 mode, bool switchEndian)
|
||||
{
|
||||
this->type = PPCREC_IML_TYPE_FPR_LOAD;
|
||||
this->operation = 0;
|
||||
this->op_storeLoad.registerData = registerDestination;
|
||||
this->op_storeLoad.registerMem = registerMemory;
|
||||
this->op_storeLoad.immS32 = immS32;
|
||||
this->op_storeLoad.mode = mode;
|
||||
this->op_storeLoad.flags2.swapEndian = switchEndian;
|
||||
}
|
||||
|
||||
void make_fpr_r_memory_indexed(IMLReg registerDestination, IMLReg registerMemory1, IMLReg registerMemory2, uint32 mode, bool switchEndian)
|
||||
{
|
||||
this->type = PPCREC_IML_TYPE_FPR_LOAD_INDEXED;
|
||||
this->operation = 0;
|
||||
this->op_storeLoad.registerData = registerDestination;
|
||||
this->op_storeLoad.registerMem = registerMemory1;
|
||||
this->op_storeLoad.registerMem2 = registerMemory2;
|
||||
this->op_storeLoad.immS32 = 0;
|
||||
this->op_storeLoad.mode = mode;
|
||||
this->op_storeLoad.flags2.swapEndian = switchEndian;
|
||||
}
|
||||
|
||||
// store to memory
|
||||
void make_fpr_memory_r(IMLReg registerSource, IMLReg registerMemory, sint32 immS32, uint32 mode, bool switchEndian)
|
||||
{
|
||||
this->type = PPCREC_IML_TYPE_FPR_STORE;
|
||||
this->operation = 0;
|
||||
this->op_storeLoad.registerData = registerSource;
|
||||
this->op_storeLoad.registerMem = registerMemory;
|
||||
this->op_storeLoad.immS32 = immS32;
|
||||
this->op_storeLoad.mode = mode;
|
||||
this->op_storeLoad.flags2.swapEndian = switchEndian;
|
||||
}
|
||||
|
||||
void make_fpr_memory_r_indexed(IMLReg registerSource, IMLReg registerMemory1, IMLReg registerMemory2, sint32 immS32, uint32 mode, bool switchEndian)
|
||||
{
|
||||
this->type = PPCREC_IML_TYPE_FPR_STORE_INDEXED;
|
||||
this->operation = 0;
|
||||
this->op_storeLoad.registerData = registerSource;
|
||||
this->op_storeLoad.registerMem = registerMemory1;
|
||||
this->op_storeLoad.registerMem2 = registerMemory2;
|
||||
this->op_storeLoad.immS32 = immS32;
|
||||
this->op_storeLoad.mode = mode;
|
||||
this->op_storeLoad.flags2.swapEndian = switchEndian;
|
||||
}
|
||||
|
||||
void make_fpr_compare(IMLReg regA, IMLReg regB, IMLReg regR, IMLCondition cond)
|
||||
{
|
||||
this->type = PPCREC_IML_TYPE_FPR_COMPARE;
|
||||
@@ -762,6 +762,44 @@ struct IMLInstruction
|
||||
this->op_fpr_compare.cond = cond;
|
||||
}
|
||||
|
||||
void make_fpr_r(sint32 operation, IMLReg registerResult)
|
||||
{
|
||||
// OP (fpr)
|
||||
this->type = PPCREC_IML_TYPE_FPR_R;
|
||||
this->operation = operation;
|
||||
this->op_fpr_r.regR = registerResult;
|
||||
}
|
||||
|
||||
void make_fpr_r_r(sint32 operation, IMLReg registerResult, IMLReg registerOperand, sint32 crRegister=PPC_REC_INVALID_REGISTER)
|
||||
{
|
||||
// fpr OP fpr
|
||||
this->type = PPCREC_IML_TYPE_FPR_R_R;
|
||||
this->operation = operation;
|
||||
this->op_fpr_r_r.regR = registerResult;
|
||||
this->op_fpr_r_r.regA = registerOperand;
|
||||
}
|
||||
|
||||
void make_fpr_r_r_r(sint32 operation, IMLReg registerResult, IMLReg registerOperand1, IMLReg registerOperand2, sint32 crRegister=PPC_REC_INVALID_REGISTER)
|
||||
{
|
||||
// fpr = OP (fpr,fpr)
|
||||
this->type = PPCREC_IML_TYPE_FPR_R_R_R;
|
||||
this->operation = operation;
|
||||
this->op_fpr_r_r_r.regR = registerResult;
|
||||
this->op_fpr_r_r_r.regA = registerOperand1;
|
||||
this->op_fpr_r_r_r.regB = registerOperand2;
|
||||
}
|
||||
|
||||
void make_fpr_r_r_r_r(sint32 operation, IMLReg registerResult, IMLReg registerOperandA, IMLReg registerOperandB, IMLReg registerOperandC, sint32 crRegister=PPC_REC_INVALID_REGISTER)
|
||||
{
|
||||
// fpr = OP (fpr,fpr,fpr)
|
||||
this->type = PPCREC_IML_TYPE_FPR_R_R_R_R;
|
||||
this->operation = operation;
|
||||
this->op_fpr_r_r_r_r.regR = registerResult;
|
||||
this->op_fpr_r_r_r_r.regA = registerOperandA;
|
||||
this->op_fpr_r_r_r_r.regB = registerOperandB;
|
||||
this->op_fpr_r_r_r_r.regC = registerOperandC;
|
||||
}
|
||||
|
||||
/* X86 specific */
|
||||
void make_x86_eflags_jcc(IMLCondition cond, bool invertedCondition)
|
||||
{
|
||||
|
||||
@@ -34,8 +34,8 @@ void PPCRecompiler_optimizeDirectFloatCopiesScanForward(ppcImlGenContext_t* ppcI
|
||||
if (imlInstruction->IsSuffixInstruction())
|
||||
break;
|
||||
// check if FPR is stored
|
||||
if ((imlInstruction->type == PPCREC_IML_TYPE_FPR_STORE && imlInstruction->op_storeLoad.mode == PPCREC_FPR_ST_MODE_SINGLE_FROM_PS0) ||
|
||||
(imlInstruction->type == PPCREC_IML_TYPE_FPR_STORE_INDEXED && imlInstruction->op_storeLoad.mode == PPCREC_FPR_ST_MODE_SINGLE_FROM_PS0))
|
||||
if ((imlInstruction->type == PPCREC_IML_TYPE_FPR_STORE && imlInstruction->op_storeLoad.mode == PPCREC_FPR_ST_MODE_SINGLE) ||
|
||||
(imlInstruction->type == PPCREC_IML_TYPE_FPR_STORE_INDEXED && imlInstruction->op_storeLoad.mode == PPCREC_FPR_ST_MODE_SINGLE))
|
||||
{
|
||||
if (imlInstruction->op_storeLoad.registerData.GetRegID() == fprIndex)
|
||||
{
|
||||
@@ -73,7 +73,7 @@ void PPCRecompiler_optimizeDirectFloatCopiesScanForward(ppcImlGenContext_t* ppcI
|
||||
{
|
||||
// insert expand instruction after store
|
||||
IMLInstruction* newExpand = PPCRecompiler_insertInstruction(imlSegment, lastStore);
|
||||
PPCRecompilerImlGen_generateNewInstruction_fpr_r(ppcImlGenContext, newExpand, PPCREC_IML_OP_FPR_EXPAND_BOTTOM32_TO_BOTTOM64_AND_TOP64, _FPRRegFromID(fprIndex));
|
||||
newExpand->make_fpr_r(PPCREC_IML_OP_FPR_EXPAND_F32_TO_F64, _FPRRegFromID(fprIndex));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,21 +90,23 @@ void PPCRecompiler_optimizeDirectFloatCopiesScanForward(ppcImlGenContext_t* ppcI
|
||||
*/
|
||||
void IMLOptimizer_OptimizeDirectFloatCopies(ppcImlGenContext_t* ppcImlGenContext)
|
||||
{
|
||||
for (IMLSegment* segIt : ppcImlGenContext->segmentList2)
|
||||
{
|
||||
for (sint32 i = 0; i < segIt->imlList.size(); i++)
|
||||
{
|
||||
IMLInstruction* imlInstruction = segIt->imlList.data() + i;
|
||||
if (imlInstruction->type == PPCREC_IML_TYPE_FPR_LOAD && imlInstruction->op_storeLoad.mode == PPCREC_FPR_LD_MODE_SINGLE_INTO_PS0_PS1)
|
||||
{
|
||||
PPCRecompiler_optimizeDirectFloatCopiesScanForward(ppcImlGenContext, segIt, i, imlInstruction->op_storeLoad.registerData);
|
||||
}
|
||||
else if (imlInstruction->type == PPCREC_IML_TYPE_FPR_LOAD_INDEXED && imlInstruction->op_storeLoad.mode == PPCREC_FPR_LD_MODE_SINGLE_INTO_PS0_PS1)
|
||||
{
|
||||
PPCRecompiler_optimizeDirectFloatCopiesScanForward(ppcImlGenContext, segIt, i, imlInstruction->op_storeLoad.registerData);
|
||||
}
|
||||
}
|
||||
}
|
||||
cemuLog_logDebugOnce(LogType::Force, "IMLOptimizer_OptimizeDirectFloatCopies(): Currently disabled\n");
|
||||
return;
|
||||
// for (IMLSegment* segIt : ppcImlGenContext->segmentList2)
|
||||
// {
|
||||
// for (sint32 i = 0; i < segIt->imlList.size(); i++)
|
||||
// {
|
||||
// IMLInstruction* imlInstruction = segIt->imlList.data() + i;
|
||||
// if (imlInstruction->type == PPCREC_IML_TYPE_FPR_LOAD && imlInstruction->op_storeLoad.mode == PPCREC_FPR_LD_MODE_SINGLE_INTO_PS0_PS1)
|
||||
// {
|
||||
// PPCRecompiler_optimizeDirectFloatCopiesScanForward(ppcImlGenContext, segIt, i, imlInstruction->op_storeLoad.registerData);
|
||||
// }
|
||||
// else if (imlInstruction->type == PPCREC_IML_TYPE_FPR_LOAD_INDEXED && imlInstruction->op_storeLoad.mode == PPCREC_FPR_LD_MODE_SINGLE_INTO_PS0_PS1)
|
||||
// {
|
||||
// PPCRecompiler_optimizeDirectFloatCopiesScanForward(ppcImlGenContext, segIt, i, imlInstruction->op_storeLoad.registerData);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
void PPCRecompiler_optimizeDirectIntegerCopiesScanForward(ppcImlGenContext_t* ppcImlGenContext, IMLSegment* imlSegment, sint32 imlIndexLoad, IMLReg gprReg)
|
||||
@@ -207,133 +209,22 @@ sint32 _getGQRIndexFromRegister(ppcImlGenContext_t* ppcImlGenContext, IMLReg gqr
|
||||
|
||||
bool PPCRecompiler_isUGQRValueKnown(ppcImlGenContext_t* ppcImlGenContext, sint32 gqrIndex, uint32& gqrValue)
|
||||
{
|
||||
// UGQR 2 to 7 are initialized by the OS and we assume that games won't ever permanently touch those
|
||||
// todo - hack - replace with more accurate solution
|
||||
if (gqrIndex == 2)
|
||||
gqrValue = 0x00040004;
|
||||
else if (gqrIndex == 3)
|
||||
gqrValue = 0x00050005;
|
||||
else if (gqrIndex == 4)
|
||||
gqrValue = 0x00060006;
|
||||
else if (gqrIndex == 5)
|
||||
gqrValue = 0x00070007;
|
||||
// the default configuration is:
|
||||
// UGQR0 = 0x00000000
|
||||
// UGQR2 = 0x00040004
|
||||
// UGQR3 = 0x00050005
|
||||
// UGQR4 = 0x00060006
|
||||
// UGQR5 = 0x00070007
|
||||
// but games are free to modify UGQR2 to UGQR7 it seems.
|
||||
// no game modifies UGQR0 so it's safe enough to optimize for the default value
|
||||
// Ideally we would do some kind of runtime tracking and second recompilation to create fast paths for PSQ_L/PSQ_ST but thats todo
|
||||
if (gqrIndex == 0)
|
||||
gqrValue = 0x00000000;
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* If value of GQR can be predicted for a given PSQ load or store instruction then replace it with an optimized version
|
||||
*/
|
||||
void PPCRecompiler_optimizePSQLoadAndStore(ppcImlGenContext_t* ppcImlGenContext)
|
||||
{
|
||||
for (IMLSegment* segIt : ppcImlGenContext->segmentList2)
|
||||
{
|
||||
for(IMLInstruction& instIt : segIt->imlList)
|
||||
{
|
||||
if (instIt.type == PPCREC_IML_TYPE_FPR_LOAD || instIt.type == PPCREC_IML_TYPE_FPR_LOAD_INDEXED)
|
||||
{
|
||||
if(instIt.op_storeLoad.mode != PPCREC_FPR_LD_MODE_PSQ_GENERIC_PS0 &&
|
||||
instIt.op_storeLoad.mode != PPCREC_FPR_LD_MODE_PSQ_GENERIC_PS0_PS1 )
|
||||
continue;
|
||||
// get GQR value
|
||||
cemu_assert_debug(instIt.op_storeLoad.registerGQR.IsValid());
|
||||
sint32 gqrIndex = _getGQRIndexFromRegister(ppcImlGenContext, instIt.op_storeLoad.registerGQR);
|
||||
cemu_assert(gqrIndex >= 0);
|
||||
if (ppcImlGenContext->tracking.modifiesGQR[gqrIndex])
|
||||
continue;
|
||||
uint32 gqrValue;
|
||||
if (!PPCRecompiler_isUGQRValueKnown(ppcImlGenContext, gqrIndex, gqrValue))
|
||||
continue;
|
||||
|
||||
uint32 formatType = (gqrValue >> 16) & 7;
|
||||
uint32 scale = (gqrValue >> 24) & 0x3F;
|
||||
if (scale != 0)
|
||||
continue; // only generic handler supports scale
|
||||
if (instIt.op_storeLoad.mode == PPCREC_FPR_LD_MODE_PSQ_GENERIC_PS0)
|
||||
{
|
||||
if (formatType == 0)
|
||||
instIt.op_storeLoad.mode = PPCREC_FPR_LD_MODE_PSQ_FLOAT_PS0;
|
||||
else if (formatType == 4)
|
||||
instIt.op_storeLoad.mode = PPCREC_FPR_LD_MODE_PSQ_U8_PS0;
|
||||
else if (formatType == 5)
|
||||
instIt.op_storeLoad.mode = PPCREC_FPR_LD_MODE_PSQ_U16_PS0;
|
||||
else if (formatType == 6)
|
||||
instIt.op_storeLoad.mode = PPCREC_FPR_LD_MODE_PSQ_S8_PS0;
|
||||
else if (formatType == 7)
|
||||
instIt.op_storeLoad.mode = PPCREC_FPR_LD_MODE_PSQ_S16_PS0;
|
||||
if (instIt.op_storeLoad.mode != PPCREC_FPR_LD_MODE_PSQ_GENERIC_PS0)
|
||||
instIt.op_storeLoad.registerGQR = IMLREG_INVALID;
|
||||
}
|
||||
else if (instIt.op_storeLoad.mode == PPCREC_FPR_LD_MODE_PSQ_GENERIC_PS0_PS1)
|
||||
{
|
||||
if (formatType == 0)
|
||||
instIt.op_storeLoad.mode = PPCREC_FPR_LD_MODE_PSQ_FLOAT_PS0_PS1;
|
||||
else if (formatType == 4)
|
||||
instIt.op_storeLoad.mode = PPCREC_FPR_LD_MODE_PSQ_U8_PS0_PS1;
|
||||
else if (formatType == 5)
|
||||
instIt.op_storeLoad.mode = PPCREC_FPR_LD_MODE_PSQ_U16_PS0_PS1;
|
||||
else if (formatType == 6)
|
||||
instIt.op_storeLoad.mode = PPCREC_FPR_LD_MODE_PSQ_S8_PS0_PS1;
|
||||
else if (formatType == 7)
|
||||
instIt.op_storeLoad.mode = PPCREC_FPR_LD_MODE_PSQ_S16_PS0_PS1;
|
||||
if (instIt.op_storeLoad.mode != PPCREC_FPR_LD_MODE_PSQ_GENERIC_PS0_PS1)
|
||||
instIt.op_storeLoad.registerGQR = IMLREG_INVALID;
|
||||
}
|
||||
}
|
||||
else if (instIt.type == PPCREC_IML_TYPE_FPR_STORE || instIt.type == PPCREC_IML_TYPE_FPR_STORE_INDEXED)
|
||||
{
|
||||
if(instIt.op_storeLoad.mode != PPCREC_FPR_ST_MODE_PSQ_GENERIC_PS0 &&
|
||||
instIt.op_storeLoad.mode != PPCREC_FPR_ST_MODE_PSQ_GENERIC_PS0_PS1)
|
||||
continue;
|
||||
// get GQR value
|
||||
cemu_assert_debug(instIt.op_storeLoad.registerGQR.IsValid());
|
||||
sint32 gqrIndex = _getGQRIndexFromRegister(ppcImlGenContext, instIt.op_storeLoad.registerGQR);
|
||||
cemu_assert(gqrIndex >= 0 && gqrIndex < 8);
|
||||
if (ppcImlGenContext->tracking.modifiesGQR[gqrIndex])
|
||||
continue;
|
||||
uint32 gqrValue;
|
||||
if(!PPCRecompiler_isUGQRValueKnown(ppcImlGenContext, gqrIndex, gqrValue))
|
||||
continue;
|
||||
uint32 formatType = (gqrValue >> 16) & 7;
|
||||
uint32 scale = (gqrValue >> 24) & 0x3F;
|
||||
if (scale != 0)
|
||||
continue; // only generic handler supports scale
|
||||
if (instIt.op_storeLoad.mode == PPCREC_FPR_ST_MODE_PSQ_GENERIC_PS0)
|
||||
{
|
||||
if (formatType == 0)
|
||||
instIt.op_storeLoad.mode = PPCREC_FPR_ST_MODE_PSQ_FLOAT_PS0;
|
||||
else if (formatType == 4)
|
||||
instIt.op_storeLoad.mode = PPCREC_FPR_ST_MODE_PSQ_U8_PS0;
|
||||
else if (formatType == 5)
|
||||
instIt.op_storeLoad.mode = PPCREC_FPR_ST_MODE_PSQ_U16_PS0;
|
||||
else if (formatType == 6)
|
||||
instIt.op_storeLoad.mode = PPCREC_FPR_ST_MODE_PSQ_S8_PS0;
|
||||
else if (formatType == 7)
|
||||
instIt.op_storeLoad.mode = PPCREC_FPR_ST_MODE_PSQ_S16_PS0;
|
||||
if (instIt.op_storeLoad.mode != PPCREC_FPR_ST_MODE_PSQ_GENERIC_PS0)
|
||||
instIt.op_storeLoad.registerGQR = IMLREG_INVALID;
|
||||
}
|
||||
else if (instIt.op_storeLoad.mode == PPCREC_FPR_ST_MODE_PSQ_GENERIC_PS0_PS1)
|
||||
{
|
||||
if (formatType == 0)
|
||||
instIt.op_storeLoad.mode = PPCREC_FPR_ST_MODE_PSQ_FLOAT_PS0_PS1;
|
||||
else if (formatType == 4)
|
||||
instIt.op_storeLoad.mode = PPCREC_FPR_ST_MODE_PSQ_U8_PS0_PS1;
|
||||
else if (formatType == 5)
|
||||
instIt.op_storeLoad.mode = PPCREC_FPR_ST_MODE_PSQ_U16_PS0_PS1;
|
||||
else if (formatType == 6)
|
||||
instIt.op_storeLoad.mode = PPCREC_FPR_ST_MODE_PSQ_S8_PS0_PS1;
|
||||
else if (formatType == 7)
|
||||
instIt.op_storeLoad.mode = PPCREC_FPR_ST_MODE_PSQ_S16_PS0_PS1;
|
||||
if (instIt.op_storeLoad.mode != PPCREC_FPR_ST_MODE_PSQ_GENERIC_PS0_PS1)
|
||||
instIt.op_storeLoad.registerGQR = IMLREG_INVALID;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// analyses register dependencies across the entire function
|
||||
// per segment this will generate information about which registers need to be preserved and which ones don't (e.g. are overwritten)
|
||||
class IMLOptimizerRegIOAnalysis
|
||||
|
||||
@@ -2095,7 +2095,10 @@ void IMLRA_GenerateSegmentMoveInstructions2(IMLRegisterAllocatorContext& ctx, IM
|
||||
cemu_assert_debug(hadSuffixInstruction == imlSegment->HasSuffixInstruction());
|
||||
if (imlSegment->HasSuffixInstruction())
|
||||
{
|
||||
cemu_assert_debug(!currentRange); // currentRange should be NULL?
|
||||
if (currentRange)
|
||||
{
|
||||
cemuLog_logDebug(LogType::Force, "[DEBUG] GenerateSegmentMoveInstructions() hit suffix path with non-null currentRange. Segment: {:08x}", imlSegment->ppcAddress);
|
||||
}
|
||||
for (auto& remainingRange : activeRanges)
|
||||
{
|
||||
cemu_assert_debug(!remainingRange->hasStore);
|
||||
|
||||
@@ -336,10 +336,7 @@ bool PPCRecompiler_ApplyIMLPasses(ppcImlGenContext_t& ppcImlGenContext)
|
||||
// this simplifies logic during register allocation
|
||||
PPCRecompilerIML_isolateEnterableSegments(&ppcImlGenContext);
|
||||
|
||||
// if GQRs can be predicted, optimize PSQ load/stores
|
||||
PPCRecompiler_optimizePSQLoadAndStore(&ppcImlGenContext);
|
||||
|
||||
// merge certain float load+store patterns (must happen before FPR register remapping)
|
||||
// merge certain float load+store patterns
|
||||
IMLOptimizer_OptimizeDirectFloatCopies(&ppcImlGenContext);
|
||||
// delay byte swapping for certain load+store patterns
|
||||
IMLOptimizer_OptimizeDirectIntegerCopies(&ppcImlGenContext);
|
||||
@@ -694,9 +691,9 @@ void PPCRecompiler_init()
|
||||
ppcRecompilerEnabled = false;
|
||||
return;
|
||||
}
|
||||
if (LaunchSettings::ForceInterpreter())
|
||||
if (LaunchSettings::ForceInterpreter() || LaunchSettings::ForceMultiCoreInterpreter())
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Recompiler disabled. Command line --force-interpreter was passed");
|
||||
cemuLog_log(LogType::Force, "Recompiler disabled. Command line --force-interpreter or force-multicore-interpreter was passed");
|
||||
return;
|
||||
}
|
||||
if (ppcRecompilerInstanceData)
|
||||
|
||||
@@ -14,34 +14,20 @@ void PPCRecompilerIml_insertSegments(ppcImlGenContext_t* ppcImlGenContext, sint3
|
||||
void PPCRecompilerIml_setSegmentPoint(IMLSegmentPoint* segmentPoint, IMLSegment* imlSegment, sint32 index);
|
||||
void PPCRecompilerIml_removeSegmentPoint(IMLSegmentPoint* segmentPoint);
|
||||
|
||||
// GPR register management
|
||||
IMLReg PPCRecompilerImlGen_loadRegister(ppcImlGenContext_t* ppcImlGenContext, uint32 mappedName);
|
||||
// Register management
|
||||
IMLReg PPCRecompilerImlGen_LookupReg(ppcImlGenContext_t* ppcImlGenContext, IMLName mappedName, IMLRegFormat regFormat);
|
||||
|
||||
// FPR register management
|
||||
IMLReg PPCRecompilerImlGen_loadFPRRegister(ppcImlGenContext_t* ppcImlGenContext, uint32 mappedName, bool loadNew = false);
|
||||
IMLReg PPCRecompilerImlGen_loadOverwriteFPRRegister(ppcImlGenContext_t* ppcImlGenContext, uint32 mappedName);
|
||||
IMLReg PPCRecompilerImlGen_loadRegister(ppcImlGenContext_t* ppcImlGenContext, uint32 mappedName);
|
||||
|
||||
// IML instruction generation
|
||||
void PPCRecompilerImlGen_generateNewInstruction_conditional_r_s32(ppcImlGenContext_t* ppcImlGenContext, IMLInstruction* imlInstruction, uint32 operation, IMLReg registerIndex, sint32 immS32, uint32 crRegisterIndex, uint32 crBitIndex, bool bitMustBeSet);
|
||||
void PPCRecompilerImlGen_generateNewInstruction_fpr_r(ppcImlGenContext_t* ppcImlGenContext, IMLInstruction* imlInstruction, sint32 operation, IMLReg registerResult);
|
||||
|
||||
// IML generation - FPU
|
||||
bool PPCRecompilerImlGen_LFS(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_LFSU(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_LFSX(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_LFSUX(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_LFD(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_LFDU(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_LFDX(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_LFDUX(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_STFS(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_STFSU(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_STFSX(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_STFSUX(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_LFS_LFSU_LFD_LFDU(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool withUpdate, bool isDouble);
|
||||
bool PPCRecompilerImlGen_LFSX_LFSUX_LFDX_LFDUX(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool withUpdate, bool isDouble);
|
||||
bool PPCRecompilerImlGen_STFS_STFSU_STFD_STFDU(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool withUpdate, bool isDouble);
|
||||
bool PPCRecompilerImlGen_STFSX_STFSUX_STFDX_STFDUX(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool hasUpdate, bool isDouble);
|
||||
bool PPCRecompilerImlGen_STFIWX(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_STFD(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_STFDU(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_STFDX(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_FADD(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_FSUB(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_FMUL(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
@@ -67,22 +53,17 @@ bool PPCRecompilerImlGen_FNEG(ppcImlGenContext_t* ppcImlGenContext, uint32 opcod
|
||||
bool PPCRecompilerImlGen_FSEL(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_FRSQRTE(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_FCTIWZ(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_PSQ_L(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_PSQ_LU(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_PSQ_ST(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_PSQ_STU(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_PS_MULS0(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_PS_MULS1(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_PS_MADDS0(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_PS_MADDS1(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_PSQ_L(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool withUpdate);
|
||||
bool PPCRecompilerImlGen_PSQ_ST(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool withUpdate);
|
||||
bool PPCRecompilerImlGen_PS_MULSX(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool isVariant1);
|
||||
bool PPCRecompilerImlGen_PS_MADDSX(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool isVariant1);
|
||||
bool PPCRecompilerImlGen_PS_ADD(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_PS_SUB(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_PS_MUL(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_PS_DIV(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_PS_MADD(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_PS_NMADD(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_PS_MSUB(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_PS_NMSUB(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_PS_MSUB(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool withNegative);
|
||||
bool PPCRecompilerImlGen_PS_SUM0(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_PS_SUM1(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
bool PPCRecompilerImlGen_PS_NEG(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
|
||||
@@ -102,3 +83,19 @@ bool PPCRecompilerImlGen_PS_CMPU1(ppcImlGenContext_t* ppcImlGenContext, uint32 o
|
||||
// IML general
|
||||
|
||||
void PPCRecompilerIML_isolateEnterableSegments(ppcImlGenContext_t* ppcImlGenContext);
|
||||
|
||||
void PPCIMLGen_CreateSegmentBranchedPath(ppcImlGenContext_t& ppcImlGenContext, PPCBasicBlockInfo& basicBlockInfo, const std::function<void(ppcImlGenContext_t&)>& genSegmentBranchTaken, const std::function<void(ppcImlGenContext_t&)>& genSegmentBranchNotTaken);
|
||||
void PPCIMLGen_CreateSegmentBranchedPath(ppcImlGenContext_t& ppcImlGenContext, PPCBasicBlockInfo& basicBlockInfo, const std::function<void(ppcImlGenContext_t&)>& genSegmentBranchNotTaken); // no else segment
|
||||
void PPCIMLGen_CreateSegmentBranchedPathMultiple(ppcImlGenContext_t& ppcImlGenContext, PPCBasicBlockInfo& basicBlockInfo, IMLSegment** segmentsOut, IMLReg compareReg, sint32* compareValues, sint32 count, sint32 defaultCaseIndex);
|
||||
|
||||
class IMLRedirectInstOutput
|
||||
{
|
||||
public:
|
||||
IMLRedirectInstOutput(ppcImlGenContext_t* ppcImlGenContext, IMLSegment* outputSegment);
|
||||
~IMLRedirectInstOutput();
|
||||
|
||||
|
||||
private:
|
||||
ppcImlGenContext_t* m_context;
|
||||
IMLSegment* m_prevSegment;
|
||||
};
|
||||
@@ -87,8 +87,7 @@ void PPCRecompilerImlGen_generateNewInstruction_memory_r_indexed(ppcImlGenContex
|
||||
}
|
||||
|
||||
// create and fill two segments (branch taken and branch not taken) as a follow up to the current segment and then merge flow afterwards
|
||||
template<typename F1n, typename F2n>
|
||||
void PPCIMLGen_CreateSegmentBranchedPath(ppcImlGenContext_t& ppcImlGenContext, PPCBasicBlockInfo& basicBlockInfo, F1n genSegmentBranchTaken, F2n genSegmentBranchNotTaken)
|
||||
void PPCIMLGen_CreateSegmentBranchedPath(ppcImlGenContext_t& ppcImlGenContext, PPCBasicBlockInfo& basicBlockInfo, const std::function<void(ppcImlGenContext_t&)>& genSegmentBranchTaken, const std::function<void(ppcImlGenContext_t&)>& genSegmentBranchNotTaken)
|
||||
{
|
||||
IMLSegment* currentWriteSegment = basicBlockInfo.GetSegmentForInstructionAppend();
|
||||
|
||||
@@ -118,6 +117,122 @@ void PPCIMLGen_CreateSegmentBranchedPath(ppcImlGenContext_t& ppcImlGenContext, P
|
||||
basicBlockInfo.appendSegment = segMerge;
|
||||
}
|
||||
|
||||
void PPCIMLGen_CreateSegmentBranchedPath(ppcImlGenContext_t& ppcImlGenContext, PPCBasicBlockInfo& basicBlockInfo, const std::function<void(ppcImlGenContext_t&)>& genSegmentBranchNotTaken)
|
||||
{
|
||||
IMLSegment* currentWriteSegment = basicBlockInfo.GetSegmentForInstructionAppend();
|
||||
|
||||
std::span<IMLSegment*> segments = ppcImlGenContext.InsertSegments(ppcImlGenContext.GetSegmentIndex(currentWriteSegment) + 1, 2);
|
||||
IMLSegment* segBranchNotTaken = segments[0];
|
||||
IMLSegment* segMerge = segments[1];
|
||||
|
||||
// link the segments
|
||||
segMerge->SetLinkBranchTaken(currentWriteSegment->GetBranchTaken());
|
||||
segMerge->SetLinkBranchNotTaken(currentWriteSegment->GetBranchNotTaken());
|
||||
currentWriteSegment->SetLinkBranchTaken(segMerge);
|
||||
currentWriteSegment->SetLinkBranchNotTaken(segBranchNotTaken);
|
||||
segBranchNotTaken->SetLinkBranchNotTaken(segMerge);
|
||||
// generate code for branch not taken segment
|
||||
ppcImlGenContext.currentOutputSegment = segBranchNotTaken;
|
||||
genSegmentBranchNotTaken(ppcImlGenContext);
|
||||
cemu_assert_debug(ppcImlGenContext.currentOutputSegment == segBranchNotTaken);
|
||||
// make merge segment the new write segment
|
||||
ppcImlGenContext.currentOutputSegment = segMerge;
|
||||
basicBlockInfo.appendSegment = segMerge;
|
||||
}
|
||||
|
||||
IMLReg _GetRegTemporaryS8(ppcImlGenContext_t* ppcImlGenContext, uint32 index);
|
||||
|
||||
IMLRedirectInstOutput::IMLRedirectInstOutput(ppcImlGenContext_t* ppcImlGenContext, IMLSegment* outputSegment) : m_context(ppcImlGenContext)
|
||||
{
|
||||
m_prevSegment = ppcImlGenContext->currentOutputSegment;
|
||||
cemu_assert_debug(ppcImlGenContext->currentOutputSegment == ppcImlGenContext->currentBasicBlock->appendSegment);
|
||||
if (outputSegment == ppcImlGenContext->currentOutputSegment)
|
||||
{
|
||||
m_prevSegment = nullptr;
|
||||
return;
|
||||
}
|
||||
m_context->currentBasicBlock->appendSegment = outputSegment;
|
||||
m_context->currentOutputSegment = outputSegment;
|
||||
}
|
||||
|
||||
IMLRedirectInstOutput::~IMLRedirectInstOutput()
|
||||
{
|
||||
if (m_prevSegment)
|
||||
{
|
||||
m_context->currentBasicBlock->appendSegment = m_prevSegment;
|
||||
m_context->currentOutputSegment = m_prevSegment;
|
||||
}
|
||||
}
|
||||
|
||||
// compare values and branch to segment with same index in segmentsOut. The last segment doesn't actually have any comparison and just is the default case. Thus compareValues is one shorter than count
|
||||
void PPCIMLGen_CreateSegmentBranchedPathMultiple(ppcImlGenContext_t& ppcImlGenContext, PPCBasicBlockInfo& basicBlockInfo, IMLSegment** segmentsOut, IMLReg compareReg, sint32* compareValues, sint32 count, sint32 defaultCaseIndex)
|
||||
{
|
||||
IMLSegment* currentWriteSegment = basicBlockInfo.GetSegmentForInstructionAppend();
|
||||
cemu_assert_debug(!currentWriteSegment->HasSuffixInstruction()); // must not already have a suffix instruction
|
||||
|
||||
const sint32 numBranchSegments = count + 1;
|
||||
const sint32 numCaseSegments = count;
|
||||
|
||||
std::span<IMLSegment*> segments = ppcImlGenContext.InsertSegments(ppcImlGenContext.GetSegmentIndex(currentWriteSegment) + 1, numBranchSegments - 1 + numCaseSegments + 1);
|
||||
IMLSegment** extraBranchSegments = segments.data();
|
||||
IMLSegment** caseSegments = segments.data() + numBranchSegments - 1;
|
||||
IMLSegment* mergeSegment = segments[numBranchSegments - 1 + numCaseSegments];
|
||||
|
||||
// move links to the merge segment
|
||||
mergeSegment->SetLinkBranchTaken(currentWriteSegment->GetBranchTaken());
|
||||
mergeSegment->SetLinkBranchNotTaken(currentWriteSegment->GetBranchNotTaken());
|
||||
currentWriteSegment->SetLinkBranchTaken(nullptr);
|
||||
currentWriteSegment->SetLinkBranchNotTaken(nullptr);
|
||||
|
||||
for (sint32 i=0; i<numCaseSegments; i++)
|
||||
segmentsOut[i] = caseSegments[i];
|
||||
|
||||
IMLReg tmpBoolReg = _GetRegTemporaryS8(&ppcImlGenContext, 2);
|
||||
|
||||
// the first branch segment is the original current write segment
|
||||
auto GetBranchSegment = [&](sint32 index) {
|
||||
if (index == 0)
|
||||
return currentWriteSegment;
|
||||
else
|
||||
return extraBranchSegments[index - 1];
|
||||
};
|
||||
// link branch segments (taken: Link to case segment. NotTaken: Link to next branch segment. For the last one use a non-conditional jump)
|
||||
for (sint32 i=0; i<numBranchSegments; i++)
|
||||
{
|
||||
IMLSegment* seg = GetBranchSegment(i);
|
||||
if (i < numBranchSegments - 1)
|
||||
{
|
||||
cemu_assert_debug(i < numCaseSegments);
|
||||
seg->SetLinkBranchTaken(caseSegments[i]);
|
||||
seg->SetLinkBranchNotTaken(GetBranchSegment(i + 1));
|
||||
seg->AppendInstruction()->make_compare_s32(compareReg, compareValues[i], tmpBoolReg, IMLCondition::EQ);
|
||||
seg->AppendInstruction()->make_conditional_jump(tmpBoolReg, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
cemu_assert_debug(defaultCaseIndex < numCaseSegments);
|
||||
seg->SetLinkBranchTaken(caseSegments[defaultCaseIndex]);
|
||||
seg->AppendInstruction()->make_jump();
|
||||
}
|
||||
}
|
||||
// link case segments
|
||||
for (sint32 i=0; i<numCaseSegments; i++)
|
||||
{
|
||||
IMLSegment* seg = caseSegments[i];
|
||||
if (i < numCaseSegments - 1)
|
||||
{
|
||||
seg->SetLinkBranchTaken(mergeSegment);
|
||||
// -> Jumps are added after the instructions
|
||||
}
|
||||
else
|
||||
{
|
||||
seg->SetLinkBranchTaken(mergeSegment);
|
||||
}
|
||||
}
|
||||
ppcImlGenContext.currentOutputSegment = mergeSegment;
|
||||
basicBlockInfo.appendSegment = mergeSegment;
|
||||
}
|
||||
|
||||
IMLReg PPCRecompilerImlGen_LookupReg(ppcImlGenContext_t* ppcImlGenContext, IMLName mappedName, IMLRegFormat regFormat)
|
||||
{
|
||||
auto it = ppcImlGenContext->mappedRegs.find(mappedName);
|
||||
@@ -212,32 +327,14 @@ IMLReg _GetRegTemporary(ppcImlGenContext_t* ppcImlGenContext, uint32 index)
|
||||
return PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_TEMPORARY + index);
|
||||
}
|
||||
|
||||
// get throw-away register. Only valid for the scope of a single translated instruction
|
||||
// be careful to not collide with manually loaded temporary register
|
||||
// get throw-away register
|
||||
// be careful to not collide with other temporary register
|
||||
IMLReg _GetRegTemporaryS8(ppcImlGenContext_t* ppcImlGenContext, uint32 index)
|
||||
{
|
||||
cemu_assert_debug(index < 4);
|
||||
return PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_TEMPORARY + index);
|
||||
}
|
||||
|
||||
/*
|
||||
* Loads a PPC fpr into any of the available IML FPU registers
|
||||
* If loadNew is false, it will check first if the fpr is already loaded into any IML register
|
||||
*/
|
||||
IMLReg PPCRecompilerImlGen_loadFPRRegister(ppcImlGenContext_t* ppcImlGenContext, uint32 mappedName, bool loadNew)
|
||||
{
|
||||
return PPCRecompilerImlGen_LookupReg(ppcImlGenContext, mappedName, IMLRegFormat::F64);
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if a PPC fpr register is already loaded into any IML register
|
||||
* If not, it will create a new undefined temporary IML FPU register and map the name (effectively overwriting the old ppc register)
|
||||
*/
|
||||
IMLReg PPCRecompilerImlGen_loadOverwriteFPRRegister(ppcImlGenContext_t* ppcImlGenContext, uint32 mappedName)
|
||||
{
|
||||
return PPCRecompilerImlGen_LookupReg(ppcImlGenContext, mappedName, IMLRegFormat::F64);
|
||||
}
|
||||
|
||||
bool PPCRecompiler_canInlineFunction(MPTR functionPtr, sint32* functionInstructionCount)
|
||||
{
|
||||
for (sint32 i = 0; i < 6; i++)
|
||||
@@ -1050,15 +1147,15 @@ bool PPCRecompilerImlGen_SRAW(ppcImlGenContext_t* ppcImlGenContext, uint32 opcod
|
||||
|
||||
// load masked shift factor into temporary register
|
||||
ppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_AND, regTmpShiftAmount, regB, 0x3F);
|
||||
ppcImlGenContext->emitInst().make_compare_s32(regTmpShiftAmount, 32, regTmpCondBool, IMLCondition::UNSIGNED_GT);
|
||||
ppcImlGenContext->emitInst().make_compare_s32(regTmpShiftAmount, 31, regTmpCondBool, IMLCondition::UNSIGNED_GT);
|
||||
ppcImlGenContext->emitInst().make_conditional_jump(regTmpCondBool, true);
|
||||
|
||||
PPCIMLGen_CreateSegmentBranchedPath(*ppcImlGenContext, *ppcImlGenContext->currentBasicBlock,
|
||||
[&](ppcImlGenContext_t& genCtx)
|
||||
{
|
||||
/* branch taken */
|
||||
genCtx.emitInst().make_r_r_r(PPCREC_IML_OP_RIGHT_SHIFT_S, regA, regS, regTmpShiftAmount);
|
||||
genCtx.emitInst().make_compare_s32(regA, 0, regCarry, IMLCondition::NEQ); // if the sign bit is still set it also means it was shifted out and we can set carry
|
||||
/* branch taken, shift size 32 or above */
|
||||
genCtx.emitInst().make_r_r_s32(PPCREC_IML_OP_RIGHT_SHIFT_S, regA, regS, 31); // shift the sign bit into all the bits
|
||||
genCtx.emitInst().make_compare_s32(regA, 0, regCarry, IMLCondition::NEQ);
|
||||
},
|
||||
[&](ppcImlGenContext_t& genCtx)
|
||||
{
|
||||
@@ -1073,6 +1170,8 @@ bool PPCRecompilerImlGen_SRAW(ppcImlGenContext_t* ppcImlGenContext, uint32 opcod
|
||||
genCtx.emitInst().make_r_r_r(PPCREC_IML_OP_RIGHT_SHIFT_S, regA, regS, regTmpShiftAmount);
|
||||
}
|
||||
);
|
||||
if (opcode & PPC_OPC_RC)
|
||||
PPCImlGen_UpdateCR0(ppcImlGenContext, regA);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1909,23 +2008,23 @@ bool PPCRecompiler_decodePPCInstruction(ppcImlGenContext_t* ppcImlGenContext)
|
||||
unsupportedInstructionFound = true;
|
||||
ppcImlGenContext->hasFPUInstruction = true;
|
||||
break;
|
||||
case 12: // multiply scalar
|
||||
if (PPCRecompilerImlGen_PS_MULS0(ppcImlGenContext, opcode) == false)
|
||||
case 12: // PS_MULS0
|
||||
if (PPCRecompilerImlGen_PS_MULSX(ppcImlGenContext, opcode, false) == false)
|
||||
unsupportedInstructionFound = true;
|
||||
ppcImlGenContext->hasFPUInstruction = true;
|
||||
break;
|
||||
case 13: // multiply scalar
|
||||
if (PPCRecompilerImlGen_PS_MULS1(ppcImlGenContext, opcode) == false)
|
||||
case 13: // PS_MULS1
|
||||
if (PPCRecompilerImlGen_PS_MULSX(ppcImlGenContext, opcode, true) == false)
|
||||
unsupportedInstructionFound = true;
|
||||
ppcImlGenContext->hasFPUInstruction = true;
|
||||
break;
|
||||
case 14: // multiply add scalar
|
||||
if (PPCRecompilerImlGen_PS_MADDS0(ppcImlGenContext, opcode) == false)
|
||||
case 14: // PS_MADDS0
|
||||
if (PPCRecompilerImlGen_PS_MADDSX(ppcImlGenContext, opcode, false) == false)
|
||||
unsupportedInstructionFound = true;
|
||||
ppcImlGenContext->hasFPUInstruction = true;
|
||||
break;
|
||||
case 15: // multiply add scalar
|
||||
if (PPCRecompilerImlGen_PS_MADDS1(ppcImlGenContext, opcode) == false)
|
||||
case 15: // PS_MADDS1
|
||||
if (PPCRecompilerImlGen_PS_MADDSX(ppcImlGenContext, opcode, true) == false)
|
||||
unsupportedInstructionFound = true;
|
||||
ppcImlGenContext->hasFPUInstruction = true;
|
||||
break;
|
||||
@@ -1992,22 +2091,22 @@ bool PPCRecompiler_decodePPCInstruction(ppcImlGenContext_t* ppcImlGenContext)
|
||||
unsupportedInstructionFound = true;
|
||||
ppcImlGenContext->hasFPUInstruction = true;
|
||||
break;
|
||||
case 28: // multiply sub paired
|
||||
if (PPCRecompilerImlGen_PS_MSUB(ppcImlGenContext, opcode) == false)
|
||||
case 28: // PS_MSUB
|
||||
if (PPCRecompilerImlGen_PS_MSUB(ppcImlGenContext, opcode, false) == false)
|
||||
unsupportedInstructionFound = true;
|
||||
ppcImlGenContext->hasFPUInstruction = true;
|
||||
break;
|
||||
case 29: // multiply add paired
|
||||
case 29: // PS_MADD
|
||||
if (PPCRecompilerImlGen_PS_MADD(ppcImlGenContext, opcode) == false)
|
||||
unsupportedInstructionFound = true;
|
||||
ppcImlGenContext->hasFPUInstruction = true;
|
||||
break;
|
||||
case 30: // negative multiply sub paired
|
||||
if (PPCRecompilerImlGen_PS_NMSUB(ppcImlGenContext, opcode) == false)
|
||||
case 30: // PS_NMSUB
|
||||
if (PPCRecompilerImlGen_PS_MSUB(ppcImlGenContext, opcode, true) == false)
|
||||
unsupportedInstructionFound = true;
|
||||
ppcImlGenContext->hasFPUInstruction = true;
|
||||
break;
|
||||
case 31: // negative multiply add paired
|
||||
case 31: // PS_NMADD
|
||||
if (PPCRecompilerImlGen_PS_NMADD(ppcImlGenContext, opcode) == false)
|
||||
unsupportedInstructionFound = true;
|
||||
ppcImlGenContext->hasFPUInstruction = true;
|
||||
@@ -2339,8 +2438,8 @@ bool PPCRecompiler_decodePPCInstruction(ppcImlGenContext_t* ppcImlGenContext)
|
||||
case 534: // LWBRX
|
||||
PPCRecompilerImlGen_LOAD_INDEXED(ppcImlGenContext, opcode, 32, false, false, false);
|
||||
break;
|
||||
case 535:
|
||||
if (PPCRecompilerImlGen_LFSX(ppcImlGenContext, opcode) == false)
|
||||
case 535: // LFSX
|
||||
if (PPCRecompilerImlGen_LFSX_LFSUX_LFDX_LFDUX(ppcImlGenContext, opcode, false, false) == false)
|
||||
unsupportedInstructionFound = true;
|
||||
ppcImlGenContext->hasFPUInstruction = true;
|
||||
break;
|
||||
@@ -2348,8 +2447,8 @@ bool PPCRecompiler_decodePPCInstruction(ppcImlGenContext_t* ppcImlGenContext)
|
||||
if (PPCRecompilerImlGen_SRW(ppcImlGenContext, opcode) == false)
|
||||
unsupportedInstructionFound = true;
|
||||
break;
|
||||
case 567:
|
||||
if (PPCRecompilerImlGen_LFSUX(ppcImlGenContext, opcode) == false)
|
||||
case 567: // LFSUX
|
||||
if (PPCRecompilerImlGen_LFSX_LFSUX_LFDX_LFDUX(ppcImlGenContext, opcode, true, false) == false)
|
||||
unsupportedInstructionFound = true;
|
||||
ppcImlGenContext->hasFPUInstruction = true;
|
||||
break;
|
||||
@@ -2360,13 +2459,13 @@ bool PPCRecompiler_decodePPCInstruction(ppcImlGenContext_t* ppcImlGenContext)
|
||||
case 598:
|
||||
PPCRecompilerImlGen_SYNC(ppcImlGenContext, opcode);
|
||||
break;
|
||||
case 599:
|
||||
if (PPCRecompilerImlGen_LFDX(ppcImlGenContext, opcode) == false)
|
||||
case 599: // LFDX
|
||||
if (PPCRecompilerImlGen_LFSX_LFSUX_LFDX_LFDUX(ppcImlGenContext, opcode, false, true) == false)
|
||||
unsupportedInstructionFound = true;
|
||||
ppcImlGenContext->hasFPUInstruction = true;
|
||||
break;
|
||||
case 631:
|
||||
if (PPCRecompilerImlGen_LFDUX(ppcImlGenContext, opcode) == false)
|
||||
case 631: // LFDUX
|
||||
if (PPCRecompilerImlGen_LFSX_LFSUX_LFDX_LFDUX(ppcImlGenContext, opcode, true, true) == false)
|
||||
unsupportedInstructionFound = true;
|
||||
ppcImlGenContext->hasFPUInstruction = true;
|
||||
break;
|
||||
@@ -2374,20 +2473,24 @@ bool PPCRecompiler_decodePPCInstruction(ppcImlGenContext_t* ppcImlGenContext)
|
||||
if (!PPCRecompilerImlGen_STORE_INDEXED(ppcImlGenContext, opcode, 32, false, false))
|
||||
unsupportedInstructionFound = true;
|
||||
break;
|
||||
case 663:
|
||||
if (PPCRecompilerImlGen_STFSX(ppcImlGenContext, opcode) == false)
|
||||
case 663: // STFSX
|
||||
if (PPCRecompilerImlGen_STFSX_STFSUX_STFDX_STFDUX(ppcImlGenContext, opcode, false, false) == false)
|
||||
unsupportedInstructionFound = true;
|
||||
break;
|
||||
case 695:
|
||||
if (PPCRecompilerImlGen_STFSUX(ppcImlGenContext, opcode) == false)
|
||||
case 695: // STFSUX
|
||||
if (PPCRecompilerImlGen_STFSX_STFSUX_STFDX_STFDUX(ppcImlGenContext, opcode, true, false) == false)
|
||||
unsupportedInstructionFound = true;
|
||||
break;
|
||||
case 725:
|
||||
if (PPCRecompilerImlGen_STSWI(ppcImlGenContext, opcode) == false)
|
||||
unsupportedInstructionFound = true;
|
||||
break;
|
||||
case 727:
|
||||
if (PPCRecompilerImlGen_STFDX(ppcImlGenContext, opcode) == false)
|
||||
case 727: // STFDX
|
||||
if (PPCRecompilerImlGen_STFSX_STFSUX_STFDX_STFDUX(ppcImlGenContext, opcode, false, true) == false)
|
||||
unsupportedInstructionFound = true;
|
||||
break;
|
||||
case 759: // STFDUX
|
||||
if (PPCRecompilerImlGen_STFSX_STFSUX_STFDX_STFDUX(ppcImlGenContext, opcode, true, true) == false)
|
||||
unsupportedInstructionFound = true;
|
||||
break;
|
||||
case 790: // LHBRX
|
||||
@@ -2488,53 +2591,53 @@ bool PPCRecompiler_decodePPCInstruction(ppcImlGenContext_t* ppcImlGenContext)
|
||||
case 47:
|
||||
PPCRecompilerImlGen_STMW(ppcImlGenContext, opcode);
|
||||
break;
|
||||
case 48:
|
||||
if (PPCRecompilerImlGen_LFS(ppcImlGenContext, opcode) == false)
|
||||
case 48: // LFS
|
||||
if (PPCRecompilerImlGen_LFS_LFSU_LFD_LFDU(ppcImlGenContext, opcode, false, false) == false)
|
||||
unsupportedInstructionFound = true;
|
||||
ppcImlGenContext->hasFPUInstruction = true;
|
||||
break;
|
||||
case 49:
|
||||
if (PPCRecompilerImlGen_LFSU(ppcImlGenContext, opcode) == false)
|
||||
case 49: // LFSU
|
||||
if (PPCRecompilerImlGen_LFS_LFSU_LFD_LFDU(ppcImlGenContext, opcode, true, false) == false)
|
||||
unsupportedInstructionFound = true;
|
||||
ppcImlGenContext->hasFPUInstruction = true;
|
||||
break;
|
||||
case 50:
|
||||
if (PPCRecompilerImlGen_LFD(ppcImlGenContext, opcode) == false)
|
||||
case 50: // LFD
|
||||
if (PPCRecompilerImlGen_LFS_LFSU_LFD_LFDU(ppcImlGenContext, opcode, false, true) == false)
|
||||
unsupportedInstructionFound = true;
|
||||
ppcImlGenContext->hasFPUInstruction = true;
|
||||
break;
|
||||
case 51:
|
||||
if (PPCRecompilerImlGen_LFDU(ppcImlGenContext, opcode) == false)
|
||||
case 51: // LFDU
|
||||
if (PPCRecompilerImlGen_LFS_LFSU_LFD_LFDU(ppcImlGenContext, opcode, true, true) == false)
|
||||
unsupportedInstructionFound = true;
|
||||
ppcImlGenContext->hasFPUInstruction = true;
|
||||
break;
|
||||
case 52:
|
||||
if (PPCRecompilerImlGen_STFS(ppcImlGenContext, opcode) == false)
|
||||
case 52: // STFS
|
||||
if (PPCRecompilerImlGen_STFS_STFSU_STFD_STFDU(ppcImlGenContext, opcode, false, false) == false)
|
||||
unsupportedInstructionFound = true;
|
||||
ppcImlGenContext->hasFPUInstruction = true;
|
||||
break;
|
||||
case 53:
|
||||
if (PPCRecompilerImlGen_STFSU(ppcImlGenContext, opcode) == false)
|
||||
case 53: // STFSU
|
||||
if (PPCRecompilerImlGen_STFS_STFSU_STFD_STFDU(ppcImlGenContext, opcode, true, false) == false)
|
||||
unsupportedInstructionFound = true;
|
||||
ppcImlGenContext->hasFPUInstruction = true;
|
||||
break;
|
||||
case 54:
|
||||
if (PPCRecompilerImlGen_STFD(ppcImlGenContext, opcode) == false)
|
||||
case 54: // STFD
|
||||
if (PPCRecompilerImlGen_STFS_STFSU_STFD_STFDU(ppcImlGenContext, opcode, false, true) == false)
|
||||
unsupportedInstructionFound = true;
|
||||
ppcImlGenContext->hasFPUInstruction = true;
|
||||
break;
|
||||
case 55:
|
||||
if (PPCRecompilerImlGen_STFDU(ppcImlGenContext, opcode) == false)
|
||||
case 55: // STFDU
|
||||
if (PPCRecompilerImlGen_STFS_STFSU_STFD_STFDU(ppcImlGenContext, opcode, true, true) == false)
|
||||
unsupportedInstructionFound = true;
|
||||
ppcImlGenContext->hasFPUInstruction = true;
|
||||
break;
|
||||
case 56:
|
||||
if (PPCRecompilerImlGen_PSQ_L(ppcImlGenContext, opcode) == false)
|
||||
if (PPCRecompilerImlGen_PSQ_L(ppcImlGenContext, opcode, false) == false)
|
||||
unsupportedInstructionFound = true;
|
||||
ppcImlGenContext->hasFPUInstruction = true;
|
||||
break;
|
||||
case 57:
|
||||
if (PPCRecompilerImlGen_PSQ_LU(ppcImlGenContext, opcode) == false)
|
||||
if (PPCRecompilerImlGen_PSQ_L(ppcImlGenContext, opcode, true) == false)
|
||||
unsupportedInstructionFound = true;
|
||||
ppcImlGenContext->hasFPUInstruction = true;
|
||||
break;
|
||||
@@ -2587,12 +2690,12 @@ bool PPCRecompiler_decodePPCInstruction(ppcImlGenContext_t* ppcImlGenContext)
|
||||
}
|
||||
break;
|
||||
case 60:
|
||||
if (PPCRecompilerImlGen_PSQ_ST(ppcImlGenContext, opcode) == false)
|
||||
if (PPCRecompilerImlGen_PSQ_ST(ppcImlGenContext, opcode, false) == false)
|
||||
unsupportedInstructionFound = true;
|
||||
ppcImlGenContext->hasFPUInstruction = true;
|
||||
break;
|
||||
case 61:
|
||||
if (PPCRecompilerImlGen_PSQ_STU(ppcImlGenContext, opcode) == false)
|
||||
if (PPCRecompilerImlGen_PSQ_ST(ppcImlGenContext, opcode, true) == false)
|
||||
unsupportedInstructionFound = true;
|
||||
ppcImlGenContext->hasFPUInstruction = true;
|
||||
break;
|
||||
@@ -2702,7 +2805,6 @@ bool PPCRecompiler_decodePPCInstruction(ppcImlGenContext_t* ppcImlGenContext)
|
||||
}
|
||||
|
||||
// returns false if code flow is not interrupted
|
||||
// continueDefaultPath: Controls if
|
||||
bool PPCRecompiler_CheckIfInstructionEndsSegment(PPCFunctionBoundaryTracker& boundaryTracker, uint32 instructionAddress, uint32 opcode, bool& makeNextInstEnterable, bool& continueDefaultPath, bool& hasBranchTarget, uint32& branchTarget)
|
||||
{
|
||||
hasBranchTarget = false;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user