Merge branch 'master' into wii-network

This commit is contained in:
Shawn Hoffman
2012-02-27 22:36:41 -08:00
103 changed files with 1527 additions and 824 deletions

View File

@ -19,7 +19,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
====================================================================*/

View File

@ -19,7 +19,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
====================================================================*/

View File

@ -19,7 +19,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
====================================================================*/

View File

@ -19,7 +19,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
====================================================================*/

View File

@ -19,7 +19,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
====================================================================*/

View File

@ -19,7 +19,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
====================================================================*/

View File

@ -19,7 +19,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
====================================================================*/

View File

@ -19,7 +19,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
====================================================================*/

View File

@ -19,7 +19,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
====================================================================*/

View File

@ -19,7 +19,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
====================================================================*/

View File

@ -19,7 +19,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
====================================================================*/

View File

@ -19,7 +19,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
====================================================================*/

View File

@ -18,7 +18,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
====================================================================*/

View File

@ -85,14 +85,14 @@ void LoadBPReg(const BPCmd &bp, BPMemory &bpMem)
void GetTlutLoadData(u32 &tlutAddr, u32 &memAddr, u32 &tlutXferCount, BPMemory &bpMem)
{
tlutAddr = (bpMem.tlutXferDest & 0x3FF) << 9;
tlutXferCount = (bpMem.tlutXferDest & 0x1FFC00) >> 5;
tlutAddr = (bpMem.tmem_config.tlut_dest & 0x3FF) << 9;
tlutXferCount = (bpMem.tmem_config.tlut_dest & 0x1FFC00) >> 5;
// TODO - figure out a cleaner way.
if (Core::g_CoreStartupParameter.bWii)
memAddr = bpmem.tlutXferSrc << 5;
memAddr = bpmem.tmem_config.tlut_src << 5;
else
memAddr = (bpmem.tlutXferSrc & 0xFFFFF) << 5;
memAddr = (bpmem.tmem_config.tlut_src & 0xFFFFF) << 5;
}
void LoadCPReg(u32 subCmd, u32 value, CPMemory &cpMem)

View File

@ -49,6 +49,9 @@ DSPLLE::DSPLLE() {
m_cycle_count = 0;
}
Common::Event dspEvent;
Common::Event ppcEvent;
void DSPLLE::DoState(PointerWrap &p)
{
p.Do(g_dsp.r);
@ -96,7 +99,10 @@ void DSPLLE::dsp_thread(DSPLLE *dsp_lle)
Common::AtomicStore(dsp_lle->m_cycle_count, 0);
}
else
Common::YieldCPU();
{
ppcEvent.Set();
dspEvent.Wait();
}
}
}
@ -138,6 +144,8 @@ void DSPLLE::DSP_StopSoundStream()
m_bIsRunning = false;
if (m_bDSPThread)
{
ppcEvent.Set();
dspEvent.Set();
m_hDSPThread.join();
}
}
@ -274,9 +282,10 @@ void DSPLLE::DSP_Update(int cycles)
else
{
// Wait for dsp thread to complete its cycle. Note: this logic should be thought through.
while (m_cycle_count != 0)
;
ppcEvent.Wait();
Common::AtomicStore(m_cycle_count, dsp_cycles);
dspEvent.Set();
}
}

View File

@ -1126,7 +1126,7 @@ bool GCMemcard::Format(u8 * card_data, bool sjis, u16 SizeMb)
gcp.bat_backup = (BlockAlloc *)(card_data + BLOCK_SIZE*4);
*(u16*)gcp.hdr->SizeMb = BE16(SizeMb);
*(u16*)gcp.hdr->Encoding = BE16(sjis ? 1 : 0);
gcp.hdr->Encoding = BE16(sjis ? 1 : 0);
FormatInternal(gcp);
return true;
@ -1148,7 +1148,7 @@ bool GCMemcard::Format(bool sjis, u16 SizeMb)
gcp.bat_backup = &bat_backup;
*(u16*)hdr.SizeMb = BE16(SizeMb);
*(u16*)hdr.Encoding = BE16(sjis ? 1 : 0);
hdr.Encoding = BE16(sjis ? 1 : 0);
FormatInternal(gcp);
m_sizeMb = SizeMb;

View File

@ -91,7 +91,7 @@ private:
// end Serial in libogc
u8 deviceID[2]; //0x0020 2 0 if formated in slot A 1 if formated in slot B
u8 SizeMb[2]; //0x0022 2 size of memcard in Mbits
u8 Encoding[2]; //0x0024 2 encoding (ASCII or japanese)
u16 Encoding; //0x0024 2 encoding (ASCII or japanese)
u8 Unused1[468]; //0x0026 468 unused (0xff)
u8 UpdateCounter[2];//0x01fa 2 update Counter (?, probably unused)
u16 Checksum; //0x01fc 2 Additive Checksum

View File

@ -129,7 +129,7 @@ int FindWiimotes(Wiimote **wm, int max_wiimotes)
[bti setInquiryLength: 5];
[bti setSearchCriteria: kBluetoothServiceClassMajorAny
majorDeviceClass: kBluetoothDeviceClassMajorPeripheral
minorDeviceClass: kBluetoothDeviceClassMinorPeripheral2Joystick
minorDeviceClass: kBluetoothDeviceClassMinorAny
];
[bti setUpdateNewDeviceNames: NO];
@ -177,6 +177,10 @@ bool Wiimote::Connect()
if (IsConnected())
return false;
if ([btd remoteNameRequest:nil] == kIOReturnSuccess)
m_motion_plus_inside =
static_cast<bool>([[btd getName] hasSuffix:@"-TR"]);
[btd openL2CAPChannelSync: &cchan
withPSM: kBluetoothL2CAPPSMHIDControl delegate: cbt];
[btd openL2CAPChannelSync: &ichan
@ -244,7 +248,7 @@ int Wiimote::IOWrite(unsigned char *buf, int len)
if (!IsConnected())
return 0;
ret = [cchan writeAsync: buf length: len refcon: nil];
ret = [ichan writeAsync: buf length: len refcon: nil];
if (ret == kIOReturnSuccess)
return len;

View File

@ -50,6 +50,7 @@ Wiimote::Wiimote(const unsigned int _index)
#endif
, leds(0), m_last_data_report(Report((u8 *)NULL, 0))
, m_channel(0), m_connected(false)
, m_motion_plus_inside(false)
{
#if defined(__linux__) && HAVE_BLUEZ
bdaddr = (bdaddr_t){{0, 0, 0, 0, 0, 0}};
@ -142,15 +143,16 @@ void Wiimote::InterruptChannel(const u16 channel, const void* const data, const
rpt.second = (u8)size;
memcpy(rpt.first, (u8*)data, size);
// Convert output DATA packets to SET_REPORT packets.
// Nintendo Wiimotes work without this translation, but 3rd
// Convert output DATA packets to SET_REPORT packets for non-TR
// Wiimotes. Nintendo Wiimotes work without this translation, but 3rd
// party ones don't.
u8 head = m_motion_plus_inside ? 0xa2 : 0x52;
if (rpt.first[0] == 0xa2)
{
rpt.first[0] = 0x52;
rpt.first[0] = head;
}
if (rpt.first[0] == 0x52 && rpt.first[1] == 0x18 && rpt.second == 23)
if (rpt.first[0] == head && rpt.first[1] == 0x18 && rpt.second == 23)
{
m_audio_reports.Push(rpt);
return;

View File

@ -95,6 +95,7 @@ private:
void ThreadFunc();
bool m_connected;
bool m_motion_plus_inside;
std::thread m_wiimote_thread;
Common::FifoQueue<Report> m_read_reports;
Common::FifoQueue<Report> m_write_reports;

View File

@ -211,7 +211,9 @@ u32 CWII_IPC_HLE_Device_di::ExecuteCommand(u32 _BufferIn, u32 _BufferInSize, u32
// Don't do anything if the log is unselected
if (LogManager::GetInstance()->IsEnabled(LogTypes::FILEMON))
{
const char *pFilename = m_pFileSystem->GetFileName(DVDAddress);
const char *pFilename = NULL;
if (m_pFileSystem)
pFilename = m_pFileSystem->GetFileName(DVDAddress);
if (pFilename != NULL)
{
INFO_LOG(WII_IPC_DVD, "DVDLowRead: %s (0x%llx) - (DVDAddr: 0x%llx, Size: 0x%x)",
@ -233,7 +235,7 @@ u32 CWII_IPC_HLE_Device_di::ExecuteCommand(u32 _BufferIn, u32 _BufferInSize, u32
if (!VolumeHandler::ReadToPtr(Memory::GetPointer(_BufferOut), DVDAddress, Size))
{
PanicAlertT("Cant read from DVD_Plugin - DVD-Interface: Fatal Error");
PanicAlertT("DVDLowRead - Fatal Error: failed to read from volume");
}
}
break;
@ -325,10 +327,9 @@ u32 CWII_IPC_HLE_Device_di::ExecuteCommand(u32 _BufferIn, u32 _BufferInSize, u32
PanicAlertT("Detected attempt to read more data from the DVD than fit inside the out buffer. Clamp.");
Size = _BufferOutSize;
}
if (!VolumeHandler::RAWReadToPtr(Memory::GetPointer(_BufferOut), DVDAddress, Size))
if(!VolumeHandler::RAWReadToPtr(Memory::GetPointer(_BufferOut), DVDAddress, Size))
{
PanicAlertT("Cant read from DVD_Plugin - DVD-Interface: Fatal Error");
PanicAlertT("DVDLowUnencryptedRead - Fatal Error: failed to read from volume");
}
}
break;
@ -348,7 +349,9 @@ u32 CWII_IPC_HLE_Device_di::ExecuteCommand(u32 _BufferIn, u32 _BufferInSize, u32
case DVDLowSeek:
{
u64 DVDAddress = Memory::Read_U32(_BufferIn + 0x4) << 2;
const char *pFilename = m_pFileSystem->GetFileName(DVDAddress);
const char *pFilename = NULL;
if (m_pFileSystem)
pFilename = m_pFileSystem->GetFileName(DVDAddress);
if (pFilename != NULL)
{
INFO_LOG(WII_IPC_DVD, "DVDLowSeek: %s (0x%llx) - (DVDAddr: 0x%llx)",

View File

@ -120,7 +120,7 @@ bool CWII_IPC_HLE_Device_es::Open(u32 _CommandAddress, u32 _Mode)
{
// blindly grab the titleID from the disc - it's unencrypted at:
// offset 0x0F8001DC and 0x0F80044C
VolumeHandler::RAWReadToPtr((u8*)&m_TitleID, (u64)0x0F8001DC, 8);
VolumeHandler::GetVolume()->GetTitleID((u8*)&m_TitleID);
m_TitleID = Common::swap64(m_TitleID);
}
else
@ -189,11 +189,11 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
const DiscIO::INANDContentLoader& rNANDCOntent = AccessContentDevice(TitleID);
const DiscIO::INANDContentLoader& rNANDContent = AccessContentDevice(TitleID);
u16 NumberOfPrivateContent = 0;
if (rNANDCOntent.IsValid()) // Not sure if dolphin will ever fail this check
if (rNANDContent.IsValid()) // Not sure if dolphin will ever fail this check
{
NumberOfPrivateContent = rNANDCOntent.GetNumEntries();
NumberOfPrivateContent = rNANDContent.GetNumEntries();
if ((u32)(TitleID>>32) == 0x00010000)
Memory::Write_U32(0, Buffer.PayloadBuffer[0].m_Address);
@ -203,10 +203,10 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
Memory::Write_U32(0, _CommandAddress + 0x4);
}
else
Memory::Write_U32((u32)rNANDCOntent.GetContentSize(), _CommandAddress + 0x4);
Memory::Write_U32((u32)rNANDContent.GetContentSize(), _CommandAddress + 0x4);
INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTITLECONTENTSCNT: TitleID: %08x/%08x content count %i",
(u32)(TitleID>>32), (u32)TitleID, rNANDCOntent.IsValid() ? NumberOfPrivateContent : (u32)rNANDCOntent.GetContentSize());
(u32)(TitleID>>32), (u32)TitleID, rNANDContent.IsValid() ? NumberOfPrivateContent : (u32)rNANDContent.GetContentSize());
return true;
}
@ -266,24 +266,27 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
}
break;
case IOCTL_ES_OPENCONTENT:
{
_dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 1);
_dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 0);
case IOCTL_ES_OPENCONTENT:
{
_dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 1);
_dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 0);
u32 CFD = AccessIdentID++;
u32 Index = Memory::Read_U32(Buffer.InBuffer[0].m_Address);
u32 CFD = AccessIdentID++;
u32 Index = Memory::Read_U32(Buffer.InBuffer[0].m_Address);
m_ContentAccessMap[CFD].m_Position = 0;
m_ContentAccessMap[CFD].m_pContent = AccessContentDevice(m_TitleID).GetContentByIndex(Index);
_dbg_assert_(WII_IPC_ES, m_ContentAccessMap[CFD].m_pContent != NULL);
m_ContentAccessMap[CFD].m_Position = 0;
m_ContentAccessMap[CFD].m_pContent = AccessContentDevice(m_TitleID).GetContentByIndex(Index);
_dbg_assert_(WII_IPC_ES, m_ContentAccessMap[CFD].m_pContent != NULL);
Memory::Write_U32(CFD, _CommandAddress + 0x4);
if (m_ContentAccessMap[CFD].m_pContent == NULL)
CFD = 0xffffffff; //TODO: what is the correct error value here?
INFO_LOG(WII_IPC_ES, "IOCTL_ES_OPENCONTENT: Index %i -> got CFD %x", Index, CFD);
return true;
}
break;
Memory::Write_U32(CFD, _CommandAddress + 0x4);
INFO_LOG(WII_IPC_ES, "IOCTL_ES_OPENCONTENT: Index %i -> got CFD %x", Index, CFD);
return true;
}
break;
case IOCTL_ES_READCONTENT:
{
@ -383,7 +386,7 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
char* Path = (char*)Memory::GetPointer(Buffer.PayloadBuffer[0].m_Address);
sprintf(Path, "/%08x/%08x/data", (u32)(TitleID >> 32), (u32)TitleID);
sprintf(Path, "/title/%08x/%08x/data", (u32)(TitleID >> 32), (u32)TitleID);
INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTITLEDIR: %s", Path);
}
@ -551,11 +554,6 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
const DiscIO::INANDContentLoader& Loader = AccessContentDevice(TitleID);
// Assert if title is not a disc title and the loader is not valid
_dbg_assert_msg_(WII_IPC_ES, ((u32)(TitleID >> 32) == 0x00010000) ||
((u32)(TitleID >> 32) == 0x00010004) || Loader.IsValid(),
"Loader not valid for TitleID %08x/%08x", (u32)(TitleID >> 32), (u32)TitleID);
u32 TMDViewCnt = 0;
if (Loader.IsValid())
{
@ -687,7 +685,7 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
// TODO: actually use this param in when writing to the outbuffer :/
MaxCount = Memory::Read_U32(Buffer.InBuffer[1].m_Address);
}
const DiscIO::INANDContentLoader& Loader = DiscIO::CNANDContentManager::Access().GetNANDLoader(TitleID);
const DiscIO::INANDContentLoader& Loader = AccessContentDevice(TitleID);
INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETSTOREDTMD: title: %08x/%08x buffersize: %i", (u32)(TitleID >> 32), (u32)TitleID, MaxCount);
@ -1003,7 +1001,7 @@ const DiscIO::INANDContentLoader& CWII_IPC_HLE_Device_es::AccessContentDevice(u6
m_NANDContent[_TitleID] = &DiscIO::CNANDContentManager::Access().GetNANDLoader(_TitleID);
_dbg_assert_msg_(WII_IPC_ES, m_NANDContent[_TitleID]->IsValid(), "NandContent not valid for TitleID %08x/%08x", (u32)(_TitleID >> 32), (u32)_TitleID);
_dbg_assert_msg_(WII_IPC_ES, ((u32)(_TitleID >> 32) == 0x00010000) || m_NANDContent[_TitleID]->IsValid(), "NandContent not valid for TitleID %08x/%08x", (u32)(_TitleID >> 32), (u32)_TitleID);
return *m_NANDContent[_TitleID];
}
@ -1025,11 +1023,10 @@ u32 CWII_IPC_HLE_Device_es::ES_DIVerify(u8* _pTMD, u32 _sz)
{
return -1;
}
std::string tmdPath = Common::GetTMDFileName(tmdTitleID),
dataPath = Common::GetTitleDataPath(tmdTitleID);
std::string tmdPath = Common::GetTMDFileName(tmdTitleID);
File::CreateFullPath(tmdPath);
File::CreateFullPath(dataPath);
File::CreateFullPath(Common::GetTitleDataPath(tmdTitleID));
if(!File::Exists(tmdPath))
{
File::IOFile _pTMDFile(tmdPath, "wb");

View File

@ -401,7 +401,7 @@ void Interpreter::dcbtst(UGeckoInstruction _inst)
void Interpreter::dcbz(UGeckoInstruction _inst)
{
// HACK but works... we think
if (!HID0.DCFA)
if (HID2.WPE || !HID0.DCFA)
Memory::Memset(Helper_Get_EA_X(_inst) & (~31), 0, 32);
}

View File

@ -150,6 +150,8 @@ public:
void GenerateConstantOverflow(bool overflow);
void GenerateOverflow();
void FinalizeCarryOverflow(bool oe, bool inv = false);
void GetCarryEAXAndClear();
void FinalizeCarryGenerateOverflowEAX(bool oe, bool inv = false);
void GenerateCarry();
void GenerateRC();
void ComputeRC(const Gen::OpArg & arg);
@ -177,6 +179,7 @@ public:
void mulhwux(UGeckoInstruction inst);
void mullwx(UGeckoInstruction inst);
void divwux(UGeckoInstruction inst);
void divwx(UGeckoInstruction inst);
void srawix(UGeckoInstruction inst);
void srawx(UGeckoInstruction inst);
void addex(UGeckoInstruction inst);

View File

@ -311,8 +311,8 @@ static GekkoOPTemplate table31_2[] =
{138, &Jit64::addex}, //"addex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
{234, &Jit64::addmex}, //"addmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
{202, &Jit64::addzex}, //"addzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
{491, &Jit64::Default}, //"divwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}},
{1003, &Jit64::Default}, //"divwox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}},
{491, &Jit64::divwx}, //"divwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}},
{1003, &Jit64::divwx}, //"divwox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}},
{459, &Jit64::divwux}, //"divwux", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}},
{971, &Jit64::divwux}, //"divwuox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}},
{75, &Jit64::Default}, //"mulhwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}},

View File

@ -73,13 +73,53 @@ void Jit64::FinalizeCarryOverflow(bool oe, bool inv)
}
else
{
// Output carry is inverted
// Do carry
FixupBranch carry1 = J_CC(inv ? CC_C : CC_NC);
JitSetCA();
SetJumpTarget(carry1);
}
}
void Jit64::GetCarryEAXAndClear()
{
MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER]));
BTR(32, R(EAX), Imm8(29));
}
// Assumes that XER is in EAX and that the CA bit is clear.
void Jit64::FinalizeCarryGenerateOverflowEAX(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);
OR(32, R(EAX), Imm32(XER_CA_MASK));
SetJumpTarget(carry1);
//XER[OV/SO] = 1
OR(32, R(EAX), Imm32(XER_SO_MASK | XER_OV_MASK));
FixupBranch exit = J();
SetJumpTarget(jno);
// Do carry
FixupBranch carry2 = J_CC(inv ? CC_C : CC_NC);
OR(32, R(EAX), Imm32(XER_CA_MASK));
SetJumpTarget(carry2);
//XER[OV] = 0
AND(32, R(EAX), Imm32(~XER_OV_MASK));
SetJumpTarget(exit);
}
else
{
// Do carry
FixupBranch carry1 = J_CC(inv ? CC_C : CC_NC);
OR(32, R(EAX), Imm32(XER_CA_MASK));
SetJumpTarget(carry1);
}
// Dump EAX back into XER
MOV(32, M(&PowerPC::ppcState.spr[SPR_XER]), R(EAX));
}
// Assumes that the flags were just set through an addition.
void Jit64::GenerateCarry() {
// USES_XER
@ -122,7 +162,10 @@ void Jit64::ComputeRC(const Gen::OpArg & arg) {
}
else
{
CMP(32, arg, Imm8(0));
if (arg.IsSimpleReg())
TEST(32, arg, arg);
else
CMP(32, arg, Imm8(0));
FixupBranch pLesser = J_CC(CC_L);
FixupBranch pGreater = J_CC(CC_G);
MOV(8, M(&PowerPC::ppcState.cr_fast[0]), Imm8(0x2)); // _x86Reg == 0
@ -908,33 +951,31 @@ void Jit64::subfex(UGeckoInstruction inst)
gpr.Lock(a, b, d);
gpr.BindToRegister(d, (d == a || d == b), true);
// Get CA and clear it (along with OV if applicable)
MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER]));
JitClearCAOV(inst.OE);
SHR(32, R(EAX), Imm8(30));
// Convert carry to borrow
CMC();
GetCarryEAXAndClear();
bool invertedCarry = false;
if (d == b)
{
// Convert carry to borrow
CMC();
SBB(32, gpr.R(d), gpr.R(a));
invertedCarry = true;
}
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));
NOT(32, gpr.R(d));
ADC(32, gpr.R(d), gpr.R(b));
}
else
{
MOV(32, gpr.R(d), gpr.R(b));
SBB(32, gpr.R(d), gpr.R(a));
MOV(32, gpr.R(d), gpr.R(a));
NOT(32, gpr.R(d));
ADC(32, gpr.R(d), gpr.R(b));
}
if (inst.Rc) {
GenerateRC();
}
FinalizeCarryOverflow(inst.OE, true);
FinalizeCarryGenerateOverflowEAX(inst.OE, invertedCarry);
gpr.UnlockAll();
}
@ -948,9 +989,7 @@ void Jit64::subfmex(UGeckoInstruction inst)
gpr.Lock(a, d);
gpr.BindToRegister(d, d == a);
MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER]));
JitClearCAOV(inst.OE);
SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag
GetCarryEAXAndClear();
if (d != a)
{
MOV(32, gpr.R(d), gpr.R(a));
@ -961,7 +1000,7 @@ void Jit64::subfmex(UGeckoInstruction inst)
{
GenerateRC();
}
FinalizeCarryOverflow(inst.OE);
FinalizeCarryGenerateOverflowEAX(inst.OE);
gpr.UnlockAll();
}
@ -974,9 +1013,8 @@ void Jit64::subfzex(UGeckoInstruction inst)
gpr.Lock(a, d);
gpr.BindToRegister(d, d == a);
MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER]));
JitClearCAOV(inst.OE);
SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag
GetCarryEAXAndClear();
if (d != a)
{
MOV(32, gpr.R(d), gpr.R(a));
@ -987,7 +1025,7 @@ void Jit64::subfzex(UGeckoInstruction inst)
{
GenerateRC();
}
FinalizeCarryOverflow(inst.OE);
FinalizeCarryGenerateOverflowEAX(inst.OE);
gpr.UnlockAll();
}
@ -1047,17 +1085,39 @@ void Jit64::mulli(UGeckoInstruction inst)
INSTRUCTION_START
JITDISABLE(Integer)
int a = inst.RA, d = inst.RD;
u32 imm = inst.SIMM_16;
if (gpr.R(a).IsImm())
{
gpr.SetImmediate32(d, (s32)gpr.R(a).offset * (s32)inst.SIMM_16);
gpr.SetImmediate32(d, (u32)gpr.R(a).offset * imm);
}
else
{
gpr.Lock(a, d);
gpr.BindToRegister(d, (d == a), true);
gpr.KillImmediate(a, true, false);
IMUL(32, gpr.RX(d), gpr.R(a), Imm32((u32)(s32)inst.SIMM_16));
if (imm == 0)
XOR(32, gpr.R(d), gpr.R(d));
else if(imm == -1)
{
if (d != a)
MOV(32, gpr.R(d), gpr.R(a));
NEG(32, gpr.R(d));
}
else if((imm & (imm - 1)) == 0)
{
u32 shift = 0;
if (imm & 0xFFFF0000) shift |= 16;
if (imm & 0xFF00FF00) shift |= 8;
if (imm & 0xF0F0F0F0) shift |= 4;
if (imm & 0xCCCCCCCC) shift |= 2;
if (imm & 0xAAAAAAAA) shift |= 1;
if (d != a)
MOV(32, gpr.R(d), gpr.R(a));
if (shift)
SHL(32, gpr.R(d), Imm8(shift));
}
else
IMUL(32, gpr.RX(d), gpr.R(a), Imm32(imm));
gpr.UnlockAll();
}
}
@ -1081,13 +1141,42 @@ void Jit64::mullwx(UGeckoInstruction inst)
{
gpr.Lock(a, b, d);
gpr.BindToRegister(d, (d == a || d == b), true);
if (d == a) {
if (gpr.R(a).IsImm() || gpr.R(b).IsImm())
{
u32 imm = gpr.R(a).IsImm() ? (u32)gpr.R(a).offset : (u32)gpr.R(b).offset;
int src = gpr.R(a).IsImm() ? b : a;
if (imm == 0)
XOR(32, gpr.R(d), gpr.R(d));
else if(imm == -1)
{
if (d != src)
MOV(32, gpr.R(d), gpr.R(src));
NEG(32, gpr.R(d));
}
else if((imm & (imm - 1)) == 0 && !inst.OE)
{
u32 shift = 0;
if (imm & 0xFFFF0000) shift |= 16;
if (imm & 0xFF00FF00) shift |= 8;
if (imm & 0xF0F0F0F0) shift |= 4;
if (imm & 0xCCCCCCCC) shift |= 2;
if (imm & 0xAAAAAAAA) shift |= 1;
if (d != src)
MOV(32, gpr.R(d), gpr.R(src));
if (shift)
SHL(32, gpr.R(d), Imm8(shift));
}
else
IMUL(32, gpr.RX(d), gpr.R(src), Imm32(imm));
}
else if (d == a)
IMUL(32, gpr.RX(d), gpr.R(b));
} else if (d == b) {
IMUL(32, gpr.RX(d), gpr.R(a));
} else {
MOV(32, gpr.R(d), gpr.R(b));
else if (d == b)
IMUL(32, gpr.RX(d), gpr.R(a));
else
{
MOV(32, gpr.R(d), gpr.R(b));
IMUL(32, gpr.RX(d), gpr.R(a));
}
if (inst.OE)
{
@ -1157,6 +1246,103 @@ void Jit64::divwux(UGeckoInstruction inst)
}
}
}
else if (gpr.R(b).IsImm())
{
u32 divisor = (u32)gpr.R(b).offset;
if (divisor == 0)
{
gpr.SetImmediate32(d, 0);
if (inst.OE)
{
GenerateConstantOverflow(true);
}
}
else
{
u32 shift = 31;
while(!(divisor & (1 << shift)))
shift--;
if (divisor == (1 << shift))
{
gpr.Lock(a, b, d);
gpr.BindToRegister(d, d == a, true);
if (d != a)
MOV(32, gpr.R(d), gpr.R(a));
if (shift)
SHR(32, gpr.R(d), Imm8(shift));
}
else
{
u64 magic_dividend = 0x100000000ULL << shift;
u32 magic = (u32)(magic_dividend / divisor);
u32 max_quotient = magic >> shift;
// Test for failure in round-up method
if (((u64)(magic+1) * (max_quotient*divisor-1)) >> (shift + 32) != max_quotient-1)
{
// If failed, use slower round-down method
#ifdef _M_X64
gpr.Lock(a, b, d);
gpr.BindToRegister(d, d == a, true);
MOV(32, R(EAX), Imm32(magic));
if (d != a)
MOV(32, gpr.R(d), gpr.R(a));
IMUL(64, gpr.RX(d), R(RAX));
ADD(64, gpr.R(d), R(RAX));
SHR(64, gpr.R(d), Imm8(shift+32));
#else
gpr.FlushLockX(EDX);
gpr.Lock(a, b, d);
gpr.BindToRegister(d, d == a, true);
MOV(32, R(EAX), Imm32(magic));
MUL(32, gpr.R(a));
XOR(32, gpr.R(d), gpr.R(d));
ADD(32, R(EAX), Imm32(magic));
ADC(32, gpr.R(d), R(EDX));
if (shift)
SHR(32, gpr.R(d), Imm8(shift));
gpr.UnlockAllX();
#endif
}
else
{
// If success, use faster round-up method
#ifdef _M_X64
gpr.Lock(a, b, d);
gpr.BindToRegister(a, true, false);
gpr.BindToRegister(d, false, true);
if (d == a)
{
MOV(32, R(EAX), Imm32(magic+1));
IMUL(64, gpr.RX(d), R(RAX));
}
else
{
MOV(32, gpr.R(d), Imm32(magic+1));
IMUL(64, gpr.RX(d), gpr.R(a));
}
SHR(64, gpr.R(d), Imm8(shift+32));
#else
gpr.FlushLockX(EDX);
gpr.Lock(a, b, d);
gpr.BindToRegister(d, d == a, true);
MOV(32, R(EAX), Imm32(magic+1));
MUL(32, gpr.R(a));
MOV(32, gpr.R(d), R(EDX));
if (shift)
SHR(32, gpr.R(d), Imm8(shift));
gpr.UnlockAllX();
#endif
}
}
if (inst.OE)
{
GenerateConstantOverflow(false);
}
gpr.UnlockAll();
}
}
else
{
gpr.FlushLockX(EDX);
@ -1166,7 +1352,6 @@ void Jit64::divwux(UGeckoInstruction inst)
XOR(32, R(EDX), R(EDX));
gpr.KillImmediate(b, true, false);
CMP(32, gpr.R(b), Imm32(0));
// 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));
if (inst.OE)
@ -1193,6 +1378,80 @@ void Jit64::divwux(UGeckoInstruction inst)
}
}
void Jit64::divwx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
int a = inst.RA, b = inst.RB, d = inst.RD;
if (gpr.R(a).IsImm() && gpr.R(b).IsImm())
{
s32 i = (s32)gpr.R(a).offset, j = (s32)gpr.R(b).offset;
if( j == 0 || i == 0x80000000 && j == -1)
{
gpr.SetImmediate32(d, (i >> 31) ^ j);
if (inst.OE)
{
GenerateConstantOverflow(true);
}
}
else
{
gpr.SetImmediate32(d, i / j);
if (inst.OE)
{
GenerateConstantOverflow(false);
}
}
}
else
{
gpr.FlushLockX(EDX);
gpr.Lock(a, b, d);
gpr.BindToRegister(d, (d == a || d == b), true);
MOV(32, R(EAX), gpr.R(a));
CDQ();
gpr.BindToRegister(b, true, false);
TEST(32, gpr.R(b), gpr.R(b));
FixupBranch not_div_by_zero = J_CC(CC_NZ);
MOV(32, gpr.R(d), R(EDX));
if (inst.OE)
{
GenerateConstantOverflow(true);
}
FixupBranch end1 = J();
SetJumpTarget(not_div_by_zero);
CMP(32, gpr.R(b), R(EDX));
FixupBranch not_div_by_neg_one = J_CC(CC_NZ);
MOV(32, gpr.R(d), R(EAX));
NEG(32, gpr.R(d));
FixupBranch no_overflow = J_CC(CC_NO);
XOR(32, gpr.R(d), gpr.R(d));
if (inst.OE)
{
GenerateConstantOverflow(true);
}
FixupBranch end2 = J();
SetJumpTarget(not_div_by_neg_one);
IDIV(32, gpr.R(b));
MOV(32, gpr.R(d), R(EAX));
SetJumpTarget(no_overflow);
if (inst.OE)
{
GenerateConstantOverflow(false);
}
SetJumpTarget(end1);
SetJumpTarget(end2);
gpr.UnlockAll();
gpr.UnlockAllX();
}
if (inst.Rc)
{
ComputeRC(gpr.R(d));
}
}
void Jit64::addx(UGeckoInstruction inst)
{
INSTRUCTION_START
@ -1264,31 +1523,29 @@ void Jit64::addex(UGeckoInstruction inst)
{
gpr.Lock(a, b, d);
gpr.BindToRegister(d, true);
MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER]));
JitClearCAOV(inst.OE);
SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag
GetCarryEAXAndClear();
ADC(32, gpr.R(d), gpr.R((d == a) ? b : a));
if (inst.Rc)
{
GenerateRC();
}
FinalizeCarryOverflow(inst.OE);
FinalizeCarryGenerateOverflowEAX(inst.OE);
gpr.UnlockAll();
}
else
{
gpr.Lock(a, b, d);
gpr.BindToRegister(d, false);
MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER]));
JitClearCAOV(inst.OE);
SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag
GetCarryEAXAndClear();
MOV(32, gpr.R(d), gpr.R(a));
ADC(32, gpr.R(d), gpr.R(b));
if (inst.Rc)
{
GenerateRC();
}
FinalizeCarryOverflow(inst.OE);
FinalizeCarryGenerateOverflowEAX(inst.OE);
gpr.UnlockAll();
}
}
@ -1340,31 +1597,29 @@ void Jit64::addmex(UGeckoInstruction inst)
{
gpr.Lock(d);
gpr.BindToRegister(d, true);
MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER]));
JitClearCAOV(inst.OE);
SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag
GetCarryEAXAndClear();
ADC(32, gpr.R(d), Imm32(0xFFFFFFFF));
if (inst.Rc)
{
GenerateRC();
}
FinalizeCarryOverflow(inst.OE);
FinalizeCarryGenerateOverflowEAX(inst.OE);
gpr.UnlockAll();
}
else
{
gpr.Lock(a, d);
gpr.BindToRegister(d, false);
MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER]));
JitClearCAOV(inst.OE);
SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag
GetCarryEAXAndClear();
MOV(32, gpr.R(d), gpr.R(a));
ADC(32, gpr.R(d), Imm32(0xFFFFFFFF));
if (inst.Rc)
{
GenerateRC();
}
FinalizeCarryOverflow(inst.OE);
FinalizeCarryGenerateOverflowEAX(inst.OE);
gpr.UnlockAll();
}
}
@ -1380,31 +1635,29 @@ void Jit64::addzex(UGeckoInstruction inst)
{
gpr.Lock(d);
gpr.BindToRegister(d, true);
MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER]));
JitClearCAOV(inst.OE);
SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag
GetCarryEAXAndClear();
ADC(32, gpr.R(d), Imm8(0));
if (inst.Rc)
{
GenerateRC();
}
FinalizeCarryOverflow(inst.OE);
FinalizeCarryGenerateOverflowEAX(inst.OE);
gpr.UnlockAll();
}
else
{
gpr.Lock(a, d);
gpr.BindToRegister(d, false);
MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER]));
JitClearCAOV(inst.OE);
SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag
GetCarryEAXAndClear();
MOV(32, gpr.R(d), gpr.R(a));
ADC(32, gpr.R(d), Imm8(0));
if (inst.Rc)
{
GenerateRC();
}
FinalizeCarryOverflow(inst.OE);
FinalizeCarryGenerateOverflowEAX(inst.OE);
gpr.UnlockAll();
}
}
@ -1581,7 +1834,7 @@ void Jit64::rlwnmx(UGeckoInstruction inst)
{
gpr.FlushLockX(ECX);
gpr.Lock(a, b, s);
gpr.BindToRegister(a, true, true);
gpr.BindToRegister(a, (a == b || a == s), true);
MOV(32, R(ECX), gpr.R(b));
if (a != s)
{
@ -1651,9 +1904,22 @@ void Jit64::srwx(UGeckoInstruction inst)
}
else
{
#ifdef _M_X64
gpr.FlushLockX(ECX);
gpr.Lock(a, b, s);
gpr.BindToRegister(a, true, true);
gpr.BindToRegister(a, (a == b || a == s), true);
MOV(32, R(ECX), gpr.R(b));
if (a != s)
{
MOV(32, gpr.R(a), gpr.R(s));
}
SHR(64, gpr.R(a), R(ECX));
gpr.UnlockAll();
gpr.UnlockAllX();
#else
gpr.FlushLockX(ECX);
gpr.Lock(a, b, s);
gpr.BindToRegister(a, (a == b || a == s), true);
MOV(32, R(ECX), gpr.R(b));
TEST(32, R(ECX), Imm32(32));
if (a != s)
@ -1666,6 +1932,7 @@ void Jit64::srwx(UGeckoInstruction inst)
SHR(32, gpr.R(a), R(ECX));
gpr.UnlockAll();
gpr.UnlockAllX();
#endif
}
// Shift of 0 doesn't update flags, so compare manually just in case
if (inst.Rc)
@ -1686,12 +1953,38 @@ 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
{
#ifdef _M_X64
gpr.FlushLockX(ECX);
gpr.Lock(a, b, s);
gpr.BindToRegister(a, true, true);
gpr.BindToRegister(a, (a == b || a == s), true);
MOV(32, R(ECX), gpr.R(b));
if (a != s)
{
MOV(32, gpr.R(a), gpr.R(s));
}
SHL(64, gpr.R(a), R(ECX));
if (inst.Rc)
{
AND(32, gpr.R(a), gpr.R(a));
GenerateRC();
}
else
{
MOV(32, gpr.R(a), gpr.R(a));
}
gpr.UnlockAll();
gpr.UnlockAllX();
#else
gpr.FlushLockX(ECX);
gpr.Lock(a, b, s);
gpr.BindToRegister(a, (a == b || a == s), true);
MOV(32, R(ECX), gpr.R(b));
TEST(32, R(ECX), Imm32(32));
if (a != s)
@ -1704,11 +1997,12 @@ void Jit64::slwx(UGeckoInstruction inst)
SHL(32, gpr.R(a), R(ECX));
gpr.UnlockAll();
gpr.UnlockAllX();
}
// Shift of 0 doesn't update flags, so compare manually just in case
if (inst.Rc)
{
ComputeRC(gpr.R(a));
// Shift of 0 doesn't update flags, so compare manually just in case
if (inst.Rc)
{
ComputeRC(gpr.R(a));
}
#endif
}
}
@ -1720,19 +2014,37 @@ void Jit64::srawx(UGeckoInstruction inst)
int a = inst.RA;
int b = inst.RB;
int s = inst.RS;
#ifdef _M_X64
gpr.Lock(a, s, b);
gpr.FlushLockX(ECX);
gpr.BindToRegister(a, true, true);
gpr.BindToRegister(a, (a == s || a == b), true);
JitClearCA();
MOV(32, R(ECX), gpr.R(b));
if (a != s)
MOV(32, gpr.R(a), gpr.R(s));
SHL(64, gpr.R(a), Imm8(32));
SAR(64, gpr.R(a), R(ECX));
MOV(32, R(EAX), gpr.R(a));
SHR(64, gpr.R(a), Imm8(32));
TEST(32, gpr.R(a), R(EAX));
FixupBranch nocarry = J_CC(CC_Z);
JitSetCA();
SetJumpTarget(nocarry);
gpr.UnlockAll();
gpr.UnlockAllX();
#else
gpr.Lock(a, s, b);
gpr.FlushLockX(ECX);
gpr.BindToRegister(a, (a == s || a == b), true);
JitClearCA();
MOV(32, R(ECX), gpr.R(b));
if (a != s)
MOV(32, gpr.R(a), gpr.R(s));
TEST(32, R(ECX), Imm32(32));
FixupBranch topBitSet = J_CC(CC_NZ);
LEA(32, EAX, MComplex(gpr.RX(a), gpr.RX(a), 1, 0));
XOR(32, R(EAX), R(EAX));
SHRD(32, R(EAX), gpr.R(a), R(ECX));
SAR(32, gpr.R(a), R(ECX));
NOT(32, R(ECX));
SHL(32, R(EAX), R(ECX));
TEST(32, R(EAX), gpr.R(a));
FixupBranch nocarry1 = J_CC(CC_Z);
JitSetCA();
@ -1746,7 +2058,7 @@ void Jit64::srawx(UGeckoInstruction inst)
SetJumpTarget(nocarry2);
gpr.UnlockAll();
gpr.UnlockAllX();
#endif
if (inst.Rc) {
ComputeRC(gpr.R(a));
}