From 5607eaa312bd77f391393cab6ae96ca49adddb96 Mon Sep 17 00:00:00 2001 From: k2154 Date: Fri, 25 Jul 2025 03:57:20 +0900 Subject: [PATCH] Android project - Applying LOADSTORE_RECOMPILE will improve game fps --- app/src/main/cpp/common/arm64/AsmHelpers.cpp | 5 +- app/src/main/cpp/common/arm64/AsmHelpers.h | 17 +- app/src/main/cpp/pcsx2/Config.h | 2 +- app/src/main/cpp/pcsx2/x86/ix86-32/iR5900.cpp | 4 +- .../cpp/pcsx2/x86/ix86-32/iR5900LoadStore.cpp | 942 ++++++++++++------ .../main/cpp/pcsx2/x86/ix86-32/recVTLB.cpp | 373 +++++-- app/src/main/cpp/pcsx2/x86/microVU_Macro.inl | 32 +- app/src/main/cpp/pcsx2/x86/microVU_Misc.inl | 4 +- 8 files changed, 949 insertions(+), 430 deletions(-) diff --git a/app/src/main/cpp/common/arm64/AsmHelpers.cpp b/app/src/main/cpp/common/arm64/AsmHelpers.cpp index ddb7119..0581c90 100644 --- a/app/src/main/cpp/common/arm64/AsmHelpers.cpp +++ b/app/src/main/cpp/common/arm64/AsmHelpers.cpp @@ -333,6 +333,7 @@ bool armIsCalleeSavedRegister(int reg) bool armIsCallerSaved(int id) { #if defined(__ANDROID__) + // gpr registers callee saved => r19 ~ r28 // 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 return (id <= 15); #else @@ -349,9 +350,9 @@ bool armIsCallerSaved(int id) bool armIsCallerSavedXmm(int id) { #if defined(__ANDROID__) - // v9,v10,v11,v12,v13,v14,v15 + // vector registers callee saved => d8 ~ d15 + // d9,d10,d11,d12,d13,d14,d15 return (id < 9); -// return true; #else #ifdef _WIN32 // XMM6 through XMM15 are saved. Upper 128 bits is always volatile. diff --git a/app/src/main/cpp/common/arm64/AsmHelpers.h b/app/src/main/cpp/common/arm64/AsmHelpers.h index 6ed2ff7..b3bed0d 100644 --- a/app/src/main/cpp/common/arm64/AsmHelpers.h +++ b/app/src/main/cpp/common/arm64/AsmHelpers.h @@ -13,10 +13,6 @@ namespace a64 = vixl::aarch64; -#define RWRET a64::w0 -#define RXRET a64::x0 -#define RQRET a64::q0 - #define RWARG1 a64::w0 #define RWARG2 a64::w1 #define RWARG3 a64::w2 @@ -40,29 +36,17 @@ namespace a64 = vixl::aarch64; #define RDSCRATCH3 a64::d29 #define RSSCRATCH3 a64::s29 -#define RQSCRATCHI a64::VRegister(30, 128, 16) -#define RQSCRATCHF a64::VRegister(30, 128, 4) -#define RQSCRATCHD a64::VRegister(30, 128, 2) - -#define RQSCRATCH2I a64::VRegister(31, 128, 16) -#define RQSCRATCH2F a64::VRegister(31, 128, 4) -#define RQSCRATCH2D a64::VRegister(31, 128, 2) - #define EAX a64::w0 #define ECX a64::w1 #define EDX a64::w2 #define EBX a64::w3 #define EEX a64::w4 -#define E5X a64::w5 -#define E8X a64::w8 #define RAX a64::x0 #define RCX a64::x1 #define RDX a64::x2 #define RBX a64::x3 #define REX a64::x4 -#define R5X a64::x5 -#define R8X a64::x8 #define RSTATE_x19 a64::x19 #define RSTATE_x20 a64::x20 @@ -71,6 +55,7 @@ namespace a64 = vixl::aarch64; #define RSTATE_x23 a64::x23 #define RSTATE_x24 a64::x24 #define RFASTMEMBASE a64::x25 +#define RSTATE_x26 a64::x26 #define RSTATE_FPU a64::x27 #define RSTATE_PSX a64::x28 #define RSTATE_CPU a64::x29 diff --git a/app/src/main/cpp/pcsx2/Config.h b/app/src/main/cpp/pcsx2/Config.h index 0864397..338b533 100644 --- a/app/src/main/cpp/pcsx2/Config.h +++ b/app/src/main/cpp/pcsx2/Config.h @@ -1452,7 +1452,7 @@ namespace EmuFolders #define ARITHMETIC_RECOMPILE #define MULTDIV_RECOMPILE #define JUMP_RECOMPILE -//#define LOADSTORE_RECOMPILE +#define LOADSTORE_RECOMPILE #define MOVE_RECOMPILE //#define MMI_RECOMPILE //#define MMI0_RECOMPILE diff --git a/app/src/main/cpp/pcsx2/x86/ix86-32/iR5900.cpp b/app/src/main/cpp/pcsx2/x86/ix86-32/iR5900.cpp index 89124fe..8262b42 100644 --- a/app/src/main/cpp/pcsx2/x86/ix86-32/iR5900.cpp +++ b/app/src/main/cpp/pcsx2/x86/ix86-32/iR5900.cpp @@ -652,12 +652,14 @@ static void recResetRaw() EE::Profiler.Reset(); + // recVTLB => iR5900LoadStore + vtlb_DynGenDispatchers(); + // xSetPtr(SysMemory::GetEERec()); armSetAsmPtr(recPtr, recPtrEnd - recPtr, nullptr); armStartBlock(); _DynGen_Dispatchers(); -// vtlb_DynGenDispatchers(); // recPtr = xGetPtr(); recPtr = armEndBlock(); diff --git a/app/src/main/cpp/pcsx2/x86/ix86-32/iR5900LoadStore.cpp b/app/src/main/cpp/pcsx2/x86/ix86-32/iR5900LoadStore.cpp index 74cbd07..af62077 100644 --- a/app/src/main/cpp/pcsx2/x86/ix86-32/iR5900LoadStore.cpp +++ b/app/src/main/cpp/pcsx2/x86/ix86-32/iR5900LoadStore.cpp @@ -25,7 +25,7 @@ namespace R5900::Dynarec::OpcodeImpl * Load and store for GPR * * Format: OP rt, offset(base) * *********************************************************/ -#ifndef LOADSTORE_RECOMPILE2 +#ifndef LOADSTORE_RECOMPILE namespace Interp = R5900::Interpreter::OpcodeImpl; @@ -79,15 +79,19 @@ static void recLoadQuad(u32 bits, bool sign) else { // Load ECX with the source memory address that we're reading from. - _freeX86reg(arg1regd); - _eeMoveGPRtoR(arg1reg, _Rs_); - if (_Imm_ != 0) - xADD(arg1regd, _Imm_); + _freeX86reg(ECX); +// _eeMoveGPRtoR(arg1reg, _Rs_); + _eeMoveGPRtoR(a64::XRegister(RCX), _Rs_); + if (_Imm_ != 0) { +// xADD(arg1regd, _Imm_); + armAsm->Add(ECX, ECX, _Imm_); + } // force 16 byte alignment on 128 bit reads - xAND(arg1regd, ~0x0F); +// xAND(arg1regd, ~0x0F); + armAsm->And(ECX, ECX, ~0x0F); - xmmreg = vtlb_DynGenReadQuad(bits, arg1regd.GetId(), _Rt_ ? alloc_cb : nullptr); + xmmreg = vtlb_DynGenReadQuad(bits, ECX.GetCode(), _Rt_ ? alloc_cb : nullptr); } // if there was a constant, it should have been invalidated. @@ -117,12 +121,15 @@ static void recLoad(u32 bits, bool sign) else { // Load arg1 with the source memory address that we're reading from. - _freeX86reg(arg1regd); - _eeMoveGPRtoR(arg1regd, _Rs_); - if (_Imm_ != 0) - xADD(arg1regd, _Imm_); + _freeX86reg(ECX); +// _eeMoveGPRtoR(arg1regd, _Rs_); + _eeMoveGPRtoR(a64::WRegister(ECX), _Rs_); + if (_Imm_ != 0) { +// xADD(arg1regd, _Imm_); + armAsm->Add(ECX, ECX, _Imm_); + } - x86reg = vtlb_DynGenReadNonQuad(bits, sign, false, arg1regd.GetId(), alloc_cb); + x86reg = vtlb_DynGenReadNonQuad(bits, sign, false, ECX.GetCode(), alloc_cb); } // if there was a constant, it should have been invalidated. @@ -169,20 +176,26 @@ static void recStore(u32 bits) if (_Rs_ != 0) { // TODO(Stenzek): Preload Rs when it's live. Turn into LEA. - _eeMoveGPRtoR(arg1regd, _Rs_); - if (_Imm_ != 0) - xADD(arg1regd, _Imm_); +// _eeMoveGPRtoR(arg1regd, _Rs_); + _eeMoveGPRtoR(a64::WRegister(ECX), _Rs_); + if (_Imm_ != 0) { +// xADD(arg1regd, _Imm_); + armAsm->Add(ECX, ECX, _Imm_); + } } else { - xMOV(arg1regd, _Imm_); +// xMOV(arg1regd, _Imm_); + armAsm->Mov(ECX, _Imm_); } - if (bits == 128) - xAND(arg1regd, ~0x0F); + if (bits == 128) { +// xAND(arg1regd, ~0x0F); + armAsm->And(ECX, ECX, ~0x0F); + } // TODO(Stenzek): Use Rs directly if imm=0. But beware of upper bits. - vtlb_DynGenWrite(bits, xmm, arg1regd.GetId(), regt); + vtlb_DynGenWrite(bits, xmm, ECX.GetCode(), regt); } } @@ -261,10 +274,10 @@ void recSQ() void recLWL() { #ifdef REC_LOADS - _freeX86reg(eax); - _freeX86reg(ecx); - _freeX86reg(edx); - _freeX86reg(arg1regd); + _freeX86reg(EAX); + _freeX86reg(ECX); + _freeX86reg(EDX); +// _freeX86reg(arg1regd); // avoid flushing and immediately reading back if (_Rt_) @@ -272,19 +285,25 @@ void recLWL() if (_Rs_) _addNeededX86reg(X86TYPE_GPR, _Rs_); - const xRegister32 temp(_allocX86reg(X86TYPE_TEMP, 0, MODE_CALLEESAVED)); + const a64::WRegister temp(_allocX86reg(X86TYPE_TEMP, 0, MODE_CALLEESAVED)); _eeMoveGPRtoR(arg1regd, _Rs_); - if (_Imm_ != 0) - xADD(arg1regd, _Imm_); + if (_Imm_ != 0) { +// xADD(arg1regd, _Imm_); + armAsm->Add(ECX, ECX, _Imm_); + } // calleeSavedReg1 = bit offset in word - xMOV(temp, arg1regd); - xAND(temp, 3); - xSHL(temp, 3); +// xMOV(temp, arg1regd); + armAsm->Mov(temp, ECX); +// xAND(temp, 3); + armAsm->And(temp, temp, 3); +// xSHL(temp, 3); + armAsm->Lsl(temp, temp, 3); - xAND(arg1regd, ~3); - vtlb_DynGenReadNonQuad(32, false, false, arg1regd.GetId(), RETURN_READ_IN_RAX); +// xAND(arg1regd, ~3); + armAsm->And(ECX, ECX, ~3); + vtlb_DynGenReadNonQuad(32, false, false, ECX.GetCode(), RETURN_READ_IN_RAX); if (!_Rt_) { @@ -293,20 +312,29 @@ void recLWL() } // mask off bytes loaded - xMOV(ecx, temp); +// xMOV(ecx, temp); + armAsm->Mov(ECX, temp); _freeX86reg(temp); const int treg = _allocX86reg(X86TYPE_GPR, _Rt_, MODE_READ | MODE_WRITE); - xMOV(edx, 0xffffff); - xSHR(edx, cl); - xAND(edx, xRegister32(treg)); +// xMOV(edx, 0xffffff); + armAsm->Mov(EDX, 0xffffff); +// xSHR(edx, cl); + armAsm->Lsr(EDX, EDX, ECX); +// xAND(edx, xRegister32(treg)); + armAsm->And(EDX, EDX, a64::WRegister(treg)); // OR in bytes loaded - xNEG(ecx); - xADD(ecx, 24); - xSHL(eax, cl); - xOR(eax, edx); - xMOVSX(xRegister64(treg), eax); +// xNEG(ecx); + armAsm->Neg(ECX, ECX); +// xADD(ecx, 24); + armAsm->Add(ECX, ECX, 24); +// xSHL(eax, cl); + armAsm->Lsl(EAX, EAX, ECX); +// xOR(eax, edx); + armAsm->Orr(EAX, EAX, EDX); +// xMOVSX(xRegister64(treg), eax); + armAsm->Sxtw(a64::XRegister(treg), EAX); #else iFlushCall(FLUSH_INTERPRETER); _deleteEEreg(_Rs_, 1); @@ -322,10 +350,10 @@ void recLWL() void recLWR() { #ifdef REC_LOADS - _freeX86reg(eax); - _freeX86reg(ecx); - _freeX86reg(edx); - _freeX86reg(arg1regd); + _freeX86reg(EAX); + _freeX86reg(ECX); + _freeX86reg(EDX); +// _freeX86reg(arg1regd); // avoid flushing and immediately reading back if (_Rt_) @@ -333,17 +361,22 @@ void recLWR() if (_Rs_) _addNeededX86reg(X86TYPE_GPR, _Rs_); - const xRegister32 temp(_allocX86reg(X86TYPE_TEMP, 0, MODE_CALLEESAVED)); + const a64::WRegister temp(_allocX86reg(X86TYPE_TEMP, 0, MODE_CALLEESAVED)); - _eeMoveGPRtoR(arg1regd, _Rs_); - if (_Imm_ != 0) - xADD(arg1regd, _Imm_); +// _eeMoveGPRtoR(arg1regd, _Rs_); + _eeMoveGPRtoR(a64::WRegister(ECX), _Rs_); + if (_Imm_ != 0) { +// xADD(arg1regd, _Imm_); + armAsm->Add(ECX, ECX, _Imm_); + } // edi = bit offset in word - xMOV(temp, arg1regd); +// xMOV(temp, arg1regd); + armAsm->Mov(temp, ECX); - xAND(arg1regd, ~3); - vtlb_DynGenReadNonQuad(32, false, false, arg1regd.GetId(), RETURN_READ_IN_RAX); +// xAND(arg1regd, ~3); + armAsm->And(ECX, ECX, ~3); + vtlb_DynGenReadNonQuad(32, false, false, ECX.GetCode(), RETURN_READ_IN_RAX); if (!_Rt_) { @@ -352,27 +385,46 @@ void recLWR() } const int treg = _allocX86reg(X86TYPE_GPR, _Rt_, MODE_READ | MODE_WRITE); - xAND(temp, 3); + auto reg32 = a64::WRegister(treg); - xForwardJE8 nomask; - xSHL(temp, 3); +// xAND(temp, 3); + armAsm->Ands(temp, temp, 3); + +// xForwardJE8 nomask; + a64::Label nomask; + armAsm->B(&nomask, a64::Condition::eq); +// xSHL(temp, 3); + armAsm->Lsl(temp, temp, 3); // mask off bytes loaded - xMOV(ecx, 24); - xSUB(ecx, temp); - xMOV(edx, 0xffffff00); - xSHL(edx, cl); - xAND(xRegister32(treg), edx); +// xMOV(ecx, 24); + armAsm->Mov(ECX, 24); +// xSUB(ecx, temp); + armAsm->Sub(ECX, ECX, temp); +// xMOV(edx, 0xffffff00); + armAsm->Mov(EDX, 0xffffff00); +// xSHL(edx, cl); + armAsm->Lsl(EDX, EDX, ECX); +// xAND(xRegister32(treg), edx); + armAsm->And(reg32, reg32, EDX); // OR in bytes loaded - xMOV(ecx, temp); - xSHR(eax, cl); - xOR(xRegister32(treg), eax); +// xMOV(ecx, temp); + armAsm->Mov(ECX, temp); +// xSHR(eax, cl); + armAsm->Lsr(EAX, EAX, ECX); +// xOR(xRegister32(treg), eax); + armAsm->Orr(reg32, reg32, EAX); - xForwardJump8 end; - nomask.SetTarget(); +// xForwardJump8 end; + a64::Label end; + armAsm->B(&end); +// nomask.SetTarget(); + armBind(&nomask); // NOTE: This might look wrong, but it's correct - see interpreter. - xMOVSX(xRegister64(treg), eax); - end.SetTarget(); +// xMOVSX(xRegister64(treg), eax); + armAsm->Sxtw(a64::XRegister(treg), EAX); +// end.SetTarget(); + armBind(&end); _freeX86reg(temp); #else iFlushCall(FLUSH_INTERPRETER); @@ -399,60 +451,90 @@ void recSWL() else _addNeededX86reg(X86TYPE_GPR, _Rt_); - const xRegister32 temp(_allocX86reg(X86TYPE_TEMP, 0, MODE_CALLEESAVED)); - _freeX86reg(eax); - _freeX86reg(ecx); - _freeX86reg(arg1regd); - _freeX86reg(arg2regd); + const a64::WRegister temp(_allocX86reg(X86TYPE_TEMP, 0, MODE_CALLEESAVED)); + _freeX86reg(EAX); + _freeX86reg(ECX); + _freeX86reg(EDX); +// _freeX86reg(arg1regd); +// _freeX86reg(arg2regd); - _eeMoveGPRtoR(arg1regd, _Rs_); - if (_Imm_ != 0) - xADD(arg1regd, _Imm_); +// _eeMoveGPRtoR(arg1regd, _Rs_); + _eeMoveGPRtoR(a64::WRegister(ECX), _Rs_); + if (_Imm_ != 0) { +// xADD(arg1regd, _Imm_); + armAsm->Add(ECX, ECX, _Imm_); + } // edi = bit offset in word - xMOV(temp, arg1regd); - xAND(arg1regd, ~3); - xAND(temp, 3); - xCMP(temp, 3); +// xMOV(temp, arg1regd); + armAsm->Mov(temp, ECX); +// xAND(arg1regd, ~3); + armAsm->And(ECX, ECX, ~3); +// xAND(temp, 3); + armAsm->And(temp, temp, 3); +// xCMP(temp, 3); + armAsm->Cmp(temp, 3); // If we're not using fastmem, we need to flush early. Because the first read // (which would flush) happens inside a branch. if (!CHECK_FASTMEM || vtlb_IsFaultingPC(pc)) iFlushCall(FLUSH_FULLVTLB); - xForwardJE8 skip; - xSHL(temp, 3); +// xForwardJE8 skip; + a64::Label skip; + armAsm->B(&skip, a64::Condition::eq); +// xSHL(temp, 3); + armAsm->Lsl(temp, temp, 3); - vtlb_DynGenReadNonQuad(32, false, false, arg1regd.GetId(), RETURN_READ_IN_RAX); + vtlb_DynGenReadNonQuad(32, false, false, ECX.GetCode(), RETURN_READ_IN_RAX); // mask read -> arg2 - xMOV(ecx, temp); - xMOV(arg2regd, 0xffffff00); - xSHL(arg2regd, cl); - xAND(arg2regd, eax); +// xMOV(ecx, temp); + armAsm->Mov(ECX, temp); +// xMOV(arg2regd, 0xffffff00); + armAsm->Mov(EDX, 0xffffff00); +// xSHL(arg2regd, cl); + armAsm->Lsl(EDX, EDX, ECX); +// xAND(arg2regd, eax); + armAsm->And(EDX, EDX, EAX); if (_Rt_) { // mask write and OR -> edx - xNEG(ecx); - xADD(ecx, 24); - _eeMoveGPRtoR(eax, _Rt_, false); - xSHR(eax, cl); - xOR(arg2regd, eax); +// xNEG(ecx); + armAsm->Neg(ECX, ECX); +// xADD(ecx, 24); + armAsm->Add(ECX, ECX, 24); +// _eeMoveGPRtoR(eax, _Rt_, false); + _eeMoveGPRtoR(a64::WRegister(EAX), _Rt_, false); +// xSHR(eax, cl); + armAsm->Lsr(EAX, EAX, ECX); +// xOR(arg2regd, eax); + armAsm->Orr(EDX, EDX, EAX); } - _eeMoveGPRtoR(arg1regd, _Rs_, false); - if (_Imm_ != 0) - xADD(arg1regd, _Imm_); - xAND(arg1regd, ~3); +// _eeMoveGPRtoR(arg1regd, _Rs_, false); + _eeMoveGPRtoR(a64::WRegister(ECX), _Rs_, false); + if (_Imm_ != 0) { +// xADD(arg1regd, _Imm_); + armAsm->Add(ECX, ECX, _Imm_); + } +// xAND(arg1regd, ~3); + armAsm->And(ECX, ECX, ~3); - xForwardJump8 end; - skip.SetTarget(); - _eeMoveGPRtoR(arg2regd, _Rt_, false); - end.SetTarget(); +// xForwardJump8 end; + a64::Label end; + armAsm->B(&end); +// skip.SetTarget(); + armBind(&skip); +// _eeMoveGPRtoR(arg2regd, _Rt_, false); + _eeMoveGPRtoR(a64::WRegister(EDX), _Rt_, false); +// end.SetTarget(); + armBind(&end); _freeX86reg(temp); - vtlb_DynGenWrite(32, false, arg1regd.GetId(), arg2regd.GetId()); +// vtlb_DynGenWrite(32, false, arg1regd.GetId(), arg2regd.GetId()); + vtlb_DynGenWrite(32, false, ECX.GetCode(), EDX.GetCode()); #else iFlushCall(FLUSH_INTERPRETER); _deleteEEreg(_Rs_, 1); @@ -476,58 +558,87 @@ void recSWR() else _addNeededX86reg(X86TYPE_GPR, _Rt_); - const xRegister32 temp(_allocX86reg(X86TYPE_TEMP, 0, MODE_CALLEESAVED)); - _freeX86reg(ecx); - _freeX86reg(arg1regd); - _freeX86reg(arg2regd); + const a64::WRegister temp(_allocX86reg(X86TYPE_TEMP, 0, MODE_CALLEESAVED)); + _freeX86reg(ECX); + _freeX86reg(EDX); +// _freeX86reg(arg1regd); +// _freeX86reg(arg2regd); - _eeMoveGPRtoR(arg1regd, _Rs_); - if (_Imm_ != 0) - xADD(arg1regd, _Imm_); +// _eeMoveGPRtoR(arg1regd, _Rs_); + _eeMoveGPRtoR(a64::WRegister(ECX), _Rs_); + if (_Imm_ != 0) { +// xADD(arg1regd, _Imm_); + armAsm->Add(ECX, ECX, _Imm_); + } // edi = bit offset in word - xMOV(temp, arg1regd); - xAND(arg1regd, ~3); - xAND(temp, 3); +// xMOV(temp, arg1regd); + armAsm->Mov(temp, ECX); +// xAND(arg1regd, ~3); + armAsm->And(ECX, ECX, ~3); +// xAND(temp, 3); + armAsm->Ands(temp, temp, 3); // If we're not using fastmem, we need to flush early. Because the first read // (which would flush) happens inside a branch. if (!CHECK_FASTMEM || vtlb_IsFaultingPC(pc)) iFlushCall(FLUSH_FULLVTLB); - xForwardJE8 skip; - xSHL(temp, 3); +// xForwardJE8 skip; + a64::Label skip; + armAsm->B(&skip, a64::Condition::eq); +// xSHL(temp, 3); + armAsm->Lsl(temp, temp, 3); - vtlb_DynGenReadNonQuad(32, false, false, arg1regd.GetId(), RETURN_READ_IN_RAX); + vtlb_DynGenReadNonQuad(32, false, false, ECX.GetCode(), RETURN_READ_IN_RAX); // mask read -> edx - xMOV(ecx, 24); - xSUB(ecx, temp); - xMOV(arg2regd, 0xffffff); - xSHR(arg2regd, cl); - xAND(arg2regd, eax); +// xMOV(ecx, 24); + armAsm->Mov(ECX, 24); +// xSUB(ecx, temp); + armAsm->Sub(ECX, ECX, temp); +// xMOV(arg2regd, 0xffffff); + armAsm->Mov(EDX, 0xffffff); +// xSHR(arg2regd, cl); + armAsm->Lsr(EDX, EDX, ECX); +// xAND(arg2regd, eax); + armAsm->And(EDX, EDX, EAX); if (_Rt_) { // mask write and OR -> edx - xMOV(ecx, temp); - _eeMoveGPRtoR(eax, _Rt_, false); - xSHL(eax, cl); - xOR(arg2regd, eax); +// xMOV(ecx, temp); + armAsm->Mov(ECX, temp); +// _eeMoveGPRtoR(eax, _Rt_, false); + _eeMoveGPRtoR(a64::WRegister(EAX), _Rt_, false); +// xSHL(eax, cl); + armAsm->Lsl(EAX, EAX, ECX); +// xOR(arg2regd, eax); + armAsm->Orr(EDX, EDX, EAX); } - _eeMoveGPRtoR(arg1regd, _Rs_, false); - if (_Imm_ != 0) - xADD(arg1regd, _Imm_); - xAND(arg1regd, ~3); +// _eeMoveGPRtoR(arg1regd, _Rs_, false); + _eeMoveGPRtoR(a64::WRegister(ECX), _Rs_, false); + if (_Imm_ != 0) { +// xADD(arg1regd, _Imm_); + armAsm->Add(ECX, ECX, _Imm_); + } +// xAND(arg1regd, ~3); + armAsm->And(ECX, ECX, ~3); - xForwardJump8 end; - skip.SetTarget(); - _eeMoveGPRtoR(arg2regd, _Rt_, false); - end.SetTarget(); +// xForwardJump8 end; + a64::Label end; + armAsm->B(&end); +// skip.SetTarget(); + armBind(&skip); +// _eeMoveGPRtoR(arg2regd, _Rt_, false); + _eeMoveGPRtoR(a64::WRegister(EDX), _Rt_, false); +// end.SetTarget(); + armBind(&end); _freeX86reg(temp); - vtlb_DynGenWrite(32, false, arg1regd.GetId(), arg2regd.GetId()); +// vtlb_DynGenWrite(32, false, arg1regd.GetId(), arg2regd.GetId()); + vtlb_DynGenWrite(32, false, ECX.GetCode(), EDX.GetCode()); #else iFlushCall(FLUSH_INTERPRETER); _deleteEEreg(_Rs_, 1); @@ -540,36 +651,109 @@ void recSWR() //////////////////////////////////////////////////// -/// Masks rt with (0xffffffffffffffff maskshift maskamt), merges with (value shift amt), leaves result in value -static void ldlrhelper_const(int maskamt, const xImpl_Group2& maskshift, int amt, const xImpl_Group2& shift, const xRegister64& value, const xRegister64& rt) +namespace { - pxAssert(rt.GetId() != ecx.GetId() && value.GetId() != ecx.GetId()); + enum class SHIFTV + { + xSHL, + xSHR, + xSAR + }; +} // namespace + +/// Masks rt with (0xffffffffffffffff maskshift maskamt), merges with (value shift amt), leaves result in value +//static void ldlrhelper_const(int maskamt, const xImpl_Group2& maskshift, int amt, const xImpl_Group2& shift, const xRegister64& value, const xRegister64& rt) +static void ldlrhelper_const(int maskamt, const SHIFTV maskshift, int amt, const SHIFTV shift, const a64::XRegister& value, const a64::XRegister& rt) +{ + pxAssert(rt.GetCode() != ECX.GetCode() && value.GetCode() != ECX.GetCode()); // Would xor rcx, rcx; not rcx be better here? - xMOV(rcx, -1); +// xMOV(rcx, -1); + armAsm->Mov(RCX, -1); - maskshift(rcx, maskamt); - xAND(rt, rcx); +// maskshift(rcx, maskamt); + switch (maskshift) + { + case SHIFTV::xSHR: + armAsm->Lsr(RCX, RCX, maskamt); + break; + case SHIFTV::xSAR: + armAsm->Asr(RCX, RCX, maskamt); + break; + case SHIFTV::xSHL: + armAsm->Lsl(RCX, RCX, maskamt); + break; + } - shift(value, amt); - xOR(rt, value); +// xAND(rt, rcx); + armAsm->And(rt, rt, RCX); + +// shift(value, amt); + switch (shift) + { + case SHIFTV::xSHR: + armAsm->Lsr(value, value, amt); + break; + case SHIFTV::xSAR: + armAsm->Asr(value, value, amt); + break; + case SHIFTV::xSHL: + armAsm->Lsl(value, value, amt); + break; + } + +// xOR(rt, value); + armAsm->Orr(rt, rt, value); } /// Masks rt with (0xffffffffffffffff maskshift maskamt), merges with (value shift amt), leaves result in value -static void ldlrhelper(const xRegister32& maskamt, const xImpl_Group2& maskshift, const xRegister32& amt, const xImpl_Group2& shift, const xRegister64& value, const xRegister64& rt) +//static void ldlrhelper(const xRegister32& maskamt, const xImpl_Group2& maskshift, const xRegister32& amt, const xImpl_Group2& shift, const xRegister64& value, const xRegister64& rt) +static void ldlrhelper(const a64::WRegister& maskamt, const SHIFTV maskshift, const a64::WRegister& amt, const SHIFTV shift, const a64::XRegister& value, const a64::XRegister& rt) { - pxAssert(rt.GetId() != ecx.GetId() && amt.GetId() != ecx.GetId() && value.GetId() != ecx.GetId()); + pxAssert(rt.GetCode() != ECX.GetCode() && amt.GetCode() != ECX.GetCode() && value.GetCode() != ECX.GetCode()); // Would xor rcx, rcx; not rcx be better here? - const xRegister64 maskamt64(maskamt); - xMOV(ecx, maskamt); - xMOV(maskamt64, -1); - maskshift(maskamt64, cl); - xAND(rt, maskamt64); + const a64::XRegister maskamt64(maskamt.GetCode()); +// xMOV(ecx, maskamt); + armAsm->Mov(ECX, maskamt); +// xMOV(maskamt64, -1); + armAsm->Mov(maskamt64, -1); +// maskshift(maskamt64, cl); + switch (maskshift) + { + case SHIFTV::xSHR: + armAsm->Lsr(maskamt64, maskamt64, RCX); + break; + case SHIFTV::xSAR: + armAsm->Asr(maskamt64, maskamt64, RCX); + break; + case SHIFTV::xSHL: + armAsm->Lsl(maskamt64, maskamt64, RCX); + break; + } - xMOV(ecx, amt); - shift(value, cl); - xOR(rt, value); +// xAND(rt, maskamt64); + armAsm->And(rt, rt, maskamt64); + +// xMOV(ecx, amt); + armAsm->Mov(ECX, amt); + +// shift(value, cl); + switch (shift) + { + case SHIFTV::xSHR: + armAsm->Lsr(value, value, RCX); + break; + case SHIFTV::xSAR: + armAsm->Asr(value, value, RCX); + break; + case SHIFTV::xSHL: + armAsm->Lsl(value, value, RCX); + break; + } + +// xOR(rt, value); + armAsm->Orr(rt, rt, value); } void recLDL() @@ -584,19 +768,21 @@ void recLDL() if (_Rs_) _addNeededX86reg(X86TYPE_GPR, _Rs_); - const xRegister32 temp1(_allocX86reg(X86TYPE_TEMP, 0, MODE_CALLEESAVED)); - _freeX86reg(eax); - _freeX86reg(ecx); - _freeX86reg(edx); - _freeX86reg(arg1regd); + const a64::WRegister temp1(_allocX86reg(X86TYPE_TEMP, 0, MODE_CALLEESAVED)); + _freeX86reg(EAX); + _freeX86reg(ECX); + _freeX86reg(EDX); +// _freeX86reg(arg1regd); if (GPR_IS_CONST1(_Rs_)) { u32 srcadr = g_cpuConstRegs[_Rs_].UL[0] + _Imm_; // If _Rs_ is equal to _Rt_ we need to put the shift in to eax since it won't take the CONST path. - if (_Rs_ == _Rt_) - xMOV(temp1, srcadr); + if (_Rs_ == _Rt_) { +// xMOV(temp1, srcadr); + armAsm->Mov(temp1, srcadr); + } srcadr &= ~0x07; @@ -605,18 +791,24 @@ void recLDL() else { // Load ECX with the source memory address that we're reading from. - _freeX86reg(arg1regd); - _eeMoveGPRtoR(arg1regd, _Rs_); - if (_Imm_ != 0) - xADD(arg1regd, _Imm_); +// _freeX86reg(arg1regd); + _freeX86reg(ECX); +// _eeMoveGPRtoR(arg1regd, _Rs_); + _eeMoveGPRtoR(a64::WRegister(ECX), _Rs_); + if (_Imm_ != 0) { +// xADD(arg1regd, _Imm_); + armAsm->Add(ECX, ECX, _Imm_); + } - xMOV(temp1, arg1regd); - xAND(arg1regd, ~0x07); +// xMOV(temp1, arg1regd); + armAsm->Mov(temp1, ECX); +// xAND(arg1regd, ~0x07); + armAsm->And(ECX, ECX, ~0x07); - vtlb_DynGenReadNonQuad(64, false, false, arg1regd.GetId(), RETURN_READ_IN_RAX); + vtlb_DynGenReadNonQuad(64, false, false, ECX.GetCode(), RETURN_READ_IN_RAX); } - const xRegister64 treg(_allocX86reg(X86TYPE_GPR, _Rt_, MODE_READ | MODE_WRITE)); + const a64::XRegister treg(_allocX86reg(X86TYPE_GPR, _Rt_, MODE_READ | MODE_WRITE)); if (GPR_IS_CONST1(_Rs_)) { @@ -624,27 +816,40 @@ void recLDL() shift = ((shift & 0x7) + 1) * 8; if (shift != 64) { - ldlrhelper_const(shift, xSHR, 64 - shift, xSHL, rax, treg); +// ldlrhelper_const(shift, xSHR, 64 - shift, xSHL, rax, treg); + ldlrhelper_const(shift, SHIFTV::xSHR, 64 - shift, SHIFTV::xSHL, a64::XRegister(RAX), treg); } else { - xMOV(treg, rax); +// xMOV(treg, rax); + armAsm->Mov(treg, RAX); } } else { - xAND(temp1, 0x7); - xCMP(temp1, 7); - xCMOVE(treg, rax); // swap register with memory when not shifting - xForwardJE8 skip; +// xAND(temp1, 0x7); + armAsm->And(temp1, temp1, 0x7); +// xCMP(temp1, 7); + armAsm->Cmp(temp1, 7); +// xCMOVE(treg, rax); // swap register with memory when not shifting + armAsm->Csel(treg, RAX, treg, a64::Condition::eq); +// xForwardJE8 skip; + a64::Label skip; + armAsm->B(&skip, a64::Condition::eq); // Calculate the shift from top bit to lowest. - xADD(temp1, 1); - xMOV(edx, 64); - xSHL(temp1, 3); - xSUB(edx, temp1); +// xADD(temp1, 1); + armAsm->Add(temp1, temp1, 1); +// xMOV(edx, 64); + armAsm->Mov(EDX, 64); +// xSHL(temp1, 3); + armAsm->Lsl(temp1, temp1, 3); +// xSUB(edx, temp1); + armAsm->Sub(EDX, EDX, temp1); - ldlrhelper(temp1, xSHR, edx, xSHL, rax, treg); - skip.SetTarget(); +// ldlrhelper(temp1, xSHR, edx, xSHL, rax, treg); + ldlrhelper(temp1, SHIFTV::xSHR, a64::WRegister(EDX), SHIFTV::xSHL, a64::XRegister(RAX), treg); +// skip.SetTarget(); + armBind(&skip); } _freeX86reg(temp1); @@ -671,19 +876,21 @@ void recLDR() if (_Rs_) _addNeededX86reg(X86TYPE_GPR, _Rs_); - const xRegister32 temp1(_allocX86reg(X86TYPE_TEMP, 0, MODE_CALLEESAVED)); - _freeX86reg(eax); - _freeX86reg(ecx); - _freeX86reg(edx); - _freeX86reg(arg1regd); + const a64::WRegister temp1(_allocX86reg(X86TYPE_TEMP, 0, MODE_CALLEESAVED)); + _freeX86reg(EAX); + _freeX86reg(ECX); + _freeX86reg(EDX); +// _freeX86reg(arg1regd); if (GPR_IS_CONST1(_Rs_)) { u32 srcadr = g_cpuConstRegs[_Rs_].UL[0] + _Imm_; // If _Rs_ is equal to _Rt_ we need to put the shift in to eax since it won't take the CONST path. - if (_Rs_ == _Rt_) - xMOV(temp1, srcadr); + if (_Rs_ == _Rt_) { +// xMOV(temp1, srcadr); + armAsm->Mov(temp1, srcadr); + } srcadr &= ~0x07; @@ -692,18 +899,24 @@ void recLDR() else { // Load ECX with the source memory address that we're reading from. - _freeX86reg(arg1regd); - _eeMoveGPRtoR(arg1regd, _Rs_); - if (_Imm_ != 0) - xADD(arg1regd, _Imm_); +// _freeX86reg(arg1regd); + _freeX86reg(ECX); +// _eeMoveGPRtoR(arg1regd, _Rs_); + _eeMoveGPRtoR(a64::WRegister(ECX), _Rs_); + if (_Imm_ != 0) { +// xADD(arg1regd, _Imm_); + armAsm->Add(ECX, ECX, _Imm_); + } - xMOV(temp1, arg1regd); - xAND(arg1regd, ~0x07); +// xMOV(temp1, arg1regd); + armAsm->Mov(temp1, ECX); +// xAND(arg1regd, ~0x07); + armAsm->And(ECX, ECX, ~0x07); - vtlb_DynGenReadNonQuad(64, false, false, arg1regd.GetId(), RETURN_READ_IN_RAX); + vtlb_DynGenReadNonQuad(64, false, false, ECX.GetCode(), RETURN_READ_IN_RAX); } - const xRegister64 treg(_allocX86reg(X86TYPE_GPR, _Rt_, MODE_READ | MODE_WRITE)); + const a64::XRegister treg(_allocX86reg(X86TYPE_GPR, _Rt_, MODE_READ | MODE_WRITE)); if (GPR_IS_CONST1(_Rs_)) { @@ -711,25 +924,36 @@ void recLDR() shift = (shift & 0x7) * 8; if (shift != 0) { - ldlrhelper_const(64 - shift, xSHL, shift, xSHR, rax, treg); +// ldlrhelper_const(64 - shift, xSHL, shift, xSHR, rax, treg); + ldlrhelper_const(64 - shift, SHIFTV::xSHL, shift, SHIFTV::xSHR, a64::XRegister(RAX), treg); } else { - xMOV(treg, rax); +// xMOV(treg, rax); + armAsm->Mov(treg, RAX); } } else { - xAND(temp1, 0x7); - xCMOVE(treg, rax); // swap register with memory when not shifting - xForwardJE8 skip; +// xAND(temp1, 0x7); + armAsm->Ands(temp1, temp1, 0x7); +// xCMOVE(treg, rax); // swap register with memory when not shifting + armAsm->Csel(treg, RAX, treg, a64::Condition::eq); +// xForwardJE8 skip; + a64::Label skip; + armAsm->B(&skip, a64::Condition::eq); // Calculate the shift from top bit to lowest. - xMOV(edx, 64); - xSHL(temp1, 3); - xSUB(edx, temp1); +// xMOV(edx, 64); + armAsm->Mov(EDX, 64); +// xSHL(temp1, 3); + armAsm->Lsl(temp1, temp1, 3); +// xSUB(edx, temp1); + armAsm->Sub(EDX, EDX, temp1); - ldlrhelper(edx, xSHL, temp1, xSHR, rax, treg); - skip.SetTarget(); +// ldlrhelper(edx, xSHL, temp1, xSHR, rax, treg); + ldlrhelper(a64::WRegister(EDX), SHIFTV::xSHL, temp1, SHIFTV::xSHR, a64::XRegister(RAX), treg); +// skip.SetTarget(); + armBind(&skip); } _freeX86reg(temp1); @@ -746,33 +970,98 @@ void recLDR() //////////////////////////////////////////////////// /// Masks value with (0xffffffffffffffff maskshift maskamt), merges with (rt shift amt), saves to dummyValue -static void sdlrhelper_const(int maskamt, const xImpl_Group2& maskshift, int amt, const xImpl_Group2& shift, const xRegister64& value, const xRegister64& rt) +//static void sdlrhelper_const(int maskamt, const xImpl_Group2& maskshift, int amt, const xImpl_Group2& shift, const xRegister64& value, const xRegister64& rt) +static void sdlrhelper_const(int maskamt, const SHIFTV maskshift, int amt, const SHIFTV shift, const a64::XRegister& value, const a64::XRegister& rt) { - pxAssert(rt.GetId() != ecx.GetId() && value.GetId() != ecx.GetId()); - xMOV(rcx, -1); - maskshift(rcx, maskamt); - xAND(rcx, value); + pxAssert(rt.GetCode() != ECX.GetCode() && value.GetCode() != ECX.GetCode()); +// xMOV(rcx, -1); + armAsm->Mov(RCX, -1); - shift(rt, amt); - xOR(rt, rcx); +// maskshift(rcx, maskamt); + switch (maskshift) + { + case SHIFTV::xSHR: + armAsm->Lsr(RCX, RCX, maskamt); + break; + case SHIFTV::xSAR: + armAsm->Asr(RCX, RCX, maskamt); + break; + case SHIFTV::xSHL: + armAsm->Lsl(RCX, RCX, maskamt); + break; + } + +// xAND(rcx, value); + armAsm->And(RCX, RCX, value); + +// shift(rt, amt); + switch (shift) + { + case SHIFTV::xSHR: + armAsm->Lsr(rt, rt, amt); + break; + case SHIFTV::xSAR: + armAsm->Asr(rt, rt, amt); + break; + case SHIFTV::xSHL: + armAsm->Lsl(rt, rt, amt); + break; + } + +// xOR(rt, rcx); + armAsm->Orr(rt, rt, RCX); } /// Masks value with (0xffffffffffffffff maskshift maskamt), merges with (rt shift amt), saves to dummyValue -static void sdlrhelper(const xRegister32& maskamt, const xImpl_Group2& maskshift, const xRegister32& amt, const xImpl_Group2& shift, const xRegister64& value, const xRegister64& rt) +//static void sdlrhelper(const xRegister32& maskamt, const xImpl_Group2& maskshift, const xRegister32& amt, const xImpl_Group2& shift, const xRegister64& value, const xRegister64& rt) +static void sdlrhelper(const a64::WRegister& maskamt, const SHIFTV maskshift, const a64::WRegister& amt, const SHIFTV shift, const a64::XRegister& value, const a64::XRegister& rt) { - pxAssert(rt.GetId() != ecx.GetId() && amt.GetId() != ecx.GetId() && value.GetId() != ecx.GetId()); + pxAssert(rt.GetCode() != ECX.GetCode() && amt.GetCode() != ECX.GetCode() && value.GetCode() != ECX.GetCode()); // Generate mask 128-(shiftx8) - const xRegister64 maskamt64(maskamt); - xMOV(ecx, maskamt); - xMOV(maskamt64, -1); - maskshift(maskamt64, cl); - xAND(maskamt64, value); + const a64::XRegister maskamt64(maskamt.GetCode()); +// xMOV(ecx, maskamt); + armAsm->Mov(ECX, maskamt); +// xMOV(maskamt64, -1); + armAsm->Mov(maskamt64, -1); + +// maskshift(maskamt64, cl); + switch (maskshift) + { + case SHIFTV::xSHR: + armAsm->Lsr(maskamt64, maskamt64, RCX); + break; + case SHIFTV::xSAR: + armAsm->Asr(maskamt64, maskamt64, RCX); + break; + case SHIFTV::xSHL: + armAsm->Lsl(maskamt64, maskamt64, RCX); + break; + } + +// xAND(maskamt64, value); + armAsm->And(maskamt64, maskamt64, value); // Shift over reg value - xMOV(ecx, amt); - shift(rt, cl); - xOR(rt, maskamt64); +// xMOV(ecx, amt); + armAsm->Mov(ECX, amt); + +// shift(rt, cl); + switch (shift) + { + case SHIFTV::xSHR: + armAsm->Lsr(rt, rt, RCX); + break; + case SHIFTV::xSAR: + armAsm->Asr(rt, rt, RCX); + break; + case SHIFTV::xSHL: + armAsm->Lsl(rt, rt, RCX); + break; + } + +// xOR(rt, maskamt64); + armAsm->Orr(rt, rt, maskamt64); } void recSDL() @@ -782,8 +1071,9 @@ void recSDL() if (_Rt_) _addNeededX86reg(X86TYPE_GPR, _Rt_); - _freeX86reg(ecx); - _freeX86reg(arg2regd); + _freeX86reg(ECX); + _freeX86reg(EDX); +// _freeX86reg(arg2regd); if (GPR_IS_CONST1(_Rs_)) { @@ -792,15 +1082,17 @@ void recSDL() u32 shift = ((adr & 0x7) + 1) * 8; if (shift == 64) { - _eeMoveGPRtoR(arg2reg, _Rt_); +// _eeMoveGPRtoR(arg2reg, _Rt_); + _eeMoveGPRtoR(a64::XRegister(RDX), _Rt_); } else { vtlb_DynGenReadNonQuad_Const(64, false, false, aligned, RETURN_READ_IN_RAX); _eeMoveGPRtoR(arg2reg, _Rt_); - sdlrhelper_const(shift, xSHL, 64 - shift, xSHR, rax, arg2reg); +// sdlrhelper_const(shift, xSHL, 64 - shift, xSHR, rax, arg2reg); + sdlrhelper_const(shift, SHIFTV::xSHL, 64 - shift, SHIFTV::xSHR, a64::XRegister(RAX), a64::XRegister(RDX)); } - vtlb_DynGenWrite_Const(64, false, aligned, arg2regd.GetId()); + vtlb_DynGenWrite_Const(64, false, aligned, EDX.GetCode()); } else { @@ -808,49 +1100,73 @@ void recSDL() _addNeededX86reg(X86TYPE_GPR, _Rs_); // Load ECX with the source memory address that we're reading from. - _freeX86reg(arg1regd); - _eeMoveGPRtoR(arg1regd, _Rs_); - if (_Imm_ != 0) - xADD(arg1regd, _Imm_); +// _freeX86reg(arg1regd); + _freeX86reg(ECX); +// _eeMoveGPRtoR(arg1regd, _Rs_); + _eeMoveGPRtoR(a64::WRegister(ECX), _Rs_); + if (_Imm_ != 0) { +// xADD(arg1regd, _Imm_); + armAsm->Add(ECX, ECX, _Imm_); + } - _freeX86reg(ecx); - _freeX86reg(edx); - _freeX86reg(arg2regd); - const xRegister32 temp1(_allocX86reg(X86TYPE_TEMP, 0, MODE_CALLEESAVED)); - const xRegister64 temp2(_allocX86reg(X86TYPE_TEMP, 0, MODE_CALLEESAVED)); - _eeMoveGPRtoR(arg2reg, _Rt_); + _freeX86reg(ECX); + _freeX86reg(EDX); +// _freeX86reg(arg2regd); - xMOV(temp1, arg1regd); - xMOV(temp2, arg2reg); - xAND(arg1regd, ~0x07); - xAND(temp1, 0x7); - xCMP(temp1, 7); + const a64::WRegister temp1(_allocX86reg(X86TYPE_TEMP, 0, MODE_CALLEESAVED)); + const a64::XRegister temp2(_allocX86reg(X86TYPE_TEMP, 0, MODE_CALLEESAVED)); +// _eeMoveGPRtoR(arg2reg, _Rt_); + _eeMoveGPRtoR(a64::XRegister(RDX), _Rt_); + +// xMOV(temp1, arg1regd); + armAsm->Mov(temp1, ECX); +// xMOV(temp2, arg2reg); + armAsm->Mov(temp2, RDX); +// xAND(arg1regd, ~0x07); + armAsm->And(ECX, ECX, ~0x07); +// xAND(temp1, 0x7); + armAsm->And(temp1, temp1, 0x7); +// xCMP(temp1, 7); + armAsm->Cmp(temp1, 7); // If we're not using fastmem, we need to flush early. Because the first read // (which would flush) happens inside a branch. if (!CHECK_FASTMEM || vtlb_IsFaultingPC(pc)) iFlushCall(FLUSH_FULLVTLB); - xForwardJE8 skip; - xADD(temp1, 1); - vtlb_DynGenReadNonQuad(64, false, false, arg1regd.GetId(), RETURN_READ_IN_RAX); +// xForwardJE8 skip; + a64::Label skip; + armAsm->B(&skip, a64::Condition::eq); +// xADD(temp1, 1); + armAsm->Add(temp1, temp1, 1); + vtlb_DynGenReadNonQuad(64, false, false, ECX.GetCode(), RETURN_READ_IN_RAX); //Calculate the shift from top bit to lowest - xMOV(edx, 64); - xSHL(temp1, 3); - xSUB(edx, temp1); +// xMOV(edx, 64); + armAsm->Mov(EDX, 64); +// xSHL(temp1, 3); + armAsm->Lsl(temp1, temp1, 3); +// xSUB(edx, temp1); + armAsm->Sub(EDX, EDX, temp1); - sdlrhelper(temp1, xSHL, edx, xSHR, rax, temp2); +// sdlrhelper(temp1, xSHL, edx, xSHR, rax, temp2); + sdlrhelper(temp1, SHIFTV::xSHL, a64::WRegister(EDX), SHIFTV::xSHR, a64::XRegister(RAX), temp2); - _eeMoveGPRtoR(arg1regd, _Rs_, false); - if (_Imm_ != 0) - xADD(arg1regd, _Imm_); - xAND(arg1regd, ~0x7); - skip.SetTarget(); +// _eeMoveGPRtoR(arg1regd, _Rs_, false); + _eeMoveGPRtoR(a64::WRegister(ECX), _Rs_, false); + if (_Imm_ != 0) { +// xADD(arg1regd, _Imm_); + armAsm->Add(ECX, ECX, _Imm_); + } +// xAND(arg1regd, ~0x7); + armAsm->And(ECX, ECX, ~0x7); +// skip.SetTarget(); + armBind(&skip); - vtlb_DynGenWrite(64, false, arg1regd.GetId(), temp2.GetId()); - _freeX86reg(temp2.GetId()); - _freeX86reg(temp1.GetId()); +// vtlb_DynGenWrite(64, false, arg1regd.GetId(), temp2.GetId()); + vtlb_DynGenWrite(64, false, ECX.GetCode(), temp2.GetCode()); + _freeX86reg(temp2.GetCode()); + _freeX86reg(temp1.GetCode()); } #else iFlushCall(FLUSH_INTERPRETER); @@ -869,8 +1185,9 @@ void recSDR() if (_Rt_) _addNeededX86reg(X86TYPE_GPR, _Rt_); - _freeX86reg(ecx); - _freeX86reg(arg2regd); + _freeX86reg(ECX); + _freeX86reg(EDX); +// _freeX86reg(arg2regd); if (GPR_IS_CONST1(_Rs_)) { @@ -879,16 +1196,19 @@ void recSDR() u32 shift = (adr & 0x7) * 8; if (shift == 0) { - _eeMoveGPRtoR(arg2reg, _Rt_); +// _eeMoveGPRtoR(arg2reg, _Rt_); + _eeMoveGPRtoR(a64::XRegister(RDX), _Rt_); } else { vtlb_DynGenReadNonQuad_Const(64, false, false, aligned, RETURN_READ_IN_RAX); - _eeMoveGPRtoR(arg2reg, _Rt_); - sdlrhelper_const(64 - shift, xSHR, shift, xSHL, rax, arg2reg); +// _eeMoveGPRtoR(arg2reg, _Rt_); + _eeMoveGPRtoR(a64::XRegister(RDX), _Rt_); +// sdlrhelper_const(64 - shift, xSHR, shift, xSHL, rax, arg2reg); + sdlrhelper_const(64 - shift, SHIFTV::xSHR, shift, SHIFTV::xSHL, a64::XRegister(RAX), a64::XRegister(RDX)); } - vtlb_DynGenWrite_Const(64, false, aligned, arg2reg.GetId()); + vtlb_DynGenWrite_Const(64, false, aligned, RDX.GetCode()); } else { @@ -896,46 +1216,68 @@ void recSDR() _addNeededX86reg(X86TYPE_GPR, _Rs_); // Load ECX with the source memory address that we're reading from. - _eeMoveGPRtoR(arg1regd, _Rs_); - if (_Imm_ != 0) - xADD(arg1regd, _Imm_); +// _eeMoveGPRtoR(arg1regd, _Rs_); + _eeMoveGPRtoR(a64::WRegister(ECX), _Rs_); + if (_Imm_ != 0) { +// xADD(arg1regd, _Imm_); + armAsm->Add(ECX, ECX, _Imm_); + } - _freeX86reg(ecx); - _freeX86reg(edx); - _freeX86reg(arg2regd); - const xRegister32 temp1(_allocX86reg(X86TYPE_TEMP, 0, MODE_CALLEESAVED)); - const xRegister64 temp2(_allocX86reg(X86TYPE_TEMP, 0, MODE_CALLEESAVED)); - _eeMoveGPRtoR(arg2reg, _Rt_); + _freeX86reg(ECX); + _freeX86reg(EDX); +// _freeX86reg(arg2regd); - xMOV(temp1, arg1regd); - xMOV(temp2, arg2reg); - xAND(arg1regd, ~0x07); - xAND(temp1, 0x7); + const a64::WRegister temp1(_allocX86reg(X86TYPE_TEMP, 0, MODE_CALLEESAVED)); + const a64::XRegister temp2(_allocX86reg(X86TYPE_TEMP, 0, MODE_CALLEESAVED)); +// _eeMoveGPRtoR(arg2reg, _Rt_); + _eeMoveGPRtoR(a64::XRegister(RDX), _Rt_); + +// xMOV(temp1, arg1regd); + armAsm->Mov(temp1, ECX); +// xMOV(temp2, arg2reg); + armAsm->Mov(temp2, RDX); +// xAND(arg1regd, ~0x07); + armAsm->And(ECX, ECX, ~0x07); +// xAND(temp1, 0x7); + armAsm->Ands(temp1, temp1, 0x7); // If we're not using fastmem, we need to flush early. Because the first read // (which would flush) happens inside a branch. if (!CHECK_FASTMEM || vtlb_IsFaultingPC(pc)) iFlushCall(FLUSH_FULLVTLB); - xForwardJE8 skip; - vtlb_DynGenReadNonQuad(64, false, false, arg1regd.GetId(), RETURN_READ_IN_RAX); +// xForwardJE8 skip; + a64::Label skip; + armAsm->B(&skip, a64::Condition::eq); + vtlb_DynGenReadNonQuad(64, false, false, ECX.GetCode(), RETURN_READ_IN_RAX); - xMOV(edx, 64); - xSHL(temp1, 3); - xSUB(edx, temp1); +// xMOV(edx, 64); + armAsm->Mov(EDX, 64); +// xSHL(temp1, 3); + armAsm->Lsl(temp1, temp1, 3); +// xSUB(edx, temp1); + armAsm->Sub(EDX, EDX, temp1); - sdlrhelper(edx, xSHR, temp1, xSHL, rax, temp2); +// sdlrhelper(edx, xSHR, temp1, xSHL, rax, temp2); + sdlrhelper(a64::WRegister(EDX), SHIFTV::xSHR, temp1, SHIFTV::xSHL, a64::XRegister(RAX), temp2); - _eeMoveGPRtoR(arg1regd, _Rs_, false); - if (_Imm_ != 0) - xADD(arg1regd, _Imm_); - xAND(arg1regd, ~0x7); - xMOV(arg2reg, temp2); - skip.SetTarget(); +// _eeMoveGPRtoR(arg1regd, _Rs_, false); + _eeMoveGPRtoR(a64::WRegister(ECX), _Rs_, false); + if (_Imm_ != 0) { +// xADD(arg1regd, _Imm_); + armAsm->Add(ECX, ECX, _Imm_); + } +// xAND(arg1regd, ~0x7); + armAsm->And(ECX, ECX, ~0x7); +// xMOV(arg2reg, temp2); + armAsm->Mov(RDX, temp2); +// skip.SetTarget(); + armBind(&skip); - vtlb_DynGenWrite(64, false, arg1regd.GetId(), temp2.GetId()); - _freeX86reg(temp2.GetId()); - _freeX86reg(temp1.GetId()); +// vtlb_DynGenWrite(64, false, arg1regd.GetId(), temp2.GetId()); + vtlb_DynGenWrite(64, false, ECX.GetCode(), temp2.GetCode()); + _freeX86reg(temp2.GetCode()); + _freeX86reg(temp1.GetCode()); } #else iFlushCall(FLUSH_INTERPRETER); @@ -968,12 +1310,16 @@ void recLWC1() } else { - _freeX86reg(arg1regd); - _eeMoveGPRtoR(arg1regd, _Rs_); - if (_Imm_ != 0) - xADD(arg1regd, _Imm_); +// _freeX86reg(arg1regd); + _freeX86reg(ECX); +// _eeMoveGPRtoR(arg1regd, _Rs_); + _eeMoveGPRtoR(a64::WRegister(ECX), _Rs_); + if (_Imm_ != 0) { +// xADD(arg1regd, _Imm_); + armAsm->Add(ECX, ECX, _Imm_); + } - vtlb_DynGenReadNonQuad(32, false, true, arg1regd.GetId(), alloc_cb); + vtlb_DynGenReadNonQuad(32, false, true, ECX.GetCode(), alloc_cb); } EE::Profiler.EmitOp(eeOpcode::LWC1); @@ -995,12 +1341,16 @@ void recSWC1() } else { - _freeX86reg(arg1regd); - _eeMoveGPRtoR(arg1regd, _Rs_); - if (_Imm_ != 0) - xADD(arg1regd, _Imm_); +// _freeX86reg(arg1regd); + _freeX86reg(ECX); +// _eeMoveGPRtoR(arg1regd, _Rs_); + _eeMoveGPRtoR(a64::WRegister(ECX), _Rs_); + if (_Imm_ != 0) { +// xADD(arg1regd, _Imm_); + armAsm->Add(ECX, ECX, _Imm_); + } - vtlb_DynGenWrite(32, true, arg1regd.GetId(), regt); + vtlb_DynGenWrite(32, true, ECX.GetCode(), regt); } EE::Profiler.EmitOp(eeOpcode::SWC1); diff --git a/app/src/main/cpp/pcsx2/x86/ix86-32/recVTLB.cpp b/app/src/main/cpp/pcsx2/x86/ix86-32/recVTLB.cpp index 101b3d8..e2395f6 100644 --- a/app/src/main/cpp/pcsx2/x86/ix86-32/recVTLB.cpp +++ b/app/src/main/cpp/pcsx2/x86/ix86-32/recVTLB.cpp @@ -261,7 +261,6 @@ namespace vtlb_private static constexpr u32 INDIRECT_DISPATCHER_SIZE = 96; static constexpr u32 INDIRECT_DISPATCHERS_SIZE = 2 * 5 * 2 * INDIRECT_DISPATCHER_SIZE; -//static u8* m_IndirectDispatchers = nullptr; alignas(__pagesize) static u8 m_IndirectDispatchers[__pagesize]; // ------------------------------------------------------------------------ @@ -302,14 +301,14 @@ static void DynGen_HandlerTest(const GenDirectFn& gen_direct, int mode, int bits a64::Label done; armAsm->B(&done); // to_handler.SetTarget(); - armAsm->Bind(&to_handler); + armBind(&to_handler); + // xFastCall(GetIndirectDispatcherPtr(mode, szidx, sign)); - armAsm->Mov(RXVIXLSCRATCH, reinterpret_cast(GetIndirectDispatcherPtr(mode, szidx, sign))); + armAsm->Mov(RXVIXLSCRATCH, reinterpret_cast(GetIndirectDispatcherPtr(mode, szidx, sign))); armAsm->Blr(RXVIXLSCRATCH); + // done.SetTarget(); - if(done.IsLinked()) { - armAsm->Bind(&done); - } + armBind(&done); } // ------------------------------------------------------------------------ @@ -323,7 +322,7 @@ static void DynGen_IndirectTlbDispatcher(int mode, int bits, bool sign) xSUB(rsp, 32 + 8); #else // xSUB(rsp, 8); - armAsm->Sub(a64::sp, a64::sp, 48); +// armAsm->Sub(a64::sp, a64::sp, 48); #endif // xMOVZX(eax, al); @@ -335,34 +334,20 @@ static void DynGen_IndirectTlbDispatcher(int mode, int bits, bool sign) // xSUB(arg1regd, eax); armAsm->Sub(ECX, ECX, EEX); + // jump to the indirect handler, which is a C++ function. + // [ecx is address, edx is data] +// sptr table = (sptr)vtlbdata.RWFT[bits][mode]; +// xFastCall(ptrNative[(rax * wordsize) + table], arg1reg, arg2reg); + + armAsm->Mov(RXVIXLSCRATCH, reinterpret_cast(vtlbdata.RWFT[bits][mode])); + armAsm->Ldr(REX, a64::MemOperand(RXVIXLSCRATCH, REX, a64::LSL, 3)); + armAsm->Mov(RAX, RCX); armAsm->Mov(RCX, RDX); - // jump to the indirect handler, which is a C++ function. - // [ecx is address, edx is data] - sptr table = (sptr)vtlbdata.RWFT[bits][mode]; - if (table == (s32)table) - { -// xFastCall(ptrNative[(rax * wordsize) + table], arg1reg, arg2reg); - armAsm->Mov(RXVIXLSCRATCH, reinterpret_cast(table)); - armAsm->Ldr(REX, a64::MemOperand(RXVIXLSCRATCH, REX, a64::LSL, 3)); - } - else - { -// xLEA(arg3reg, ptr[(void*)table]); - armAsm->Mov(RXVIXLSCRATCH, reinterpret_cast(table)); -// xFastCall(ptrNative[(rax * wordsize) + arg3reg], arg1reg, arg2reg); - armAsm->Ldr(REX, a64::MemOperand(RXVIXLSCRATCH, REX, a64::LSL, 3)); - } - - const a64::Register old_stack_pointer = armAsm->StackPointer(); - armAsm->SetStackPointer(a64::sp); - armAsm->Stp(a64::lr, a64::x3, a64::MemOperand(a64::sp, 16)); - + armAsm->Push(a64::xzr, a64::lr); armAsm->Blr(REX); - - armAsm->Ldp(a64::lr, a64::x3, a64::MemOperand(a64::sp, 16)); - armAsm->SetStackPointer(old_stack_pointer); + armAsm->Pop(a64::lr, a64::xzr); if (!mode) { @@ -401,41 +386,13 @@ static void DynGen_IndirectTlbDispatcher(int mode, int bits, bool sign) xADD(rsp, 32 + 8); #else // xADD(rsp, 8); - armAsm->Add(a64::sp, a64::sp, 48); +// armAsm->Add(a64::sp, a64::sp, 48); #endif // xRET(); armAsm->Ret(); } -// One-time initialization procedure. Multiple subsequent calls during the lifespan of the -// process will be ignored. -// -//void vtlb_DynGenDispatchers() -//{ -// m_IndirectDispatchers = xGetAlignedCallTarget(); -// -// // clear the buffer to 0xcc (easier debugging). -// std::memset(m_IndirectDispatchers, 0xcc, INDIRECT_DISPATCHERS_SIZE); -// -// for (int mode = 0; mode < 2; ++mode) -// { -// for (int bits = 0; bits < 5; ++bits) -// { -// for (int sign = 0; sign < (!mode && bits < 3 ? 2 : 1); sign++) -// { -// xSetPtr(GetIndirectDispatcherPtr(mode, bits, !!sign)); -// -// DynGen_IndirectTlbDispatcher(mode, bits, !!sign); -// } -// } -// } -// -// Perf::any.Register(m_IndirectDispatchers, INDIRECT_DISPATCHERS_SIZE, "TLB Dispatcher"); -// -// xSetPtr(m_IndirectDispatchers + INDIRECT_DISPATCHERS_SIZE); -//} - void vtlb_DynGenDispatchers() { static bool hasBeenCalled = false; @@ -452,7 +409,7 @@ void vtlb_DynGenDispatchers() { for (int bits = 0; bits < 5; ++bits) { - for (int sign = 0; sign < (!mode && bits < 3 ? 2 : 1); sign++) + for (int sign = 0; sign < (!mode && bits < 3 ? 2 : 1); ++sign) { armSetAsmPtr(GetIndirectDispatcherPtr(mode, bits, !!sign), INDIRECT_DISPATCHERS_SIZE, nullptr); armStartBlock(); @@ -476,10 +433,89 @@ void vtlb_DynGenDispatchers() // Returns read value in eax. int vtlb_DynGenReadNonQuad(u32 bits, bool sign, bool xmm, int addr_reg, vtlb_ReadRegAllocCallback dest_reg_alloc) { - pxAssume(bits <= 64); + pxAssume(bits <= 64); + int x86_dest_reg; + if (!CHECK_FASTMEM || vtlb_IsFaultingPC(pc)) + { + iFlushCall(FLUSH_FULLVTLB); - return 0; + DynGen_PrepRegs(addr_reg, -1, bits, xmm); + DynGen_HandlerTest([bits, sign]() { DynGen_DirectRead(bits, sign); }, 0, bits, sign && bits < 64); + + if (!xmm) + { +// x86_dest_reg = dest_reg_alloc ? dest_reg_alloc() : (_freeX86reg(eax), eax.GetId()); + x86_dest_reg = dest_reg_alloc ? dest_reg_alloc() : (_freeX86reg(EAX), EAX.GetCode()); +// xMOV(xRegister64(x86_dest_reg), rax); + armAsm->Mov(a64::XRegister(x86_dest_reg), RAX); + } + else + { + // we shouldn't be loading any FPRs which aren't 32bit.. + // we use MOVD here despite it being floating-point data, because we're going int->float reinterpret. + pxAssert(bits == 32); + x86_dest_reg = dest_reg_alloc ? dest_reg_alloc() : (_freeXMMreg(0), 0); +// xMOVDZX(xRegisterSSE(x86_dest_reg), eax); + armAsm->Fmov(a64::QRegister(x86_dest_reg).S(), EAX); + } + + return x86_dest_reg; + } + + const u8* codeStart; +// const xAddressReg x86addr(addr_reg); + a64::MemOperand baseAddr = a64::MemOperand(RFASTMEMBASE, a64::XRegister(addr_reg)); + + if (!xmm) + { +// x86_dest_reg = dest_reg_alloc ? dest_reg_alloc() : (_freeX86reg(eax), eax.GetId()); + x86_dest_reg = dest_reg_alloc ? dest_reg_alloc() : (_freeX86reg(EAX), EAX.GetCode()); +// codeStart = x86Ptr; + codeStart = armGetCurrentCodePointer(); +// const xRegister64 x86reg(x86_dest_reg); + + switch (bits) + { + case 8: +// sign ? xMOVSX(x86reg, ptr8[RFASTMEMBASE + x86addr]) : xMOVZX(xRegister32(x86reg), ptr8[RFASTMEMBASE + x86addr]); + sign ? armAsm->Ldrsb(a64::XRegister(x86_dest_reg), baseAddr) : armAsm->Ldrb(a64::WRegister(x86_dest_reg), baseAddr); + break; + case 16: +// sign ? xMOVSX(x86reg, ptr16[RFASTMEMBASE + x86addr]) : xMOVZX(xRegister32(x86reg), ptr16[RFASTMEMBASE + x86addr]); + sign ? armAsm->Ldrsh(a64::XRegister(x86_dest_reg), baseAddr) : armAsm->Ldrh(a64::WRegister(x86_dest_reg), baseAddr); + break; + case 32: +// sign ? xMOVSX(x86reg, ptr32[RFASTMEMBASE + x86addr]) : xMOV(xRegister32(x86reg), ptr32[RFASTMEMBASE + x86addr]); + sign ? armAsm->Ldrsw(a64::XRegister(x86_dest_reg), baseAddr) : armAsm->Ldr(a64::WRegister(x86_dest_reg), baseAddr); + break; + case 64: +// xMOV(x86reg, ptr64[RFASTMEMBASE + x86addr]); + armAsm->Ldr(a64::XRegister(x86_dest_reg), baseAddr); + break; + + jNO_DEFAULT + } + } + else + { + pxAssert(bits == 32); + x86_dest_reg = dest_reg_alloc ? dest_reg_alloc() : (_freeXMMreg(0), 0); +// codeStart = x86Ptr; + codeStart = armGetCurrentCodePointer(); +// const xRegisterSSE xmmreg(x86_dest_reg); + const a64::QRegister xmmreg(x86_dest_reg); +// xMOVSSZX(xmmreg, ptr32[RFASTMEMBASE + x86addr]); + armAsm->Ldr(xmmreg.S(), baseAddr); + } + +// vtlb_AddLoadStoreInfo((uptr)codeStart, static_cast(x86Ptr - codeStart), + vtlb_AddLoadStoreInfo((uptr)codeStart, static_cast(armGetCurrentCodePointer() - codeStart), + pc, GetAllocatedGPRBitmask(), GetAllocatedXMMBitmask(), + static_cast(addr_reg), static_cast(x86_dest_reg), + static_cast(bits), sign, true, xmm); + + return x86_dest_reg; } // ------------------------------------------------------------------------ @@ -492,10 +528,127 @@ int vtlb_DynGenReadNonQuad(u32 bits, bool sign, bool xmm, int addr_reg, vtlb_Rea // int vtlb_DynGenReadNonQuad_Const(u32 bits, bool sign, bool xmm, u32 addr_const, vtlb_ReadRegAllocCallback dest_reg_alloc) { - EE::Profiler.EmitConstMem(addr_const); + int x86_dest_reg; + auto vmv = vtlbdata.vmap[addr_const >> VTLB_PAGE_BITS]; + if (!vmv.isHandler(addr_const)) + { + auto ppf = vmv.assumePtr(addr_const); + if (!xmm) + { +// x86_dest_reg = dest_reg_alloc ? dest_reg_alloc() : (_freeX86reg(eax), eax.GetId()); + x86_dest_reg = dest_reg_alloc ? dest_reg_alloc() : (_freeX86reg(EAX), EAX.GetCode()); + switch (bits) + { + case 8: +// sign ? xMOVSX(xRegister64(x86_dest_reg), ptr8[(u8*)ppf]) : xMOVZX(xRegister32(x86_dest_reg), ptr8[(u8*)ppf]); + sign ? armAsm->Ldrsb(a64::XRegister(x86_dest_reg), armMemOperandPtr((u8*)ppf)) : armAsm->Ldrb(a64::WRegister(x86_dest_reg), armMemOperandPtr((u8*)ppf)); + break; + case 16: +// sign ? xMOVSX(xRegister64(x86_dest_reg), ptr16[(u16*)ppf]) : xMOVZX(xRegister32(x86_dest_reg), ptr16[(u16*)ppf]); + sign ? armAsm->Ldrsh(a64::XRegister(x86_dest_reg), armMemOperandPtr((u16*)ppf)) : armAsm->Ldrh(a64::WRegister(x86_dest_reg), armMemOperandPtr((u16*)ppf)); + break; - return 0; + case 32: +// sign ? xMOVSX(xRegister64(x86_dest_reg), ptr32[(u32*)ppf]) : xMOV(xRegister32(x86_dest_reg), ptr32[(u32*)ppf]); + sign ? armAsm->Ldrsw(a64::XRegister(x86_dest_reg), armMemOperandPtr((u32*)ppf)) : armAsm->Ldr(a64::WRegister(x86_dest_reg), armMemOperandPtr((u32*)ppf)); + break; + + case 64: +// xMOV(xRegister64(x86_dest_reg), ptr64[(u64*)ppf]); + armAsm->Ldr(a64::XRegister(x86_dest_reg), armMemOperandPtr((u64*)ppf)); + break; + } + } + else + { + x86_dest_reg = dest_reg_alloc ? dest_reg_alloc() : (_freeXMMreg(0), 0); +// xMOVSSZX(xRegisterSSE(x86_dest_reg), ptr32[(float*)ppf]); + armAsm->Ldr(a64::QRegister(x86_dest_reg).S(), armMemOperandPtr((float*)ppf)); + } + } + else + { + // has to: translate, find function, call function + u32 paddr = vmv.assumeHandlerGetPAddr(addr_const); + + int szidx = 0; + switch (bits) + { + case 8: szidx = 0; break; + case 16: szidx = 1; break; + case 32: szidx = 2; break; + case 64: szidx = 3; break; + } + + // Shortcut for the INTC_STAT register, which many games like to spin on heavily. + if ((bits == 32) && !EmuConfig.Speedhacks.IntcStat && (paddr == INTC_STAT)) + { +// x86_dest_reg = dest_reg_alloc ? dest_reg_alloc() : (_freeX86reg(eax), eax.GetId()); + x86_dest_reg = dest_reg_alloc ? dest_reg_alloc() : (_freeX86reg(EAX), EAX.GetCode()); + if (!xmm) + { + if (sign) { +// xMOVSX(xRegister64(x86_dest_reg), ptr32[&psHu32(INTC_STAT)]); + armAsm->Ldrsw(a64::XRegister(x86_dest_reg), armMemOperandPtr(&psHu32(INTC_STAT))); + } + else { +// xMOV(xRegister32(x86_dest_reg), ptr32[&psHu32(INTC_STAT)]); + armAsm->Ldr(a64::WRegister(x86_dest_reg), armMemOperandPtr(&psHu32(INTC_STAT))); + } + } + else + { +// xMOVDZX(xRegisterSSE(x86_dest_reg), ptr32[&psHu32(INTC_STAT)]); + armAsm->Ldr(a64::QRegister(x86_dest_reg).S(), armMemOperandPtr(&psHu32(INTC_STAT))); + } + } + else + { + iFlushCall(FLUSH_FULLVTLB); +// xFastCall(vmv.assumeHandlerGetRaw(szidx, false), paddr); + + armAsm->Mov(EAX, paddr); + armEmitCall(vmv.assumeHandlerGetRaw(szidx, false)); // read + + if (!xmm) + { +// x86_dest_reg = dest_reg_alloc ? dest_reg_alloc() : (_freeX86reg(eax), eax.GetId()); + x86_dest_reg = dest_reg_alloc ? dest_reg_alloc() : (_freeX86reg(EAX), EAX.GetCode()); + switch (bits) + { + // save REX prefix by using 32bit dest for zext + case 8: +// sign ? xMOVSX(xRegister64(x86_dest_reg), al) : xMOVZX(xRegister32(x86_dest_reg), al); + sign ? armAsm->Sxtb(a64::XRegister(x86_dest_reg), EAX) : armAsm->Uxtb(a64::WRegister(x86_dest_reg), EAX); + break; + + case 16: +// sign ? xMOVSX(xRegister64(x86_dest_reg), ax) : xMOVZX(xRegister32(x86_dest_reg), ax); + sign ? armAsm->Sxth(a64::XRegister(x86_dest_reg), EAX) : armAsm->Uxth(a64::WRegister(x86_dest_reg), EAX); + break; + + case 32: +// sign ? xMOVSX(xRegister64(x86_dest_reg), eax) : xMOV(xRegister32(x86_dest_reg), eax); + sign ? armAsm->Sxtw(a64::XRegister(x86_dest_reg), EAX) : armAsm->Mov(a64::WRegister(x86_dest_reg), EAX); + break; + + case 64: +// xMOV(xRegister64(x86_dest_reg), rax); + armAsm->Mov(a64::XRegister(x86_dest_reg) , RAX); + break; + } + } + else + { + x86_dest_reg = dest_reg_alloc ? dest_reg_alloc() : (_freeXMMreg(0), 0); +// xMOVDZX(xRegisterSSE(x86_dest_reg), eax); + armAsm->Fmov(a64::QRegister(x86_dest_reg).S(), EAX); + } + } + } + + return x86_dest_reg; } int vtlb_DynGenReadQuad(u32 bits, int addr_reg, vtlb_ReadRegAllocCallback dest_reg_alloc) @@ -523,7 +676,7 @@ int vtlb_DynGenReadQuad(u32 bits, int addr_reg, vtlb_ReadRegAllocCallback dest_r const u8* codeStart = armGetCurrentCodePointer(); // xMOVAPS(xRegisterSSE(reg), ptr128[RFASTMEMBASE + arg1reg]); -// armAsm->Ldr(a64::QRegister(reg).Q(), a64::MemOperand(RFASTMEMBASE, RCX)); + armAsm->Ldr(a64::QRegister(reg).Q(), a64::MemOperand(RFASTMEMBASE, RCX)); vtlb_AddLoadStoreInfo((uptr)codeStart, static_cast(armGetCurrentCodePointer() - codeStart), pc, GetAllocatedGPRBitmask(), GetAllocatedXMMBitmask(), @@ -561,6 +714,7 @@ int vtlb_DynGenReadQuad_Const(u32 bits, u32 addr_const, vtlb_ReadRegAllocCallbac const int szidx = 4; iFlushCall(FLUSH_FULLVTLB); + // xFastCall(vmv.assumeHandlerGetRaw(szidx, 0), paddr); armAsm->Mov(EAX, paddr); armEmitCall(vmv.assumeHandlerGetRaw(szidx, 0)); @@ -644,7 +798,49 @@ void vtlb_DynGenWrite(u32 sz, bool xmm, int addr_reg, int value_reg) const u8* codeStart = armGetCurrentCodePointer(); // const xAddressReg vaddr_reg(addr_reg); + a64::MemOperand mop = a64::MemOperand(RFASTMEMBASE, a64::XRegister(addr_reg)); + if (!xmm) + { + switch (sz) + { + case 8: +// xMOV(ptr8[RFASTMEMBASE + vaddr_reg], xRegister8(xRegister32(value_reg))); + armAsm->Strb(a64::WRegister(value_reg), mop); + break; + case 16: +// xMOV(ptr16[RFASTMEMBASE + vaddr_reg], xRegister16(value_reg)); + armAsm->Strh(a64::WRegister(value_reg), mop); + break; + case 32: +// xMOV(ptr32[RFASTMEMBASE + vaddr_reg], xRegister32(value_reg)); + armAsm->Str(a64::WRegister(value_reg), mop); + break; + case 64: +// xMOV(ptr64[RFASTMEMBASE + vaddr_reg], xRegister64(value_reg)); + armAsm->Str(a64::XRegister(value_reg), mop); + break; + + jNO_DEFAULT + } + } + else + { + pxAssert(sz == 32 || sz == 128); + switch (sz) + { + case 32: +// xMOVSS(ptr32[RFASTMEMBASE + vaddr_reg], xRegisterSSE(value_reg)); + armAsm->Str(a64::QRegister(value_reg).S(), mop); + break; + case 128: +// xMOVAPS(ptr128[RFASTMEMBASE + vaddr_reg], xRegisterSSE(value_reg)); + armAsm->Str(a64::QRegister(value_reg).Q(), mop); + break; + + jNO_DEFAULT + } + } vtlb_AddLoadStoreInfo((uptr)codeStart, static_cast(armGetCurrentCodePointer() - codeStart), pc, GetAllocatedGPRBitmask(), GetAllocatedXMMBitmask(), @@ -719,28 +915,29 @@ void vtlb_DynGenWrite_Const(u32 bits, bool xmm, u32 addr_const, int value_reg) if (!vmv.isHandler(addr_const)) { auto ppf = vmv.assumePtr(addr_const); + a64::MemOperand mop = armMemOperandPtr((void*)ppf); if (!xmm) { switch (bits) { case 8: // xMOV(ptr[(void*)ppf], xRegister8(xRegister32(value_reg))); - armAsm->Strb(a64::WRegister(value_reg), armMemOperandPtr((void*)ppf)); + armAsm->Strb(a64::WRegister(value_reg), mop); break; case 16: // xMOV(ptr[(void*)ppf], xRegister16(value_reg)); - armAsm->Strh(a64::WRegister(value_reg), armMemOperandPtr((void*)ppf)); + armAsm->Strh(a64::WRegister(value_reg), mop); break; case 32: // xMOV(ptr[(void*)ppf], xRegister32(value_reg)); - armAsm->Str(a64::WRegister(value_reg), armMemOperandPtr((void*)ppf)); + armAsm->Str(a64::WRegister(value_reg), mop); break; case 64: // xMOV(ptr64[(void*)ppf], xRegister64(value_reg)); - armAsm->Str(a64::XRegister(value_reg), armMemOperandPtr((void*)ppf)); + armAsm->Str(a64::XRegister(value_reg), mop); break; jNO_DEFAULT @@ -752,12 +949,12 @@ void vtlb_DynGenWrite_Const(u32 bits, bool xmm, u32 addr_const, int value_reg) { case 32: // xMOVSS(ptr[(void*)ppf], xRegisterSSE(value_reg)); - armAsm->Str(a64::QRegister(value_reg).S(), armMemOperandPtr((void*)ppf)); + armAsm->Str(a64::QRegister(value_reg).S(), mop); break; case 128: // xMOVAPS(ptr128[(void*)ppf], xRegisterSSE(value_reg)); - armAsm->Str(a64::QRegister(value_reg).Q(), armMemOperandPtr((void*)ppf)); + armAsm->Str(a64::QRegister(value_reg).Q(), mop); break; jNO_DEFAULT @@ -793,8 +990,10 @@ void vtlb_DynGenWrite_Const(u32 bits, bool xmm, u32 addr_const, int value_reg) // _freeX86reg(arg1regd); _freeX86reg(ECX.GetCode()); + // xMOV(arg1regd, paddr); armAsm->Mov(ECX, paddr); + if (bits == 128) { pxAssert(xmm); @@ -843,7 +1042,7 @@ void vtlb_DynV2P() // xSHR(eax, VTLB_PAGE_BITS); armAsm->Lsr(EAX, EAX, VTLB_PAGE_BITS); -// xMOV(eax, ptr[xComplexAddress(rdx, vtlbdata.ppmap, rax * 4)]); // vtlbdata.ppmap[vaddr >> VTLB_PAGE_BITS]; +// xMOV(eax, ptr[xComplexAddress(rdx, vtlbdata.ppmap, rax * 4)]); armMoveAddressToReg(RDX, vtlbdata.ppmap); armAsm->Ldr(EAX, a64::MemOperand(RDX, RAX, a64::LSL, 2)); @@ -875,14 +1074,8 @@ void vtlb_DynBackpatchLoadStore(uptr code_address, u32 code_size, u32 guest_pc, u32 num_gprs = 0; u32 num_fprs = 0; -// const u32 rbxid = static_cast(RBX.GetCode()); -// const u32 arg1id = static_cast(RCX.GetCode()); -// const u32 arg2id = static_cast(RDX.GetCode()); -// const u32 arg3id = static_cast(R8X.GetCode()); - for (u32 i = 0; i < iREGCNT_GPR; i++) { -// if ((gpr_bitmask & (1u << i)) && (i == rbxid || i == arg1id || i == arg2id || armIsCallerSaved(i)) && (!is_load || is_xmm || data_register != i)) if ((gpr_bitmask & (1u << i)) && armIsCallerSaved(i) && (!is_load || is_xmm || data_register != i)) num_gprs++; } @@ -893,11 +1086,6 @@ void vtlb_DynBackpatchLoadStore(uptr code_address, u32 code_size, u32 guest_pc, } const u32 stack_size = (((num_gprs + 1) & ~1u) * GPR_SIZE) + (num_fprs * XMM_SIZE) + SHADOW_SIZE; - -// const a64::Register old_stack_pointer = armAsm->StackPointer(); -// armAsm->SetStackPointer(a64::sp); -// armAsm->Str(a64::lr, a64::MemOperand(a64::sp, 8)); - if (stack_size > 0) { // xSUB(rsp, stack_size); @@ -916,7 +1104,6 @@ void vtlb_DynBackpatchLoadStore(uptr code_address, u32 code_size, u32 guest_pc, for (u32 i = 0; i < iREGCNT_GPR; i++) { -// if ((gpr_bitmask & (1u << i)) && (i == arg1id || i == arg2id || i == arg3id || armIsCallerSaved(i)) && (!is_load || is_xmm || data_register != i)) if ((gpr_bitmask & (1u << i)) && armIsCallerSaved(i) && (!is_load || is_xmm || data_register != i)) { // xMOV(ptr64[rsp + stack_offset], xRegister64(i)); @@ -1006,7 +1193,6 @@ void vtlb_DynBackpatchLoadStore(uptr code_address, u32 code_size, u32 guest_pc, for (u32 i = 0; i < iREGCNT_GPR; i++) { -// if ((gpr_bitmask & (1u << i)) && (i == arg1id || i == arg2id || i == arg3id || armIsCallerSaved(i)) && (!is_load || is_xmm || data_register != i)) if ((gpr_bitmask & (1u << i)) && armIsCallerSaved(i) && (!is_load || is_xmm || data_register != i)) { // xMOV(xRegister64(i), ptr64[rsp + stack_offset]); @@ -1019,9 +1205,6 @@ void vtlb_DynBackpatchLoadStore(uptr code_address, u32 code_size, u32 guest_pc, armAsm->Add(a64::sp, a64::sp, stack_size); } -// armAsm->Ldr(a64::lr, a64::MemOperand(a64::sp, 8)); -// armAsm->SetStackPointer(old_stack_pointer); - // xJMP((void*)(code_address + code_size)); armEmitJmp(reinterpret_cast(code_address + code_size), true); @@ -1030,17 +1213,5 @@ void vtlb_DynBackpatchLoadStore(uptr code_address, u32 code_size, u32 guest_pc, // backpatch to a jump to the slowmem handler // x86Ptr = (u8*)code_address; // xJMP(thunk); - armEmitJmpPtr((void*)code_address, thunk, true); - -// const s64 displacement = GetPCDisplacement((void*)code_address, thunk); -// a64::MacroAssembler masm((u8*)code_address, 4); -// a64::SingleEmissionCheckScope guard(&masm); -// masm.b(displacement); -// masm.FinalizeCode(); - -// // fill the rest of it with nops, if any -// pxAssertRel(static_cast((uptr)x86Ptr - code_address) <= code_size, "Overflowed when backpatching"); -// for (u32 i = static_cast((uptr)x86Ptr - code_address); i < code_size; i++) -// xNOP(); } diff --git a/app/src/main/cpp/pcsx2/x86/microVU_Macro.inl b/app/src/main/cpp/pcsx2/x86/microVU_Macro.inl index 7fa9681..f2aa59d 100644 --- a/app/src/main/cpp/pcsx2/x86/microVU_Macro.inl +++ b/app/src/main/cpp/pcsx2/x86/microVU_Macro.inl @@ -928,7 +928,7 @@ namespace Dynarec { namespace OpcodeImpl { void recCOP2() { recCOP2t[_Rs_](); } -#if defined(LOADSTORE_RECOMPILE2) && defined(CP2_RECOMPILE) +#if defined(LOADSTORE_RECOMPILE) && defined(CP2_RECOMPILE) /********************************************************* * Load and store for COP2 (VU0 unit) * @@ -958,11 +958,15 @@ void recLQC2() else { _eeMoveGPRtoR(arg1regd, _Rs_); - if (_Imm_ != 0) - xADD(arg1regd, _Imm_); - xAND(arg1regd, ~0xF); + if (_Imm_ != 0) { +// xADD(arg1regd, _Imm_); + armAsm->Add(ECX, ECX, _Imm_); + } +// xAND(arg1regd, ~0xF); + armAsm->And(ECX, ECX, ~0xF); - xmmreg = vtlb_DynGenReadQuad(128, arg1regd.GetId(), alloc_cb); +// xmmreg = vtlb_DynGenReadQuad(128, arg1regd.GetId(), alloc_cb); + xmmreg = vtlb_DynGenReadQuad(128, ECX.GetCode(), alloc_cb); } // toss away if loading to vf00 @@ -983,8 +987,10 @@ void recSQC2() // vf00 has to be special cased here, because of the microvu temps... const int ftreg = _Rt_ ? _allocVFtoXMMreg(_Rt_, MODE_READ) : _allocTempXMMreg(XMMT_FPS); - if (!_Rt_) - xMOVAPS(xRegisterSSE(ftreg), ptr128[&vu0Regs.VF[0].F]); + if (!_Rt_) { +// xMOVAPS(xRegisterSSE(ftreg), ptr128[&vu0Regs.VF[0].F]); + armAsm->Ldr(a64::QRegister(ftreg).Q(), armMemOperandPtr(&vu0Regs.VF[0].F)); + } if (GPR_IS_CONST1(_Rs_)) { @@ -994,11 +1000,15 @@ void recSQC2() else { _eeMoveGPRtoR(arg1regd, _Rs_); - if (_Imm_ != 0) - xADD(arg1regd, _Imm_); - xAND(arg1regd, ~0xF); + if (_Imm_ != 0) { +// xADD(arg1regd, _Imm_); + armAsm->Add(ECX, ECX, _Imm_); + } +// xAND(arg1regd, ~0xF); + armAsm->And(ECX, ECX, ~0xF); - vtlb_DynGenWrite(128, true, arg1regd.GetId(), ftreg); +// vtlb_DynGenWrite(128, true, arg1regd.GetId(), ftreg); + vtlb_DynGenWrite(128, true, ECX.GetCode(), ftreg); } if (!_Rt_) diff --git a/app/src/main/cpp/pcsx2/x86/microVU_Misc.inl b/app/src/main/cpp/pcsx2/x86/microVU_Misc.inl index 00d5ab4..f455934 100644 --- a/app/src/main/cpp/pcsx2/x86/microVU_Misc.inl +++ b/app/src/main/cpp/pcsx2/x86/microVU_Misc.inl @@ -293,7 +293,7 @@ __fi void mVUrestoreRegs(microVU& mVU, bool fromMemory = false, bool onlyNeeded if (fromMemory) { int i; - for (i = 0; i < static_cast(iREGCNT_XMM); ++i) + for (i = static_cast(iREGCNT_XMM - 1); i >= 0; --i) { if (!armIsCallerSavedXmm(i)) continue; @@ -303,7 +303,7 @@ __fi void mVUrestoreRegs(microVU& mVU, bool fromMemory = false, bool onlyNeeded } } - for (i = 0; i < static_cast(iREGCNT_GPR); ++i) + for (i = static_cast(iREGCNT_GPR - 1); i >= 0; --i) { if (!armIsCallerSaved(i) || i == 4) continue;