From f7ef58ff9a44dff06be78a5c2dd34586ffa71591 Mon Sep 17 00:00:00 2001 From: skidau Date: Thu, 29 Dec 2011 21:18:35 +1100 Subject: [PATCH 01/15] Removed the VID/PID validation for Wiimotes allowing Dolphin to detect third party wiimotes with a VID/PID that is different to Nintendo's. Checked for timeouts reported by the bluetooth stack. Added RVL-CNT-01-TR detection. --- Source/Core/Core/Src/HW/WiimoteReal/IOWin.cpp | 65 +++++-------------- .../Core/Src/HW/WiimoteReal/WiimoteReal.cpp | 17 ----- 2 files changed, 16 insertions(+), 66 deletions(-) diff --git a/Source/Core/Core/Src/HW/WiimoteReal/IOWin.cpp b/Source/Core/Core/Src/HW/WiimoteReal/IOWin.cpp index e7316a896d..c22e1972dc 100644 --- a/Source/Core/Core/Src/HW/WiimoteReal/IOWin.cpp +++ b/Source/Core/Core/Src/HW/WiimoteReal/IOWin.cpp @@ -124,11 +124,6 @@ inline void init_lib() } } -// VID = Nintendo, PID = Wiimote -static int VIDLength = 3; -static int VID[3] = {0x057E, 0x0001, 0x0002}; -static int PID[3] = {0x0306, 0x0002, 0x00F7}; - namespace WiimoteReal { @@ -210,39 +205,23 @@ int FindWiimotes(Wiimote** wm, int max_wiimotes) attr.Size = sizeof(attr); HidD_GetAttributes(dev, &attr); - bool foundWiimote = false; - for (int i = 0; i < VIDLength; i++) - { - if (attr.VendorID == VID[i] && attr.ProductID == PID[i]) - { - foundWiimote = true; - break; - } - } + // Find an unused slot + unsigned int k = 0; + for (; k < MAX_WIIMOTES && !(WIIMOTE_SRC_REAL & g_wiimote_sources[k] && !wm[k]); ++k); + wm[k] = new Wiimote(k); + wm[k]->dev_handle = dev; + memcpy(wm[k]->devicepath, detail_data->DevicePath, 197); - if (foundWiimote) + if (!wm[k]->Connect()) { - // This is a wiimote - // Find an unused slot - unsigned int k = 0; - for (; k < MAX_WIIMOTES && !(WIIMOTE_SRC_REAL & g_wiimote_sources[k] && !wm[k]); ++k); - wm[k] = new Wiimote(k); - wm[k]->dev_handle = dev; - memcpy(wm[k]->devicepath, detail_data->DevicePath, 197); - - if (!wm[k]->Connect()) - { - ERROR_LOG(WIIMOTE, "Unable to connect to wiimote %i.", wm[k]->index + 1); - delete wm[k]; - wm[k] = NULL; - } - else - ++found_wiimotes; + ERROR_LOG(WIIMOTE, "Unable to connect to wiimote %i.", wm[k]->index + 1); + delete wm[k]; + wm[k] = NULL; + CloseHandle(dev); } else { - // Not a wiimote - CloseHandle(dev); + ++found_wiimotes; } } @@ -399,28 +378,16 @@ int Wiimote::IOWrite(unsigned char* buf, int len) return i; } -#if 0 dw = GetLastError(); // Checking for 121 = timeout on semaphore/device off/disconnected to // avoid trouble with other stacks toshiba/widcomm - // 995 = The I/O operation has been aborted because of a thread exit or - // an application request. - - if ( (dw == 121) || (dw == 995) ) + if (dw == 121) { - NOTICE_LOG(WIIMOTE, "IOWrite[MSBT_STACK_UNKNOWN]"); + NOTICE_LOG(WIIMOTE, "IOWrite[MSBT_STACK_UNKNOWN]: Timeout"); RealDisconnect(); } else ERROR_LOG(WIIMOTE, "IOWrite[MSBT_STACK_UNKNOWN]: ERROR: %08x", dw); -#endif - - - // If the part below causes trouble on WIDCOMM/TOSHIBA stack uncomment - // the lines above, and comment out the 3 lines below instead. - - NOTICE_LOG(WIIMOTE, "IOWrite[MSBT_STACK_UNKNOWN]"); - RealDisconnect(); return 0; } @@ -456,8 +423,8 @@ int PairUp(bool unpair) { init_lib(); - // match strings like "Nintendo RVL-WBC-01", "Nintendo RVL-CNT-01" - const std::wregex wiimote_device_name(L"Nintendo RVL-\\w{3}-\\d{2}"); + // match strings like "Nintendo RVL-WBC-01", "Nintendo RVL-CNT-01", "Nintendo RVL-CNT-01-TR" + const std::wregex wiimote_device_name(L"Nintendo RVL-\\w{3}-\\d{2}(-\\w{2})?"); int nPaired = 0; diff --git a/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp b/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp index d1e2826ed3..f5ded4125d 100644 --- a/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp +++ b/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp @@ -142,23 +142,6 @@ void Wiimote::InterruptChannel(const u16 channel, const void* const data, const rpt.second = (u8)size; memcpy(rpt.first, (u8*)data, size); - // some hax, since we just send the last data report to Dolphin on each Update() call - // , make the wiimote only send updated data reports when data changes - // == less bt traffic, eliminates some unneeded packets - //if (WM_REPORT_MODE == ((u8*)data)[1]) - //{ - // // also delete the last data report - // if (m_last_data_report.first) - // { - // delete[] m_last_data_report.first; - // m_last_data_report.first = NULL; - // } - - // // nice var names :p, this seems to be this one - // ((wm_report_mode*)(rpt.first + 2))->all_the_time = false; - // //((wm_report_mode*)(data + 2))->continuous = false; - //} - // Convert output DATA packets to SET_REPORT packets. // Nintendo Wiimotes work without this translation, but 3rd // party ones don't. From 80504efcdf6df7a459b47d52bd4ee64902f6e4f1 Mon Sep 17 00:00:00 2001 From: skidau Date: Sat, 31 Dec 2011 15:18:48 +1100 Subject: [PATCH 02/15] Changed the Gecko code handling to the native code handler. This provides full compatibility with all Gecko codes. To use the native code handler, place the kenobiwii.bin file into the Sys directory. Dolphin will silently fall-back to the emulated code handler if the file is not there. Fixes issue 4561. --- Source/Core/Common/Src/CommonPaths.h | 2 + Source/Core/Core/Src/Boot/Boot.cpp | 11 ++- Source/Core/Core/Src/GeckoCode.cpp | 98 ++++++++++++++++++++++++ Source/Core/Core/Src/GeckoCode.h | 1 + Source/Core/Core/Src/PatchEngine.cpp | 5 +- Source/Core/Core/Src/PowerPC/PowerPC.cpp | 6 +- Source/Core/Core/Src/PowerPC/PowerPC.h | 1 + 7 files changed, 117 insertions(+), 7 deletions(-) diff --git a/Source/Core/Common/Src/CommonPaths.h b/Source/Core/Common/Src/CommonPaths.h index 8d37482ce1..150453928e 100644 --- a/Source/Core/Common/Src/CommonPaths.h +++ b/Source/Core/Common/Src/CommonPaths.h @@ -126,6 +126,8 @@ #define WII_USA_SETTING "setting-usa.txt" #define WII_JAP_SETTING "setting-jpn.txt" +#define GECKO_CODE_HANDLER "kenobiwii.bin" + // Subdirs in Sys #define GC_SYS_DIR "GC" #define WII_SYS_DIR "Wii" diff --git a/Source/Core/Core/Src/Boot/Boot.cpp b/Source/Core/Core/Src/Boot/Boot.cpp index 5a9880533e..3dcbf5730c 100644 --- a/Source/Core/Core/Src/Boot/Boot.cpp +++ b/Source/Core/Core/Src/Boot/Boot.cpp @@ -195,10 +195,13 @@ bool CBoot::BootUp() NOTICE_LOG(BOOT, "Booting %s", _StartupPara.m_strFilename.c_str()); - // HLE jump to loader (homebrew) - HLE::Patch(0x80001800, "HBReload"); - const u8 stubstr[] = { 'S', 'T', 'U', 'B', 'H', 'A', 'X', 'X' }; - Memory::WriteBigEData(stubstr, 0x80001804, 8); + // HLE jump to loader (homebrew). Disabled when Gecko is active as it interferes with the code handler + if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableCheats) + { + HLE::Patch(0x80001800, "HBReload"); + const u8 stubstr[] = { 'S', 'T', 'U', 'B', 'H', 'A', 'X', 'X' }; + Memory::WriteBigEData(stubstr, 0x80001804, 8); + } g_symbolDB.Clear(); VideoInterface::Preset(_StartupPara.bNTSC); diff --git a/Source/Core/Core/Src/GeckoCode.cpp b/Source/Core/Core/Src/GeckoCode.cpp index 9ea30b9fb0..207aa8fb8b 100644 --- a/Source/Core/Core/Src/GeckoCode.cpp +++ b/Source/Core/Core/Src/GeckoCode.cpp @@ -5,6 +5,8 @@ #include "ConfigManager.h" #include "vector" +#include "PowerPC/PowerPC.h" +#include "CommonPaths.h" namespace Gecko { @@ -40,6 +42,9 @@ static struct // codes execute when counter is 0 static int code_execution_counter = 0; +// Track whether the code handler has been installed +static bool code_handler_installed = false; + // the currently active codes std::vector active_codes; @@ -93,6 +98,64 @@ void SetActiveCodes(const std::vector& gcodes) } inserted_asm_codes.clear(); + + code_handler_installed = false; +} + +bool InstallCodeHandler() +{ + std::string data; + std::string _rCodeHandlerFilename = File::GetSysDirectory() + GECKO_CODE_HANDLER; + if (!File::ReadFileToString(false, _rCodeHandlerFilename.c_str(), data)) + return false; + + // Install code handler + Memory::WriteBigEData((const u8*)data.data(), 0x80001800, data.length()); + + // Turn off Pause on start + Memory::Write_U32(0, 0x80001808); + + // Write the Game ID into the location expected by WiiRD + Memory::WriteBigEData(Memory::GetPointer(0x80000000), 0x80001800, 6); + + // Create GCT in memory + Memory::Write_U32(0x00d0c0de, 0x800027d0); + Memory::Write_U32(0x00d0c0de, 0x800027d4); + + std::lock_guard lk(active_codes_lock); + + int i = 0; + std::vector::iterator + gcodes_iter = active_codes.begin(), + gcodes_end = active_codes.end(); + for (; gcodes_iter!=gcodes_end; ++gcodes_iter) + { + if (gcodes_iter->enabled) + { + current_code = codes_start = &*gcodes_iter->codes.begin(); + codes_end = &*gcodes_iter->codes.end(); + for (; current_code < codes_end; ++current_code) + { + const GeckoCode::Code& code = *current_code; + Memory::Write_U32(code.address, 0x800027d8 + i); + Memory::Write_U32(code.data, 0x800027d8 + i + 4); + i += 8; + } + } + } + + Memory::Write_U32(0xff000000, 0x800027d8 + i); + Memory::Write_U32(0x00000000, 0x800027d8 + i + 4); + + // Turn on codes + Memory::Write_U8(1, 0x80001807); + + // Invalidate the icache + for (int i = 0; i < data.length(); i += 32) + { + PowerPC::ppcState.iCache.Invalidate(0x80001800 + i); + } + return true; } bool RunGeckoCode(GeckoCode& gecko_code) @@ -168,6 +231,41 @@ bool RunActiveCodes() return true; } +void RunCodeHandler() +{ + if (SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableCheats) + { + if (!code_handler_installed) + code_handler_installed = InstallCodeHandler(); + + if (code_handler_installed) + { + if (PC == LR) + { + u32 oldLR = LR; + PowerPC::CoreMode oldMode = PowerPC::GetMode(); + + PC = 0x800018A8; + LR = 0; + + // Execute the code handler in interpreter mode to track when it exits + PowerPC::SetMode(PowerPC::MODE_INTERPRETER); + + while (PC != 0) + PowerPC::SingleStep(); + + PowerPC::SetMode(oldMode); + PC = LR = oldLR; + } + } + else + { + // Use the emulated code handler + Gecko::RunActiveCodes(); + } + } +} + const std::map >& GetInsertedAsmCodes() { return inserted_asm_codes; } diff --git a/Source/Core/Core/Src/GeckoCode.h b/Source/Core/Core/Src/GeckoCode.h index 016e38f3d2..1cd83bdf65 100644 --- a/Source/Core/Core/Src/GeckoCode.h +++ b/Source/Core/Core/Src/GeckoCode.h @@ -67,6 +67,7 @@ namespace Gecko void SetActiveCodes(const std::vector& gcodes); bool RunActiveCodes(); + void RunCodeHandler(); const std::map >& GetInsertedAsmCodes(); } // namespace Gecko diff --git a/Source/Core/Core/Src/PatchEngine.cpp b/Source/Core/Core/Src/PatchEngine.cpp index 6528ad6752..74e778c916 100644 --- a/Source/Core/Core/Src/PatchEngine.cpp +++ b/Source/Core/Core/Src/PatchEngine.cpp @@ -210,13 +210,14 @@ void ApplyPatches(const std::vector &patches) void ApplyFramePatches() { ApplyPatches(onFrame); + + // Run the Gecko code handler + Gecko::RunCodeHandler(); } void ApplyARPatches() { ActionReplay::RunAllActive(); - // w/e this can be changed later - Gecko::RunActiveCodes(); } } // namespace diff --git a/Source/Core/Core/Src/PowerPC/PowerPC.cpp b/Source/Core/Core/Src/PowerPC/PowerPC.cpp index a247ec5035..7e5d9ba763 100644 --- a/Source/Core/Core/Src/PowerPC/PowerPC.cpp +++ b/Source/Core/Core/Src/PowerPC/PowerPC.cpp @@ -213,6 +213,11 @@ void Shutdown() state = CPU_POWERDOWN; } +CoreMode GetMode() +{ + return mode; +} + void SetMode(CoreMode new_mode) { if (new_mode == mode) @@ -223,7 +228,6 @@ void SetMode(CoreMode new_mode) switch (mode) { case MODE_INTERPRETER: // Switching from JIT to interpreter - jit->ClearCache(); // Remove all those nasty JIT patches. cpu_core_base = interpreter; break; diff --git a/Source/Core/Core/Src/PowerPC/PowerPC.h b/Source/Core/Core/Src/PowerPC/PowerPC.h index 9ac979bcfb..54690ac6b5 100644 --- a/Source/Core/Core/Src/PowerPC/PowerPC.h +++ b/Source/Core/Core/Src/PowerPC/PowerPC.h @@ -97,6 +97,7 @@ void Init(int cpu_core); void Shutdown(); void DoState(PointerWrap &p); +CoreMode GetMode(); void SetMode(CoreMode _coreType); void SingleStep(); From 96600ef48df5f801e265e95024df0fa894dc0930 Mon Sep 17 00:00:00 2001 From: skidau Date: Mon, 2 Jan 2012 13:53:39 +1100 Subject: [PATCH 03/15] Added a note to try the native code handler in the error message window. Added copyright notices. --- Source/Core/Core/Src/GeckoCode.cpp | 16 +++++++++++++++- Source/Core/Core/Src/GeckoCode.h | 13 +++++++++++++ Source/Core/Core/Src/GeckoCodeConfig.cpp | 13 +++++++++++++ Source/Core/Core/Src/GeckoCodeConfig.h | 13 +++++++++++++ Source/Core/DolphinWX/Src/GeckoCodeDiag.cpp | 13 +++++++++++++ Source/Core/DolphinWX/Src/GeckoCodeDiag.h | 13 +++++++++++++ 6 files changed, 80 insertions(+), 1 deletion(-) diff --git a/Source/Core/Core/Src/GeckoCode.cpp b/Source/Core/Core/Src/GeckoCode.cpp index 207aa8fb8b..2bbe101cee 100644 --- a/Source/Core/Core/Src/GeckoCode.cpp +++ b/Source/Core/Core/Src/GeckoCode.cpp @@ -1,3 +1,17 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + #include "GeckoCode.h" #include "Thread.h" @@ -200,7 +214,7 @@ bool RunGeckoCode(GeckoCode& gecko_code) gecko_code.enabled = false; PanicAlertT("GeckoCode failed to run (CT%i CST%i) (%s)" - "\n(either a bad code or the code type is not yet supported.)" + "\n(either a bad code or the code type is not yet supported. Try using the native code handler by placing the kenobiwii.bin file into the Sys directory and restarting Dolphin.)" , code.type, code.subtype, gecko_code.name.c_str()); return false; } diff --git a/Source/Core/Core/Src/GeckoCode.h b/Source/Core/Core/Src/GeckoCode.h index 1cd83bdf65..d9a53dcfc3 100644 --- a/Source/Core/Core/Src/GeckoCode.h +++ b/Source/Core/Core/Src/GeckoCode.h @@ -1,3 +1,16 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ #ifndef __GECKOCODE_h__ #define __GECKOCODE_h__ diff --git a/Source/Core/Core/Src/GeckoCodeConfig.cpp b/Source/Core/Core/Src/GeckoCodeConfig.cpp index f0e5a0585b..a23d531f7e 100644 --- a/Source/Core/Core/Src/GeckoCodeConfig.cpp +++ b/Source/Core/Core/Src/GeckoCodeConfig.cpp @@ -1,3 +1,16 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ #include "GeckoCodeConfig.h" diff --git a/Source/Core/Core/Src/GeckoCodeConfig.h b/Source/Core/Core/Src/GeckoCodeConfig.h index d7e28086c7..0ae630f784 100644 --- a/Source/Core/Core/Src/GeckoCodeConfig.h +++ b/Source/Core/Core/Src/GeckoCodeConfig.h @@ -1,3 +1,16 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ #ifndef __GECKOCODECONFIG_h__ #define __GECKOCODECONFIG_h__ diff --git a/Source/Core/DolphinWX/Src/GeckoCodeDiag.cpp b/Source/Core/DolphinWX/Src/GeckoCodeDiag.cpp index c491424376..e9089c6006 100644 --- a/Source/Core/DolphinWX/Src/GeckoCodeDiag.cpp +++ b/Source/Core/DolphinWX/Src/GeckoCodeDiag.cpp @@ -1,3 +1,16 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ #include "GeckoCodeDiag.h" diff --git a/Source/Core/DolphinWX/Src/GeckoCodeDiag.h b/Source/Core/DolphinWX/Src/GeckoCodeDiag.h index 92328d5f43..338c57c6e9 100644 --- a/Source/Core/DolphinWX/Src/GeckoCodeDiag.h +++ b/Source/Core/DolphinWX/Src/GeckoCodeDiag.h @@ -1,3 +1,16 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ #ifndef __GECKOCODEDIAG_h__ #define __GECKOCODEDIAG_h__ From f4d8e527b5c81e4a181f41105a71aec932d3810a Mon Sep 17 00:00:00 2001 From: skidau Date: Mon, 2 Jan 2012 15:14:30 +1100 Subject: [PATCH 04/15] Updated the Gecko code handler to the latest version from Gecko OS 1.9.3.1. Added a check to ensure that the number of codes fits in memory (maximum 231 codes). Store a copy of codehandler.bin in the Sys directory. --- Data/Sys/codehandler.bin | Bin 0 -> 4288 bytes Source/Core/Common/Src/CommonPaths.h | 2 +- Source/Core/Core/Src/GeckoCode.cpp | 24 +++++++++++++++--------- 3 files changed, 16 insertions(+), 10 deletions(-) create mode 100644 Data/Sys/codehandler.bin diff --git a/Data/Sys/codehandler.bin b/Data/Sys/codehandler.bin new file mode 100644 index 0000000000000000000000000000000000000000..7a95e724b1e69655f521c67e22e2b8c0479007dd GIT binary patch literal 4288 zcmeHKe{3AZ6@GiSw%4#K2i=Avn0OsuuuTrfNeG-BbKWJPJ>sanwCe=iAF^|{Vq=Rq zvD+SD_PjnWU?*;RHYPYxK$k#{K#dzxkc>$!OQlk%Qgl>^rc#7bDG{lZDsF`oC+B$k z&7KXkfA^36(UVr+?97`tGvE8>y*;Ab&!V!Ph35YxjFi}qCk2w2uS)4ijY{2(*X>?S@SW3X^jtHg>MmFmw9eA2Bbq1jBH5?j(L5o_Z>UKT z)lAb}H5VvTM}MTqKg)V7tdYEf#NmmS+7OBN>+!tT{P&QkS>yoJ4BwZ z-d)$RM!(fUWF<&syR&KbVm6Jv6tOiM(yYdnX5GMNTxlbccOuzTcG8ICFKddZ#GY}d zb7xt4neB0>Hxsqw-pfXlrKGUtyQ8f8k@RVue9U)il&yIrofN4k=_8f3K}Riggf&55 zSerFF?;>k=P-43slv%ffo@$lIT$4?k>$2(E6!<%ScURqoj2N*g^};30r}9olBJ{dy zY%>Y|j7X{VHi>mMsoQ3RdOdER=emqsD(jEu5ye-K7;h!n|4kyqx(CR)^@3}qdM&w! zRuJLgJa;nBD7Oi)+a0VjtM(~;41OfP$C)1je;(%X5`1`|0~*E{=2qc)&@gOy48MvG zRmJYerein@&Lu3YQxr&%3$f@)zD9&t-5w(0y?T3Y7sEX>N(ycmCE`z*D)=IQEgQ9( zaps->P=N~P9_Z!q03Km&?(_sW$K5KjN=W5#89v2z>N21~7ko?58N>c=TF{!+N#bZL z&M`uslN=9{lmvoP@c9*|n2$3FC0s`f^M4zci5|8rY91_~fWIP)3t#j9GRDQeL83^u zEK#H0X2C}_xKv}M`=hWo@qCQf%$b9`m31Aqt@qiNt!EsqbIv)3PcUj)*vAehwphdJ zJ>!D*QaBTR>t}9>w%+qxu=k8R{auUH;n_AN8Ex|opKDXCi8i(CI0;(Zo{f9ke94J6 zh1-}R=(^pVuAb(+(9?K+T5sELVJ~0wjyI22e?-C~WM4KzIiFv*XPsT+u)hbkvkP`J zi*`8sn|yCZB(#_zVHx$NPEUo8aX9m%Ll# zhy6RTccIHu+4N%GSo>x`L5@FzynhCHpVtFuZj4FLA+H&? zL7xKdMWOSqFaf%RPSGa?O6UZ?r#u$1QZ-zg3eoph2$RWIx$e9R@h*1a?Zm5V|DVnJ zfltj%R(R-#M7*!}ge(0p?sW6j@`=djUa5B4B9>Vjt;YSUZK6z5WcoAfm+>Z^{n*?^25fSF$M>ftnc|nTF z&qgcrz{M@7Qz`Q6$LJ#3ZapQ8>2X&W?L6IbeWD)|FQ8qZr<__cV-7A={CTiLJP^Mo zZOTr-kDw2c-`JN3>cik{02-_yf%DD=B9&;n)@`zFEoEOs42*_Bs!8Hrp&eoarBUq_ z@yxmk+#gGvW^Y8t*&EH{7@Ohefq$R%YkRhDr#)x9Ee4G@_XdsQWx>k5SQB+ae-}9f z>tQXd8>s|Jc&}uMM#Zeyr#S0c_9xKNd854mIwenoG#gvw34X-;_fg&!NvhRep{V`~ zae|*wA4IJhp(^+*(vVyDp8GnT`&NW@?NPMZfI8bykqDX{p@5MPgT1$^TGty6H(q}s zxv-WO92IGYNrfLTY8mPq_KX_F_ov- z#2y86+l`^6Bq6ag_VP74|%v%Ha&>4)2$Z?n^<~sED=akPo#m;oJl7+qt$2 zHu6xeEk4+dJK<<^PWy7L#CB!Z@13|G;W2{!i1Fm}Q^tWMld&DU`FW)p+y(0}QQumk zUGS?yfe6)YueDtyLz;O~-p33vbmCAi2HmrVd5;deYR@PsM94DC{cSpINkF6$Z zsMtCQE!1+&J7XW_#*S9x@-WW8zt_uo9x{KoU1|7;YT@@SmQZK;oimkr=yvo^{7>`zq!+| z?m_?4e~7Nfp78zh1@oTawQmf$F1e7Oj~G8c=|#>F2qdYn|sgqa{CBlz{f2fqHwk3vrftEyuWG xwCCHnhx4YixvJq#+AtA3mx{rS#L_F#wsP&0E0H^At1$KdzyA^g{{qDLsKEdL literal 0 HcmV?d00001 diff --git a/Source/Core/Common/Src/CommonPaths.h b/Source/Core/Common/Src/CommonPaths.h index 150453928e..d319fb541e 100644 --- a/Source/Core/Common/Src/CommonPaths.h +++ b/Source/Core/Common/Src/CommonPaths.h @@ -126,7 +126,7 @@ #define WII_USA_SETTING "setting-usa.txt" #define WII_JAP_SETTING "setting-jpn.txt" -#define GECKO_CODE_HANDLER "kenobiwii.bin" +#define GECKO_CODE_HANDLER "codehandler.bin" // Subdirs in Sys #define GC_SYS_DIR "GC" diff --git a/Source/Core/Core/Src/GeckoCode.cpp b/Source/Core/Core/Src/GeckoCode.cpp index 2bbe101cee..c0b7af3779 100644 --- a/Source/Core/Core/Src/GeckoCode.cpp +++ b/Source/Core/Core/Src/GeckoCode.cpp @@ -118,6 +118,7 @@ void SetActiveCodes(const std::vector& gcodes) bool InstallCodeHandler() { + u32 codelist_location = 0x800028B8; // Debugger on location (0x800022A8 = Debugger off, using codehandleronly.bin) std::string data; std::string _rCodeHandlerFilename = File::GetSysDirectory() + GECKO_CODE_HANDLER; if (!File::ReadFileToString(false, _rCodeHandlerFilename.c_str(), data)) @@ -127,14 +128,14 @@ bool InstallCodeHandler() Memory::WriteBigEData((const u8*)data.data(), 0x80001800, data.length()); // Turn off Pause on start - Memory::Write_U32(0, 0x80001808); + Memory::Write_U32(0, 0x80002774); // Write the Game ID into the location expected by WiiRD Memory::WriteBigEData(Memory::GetPointer(0x80000000), 0x80001800, 6); // Create GCT in memory - Memory::Write_U32(0x00d0c0de, 0x800027d0); - Memory::Write_U32(0x00d0c0de, 0x800027d4); + Memory::Write_U32(0x00d0c0de, codelist_location); + Memory::Write_U32(0x00d0c0de, codelist_location + 4); std::lock_guard lk(active_codes_lock); @@ -151,15 +152,20 @@ bool InstallCodeHandler() for (; current_code < codes_end; ++current_code) { const GeckoCode::Code& code = *current_code; - Memory::Write_U32(code.address, 0x800027d8 + i); - Memory::Write_U32(code.data, 0x800027d8 + i + 4); - i += 8; + + // Make sure we have enough memory to hold the code list + if ((codelist_location + 24 + i) < 0x80003000) + { + Memory::Write_U32(code.address, codelist_location + 8 + i); + Memory::Write_U32(code.data, codelist_location + 12 + i); + i += 8; + } } } } - Memory::Write_U32(0xff000000, 0x800027d8 + i); - Memory::Write_U32(0x00000000, 0x800027d8 + i + 4); + Memory::Write_U32(0xff000000, codelist_location + 8 + i); + Memory::Write_U32(0x00000000, codelist_location + 12 + i); // Turn on codes Memory::Write_U8(1, 0x80001807); @@ -214,7 +220,7 @@ bool RunGeckoCode(GeckoCode& gecko_code) gecko_code.enabled = false; PanicAlertT("GeckoCode failed to run (CT%i CST%i) (%s)" - "\n(either a bad code or the code type is not yet supported. Try using the native code handler by placing the kenobiwii.bin file into the Sys directory and restarting Dolphin.)" + "\n(either a bad code or the code type is not yet supported. Try using the native code handler by placing the codehandler.bin file into the Sys directory and restarting Dolphin.)" , code.type, code.subtype, gecko_code.name.c_str()); return false; } From 67e38fb6c654cae2e693fabe520f5c3a94970850 Mon Sep 17 00:00:00 2001 From: skidau Date: Tue, 3 Jan 2012 01:17:52 +1100 Subject: [PATCH 05/15] Fixed the safe write path of the stfd instruction in the JIT. Fixes issue 4001. --- .../PowerPC/Jit64/Jit_LoadStoreFloating.cpp | 99 ++++++++----------- 1 file changed, 41 insertions(+), 58 deletions(-) diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStoreFloating.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStoreFloating.cpp index 55990d6abf..46e888f935 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStoreFloating.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStoreFloating.cpp @@ -172,80 +172,63 @@ void Jit64::stfd(UGeckoInstruction inst) int s = inst.RS; int a = inst.RA; - if (!a) - { - Default(inst); - return; + + u32 mem_mask = Memory::ADDR_MASK_HW_ACCESS; + if (Core::g_CoreStartupParameter.bMMU || + Core::g_CoreStartupParameter.iTLBHack) { + mem_mask |= Memory::ADDR_MASK_MEM1; } - s32 offset = (s32)(s16)inst.SIMM_16; +#ifdef ENABLE_MEM_CHECK + if (Core::g_CoreStartupParameter.bEnableDebugging) + { + mem_mask |= Memory::EXRAM_MASK; + } +#endif + gpr.FlushLockX(ABI_PARAM1); gpr.Lock(a); fpr.Lock(s); gpr.BindToRegister(a, true, false); + + s32 offset = (s32)(s16)inst.SIMM_16; LEA(32, ABI_PARAM1, MDisp(gpr.R(a).GetSimpleReg(), offset)); - TEST(32, R(ABI_PARAM1), Imm32(0x0c000000)); - FixupBranch not_ram = J_CC(CC_Z); - // Assume that any hardware writes using this instruction will go to the FIFO. - // Star Wars - The Force Unleashed uses this trick. + TEST(32, R(ABI_PARAM1), Imm32(mem_mask)); + FixupBranch safe = J_CC(CC_NZ); + + // Fast routine if (cpu_info.bSSSE3) { MOVAPD(XMM0, fpr.R(s)); - PSHUFB(XMM0, M((void *)bswapShuffle1x8)); - CALL(asm_routines.fifoDirectWriteXmm64); - } else { - // This ain't working yet - MOVAPD(XMM0, fpr.R(s)); - MOVQ_xmm(M(&temp64), XMM0); - MOV(32, R(EAX), M(&temp64)); - MOV(32, R(ABI_PARAM1), M((void*)((u8 *)&temp64 + 4))); - BSWAP(32, EAX); - BSWAP(32, ABI_PARAM1); - MOV(32, M(((u8 *)&temp64) + 4), R(EAX)); - MOV(32, M((u8 *)&temp64), R(ABI_PARAM1)); - MOVQ_xmm(XMM0, M(&temp64)); - CALL(asm_routines.fifoDirectWriteXmm64); - } - FixupBranch quit = J(false); - SetJumpTarget(not_ram); -#ifdef _M_IX86 - AND(32, R(ABI_PARAM1), Imm32(Memory::MEMVIEW32_MASK)); -#endif - if (cpu_info.bSSSE3) { - MOVAPD(XMM0, fpr.R(s)); - PSHUFB(XMM0, M((void *)bswapShuffle1x8)); + PSHUFB(XMM0, M((void*)bswapShuffle1x8)); #ifdef _M_X64 MOVQ_xmm(MComplex(RBX, ABI_PARAM1, SCALE_1, 0), XMM0); #else + AND(32, R(ECX), Imm32(Memory::MEMVIEW32_MASK)); MOVQ_xmm(MDisp(ABI_PARAM1, (u32)Memory::base), XMM0); #endif } else { -#ifdef _M_X64 - fpr.BindToRegister(s, true, false); - MOVSD(M(&temp64), fpr.RX(s)); + MOVAPD(XMM0, fpr.R(s)); + MOVD_xmm(R(EAX), XMM0); + UnsafeWriteRegToReg(EAX, ABI_PARAM1, 32, 4); - MEMCHECK_START - - MOV(64, R(EAX), M(&temp64)); - BSWAP(64, EAX); - MOV(64, MComplex(RBX, ABI_PARAM1, SCALE_1, 0), R(EAX)); - - MEMCHECK_END -#else - fpr.BindToRegister(s, true, false); - MOVSD(M(&temp64), fpr.RX(s)); - - MEMCHECK_START - - MOV(32, R(EAX), M(&temp64)); - BSWAP(32, EAX); - MOV(32, MDisp(ABI_PARAM1, (u32)Memory::base + 4), R(EAX)); - MOV(32, R(EAX), M((void*)((u8 *)&temp64 + 4))); - BSWAP(32, EAX); - MOV(32, MDisp(ABI_PARAM1, (u32)Memory::base), R(EAX)); - - MEMCHECK_END -#endif + PSRLQ(XMM0, 32); + MOVD_xmm(R(EAX), XMM0); + UnsafeWriteRegToReg(EAX, ABI_PARAM1, 32, 0); } - SetJumpTarget(quit); + FixupBranch exit = J(); + SetJumpTarget(safe); + + // Safe but slow routine + MOVAPD(XMM0, fpr.R(s)); + MOVD_xmm(R(EAX), XMM0); + SafeWriteRegToReg(EAX, ABI_PARAM1, 32, 4); + + PSRLQ(XMM0, 32); + MOVD_xmm(R(EAX), XMM0); + LEA(32, ABI_PARAM1, MDisp(gpr.R(a).GetSimpleReg(), offset)); + SafeWriteRegToReg(EAX, ABI_PARAM1, 32, 0); + + SetJumpTarget(exit); + gpr.UnlockAll(); gpr.UnlockAllX(); fpr.UnlockAll(); From d399e6b26d698f2e43f46e54bfac9db4b40f14cd Mon Sep 17 00:00:00 2001 From: skidau Date: Tue, 3 Jan 2012 10:20:20 +1100 Subject: [PATCH 06/15] Reordered the safe write path of the stfd instruction. --- .../Src/PowerPC/Jit64/Jit_LoadStoreFloating.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStoreFloating.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStoreFloating.cpp index 46e888f935..41c9a3ceb7 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStoreFloating.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStoreFloating.cpp @@ -172,6 +172,11 @@ void Jit64::stfd(UGeckoInstruction inst) int s = inst.RS; int a = inst.RA; + if (!a) + { + Default(inst); + return; + } u32 mem_mask = Memory::ADDR_MASK_HW_ACCESS; if (Core::g_CoreStartupParameter.bMMU || @@ -219,14 +224,15 @@ void Jit64::stfd(UGeckoInstruction inst) // Safe but slow routine MOVAPD(XMM0, fpr.R(s)); - MOVD_xmm(R(EAX), XMM0); - SafeWriteRegToReg(EAX, ABI_PARAM1, 32, 4); - PSRLQ(XMM0, 32); MOVD_xmm(R(EAX), XMM0); - LEA(32, ABI_PARAM1, MDisp(gpr.R(a).GetSimpleReg(), offset)); SafeWriteRegToReg(EAX, ABI_PARAM1, 32, 0); + MOVAPD(XMM0, fpr.R(s)); + MOVD_xmm(R(EAX), XMM0); + LEA(32, ABI_PARAM1, MDisp(gpr.R(a).GetSimpleReg(), offset)); + SafeWriteRegToReg(EAX, ABI_PARAM1, 32, 4); + SetJumpTarget(exit); gpr.UnlockAll(); From ab54000d73653b81fc269867db65e70e6c5fe72b Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 2 Jan 2012 03:42:00 -0500 Subject: [PATCH 07/15] Fixed and streamlined overflow detection, improved subtraction methods, general flag-based optimizations including GenerateRC() which uses the sign/zero flag of the last operation --- Source/Core/Core/Src/PowerPC/Jit64/Jit.h | 4 + .../Core/Src/PowerPC/Jit64/Jit_Integer.cpp | 680 +++++++++++------- 2 files changed, 441 insertions(+), 243 deletions(-) diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit.h b/Source/Core/Core/Src/PowerPC/Jit64/Jit.h index 38de5c8fa2..832417f82f 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit.h +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit.h @@ -147,7 +147,11 @@ public: void WriteCallInterpreter(UGeckoInstruction _inst); void Cleanup(); + void GenerateConstantOverflow(bool overflow); + void GenerateOverflow(); + void GenerateOverflowFinalizeCarry(bool oe, bool inv = false); void GenerateCarry(); + void GenerateRC(); void ComputeRC(const Gen::OpArg & arg); void tri_op(int d, int a, int b, bool reversible, void (XEmitter::*op)(Gen::X64Reg, Gen::OpArg)); diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp index 351536ba56..6d6626dfdf 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp @@ -24,6 +24,64 @@ #include "JitRegCache.h" #include "JitAsm.h" +void Jit64::GenerateConstantOverflow(bool overflow) +{ + if (overflow) + { + //XER[OV/SO] = 1 + OR(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(XER_SO_MASK | XER_OV_MASK)); + } + else + { + //XER[OV] = 0 + AND(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(~XER_OV_MASK)); + } +} + +void Jit64::GenerateOverflow() +{ + FixupBranch jno = J_CC(CC_NO); + //XER[OV/SO] = 1 + OR(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(XER_SO_MASK | XER_OV_MASK)); + FixupBranch exit = J(); + SetJumpTarget(jno); + //XER[OV] = 0 + AND(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(~XER_OV_MASK)); + SetJumpTarget(exit); +} + +// Assumes CA is clear +void Jit64::GenerateOverflowFinalizeCarry(bool oe, bool inv) +{ + // USES_XER + if (oe) + { + FixupBranch jno = J_CC(CC_NO); + // Do carry + FixupBranch carry1 = J_CC(inv ? CC_C : CC_NC); + JitSetCA(); + SetJumpTarget(carry1); + //XER[OV/SO] = 1 + OR(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(XER_SO_MASK | XER_OV_MASK)); + FixupBranch exit = J(); + SetJumpTarget(jno); + // Do carry + FixupBranch carry2 = J_CC(inv ? CC_C : CC_NC); + JitSetCA(); + SetJumpTarget(carry2); + //XER[OV] = 0 + AND(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(~XER_OV_MASK)); + SetJumpTarget(exit); + } + else + { + // Output carry is inverted + FixupBranch carry1 = J_CC(inv ? CC_C : CC_NC); + JitSetCA(); + SetJumpTarget(carry1); + } +} + // Assumes that the flags were just set through an addition. void Jit64::GenerateCarry() { // USES_XER @@ -35,6 +93,24 @@ void Jit64::GenerateCarry() { SetJumpTarget(pContinue); } +// Assumes that Sign and Zero flags were set by the last operation. Preserves all flags and registers. +void Jit64::GenerateRC() { + FixupBranch pZero = J_CC(CC_Z); + FixupBranch pNegative = J_CC(CC_S); + MOV(8, M(&PowerPC::ppcState.cr_fast[0]), Imm8(0x4)); // Result > 0 + FixupBranch continue1 = J(); + + SetJumpTarget(pNegative); + MOV(8, M(&PowerPC::ppcState.cr_fast[0]), Imm8(0x8)); // Result < 0 + FixupBranch continue2 = J(); + + SetJumpTarget(pZero); + MOV(8, M(&PowerPC::ppcState.cr_fast[0]), Imm8(0x2)); // Result == 0 + + SetJumpTarget(continue1); + SetJumpTarget(continue2); +} + void Jit64::ComputeRC(const Gen::OpArg & arg) { if( arg.IsImm() ) { @@ -79,11 +155,20 @@ void Jit64::regimmop(int d, int a, bool binary, u32 value, Operation doop, void if (gpr.R(a).IsImm() && !carry) { gpr.SetImmediate32(d, doop((u32)gpr.R(a).offset, value)); + if (Rc) + { + ComputeRC(gpr.R(d)); + } } else if (a == d) { gpr.KillImmediate(d, true, true); (this->*op)(32, gpr.R(d), Imm32(value)); //m_GPR[d] = m_GPR[_inst.RA] + _inst.SIMM_16; + if (Rc) + { + // All of the possible passed operators affect Sign/Zero flags + GenerateRC(); + } if (carry) GenerateCarry(); } @@ -92,6 +177,11 @@ void Jit64::regimmop(int d, int a, bool binary, u32 value, Operation doop, void gpr.BindToRegister(d, false); MOV(32, gpr.R(d), gpr.R(a)); (this->*op)(32, gpr.R(d), Imm32(value)); //m_GPR[d] = m_GPR[_inst.RA] + _inst.SIMM_16; + if (Rc) + { + // All of the possible passed operators affect Sign/Zero flags + GenerateRC(); + } if (carry) GenerateCarry(); } @@ -100,15 +190,15 @@ void Jit64::regimmop(int d, int a, bool binary, u32 value, Operation doop, void { // a == 0, which for these instructions imply value = 0 gpr.SetImmediate32(d, value); + if (Rc) + { + ComputeRC(gpr.R(d)); + } } else { _assert_msg_(DYNA_REC, 0, "WTF regimmop"); } - if (Rc) - { - ComputeRC(gpr.R(d)); - } gpr.UnlockAll(); } @@ -435,6 +525,10 @@ void Jit64::boolX(UGeckoInstruction inst) gpr.SetImmediate32(a, (u32)gpr.R(s).offset ^ (u32)gpr.R(b).offset); else if (inst.SUBOP10 == 284) /* eqvx */ gpr.SetImmediate32(a, ~((u32)gpr.R(s).offset ^ (u32)gpr.R(b).offset)); + if (inst.Rc) + { + ComputeRC(gpr.R(a)); + } } else if (s == b) { @@ -475,6 +569,10 @@ void Jit64::boolX(UGeckoInstruction inst) { PanicAlert("WTF!"); } + if (inst.Rc) + { + ComputeRC(gpr.R(a)); + } } else if ((a == s) || (a == b)) { @@ -485,11 +583,19 @@ void Jit64::boolX(UGeckoInstruction inst) if (inst.SUBOP10 == 28) /* andx */ { AND(32, gpr.R(a), operand); + if (inst.Rc) + { + GenerateRC(); + } } else if (inst.SUBOP10 == 476) /* nandx */ { AND(32, gpr.R(a), operand); NOT(32, gpr.R(a)); + if (inst.Rc) + { + ComputeRC(gpr.R(a)); + } } else if (inst.SUBOP10 == 60) /* andcx */ { @@ -504,15 +610,27 @@ void Jit64::boolX(UGeckoInstruction inst) NOT(32, R(EAX)); AND(32, gpr.R(a), R(EAX)); } + if (inst.Rc) + { + GenerateRC(); + } } else if (inst.SUBOP10 == 444) /* orx */ { OR(32, gpr.R(a), operand); + if (inst.Rc) + { + GenerateRC(); + } } else if (inst.SUBOP10 == 124) /* norx */ { OR(32, gpr.R(a), operand); NOT(32, gpr.R(a)); + if (inst.Rc) + { + ComputeRC(gpr.R(a)); + } } else if (inst.SUBOP10 == 412) /* orcx */ { @@ -527,15 +645,27 @@ void Jit64::boolX(UGeckoInstruction inst) NOT(32, R(EAX)); OR(32, gpr.R(a), R(EAX)); } + if (inst.Rc) + { + GenerateRC(); + } } else if (inst.SUBOP10 == 316) /* xorx */ { XOR(32, gpr.R(a), operand); + if (inst.Rc) + { + GenerateRC(); + } } else if (inst.SUBOP10 == 284) /* eqvx */ { - XOR(32, gpr.R(a), operand); NOT(32, gpr.R(a)); + XOR(32, gpr.R(a), operand); + if (inst.Rc) + { + GenerateRC(); + } } else { @@ -552,46 +682,78 @@ void Jit64::boolX(UGeckoInstruction inst) { MOV(32, gpr.R(a), gpr.R(s)); AND(32, gpr.R(a), gpr.R(b)); + if (inst.Rc) + { + GenerateRC(); + } } else if (inst.SUBOP10 == 476) /* nandx */ { MOV(32, gpr.R(a), gpr.R(s)); AND(32, gpr.R(a), gpr.R(b)); NOT(32, gpr.R(a)); + if (inst.Rc) + { + ComputeRC(gpr.R(a)); + } } else if (inst.SUBOP10 == 60) /* andcx */ { MOV(32, gpr.R(a), gpr.R(b)); NOT(32, gpr.R(a)); AND(32, gpr.R(a), gpr.R(s)); + if (inst.Rc) + { + GenerateRC(); + } } else if (inst.SUBOP10 == 444) /* orx */ { MOV(32, gpr.R(a), gpr.R(s)); OR(32, gpr.R(a), gpr.R(b)); + if (inst.Rc) + { + GenerateRC(); + } } else if (inst.SUBOP10 == 124) /* norx */ { MOV(32, gpr.R(a), gpr.R(s)); OR(32, gpr.R(a), gpr.R(b)); NOT(32, gpr.R(a)); + if (inst.Rc) + { + ComputeRC(gpr.R(a)); + } } else if (inst.SUBOP10 == 412) /* orcx */ { MOV(32, gpr.R(a), gpr.R(b)); NOT(32, gpr.R(a)); OR(32, gpr.R(a), gpr.R(s)); + if (inst.Rc) + { + GenerateRC(); + } } else if (inst.SUBOP10 == 316) /* xorx */ { MOV(32, gpr.R(a), gpr.R(s)); XOR(32, gpr.R(a), gpr.R(b)); + if (inst.Rc) + { + GenerateRC(); + } } else if (inst.SUBOP10 == 284) /* eqvx */ { MOV(32, gpr.R(a), gpr.R(s)); - XOR(32, gpr.R(a), gpr.R(b)); NOT(32, gpr.R(a)); + XOR(32, gpr.R(a), gpr.R(b)); + if (inst.Rc) + { + GenerateRC(); + } } else { @@ -599,11 +761,6 @@ void Jit64::boolX(UGeckoInstruction inst) } gpr.UnlockAll(); } - - if (inst.Rc) - { - ComputeRC(gpr.R(a)); - } } void Jit64::extsbx(UGeckoInstruction inst) @@ -670,11 +827,45 @@ void Jit64::subfic(UGeckoInstruction inst) gpr.Lock(a, d); gpr.BindToRegister(d, a == d, true); int imm = inst.SIMM_16; - MOV(32, R(EAX), gpr.R(a)); - NOT(32, R(EAX)); - ADD(32, R(EAX), Imm32(imm + 1)); - MOV(32, gpr.R(d), R(EAX)); - GenerateCarry(); + if (d == a) + { + if (imm == 0) + { + JitClearCA(); + // Flags act exactly like subtracting from 0 + NEG(32, gpr.R(d)); + // Output carry is inverted + FixupBranch carry1 = J_CC(CC_C); + JitSetCA(); + SetJumpTarget(carry1); + } + else if (imm == -1) + { + // CA is always set in this case + JitSetCA(); + NOT(32, gpr.R(d)); + } + else + { + JitClearCA(); + NOT(32, gpr.R(d)); + ADD(32, gpr.R(d), Imm32(imm+1)); + // Output carry is normal + FixupBranch carry1 = J_CC(CC_NC); + JitSetCA(); + SetJumpTarget(carry1); + } + } + else + { + JitClearCA(); + MOV(32, gpr.R(d), Imm32(imm)); + SUB(32, gpr.R(d), gpr.R(a)); + // Output carry is inverted + FixupBranch carry1 = J_CC(CC_C); + JitSetCA(); + SetJumpTarget(carry1); + } gpr.UnlockAll(); // This instruction has no RC flag } @@ -687,37 +878,28 @@ void Jit64::subfcx(UGeckoInstruction inst) gpr.Lock(a, b, d); gpr.BindToRegister(d, (d == a || d == b), true); - // For some reason, I could not get the jit versions of sub* - // working with x86 sub...so we use the ~a + b + 1 method JitClearCA(); - MOV(32, R(EAX), gpr.R(a)); - NOT(32, R(EAX)); - ADD(32, R(EAX), gpr.R(b)); - FixupBranch carry1 = J_CC(CC_NC); - JitSetCA(); - SetJumpTarget(carry1); - ADD(32, R(EAX), Imm32(1)); - FixupBranch carry2 = J_CC(CC_NC); - JitSetCA(); - SetJumpTarget(carry2); - MOV(32, gpr.R(d), R(EAX)); - - gpr.UnlockAll(); - if (inst.OE) + if (d == b) { - FixupBranch jno = J_CC(CC_NO); - //XER[OV/SO] = 1 - OR(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(XER_SO_MASK)); - OR(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(XER_OV_MASK)); - FixupBranch exit = J(); - SetJumpTarget(jno); - //XER[OV] = 0 - AND(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(~XER_OV_MASK)); - SetJumpTarget(exit); + SUB(32, gpr.R(d), gpr.R(a)); + } + else if (d == a) + { + MOV(32, R(EAX), gpr.R(a)); + MOV(32, gpr.R(d), gpr.R(b)); + SUB(32, gpr.R(d), R(EAX)); + } + else + { + MOV(32, gpr.R(d), gpr.R(b)); + SUB(32, gpr.R(d), gpr.R(a)); } if (inst.Rc) { - ComputeRC(R(EAX)); + GenerateRC(); } + GenerateOverflowFinalizeCarry(inst.OE, true); + + gpr.UnlockAll(); } void Jit64::subfex(UGeckoInstruction inst) @@ -729,46 +911,36 @@ void Jit64::subfex(UGeckoInstruction inst) gpr.Lock(a, b, d); gpr.BindToRegister(d, (d == a || d == b), true); - // Get CA - MOV(32, R(ECX), M(&PowerPC::ppcState.spr[SPR_XER])); - SHR(32, R(ECX), Imm8(29)); - AND(32, R(ECX), Imm32(1)); - // Don't need it anymore + // Get CA and clear it + MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER])); JitClearCA(); - - // ~a + b - MOV(32, R(EAX), gpr.R(a)); - NOT(32, R(EAX)); - ADD(32, R(EAX), gpr.R(b)); - FixupBranch carry1 = J_CC(CC_NC); - JitSetCA(); - SetJumpTarget(carry1); - - // + CA - ADD(32, R(EAX), R(ECX)); - FixupBranch carry2 = J_CC(CC_NC); - JitSetCA(); - SetJumpTarget(carry2); - - MOV(32, gpr.R(d), R(EAX)); + SHR(32, R(EAX), Imm8(30)); + + // Convert carry to borrow + CMC(); + + if (d == b) + { + SBB(32, gpr.R(d), gpr.R(a)); + } + else if (d == a) + { + MOV(32, R(EAX), gpr.R(a)); + MOV(32, gpr.R(d), gpr.R(b)); + SBB(32, gpr.R(d), R(EAX)); + } + else + { + MOV(32, gpr.R(d), gpr.R(b)); + SBB(32, gpr.R(d), gpr.R(a)); + } + if (inst.Rc) { + GenerateRC(); + } + GenerateOverflowFinalizeCarry(inst.OE, true); gpr.UnlockAll(); gpr.UnlockAllX(); - if (inst.OE) - { - FixupBranch jno = J_CC(CC_NO); - //XER[OV/SO] = 1 - OR(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(XER_SO_MASK)); - OR(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(XER_OV_MASK)); - FixupBranch exit = J(); - SetJumpTarget(jno); - //XER[OV] = 0 - AND(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(~XER_OV_MASK)); - SetJumpTarget(exit); - } - if (inst.Rc) { - ComputeRC(R(EAX)); - } } void Jit64::subfmex(UGeckoInstruction inst) @@ -777,35 +949,24 @@ void Jit64::subfmex(UGeckoInstruction inst) INSTRUCTION_START JITDISABLE(Integer) int a = inst.RA, d = inst.RD; - - if (d == a) + gpr.Lock(a, d); + gpr.BindToRegister(d, d == a); + + MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER])); + JitClearCA(); + SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag + if (d != a) { - gpr.Lock(d); - gpr.BindToRegister(d, true); - MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER])); - SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag - NOT(32, gpr.R(d)); - ADC(32, gpr.R(d), Imm32(0xFFFFFFFF)); - GenerateCarry(); - gpr.UnlockAll(); - } - else - { - gpr.Lock(a, d); - gpr.BindToRegister(d, false); - MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER])); - SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag MOV(32, gpr.R(d), gpr.R(a)); - NOT(32, gpr.R(d)); - ADC(32, gpr.R(d), Imm32(0xFFFFFFFF)); - GenerateCarry(); - gpr.UnlockAll(); } - - if (inst.Rc) - { - ComputeRC(gpr.R(d)); - } + NOT(32, gpr.R(d)); + ADC(32, gpr.R(d), Imm32(0xFFFFFFFF)); + if (inst.Rc) + { + GenerateRC(); + } + GenerateOverflowFinalizeCarry(inst.OE); + gpr.UnlockAll(); } void Jit64::subfzex(UGeckoInstruction inst) @@ -815,34 +976,24 @@ void Jit64::subfzex(UGeckoInstruction inst) JITDISABLE(Integer) int a = inst.RA, d = inst.RD; - if (d == a) + gpr.Lock(a, d); + gpr.BindToRegister(d, d == a); + MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER])); + JitClearCA(); + SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag + if (d != a) { - gpr.Lock(d); - gpr.BindToRegister(d, true); - MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER])); - SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag - NOT(32, gpr.R(d)); - ADC(32, gpr.R(d), Imm8(0)); - GenerateCarry(); - gpr.UnlockAll(); - } - else - { - gpr.Lock(a, d); - gpr.BindToRegister(d, false); - MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER])); - SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag MOV(32, gpr.R(d), gpr.R(a)); - NOT(32, gpr.R(d)); - ADC(32, gpr.R(d), Imm8(0)); - GenerateCarry(); - gpr.UnlockAll(); } - - if (inst.Rc) - { - ComputeRC(gpr.R(d)); - } + NOT(32, gpr.R(d)); + ADC(32, gpr.R(d), Imm8(0)); + if (inst.Rc) + { + GenerateRC(); + } + GenerateOverflowFinalizeCarry(inst.OE); + + gpr.UnlockAll(); } void Jit64::subfx(UGeckoInstruction inst) @@ -853,34 +1004,46 @@ void Jit64::subfx(UGeckoInstruction inst) if (gpr.R(a).IsImm() && gpr.R(b).IsImm()) { - gpr.SetImmediate32(d, (u32)gpr.R(b).offset - (u32)gpr.R(a).offset); + s32 i = (s32)gpr.R(b).offset, j = (s32)gpr.R(a).offset; + gpr.SetImmediate32(d, i - j); + if (inst.RC) + { + ComputeRC(gpr.R(d)); + } + if (inst.OE) + { + GenerateConstantOverflow((s64)(i - j) != (s64)i - (s64)j); + } } else { gpr.Lock(a, b, d); gpr.BindToRegister(d, (d == a || d == b), true); - MOV(32, R(EAX), gpr.R(b)); - SUB(32, R(EAX), gpr.R(a)); - MOV(32, gpr.R(d), R(EAX)); + if (d == b) + { + SUB(32, gpr.R(d), gpr.R(a)); + } + else if (d == a) + { + MOV(32, R(EAX), gpr.R(a)); + MOV(32, gpr.R(d), gpr.R(b)); + SUB(32, gpr.R(d), R(EAX)); + } + else + { + MOV(32, gpr.R(d), gpr.R(b)); + SUB(32, gpr.R(d), gpr.R(a)); + } + if (inst.Rc) + { + GenerateRC(); + } + if (inst.OE) + { + GenerateOverflow(); + } gpr.UnlockAll(); } - - if (inst.OE) - { - FixupBranch jno = J_CC(CC_NO); - //XER[OV/SO] = 1 - OR(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(XER_SO_MASK)); - OR(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(XER_OV_MASK)); - FixupBranch exit = J(); - SetJumpTarget(jno); - //XER[OV] = 0 - AND(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(~XER_OV_MASK)); - SetJumpTarget(exit); - } - if (inst.Rc) - { - ComputeRC(gpr.R(d)); - } } void Jit64::mulli(UGeckoInstruction inst) @@ -911,7 +1074,12 @@ void Jit64::mullwx(UGeckoInstruction inst) if (gpr.R(a).IsImm() && gpr.R(b).IsImm()) { - gpr.SetImmediate32(d, (s32)gpr.R(a).offset * (s32)gpr.R(b).offset); + s32 i = (s32)gpr.R(a).offset, j = (s32)gpr.R(b).offset; + gpr.SetImmediate32(d, i * j); + if (inst.OE) + { + GenerateConstantOverflow((s64)(i*j) != (s64)i * (s64)j); + } } else { @@ -925,21 +1093,12 @@ void Jit64::mullwx(UGeckoInstruction inst) MOV(32, gpr.R(d), gpr.R(b)); IMUL(32, gpr.RX(d), gpr.R(a)); } + if (inst.OE) + { + GenerateOverflow(); + } gpr.UnlockAll(); } - - if (inst.OE) - { - FixupBranch jno = J_CC(CC_NO); - //XER[OV/SO] = 1 - OR(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(XER_SO_MASK)); - OR(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(XER_OV_MASK)); - FixupBranch exit = J(); - SetJumpTarget(jno); - //XER[OV] = 0 - AND(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(~XER_OV_MASK)); - SetJumpTarget(exit); - } if (inst.Rc) { ComputeRC(gpr.R(d)); @@ -972,7 +1131,9 @@ void Jit64::mulhwux(UGeckoInstruction inst) } if (inst.Rc) + { ComputeRC(gpr.R(d)); + } } void Jit64::divwux(UGeckoInstruction inst) @@ -984,9 +1145,21 @@ void Jit64::divwux(UGeckoInstruction inst) if (gpr.R(a).IsImm() && gpr.R(b).IsImm()) { if( gpr.R(b).offset == 0 ) + { gpr.SetImmediate32(d, 0); + if (inst.OE) + { + GenerateConstantOverflow(true); + } + } else + { gpr.SetImmediate32(d, (u32)gpr.R(a).offset / (u32)gpr.R(b).offset); + if (inst.OE) + { + GenerateConstantOverflow(false); + } + } } else { @@ -1000,28 +1173,24 @@ void Jit64::divwux(UGeckoInstruction inst) // doesn't handle if OE is set, but int doesn't either... FixupBranch not_div_by_zero = J_CC(CC_NZ); MOV(32, gpr.R(d), R(EDX)); - MOV(32, R(EAX), gpr.R(d)); + if (inst.OE) + { + GenerateConstantOverflow(true); + } + //MOV(32, R(EAX), gpr.R(d)); FixupBranch end = J(); SetJumpTarget(not_div_by_zero); DIV(32, gpr.R(b)); MOV(32, gpr.R(d), R(EAX)); + if (inst.OE) + { + GenerateConstantOverflow(false); + } SetJumpTarget(end); gpr.UnlockAll(); gpr.UnlockAllX(); } - if (inst.OE) - { - FixupBranch jno = J_CC(CC_NO); - //XER[OV/SO] = 1 - OR(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(XER_SO_MASK)); - OR(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(XER_OV_MASK)); - FixupBranch exit = J(); - SetJumpTarget(jno); - //XER[OV] = 0 - AND(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(~XER_OV_MASK)); - SetJumpTarget(exit); - } if (inst.Rc) { ComputeRC(gpr.R(d)); @@ -1036,9 +1205,18 @@ void Jit64::addx(UGeckoInstruction inst) if (gpr.R(a).IsImm() && gpr.R(b).IsImm()) { - gpr.SetImmediate32(d, (u32)gpr.R(a).offset + (u32)gpr.R(b).offset); + s32 i = (s32)gpr.R(a).offset, j = (s32)gpr.R(b).offset; + gpr.SetImmediate32(d, i + j); + if (inst.Rc) + { + ComputeRC(gpr.R(d)); + } + if (inst.OE) + { + GenerateConstantOverflow((s64)(i + j) != (s64)i + (s64)j); + } } - else if (gpr.R(a).IsSimpleReg() && gpr.R(b).IsSimpleReg()) + else if (gpr.R(a).IsSimpleReg() && gpr.R(b).IsSimpleReg() && !inst.Rc && !inst.OE) { gpr.Lock(a, b, d); gpr.BindToRegister(d, false); @@ -1051,6 +1229,14 @@ void Jit64::addx(UGeckoInstruction inst) gpr.Lock(a, b, d); gpr.BindToRegister(d, true); ADD(32, gpr.R(d), gpr.R(operand)); + if (inst.Rc) + { + GenerateRC(); + } + if (inst.OE) + { + GenerateOverflow(); + } gpr.UnlockAll(); } else @@ -1059,26 +1245,16 @@ void Jit64::addx(UGeckoInstruction inst) gpr.BindToRegister(d, false); MOV(32, gpr.R(d), gpr.R(a)); ADD(32, gpr.R(d), gpr.R(b)); + if (inst.Rc) + { + GenerateRC(); + } + if (inst.OE) + { + GenerateOverflow(); + } gpr.UnlockAll(); } - - if (inst.OE) - { - FixupBranch jno = J_CC(CC_NO); - //XER[OV/SO] = 1 - OR(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(XER_SO_MASK)); - OR(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(XER_OV_MASK)); - FixupBranch exit = J(); - SetJumpTarget(jno); - //XER[OV] = 0 - AND(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(~XER_OV_MASK)); - SetJumpTarget(exit); - } - - if (inst.Rc) - { - ComputeRC(gpr.R(d)); - } } void Jit64::addex(UGeckoInstruction inst) @@ -1093,9 +1269,14 @@ void Jit64::addex(UGeckoInstruction inst) gpr.Lock(a, b, d); gpr.BindToRegister(d, true); MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER])); + JitClearCA(); SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag ADC(32, gpr.R(d), gpr.R((d == a) ? b : a)); - GenerateCarry(); + if (inst.Rc) + { + GenerateRC(); + } + GenerateOverflowFinalizeCarry(inst.OE); gpr.UnlockAll(); } else @@ -1103,17 +1284,17 @@ void Jit64::addex(UGeckoInstruction inst) gpr.Lock(a, b, d); gpr.BindToRegister(d, false); MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER])); + JitClearCA(); SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag MOV(32, gpr.R(d), gpr.R(a)); ADC(32, gpr.R(d), gpr.R(b)); - GenerateCarry(); + if (inst.Rc) + { + GenerateRC(); + } + GenerateOverflowFinalizeCarry(inst.OE); gpr.UnlockAll(); } - - if (inst.Rc) - { - ComputeRC(gpr.R(d)); - } } void Jit64::addcx(UGeckoInstruction inst) @@ -1127,37 +1308,29 @@ void Jit64::addcx(UGeckoInstruction inst) int operand = ((d == a) ? b : a); gpr.Lock(a, b, d); gpr.BindToRegister(d, true); + JitClearCA(); ADD(32, gpr.R(d), gpr.R(operand)); - GenerateCarry(); + if (inst.Rc) + { + GenerateRC(); + } + GenerateOverflowFinalizeCarry(inst.OE); gpr.UnlockAll(); } else { gpr.Lock(a, b, d); gpr.BindToRegister(d, false); + JitClearCA(); MOV(32, gpr.R(d), gpr.R(a)); ADD(32, gpr.R(d), gpr.R(b)); - GenerateCarry(); + if (inst.Rc) + { + GenerateRC(); + } + GenerateOverflowFinalizeCarry(inst.OE); gpr.UnlockAll(); } - - if (inst.OE) - { - FixupBranch jno = J_CC(CC_NO); - //XER[OV/SO] = 1 - OR(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(XER_SO_MASK)); - OR(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(XER_OV_MASK)); - FixupBranch exit = J(); - SetJumpTarget(jno); - //XER[OV] = 0 - AND(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(~XER_OV_MASK)); - SetJumpTarget(exit); - } - - if (inst.Rc) - { - ComputeRC(gpr.R(d)); - } } void Jit64::addmex(UGeckoInstruction inst) @@ -1172,9 +1345,14 @@ void Jit64::addmex(UGeckoInstruction inst) gpr.Lock(d); gpr.BindToRegister(d, true); MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER])); + JitClearCA(); SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag ADC(32, gpr.R(d), Imm32(0xFFFFFFFF)); - GenerateCarry(); + if (inst.Rc) + { + GenerateRC(); + } + GenerateOverflowFinalizeCarry(inst.OE); gpr.UnlockAll(); } else @@ -1182,17 +1360,17 @@ void Jit64::addmex(UGeckoInstruction inst) gpr.Lock(a, d); gpr.BindToRegister(d, false); MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER])); + JitClearCA(); SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag MOV(32, gpr.R(d), gpr.R(a)); ADC(32, gpr.R(d), Imm32(0xFFFFFFFF)); - GenerateCarry(); + if (inst.Rc) + { + GenerateRC(); + } + GenerateOverflowFinalizeCarry(inst.OE); gpr.UnlockAll(); } - - if (inst.Rc) - { - ComputeRC(gpr.R(d)); - } } void Jit64::addzex(UGeckoInstruction inst) @@ -1207,9 +1385,14 @@ void Jit64::addzex(UGeckoInstruction inst) gpr.Lock(d); gpr.BindToRegister(d, true); MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER])); + JitClearCA(); SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag ADC(32, gpr.R(d), Imm8(0)); - GenerateCarry(); + if (inst.Rc) + { + GenerateRC(); + } + GenerateOverflowFinalizeCarry(inst.OE); gpr.UnlockAll(); } else @@ -1217,17 +1400,17 @@ void Jit64::addzex(UGeckoInstruction inst) gpr.Lock(a, d); gpr.BindToRegister(d, false); MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER])); + JitClearCA(); SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag MOV(32, gpr.R(d), gpr.R(a)); ADC(32, gpr.R(d), Imm8(0)); - GenerateCarry(); + if (inst.Rc) + { + GenerateRC(); + } + GenerateOverflowFinalizeCarry(inst.OE); gpr.UnlockAll(); } - - if (inst.Rc) - { - ComputeRC(gpr.R(d)); - } } void Jit64::rlwinmx(UGeckoInstruction inst) @@ -1360,6 +1543,14 @@ void Jit64::negx(UGeckoInstruction inst) if (gpr.R(a).IsImm()) { gpr.SetImmediate32(d, ~((u32)gpr.R(a).offset) + 1); + if (inst.Rc) + { + ComputeRC(gpr.R(d)); + } + if (inst.OE) + { + GenerateConstantOverflow(gpr.R(d).offset == 0x80000000); + } } else { @@ -1368,13 +1559,16 @@ void Jit64::negx(UGeckoInstruction inst) if (a != d) MOV(32, gpr.R(d), gpr.R(a)); NEG(32, gpr.R(d)); + if (inst.Rc) + { + GenerateRC(); + } + if (inst.OE) + { + GenerateOverflow(); + } gpr.UnlockAll(); } - - if (inst.Rc) - { - ComputeRC(gpr.R(d)); - } } void Jit64::srwx(UGeckoInstruction inst) From 4cb1af0f133ea7e7a434f25d01646381f9b3b30b Mon Sep 17 00:00:00 2001 From: calc84maniac Date: Mon, 2 Jan 2012 04:00:47 -0500 Subject: [PATCH 08/15] Fixed a bad typo. Why are there different inst.Rc and inst.RC variables? >_> --- Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp index 6d6626dfdf..5af80baf5d 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp @@ -1006,7 +1006,7 @@ void Jit64::subfx(UGeckoInstruction inst) { s32 i = (s32)gpr.R(b).offset, j = (s32)gpr.R(a).offset; gpr.SetImmediate32(d, i - j); - if (inst.RC) + if (inst.Rc) { ComputeRC(gpr.R(d)); } From a6d041bfa963cbed78b1edd18057d2ce9353a0b7 Mon Sep 17 00:00:00 2001 From: calc84maniac Date: Mon, 2 Jan 2012 11:50:01 -0500 Subject: [PATCH 09/15] Removed an extraneous FlushLockX, further optimized simultaneous handling of carry/overflow. --- Source/Core/Core/Src/PowerPC/Jit64/Jit.h | 2 +- .../Core/Src/PowerPC/Jit64/Jit_Integer.cpp | 58 +++++++++---------- .../Core/Src/PowerPC/JitCommon/Jit_Util.cpp | 8 +++ .../Core/Src/PowerPC/JitCommon/Jit_Util.h | 1 + 4 files changed, 37 insertions(+), 32 deletions(-) diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit.h b/Source/Core/Core/Src/PowerPC/Jit64/Jit.h index 832417f82f..9d9b57658b 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit.h +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit.h @@ -149,7 +149,7 @@ public: void GenerateConstantOverflow(bool overflow); void GenerateOverflow(); - void GenerateOverflowFinalizeCarry(bool oe, bool inv = false); + void FinalizeCarryOverflow(bool oe, bool inv = false); void GenerateCarry(); void GenerateRC(); void ComputeRC(const Gen::OpArg & arg); diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp index 5af80baf5d..b246a2cc9e 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp @@ -50,8 +50,8 @@ void Jit64::GenerateOverflow() SetJumpTarget(exit); } -// Assumes CA is clear -void Jit64::GenerateOverflowFinalizeCarry(bool oe, bool inv) +// Assumes CA,OV are clear +void Jit64::FinalizeCarryOverflow(bool oe, bool inv) { // USES_XER if (oe) @@ -69,8 +69,6 @@ void Jit64::GenerateOverflowFinalizeCarry(bool oe, bool inv) FixupBranch carry2 = J_CC(inv ? CC_C : CC_NC); JitSetCA(); SetJumpTarget(carry2); - //XER[OV] = 0 - AND(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(~XER_OV_MASK)); SetJumpTarget(exit); } else @@ -878,7 +876,7 @@ void Jit64::subfcx(UGeckoInstruction inst) gpr.Lock(a, b, d); gpr.BindToRegister(d, (d == a || d == b), true); - JitClearCA(); + JitClearCAOV(inst.OE); if (d == b) { SUB(32, gpr.R(d), gpr.R(a)); @@ -897,7 +895,7 @@ void Jit64::subfcx(UGeckoInstruction inst) if (inst.Rc) { GenerateRC(); } - GenerateOverflowFinalizeCarry(inst.OE, true); + FinalizeCarryOverflow(inst.OE, true); gpr.UnlockAll(); } @@ -907,13 +905,12 @@ void Jit64::subfex(UGeckoInstruction inst) INSTRUCTION_START; JITDISABLE(Integer) int a = inst.RA, b = inst.RB, d = inst.RD; - gpr.FlushLockX(ECX); gpr.Lock(a, b, d); gpr.BindToRegister(d, (d == a || d == b), true); - // Get CA and clear it + // Get CA and clear it (along with OV if applicable) MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER])); - JitClearCA(); + JitClearCAOV(inst.OE); SHR(32, R(EAX), Imm8(30)); // Convert carry to borrow @@ -937,10 +934,9 @@ void Jit64::subfex(UGeckoInstruction inst) if (inst.Rc) { GenerateRC(); } - GenerateOverflowFinalizeCarry(inst.OE, true); + FinalizeCarryOverflow(inst.OE, true); gpr.UnlockAll(); - gpr.UnlockAllX(); } void Jit64::subfmex(UGeckoInstruction inst) @@ -953,7 +949,7 @@ void Jit64::subfmex(UGeckoInstruction inst) gpr.BindToRegister(d, d == a); MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER])); - JitClearCA(); + JitClearCAOV(inst.OE); SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag if (d != a) { @@ -965,7 +961,7 @@ void Jit64::subfmex(UGeckoInstruction inst) { GenerateRC(); } - GenerateOverflowFinalizeCarry(inst.OE); + FinalizeCarryOverflow(inst.OE); gpr.UnlockAll(); } @@ -979,7 +975,7 @@ void Jit64::subfzex(UGeckoInstruction inst) gpr.Lock(a, d); gpr.BindToRegister(d, d == a); MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER])); - JitClearCA(); + JitClearCAOV(inst.OE); SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag if (d != a) { @@ -991,7 +987,7 @@ void Jit64::subfzex(UGeckoInstruction inst) { GenerateRC(); } - GenerateOverflowFinalizeCarry(inst.OE); + FinalizeCarryOverflow(inst.OE); gpr.UnlockAll(); } @@ -1269,14 +1265,14 @@ void Jit64::addex(UGeckoInstruction inst) gpr.Lock(a, b, d); gpr.BindToRegister(d, true); MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER])); - JitClearCA(); + JitClearCAOV(inst.OE); SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag ADC(32, gpr.R(d), gpr.R((d == a) ? b : a)); if (inst.Rc) { GenerateRC(); } - GenerateOverflowFinalizeCarry(inst.OE); + FinalizeCarryOverflow(inst.OE); gpr.UnlockAll(); } else @@ -1284,7 +1280,7 @@ void Jit64::addex(UGeckoInstruction inst) gpr.Lock(a, b, d); gpr.BindToRegister(d, false); MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER])); - JitClearCA(); + JitClearCAOV(inst.OE); SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag MOV(32, gpr.R(d), gpr.R(a)); ADC(32, gpr.R(d), gpr.R(b)); @@ -1292,7 +1288,7 @@ void Jit64::addex(UGeckoInstruction inst) { GenerateRC(); } - GenerateOverflowFinalizeCarry(inst.OE); + FinalizeCarryOverflow(inst.OE); gpr.UnlockAll(); } } @@ -1308,27 +1304,27 @@ void Jit64::addcx(UGeckoInstruction inst) int operand = ((d == a) ? b : a); gpr.Lock(a, b, d); gpr.BindToRegister(d, true); - JitClearCA(); + JitClearCAOV(inst.OE); ADD(32, gpr.R(d), gpr.R(operand)); if (inst.Rc) { GenerateRC(); } - GenerateOverflowFinalizeCarry(inst.OE); + FinalizeCarryOverflow(inst.OE); gpr.UnlockAll(); } else { gpr.Lock(a, b, d); gpr.BindToRegister(d, false); - JitClearCA(); + JitClearCAOV(inst.OE); MOV(32, gpr.R(d), gpr.R(a)); ADD(32, gpr.R(d), gpr.R(b)); if (inst.Rc) { GenerateRC(); } - GenerateOverflowFinalizeCarry(inst.OE); + FinalizeCarryOverflow(inst.OE); gpr.UnlockAll(); } } @@ -1345,14 +1341,14 @@ void Jit64::addmex(UGeckoInstruction inst) gpr.Lock(d); gpr.BindToRegister(d, true); MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER])); - JitClearCA(); + JitClearCAOV(inst.OE); SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag ADC(32, gpr.R(d), Imm32(0xFFFFFFFF)); if (inst.Rc) { GenerateRC(); } - GenerateOverflowFinalizeCarry(inst.OE); + FinalizeCarryOverflow(inst.OE); gpr.UnlockAll(); } else @@ -1360,7 +1356,7 @@ void Jit64::addmex(UGeckoInstruction inst) gpr.Lock(a, d); gpr.BindToRegister(d, false); MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER])); - JitClearCA(); + JitClearCAOV(inst.OE); SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag MOV(32, gpr.R(d), gpr.R(a)); ADC(32, gpr.R(d), Imm32(0xFFFFFFFF)); @@ -1368,7 +1364,7 @@ void Jit64::addmex(UGeckoInstruction inst) { GenerateRC(); } - GenerateOverflowFinalizeCarry(inst.OE); + FinalizeCarryOverflow(inst.OE); gpr.UnlockAll(); } } @@ -1385,14 +1381,14 @@ void Jit64::addzex(UGeckoInstruction inst) gpr.Lock(d); gpr.BindToRegister(d, true); MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER])); - JitClearCA(); + JitClearCAOV(inst.OE); SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag ADC(32, gpr.R(d), Imm8(0)); if (inst.Rc) { GenerateRC(); } - GenerateOverflowFinalizeCarry(inst.OE); + FinalizeCarryOverflow(inst.OE); gpr.UnlockAll(); } else @@ -1400,7 +1396,7 @@ void Jit64::addzex(UGeckoInstruction inst) gpr.Lock(a, d); gpr.BindToRegister(d, false); MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER])); - JitClearCA(); + JitClearCAOV(inst.OE); SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag MOV(32, gpr.R(d), gpr.R(a)); ADC(32, gpr.R(d), Imm8(0)); @@ -1408,7 +1404,7 @@ void Jit64::addzex(UGeckoInstruction inst) { GenerateRC(); } - GenerateOverflowFinalizeCarry(inst.OE); + FinalizeCarryOverflow(inst.OE); gpr.UnlockAll(); } } diff --git a/Source/Core/Core/Src/PowerPC/JitCommon/Jit_Util.cpp b/Source/Core/Core/Src/PowerPC/JitCommon/Jit_Util.cpp index 8abf0fc18a..b1f8a01f96 100644 --- a/Source/Core/Core/Src/PowerPC/JitCommon/Jit_Util.cpp +++ b/Source/Core/Core/Src/PowerPC/JitCommon/Jit_Util.cpp @@ -352,3 +352,11 @@ void EmuCodeBlock::JitSetCA() { OR(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(XER_CA_MASK)); //XER.CA = 1 } + +void EmuCodeBlock::JitClearCAOV(bool oe) +{ + if (oe) + AND(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(~XER_CA_MASK & ~XER_OV_MASK)); //XER.CA, XER.OV = 0 + else + AND(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(~XER_CA_MASK)); //XER.CA = 0 +} \ No newline at end of file diff --git a/Source/Core/Core/Src/PowerPC/JitCommon/Jit_Util.h b/Source/Core/Core/Src/PowerPC/JitCommon/Jit_Util.h index 70d4e294e4..e151c5e914 100644 --- a/Source/Core/Core/Src/PowerPC/JitCommon/Jit_Util.h +++ b/Source/Core/Core/Src/PowerPC/JitCommon/Jit_Util.h @@ -38,6 +38,7 @@ public: void WriteFloatToConstRamAddress(const Gen::X64Reg& xmm_reg, u32 address); void JitClearCA(); void JitSetCA(); + void JitClearCAOV(bool oe); void ForceSinglePrecisionS(Gen::X64Reg xmm); void ForceSinglePrecisionP(Gen::X64Reg xmm); From 9530bd0292b36a73c0d9764f011560640d1126e5 Mon Sep 17 00:00:00 2001 From: calc84maniac Date: Mon, 2 Jan 2012 15:07:36 -0500 Subject: [PATCH 10/15] rlwimix optimizations --- .../Core/Src/PowerPC/Jit64/Jit_Integer.cpp | 78 ++++++++++++++++--- 1 file changed, 66 insertions(+), 12 deletions(-) diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp index b246a2cc9e..cfac1728d6 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp @@ -1476,25 +1476,79 @@ void Jit64::rlwimix(UGeckoInstruction inst) { u32 mask = Helper_Mask(inst.MB,inst.ME); gpr.SetImmediate32(a, ((u32)gpr.R(a).offset & ~mask) | (_rotl((u32)gpr.R(s).offset,inst.SH) & mask)); + if (inst.Rc) + { + ComputeRC(gpr.R(a)); + } } else { gpr.Lock(a, s); - gpr.KillImmediate(a, true, true); + gpr.BindToRegister(a, true, true); u32 mask = Helper_Mask(inst.MB, inst.ME); - MOV(32, R(EAX), gpr.R(s)); - AND(32, gpr.R(a), Imm32(~mask)); - if (inst.SH) - ROL(32, R(EAX), Imm8(inst.SH)); - AND(32, R(EAX), Imm32(mask)); - OR(32, gpr.R(a), R(EAX)); + if (mask == 0 || (a == s && inst.SH == 0)) + { + if (inst.RC) + { + ComputeRC(gpr.R(a)); + } + } + else if (mask == 0xFFFFFFFF) + { + if (a != s) + { + MOV(32, gpr.R(a), gpr.R(s)); + } + if (inst.SH) + { + ROL(32, gpr.R(a), Imm8(inst.SH)); + } + if (inst.Rc) + { + ComputeRC(gpr.R(a)); + } + } + else if (inst.SH) + { + if (mask == -(1 << inst.SH)) + { + MOV(32, R(EAX), gpr.R(s)); + SHL(32, R(EAX), Imm8(inst.SH)); + AND(32, gpr.R(a), Imm32(~mask)); + OR(32, gpr.R(a), R(EAX)); + } + else if (mask == (1 << inst.SH) - 1) + { + MOV(32, R(EAX), gpr.R(s)); + SHR(32, R(EAX), Imm8(32-inst.SH)); + AND(32, gpr.R(a), Imm32(~mask)); + OR(32, gpr.R(a), R(EAX)); + } + else + { + MOV(32, R(EAX), gpr.R(s)); + ROL(32, R(EAX), Imm8(inst.SH)); + XOR(32, R(EAX), gpr.R(a)); + AND(32, R(EAX), Imm32(mask)); + XOR(32, gpr.R(a), R(EAX)); + } + if (inst.Rc) + { + GenerateRC(); + } + } + else + { + XOR(32, gpr.R(a), gpr.R(s)); + AND(32, gpr.R(a), Imm32(~mask)); + XOR(32, gpr.R(a), gpr.R(s)); + if (inst.Rc) + { + GenerateRC(); + } + } gpr.UnlockAll(); } - - if (inst.Rc) - { - ComputeRC(gpr.R(a)); - } } void Jit64::rlwnmx(UGeckoInstruction inst) From ff6d0d056affeb31ce64e4ac4590254f773e42a7 Mon Sep 17 00:00:00 2001 From: calc84maniac Date: Mon, 2 Jan 2012 17:30:54 -0500 Subject: [PATCH 11/15] rolwinmix and rlwnmx optimizations, another Rc/RC typo fixed --- .../Core/Src/PowerPC/Jit64/Jit_Integer.cpp | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp index cfac1728d6..bf57681295 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp @@ -1556,31 +1556,35 @@ void Jit64::rlwnmx(UGeckoInstruction inst) INSTRUCTION_START JITDISABLE(Integer) int a = inst.RA, b = inst.RB, s = inst.RS; - + u32 mask = Helper_Mask(inst.MB, inst.ME); if (gpr.R(b).IsImm() && gpr.R(s).IsImm()) { gpr.SetImmediate32(a, _rotl((u32)gpr.R(s).offset, (u32)gpr.R(b).offset & 0x1F) & mask); + if (inst.Rc) + { + ComputeRC(gpr.R(a)); + } } else { gpr.FlushLockX(ECX); gpr.Lock(a, b, s); - gpr.KillImmediate(a, (a == s || a == b), true); - MOV(32, R(EAX), gpr.R(s)); + gpr.BindToRegister(a, true, true); MOV(32, R(ECX), gpr.R(b)); - AND(32, R(ECX), Imm32(0x1f)); - ROL(32, R(EAX), R(ECX)); - AND(32, R(EAX), Imm32(mask)); - MOV(32, gpr.R(a), R(EAX)); + if (a != s) + { + MOV(32, gpr.R(a), gpr.R(s)); + } + ROL(32, gpr.R(a), R(ECX)); + AND(32, gpr.R(a), Imm32(mask)); + if (inst.Rc) + { + GenerateRC(); + } gpr.UnlockAll(); gpr.UnlockAllX(); } - - if (inst.Rc) - { - ComputeRC(gpr.R(a)); - } } void Jit64::negx(UGeckoInstruction inst) From 9c4106027ce7ff4847b2e06d25a4cadf30e27faf Mon Sep 17 00:00:00 2001 From: calc84maniac Date: Mon, 2 Jan 2012 17:34:07 -0500 Subject: [PATCH 12/15] Erp, some changes were not committed --- .../Core/Src/PowerPC/Jit64/Jit_Integer.cpp | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp index bf57681295..c2726fc7de 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp @@ -1422,6 +1422,10 @@ void Jit64::rlwinmx(UGeckoInstruction inst) result = _rotl(result, inst.SH); result &= Helper_Mask(inst.MB, inst.ME); gpr.SetImmediate32(a, result); + if (inst.Rc) + { + ComputeRC(gpr.R(a)); + } } else { @@ -1435,10 +1439,18 @@ void Jit64::rlwinmx(UGeckoInstruction inst) if (inst.MB == 0 && inst.ME==31-inst.SH) { SHL(32, gpr.R(a), Imm8(inst.SH)); + if (inst.Rc) + { + GenerateRC(); + } } else if (inst.ME == 31 && inst.MB == 32 - inst.SH) { SHR(32, gpr.R(a), Imm8(inst.MB)); + if (inst.Rc) + { + GenerateRC(); + } } else { @@ -1452,16 +1464,19 @@ void Jit64::rlwinmx(UGeckoInstruction inst) { written = true; AND(32, gpr.R(a), Imm32(Helper_Mask(inst.MB, inst.ME))); + if (inst.Rc) + { + GenerateRC(); + } + } + else if (inst.Rc) + { + ComputeRC(gpr.R(a)); } _assert_msg_(DYNA_REC, written, "W T F!!!"); } gpr.UnlockAll(); } - - if (inst.Rc) - { - ComputeRC(gpr.R(a)); - } } @@ -1488,7 +1503,7 @@ void Jit64::rlwimix(UGeckoInstruction inst) u32 mask = Helper_Mask(inst.MB, inst.ME); if (mask == 0 || (a == s && inst.SH == 0)) { - if (inst.RC) + if (inst.Rc) { ComputeRC(gpr.R(a)); } From 6ecae3e556ce8ac75ea137ef8258c332b4941cf6 Mon Sep 17 00:00:00 2001 From: calc84maniac Date: Mon, 2 Jan 2012 18:00:28 -0500 Subject: [PATCH 13/15] srwx and slwx optimizations --- .../Core/Src/PowerPC/Jit64/Jit_Integer.cpp | 54 +++++++++++-------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp index c2726fc7de..b0be8517c7 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp @@ -1652,28 +1652,33 @@ void Jit64::srwx(UGeckoInstruction inst) { u32 amount = (u32)gpr.R(b).offset; gpr.SetImmediate32(a, (amount & 0x20) ? 0 : ((u32)gpr.R(s).offset >> (amount & 0x1f))); + if (inst.Rc) + { + ComputeRC(gpr.R(a)); + } } else { gpr.FlushLockX(ECX); gpr.Lock(a, b, s); - gpr.BindToRegister(a, a == s || a == b || s == b, true); + gpr.BindToRegister(a, true, true); MOV(32, R(ECX), gpr.R(b)); - XOR(32, R(EAX), R(EAX)); TEST(32, R(ECX), Imm32(32)); - FixupBranch branch = J_CC(CC_NZ); - MOV(32, R(EAX), gpr.R(s)); - SHR(32, R(EAX), R(ECX)); + if (a != s) + { + MOV(32, gpr.R(a), gpr.R(s)); + } + FixupBranch branch = J_CC(CC_Z); + XOR(32, gpr.R(a), gpr.R(a)); SetJumpTarget(branch); - MOV(32, gpr.R(a), R(EAX)); + SHR(32, gpr.R(a), R(ECX)); + if (inst.Rc) + { + GenerateRC(); + } gpr.UnlockAll(); gpr.UnlockAllX(); } - - if (inst.Rc) - { - ComputeRC(gpr.R(a)); - } } void Jit64::slwx(UGeckoInstruction inst) @@ -1688,28 +1693,33 @@ void Jit64::slwx(UGeckoInstruction inst) { u32 amount = (u32)gpr.R(b).offset; gpr.SetImmediate32(a, (amount & 0x20) ? 0 : (u32)gpr.R(s).offset << amount); + if (inst.Rc) + { + ComputeRC(gpr.R(a)); + } } else { gpr.FlushLockX(ECX); gpr.Lock(a, b, s); - gpr.BindToRegister(a, a == s || a == b || s == b, true); + gpr.BindToRegister(a, true, true); MOV(32, R(ECX), gpr.R(b)); - XOR(32, R(EAX), R(EAX)); TEST(32, R(ECX), Imm32(32)); - FixupBranch branch = J_CC(CC_NZ); - MOV(32, R(EAX), gpr.R(s)); - SHL(32, R(EAX), R(ECX)); + if (a != s) + { + MOV(32, gpr.R(a), gpr.R(s)); + } + FixupBranch branch = J_CC(CC_Z); + XOR(32, gpr.R(a), gpr.R(a)); SetJumpTarget(branch); - MOV(32, gpr.R(a), R(EAX)); + SHL(32, gpr.R(a), R(ECX)); + if (inst.Rc) + { + GenerateRC(); + } gpr.UnlockAll(); gpr.UnlockAllX(); } - - if (inst.Rc) - { - ComputeRC(gpr.R(a)); - } } void Jit64::srawx(UGeckoInstruction inst) From ca287e7957c7a6ddca4275ce8299c9730e38ac29 Mon Sep 17 00:00:00 2001 From: skidau Date: Tue, 3 Jan 2012 15:36:32 +1100 Subject: [PATCH 14/15] Removed the "Reload MemCard on load state" hack as it is no longer needed with the new save states system. Fixes issue 4898. --- Source/Core/Core/Src/ConfigManager.cpp | 2 -- Source/Core/Core/Src/ConfigManager.h | 4 ---- Source/Core/Core/Src/HW/EXI_Channel.cpp | 6 +----- Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp | 12 ++---------- Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.h | 1 - 5 files changed, 3 insertions(+), 22 deletions(-) diff --git a/Source/Core/Core/Src/ConfigManager.cpp b/Source/Core/Core/Src/ConfigManager.cpp index e70b021a0c..da8337bd04 100644 --- a/Source/Core/Core/Src/ConfigManager.cpp +++ b/Source/Core/Core/Src/ConfigManager.cpp @@ -223,7 +223,6 @@ void SConfig::SaveSettings() ini.Set("Core", "SelectedLanguage", m_LocalCoreStartupParameter.SelectedLanguage); ini.Set("Core", "MemcardA", m_strMemoryCardA); ini.Set("Core", "MemcardB", m_strMemoryCardB); - ini.Set("Core", "ReloadMemcardOnState", b_reloadMCOnState); ini.Set("Core", "SlotA", m_EXIDevice[0]); ini.Set("Core", "SlotB", m_EXIDevice[1]); ini.Set("Core", "SerialPort1", m_EXIDevice[2]); @@ -354,7 +353,6 @@ void SConfig::LoadSettings() ini.Get("Core", "SelectedLanguage", &m_LocalCoreStartupParameter.SelectedLanguage, 0); ini.Get("Core", "MemcardA", &m_strMemoryCardA); ini.Get("Core", "MemcardB", &m_strMemoryCardB); - ini.Get("Core", "ReloadMemcardOnState", &b_reloadMCOnState, true); ini.Get("Core", "SlotA", (int*)&m_EXIDevice[0], EXIDEVICE_MEMORYCARD); ini.Get("Core", "SlotB", (int*)&m_EXIDevice[1], EXIDEVICE_NONE); ini.Get("Core", "SerialPort1", (int*)&m_EXIDevice[2], EXIDEVICE_NONE); diff --git a/Source/Core/Core/Src/ConfigManager.h b/Source/Core/Core/Src/ConfigManager.h index 35ac8269e9..0c8f3f1af1 100644 --- a/Source/Core/Core/Src/ConfigManager.h +++ b/Source/Core/Core/Src/ConfigManager.h @@ -47,10 +47,6 @@ struct SConfig : NonCopyable std::string m_strMemoryCardA; std::string m_strMemoryCardB; - // eject and reload the memory card on state - // in ZTP and other games if the save file has been deleted from the memory card - //this is necessary to save after loading a savestate - bool b_reloadMCOnState; TEXIDevices m_EXIDevice[3]; SIDevices m_SIDevice[4]; std::string m_bba_mac; diff --git a/Source/Core/Core/Src/HW/EXI_Channel.cpp b/Source/Core/Core/Src/HW/EXI_Channel.cpp index c29a6f2bb2..91cb691546 100644 --- a/Source/Core/Core/Src/HW/EXI_Channel.cpp +++ b/Source/Core/Core/Src/HW/EXI_Channel.cpp @@ -284,8 +284,6 @@ void CEXIChannel::DoState(PointerWrap &p) p.Do(m_Control); p.Do(m_ImmData); - bool reloadOnState = SConfig::GetInstance().b_reloadMCOnState; - for (int d = 0; d < NUM_DEVICES; ++d) { IEXIDevice* pDevice = m_pDevices[d]; @@ -299,9 +297,7 @@ void CEXIChannel::DoState(PointerWrap &p) // also, if no movie is active, we'll assume the user wants to keep their current devices // instead of the ones they had when the savestate was created, // unless the device is NONE (since ChangeDevice sets that temporarily). - if(p.GetMode() != PointerWrap::MODE_READ || - (pDevice->m_deviceType != EXIDEVICE_NONE && - reloadOnState && !Movie::IsRecordingInput() && !Movie::IsPlayingInput())) + if(p.GetMode() != PointerWrap::MODE_READ) { delete pSaveDevice; } diff --git a/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp b/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp index 88116e9c7c..e7f052b864 100644 --- a/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp +++ b/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp @@ -52,7 +52,6 @@ CEXIMemoryCard::CEXIMemoryCard(const int index) m_strFilename = (card_index == 0) ? SConfig::GetInstance().m_strMemoryCardA : SConfig::GetInstance().m_strMemoryCardB; // we're potentially leaking events here, since there's no UnregisterEvent until emu shutdown, but I guess it's inconsequential et_this_card = CoreTiming::RegisterEvent((card_index == 0) ? "memcardA" : "memcardB", FlushCallback); - reloadOnState = SConfig::GetInstance().b_reloadMCOnState; interruptSwitch = 0; m_bInterruptSet = 0; @@ -426,14 +425,7 @@ void CEXIMemoryCard::TransferByte(u8 &byte) void CEXIMemoryCard::OnAfterLoad() { - // hack for memory card switching, so you can load an old savestate and expect your newer memcard data to show up. - // it breaks movie sync, so we disable it if a movie is active. - // this was moved out of DoState because other things that got loaded later conflicted with it. - // note: the reloadOnState flag is almost always true. maybe only a few TASers have it off. - if (reloadOnState && !Movie::IsRecordingInput() && !Movie::IsPlayingInput()) - { - ExpansionInterface::ChangeDevice(card_index, EXIDEVICE_MEMORYCARD, 0); - } + } void CEXIMemoryCard::DoState(PointerWrap &p) @@ -441,7 +433,7 @@ void CEXIMemoryCard::DoState(PointerWrap &p) // for movie sync, we need to save/load memory card contents (and other data) in savestates. // otherwise, we'll assume the user wants to keep their memcards and saves separate, // unless we're loading (in which case we let the savestate contents decide, in order to stay aligned with them). - bool storeContents = (!reloadOnState || Movie::IsRecordingInput() || Movie::IsPlayingInput()); + bool storeContents = (Movie::IsRecordingInput() || Movie::IsPlayingInput()); p.Do(storeContents); if (storeContents) diff --git a/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.h b/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.h index ac2cdd69f8..5da8c63183 100644 --- a/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.h +++ b/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.h @@ -71,7 +71,6 @@ private: std::string m_strFilename; int card_index; int et_this_card; - bool reloadOnState; //! memory card state // STATE_TO_SAVE From aa47a8c69053725d2131c48b199eac6a3f8dbc82 Mon Sep 17 00:00:00 2001 From: calc84maniac Date: Tue, 3 Jan 2012 00:37:43 -0500 Subject: [PATCH 15/15] x86 shift of 0 doesn't update flags, check the value manually --- .../Core/Src/PowerPC/Jit64/Jit_Integer.cpp | 26 +++++++------------ 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp index b0be8517c7..0be20dc4e6 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp @@ -1652,10 +1652,6 @@ void Jit64::srwx(UGeckoInstruction inst) { u32 amount = (u32)gpr.R(b).offset; gpr.SetImmediate32(a, (amount & 0x20) ? 0 : ((u32)gpr.R(s).offset >> (amount & 0x1f))); - if (inst.Rc) - { - ComputeRC(gpr.R(a)); - } } else { @@ -1672,13 +1668,14 @@ void Jit64::srwx(UGeckoInstruction inst) XOR(32, gpr.R(a), gpr.R(a)); SetJumpTarget(branch); SHR(32, gpr.R(a), R(ECX)); - if (inst.Rc) - { - GenerateRC(); - } gpr.UnlockAll(); gpr.UnlockAllX(); } + // Shift of 0 doesn't update flags, so compare manually just in case + if (inst.Rc) + { + ComputeRC(gpr.R(a)); + } } void Jit64::slwx(UGeckoInstruction inst) @@ -1693,10 +1690,6 @@ void Jit64::slwx(UGeckoInstruction inst) { u32 amount = (u32)gpr.R(b).offset; gpr.SetImmediate32(a, (amount & 0x20) ? 0 : (u32)gpr.R(s).offset << amount); - if (inst.Rc) - { - ComputeRC(gpr.R(a)); - } } else { @@ -1713,13 +1706,14 @@ void Jit64::slwx(UGeckoInstruction inst) XOR(32, gpr.R(a), gpr.R(a)); SetJumpTarget(branch); SHL(32, gpr.R(a), R(ECX)); - if (inst.Rc) - { - GenerateRC(); - } gpr.UnlockAll(); gpr.UnlockAllX(); } + // Shift of 0 doesn't update flags, so compare manually just in case + if (inst.Rc) + { + ComputeRC(gpr.R(a)); + } } void Jit64::srawx(UGeckoInstruction inst)