Merge branch 'master' into wxw3-update
Conflicts: Source/Core/DolphinWX/Src/LogWindow.cpp
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
#include "Common.h"
|
||||
#include "DebugInterface.h"
|
||||
#include "BreakPoints.h"
|
||||
#include "../../Core/Src/PowerPC/JitCommon/JitBase.h"
|
||||
#include <sstream>
|
||||
|
||||
bool BreakPoints::IsAddressBreakPoint(u32 _iAddress)
|
||||
@@ -70,7 +71,11 @@ void BreakPoints::AddFromStrings(const TBreakPointsStr& bps)
|
||||
void BreakPoints::Add(const TBreakPoint& bp)
|
||||
{
|
||||
if (!IsAddressBreakPoint(bp.iAddress))
|
||||
{
|
||||
m_BreakPoints.push_back(bp);
|
||||
if (jit)
|
||||
jit->GetBlockCache()->InvalidateICache(bp.iAddress, 4);
|
||||
}
|
||||
}
|
||||
|
||||
void BreakPoints::Add(u32 em_address, bool temp)
|
||||
@@ -83,21 +88,35 @@ void BreakPoints::Add(u32 em_address, bool temp)
|
||||
pt.iAddress = em_address;
|
||||
|
||||
m_BreakPoints.push_back(pt);
|
||||
|
||||
if (jit)
|
||||
jit->GetBlockCache()->InvalidateICache(em_address, 4);
|
||||
}
|
||||
}
|
||||
|
||||
void BreakPoints::Remove(u32 _iAddress)
|
||||
void BreakPoints::Remove(u32 em_address)
|
||||
{
|
||||
for (TBreakPoints::iterator i = m_BreakPoints.begin(); i != m_BreakPoints.end(); ++i)
|
||||
{
|
||||
if (i->iAddress == _iAddress)
|
||||
if (i->iAddress == em_address)
|
||||
{
|
||||
m_BreakPoints.erase(i);
|
||||
if (jit)
|
||||
jit->GetBlockCache()->InvalidateICache(em_address, 4);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BreakPoints::Clear()
|
||||
{
|
||||
for (TBreakPoints::iterator i = m_BreakPoints.begin(); i != m_BreakPoints.end(); ++i)
|
||||
{
|
||||
if (jit)
|
||||
jit->GetBlockCache()->InvalidateICache(i->iAddress, 4);
|
||||
m_BreakPoints.erase(i);
|
||||
}
|
||||
}
|
||||
|
||||
MemChecks::TMemChecksStr MemChecks::GetStrings() const
|
||||
{
|
||||
|
||||
@@ -78,7 +78,7 @@ public:
|
||||
|
||||
// Remove Breakpoint
|
||||
void Remove(u32 _iAddress);
|
||||
void Clear() { m_BreakPoints.clear(); };
|
||||
void Clear();
|
||||
|
||||
void DeleteByAddress(u32 _Address);
|
||||
|
||||
|
||||
@@ -119,6 +119,7 @@ public:
|
||||
virtual void Video_GatherPipeBursted() = 0;
|
||||
|
||||
virtual bool Video_IsPossibleWaitingSetDrawDone() = 0;
|
||||
virtual bool Video_IsHiWatermarkActive() = 0;
|
||||
virtual void Video_AbortFrame() = 0;
|
||||
|
||||
virtual readFn16 Video_CPRead16() = 0;
|
||||
@@ -159,6 +160,7 @@ class VideoBackendHardware : public VideoBackend
|
||||
void Video_GatherPipeBursted();
|
||||
|
||||
bool Video_IsPossibleWaitingSetDrawDone();
|
||||
bool Video_IsHiWatermarkActive();
|
||||
void Video_AbortFrame();
|
||||
|
||||
readFn16 Video_CPRead16();
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
#include "ChunkFile.h"
|
||||
#include "ProcessorInterface.h"
|
||||
#include "Memmap.h"
|
||||
#include "../PowerPC/PowerPC.h"
|
||||
|
||||
#include "VideoBackendBase.h"
|
||||
#include "../PowerPC/JitCommon/JitBase.h"
|
||||
#include "../PowerPC/PowerPC.h"
|
||||
|
||||
#include "GPFifo.h"
|
||||
|
||||
@@ -96,6 +96,15 @@ void STACKALIGN CheckGatherPipe()
|
||||
|
||||
// move back the spill bytes
|
||||
memmove(m_gatherPipe, m_gatherPipe + cnt, m_gatherPipeCount);
|
||||
|
||||
// Profile where the FIFO writes are occurring.
|
||||
if (jit && (jit->js.fifoWriteAddresses.find(PC)) == (jit->js.fifoWriteAddresses.end()))
|
||||
{
|
||||
jit->js.fifoWriteAddresses.insert(PC);
|
||||
|
||||
// Invalidate the JIT block so that it gets recompiled with the external exception check included.
|
||||
jit->GetBlockCache()->InvalidateICache(PC, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -68,8 +68,13 @@ TDeviceMap g_DeviceMap;
|
||||
|
||||
// STATE_TO_SAVE
|
||||
typedef std::map<u32, std::string> TFileNameMap;
|
||||
TFileNameMap g_FileNameMap;
|
||||
u32 g_LastDeviceID;
|
||||
|
||||
#define IPC_MAX_FDS 0x18
|
||||
#define ES_MAX_COUNT 2
|
||||
IWII_IPC_HLE_Device* g_FdMap[IPC_MAX_FDS];
|
||||
bool es_inuse[ES_MAX_COUNT];
|
||||
IWII_IPC_HLE_Device* es_handles[ES_MAX_COUNT];
|
||||
|
||||
|
||||
typedef std::deque<u32> ipc_msg_queue;
|
||||
static ipc_msg_queue request_queue; // ppc -> arm
|
||||
@@ -78,14 +83,28 @@ static ipc_msg_queue reply_queue; // arm -> ppc
|
||||
void Init()
|
||||
{
|
||||
_dbg_assert_msg_(WII_IPC_HLE, g_DeviceMap.empty(), "DeviceMap isnt empty on init");
|
||||
|
||||
u32 i;
|
||||
for (i=0; i<IPC_MAX_FDS; i++)
|
||||
{
|
||||
g_FdMap[i] = NULL;
|
||||
}
|
||||
|
||||
u32 i = IPC_FIRST_HARDWARE_ID;
|
||||
i = 0;
|
||||
// Build hardware devices
|
||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_usb_oh1_57e_305(i, std::string("/dev/usb/oh1/57e/305")); i++;
|
||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_stm_immediate(i, std::string("/dev/stm/immediate")); i++;
|
||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_stm_eventhook(i, std::string("/dev/stm/eventhook")); i++;
|
||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_fs(i, std::string("/dev/fs")); i++;
|
||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_es(i, std::string("/dev/es")); i++;
|
||||
|
||||
// IOS allows two ES devices at a time<
|
||||
u32 j;
|
||||
for (j=0; j<ES_MAX_COUNT; j++)
|
||||
{
|
||||
g_DeviceMap[i] = es_handles[j] = new CWII_IPC_HLE_Device_es(i, std::string("/dev/es")); i++;
|
||||
es_inuse[j] = false;
|
||||
}
|
||||
|
||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_di(i, std::string("/dev/di")); i++;
|
||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_kd_request(i, std::string("/dev/net/kd/request")); i++;
|
||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_kd_time(i, std::string("/dev/net/kd/time")); i++;
|
||||
@@ -96,13 +115,24 @@ void Init()
|
||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, std::string("/dev/sdio/slot1")); i++;
|
||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, std::string("/dev/usb/hid")); i++;
|
||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, std::string("/dev/usb/oh1")); i++;
|
||||
g_DeviceMap[i] = new IWII_IPC_HLE_Device(i, std::string("_Unimplemented_Device_"));
|
||||
|
||||
g_LastDeviceID = IPC_FIRST_FILEIO_ID;
|
||||
g_DeviceMap[i] = new IWII_IPC_HLE_Device(i, std::string("_Unimplemented_Device_")); i++;
|
||||
}
|
||||
|
||||
void Reset(bool _bHard)
|
||||
{
|
||||
|
||||
u32 i;
|
||||
for (i=0; i<IPC_MAX_FDS; i++)
|
||||
{
|
||||
if (g_FdMap[i] != NULL && !g_FdMap[i]->IsHardware())
|
||||
{
|
||||
// close all files and delete their resources
|
||||
g_FdMap[i]->Close(0, true);
|
||||
delete g_FdMap[i];
|
||||
}
|
||||
g_FdMap[i] = NULL;
|
||||
}
|
||||
|
||||
TDeviceMap::iterator itr = g_DeviceMap.begin();
|
||||
while (itr != g_DeviceMap.end())
|
||||
{
|
||||
@@ -111,21 +141,17 @@ void Reset(bool _bHard)
|
||||
// Force close
|
||||
itr->second->Close(0, true);
|
||||
// Hardware should not be deleted unless it is a hard reset
|
||||
if (_bHard || !itr->second->IsHardware())
|
||||
if (_bHard)
|
||||
delete itr->second;
|
||||
}
|
||||
++itr;
|
||||
}
|
||||
// Skip hardware devices if not a hard reset
|
||||
itr = (_bHard) ? g_DeviceMap.begin() : g_DeviceMap.lower_bound(IPC_FIRST_FILEIO_ID);
|
||||
// Erase devices
|
||||
g_DeviceMap.erase(itr, g_DeviceMap.end());
|
||||
g_FileNameMap.clear();
|
||||
|
||||
if (_bHard)
|
||||
{
|
||||
g_DeviceMap.erase(g_DeviceMap.begin(), g_DeviceMap.end());
|
||||
}
|
||||
request_queue.clear();
|
||||
reply_queue.clear();
|
||||
|
||||
g_LastDeviceID = IPC_FIRST_FILEIO_ID;
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
@@ -135,41 +161,53 @@ void Shutdown()
|
||||
|
||||
void SetDefaultContentFile(const std::string& _rFilename)
|
||||
{
|
||||
CWII_IPC_HLE_Device_es* pDevice =
|
||||
(CWII_IPC_HLE_Device_es*)AccessDeviceByID(GetDeviceIDByName(std::string("/dev/es")));
|
||||
if (pDevice)
|
||||
pDevice->LoadWAD(_rFilename);
|
||||
TDeviceMap::const_iterator itr = g_DeviceMap.begin();
|
||||
while (itr != g_DeviceMap.end())
|
||||
{
|
||||
if (itr->second && itr->second->GetDeviceName().find(std::string("/dev/es")) == 0)
|
||||
{
|
||||
((CWII_IPC_HLE_Device_es*)itr->second)->LoadWAD(_rFilename);
|
||||
}
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
|
||||
void ES_DIVerify(u8 *_pTMD, u32 _sz)
|
||||
{
|
||||
CWII_IPC_HLE_Device_es* pDevice =
|
||||
(CWII_IPC_HLE_Device_es*)AccessDeviceByID(GetDeviceIDByName(std::string("/dev/es")));
|
||||
if (pDevice)
|
||||
pDevice->ES_DIVerify(_pTMD, _sz);
|
||||
else
|
||||
ERROR_LOG(WII_IPC_ES, "DIVerify called but /dev/es is not available");
|
||||
CWII_IPC_HLE_Device_es::ES_DIVerify(_pTMD, _sz);
|
||||
}
|
||||
|
||||
void SDIO_EventNotify()
|
||||
{
|
||||
CWII_IPC_HLE_Device_sdio_slot0 *pDevice =
|
||||
(CWII_IPC_HLE_Device_sdio_slot0*)AccessDeviceByID(GetDeviceIDByName(std::string("/dev/sdio/slot0")));
|
||||
(CWII_IPC_HLE_Device_sdio_slot0*)GetDeviceByName(std::string("/dev/sdio/slot0"));
|
||||
if (pDevice)
|
||||
pDevice->EventNotify();
|
||||
}
|
||||
int getFreeDeviceId()
|
||||
{
|
||||
u32 i;
|
||||
for (i=0; i<IPC_MAX_FDS; i++)
|
||||
{
|
||||
if (g_FdMap[i] == NULL)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int GetDeviceIDByName(const std::string& _rDeviceName)
|
||||
IWII_IPC_HLE_Device* GetDeviceByName(const std::string& _rDeviceName)
|
||||
{
|
||||
TDeviceMap::const_iterator itr = g_DeviceMap.begin();
|
||||
while(itr != g_DeviceMap.end())
|
||||
while (itr != g_DeviceMap.end())
|
||||
{
|
||||
if (itr->second->GetDeviceName() == _rDeviceName)
|
||||
return itr->first;
|
||||
if (itr->second && itr->second->GetDeviceName() == _rDeviceName)
|
||||
return itr->second;
|
||||
++itr;
|
||||
}
|
||||
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID)
|
||||
@@ -177,17 +215,7 @@ IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID)
|
||||
if (g_DeviceMap.find(_ID) != g_DeviceMap.end())
|
||||
return g_DeviceMap[_ID];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DeleteDeviceByID(u32 ID)
|
||||
{
|
||||
IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(ID);
|
||||
if (pDevice)
|
||||
delete pDevice;
|
||||
|
||||
g_DeviceMap.erase(ID);
|
||||
g_FileNameMap.erase(ID);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// This is called from ExecuteCommand() COMMAND_OPEN_DEVICE
|
||||
@@ -205,60 +233,86 @@ IWII_IPC_HLE_Device* CreateFileIO(u32 _DeviceID, const std::string& _rDeviceName
|
||||
|
||||
void DoState(PointerWrap &p)
|
||||
{
|
||||
p.Do(g_LastDeviceID);
|
||||
p.Do(request_queue);
|
||||
p.Do(reply_queue);
|
||||
|
||||
if (p.GetMode() == PointerWrap::MODE_READ)
|
||||
{
|
||||
TFileNameMap::const_iterator itr;
|
||||
// Delete file Handles
|
||||
itr = g_FileNameMap.begin();
|
||||
while (itr != g_FileNameMap.end())
|
||||
{
|
||||
TDeviceMap::const_iterator devitr = g_DeviceMap.find(itr->first);
|
||||
if (devitr != g_DeviceMap.end())
|
||||
TDeviceMap::const_iterator itr;
|
||||
|
||||
itr = g_DeviceMap.begin();
|
||||
while (itr != g_DeviceMap.end())
|
||||
{
|
||||
if (itr->second->IsHardware())
|
||||
{
|
||||
if (devitr->second)
|
||||
delete devitr->second;
|
||||
g_DeviceMap.erase(itr->first);
|
||||
itr->second->DoState(p);
|
||||
}
|
||||
++itr;
|
||||
}
|
||||
// Load file names
|
||||
p.Do(g_FileNameMap);
|
||||
// Rebuild file handles
|
||||
itr = g_FileNameMap.begin();
|
||||
while (itr != g_FileNameMap.end())
|
||||
}
|
||||
|
||||
if (p.GetMode() == PointerWrap::MODE_READ)
|
||||
{
|
||||
u32 i;
|
||||
for (i=0; i<IPC_MAX_FDS; i++)
|
||||
{
|
||||
g_DeviceMap[itr->first] = new CWII_IPC_HLE_Device_FileIO(itr->first, itr->second);
|
||||
++itr;
|
||||
u32 exists;
|
||||
p.Do(exists);
|
||||
if (exists)
|
||||
{
|
||||
u32 isHw;
|
||||
p.Do(isHw);
|
||||
if (isHw)
|
||||
{
|
||||
u32 hwId;
|
||||
p.Do(hwId);
|
||||
g_FdMap[i] = AccessDeviceByID(hwId);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_FdMap[i] = new CWII_IPC_HLE_Device_FileIO(i, "");
|
||||
g_FdMap[i]->DoState(p);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_FdMap[i] = NULL;
|
||||
}
|
||||
}
|
||||
for (i=0; i<ES_MAX_COUNT; i++)
|
||||
{
|
||||
p.Do(es_inuse[i]);
|
||||
u32 handleID = es_handles[i]->GetDeviceID();
|
||||
p.Do(handleID);
|
||||
|
||||
es_handles[i] = AccessDeviceByID(handleID);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
p.Do(g_FileNameMap);
|
||||
}
|
||||
|
||||
p.Do(request_queue);
|
||||
p.Do(reply_queue);
|
||||
|
||||
|
||||
TDeviceMap::const_iterator itr;
|
||||
//first, all the real devices
|
||||
//(because we need fs to be deserialized first)
|
||||
itr = g_DeviceMap.begin();
|
||||
while (itr != g_DeviceMap.end())
|
||||
{
|
||||
if (itr->second->IsHardware())
|
||||
itr->second->DoState(p);
|
||||
++itr;
|
||||
}
|
||||
//then all the files
|
||||
itr = g_DeviceMap.begin();
|
||||
while (itr != g_DeviceMap.end())
|
||||
{
|
||||
if (!itr->second->IsHardware())
|
||||
itr->second->DoState(p);
|
||||
++itr;
|
||||
u32 i;
|
||||
for (i=0; i<IPC_MAX_FDS; i++)
|
||||
{
|
||||
u32 exists = g_FdMap[i] ? 1 : 0;
|
||||
p.Do(exists);
|
||||
if (exists)
|
||||
{
|
||||
u32 isHw = g_FdMap[i]->IsHardware() ? 1 : 0;
|
||||
p.Do(isHw);
|
||||
if (isHw)
|
||||
{
|
||||
u32 hwId = g_FdMap[i]->GetDeviceID();
|
||||
p.Do(hwId);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_FdMap[i]->DoState(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i=0; i<ES_MAX_COUNT; i++)
|
||||
{
|
||||
p.Do(es_inuse[i]);
|
||||
u32 handleID = es_handles[i]->GetDeviceID();
|
||||
p.Do(handleID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,67 +321,110 @@ void ExecuteCommand(u32 _Address)
|
||||
bool CmdSuccess = false;
|
||||
|
||||
ECommandType Command = static_cast<ECommandType>(Memory::Read_U32(_Address));
|
||||
int DeviceID = Memory::Read_U32(_Address + 8);
|
||||
IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(DeviceID);
|
||||
volatile int DeviceID = Memory::Read_U32(_Address + 8);
|
||||
|
||||
INFO_LOG(WII_IPC_HLE, "-->> Execute Command Address: 0x%08x (code: %x, device: %x) ", _Address, Command, DeviceID);
|
||||
IWII_IPC_HLE_Device* pDevice = (DeviceID >= 0 && DeviceID < IPC_MAX_FDS) ? g_FdMap[DeviceID] : NULL;
|
||||
|
||||
INFO_LOG(WII_IPC_HLE, "-->> Execute Command Address: 0x%08x (code: %x, device: %x) %p", _Address, Command, DeviceID, pDevice);
|
||||
|
||||
switch (Command)
|
||||
{
|
||||
case COMMAND_OPEN_DEVICE:
|
||||
{
|
||||
// Create a new HLE device. The Mode and DeviceName is given to us but we
|
||||
// generate a DeviceID to be used for access to this device until it is Closed.
|
||||
std::string DeviceName;
|
||||
Memory::GetString(DeviceName, Memory::Read_U32(_Address + 0xC));
|
||||
{
|
||||
u32 Mode = Memory::Read_U32(_Address + 0x10);
|
||||
DeviceID = getFreeDeviceId();
|
||||
|
||||
std::string DeviceName;
|
||||
Memory::GetString(DeviceName, Memory::Read_U32(_Address + 0xC));
|
||||
|
||||
u32 Mode = Memory::Read_U32(_Address + 0x10);
|
||||
DeviceID = GetDeviceIDByName(DeviceName);
|
||||
|
||||
// check if a device with this name has been created already
|
||||
if (DeviceName.find("/dev/") == std::string::npos || DeviceID == -1)
|
||||
{
|
||||
if (DeviceName.find("/dev/") == 0)
|
||||
|
||||
WARN_LOG(WII_IPC_HLE, "Tried to open %s as %d", DeviceName.c_str(), DeviceID);
|
||||
if (DeviceID >= 0)
|
||||
{
|
||||
if (DeviceName.find("/dev/es") == 0)
|
||||
{
|
||||
u32 j;
|
||||
for (j=0; j<ES_MAX_COUNT; j++)
|
||||
{
|
||||
WARN_LOG(WII_IPC_HLE, "Unimplemented device: %s", DeviceName.c_str());
|
||||
if (!es_inuse[j])
|
||||
{
|
||||
es_inuse[j] = true;
|
||||
g_FdMap[DeviceID] = es_handles[j];
|
||||
CmdSuccess = es_handles[j]->Open(_Address, Mode);
|
||||
Memory::Write_U32(DeviceID, _Address+4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j == ES_MAX_COUNT)
|
||||
{
|
||||
Memory::Write_U32(FS_EESEXHAUSTED, _Address + 4);
|
||||
CmdSuccess = true;
|
||||
}
|
||||
|
||||
pDevice = AccessDeviceByID(GetDeviceIDByName(std::string("_Unimplemented_Device_")));
|
||||
}
|
||||
else if (DeviceName.find("/dev/") == 0)
|
||||
{
|
||||
pDevice = GetDeviceByName(DeviceName);
|
||||
if (pDevice)
|
||||
{
|
||||
g_FdMap[DeviceID] = pDevice;
|
||||
CmdSuccess = pDevice->Open(_Address, Mode);
|
||||
INFO_LOG(WII_IPC_FILEIO, "IOP: ReOpen (Device=%s, DeviceID=%08x, Mode=%i)",
|
||||
pDevice->GetDeviceName().c_str(), DeviceID, Mode);
|
||||
Memory::Write_U32(DeviceID, _Address+4);
|
||||
}
|
||||
else
|
||||
{
|
||||
// create new file handle
|
||||
u32 CurrentDeviceID = g_LastDeviceID;
|
||||
pDevice = CreateFileIO(CurrentDeviceID, DeviceName);
|
||||
g_DeviceMap[CurrentDeviceID] = pDevice;
|
||||
g_FileNameMap[CurrentDeviceID] = DeviceName;
|
||||
g_LastDeviceID++;
|
||||
|
||||
CmdSuccess = pDevice->Open(_Address, Mode);
|
||||
|
||||
INFO_LOG(WII_IPC_FILEIO, "IOP: Open File (Device=%s, ID=%08x, Mode=%i)",
|
||||
pDevice->GetDeviceName().c_str(), CurrentDeviceID, Mode);
|
||||
WARN_LOG(WII_IPC_HLE, "Unimplemented device: %s", DeviceName.c_str());
|
||||
Memory::Write_U32(FS_ENOENT, _Address+4);
|
||||
CmdSuccess = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// F|RES: prolly the re-open is just a mode change
|
||||
pDevice = AccessDeviceByID(DeviceID);
|
||||
}
|
||||
else
|
||||
{
|
||||
IWII_IPC_HLE_Device* pDevice = CreateFileIO(DeviceID, DeviceName);
|
||||
CmdSuccess = pDevice->Open(_Address, Mode);
|
||||
|
||||
INFO_LOG(WII_IPC_FILEIO, "IOP: ReOpen (Device=%s, DeviceID=%08x, Mode=%i)",
|
||||
pDevice->GetDeviceName().c_str(), DeviceID, Mode);
|
||||
}
|
||||
}
|
||||
break;
|
||||
INFO_LOG(WII_IPC_FILEIO, "IOP: Open File (Device=%s, ID=%08x, Mode=%i)",
|
||||
pDevice->GetDeviceName().c_str(), DeviceID, Mode);
|
||||
if (Memory::Read_U32(_Address + 4) == DeviceID)
|
||||
{
|
||||
g_FdMap[DeviceID] = pDevice;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete pDevice;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Memory::Write_U32(FS_EFDEXHAUSTED, _Address + 4);
|
||||
CmdSuccess = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case COMMAND_CLOSE_DEVICE:
|
||||
if (pDevice)
|
||||
{
|
||||
if (pDevice)
|
||||
{
|
||||
CmdSuccess = pDevice->Close(_Address);
|
||||
|
||||
u32 j;
|
||||
for (j=0; j<ES_MAX_COUNT; j++)
|
||||
{
|
||||
if (es_handles[j] == g_FdMap[DeviceID])
|
||||
{
|
||||
es_inuse[j] = false;
|
||||
}
|
||||
}
|
||||
|
||||
g_FdMap[DeviceID] = NULL;
|
||||
|
||||
// Don't delete hardware
|
||||
if (!pDevice->IsHardware())
|
||||
DeleteDeviceByID(DeviceID);
|
||||
delete pDevice;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -335,50 +432,67 @@ void ExecuteCommand(u32 _Address)
|
||||
CmdSuccess = true;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
case COMMAND_READ:
|
||||
{
|
||||
if (pDevice)
|
||||
{
|
||||
CmdSuccess = pDevice->Read(_Address);
|
||||
}
|
||||
else
|
||||
{
|
||||
Memory::Write_U32(FS_EINVAL, _Address + 4);
|
||||
CmdSuccess = true;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
case COMMAND_WRITE:
|
||||
{
|
||||
if (pDevice)
|
||||
{
|
||||
CmdSuccess = pDevice->Write(_Address);
|
||||
}
|
||||
else
|
||||
{
|
||||
Memory::Write_U32(FS_EINVAL, _Address + 4);
|
||||
CmdSuccess = true;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
case COMMAND_SEEK:
|
||||
{
|
||||
if (pDevice)
|
||||
{
|
||||
CmdSuccess = pDevice->Seek(_Address);
|
||||
}
|
||||
else
|
||||
{
|
||||
Memory::Write_U32(FS_EINVAL, _Address + 4);
|
||||
CmdSuccess = true;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
case COMMAND_IOCTL:
|
||||
{
|
||||
if (pDevice)
|
||||
{
|
||||
CmdSuccess = pDevice->IOCtl(_Address);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
case COMMAND_IOCTLV:
|
||||
{
|
||||
if (pDevice)
|
||||
{
|
||||
CmdSuccess = pDevice->IOCtlV(_Address);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
default:
|
||||
{
|
||||
_dbg_assert_msg_(WII_IPC_HLE, 0, "Unknown IPC Command %i (0x%08x)", Command, _Address);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// It seems that the original hardware overwrites the command after it has been
|
||||
@@ -450,9 +564,10 @@ void Update()
|
||||
void UpdateDevices()
|
||||
{
|
||||
// Check if a hardware device must be updated
|
||||
TDeviceMap::const_iterator itrEnd = g_DeviceMap.lower_bound(IPC_FIRST_FILEIO_ID);
|
||||
for (TDeviceMap::const_iterator itr = g_DeviceMap.begin(); itr != itrEnd; ++itr) {
|
||||
if (itr->second->IsOpened() && itr->second->Update()) {
|
||||
for (TDeviceMap::const_iterator itr = g_DeviceMap.begin(); itr != g_DeviceMap.end(); ++itr)
|
||||
{
|
||||
if (itr->second->IsOpened() && itr->second->Update())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,9 +25,9 @@ class IWII_IPC_HLE_Device;
|
||||
namespace WII_IPC_HLE_Interface
|
||||
{
|
||||
|
||||
#define IPC_FIRST_HARDWARE_ID 0 // first IPC device ID
|
||||
#define IPC_FIRST_FILEIO_ID 33 // first IPC file ID
|
||||
|
||||
#define IPC_FIRST_ID 0x00 // first IPC device ID
|
||||
#define IPC_MAX_FILES 0x10 // first IPC file ID
|
||||
|
||||
// Init
|
||||
void Init();
|
||||
|
||||
@@ -46,14 +46,13 @@ void ES_DIVerify(u8 *_pTMD, u32 _sz);
|
||||
|
||||
void SDIO_EventNotify();
|
||||
|
||||
int GetDeviceIDByName(const std::string& _rDeviceName);
|
||||
|
||||
IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID);
|
||||
|
||||
void DeleteDeviceByID(u32 _ID);
|
||||
|
||||
IWII_IPC_HLE_Device* CreateFileIO(u32 _DeviceID, const std::string& _rDeviceName);
|
||||
|
||||
IWII_IPC_HLE_Device* GetDeviceByName(const std::string& _rDeviceName);
|
||||
IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID);
|
||||
int getFreeDeviceId();
|
||||
|
||||
// Update
|
||||
void Update();
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ class PointerWrap;
|
||||
#define FS_ENOENT2 (u32)-106 // File not found
|
||||
#define FS_ENFILE (u32)-107 // Too many fds open
|
||||
#define FS_EFBIG (u32)-108 // max block count reached?
|
||||
#define FS_ENFILE2 (u32)-109 // Too many fds open
|
||||
#define FS_EFDEXHAUSTED (u32)-109 // Too many fds open
|
||||
#define FS_ENAMELEN (u32)-110 // pathname is too long
|
||||
#define FS_EFDOPEN (u32)-111 // FD is already open
|
||||
#define FS_EIO2 (u32)-114 // returned on ECC error
|
||||
@@ -47,6 +47,7 @@ class PointerWrap;
|
||||
#define FS_EDIRDEPTH (u32)-116 // max directory depth exceeded
|
||||
#define FS_EBUSY2 (u32)-118 // Resource busy
|
||||
//#define FS_EFATAL (u32)-119 // fatal error not used by IOS as fatal ERROR
|
||||
#define FS_EESEXHAUSTED (u32)-1016 // Max of 2 ES handles at a time
|
||||
|
||||
class IWII_IPC_HLE_Device
|
||||
{
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
static Common::replace_v replacements;
|
||||
|
||||
// This is used by several of the FileIO and /dev/fs/ functions
|
||||
// This is used by several of the FileIO and /dev/fs functions
|
||||
std::string HLE_IPC_BuildFilename(const char* _pFilename, int _size)
|
||||
{
|
||||
std::string path_full = File::GetUserPath(D_WIIROOT_IDX);
|
||||
@@ -128,7 +128,7 @@ bool CWII_IPC_HLE_Device_FileIO::Open(u32 _CommandAddress, u32 _Mode)
|
||||
|
||||
// The file must exist before we can open it
|
||||
// It should be created by ISFS_CreateFile, not here
|
||||
if(File::Exists(m_Filename))
|
||||
if (File::Exists(m_Filename))
|
||||
{
|
||||
INFO_LOG(WII_IPC_FILEIO, "FileIO: Open %s (%s == %08X)", m_Name.c_str(), Modes[_Mode], _Mode);
|
||||
ReturnValue = m_DeviceID;
|
||||
@@ -149,25 +149,29 @@ bool CWII_IPC_HLE_Device_FileIO::Open(u32 _CommandAddress, u32 _Mode)
|
||||
|
||||
bool CWII_IPC_HLE_Device_FileIO::OpenFile()
|
||||
{
|
||||
switch(m_Mode)
|
||||
switch (m_Mode)
|
||||
{
|
||||
case ISFS_OPEN_READ:
|
||||
{
|
||||
m_pFileHandle.Open(m_Filename, "rb");
|
||||
break;
|
||||
|
||||
// "r+b" is technically wrong, but OPEN_WRITE should not truncate the file as "wb" does.
|
||||
}
|
||||
case ISFS_OPEN_WRITE:
|
||||
{
|
||||
m_pFileHandle.Open(m_Filename, "r+b");
|
||||
break;
|
||||
|
||||
}
|
||||
case ISFS_OPEN_RW:
|
||||
{
|
||||
m_pFileHandle.Open(m_Filename, "r+b");
|
||||
break;
|
||||
|
||||
}
|
||||
default:
|
||||
{
|
||||
PanicAlertT("FileIO: Unknown open mode : 0x%02x", m_Mode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return m_pFileHandle.IsOpen();
|
||||
}
|
||||
|
||||
@@ -178,21 +182,21 @@ void CWII_IPC_HLE_Device_FileIO::CloseFile()
|
||||
|
||||
bool CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress)
|
||||
{
|
||||
u32 ReturnValue = FS_RESULT_FATAL;
|
||||
const s32 SeekPosition = Memory::Read_U32(_CommandAddress + 0xC);
|
||||
const s32 Mode = Memory::Read_U32(_CommandAddress + 0x10);
|
||||
u32 ReturnValue = FS_RESULT_FATAL;
|
||||
const s32 SeekPosition = Memory::Read_U32(_CommandAddress + 0xC);
|
||||
const s32 Mode = Memory::Read_U32(_CommandAddress + 0x10);
|
||||
|
||||
|
||||
if(OpenFile())
|
||||
if (OpenFile())
|
||||
{
|
||||
ReturnValue = FS_RESULT_FATAL;
|
||||
|
||||
const u64 fileSize = m_pFileHandle.GetSize();
|
||||
const u64 fileSize = m_pFileHandle.GetSize();
|
||||
INFO_LOG(WII_IPC_FILEIO, "FileIO: Seek Pos: 0x%08x, Mode: %i (%s, Length=0x%08llx)", SeekPosition, Mode, m_Name.c_str(), fileSize);
|
||||
switch(Mode){
|
||||
switch (Mode){
|
||||
case 0:
|
||||
{
|
||||
if(SeekPosition >=0 && SeekPosition <= fileSize)
|
||||
if (SeekPosition >=0 && SeekPosition <= fileSize)
|
||||
{
|
||||
m_SeekPos = SeekPosition;
|
||||
ReturnValue = m_SeekPos;
|
||||
@@ -202,7 +206,7 @@ bool CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress)
|
||||
case 1:
|
||||
{
|
||||
s32 wantedPos = SeekPosition+m_SeekPos;
|
||||
if(wantedPos >=0 && wantedPos <= fileSize)
|
||||
if (wantedPos >=0 && wantedPos <= fileSize)
|
||||
{
|
||||
m_SeekPos = wantedPos;
|
||||
ReturnValue = m_SeekPos;
|
||||
@@ -212,7 +216,7 @@ bool CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress)
|
||||
case 2:
|
||||
{
|
||||
s32 wantedPos = fileSize+m_SeekPos;
|
||||
if(wantedPos >=0 && wantedPos <= fileSize)
|
||||
if (wantedPos >=0 && wantedPos <= fileSize)
|
||||
{
|
||||
m_SeekPos = wantedPos;
|
||||
ReturnValue = m_SeekPos;
|
||||
@@ -244,7 +248,7 @@ bool CWII_IPC_HLE_Device_FileIO::Read(u32 _CommandAddress)
|
||||
const u32 Size = Memory::Read_U32(_CommandAddress + 0x10);
|
||||
|
||||
|
||||
if(OpenFile())
|
||||
if (OpenFile())
|
||||
{
|
||||
if (m_Mode == ISFS_OPEN_WRITE)
|
||||
{
|
||||
@@ -284,7 +288,7 @@ bool CWII_IPC_HLE_Device_FileIO::Write(u32 _CommandAddress)
|
||||
const u32 Size = Memory::Read_U32(_CommandAddress + 0x10);
|
||||
|
||||
|
||||
if(OpenFile())
|
||||
if (OpenFile())
|
||||
{
|
||||
if (m_Mode == ISFS_OPEN_READ)
|
||||
{
|
||||
@@ -318,21 +322,14 @@ bool CWII_IPC_HLE_Device_FileIO::IOCtl(u32 _CommandAddress)
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
DumpCommands(_CommandAddress);
|
||||
#endif
|
||||
const u32 Parameter = Memory::Read_U32(_CommandAddress + 0xC);
|
||||
const u32 Parameter = Memory::Read_U32(_CommandAddress + 0xC);
|
||||
u32 ReturnValue = 0;
|
||||
|
||||
//u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10);
|
||||
//u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14);
|
||||
//u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18);
|
||||
//u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C);
|
||||
|
||||
// Return Value
|
||||
u32 ReturnValue = 0; // no error
|
||||
|
||||
switch(Parameter)
|
||||
switch (Parameter)
|
||||
{
|
||||
case ISFS_IOCTL_GETFILESTATS:
|
||||
{
|
||||
if(OpenFile())
|
||||
if (OpenFile())
|
||||
{
|
||||
u32 m_FileLength = (u32)m_pFileHandle.GetSize();
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ public:
|
||||
virtual bool Close(u32 _CommandAddress, bool _bForce);
|
||||
|
||||
virtual bool IOCtlV(u32 _CommandAddress);
|
||||
u32 ES_DIVerify(u8 *_pTMD, u32 _sz);
|
||||
static u32 ES_DIVerify(u8 *_pTMD, u32 _sz);
|
||||
private:
|
||||
|
||||
enum
|
||||
|
||||
@@ -42,10 +42,6 @@ using namespace MathUtil;
|
||||
|
||||
void UpdateSSEState();
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma float_control(precise, on, push)
|
||||
#endif
|
||||
|
||||
// Extremely rare - actually, never seen.
|
||||
// Star Wars : Rogue Leader spams that at some point :|
|
||||
void Interpreter::Helper_UpdateCR1(double _fValue)
|
||||
@@ -518,8 +514,4 @@ void Interpreter::fsqrtx(UGeckoInstruction _inst)
|
||||
rPS0(_inst.FD) = sqrt(b);
|
||||
UpdateFPRF(rPS0(_inst.FD));
|
||||
if (_inst.Rc) Helper_UpdateCR1(rPS0(_inst.FD));
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma float_control(pop)
|
||||
#endif
|
||||
}
|
||||
@@ -367,7 +367,7 @@ void Interpreter::dcbf(UGeckoInstruction _inst)
|
||||
if (jit)
|
||||
{
|
||||
u32 address = Helper_Get_EA_X(_inst);
|
||||
jit->GetBlockCache()->InvalidateICache(address & ~0x1f);
|
||||
jit->GetBlockCache()->InvalidateICache(address & ~0x1f, 32);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -378,7 +378,7 @@ void Interpreter::dcbi(UGeckoInstruction _inst)
|
||||
if (jit)
|
||||
{
|
||||
u32 address = Helper_Get_EA_X(_inst);
|
||||
jit->GetBlockCache()->InvalidateICache(address & ~0x1f);
|
||||
jit->GetBlockCache()->InvalidateICache(address & ~0x1f, 32);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,10 @@
|
||||
#include "JitAsm.h"
|
||||
#include "JitRegCache.h"
|
||||
#include "Jit64_Tables.h"
|
||||
#include "HW/ProcessorInterface.h"
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
#include "PowerPCDisasm.h"
|
||||
#endif
|
||||
|
||||
using namespace Gen;
|
||||
using namespace PowerPC;
|
||||
@@ -414,8 +418,8 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
||||
// Comment out the following to disable breakpoints (speed-up)
|
||||
if (!Profiler::g_ProfileBlocks)
|
||||
{
|
||||
blockSize = 1;
|
||||
broken_block = true;
|
||||
if (GetState() == CPU_STEPPING)
|
||||
blockSize = 1;
|
||||
Trace();
|
||||
}
|
||||
}
|
||||
@@ -572,6 +576,44 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
||||
SetJumpTarget(b1);
|
||||
}
|
||||
|
||||
// Add an external exception check if the instruction writes to the FIFO.
|
||||
if (jit->js.fifoWriteAddresses.find(ops[i].address) != jit->js.fifoWriteAddresses.end())
|
||||
{
|
||||
gpr.Flush(FLUSH_ALL);
|
||||
fpr.Flush(FLUSH_ALL);
|
||||
|
||||
TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_ISI | EXCEPTION_PROGRAM | EXCEPTION_SYSCALL | EXCEPTION_FPU_UNAVAILABLE | EXCEPTION_DSI | EXCEPTION_ALIGNMENT | EXCEPTION_DECREMENTER));
|
||||
FixupBranch clearInt = J_CC(CC_NZ);
|
||||
TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_EXTERNAL_INT));
|
||||
FixupBranch noExtException = J_CC(CC_Z);
|
||||
TEST(32, M((void *)&PowerPC::ppcState.msr), Imm32(0x0008000));
|
||||
FixupBranch noExtIntEnable = J_CC(CC_Z);
|
||||
TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_CP | ProcessorInterface::INT_CAUSE_PE_TOKEN | ProcessorInterface::INT_CAUSE_PE_FINISH));
|
||||
FixupBranch noCPInt = J_CC(CC_Z);
|
||||
|
||||
MOV(32, M(&PC), Imm32(ops[i].address));
|
||||
WriteExceptionExit();
|
||||
|
||||
SetJumpTarget(noCPInt);
|
||||
SetJumpTarget(noExtIntEnable);
|
||||
SetJumpTarget(noExtException);
|
||||
SetJumpTarget(clearInt);
|
||||
}
|
||||
|
||||
if (Core::g_CoreStartupParameter.bEnableDebugging && breakpoints.IsAddressBreakPoint(ops[i].address) && GetState() != CPU_STEPPING)
|
||||
{
|
||||
MOV(32, M(&PC), Imm32(ops[i].address));
|
||||
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckBreakPoints));
|
||||
TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF));
|
||||
FixupBranch noBreakpoint = J_CC(CC_Z);
|
||||
|
||||
gpr.Flush(FLUSH_ALL);
|
||||
fpr.Flush(FLUSH_ALL);
|
||||
|
||||
WriteExit(ops[i].address, 0);
|
||||
SetJumpTarget(noBreakpoint);
|
||||
}
|
||||
|
||||
Jit64Tables::CompileInstruction(ops[i]);
|
||||
|
||||
if (js.memcheck && (opinfo->flags & FL_LOADSTORE))
|
||||
|
||||
@@ -100,8 +100,8 @@ static GekkoOPTemplate primarytable[] =
|
||||
{50, &Jit64::lfd}, //"lfd", OPTYPE_LOADFP, FL_IN_A}},
|
||||
{51, &Jit64::Default}, //"lfdu", OPTYPE_LOADFP, FL_OUT_A | FL_IN_A}},
|
||||
|
||||
{52, &Jit64::Default}, //"stfs", OPTYPE_STOREFP, FL_IN_A}},
|
||||
{53, &Jit64::Default}, //"stfsu", OPTYPE_STOREFP, FL_OUT_A | FL_IN_A}},
|
||||
{52, &Jit64::stfs}, //"stfs", OPTYPE_STOREFP, FL_IN_A}},
|
||||
{53, &Jit64::stfs}, //"stfsu", OPTYPE_STOREFP, FL_OUT_A | FL_IN_A}},
|
||||
{54, &Jit64::stfd}, //"stfd", OPTYPE_STOREFP, FL_IN_A}},
|
||||
{55, &Jit64::Default}, //"stfdu", OPTYPE_STOREFP, FL_OUT_A | FL_IN_A}},
|
||||
|
||||
|
||||
@@ -81,12 +81,15 @@ void Jit64AsmRoutineManager::Generate()
|
||||
|
||||
if (Core::g_CoreStartupParameter.bEnableDebugging)
|
||||
{
|
||||
TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(PowerPC::CPU_STEPPING));
|
||||
FixupBranch notStepping = J_CC(CC_Z);
|
||||
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckBreakPoints));
|
||||
TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF));
|
||||
FixupBranch noBreakpoint = J_CC(CC_Z);
|
||||
ABI_PopAllCalleeSavedRegsAndAdjustStack();
|
||||
RET();
|
||||
SetJumpTarget(noBreakpoint);
|
||||
SetJumpTarget(notStepping);
|
||||
}
|
||||
|
||||
SetJumpTarget(skipToRealDispatch);
|
||||
|
||||
@@ -266,7 +266,7 @@ void Jit64::reg_imm(UGeckoInstruction inst)
|
||||
case 15:
|
||||
if (a == 0) { // lis
|
||||
// Merge with next instruction if loading a 32-bits immediate value (lis + addi, lis + ori)
|
||||
if (!js.isLastInstruction) {
|
||||
if (!js.isLastInstruction && !Core::g_CoreStartupParameter.bEnableDebugging) {
|
||||
if ((js.next_inst.OPCD == 14) && (js.next_inst.RD == d) && (js.next_inst.RA == d)) { // addi
|
||||
gpr.SetImmediate32(d, ((u32)inst.SIMM_16 << 16) + (u32)(s32)js.next_inst.SIMM_16);
|
||||
js.downcountAmount++;
|
||||
|
||||
@@ -1260,8 +1260,8 @@ static const std::string opcodeNames[] = {
|
||||
"FResult_End", "StorePaired", "StoreSingle", "StoreDouble", "StoreFReg",
|
||||
"FDCmpCR", "CInt16", "CInt32", "SystemCall", "RFIExit",
|
||||
"InterpreterBranch", "IdleBranch", "ShortIdleLoop",
|
||||
"FPExceptionCheckStart", "FPExceptionCheckEnd", "ISIException", "Tramp",
|
||||
"BlockStart", "BlockEnd", "Int3",
|
||||
"FPExceptionCheckStart", "FPExceptionCheckEnd", "ISIException", "ExtExceptionCheck",
|
||||
"Tramp", "BlockStart", "BlockEnd", "Int3",
|
||||
};
|
||||
static const unsigned alwaysUsedList[] = {
|
||||
InterpreterFallback, StoreGReg, StoreCR, StoreLink, StoreCTR, StoreMSR,
|
||||
@@ -1269,7 +1269,8 @@ static const unsigned alwaysUsedList[] = {
|
||||
Store16, Store32, StoreSingle, StoreDouble, StorePaired, StoreFReg, FDCmpCR,
|
||||
BlockStart, BlockEnd, IdleBranch, BranchCond, BranchUncond, ShortIdleLoop,
|
||||
SystemCall, InterpreterBranch, RFIExit, FPExceptionCheckStart,
|
||||
FPExceptionCheckEnd, ISIException, Int3, Tramp, Nop
|
||||
FPExceptionCheckEnd, ISIException, ExtExceptionCheck, BreakPointCheck,
|
||||
Int3, Tramp, Nop
|
||||
};
|
||||
static const unsigned extra8RegList[] = {
|
||||
LoadGReg, LoadCR, LoadGQR, LoadFReg, LoadFRegDENToZero,
|
||||
|
||||
@@ -165,10 +165,10 @@ enum Opcode {
|
||||
ShortIdleLoop, // Idle loop seen in homebrew like wii mahjong,
|
||||
// just a branch
|
||||
|
||||
// used for MMU, at least until someone
|
||||
// used for exception checking, at least until someone
|
||||
// has a better idea of integrating it
|
||||
FPExceptionCheckStart, FPExceptionCheckEnd,
|
||||
ISIException,
|
||||
ISIException, ExtExceptionCheck, BreakPointCheck,
|
||||
// "Opcode" representing a register too far away to
|
||||
// reference directly; this is a size optimization
|
||||
Tramp,
|
||||
@@ -411,6 +411,12 @@ public:
|
||||
InstLoc EmitISIException(InstLoc dest) {
|
||||
return EmitUOp(ISIException, dest);
|
||||
}
|
||||
InstLoc EmitExtExceptionCheck(InstLoc pc) {
|
||||
return EmitUOp(ExtExceptionCheck, pc);
|
||||
}
|
||||
InstLoc EmitBreakPointCheck(InstLoc pc) {
|
||||
return EmitUOp(BreakPointCheck, pc);
|
||||
}
|
||||
InstLoc EmitRFIExit() {
|
||||
return FoldZeroOp(RFIExit, 0);
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ The register allocation is linear scan allocation.
|
||||
#include "../../../../Common/Src/CPUDetect.h"
|
||||
#include "MathUtil.h"
|
||||
#include "../../Core.h"
|
||||
#include "HW/ProcessorInterface.h"
|
||||
|
||||
static ThunkManager thunks;
|
||||
|
||||
@@ -761,6 +762,8 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak
|
||||
case FPExceptionCheckStart:
|
||||
case FPExceptionCheckEnd:
|
||||
case ISIException:
|
||||
case ExtExceptionCheck:
|
||||
case BreakPointCheck:
|
||||
case Int3:
|
||||
case Tramp:
|
||||
// No liveness effects
|
||||
@@ -1920,6 +1923,38 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak
|
||||
Jit->WriteExceptionExit();
|
||||
break;
|
||||
}
|
||||
case ExtExceptionCheck: {
|
||||
unsigned InstLoc = ibuild->GetImmValue(getOp1(I));
|
||||
|
||||
Jit->TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_ISI | EXCEPTION_PROGRAM | EXCEPTION_SYSCALL | EXCEPTION_FPU_UNAVAILABLE | EXCEPTION_DSI | EXCEPTION_ALIGNMENT | EXCEPTION_DECREMENTER));
|
||||
FixupBranch clearInt = Jit->J_CC(CC_NZ);
|
||||
Jit->TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_EXTERNAL_INT));
|
||||
FixupBranch noExtException = Jit->J_CC(CC_Z);
|
||||
Jit->TEST(32, M((void *)&PowerPC::ppcState.msr), Imm32(0x0008000));
|
||||
FixupBranch noExtIntEnable = Jit->J_CC(CC_Z);
|
||||
Jit->TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_CP || ProcessorInterface::INT_CAUSE_PE_TOKEN || ProcessorInterface::INT_CAUSE_PE_FINISH));
|
||||
FixupBranch noCPInt = Jit->J_CC(CC_Z);
|
||||
|
||||
Jit->MOV(32, M(&PC), Imm32(InstLoc));
|
||||
Jit->WriteExceptionExit();
|
||||
|
||||
Jit->SetJumpTarget(noCPInt);
|
||||
Jit->SetJumpTarget(noExtIntEnable);
|
||||
Jit->SetJumpTarget(noExtException);
|
||||
Jit->SetJumpTarget(clearInt);
|
||||
break;
|
||||
}
|
||||
case BreakPointCheck: {
|
||||
unsigned InstLoc = ibuild->GetImmValue(getOp1(I));
|
||||
|
||||
Jit->MOV(32, M(&PC), Imm32(InstLoc));
|
||||
Jit->ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckBreakPoints));
|
||||
Jit->TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF));
|
||||
FixupBranch noBreakpoint = Jit->J_CC(CC_Z);
|
||||
Jit->WriteExit(InstLoc, 0);
|
||||
Jit->SetJumpTarget(noBreakpoint);
|
||||
break;
|
||||
}
|
||||
case Int3: {
|
||||
Jit->INT3();
|
||||
break;
|
||||
|
||||
@@ -526,7 +526,8 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
||||
// Comment out the following to disable breakpoints (speed-up)
|
||||
if (!Profiler::g_ProfileBlocks)
|
||||
{
|
||||
blockSize = 1;
|
||||
if (GetState() == CPU_STEPPING)
|
||||
blockSize = 1;
|
||||
Trace();
|
||||
}
|
||||
}
|
||||
@@ -651,6 +652,16 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
||||
{
|
||||
ibuild.EmitFPExceptionCheckStart(ibuild.EmitIntConst(ops[i].address));
|
||||
}
|
||||
|
||||
if (jit->js.fifoWriteAddresses.find(js.compilerPC) != jit->js.fifoWriteAddresses.end())
|
||||
{
|
||||
ibuild.EmitExtExceptionCheck(ibuild.EmitIntConst(ops[i].address));
|
||||
}
|
||||
|
||||
if (Core::g_CoreStartupParameter.bEnableDebugging && breakpoints.IsAddressBreakPoint(ops[i].address) && GetState() != CPU_STEPPING)
|
||||
{
|
||||
ibuild.EmitBreakPointCheck(ibuild.EmitIntConst(ops[i].address));
|
||||
}
|
||||
|
||||
JitILTables::CompileInstruction(ops[i]);
|
||||
|
||||
|
||||
@@ -83,12 +83,15 @@ void JitILAsmRoutineManager::Generate()
|
||||
|
||||
if (Core::g_CoreStartupParameter.bEnableDebugging)
|
||||
{
|
||||
TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(PowerPC::CPU_STEPPING));
|
||||
FixupBranch notStepping = J_CC(CC_Z);
|
||||
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckBreakPoints));
|
||||
TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF));
|
||||
FixupBranch noBreakpoint = J_CC(CC_Z);
|
||||
ABI_PopAllCalleeSavedRegsAndAdjustStack();
|
||||
RET();
|
||||
SetJumpTarget(noBreakpoint);
|
||||
SetJumpTarget(notStepping);
|
||||
}
|
||||
|
||||
SetJumpTarget(skipToRealDispatch);
|
||||
|
||||
@@ -493,6 +493,9 @@ void JitIL::srawx(UGeckoInstruction inst)
|
||||
test = ibuild.EmitOr(val, mask2);
|
||||
test = ibuild.EmitICmpUgt(test, mask);
|
||||
ibuild.EmitStoreCarry(test);
|
||||
|
||||
if (inst.Rc)
|
||||
ComputeRC(ibuild, val);
|
||||
}
|
||||
|
||||
void JitIL::srawix(UGeckoInstruction inst)
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
#include "JitBase.h"
|
||||
#include "PowerPCDisasm.h"
|
||||
#include "disasm.h"
|
||||
|
||||
JitBase *jit;
|
||||
|
||||
|
||||
@@ -28,8 +28,7 @@
|
||||
#include "JitBackpatch.h" // for EmuCodeBlock
|
||||
#include "JitAsmCommon.h"
|
||||
|
||||
#include "PowerPCDisasm.h"
|
||||
#include "disasm.h"
|
||||
#include <set>
|
||||
|
||||
#define JIT_OPCODE 0
|
||||
|
||||
@@ -75,6 +74,8 @@ protected:
|
||||
u8* rewriteStart;
|
||||
|
||||
JitBlock *curBlock;
|
||||
|
||||
std::set<u32> fifoWriteAddresses;
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
@@ -353,6 +353,24 @@ bool JitBlock::ContainsAddress(u32 em_address)
|
||||
}
|
||||
}
|
||||
|
||||
void JitBlockCache::UnlinkBlock(int i)
|
||||
{
|
||||
JitBlock &b = blocks[i];
|
||||
std::map<u32, int>::iterator iter;
|
||||
pair<multimap<u32, int>::iterator, multimap<u32, int>::iterator> ppp;
|
||||
ppp = links_to.equal_range(b.originalAddress);
|
||||
if (ppp.first == ppp.second)
|
||||
return;
|
||||
for (multimap<u32, int>::iterator iter2 = ppp.first; iter2 != ppp.second; ++iter2) {
|
||||
JitBlock &sourceBlock = blocks[iter2->second];
|
||||
for (int e = 0; e < 2; e++)
|
||||
{
|
||||
if (sourceBlock.exitAddress[e] == b.originalAddress)
|
||||
sourceBlock.linkStatus[e] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JitBlockCache::DestroyBlock(int block_num, bool invalidate)
|
||||
{
|
||||
if (block_num < 0 || block_num >= num_blocks)
|
||||
@@ -375,7 +393,9 @@ bool JitBlock::ContainsAddress(u32 em_address)
|
||||
Memory::WriteUnchecked_U32(b.originalFirstOpcode, b.originalAddress);
|
||||
#endif
|
||||
|
||||
// We don't unlink blocks, we just send anyone who tries to run them back to the dispatcher.
|
||||
UnlinkBlock(block_num);
|
||||
|
||||
// Send anyone who tries to run this block back to the dispatcher.
|
||||
// Not entirely ideal, but .. pretty good.
|
||||
// Spurious entrances from previously linked blocks can only come through checkedEntry
|
||||
XEmitter emit((u8 *)b.checkedEntry);
|
||||
@@ -390,14 +410,31 @@ bool JitBlock::ContainsAddress(u32 em_address)
|
||||
}
|
||||
|
||||
|
||||
void JitBlockCache::InvalidateICache(u32 address)
|
||||
void JitBlockCache::InvalidateICache(u32 address, const u32 length)
|
||||
{
|
||||
address &= ~0x1f;
|
||||
// destroy JIT blocks
|
||||
// !! this works correctly under assumption that any two overlapping blocks end at the same address
|
||||
std::map<pair<u32,u32>, u32>::iterator it1 = block_map.lower_bound(std::make_pair(address, 0)), it2 = it1, it;
|
||||
while (it2 != block_map.end() && it2->first.second < address + 0x20)
|
||||
while (it2 != block_map.end() && it2->first.second < address + length)
|
||||
{
|
||||
#ifdef JIT_UNLIMITED_ICACHE
|
||||
JitBlock &b = blocks[it2->second];
|
||||
if (b.originalAddress & JIT_ICACHE_VMEM_BIT)
|
||||
{
|
||||
u32 cacheaddr = b.originalAddress & JIT_ICACHE_MASK;
|
||||
memset(iCacheVMEM + cacheaddr, JIT_ICACHE_INVALID_BYTE, 4);
|
||||
}
|
||||
else if (b.originalAddress & JIT_ICACHE_EXRAM_BIT)
|
||||
{
|
||||
u32 cacheaddr = b.originalAddress & JIT_ICACHEEX_MASK;
|
||||
memset(iCacheEx + cacheaddr, JIT_ICACHE_INVALID_BYTE, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 cacheaddr = b.originalAddress & JIT_ICACHE_MASK;
|
||||
memset(iCache + cacheaddr, JIT_ICACHE_INVALID_BYTE, 4);
|
||||
}
|
||||
#endif
|
||||
DestroyBlock(it2->second, true);
|
||||
it2++;
|
||||
}
|
||||
@@ -418,17 +455,17 @@ bool JitBlock::ContainsAddress(u32 em_address)
|
||||
if (address & JIT_ICACHE_VMEM_BIT)
|
||||
{
|
||||
u32 cacheaddr = address & JIT_ICACHE_MASK;
|
||||
memset(iCacheVMEM + cacheaddr, JIT_ICACHE_INVALID_BYTE, 32);
|
||||
memset(iCacheVMEM + cacheaddr, JIT_ICACHE_INVALID_BYTE, length);
|
||||
}
|
||||
else if (address & JIT_ICACHE_EXRAM_BIT)
|
||||
{
|
||||
u32 cacheaddr = address & JIT_ICACHEEX_MASK;
|
||||
memset(iCacheEx + cacheaddr, JIT_ICACHE_INVALID_BYTE, 32);
|
||||
memset(iCacheEx + cacheaddr, JIT_ICACHE_INVALID_BYTE, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 cacheaddr = address & JIT_ICACHE_MASK;
|
||||
memset(iCache + cacheaddr, JIT_ICACHE_INVALID_BYTE, 32);
|
||||
memset(iCache + cacheaddr, JIT_ICACHE_INVALID_BYTE, length);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -87,6 +87,7 @@ class JitBlockCache
|
||||
bool RangeIntersect(int s1, int e1, int s2, int e2) const;
|
||||
void LinkBlockExits(int i);
|
||||
void LinkBlock(int i);
|
||||
void UnlinkBlock(int i);
|
||||
|
||||
public:
|
||||
JitBlockCache() :
|
||||
@@ -129,7 +130,7 @@ public:
|
||||
CompiledCode GetCompiledCodeFromBlock(int block_num);
|
||||
|
||||
// DOES NOT WORK CORRECTLY WITH INLINING
|
||||
void InvalidateICache(u32 em_address);
|
||||
void InvalidateICache(u32 address, const u32 length);
|
||||
void DestroyBlock(int block_num, bool invalidate);
|
||||
|
||||
// Not currently used
|
||||
|
||||
@@ -110,7 +110,7 @@ namespace PowerPC
|
||||
#endif
|
||||
valid[set] = 0;
|
||||
if (jit)
|
||||
jit->GetBlockCache()->InvalidateICache(addr);
|
||||
jit->GetBlockCache()->InvalidateICache(addr & ~0x1f, 32);
|
||||
}
|
||||
|
||||
u32 InstructionCache::ReadInstruction(u32 addr)
|
||||
|
||||
@@ -389,8 +389,8 @@ void CVolumeDirectory::BuildFST()
|
||||
// write FST size and location
|
||||
_dbg_assert_(DVDINTERFACE, m_diskHeader);
|
||||
Write32((u32)(FST_ADDRESS >> m_addressShift), 0x0424, m_diskHeader);
|
||||
Write32((u32)m_fstSize, 0x0428, m_diskHeader);
|
||||
Write32((u32)m_fstSize, 0x042c, m_diskHeader);
|
||||
Write32((u32)(m_fstSize >> m_addressShift), 0x0428, m_diskHeader);
|
||||
Write32((u32)(m_fstSize >> m_addressShift), 0x042c, m_diskHeader);
|
||||
}
|
||||
|
||||
void CVolumeDirectory::WriteToBuffer(u64 _SrcStartAddress, u64 _SrcLength, u8* _Src,
|
||||
|
||||
@@ -90,7 +90,7 @@ static const wxLanguage langIds[] =
|
||||
#define EXIDEV_GECKO_STR "USBGecko"
|
||||
|
||||
#define CSTR_TRANS(a) wxString(wxGetTranslation(wxT(a))).mb_str()
|
||||
|
||||
#define WXSTR_TRANS(a) wxString(wxGetTranslation(wxT(a)))
|
||||
#ifdef WIN32
|
||||
//only used with xgettext to be picked up as translatable string.
|
||||
//win32 does not have wx on its path, the provided wxALL_FILES
|
||||
@@ -979,7 +979,7 @@ void CConfigMain::GCSettingsChanged(wxCommandEvent& event)
|
||||
case ID_GC_EXIDEVICE_SLOTB:
|
||||
exidevice++;
|
||||
case ID_GC_EXIDEVICE_SLOTA:
|
||||
ChooseEXIDevice(std::string(event.GetString().mb_str()), exidevice);
|
||||
ChooseEXIDevice(event.GetString(), exidevice);
|
||||
break;
|
||||
case ID_GC_EXIDEVICE_SLOTA_PATH:
|
||||
ChooseMemcardPath(SConfig::GetInstance().m_strMemoryCardA, true);
|
||||
@@ -994,7 +994,7 @@ void CConfigMain::GCSettingsChanged(wxCommandEvent& event)
|
||||
case ID_GC_SIDEVICE1:
|
||||
sidevice++;
|
||||
case ID_GC_SIDEVICE0:
|
||||
ChooseSIDevice(std::string(event.GetString().mb_str()), sidevice);
|
||||
ChooseSIDevice(event.GetString(), sidevice);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1044,16 +1044,16 @@ void CConfigMain::ChooseMemcardPath(std::string& strMemcard, bool isSlotA)
|
||||
}
|
||||
}
|
||||
|
||||
void CConfigMain::ChooseSIDevice(std::string deviceName, int deviceNum)
|
||||
void CConfigMain::ChooseSIDevice(wxString deviceName, int deviceNum)
|
||||
{
|
||||
SIDevices tempType;
|
||||
if (!deviceName.compare(CSTR_TRANS(SIDEV_STDCONT_STR)))
|
||||
if (!deviceName.compare(WXSTR_TRANS(SIDEV_STDCONT_STR)))
|
||||
tempType = SIDEVICE_GC_CONTROLLER;
|
||||
else if (!deviceName.compare(CSTR_TRANS(SIDEV_BONGO_STR)))
|
||||
else if (!deviceName.compare(WXSTR_TRANS(SIDEV_BONGO_STR)))
|
||||
tempType = SIDEVICE_GC_TARUKONGA;
|
||||
else if (!deviceName.compare(SIDEV_GBA_STR))
|
||||
else if (!deviceName.compare(wxT(SIDEV_GBA_STR)))
|
||||
tempType = SIDEVICE_GC_GBA;
|
||||
else if (!deviceName.compare(CSTR_TRANS(SIDEV_AM_BB_STR)))
|
||||
else if (!deviceName.compare(WXSTR_TRANS(SIDEV_AM_BB_STR)))
|
||||
tempType = SIDEVICE_AM_BASEBOARD;
|
||||
else
|
||||
tempType = SIDEVICE_NONE;
|
||||
@@ -1067,21 +1067,21 @@ void CConfigMain::ChooseSIDevice(std::string deviceName, int deviceNum)
|
||||
}
|
||||
}
|
||||
|
||||
void CConfigMain::ChooseEXIDevice(std::string deviceName, int deviceNum)
|
||||
void CConfigMain::ChooseEXIDevice(wxString deviceName, int deviceNum)
|
||||
{
|
||||
TEXIDevices tempType;
|
||||
|
||||
if (!deviceName.compare(CSTR_TRANS(EXIDEV_MEMCARD_STR)))
|
||||
if (!deviceName.compare(WXSTR_TRANS(EXIDEV_MEMCARD_STR)))
|
||||
tempType = EXIDEVICE_MEMORYCARD;
|
||||
else if (!deviceName.compare(CSTR_TRANS(EXIDEV_MIC_STR)))
|
||||
else if (!deviceName.compare(WXSTR_TRANS(EXIDEV_MIC_STR)))
|
||||
tempType = EXIDEVICE_MIC;
|
||||
else if (!deviceName.compare(EXIDEV_BBA_STR))
|
||||
else if (!deviceName.compare(wxT(EXIDEV_BBA_STR)))
|
||||
tempType = EXIDEVICE_ETH;
|
||||
else if (!deviceName.compare(CSTR_TRANS(EXIDEV_AM_BB_STR)))
|
||||
else if (!deviceName.compare(WXSTR_TRANS(EXIDEV_AM_BB_STR)))
|
||||
tempType = EXIDEVICE_AM_BASEBOARD;
|
||||
else if (!deviceName.compare(EXIDEV_GECKO_STR))
|
||||
else if (!deviceName.compare(wxT(EXIDEV_GECKO_STR)))
|
||||
tempType = EXIDEVICE_GECKO;
|
||||
else if (!deviceName.compare(CSTR_TRANS(DEV_NONE_STR)))
|
||||
else if (!deviceName.compare(WXSTR_TRANS(DEV_NONE_STR)))
|
||||
tempType = EXIDEVICE_NONE;
|
||||
else
|
||||
tempType = EXIDEVICE_DUMMY;
|
||||
|
||||
@@ -253,8 +253,8 @@ private:
|
||||
|
||||
void GCSettingsChanged(wxCommandEvent& event);
|
||||
void ChooseMemcardPath(std::string& strMemcard, bool isSlotA);
|
||||
void ChooseSIDevice(std::string deviceName, int deviceNum);
|
||||
void ChooseEXIDevice(std::string deviceName, int deviceNum);
|
||||
void ChooseSIDevice(wxString deviceName, int deviceNum);
|
||||
void ChooseEXIDevice(wxString deviceName, int deviceNum);
|
||||
|
||||
void WiiSettingsChanged(wxCommandEvent& event);
|
||||
// Change from IPL.LNG value to country code
|
||||
|
||||
@@ -263,6 +263,8 @@ void CCodeWindow::SingleStep()
|
||||
{
|
||||
if (CCPU::IsStepping())
|
||||
{
|
||||
if (jit)
|
||||
jit->GetBlockCache()->InvalidateICache(PC, 4);
|
||||
CCPU::StepOpcode(&sync_event);
|
||||
wxThread::Sleep(20);
|
||||
// need a short wait here
|
||||
|
||||
@@ -41,7 +41,7 @@ CLogWindow::CLogWindow(CFrame *parent, wxWindowID id, const wxPoint& pos,
|
||||
, x(0), y(0), winpos(0)
|
||||
, Parent(parent), m_ignoreLogTimer(false), m_LogAccess(true)
|
||||
, m_Log(NULL), m_cmdline(NULL), m_FontChoice(NULL)
|
||||
, m_SJISConv(wxConvLocal)
|
||||
, m_SJISConv(wxT(""))
|
||||
{
|
||||
#ifdef _WIN32
|
||||
static bool validCP932 = ::IsValidCodePage(932) != 0;
|
||||
@@ -52,6 +52,7 @@ CLogWindow::CLogWindow(CFrame *parent, wxWindowID id, const wxPoint& pos,
|
||||
else
|
||||
{
|
||||
WARN_LOG(COMMON, "Cannot Convert from Charset Windows Japanese cp 932");
|
||||
m_SJISConv = *(wxCSConv*)wxConvCurrent;
|
||||
}
|
||||
#else
|
||||
// on linux the wrong string is returned from wxFontMapper::GetEncodingName(wxFONTENCODING_SHIFT_JIS)
|
||||
|
||||
@@ -56,11 +56,12 @@ static bool bProcessFifoToLoWatermark = false;
|
||||
static bool bProcessFifoAllDistance = false;
|
||||
|
||||
volatile bool isPossibleWaitingSetDrawDone = false;
|
||||
volatile bool isHiWatermarkActive = false;
|
||||
volatile bool interruptSet= false;
|
||||
volatile bool interruptWaiting= false;
|
||||
volatile bool interruptTokenWaiting = false;
|
||||
volatile bool interruptFinishWaiting = false;
|
||||
volatile bool OnOverflow = false;
|
||||
volatile bool waitingForPEInterruptDisable = false;
|
||||
|
||||
bool IsOnThread()
|
||||
{
|
||||
@@ -86,13 +87,12 @@ void DoState(PointerWrap &p)
|
||||
|
||||
p.Do(bProcessFifoToLoWatermark);
|
||||
p.Do(bProcessFifoAllDistance);
|
||||
|
||||
p.Do(isHiWatermarkActive);
|
||||
p.Do(isPossibleWaitingSetDrawDone);
|
||||
p.Do(interruptSet);
|
||||
p.Do(interruptWaiting);
|
||||
p.Do(interruptTokenWaiting);
|
||||
p.Do(interruptFinishWaiting);
|
||||
p.Do(OnOverflow);
|
||||
}
|
||||
|
||||
inline void WriteLow (volatile u32& _reg, u16 lowbits) {Common::AtomicStore(_reg,(_reg & 0xFFFF0000) | lowbits);}
|
||||
@@ -135,16 +135,14 @@ void Init()
|
||||
bProcessFifoToLoWatermark = false;
|
||||
bProcessFifoAllDistance = false;
|
||||
isPossibleWaitingSetDrawDone = false;
|
||||
OnOverflow = false;
|
||||
isHiWatermarkActive = false;
|
||||
|
||||
et_UpdateInterrupts = CoreTiming::RegisterEvent("UpdateInterrupts", UpdateInterrupts_Wrapper);
|
||||
}
|
||||
|
||||
void Read16(u16& _rReturnValue, const u32 _Address)
|
||||
{
|
||||
|
||||
INFO_LOG(COMMANDPROCESSOR, "(r): 0x%08x", _Address);
|
||||
ProcessFifoEvents();
|
||||
switch (_Address & 0xFFF)
|
||||
{
|
||||
case STATUS_REGISTER:
|
||||
@@ -173,11 +171,23 @@ void Read16(u16& _rReturnValue, const u32 _Address)
|
||||
case FIFO_LO_WATERMARK_HI: _rReturnValue = ReadHigh(fifo.CPLoWatermark); return;
|
||||
|
||||
case FIFO_RW_DISTANCE_LO:
|
||||
_rReturnValue = ReadLow (fifo.CPReadWriteDistance);
|
||||
if (IsOnThread())
|
||||
if(fifo.CPWritePointer >= fifo.SafeCPReadPointer)
|
||||
_rReturnValue = ReadLow (fifo.CPWritePointer - fifo.SafeCPReadPointer);
|
||||
else
|
||||
_rReturnValue = ReadLow (fifo.CPEnd - fifo.SafeCPReadPointer + fifo.CPWritePointer - fifo.CPBase + 32);
|
||||
else
|
||||
_rReturnValue = ReadLow (fifo.CPReadWriteDistance);
|
||||
DEBUG_LOG(COMMANDPROCESSOR, "read FIFO_RW_DISTANCE_LO : %04x", _rReturnValue);
|
||||
return;
|
||||
case FIFO_RW_DISTANCE_HI:
|
||||
_rReturnValue = ReadHigh(fifo.CPReadWriteDistance);
|
||||
if (IsOnThread())
|
||||
if(fifo.CPWritePointer >= fifo.SafeCPReadPointer)
|
||||
_rReturnValue = ReadHigh (fifo.CPWritePointer - fifo.SafeCPReadPointer);
|
||||
else
|
||||
_rReturnValue = ReadHigh (fifo.CPEnd - fifo.SafeCPReadPointer + fifo.CPWritePointer - fifo.CPBase + 32);
|
||||
else
|
||||
_rReturnValue = ReadHigh(fifo.CPReadWriteDistance);
|
||||
DEBUG_LOG(COMMANDPROCESSOR, "read FIFO_RW_DISTANCE_HI : %04x", _rReturnValue);
|
||||
return;
|
||||
case FIFO_WRITE_POINTER_LO:
|
||||
@@ -358,6 +368,7 @@ void Write16(const u16 _Value, const u32 _Address)
|
||||
break;
|
||||
case FIFO_READ_POINTER_HI:
|
||||
WriteHigh((u32 &)fifo.CPReadPointer, _Value);
|
||||
fifo.SafeCPReadPointer = fifo.CPReadPointer;
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_READ_POINTER_HI : %04x", _Value);
|
||||
break;
|
||||
|
||||
@@ -390,10 +401,6 @@ void Write16(const u16 _Value, const u32 _Address)
|
||||
|
||||
case FIFO_RW_DISTANCE_HI:
|
||||
WriteHigh((u32 &)fifo.CPReadWriteDistance, _Value);
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"try to write to FIFO_RW_DISTANCE_HI : %04x", _Value);
|
||||
break;
|
||||
case FIFO_RW_DISTANCE_LO:
|
||||
WriteLow((u32 &)fifo.CPReadWriteDistance, _Value & 0xFFE0);
|
||||
if (fifo.CPReadWriteDistance == 0)
|
||||
{
|
||||
GPFifo::ResetGatherPipe();
|
||||
@@ -403,6 +410,10 @@ void Write16(const u16 _Value, const u32 _Address)
|
||||
ResetVideoBuffer();
|
||||
}
|
||||
IncrementCheckContextId();
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"try to write to FIFO_RW_DISTANCE_HI : %04x", _Value);
|
||||
break;
|
||||
case FIFO_RW_DISTANCE_LO:
|
||||
WriteLow((u32 &)fifo.CPReadWriteDistance, _Value & 0xFFE0);
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"try to write to FIFO_RW_DISTANCE_LO : %04x", _Value);
|
||||
break;
|
||||
|
||||
@@ -412,7 +423,6 @@ void Write16(const u16 _Value, const u32 _Address)
|
||||
|
||||
if (!IsOnThread())
|
||||
RunGpu();
|
||||
ProcessFifoEvents();
|
||||
}
|
||||
|
||||
void Read32(u32& _rReturnValue, const u32 _Address)
|
||||
@@ -434,6 +444,19 @@ void STACKALIGN GatherPipeBursted()
|
||||
{
|
||||
if (!IsOnThread())
|
||||
RunGpu();
|
||||
else
|
||||
{
|
||||
// In multibuffer mode is not allowed write in the same fifo attached to the GPU.
|
||||
// Fix Pokemon XD in DC mode.
|
||||
if((ProcessorInterface::Fifo_CPUEnd == fifo.CPEnd) && (ProcessorInterface::Fifo_CPUBase == fifo.CPBase)
|
||||
&& fifo.CPReadWriteDistance > 0)
|
||||
{
|
||||
waitingForPEInterruptDisable = true;
|
||||
ProcessFifoAllDistance();
|
||||
waitingForPEInterruptDisable = false;
|
||||
}
|
||||
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -449,26 +472,7 @@ void STACKALIGN GatherPipeBursted()
|
||||
Common::AtomicAdd(fifo.CPReadWriteDistance, GATHER_PIPE_SIZE);
|
||||
|
||||
if (!IsOnThread())
|
||||
{
|
||||
RunGpu();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(fifo.CPReadWriteDistance == fifo.CPEnd - fifo.CPBase - 32)
|
||||
{
|
||||
if(!OnOverflow)
|
||||
NOTICE_LOG(COMMANDPROCESSOR,"FIFO is almost in overflown, BreakPoint: %i", fifo.bFF_Breakpoint);
|
||||
OnOverflow = true;
|
||||
while (!CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable &&
|
||||
fifo.CPReadWriteDistance > fifo.CPEnd - fifo.CPBase - 64)
|
||||
Common::YieldCPU();
|
||||
}
|
||||
else
|
||||
{
|
||||
OnOverflow = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_assert_msg_(COMMANDPROCESSOR, fifo.CPReadWriteDistance <= fifo.CPEnd - fifo.CPBase,
|
||||
"FIFO is overflown by GatherPipe !\nCPU thread is too fast!");
|
||||
@@ -509,17 +513,15 @@ void AbortFrame()
|
||||
|
||||
void SetOverflowStatusFromGatherPipe()
|
||||
{
|
||||
if (!fifo.bFF_HiWatermarkInt) return;
|
||||
|
||||
fifo.bFF_HiWatermark = (fifo.CPReadWriteDistance > fifo.CPHiWatermark);
|
||||
fifo.bFF_LoWatermark = (fifo.CPReadWriteDistance < fifo.CPLoWatermark);
|
||||
|
||||
bool interrupt = fifo.bFF_HiWatermark && fifo.bFF_HiWatermarkInt &&
|
||||
m_CPCtrlReg.GPLinkEnable && m_CPCtrlReg.GPReadEnable;
|
||||
isHiWatermarkActive = fifo.bFF_HiWatermark && fifo.bFF_HiWatermarkInt && m_CPCtrlReg.GPReadEnable;
|
||||
|
||||
if (interrupt != interruptSet && interrupt)
|
||||
CommandProcessor::UpdateInterrupts(true);
|
||||
|
||||
if (isHiWatermarkActive)
|
||||
{
|
||||
interruptSet = true;
|
||||
INFO_LOG(COMMANDPROCESSOR,"Interrupt set");
|
||||
ProcessorInterface::SetInterrupt(INT_CAUSE_CP, true);
|
||||
}
|
||||
}
|
||||
|
||||
void SetCpStatus()
|
||||
@@ -527,14 +529,12 @@ void SetCpStatus()
|
||||
// overflow & underflow check
|
||||
fifo.bFF_HiWatermark = (fifo.CPReadWriteDistance > fifo.CPHiWatermark);
|
||||
fifo.bFF_LoWatermark = (fifo.CPReadWriteDistance < fifo.CPLoWatermark);
|
||||
|
||||
// breakpoint
|
||||
|
||||
// breakpoint
|
||||
if (fifo.bFF_BPEnable)
|
||||
{
|
||||
if (fifo.CPBreakpoint == fifo.CPReadPointer)
|
||||
{
|
||||
|
||||
{
|
||||
if (!fifo.bFF_Breakpoint)
|
||||
{
|
||||
INFO_LOG(COMMANDPROCESSOR, "Hit breakpoint at %i", fifo.CPReadPointer);
|
||||
@@ -562,13 +562,18 @@ void SetCpStatus()
|
||||
|
||||
bool interrupt = (bpInt || ovfInt || undfInt) && m_CPCtrlReg.GPReadEnable;
|
||||
|
||||
isHiWatermarkActive = ovfInt && m_CPCtrlReg.GPReadEnable;
|
||||
|
||||
if (interrupt != interruptSet && !interruptWaiting)
|
||||
{
|
||||
u64 userdata = interrupt?1:0;
|
||||
if (IsOnThread())
|
||||
{
|
||||
interruptWaiting = true;
|
||||
CommandProcessor::UpdateInterruptsFromVideoBackend(userdata);
|
||||
if(!interrupt || bpInt || undfInt)
|
||||
{
|
||||
interruptWaiting = true;
|
||||
CommandProcessor::UpdateInterruptsFromVideoBackend(userdata);
|
||||
}
|
||||
}
|
||||
else
|
||||
CommandProcessor::UpdateInterrupts(userdata);
|
||||
@@ -591,7 +596,7 @@ void ProcessFifoAllDistance()
|
||||
if (IsOnThread())
|
||||
{
|
||||
while (!CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable &&
|
||||
fifo.CPReadWriteDistance && !AtBreakpoint())
|
||||
fifo.CPReadWriteDistance && !AtBreakpoint() && !PixelEngine::WaitingForPEInterrupt())
|
||||
Common::YieldCPU();
|
||||
}
|
||||
bProcessFifoAllDistance = false;
|
||||
@@ -611,13 +616,16 @@ void Shutdown()
|
||||
void SetCpStatusRegister()
|
||||
{
|
||||
// Here always there is one fifo attached to the GPU
|
||||
|
||||
m_CPStatusReg.Breakpoint = fifo.bFF_Breakpoint;
|
||||
m_CPStatusReg.ReadIdle = (fifo.CPReadPointer == fifo.CPWritePointer) || (fifo.CPReadPointer == fifo.CPBreakpoint);
|
||||
m_CPStatusReg.ReadIdle = !fifo.CPReadWriteDistance || (fifo.CPReadPointer == fifo.CPWritePointer) || (fifo.CPReadPointer == fifo.CPBreakpoint) ;
|
||||
m_CPStatusReg.CommandIdle = !fifo.CPReadWriteDistance;
|
||||
m_CPStatusReg.UnderflowLoWatermark = fifo.bFF_LoWatermark;
|
||||
m_CPStatusReg.OverflowHiWatermark = fifo.bFF_HiWatermark;
|
||||
|
||||
// HACK to compensate for slow response to PE interrupts in Time Splitters: Future Perfect
|
||||
if (IsOnThread())
|
||||
PixelEngine::ResumeWaitingForPEInterrupt();
|
||||
|
||||
INFO_LOG(COMMANDPROCESSOR,"\t Read from STATUS_REGISTER : %04x", m_CPStatusReg.Hex);
|
||||
DEBUG_LOG(COMMANDPROCESSOR, "(r) status: iBP %s | fReadIdle %s | fCmdIdle %s | iOvF %s | iUndF %s"
|
||||
, m_CPStatusReg.Breakpoint ? "ON" : "OFF"
|
||||
@@ -630,14 +638,14 @@ void SetCpStatusRegister()
|
||||
|
||||
void SetCpControlRegister()
|
||||
{
|
||||
|
||||
// If the new fifo is being attached We make sure there wont be SetFinish event pending.
|
||||
// This protection fix eternal darkness booting, because the second SetFinish event when it is booting
|
||||
// seems invalid or has a bug and hang the game.
|
||||
|
||||
if (!fifo.bFF_GPReadEnable && m_CPCtrlReg.GPReadEnable && !m_CPCtrlReg.BPEnable)
|
||||
{
|
||||
PixelEngine::ResetSetFinish();
|
||||
ProcessFifoEvents();
|
||||
PixelEngine::ResetSetFinish();
|
||||
}
|
||||
|
||||
fifo.bFF_BPInt = m_CPCtrlReg.BPInt;
|
||||
@@ -652,9 +660,6 @@ void SetCpControlRegister()
|
||||
ProcessorInterface::Fifo_CPUBase = fifo.CPBase;
|
||||
ProcessorInterface::Fifo_CPUEnd = fifo.CPEnd;
|
||||
}
|
||||
// If overflown happens process the fifo to LoWatemark
|
||||
if (bProcessFifoToLoWatermark)
|
||||
ProcessFifoToLoWatermark();
|
||||
|
||||
if(fifo.bFF_GPReadEnable && !m_CPCtrlReg.GPReadEnable)
|
||||
{
|
||||
@@ -666,7 +671,6 @@ void SetCpControlRegister()
|
||||
fifo.bFF_GPReadEnable = m_CPCtrlReg.GPReadEnable;
|
||||
}
|
||||
|
||||
|
||||
DEBUG_LOG(COMMANDPROCESSOR, "\t GPREAD %s | BP %s | Int %s | OvF %s | UndF %s | LINK %s"
|
||||
, fifo.bFF_GPReadEnable ? "ON" : "OFF"
|
||||
, fifo.bFF_BPEnable ? "ON" : "OFF"
|
||||
|
||||
@@ -25,18 +25,18 @@ class PointerWrap;
|
||||
|
||||
extern bool MT;
|
||||
|
||||
|
||||
namespace CommandProcessor
|
||||
{
|
||||
|
||||
extern SCPFifoStruct fifo; //This one is shared between gfx thread and emulator thread.
|
||||
extern volatile bool isPossibleWaitingSetDrawDone; //This one is used for sync gfx thread and emulator thread.
|
||||
extern volatile bool isHiWatermarkActive;
|
||||
extern volatile bool interruptSet;
|
||||
extern volatile bool interruptWaiting;
|
||||
extern volatile bool interruptTokenWaiting;
|
||||
extern volatile bool interruptFinishWaiting;
|
||||
extern volatile bool OnOverflow;
|
||||
|
||||
extern volatile bool waitingForPEInterruptDisable;
|
||||
|
||||
// internal hardware addresses
|
||||
enum
|
||||
{
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "Atomic.h"
|
||||
#include "OpcodeDecoding.h"
|
||||
#include "CommandProcessor.h"
|
||||
#include "PixelEngine.h"
|
||||
#include "ChunkFile.h"
|
||||
#include "Fifo.h"
|
||||
#include "HW/Memmap.h"
|
||||
@@ -137,8 +138,7 @@ void RunGpuLoop()
|
||||
|
||||
CommandProcessor::SetCpStatus();
|
||||
// check if we are able to run this buffer
|
||||
while (!CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable &&
|
||||
fifo.CPReadWriteDistance && (!AtBreakpoint() || CommandProcessor::OnOverflow))
|
||||
while (GpuRunningState && !CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint() && !PixelEngine::WaitingForPEInterrupt())
|
||||
{
|
||||
if (!GpuRunningState) break;
|
||||
|
||||
|
||||
@@ -250,6 +250,11 @@ bool VideoBackendHardware::Video_IsPossibleWaitingSetDrawDone()
|
||||
return CommandProcessor::isPossibleWaitingSetDrawDone;
|
||||
}
|
||||
|
||||
bool VideoBackendHardware::Video_IsHiWatermarkActive()
|
||||
{
|
||||
return CommandProcessor::isHiWatermarkActive;
|
||||
}
|
||||
|
||||
void VideoBackendHardware::Video_AbortFrame()
|
||||
{
|
||||
CommandProcessor::AbortFrame();
|
||||
|
||||
@@ -180,7 +180,6 @@ void Init()
|
||||
void Read16(u16& _uReturnValue, const u32 _iAddress)
|
||||
{
|
||||
DEBUG_LOG(PIXELENGINE, "(r16) 0x%08x", _iAddress);
|
||||
CommandProcessor::ProcessFifoEvents();
|
||||
switch (_iAddress & 0xFFF)
|
||||
{
|
||||
// CPU Direct Access EFB Raster State Config
|
||||
@@ -327,7 +326,6 @@ void Write16(const u16 _iValue, const u32 _iAddress)
|
||||
break;
|
||||
|
||||
case PE_TOKEN_REG:
|
||||
//LOG(PIXELENGINE,"WEIRD: program wrote token: %i",_iValue);
|
||||
PanicAlert("(w16) WTF? PowerPC program wrote token: %i", _iValue);
|
||||
//only the gx pipeline is supposed to be able to write here
|
||||
//g_token = _iValue;
|
||||
@@ -338,7 +336,6 @@ void Write16(const u16 _iValue, const u32 _iAddress)
|
||||
break;
|
||||
}
|
||||
|
||||
CommandProcessor::ProcessFifoEvents();
|
||||
}
|
||||
|
||||
void Write32(const u32 _iValue, const u32 _iAddress)
|
||||
@@ -362,22 +359,16 @@ void UpdateInterrupts()
|
||||
|
||||
void UpdateTokenInterrupt(bool active)
|
||||
{
|
||||
if(interruptSetToken != active)
|
||||
{
|
||||
ProcessorInterface::SetInterrupt(INT_CAUSE_PE_TOKEN, active);
|
||||
interruptSetToken = active;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateFinishInterrupt(bool active)
|
||||
{
|
||||
if(interruptSetFinish != active)
|
||||
{
|
||||
ProcessorInterface::SetInterrupt(INT_CAUSE_PE_FINISH, active);
|
||||
interruptSetFinish = active;
|
||||
if (active)
|
||||
State::ProcessRequestedStates(0);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(mb2): Refactor SetTokenINT_OnMainThread(u64 userdata, int cyclesLate).
|
||||
@@ -396,8 +387,6 @@ void SetToken_OnMainThread(u64 userdata, int cyclesLate)
|
||||
CommandProcessor::interruptTokenWaiting = false;
|
||||
IncrementCheckContextId();
|
||||
//}
|
||||
//else
|
||||
// LOGV(PIXELENGINE, 1, "VIDEO Backend wrote token: %i", CommandProcessor::fifo.PEToken);
|
||||
}
|
||||
|
||||
void SetFinish_OnMainThread(u64 userdata, int cyclesLate)
|
||||
@@ -474,4 +463,17 @@ void ResetSetToken()
|
||||
}
|
||||
CommandProcessor::interruptTokenWaiting = false;
|
||||
}
|
||||
|
||||
bool WaitingForPEInterrupt()
|
||||
{
|
||||
return !CommandProcessor::waitingForPEInterruptDisable && (CommandProcessor::interruptFinishWaiting || CommandProcessor::interruptTokenWaiting || interruptSetFinish || interruptSetToken);
|
||||
}
|
||||
|
||||
void ResumeWaitingForPEInterrupt()
|
||||
{
|
||||
interruptSetFinish = false;
|
||||
interruptSetToken = false;
|
||||
CommandProcessor::interruptFinishWaiting = false;
|
||||
CommandProcessor::interruptTokenWaiting = false;
|
||||
}
|
||||
} // end of namespace PixelEngine
|
||||
|
||||
@@ -80,7 +80,8 @@ void SetToken(const u16 _token, const int _bSetTokenAcknowledge);
|
||||
void SetFinish(void);
|
||||
void ResetSetFinish(void);
|
||||
void ResetSetToken(void);
|
||||
bool AllowIdleSkipping();
|
||||
bool WaitingForPEInterrupt();
|
||||
void ResumeWaitingForPEInterrupt();
|
||||
|
||||
// Bounding box functionality. Paper Mario (both) are a couple of the few games that use it.
|
||||
extern u16 bbox[4];
|
||||
|
||||
@@ -172,8 +172,10 @@ void TextureCache::ClearRenderTargets()
|
||||
TexCache::iterator
|
||||
iter = textures.begin(),
|
||||
tcend = textures.end();
|
||||
|
||||
for (; iter!=tcend; ++iter)
|
||||
iter->second->type = TCET_NORMAL;
|
||||
if (iter->second->type != TCET_EC_DYNAMIC)
|
||||
iter->second->type = TCET_NORMAL;
|
||||
}
|
||||
|
||||
TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
|
||||
@@ -238,6 +240,9 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
|
||||
// 2. a) For EFB copies, only the hash and the texture address need to match
|
||||
if (entry->IsEfbCopy() && tex_hash == entry->hash && address == entry->addr)
|
||||
{
|
||||
if (entry->type != TCET_EC_VRAM)
|
||||
entry->type = TCET_NORMAL;
|
||||
|
||||
// TODO: Print a warning if the format changes! In this case, we could reinterpret the internal texture object data to the new pixel format (similiar to what is already being done in Renderer::ReinterpretPixelFormat())
|
||||
goto return_entry;
|
||||
}
|
||||
@@ -318,8 +323,8 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
|
||||
entry->SetGeneralParameters(address, texture_size, full_format, entry->num_mipmaps);
|
||||
entry->SetDimensions(nativeW, nativeH, width, height);
|
||||
entry->hash = tex_hash;
|
||||
if (g_ActiveConfig.bCopyEFBToTexture) entry->type = TCET_NORMAL;
|
||||
else if (entry->IsEfbCopy()) entry->type = TCET_EC_DYNAMIC;
|
||||
if (entry->IsEfbCopy() && !g_ActiveConfig.bCopyEFBToTexture) entry->type = TCET_EC_DYNAMIC;
|
||||
else entry->type = TCET_NORMAL;
|
||||
|
||||
// load texture
|
||||
entry->Load(width, height, expandedWidth, 0, (texLevels == 0));
|
||||
@@ -647,8 +652,11 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat
|
||||
if ((entry->type == TCET_EC_VRAM && entry->virtual_width == scaled_tex_w && entry->virtual_height == scaled_tex_h)
|
||||
|| (entry->type == TCET_EC_DYNAMIC && entry->native_width == tex_w && entry->native_height == tex_h))
|
||||
{
|
||||
scaled_tex_w = tex_w;
|
||||
scaled_tex_h = tex_h;
|
||||
if (entry->type == TCET_EC_DYNAMIC)
|
||||
{
|
||||
scaled_tex_w = tex_w;
|
||||
scaled_tex_h = tex_h;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -215,6 +215,12 @@ bool VideoSoftware::Video_IsPossibleWaitingSetDrawDone(void)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VideoSoftware::Video_IsHiWatermarkActive(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void VideoSoftware::Video_AbortFrame(void)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ class VideoSoftware : public VideoBackend
|
||||
void Video_SetRendering(bool bEnabled);
|
||||
|
||||
void Video_GatherPipeBursted();
|
||||
|
||||
bool Video_IsHiWatermarkActive();
|
||||
bool Video_IsPossibleWaitingSetDrawDone();
|
||||
void Video_AbortFrame();
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
<FunctionLevelLinking>false</FunctionLevelLinking>
|
||||
<PreprocessorDefinitions>_SECURE_SCL=0;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
|
||||
<FloatingPointModel>Fast</FloatingPointModel>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
|
||||
Reference in New Issue
Block a user