1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-22 02:32:36 +01:00
DH 2012-11-15 01:39:56 +02:00
parent de070bf485
commit a90b5cf37a
1998 changed files with 1034301 additions and 0 deletions

11486
GL/glext.h Normal file

File diff suppressed because it is too large Load Diff

267
Utilities/Array.h Normal file
View File

@ -0,0 +1,267 @@
#pragma once
template<typename T> class Array
{
u32 m_count;
T* m_array;
public:
Array()
: m_count(0)
, m_array(NULL)
{
}
~Array()
{
Clear();
}
inline bool RemoveAt(const u32 from, const u32 count = 1)
{
if(!GetCount()) return false;
const u32 to = from + count;
if(to > GetCount()) return false;
memmove(m_array + from, m_array + to, (m_count-to) * sizeof(T));
m_count -= count;
return true;
}
void InsertRoomEnd(const u32 size)
{
_InsertRoomEnd(size);
}
bool InsertRoom(const u32 pos, const u32 size)
{
if(pos >= m_count) return false;
_InsertRoomEnd(size);
memmove(m_array + pos + size, m_array + pos, sizeof(T) * (m_count - size - pos));
return true;
}
bool Insert(const u32 pos, T* data)
{
if(!InsertRoom(pos, 1)) return false;
memmove(m_array + pos, data, sizeof(T));
return true;
}
bool Insert(const u32 pos, T& data)
{
return Insert(pos, &data);
}
bool InsertCpy(const u32 pos, const T* data)
{
if(!InsertRoom(pos, 1)) return false;
memcpy(m_array + pos, data, sizeof(T));
return true;
}
bool InsertCpy(const u32 pos, const T& data)
{
return InsertCpy(pos, &data);
}
inline u32 Add(T* data)
{
_InsertRoomEnd(1);
memmove(m_array + GetCount() - 1, data, sizeof(T));
return m_count - 1;
}
inline u32 Add(T& data)
{
return Add(&data);
}
inline u32 AddCpy(const T* data)
{
_InsertRoomEnd(1);
memcpy(m_array + GetCount() - 1, data, sizeof(T));
return m_count - 1;
}
inline u32 AddCpy(const T& data)
{
return AddCpy(&data);
}
inline void Clear()
{
m_count = 0;
safe_delete(m_array);
}
inline T& Get(u32 num)
{
//if(num >= GetCount()) return *new T();
return m_array[num];
}
u32 GetCount() const { return m_count; }
void SetCount(const u32 count, bool memzero = true)
{
if(GetCount() >= count) return;
_InsertRoomEnd(count - GetCount());
if(memzero) memset(m_array + GetCount(), 0, count - GetCount());
}
void Reserve(const u32 count)
{
SetCount(GetCount() + count);
}
void AppendFrom(const Array<T>& src)
{
if(!src.GetCount()) return;
Reserve(src.GetCount());
memcpy(m_array, &src[0], GetCount() * sizeof(T));
}
void CopyFrom(const Array<T>& src)
{
Clear();
AppendFrom(src);
}
T& operator[](u32 num) const { return m_array[num]; }
protected:
void _InsertRoomEnd(const u32 size)
{
if(!size) return;
m_array = m_count ? (T*)realloc(m_array, sizeof(T) * (m_count + size)) : (T*)malloc(sizeof(T) * size);
m_count += size;
}
};
template<typename T> struct Stack : public Array<T>
{
Stack() : Array<T>()
{
}
~Stack()
{
Clear();
}
void Push(const T data) { AddCpy(data); }
T Pop()
{
const u32 pos = GetCount() - 1;
const T ret = Get(pos);
RemoveAt(pos);
return ret;
}
};
template<typename T> class ArrayF
{
u32 m_count;
T** m_array;
public:
ArrayF()
: m_count(0)
, m_array(NULL)
{
}
~ArrayF()
{
Clear();
}
inline bool RemoveFAt(const u32 from, const u32 count = 1)
{
if(from + count > m_count) return false;
memmove(&m_array[from], &m_array[from+count], (m_count-(from+count)) * sizeof(T**));
m_count -= count;
return true;
}
inline bool RemoveAt(const u32 from, const u32 count = 1)
{
if(from + count > m_count) return false;
for(uint i = from; i < from + count; ++i)
{
free(m_array[i]);
}
return RemoveFAt(from, count);
}
inline u32 Add(T& data)
{
return Add(&data);
}
inline u32 Add(T* data)
{
if(!m_array)
{
m_array = (T**)malloc(sizeof(T*));
}
else
{
m_array = (T**)realloc(m_array, sizeof(T*) * (m_count + 1));
}
m_array[m_count] = data;
return m_count++;
}
inline void ClearF()
{
if(m_count == 0) return;
m_count = 0;
m_array = NULL;
}
inline void Clear()
{
if(m_count == 0) return;
m_count = 0;
safe_delete(m_array);
}
inline T& Get(const u64 num)
{
//if(m_count <= num) *m_array[0]; //TODO
return *m_array[num];
}
inline u32 GetCount() const { return m_count; }
T& operator[](u32 num) const { return *m_array[num]; }
};

136
Utilities/IdManager.h Normal file
View File

@ -0,0 +1,136 @@
#pragma once
#include "Array.h"
typedef u32 ID_TYPE;
struct ID
{
bool m_used;
wxString m_name;
u8 m_attr;
void* m_data;
ID(bool used = false, const wxString& name = wxEmptyString, void* data = NULL, const u8 attr = 0)
: m_used(used)
, m_name(name)
, m_data(data)
, m_attr(attr)
{
}
};
class IdManager
{
ArrayF<ID> IDs;
static const u64 first_id = 1;
void Cleanup()
{
while(IDs.GetCount())
{
const u32 num = IDs.GetCount()-1;
ID& id = IDs[num];
if(id.m_used) break;
IDs.RemoveAt(num);
}
}
public:
IdManager()
{
}
~IdManager()
{
Clear();
}
static ID_TYPE GetMaxID()
{
return (ID_TYPE)-1;
}
bool CheckID(const u64 id)
{
if(id == 0 || id > (u64)NumToID(IDs.GetCount()-1) || id >= GetMaxID()) return false;
return IDs[IDToNum(id)].m_used;
}
__forceinline const ID_TYPE NumToID(const ID_TYPE num) const
{
return num + first_id;
}
__forceinline const ID_TYPE IDToNum(const ID_TYPE id) const
{
return id - first_id;
}
void Clear()
{
IDs.Clear();
}
virtual ID_TYPE GetNewID(const wxString& name = wxEmptyString, void* data = NULL, const u8 attr = 0)
{
for(uint i=0; i<IDs.GetCount(); ++i)
{
if(IDs[i].m_used) continue;
return NumToID(i);
}
const ID_TYPE pos = IDs.GetCount();
if(NumToID(pos) >= GetMaxID()) return 0;
IDs.Add(new ID(true, name, data, attr));
return NumToID(pos);
}
ID& GetIDData(const ID_TYPE _id)
{
//if(!CheckID(_id)) return IDs.Get(0); //TODO
return IDs[IDToNum(_id)];
}
bool GetFirst(ID& dst, ID_TYPE* _id = NULL)
{
u32 pos = 0;
return GetNext(pos, dst, _id);
}
bool HasID(const s64 id)
{
if(id == wxID_ANY) return IDs.GetCount() != 0;
return CheckID(id);
}
bool GetNext(u32& pos, ID& dst, ID_TYPE* _id = NULL)
{
while(pos < IDs.GetCount())
{
ID& id = IDs[pos++];
if(!id.m_used) continue;
dst = id;
if(_id) *_id = NumToID(pos - 1);
return true;
}
return false;
}
virtual bool RemoveID(const ID_TYPE _id, bool free_data = true)
{
if(!CheckID(_id)) return false;
ID& id = IDs[IDToNum(_id)];
if(!id.m_used) return false;
id.m_used = false;
id.m_attr = 0;
id.m_name.Clear();
if(free_data) free(id.m_data);
id.m_data = NULL;
if(IDToNum(_id) == IDs.GetCount()-1) Cleanup();
return true;
}
};

View File

@ -0,0 +1,98 @@
#pragma once
class MTProgressDialog : public wxDialog
{
wxGauge** m_gauge;
wxStaticText** m_msg;
wxArrayLong m_maximum;
const u8 m_cores;
static const uint layout = 16;
static const uint maxdial = 65536;
wxArrayInt m_lastupdate;
public:
MTProgressDialog(wxWindow* parent, const wxSize& size, const wxString& title,
const wxString& msg, const wxArrayLong& maximum, const u8 cores)
: wxDialog(parent, wxID_ANY, title, wxDefaultPosition)
, m_maximum(maximum)
, m_cores(cores)
{
wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
m_gauge = new wxGauge*[m_cores];
m_msg = new wxStaticText*[m_cores];
m_lastupdate.SetCount(cores);
for(uint i=0; i<m_cores; ++i)
{
m_lastupdate[i] = -1;
m_msg[i] = new wxStaticText(this, wxID_ANY, msg);
sizer->Add(m_msg[i], 0, wxLEFT | wxTOP, layout);
m_gauge[i] = new wxGauge(this, wxID_ANY, maxdial,
wxDefaultPosition, wxDefaultSize,
wxGA_HORIZONTAL );
sizer->Add(m_gauge[i], 0, wxLEFT | wxRIGHT | wxTOP | wxEXPAND, layout);
m_gauge[i]->SetValue(0);
sizer->AddSpacer(5);
}
SetSizerAndFit(sizer);
if(size != wxDefaultSize)
{
SetSize(size);
}
else
{
wxSize ws;
ws.x = 400;
ws.y = GetSize().y + 8;
SetSize(ws);
}
m_maximum.SetCount(m_cores);
Show();
}
__forceinline void Update(const u8 thread_id, const u64 value, const wxString& msg)
{
if(thread_id > m_cores) return;
const int curupdate = (int)(((double)value/(double)m_maximum[thread_id])*1000);
if(curupdate == m_lastupdate[thread_id]) return;
m_lastupdate[thread_id] = curupdate;
m_msg[thread_id]->SetLabel(msg);
if(value >= (u32)m_maximum[thread_id]) return;
m_gauge[thread_id]->SetValue(((double)value / (double)m_maximum[thread_id]) * maxdial);
}
const u32 GetMaxValue(const uint thread_id) const
{
if(thread_id > m_cores) return 0;
return m_maximum[thread_id];
}
void SetMaxFor(const uint thread_id, const u64 val)
{
if(thread_id > m_cores) return;
m_maximum[thread_id] = val;
m_lastupdate[thread_id] = 0;
}
virtual void Close(bool force = false)
{
m_lastupdate.Empty();
m_maximum.Empty();
wxDialog::Close(force);
}
};

29
Utilities/Thread.cpp Normal file
View File

@ -0,0 +1,29 @@
#include "stdafx.h"
#include "Thread.h"
void ThreadBase::Start()
{
if(m_executor) return;
m_executor = new ThreadExec(m_detached, this);
}
void ThreadBase::Stop(bool wait)
{
if(!m_executor) return;
ThreadExec* exec = m_executor;
m_executor = nullptr;
exec->Stop(wait);
}
bool ThreadBase::IsAlive()
{
return m_executor != nullptr;
}
bool ThreadBase::TestDestroy()
{
if(!m_executor) return true;
return m_executor->TestDestroy();
}

177
Utilities/Thread.h Normal file
View File

@ -0,0 +1,177 @@
#pragma once
#include "Array.h"
class ThreadExec;
class ThreadBase
{
protected:
wxString m_name;
bool m_detached;
protected:
ThreadBase(bool detached = true, const wxString& name = "Unknown ThreadBase")
: m_detached(detached)
, m_name(name)
, m_executor(nullptr)
{
}
public:
ThreadExec* m_executor;
virtual void Task()=0;
void Start();
void Stop(bool wait = true);
bool IsAlive();
bool TestDestroy();
};
class ThreadExec : public wxThread
{
ThreadBase* m_parent;
wxSemaphore m_wait_for_exit;
volatile bool m_alive;
public:
ThreadExec(bool detached, ThreadBase* parent)
: wxThread(detached ? wxTHREAD_DETACHED : wxTHREAD_JOINABLE)
, m_parent(parent)
, m_alive(true)
{
Create();
Run();
}
void Stop(bool wait = true)
{
if(!m_alive) return;
m_parent = nullptr;
Delete();
if(wait && m_alive) m_wait_for_exit.Wait();
}
ExitCode Entry()
{
m_parent->Task();
m_alive = false;
m_wait_for_exit.Post();
if(m_parent) m_parent->m_executor = nullptr;
return (ExitCode)0;
}
};
template<typename T> class MTPacketBuffer
{
protected:
volatile bool m_busy;
volatile u32 m_put, m_get;
Array<u8> m_buffer;
u32 m_max_buffer_size;
void CheckBusy()
{
m_busy = m_put >= m_max_buffer_size;
}
public:
MTPacketBuffer(u32 max_buffer_size)
: m_max_buffer_size(max_buffer_size)
{
Flush();
}
~MTPacketBuffer()
{
Flush();
}
void Flush()
{
m_put = m_get = 0;
m_buffer.Clear();
m_busy = false;
}
virtual void Push(const T& v) = 0;
virtual T Pop() = 0;
bool HasNewPacket() const { return m_put != m_get; }
bool IsBusy() const { return m_busy; }
};
/*
class StepThread : public ThreadBase
{
wxSemaphore m_main_sem;
wxSemaphore m_destroy_sem;
volatile bool m_exit;
protected:
StepThread(const wxString& name = "Unknown StepThread")
: ThreadBase(true, name)
, m_exit(false)
{
}
virtual ~StepThread() throw()
{
}
private:
virtual void Task()
{
m_exit = false;
while(!TestDestroy())
{
m_main_sem.Wait();
if(TestDestroy() || m_exit) break;
Step();
}
while(!TestDestroy()) Sleep(0);
if(m_destroy_sem.TryWait() != wxSEMA_NO_ERROR) m_destroy_sem.Post();
}
virtual void Step()=0;
public:
void DoStep()
{
if(IsRunning()) m_main_sem.Post();
}
void WaitForExit()
{
if(TestDestroy()) m_destroy_sem.Wait();
}
void WaitForNextStep()
{
if(!IsRunning()) return;
while(m_main_sem.TryWait() != wxSEMA_NO_ERROR) Sleep(0);
}
void Exit(bool wait = false)
{
if(!IsAlive()) return;
if(m_main_sem.TryWait() != wxSEMA_NO_ERROR)
{
m_exit = true;
m_main_sem.Post();
}
Delete();
if(wait) WaitForExit();
}
};
*/

47
Utilities/Timer.h Normal file
View File

@ -0,0 +1,47 @@
#pragma once
class Timer
{
private:
bool stopped;
double startTimeInMicroSec;
double endTimeInMicroSec;
LARGE_INTEGER frequency;
LARGE_INTEGER startCycle;
LARGE_INTEGER endCycle;
public:
Timer()
{
QueryPerformanceFrequency(&frequency);
startCycle.QuadPart = 0;
endCycle.QuadPart = 0;
stopped = false;
startTimeInMicroSec = 0;
endTimeInMicroSec = 0;
}
void Start()
{
stopped = false;
QueryPerformanceCounter(&startCycle);
}
void Stop()
{
stopped = true;
QueryPerformanceCounter(&endCycle);
}
double GetElapsedTimeInSec(){return GetElapsedTimeInMicroSec() / 1000000.0;}
double GetElapsedTimeInMilliSec(){return GetElapsedTimeInMicroSec() / 1000.0;}
double GetElapsedTimeInMicroSec()
{
if(!stopped) QueryPerformanceCounter(&endCycle);
startTimeInMicroSec = startCycle.QuadPart * (1000000.0 / frequency.QuadPart);
endTimeInMicroSec = endCycle.QuadPart * (1000000.0 / frequency.QuadPart);
return endTimeInMicroSec - startTimeInMicroSec;
}
};

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

262
rpcs3.sln Normal file
View File

@ -0,0 +1,262 @@
Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rpcs3", "rpcs3\rpcs3.vcxproj", "{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}"
ProjectSection(ProjectDependencies) = postProject
{7F6DB432-0C72-FFB1-DE82-D450DAD5CF04} = {7F6DB432-0C72-FFB1-DE82-D450DAD5CF04}
{156E1310-DA46-F664-E3C1-EE90B4CD92AE} = {156E1310-DA46-F664-E3C1-EE90B4CD92AE}
{90A67BD5-253F-CD50-BB9E-7002DA7D35CF} = {90A67BD5-253F-CD50-BB9E-7002DA7D35CF}
{032DB7F5-755A-DF9E-5CBE-553BF92898EC} = {032DB7F5-755A-DF9E-5CBE-553BF92898EC}
{A66455C9-DAD3-9BB7-13E6-08E6E33D9B85} = {A66455C9-DAD3-9BB7-13E6-08E6E33D9B85}
{7C123413-10B1-F29F-EEE5-B57A36827C70} = {7C123413-10B1-F29F-EEE5-B57A36827C70}
{F8EC63A1-40C4-541B-911E-3679CCA1132D} = {F8EC63A1-40C4-541B-911E-3679CCA1132D}
{CF3420B3-B31E-FDD0-4897-648FD5125566} = {CF3420B3-B31E-FDD0-4897-648FD5125566}
{8A8F7ACD-0DB7-90B1-F4F8-F31D60255FD6} = {8A8F7ACD-0DB7-90B1-F4F8-F31D60255FD6}
{0C1DDDB4-F751-0E8E-982C-A6B14886FC7B} = {0C1DDDB4-F751-0E8E-982C-A6B14886FC7B}
{350261DE-995E-5363-B942-85B09B015F2B} = {350261DE-995E-5363-B942-85B09B015F2B}
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "wxWidgets", "wxWidgets", "{5812E712-6213-4372-B095-9EB9BAA1F2DF}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "adv", "wxWidgets\build\msw\wx_adv.vcxproj", "{7C123413-10B1-F29F-EEE5-B57A36827C70}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "aui", "wxWidgets\build\msw\wx_aui.vcxproj", "{0C1DDDB4-F751-0E8E-982C-A6B14886FC7B}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "base", "wxWidgets\build\msw\wx_base.vcxproj", "{7F6DB432-0C72-FFB1-DE82-D450DAD5CF04}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core", "wxWidgets\build\msw\wx_core.vcxproj", "{8A8F7ACD-0DB7-90B1-F4F8-F31D60255FD6}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dbgrid", "wxWidgets\build\msw\wx_dbgrid.vcxproj", "{16CD4B8D-C653-6AFD-426A-D10A768C1CE5}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gl", "wxWidgets\build\msw\wx_gl.vcxproj", "{A66455C9-DAD3-9BB7-13E6-08E6E33D9B85}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "html", "wxWidgets\build\msw\wx_html.vcxproj", "{CABB82BE-DFB1-E556-0AC3-5FC4D6933AE8}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "media", "wxWidgets\build\msw\wx_media.vcxproj", "{28365CAD-FDA4-E41A-7C13-FD86AC470A0D}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "net", "wxWidgets\build\msw\wx_net.vcxproj", "{995774A7-FA69-E03D-1759-A4C33AE7FF7C}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "odbc", "wxWidgets\build\msw\wx_odbc.vcxproj", "{EE9EE1EA-E48D-7B28-2825-6F014802A43B}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qa", "wxWidgets\build\msw\wx_qa.vcxproj", "{D78B0119-3CA8-C0A4-E1C2-4D646A68AC5B}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "richtext", "wxWidgets\build\msw\wx_richtext.vcxproj", "{DCF03EA6-9806-338B-3B07-60273468D4A9}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wxexpat", "wxWidgets\build\msw\wx_wxexpat.vcxproj", "{90A67BD5-253F-CD50-BB9E-7002DA7D35CF}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wxjpeg", "wxWidgets\build\msw\wx_wxjpeg.vcxproj", "{156E1310-DA46-F664-E3C1-EE90B4CD92AE}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wxpng", "wxWidgets\build\msw\wx_wxpng.vcxproj", "{CF3420B3-B31E-FDD0-4897-648FD5125566}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wxregex", "wxWidgets\build\msw\wx_wxregex.vcxproj", "{032DB7F5-755A-DF9E-5CBE-553BF92898EC}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wxtiff", "wxWidgets\build\msw\wx_wxtiff.vcxproj", "{F8EC63A1-40C4-541B-911E-3679CCA1132D}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wxzlib", "wxWidgets\build\msw\wx_wxzlib.vcxproj", "{350261DE-995E-5363-B942-85B09B015F2B}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xml", "wxWidgets\build\msw\wx_xml.vcxproj", "{503E4C3C-5D61-7928-7745-526C6EE2646F}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xrc", "wxWidgets\build\msw\wx_xrc.vcxproj", "{EB4E73BF-E88A-8B43-D654-EE1A4D88D10E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
Release|Win32 = Release|Win32
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Debug|Win32.ActiveCfg = Debug|Win32
{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Debug|Win32.Build.0 = Debug|Win32
{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Debug|x64.ActiveCfg = Debug|x64
{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Debug|x64.Build.0 = Debug|x64
{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Release|Win32.ActiveCfg = Release|Win32
{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Release|Win32.Build.0 = Release|Win32
{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Release|x64.ActiveCfg = Release|x64
{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Release|x64.Build.0 = Release|x64
{7C123413-10B1-F29F-EEE5-B57A36827C70}.Debug|Win32.ActiveCfg = Debug|Win32
{7C123413-10B1-F29F-EEE5-B57A36827C70}.Debug|Win32.Build.0 = Debug|Win32
{7C123413-10B1-F29F-EEE5-B57A36827C70}.Debug|x64.ActiveCfg = Debug|x64
{7C123413-10B1-F29F-EEE5-B57A36827C70}.Debug|x64.Build.0 = Debug|x64
{7C123413-10B1-F29F-EEE5-B57A36827C70}.Release|Win32.ActiveCfg = Release|Win32
{7C123413-10B1-F29F-EEE5-B57A36827C70}.Release|Win32.Build.0 = Release|Win32
{7C123413-10B1-F29F-EEE5-B57A36827C70}.Release|x64.ActiveCfg = Release|x64
{7C123413-10B1-F29F-EEE5-B57A36827C70}.Release|x64.Build.0 = Release|x64
{0C1DDDB4-F751-0E8E-982C-A6B14886FC7B}.Debug|Win32.ActiveCfg = Debug|Win32
{0C1DDDB4-F751-0E8E-982C-A6B14886FC7B}.Debug|Win32.Build.0 = Debug|Win32
{0C1DDDB4-F751-0E8E-982C-A6B14886FC7B}.Debug|x64.ActiveCfg = Debug|x64
{0C1DDDB4-F751-0E8E-982C-A6B14886FC7B}.Debug|x64.Build.0 = Debug|x64
{0C1DDDB4-F751-0E8E-982C-A6B14886FC7B}.Release|Win32.ActiveCfg = Release|Win32
{0C1DDDB4-F751-0E8E-982C-A6B14886FC7B}.Release|Win32.Build.0 = Release|Win32
{0C1DDDB4-F751-0E8E-982C-A6B14886FC7B}.Release|x64.ActiveCfg = Release|x64
{0C1DDDB4-F751-0E8E-982C-A6B14886FC7B}.Release|x64.Build.0 = Release|x64
{7F6DB432-0C72-FFB1-DE82-D450DAD5CF04}.Debug|Win32.ActiveCfg = Debug|Win32
{7F6DB432-0C72-FFB1-DE82-D450DAD5CF04}.Debug|Win32.Build.0 = Debug|Win32
{7F6DB432-0C72-FFB1-DE82-D450DAD5CF04}.Debug|x64.ActiveCfg = Debug|x64
{7F6DB432-0C72-FFB1-DE82-D450DAD5CF04}.Debug|x64.Build.0 = Debug|x64
{7F6DB432-0C72-FFB1-DE82-D450DAD5CF04}.Release|Win32.ActiveCfg = Release|Win32
{7F6DB432-0C72-FFB1-DE82-D450DAD5CF04}.Release|Win32.Build.0 = Release|Win32
{7F6DB432-0C72-FFB1-DE82-D450DAD5CF04}.Release|x64.ActiveCfg = Release|x64
{7F6DB432-0C72-FFB1-DE82-D450DAD5CF04}.Release|x64.Build.0 = Release|x64
{8A8F7ACD-0DB7-90B1-F4F8-F31D60255FD6}.Debug|Win32.ActiveCfg = Debug|Win32
{8A8F7ACD-0DB7-90B1-F4F8-F31D60255FD6}.Debug|Win32.Build.0 = Debug|Win32
{8A8F7ACD-0DB7-90B1-F4F8-F31D60255FD6}.Debug|x64.ActiveCfg = Debug|x64
{8A8F7ACD-0DB7-90B1-F4F8-F31D60255FD6}.Debug|x64.Build.0 = Debug|x64
{8A8F7ACD-0DB7-90B1-F4F8-F31D60255FD6}.Release|Win32.ActiveCfg = Release|Win32
{8A8F7ACD-0DB7-90B1-F4F8-F31D60255FD6}.Release|Win32.Build.0 = Release|Win32
{8A8F7ACD-0DB7-90B1-F4F8-F31D60255FD6}.Release|x64.ActiveCfg = Release|x64
{8A8F7ACD-0DB7-90B1-F4F8-F31D60255FD6}.Release|x64.Build.0 = Release|x64
{16CD4B8D-C653-6AFD-426A-D10A768C1CE5}.Debug|Win32.ActiveCfg = Debug|Win32
{16CD4B8D-C653-6AFD-426A-D10A768C1CE5}.Debug|Win32.Build.0 = Debug|Win32
{16CD4B8D-C653-6AFD-426A-D10A768C1CE5}.Debug|x64.ActiveCfg = Debug|x64
{16CD4B8D-C653-6AFD-426A-D10A768C1CE5}.Debug|x64.Build.0 = Debug|x64
{16CD4B8D-C653-6AFD-426A-D10A768C1CE5}.Release|Win32.ActiveCfg = Release|Win32
{16CD4B8D-C653-6AFD-426A-D10A768C1CE5}.Release|Win32.Build.0 = Release|Win32
{16CD4B8D-C653-6AFD-426A-D10A768C1CE5}.Release|x64.ActiveCfg = Release|x64
{16CD4B8D-C653-6AFD-426A-D10A768C1CE5}.Release|x64.Build.0 = Release|x64
{A66455C9-DAD3-9BB7-13E6-08E6E33D9B85}.Debug|Win32.ActiveCfg = Debug|Win32
{A66455C9-DAD3-9BB7-13E6-08E6E33D9B85}.Debug|Win32.Build.0 = Debug|Win32
{A66455C9-DAD3-9BB7-13E6-08E6E33D9B85}.Debug|x64.ActiveCfg = Debug|x64
{A66455C9-DAD3-9BB7-13E6-08E6E33D9B85}.Debug|x64.Build.0 = Debug|x64
{A66455C9-DAD3-9BB7-13E6-08E6E33D9B85}.Release|Win32.ActiveCfg = Release|Win32
{A66455C9-DAD3-9BB7-13E6-08E6E33D9B85}.Release|Win32.Build.0 = Release|Win32
{A66455C9-DAD3-9BB7-13E6-08E6E33D9B85}.Release|x64.ActiveCfg = Release|x64
{A66455C9-DAD3-9BB7-13E6-08E6E33D9B85}.Release|x64.Build.0 = Release|x64
{CABB82BE-DFB1-E556-0AC3-5FC4D6933AE8}.Debug|Win32.ActiveCfg = Debug|Win32
{CABB82BE-DFB1-E556-0AC3-5FC4D6933AE8}.Debug|Win32.Build.0 = Debug|Win32
{CABB82BE-DFB1-E556-0AC3-5FC4D6933AE8}.Debug|x64.ActiveCfg = Debug|x64
{CABB82BE-DFB1-E556-0AC3-5FC4D6933AE8}.Debug|x64.Build.0 = Debug|x64
{CABB82BE-DFB1-E556-0AC3-5FC4D6933AE8}.Release|Win32.ActiveCfg = Release|Win32
{CABB82BE-DFB1-E556-0AC3-5FC4D6933AE8}.Release|Win32.Build.0 = Release|Win32
{CABB82BE-DFB1-E556-0AC3-5FC4D6933AE8}.Release|x64.ActiveCfg = Release|x64
{CABB82BE-DFB1-E556-0AC3-5FC4D6933AE8}.Release|x64.Build.0 = Release|x64
{28365CAD-FDA4-E41A-7C13-FD86AC470A0D}.Debug|Win32.ActiveCfg = Debug|Win32
{28365CAD-FDA4-E41A-7C13-FD86AC470A0D}.Debug|Win32.Build.0 = Debug|Win32
{28365CAD-FDA4-E41A-7C13-FD86AC470A0D}.Debug|x64.ActiveCfg = Debug|x64
{28365CAD-FDA4-E41A-7C13-FD86AC470A0D}.Debug|x64.Build.0 = Debug|x64
{28365CAD-FDA4-E41A-7C13-FD86AC470A0D}.Release|Win32.ActiveCfg = Release|Win32
{28365CAD-FDA4-E41A-7C13-FD86AC470A0D}.Release|Win32.Build.0 = Release|Win32
{28365CAD-FDA4-E41A-7C13-FD86AC470A0D}.Release|x64.ActiveCfg = Release|x64
{28365CAD-FDA4-E41A-7C13-FD86AC470A0D}.Release|x64.Build.0 = Release|x64
{995774A7-FA69-E03D-1759-A4C33AE7FF7C}.Debug|Win32.ActiveCfg = Debug|Win32
{995774A7-FA69-E03D-1759-A4C33AE7FF7C}.Debug|Win32.Build.0 = Debug|Win32
{995774A7-FA69-E03D-1759-A4C33AE7FF7C}.Debug|x64.ActiveCfg = Debug|x64
{995774A7-FA69-E03D-1759-A4C33AE7FF7C}.Debug|x64.Build.0 = Debug|x64
{995774A7-FA69-E03D-1759-A4C33AE7FF7C}.Release|Win32.ActiveCfg = Release|Win32
{995774A7-FA69-E03D-1759-A4C33AE7FF7C}.Release|Win32.Build.0 = Release|Win32
{995774A7-FA69-E03D-1759-A4C33AE7FF7C}.Release|x64.ActiveCfg = Release|x64
{995774A7-FA69-E03D-1759-A4C33AE7FF7C}.Release|x64.Build.0 = Release|x64
{EE9EE1EA-E48D-7B28-2825-6F014802A43B}.Debug|Win32.ActiveCfg = Debug|Win32
{EE9EE1EA-E48D-7B28-2825-6F014802A43B}.Debug|Win32.Build.0 = Debug|Win32
{EE9EE1EA-E48D-7B28-2825-6F014802A43B}.Debug|x64.ActiveCfg = Debug|x64
{EE9EE1EA-E48D-7B28-2825-6F014802A43B}.Debug|x64.Build.0 = Debug|x64
{EE9EE1EA-E48D-7B28-2825-6F014802A43B}.Release|Win32.ActiveCfg = Release|Win32
{EE9EE1EA-E48D-7B28-2825-6F014802A43B}.Release|Win32.Build.0 = Release|Win32
{EE9EE1EA-E48D-7B28-2825-6F014802A43B}.Release|x64.ActiveCfg = Release|x64
{EE9EE1EA-E48D-7B28-2825-6F014802A43B}.Release|x64.Build.0 = Release|x64
{D78B0119-3CA8-C0A4-E1C2-4D646A68AC5B}.Debug|Win32.ActiveCfg = Debug|Win32
{D78B0119-3CA8-C0A4-E1C2-4D646A68AC5B}.Debug|Win32.Build.0 = Debug|Win32
{D78B0119-3CA8-C0A4-E1C2-4D646A68AC5B}.Debug|x64.ActiveCfg = Debug|x64
{D78B0119-3CA8-C0A4-E1C2-4D646A68AC5B}.Debug|x64.Build.0 = Debug|x64
{D78B0119-3CA8-C0A4-E1C2-4D646A68AC5B}.Release|Win32.ActiveCfg = Release|Win32
{D78B0119-3CA8-C0A4-E1C2-4D646A68AC5B}.Release|Win32.Build.0 = Release|Win32
{D78B0119-3CA8-C0A4-E1C2-4D646A68AC5B}.Release|x64.ActiveCfg = Release|x64
{D78B0119-3CA8-C0A4-E1C2-4D646A68AC5B}.Release|x64.Build.0 = Release|x64
{DCF03EA6-9806-338B-3B07-60273468D4A9}.Debug|Win32.ActiveCfg = Debug|Win32
{DCF03EA6-9806-338B-3B07-60273468D4A9}.Debug|Win32.Build.0 = Debug|Win32
{DCF03EA6-9806-338B-3B07-60273468D4A9}.Debug|x64.ActiveCfg = Debug|x64
{DCF03EA6-9806-338B-3B07-60273468D4A9}.Debug|x64.Build.0 = Debug|x64
{DCF03EA6-9806-338B-3B07-60273468D4A9}.Release|Win32.ActiveCfg = Release|Win32
{DCF03EA6-9806-338B-3B07-60273468D4A9}.Release|Win32.Build.0 = Release|Win32
{DCF03EA6-9806-338B-3B07-60273468D4A9}.Release|x64.ActiveCfg = Release|x64
{DCF03EA6-9806-338B-3B07-60273468D4A9}.Release|x64.Build.0 = Release|x64
{90A67BD5-253F-CD50-BB9E-7002DA7D35CF}.Debug|Win32.ActiveCfg = Debug|Win32
{90A67BD5-253F-CD50-BB9E-7002DA7D35CF}.Debug|Win32.Build.0 = Debug|Win32
{90A67BD5-253F-CD50-BB9E-7002DA7D35CF}.Debug|x64.ActiveCfg = Debug|x64
{90A67BD5-253F-CD50-BB9E-7002DA7D35CF}.Debug|x64.Build.0 = Debug|x64
{90A67BD5-253F-CD50-BB9E-7002DA7D35CF}.Release|Win32.ActiveCfg = Release|Win32
{90A67BD5-253F-CD50-BB9E-7002DA7D35CF}.Release|Win32.Build.0 = Release|Win32
{90A67BD5-253F-CD50-BB9E-7002DA7D35CF}.Release|x64.ActiveCfg = Release|x64
{90A67BD5-253F-CD50-BB9E-7002DA7D35CF}.Release|x64.Build.0 = Release|x64
{156E1310-DA46-F664-E3C1-EE90B4CD92AE}.Debug|Win32.ActiveCfg = Debug|Win32
{156E1310-DA46-F664-E3C1-EE90B4CD92AE}.Debug|Win32.Build.0 = Debug|Win32
{156E1310-DA46-F664-E3C1-EE90B4CD92AE}.Debug|x64.ActiveCfg = Debug|x64
{156E1310-DA46-F664-E3C1-EE90B4CD92AE}.Debug|x64.Build.0 = Debug|x64
{156E1310-DA46-F664-E3C1-EE90B4CD92AE}.Release|Win32.ActiveCfg = Release|Win32
{156E1310-DA46-F664-E3C1-EE90B4CD92AE}.Release|Win32.Build.0 = Release|Win32
{156E1310-DA46-F664-E3C1-EE90B4CD92AE}.Release|x64.ActiveCfg = Release|x64
{156E1310-DA46-F664-E3C1-EE90B4CD92AE}.Release|x64.Build.0 = Release|x64
{CF3420B3-B31E-FDD0-4897-648FD5125566}.Debug|Win32.ActiveCfg = Debug|Win32
{CF3420B3-B31E-FDD0-4897-648FD5125566}.Debug|Win32.Build.0 = Debug|Win32
{CF3420B3-B31E-FDD0-4897-648FD5125566}.Debug|x64.ActiveCfg = Debug|x64
{CF3420B3-B31E-FDD0-4897-648FD5125566}.Debug|x64.Build.0 = Debug|x64
{CF3420B3-B31E-FDD0-4897-648FD5125566}.Release|Win32.ActiveCfg = Release|Win32
{CF3420B3-B31E-FDD0-4897-648FD5125566}.Release|Win32.Build.0 = Release|Win32
{CF3420B3-B31E-FDD0-4897-648FD5125566}.Release|x64.ActiveCfg = Release|x64
{CF3420B3-B31E-FDD0-4897-648FD5125566}.Release|x64.Build.0 = Release|x64
{032DB7F5-755A-DF9E-5CBE-553BF92898EC}.Debug|Win32.ActiveCfg = Debug|Win32
{032DB7F5-755A-DF9E-5CBE-553BF92898EC}.Debug|Win32.Build.0 = Debug|Win32
{032DB7F5-755A-DF9E-5CBE-553BF92898EC}.Debug|x64.ActiveCfg = Debug|x64
{032DB7F5-755A-DF9E-5CBE-553BF92898EC}.Debug|x64.Build.0 = Debug|x64
{032DB7F5-755A-DF9E-5CBE-553BF92898EC}.Release|Win32.ActiveCfg = Release|Win32
{032DB7F5-755A-DF9E-5CBE-553BF92898EC}.Release|Win32.Build.0 = Release|Win32
{032DB7F5-755A-DF9E-5CBE-553BF92898EC}.Release|x64.ActiveCfg = Release|x64
{032DB7F5-755A-DF9E-5CBE-553BF92898EC}.Release|x64.Build.0 = Release|x64
{F8EC63A1-40C4-541B-911E-3679CCA1132D}.Debug|Win32.ActiveCfg = Debug|Win32
{F8EC63A1-40C4-541B-911E-3679CCA1132D}.Debug|Win32.Build.0 = Debug|Win32
{F8EC63A1-40C4-541B-911E-3679CCA1132D}.Debug|x64.ActiveCfg = Debug|x64
{F8EC63A1-40C4-541B-911E-3679CCA1132D}.Debug|x64.Build.0 = Debug|x64
{F8EC63A1-40C4-541B-911E-3679CCA1132D}.Release|Win32.ActiveCfg = Release|Win32
{F8EC63A1-40C4-541B-911E-3679CCA1132D}.Release|Win32.Build.0 = Release|Win32
{F8EC63A1-40C4-541B-911E-3679CCA1132D}.Release|x64.ActiveCfg = Release|x64
{F8EC63A1-40C4-541B-911E-3679CCA1132D}.Release|x64.Build.0 = Release|x64
{350261DE-995E-5363-B942-85B09B015F2B}.Debug|Win32.ActiveCfg = Debug|Win32
{350261DE-995E-5363-B942-85B09B015F2B}.Debug|Win32.Build.0 = Debug|Win32
{350261DE-995E-5363-B942-85B09B015F2B}.Debug|x64.ActiveCfg = Debug|x64
{350261DE-995E-5363-B942-85B09B015F2B}.Debug|x64.Build.0 = Debug|x64
{350261DE-995E-5363-B942-85B09B015F2B}.Release|Win32.ActiveCfg = Release|Win32
{350261DE-995E-5363-B942-85B09B015F2B}.Release|Win32.Build.0 = Release|Win32
{350261DE-995E-5363-B942-85B09B015F2B}.Release|x64.ActiveCfg = Release|x64
{350261DE-995E-5363-B942-85B09B015F2B}.Release|x64.Build.0 = Release|x64
{503E4C3C-5D61-7928-7745-526C6EE2646F}.Debug|Win32.ActiveCfg = Debug|Win32
{503E4C3C-5D61-7928-7745-526C6EE2646F}.Debug|Win32.Build.0 = Debug|Win32
{503E4C3C-5D61-7928-7745-526C6EE2646F}.Debug|x64.ActiveCfg = Debug|x64
{503E4C3C-5D61-7928-7745-526C6EE2646F}.Debug|x64.Build.0 = Debug|x64
{503E4C3C-5D61-7928-7745-526C6EE2646F}.Release|Win32.ActiveCfg = Release|Win32
{503E4C3C-5D61-7928-7745-526C6EE2646F}.Release|Win32.Build.0 = Release|Win32
{503E4C3C-5D61-7928-7745-526C6EE2646F}.Release|x64.ActiveCfg = Release|x64
{503E4C3C-5D61-7928-7745-526C6EE2646F}.Release|x64.Build.0 = Release|x64
{EB4E73BF-E88A-8B43-D654-EE1A4D88D10E}.Debug|Win32.ActiveCfg = Debug|Win32
{EB4E73BF-E88A-8B43-D654-EE1A4D88D10E}.Debug|Win32.Build.0 = Debug|Win32
{EB4E73BF-E88A-8B43-D654-EE1A4D88D10E}.Debug|x64.ActiveCfg = Debug|x64
{EB4E73BF-E88A-8B43-D654-EE1A4D88D10E}.Debug|x64.Build.0 = Debug|x64
{EB4E73BF-E88A-8B43-D654-EE1A4D88D10E}.Release|Win32.ActiveCfg = Release|Win32
{EB4E73BF-E88A-8B43-D654-EE1A4D88D10E}.Release|Win32.Build.0 = Release|Win32
{EB4E73BF-E88A-8B43-D654-EE1A4D88D10E}.Release|x64.ActiveCfg = Release|x64
{EB4E73BF-E88A-8B43-D654-EE1A4D88D10E}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{7C123413-10B1-F29F-EEE5-B57A36827C70} = {5812E712-6213-4372-B095-9EB9BAA1F2DF}
{0C1DDDB4-F751-0E8E-982C-A6B14886FC7B} = {5812E712-6213-4372-B095-9EB9BAA1F2DF}
{7F6DB432-0C72-FFB1-DE82-D450DAD5CF04} = {5812E712-6213-4372-B095-9EB9BAA1F2DF}
{8A8F7ACD-0DB7-90B1-F4F8-F31D60255FD6} = {5812E712-6213-4372-B095-9EB9BAA1F2DF}
{16CD4B8D-C653-6AFD-426A-D10A768C1CE5} = {5812E712-6213-4372-B095-9EB9BAA1F2DF}
{A66455C9-DAD3-9BB7-13E6-08E6E33D9B85} = {5812E712-6213-4372-B095-9EB9BAA1F2DF}
{CABB82BE-DFB1-E556-0AC3-5FC4D6933AE8} = {5812E712-6213-4372-B095-9EB9BAA1F2DF}
{28365CAD-FDA4-E41A-7C13-FD86AC470A0D} = {5812E712-6213-4372-B095-9EB9BAA1F2DF}
{995774A7-FA69-E03D-1759-A4C33AE7FF7C} = {5812E712-6213-4372-B095-9EB9BAA1F2DF}
{EE9EE1EA-E48D-7B28-2825-6F014802A43B} = {5812E712-6213-4372-B095-9EB9BAA1F2DF}
{D78B0119-3CA8-C0A4-E1C2-4D646A68AC5B} = {5812E712-6213-4372-B095-9EB9BAA1F2DF}
{DCF03EA6-9806-338B-3B07-60273468D4A9} = {5812E712-6213-4372-B095-9EB9BAA1F2DF}
{90A67BD5-253F-CD50-BB9E-7002DA7D35CF} = {5812E712-6213-4372-B095-9EB9BAA1F2DF}
{156E1310-DA46-F664-E3C1-EE90B4CD92AE} = {5812E712-6213-4372-B095-9EB9BAA1F2DF}
{CF3420B3-B31E-FDD0-4897-648FD5125566} = {5812E712-6213-4372-B095-9EB9BAA1F2DF}
{032DB7F5-755A-DF9E-5CBE-553BF92898EC} = {5812E712-6213-4372-B095-9EB9BAA1F2DF}
{F8EC63A1-40C4-541B-911E-3679CCA1132D} = {5812E712-6213-4372-B095-9EB9BAA1F2DF}
{350261DE-995E-5363-B942-85B09B015F2B} = {5812E712-6213-4372-B095-9EB9BAA1F2DF}
{503E4C3C-5D61-7928-7745-526C6EE2646F} = {5812E712-6213-4372-B095-9EB9BAA1F2DF}
{EB4E73BF-E88A-8B43-D654-EE1A4D88D10E} = {5812E712-6213-4372-B095-9EB9BAA1F2DF}
EndGlobalSection
EndGlobal

7
rpcs3/Emu/Cell/Decoder.h Normal file
View File

@ -0,0 +1,7 @@
#pragma once
class Decoder
{
public:
virtual void Decode(const u32 code)=0;
};

277
rpcs3/Emu/Cell/DisAsm.h Normal file
View File

@ -0,0 +1,277 @@
#pragma once
#include "Gui/DisAsmFrame.h"
#include "Emu/Memory/Memory.h"
enum DisAsmModes
{
DumpMode,
InterpreterMode,
NormalMode,
CompilerElfMode,
};
class DisAsm
{
protected:
DisAsmFrame* disasm_frame;
const DisAsmModes m_mode;
virtual void Write(const wxString value)
{
switch(m_mode)
{
case DumpMode:
{
wxString mem = wxString::Format("\t%x:\t", dump_pc);
for(u8 i=0; i < 4; ++i)
{
mem += wxString::Format("%02x", Memory.Read8(dump_pc + i));
if(i < 3) mem += " ";
}
last_opcode = mem + "\t" + value + "\n";
}
break;
case InterpreterMode:
{
wxString mem = wxString::Format("[%x] ", dump_pc);
for(u8 i=0; i < 4; ++i)
{
mem += wxString::Format("%02x", Memory.Read8(dump_pc + i));
if(i < 3) mem += " ";
}
last_opcode = mem + ": " + value;
}
break;
case CompilerElfMode: last_opcode = value + "\n"; break;
default: if(disasm_frame) disasm_frame->AddLine(value); break;
}
}
public:
wxString last_opcode;
uint dump_pc;
protected:
DisAsm(PPCThread& cpu, DisAsmModes mode = NormalMode)
: m_mode(mode)
, disasm_frame(NULL)
{
if(m_mode != NormalMode) return;
disasm_frame = new DisAsmFrame(cpu);
disasm_frame->Show();
}
virtual u32 DisAsmBranchTarget(const s32 imm)=0;
wxString FixOp(wxString op)
{
op.Append(' ', max<int>(8 - op.Len(), 0));
return op;
}
void DisAsm_V3(const wxString& op, OP_REG v0, OP_REG v1, OP_REG v2)
{
Write(wxString::Format("%s v%d,v%d,v%d", FixOp(op), v0, v1, v2));
}
void DisAsm_V1_R2(const wxString& op, OP_REG v0, OP_REG r1, OP_REG r2)
{
Write(wxString::Format("%s v%d,r%d,r%d", FixOp(op), v0, r1, r2));
}
void DisAsm_CR1_F2_RC(const wxString& op, OP_REG cr0, OP_REG f0, OP_REG f1, bool rc)
{
Write(wxString::Format("%s%s cr%d,f%d,f%d", FixOp(op), rc ? "." : "", cr0, f0, f1));
}
void DisAsm_CR1_F2(const wxString& op, OP_REG cr0, OP_REG f0, OP_REG f1)
{
DisAsm_CR1_F2_RC(op, cr0, f0, f1, false);
}
void DisAsm_INT1_R2(const wxString& op, OP_REG i0, OP_REG r0, OP_REG r1)
{
Write(wxString::Format("%s %d,r%d,r%d", FixOp(op), i0, r0, r1));
}
void DisAsm_INT1_R1_IMM(const wxString& op, OP_REG i0, OP_REG r0, OP_sIMM imm0)
{
Write(wxString::Format("%s %d,r%d,%d #%x", FixOp(op), i0, r0, imm0, imm0));
}
void DisAsm_INT1_R1_RC(const wxString& op, OP_REG i0, OP_REG r0, bool rc)
{
Write(wxString::Format("%s%s %d,r%d", FixOp(op), rc ? "." : "", i0, r0));
}
void DisAsm_INT1_R1(const wxString& op, OP_REG i0, OP_REG r0)
{
DisAsm_INT1_R1_RC(op, i0, r0, false);
}
void DisAsm_F4_RC(const wxString& op, OP_REG f0, OP_REG f1, OP_REG f2, OP_REG f3, bool rc)
{
Write(wxString::Format("%s%s f%d,f%d,f%d,f%d", FixOp(op), rc ? "." : "", f0, f1, f2, f3));
}
void DisAsm_F3_RC(const wxString& op, OP_REG f0, OP_REG f1, OP_REG f2, bool rc)
{
Write(wxString::Format("%s%s f%d,f%d,f%d", FixOp(op), rc ? "." : "", f0, f1, f2));
}
void DisAsm_F3(const wxString& op, OP_REG f0, OP_REG f1, OP_REG f2)
{
DisAsm_F3_RC(op, f0, f1, f2, false);
}
void DisAsm_F2_RC(const wxString& op, OP_REG f0, OP_REG f1, bool rc)
{
Write(wxString::Format("%s%s f%d,f%d", FixOp(op), rc ? "." : "", f0, f1));
}
void DisAsm_F2(const wxString& op, OP_REG f0, OP_REG f1)
{
DisAsm_F2_RC(op, f0, f1, false);
}
void DisAsm_F1_R2(const wxString& op, OP_REG f0, OP_REG r0, OP_REG r1)
{
if(m_mode == CompilerElfMode)
{
Write(wxString::Format("%s f%d,r%d,r%d", FixOp(op), f0, r0, r1));
return;
}
Write(wxString::Format("%s f%d,r%d(r%d)", FixOp(op), f0, r0, r1));
}
void DisAsm_F1_IMM_R1_RC(const wxString& op, OP_REG f0, OP_sIMM imm0, OP_REG r0, bool rc)
{
if(m_mode == CompilerElfMode)
{
Write(wxString::Format("%s%s f%d,r%d,%d #%x", FixOp(op), rc ? "." : "", f0, r0, imm0, imm0));
return;
}
Write(wxString::Format("%s%s f%d,%d(r%d) #%x", FixOp(op), rc ? "." : "", f0, imm0, r0, imm0));
}
void DisAsm_F1_IMM_R1(const wxString& op, OP_REG f0, OP_sIMM imm0, OP_REG r0)
{
DisAsm_F1_IMM_R1_RC(op, f0, imm0, r0, false);
}
void DisAsm_F1_RC(const wxString& op, OP_REG f0, bool rc)
{
Write(wxString::Format("%s%s f%d", FixOp(op), rc ? "." : "", f0));
}
void DisAsm_R1_RC(const wxString& op, OP_REG r0, bool rc)
{
Write(wxString::Format("%s%s r%d", FixOp(op), rc ? "." : "", r0));
}
void DisAsm_R1(const wxString& op, OP_REG r0)
{
DisAsm_R1_RC(op, r0, false);
}
void DisAsm_R2_OE_RC(const wxString& op, OP_REG r0, OP_REG r1, OP_REG oe, bool rc)
{
Write(wxString::Format("%s%s%s r%d,r%d", FixOp(op), oe ? "o" : "", rc ? "." : "", r0, r1));
}
void DisAsm_R2_RC(const wxString& op, OP_REG r0, OP_REG r1, bool rc)
{
DisAsm_R2_OE_RC(op, r0, r1, false, rc);
}
void DisAsm_R2(const wxString& op, OP_REG r0, OP_REG r1)
{
DisAsm_R2_RC(op, r0, r1, false);
}
void DisAsm_R3_OE_RC(const wxString& op, OP_REG r0, OP_REG r1, OP_REG r2, OP_REG oe, bool rc)
{
Write(wxString::Format("%s%s%s r%d,r%d,r%d", FixOp(op), oe ? "o" : "", rc ? "." : "", r0, r1, r2));
}
void DisAsm_R3_INT2_RC(const wxString& op, OP_REG r0, OP_REG r1, OP_REG r2, OP_sIMM i0, OP_sIMM i1, bool rc)
{
Write(wxString::Format("%s%s r%d,r%d,r%d,%d,%d", FixOp(op), rc ? "." : "", r0, r1, r2, i0, i1));
}
void DisAsm_R3_RC(const wxString& op, OP_REG r0, OP_REG r1, OP_REG r2, bool rc)
{
DisAsm_R3_OE_RC(op, r0, r1, r2, false, rc);
}
void DisAsm_R3(const wxString& op, OP_REG r0, OP_REG r1, OP_REG r2)
{
DisAsm_R3_RC(op, r0, r1, r2, false);
}
void DisAsm_R2_INT3_RC(const wxString& op, OP_REG r0, OP_REG r1, OP_sIMM i0, OP_sIMM i1, OP_sIMM i2, bool rc)
{
Write(wxString::Format("%s%s r%d,r%d,%d,%d,%d", FixOp(op), rc ? "." : "", r0, r1, i0, i1, i2));
}
void DisAsm_R2_INT3(const wxString& op, OP_REG r0, OP_REG r1, OP_sIMM i0, OP_sIMM i1, OP_sIMM i2)
{
DisAsm_R2_INT3_RC(op, r0, r1, i0, i1, i2, false);
}
void DisAsm_R2_INT2_RC(const wxString& op, OP_REG r0, OP_REG r1, OP_sIMM i0, OP_sIMM i1, bool rc)
{
Write(wxString::Format("%s%s r%d,r%d,%d,%d", FixOp(op), rc ? "." : "", r0, r1, i0, i1));
}
void DisAsm_R2_INT2(const wxString& op, OP_REG r0, OP_REG r1, OP_sIMM i0, OP_sIMM i1)
{
DisAsm_R2_INT2_RC(op, r0, r1, i0, i1, false);
}
void DisAsm_R2_INT1_RC(const wxString& op, OP_REG r0, OP_REG r1, OP_sIMM i0, bool rc)
{
Write(wxString::Format("%s%s r%d,r%d,%d", FixOp(op), rc ? "." : "", r0, r1, i0));
}
void DisAsm_R2_INT1(const wxString& op, OP_REG r0, OP_REG r1, OP_sIMM i0)
{
DisAsm_R2_INT1_RC(op, r0, r1, i0, false);
}
void DisAsm_R2_IMM(const wxString& op, OP_REG r0, OP_REG r1, OP_sIMM imm0)
{
if(m_mode == CompilerElfMode)
{
Write(wxString::Format("%s r%d,r%d,%d #%x", FixOp(op), r0, r1, imm0, imm0));
return;
}
Write(wxString::Format("%s r%d,%d(r%d) #%x", FixOp(op), r0, imm0, r1, imm0));
}
void DisAsm_R1_IMM(const wxString& op, OP_REG r0, OP_sIMM imm0)
{
Write(wxString::Format("%s r%d,%d #%x", FixOp(op), r0, imm0, imm0));
}
void DisAsm_IMM_R1(const wxString& op, OP_sIMM imm0, OP_REG r0)
{
Write(wxString::Format("%s %d,r%d #%x", FixOp(op), imm0, r0, imm0));
}
void DisAsm_CR1_R1_IMM(const wxString& op, OP_REG cr0, OP_REG r0, OP_sIMM imm0)
{
Write(wxString::Format("%s cr%d,r%d,%d #%x", FixOp(op), cr0, r0, imm0, imm0));
}
void DisAsm_CR1_R2_RC(const wxString& op, OP_REG cr0, OP_REG r0, OP_REG r1, bool rc)
{
Write(wxString::Format("%s%s cr%d,r%d,r%d", FixOp(op), rc ? "." : "", cr0, r0, r1));
}
void DisAsm_CR1_R2(const wxString& op, OP_REG cr0, OP_REG r0, OP_REG r1)
{
DisAsm_CR1_R2_RC(op, cr0, r0, r1, false);
}
void DisAsm_CR2(const wxString& op, OP_REG cr0, OP_REG cr1)
{
Write(wxString::Format("%s cr%d,cr%d", FixOp(op), cr0, cr1));
}
void DisAsm_INT3(const wxString& op, const int i0, const int i1, const int i2)
{
Write(wxString::Format("%s %d,%d,%d", FixOp(op), i0, i1, i2));
}
void DisAsm_INT1(const wxString& op, const int i0)
{
Write(wxString::Format("%s %d", FixOp(op), i0));
}
void DisAsm_BRANCH(const wxString& op, const int pc)
{
Write(wxString::Format("%s 0x%x", FixOp(op), DisAsmBranchTarget(pc)));
}
void DisAsm_BRANCH_A(const wxString& op, const int pc)
{
Write(wxString::Format("%s 0x%x", FixOp(op), pc));
}
void DisAsm_B2_BRANCH(const wxString& op, OP_REG b0, OP_REG b1, const int pc)
{
Write(wxString::Format("%s %d,%d,0x%x ", FixOp(op), b0, b1, DisAsmBranchTarget(pc)));
}
void DisAsm_CR_BRANCH(const wxString& op, OP_REG cr, const int pc)
{
Write(wxString::Format("%s cr%d,0x%x ", FixOp(op), cr, DisAsmBranchTarget(pc)));
}
};

View File

@ -0,0 +1,204 @@
#include "stdafx.h"
#include "PPCThread.h"
#include "Gui/InterpreterDisAsm.h"
PPCThread::PPCThread(PPCThreadType type)
: m_type(type)
, DisAsmFrame(NULL)
, m_arg(0)
, m_dec(NULL)
, stack_size(0)
, stack_addr(0)
, m_prio(0)
, m_offset(0)
{
}
PPCThread::~PPCThread()
{
Close();
}
void PPCThread::Close()
{
Stop();
if(DisAsmFrame)
{
DisAsmFrame->Close();
DisAsmFrame = nullptr;
}
}
void PPCThread::Reset()
{
CloseStack();
SetPc(0);
cycle = 0;
isBranch = false;
m_status = Stopped;
m_error = 0;
DoReset();
}
void PPCThread::InitStack()
{
if(stack_addr) return;
if(stack_size == 0) stack_size = 0x10000;
stack_addr = Memory.StackMem.Alloc(Memory.AlignAddr(stack_size, 0x100));
stack_point = stack_addr + stack_size;
/*
stack_point += stack_size - 0x10;
stack_point &= -0x10;
Memory.Write64(stack_point, 0);
stack_point -= 0x60;
Memory.Write64(stack_point, stack_point + 0x60);
*/
if(wxFileExists("stack.dat"))
{
ConLog.Warning("loading stack.dat...");
wxFile stack("stack.dat");
stack.Read(Memory.GetMemFromAddr(stack_addr), 0x10000);
stack.Close();
}
}
void PPCThread::CloseStack()
{
Memory.Free(stack_addr);
stack_addr = 0;
stack_size = 0;
}
void PPCThread::SetId(const u32 id)
{
m_id = id;
ID& thread = Emu.GetIdManager().GetIDData(m_id);
thread.m_name = GetName();
if(Ini.CPUDecoderMode.GetValue() != 1) return;
DisAsmFrame = new InterpreterDisAsmFrame(GetFName(), this);
(*(InterpreterDisAsmFrame*)DisAsmFrame).Show();
}
void PPCThread::SetName(const wxString& name)
{
m_name = name;
if(DisAsmFrame) (*(InterpreterDisAsmFrame*)DisAsmFrame).SetTitle(GetFName());
}
void PPCThread::NextBranchPc()
{
SetPc(nPC);
}
void PPCThread::NextPc()
{
if(isBranch)
{
NextBranchPc();
isBranch = false;
return;
}
SetPc(PC + 4);
}
void PPCThread::PrevPc()
{
SetPc(PC - 4);
}
void PPCThread::SetPc(const u64 pc)
{
PC = pc;
nPC = PC + 4;
}
void PPCThread::SetBranch(const u64 pc)
{
if(!Memory.IsGoodAddr(pc))
{
ConLog.Error("%s branch error: bad address 0x%llx #pc: 0x%llx", GetFName(), pc, PC);
Emu.Pause();
}
nPC = pc;
isBranch = true;
}
void PPCThread::SetError(const u32 error)
{
if(error == 0)
{
m_error = 0;
}
else
{
m_error |= error;
}
}
wxArrayString PPCThread::ErrorToString(const u32 error)
{
wxArrayString earr;
earr.Clear();
if(error == 0) return earr;
earr.Add("Unknown error");
return earr;
}
void PPCThread::Run()
{
if(IsRunned()) Stop();
if(IsPaused())
{
Resume();
return;
}
m_status = Runned;
InitStack();
InitRegs();
DoRun();
Emu.CheckStatus();
if(DisAsmFrame) (*(InterpreterDisAsmFrame*)DisAsmFrame).DoUpdate();
}
void PPCThread::Resume()
{
if(!IsPaused()) return;
m_status = Runned;
DoResume();
Emu.CheckStatus();
}
void PPCThread::Pause()
{
if(!IsRunned()) return;
m_status = Paused;
DoPause();
Emu.CheckStatus();
}
void PPCThread::Stop()
{
if(IsStopped()) return;
m_status = Stopped;
Reset();
DoStop();
Emu.CheckStatus();
}
void PPCThread::Exec()
{
if(!IsRunned()) return;
DoCode(Memory.Read32(m_offset + PC));
NextPc();
}

133
rpcs3/Emu/Cell/PPCThread.h Normal file
View File

@ -0,0 +1,133 @@
#pragma once
#include "Emu/Memory/MemoryBlock.h"
#include "Emu/Cell/Decoder.h"
enum PPCThreadType
{
PPC_THREAD_PPU,
PPC_THREAD_SPU,
};
class PPCThread// : public StepThread
{
protected:
u32 m_status;
u32 m_error;
Decoder* m_dec;
wxWindow* DisAsmFrame;
u32 m_id;
PPCThreadType m_type;
u64 m_arg;
u64 m_prio;
wxString m_name;
bool m_joinable;
bool m_joining;
Array<u64> argv_addr;
u64 m_offset;
public:
u64 stack_size;
u64 stack_addr;
u64 stack_point;
virtual void InitRegs()=0;
virtual void InitStack();
virtual void CloseStack();
virtual u64 GetStackAddr() const { return stack_addr; }
virtual u64 GetStackSize() const { return stack_size; }
virtual u64 GetFreeStackSize() const=0;
void SetArg(const u64 arg) { m_arg = arg; }
void SetId(const u32 id);
void SetName(const wxString& name);
void SetPrio(const u64 prio) { m_prio = prio; }
void SetOffset(const u64 offset) { m_offset = offset; }
u64 GetPrio() const { return m_prio; }
wxString GetName() const { return m_name; }
wxString GetFName() const
{
return
wxString::Format("%s[%d] Thread%s",
GetTypeString(),
m_id,
(GetName().IsEmpty() ? "" : " (" + GetName() + ")")
);
}
static wxString PPCThreadTypeToString(PPCThreadType type)
{
switch(type)
{
case PPC_THREAD_PPU: return "PPU";
case PPC_THREAD_SPU: return "SPU";
}
return "Unknown";
}
wxString GetTypeString() const { return PPCThreadTypeToString(m_type); }
public:
bool isBranch;
u64 PC;
u64 nPC;
u64 cycle;
protected:
PPCThread(PPCThreadType type);
public:
~PPCThread();
void NextPc();
void NextBranchPc();
void PrevPc();
void SetBranch(const u64 pc);
void SetPc(const u64 pc);
void SetError(const u32 error);
static wxArrayString ErrorToString(const u32 error);
wxArrayString ErrorToString() { return ErrorToString(m_error); }
bool IsSPU() const { return m_type == PPC_THREAD_SPU; }
bool IsOk() const { return m_error == 0; }
bool IsRunned() const { return m_status == Runned; }
bool IsPaused() const { return m_status == Paused; }
bool IsStopped() const { return m_status == Stopped; }
bool IsJoinable() const { return m_joinable; }
bool IsJoining() const { return m_joining; }
void SetJoinable(bool joinable) { m_joinable = joinable; }
void SetJoining(bool joining) { m_joining = joining; }
u32 GetError() const { return m_error; }
u32 GetId() const { return m_id; }
void Reset();
void Close();
void Run();
void Pause();
void Resume();
void Stop();
virtual wxString RegsToString() { return wxEmptyString; }
virtual void Exec();
virtual void AddArgv(const wxString& arg) {}
protected:
virtual void DoReset()=0;
virtual void DoRun()=0;
virtual void DoPause()=0;
virtual void DoResume()=0;
virtual void DoStop()=0;
private:
virtual void DoCode(const s32 code)=0;
};

View File

@ -0,0 +1,80 @@
#include "stdafx.h"
#include "PPCThreadManager.h"
#include "PPUThread.h"
#include "SPUThread.h"
PPCThreadManager::PPCThreadManager()
: ThreadBase(true, "PPCThreadManager")
{
}
PPCThreadManager::~PPCThreadManager()
{
Close();
}
void PPCThreadManager::Close()
{
if(IsAlive()) Stop();
while(m_threads.GetCount()) RemoveThread(m_threads[0].GetId());
}
PPCThread& PPCThreadManager::AddThread(bool isPPU)
{
PPCThread* new_thread = isPPU ? (PPCThread*)new PPUThread() : (PPCThread*)new SPUThread();
new_thread->SetId(Emu.GetIdManager().GetNewID(
wxString::Format("%s Thread", isPPU ? "PPU" : "SPU"), new_thread, 0)
);
m_threads.Add(new_thread);
return *new_thread;
}
void PPCThreadManager::RemoveThread(const u32 id)
{
for(u32 i=0; i<m_threads.GetCount(); ++i)
{
if(m_threads[i].GetId() != id) continue;
m_threads[i].Close();
m_threads.RemoveAt(i);
break;
}
Emu.GetIdManager().RemoveID(id, false);
Emu.CheckStatus();
}
s32 PPCThreadManager::GetThreadNumById(bool isPPU, u32 id)
{
s32 num = 0;
for(u32 i=0; i<m_threads.GetCount(); ++i)
{
if(m_threads[i].GetId() == id) return num;
if(m_threads[i].IsSPU() == !isPPU) num++;
}
return -1;
}
void PPCThreadManager::Exec()
{
Start();
}
void PPCThreadManager::Task()
{
u32 thread = 0;
while(!TestDestroy() && Emu.IsRunned() && m_threads.GetCount())
{
m_threads[thread].Exec();
thread = (thread + 1) % m_threads.GetCount();
}
}

View File

@ -0,0 +1,26 @@
#pragma once
#include "PPCThread.h"
class PPCThreadManager : public ThreadBase
{
//IdManager m_threads_id;
//ArrayF<PPUThread> m_ppu_threads;
//ArrayF<SPUThread> m_spu_threads;
ArrayF<PPCThread> m_threads;
public:
PPCThreadManager();
~PPCThreadManager();
void Close();
PPCThread& AddThread(bool isPPU);
void RemoveThread(const u32 id);
ArrayF<PPCThread>& GetThreads() { return m_threads; }
s32 GetThreadNumById(bool isPPU, u32 id);
//IdManager& GetIDs() {return m_threads_id;}
void Exec();
virtual void Task();
};

487
rpcs3/Emu/Cell/PPUDecoder.h Normal file
View File

@ -0,0 +1,487 @@
#pragma once
#include "Emu/Cell/PPUOpcodes.h"
#include "Emu/Cell/Decoder.h"
#define START_OPCODES_GROUP(group, reg) \
case(##group##): \
temp=##reg##;\
switch(temp)\
{
#define END_OPCODES_GROUP(group) \
default:\
m_op.UNK(m_code, opcode, temp);\
break;\
}\
break
#define ADD_OPCODE(name, ...) case(##name##):m_op.##name##(__VA_ARGS__); break
class PPU_Decoder : public Decoder
{
u32 m_code;
PPU_Opcodes& m_op;
//This field is used in rotate instructions to specify the first 1 bit of a 64-bit mask
OP_REG mb() const { return GetField(21, 25) | (m_code & 0x20); }
//This field is used in rotate instructions to specify the last 1 bit of a 64-bit mask
OP_REG me() const { return GetField(21, 25) | (m_code & 0x20); }
//This field is used to specify a shift amount
OP_REG sh() const { return GetField(16, 20) | ((m_code & 0x2) << 4); }
//This field is used to specify a special-purpose register for the mtspr and mfspr instructions
OP_REG SPR() const { return GetField(11, 20); }
//
OP_REG VD() const { return GetField(6, 10); }
//
OP_REG VA() const { return GetField(11, 15); }
//
OP_REG VB() const { return GetField(16, 20); }
//This field is used to specify a GPR to be used as a destination
OP_REG RD() const { return GetField(6, 10); }
//This field is used to specify a GPR to be used as a source
OP_REG RS() const { return GetField(6, 10); }
//This field is used to specify a GPR to be used as a source or destination
OP_REG RA() const { return GetField(11, 15); }
//This field is used to specify a GPR to be used as a source
OP_REG RB() const { return GetField(16, 20); }
//This field is used to specify the number of bytes to move in an immediate string load or store
OP_REG NB() const { return GetField(16, 20); }
//This field is used to specify one of the CR fields, or one of the FPSCR fields, as a destination
OP_REG CRFD() const { return GetField(6, 8); }
//This field is used to specify one of the CR fields, or one of the FPSCR fields, as a source
OP_REG CRFS() const { return GetField(11, 13); }
//This field is used to specify a bit in the CR to be used as a source
OP_REG CRBA() const { return GetField(11, 15); }
//This field is used to specify a bit in the CR to be used as a source
OP_REG CRBB() const { return GetField(16, 20); }
//This field is used to specify a bit in the CR, or in the FPSCR, as the destination of the result of an instruction
OP_REG CRBD() const { return GetField(6, 10); }
//
OP_REG BT() const { return GetField(6, 10); }
//
OP_REG BA() const { return GetField(11, 15); }
//
OP_REG BB() const { return GetField(16, 20); }
//
OP_REG BF() const { return GetField(6, 10); }
//This field is used to specify options for the branch conditional instructions
OP_REG BO() const { return GetField(6, 10); }
//This field is used to specify a bit in the CR to be used as the condition of a branch conditional instruction
OP_REG BI() const { return GetField(11, 15); }
//Immediate field specifying a 14-bit signed two's complement branch displacement that is concatenated on the
//right with 00 and sign-extended to 64 bits.
OP_sIMM BD() const { return (s32)(s16)GetField(16, 31); }
//
OP_REG BH() const { return GetField(19, 20); }
//
OP_REG BFA() const { return GetField(11, 13); }
//Field used by the optional data stream variant of the dcbt instruction.
OP_uIMM TH() const { return GetField(9, 10); }
//This field is used to specify the conditions on which to trap
OP_uIMM TO() const { return GetField(6, 10); }
//
OP_REG MB() const { return GetField(21, 25); }
//
OP_REG ME() const { return GetField(26, 30); }
//This field is used to specify a shift amount
OP_REG SH() const { return GetField(16, 20); }
/*
Absolute address bit.
0 The immediate field represents an address relative to the current instruction address (CIA). (For more
information on the CIA, see Table 8-3.) The effective (logical) address of the branch is either the sum
of the LI field sign-extended to 64 bits and the address of the branch instruction or the sum of the BD
field sign-extended to 64 bits and the address of the branch instruction.
1 The immediate field represents an absolute address. The effective address (EA) of the branch is the
LI field sign-extended to 64 bits or the BD field sign-extended to 64 bits.
*/
OP_REG AA() const { return GetField(30); }
//
OP_sIMM LL() const
{
OP_sIMM ll = m_code & 0x03fffffc;
if (ll & 0x02000000) return ll - 0x04000000;
return ll;
}
/*
Link bit.
0 Does not update the link register (LR).
1 Updates the LR. If the instruction is a branch instruction, the address of the instruction following the
branch instruction is placed into the LR.
*/
OP_REG LK() const { return GetField(31); }
//This field is used for extended arithmetic to enable setting OV and SO in the XER
OP_REG OE() const { return GetField(21); }
//Field used to specify whether an integer compare instruction is to compare 64-bit numbers or 32-bit numbers
OP_REG L() const { return GetField(10); }
//
OP_REG I() const { return GetField(16, 19); }
//
OP_REG DQ() const { return GetField(16, 27); }
//This field is used to specify an FPR as the destination
OP_REG FRD() const { return GetField(6, 10); }
//This field is used to specify an FPR as a source
OP_REG FRS() const { return GetField(6, 10); }
//
OP_REG FLM() const { return GetField(7, 14); }
//This field is used to specify an FPR as a source
OP_REG FRA() const { return GetField(11, 15); }
//This field is used to specify an FPR as a source
OP_REG FRB() const { return GetField(16, 20); }
//This field is used to specify an FPR as a source
OP_REG FRC() const { return GetField(21, 25); }
//
OP_REG FXM() const { return GetField(12, 19); }
//
const s32 SYS() const { return GetField(6, 31); }
//Immediate field specifying a 16-bit signed two's complement integer that is sign-extended to 64 bits
OP_sIMM D() const { return (s32)(s16)GetField(16, 31); }
//
OP_sIMM DS() const
{
OP_sIMM d = D();
if(d < 0) return d - 1;
return d;
}
//This immediate field is used to specify a 16-bit signed integer
OP_sIMM simm16() const { return (s32)(s16)m_code; }
//This immediate field is used to specify a 16-bit unsigned integer
OP_uIMM uimm16() const { return (u32)(u16)m_code; }
/*
Record bit.
0 Does not update the condition register (CR).
1 Updates the CR to reflect the result of the operation.
For integer instructions, CR bits [02] are set to reflect the result as a signed quantity and CR bit [3]
receives a copy of the summary overflow bit, XER[SO]. The result as an unsigned quantity or a bit
string can be deduced from the EQ bit. For floating-point instructions, CR bits [47] are set to reflect
floating-point exception, floating-point enabled exception, floating-point invalid operation exception,
and floating-point overflow exception.
*/
const bool RC() const { return m_code & 0x1; }
//Primary opcode field
OP_uIMM OPCD() const { return GetField(0, 5); }
__forceinline u32 GetField(const u32 p) const
{
return (m_code >> (31 - p)) & 0x1;
}
__forceinline u32 GetField(const u32 from, const u32 to) const
{
return (m_code >> (31 - to)) & ((1 << ((to - from) + 1)) - 1);
}
public:
PPU_Decoder(PPU_Opcodes& op) : m_op(op)
{
}
~PPU_Decoder()
{
m_op.Exit();
}
virtual void Decode(const u32 code)
{
if(code == 0)
{
m_op.NULL_OP();
return;
}
m_code = code;
u32 opcode, temp;
switch((opcode = OPCD()))
{
ADD_OPCODE(TDI, TO(), RA(), simm16());
ADD_OPCODE(TWI, TO(), RA(), simm16());
START_OPCODES_GROUP(G_04, ((m_code >> 1) & 0x3ff))
ADD_OPCODE(VXOR, VD(), VA(), VB());
END_OPCODES_GROUP(G_04);
ADD_OPCODE(MULLI, RD(), RA(), simm16());
ADD_OPCODE(SUBFIC, RD(), RA(), simm16());
ADD_OPCODE(CMPLI, CRFD(), L(), RA(), uimm16());
ADD_OPCODE(CMPI, CRFD(), L(), RA(), simm16());
ADD_OPCODE(ADDIC, RD(), RA(), simm16());
ADD_OPCODE(ADDIC_, RD(), RA(), simm16());
ADD_OPCODE(ADDI, RD(), RA(), simm16());
ADD_OPCODE(ADDIS, RD(), RA(), simm16());
ADD_OPCODE(BC, BO(), BI(), BD(), AA(), LK());
ADD_OPCODE(SC, SYS());
ADD_OPCODE(B, LL(), AA(), LK());
START_OPCODES_GROUP(G_13, GetField(21, 30))
ADD_OPCODE(MCRF, CRFD(), CRFS());
ADD_OPCODE(BCLR, BO(), BI(), BH(), LK());
ADD_OPCODE(CRNOR, CRBD(), CRBA(), CRBB());
ADD_OPCODE(CRANDC, CRBD(), CRBA(), CRBB());
ADD_OPCODE(ISYNC);
ADD_OPCODE(CRXOR, CRBD(), CRBA(), CRBB());
ADD_OPCODE(CRNAND, CRBD(), CRBA(), CRBB());
ADD_OPCODE(CRAND, CRBD(), CRBA(), CRBB());
ADD_OPCODE(CREQV, CRBD(), CRBA(), CRBB());
ADD_OPCODE(CRORC, CRBD(), CRBA(), CRBB());
ADD_OPCODE(CROR, CRBD(), CRBA(), CRBB());
ADD_OPCODE(BCCTR, BO(), BI(), BH(), LK());
END_OPCODES_GROUP(G_13);
ADD_OPCODE(RLWIMI, RA(), RS(), SH(), MB(), ME(), RC());
ADD_OPCODE(RLWINM, RA(), RS(), SH(), MB(), ME(), RC());
ADD_OPCODE(RLWNM, RA(), RS(), RB(), MB(), ME(), RC());
ADD_OPCODE(ORI, RA(), RS(), uimm16());
ADD_OPCODE(ORIS, RA(), RS(), uimm16());
ADD_OPCODE(XORI, RA(), RS(), uimm16());
ADD_OPCODE(XORIS, RA(), RS(), uimm16());
ADD_OPCODE(ANDI_, RA(), RS(), uimm16());
ADD_OPCODE(ANDIS_, RA(), RS(), uimm16());
START_OPCODES_GROUP(G_1e, GetField(28, 29))
ADD_OPCODE(RLDICL, RA(), RS(), sh(), mb(), RC());
ADD_OPCODE(RLDICR, RA(), RS(), sh(), me(), RC());
ADD_OPCODE(RLDIC, RA(), RS(), sh(), mb(), RC());
ADD_OPCODE(RLDIMI, RA(), RS(), sh(), mb(), RC());
END_OPCODES_GROUP(G_1e);
START_OPCODES_GROUP(G_1f, GetField(21, 30))
/*0x000*/ADD_OPCODE(CMP, CRFD(), L(), RA(), RB());
/*0x004*/ADD_OPCODE(TW, TO(), RA(), RB());
/*0x007*/ADD_OPCODE(LVEBX, VD(), RA(), RB());
/*0x008*/ADD_OPCODE(SUBFC, RD(), RA(), RB(), OE(), RC());
/*0x009*/ADD_OPCODE(MULHDU, RD(), RA(), RB(), RC());
/*0x00a*/ADD_OPCODE(ADDC, RD(), RA(), RB(), OE(), RC());
/*0x00b*/ADD_OPCODE(MULHWU, RD(), RA(), RB(), RC());
/*0x013*/ADD_OPCODE(MFOCRF, GetField(11), FXM(), RD());
/*0x014*/ADD_OPCODE(LWARX, RD(), RA(), RB());
/*0x015*/ADD_OPCODE(LDX, RA(), RS(), RB());
/*0x017*/ADD_OPCODE(LWZX, RD(), RA(), RB());
/*0x018*/ADD_OPCODE(SLW, RA(), RS(), RB(), RC());
/*0x01a*/ADD_OPCODE(CNTLZW, RA(), RS(), RC());
/*0x01b*/ADD_OPCODE(SLD, RA(), RS(), RB(), RC());
/*0x01c*/ADD_OPCODE(AND, RA(), RS(), RB(), RC());
/*0x020*/ADD_OPCODE(CMPL, CRFD(), L(), RA(), RB());
/*0x027*/ADD_OPCODE(LVEHX, VD(), RA(), RB());
/*0x028*/ADD_OPCODE(SUBF, RD(), RA(), RB(), OE(), RC());
/*0x036*/ADD_OPCODE(DCBST, RA(), RB());
/*0x03a*/ADD_OPCODE(CNTLZD, RA(), RS(), RC());
/*0x03c*/ADD_OPCODE(ANDC, RA(), RS(), RB(), RC());
/*0x049*/ADD_OPCODE(MULHD, RD(), RA(), RB(), RC());
/*0x04b*/ADD_OPCODE(MULHW, RD(), RA(), RB(), RC());
/*0x054*/ADD_OPCODE(LDARX, RD(), RA(), RB());
/*0x056*/ADD_OPCODE(DCBF, RA(), RB());
/*0x057*/ADD_OPCODE(LBZX, RD(), RA(), RB());
/*0x067*/ADD_OPCODE(LVX, VD(), RA(), RB());
/*0x068*/ADD_OPCODE(NEG, RD(), RA(), OE(), RC());
/*0x077*/ADD_OPCODE(LBZUX, RD(), RA(), RB());
/*0x07c*/ADD_OPCODE(NOR, RA(), RS(), RB(), RC());
/*0x088*/ADD_OPCODE(SUBFE, RD(), RA(), RB(), OE(), RC());
/*0x08a*/ADD_OPCODE(ADDE, RD(), RA(), RB(), OE(), RC());
/*0x090*/ADD_OPCODE(MTOCRF, FXM(), RS());
/*0x095*/ADD_OPCODE(STDX, RS(), RA(), RB());
/*0x096*/ADD_OPCODE(STWCX_, RS(), RA(), RB());
/*0x097*/ADD_OPCODE(STWX, RS(), RA(), RB());
/*0x0b5*/ADD_OPCODE(STDUX, RS(), RA(), RB());
/*0x0ca*/ADD_OPCODE(ADDZE, RD(), RA(), OE(), RC());
/*0x0d6*/ADD_OPCODE(STDCX_, RS(), RA(), RB());
/*0x0d7*/ADD_OPCODE(STBX, RS(), RA(), RB());
/*0x0e7*/ADD_OPCODE(STVX, VD(), RA(), RB());
/*0x0e9*/ADD_OPCODE(MULLD, RD(), RA(), RB(), OE(), RC());
/*0x0ea*/ADD_OPCODE(ADDME, RD(), RA(), OE(), RC());
/*0x0eb*/ADD_OPCODE(MULLW, RD(), RA(), RB(), OE(), RC());
/*0x0f6*/ADD_OPCODE(DCBTST, TH(), RA(), RB());
/*0x10a*/ADD_OPCODE(ADD, RD(), RA(), RB(), OE(), RC());
/*0x116*/ADD_OPCODE(DCBT, RA(), RB(), TH());
/*0x117*/ADD_OPCODE(LHZX, RD(), RA(), RB());
/*0x11c*/ADD_OPCODE(EQV, RA(), RS(), RB(), RC());
/*0x136*/ADD_OPCODE(ECIWX, RD(), RA(), RB());
/*0x137*/ADD_OPCODE(LHZUX, RD(), RA(), RB());
/*0x13c*/ADD_OPCODE(XOR, RA(), RS(), RB(), RC());
/*0x153*/ADD_OPCODE(MFSPR, RD(), SPR());
/*0x157*/ADD_OPCODE(LHAX, RD(), RA(), RB());
/*0x168*/ADD_OPCODE(ABS, RD(), RA(), OE(), RC());
/*0x173*/ADD_OPCODE(MFTB, RD(), SPR());
/*0x177*/ADD_OPCODE(LHAUX, RD(), RA(), RB());
/*0x197*/ADD_OPCODE(STHX, RS(), RA(), RB());
/*0x19c*/ADD_OPCODE(ORC, RA(), RS(), RB(), RC());
/*0x1b6*/ADD_OPCODE(ECOWX, RS(), RA(), RB());
/*0x1bc*/ADD_OPCODE(OR, RA(), RS(), RB(), RC());
/*0x1c9*/ADD_OPCODE(DIVDU, RD(), RA(), RB(), OE(), RC());
/*0x1cb*/ADD_OPCODE(DIVWU, RD(), RA(), RB(), OE(), RC());
/*0x1d3*/ADD_OPCODE(MTSPR, SPR(), RS());
/*0x1d6*///DCBI
/*0x1e9*/ADD_OPCODE(DIVD, RD(), RA(), RB(), OE(), RC());
/*0x1eb*/ADD_OPCODE(DIVW, RD(), RA(), RB(), OE(), RC());
/*0x216*/ADD_OPCODE(LWBRX, RD(), RA(), RB());
/*0x217*/ADD_OPCODE(LFSX, FRD(), RA(), RB());
/*0x218*/ADD_OPCODE(SRW, RA(), RS(), RB(), RC());
/*0x21b*/ADD_OPCODE(SRD, RA(), RS(), RB(), RC());
/*0x237*/ADD_OPCODE(LFSUX, FRD(), RA(), RB());
/*0x256*/ADD_OPCODE(SYNC, GetField(9, 10));
/*0x257*/ADD_OPCODE(LFDX, FRD(), RA(), RB());
/*0x277*/ADD_OPCODE(LFDUX, FRD(), RA(), RB());
/*0x297*/ADD_OPCODE(STFSX, RS(), RA(), RB());
/*0x316*/ADD_OPCODE(LHBRX, RD(), RA(), RB());
/*0x318*/ADD_OPCODE(SRAW, RA(), RS(), RB(), RC());
/*0x31A*/ADD_OPCODE(SRAD, RA(), RS(), RB(), RC());
/*0x338*/ADD_OPCODE(SRAWI, RA(), RS(), sh(), RC());
/*0x33a*/ADD_OPCODE(SRADI1, RA(), RS(), sh(), RC());
/*0x33b*/ADD_OPCODE(SRADI2, RA(), RS(), sh(), RC());
/*0x356*/ADD_OPCODE(EIEIO);
/*0x39a*/ADD_OPCODE(EXTSH, RA(), RS(), RC());
/*0x3ba*/ADD_OPCODE(EXTSB, RA(), RS(), RC());
/*0x3d7*/ADD_OPCODE(STFIWX, FRS(), RA(), RB());
/*0x3da*/ADD_OPCODE(EXTSW, RA(), RS(), RC());
/*0x3d6*///ICBI
/*0x3f6*/ADD_OPCODE(DCBZ, RA(), RB());
END_OPCODES_GROUP(G_1f);
ADD_OPCODE(LWZ, RD(), RA(), D());
ADD_OPCODE(LWZU, RD(), RA(), D());
ADD_OPCODE(LBZ, RD(), RA(), D());
ADD_OPCODE(LBZU, RD(), RA(), D());
ADD_OPCODE(STW, RS(), RA(), D());
ADD_OPCODE(STWU, RS(), RA(), D());
ADD_OPCODE(STB, RS(), RA(), D());
ADD_OPCODE(STBU, RS(), RA(), D());
ADD_OPCODE(LHZ, RD(), RA(), D());
ADD_OPCODE(LHZU, RD(), RA(), D());
ADD_OPCODE(STH, RS(), RA(), D());
ADD_OPCODE(STHU, RS(), RA(), D());
ADD_OPCODE(LMW, RD(), RA(), D());
ADD_OPCODE(STMW, RS(), RA(), D());
ADD_OPCODE(LFS, FRD(), RA(), D());
ADD_OPCODE(LFSU, FRD(), RA(), D());
ADD_OPCODE(LFD, FRD(), RA(), D());
ADD_OPCODE(LFDU, FRD(), RA(), D());
ADD_OPCODE(STFS, FRS(), RA(), D());
ADD_OPCODE(STFSU, FRS(), RA(), D());
ADD_OPCODE(STFD, FRS(), RA(), D());
ADD_OPCODE(STFDU, FRS(), RA(), D());
START_OPCODES_GROUP(G_3a, GetField(30, 31))
ADD_OPCODE(LD, RD(), RA(), D());
ADD_OPCODE(LDU, RD(), RA(), DS());
END_OPCODES_GROUP(G_3a);
START_OPCODES_GROUP(G_3b, GetField(26, 30))
ADD_OPCODE(FDIVS, FRD(), FRA(), FRB(), RC());
ADD_OPCODE(FSUBS, FRD(), FRA(), FRB(), RC());
ADD_OPCODE(FADDS, FRD(), FRA(), FRB(), RC());
ADD_OPCODE(FSQRTS, FRD(), FRB(), RC());
ADD_OPCODE(FRES, FRD(), FRB(), RC());
ADD_OPCODE(FMULS, FRD(), FRA(), FRC(), RC());
ADD_OPCODE(FMADDS, FRD(), FRA(), FRC(), FRB(), RC());
ADD_OPCODE(FMSUBS, FRD(), FRA(), FRC(), FRB(), RC());
ADD_OPCODE(FNMSUBS, FRD(), FRA(), FRC(), FRB(), RC());
ADD_OPCODE(FNMADDS, FRD(), FRA(), FRC(), FRB(), RC());
END_OPCODES_GROUP(G_3b);
START_OPCODES_GROUP(G_3e, GetField(30, 31))
ADD_OPCODE(STD, RS(), RA(), D());
ADD_OPCODE(STDU, RS(), RA(), DS());
END_OPCODES_GROUP(G_3e);
START_OPCODES_GROUP(G_3f, GetField(26, 30))
ADD_OPCODE(FDIV, FRD(), FRA(), FRB(), RC());
ADD_OPCODE(FSUB, FRD(), FRA(), FRB(), RC());
ADD_OPCODE(FADD, FRD(), FRA(), FRB(), RC());
ADD_OPCODE(FSQRT, FRD(), FRB(), RC());
ADD_OPCODE(FSEL, FRD(), FRA(), FRC(), FRB(), RC());
ADD_OPCODE(FMUL, FRD(), FRA(), FRC(), RC());
ADD_OPCODE(FRSQRTE, FRD(), FRB(), RC());
ADD_OPCODE(FMSUB, FRD(), FRA(), FRC(), FRB(), RC());
ADD_OPCODE(FMADD, FRD(), FRA(), FRC(), FRB(), RC());
ADD_OPCODE(FNMSUB, FRD(), FRA(), FRC(), FRB(), RC());
ADD_OPCODE(FNMADD, FRD(), FRA(), FRC(), FRB(), RC());
ADD_OPCODE(FCMPO, CRFD(), FRA(), FRB());
default:
START_OPCODES_GROUP(0x8, GetField(21, 30))
ADD_OPCODE(FCMPU, CRFD(), FRA(), FRB());
ADD_OPCODE(FRSP, FRD(), FRB(), RC());
ADD_OPCODE(FCTIW, FRD(), FRB(), RC());
ADD_OPCODE(FCTIWZ, FRD(), FRB(), RC());
ADD_OPCODE(FNEG, FRD(), FRB(), RC());
ADD_OPCODE(FMR, FRD(), FRB(), RC());
ADD_OPCODE(FNABS, FRD(), FRB(), RC());
ADD_OPCODE(FABS, FRD(), FRB(), RC());
ADD_OPCODE(FCFID, FRD(), FRB(), RC());
ADD_OPCODE(FCTID, FRD(), FRB(), RC());
ADD_OPCODE(FCTIDZ, FRD(), FRB(), RC());
ADD_OPCODE(MTFSB1, BT(), RC());
ADD_OPCODE(MCRFS, BF(), BFA());
ADD_OPCODE(MTFSB0, BT(), RC());
ADD_OPCODE(MTFSFI, CRFD(), I(), RC());
ADD_OPCODE(MFFS, FRD(), RC());
ADD_OPCODE(MTFSF, FLM(), FRB(), RC());
END_OPCODES_GROUP(0x8);
break;
}
break;
//END_OPCODES_GROUP(G_3f);
default: m_op.UNK(m_code, opcode, opcode); break;
}
}
};
#undef START_OPCODES_GROUP
#undef ADD_OPCODE
#undef ADD_NULL_OPCODE
#undef END_OPCODES_GROUP

1091
rpcs3/Emu/Cell/PPUDisAsm.h Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

502
rpcs3/Emu/Cell/PPUOpcodes.h Normal file
View File

@ -0,0 +1,502 @@
#pragma once
#define OP_REG const u32
#define OP_sIMM const s32
#define OP_uIMM const u32
#define START_OPCODES_GROUP(x) /*x*/
#define ADD_OPCODE(name, regs) virtual void(##name##)##regs##=0
#define ADD_NULL_OPCODE(name) virtual void(##name##)()=0
#define END_OPCODES_GROUP(x) /*x*/
enum PPU_MainOpcodes
{
TDI = 0x02, //Trap Doubleword Immediate
TWI = 0x03, //Trap Word Immediate
G_04 = 0x04,
MULLI = 0x07, //Multiply Low Immediate
SUBFIC = 0x08, //Subtract from Immediate Carrying
//DOZI = 0x09,
CMPLI = 0x0a, //Compare Logical Immediate
CMPI = 0x0b, //Compare Immediate
ADDIC = 0x0c, //Add Immediate Carrying
ADDIC_ = 0x0d, //Add Immediate Carrying and Record
ADDI = 0x0e, //Add Immediate
ADDIS = 0x0f, //Add Immediate Shifted
BC = 0x10, //Branch Conditional
SC = 0x11, //System Call
B = 0x12, //Branch
G_13 = 0x13,
RLWIMI = 0x14, //Rotate Left Word Immediate then Mask Insert
RLWINM = 0x15, //Rotate Left Word Immediate then AND with Mask
RLWNM = 0x17, //Rotate Left Word then AND with Mask
ORI = 0x18, //OR Immediate
ORIS = 0x19, //OR Immediate Shifted
XORI = 0x1a, //XOR Immediate
XORIS = 0x1b, //XOR Immediate Shifted
ANDI_ = 0x1c, //AND Immediate
ANDIS_ = 0x1d, //AND Immediate Shifted
G_1e = 0x1e,
G_1f = 0x1f,
LWZ = 0x20, //Load Word and Zero Indexed
LWZU = 0x21, //Load Word and Zero with Update Indexed
LBZ = 0x22, //Load Byte and Zero
LBZU = 0x23, //Load Byte and Zero with Update
STW = 0x24, //Store Word
STWU = 0x25, //Store Word with Update
STB = 0x26, //Store Byte
STBU = 0x27, //Store Byte with Update
LHZ = 0x28, //Load Halfword and Zero
LHZU = 0x29, //Load Halfword and Zero with Update
LHA = 0x2a, //Load Halfword Algebraic with Update
LHAU = 0x2b, //Load Halfword Algebraic
STH = 0x2c, //Store Halfword
STHU = 0x2d, //Store Halfword with Update
LMW = 0x2e, //Load Multiple Word
STMW = 0x2f, //Store Multiple Word
LFS = 0x30, //Load Floating-Point Single
LFSU = 0x31, //Load Floating-Point Single with Update
LFD = 0x32, //Load Floating-Point Double
LFDU = 0x33, //Load Floating-Point Double with Update
STFS = 0x34, //Store Floating-Point Single
STFSU = 0x35, //Store Floating-Point Single with Update
STFD = 0x36, //Store Floating-Point Double
STFDU = 0x37, //Store Floating-Point Double with Update
LFQ = 0x38, //
LFQU = 0x39, //
G_3a = 0x3a,
G_3b = 0x3b,
G_3e = 0x3e,
G_3f = 0x3f,
};
enum G_04Opcodes
{
VXOR = 0x262,
};
enum G_13Opcodes //Field 21 - 30
{
MCRF = 0x000,
BCLR = 0x010,
CRNOR = 0x021,
CRANDC = 0x081,
ISYNC = 0x096,
CRXOR = 0x0c1,
CRNAND = 0x0e1,
CRAND = 0x101,
CREQV = 0x121,
CRORC = 0x1a1,
CROR = 0x1c1,
BCCTR = 0x210,
};
enum G_1eOpcodes //Field 27 - 29
{
RLDICL = 0x0,
RLDICR = 0x1,
RLDIC = 0x2,
RLDIMI = 0x3,
};
enum G_1fOpcodes //Field 21 - 30
{
CMP = 0x000,
TW = 0x004,
LVEBX = 0x007, //Load Vector Element Byte Indexed
SUBFC = 0x008, //Subtract from Carrying
MULHDU = 0x009,
ADDC = 0x00a,
MULHWU = 0x00b,
MFOCRF = 0x013,
LWARX = 0x014,
LDX = 0x015,
LWZX = 0x017,
SLW = 0x018,
CNTLZW = 0x01a,
SLD = 0x01b,
AND = 0x01c,
CMPL = 0x020,
LVEHX = 0x027, //Load Vector Element Halfword Indexed
SUBF = 0x028,
LDUX = 0x035, //Load Doubleword with Update Indexed
DCBST = 0x036,
CNTLZD = 0x03a,
ANDC = 0x03c,
LVEWX = 0x047, //Load Vector Element Word Indexed
MULHD = 0x049,
MULHW = 0x04b,
LDARX = 0x054,
DCBF = 0x056,
LBZX = 0x057,
LVX = 0x067,
NEG = 0x068,
LBZUX = 0x077,
NOR = 0x07c,
SUBFE = 0x088, //Subtract from Extended
ADDE = 0x08a,
MTOCRF = 0x090,
STDX = 0x095,
STWCX_ = 0x096,
STWX = 0x097,
STDUX = 0x0b5,
ADDZE = 0x0ca,
STDCX_ = 0x0d6,
STBX = 0x0d7,
STVX = 0x0e7,
MULLD = 0x0e9,
ADDME = 0x0ea,
MULLW = 0x0eb,
DCBTST = 0x0f6,
DOZ = 0x108,
ADD = 0x10a,
DCBT = 0x116,
LHZX = 0x117,
EQV = 0x11c,
ECIWX = 0x136,
LHZUX = 0x137,
XOR = 0x13c,
MFSPR = 0x153,
LHAX = 0x157,
ABS = 0x168,
MFTB = 0x173,
LHAUX = 0x177,
STHX = 0x197, //Store Halfword Indexed
ORC = 0x19c, //OR with Complement
ECOWX = 0x1b6,
OR = 0x1bc,
DIVDU = 0x1c9,
DIVWU = 0x1cb,
MTSPR = 0x1d3,
DCBI = 0x1d6,
DIVD = 0x1e9,
DIVW = 0x1eb,
LWBRX = 0x216,
LFSX = 0x217,
SRW = 0x218,
SRD = 0x21b,
LFSUX = 0x237,
SYNC = 0x256,
LFDX = 0x257,
LFDUX = 0x277,
STFSX = 0x297,
LHBRX = 0x316,
SRAW = 0x318,
SRAD = 0x31A,
SRAWI = 0x338,
SRADI1 = 0x33a, //sh_5 == 0
SRADI2 = 0x33b, //sh_5 != 0
EIEIO = 0x356,
EXTSH = 0x39a,
EXTSB = 0x3ba,
STFIWX = 0x3d7,
EXTSW = 0x3da,
ICBI = 0x3d6,
DCBZ = 0x3f6,
};
enum G_3aOpcodes //Field 30 - 31
{
LD = 0x0,
LDU = 0x1,
};
enum G_3bOpcodes //Field 26 - 30
{
FDIVS = 0x12,
FSUBS = 0x14,
FADDS = 0x15,
FSQRTS = 0x16,
FRES = 0x18,
FMULS = 0x19,
FMSUBS = 0x1c,
FMADDS = 0x1d,
FNMSUBS = 0x1e,
FNMADDS = 0x1f,
};
enum G_3eOpcodes //Field 30 - 31
{
STD = 0x0,
STDU = 0x1,
};
enum G_3fOpcodes //Field 21 - 30
{
MTFSB1 = 0x026,
MCRFS = 0x040,
MTFSB0 = 0x046,
MTFSFI = 0x086,
MFFS = 0x247,
MTFSF = 0x2c7,
FCMPU = 0x000,
FRSP = 0x00c,
FCTIW = 0x00e,
FCTIWZ = 0x00f,
FDIV = 0x012,
FSUB = 0x014,
FADD = 0x015,
FSQRT = 0x016,
FSEL = 0x017,
FMUL = 0x019,
FRSQRTE = 0x01a,
FMSUB = 0x01c,
FMADD = 0x01d,
FNMSUB = 0x01e,
FNMADD = 0x01f,
FCMPO = 0x020,
FNEG = 0x028,
FMR = 0x048,
FNABS = 0x088,
FABS = 0x108,
FCTID = 0x32e,
FCTIDZ = 0x32f,
FCFID = 0x34e,
};
//118
class PPU_Opcodes
{
public:
virtual void Exit()=0;
static u64 branchTarget(const u64 pc, const u64 imm)
{
return pc + (imm & ~0x3);
}
ADD_NULL_OPCODE(NULL_OP);
ADD_NULL_OPCODE(NOP);
ADD_OPCODE(TDI,(OP_uIMM to, OP_REG ra, OP_sIMM simm16));
ADD_OPCODE(TWI,(OP_uIMM to, OP_REG ra, OP_sIMM simm16));
START_OPCODES_GROUP(G_04)
ADD_OPCODE(VXOR,(OP_REG vrd, OP_REG vra, OP_REG vrb));
END_OPCODES_GROUP(G_04);
ADD_OPCODE(MULLI,(OP_REG rd, OP_REG ra, OP_sIMM simm16));
ADD_OPCODE(SUBFIC,(OP_REG rd, OP_REG ra, OP_sIMM simm16));
ADD_OPCODE(CMPLI,(OP_REG bf, OP_REG l, OP_REG ra, OP_uIMM uimm16));
ADD_OPCODE(CMPI,(OP_REG bf, OP_REG l, OP_REG ra, OP_sIMM simm16));
ADD_OPCODE(ADDIC,(OP_REG rd, OP_REG ra, OP_sIMM simm16));
ADD_OPCODE(ADDIC_,(OP_REG rd, OP_REG ra, OP_sIMM simm16));
ADD_OPCODE(ADDI,(OP_REG rd, OP_REG ra, OP_sIMM simm16));
ADD_OPCODE(ADDIS,(OP_REG rd, OP_REG ra, OP_sIMM simm16));
ADD_OPCODE(BC,(OP_REG bo, OP_REG bi, OP_sIMM bd, OP_REG aa, OP_REG lk));
ADD_OPCODE(SC,(const s32 sc_code));
ADD_OPCODE(B,(OP_sIMM ll, OP_REG aa, OP_REG lk));
START_OPCODES_GROUP(G_13)
ADD_OPCODE(MCRF,(OP_REG crfd, OP_REG crfs));
ADD_OPCODE(BCLR,(OP_REG bo, OP_REG bi, OP_REG bh, OP_REG lk));
ADD_OPCODE(CRNOR,(OP_REG bt, OP_REG ba, OP_REG bb));
ADD_OPCODE(CRANDC,(OP_REG bt, OP_REG ba, OP_REG bb));
ADD_OPCODE(ISYNC,());
ADD_OPCODE(CRXOR,(OP_REG bt, OP_REG ba, OP_REG bb));
ADD_OPCODE(CRNAND,(OP_REG bt, OP_REG ba, OP_REG bb));
ADD_OPCODE(CRAND,(OP_REG bt, OP_REG ba, OP_REG bb));
ADD_OPCODE(CREQV,(OP_REG bt, OP_REG ba, OP_REG bb));
ADD_OPCODE(CRORC,(OP_REG bt, OP_REG ba, OP_REG bb));
ADD_OPCODE(CROR,(OP_REG bt, OP_REG ba, OP_REG bb));
ADD_OPCODE(BCCTR,(OP_REG bo, OP_REG bi, OP_REG bh, OP_REG lk));
END_OPCODES_GROUP(G_13);
ADD_OPCODE(RLWIMI,(OP_REG ra, OP_REG rs, OP_REG sh, OP_REG mb, OP_REG me, bool rc));
ADD_OPCODE(RLWINM,(OP_REG ra, OP_REG rs, OP_REG sh, OP_REG mb, OP_REG me, bool rc));
ADD_OPCODE(RLWNM,(OP_REG ra, OP_REG rs, OP_REG rb, OP_REG MB, OP_REG ME, bool rc));
ADD_OPCODE(ORI,(OP_REG rs, OP_REG ra, OP_uIMM uimm16));
ADD_OPCODE(ORIS,(OP_REG rs, OP_REG ra, OP_uIMM uimm16));
ADD_OPCODE(XORI,(OP_REG ra, OP_REG rs, OP_uIMM uimm16));
ADD_OPCODE(XORIS,(OP_REG ra, OP_REG rs, OP_uIMM uimm16));
ADD_OPCODE(ANDI_,(OP_REG ra, OP_REG rs, OP_uIMM uimm16));
ADD_OPCODE(ANDIS_,(OP_REG ra, OP_REG rs, OP_uIMM uimm16));
START_OPCODES_GROUP(G_1e)
ADD_OPCODE(RLDICL,(OP_REG ra, OP_REG rs, OP_REG sh, OP_REG mb, bool rc));
ADD_OPCODE(RLDICR,(OP_REG ra, OP_REG rs, OP_REG sh, OP_REG me, bool rc));
ADD_OPCODE(RLDIC,(OP_REG ra, OP_REG rs, OP_REG sh, OP_REG mb, bool rc));
ADD_OPCODE(RLDIMI,(OP_REG ra, OP_REG rs, OP_REG sh, OP_REG mb, bool rc));
END_OPCODES_GROUP(G_1e);
START_OPCODES_GROUP(G_1f)
/*0x000*/ADD_OPCODE(CMP,(OP_REG crfd, OP_REG l, OP_REG ra, OP_REG rb));
/*0x004*/ADD_OPCODE(TW,(OP_uIMM to, OP_REG ra, OP_REG rb));
/*0x007*/ADD_OPCODE(LVEBX,(OP_REG vd, OP_REG ra, OP_REG rb));
/*0x008*/ADD_OPCODE(SUBFC,(OP_REG rd, OP_REG ra, OP_REG rb, OP_REG oe, bool rc));
/*0x009*/ADD_OPCODE(MULHDU,(OP_REG rd, OP_REG ra, OP_REG rb, bool rc));
/*0x00a*/ADD_OPCODE(ADDC,(OP_REG rd, OP_REG ra, OP_REG rb, OP_REG oe, bool rc));
/*0x00b*/ADD_OPCODE(MULHWU,(OP_REG rd, OP_REG ra, OP_REG rb, bool rc));
/*0x013*/ADD_OPCODE(MFOCRF,(OP_REG a, OP_REG fxm, OP_REG rd));
/*0x014*/ADD_OPCODE(LWARX,(OP_REG rd, OP_REG ra, OP_REG rb));
/*0x015*/ADD_OPCODE(LDX,(OP_REG ra, OP_REG rs, OP_REG rb));
/*0x017*/ADD_OPCODE(LWZX,(OP_REG rd, OP_REG ra, OP_REG rb));
/*0x018*/ADD_OPCODE(SLW,(OP_REG ra, OP_REG rs, OP_REG rb, bool rc));
/*0x01a*/ADD_OPCODE(CNTLZW,(OP_REG ra, OP_REG rs, bool rc));
/*0x01b*/ADD_OPCODE(SLD,(OP_REG ra, OP_REG rs, OP_REG rb, bool rc));
/*0x01c*/ADD_OPCODE(AND,(OP_REG ra, OP_REG rs, OP_REG rb, bool rc));
/*0x020*/ADD_OPCODE(CMPL,(OP_REG bf, OP_REG l, OP_REG ra, OP_REG rb));
/*0x027*/ADD_OPCODE(LVEHX,(OP_REG vd, OP_REG ra, OP_REG rb));
/*0x028*/ADD_OPCODE(SUBF,(OP_REG rd, OP_REG ra, OP_REG rb, OP_REG oe, bool rc));
/*0x035*/ADD_OPCODE(LDUX,(OP_REG rd, OP_REG ra, OP_REG rb));
/*0x036*/ADD_OPCODE(DCBST,(OP_REG ra, OP_REG rb));
/*0x03a*/ADD_OPCODE(CNTLZD,(OP_REG ra, OP_REG rs, bool rc));
/*0x03c*/ADD_OPCODE(ANDC,(OP_REG ra, OP_REG rs, OP_REG rb, bool rc));
/*0x047*/ADD_OPCODE(LVEWX,(OP_REG vd, OP_REG ra, OP_REG rb));
/*0x049*/ADD_OPCODE(MULHD,(OP_REG rd, OP_REG ra, OP_REG rb, bool rc));
/*0x04b*/ADD_OPCODE(MULHW,(OP_REG rd, OP_REG ra, OP_REG rb, bool rc));
/*0x054*/ADD_OPCODE(LDARX,(OP_REG rd, OP_REG ra, OP_REG rb));
/*0x056*/ADD_OPCODE(DCBF,(OP_REG ra, OP_REG rb));
/*0x057*/ADD_OPCODE(LBZX,(OP_REG rd, OP_REG ra, OP_REG rb));
/*0x067*/ADD_OPCODE(LVX,(OP_REG vrd, OP_REG ra, OP_REG rb));
/*0x068*/ADD_OPCODE(NEG,(OP_REG rd, OP_REG ra, OP_REG oe, bool rc));
/*0x077*/ADD_OPCODE(LBZUX,(OP_REG rd, OP_REG ra, OP_REG rb));
/*0x07c*/ADD_OPCODE(NOR,(OP_REG ra, OP_REG rs, OP_REG rb, bool rc));
/*0x088*/ADD_OPCODE(SUBFE,(OP_REG rd, OP_REG ra, OP_REG rb, OP_REG oe, bool rc));
/*0x08a*/ADD_OPCODE(ADDE,(OP_REG rd, OP_REG ra, OP_REG rb, OP_REG oe, bool rc));
/*0x090*/ADD_OPCODE(MTOCRF,(OP_REG fxm, OP_REG rs));
/*0x095*/ADD_OPCODE(STDX,(OP_REG rs, OP_REG ra, OP_REG rb));
/*0x096*/ADD_OPCODE(STWCX_,(OP_REG rs, OP_REG ra, OP_REG rb));
/*0x097*/ADD_OPCODE(STWX,(OP_REG rs, OP_REG ra, OP_REG rb));
/*0x0b5*/ADD_OPCODE(STDUX,(OP_REG rs, OP_REG ra, OP_REG rb));
/*0x0ca*/ADD_OPCODE(ADDZE,(OP_REG rd, OP_REG ra, OP_REG oe, bool rc));
/*0x0d6*/ADD_OPCODE(STDCX_,(OP_REG rs, OP_REG ra, OP_REG rb));
/*0x0d7*/ADD_OPCODE(STBX,(OP_REG rs, OP_REG ra, OP_REG rb));
/*0x0e7*/ADD_OPCODE(STVX,(OP_REG vrd, OP_REG ra, OP_REG rb));
/*0x0e9*/ADD_OPCODE(MULLD,(OP_REG rd, OP_REG ra, OP_REG rb, OP_REG oe, bool rc));
/*0x0ea*/ADD_OPCODE(ADDME,(OP_REG rd, OP_REG ra, OP_REG oe, bool rc));
/*0x0eb*/ADD_OPCODE(MULLW,(OP_REG rd, OP_REG ra, OP_REG rb, OP_REG oe, bool rc));
/*0x0f6*/ADD_OPCODE(DCBTST,(OP_REG th, OP_REG ra, OP_REG rb));
/*0x10a*/ADD_OPCODE(ADD,(OP_REG rd, OP_REG ra, OP_REG rb, OP_REG oe, bool rc));
/*0x116*/ADD_OPCODE(DCBT,(OP_REG ra, OP_REG rb, OP_REG th));
/*0x117*/ADD_OPCODE(LHZX,(OP_REG rd, OP_REG ra, OP_REG rb));
/*0x11c*/ADD_OPCODE(EQV,(OP_REG ra, OP_REG rs, OP_REG rb, bool rc));
/*0x136*/ADD_OPCODE(ECIWX,(OP_REG rd, OP_REG ra, OP_REG rb));
/*0x137*/ADD_OPCODE(LHZUX,(OP_REG rd, OP_REG ra, OP_REG rb));
/*0x13c*/ADD_OPCODE(XOR,(OP_REG rs, OP_REG ra, OP_REG rb, bool rc));
/*0x153*/ADD_OPCODE(MFSPR,(OP_REG rd, OP_REG spr));
/*0x157*/ADD_OPCODE(LHAX,(OP_REG rd, OP_REG ra, OP_REG rb));
/*0x168*/ADD_OPCODE(ABS,(OP_REG rd, OP_REG ra, OP_REG oe, bool rc));
/*0x173*/ADD_OPCODE(MFTB,(OP_REG rd, OP_REG spr));
/*0x177*/ADD_OPCODE(LHAUX,(OP_REG rd, OP_REG ra, OP_REG rb));
/*0x197*/ADD_OPCODE(STHX,(OP_REG rs, OP_REG ra, OP_REG rb));
/*0x19c*/ADD_OPCODE(ORC,(OP_REG rs, OP_REG ra, OP_REG rb, bool rc));
/*0x1b6*/ADD_OPCODE(ECOWX,(OP_REG rs, OP_REG ra, OP_REG rb));
/*0x1bc*/ADD_OPCODE(OR,(OP_REG ra, OP_REG rs, OP_REG rb, bool rc));
/*0x1c9*/ADD_OPCODE(DIVDU,(OP_REG rd, OP_REG ra, OP_REG rb, OP_REG oe, bool rc));
/*0x1cb*/ADD_OPCODE(DIVWU,(OP_REG rd, OP_REG ra, OP_REG rb, OP_REG oe, bool rc));
/*0x1d3*/ADD_OPCODE(MTSPR,(OP_REG spr, OP_REG rs));
/*0x1d6*///DCBI
/*0x1e9*/ADD_OPCODE(DIVD,(OP_REG rd, OP_REG ra, OP_REG rb, OP_REG oe, bool rc));
/*0x1eb*/ADD_OPCODE(DIVW,(OP_REG rd, OP_REG ra, OP_REG rb, OP_REG oe, bool rc));
/*0x216*/ADD_OPCODE(LWBRX,(OP_REG rd, OP_REG ra, OP_REG rb));
/*0x217*/ADD_OPCODE(LFSX,(OP_REG frd, OP_REG ra, OP_REG rb));
/*0x218*/ADD_OPCODE(SRW,(OP_REG ra, OP_REG rs, OP_REG rb, bool rc));
/*0x21b*/ADD_OPCODE(SRD,(OP_REG ra, OP_REG rs, OP_REG rb, bool rc));
/*0x237*/ADD_OPCODE(LFSUX,(OP_REG frd, OP_REG ra, OP_REG rb));
/*0x256*/ADD_OPCODE(SYNC,(OP_REG l));
/*0x257*/ADD_OPCODE(LFDX,(OP_REG frd, OP_REG ra, OP_REG rb));
/*0x277*/ADD_OPCODE(LFDUX,(OP_REG frd, OP_REG ra, OP_REG rb));
/*0x297*/ADD_OPCODE(STFSX,(OP_REG rs, OP_REG ra, OP_REG rb));
/*0x316*/ADD_OPCODE(LHBRX,(OP_REG rd, OP_REG ra, OP_REG rb));
/*0x318*/ADD_OPCODE(SRAW,(OP_REG ra, OP_REG rs, OP_REG rb, bool rc));
/*0x31A*/ADD_OPCODE(SRAD,(OP_REG ra, OP_REG rs, OP_REG rb, bool rc));
/*0x338*/ADD_OPCODE(SRAWI,(OP_REG ra, OP_REG rs, OP_REG sh, bool rc));
/*0x33a*/ADD_OPCODE(SRADI1,(OP_REG ra, OP_REG rs, OP_REG sh, bool rc));
/*0x33b*/ADD_OPCODE(SRADI2,(OP_REG ra, OP_REG rs, OP_REG sh, bool rc));
/*0x356*/ADD_OPCODE(EIEIO,());
/*0x39a*/ADD_OPCODE(EXTSH,(OP_REG ra, OP_REG rs, bool rc));
/*0x3ba*/ADD_OPCODE(EXTSB,(OP_REG ra, OP_REG rs, bool rc));
/*0x3d7*/ADD_OPCODE(STFIWX,(OP_REG frs, OP_REG ra, OP_REG rb));
/*0x3da*/ADD_OPCODE(EXTSW,(OP_REG ra, OP_REG rs, bool rc));
/*0x3d6*///ICBI
/*0x3f6*/ADD_OPCODE(DCBZ,(OP_REG ra, OP_REG rb));
END_OPCODES_GROUP(G_1f);
ADD_OPCODE(LWZ,(OP_REG rd, OP_REG ra, OP_sIMM d));
ADD_OPCODE(LWZU,(OP_REG rd, OP_REG ra, OP_sIMM d));
ADD_OPCODE(LBZ,(OP_REG rd, OP_REG ra, OP_sIMM d));
ADD_OPCODE(LBZU,(OP_REG rd, OP_REG ra, OP_sIMM d));
ADD_OPCODE(STW,(OP_REG rs, OP_REG ra, OP_sIMM d));
ADD_OPCODE(STWU,(OP_REG rs, OP_REG ra, OP_sIMM d));
ADD_OPCODE(STB,(OP_REG rs, OP_REG ra, OP_sIMM d));
ADD_OPCODE(STBU,(OP_REG rs, OP_REG ra, OP_sIMM d));
ADD_OPCODE(LHZ,(OP_REG rd, OP_REG ra, OP_sIMM d));
ADD_OPCODE(LHZU,(OP_REG rd, OP_REG ra, OP_sIMM d));
ADD_OPCODE(STH,(OP_REG rs, OP_REG ra, OP_sIMM d));
ADD_OPCODE(STHU,(OP_REG rs, OP_REG ra, OP_sIMM d));
ADD_OPCODE(LMW,(OP_REG rd, OP_REG ra, OP_sIMM d));
ADD_OPCODE(STMW,(OP_REG rs, OP_REG ra, OP_sIMM d));
ADD_OPCODE(LFS,(OP_REG frd, OP_REG ra, OP_sIMM d));
ADD_OPCODE(LFSU,(OP_REG frd, OP_REG ra, OP_sIMM d));
ADD_OPCODE(LFD,(OP_REG frd, OP_REG ra, OP_sIMM d));
ADD_OPCODE(LFDU,(OP_REG frd, OP_REG ra, OP_sIMM d));
ADD_OPCODE(STFS,(OP_REG frs, OP_REG ra, OP_sIMM d));
ADD_OPCODE(STFSU,(OP_REG frs, OP_REG ra, OP_sIMM d));
ADD_OPCODE(STFD,(OP_REG frs, OP_REG ra, OP_sIMM d));
ADD_OPCODE(STFDU,(OP_REG frs, OP_REG ra, OP_sIMM d));
START_OPCODES_GROUP(G_3a)
ADD_OPCODE(LD,(OP_REG rd, OP_REG ra, OP_sIMM ds));
ADD_OPCODE(LDU,(OP_REG rd, OP_REG ra, OP_sIMM ds));
END_OPCODES_GROUP(G_3a);
START_OPCODES_GROUP(G_3b)
ADD_OPCODE(FDIVS,(OP_REG frd, OP_REG fra, OP_REG frb, bool rc));
ADD_OPCODE(FSUBS,(OP_REG frd, OP_REG fra, OP_REG frb, bool rc));
ADD_OPCODE(FADDS,(OP_REG frd, OP_REG fra, OP_REG frb, bool rc));
ADD_OPCODE(FSQRTS,(OP_REG frd, OP_REG frb, bool rc));
ADD_OPCODE(FRES,(OP_REG frd, OP_REG frb, bool rc));
ADD_OPCODE(FMULS,(OP_REG frd, OP_REG fra, OP_REG frc, bool rc));
ADD_OPCODE(FMADDS,(OP_REG frd, OP_REG fra, OP_REG frc, OP_REG frb, bool rc));
ADD_OPCODE(FMSUBS,(OP_REG frd, OP_REG fra, OP_REG frc, OP_REG frb, bool rc));
ADD_OPCODE(FNMSUBS,(OP_REG frd, OP_REG fra, OP_REG frc, OP_REG frb, bool rc));
ADD_OPCODE(FNMADDS,(OP_REG frd, OP_REG fra, OP_REG frc, OP_REG frb, bool rc));
END_OPCODES_GROUP(G_3b);
START_OPCODES_GROUP(G_3e)
ADD_OPCODE(STD,(OP_REG rs, OP_REG ra, OP_sIMM ds));
ADD_OPCODE(STDU,(OP_REG rs, OP_REG ra, OP_sIMM ds));
END_OPCODES_GROUP(G_3e);
START_OPCODES_GROUP(G_3f)
ADD_OPCODE(MTFSB1,(OP_REG bt, bool rc));
ADD_OPCODE(MCRFS,(OP_REG bf, OP_REG bfa));
ADD_OPCODE(MTFSB0,(OP_REG bt, bool rc));
ADD_OPCODE(MTFSFI,(OP_REG crfd, OP_REG i, bool rc));
ADD_OPCODE(MFFS,(OP_REG frd, bool rc));
ADD_OPCODE(MTFSF,(OP_REG flm, OP_REG frb, bool rc));
ADD_OPCODE(FCMPU,(OP_REG bf, OP_REG fra, OP_REG frb));
ADD_OPCODE(FRSP,(OP_REG frd, OP_REG frb, bool rc));
ADD_OPCODE(FCTIW,(OP_REG frd, OP_REG frb, bool rc));
ADD_OPCODE(FCTIWZ,(OP_REG frd, OP_REG frb, bool rc));
ADD_OPCODE(FDIV,(OP_REG frd, OP_REG fra, OP_REG frb, bool rc));
ADD_OPCODE(FSUB,(OP_REG frd, OP_REG fra, OP_REG frb, bool rc));
ADD_OPCODE(FADD,(OP_REG frd, OP_REG fra, OP_REG frb, bool rc));
ADD_OPCODE(FSQRT,(OP_REG frd, OP_REG frb, bool rc));
ADD_OPCODE(FSEL,(OP_REG frd, OP_REG fra, OP_REG frc, OP_REG frb, bool rc));
ADD_OPCODE(FMUL,(OP_REG frd, OP_REG fra, OP_REG frc, bool rc));
ADD_OPCODE(FRSQRTE,(OP_REG frd, OP_REG frb, bool rc));
ADD_OPCODE(FMSUB,(OP_REG frd, OP_REG fra, OP_REG frc, OP_REG frb, bool rc));
ADD_OPCODE(FMADD,(OP_REG frd, OP_REG fra, OP_REG frc, OP_REG frb, bool rc));
ADD_OPCODE(FNMSUB,(OP_REG frd, OP_REG fra, OP_REG frc, OP_REG frb, bool rc));
ADD_OPCODE(FNMADD,(OP_REG frd, OP_REG fra, OP_REG frc, OP_REG frb, bool rc));
ADD_OPCODE(FCMPO,(OP_REG crfd, OP_REG fra, OP_REG frb));
ADD_OPCODE(FNEG,(OP_REG frd, OP_REG frb, bool rc));
ADD_OPCODE(FMR,(OP_REG frd, OP_REG frb, bool rc));
ADD_OPCODE(FNABS,(OP_REG frd, OP_REG frb, bool rc));
ADD_OPCODE(FABS,(OP_REG frd, OP_REG frb, bool rc));
ADD_OPCODE(FCTID,(OP_REG frd, OP_REG frb, bool rc));
ADD_OPCODE(FCTIDZ,(OP_REG frd, OP_REG frb, bool rc));
ADD_OPCODE(FCFID,(OP_REG frd, OP_REG frb, bool rc));
END_OPCODES_GROUP(G_3f);
ADD_OPCODE(UNK,(const s32 code, const s32 opcode, const s32 gcode));
};
#undef START_OPCODES_GROUP
#undef ADD_OPCODE
#undef ADD_NULL_OPCODE
#undef END_OPCODES_GROUP

View File

@ -0,0 +1,255 @@
#include "stdafx.h"
#include "Emu/Cell/PPUThread.h"
#include "Emu/Cell/PPUDecoder.h"
#include "Emu/Cell/PPUInterpreter.h"
#include "Emu/Cell/PPUDisAsm.h"
#include "Emu/SysCalls/SysCalls.h"
extern gcmInfo gcm_info;
PPUThread::PPUThread() : PPCThread(PPC_THREAD_PPU)
{
Reset();
}
PPUThread::~PPUThread()
{
//~PPCThread();
}
void PPUThread::DoReset()
{
//reset regs
memset(VPR, 0, sizeof(VPR));
memset(FPR, 0, sizeof(FPR));
memset(GPR, 0, sizeof(GPR));
memset(SPRG, 0, sizeof(SPRG));
CR.CR = 0;
LR = 0;
CTR = 0;
USPRG = 0;
TB = 0;
XER.XER = 0;
FPSCR.FPSCR = 0;
cycle = 0;
reserve = false;
reserve_addr = 0;
}
void PPUThread::SetBranch(const u64 pc)
{
u64 fid, waddr;
if(Memory.MemFlags.IsFlag(pc, waddr, fid))
{
GPR[3] = SysCallsManager.DoFunc(fid, *this);
if((s64)GPR[3] < 0 && fid != 0x72a577ce && fid != 0x8461e528) ConLog.Write("Func[0x%llx] done with code [0x%llx]! #pc: 0x%llx", fid, GPR[3], PC);
#ifdef HLE_CALL_LOG
else ConLog.Warning("Func[0xll%x] done with code [0x%llx]! #pc: 0x%llx", fid, GPR[3], PC);
#endif
//ConLog.Warning("Func waddr: 0x%llx", waddr);
const u64 addr = Emu.GetTLSAddr();
Memory.Write32(waddr, addr);
Memory.Write32(addr, PC + 4);
if(fid == 0x744680a2) Memory.Write32(addr+4, GPR[3]);
//Memory.Write32(addr+4, Emu.GetTLSMemsz());
}
else if(pc == Emu.GetRSXCallback())
{
//ConLog.Warning("gcm: callback(context=0x%llx, count=0x%llx) #pc: 0x%llx", GPR[3], GPR[4], PC);
CellGcmContextData& ctx = *(CellGcmContextData*)Memory.GetMemFromAddr(GPR[3]);
CellGcmControl& ctrl = *(CellGcmControl*)Memory.GetMemFromAddr(gcm_info.control_addr);
while(ctrl.put != ctrl.get) Sleep(1);
const u32 reserve = GPR[4];
ctx.current = re(re(ctx.begin) + reserve);
Emu.GetGSManager().GetRender().Pause();
ctrl.put = ctrl.get = re(reserve);
Emu.GetGSManager().GetRender().Resume();
GPR[3] = 0;
PPCThread::SetBranch(PC + 4);
return;
}
PPCThread::SetBranch(pc);
}
void PPUThread::AddArgv(const wxString& arg)
{
stack_point -= arg.Len() + 1;
stack_point = Memory.AlignAddr(stack_point, 0x10) - 0x10;
argv_addr.AddCpy(stack_point);
Memory.WriteString(stack_point, arg);
}
void PPUThread::InitRegs()
{
const u32 entry = Memory.Read32(PC);
const u32 rtoc = Memory.Read32(PC + 4);
ConLog.Write("rtoc = 0x%x", rtoc);
SetPc(entry);
u64 argc = m_arg;
u64 argv = 0;
if(argv_addr.GetCount())
{
argc = argv_addr.GetCount();
stack_point -= 0xc + 4 * argc;
argv = stack_point;
mem64_t argv_list(argv);
for(int i=0; i<argc; ++i) argv_list += argv_addr[i];
}
const s32 thread_num = Emu.GetCPU().GetThreadNumById(!IsSPU(), GetId());
if(thread_num < 0)
{
ConLog.Error("GetThreadNumById failed.");
Emu.Pause();
return;
}
const s32 tls_size = Emu.GetTLSFilesz() * thread_num;
if(tls_size >= Emu.GetTLSMemsz())
{
ConLog.Error("Out of TLS memory.");
Emu.Pause();
return;
}
stack_point = Memory.AlignAddr(stack_point, 0x200) - 0x200;
GPR[1] = stack_point;
GPR[2] = rtoc;
if(argc)
{
GPR[3] = argc;
GPR[4] = argv;
GPR[5] = argv ? argv - 0xc - 4 * argc : 0; //unk
}
else
{
GPR[3] = m_arg;
}
GPR[0] = entry;
//GPR[7] = 0x80d90;
GPR[8] = entry;
//GPR[10] = 0x131700;
GPR[11] = 0x80;
GPR[12] = Emu.GetMallocPageSize();
GPR[13] = 0x10007060;
GPR[28] = GPR[4];
GPR[29] = GPR[3];
GPR[31] = GPR[5];
CTR = PC;
CR.CR = 0x22000082;
}
u64 PPUThread::GetFreeStackSize() const
{
return (GetStackAddr() + GetStackSize()) - GPR[1];
}
void PPUThread::DoRun()
{
switch(Ini.CPUDecoderMode.GetValue())
{
case 0:
m_dec = new PPU_Decoder(*new PPU_DisAsm(*this));
break;
case 1:
case 2:
m_dec = new PPU_Decoder(*new PPU_Interpreter(*this));
break;
}
}
void PPUThread::DoResume()
{
}
void PPUThread::DoPause()
{
}
void PPUThread::DoStop()
{
delete m_dec;
m_dec = 0;
}
bool dump_enable = false;
void PPUThread::DoCode(const s32 code)
{
if(dump_enable)
{
static wxFile f("dump.txt", wxFile::write);
static PPU_DisAsm disasm(*this, DumpMode);
static PPU_Decoder decoder(disasm);
disasm.dump_pc = PC;
decoder.Decode(code);
f.Write(disasm.last_opcode);
}
if(++cycle > 220)
{
cycle = 0;
TB++;
}
m_dec->Decode(code);
}
bool FPRdouble::IsINF(double d)
{
return wxFinite(d) ? 1 : 0;
}
bool FPRdouble::IsNaN(double d)
{
return wxIsNaN(d) ? 1 : 0;
}
bool FPRdouble::IsQNaN(double d)
{
return
((*(u64*)&d & DOUBLE_EXP) == DOUBLE_EXP) &&
((*(u64*)&d & 0x0007fffffffffffULL) == DOUBLE_ZERO) &&
((*(u64*)&d & 0x000800000000000ULL) == 0x000800000000000ULL);
}
bool FPRdouble::IsSNaN(double d)
{
return
((*(u64*)&d & DOUBLE_EXP) == DOUBLE_EXP) &&
((*(u64*)&d & DOUBLE_FRAC) != DOUBLE_ZERO) &&
((*(u64*)&d & 0x0008000000000000ULL) == DOUBLE_ZERO);
}
int FPRdouble::Cmp(double a, double b)
{
if(a < b) return CR_LT;
if(a > b) return CR_GT;
if(a == b) return CR_EQ;
return CR_SO;
}

945
rpcs3/Emu/Cell/PPUThread.h Normal file
View File

@ -0,0 +1,945 @@
#pragma once
#include "Emu/Cell/PPCThread.h"
enum
{
XER_SO = 0x80000000,
XER_OV = 0x40000000,
XER_CA = 0x20000000,
};
enum
{
CR_LT = 0x8,
CR_GT = 0x4,
CR_EQ = 0x2,
CR_SO = 0x1,
};
enum FPSCR_EXP
{
FPSCR_FX = 0x80000000,
FPSCR_FEX = 0x40000000,
FPSCR_VX = 0x20000000,
FPSCR_OX = 0x10000000,
FPSCR_UX = 0x08000000,
FPSCR_ZX = 0x04000000,
FPSCR_XX = 0x02000000,
FPSCR_VXSNAN = 0x01000000,
FPSCR_VXISI = 0x00800000,
FPSCR_VXIDI = 0x00400000,
FPSCR_VXZDZ = 0x00200000,
FPSCR_VXIMZ = 0x00100000,
FPSCR_VXVC = 0x00080000,
FPSCR_FR = 0x00040000,
FPSCR_FI = 0x00020000,
FPSCR_VXSOFT = 0x00000400,
FPSCR_VXSQRT = 0x00000200,
FPSCR_VXCVI = 0x00000100,
};
enum FPSCR_RN
{
FPSCR_RN_NEAR = 0,
FPSCR_RN_ZERO = 1,
FPSCR_RN_PINF = 2,
FPSCR_RN_MINF = 3,
};
static const u64 DOUBLE_SIGN = 0x8000000000000000ULL;
static const u64 DOUBLE_EXP = 0x7FF0000000000000ULL;
static const u64 DOUBLE_FRAC = 0x000FFFFFFFFFFFFFULL;
static const u64 DOUBLE_ZERO = 0x0000000000000000ULL;
union FPSCRhdr
{
struct
{
u32 RN :2; //Floating-point rounding control
u32 NI :1; //Floating-point non-IEEE mode
u32 XE :1; //Floating-point inexact exception enable
u32 ZE :1; //IEEE floating-point zero divide exception enable
u32 UE :1; //IEEE floating-point underflow exception enable
u32 OE :1; //IEEE floating-point overflow exception enable
u32 VE :1; //Floating-point invalid operation exception enable
u32 VXCVI :1; //Floating-point invalid operation exception for invalid integer convert
u32 VXSQRT :1; //Floating-point invalid operation exception for invalid square root
u32 VXSOFT :1; //Floating-point invalid operation exception for software request
u32 :1; //Reserved
u32 FPRF :5; //Floating-point result flags
u32 FI :1; //Floating-point fraction inexact
u32 FR :1; //Floating-point fraction rounded
u32 VXVC :1; //Floating-point invalid operation exception for invalid compare
u32 VXIMZ :1; //Floating-point invalid operation exception for * * 0
u32 VXZDZ :1; //Floating-point invalid operation exception for 0 / 0
u32 VXIDI :1; //Floating-point invalid operation exception for * + *
u32 VXISI :1; //Floating-point invalid operation exception for * - *
u32 VXSNAN :1; //Floating-point invalid operation exception for SNaN
u32 XX :1; //Floating-point inexact exception
u32 ZX :1; //Floating-point zero divide exception
u32 UX :1; //Floating-point underflow exception
u32 OX :1; //Floating-point overflow exception
u32 VX :1; //Floating-point invalid operation exception summary
u32 FEX :1; //Floating-point enabled exception summary
u32 FX :1; //Floating-point exception summary
};
u32 FPSCR;
};
union MSRhdr
{
struct
{
//Little-endian mode enable
//0 The processor runs in big-endian mode.
//1 The processor runs in little-endian mode.
u64 LE : 1;
//Recoverable exception (for system reset and machine check exceptions).
//0 Exception is not recoverable.
//1 Exception is recoverable.
u64 RI : 1;
//Reserved
u64 : 2;
//Data address translation
//0 Data address translation is disabled.
//1 Data address translation is enabled.
u64 DR : 1;
//Instruction address translation
//0 Instruction address translation is disabled.
//1 Instruction address translation is enabled.
u64 IR : 1;
//Exception prefix. The setting of this bit specifies whether an exception vector offset
//is prepended with Fs or 0s. In the following description, nnnnn is the offset of the
//exception.
//0 Exceptions are vectored to the physical address 0x0000_0000_000n_nnnn in 64-bit implementations.
//1 Exceptions are vectored to the physical address 0xFFFF_FFFF_FFFn_nnnn in 64-bit implementations.
u64 IP : 1;
//Reserved
u64 : 1;
//Floating-point exception mode 1
u64 FE1 : 1;
//Branch trace enable (Optional)
//0 The processor executes branch instructions normally.
//1 The processor generates a branch trace exception after completing the
//execution of a branch instruction, regardless of whether or not the branch was
//taken.
//Note: If the function is not implemented, this bit is treated as reserved.
u64 BE : 1;
//Single-step trace enable (Optional)
//0 The processor executes instructions normally.
//1 The processor generates a single-step trace exception upon the successful
//execution of the next instruction.
//Note: If the function is not implemented, this bit is treated as reserved.
u64 SE : 1;
//Floating-point exception mode 0
u64 FE0 : 1;
//Machine check enable
//0 Machine check exceptions are disabled.
//1 Machine check exceptions are enabled.
u64 ME : 1;
//Floating-point available
//0 The processor prevents dispatch of floating-point instructions, including
//floating-point loads, stores, and moves.
//1 The processor can execute floating-point instructions.
u64 FP : 1;
//Privilege level
//0 The processor can execute both user- and supervisor-level instructions.
//1 The processor can only execute user-level instructions.
u64 PR : 1;
//External interrupt enable
//0 While the bit is cleared the processor delays recognition of external interrupts
//and decrementer exception conditions.
//1 The processor is enabled to take an external interrupt or the decrementer
//exception.
u64 EE : 1;
//Exception little-endian mode. When an exception occurs, this bit is copied into
//MSR[LE] to select the endian mode for the context established by the exception
u64 ILE : 1;
//Reserved
u64 : 1;
//Power management enable
//0 Power management disabled (normal operation mode).
//1 Power management enabled (reduced power mode).
//Note: Power management functions are implementation-dependent. If the function
//is not implemented, this bit is treated as reserved.
u64 POW : 1;
//Reserved
u64 : 44;
//Sixty-four bit mode
//0 The 64-bit processor runs in 32-bit mode.
//1 The 64-bit processor runs in 64-bit mode. Note that this is the default setting.
u64 SF : 1;
};
u64 MSR;
};
union PVRhdr
{
struct
{
u16 revision;
u16 version;
};
u32 PVR;
};
union CRhdr
{
u32 CR;
struct
{
u8 cr0 : 4;
u8 cr1 : 4;
u8 cr2 : 4;
u8 cr3 : 4;
u8 cr4 : 4;
u8 cr5 : 4;
u8 cr6 : 4;
u8 cr7 : 4;
};
};
union XERhdr
{
u64 XER;
struct
{
u64 L : 61;
u64 CA : 1;
u64 OV : 1;
u64 SO : 1;
};
};
enum FPRType
{
FPR_NORM,
FPR_ZERO,
FPR_SNAN,
//FPR_QNAN,
FPR_INF,
FPR_PZ = 0x2,
FPR_PN = 0x4,
FPR_PINF = 0x5,
FPR_NN = 0x8,
FPR_NINF = 0x9,
FPR_QNAN = 0x11,
FPR_NZ = 0x12,
FPR_PD = 0x14,
FPR_ND = 0x18,
};
struct PPCdouble
{
union
{
double _double;
u64 _u64;
struct
{
u64 frac : 52;
u64 exp : 11;
u64 sign : 1;
};
struct
{
u64 : 51;
u64 nan : 1;
u64 : 12;
};
};
FPRType type;
u32 GetType()
{
if(exp > 0 && exp < 0x7ff) return sign ? FPR_NN : FPR_PN;
if(frac)
{
if(exp) return FPR_QNAN;
return sign ? FPR_INF : FPR_PINF;
}
return sign ? FPR_NZ : FPR_PZ;
}
u32 To32()
{
if (exp > 896 || (!frac && !exp))
{
return ((_u64 >> 32) & 0xc0000000) | ((_u64 >> 29) & 0x3fffffff);
}
if (exp >= 874)
{
return ((0x80000000 | (frac >> 21)) >> (905 - exp)) | (_u64 >> 32) & 0x80000000;
}
//?
return ((_u64 >> 32) & 0xc0000000) | ((_u64 >> 29) & 0x3fffffff);
}
u32 GetZerosCount()
{
u32 ret;
u32 dd = frac >> 32;
if(dd)
{
ret = 31;
}
else
{
dd = frac;
ret = 63;
}
if(dd > 0xffff)
{
ret -= 16;
dd >>= 16;
}
if(dd > 0xff)
{
ret -= 8;
dd >>= 8;
}
if(dd & 0xf0)
{
ret -= 4;
dd >>= 4;
}
if(dd & 0xc)
{
ret -= 2;
dd >>= 2;
}
if(dd & 0x2) ret--;
return ret;
}
PPCdouble() : _u64(0)
{
}
PPCdouble(double val) : _double(val)
{
}
PPCdouble(u64 val) : _u64(val)
{
}
PPCdouble(u32 val) : _u64(val)
{
}
};
struct FPRdouble
{
static PPCdouble ConvertToIntegerMode(const PPCdouble& d, FPSCRhdr& fpscr, bool is_64, u32 round_mode)
{
PPCdouble ret;
if(d.exp == 2047)
{
if (d.frac == 0)
{
ret.type = FPR_INF;
fpscr.FI = 0;
fpscr.FR = 0;
fpscr.VXCVI = 1;
if(fpscr.VE == 0)
{
if(is_64)
{
return d.sign ? 0x8000000000000000 : 0x7FFFFFFFFFFFFFFF;
}
else
{
return d.sign ? 0x80000000 : 0x7FFFFFFF;
}
fpscr.FPRF = 0;
}
}
else if(d.nan == 0)
{
ret.type = FPR_SNAN;
fpscr.FI = 0;
fpscr.FR = 0;
fpscr.VXCVI = 1;
fpscr.VXSNAN = 1;
if(fpscr.VE == 0)
{
return is_64 ? 0x8000000000000000 : 0x80000000;
fpscr.FPRF = 0;
}
}
else
{
ret.type = FPR_QNAN;
fpscr.FI = 0;
fpscr.FR = 0;
fpscr.VXCVI = 1;
if(fpscr.VE == 0)
{
return is_64 ? 0x8000000000000000 : 0x80000000;
fpscr.FPRF = 0;
}
}
}
else if(d.exp > 1054)
{
fpscr.FI = 0;
fpscr.FR = 0;
fpscr.VXCVI = 1;
if(fpscr.VE == 0)
{
if(is_64)
{
return d.sign ? 0x8000000000000000 : 0x7FFFFFFFFFFFFFFF;
}
else
{
return d.sign ? 0x80000000 : 0x7FFFFFFF;
}
fpscr.FPRF = 0;
}
}
ret.sign = d.sign;
if(d.exp > 0)
{
ret.exp = d.exp - 1023;
ret.frac = 1 | d.frac;
}
else if(d.exp == 0)
{
ret.exp = -1022;
ret.frac = d.frac;
}
/*
if(d.exp == 0)
{
if (d.frac == 0)
{
d.type = FPR_ZERO;
}
else
{
const u32 z = d.GetZerosCount() - 8;
d.frac <<= z + 3;
d.exp -= 1023 - 1 + z;
d.type = FPR_NORM;
}
}
else
{
d.exp -= 1023;
d.type = FPR_NORM;
d.nan = 1;
d.frac <<= 3;
}
*/
return ret;
}
static u32 ConvertToFloatMode(PPCdouble& d, u32 RN)
{
/*
u32 fpscr = 0;
switch (d.type)
{
case FPR_NORM:
d.exp += 1023;
if (d.exp > 0)
{
fpscr |= Round(d, RN);
if(d.nan)
{
d.exp++;
d.frac >>= 4;
}
else
{
d.frac >>= 3;
}
if(d.exp >= 2047)
{
d.exp = 2047;
d.frac = 0;
fpscr |= FPSCR_OX;
}
}
else
{
d.exp = -(s64)d.exp + 1;
if(d.exp <= 56)
{
d.frac >>= d.exp;
fpscr |= Round(d, RN);
d.frac <<= 1;
if(d.nan)
{
d.exp = 1;
d.frac = 0;
}
else
{
d.exp = 0;
d.frac >>= 4;
fpscr |= FPSCR_UX;
}
}
else
{
d.exp = 0;
d.frac = 0;
fpscr |= FPSCR_UX;
}
}
break;
case FPR_ZERO:
d.exp = 0;
d.frac = 0;
break;
case FPR_NAN:
d.exp = 2047;
d.frac = 1;
break;
case FPR_INF:
d.exp = 2047;
d.frac = 0;
break;
}
return fpscr;
*/
return 0;
}
static u32 Round(PPCdouble& d, u32 RN)
{
switch(RN)
{
case FPSCR_RN_NEAR:
if(d.frac & 0x7)
{
if((d.frac & 0x7) != 4 || d.frac & 0x8)
{
d.frac += 4;
}
return FPSCR_XX;
}
return 0;
case FPSCR_RN_ZERO:
if(d.frac & 0x7) return FPSCR_XX;
return 0;
case FPSCR_RN_PINF:
if(!d.sign && (d.frac & 0x7))
{
d.frac += 8;
return FPSCR_XX;
}
return 0;
case FPSCR_RN_MINF:
if(d.sign && (d.frac & 0x7))
{
d.frac += 8;
return FPSCR_XX;
}
return 0;
}
return 0;
}
static const u64 double_sign = 0x8000000000000000ULL;
static const u64 double_frac = 0x000FFFFFFFFFFFFFULL;
static bool IsINF(double d);
static bool IsNaN(double d);
static bool IsQNaN(double d);
static bool IsSNaN(double d);
static int Cmp(double a, double b);
};
union VPR_reg
{
//__m128i _m128i;
u128 _u128;
s128 _i128;
u64 _u64[2];
s64 _i64[2];
u32 _u32[4];
s32 _i32[4];
u16 _u16[8];
s16 _i16[8];
u8 _u8[16];
s8 _i8[16];
//struct { float x, y, z, w; };
VPR_reg() { Clear(); }
VPR_reg(const __m128i val){_u128._u64[0] = val.m128i_u64[0]; _u128._u64[1] = val.m128i_u64[1];}
VPR_reg(const u128 val) { _u128 = val; }
VPR_reg(const u64 val) { Clear(); _u64[0] = val; }
VPR_reg(const u32 val) { Clear(); _u32[0] = val; }
VPR_reg(const u16 val) { Clear(); _u16[0] = val; }
VPR_reg(const u8 val) { Clear(); _u8[0] = val; }
VPR_reg(const s128 val) { _i128 = val; }
VPR_reg(const s64 val) { Clear(); _i64[0] = val; }
VPR_reg(const s32 val) { Clear(); _i32[0] = val; }
VPR_reg(const s16 val) { Clear(); _i16[0] = val; }
VPR_reg(const s8 val) { Clear(); _i8[0] = val; }
operator u128() const { return _u128; }
operator s128() const { return _i128; }
operator u64() const { return _u64[0]; }
operator s64() const { return _i64[0]; }
operator u32() const { return _u32[0]; }
operator s32() const { return _i32[0]; }
operator u16() const { return _u16[0]; }
operator s16() const { return _i16[0]; }
operator u8() const { return _u8[0]; }
operator s8() const { return _i8[0]; }
operator __m128i() { __m128i ret; ret.m128i_u64[0]=_u128._u64[0]; ret.m128i_u64[1]=_u128._u64[1]; return ret; }
operator bool() const { return _u64[0] != 0 || _u64[1] != 0; }
wxString ToString() const
{
return wxString::Format("%08x%08x%08x%08x", _u32[3], _u32[2], _u32[1], _u32[0]);
}
VPR_reg operator ^ (VPR_reg right) { return _mm_xor_si128(*this, right); }
VPR_reg operator | (VPR_reg right) { return _mm_or_si128 (*this, right); }
VPR_reg operator & (VPR_reg right) { return _mm_and_si128(*this, right); }
VPR_reg operator ^ (__m128i right) { return _mm_xor_si128(*this, right); }
VPR_reg operator | (__m128i right) { return _mm_or_si128 (*this, right); }
VPR_reg operator & (__m128i right) { return _mm_and_si128(*this, right); }
bool operator == (const VPR_reg& right){ return _u64[0] == right._u64[0] && _u64[1] == right._u64[1]; }
bool operator == (const u128 right) { return _u64[0] == right._u64[0] && _u64[1] == right._u64[1]; }
bool operator == (const s128 right) { return _i64[0] == right._i64[0] && _i64[1] == right._i64[1]; }
bool operator == (const u64 right) { return _u64[0] == (u64)right && _u64[1] == 0; }
bool operator == (const s64 right) { return _i64[0] == (s64)right && _i64[1] == 0; }
bool operator == (const u32 right) { return _u64[0] == (u64)right && _u64[1] == 0; }
bool operator == (const s32 right) { return _i64[0] == (s64)right && _i64[1] == 0; }
bool operator == (const u16 right) { return _u64[0] == (u64)right && _u64[1] == 0; }
bool operator == (const s16 right) { return _i64[0] == (s64)right && _i64[1] == 0; }
bool operator == (const u8 right) { return _u64[0] == (u64)right && _u64[1] == 0; }
bool operator == (const s8 right) { return _i64[0] == (s64)right && _i64[1] == 0; }
bool operator != (const VPR_reg& right){ return !(*this == right); }
bool operator != (const u128 right) { return !(*this == right); }
bool operator != (const u64 right) { return !(*this == right); }
bool operator != (const u32 right) { return !(*this == right); }
bool operator != (const u16 right) { return !(*this == right); }
bool operator != (const u8 right) { return !(*this == right); }
bool operator != (const s128 right) { return !(*this == right); }
bool operator != (const s64 right) { return !(*this == right); }
bool operator != (const s32 right) { return !(*this == right); }
bool operator != (const s16 right) { return !(*this == right); }
bool operator != (const s8 right) { return !(*this == right); }
s64& d(const u32 c) { return _i64[1 - c]; }
u64& ud(const u32 c) { return _u64[1 - c]; }
s32& w(const u32 c) { return _i32[3 - c]; }
u32& uw(const u32 c) { return _u32[3 - c]; }
s16& h(const u32 c) { return _i16[7 - c]; }
u16& uh(const u32 c) { return _u16[7 - c]; }
s8& b(const u32 c) { return _i8[15 - c]; }
u8& ub(const u32 c) { return _u8[15 - c]; }
void Clear() { memset(this, 0, sizeof(*this)); }
};
/*
struct VPR_table
{
VPR_reg t[32];
operator VPR_reg*() { return t; }
VPR_reg& operator [] (int index)
{
return t[index];
}
}
*/
static const s32 MAX_INT_VALUE = 0x7fffffff;
class PPUThread : public PPCThread
{
public:
double FPR[32]; //Floating Point Register
FPSCRhdr FPSCR; //Floating Point Status and Control Register
u64 GPR[32]; //General-Purpose Register
VPR_reg VPR[32];
u32 vpcr;
CRhdr CR; //Condition Register
//CR0
// 0 : LT - Negative (is negative)
// : 0 - Result is not negative
// : 1 - Result is negative
// 1 : GT - Positive (is positive)
// : 0 - Result is not positive
// : 1 - Result is positive
// 2 : EQ - Zero (is zero)
// : 0 - Result is not equal to zero
// : 1 - Result is equal to zero
// 3 : SO - Summary overflow (copy of the final state XER[S0])
// : 0 - No overflow occurred
// : 1 - Overflow occurred
//CRn
// 0 : LT - Less than (rA > X)
// : 0 - rA is not less than
// : 1 - rA is less than
// 1 : GT - Greater than (rA < X)
// : 0 - rA is not greater than
// : 1 - rA is greater than
// 2 : EQ - Equal to (rA == X)
// : 0 - Result is not equal to zero
// : 1 - Result is equal to zero
// 3 : SO - Summary overflow (copy of the final state XER[S0])
// : 0 - No overflow occurred
// : 1 - Overflow occurred
//SPR : Special-Purpose Registers
XERhdr XER; //SPR 0x001 : Fixed-Point Expection Register
// 0 : SO - Summary overflow
// : 0 - No overflow occurred
// : 1 - Overflow occurred
// 1 : OV - Overflow
// : 0 - No overflow occurred
// : 1 - Overflow occurred
// 2 : CA - Carry
// : 0 - Carry did not occur
// : 1 - Carry occured
// 3 - 24 : Reserved
// 25 - 31 : TBC
// Transfer-byte count
MSRhdr MSR; //Machine State Register
PVRhdr PVR; //Processor Version Register
u64 LR; //SPR 0x008 : Link Register
u64 CTR; //SPR 0x009 : Count Register
s32 USPRG; //SPR 0x100 : User-SPR General-Purpose Registers
s32 SPRG[8]; //SPR 0x100 - 0x107 : SPR General-Purpose Registers
//TBR : Time-Base Registers
union
{
u64 TB; //TBR 0x10C - 0x10D
struct
{
u32 TBH;
u32 TBL;
};
};
u64 reserve_addr;
bool reserve;
u64 cycle;
public:
PPUThread();
~PPUThread();
inline u8 GetCR(const u8 n) const
{
switch(n)
{
case 7: return CR.cr0;
case 6: return CR.cr1;
case 5: return CR.cr2;
case 4: return CR.cr3;
case 3: return CR.cr4;
case 2: return CR.cr5;
case 1: return CR.cr6;
case 0: return CR.cr7;
}
return 0;
}
inline void SetCR(const u8 n, const u32 value)
{
switch(n)
{
case 7: CR.cr0 = value; break;
case 6: CR.cr1 = value; break;
case 5: CR.cr2 = value; break;
case 4: CR.cr3 = value; break;
case 3: CR.cr4 = value; break;
case 2: CR.cr5 = value; break;
case 1: CR.cr6 = value; break;
case 0: CR.cr7 = value; break;
}
}
inline void SetCRBit(const u8 n, const u32 bit, const bool value)
{
switch(n)
{
case 7: value ? CR.cr0 |= bit : CR.cr0 &= ~bit; break;
case 6: value ? CR.cr1 |= bit : CR.cr1 &= ~bit; break;
case 5: value ? CR.cr2 |= bit : CR.cr2 &= ~bit; break;
case 4: value ? CR.cr3 |= bit : CR.cr3 &= ~bit; break;
case 3: value ? CR.cr4 |= bit : CR.cr4 &= ~bit; break;
case 2: value ? CR.cr5 |= bit : CR.cr5 &= ~bit; break;
case 1: value ? CR.cr6 |= bit : CR.cr6 &= ~bit; break;
case 0: value ? CR.cr7 |= bit : CR.cr7 &= ~bit; break;
}
}
inline void SetCR_EQ(const u8 n, const bool value) { SetCRBit(n, CR_EQ, value); }
inline void SetCR_GT(const u8 n, const bool value) { SetCRBit(n, CR_GT, value); }
inline void SetCR_LT(const u8 n, const bool value) { SetCRBit(n, CR_LT, value); }
inline void SetCR_SO(const u8 n, const bool value) { SetCRBit(n, CR_SO, value); }
inline bool IsCR_EQ(const u8 n) const { return (GetCR(n) & CR_EQ) ? 1 : 0; }
inline bool IsCR_GT(const u8 n) const { return (GetCR(n) & CR_GT) ? 1 : 0; }
inline bool IsCR_LT(const u8 n) const { return (GetCR(n) & CR_LT) ? 1 : 0; }
template<typename T> void UpdateCRn(const u8 n, const T a, const T b)
{
if (a < b) SetCR(n, CR_LT);
else if (a > b) SetCR(n, CR_GT);
else if (a == b) SetCR(n, CR_EQ);
SetCR_SO(n, XER.SO);
}
template<typename T> void UpdateCR0(const T val)
{
UpdateCRn<T>(0, val, 0);
}
template<typename T> void UpdateCR1()
{
SetCR_LT(1, FPSCR.FX);
SetCR_GT(1, FPSCR.FEX);
SetCR_EQ(1, FPSCR.VX);
SetCR_SO(1, FPSCR.OX);
}
const u8 GetCRBit(const u32 bit) const { return 1 << (3 - (bit % 4)); }
void SetCRBit (const u32 bit, bool set) { SetCRBit(bit >> 2, GetCRBit(bit), set); }
void SetCRBit2(const u32 bit, bool set) { SetCRBit(bit >> 2, 0x8 >> (bit & 3), set); }
const u8 IsCR(const u32 bit) const { return (GetCR(bit >> 2) & GetCRBit(bit)) ? 1 : 0; }
bool IsCarry(const u64 a, const u64 b) { return a > (~b); }
void SetFPSCRException(const FPSCR_EXP mask)
{
if ((FPSCR.FPSCR & mask) != mask) FPSCR.FX = 1;
FPSCR.FPSCR |= mask;
}
void SetFPSCR_FI(const u32 val)
{
if(val) SetFPSCRException(FPSCR_XX);
FPSCR.FI = val;
}
virtual wxString RegsToString()
{
wxString ret = PPCThread::RegsToString();
for(uint i=0; i<32; ++i) ret += wxString::Format("GPR[%d] = 0x%llx\n", i, GPR[i]);
for(uint i=0; i<32; ++i) ret += wxString::Format("FPR[%d] = %.6G\n", i, FPR[i]);
ret += wxString::Format("CR = 0x%08x\n", CR);
ret += wxString::Format("LR = 0x%llx\n", LR);
ret += wxString::Format("CTR = 0x%llx\n", CTR);
ret += wxString::Format("XER = 0x%llx\n", XER);
ret += wxString::Format("FPSCR = 0x%x\n", FPSCR);
return ret;
}
void SetBranch(const u64 pc);
virtual void AddArgv(const wxString& arg);
public:
virtual void InitRegs();
virtual u64 GetFreeStackSize() const;
protected:
virtual void DoReset();
virtual void DoRun();
virtual void DoPause();
virtual void DoResume();
virtual void DoStop();
private:
virtual void DoCode(const s32 code);
};

167
rpcs3/Emu/Cell/SPUDecoder.h Normal file
View File

@ -0,0 +1,167 @@
#pragma once
#include "Emu/Cell/SPUOpcodes.h"
#include "Emu/Cell/Decoder.h"
#define START_OPCODES_GROUP_(group, reg) \
case(##group##): \
temp=##reg##;\
switch(temp)\
{
#define START_OPCODES_GROUP(group, reg) START_OPCODES_GROUP_(##group##, ##reg##())
#define END_OPCODES_GROUP(group) \
default:\
m_op.UNK(m_code, opcode, temp);\
break;\
}\
break
#define ADD_OPCODE(name, regs) case(##name##):m_op.##name####regs##; return
#define ADD_NULL_OPCODE(name) ADD_OPCODE(##name##, ())
class SPU_Decoder : public Decoder
{
u32 m_code;
SPU_Opcodes& m_op;
OP_REG RC() const { return GetField(4, 10); }
OP_REG RT() const { return GetField(25, 31); }
OP_REG RA() const { return GetField(18, 24); }
OP_REG RB() const { return GetField(11, 17); }
OP_sIMM i7() const { return GetField(11, 17); }
OP_sIMM i10() const { return GetField(8, 17); }
OP_sIMM i16() const { return GetField(9, 24); }
OP_sIMM i18() const { return GetField(7, 24); }
OP_sIMM ROH() const { return GetField(16, 17); }
OP_sIMM ROL() const { return GetField(25, 31); }
OP_sIMM RO() const { return ROL()/* | (ROH() << 8)*/; }
OP_uIMM RR() const { return GetField(0, 10); }
OP_uIMM RRR() const { return GetField(0, 3); }
OP_uIMM RI7() const { return GetField(0, 10); }
OP_uIMM RI10() const { return GetField(0, 7); }
OP_uIMM RI16() const { return GetField(0, 8); }
OP_uIMM RI18() const { return GetField(0, 6); }
__forceinline u32 GetField(const u32 p) const
{
return (m_code >> (31 - p)) & 0x1;
}
__forceinline u32 GetField(const u32 from, const u32 to) const
{
return (m_code >> (31 - to)) & ((1 << ((to - from) + 1)) - 1);
}
OP_sIMM exts18(OP_sIMM i18) const
{
if(i18 & 0x20000) return i18 - 0x40000;
return i18;
}
OP_sIMM exts16(OP_sIMM i16) const
{
return (s32)(s16)i16;
}
OP_sIMM exts10(OP_sIMM i10) const
{
if(i10 & 0x200) return i10 - 0x400;
return i10;
}
OP_sIMM exts7(OP_sIMM i7) const
{
if(i7 & 0x40) return i7 - 0x80;
return i7;
}
public:
SPU_Decoder(SPU_Opcodes& op) : m_op(op)
{
}
~SPU_Decoder()
{
m_op.Exit();
delete &m_op;
}
virtual void Decode(const u32 code)
{
m_code = code;
switch(RR()) //& RI7 //0 - 10
{
ADD_OPCODE(STOP,(GetField(18, 31)));
ADD_OPCODE(LNOP,());
ADD_OPCODE(RDCH,(RT(), RA()));
ADD_OPCODE(RCHCNT,(RT(), RA()));
ADD_OPCODE(SF,(RT(), RA(), RB()));
ADD_OPCODE(SHLI,(RT(), RA(), i7()));
ADD_OPCODE(A,(RT(), RA(), RB()));
ADD_OPCODE(SPU_AND,(RT(), RA(), RB()));
ADD_OPCODE(LQX,(RT(), RA(), RB()));
ADD_OPCODE(WRCH,(RA(), RT()));
ADD_OPCODE(STQX,(RT(), RA(), RB()));
ADD_OPCODE(BI,(RA()));
ADD_OPCODE(BISL,(RT(), RA()));
ADD_OPCODE(HBR,(GetField(11), RO(), RA()));
ADD_OPCODE(CWX,(RT(), RA(), RB()));
ADD_OPCODE(ROTQBY,(RT(), RA(), RB()));
ADD_OPCODE(ROTQBYI,(RT(), RA(), i7()));
ADD_OPCODE(SHLQBYI,(RT(), RA(), i7()));
ADD_OPCODE(SPU_NOP,(RT()));
ADD_OPCODE(CLGT,(RT(), RA(), RB()));
}
switch(RI16()) //0 - 8
{
ADD_OPCODE(BRZ,(RT(), exts16(i16())));
ADD_OPCODE(BRHZ,(RT(), exts16(i16())));
ADD_OPCODE(BRHNZ,(RT(), exts16(i16())));
ADD_OPCODE(STQR,(RT(), i16()));
ADD_OPCODE(BR,(exts16(i16())));
ADD_OPCODE(FSMBI,(RT(), i16()));
ADD_OPCODE(BRSL,(RT(), exts16(i16())));
ADD_OPCODE(IL,(RT(), exts16(i16())));
ADD_OPCODE(LQR,(RT(), exts16(i16())));
}
switch(RI10()) //0 - 7
{
ADD_OPCODE(SPU_ORI,(RT(), RA(), exts10(i10())));
ADD_OPCODE(AI,(RT(), RA(), exts10(i10())));
ADD_OPCODE(AHI,(RT(), RA(), exts10(i10())));
ADD_OPCODE(STQD,(RT(), exts10(i10()) << 4, RA()));
ADD_OPCODE(LQD,(RT(), exts10(i10()) << 4, RA()));
ADD_OPCODE(CLGTI,(RT(), RA(), i10()));
ADD_OPCODE(CLGTHI,(RT(), RA(), i10()));
ADD_OPCODE(CEQI,(RT(), RA(), i10()));
}
switch(RI18()) //0 - 6
{
ADD_OPCODE(HBRR,(RO(), exts16(i16())));
ADD_OPCODE(ILA,(RT(), i18()));
}
switch(RRR()) //0 - 3
{
ADD_OPCODE(SELB,(RC(), RA(), RB(), RT()));
ADD_OPCODE(SHUFB,(RC(), RA(), RB(), RT()));
}
m_op.UNK(m_code, 0, 0);
}
};
#undef START_OPCODES_GROUP_
#undef START_OPCODES_GROUP
#undef ADD_OPCODE
#undef ADD_NULL_OPCODE
#undef END_OPCODES_GROUP

233
rpcs3/Emu/Cell/SPUDisAsm.h Normal file
View File

@ -0,0 +1,233 @@
#pragma once
#include "Emu/Cell/SPUOpcodes.h"
#include "Emu/Cell/DisAsm.h"
#include "Emu/Cell/SPUThread.h"
#include "Gui/DisAsmFrame.h"
#include "Emu/Memory/Memory.h"
#define START_OPCODES_GROUP(x) /*x*/
#define END_OPCODES_GROUP(x) /*x*/
class SPU_DisAsm
: public SPU_Opcodes
, public DisAsm
{
public:
PPCThread& CPU;
SPU_DisAsm()
: DisAsm(*(PPCThread*)NULL, DumpMode)
, CPU(*(PPCThread*)NULL)
{
}
SPU_DisAsm(PPCThread& cpu, DisAsmModes mode = NormalMode)
: DisAsm(cpu, mode)
, CPU(cpu)
{
}
~SPU_DisAsm()
{
}
private:
virtual void Exit()
{
if(m_mode == NormalMode && !disasm_frame->exit)
{
disasm_frame->Close();
}
this->~SPU_DisAsm();
}
virtual u32 DisAsmBranchTarget(const s32 imm)
{
return branchTarget(m_mode == NormalMode ? CPU.PC : dump_pc, imm);
}
private:
//0 - 10
virtual void STOP(OP_uIMM code)
{
Write(wxString::Format("stop 0x%x", code));
}
virtual void LNOP()
{
Write("lnop");
}
virtual void RDCH(OP_REG rt, OP_REG ra)
{
Write(wxString::Format("rdch %s,%s", spu_reg_name[rt], spu_ch_name[ra]));
}
virtual void RCHCNT(OP_REG rt, OP_REG ra)
{
Write(wxString::Format("rchcnt %s,%s", spu_reg_name[rt], spu_ch_name[ra]));
}
virtual void SF(OP_REG rt, OP_REG ra, OP_REG rb)
{
Write(wxString::Format("sf %s,%s,%s", spu_reg_name[rt], spu_reg_name[ra], spu_reg_name[rb]));
}
virtual void SHLI(OP_REG rt, OP_REG ra, OP_sIMM i7)
{
Write(wxString::Format("shli %s,%s,%d", spu_reg_name[rt], spu_reg_name[ra], i7));
}
virtual void A(OP_REG rt, OP_REG ra, OP_REG rb)
{
Write(wxString::Format("a %s,%s,%s", spu_reg_name[rt], spu_reg_name[ra], spu_reg_name[rb]));
}
virtual void SPU_AND(OP_REG rt, OP_REG ra, OP_REG rb)
{
Write(wxString::Format("and %s,%s,%s", spu_reg_name[rt], spu_reg_name[ra], spu_reg_name[rb]));
}
virtual void LQX(OP_REG rt, OP_REG ra, OP_REG rb)
{
Write(wxString::Format("lqx %s,%s,%s", spu_reg_name[rt], spu_reg_name[ra], spu_reg_name[rb]));
}
virtual void WRCH(OP_REG ra, OP_REG rt)
{
Write(wxString::Format("wrch %s,%s", spu_ch_name[ra], spu_reg_name[rt]));
}
virtual void STQX(OP_REG rt, OP_REG ra, OP_REG rb)
{
Write(wxString::Format("stqx %s,%s,%s", spu_reg_name[rt], spu_reg_name[ra], spu_reg_name[rb]));
}
virtual void BI(OP_REG ra)
{
Write(wxString::Format("bi %s", spu_reg_name[ra]));
}
virtual void BISL(OP_REG rt, OP_REG ra)
{
Write(wxString::Format("bisl %s,%s", spu_reg_name[rt], spu_reg_name[ra]));
}
virtual void HBR(OP_REG p, OP_REG ro, OP_REG ra)
{
Write(wxString::Format("hbr 0x%x,%s", DisAsmBranchTarget(ro), spu_reg_name[ra]));
}
virtual void CWX(OP_REG rt, OP_REG ra, OP_REG rb)
{
Write(wxString::Format("cwx %s,%s,%s", spu_reg_name[rt], spu_reg_name[ra], spu_reg_name[rb]));
}
virtual void ROTQBY(OP_REG rt, OP_REG ra, OP_REG rb)
{
Write(wxString::Format("rotqby %s,%s,%s", spu_reg_name[rt], spu_reg_name[ra], rb));
}
virtual void ROTQBYI(OP_REG rt, OP_REG ra, OP_sIMM i7)
{
Write(wxString::Format("rotqbyi %s,%s,%d", spu_reg_name[rt], spu_reg_name[ra], i7));
}
virtual void SHLQBYI(OP_REG rt, OP_REG ra, OP_sIMM i7)
{
Write(wxString::Format("shlqbyi %s,%s,%d", spu_reg_name[rt], spu_reg_name[ra], i7));
}
virtual void SPU_NOP(OP_REG rt)
{
Write(wxString::Format("nop %s", spu_reg_name[rt]));
}
virtual void CLGT(OP_REG rt, OP_REG ra, OP_REG rb)
{
Write(wxString::Format("clgt %s,%s,%s", spu_reg_name[rt], spu_reg_name[ra], spu_reg_name[rb]));
}
//0 - 8
virtual void BRZ(OP_REG rt, OP_sIMM i16)
{
Write(wxString::Format("brz %s,0x%x", spu_reg_name[rt], DisAsmBranchTarget(i16)));
}
virtual void BRHZ(OP_REG rt, OP_sIMM i16)
{
Write(wxString::Format("brhz %s,0x%x", spu_reg_name[rt], DisAsmBranchTarget(i16)));
}
virtual void BRHNZ(OP_REG rt, OP_sIMM i16)
{
Write(wxString::Format("brhnz %s,0x%x", spu_reg_name[rt], DisAsmBranchTarget(i16)));
}
virtual void STQR(OP_REG rt, OP_sIMM i16)
{
Write(wxString::Format("stqr %s,0x%x", spu_reg_name[rt], DisAsmBranchTarget(i16)));
}
virtual void BR(OP_sIMM i16)
{
Write(wxString::Format("br 0x%x", DisAsmBranchTarget(i16)));
}
virtual void FSMBI(OP_REG rt, OP_sIMM i16)
{
Write(wxString::Format("fsmbi %s,%d", spu_reg_name[rt], i16));
}
virtual void BRSL(OP_REG rt, OP_sIMM i16)
{
Write(wxString::Format("brsl %s,0x%x", spu_reg_name[rt], DisAsmBranchTarget(i16)));
}
virtual void IL(OP_REG rt, OP_sIMM i16)
{
Write(wxString::Format("il %s,%d", spu_reg_name[rt], i16));
}
virtual void LQR(OP_REG rt, OP_sIMM i16)
{
Write(wxString::Format("lqr %s,0x%x", spu_reg_name[rt], DisAsmBranchTarget(i16)));
}
//0 - 7
virtual void SPU_ORI(OP_REG rt, OP_REG ra, OP_sIMM i10)
{
Write(wxString::Format("ori %s,%s,%d", spu_reg_name[rt], spu_reg_name[ra], i10));
}
virtual void AI(OP_REG rt, OP_REG ra, OP_sIMM i10)
{
Write(wxString::Format("ai %s,%s,%d", spu_reg_name[rt], spu_reg_name[ra], i10));
}
virtual void AHI(OP_REG rt, OP_REG ra, OP_sIMM i10)
{
Write(wxString::Format("ahi %s,%s,%d", spu_reg_name[rt], spu_reg_name[ra], i10));
}
virtual void STQD(OP_REG rt, OP_sIMM i10, OP_REG ra)
{
Write(wxString::Format("stqd %s,%d(%s)", spu_reg_name[rt], i10, spu_reg_name[ra]));
}
virtual void LQD(OP_REG rt, OP_sIMM i10, OP_REG ra)
{
Write(wxString::Format("lqd %s,%d(%s)", spu_reg_name[rt], i10, spu_reg_name[ra]));
}
virtual void CLGTI(OP_REG rt, OP_REG ra, OP_sIMM i10)
{
Write(wxString::Format("clgti %s,%s,%d", spu_reg_name[rt], spu_reg_name[ra], i10));
}
virtual void CLGTHI(OP_REG rt, OP_REG ra, OP_sIMM i10)
{
Write(wxString::Format("clgthi %s,%s,%d", spu_reg_name[rt], spu_reg_name[ra], i10));
}
virtual void CEQI(OP_REG rt, OP_REG ra, OP_sIMM i10)
{
Write(wxString::Format("ceqi %s,%s,%d", spu_reg_name[rt], spu_reg_name[ra], i10));
}
//0 - 6
virtual void HBRR(OP_sIMM ro, OP_sIMM i16)
{
Write(wxString::Format("hbrr 0x%x,0x%x", DisAsmBranchTarget(ro), DisAsmBranchTarget(i16)));
}
virtual void ILA(OP_REG rt, OP_sIMM i18)
{
Write(wxString::Format("ila %s,%d", spu_reg_name[rt], i18));
}
//0 - 3
virtual void SELB(OP_REG rc, OP_REG ra, OP_REG rb, OP_REG rt)
{
Write(wxString::Format("selb %s,%s,%s,%s", spu_reg_name[rc], spu_reg_name[ra], spu_reg_name[rb], spu_reg_name[rt]));
}
virtual void SHUFB(OP_REG rc, OP_REG ra, OP_REG rb, OP_REG rt)
{
Write(wxString::Format("shufb %s,%s,%s,%s", spu_reg_name[rc], spu_reg_name[ra], spu_reg_name[rb], spu_reg_name[rt]));
}
virtual void UNK(const s32 code, const s32 opcode, const s32 gcode)
{
Write(wxString::Format("Unknown/Illegal opcode! (0x%08x)", code));
}
};
#undef START_OPCODES_GROUP
#undef END_OPCODES_GROUP

View File

@ -0,0 +1,338 @@
#pragma once
#include "Emu/Cell/SPUOpcodes.h"
#include "Emu/Memory/Memory.h"
#include "Emu/Cell/SPUThread.h"
#include "Emu/SysCalls/SysCalls.h"
#define START_OPCODES_GROUP(x)
#define END_OPCODES_GROUP(x)
class SPU_Interpreter : public SPU_Opcodes
{
private:
SPUThread& CPU;
public:
SPU_Interpreter(SPUThread& cpu) : CPU(cpu)
{
}
private:
virtual void Exit(){}
virtual void SysCall()
{
}
//0 - 10
virtual void STOP(OP_uIMM code)
{
Emu.Pause();
}
virtual void LNOP()
{
}
virtual void RDCH(OP_REG rt, OP_REG ra)
{
CPU.ReadChannel(CPU.GPR[rt], ra);
}
virtual void RCHCNT(OP_REG rt, OP_REG ra)
{
CPU.GPR[rt].Reset();
CPU.GPR[rt]._u32[0] = CPU.GetChannelCount(ra);
}
virtual void SF(OP_REG rt, OP_REG ra, OP_REG rb)
{
CPU.GPR[rt]._u32[0] = CPU.GPR[rb]._u32[0] + ~CPU.GPR[ra]._u32[0] + 1;
CPU.GPR[rt]._u32[1] = CPU.GPR[rb]._u32[1] + ~CPU.GPR[ra]._u32[1] + 1;
CPU.GPR[rt]._u32[2] = CPU.GPR[rb]._u32[2] + ~CPU.GPR[ra]._u32[2] + 1;
CPU.GPR[rt]._u32[3] = CPU.GPR[rb]._u32[3] + ~CPU.GPR[ra]._u32[3] + 1;
}
virtual void SHLI(OP_REG rt, OP_REG ra, OP_sIMM i7)
{
const u32 s = i7 & 0x3f;
for(u32 j = 0; j < 4; ++j)
{
const u32 t = CPU.GPR[ra]._u32[j];
u32 r = 0;
for(u32 b = 0; b + s < 32; ++b)
{
r |= t & (1 << (b + s));
}
CPU.GPR[rt]._u32[j] = r;
}
}
virtual void A(OP_REG rt, OP_REG ra, OP_REG rb)
{
CPU.GPR[rt]._u32[0] = CPU.GPR[ra]._u32[0] + CPU.GPR[rb]._u32[0];
CPU.GPR[rt]._u32[1] = CPU.GPR[ra]._u32[1] + CPU.GPR[rb]._u32[1];
CPU.GPR[rt]._u32[2] = CPU.GPR[ra]._u32[2] + CPU.GPR[rb]._u32[2];
CPU.GPR[rt]._u32[3] = CPU.GPR[ra]._u32[3] + CPU.GPR[rb]._u32[3];
}
virtual void SPU_AND(OP_REG rt, OP_REG ra, OP_REG rb)
{
CPU.GPR[rt]._u32[0] = CPU.GPR[ra]._u32[0] & CPU.GPR[rb]._u32[0];
CPU.GPR[rt]._u32[1] = CPU.GPR[ra]._u32[1] & CPU.GPR[rb]._u32[1];
CPU.GPR[rt]._u32[2] = CPU.GPR[ra]._u32[2] & CPU.GPR[rb]._u32[2];
CPU.GPR[rt]._u32[3] = CPU.GPR[ra]._u32[3] & CPU.GPR[rb]._u32[3];
}
virtual void LQX(OP_REG rt, OP_REG ra, OP_REG rb)
{
CPU.LSA = CPU.GPR[ra]._u32[0] + CPU.GPR[rb]._u32[0];
CPU.GPR[rt]._u128 = CPU.ReadLSA128();
}
virtual void WRCH(OP_REG ra, OP_REG rt)
{
CPU.WriteChannel(ra, CPU.GPR[rt]);
}
virtual void STQX(OP_REG rt, OP_REG ra, OP_REG rb)
{
CPU.LSA = CPU.GPR[ra]._u32[0] + CPU.GPR[rb]._u32[0];
CPU.WriteLSA128(CPU.GPR[rt]._u128);
}
virtual void BI(OP_REG ra)
{
CPU.SetBranch(CPU.GPR[ra]._u32[0] & 0xfffffffc);
}
virtual void BISL(OP_REG rt, OP_REG ra)
{
CPU.SetBranch(CPU.GPR[ra]._u32[0] & 0xfffffffc);
CPU.GPR[rt].Reset();
CPU.GPR[rt]._u32[0] = CPU.PC + 4;
}
virtual void HBR(OP_REG p, OP_REG ro, OP_REG ra)
{
CPU.SetBranch(CPU.GPR[ra]._u32[0]);
}
virtual void CWX(OP_REG rt, OP_REG ra, OP_REG rb)
{
const u32 t = ((CPU.GPR[ra]._u32[0] + CPU.GPR[rb]._u32[0]) & 0xc) / 4;
for(u32 i=0; i<16; ++i) CPU.GPR[rt]._i8[i] = 0x1f - i;
CPU.GPR[rt]._u32[t] = 0x10203;
}
virtual void ROTQBY(OP_REG rt, OP_REG ra, OP_REG rb)
{
const s32 s = CPU.GPR[rb]._u8[0] & 0xf;
for(u32 b = 0; b < 16; ++b)
{
if(b + s < 16)
{
CPU.GPR[rt]._u8[b] = CPU.GPR[ra]._u8[b + s];
}
else
{
CPU.GPR[rt]._u8[b] = CPU.GPR[ra]._u8[b + s - 16];
}
}
}
virtual void ROTQBYI(OP_REG rt, OP_REG ra, OP_sIMM i7)
{
const u16 s = i7 & 0xf;
for(u32 b = 0; b < 16; ++b)
{
if(b + s < 16)
{
CPU.GPR[rt]._u8[b] = CPU.GPR[ra]._u8[b + s];
}
else
{
CPU.GPR[rt]._u8[b] = CPU.GPR[ra]._u8[b + s - 16];
}
}
}
virtual void SHLQBYI(OP_REG rt, OP_REG ra, OP_sIMM i7)
{
const u16 s = i7 & 0x1f;
CPU.GPR[rt].Reset();
for(u32 b = 0; b + s < 16; ++b)
{
CPU.GPR[rt]._u8[b] = CPU.GPR[ra]._u8[b + s];
}
}
virtual void SPU_NOP(OP_REG rt)
{
}
virtual void CLGT(OP_REG rt, OP_REG ra, OP_REG rb)
{
for(u32 i = 0; i < 4; ++i)
{
CPU.GPR[rt]._u32[i] = (CPU.GPR[ra]._u32[i] > CPU.GPR[rb]._u32[i]) ? 0xffffffff : 0x00000000;
}
}
//0 - 8
virtual void BRZ(OP_REG rt, OP_sIMM i16)
{
if(!CPU.GPR[rt]._u32[0]) CPU.SetBranch(branchTarget(CPU.PC, i16));
}
virtual void BRHZ(OP_REG rt, OP_sIMM i16)
{
if(!CPU.GPR[rt]._u16[0]) CPU.SetBranch(branchTarget(CPU.PC, i16));
}
virtual void BRHNZ(OP_REG rt, OP_sIMM i16)
{
if(CPU.GPR[rt]._u16[0]) CPU.SetBranch(branchTarget(CPU.PC, i16));
}
virtual void STQR(OP_REG rt, OP_sIMM i16)
{
CPU.LSA = branchTarget(CPU.PC, i16);
CPU.WriteLSA128(CPU.GPR[rt]._u128);
}
virtual void BR(OP_sIMM i16)
{
CPU.SetBranch(branchTarget(CPU.PC, i16));
}
virtual void FSMBI(OP_REG rt, OP_sIMM i16)
{
const u32 s = i16;
for(u32 j = 0; j < 16; ++j)
{
if((s >> j) & 0x1)
{
CPU.GPR[rt]._u8[j] = 0xFF;
}
else
{
CPU.GPR[rt]._u8[j] = 0x00;
}
}
}
virtual void BRSL(OP_REG rt, OP_sIMM i16)
{
CPU.GPR[rt].Reset();
CPU.GPR[rt]._u32[0] = CPU.PC + 4;
CPU.SetBranch(branchTarget(CPU.PC, i16));
}
virtual void IL(OP_REG rt, OP_sIMM i16)
{
CPU.GPR[rt]._u32[0] = i16;
CPU.GPR[rt]._u32[1] = i16;
CPU.GPR[rt]._u32[2] = i16;
CPU.GPR[rt]._u32[3] = i16;
}
virtual void LQR(OP_REG rt, OP_sIMM i16)
{
CPU.LSA = branchTarget(CPU.PC, i16);
if(!Memory.IsGoodAddr(CPU.LSA))
{
ConLog.Warning("LQR: Bad addr: 0x%x", CPU.LSA);
return;
}
CPU.GPR[rt]._u128 = CPU.ReadLSA128();
}
//0 - 7
virtual void SPU_ORI(OP_REG rt, OP_REG ra, OP_sIMM i10)
{
for(u32 i = 0; i < 4; ++i)
{
CPU.GPR[rt]._u32[i] = CPU.GPR[ra]._u32[i] | i10;
}
}
virtual void AI(OP_REG rt, OP_REG ra, OP_sIMM i10)
{
for(u32 i = 0; i < 4; ++i)
{
CPU.GPR[rt]._u32[i] = CPU.GPR[ra]._u32[i] + i10;
}
}
virtual void AHI(OP_REG rt, OP_REG ra, OP_sIMM i10)
{
for(u32 i = 0; i < 8; ++i)
{
CPU.GPR[rt]._u16[i] = CPU.GPR[ra]._u16[i] + i10;
}
}
virtual void STQD(OP_REG rt, OP_sIMM i10, OP_REG ra)
{
CPU.LSA = branchTarget(0, i10 + CPU.GPR[ra]._u32[0]);
CPU.WriteLSA128(CPU.GPR[rt]._u128);
}
virtual void LQD(OP_REG rt, OP_sIMM i10, OP_REG ra)
{
CPU.LSA = branchTarget(0, i10 + CPU.GPR[ra]._u32[0]);
CPU.GPR[rt]._u128 = CPU.ReadLSA128();
}
virtual void CLGTI(OP_REG rt, OP_REG ra, OP_sIMM i10)
{
for(u32 i = 0; i < 4; ++i)
{
CPU.GPR[rt]._u32[i] = (CPU.GPR[rt]._u32[i] > (u32)i10) ? 0xffffffff : 0x00000000;
}
}
virtual void CLGTHI(OP_REG rt, OP_REG ra, OP_sIMM i10)
{
for(u32 i = 0; i < 8; ++i)
{
CPU.GPR[rt]._u16[i] = (CPU.GPR[rt]._u16[i] > (u16)i10) ? 0xffff : 0x0000;
}
}
virtual void CEQI(OP_REG rt, OP_REG ra, OP_sIMM i10)
{
for(u32 i = 0; i < 4; ++i)
{
CPU.GPR[rt]._u32[i] = (CPU.GPR[rt]._u32[i] == (u32)i10) ? 0xffffffff : 0x00000000;
}
}
//0 - 6
virtual void HBRR(OP_sIMM ro, OP_sIMM i16)
{
//CHECK ME
//CPU.GPR[0]._u64[0] = branchTarget(CPU.PC, i16);
//CPU.SetBranch(branchTarget(CPU.PC, ro));
}
virtual void ILA(OP_REG rt, OP_sIMM i18)
{
CPU.GPR[rt]._u32[0] = i18;
CPU.GPR[rt]._u32[1] = i18;
CPU.GPR[rt]._u32[2] = i18;
CPU.GPR[rt]._u32[3] = i18;
}
//0 - 3
virtual void SELB(OP_REG rt, OP_REG ra, OP_REG rb, OP_REG rc)
{
for(u32 i = 0; i < 4; ++i)
{
CPU.GPR[rt]._u32[i] =
( CPU.GPR[rc]._u32[i] & CPU.GPR[rb]._u32[i]) |
(~CPU.GPR[rc]._u32[i] & CPU.GPR[ra]._u32[i]);
}
/*
CPU.GPR[rt] = _mm_or_si128(
_mm_and_si128(CPU.GPR[rc], CPU.GPR[rb]),
_mm_andnot_si128(CPU.GPR[rc], CPU.GPR[ra])
);
*/
}
virtual void SHUFB(OP_REG rc, OP_REG ra, OP_REG rb, OP_REG rt)
{
ConLog.Warning("SHUFB");
}
virtual void UNK(const s32 code, const s32 opcode, const s32 gcode)
{
UNK(wxString::Format("Unknown/Illegal opcode! (0x%08x)", code));
}
void UNK(const wxString& err)
{
ConLog.Error(err + wxString::Format(" #pc: 0x%x", CPU.PC));
Emu.Pause();
for(uint i=0; i<128; ++i) ConLog.Write("r%d = 0x%s", i, CPU.GPR[i].ToString());
}
};
#undef START_OPCODES_GROUP
#undef END_OPCODES_GROUP

162
rpcs3/Emu/Cell/SPUOpcodes.h Normal file
View File

@ -0,0 +1,162 @@
#pragma once
#define OP_REG const u32
#define OP_sIMM const s32
#define OP_uIMM const u32
#define START_OPCODES_GROUP(x) /*x*/
#define ADD_OPCODE(name, regs) virtual void(##name##)##regs##=0
#define ADD_NULL_OPCODE(name) virtual void(##name##)()=0
#define END_OPCODES_GROUP(x) /*x*/
enum SPU_0_10_Opcodes
{
STOP = 0x0,
LNOP = 0x1,
RDCH = 0xd,
RCHCNT = 0xf,
SF = 0x40,
SHLI = 0x7b,
A = 0xc0,
SPU_AND = 0xc1,
LQX = 0x1c4,
WRCH = 0x10d,
STQX = 0x144,
BI = 0x1a8,
BISL = 0x1a9,
HBR = 0x1ac,
CWX = 0x1d6,
ROTQBY = 0x1dc,
ROTQBYI = 0x1fc,
SHLQBYI = 0x1ff,
SPU_NOP = 0x201,
CLGT = 0x2c0,
};
enum SPU_0_8_Opcodes
{
BRZ = 0x40,
BRHZ = 0x44,
BRHNZ = 0x46,
STQR = 0x47,
BR = 0x64,
FSMBI = 0x65,
BRSL = 0x66,
LQR = 0x67,
IL = 0x81,
};
enum SPU_0_7_Opcodes
{
SPU_ORI = 0x4,
AI = 0x1c,
AHI = 0x1d,
STQD = 0x24,
LQD = 0x34,
CLGTI = 0x5c,
CLGTHI = 0x5d,
CEQI = 0x7c,
};
enum SPU_0_6_Opcodes
{
HBRR = 0x9,
ILA = 0x21,
};
enum SPU_0_3_Opcodes
{
SELB = 0x8,
SHUFB = 0xb,
};
class SPU_Opcodes
{
public:
static u32 branchTarget(const u64 pc, const s32 imm)
{
return (pc + ((imm << 2) & ~0x3)) & 0x3fff0;
}
virtual void Exit()=0;
/*
- 1: Unk/0xb0c2c58c -> 11c: b0 c2 c5 8c shufb $6,$11,$11,$12
- 2: Unk/0x5800c505 -> 124: 58 00 c5 05 clgt $5,$10,$3
- 3: Unk/0x5c000184 -> 128: 5c 00 01 84 clgti $4,$3,0
- 4: Unk/0x18210282 -> 12c: 18 21 02 82 and $2,$5,$4
- 5: Unk/0x00000000 -> 154: 00 00 00 00 stop
- 6: Unk/0x00200000 -> 1b4: 00 20 00 00 lnop
- 7: Unk/0x0f608487 -> 1c0: 0f 60 84 87 shli $7,$9,2
- 8: Unk/0x18140384 -> 1c8: 18 14 03 84 a $4,$7,$80
- 9: Unk/0x38940386 -> 1cc: 38 94 03 86 lqx $6,$7,$80
- 10: Unk/0x3b810305 -> 1d0: 3b 81 03 05 rotqby $5,$6,$4
- 11: Unk/0x35200280 -> 1d4: 35 20 02 80 bisl $0,$5
- 12: Unk/0x237ff982 -> 1e4: 23 7f f9 82 brhnz $2,0x1b0
- 13: Unk/0x35800014 -> 204: 35 80 00 14 hbr 0x254,$0
- 14: Unk/0x5d13c482 -> 224: 5d 13 c4 82 clgthi $2,$9,79
- 15: Unk/0x3ac1828d -> 240: 3a c1 82 8d cwx $13,$5,$6
- 16: Unk/0x2881828b -> 24c: 28 81 82 8b stqx $11,$5,$6
- 17: Unk/0x21a00b82 -> 25c: 21 a0 0b 82 wrch $ch23,$2
- 18: Unk/0x01e00c05 -> 260: 01 e0 0c 05 rchcnt $5,$ch24
- 19: Unk/0x7c004284 -> 264: 7c 00 42 84 ceqi $4,$5,1
- 20: Unk/0x207ffe84 -> 26c: 20 7f fe 84 brz $4,0x260
- 21: Unk/0x01a00c03 -> 27c: 01 a0 0c 03 rdch $3,$ch24
*/
//0 - 10
ADD_OPCODE(STOP,(OP_uIMM code));
ADD_OPCODE(LNOP,());
ADD_OPCODE(RDCH,(OP_REG rt, OP_REG ra));
ADD_OPCODE(RCHCNT,(OP_REG rt, OP_REG ra));
ADD_OPCODE(SF,(OP_REG rt, OP_REG ra, OP_REG rb));
ADD_OPCODE(SHLI,(OP_REG rt, OP_REG ra, OP_sIMM i7));
ADD_OPCODE(A,(OP_REG rt, OP_REG ra, OP_REG rb));
ADD_OPCODE(SPU_AND,(OP_REG rt, OP_REG ra, OP_REG rb));
ADD_OPCODE(LQX,(OP_REG rt, OP_REG ra, OP_REG rb));
ADD_OPCODE(WRCH,(OP_REG ra, OP_REG rt));
ADD_OPCODE(STQX,(OP_REG rt, OP_REG ra, OP_REG rb));
ADD_OPCODE(BI,(OP_REG ra));
ADD_OPCODE(BISL,(OP_REG rt, OP_REG ra));
ADD_OPCODE(HBR,(OP_REG p, OP_REG ro, OP_REG ra));
ADD_OPCODE(CWX,(OP_REG rt, OP_REG ra, OP_REG rb));
ADD_OPCODE(ROTQBY,(OP_REG rt, OP_REG ra, OP_REG rb));
ADD_OPCODE(ROTQBYI,(OP_REG rt, OP_REG ra, OP_sIMM i7));
ADD_OPCODE(SHLQBYI,(OP_REG rt, OP_REG ra, OP_sIMM i7));
ADD_OPCODE(SPU_NOP,(OP_REG rt));
ADD_OPCODE(CLGT,(OP_REG rt, OP_REG ra, OP_REG rb));
//0 - 8
ADD_OPCODE(BRZ,(OP_REG rt, OP_sIMM i16));
ADD_OPCODE(BRHZ,(OP_REG rt, OP_sIMM i16));
ADD_OPCODE(BRHNZ,(OP_REG rt, OP_sIMM i16));
ADD_OPCODE(STQR,(OP_REG rt, OP_sIMM i16));
ADD_OPCODE(BR,(OP_sIMM i16));
ADD_OPCODE(FSMBI,(OP_REG rt, OP_sIMM i16));
ADD_OPCODE(BRSL,(OP_REG rt, OP_sIMM i16));
ADD_OPCODE(IL,(OP_REG rt, OP_sIMM i16));
ADD_OPCODE(LQR,(OP_REG rt, OP_sIMM i16));
//0 - 7
ADD_OPCODE(SPU_ORI,(OP_REG rt, OP_REG ra, OP_sIMM i10));
ADD_OPCODE(AI,(OP_REG rt, OP_REG ra, OP_sIMM i10));
ADD_OPCODE(AHI,(OP_REG rt, OP_REG ra, OP_sIMM i10));
ADD_OPCODE(STQD,(OP_REG rt, OP_sIMM i10, OP_REG ra));
ADD_OPCODE(LQD,(OP_REG rt, OP_sIMM i10, OP_REG ra));
ADD_OPCODE(CLGTI,(OP_REG rt, OP_REG ra, OP_sIMM i10));
ADD_OPCODE(CLGTHI,(OP_REG rt, OP_REG ra, OP_sIMM i10));
ADD_OPCODE(CEQI,(OP_REG rt, OP_REG ra, OP_sIMM i10));
//0 - 6
ADD_OPCODE(HBRR,(OP_sIMM ro, OP_sIMM i16));
ADD_OPCODE(ILA,(OP_REG rt, OP_sIMM i18));
//0 - 3
ADD_OPCODE(SELB,(OP_REG rc, OP_REG ra, OP_REG rb, OP_REG rt));
ADD_OPCODE(SHUFB,(OP_REG rc, OP_REG ra, OP_REG rb, OP_REG rt));
ADD_OPCODE(UNK,(const s32 code, const s32 opcode, const s32 gcode));
};
#undef START_OPCODES_GROUP
#undef ADD_OPCODE
#undef ADD_NULL_OPCODE
#undef END_OPCODES_GROUP

View File

@ -0,0 +1,66 @@
#include "stdafx.h"
#include "Emu/Cell/SPUThread.h"
#include "Emu/Cell/SPUDecoder.h"
#include "Emu/Cell/SPUInterpreter.h"
#include "Emu/Cell/SPUDisAsm.h"
SPUThread::SPUThread() : PPCThread(PPC_THREAD_SPU)
{
Reset();
}
SPUThread::~SPUThread()
{
}
void SPUThread::DoReset()
{
//reset regs
for(u32 i=0; i<128; ++i) GPR[i].Reset();
LSA = 0;
}
void SPUThread::InitRegs()
{
GPR[1]._u64[0] = stack_point;
}
u64 SPUThread::GetFreeStackSize() const
{
return (GetStackAddr() + GetStackSize()) - GPR[1]._u64[0];
}
void SPUThread::DoRun()
{
switch(Ini.CPUDecoderMode.GetValue())
{
case 0:
m_dec = new SPU_Decoder(*new SPU_DisAsm(*this));
break;
case 1:
case 2:
m_dec = new SPU_Decoder(*new SPU_Interpreter(*this));
break;
}
}
void SPUThread::DoResume()
{
}
void SPUThread::DoPause()
{
}
void SPUThread::DoStop()
{
delete m_dec;
m_dec = 0;
}
void SPUThread::DoCode(const s32 code)
{
m_dec->Decode(code);
}

251
rpcs3/Emu/Cell/SPUThread.h Normal file
View File

@ -0,0 +1,251 @@
#pragma once
#include "PPCThread.h"
static const wxString spu_reg_name[128] =
{
"$LR", "$SP", "$3", "$4", "$5", "$6", "$7", "$8",
"$9", "$10", "$11", "$12", "$13", "$14", "$15", "$16",
"$17", "$18", "$19", "$20", "$21", "$22", "$23", "$24",
"$25", "$26", "$27", "$28", "$29", "$30", "$31", "$32",
"$33", "$34", "$35", "$36", "$37", "$38", "$39", "$40",
"$41", "$42", "$43", "$44", "$45", "$46", "$47", "$48",
"$49", "$50", "$51", "$52", "$53", "$54", "$55", "$56",
"$57", "$58", "$59", "$60", "$61", "$62", "$63", "$64",
"$65", "$66", "$67", "$68", "$69", "$70", "$71", "$72",
"$73", "$74", "$75", "$76", "$77", "$78", "$79", "$80",
"$81", "$82", "$83", "$84", "$85", "$86", "$87", "$88",
"$89", "$90", "$91", "$92", "$93", "$94", "$95", "$96",
"$97", "$98", "$99", "$100", "$101", "$102", "$103", "$104",
"$105", "$106", "$107", "$108", "$109", "$110", "$111", "$112",
"$113", "$114", "$115", "$116", "$117", "$118", "$119", "$120",
"$121", "$122", "$123", "$124", "$125", "$126", "$127",
};
static const wxString spu_ch_name[128] =
{
"$SPU_RdEventStat", "$SPU_WrEventMask", "$SPU_RdSigNotify1",
"$SPU_RdSigNotify2", "$ch5", "$ch6", "$SPU_WrDec", "$SPU_RdDec",
"$MFC_WrMSSyncReq", "$ch10", "$SPU_RdEventMask", "$MFC_RdTagMask", "$SPU_RdMachStat",
"$SPU_WrSRR0", "$SPU_RdSRR0", "$MFC_LSA", "$MFC_EAH", "$MFC_EAL", "$MFC_Size",
"$MFC_TagID", "$MFC_Cmd", "$MFC_WrTagMask", "$MFC_WrTagUpdate", "$MFC_RdTagStat",
"$MFC_RdListStallStat", "$MFC_WrListStallAck", "$MFC_RdAtomicStat",
"$SPU_WrOutMbox", "$SPU_RdInMbox", "$SPU_WrOutIntrMbox", "$ch31", "$ch32",
"$ch33", "$ch34", "$ch35", "$ch36", "$ch37", "$ch38", "$ch39", "$ch40",
"$ch41", "$ch42", "$ch43", "$ch44", "$ch45", "$ch46", "$ch47", "$ch48",
"$ch49", "$ch50", "$ch51", "$ch52", "$ch53", "$ch54", "$ch55", "$ch56",
"$ch57", "$ch58", "$ch59", "$ch60", "$ch61", "$ch62", "$ch63", "$ch64",
"$ch65", "$ch66", "$ch67", "$ch68", "$ch69", "$ch70", "$ch71", "$ch72",
"$ch73", "$ch74", "$ch75", "$ch76", "$ch77", "$ch78", "$ch79", "$ch80",
"$ch81", "$ch82", "$ch83", "$ch84", "$ch85", "$ch86", "$ch87", "$ch88",
"$ch89", "$ch90", "$ch91", "$ch92", "$ch93", "$ch94", "$ch95", "$ch96",
"$ch97", "$ch98", "$ch99", "$ch100", "$ch101", "$ch102", "$ch103", "$ch104",
"$ch105", "$ch106", "$ch107", "$ch108", "$ch109", "$ch110", "$ch111", "$ch112",
"$ch113", "$ch114", "$ch115", "$ch116", "$ch117", "$ch118", "$ch119", "$ch120",
"$ch121", "$ch122", "$ch123", "$ch124", "$ch125", "$ch126", "$ch127",
};
enum SPUchannels
{
SPU_RdEventStat = 0, //Read event status with mask applied
SPU_WrEventMask = 1, //Write event mask
SPU_WrEventAck = 2, //Write end of event processing
SPU_RdSigNotify1 = 3, //Signal notification 1
SPU_RdSigNotify2 = 4, //Signal notification 2
SPU_WrDec = 7, //Write decrementer count
SPU_RdDec = 8, //Read decrementer count
SPU_RdEventMask = 11, //Read event mask
SPU_RdMachStat = 13, //Read SPU run status
SPU_WrSRR0 = 14, //Write SPU machine state save/restore register 0 (SRR0)
SPU_RdSRR0 = 15, //Read SPU machine state save/restore register 0 (SRR0)
SPU_WrOutMbox = 28, //Write outbound mailbox contents
SPU_RdInMbox = 29, //Read inbound mailbox contents
SPU_WrOutIntrMbox = 30, //Write outbound interrupt mailbox contents (interrupting PPU)
};
enum MFCchannels
{
MFC_WrMSSyncReq = 9, //Write multisource synchronization request
MFC_RdTagMask = 12, //Read tag mask
MFC_LSA = 16, //Write local memory address command parameter
MFC_EAH = 17, //Write high order DMA effective address command parameter
MFC_EAL = 18, //Write low order DMA effective address command parameter
MFC_Size = 19, //Write DMA transfer size command parameter
MFC_TagID = 20, //Write tag identifier command parameter
MFC_Cmd = 21, //Write and enqueue DMA command with associated class ID
MFC_WrTagMask = 22, //Write tag mask
MFC_WrTagUpdate = 23, //Write request for conditional or unconditional tag status update
MFC_RdTagStat = 24, //Read tag status with mask applied
MFC_RdListStallStat = 25, //Read DMA list stall-and-notify status
MFC_WrListStallAck = 26, //Write DMA list stall-and-notify acknowledge
MFC_RdAtomicStat = 27, //Read completion status of last completed immediate MFC atomic update command
};
union SPU_GPR_hdr
{
//__m128i _m128i;
u128 _u128;
s128 _i128;
u64 _u64[2];
s64 _i64[2];
u32 _u32[4];
s32 _i32[4];
u16 _u16[8];
s16 _i16[8];
u8 _u8[16];
s8 _i8[16];
SPU_GPR_hdr() {}
/*
SPU_GPR_hdr(const __m128i val){_u128._u64[0] = val.m128i_u64[0]; _u128._u64[1] = val.m128i_u64[1];}
SPU_GPR_hdr(const u128 val) { _u128 = val; }
SPU_GPR_hdr(const u64 val) { Reset(); _u64[0] = val; }
SPU_GPR_hdr(const u32 val) { Reset(); _u32[0] = val; }
SPU_GPR_hdr(const u16 val) { Reset(); _u16[0] = val; }
SPU_GPR_hdr(const u8 val) { Reset(); _u8[0] = val; }
SPU_GPR_hdr(const s128 val) { _i128 = val; }
SPU_GPR_hdr(const s64 val) { Reset(); _i64[0] = val; }
SPU_GPR_hdr(const s32 val) { Reset(); _i32[0] = val; }
SPU_GPR_hdr(const s16 val) { Reset(); _i16[0] = val; }
SPU_GPR_hdr(const s8 val) { Reset(); _i8[0] = val; }
*/
wxString ToString() const
{
return wxString::Format("%08x%08x%08x%08x", _u32[3], _u32[2], _u32[1], _u32[0]);
}
void Reset()
{
memset(this, 0, sizeof(*this));
}
//operator __m128i() { __m128i ret; ret.m128i_u64[0]=_u128._u64[0]; ret.m128i_u64[1]=_u128._u64[1]; return ret; }
/*
SPU_GPR_hdr operator ^ (__m128i right) { return _mm_xor_si128(*this, right); }
SPU_GPR_hdr operator | (__m128i right) { return _mm_or_si128 (*this, right); }
SPU_GPR_hdr operator & (__m128i right) { return _mm_and_si128(*this, right); }
SPU_GPR_hdr operator << (int right) { return _mm_slli_epi32(*this, right); }
SPU_GPR_hdr operator << (__m128i right) { return _mm_sll_epi32(*this, right); }
SPU_GPR_hdr operator >> (int right) { return _mm_srai_epi32(*this, right); }
SPU_GPR_hdr operator >> (__m128i right) { return _mm_sra_epi32(*this, right); }
SPU_GPR_hdr operator | (__m128i right) { return _mm_or_si128 (*this, right); }
SPU_GPR_hdr operator & (__m128i right) { return _mm_and_si128(*this, right); }
SPU_GPR_hdr operator << (int right) { return _mm_slli_epi32(*this, right); }
SPU_GPR_hdr operator << (__m128i right) { return _mm_sll_epi32(*this, right); }
SPU_GPR_hdr operator >> (int right) { return _mm_srai_epi32(*this, right); }
SPU_GPR_hdr operator >> (__m128i right) { return _mm_sra_epi32(*this, right); }
SPU_GPR_hdr operator ^= (__m128i right) { return *this = *this ^ right; }
SPU_GPR_hdr operator |= (__m128i right) { return *this = *this | right; }
SPU_GPR_hdr operator &= (__m128i right) { return *this = *this & right; }
SPU_GPR_hdr operator <<= (int right) { return *this = *this << right; }
SPU_GPR_hdr operator <<= (__m128i right){ return *this = *this << right; }
SPU_GPR_hdr operator >>= (int right) { return *this = *this >> right; }
SPU_GPR_hdr operator >>= (__m128i right){ return *this = *this >> right; }
*/
};
class SPUThread : public PPCThread
{
public:
SPU_GPR_hdr GPR[128]; //General-Purpose Register
Stack<u32> Mbox;
u32 LSA; //local storage address
union
{
u64 EA;
struct { u32 EAH, EAL; };
};
u32 GetChannelCount(u32 ch)
{
switch(ch)
{
case SPU_RdInMbox:
return 1;
case SPU_WrOutIntrMbox:
return 0;
default:
ConLog.Error("%s error: unknown/illegal channel (%d).", __FUNCTION__, ch);
break;
}
return 0;
}
void WriteChannel(u32 ch, const SPU_GPR_hdr& r)
{
const u32 v = r._u32[0];
switch(ch)
{
case SPU_WrOutIntrMbox:
Mbox.Push(v);
break;
default:
ConLog.Error("%s error: unknown/illegal channel (%d).", __FUNCTION__, ch);
break;
}
}
void ReadChannel(SPU_GPR_hdr& r, u32 ch)
{
r.Reset();
u32& v = r._u32[0];
switch(ch)
{
case SPU_RdInMbox:
v = Mbox.Pop();
break;
default:
ConLog.Error("%s error: unknown/illegal channel (%d).", __FUNCTION__, ch);
break;
}
}
u8 ReadLSA8 () { return Memory.Read8 (LSA + m_offset); }
u16 ReadLSA16 () { return Memory.Read16 (LSA + m_offset); }
u32 ReadLSA32 () { return Memory.Read32 (LSA + m_offset); }
u64 ReadLSA64 () { return Memory.Read64 (LSA + m_offset); }
u128 ReadLSA128() { return Memory.Read128(LSA + m_offset); }
void WriteLSA8 (const u8& data) { Memory.Write8 (LSA + m_offset, data); }
void WriteLSA16 (const u16& data) { Memory.Write16 (LSA + m_offset, data); }
void WriteLSA32 (const u32& data) { Memory.Write32 (LSA + m_offset, data); }
void WriteLSA64 (const u64& data) { Memory.Write64 (LSA + m_offset, data); }
void WriteLSA128(const u128& data) { Memory.Write128(LSA + m_offset, data); }
public:
SPUThread();
~SPUThread();
virtual wxString RegsToString()
{
wxString ret = PPCThread::RegsToString();
for(uint i=0; i<128; ++i) ret += wxString::Format("GPR[%d] = 0x%s\n", i, GPR[i].ToString());
return ret;
}
public:
virtual void InitRegs();
virtual u64 GetFreeStackSize() const;
protected:
virtual void DoReset();
virtual void DoRun();
virtual void DoPause();
virtual void DoResume();
virtual void DoStop();
private:
virtual void DoCode(const s32 code);
};

56
rpcs3/Emu/DbgConsole.cpp Normal file
View File

@ -0,0 +1,56 @@
#include "stdafx.h"
#include "DbgConsole.h"
BEGIN_EVENT_TABLE(DbgConsole, FrameBase)
EVT_CLOSE(DbgConsole::OnQuit)
END_EVENT_TABLE()
DbgConsole::DbgConsole()
: FrameBase(NULL, wxID_ANY, "DbgConsole", wxEmptyString, wxDefaultSize, wxDefaultPosition)
, ThreadBase(false, "DbgConsole thread")
{
m_console = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition,
wxSize(500, 500), wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH2);
m_console->SetBackgroundColour(wxColor("Black"));
m_console->SetFont(wxFont(8, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL));
m_color_white = new wxTextAttr(wxColour(255, 255, 255));
m_color_red = new wxTextAttr(wxColour(255, 0, 0));
}
DbgConsole::~DbgConsole()
{
Stop();
m_dbg_buffer.Flush();
}
void DbgConsole::Write(int ch, const wxString& text)
{
while(m_dbg_buffer.IsBusy()) Sleep(1);
m_dbg_buffer.Push(DbgPacket(ch, text));
if(!IsAlive()) Start();
}
void DbgConsole::Clear()
{
m_console->Clear();
}
void DbgConsole::Task()
{
while(m_dbg_buffer.HasNewPacket())
{
DbgPacket packet = m_dbg_buffer.Pop();
m_console->SetDefaultStyle(packet.m_ch == 1 ? *m_color_red : *m_color_white);
m_console->SetInsertionPointEnd();
m_console->WriteText(packet.m_text);
if(!DbgConsole::IsShown()) Show();
}
}
void DbgConsole::OnQuit(wxCloseEvent& event)
{
Hide();
}

90
rpcs3/Emu/DbgConsole.h Normal file
View File

@ -0,0 +1,90 @@
#pragma once
struct DbgPacket
{
int m_ch;
wxString m_text;
DbgPacket(int ch, const wxString& text)
: m_ch(ch)
, m_text(text)
{
}
DbgPacket()
{
}
void Clear()
{
m_text.Clear();
}
};
struct _DbgBuffer : public MTPacketBuffer<DbgPacket>
{
_DbgBuffer() : MTPacketBuffer<DbgPacket>(1024)
{
}
void Push(const DbgPacket& data)
{
const u32 stext = data.m_text.Len();
m_buffer.Reserve(sizeof(int) + sizeof(u32) + stext);
u32 c_put = m_put;
memcpy(&m_buffer[c_put], &data.m_ch, sizeof(int));
c_put += sizeof(int);
memcpy(&m_buffer[c_put], &stext, sizeof(u32));
c_put += sizeof(u32);
memcpy(&m_buffer[c_put], data.m_text.c_str(), stext);
c_put += stext;
m_put = c_put;
CheckBusy();
}
DbgPacket Pop()
{
DbgPacket ret;
u32 c_get = m_get;
ret.m_ch = *(int*)&m_buffer[c_get];
c_get += sizeof(int);
const u32& stext = *(u32*)&m_buffer[c_get];
c_get += sizeof(u32);
if(stext) memcpy(wxStringBuffer(ret.m_text, stext), &m_buffer[c_get], stext);
c_get += stext;
m_get = c_get;
if(!HasNewPacket()) Flush();
return ret;
}
};
class DbgConsole
: public FrameBase
, public ThreadBase
{
wxTextCtrl* m_console;
wxTextAttr* m_color_white;
wxTextAttr* m_color_red;
_DbgBuffer m_dbg_buffer;
public:
DbgConsole();
~DbgConsole();
void Write(int ch, const wxString& text);
void Clear();
virtual void Task();
private:
void OnQuit(wxCloseEvent& event);
DECLARE_EVENT_TABLE();
};

1038
rpcs3/Emu/GS/GCM.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,277 @@
#include "stdafx.h"
#include "FragmentProgram.h"
void FragmentDecompilerThread::AddCode(wxString code, bool bkt)
{
if(!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_le) return;
if(!src0.exec_if_eq || !src0.exec_if_gr || !src0.exec_if_le)
{
ConLog.Error("Bad cond! eq: %d gr: %d le: %d", src0.exec_if_eq, src0.exec_if_gr, src0.exec_if_le);
Emu.Pause();
return;
}
if(src1.scale)
{
switch(src1.scale)
{
case 1: code = "(" + code + ") * 2"; break;
case 2: code = "(" + code + ") * 4"; break;
case 3: code = "(" + code + ") * 8"; break;
case 5: code = "(" + code + ") / 2"; break;
case 6: code = "(" + code + ") / 4"; break;
case 7: code = "(" + code + ") / 8"; break;
default:
ConLog.Error("Bad scale: %d", src1.scale);
Emu.Pause();
break;
}
}
code = AddReg(dst.dest_reg) + GetMask() + " = " + (bkt ? "(" + code + ")" : code) + GetMask();
main += "\t" + code + ";\n";
}
wxString FragmentDecompilerThread::GetMask()
{
wxString ret = wxEmptyString;
if(dst.mask_x) ret += 'x';
if(dst.mask_y) ret += 'y';
if(dst.mask_z) ret += 'z';
if(dst.mask_w) ret += 'w';
return ret.IsEmpty() || ret == "xyzw" ? wxEmptyString : ("." + ret);
}
wxString FragmentDecompilerThread::AddReg(u32 index)
{
//if(!index) return "gl_FragColor";
return m_parr.AddParam(index ? PARAM_NONE : PARAM_OUT, "vec4", wxString::Format("r%d", index));
}
wxString FragmentDecompilerThread::AddTex()
{
return m_parr.AddParam(PARAM_CONST, "sampler2D", wxString::Format("tex_%d", dst.tex_num));
}
template<typename T> wxString FragmentDecompilerThread::GetSRC(T src)
{
wxString ret = wxEmptyString;
switch(src.reg_type)
{
case 0: //tmp
ret += AddReg(src.tmp_reg_index);
break;
case 1: //input
{
static const wxString reg_table[] =
{
"gl_Position",
"col0", "col1",
"fogc",
"tc0", "tc1", "tc2", "tc3", "tc4", "tc5", "tc6", "tc7"
};
switch(dst.src_attr_reg_num)
{
case 0x00: ret += reg_table[0]; break;
default:
if(dst.src_attr_reg_num < WXSIZEOF(reg_table))
{
ret += m_parr.AddParam(PARAM_IN, "vec4", reg_table[dst.src_attr_reg_num]);
}
else
{
ConLog.Error("Bad src reg num: %d", dst.src_attr_reg_num);
ret += m_parr.AddParam(PARAM_IN, "vec4", "unk");
Emu.Pause();
}
break;
}
}
break;
//case 2: //imm
//break;
default:
ConLog.Error("Bad src type %d", src.reg_type);
Emu.Pause();
break;
}
static const char f[4] = {'x', 'y', 'z', 'w'};
wxString swizzle = wxEmptyString;
swizzle += f[src.swizzle_x];
swizzle += f[src.swizzle_y];
swizzle += f[src.swizzle_z];
swizzle += f[src.swizzle_w];
if(swizzle != "xyzw") ret += "." + swizzle;
if(src.abs) ret = "abs(" + ret + ")";
if(src.neg) ret = "-" + ret;
return ret;
}
wxString FragmentDecompilerThread::BuildCode()
{
wxString p = wxEmptyString;
for(u32 i=0; i<m_parr.params.GetCount(); ++i)
{
for(u32 n=0; n<m_parr.params[i].names.GetCount(); ++n)
{
p += m_parr.params[i].type;
p += " ";
p += m_parr.params[i].names[n];
p += ";\n";
}
}
static const wxString& prot =
"#version 330 core\n"
"\n"
"%s\n"
"void main()\n{\n%s}\n";
return wxString::Format(prot, p, main);
}
wxThread::ExitCode FragmentDecompilerThread::Entry()
{
mem32_t data(m_addr);
for(;;)
{
dst.HEX = GetData(data[0]);
src0.HEX = GetData(data[1]);
src1.HEX = GetData(data[2]);
src2.HEX = GetData(data[3]);
switch(dst.opcode)
{
case 0x0: break; //NOP
case 0x1:
AddCode(GetSRC(src0), false);
break;
case 0x2:
AddCode(GetSRC(src0) + " * " + GetSRC(src1));
break;
case 0x17:
AddCode("texture(" + AddTex() + ", (" + GetSRC(src0) + ").xy)", false);
break;
default:
ConLog.Error("Unknown opcode 0x%x", dst.opcode);
Emu.Pause();
break;
}
m_size += 4 * 4;
if(dst.end) break;
data.SetOffset(4 * 4);
}
m_shader = BuildCode();
main.Clear();
return (ExitCode)0;
}
ShaderProgram::ShaderProgram()
: m_decompiler_thread(NULL)
, id(0)
{
}
ShaderProgram::~ShaderProgram()
{
if(m_decompiler_thread)
{
Wait();
if(m_decompiler_thread->IsAlive()) m_decompiler_thread->Delete();
safe_delete(m_decompiler_thread);
}
Delete();
}
void ShaderProgram::Decompile()
{
#if 0
FragmentDecompilerThread(shader, parr, addr).Entry();
#else
if(m_decompiler_thread)
{
Wait();
if(m_decompiler_thread->IsAlive()) m_decompiler_thread->Delete();
safe_delete(m_decompiler_thread);
}
m_decompiler_thread = new FragmentDecompilerThread(shader, parr, addr, size);
m_decompiler_thread->Create();
m_decompiler_thread->Run();
#endif
}
void ShaderProgram::Compile()
{
if(id) glDeleteShader(id);
id = glCreateShader(GL_FRAGMENT_SHADER);
const char* str = shader.c_str();
const int strlen = shader.Len();
glShaderSource(id, 1, &str, &strlen);
glCompileShader(id);
GLint r = GL_FALSE;
glGetShaderiv(id, GL_COMPILE_STATUS, &r);
if(r != GL_TRUE)
{
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &r);
if(r)
{
char* buf = new char[r+1];
GLsizei len;
memset(buf, 0, r+1);
glGetShaderInfoLog(id, r, &len, buf);
ConLog.Error("Failed to compile shader: %s", buf);
free(buf);
}
ConLog.Write(shader);
Emu.Pause();
}
//else ConLog.Write("Shader compiled successfully!");
}
void ShaderProgram::Delete()
{
for(u32 i=0; i<parr.params.GetCount(); ++i)
{
parr.params[i].names.Clear();
parr.params[i].type.Clear();
}
parr.params.Clear();
shader.Clear();
if(id)
{
glDeleteShader(id);
id = 0;
}
}

View File

@ -0,0 +1,146 @@
#pragma once
#include "ShaderParam.h"
struct FragmentDecompilerThread : public wxThread
{
union OPDEST
{
u32 HEX;
struct
{
u32 end : 1;
u32 dest_reg : 6;
u32 fp16 : 1;
u32 set_cond : 1;
u32 mask_x : 1;
u32 mask_y : 1;
u32 mask_z : 1;
u32 mask_w : 1;
u32 src_attr_reg_num : 4;
u32 tex_num : 4;
u32 exp_tex : 1;
u32 prec : 2;
u32 opcode : 6;
u32 no_dest : 1;
u32 saturate : 1;
};
} dst;
union SRC0
{
u32 HEX;
struct
{
u32 reg_type : 2;
u32 tmp_reg_index : 6;
u32 fp16 : 1;
u32 swizzle_x : 2;
u32 swizzle_y : 2;
u32 swizzle_z : 2;
u32 swizzle_w : 2;
u32 neg : 1;
u32 exec_if_le : 1;
u32 exec_if_eq : 1;
u32 exec_if_gr : 1;
u32 cond_swizzle_x : 2;
u32 cond_swizzle_y : 2;
u32 cond_swizzle_z : 2;
u32 cond_swizzle_w : 2;
u32 abs : 1;
};
} src0;
union SRC1
{
u32 HEX;
struct
{
u32 reg_type : 2;
u32 tmp_reg_index : 6;
u32 fp16 : 1;
u32 swizzle_x : 2;
u32 swizzle_y : 2;
u32 swizzle_z : 2;
u32 swizzle_w : 2;
u32 neg : 1;
u32 abs : 1;
u32 input_prec : 2;
u32 : 7;
u32 scale : 3;
u32 opcode_is_branch : 1;
};
} src1;
union SRC2
{
u32 HEX;
struct
{
u32 reg_type : 2;
u32 tmp_reg_index : 6;
u32 fp16 : 1;
u32 swizzle_x : 2;
u32 swizzle_y : 2;
u32 swizzle_z : 2;
u32 swizzle_w : 2;
u32 neg : 1;
u32 abs : 1;
u32 addr_reg : 11;
u32 use_index_reg : 1;
};
} src2;
wxString main;
wxString& m_shader;
ParamArray& m_parr;
u32 m_addr;
u32& m_size;
FragmentDecompilerThread(wxString& shader, ParamArray& parr, u32 addr, u32& size)
: wxThread(wxTHREAD_JOINABLE)
, m_shader(shader)
, m_parr(parr)
, m_addr(addr)
, m_size(size)
{
}
wxString GetMask();
void AddCode(wxString code, bool bkt = true);
wxString AddReg(u32 index);
wxString AddTex();
template<typename T> wxString GetSRC(T src);
wxString BuildCode();
ExitCode Entry();
u32 GetData(const u32 d) const { return d << 16 | d >> 16; }
};
struct ShaderProgram
{
ShaderProgram();
~ShaderProgram();
FragmentDecompilerThread* m_decompiler_thread;
ParamArray parr;
u32 size;
u32 addr;
wxString shader;
u32 id;
void Wait() { if(m_decompiler_thread && m_decompiler_thread->IsRunning()) m_decompiler_thread->Wait(); }
void Decompile();
void Compile();
void Delete();
};

View File

@ -0,0 +1,53 @@
#include "stdafx.h"
#include "GLBuffers.h"
#include "GLGSRender.h"
BufferObject::BufferObject()
: m_id(0)
, m_type(0)
{
}
BufferObject::BufferObject(u32 type)
: m_id(0)
, m_type(0)
{
Create(type);
}
void BufferObject::Create(u32 type)
{
if(m_id) return;
glGenBuffers(1, &m_id);
m_type = type;
}
void BufferObject::Delete()
{
if(!m_id) return;
glDeleteBuffers(1, &m_id);
m_id = 0;
m_type = 0;
}
void BufferObject::Bind()
{
if(m_id) glBindBuffer(m_type, m_id);
}
void BufferObject::UnBind()
{
glBindBuffer(m_type, 0);
}
void BufferObject::SetData(const void* data, u32 size, u32 type)
{
if(!m_type) return;
Bind();
glBufferData(m_type, size, data, type);
}
void VBO::Create()
{
BufferObject::Create(GL_ARRAY_BUFFER);
}

View File

@ -0,0 +1,24 @@
#pragma once
#include "OpenGL.h"
struct BufferObject
{
protected:
u32 m_id;
u32 m_type;
public:
BufferObject();
BufferObject(u32 type);
void Create(u32 type);
void Delete();
void Bind();
void UnBind();
void SetData(const void* data, u32 size, u32 type = GL_DYNAMIC_DRAW);
};
struct VBO : public BufferObject
{
void Create();
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,238 @@
#pragma once
#include "Emu/GS/GSRender.h"
#include "wx/glcanvas.h"
#include "GLBuffers.h"
#include "Program.h"
#include "OpenGL.h"
#pragma comment(lib, "opengl32.lib")
#pragma comment(lib, "gl.lib")
void checkForGlError(const char* situation);
class GLTexture
{
u32 m_width, m_height;
u32 m_id;
u32 m_offset;
bool m_enabled;
bool m_cubemap;
u8 m_dimension;
u32 m_format;
u16 m_mipmap;
public:
GLTexture()
: m_width(0), m_height(0),
m_id(0),
m_offset(0),
m_enabled(false),
m_cubemap(false),
m_dimension(0),
m_format(0),
m_mipmap(0)
{
}
void SetRect(const u32 width, const u32 height)
{
m_width = width;
m_height = height;
}
u32 GetOffset() const { return m_offset; }
void SetFormat(const bool cubemap, const u8 dimension, const u32 format, const u16 mipmap)
{
m_cubemap = cubemap;
m_dimension = dimension;
m_format = format;
m_mipmap = mipmap;
}
u32 GetFormat() const { return m_format; }
void SetOffset(const u32 offset)
{
m_offset = offset;
}
wxSize GetRect() const
{
return wxSize(m_width, m_height);
}
void Init()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if(!m_id)
{
glGenTextures(1, &m_id);
checkForGlError("GLTexture::Init() -> glGenTextures");
glBindTexture(GL_TEXTURE_2D, m_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
}
else
{
glBindTexture(GL_TEXTURE_2D, m_id);
}
//TODO: safe init
checkForGlError("GLTexture::Init() -> glBindTexture");
switch(m_format)
{
case 0xA1:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, GL_RED, GL_UNSIGNED_BYTE, Memory.GetMemFromAddr(m_offset));
checkForGlError("GLTexture::Init() -> glTexImage2D");
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_RED);
checkForGlError("GLTexture::Init() -> glTexParameteri");
break;
case 0xA5:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, Memory.GetMemFromAddr(m_offset));
checkForGlError("GLTexture::Init() -> glTexImage2D");
break;
default: ConLog.Error("Init tex error: Bad tex format (0x%x)", m_format); break;
}
//glBindTexture(GL_TEXTURE_2D, 0);
}
void Save(const wxString& name)
{
if(!m_id || !m_offset) return;
u8* data = new u8[m_width * m_height * 3];
u8* alpha = new u8[m_width * m_height];
u8* src = Memory.GetMemFromAddr(m_offset);
u8* dst = data;
u8* dst_a = alpha;
switch(m_format)
{
case 0xA1:
for(u32 y=0; y<m_height; ++y) for(u32 x=0; x<m_width; ++x)
{
*dst++ = *src;
*dst++ = *src;
*dst++ = *src;
*dst_a++ = *src;
src++;
}
break;
case 0xA5:
for(u32 y=0; y<m_height; ++y) for(u32 x=0; x<m_width; ++x)
{
*dst++ = *src++;
*dst++ = *src++;
*dst++ = *src++;
*dst_a++ = *src++;
}
break;
default: ConLog.Error("Save tex error: Bad tex format (0x%x)", m_format); break;
}
wxImage out;
out.Create(m_width, m_height, data, alpha);
out.SaveFile(name, wxBITMAP_TYPE_PNG);
//free(data);
//free(alpha);
}
void Save()
{
static const wxString& dir_path = "textures";
static const wxString& file_fmt = dir_path + "\\" + "tex[%d].png";
if(!wxDirExists(dir_path)) wxMkDir(dir_path);
u32 count = 0;
while(wxFileExists(wxString::Format(file_fmt, count))) count++;
Save(wxString::Format(file_fmt, count));
}
void Bind()
{
glBindTexture(GL_TEXTURE_2D, m_id);
}
void Enable(bool enable) { m_enabled = enable; }
bool IsEnabled() const { return m_enabled; }
};
struct GLGSFrame : public GSFrame
{
wxGLCanvas* canvas;
GLTexture m_textures[16];
u32 m_frames;
GLGSFrame();
~GLGSFrame() {}
void Flip();
wxGLCanvas* GetCanvas() const { return canvas; }
GLTexture& GetTexture(const u32 index) { return m_textures[index]; }
virtual void SetViewport(int x, int y, u32 w, u32 h);
private:
virtual void OnSize(wxSizeEvent& event);
};
extern gcmBuffer gcmBuffers[2];
struct GLRSXThread : public wxThread
{
wxWindow* m_parent;
Stack<u32> call_stack;
volatile bool m_paused;
GLRSXThread(wxWindow* parent);
virtual void OnExit();
void Start();
ExitCode Entry();
};
class GLGSRender
: public wxWindow
, public GSRender
{
private:
GLRSXThread* m_rsx_thread;
public:
GLGSFrame* m_frame;
volatile bool m_draw;
GLGSRender();
~GLGSRender();
private:
void Enable(bool enable, const u32 cap);
virtual void Init(const u32 ioAddress, const u32 ioSize, const u32 ctrlAddress, const u32 localAddress);
virtual void Draw();
virtual void Close();
virtual void Pause();
virtual void Resume();
public:
void DoCmd(const u32 fcmd, const u32 cmd, mem32_t& args, const u32 count);
};

View File

@ -0,0 +1,42 @@
OPENGL_PROC(PFNGLGENBUFFERSPROC,glGenBuffers);
OPENGL_PROC(PFNGLDELETEBUFFERSPROC, glDeleteBuffers);
OPENGL_PROC(PFNGLBINDBUFFERPROC, glBindBuffer);
OPENGL_PROC(PFNGLISBUFFERPROC, glIsBuffer);
OPENGL_PROC(PFNGLBUFFERDATAPROC, glBufferData);
OPENGL_PROC(PFNGLBUFFERSUBDATAPROC, glBufferSubData);
OPENGL_PROC(PFNGLGETBUFFERSUBDATAPROC, glGetBufferSubData);
OPENGL_PROC(PFNGLMAPBUFFERPROC, glMapBuffer);
OPENGL_PROC(PFNGLUNMAPBUFFERPROC, glUnmapBuffer);
OPENGL_PROC(PFNGLGETBUFFERPARAMETERIVPROC, glGetBufferParameteriv);
OPENGL_PROC(PFNGLGETBUFFERPOINTERVPROC, glGetBufferPointerv);
OPENGL_PROC(PFNGLBLENDFUNCSEPARATEPROC, glBlendFuncSeparate);
OPENGL_PROC(PFNGLBLENDEQUATIONSEPARATEPROC, glBlendEquationSeparate);
OPENGL_PROC(PFNGLBLENDCOLORPROC, glBlendColor);
OPENGL_PROC(PFNGLBLENDEQUATIONPROC, glBlendEquation);
OPENGL_PROC(PFNGLCREATESHADERPROC, glCreateShader);
OPENGL_PROC(PFNGLDELETESHADERPROC, glDeleteShader);
OPENGL_PROC(PFNGLCOMPILESHADERPROC, glCompileShader);
OPENGL_PROC(PFNGLSHADERSOURCEPROC, glShaderSource);
OPENGL_PROC(PFNGLGETSHADERIVPROC, glGetShaderiv);
OPENGL_PROC(PFNGLGETSHADERINFOLOGPROC, glGetShaderInfoLog);
OPENGL_PROC(PFNGLACTIVETEXTUREPROC, glActiveTexture);
OPENGL_PROC(PFNGLCREATEPROGRAMPROC, glCreateProgram);
OPENGL_PROC(PFNGLDELETEPROGRAMPROC, glDeleteProgram);
OPENGL_PROC(PFNGLATTACHSHADERPROC, glAttachShader);
OPENGL_PROC(PFNGLGETATTRIBLOCATIONPROC, glGetAttribLocation);
OPENGL_PROC(PFNGLLINKPROGRAMPROC, glLinkProgram);
OPENGL_PROC(PFNGLBINDFRAGDATALOCATIONPROC, glBindFragDataLocation);
OPENGL_PROC(PFNGLBINDATTRIBLOCATIONPROC, glBindAttribLocation);
OPENGL_PROC(PFNGLGETUNIFORMLOCATIONPROC, glGetUniformLocation);
OPENGL_PROC(PFNGLGETPROGRAMIVPROC, glGetProgramiv);
OPENGL_PROC(PFNGLGETPROGRAMINFOLOGPROC, glGetProgramInfoLog);
OPENGL_PROC(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer);
OPENGL_PROC(PFNGLENABLEVERTEXATTRIBARRAYPROC, glEnableVertexAttribArray);
OPENGL_PROC(PFNGLDISABLEVERTEXATTRIBARRAYPROC, glDisableVertexAttribArray);
OPENGL_PROC(PFNGLGENVERTEXARRAYSPROC, glGenVertexArrays);
OPENGL_PROC(PFNGLBINDVERTEXARRAYPROC, glBindVertexArray);
OPENGL_PROC(PFNGLDEPTHRANGEFPROC, glDepthRangef);
OPENGL_PROC(PFNGLUNIFORM1IPROC, glUniform1i);
OPENGL_PROC(PFNGLUNIFORM4FPROC, glUniform4f);
OPENGL_PROC(PFNGLUSEPROGRAMPROC, glUseProgram);

View File

@ -0,0 +1,13 @@
#include "stdafx.h"
#include "OpenGL.h"
void InitProcTable()
{
#define OPENGL_PROC(p, n) n = (p)wglGetProcAddress(#n)
#include "GLProcTable.tbl"
#undef OPENGL_PROC
}
#define OPENGL_PROC(p, n) p n = NULL
#include "GLProcTable.tbl"
#undef OPENGL_PROC

9
rpcs3/Emu/GS/GL/OpenGL.h Normal file
View File

@ -0,0 +1,9 @@
#pragma once
#include <GL/gl.h>
#include "GL/glext.h"
#define OPENGL_PROC(p, n) extern p n
#include "GLProcTable.tbl"
#undef OPENGL_PROC
void InitProcTable();

View File

@ -0,0 +1,93 @@
#include "stdafx.h"
#include "Program.h"
#include "GLGSRender.h"
Program::Program() : id(0)
{
}
bool Program::IsCreated() const
{
return id > 0;
}
void Program::Create(const u32 vp, const u32 fp)
{
if(IsCreated()) Delete();
id = glCreateProgram();
glAttachShader(id, vp);
glAttachShader(id, fp);
glBindFragDataLocation(id, 0, "r0");
static const wxString reg_table[] =
{
"in_pos", "in_weight", "in_normal",
"in_col0", "in_col1",
"in_fogc",
"in_6", "in_7",
"in_tc0", "in_tc1", "in_tc2", "in_tc3",
"in_tc4", "in_tc5", "in_tc6", "in_tc7"
};
for(u32 i=0; i<WXSIZEOF(reg_table); ++i)
{
glBindAttribLocation(id, i, reg_table[i]);
checkForGlError("glBindAttribLocation");
}
glLinkProgram(id);
GLint linkStatus = GL_FALSE;
glGetProgramiv(id, GL_LINK_STATUS, &linkStatus);
if(linkStatus != GL_TRUE)
{
GLint bufLength = 0;
glGetProgramiv(id, GL_INFO_LOG_LENGTH, &bufLength);
if (bufLength)
{
char* buf = new char[bufLength+1];
memset(buf, 0, bufLength+1);
glGetProgramInfoLog(id, bufLength, NULL, buf);
ConLog.Error("Could not link program: %s", buf);
delete[] buf;
}
}
//else ConLog.Write("program linked!");
glGetProgramiv(id, GL_VALIDATE_STATUS, &linkStatus);
if(linkStatus != GL_TRUE)
{
GLint bufLength = 0;
glGetProgramiv(id, GL_INFO_LOG_LENGTH, &bufLength);
if (bufLength)
{
char* buf = new char[bufLength];
memset(buf, 0, bufLength);
glGetProgramInfoLog(id, bufLength, NULL, buf);
ConLog.Error("Could not link program: %s", buf);
delete[] buf;
}
}
}
void Program::Use()
{
glUseProgram(id);
checkForGlError("glUseProgram");
}
void Program::SetTex(u32 index)
{
glUniform1i(glGetUniformLocation(id, wxString::Format("tex_%d", index)), index);
checkForGlError(wxString::Format("SetTex(%d)", index));
}
void Program::Delete()
{
if(!IsCreated()) return;
glDeleteProgram(id);
id = 0;
}

16
rpcs3/Emu/GS/GL/Program.h Normal file
View File

@ -0,0 +1,16 @@
#pragma once
#include "VertexProgram.h"
#include "FragmentProgram.h"
struct Program
{
u32 id;
Program();
bool IsCreated() const;
void Create(const u32 vp, const u32 fp);
void Use();
void SetTex(u32 index);
void Delete();
};

View File

@ -0,0 +1,117 @@
#include "stdafx.h"
#include "ProgramBuffer.h"
int ProgramBuffer::SearchFp(ShaderProgram& fp)
{
for(u32 i=0; i<m_buf.GetCount(); ++i)
{
if(memcmp(&m_buf[i].fp_data[0], &Memory[fp.addr], m_buf[i].fp_data.GetCount()) != 0) continue;
fp.id = m_buf[i].fp_id;
fp.shader = m_buf[i].fp_shader;
return i;
}
return -1;
}
int ProgramBuffer::SearchVp(VertexProgram& vp)
{
for(u32 i=0; i<m_buf.GetCount(); ++i)
{
if(m_buf[i].vp_data.GetCount() != vp.data.GetCount()) continue;
if(memcmp(&m_buf[i].vp_data[0], &vp.data[0], vp.data.GetCount() * 4) != 0) continue;
vp.id = m_buf[i].vp_id;
vp.shader = m_buf[i].vp_shader;
return i;
}
return -1;
}
bool ProgramBuffer::CmpVP(const u32 a, const u32 b) const
{
if(m_buf[a].vp_data.GetCount() != m_buf[b].vp_data.GetCount()) return false;
return memcmp(&m_buf[a].vp_data[0], &m_buf[b].vp_data[0], m_buf[a].vp_data.GetCount() * 4) == 0;
}
bool ProgramBuffer::CmpFP(const u32 a, const u32 b) const
{
if(m_buf[a].fp_data.GetCount() != m_buf[b].fp_data.GetCount()) return false;
return memcmp(&m_buf[a].fp_data[0], &m_buf[b].fp_data[0], m_buf[a].fp_data.GetCount()) == 0;
}
u32 ProgramBuffer::GetProg(u32 fp, u32 vp) const
{
if(fp == vp) return m_buf[fp].prog_id;
for(u32 i=0; i<m_buf.GetCount(); ++i)
{
if(i == fp || i == vp) continue;
if(CmpVP(vp, i) && CmpFP(fp, i))
{
ConLog.Write("Get program (%d):", i);
ConLog.Write("*** prog id = %d", m_buf[i].prog_id);
ConLog.Write("*** vp id = %d", m_buf[i].vp_id);
ConLog.Write("*** fp id = %d", m_buf[i].fp_id);
ConLog.Write("*** vp shader = %s\n", m_buf[i].vp_shader);
ConLog.Write("*** fp shader = %s\n", m_buf[i].fp_shader);
return m_buf[i].prog_id;
}
}
return 0;
}
void ProgramBuffer::Add(Program& prog, ShaderProgram& fp, VertexProgram& vp)
{
const u32 pos = m_buf.GetCount();
m_buf.Add(new BufferInfo());
BufferInfo& new_buf = m_buf[pos];
ConLog.Write("Add program (%d):", pos);
ConLog.Write("*** prog id = %d", prog.id);
ConLog.Write("*** vp id = %d", vp.id);
ConLog.Write("*** fp id = %d", fp.id);
ConLog.Write("*** vp data size = %d", vp.data.GetCount() * 4);
ConLog.Write("*** fp data size = %d", fp.size);
ConLog.Write("*** vp shader = %s\n", vp.shader);
ConLog.Write("*** fp shader = %s\n", fp.shader);
new_buf.prog_id = prog.id;
new_buf.vp_id = vp.id;
new_buf.fp_id = fp.id;
new_buf.fp_data.SetCount(fp.size);
memcpy(&new_buf.fp_data[0], &Memory[fp.addr], fp.size);
new_buf.vp_data.SetCount(vp.data.GetCount());
memcpy(&new_buf.vp_data[0], &vp.data[0], vp.data.GetCount() * 4);
new_buf.vp_shader = vp.shader;
new_buf.fp_shader = fp.shader;
}
void ProgramBuffer::Clear()
{
for(u32 i=0; i<m_buf.GetCount(); ++i)
{
glDeleteProgram(m_buf[i].prog_id);
glDeleteShader(m_buf[i].fp_id);
glDeleteShader(m_buf[i].vp_id);
m_buf[i].fp_data.Clear();
m_buf[i].vp_data.Clear();
m_buf[i].vp_shader.Clear();
m_buf[i].fp_shader.Clear();
}
m_buf.Clear();
}

View File

@ -0,0 +1,29 @@
#pragma once
#include "Program.h"
struct BufferInfo
{
u32 prog_id;
u32 fp_id;
u32 vp_id;
Array<u8> fp_data;
Array<u32> vp_data;
wxString fp_shader;
wxString vp_shader;
};
struct ProgramBuffer
{
Array<BufferInfo> m_buf;
int SearchFp(ShaderProgram& fp);
int SearchVp(VertexProgram& vp);
bool CmpVP(const u32 a, const u32 b) const;
bool CmpFP(const u32 a, const u32 b) const;
u32 GetProg(u32 fp, u32 vp) const;
void Add(Program& prog, ShaderProgram& fp, VertexProgram& vp);
void Clear();
};

View File

@ -0,0 +1,78 @@
#pragma once
#include "OpenGL.h"
enum ParamFlag
{
PARAM_IN,
PARAM_OUT,
PARAM_CONST,
PARAM_NONE,
};
struct ParamType
{
const ParamFlag flag;
wxString type;
wxArrayString names;
ParamType(const ParamFlag _flag, const wxString& _type)
: type(_type)
, flag(_flag)
{
}
bool SearchName(const wxString& name)
{
for(u32 i=0; i<names.GetCount(); ++i)
{
if(names[i].Cmp(name) == 0) return true;
}
return false;
}
};
struct ParamArray
{
Array<ParamType> params;
ParamType* SearchParam(const wxString& type)
{
for(u32 i=0; i<params.GetCount(); ++i)
{
if(params[i].type.Cmp(type) == 0) return &params[i];
}
return NULL;
}
wxString GetParamFlag(const ParamFlag flag)
{
switch(flag)
{
case PARAM_OUT: return "out ";
case PARAM_IN: return "in ";
case PARAM_CONST: return "uniform ";
}
return wxEmptyString;
}
wxString AddParam(const ParamFlag flag, wxString type, const wxString& name)
{
type = GetParamFlag(flag) + type;
ParamType* t = SearchParam(type);
if(t)
{
if(!t->SearchName(name)) t->names.Add(name);
}
else
{
const u32 num = params.GetCount();
params.Add(new ParamType(flag, type));
params[num].names.Add(name);
}
return name;
}
};

View File

@ -0,0 +1,362 @@
#include "stdafx.h"
#include "VertexProgram.h"
wxString VertexDecompilerThread::GetMask()
{
wxString ret = wxEmptyString;
if(d3.vec_writemask_x) ret += "x";
if(d3.vec_writemask_y) ret += "y";
if(d3.vec_writemask_z) ret += "z";
if(d3.vec_writemask_w) ret += "w";
return ret.IsEmpty() || ret == "xyzw" ? wxEmptyString : ("." + ret);
}
wxString VertexDecompilerThread::GetDST()
{
static const wxString reg_table[] =
{
"gl_Position",
"col0", "col1",
"bfc0", "bfc1",
"fogc",
"gl_Pointsize",
"tc0", "tc1", "tc2", "tc3", "tc4", "tc5", "tc6", "tc7"
};
wxString ret = wxEmptyString;
switch(d3.dst)
{
case 0x0: case 0x6:
ret += reg_table[d3.dst];
break;
case 0x1f:
ret += m_parr.AddParam(PARAM_NONE, "vec4", wxString::Format("tmp%d", d0.dst_tmp));
break;
default:
if(d3.dst < WXSIZEOF(reg_table))
{
ret += m_parr.AddParam(PARAM_OUT, "vec4", reg_table[d3.dst]);
}
else
{
ConLog.Error("Bad dst reg num: %d", d3.dst);
ret += m_parr.AddParam(PARAM_OUT, "vec4", "unk");
}
break;
}
return ret;
}
wxString VertexDecompilerThread::GetSRC(const u32 n)
{
static const wxString reg_table[] =
{
"in_pos", "in_weight", "in_normal",
"in_col0", "in_col1",
"in_fogc",
"in_6", "in_7",
"in_tc0", "in_tc1", "in_tc2", "in_tc3",
"in_tc4", "in_tc5", "in_tc6", "in_tc7"
};
wxString ret = wxEmptyString;
switch(src[n].reg_type)
{
case 1: //temp
ret += m_parr.AddParam(PARAM_NONE, "vec4", wxString::Format("tmp%d", src[n].tmp_src));
break;
case 2: //input
if(d1.input_src < WXSIZEOF(reg_table))
{
ret += m_parr.AddParam(PARAM_IN, "vec4", reg_table[d1.input_src]);
}
else
{
ConLog.Error("Bad input src num: %d", d1.input_src);
ret += m_parr.AddParam(PARAM_IN, "vec4", "in_unk");
}
break;
case 3: //const
ret += m_parr.AddParam(PARAM_CONST, "vec4", wxString::Format("vc%d", d1.const_src));
break;
default:
ConLog.Error("Bad src%d reg type: %d", n, src[n].reg_type);
Emu.Pause();
break;
}
static const char f[4] = {'x', 'z', 'w', 'y'};
wxString swizzle = wxEmptyString;
swizzle += f[src[n].swz_x];
swizzle += f[src[n].swz_y];
swizzle += f[src[n].swz_z];
swizzle += f[src[n].swz_w];
if(swizzle != "xyzw") ret += "." + swizzle;
bool abs;
switch(n)
{
case 0: abs = d0.src0_abs; break;
case 1: abs = d0.src1_abs; break;
case 2: abs = d0.src2_abs; break;
}
if(abs) ret = "abs(" + ret + ")";
if(src[n].neg) ret = "-" + ret;
return ret;
}
void VertexDecompilerThread::AddCode(wxString code, bool bkt, bool src_mask)
{
if(d0.cond == 0) return;
if(d0.cond != 7)
{
ConLog.Error("Bad cond! %d", d0.cond);
Emu.Pause();
return;
}
if(src_mask)
{
code = GetDST() + GetMask() + " = " + (bkt ? "(" + code + ")" : code) + GetMask();
}
else
{
code = GetDST() + GetMask() + " = " + (bkt ? "(" + code + ")" : code);
}
main += "\t" + code + ";\n";
}
wxString VertexDecompilerThread::BuildCode()
{
wxString p = wxEmptyString;
for(u32 i=0; i<m_parr.params.GetCount(); ++i)
{
for(u32 n=0; n<m_parr.params[i].names.GetCount(); ++n)
{
p += m_parr.params[i].type;
p += " ";
p += m_parr.params[i].names[n];
p += ";\n";
}
}
static const wxString& prot =
"#version 330 core\n"
"\n"
"%s\n"
"void main()\n{\n%s}\n";
return wxString::Format(prot, p, main);
}
wxThread::ExitCode VertexDecompilerThread::Entry()
{
for(u32 i=0;;)
{
d0.HEX = m_data[i++];
d1.HEX = m_data[i++];
d2.HEX = m_data[i++];
d3.HEX = m_data[i++];
src[0].HEX = d2.src0l | (d1.src0h << 9);
src[1].HEX = d2.src1;
src[2].HEX = d3.src2l | (d2.src2h << 11);
switch(d1.vec_opcode)
{
case 0x00: break; //NOP
case 0x01: AddCode(GetSRC(0), false); break; //MOV
case 0x02: AddCode(GetSRC(0) + " * " + GetSRC(1)); break; //MUL
case 0x03: AddCode(GetSRC(0) + " + " + GetSRC(1)); break; //ADD
case 0x04: AddCode(GetSRC(0) + " * " + GetSRC(1) + " + " + GetSRC(2)); break; //MAD
case 0x05: AddCode("dot(" + GetSRC(0) + ".xyz, " + GetSRC(1) + ".xyz).xxx"); break; //DP3
//case 0x06: TODO //DPH
case 0x07: AddCode("dot(" + GetSRC(0) + ", " + GetSRC(1) + ").xxxx"); break; //DP4
case 0x08: AddCode("distance(" + GetSRC(0) + ", " + GetSRC(1) + ")", false); break; //DST
case 0x09: AddCode("min(" + GetSRC(0) + ", " + GetSRC(1) + ")", false); break; //MAX
case 0x0a: AddCode("max(" + GetSRC(0) + ", " + GetSRC(1) + ")", false); break; //MAX
case 0x0b: AddCode("lessThan(" + GetSRC(0) + ", " + GetSRC(1) + ")", false); break; //SLT
case 0x0c: AddCode("greaterThanEqual(" + GetSRC(0) + ", " + GetSRC(1) + ")", false); break; //SGE
case 0x0e: AddCode("fract(" + GetSRC(0) + ")", false); break; //FRC
case 0x0f: AddCode("floor(" + GetSRC(0) + ")", false); break; //FLR
case 0x10: AddCode("equal(" + GetSRC(0) + ", " + GetSRC(1) + ")", false); break; //SEQ
case 0x11: AddCode("vec4(0.0f, 0.0f, 0.0f, 0.0f)", false); break; //SFL
case 0x12: AddCode("greaterThan(" + GetSRC(0) + ", " + GetSRC(1) + ")", false); break; //SGT
case 0x13: AddCode("lessThanEqual(" + GetSRC(0) + ", " + GetSRC(1) + ")", false); break; //SLE
case 0x14: AddCode("notEqual(" + GetSRC(0) + ", " + GetSRC(1) + ")", false); break; //SNE
case 0x15: AddCode("vec4(1.0f, 1.0f, 1.0f, 1.0f)", false); break; //STR
case 0x16: AddCode("sign(" + GetSRC(0) + ", " + GetSRC(1) + ")", false); break; //SSG
default:
ConLog.Error("Unknown vp opcode 0x%x", d1.vec_opcode);
Emu.Pause();
break;
}
if(d3.end) break;
}
m_shader = BuildCode();
main = wxEmptyString;
return (ExitCode)0;
}
VertexProgram::VertexProgram()
: m_decompiler_thread(NULL)
, id(0)
{
}
VertexProgram::~VertexProgram()
{
if(m_decompiler_thread)
{
Wait();
if(m_decompiler_thread->IsAlive()) m_decompiler_thread->Delete();
safe_delete(m_decompiler_thread);
}
Delete();
}
void VertexProgram::Decompile()
{
#if 0
VertexDecompilerThread(data, shader, parr).Entry();
#else
if(m_decompiler_thread)
{
Wait();
if(m_decompiler_thread->IsAlive()) m_decompiler_thread->Delete();
safe_delete(m_decompiler_thread);
}
m_decompiler_thread = new VertexDecompilerThread(data, shader, parr);
m_decompiler_thread->Create();
m_decompiler_thread->Run();
#endif
}
void VertexProgram::Compile()
{
if(id) glDeleteShader(id);
id = glCreateShader(GL_VERTEX_SHADER);
const char* str = shader.c_str();
const int strlen = shader.Len();
glShaderSource(id, 1, &str, &strlen);
glCompileShader(id);
GLint r = GL_FALSE;
glGetShaderiv(id, GL_COMPILE_STATUS, &r);
if(r != GL_TRUE)
{
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &r);
if(r)
{
char* buf = new char[r+1];
GLsizei len;
memset(buf, 0, r+1);
glGetShaderInfoLog(id, r, &len, buf);
ConLog.Error("Failed to compile vertex shader: %s", buf);
free(buf);
}
ConLog.Write(shader);
Emu.Pause();
}
//else ConLog.Write("Vertex shader compiled successfully!");
}
void VertexProgram::Delete()
{
data.Clear();
for(u32 i=0; i<parr.params.GetCount(); ++i)
{
parr.params[i].names.Clear();
parr.params[i].type.Clear();
}
parr.params.Clear();
constants4.Clear();
shader.Clear();
if(id)
{
glDeleteShader(id);
id = 0;
}
}
void VertexData::Load(u32 start, u32 count)
{
const u32 tsize = GetTypeSize();
data.SetCount((start + count) * tsize * size);
for(u32 i=start; i<start + count; ++i)
{
const u8* src = Memory.GetMemFromAddr(addr) + stride * i;
u8* dst = &data[i * tsize * size];
switch(tsize)
{
case 1:
{
memcpy(dst, src, size);
}
break;
case 2:
{
const u16* c_src = (const u16*)src;
u16* c_dst = (u16*)dst;
for(u32 j=0; j<size; ++j) *c_dst++ = re(*c_src++);
}
break;
case 4:
{
const u32* c_src = (const u32*)src;
u32* c_dst = (u32*)dst;
for(u32 j=0; j<size; ++j) *c_dst++ = re(*c_src++);
}
break;
}
}
}
u32 VertexData::GetTypeSize()
{
switch (type)
{
case 1: return 2;
case 2: return 4;
case 3: return 2;
case 4: return 1;
case 5: return 2;
case 7: return 1;
}
ConLog.Error("Bad vertex data type! %d", type);
return 1;
}

View File

@ -0,0 +1,177 @@
#pragma once
#include "ShaderParam.h"
struct VertexDecompilerThread : public wxThread
{
union D0
{
u32 HEX;
struct
{
u32 addr_swz : 2;
u32 mask_w : 2;
u32 mask_z : 2;
u32 mask_y : 2;
u32 mask_x : 2;
u32 cond : 3;
u32 cond_test_enable : 1;
u32 cond_update_enable_0 : 1;
u32 dst_tmp : 6;
u32 src0_abs : 1;
u32 src1_abs : 1;
u32 src2_abs : 1;
u32 addr_reg_sel_1 : 1;
u32 cond_reg_sel_1 : 1;
u32 staturate : 1;
u32 index_input : 1;
u32 : 1;
u32 cond_update_enable_1 : 1;
u32 vec_result : 1;
u32 : 1;
};
} d0;
union D1
{
u32 HEX;
struct
{
u32 src0h : 8;
u32 input_src : 4;
u32 const_src : 10;
u32 vec_opcode : 5;
u32 sca_opcode : 5;
};
} d1;
union D2
{
u32 HEX;
struct
{
u32 src2h : 6;
u32 src1 : 17;
u32 src0l : 9;
};
struct
{
u32 iaddrh : 6;
u32 : 26;
};
} d2;
union D3
{
u32 HEX;
struct
{
u32 end : 1;
u32 index_const : 1;
u32 dst : 5;
u32 sca_dst : 5;
u32 sca_result : 1;
u32 vec_writemask_w : 1;
u32 vec_writemask_z : 1;
u32 vec_writemask_y : 1;
u32 vec_writemask_x : 1;
u32 sca_writemask_w : 1;
u32 sca_writemask_z : 1;
u32 sca_writemask_y : 1;
u32 sca_writemask_x : 1;
u32 src2l : 11;
};
struct
{
u32 : 29;
u32 iaddrl : 3;
};
} d3;
union SRC
{
u16 HEX;
struct
{
u16 reg_type : 2;
u16 tmp_src : 5;
u16 swz_w : 2;
u16 swz_z : 2;
u16 swz_y : 2;
u16 swz_x : 2;
u16 neg : 1;
};
} src[3];
wxString main;
wxString& m_shader;
Array<u32>& m_data;
ParamArray& m_parr;
VertexDecompilerThread(Array<u32>& data, wxString& shader, ParamArray& parr)
: wxThread(wxTHREAD_JOINABLE)
, m_data(data)
, m_shader(shader)
, m_parr(parr)
{
}
wxString GetMask();
wxString GetDST();
wxString GetSRC(const u32 n);
void AddCode(wxString code, bool bkt = true, bool src_mask = true);
wxString BuildCode();
ExitCode Entry();
};
struct VertexProgram
{
wxString shader;
u32 id;
VertexDecompilerThread* m_decompiler_thread;
VertexProgram();
~VertexProgram();
struct Constant4
{
u32 id;
float x, y, z, w;
};
Array<Constant4> constants4;
Array<u32> data;
ParamArray parr;
void Wait() { if(m_decompiler_thread && m_decompiler_thread->IsRunning()) m_decompiler_thread->Wait(); }
void Decompile();
void Compile();
void Delete();
};
struct VertexData
{
u32 index;
u32 frequency;
u32 stride;
u32 size;
u32 type;
u32 addr;
Array<u8> data;
VertexData() { memset(this, 0, sizeof(*this)); }
~VertexData() { data.Clear(); }
bool IsEnabled() { return size > 0; }
void Load(u32 start, u32 count);
u32 GetTypeSize();
};

View File

@ -0,0 +1,45 @@
#include "stdafx.h"
#include "GSManager.h"
#include "Null/NullGSRender.h"
#include "GL/GLGSRender.h"
BEGIN_EVENT_TABLE(GSFrame, wxFrame)
EVT_PAINT(GSFrame::OnPaint)
EVT_SIZE(GSFrame::OnSize)
END_EVENT_TABLE()
GSManager::GSManager() : m_render(NULL)
{
}
void GSManager::Init()
{
if(m_render) return;
switch(Ini.GSRenderMode.GetValue())
{
default:
case 0: m_render = new NullGSRender(); break;
case 1: m_render = new GLGSRender(); break;
}
//m_render->Init(GetInfo().outresolution.width, GetInfo().outresolution.height);
}
void GSManager::Close()
{
if(m_render)
{
m_render->Close();
//free(m_render);
}
m_render = NULL;
}
u8 GSManager::GetState()
{
return CELL_VIDEO_OUT_OUTPUT_STATE_ENABLED;
}
u8 GSManager::GetColorSpace()
{
return CELL_VIDEO_OUT_COLOR_SPACE_RGB;
}

54
rpcs3/Emu/GS/GSManager.h Normal file
View File

@ -0,0 +1,54 @@
#pragma once
#include "sysutil_video.h"
#include "GSRender.h"
struct GSInfo
{
CellVideoOutResolution outresolution;
CellVideoOutDisplayMode mode;
GSInfo()
{
outresolution.width = 740;
outresolution.height = 480;
mode.resolutionId = CELL_VIDEO_OUT_RESOLUTION_576;
mode.scanMode = CELL_VIDEO_OUT_SCAN_MODE_INTERLACE;
mode.conversion = CELL_VIDEO_OUT_DISPLAY_CONVERSION_NONE;
mode.aspect = CELL_VIDEO_OUT_ASPECT_4_3;
mode.refreshRates = CELL_VIDEO_OUT_REFRESH_RATE_50HZ;
}
};
struct gcmBuffer
{
u32 offset;
u32 pitch;
u32 width;
u32 height;
bool update;
gcmBuffer() : update(false)
{
}
};
extern gcmBuffer gcmBuffers[2];
class GSManager
{
GSInfo m_info;
GSRender* m_render;
public:
GSManager();
void Init();
void Close();
GSInfo& GetInfo() { return m_info; }
GSRender& GetRender() { return *m_render; }
u8 GetState();
u8 GetColorSpace();
};

94
rpcs3/Emu/GS/GSRender.cpp Normal file
View File

@ -0,0 +1,94 @@
#include "stdafx.h"
#include "GSRender.h"
wxSize AspectRatio(wxSize rs, const wxSize as)
{
const double aq = (double)as.x / as.y;
const double rq = (double)rs.x / rs.y;
const double q = aq / rq;
if(q > 1.0)
{
rs.y /= q;
}
else if(q < 1.0)
{
rs.x *= q;
}
return rs;
}
GSFrame::GSFrame(wxWindow* parent, const wxString& title) : wxFrame(parent, wxID_ANY, title)
{
SetClientSize(720, 576);
//Connect(wxEVT_LEFT_DCLICK, wxMouseEventHandler(GSFrame::OnLeftDclick));
wxGetApp().Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(GSFrame::OnKeyDown), (wxObject*)0, this);
wxGetApp().Connect(GetId(), wxEVT_CLOSE_WINDOW, wxCloseEventHandler(GSFrame::OnClose), (wxObject*)0, this);
}
void GSFrame::OnPaint(wxPaintEvent& event)
{
wxPaintDC(this);
}
void GSFrame::OnClose(wxCloseEvent& event)
{
Emu.Stop();
}
/*
void GSFrame::OnSize(wxSizeEvent&)
{
const wxSize client = GetClientSize();
const wxSize viewport = AspectRatio(client, m_size);
const int x = (client.GetX() - viewport.GetX()) / 2;
const int y = (client.GetY() - viewport.GetY()) / 2;
SetViewport(wxPoint(x, y), viewport);
}
*/
void GSFrame::OnKeyDown(wxKeyEvent& event)
{
switch(event.GetKeyCode())
{
case WXK_RETURN: if(event.ControlDown()) { OnFullScreen(); return; } break;
case WXK_ESCAPE: if(IsFullScreen()) { ShowFullScreen(false); return; } break;
}
event.Skip();
}
void GSFrame::OnFullScreen()
{
ShowFullScreen(!IsFullScreen());
}
/*
void GSFrame::SetSize(int width, int height)
{
m_size.SetWidth(width);
m_size.SetHeight(height);
//wxFrame::SetSize(width, height);
OnSize(wxSizeEvent());
}
*/
GSRender::GSRender()
: m_ctrl(NULL)
, m_flip_status(-1)
{
}
u32 GSRender::GetAddress(u32 offset, u8 location)
{
switch(location)
{
case CELL_GCM_LOCATION_LOCAL: return Memory.RSXFBMem.GetStartAddr() + offset;
case CELL_GCM_LOCATION_MAIN: return offset;
}
return 0;
}

47
rpcs3/Emu/GS/GSRender.h Normal file
View File

@ -0,0 +1,47 @@
#pragma once
#include "Emu/GS/GCM.h"
wxSize AspectRatio(wxSize rs, const wxSize as);
class GSFrame : public wxFrame
{
protected:
GSFrame(wxWindow* parent, const wxString& title);
virtual void SetViewport(int x, int y, u32 w, u32 h) {}
virtual void OnPaint(wxPaintEvent& event);
virtual void OnClose(wxCloseEvent& event);
//virtual void OnSize(wxSizeEvent&);
void OnLeftDclick(wxMouseEvent&)
{
OnFullScreen();
}
void OnKeyDown(wxKeyEvent& event);
void OnFullScreen();
public:
//void SetSize(int width, int height);
private:
DECLARE_EVENT_TABLE();
};
struct GSRender
{
u32 m_ioAddress, m_ioSize, m_ctrlAddress, m_localAddress;
CellGcmControl* m_ctrl;
int m_flip_status;
GSRender();
virtual void Init(const u32 ioAddress, const u32 ioSize, const u32 ctrlAddress, const u32 localAddress)=0;
virtual void Draw()=0;
virtual void Close()=0;
virtual void Pause()=0;
virtual void Resume()=0;
u32 GetAddress(u32 offset, u8 location);
};

View File

@ -0,0 +1,118 @@
#pragma once
#include "Emu/GS/GSRender.h"
struct NullGSFrame : public GSFrame
{
NullGSFrame() : GSFrame(NULL, "GSFrame[Null]")
{
}
void Draw() { Draw(wxClientDC(this)); }
private:
virtual void OnPaint(wxPaintEvent& event) { Draw(wxPaintDC(this)); }
virtual void OnSize(wxSizeEvent& event)
{
GSFrame::OnSize(event);
Draw();
}
void Draw(wxDC& dc)
{
dc.DrawText("Null GS output", 0, 0);
}
};
class NullGSRender
: public wxWindow
, public GSRender
{
private:
NullGSFrame* m_frame;
wxTimer* m_update_timer;
bool m_paused;
public:
NullGSRender()
: m_frame(NULL)
, m_paused(false)
{
m_update_timer = new wxTimer(this);
Connect(m_update_timer->GetId(), wxEVT_TIMER, wxTimerEventHandler(NullGSRender::OnTimer));
m_frame = new NullGSFrame();
}
~NullGSRender()
{
Close();
m_frame->Close();
}
private:
virtual void Init(const u32 ioAddress, const u32 ioSize, const u32 ctrlAddress, const u32 localAddress)
{
if(m_frame->IsShown()) return;
m_frame->SetSize(740, 480);
m_frame->Show();
m_ioAddress = ioAddress;
m_ctrlAddress = ctrlAddress;
m_ioSize = ioSize;
m_localAddress = localAddress;
m_ctrl = (CellGcmControl*)Memory.GetMemFromAddr(m_ctrlAddress);
m_update_timer->Start(1);
}
void OnTimer(wxTimerEvent&)
{
while(!m_paused && m_ctrl->get != m_ctrl->put && Emu.IsRunned())
{
const u32 get = re(m_ctrl->get);
const u32 cmd = Memory.Read32(m_ioAddress + get);
const u32 count = (cmd >> 18) & 0x7ff;
mem32_t data(m_ioAddress + get + 4);
m_ctrl->get = re32(get + (count + 1) * 4);
DoCmd(cmd, cmd & 0x3ffff, data, count);
memset(Memory.GetMemFromAddr(m_ioAddress + get), 0, (count + 1) * 4);
}
}
void DoCmd(const u32 fcmd, const u32 cmd, mem32_t& args, const u32 count)
{
switch(cmd)
{
case NV406E_SET_REFERENCE:
m_ctrl->ref = re32(args[0]);
break;
case NV4097_SET_BEGIN_END:
if(!args[0]) m_flip_status = 0;
break;
}
}
virtual void Draw()
{
//if(m_frame && !m_frame->IsBeingDeleted()) m_frame->Draw();
}
virtual void Close()
{
m_update_timer->Stop();
if(m_frame->IsShown()) m_frame->Hide();
m_ctrl = NULL;
}
void Pause()
{
m_paused = true;
}
void Resume()
{
m_paused = false;
}
};

View File

@ -0,0 +1,84 @@
#include "stdafx.h"
#include "RSXThread.h"
enum MethodFlag
{
CELL_GCM_METHOD_FLAG_NON_INCREMENT = 0x40000000,
CELL_GCM_METHOD_FLAG_JUMP = 0x20000000,
CELL_GCM_METHOD_FLAG_CALL = 0x00000002,
CELL_GCM_METHOD_FLAG_RETURN = 0x00020000,
};
RSXThread::RSXThread(
CellGcmControl* ctrl,
u32 ioAddress,
void (&cmd)(const u32 fcmd, const u32 cmd, mem32_t& args, const u32 count),
bool (&_flip)(),
bool (&_TestExit)()
)
: m_ctrl(*ctrl)
, m_ioAddress(ioAddress)
, DoCmd(cmd)
, flip(_flip)
, TestExit(_TestExit)
{
}
void RSXThread::Task()
{
while(!TestDestroy() && !TestExit())
{
if(m_ctrl.get == m_ctrl.put)
{
flip();
Sleep(1);
continue;
}
const u32 get = re(m_ctrl.get);
const u32 cmd = Memory.Read32(m_ioAddress + get);
const u32 count = (cmd >> 18) & 0x7ff;
mem32_t data(m_ioAddress + get + 4);
if(cmd & CELL_GCM_METHOD_FLAG_JUMP)
{
m_ctrl.get = re32(cmd & ~(CELL_GCM_METHOD_FLAG_JUMP | CELL_GCM_METHOD_FLAG_NON_INCREMENT));
continue;
}
if(cmd & CELL_GCM_METHOD_FLAG_CALL)
{
call_stack.AddCpy(get + 4);
m_ctrl.get = re32(cmd & ~CELL_GCM_METHOD_FLAG_CALL);
continue;
}
if(cmd & CELL_GCM_METHOD_FLAG_RETURN)
{
const u32 pos = call_stack.GetCount() - 1;
m_ctrl.get = re32(call_stack[pos]);
call_stack.RemoveAt(pos);
continue;
}
if(cmd & CELL_GCM_METHOD_FLAG_NON_INCREMENT)
{
//ConLog.Warning("non increment cmd! 0x%x", cmd);
}
#if 0
wxString debug = getMethodName(cmd & 0x3ffff);
debug += "(";
for(u32 i=0; i<count; ++i) debug += (i ? ", " : "") + wxString::Format("0x%x", data[i]);
debug += ")";
ConLog.Write(debug);
#endif
DoCmd(cmd, cmd & 0x3ffff, data, count);
m_ctrl.get = re32(get + (count + 1) * 4);
memset(Memory.GetMemFromAddr(m_ioAddress + get), 0, (count + 1) * 4);
}
}
void RSXThread::OnExit()
{
call_stack.Clear();
}

25
rpcs3/Emu/GS/RSXThread.h Normal file
View File

@ -0,0 +1,25 @@
#pragma once
#include "GCM.h"
class RSXThread : public ThreadBase
{
Array<u32> call_stack;
void (&DoCmd)(const u32 fcmd, const u32 cmd, mem32_t& args, const u32 count);
bool (&flip)();
bool (&TestExit)();
CellGcmControl& m_ctrl;
u32 m_ioAddress;
protected:
RSXThread(
CellGcmControl* ctrl,
u32 ioAddress,
void (&cmd)(const u32 fcmd, const u32 cmd, mem32_t& args, const u32 count),
bool (&_flip)(),
bool (&_TestExit)()
);
private:
virtual void Task();
virtual void OnExit();
};

View File

@ -0,0 +1,223 @@
#pragma once
enum VideoErrorCode
{
CELL_VIDEO_OUT_SUCCEEDED = 0,
CELL_VIDEO_OUT_ERROR_NOT_IMPLEMENTED = 0x8002b220,
CELL_VIDEO_OUT_ERROR_ILLEGAL_CONFIGURATION = 0x8002b221,
CELL_VIDEO_OUT_ERROR_ILLEGAL_PARAMETER = 0x8002b222,
CELL_VIDEO_OUT_ERROR_PARAMETER_OUT_OF_RANGE = 0x8002b223,
CELL_VIDEO_OUT_ERROR_DEVICE_NOT_FOUND = 0x8002b224,
CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT = 0x8002b225,
CELL_VIDEO_OUT_ERROR_UNSUPPORTED_DISPLAY_MODE = 0x8002b226,
CELL_VIDEO_OUT_ERROR_CONDITION_BUSY = 0x8002b227,
CELL_VIDEO_OUT_ERROR_VALUE_IS_NOT_SET = 0x8002b228,
};
enum CellVideoOut
{
CELL_VIDEO_OUT_PRIMARY,
CELL_VIDEO_OUT_SECONDARY,
};
enum CellVideoOutResolutionId
{
CELL_VIDEO_OUT_RESOLUTION_UNDEFINED = 0,
CELL_VIDEO_OUT_RESOLUTION_1080 = 1,
CELL_VIDEO_OUT_RESOLUTION_720 = 2,
CELL_VIDEO_OUT_RESOLUTION_480 = 4,
CELL_VIDEO_OUT_RESOLUTION_576 = 5,
CELL_VIDEO_OUT_RESOLUTION_1600x1080 = 10,
CELL_VIDEO_OUT_RESOLUTION_1440x1080 = 11,
CELL_VIDEO_OUT_RESOLUTION_1280x1080 = 12,
CELL_VIDEO_OUT_RESOLUTION_960x1080 = 13,
CELL_VIDEO_OUT_RESOLUTION_720_3D_FRAME_PACKING = 0x81,
CELL_VIDEO_OUT_RESOLUTION_1024x720_3D_FRAME_PACKING = 0x88,
CELL_VIDEO_OUT_RESOLUTION_960x720_3D_FRAME_PACKING = 0x89,
CELL_VIDEO_OUT_RESOLUTION_800x720_3D_FRAME_PACKING = 0x8a,
CELL_VIDEO_OUT_RESOLUTION_640x720_3D_FRAME_PACKING = 0x8b,
};
enum CellVideoOutScanMode
{
CELL_VIDEO_OUT_SCAN_MODE_INTERLACE,
CELL_VIDEO_OUT_SCAN_MODE_PROGRESSIVE,
};
enum CellVideoOutScanMode2
{
CELL_VIDEO_OUT_SCAN_MODE2_AUTO,
CELL_VIDEO_OUT_SCAN_MODE2_INTERLACE,
CELL_VIDEO_OUT_SCAN_MODE2_PROGRESSIVE,
};
enum CellVideoOutRefreshRate
{
CELL_VIDEO_OUT_REFRESH_RATE_AUTO = 0x0000,
CELL_VIDEO_OUT_REFRESH_RATE_59_94HZ = 0x0001,
CELL_VIDEO_OUT_REFRESH_RATE_50HZ = 0x0002,
CELL_VIDEO_OUT_REFRESH_RATE_60HZ = 0x0004,
CELL_VIDEO_OUT_REFRESH_RATE_30HZ = 0x0008
};
enum CellVideoOutPortType
{
CELL_VIDEO_OUT_PORT_NONE = 0x00,
CELL_VIDEO_OUT_PORT_HDMI = 0x01,
CELL_VIDEO_OUT_PORT_NETWORK = 0x41,
CELL_VIDEO_OUT_PORT_COMPOSITE_S = 0x81,
CELL_VIDEO_OUT_PORT_D = 0x82,
CELL_VIDEO_OUT_PORT_COMPONENT = 0x83,
CELL_VIDEO_OUT_PORT_RGB = 0x84,
CELL_VIDEO_OUT_PORT_AVMULTI_SCART = 0x85,
CELL_VIDEO_OUT_PORT_DSUB = 0x86
};
enum CellVideoOutDisplayAspect
{
CELL_VIDEO_OUT_ASPECT_AUTO,
CELL_VIDEO_OUT_ASPECT_4_3,
CELL_VIDEO_OUT_ASPECT_16_9,
};
enum CellVideoOutBufferColorFormat
{
CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8R8G8B8,
CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8B8G8R8,
CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_R16G16B16X16_FLOAT,
};
enum CellVideoOutOutputState
{
CELL_VIDEO_OUT_OUTPUT_STATE_ENABLED,
CELL_VIDEO_OUT_OUTPUT_STATE_DISABLED,
CELL_VIDEO_OUT_OUTPUT_STATE_PREPARING,
};
enum CellVideoOutDeviceState
{
CELL_VIDEO_OUT_DEVICE_STATE_UNAVAILABLE,
CELL_VIDEO_OUT_DEVICE_STATE_AVAILABLE,
};
enum CellVideoOutColorSpace
{
CELL_VIDEO_OUT_COLOR_SPACE_RGB = 0x01,
CELL_VIDEO_OUT_COLOR_SPACE_YUV = 0x02,
CELL_VIDEO_OUT_COLOR_SPACE_XVYCC = 0x04,
};
enum CellVideoOutDebugMonitorType
{
CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_UNDEFINED = 0,
CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_480I_59_94HZ = 1,
CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_576I_50HZ = 2,
CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_480P_59_94HZ = 3,
CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_576P_50HZ = 4,
CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_1080I_59_94HZ = 5,
CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_720P_59_94HZ = 7,
CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_1080P_59_94HZ = 9,
CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_WXGA_60HZ = 11,
CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_SXGA_60HZ = 12,
CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_WUXGA_60HZ = 13
};
struct CellVideoOutColorInfo
{
u16 redX;
u16 redY;
u16 greenX;
u16 greenY;
u16 blueX;
u16 blueY;
u16 whiteX;
u16 whiteY;
u32 gamma;
};
struct CellVideoOutKSVList
{
u8 ksv[32*5];
u8 reserved[4];
u32 count;
};
enum CellVideoOutDisplayConversion
{
CELL_VIDEO_OUT_DISPLAY_CONVERSION_NONE = 0x00,
CELL_VIDEO_OUT_DISPLAY_CONVERSION_TO_WXGA = 0x01,
CELL_VIDEO_OUT_DISPLAY_CONVERSION_TO_SXGA = 0x02,
CELL_VIDEO_OUT_DISPLAY_CONVERSION_TO_WUXGA = 0x03,
CELL_VIDEO_OUT_DISPLAY_CONVERSION_TO_1080 = 0x05,
CELL_VIDEO_OUT_DISPLAY_CONVERSION_TO_REMOTEPLAY = 0x10,
CELL_VIDEO_OUT_DISPLAY_CONVERSION_TO_720_3D_FRAME_PACKING = 0x80,
};
struct CellVideoOutDisplayMode
{
u8 resolutionId;
u8 scanMode;
u8 conversion;
u8 aspect;
u8 reserved[2];
u16 refreshRates;
};
struct CellVideoOutResolution
{
u16 width;
u16 height;
};
struct CellVideoOutDeviceInfo
{
u8 portType;
u8 colorSpace;
u16 latency;
u8 availableModeCount;
u8 state;
u8 rgbOutputRange;
u8 reserved[5];
CellVideoOutColorInfo colorInfo;
CellVideoOutDisplayMode availableModes[32];
CellVideoOutKSVList ksvList;
};
struct CellVideoOutState
{
u8 state;
u8 colorSpace;
u8 reserved[6];
CellVideoOutDisplayMode displayMode;
};
struct CellVideoOutConfiguration
{
u8 resolutionId;
u8 format;
u8 aspect;
u8 reserved[9];
u32 pitch;
};
enum CellVideoOutEvent
{
CELL_VIDEO_OUT_EVENT_DEVICE_CHANGED,
CELL_VIDEO_OUT_EVENT_OUTPUT_DISABLED,
CELL_VIDEO_OUT_EVENT_DEVICE_AUTHENTICATED,
CELL_VIDEO_OUT_EVENT_OUTPUT_ENABLED,
};
enum CellVideoOutCopyControl
{
CELL_VIDEO_OUT_COPY_CONTROL_COPY_FREE,
CELL_VIDEO_OUT_COPY_CONTROL_COPY_ONCE,
CELL_VIDEO_OUT_COPY_CONTROL_COPY_NEVER,
};
enum CellVideoOutRGBOutputRange
{
CELL_VIDEO_OUT_RGB_OUTPUT_RANGE_LIMITED,
CELL_VIDEO_OUT_RGB_OUTPUT_RANGE_FULL,
};

42
rpcs3/Emu/GameInfo.h Normal file
View File

@ -0,0 +1,42 @@
#pragma once
struct GameInfo
{
wxString root;
wxString name;
wxString serial;
wxString app_ver;
wxString category;
wxString fw;
u32 attr;
u32 bootable;
u32 parental_lvl;
u32 sound_format;
u32 resolution;
GameInfo()
{
Reset();
}
void Reset()
{
root = wxEmptyString;
name = "Unknown";
serial = "Unknown";
app_ver = "Unknown";
category = "Unknown";
fw = "Unknown";
attr = 0;
bootable = 0;
parental_lvl = 0;
sound_format = 0;
resolution = 0;
}
};
extern GameInfo CurGameInfo;

View File

@ -0,0 +1,24 @@
#pragma once
#include "Emu/Io/PadHandler.h"
class NullPadHandler : public PadHandlerBase
{
public:
NullPadHandler()
{
}
virtual void Init(const u32 max_connect)
{
memset(&m_info, 0, sizeof(PadInfo));
m_info.max_connect = max_connect;
m_pads.Clear();
}
virtual void Close()
{
memset(&m_info, 0, sizeof(PadInfo));
m_pads.Clear();
}
};

38
rpcs3/Emu/Io/Pad.cpp Normal file
View File

@ -0,0 +1,38 @@
#include "stdafx.h"
#include "Pad.h"
#include "Null/NullPadHandler.h"
#include "Windows/WindowsPadHandler.h"
PadManager::PadManager()
: m_pad_handler(NULL)
, m_inited(false)
{
}
PadManager::~PadManager()
{
}
void PadManager::Init(const u32 max_connect)
{
if(m_inited) return;
switch(Ini.PadHandlerMode.GetValue())
{
case 1: m_pad_handler = new WindowsPadHandler(); break;
default:
case 0: m_pad_handler = new NullPadHandler(); break;
}
m_pad_handler->Init(max_connect);
m_inited = true;
}
void PadManager::Close()
{
if(m_pad_handler) m_pad_handler->Close();
m_pad_handler = NULL;
m_inited = false;
}

25
rpcs3/Emu/Io/Pad.h Normal file
View File

@ -0,0 +1,25 @@
#pragma once
#include "PadHandler.h"
class PadManager //: public wxWindow
{
bool m_inited;
PadHandlerBase* m_pad_handler;
public:
PadManager();
~PadManager();
void Init(const u32 max_connect);
void Close();
Array<Pad>& GetPads() { return m_pad_handler->GetPads(); }
PadInfo& GetInfo() { return m_pad_handler->GetInfo(); }
Array<Button>& GetButtons(const u32 pad) { return m_pad_handler->GetButtons(pad); }
bool IsInited() { return m_inited; }
//private:
//DECLARE_EVENT_TABLE();
};

202
rpcs3/Emu/Io/PadHandler.h Normal file
View File

@ -0,0 +1,202 @@
#pragma once
enum PortStatus
{
CELL_PAD_STATUS_DISCONNECTED = 0x00000000,
CELL_PAD_STATUS_CONNECTED = 0x00000001,
};
enum PortSettings
{
CELL_PAD_SETTING_PRESS_ON = 0x00000002,
CELL_PAD_SETTING_SENSOR_ON = 0x00000004,
CELL_PAD_SETTING_PRESS_OFF = 0x00000000,
CELL_PAD_SETTING_SENSOR_OFF = 0x00000000,
};
enum Digital1Flags
{
CELL_PAD_CTRL_LEFT = 0x00000080,
CELL_PAD_CTRL_DOWN = 0x00000040,
CELL_PAD_CTRL_RIGHT = 0x00000020,
CELL_PAD_CTRL_UP = 0x00000010,
CELL_PAD_CTRL_START = 0x00000008,
CELL_PAD_CTRL_R3 = 0x00000004,
CELL_PAD_CTRL_L3 = 0x00000002,
CELL_PAD_CTRL_SELECT = 0x00000001,
};
enum Digital2Flags
{
CELL_PAD_CTRL_SQUARE = 0x00000080,
CELL_PAD_CTRL_CROSS = 0x00000040,
CELL_PAD_CTRL_CIRCLE = 0x00000020,
CELL_PAD_CTRL_TRIANGLE = 0x00000010,
CELL_PAD_CTRL_R1 = 0x00000008,
CELL_PAD_CTRL_L1 = 0x00000004,
CELL_PAD_CTRL_R2 = 0x00000002,
CELL_PAD_CTRL_L2 = 0x00000001,
};
enum DeviceCapability
{
CELL_PAD_CAPABILITY_PS3_CONFORMITY = 0x00000001, //PS3 Conformity Controller
CELL_PAD_CAPABILITY_PRESS_MODE = 0x00000002, //Press mode supported
CELL_PAD_CAPABILITY_SENSOR_MODE = 0x00000004, //Sensor mode supported
CELL_PAD_CAPABILITY_HP_ANALOG_STICK = 0x00000008, //High Precision analog stick
CELL_PAD_CAPABILITY_ACTUATOR = 0x00000010, //Motor supported
};
enum DeviceType
{
CELL_PAD_DEV_TYPE_STANDARD = 0,
CELL_PAD_DEV_TYPE_BD_REMOCON = 4,
CELL_PAD_DEV_TYPE_LDD = 5,
};
enum ButtonDataOffset
{
CELL_PAD_BTN_OFFSET_DIGITAL1 = 2,
CELL_PAD_BTN_OFFSET_DIGITAL2 = 3,
CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X = 4,
CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y = 5,
CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X = 6,
CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y = 7,
CELL_PAD_BTN_OFFSET_PRESS_RIGHT = 8,
CELL_PAD_BTN_OFFSET_PRESS_LEFT = 9,
CELL_PAD_BTN_OFFSET_PRESS_UP = 10,
CELL_PAD_BTN_OFFSET_PRESS_DOWN = 11,
CELL_PAD_BTN_OFFSET_PRESS_TRIANGLE = 12,
CELL_PAD_BTN_OFFSET_PRESS_CIRCLE = 13,
CELL_PAD_BTN_OFFSET_PRESS_CROSS = 14,
CELL_PAD_BTN_OFFSET_PRESS_SQUARE = 15,
CELL_PAD_BTN_OFFSET_PRESS_L1 = 16,
CELL_PAD_BTN_OFFSET_PRESS_R1 = 17,
CELL_PAD_BTN_OFFSET_PRESS_L2 = 18,
CELL_PAD_BTN_OFFSET_PRESS_R2 = 19,
CELL_PAD_BTN_OFFSET_SENSOR_X = 20,
CELL_PAD_BTN_OFFSET_SENSOR_Y = 21,
CELL_PAD_BTN_OFFSET_SENSOR_Z = 22,
CELL_PAD_BTN_OFFSET_SENSOR_G = 23,
};
static const u32 CELL_MAX_PADS = 127;
static const u32 CELL_PAD_MAX_PORT_NUM = 7;
static const u32 CELL_PAD_MAX_CODES = 64;
struct Button
{
u32 m_offset;
u32 m_keyCode;
u32 m_outKeyCode;
bool m_pressed;
Button(u32 offset, u32 keyCode, u32 outKeyCode)
: m_pressed(false)
, m_offset(offset)
, m_keyCode(keyCode)
, m_outKeyCode(outKeyCode)
{
}
};
struct Pad
{
u32 m_port_status;
u32 m_port_setting;
u32 m_device_capability;
u32 m_device_type;
Array<Button> m_buttons;
s16 m_analog_left_x;
s16 m_analog_left_y;
s16 m_analog_right_x;
s16 m_analog_right_y;
u16 m_press_right;
u16 m_press_left;
u16 m_press_up;
u16 m_press_down;
u16 m_press_triangle;
u16 m_press_circle;
u16 m_press_cross;
u16 m_press_square;
u16 m_press_L1;
u16 m_press_L2;
u16 m_press_R1;
u16 m_press_R2;
u16 m_sensor_x;
u16 m_sensor_y;
u16 m_sensor_z;
u16 m_sensor_g;
Pad(u32 port_status, u32 port_setting, u32 device_capability, u32 device_type)
: m_port_status(port_status)
, m_port_setting(port_setting)
, m_device_capability(device_capability)
, m_device_type(device_type)
, m_analog_left_x(0)
, m_analog_left_y(0)
, m_analog_right_x(0)
, m_analog_right_y(0)
, m_press_right(0)
, m_press_left(0)
, m_press_up(0)
, m_press_down(0)
, m_press_triangle(0)
, m_press_circle(0)
, m_press_cross(0)
, m_press_square(0)
, m_press_L1(0)
, m_press_L2(0)
, m_press_R1(0)
, m_press_R2(0)
, m_sensor_x(0)
, m_sensor_y(0)
, m_sensor_z(0)
, m_sensor_g(0)
{
}
~Pad() { m_buttons.Clear(); }
};
struct PadInfo
{
u32 max_connect;
u32 now_connect;
u32 system_info;
};
class PadHandlerBase
{
protected:
PadInfo m_info;
Array<Pad> m_pads;
public:
virtual void Init(const u32 max_connect)=0;
virtual void Close()=0;
void Key(const u32 code, bool pressed)
{
for(u64 p=0; p<GetPads().GetCount(); ++p)
{
for(u64 b=0; b<GetButtons(p).GetCount(); b++)
{
Button& button = GetButtons(p).Get(b);
if(button.m_keyCode != code) continue;
button.m_pressed = pressed;
}
}
}
PadInfo& GetInfo() { return m_info; }
Array<Pad>& GetPads() { return m_pads; }
Array<Button>& GetButtons(const u32 pad) { return GetPads()[pad].m_buttons; }
};

View File

@ -0,0 +1,58 @@
#pragma once
#include "Emu/Io/PadHandler.h"
class WindowsPadHandler
: public wxWindow
, public PadHandlerBase
{
public:
WindowsPadHandler() : wxWindow()
{
wxGetApp().Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(WindowsPadHandler::KeyDown), (wxObject*)0, this);
wxGetApp().Connect(wxEVT_KEY_UP, wxKeyEventHandler(WindowsPadHandler::KeyUp), (wxObject*)0, this);
}
virtual void KeyDown(wxKeyEvent& event) { Key(event.GetKeyCode(), 1); event.Skip(); }
virtual void KeyUp(wxKeyEvent& event) { Key(event.GetKeyCode(), 0); event.Skip(); }
virtual void Init(const u32 max_connect)
{
memset(&m_info, 0, sizeof(PadInfo));
m_info.max_connect = max_connect;
LoadSettings();
m_info.now_connect = min<int>(GetPads().GetCount(), max_connect);
}
virtual void Close()
{
memset(&m_info, 0, sizeof(PadInfo));
m_pads.Clear();
}
void LoadSettings()
{
m_pads.Add(new Pad(
CELL_PAD_STATUS_CONNECTED, CELL_PAD_SETTING_PRESS_ON | CELL_PAD_SETTING_SENSOR_OFF,
CELL_PAD_CAPABILITY_PS3_CONFORMITY | CELL_PAD_CAPABILITY_PRESS_MODE,
CELL_PAD_DEV_TYPE_STANDARD));
m_pads[0].m_buttons.Add(new Button(CELL_PAD_BTN_OFFSET_DIGITAL1, 'A', CELL_PAD_CTRL_LEFT));
m_pads[0].m_buttons.Add(new Button(CELL_PAD_BTN_OFFSET_DIGITAL1, 'S', CELL_PAD_CTRL_DOWN));
m_pads[0].m_buttons.Add(new Button(CELL_PAD_BTN_OFFSET_DIGITAL1, 'D', CELL_PAD_CTRL_RIGHT));
m_pads[0].m_buttons.Add(new Button(CELL_PAD_BTN_OFFSET_DIGITAL1, 'W', CELL_PAD_CTRL_UP));
m_pads[0].m_buttons.Add(new Button(CELL_PAD_BTN_OFFSET_DIGITAL1, WXK_RETURN, CELL_PAD_CTRL_START));
m_pads[0].m_buttons.Add(new Button(CELL_PAD_BTN_OFFSET_DIGITAL1, 'X', CELL_PAD_CTRL_R3));
m_pads[0].m_buttons.Add(new Button(CELL_PAD_BTN_OFFSET_DIGITAL1, 'Z', CELL_PAD_CTRL_L3));
m_pads[0].m_buttons.Add(new Button(CELL_PAD_BTN_OFFSET_DIGITAL1, WXK_SPACE, CELL_PAD_CTRL_SELECT));
m_pads[0].m_buttons.Add(new Button(CELL_PAD_BTN_OFFSET_DIGITAL2, 'K', CELL_PAD_CTRL_SQUARE));
m_pads[0].m_buttons.Add(new Button(CELL_PAD_BTN_OFFSET_DIGITAL2, 'L', CELL_PAD_CTRL_CROSS));
m_pads[0].m_buttons.Add(new Button(CELL_PAD_BTN_OFFSET_DIGITAL2, ';', CELL_PAD_CTRL_CIRCLE));
m_pads[0].m_buttons.Add(new Button(CELL_PAD_BTN_OFFSET_DIGITAL2, 'O', CELL_PAD_CTRL_TRIANGLE));
m_pads[0].m_buttons.Add(new Button(CELL_PAD_BTN_OFFSET_DIGITAL2, 'I', CELL_PAD_CTRL_R1));
m_pads[0].m_buttons.Add(new Button(CELL_PAD_BTN_OFFSET_DIGITAL2, 'Q', CELL_PAD_CTRL_L1));
m_pads[0].m_buttons.Add(new Button(CELL_PAD_BTN_OFFSET_DIGITAL2, 'P', CELL_PAD_CTRL_R2));
m_pads[0].m_buttons.Add(new Button(CELL_PAD_BTN_OFFSET_DIGITAL2, 'E', CELL_PAD_CTRL_L2));
}
};

652
rpcs3/Emu/Memory/Memory.cpp Normal file
View File

@ -0,0 +1,652 @@
#include "stdafx.h"
#include "Memory.h"
#include "MemoryBlock.h"
MemoryBase Memory;
//MemoryBlock
MemoryBlock::MemoryBlock()
{
Init();
}
MemoryBlock::~MemoryBlock()
{
Delete();
}
void MemoryBlock::Init()
{
range_start = 0;
range_size = 0;
mem = NULL;
}
void MemoryBlock::InitMemory()
{
safe_delete(mem);
mem = new u8[range_size];
memset(mem, 0, range_size);
}
void MemoryBlock::Delete()
{
safe_delete(mem);
Init();
}
u64 MemoryBlock::FixAddr(const u64 addr) const
{
return addr - GetStartAddr();
}
bool MemoryBlock::GetMemFromAddr(void* dst, const u64 addr, const u32 size)
{
if(!IsMyAddress(addr)) return false;
if(FixAddr(addr) + size > GetSize()) return false;
memcpy(dst, &mem[FixAddr(addr)], size);
return true;
}
bool MemoryBlock::SetMemFromAddr(void* src, const u64 addr, const u32 size)
{
if(!IsMyAddress(addr)) return false;
if(FixAddr(addr) + size > GetSize()) return false;
memcpy(&mem[FixAddr(addr)], src, size);
return true;
}
bool MemoryBlock::GetMemFFromAddr(void* dst, const u64 addr)
{
if(!IsMyAddress(addr)) return false;
dst = &mem[FixAddr(addr)];
return true;
}
u8* MemoryBlock::GetMemFromAddr(const u64 addr)
{
if(!IsMyAddress(addr)) return NULL;
return &mem[FixAddr(addr)];
}
MemoryBlock* MemoryBlock::SetRange(const u64 start, const u32 size)
{
range_start = start;
range_size = size;
InitMemory();
return this;
}
bool MemoryBlock::SetNewSize(const u32 size)
{
if(range_size >= size) return false;
u8* new_mem = (u8*)realloc(mem, size);
if(!new_mem)
{
ConLog.Error("Not enought free memory");
Emu.Pause();
return false;
}
mem = new_mem;
range_size = size;
return true;
}
bool MemoryBlock::IsMyAddress(const u64 addr)
{
return addr >= GetStartAddr() && addr < GetEndAddr();
}
__forceinline const u8 MemoryBlock::FastRead8(const u64 addr) const
{
return mem[addr];
}
__forceinline const u16 MemoryBlock::FastRead16(const u64 addr) const
{
return ((u16)FastRead8(addr) << 8) | (u16)FastRead8(addr + 1);
}
__forceinline const u32 MemoryBlock::FastRead32(const u64 addr) const
{
return ((u32)FastRead16(addr) << 16) | (u32)FastRead16(addr + 2);
}
__forceinline const u64 MemoryBlock::FastRead64(const u64 addr) const
{
return ((u64)FastRead32(addr) << 32) | (u64)FastRead32(addr + 4);
}
__forceinline const u128 MemoryBlock::FastRead128(const u64 addr)
{
u128 ret;
ret.hi = FastRead64(addr);
ret.lo = FastRead64(addr + 8);
return ret;
}
bool MemoryBlock::Read8(const u64 addr, u8* value)
{
if(!IsMyAddress(addr))
{
*value = 0;
return false;
}
*value = FastRead8(FixAddr(addr));
return true;
}
bool MemoryBlock::Read16(const u64 addr, u16* value)
{
if(!IsMyAddress(addr))
{
*value = 0;
return false;
}
*value = FastRead16(FixAddr(addr));
return true;
}
bool MemoryBlock::Read32(const u64 addr, u32* value)
{
if(!IsMyAddress(addr))
{
*value = 0;
return false;
}
*value = FastRead32(FixAddr(addr));
return true;
}
bool MemoryBlock::Read64(const u64 addr, u64* value)
{
if(!IsMyAddress(addr))
{
*value = 0;
return false;
}
*value = FastRead64(FixAddr(addr));
return true;
}
bool MemoryBlock::Read128(const u64 addr, u128* value)
{
if(!IsMyAddress(addr))
{
*value = u128::From32(0);
return false;
}
*value = FastRead128(FixAddr(addr));
return true;
}
__forceinline void MemoryBlock::FastWrite8(const u64 addr, const u8 value)
{
mem[addr] = value;
}
__forceinline void MemoryBlock::FastWrite16(const u64 addr, const u16 value)
{
FastWrite8(addr, (u8)(value >> 8));
FastWrite8(addr+1, (u8)value);
}
__forceinline void MemoryBlock::FastWrite32(const u64 addr, const u32 value)
{
FastWrite16(addr, (u16)(value >> 16));
FastWrite16(addr+2, (u16)value);
}
__forceinline void MemoryBlock::FastWrite64(const u64 addr, const u64 value)
{
FastWrite32(addr, (u32)(value >> 32));
FastWrite32(addr+4, (u32)value);
}
__forceinline void MemoryBlock::FastWrite128(const u64 addr, const u128 value)
{
FastWrite64(addr, value.hi);
FastWrite64(addr+8, value.lo);
}
bool MemoryBlock::Write8(const u64 addr, const u8 value)
{
if(!IsMyAddress(addr)) return false;
FastWrite8(FixAddr(addr), value);
return true;
}
bool MemoryBlock::Write16(const u64 addr, const u16 value)
{
if(!IsMyAddress(addr)) return false;
FastWrite16(FixAddr(addr), value);
return true;
}
bool MemoryBlock::Write32(const u64 addr, const u32 value)
{
if(!IsMyAddress(addr)) return false;
FastWrite32(FixAddr(addr), value);
return true;
}
bool MemoryBlock::Write64(const u64 addr, const u64 value)
{
if(!IsMyAddress(addr)) return false;
FastWrite64(FixAddr(addr), value);
return true;
}
bool MemoryBlock::Write128(const u64 addr, const u128 value)
{
if(!IsMyAddress(addr)) return false;
FastWrite128(FixAddr(addr), value);
return true;
}
//NullMemoryBlock
bool NullMemoryBlock::Read8(const u64 addr, u8* WXUNUSED(value))
{
ConLog.Error("Read8 from null block: [%08llx]", addr);
Emu.Pause();
return false;
}
bool NullMemoryBlock::Read16(const u64 addr, u16* WXUNUSED(value))
{
ConLog.Error("Read16 from null block: [%08llx]", addr);
Emu.Pause();
return false;
}
bool NullMemoryBlock::Read32(const u64 addr, u32* WXUNUSED(value))
{
ConLog.Error("Read32 from null block: [%08llx]", addr);
Emu.Pause();
return false;
}
bool NullMemoryBlock::Read64(const u64 addr, u64* WXUNUSED(value))
{
ConLog.Error("Read64 from null block: [%08llx]", addr);
Emu.Pause();
return false;
}
bool NullMemoryBlock::Read128(const u64 addr, u128* WXUNUSED(value))
{
ConLog.Error("Read128 from null block: [%08llx]", addr);
Emu.Pause();
return false;
}
bool NullMemoryBlock::Write8(const u64 addr, const u8 value)
{
ConLog.Error("Write8 to null block: [%08llx]: %x", addr, value);
Emu.Pause();
return false;
}
bool NullMemoryBlock::Write16(const u64 addr, const u16 value)
{
ConLog.Error("Write16 to null block: [%08llx]: %x", addr, value);
Emu.Pause();
return false;
}
bool NullMemoryBlock::Write32(const u64 addr, const u32 value)
{
ConLog.Error("Write32 to null block: [%08llx]: %x", addr, value);
Emu.Pause();
return false;
}
bool NullMemoryBlock::Write64(const u64 addr, const u64 value)
{
ConLog.Error("Write64 to null block: [%08llx]: %llx", addr, value);
Emu.Pause();
return false;
}
bool NullMemoryBlock::Write128(const u64 addr, const u128 value)
{
ConLog.Error("Write128 to null block: [%08llx]: %llx_%llx", addr, value.hi, value.lo);
Emu.Pause();
return false;
}
//DynamicMemoryBlock
DynamicMemoryBlock::DynamicMemoryBlock() : m_point(0)
, m_max_size(0)
{
}
bool DynamicMemoryBlock::IsInMyRange(const u64 addr)
{
return addr >= GetStartAddr() && addr < GetStartAddr() + GetSize();
}
bool DynamicMemoryBlock::IsInMyRange(const u64 addr, const u32 size)
{
return IsInMyRange(addr) && IsInMyRange(addr + size - 1);
}
bool DynamicMemoryBlock::IsMyAddress(const u64 addr)
{
for(u32 i=0; i<m_used_mem.GetCount(); ++i)
{
if(addr >= m_used_mem[i].addr && addr < m_used_mem[i].addr + m_used_mem[i].size)
{
return true;
}
}
return false;
}
MemoryBlock* DynamicMemoryBlock::SetRange(const u64 start, const u32 size)
{
m_max_size = size;
MemoryBlock::SetRange(start, 4);
m_point = GetStartAddr();
return this;
}
void DynamicMemoryBlock::Delete()
{
m_used_mem.Clear();
m_free_mem.Clear();
m_point = 0;
m_max_size = 0;
MemoryBlock::Delete();
}
void DynamicMemoryBlock::UpdateSize(u64 addr, u32 size)
{
u32 used_size = addr + size - GetStartAddr();
if(used_size > GetUsedSize()) SetNewSize(used_size);
}
void DynamicMemoryBlock::CombineFreeMem()
{
if(m_free_mem.GetCount() < 2) return;
for(u32 i1=0; i1<m_free_mem.GetCount(); ++i1)
{
MemBlockInfo& u1 = m_free_mem[i1];
for(u32 i2=i1+1; i2<m_free_mem.GetCount(); ++i2)
{
const MemBlockInfo u2 = m_free_mem[i2];
if(u1.addr + u1.size != u2.addr) continue;
u1.size += u2.size;
m_free_mem.RemoveAt(i2);
break;
}
}
}
bool DynamicMemoryBlock::Alloc(u64 addr, u32 size)
{
if(!IsInMyRange(addr, size) || IsMyAddress(addr) || IsMyAddress(addr + size - 1))
{
assert(0);
return false;
}
if(addr == m_point)
{
UpdateSize(m_point, size);
m_used_mem.AddCpy(MemBlockInfo(m_point, size));
memset(mem + (m_point - GetStartAddr()), 0, size);
m_point += size;
return true;
}
if(addr > m_point)
{
u64 free_mem_addr = GetStartAddr();
if(free_mem_addr != addr)
{
for(u32 i=0; i<m_free_mem.GetCount(); ++i)
{
if(m_free_mem[i].addr >= free_mem_addr && m_free_mem[i].addr < addr)
{
free_mem_addr = m_free_mem[i].addr + m_free_mem[i].size;
}
}
for(u32 i=0; i<m_used_mem.GetCount(); ++i)
{
if(m_used_mem[i].addr >= free_mem_addr && m_used_mem[i].addr < addr)
{
free_mem_addr = m_used_mem[i].addr + m_used_mem[i].size;
}
}
m_free_mem.AddCpy(MemBlockInfo(free_mem_addr, addr - GetStartAddr()));
}
UpdateSize(addr, size);
m_used_mem.AddCpy(MemBlockInfo(addr, size));
memset(mem + (addr - GetStartAddr()), 0, size);
m_point = addr + size;
return true;
}
for(u32 i=0; i<m_free_mem.GetCount(); ++i)
{
if(addr < m_free_mem[i].addr || addr >= m_free_mem[i].addr + m_free_mem[i].size
|| m_free_mem[i].size < size) continue;
if(m_free_mem[i].addr != addr)
{
m_free_mem.AddCpy(MemBlockInfo(m_free_mem[i].addr, addr - m_free_mem[i].addr));
}
if(m_free_mem[i].size != size)
{
m_free_mem.AddCpy(MemBlockInfo(m_free_mem[i].addr + size, m_free_mem[i].size - size));
}
m_free_mem.RemoveAt(i);
m_used_mem.AddCpy(MemBlockInfo(addr, size));
memset(mem + (addr - GetStartAddr()), 0, size);
return true;
}
return false;
}
u64 DynamicMemoryBlock::Alloc(u32 size)
{
for(u32 i=0; i<m_free_mem.GetCount(); ++i)
{
if(m_free_mem[i].size < size) continue;
const u32 addr = m_free_mem[i].addr;
if(m_free_mem[i].size != size)
{
m_free_mem.AddCpy(MemBlockInfo(addr + size, m_free_mem[i].size - size));
}
m_free_mem.RemoveAt(i);
m_used_mem.AddCpy(MemBlockInfo(addr, size));
memset(mem + (addr - GetStartAddr()), 0, size);
return addr;
}
UpdateSize(m_point, size);
MemBlockInfo res(m_point, size);
m_used_mem.AddCpy(res);
memset(mem + (m_point - GetStartAddr()), 0, size);
m_point += size;
return res.addr;
}
bool DynamicMemoryBlock::Alloc()
{
return Alloc(GetSize() - GetUsedSize()) != 0;
}
bool DynamicMemoryBlock::Free(u64 addr)
{
for(u32 i=0; i<m_used_mem.GetCount(); ++i)
{
if(addr == m_used_mem[i].addr)
{
m_free_mem.AddCpy(MemBlockInfo(m_used_mem[i].addr, m_used_mem[i].size));
m_used_mem.RemoveAt(i);
CombineFreeMem();
return true;
}
}
return false;
}
//MemoryBase
void MemoryBase::Write8(u64 addr, const u8 data)
{
GetMemByAddr(addr).Write8(addr, data);
}
void MemoryBase::Write16(u64 addr, const u16 data)
{
GetMemByAddr(addr).Write16(addr, data);
}
void MemoryBase::Write32(u64 addr, const u32 data)
{
GetMemByAddr(addr).Write32(addr, data);
}
void MemoryBase::Write64(u64 addr, const u64 data)
{
GetMemByAddr(addr).Write64(addr, data);
}
void MemoryBase::Write128(u64 addr, const u128 data)
{
GetMemByAddr(addr).Write128(addr, data);
}
bool MemoryBase::Write8NN(u64 addr, const u8 data)
{
if(!IsGoodAddr(addr)) return false;
Write8(addr, data);
return true;
}
bool MemoryBase::Write16NN(u64 addr, const u16 data)
{
if(!IsGoodAddr(addr, 2)) return false;
Write16(addr, data);
return true;
}
bool MemoryBase::Write32NN(u64 addr, const u32 data)
{
if(!IsGoodAddr(addr, 4)) return false;
Write32(addr, data);
return true;
}
bool MemoryBase::Write64NN(u64 addr, const u64 data)
{
if(!IsGoodAddr(addr, 8)) return false;
Write64(addr, data);
return true;
}
bool MemoryBase::Write128NN(u64 addr, const u128 data)
{
if(!IsGoodAddr(addr, 16)) return false;
Write128(addr, data);
return true;
}
u8 MemoryBase::Read8(u64 addr)
{
MemoryBlock& mem = GetMemByAddr(addr);
if(mem.IsNULL())
{
mem.Read8(addr, NULL);
return 0;
}
return mem.FastRead8(mem.FixAddr(addr));
}
u16 MemoryBase::Read16(u64 addr)
{
MemoryBlock& mem = GetMemByAddr(addr);
if(mem.IsNULL())
{
mem.Read16(addr, NULL);
return 0;
}
return mem.FastRead16(mem.FixAddr(addr));
}
u32 MemoryBase::Read32(u64 addr)
{
MemoryBlock& mem = GetMemByAddr(addr);
if(mem.IsNULL())
{
mem.Read32(addr, NULL);
return 0;
}
return mem.FastRead32(mem.FixAddr(addr));
}
u64 MemoryBase::Read64(u64 addr)
{
MemoryBlock& mem = GetMemByAddr(addr);
if(mem.IsNULL())
{
mem.Read64(addr, NULL);
return 0;
}
return mem.FastRead64(mem.FixAddr(addr));
}
u128 MemoryBase::Read128(u64 addr)
{
MemoryBlock& mem = GetMemByAddr(addr);
if(mem.IsNULL())
{
mem.Read128(addr, NULL);
return u128::From32(0);
}
return mem.FastRead128(mem.FixAddr(addr));
}

415
rpcs3/Emu/Memory/Memory.h Normal file
View File

@ -0,0 +1,415 @@
#pragma once
#include "MemoryBlock.h"
class MemoryFlags
{
struct Flag
{
const u64 addr;
const u64 waddr;
const u64 fid;
Flag(const u64 _addr, const u64 _waddr, const u64 _fid)
: addr(_addr)
, waddr(_waddr)
, fid(_fid)
{
}
};
Array<Flag> m_memflags;
public:
void Add(const u64 addr, const u64 waddr, const u64 fid) {m_memflags.Add(new Flag(addr, waddr, fid));}
void Clear() { m_memflags.Clear(); }
bool IsFlag(const u64 addr, u64& waddr, u64& fid)
{
for(u32 i=0; i<GetCount(); i++)
{
if(m_memflags[i].addr != addr) continue;
fid = m_memflags[i].fid;
waddr = m_memflags[i].waddr;
return true;
}
return false;
}
u64 GetCount() const { return m_memflags.GetCount(); }
};
class MemoryBase
{
NullMemoryBlock NullMem;
public:
ArrayF<MemoryBlock> MemoryBlocks;
DynamicMemoryBlock MainMem;
DynamicMemoryBlock PRXMem;
DynamicMemoryBlock RSXCMDMem;
DynamicMemoryBlock MmaperMem;
DynamicMemoryBlock RSXFBMem;
DynamicMemoryBlock StackMem;
MemoryBlock SpuRawMem;
MemoryBlock SpuThrMem;
MemoryFlags MemFlags;
bool m_inited;
MemoryBase()
{
m_inited = false;
}
~MemoryBase()
{
Close();
}
static u16 Reverse16(const u16 val)
{
return ((val >> 8) & 0xff) | ((val << 8) & 0xff00);
}
static u32 Reverse32(const u32 val)
{
return
((val >> 24) & 0x000000ff) |
((val >> 8) & 0x0000ff00) |
((val << 8) & 0x00ff0000) |
((val << 24) & 0xff000000);
}
static u64 Reverse64(const u64 val)
{
return
((val >> 56) & 0x00000000000000ff) |
((val >> 40) & 0x000000000000ff00) |
((val >> 24) & 0x0000000000ff0000) |
((val >> 8) & 0x00000000ff000000) |
((val << 8) & 0x000000ff00000000) |
((val << 24) & 0x0000ff0000000000) |
((val << 40) & 0x00ff000000000000) |
((val << 56) & 0xff00000000000000);
}
template<typename T> static T Reverse(T val)
{
switch(sizeof(T))
{
case 2: return Reverse16(val);
case 4: return Reverse32(val);
case 8: return Reverse64(val);
}
return val;
}
MemoryBlock& GetMemByNum(const u8 num)
{
if(num >= MemoryBlocks.GetCount()) return NullMem;
return MemoryBlocks.Get(num);
}
MemoryBlock& GetMemByAddr(const u64 addr)
{
for(uint i=0; i<MemoryBlocks.GetCount(); ++i)
{
if(MemoryBlocks.Get(i).IsMyAddress(addr)) return MemoryBlocks[i];
}
return NullMem;
}
u8* GetMemFromAddr(const u64 addr)
{
return GetMemByAddr(addr).GetMemFromAddr(addr);
}
void* VirtualToRealAddr(const u64 vaddr)
{
return GetMemFromAddr(vaddr);
}
u64 RealToVirtualAddr(const void* addr)
{
const u32 raddr = (u32)addr;
for(u32 i=0; i<MemoryBlocks.GetCount(); ++i)
{
MemoryBlock& b = MemoryBlocks[i];
const u32 baddr = (u32)b.GetMem();
if(raddr >= baddr && raddr < baddr + b.GetSize())
{
return b.GetStartAddr() + (raddr - baddr);
}
}
return 0;
}
bool InitSpuRawMem(const u32 max_spu_raw)
{
//if(SpuRawMem.GetSize()) return false;
MemoryBlocks.Add(SpuRawMem.SetRange(0xe0000000, 0x100000 * max_spu_raw));
return true;
}
void Init()
{
if(m_inited) return;
m_inited = true;
ConLog.Write("Initing memory...");
MemoryBlocks.Add(MainMem.SetRange(0x00010000, 0x2FFF0000));
MemoryBlocks.Add(PRXMem.SetRange(0x30000000, 0x10000000));
MemoryBlocks.Add(RSXCMDMem.SetRange(0x40000000, 0x10000000));
//MemoryBlocks.Add(MmaperMem.SetRange(0xB0000000, 0x10000000));
MemoryBlocks.Add(RSXFBMem.SetRange(0xC0000000, 0x10000000));
MemoryBlocks.Add(StackMem.SetRange(0xD0000000, 0x10000000));
//MemoryBlocks.Add(SpuRawMem.SetRange(0xE0000000, 0x10000000));
//MemoryBlocks.Add(SpuThrMem.SetRange(0xF0000000, 0x10000000));
ConLog.Write("Memory initialized.");
}
bool IsGoodAddr(const u64 addr)
{
for(uint i=0; i<MemoryBlocks.GetCount(); ++i)
{
if(MemoryBlocks[i].IsMyAddress(addr)) return true;
}
return false;
}
bool IsGoodAddr(const u64 addr, const u32 size)
{
for(uint i=0; i<MemoryBlocks.GetCount(); ++i)
{
if( MemoryBlocks[i].IsMyAddress(addr) &&
MemoryBlocks[i].IsMyAddress(addr + size - 1) ) return true;
}
return false;
}
void Close()
{
if(!m_inited) return;
m_inited = false;
ConLog.Write("Closing memory...");
for(uint i=0; i<MemoryBlocks.GetCount(); ++i)
{
MemoryBlocks[i].Delete();
}
MemoryBlocks.Clear();
MemFlags.Clear();
}
void Reset()
{
if(!m_inited) return;
ConLog.Write("Resetting memory...");
Close();
Init();
}
void Write8(const u64 addr, const u8 data);
void Write16(const u64 addr, const u16 data);
void Write32(const u64 addr, const u32 data);
void Write64(const u64 addr, const u64 data);
void Write128(const u64 addr, const u128 data);
bool Write8NN(const u64 addr, const u8 data);
bool Write16NN(const u64 addr, const u16 data);
bool Write32NN(const u64 addr, const u32 data);
bool Write64NN(const u64 addr, const u64 data);
bool Write128NN(const u64 addr, const u128 data);
u8 Read8(const u64 addr);
u16 Read16(const u64 addr);
u32 Read32(const u64 addr);
u64 Read64(const u64 addr);
u128 Read128(const u64 addr);
template<typename T> void WriteData(const u64 addr, const T* data)
{
memcpy(GetMemFromAddr(addr), data, sizeof(T));
}
template<typename T> void WriteData(const u64 addr, const T data)
{
*(T*)GetMemFromAddr(addr) = data;
}
wxString ReadString(const u64 addr, const u64 len)
{
wxString ret = wxEmptyString;
if(len) memcpy(wxStringBuffer(ret, len), GetMemFromAddr(addr), len);
return ret;
}
wxString ReadString(const u64 addr)
{
wxString buf = wxEmptyString;
for(u32 i=addr; ; i++)
{
const u8 c = Read8(i);
if(c == 0) break;
buf += c;
}
return buf;
}
void WriteString(const u64 addr, const wxString& str)
{
for(u32 i=0; i<str.Length(); i++)
{
Write8(addr + i, str[i]);
}
Write8(addr + str.Length(), 0);
}
static u64 AlignAddr(const u64 addr, const u64 align)
{
return (addr + (align-1)) & ~(align-1);
}
u32 GetUserMemTotalSize()
{
return PRXMem.GetSize();
}
u32 GetUserMemAvailSize()
{
return PRXMem.GetSize() - PRXMem.GetUsedSize();
}
u64 Alloc(const u32 size, const u32 align)
{
return PRXMem.Alloc(AlignAddr(size, align));
}
bool Free(const u64 addr)
{
return PRXMem.Free(addr);
}
u8& operator[] (const u64 vaddr) { return *GetMemFromAddr(vaddr); }
};
extern MemoryBase Memory;
template<typename T> class mem_t
{
u64 addr;
const u64 iaddr;
public:
mem_t(u64 _addr)
: addr(_addr)
, iaddr(_addr)
{
}
void operator = (T right)
{
switch(sizeof(T))
{
case 1: Memory.Write8(addr, right); return;
case 2: Memory.Write16(addr, right); return;
case 4: Memory.Write32(addr, right); return;
case 8: Memory.Write64(addr, right); return;
}
ConLog.Error("Bad mem_t size! (%d : 0x%llx)", sizeof(T), addr);
}
operator u8() const { return Memory.Read8(addr); }
operator u16() const { return Memory.Read16(addr); }
operator u32() const { return Memory.Read32(addr); }
operator u64() const { return Memory.Read64(addr); }
/*
u64 operator += (u64 right)
{
addr += right;
return addr;
}
*/
u64 operator += (T right)
{
*this = right;
addr += sizeof(T);
return addr;
}
T operator [] (u64 i)
{
const u64 offset = i*sizeof(T);
addr += offset;
const T ret = *this;
addr -= offset;
return ret;
}
void Reset() { addr = iaddr; }
u64 GetCurAddr() const { return addr; }
u64 GetAddr() const { return iaddr; }
u64 SetOffset(const u32 offset) { return addr += offset; }
};
class mem_class_t
{
u64 addr;
const u64 iaddr;
public:
mem_class_t(u64 _addr)
: addr(_addr)
, iaddr(_addr)
{
}
template<typename T> u64 operator += (T right)
{
mem_t<T> m(addr);
m = right;
addr += sizeof(T);
return addr;
}
template<typename T> operator T()
{
mem_t<T> m(addr);
const T ret = m;
addr += sizeof(T);
return ret;
}
void Reset() { addr = iaddr; }
u64 GetCurAddr() const { return addr; }
u64 GetAddr() const { return iaddr; }
void SetAddr(const u64 _addr) { addr = _addr; }
};
typedef mem_t<u8> mem8_t;
typedef mem_t<u16> mem16_t;
typedef mem_t<u32> mem32_t;
typedef mem_t<u64> mem64_t;

View File

@ -0,0 +1,122 @@
#pragma once
struct MemBlockInfo
{
u64 addr;
u32 size;
MemBlockInfo(u64 _addr, u32 _size)
: addr(_addr)
, size(_size)
{
}
};
class MemoryBlock
{
protected:
u8* mem;
u64 range_start;
u64 range_size;
public:
MemoryBlock();
~MemoryBlock();
private:
void Init();
void InitMemory();
public:
virtual void Delete();
virtual bool IsNULL() { return false; }
u64 FixAddr(const u64 addr) const;
bool GetMemFromAddr(void* dst, const u64 addr, const u32 size);
bool SetMemFromAddr(void* src, const u64 addr, const u32 size);
bool GetMemFFromAddr(void* dst, const u64 addr);
u8* GetMemFromAddr(const u64 addr);
virtual MemoryBlock* SetRange(const u64 start, const u32 size);
bool SetNewSize(const u32 size);
virtual bool IsMyAddress(const u64 addr);
__forceinline const u8 FastRead8(const u64 addr) const;
__forceinline const u16 FastRead16(const u64 addr) const;
__forceinline const u32 FastRead32(const u64 addr) const;
__forceinline const u64 FastRead64(const u64 addr) const;
__forceinline const u128 FastRead128(const u64 addr);
virtual bool Read8(const u64 addr, u8* value);
virtual bool Read16(const u64 addr, u16* value);
virtual bool Read32(const u64 addr, u32* value);
virtual bool Read64(const u64 addr, u64* value);
virtual bool Read128(const u64 addr, u128* value);
__forceinline void FastWrite8(const u64 addr, const u8 value);
__forceinline void FastWrite16(const u64 addr, const u16 value);
__forceinline void FastWrite32(const u64 addr, const u32 value);
__forceinline void FastWrite64(const u64 addr, const u64 value);
__forceinline void FastWrite128(const u64 addr, const u128 value);
virtual bool Write8(const u64 addr, const u8 value);
virtual bool Write16(const u64 addr, const u16 value);
virtual bool Write32(const u64 addr, const u32 value);
virtual bool Write64(const u64 addr, const u64 value);
virtual bool Write128(const u64 addr, const u128 value);
const u64 GetStartAddr() const { return range_start; }
const u64 GetEndAddr() const { return range_start + range_size - 1; }
virtual const u32 GetSize() const { return range_size; }
void* GetMem() const { return mem; }
};
class NullMemoryBlock : public MemoryBlock
{
virtual bool IsNULL() { return true; }
virtual bool IsMyAddress(const u64 addr) { return true; }
virtual bool Read8(const u64 addr, u8* value);
virtual bool Read16(const u64 addr, u16* value);
virtual bool Read32(const u64 addr, u32* value);
virtual bool Read64(const u64 addr, u64* value);
virtual bool Read128(const u64 addr, u128* value);
virtual bool Write8(const u64 addr, const u8 value);
virtual bool Write16(const u64 addr, const u16 value);
virtual bool Write32(const u64 addr, const u32 value);
virtual bool Write64(const u64 addr, const u64 value);
virtual bool Write128(const u64 addr, const u128 value);
};
class DynamicMemoryBlock : public MemoryBlock
{
Array<MemBlockInfo> m_used_mem;
Array<MemBlockInfo> m_free_mem;
u64 m_point;
u32 m_max_size;
public:
DynamicMemoryBlock();
const u32 GetSize() const { return m_max_size; }
const u32 GetUsedSize() const { return range_size; }
bool IsInMyRange(const u64 addr);
bool IsInMyRange(const u64 addr, const u32 size);
bool IsMyAddress(const u64 addr);
MemoryBlock* SetRange(const u64 start, const u32 size);
virtual void Delete();
void UpdateSize(u64 addr, u32 size);
void CombineFreeMem();
bool Alloc(u64 addr, u32 size);
u64 Alloc(u32 size);
bool Alloc();
bool Free(u64 addr);
};

View File

@ -0,0 +1,66 @@
#pragma once
enum ErrorCode
{
CELL_OK = 0x00000000,
CELL_EAGAIN = 0x80010001, //The resource is temporarily unavailable
CELL_EINVAL = 0x80010002, //An invalid argument value is specified
CELL_ENOSYS = 0x80010003, //The feature is not yet implemented
CELL_ENOMEM = 0x80010004, //Memory allocation failure
CELL_ESRCH = 0x80010005, //The resource with the specified identifier does not exist
CELL_ENOENT = 0x80010006, //The file does not exist
CELL_ENOEXEC = 0x80010007, //The file is in unrecognized format
CELL_EDEADLK = 0x80010008, //Resource deadlock is avoided
CELL_EPERM = 0x80010009, //The operation is not permitted
CELL_EBUSY = 0x8001000A, //The device or resource is busy
CELL_ETIMEDOUT = 0x8001000B, //The operation is timed out
CELL_EABORT = 0x8001000C, //The operation is aborted
CELL_EFAULT = 0x8001000D, //Invalid memory access
CELL_ESTAT = 0x8001000F, //State of the target thread is invalid
CELL_EALIGN = 0x80010010, //Alignment is invalid.
CELL_EKRESOURCE = 0x80010011, //Shortage of the kernel resources
CELL_EISDIR = 0x80010012, //The file is a directory
CELL_ECANCELED = 0x80010013, //Operation canceled
CELL_EEXIST = 0x80010014, //Entry already exists
CELL_EISCONN = 0x80010015, //Port is already connected
CELL_ENOTCONN = 0x80010016, //Port is not connected
CELL_EAUTHFAIL = 0x80010017, //Program authentication fail
CELL_ENOTMSELF = 0x80010018, //The file is not a MSELF
CELL_ESYSVER = 0x80010019, //System version error
CELL_EAUTHFATAL = 0x8001001A, //Fatal system error
CELL_EDOM = 0x8001001B,
CELL_ERANGE = 0x8001001C,
CELL_EILSEQ = 0x8001001D,
CELL_EFPOS = 0x8001001E,
CELL_EINTR = 0x8001001F,
CELL_EFBIG = 0x80010020,
CELL_EMLIN = 0x80010021,
CELL_ENFILE = 0x80010022,
CELL_ENOSPC = 0x80010023,
CELL_ENOTTY = 0x80010024,
CELL_EPIPE = 0x80010025,
CELL_EROFS = 0x80010026,
CELL_ESPIPE = 0x80010027,
CELL_E2BIG = 0x80010028,
CELL_EACCES = 0x80010029,
CELL_EBADF = 0x8001002A,
CELL_EIO = 0x8001002B,
CELL_EMFILE = 0x8001002C,
CELL_ENODEV = 0x8001002D,
CELL_ENOTDIR = 0x8001002E,
CELL_ENXIO = 0x8001002F,
CELL_EXDEV = 0x80010030,
CELL_EBADMSG = 0x80010031,
CELL_EINPROGRESS = 0x80010032,
CELL_EMSGSIZE = 0x80010033,
CELL_ENAMETOOLONG = 0x80010034,
CELL_ENOLCK = 0x80010035,
CELL_ENOTEMPTY = 0x80010036,
CELL_ENOTSUP = 0x80010037,
CELL_EFSSPECIFIC = 0x80010038,
CELL_EOVERFLOW = 0x80010039,
CELL_ENOTMOUNTED = 0x8001003A,
CELL_ENOTSDATA = 0x8001003B,
CELL_UNKNOWN_ERROR = 0xFFFFFFFF,
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,333 @@
#pragma once
#include <Emu/Cell/PPUThread.h>
//#include <Emu/Cell/SPUThread.h>
#include "ErrorCodes.h"
//#define SYSCALLS_DEBUG
class SysCallBase
{
private:
wxString m_module_name;
public:
SysCallBase(const wxString& name) : m_module_name(name)
{
}
wxString GetName() { return m_module_name; }
void Log(const u32 id, wxString fmt, ...)
{
#ifdef SYSCALLS_DEBUG
va_list list;
va_start(list, fmt);
ConLog.Write(GetName() + wxString::Format("[%d]: ", id) + wxString::FormatV(fmt, list));
va_end(list);
#endif
}
void Log(wxString fmt, ...)
{
#ifdef SYSCALLS_DEBUG
va_list list;
va_start(list, fmt);
ConLog.Write(GetName() + ": " + wxString::FormatV(fmt, list));
va_end(list);
#endif
}
void Warning(const u32 id, wxString fmt, ...)
{
#ifdef SYSCALLS_DEBUG
va_list list;
va_start(list, fmt);
ConLog.Warning(GetName() + wxString::Format("[%d] warning: ", id) + wxString::FormatV(fmt, list));
va_end(list);
#endif
}
void Warning(wxString fmt, ...)
{
#ifdef SYSCALLS_DEBUG
va_list list;
va_start(list, fmt);
ConLog.Warning(GetName() + wxString::Format(" warning: ") + wxString::FormatV(fmt, list));
va_end(list);
#endif
}
void Error(const u32 id, wxString fmt, ...)
{
va_list list;
va_start(list, fmt);
ConLog.Error(GetName() + wxString::Format("[%d] error: ", id) + wxString::FormatV(fmt, list));
va_end(list);
}
void Error(wxString fmt, ...)
{
va_list list;
va_start(list, fmt);
ConLog.Error(GetName() + wxString::Format(" error: ") + wxString::FormatV(fmt, list));
va_end(list);
}
};
static bool CmpPath(const wxString& path1, const wxString& path2)
{
return path1.Len() >= path2.Len() && path1(0, path2.Len()).CmpNoCase(path2) == 0;
}
static wxString GetWinPath(const wxString& path)
{
if(!CmpPath(path, "/") && CmpPath(path(1, 1), ":")) return path;
wxString ppath = wxFileName(Emu.m_path).GetPath() + '/' + wxFileName(path).GetFullName();
if(wxFileExists(ppath)) return ppath;
if (CmpPath(path, "/dev_hdd0/") ||
CmpPath(path, "/dev_hdd1/") ||
CmpPath(path, "/dev_bdvd/") ||
CmpPath(path, "/dev_usb001/") ||
CmpPath(path, "/ps3_home/") ||
CmpPath(path, "/app_home/") ||
CmpPath(path, "/dev_flash/") ||
CmpPath(path, "/dev_flash2/") ||
CmpPath(path, "/dev_flash3/")
) return wxGetCwd() + path;
return wxFileName(Emu.m_path).GetPath() + (path[0] == '/' ? path : "/" + path);
}
//process
extern int sys_process_getpid();
extern int sys_game_process_exitspawn(u32 path_addr, u32 argv_addr, u32 envp_addr,
u32 data, u32 data_size, int prio, u64 flags );
//memory
extern int sys_memory_container_create(u32 cid_addr, u32 yield_size);
extern int sys_memory_container_destroy(u32 cid);
extern int sys_memory_allocate(u32 size, u32 flags, u32 alloc_addr_addr);
extern int sys_memory_get_user_memory_size(u32 mem_info_addr);
//cellFs
extern int cellFsOpen(const u32 path_addr, const int flags, const u32 fd_addr, const u32 arg_addr, const u64 size);
extern int cellFsRead(const u32 fd, const u32 buf_addr, const u64 nbytes, const u32 nread_addr);
extern int cellFsWrite(const u32 fd, const u32 buf_addr, const u64 nbytes, const u32 nwrite_addr);
extern int cellFsClose(const u32 fd);
extern int cellFsOpendir(const u32 path_addr, const u32 fd_addr);
extern int cellFsReaddir(const u32 fd, const u32 dir_addr, const u32 nread_addr);
extern int cellFsClosedir(const u32 fd);
extern int cellFsStat(const u32 path_addr, const u32 sb_addr);
extern int cellFsFstat(const u32 fd, const u32 sb_addr);
extern int cellFsMkdir(const u32 path_addr, const u32 mode);
extern int cellFsRename(const u32 from_addr, const u32 to_addr);
extern int cellFsRmdir(const u32 path_addr);
extern int cellFsUnlink(const u32 path_addr);
extern int cellFsLseek(const u32 fd, const s64 offset, const u32 whence, const u32 pos_addr);
//cellVideo
extern int cellVideoOutGetState(u32 videoOut, u32 deviceIndex, u32 state_addr);
extern int cellVideoOutGetResolution(u32 resolutionId, u32 resolution_addr);
//cellPad
extern int cellPadInit(u32 max_connect);
extern int cellPadEnd();
extern int cellPadClearBuf(u32 port_no);
extern int cellPadGetData(u32 port_no, u32 data_addr);
extern int cellPadGetDataExtra(u32 port_no, u32 device_type_addr, u32 data_addr);
extern int cellPadSetActDirect(u32 port_no, u32 param_addr);
extern int cellPadGetInfo2(u32 info_addr);
extern int cellPadSetPortSetting(u32 port_no, u32 port_setting);
//cellGcm
extern int cellGcmInit(const u32 context_addr, const u32 cmdSize, const u32 ioSize, const u32 ioAddress);
extern int cellGcmGetConfiguration(const u32 config_addr);
extern int cellGcmAddressToOffset(const u32 address, const u32 offset_addr);
extern int cellGcmSetDisplayBuffer(const u8 id, const u32 offset, const u32 pitch, const u32 width, const u32 height);
extern u32 cellGcmGetLabelAddress(const u32 index);
extern u32 cellGcmGetControlRegister();
extern int cellGcmFlush(const u32 ctx, const u8 id);
extern int cellGcmSetTile(const u8 index, const u8 location, const u32 offset, const u32 size, const u32 pitch, const u8 comp, const u16 base, const u8 bank);
extern int cellGcmGetFlipStatus();
extern int cellGcmResetFlipStatus();
extern u32 cellGcmGetTiledPitchSize(const u32 size);
//cellResc
extern int cellRescSetSrc(const int idx, const u32 src_addr);
extern int cellRescSetBufferAddress(const u32 colorBuffers_addr, const u32 vertexArray_addr, const u32 fragmentShader_addr);
//sys_heap
extern int sys_heap_create_heap(const u32 heap_addr, const u32 start_addr, const u32 size);
extern int sys_heap_malloc(const u32 heap_addr, const u32 size);
//sys_spu
extern int sys_spu_thread_group_create(u64 id_addr, u32 num, int prio, u64 attr_addr);
extern int sys_spu_thread_create(u64 thread_id_addr, u64 entry_addr, u64 arg, int prio, u32 stacksize, u64 flags, u64 threadname_addr);
extern int sys_raw_spu_create(u32 id_addr, u32 attr_addr);
extern int sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu);
//sys_time
extern int sys_time_get_current_time(u32 sec_addr, u32 nsec_addr);
extern s64 sys_time_get_system_time();
extern u64 sys_time_get_timebase_frequency();
#define SC_ARGS_1 CPU.GPR[3]
#define SC_ARGS_2 SC_ARGS_1,CPU.GPR[4]
#define SC_ARGS_3 SC_ARGS_2,CPU.GPR[5]
#define SC_ARGS_4 SC_ARGS_3,CPU.GPR[6]
#define SC_ARGS_5 SC_ARGS_4,CPU.GPR[7]
#define SC_ARGS_6 SC_ARGS_5,CPU.GPR[8]
#define SC_ARGS_7 SC_ARGS_6,CPU.GPR[9]
#define SC_ARGS_8 SC_ARGS_7,CPU.GPR[10]
extern bool dump_enable;
class SysCalls
{
public:
//process
int lv2ProcessGetPid(PPUThread& CPU);
int lv2ProcessWaitForChild(PPUThread& CPU);
int lv2ProcessGetStatus(PPUThread& CPU);
int lv2ProcessDetachChild(PPUThread& CPU);
int lv2ProcessGetNumberOfObject(PPUThread& CPU);
int lv2ProcessGetId(PPUThread& CPU);
int lv2ProcessGetPpid(PPUThread& CPU);
int lv2ProcessKill(PPUThread& CPU);
int lv2ProcessExit(PPUThread& CPU);
int lv2ProcessWaitForChild2(PPUThread& CPU);
int lv2ProcessGetSdkVersion(PPUThread& CPU);
//ppu thread
int lv2PPUThreadCreate(PPUThread& CPU);
int lv2PPUThreadExit(PPUThread& CPU);
int lv2PPUThreadYield(PPUThread& CPU);
int lv2PPUThreadJoin(PPUThread& CPU);
int lv2PPUThreadDetach(PPUThread& CPU);
int lv2PPUThreadGetJoinState(PPUThread& CPU);
int lv2PPUThreadSetPriority(PPUThread& CPU);
int lv2PPUThreadGetPriority(PPUThread& CPU);
int lv2PPUThreadGetStackInformation(PPUThread& CPU);
int lv2PPUThreadRename(PPUThread& CPU);
int lv2PPUThreadRecoverPageFault(PPUThread& CPU);
int lv2PPUThreadGetPageFaultContext(PPUThread& CPU);
int lv2PPUThreadGetId(PPUThread& CPU);
//lwmutex
int Lv2LwmutexCreate(PPUThread& CPU);
int Lv2LwmutexDestroy(PPUThread& CPU);
int Lv2LwmutexLock(PPUThread& CPU);
int Lv2LwmutexTrylock(PPUThread& CPU);
int Lv2LwmutexUnlock(PPUThread& CPU);
//tty
int lv2TtyRead(PPUThread& CPU);
int lv2TtyWrite(PPUThread& CPU);
public:
SysCalls()// : CPU(cpu)
{
}
~SysCalls()
{
Close();
}
void Close()
{
}
s64 DoSyscall(u32 code, PPUThread& CPU)
{
switch(code)
{
//=== lv2 ===
//process
case 1: return sys_process_getpid();
case 2: return lv2ProcessWaitForChild(CPU);
case 3: return lv2ProcessExit(CPU);
case 4: return lv2ProcessGetStatus(CPU);
case 5: return lv2ProcessDetachChild(CPU);
case 12: return lv2ProcessGetNumberOfObject(CPU);
case 13: return lv2ProcessGetId(CPU);
case 18: return lv2ProcessGetPpid(CPU);
case 19: return lv2ProcessKill(CPU);
case 22: return lv2ProcessExit(CPU);
case 23: return lv2ProcessWaitForChild2(CPU);
case 25: return lv2ProcessGetSdkVersion(CPU);
//ppu thread
//case ?: return lv2PPUThreadCreate(CPU);
//case ?: return lv2PPUThreadExit(CPU);
case 43: return lv2PPUThreadYield(CPU);
case 44: return lv2PPUThreadJoin(CPU);
case 45: return lv2PPUThreadDetach(CPU);
case 46: return lv2PPUThreadGetJoinState(CPU);
case 47: return lv2PPUThreadSetPriority(CPU);
case 48: return lv2PPUThreadGetPriority(CPU);
case 49: return lv2PPUThreadGetStackInformation(CPU);
case 56: return lv2PPUThreadRename(CPU);
case 57: return lv2PPUThreadRecoverPageFault(CPU);
case 58: return lv2PPUThreadGetPageFaultContext(CPU);
//case ?: return lv2PPUThreadGetId(CPU);
//lwmutex
case 95: return Lv2LwmutexCreate(CPU);
case 96: return Lv2LwmutexDestroy(CPU);
case 97: return Lv2LwmutexLock(CPU);
case 98: return Lv2LwmutexTrylock(CPU);
case 99: return Lv2LwmutexUnlock(CPU);
//timer
case 141:
case 142:
//wxSleep(Emu.GetCPU().GetThreads().GetCount() > 1 ? 1 : /*SC_ARGS_1*/1);
return 0;
//time
case 145: return sys_time_get_current_time(SC_ARGS_2);
case 146: return sys_time_get_system_time();
case 147: return sys_time_get_timebase_frequency();
//sys_spu
case 160: return sys_raw_spu_create(SC_ARGS_2);
case 169: return sys_spu_initialize(SC_ARGS_2);
case 170: return sys_spu_thread_group_create(SC_ARGS_4);
//memory
case 324: return sys_memory_container_create(SC_ARGS_2);
case 325: return sys_memory_container_destroy(SC_ARGS_1);
case 348: return sys_memory_allocate(SC_ARGS_3);
case 352: return sys_memory_get_user_memory_size(SC_ARGS_1);
//tty
case 402: return lv2TtyRead(CPU);
case 403: return lv2TtyWrite(CPU);
//file system
case 801: return cellFsOpen(SC_ARGS_5);
case 802: return cellFsRead(SC_ARGS_4);
case 803: return cellFsWrite(SC_ARGS_4);
case 804: return cellFsClose(SC_ARGS_1);
case 805: return cellFsOpendir(SC_ARGS_2);
case 806: return cellFsReaddir(SC_ARGS_3);
case 807: return cellFsClosedir(SC_ARGS_1);
case 809: return cellFsFstat(SC_ARGS_2);
case 811: return cellFsMkdir(SC_ARGS_2);
case 812: return cellFsRename(SC_ARGS_2);
case 813: return cellFsRmdir(SC_ARGS_1);
case 818: return cellFsLseek(SC_ARGS_4);
case 988:
ConLog.Warning("SysCall 988! r3: 0x%llx, r4: 0x%llx, pc: 0x%llx",
CPU.GPR[3], CPU.GPR[4], CPU.PC);
return 0;
case 999:
dump_enable = !dump_enable;
ConLog.Warning("Dump %s", dump_enable ? "enabled" : "disabled");
return 0;
}
ConLog.Error("Unknown syscall: %d - %08x", code, code);
return 0;
}
s64 DoFunc(const u32 id, PPUThread& CPU);
};
extern SysCalls SysCallsManager;

View File

@ -0,0 +1,367 @@
#include "stdafx.h"
#include "Emu/SysCalls/SysCalls.h"
typedef u64 GPRtype;
enum Lv2FsOflag
{
LV2_O_RDONLY = 000000,
LV2_O_WRONLY = 000001,
LV2_O_RDWR = 000002,
LV2_O_ACCMODE = 000003,
LV2_O_CREAT = 000100,
LV2_O_EXCL = 000200,
LV2_O_TRUNC = 001000,
LV2_O_APPEND = 002000,
LV2_O_MSELF = 010000,
};
#define CELL_FS_TYPE_UNKNOWN 0
enum Lv2FsSeek
{
LV2_SEEK_SET,
LV2_SEEK_CUR,
LV2_SEEK_END,
};
enum Lv2FsLength
{
LV2_MAX_FS_PATH_LENGTH = 1024,
LV2_MAX_FS_FILE_NAME_LENGTH = 255,
LV2_MAX_FS_MP_LENGTH = 31,
};
enum
{
CELL_FS_S_IFDIR = 0040000, //directory
CELL_FS_S_IFREG = 0100000, //regular
CELL_FS_S_IFLNK = 0120000, //symbolic link
CELL_FS_S_IFWHT = 0160000, //unknown
CELL_FS_S_IRUSR = 0000400, //R for owner
CELL_FS_S_IWUSR = 0000200, //W for owner
CELL_FS_S_IXUSR = 0000100, //X for owner
CELL_FS_S_IRGRP = 0000040, //R for group
CELL_FS_S_IWGRP = 0000020, //W for group
CELL_FS_S_IXGRP = 0000010, //X for group
CELL_FS_S_IROTH = 0000004, //R for other
CELL_FS_S_IWOTH = 0000002, //W for other
CELL_FS_S_IXOTH = 0000001, //X for other
};
struct Lv2FsStat
{
u32 st_mode;
s32 st_uid;
s32 st_gid;
time_t st_atime;
time_t st_mtime;
time_t st_ctime;
u64 st_size;
u64 st_blksize;
};
struct Lv2FsUtimbuf
{
time_t actime;
time_t modtime;
};
struct Lv2FsDirent
{
u8 d_type;
u8 d_namlen;
char d_name[LV2_MAX_FS_FILE_NAME_LENGTH + 1];
};
enum FsDirentType
{
CELL_FS_TYPE_DIRECTORY = 1,
CELL_FS_TYPE_REGULAR = 2,
CELL_FS_TYPE_SYMLINK = 3,
};
SysCallBase sc_log("cellFs");
wxString ReadString(const u32 addr)
{
return GetWinPath(Memory.ReadString(addr));
}
int cellFsOpen(const u32 path_addr, const int flags, const u32 fd_addr, const u32 arg_addr, const u64 size)
{
const wxString& path = Memory.ReadString(path_addr);
sc_log.Log("cellFsOpen(path: %s, flags: 0x%x, fd_addr: 0x%x, arg_addr: 0x%x, size: 0x%llx)",
path, flags, fd_addr, arg_addr, size);
const wxString& ppath = GetWinPath(path);
//ConLog.Warning("path: %s [%s]", ppath, path);
s32 _oflags = flags;
if(flags & LV2_O_CREAT)
{
_oflags &= ~LV2_O_CREAT;
//create path
for(uint p=1;p<ppath.Length();p++)
{
for(;p<ppath.Length(); p++) if(ppath[p] == '/') break;
if(p == ppath.Length()) break;
const wxString& dir = ppath(0, p);
if(!wxDirExists(dir))
{
ConLog.Write("create dir: %s", dir);
wxMkdir(dir);
}
}
//create file
if(!wxFileExists(ppath))
{
wxFile f;
f.Create(ppath);
f.Close();
}
}
wxFile::OpenMode o_mode;
switch(flags & LV2_O_ACCMODE)
{
case LV2_O_RDONLY:
_oflags &= ~LV2_O_RDONLY;
o_mode = wxFile::read;
break;
case LV2_O_WRONLY:
_oflags &= ~LV2_O_WRONLY;
if(flags & LV2_O_APPEND)
{
_oflags &= ~LV2_O_APPEND;
o_mode = wxFile::write_append;
}
else if(flags & LV2_O_EXCL)
{
_oflags &= ~LV2_O_EXCL;
o_mode = wxFile::write_excl;
}
else //if(flags & LV2_O_TRUNC)
{
_oflags &= ~LV2_O_TRUNC;
o_mode = wxFile::write;
}
break;
case LV2_O_RDWR:
_oflags &= ~LV2_O_RDWR;
o_mode = wxFile::read_write;
break;
}
if(_oflags != 0)
{
sc_log.Error("'%s' has unknown flags! flags: 0x%08x", ppath, flags);
return CELL_EINVAL;
}
if(!wxFile::Access(ppath, o_mode))
{
sc_log.Error("'%s' not found! flags: 0x%08x", ppath, flags);
return CELL_ENOENT;
}
Memory.Write32(fd_addr,
Emu.GetIdManager().GetNewID(sc_log.GetName(), new wxFile(ppath, o_mode), flags));
return CELL_OK;
}
int cellFsRead(const u32 fd, const u32 buf_addr, const u64 nbytes, const u32 nread_addr)
{
sc_log.Log("cellFsRead(fd: %d, buf_addr: 0x%x, nbytes: 0x%llx, nread_addr: 0x%x)",
fd, buf_addr, nbytes, nread_addr);
if(!Emu.GetIdManager().CheckID(fd)) return CELL_ESRCH;
const ID& id = Emu.GetIdManager().GetIDData(fd);
if(!!id.m_name.Cmp(sc_log.GetName())) return CELL_ESRCH;
wxFile& file = *(wxFile*)id.m_data;
Memory.Write64NN(nread_addr, file.Read(Memory.GetMemFromAddr(buf_addr), nbytes));
return CELL_OK;
}
int cellFsWrite(const u32 fd, const u32 buf_addr, const u64 nbytes, const u32 nwrite_addr)
{
sc_log.Log("cellFsWrite(fd: %d, buf_addr: 0x%x, nbytes: 0x%llx, nwrite_addr: 0x%x)",
fd, buf_addr, nbytes, nwrite_addr);
if(!Emu.GetIdManager().CheckID(fd)) return CELL_ESRCH;
const ID& id = Emu.GetIdManager().GetIDData(fd);
if(!!id.m_name.Cmp(sc_log.GetName())) return CELL_ESRCH;
wxFile& file = *(wxFile*)id.m_data;
Memory.Write64NN(nwrite_addr, file.Write(Memory.GetMemFromAddr(buf_addr), nbytes));
return CELL_OK;
}
int cellFsClose(const u32 fd)
{
sc_log.Log("cellFsClose(fd: %d)", fd);
if(!Emu.GetIdManager().CheckID(fd)) return CELL_ESRCH;
const ID& id = Emu.GetIdManager().GetIDData(fd);
if(!!id.m_name.Cmp(sc_log.GetName())) return CELL_ESRCH;
wxFile& file = *(wxFile*)id.m_data;
file.Close();
Emu.GetIdManager().RemoveID(fd);
return CELL_OK;
}
int cellFsOpendir(const u32 path_addr, const u32 fd_addr)
{
const wxString& path = Memory.ReadString(path_addr);
sc_log.Error("cellFsOpendir(path: %s, fd_addr: 0x%x)", path, fd_addr);
return CELL_OK;
}
int cellFsReaddir(const u32 fd, const u32 dir_addr, const u32 nread_addr)
{
sc_log.Error("cellFsReaddir(fd: %d, dir_addr: 0x%x, nread_addr: 0x%x)", fd, dir_addr, nread_addr);
return CELL_OK;
}
int cellFsClosedir(const u32 fd)
{
sc_log.Error("cellFsClosedir(fd: %d)", fd);
return CELL_OK;
}
int cellFsStat(const u32 path_addr, const u32 sb_addr)
{
const wxString& path = ReadString(path_addr);
sc_log.Log("cellFsFstat(path: %s, sb_addr: 0x%x)", path, sb_addr);
if(!wxFileExists(path)) return CELL_ENOENT;
Lv2FsStat stat;
stat.st_mode =
CELL_FS_S_IRUSR | CELL_FS_S_IWUSR | CELL_FS_S_IXUSR |
CELL_FS_S_IRGRP | CELL_FS_S_IWGRP | CELL_FS_S_IXGRP |
CELL_FS_S_IROTH | CELL_FS_S_IWOTH | CELL_FS_S_IXOTH;
stat.st_mode |= CELL_FS_S_IFREG; //TODO: dir CELL_FS_S_IFDIR
stat.st_uid = 0;
stat.st_gid = 0;
stat.st_atime = 0; //TODO
stat.st_mtime = 0; //TODO
stat.st_ctime = 0; //TODO
stat.st_size = wxFile(path).Length();
stat.st_blksize = 4096;
mem_class_t stat_c(sb_addr);
stat_c += stat.st_mode;
stat_c += stat.st_uid;
stat_c += stat.st_gid;
stat_c += stat.st_atime;
stat_c += stat.st_mtime;
stat_c += stat.st_ctime;
stat_c += stat.st_size;
stat_c += stat.st_blksize;
return CELL_OK;
}
int cellFsFstat(u32 fd, u32 sb_addr)
{
sc_log.Log("cellFsFstat(fd: %d, sb_addr: 0x%x)", fd, sb_addr);
if(!Emu.GetIdManager().CheckID(fd)) return CELL_ESRCH;
const ID& id = Emu.GetIdManager().GetIDData(fd);
if(!!id.m_name.Cmp(sc_log.GetName())) return CELL_ESRCH;
wxFile& file = *(wxFile*)id.m_data;
Lv2FsStat stat;
stat.st_mode =
CELL_FS_S_IRUSR | CELL_FS_S_IWUSR | CELL_FS_S_IXUSR |
CELL_FS_S_IRGRP | CELL_FS_S_IWGRP | CELL_FS_S_IXGRP |
CELL_FS_S_IROTH | CELL_FS_S_IWOTH | CELL_FS_S_IXOTH;
stat.st_mode |= CELL_FS_S_IFREG; //TODO: dir CELL_FS_S_IFDIR
stat.st_uid = 0;
stat.st_gid = 0;
stat.st_atime = 0; //TODO
stat.st_mtime = 0; //TODO
stat.st_ctime = 0; //TODO
stat.st_size = file.Length();
stat.st_blksize = 4096;
mem_class_t stat_c(sb_addr);
stat_c += stat.st_mode;
stat_c += stat.st_uid;
stat_c += stat.st_gid;
stat_c += stat.st_atime;
stat_c += stat.st_mtime;
stat_c += stat.st_ctime;
stat_c += stat.st_size;
stat_c += stat.st_blksize;
return CELL_OK;
}
int cellFsMkdir(const u32 path_addr, const u32 mode)
{
const wxString& path = ReadString(path_addr);
sc_log.Log("cellFsMkdir(path: %s, mode: 0x%x)", path, mode);
if(wxDirExists(path)) return CELL_EEXIST;
if(!wxMkdir(path)) return CELL_EBUSY;
return CELL_OK;
}
int cellFsRename(const u32 from_addr, const u32 to_addr)
{
const wxString& from = ReadString(from_addr);
const wxString& to = ReadString(to_addr);
sc_log.Log("cellFsRename(from: %s, to: %s)", from, to);
if(!wxFileExists(from)) return CELL_ENOENT;
if(wxFileExists(to)) return CELL_EEXIST;
if(!wxRenameFile(from, to)) return CELL_EBUSY;
return CELL_OK;
}
int cellFsRmdir(const u32 path_addr)
{
const wxString& path = ReadString(path_addr);
sc_log.Log("cellFsRmdir(path: %s)", path);
if(!wxDirExists(path)) return CELL_ENOENT;
if(!wxRmdir(path)) return CELL_EBUSY;
return CELL_OK;
}
int cellFsUnlink(const u32 path_addr)
{
const wxString& path = ReadString(path_addr);
sc_log.Error("cellFsUnlink(path: %s)", path);
return CELL_OK;
}
int cellFsLseek(const u32 fd, const s64 offset, const u32 whence, const u32 pos_addr)
{
wxSeekMode seek_mode;
sc_log.Log("cellFsLseek(fd: %d, offset: 0x%llx, whence: %d, pos_addr: 0x%x)", fd, offset, whence, pos_addr);
switch(whence)
{
case LV2_SEEK_SET: seek_mode = wxFromStart; break;
case LV2_SEEK_CUR: seek_mode = wxFromCurrent; break;
case LV2_SEEK_END: seek_mode = wxFromEnd; break;
default:
sc_log.Error(fd, "Unknown seek whence! (%d)", whence);
return CELL_EINVAL;
}
if(!Emu.GetIdManager().CheckID(fd)) return CELL_ESRCH;
const ID& id = Emu.GetIdManager().GetIDData(fd);
if(!!id.m_name.Cmp(sc_log.GetName())) return CELL_ESRCH;
wxFile& file = *(wxFile*)id.m_data;
Memory.Write64(pos_addr, file.Seek(offset, seek_mode));
return CELL_OK;
}

View File

@ -0,0 +1,133 @@
#include "stdafx.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/GS/GCM.h"
SysCallBase sc_gcm("cellGcm");
CellGcmConfig current_config;
CellGcmContextData current_context;
gcmInfo gcm_info;
int cellGcmInit(const u32 context_addr, const u32 cmdSize, const u32 ioSize, const u32 ioAddress)
{
sc_gcm.Log("cellGcmInit(context_addr=0x%x,cmdSize=0x%x,ioSize=0x%x,ioAddress=0x%x)", context_addr, cmdSize, ioSize, ioAddress);
const u32 local_size = 0xf900000; //TODO
const u32 local_addr = Memory.RSXFBMem.GetStartAddr();
current_config.ioSize = re32(ioSize);
current_config.ioAddress = re32(ioAddress);
current_config.localSize = re32(local_size);
current_config.localAddress = re32(local_addr);
current_config.memoryFrequency = re32(650000000);
current_config.coreFrequency = re32(500000000);
Memory.RSXFBMem.Alloc(local_size);
Memory.RSXCMDMem.Alloc(cmdSize);
u32 ctx_begin = ioAddress + 0x1000;
u32 ctx_size = 0x6ffc;
current_context.begin = re(ctx_begin);
current_context.end = re(ctx_begin + ctx_size);
current_context.current = current_context.begin;
current_context.callback = re32(Emu.GetRSXCallback() - 4);
gcm_info.context_addr = Memory.MainMem.Alloc(0x1000);
gcm_info.control_addr = gcm_info.context_addr + 0x40;
Memory.WriteData(gcm_info.context_addr, current_context);
Memory.Write32(context_addr, gcm_info.context_addr);
CellGcmControl& ctrl = *(CellGcmControl*)Memory.GetMemFromAddr(gcm_info.control_addr);
ctrl.put = 0;
ctrl.get = 0;
ctrl.ref = -1;
Emu.GetGSManager().GetRender().Init(ctx_begin, ctx_size, gcm_info.control_addr, local_addr);
return CELL_OK;
}
int cellGcmGetConfiguration(const u32 config_addr)
{
sc_gcm.Log("cellGcmGetConfiguration(config_addr=0x%x)", config_addr);
Memory.WriteData(config_addr, current_config);
return CELL_OK;
}
int cellGcmAddressToOffset(const u32 address, const u32 offset_addr)
{
sc_gcm.Log("cellGcmAddressToOffset(address=0x%x,offset_addr=0x%x)", address, offset_addr);
Memory.Write32(offset_addr,
Memory.RSXFBMem.IsInMyRange(address)
? address - Memory.RSXFBMem.GetStartAddr()
: address - re(current_context.begin));
return CELL_OK;
}
int cellGcmSetDisplayBuffer(const u8 id, const u32 offset, const u32 pitch, const u32 width, const u32 height)
{
sc_gcm.Log("cellGcmSetDisplayBuffer(id=0x%x,offset=0x%x,pitch=%d,width=%d,height=%d)",
id, offset, width ? pitch/width : pitch, width, height);
if(id > 1) return CELL_EINVAL;
gcmBuffers[id].offset = offset;
gcmBuffers[id].pitch = pitch;
gcmBuffers[id].width = width;
gcmBuffers[id].height = height;
gcmBuffers[id].update = true;
return CELL_OK;
}
u32 cellGcmGetLabelAddress(const u32 index)
{
sc_gcm.Log("cellGcmGetLabelAddress(index=%d)", index);
return Memory.RSXCMDMem.GetStartAddr() + 0x10 * index;
}
u32 cellGcmGetControlRegister()
{
sc_gcm.Log("cellGcmGetControlRegister()");
return gcm_info.control_addr;
}
int cellGcmFlush(const u32 ctx, const u8 id)
{
sc_gcm.Log("cellGcmFlush(ctx=0x%x, id=0x%x)", ctx, id);
if(id > 1) return CELL_EINVAL;
Emu.GetGSManager().GetRender().Draw();
return CELL_OK;
}
int cellGcmSetTile(const u8 index, const u8 location, const u32 offset, const u32 size,
const u32 pitch, const u8 comp, const u16 base, const u8 bank)
{
sc_gcm.Log("cellGcmSetTile(index=%d, location=%d, offset=0x%x, size=0x%x, pitch=0x%x, comp=0x%x, base=0x%x, bank=0x%x)",
index, location, offset, size, pitch, comp, base, bank);
return CELL_OK;
}
int cellGcmGetFlipStatus()
{
return Emu.GetGSManager().GetRender().m_flip_status;
}
int cellGcmResetFlipStatus()
{
Emu.GetGSManager().GetRender().m_flip_status = 1;
return CELL_OK;
}
u32 cellGcmGetTiledPitchSize(const u32 size)
{
//TODO
sc_gcm.Log("cellGcmGetTiledPitchSize(size=%d)", size);
return size;
}

View File

@ -0,0 +1,35 @@
#include "stdafx.h"
#include "Emu/SysCalls/SysCalls.h"
SysCallBase sc_heap("sys_heap");
struct HeapInfo
{
u32 heap_addr;
u32 align;
u32 size;
HeapInfo(u32 _heap_addr, u32 _align, u32 _size)
: heap_addr(_heap_addr)
, align(_align)
, size(_size)
{
}
};
int sys_heap_create_heap(const u32 heap_addr, const u32 align, const u32 size)
{
sc_heap.Warning("sys_heap_create_heap(heap_addr=0x%x, align=0x%x, size=0x%x)", heap_addr, align, size);
return Emu.GetIdManager().GetNewID(sc_heap.GetName(), new HeapInfo(heap_addr, align, size));
}
int sys_heap_malloc(const u32 heap_id, const u32 size)
{
sc_heap.Warning("sys_heap_malloc(heap_id=0x%x, size=0x%x)", heap_id, size);
if(!Emu.GetIdManager().CheckID(heap_id)) return CELL_ESRCH;
const ID& id = Emu.GetIdManager().GetIDData(heap_id);
if(!!id.m_name.Cmp(sc_heap.GetName())) return CELL_ESRCH;
const HeapInfo& heap = *(HeapInfo*)id.m_data;
return Memory.Alloc(size, heap.align);
}

View File

@ -0,0 +1,105 @@
#include "stdafx.h"
#include "Emu/SysCalls/SysCalls.h"
struct lwmutex_lock_info
{
u32 owner;
u32 waiter;
};
union lwmutex_variable
{
lwmutex_lock_info info;
u64 all_info;
};
struct lwmutex
{
lwmutex_variable lock_var;
u32 attribute;
u32 recursive_count;
u32 sleep_queue;
u32 pad;
};
struct lwmutex_attr
{
u32 attr_protocol;
u32 attr_recursive;
char name[8];
};
SysCallBase sc_lwmutex("Lwmutex");
//TODO
int SysCalls::Lv2LwmutexCreate(PPUThread& CPU)
{
/*
//int sys_lwmutex_create(sys_lwmutex_t *lwmutex, sys_lwmutex_attribute_t *attr)
const u64 lwmutex_addr = CPU.GPR[3];
const u64 lwmutex_attr_addr = CPU.GPR[4];
//ConLog.Write("Lv2LwmutexCreate[r3: 0x%llx, r4: 0x%llx]", lwmutex_addr, lwmutex_attr_addr);
lwmutex& lmtx = *(lwmutex*)Memory.GetMemFromAddr(lwmutex_addr);
lwmutex_attr& lmtx_attr = *(lwmutex_attr*)Memory.GetMemFromAddr(lwmutex_attr_addr);
lmtx.lock_var.info.owner = CPU.GetId();
lmtx.attribute = Emu.GetIdManager().GetNewID(wxString::Format("Lwmutex[%s]", lmtx_attr.name), NULL, lwmutex_addr);
*/
/*
ConLog.Write("r3:");
ConLog.Write("*** lock_var[owner: 0x%x, waiter: 0x%x]", lmtx.lock_var.info.owner, lmtx.lock_var.info.waiter);
ConLog.Write("*** attribute: 0x%x", lmtx.attribute);
ConLog.Write("*** recursive_count: 0x%x", lmtx.recursive_count);
ConLog.Write("*** sleep_queue: 0x%x", lmtx.sleep_queue);
ConLog.Write("r4:");
ConLog.Write("*** attr_protocol: 0x%x", lmtx_attr.attr_protocol);
ConLog.Write("*** attr_recursive: 0x%x", lmtx_attr.attr_recursive);
ConLog.Write("*** name: %s", lmtx_attr.name);
*/
return 0;
}
int SysCalls::Lv2LwmutexDestroy(PPUThread& CPU)
{
/*
const u64 lwmutex_addr = CPU.GPR[3];
//ConLog.Write("Lv2LwmutexDestroy[r3: 0x%llx]", lwmutex_addr);
lwmutex& lmtx = *(lwmutex*)Memory.GetMemFromAddr(lwmutex_addr);
Emu.GetIdManager().RemoveID(lmtx.attribute);
//memset(Memory.GetMemFromAddr(lwmutex_addr), 0, sizeof(lwmutex));
*/
return 0;
}
int SysCalls::Lv2LwmutexLock(PPUThread& CPU)
{
//int sys_lwmutex_lock(sys_lwmutex_t *lwmutex, usecond_t timeout)
const u64 lwmutex_addr = CPU.GPR[3];
const u64 timeout = CPU.GPR[4];
//ConLog.Write("Lv2LwmutexLock[r3: 0x%llx, r4: 0x%llx]", lwmutex_addr, timeout);
//lwmutex& lmtx = *(lwmutex*)Memory.GetMemFromAddr(lwmutex_addr);
//lmtx.lock_var.info.waiter = CPU.GetId();
return 0;//CELL_ESRCH;
}
int SysCalls::Lv2LwmutexTrylock(PPUThread& CPU)
{
//int sys_lwmutex_trylock(sys_lwmutex_t *lwmutex)
const u64 lwmutex_addr = CPU.GPR[3];
//ConLog.Write("Lv2LwmutexTrylock[r3: 0x%llx]", lwmutex_addr);
return 0;
}
int SysCalls::Lv2LwmutexUnlock(PPUThread& CPU)
{
//int sys_lwmutex_unlock(sys_lwmutex_t *lwmutex)
const u64 lwmutex_addr = CPU.GPR[3];
//ConLog.Write("Lv2LwmutexUnlock[r3: 0x%llx]", lwmutex_addr);
return 0;
}

View File

@ -0,0 +1,217 @@
#include "stdafx.h"
#include "Emu/SysCalls/SysCalls.h"
/*
struct MemContiner
{
u8* continer;
u32 num;
void Create(u32 size)
{
continer = new u8[size];
}
void Delete()
{
if(continer != NULL) free(continer);
}
~MemContiner()
{
Delete();
}
};
class MemContiners : private SysCallBase
{
SysCallsArraysList<MemContiner> continers;
public:
MemContiners() : SysCallBase("MemContainers")
{
}
u64 AddContiner(const u64 size)
{
const u64 id = continers.Add();
bool error;
MemContiner& data = *continers.GetDataById(id, &error);
if(error)
{
ConLog.Error("%s error: id [%d] is not found!", module_name, id);
return 0;
}
data.Create(size);
return id;
}
void DeleteContiner(const u64 id)
{
bool error;
MemContiner& data = *continers.GetDataById(id, &error);
if(error)
{
ConLog.Error("%s error: id [%d] is not found!", module_name, id);
return;
}
data.Delete();
continers.RemoveById(id);
}
};
MemContiners continers;
*/
/*
int SysCalls::lv2MemContinerCreate(PPUThread& CPU)
{
u64& continer = CPU.GPR[3];
u32 size = CPU.GPR[4];
ConLog.Warning("lv2MemContinerCreate[size: 0x%x]", size);
//continer = continers.AddContiner(size);
return 0;
}
int SysCalls::lv2MemContinerDestroy(PPUThread& CPU)
{
u32 container = CPU.GPR[3];
ConLog.Warning("lv2MemContinerDestroy[container: 0x%x]", container);
//continers.DeleteContiner(container);
return 0;
}*/
/*
static const u32 max_user_mem = 0x0d500000; //100mb
u32 free_user_mem = max_user_mem;
static u64 addr_user_mem = 0;
struct MemoryInfo
{
u32 free_user_mem;
u32 aviable_user_mem;
};
enum
{
SYS_MEMORY_PAGE_SIZE_1M = 0x400,
SYS_MEMORY_PAGE_SIZE_64K = 0x200,
};
int SysCalls::sys_memory_allocate(u32 size, u64 flags, u64 alloc_addr)
{
//int sys_memory_allocate(size_t size, uint64_t flags, sys_addr_t * alloc_addr);
const u64 size = CPU.GPR[3];
const u64 flags = CPU.GPR[4];
const u64 alloc_addr = CPU.GPR[5];
ConLog.Write("lv2MemAllocate: size: 0x%llx, flags: 0x%llx, alloc_addr: 0x%llx", size, flags, alloc_addr);
//u32 addr = 0;
switch(flags)
{
case SYS_MEMORY_PAGE_SIZE_1M:
if(size & 0xfffff) return CELL_EALIGN;
//addr = Memory.Alloc(size, 0x100000);
break;
case SYS_MEMORY_PAGE_SIZE_64K:
if(size & 0xffff) return CELL_EALIGN;
//addr = Memory.Alloc(size, 0x10000);
break;
default: return CELL_EINVAL;
}
u32 num = Memory.MemoryBlocks.GetCount();
Memory.MemoryBlocks.Add(new MemoryBlock());
Memory.MemoryBlocks[num].SetRange(Memory.MemoryBlocks[num - 1].GetEndAddr(), size);
Memory.Write32(alloc_addr, Memory.MemoryBlocks[num].GetStartAddr());
ConLog.Write("Test...");
Memory.Write32(Memory.MemoryBlocks[num].GetStartAddr(), 0xfff);
if(Memory.Read32(Memory.MemoryBlocks[num].GetStartAddr()) != 0xfff)
{
ConLog.Write("Test faild");
}
else
{
ConLog.Write("Test OK");
Memory.Write32(Memory.MemoryBlocks[num].GetStartAddr(), 0x0);
}
return CELL_OK;
}
int SysCalls::sys_memory_get_user_memory_size(PPUThread& CPU)
{
ConLog.Write("lv2MemGetUserMemorySize: r3=0x%llx", CPU.GPR[3]);
//int sys_memory_get_user_memory_size(sys_memory_info_t * mem_info);
MemoryInfo& memoryinfo = *(MemoryInfo*)Memory.GetMemFromAddr(CPU.GPR[3]);
memoryinfo.aviable_user_mem = Memory.Reverse32(free_user_mem);
memoryinfo.free_user_mem = Memory.Reverse32(free_user_mem);
return CELL_OK;
}*/
SysCallBase sc_mem("memory");
enum
{
SYS_MEMORY_PAGE_SIZE_1M = 0x400,
SYS_MEMORY_PAGE_SIZE_64K = 0x200,
};
int sys_memory_container_create(u32 cid_addr, u32 yield_size)
{
sc_mem.Warning("TODO: sys_memory_container_create(cid_addr=0x%x,yield_size=0x%x)", cid_addr, yield_size);
return CELL_OK;
}
int sys_memory_container_destroy(u32 cid)
{
sc_mem.Warning("TODO: sys_memory_container_destroy(cid=0x%x)", cid);
return CELL_OK;
}
int sys_memory_allocate(u32 size, u32 flags, u32 alloc_addr_addr)
{
//0x30000100;
sc_mem.Log("sys_memory_allocate(size=0x%x, flags=0x%x)", size, flags);
u32 addr;
switch(flags)
{
case SYS_MEMORY_PAGE_SIZE_1M:
if(size & 0xfffff) return CELL_EALIGN;
addr = Memory.Alloc(size, 0x100000);
break;
case SYS_MEMORY_PAGE_SIZE_64K:
if(size & 0xffff) return CELL_EALIGN;
addr = Memory.Alloc(size, 0x10000);
break;
default: return CELL_EINVAL;
}
if(!addr) return CELL_ENOMEM;
sc_mem.Log("Memory allocated! [addr: 0x%x, size: 0x%x]", addr, size);
Memory.Write32(alloc_addr_addr, addr);
return CELL_OK;
}
struct sys_memory_info
{
u32 total_user_memory;
u32 available_user_memory;
};
int sys_memory_get_user_memory_size(u32 mem_info_addr)
{
sys_memory_info info;
info.total_user_memory = re(Memory.GetUserMemTotalSize());
info.available_user_memory = re(Memory.GetUserMemAvailSize());
Memory.WriteData(mem_info_addr, info);
return CELL_OK;
}

View File

@ -0,0 +1,126 @@
#include "stdafx.h"
#include "Emu/SysCalls/SysCalls.h"
#define PPU_THREAD_ID_INVALID 0xFFFFFFFFU
int SysCalls::lv2PPUThreadCreate(PPUThread& CPU)
{
ConLog.Write("lv2PPUThreadCreate:");
//ConLog.Write("**** id: %d", CPU.GPR[3]);
ConLog.Write("**** entry: 0x%x", CPU.GPR[4]);
ConLog.Write("**** arg: 0x%x", CPU.GPR[5]);
ConLog.Write("**** prio: 0x%x", CPU.GPR[6]);
ConLog.Write("**** stacksize: 0x%x", CPU.GPR[7]);
ConLog.Write("**** flags: 0x%x", CPU.GPR[8]);
ConLog.Write("**** threadname: \"%s\"[0x%x]", Memory.ReadString(CPU.GPR[9]), CPU.GPR[9]);
if(!Memory.IsGoodAddr(CPU.GPR[4])) return CELL_EFAULT;
PPCThread& new_thread = Emu.GetCPU().AddThread(true);
Memory.Write32(CPU.GPR[3], new_thread.GetId());
new_thread.SetPc(CPU.GPR[4]);
new_thread.SetArg(CPU.GPR[5]);
new_thread.SetPrio(CPU.GPR[6]);
new_thread.stack_size = CPU.GPR[7];
//new_thread.flags = CPU.GPR[8];
new_thread.SetName(Memory.ReadString(CPU.GPR[9]));
new_thread.Run();
return CELL_OK;
}
int SysCalls::lv2PPUThreadExit(PPUThread& CPU)
{
ConLog.Warning("PPU[%d] thread exit(%lld)", CPU.GetId(), CPU.GPR[3]);
Emu.GetCPU().RemoveThread(CPU.GetId());
return CELL_OK;
}
int SysCalls::lv2PPUThreadYield(PPUThread& CPU)
{
//ConLog.Warning("TODO: PPU[%d] thread yield!", CPU.GetId());
return CELL_OK;
}
int SysCalls::lv2PPUThreadJoin(PPUThread& CPU)
{
ConLog.Warning("TODO: PPU[%d] thread join!", CPU.GPR[3]);
return CELL_OK;
}
int SysCalls::lv2PPUThreadDetach(PPUThread& CPU)
{
ConLog.Warning("PPU[%d] thread detach", CPU.GPR[3]);
if(!Emu.GetIdManager().CheckID(CPU.GPR[3])) return CELL_ESRCH;
const ID& id = Emu.GetIdManager().GetIDData(CPU.GPR[3]);
if(!id.m_used) return CELL_ESRCH;
PPCThread& thread = *(PPCThread*)id.m_data;
if(thread.IsJoinable()) return CELL_EINVAL;
if(thread.IsJoining()) return CELL_EBUSY;
thread.SetJoinable(false);
if(!thread.IsRunned()) Emu.GetCPU().RemoveThread(thread.GetId());
return CELL_OK;
}
int SysCalls::lv2PPUThreadGetJoinState(PPUThread& CPU)
{
ConLog.Warning("PPU[%d] get join state", CPU.GetId());
Memory.Write32(CPU.GPR[3], CPU.IsJoinable() ? 1 : 0);
return CELL_OK;
}
int SysCalls::lv2PPUThreadSetPriority(PPUThread& CPU)
{
ConLog.Write("PPU[%d] thread set priority", CPU.GPR[3]);
if(!Emu.GetIdManager().CheckID(CPU.GPR[3])) return CELL_ESRCH;
const ID& id = Emu.GetIdManager().GetIDData(CPU.GPR[3]);
CPU.SetPrio(CPU.GPR[4]);
return CELL_OK;
}
int SysCalls::lv2PPUThreadGetPriority(PPUThread& CPU)
{
ConLog.Write("PPU[%d] thread get priority", CPU.GPR[3]);
if(!Emu.GetIdManager().CheckID(CPU.GPR[3])) return CELL_ESRCH;
const ID& id = Emu.GetIdManager().GetIDData(CPU.GPR[3]);
Memory.Write32(CPU.GPR[4], CPU.GetPrio());
return CELL_OK;
}
int SysCalls::lv2PPUThreadGetStackInformation(PPUThread& CPU)
{
ConLog.Write("PPU[%d] thread get stack information(0x%llx)", CPU.GetId(), CPU.GPR[3]);
Memory.Write32(CPU.GPR[3], CPU.GetStackAddr());
Memory.Write32(CPU.GPR[3]+4, CPU.GetStackSize());
return CELL_OK;
}
int SysCalls::lv2PPUThreadRename(PPUThread& CPU)
{
ConLog.Write("PPU[%d] thread rename(%s)", CPU.GPR[3], Memory.ReadString(CPU.GPR[4]));
return CELL_OK;
}
int SysCalls::lv2PPUThreadRecoverPageFault(PPUThread& CPU)
{
ConLog.Warning("TODO: PPU[%d] thread recover page fault!", CPU.GPR[3]);
return CELL_OK;
}
int SysCalls::lv2PPUThreadGetPageFaultContext(PPUThread& CPU)
{
ConLog.Warning("TODO: PPU[%d] thread get page fault context!", CPU.GPR[3]);
return CELL_OK;
}
int SysCalls::lv2PPUThreadGetId(PPUThread& CPU)
{
//ConLog.Write("PPU[%d] thread get id(0x%llx)", CPU.GetId(), CPU.GPR[3]);
Memory.Write64(CPU.GPR[3], CPU.GetId());
return CELL_OK;
}
int sys_spu_thread_once(u64 once_ctrl_addr, u64 init_addr)
{
return 0;
}

View File

@ -0,0 +1,176 @@
#include "stdafx.h"
#include "Emu/Io/Pad.h"
#include "Emu/SysCalls/SysCalls.h"
SysCallBase sc_pad("cellPad");
enum CELL_PAD_ERROR_CODE
{
CELL_PAD_ERROR_FATAL = 0x80121101,
CELL_PAD_ERROR_INVALID_PARAMETER = 0x80121102,
CELL_PAD_ERROR_ALREADY_INITIALIZED = 0x80121103,
CELL_PAD_ERROR_UNINITIALIZED = 0x80121104,
CELL_PAD_ERROR_RESOURCE_ALLOCATION_FAILED = 0x80121105,
CELL_PAD_ERROR_DATA_READ_FAILED = 0x80121106,
CELL_PAD_ERROR_NO_DEVICE = 0x80121107,
CELL_PAD_ERROR_UNSUPPORTED_GAMEPAD = 0x80121108,
CELL_PAD_ERROR_TOO_MANY_DEVICES = 0x80121109,
CELL_PAD_ERROR_EBUSY = 0x8012110a,
};
struct CellPadData
{
s32 len;
u16 button[CELL_PAD_MAX_CODES];
};
struct CellPadInfo2
{
u32 max_connect;
u32 now_connect;
u32 system_info;
u32 port_status[CELL_PAD_MAX_PORT_NUM];
u32 port_setting[CELL_PAD_MAX_PORT_NUM];
u32 device_capability[CELL_PAD_MAX_PORT_NUM];
u32 device_type[CELL_PAD_MAX_PORT_NUM];
};
int cellPadInit(u32 max_connect)
{
sc_pad.Log("cellPadInit(max_connect=%d)", max_connect);
if(Emu.GetPadManager().IsInited()) return CELL_PAD_ERROR_ALREADY_INITIALIZED;
Emu.GetPadManager().Init(max_connect);
return CELL_OK;
}
int cellPadEnd()
{
sc_pad.Log("cellPadEnd()");
if(!Emu.GetPadManager().IsInited()) return CELL_PAD_ERROR_UNINITIALIZED;
Emu.GetPadManager().Close();
return CELL_OK;
}
int cellPadClearBuf(u32 port_no)
{
sc_pad.Log("cellPadClearBuf(port_no=%d)", port_no);
if(!Emu.GetPadManager().IsInited()) return CELL_PAD_ERROR_UNINITIALIZED;
if(port_no >= Emu.GetPadManager().GetPads().GetCount()) return CELL_PAD_ERROR_INVALID_PARAMETER;
//?
return CELL_OK;
}
int cellPadGetData(u32 port_no, u32 data_addr)
{
//ConLog.Warning("cellPadGetData[port_no: %d, data_addr: 0x%x]", port_no, data_addr);
const Array<Pad>& pads = Emu.GetPadManager().GetPads();
if(!Emu.GetPadManager().IsInited()) return CELL_PAD_ERROR_UNINITIALIZED;
if(port_no >= pads.GetCount()) return CELL_PAD_ERROR_INVALID_PARAMETER;
const Pad& pad = pads[port_no];
CellPadData data;
memset(&data, 0, sizeof(CellPadData));
u16 d1 = 0;
u16 d2 = 0;
const Array<Button>& buttons = pads[port_no].m_buttons;
s32 len = 0;
for(uint i=0; i<buttons.GetCount(); ++i)
{
if(!buttons[i].m_pressed) continue;
switch(buttons[i].m_offset)
{
case CELL_PAD_BTN_OFFSET_DIGITAL1: if(!(d1 & buttons[i].m_outKeyCode)){d1 |= buttons[i].m_outKeyCode; len++;} break;
case CELL_PAD_BTN_OFFSET_DIGITAL2: if(!(d2 & buttons[i].m_outKeyCode)){d2 |= buttons[i].m_outKeyCode; len++;} break;
}
}
data.len = re(len);
data.button[CELL_PAD_BTN_OFFSET_DIGITAL1] = re(d1);
data.button[CELL_PAD_BTN_OFFSET_DIGITAL2] = re(d2);
data.button[CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X] = re(pad.m_analog_right_x);
data.button[CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y] = re(pad.m_analog_right_y);
data.button[CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X] = re(pad.m_analog_left_x);
data.button[CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y] = re(pad.m_analog_left_y);
data.button[CELL_PAD_BTN_OFFSET_PRESS_RIGHT] = re(pad.m_press_right);
data.button[CELL_PAD_BTN_OFFSET_PRESS_LEFT] = re(pad.m_press_left);
data.button[CELL_PAD_BTN_OFFSET_PRESS_UP] = re(pad.m_press_up);
data.button[CELL_PAD_BTN_OFFSET_PRESS_DOWN] = re(pad.m_press_down);
data.button[CELL_PAD_BTN_OFFSET_PRESS_TRIANGLE] = re(pad.m_press_triangle);
data.button[CELL_PAD_BTN_OFFSET_PRESS_CIRCLE] = re(pad.m_press_circle);
data.button[CELL_PAD_BTN_OFFSET_PRESS_CROSS] = re(pad.m_press_cross);
data.button[CELL_PAD_BTN_OFFSET_PRESS_SQUARE] = re(pad.m_press_square);
data.button[CELL_PAD_BTN_OFFSET_PRESS_L1] = re(pad.m_press_L1);
data.button[CELL_PAD_BTN_OFFSET_PRESS_L2] = re(pad.m_press_L2);
data.button[CELL_PAD_BTN_OFFSET_PRESS_R1] = re(pad.m_press_R1);
data.button[CELL_PAD_BTN_OFFSET_PRESS_R2] = re(pad.m_press_R2);
data.button[CELL_PAD_BTN_OFFSET_SENSOR_X] = re(pad.m_sensor_x);
data.button[CELL_PAD_BTN_OFFSET_SENSOR_Y] = re(pad.m_sensor_y);
data.button[CELL_PAD_BTN_OFFSET_SENSOR_Z] = re(pad.m_sensor_z);
data.button[CELL_PAD_BTN_OFFSET_SENSOR_G] = re(pad.m_sensor_g);
Memory.WriteData(data_addr, data);
return CELL_OK;
}
int cellPadGetDataExtra(u32 port_no, u32 device_type_addr, u32 data_addr)
{
sc_pad.Log("cellPadGetDataExtra(port_no=%d, device_type_addr=0x%x, device_type_addr=0x%x)", port_no, device_type_addr, data_addr);
if(!Emu.GetPadManager().IsInited()) return CELL_PAD_ERROR_UNINITIALIZED;
if(port_no >= Emu.GetPadManager().GetPads().GetCount()) return CELL_PAD_ERROR_INVALID_PARAMETER;
return CELL_OK;
}
int cellPadSetActDirect(u32 port_no, u32 param_addr)
{
sc_pad.Log("cellPadSetActDirect(port_no=%d, param_addr=0x%x)", port_no, param_addr);
if(!Emu.GetPadManager().IsInited()) return CELL_PAD_ERROR_UNINITIALIZED;
if(port_no >= Emu.GetPadManager().GetPads().GetCount()) return CELL_PAD_ERROR_INVALID_PARAMETER;
return CELL_OK;
}
int cellPadGetInfo2(u32 info_addr)
{
sc_pad.Log("cellPadGetInfo2(info_addr=0x%x)", info_addr);
if(!Emu.GetPadManager().IsInited()) return CELL_PAD_ERROR_UNINITIALIZED;
CellPadInfo2 info;
memset(&info, 0, sizeof(CellPadInfo2));
const PadInfo& rinfo = Emu.GetPadManager().GetInfo();
info.max_connect = re(rinfo.max_connect);
info.now_connect = re(rinfo.now_connect);
info.system_info = re(rinfo.system_info);
const Array<Pad>& pads = Emu.GetPadManager().GetPads();
for(u32 i=0; i<CELL_PAD_MAX_PORT_NUM; ++i)
{
if(i >= pads.GetCount()) break;
info.port_status[i] = re(pads[i].m_port_status);
info.port_setting[i] = re(pads[i].m_port_setting);
info.device_capability[i] = re(pads[i].m_device_capability);
info.device_type[i] = re(pads[i].m_device_type);
}
Memory.WriteData(info_addr, info);
return CELL_OK;
}
int cellPadSetPortSetting(u32 port_no, u32 port_setting)
{
sc_pad.Log("cellPadSetPortSetting(port_no=%d, port_setting=0x%x)", port_no, port_setting);
if(!Emu.GetPadManager().IsInited()) return CELL_PAD_ERROR_UNINITIALIZED;
Array<Pad>& pads = Emu.GetPadManager().GetPads();
if(port_no >= pads.GetCount()) return CELL_PAD_ERROR_INVALID_PARAMETER;
pads[port_no].m_port_setting = port_setting;
return CELL_OK;
}

View File

@ -0,0 +1,89 @@
#include "stdafx.h"
#include "Emu/SysCalls/SysCalls.h"
SysCallBase sc_p("Process");
int sys_process_getpid()
{
return 1;
}
int sys_game_process_exitspawn( u32 path_addr, u32 argv_addr, u32 envp_addr,
u32 data, u32 data_size, int prio, u64 flags )
{
sc_p.Log("sys_game_process_exitspawn: ");
sc_p.Log("path: %s", Memory.ReadString(path_addr));
sc_p.Log("argv: %x", Memory.Read32(argv_addr));
sc_p.Log("envp: %x", Memory.Read32(envp_addr));
sc_p.Log("data: %x", data);
sc_p.Log("data_size: %x", data_size);
sc_p.Log("prio: %d", prio);
sc_p.Log("flags: %d", flags);
return CELL_OK;
}
int SysCalls::lv2ProcessGetPid(PPUThread& CPU)
{
ConLog.Warning("lv2ProcessGetPid");
Memory.Write32(CPU.GPR[4], CPU.GetId());
return CELL_OK;
}
int SysCalls::lv2ProcessWaitForChild(PPUThread& CPU)
{
ConLog.Warning("lv2ProcessWaitForChild");
return CELL_OK;
}
int SysCalls::lv2ProcessGetStatus(PPUThread& CPU)
{
ConLog.Warning("lv2ProcessGetStatus");
if(CPU.IsSPU()) return CELL_UNKNOWN_ERROR;
//Memory.Write32(CPU.GPR[4], GetPPUThreadStatus(CPU));
return CELL_OK;
}
int SysCalls::lv2ProcessDetachChild(PPUThread& CPU)
{
ConLog.Warning("lv2ProcessDetachChild");
return CELL_OK;
}
int SysCalls::lv2ProcessGetNumberOfObject(PPUThread& CPU)
{
ConLog.Warning("lv2ProcessGetNumberOfObject");
Memory.Write32(CPU.GPR[4], 1);
return CELL_OK;
}
int SysCalls::lv2ProcessGetId(PPUThread& CPU)
{
ConLog.Warning("lv2ProcessGetId");
Memory.Write32(CPU.GPR[4], CPU.GetId());
return CELL_OK;
}
int SysCalls::lv2ProcessGetPpid(PPUThread& CPU)
{
ConLog.Warning("lv2ProcessGetPpid");
Memory.Write32(CPU.GPR[4], CPU.GetId());
return CELL_OK;
}
int SysCalls::lv2ProcessKill(PPUThread& CPU)
{
ConLog.Warning("lv2ProcessKill[pid: 0x%llx]", CPU.GPR[3]);
CPU.Close();
return CELL_OK;
}
int SysCalls::lv2ProcessExit(PPUThread& CPU)
{
ConLog.Warning("lv2ProcessExit(%lld)", CPU.GPR[3]);
Emu.Pause();
return CELL_OK;
}
int SysCalls::lv2ProcessWaitForChild2(PPUThread& CPU)
{
ConLog.Warning("lv2ProcessWaitForChild2[r3: 0x%llx, r4: 0x%llx, r5: 0x%llx, r6: 0x%llx, r7: 0x%llx, r8: 0x%llx]",
CPU.GPR[3], CPU.GPR[4], CPU.GPR[5], CPU.GPR[6], CPU.GPR[7], CPU.GPR[8]);
return CELL_OK;
}
int SysCalls::lv2ProcessGetSdkVersion(PPUThread& CPU)
{
ConLog.Warning("lv2ProcessGetSdkVersion[r3: 0x%llx, r4: 0x%llx]", CPU.GPR[3], CPU.GPR[4]);
CPU.GPR[4] = 0x360001; //TODO
return CELL_OK;
}

View File

@ -0,0 +1,34 @@
#include "stdafx.h"
#include "Emu/SysCalls/SysCalls.h"
SysCallBase sc_resc("cellResc");
struct CellRescSrc
{
u32 format;
u32 pitch;
u16 width;
u16 height;
u32 offset;
};
int cellRescSetSrc(const int idx, const u32 src_addr)
{
sc_resc.Warning("cellRescSetSrc(idx=0x%x, src_addr=0x%x)", idx, src_addr);
const CellRescSrc& src = *(CellRescSrc*)Memory.GetMemFromAddr(src_addr);
sc_resc.Warning(" *** format=%d", src.format);
sc_resc.Warning(" *** pitch=%d", src.pitch);
sc_resc.Warning(" *** width=%d", src.width);
sc_resc.Warning(" *** height=%d", src.height);
sc_resc.Warning(" *** offset=0x%x", src.offset);
//Emu.GetGSManager().GetRender().SetData(src.offset, 800, 600);
//Emu.GetGSManager().GetRender().Draw();
return 0;
}
int cellRescSetBufferAddress(const u32 colorBuffers_addr, const u32 vertexArray_addr, const u32 fragmentShader_addr)
{
sc_resc.Warning("cellRescSetBufferAddress(colorBuffers_addr=0x%x, vertexArray_addr=0x%x, fragmentShader_add=0x%x)",
colorBuffers_addr, vertexArray_addr, fragmentShader_addr);
return 0;
}

View File

@ -0,0 +1,68 @@
#include "stdafx.h"
#include "Emu/SysCalls/SysCalls.h"
SysCallBase sc_spu("sys_spu");
struct sys_spu_thread_group_attribute
{
u32 name_len;
u32 name_addr;
int type;
union{u32 ct;} option;
};
//170
int sys_spu_thread_group_create(u64 id_addr, u32 num, int prio, u64 attr_addr)
{
ConLog.Write("sys_spu_thread_group_create:");
ConLog.Write("*** id_addr=0x%llx", id_addr);
ConLog.Write("*** num=%d", num);
ConLog.Write("*** prio=%d", prio);
ConLog.Write("*** attr_addr=0x%llx", attr_addr);
sys_spu_thread_group_attribute& attr = *new sys_spu_thread_group_attribute(*(sys_spu_thread_group_attribute*)&Memory[attr_addr]);
ConLog.Write("*** attr.name_len=%d", re(attr.name_len));
ConLog.Write("*** attr.name_addr=0x%x", re(attr.name_addr));
ConLog.Write("*** attr.type=%d", re(attr.type));
ConLog.Write("*** attr.option.ct=%d", re(attr.option.ct));
const wxString& name = Memory.ReadString(re(attr.name_addr), re(attr.name_len));
ConLog.Write("*** name='%s'", name);
Memory.Write32(id_addr,
Emu.GetIdManager().GetNewID(wxString::Format("sys_spu_thread_group %s", name), &attr, 0));
return CELL_OK;
}
int sys_spu_thread_create(u64 thread_id_addr, u64 entry_addr, u64 arg,
int prio, u32 stacksize, u64 flags, u64 threadname_addr)
{
return CELL_OK;
}
//160
int sys_raw_spu_create(u32 id_addr, u32 attr_addr)
{
sc_spu.Log("sys_raw_spu_create(id_addr=0x%x, attr_addr=0x%x)", id_addr, attr_addr);
PPCThread& new_thread = Emu.GetCPU().AddThread(false);
Emu.GetIdManager().GetNewID("sys_raw_spu", new u32(attr_addr));
Memory.Write32(id_addr, Emu.GetCPU().GetThreadNumById(false, new_thread.GetId()));
return CELL_OK;
}
//169
int sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu)
{
sc_spu.Log("sys_spu_initialize(max_usable_spu=%d, max_raw_spu=%d)", max_usable_spu, max_raw_spu);
if(!Memory.InitSpuRawMem(max_raw_spu))
{
return CELL_UNKNOWN_ERROR;
}
return CELL_OK;
}

View File

@ -0,0 +1,100 @@
#include "stdafx.h"
#include "Emu/GS/sysutil_video.h"
#include "Emu/SysCalls/SysCalls.h"
//cellVideo
SysCallBase sc_v("cellVideo");
int cellVideoOutGetState(u32 videoOut, u32 deviceIndex, u32 state_addr)
{
sc_v.Log("cellVideoOutGetState(videoOut=0x%x, deviceIndex=0x%x, state_addr=0x%x)", videoOut, deviceIndex, state_addr);
if(deviceIndex) return CELL_VIDEO_OUT_ERROR_DEVICE_NOT_FOUND;
CellVideoOutState state;
memset(&state, 0, sizeof(CellVideoOutState));
switch(videoOut)
{
case CELL_VIDEO_OUT_PRIMARY:
{
state.colorSpace = Emu.GetGSManager().GetColorSpace();
state.state = Emu.GetGSManager().GetState();
state.displayMode.resolutionId = Emu.GetGSManager().GetInfo().mode.resolutionId;
state.displayMode.scanMode = Emu.GetGSManager().GetInfo().mode.scanMode;
state.displayMode.conversion = Emu.GetGSManager().GetInfo().mode.conversion;
state.displayMode.aspect = Emu.GetGSManager().GetInfo().mode.aspect;
state.displayMode.refreshRates = re(Emu.GetGSManager().GetInfo().mode.refreshRates);
Memory.WriteData(state_addr, state);
}
return CELL_VIDEO_OUT_SUCCEEDED;
case CELL_VIDEO_OUT_SECONDARY:
{
state.colorSpace = CELL_VIDEO_OUT_COLOR_SPACE_RGB;
state.state = CELL_VIDEO_OUT_OUTPUT_STATE_ENABLED;
Memory.WriteData(state_addr, state);
}
return CELL_VIDEO_OUT_SUCCEEDED;
}
return CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT;
}
int cellVideoOutGetResolution(u32 resolutionId, u32 resolution_addr)
{
sc_v.Log("cellVideoOutGetResolution(resolutionId=%d, resolution_addr=0x%x)",
resolutionId, resolution_addr);
CellVideoOutResolution res = {0, 0};
switch(resolutionId)
{
case CELL_VIDEO_OUT_RESOLUTION_1080:
res.width = re16(1920);
res.height = re16(1080);
break;
case CELL_VIDEO_OUT_RESOLUTION_720:
res.width = re16(1280);
res.height = re16(720);
break;
case CELL_VIDEO_OUT_RESOLUTION_480:
res.width = re16(720);
res.height = re16(480);
break;
case CELL_VIDEO_OUT_RESOLUTION_576:
res.width = re16(720);
res.height = re16(576);
break;
case CELL_VIDEO_OUT_RESOLUTION_1600x1080:
res.width = re16(1600);
res.height = re16(1080);
break;
case CELL_VIDEO_OUT_RESOLUTION_1440x1080:
res.width = re16(1440);
res.height = re16(1080);
break;
case CELL_VIDEO_OUT_RESOLUTION_1280x1080:
res.width = re16(1280);
res.height = re16(1080);
break;
case CELL_VIDEO_OUT_RESOLUTION_960x1080:
res.width = re16(960);
res.height = re16(1080);
break;
default: return CELL_EINVAL;
}
Memory.WriteData(resolution_addr, res);
return CELL_OK;
}

View File

@ -0,0 +1,34 @@
#include "stdafx.h"
#include "Emu/SysCalls/SysCalls.h"
int SysCalls::lv2TtyRead(PPUThread& CPU)
{
const u32 ch = CPU.GPR[3];
const u64 buf_addr = CPU.GPR[4];
const u32 len = CPU.GPR[5];
const u64 preadlen_addr = CPU.GPR[6];
ConLog.Warning("lv2TtyRead: ch: %d, buf addr: %llx, len: %d", ch, buf_addr, len);
Memory.Write32NN(preadlen_addr, len);
return CELL_OK;
}
int SysCalls::lv2TtyWrite(PPUThread& CPU)
{
const u32 ch = CPU.GPR[3];
const u64 buf_addr = CPU.GPR[4];
const u32 len = CPU.GPR[5];
const u64 pwritelen_addr = CPU.GPR[6];
//for(uint i=0; i<32; ++i) ConLog.Write("r%d = 0x%llx", i, CPU.GPR[i]);
//ConLog.Warning("lv2TtyWrite: ch: %d, buf addr: %llx, len: %d", ch, buf_addr, len);
if(ch < 0 || ch > 15 || len <= 0) return CELL_EINVAL;
if(!Memory.IsGoodAddr(buf_addr)) return CELL_EINVAL;
Emu.GetDbgCon().Write(ch, Memory.ReadString(buf_addr, len));
if(!Memory.IsGoodAddr(pwritelen_addr)) return CELL_EFAULT;
Memory.Write32(pwritelen_addr, len);
return CELL_OK;
}

View File

@ -0,0 +1,37 @@
#include "stdafx.h"
#include "Emu/SysCalls/SysCalls.h"
#include <sys/timeb.h>
SysCallBase sys_time("sys_time");
static const u64 timebase_frequency = 79800000;
int sys_time_get_current_time(u32 sec_addr, u32 nsec_addr)
{
sys_time.Log("sys_time_get_current_time(sec_addr=0x%x, nsec_addr=0x%x)", sec_addr, nsec_addr);
__timeb64 cur_time;
_ftime64_s(&cur_time);
Memory.Write64(sec_addr, cur_time.time);
Memory.Write64(nsec_addr, (u64)cur_time.millitm * 1000000);
return CELL_OK;
}
s64 sys_time_get_system_time()
{
sys_time.Log("sys_time_get_system_time()");
LARGE_INTEGER cycle;
QueryPerformanceCounter(&cycle);
return cycle.QuadPart;
}
u64 sys_time_get_timebase_frequency()
{
sys_time.Log("sys_time_get_timebase_frequency()");
static LARGE_INTEGER frequency = {0ULL};
if(!frequency.QuadPart) QueryPerformanceFrequency(&frequency);
return frequency.QuadPart;
}

View File

@ -0,0 +1,21 @@
#include "stdafx.h"
#include "Emu/SysCalls/SysCalls.h"
SysCallBase sc_spu("sys_spu");
u32 _max_usable_spu = 0;
u32 _max_raw_spu = 0;
int sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu)
{
sc_spu.Log("sys_spu_initialize(max_usable_spu=%d, max_raw_spu=%d)", max_usable_spu, max_raw_spu);
_max_usable_spu = max_usable_spu;
_max_raw_spu = max_raw_spu;
return CELL_OK;
}
int sys_raw_spu_create(u32 id_addr, u32 attr_addr)
{
Memory.Write32(id_addr, Emu.GetIdManager().GetNewID("raw_spu"));
return CELL_OK;
}

195
rpcs3/Emu/System.cpp Normal file
View File

@ -0,0 +1,195 @@
#include "stdafx.h"
#include "System.h"
#include "Emu/Memory/Memory.h"
#include "Ini.h"
#include "Emu/Cell/PPCThreadManager.h"
#include "Emu/Cell/PPUThread.h"
#include "Emu/Cell/SPUThread.h"
#include "Emu/SysCalls/SysCalls.h"
SysCalls SysCallsManager;
Emulator::Emulator()
: m_status(Stopped)
, m_mode(DisAsm)
, m_dbg_console(NULL)
, m_rsx_callback(0)
{
}
void Emulator::Init()
{
//if(m_memory_viewer) m_memory_viewer->Close();
//m_memory_viewer = new MemoryViewerPanel(wxGetApp().m_MainFrame);
}
void Emulator::SetSelf(const wxString& path)
{
m_path = path;
IsSelf = true;
}
void Emulator::SetElf(const wxString& path)
{
m_path = path;
IsSelf = false;
}
void Emulator::CheckStatus()
{
ArrayF<PPCThread>& threads = GetCPU().GetThreads();
if(!threads.GetCount())
{
Stop();
return;
}
bool IsAllPaused = true;
for(u32 i=0; i<threads.GetCount(); ++i)
{
if(threads[i].IsPaused()) continue;
IsAllPaused = false;
break;
}
if(IsAllPaused)
{
ConLog.Warning("all paused!");
Pause();
return;
}
bool IsAllStoped = true;
for(u32 i=0; i<threads.GetCount(); ++i)
{
if(threads[i].IsStopped()) continue;
IsAllStoped = false;
break;
}
if(IsAllStoped)
{
ConLog.Warning("all stoped!");
Pause(); //Stop();
}
}
void Emulator::Run()
{
if(IsRunned()) Stop();
if(IsPaused())
{
Resume();
return;
}
//ConLog.Write("run...");
m_status = Runned;
Memory.Init();
GetInfo().Reset();
//SetTLSData(0, 0, 0);
//SetMallocPageSize(0x100000);
Loader l(m_path);
if(!l.Load())
{
Memory.Close();
Stop();
return;
}
if(l.GetMachine() == MACHINE_Unknown)
{
ConLog.Error("Unknown machine type");
Memory.Close();
Stop();
return;
}
PPCThread& thread = GetCPU().AddThread(l.GetMachine() == MACHINE_PPC64);
Memory.MainMem.Alloc(0x10000000, 0x10010000);
Memory.PRXMem.Write64(Memory.PRXMem.GetStartAddr(), 0xDEADBEEFABADCAFE);
thread.SetPc(l.GetEntry());
thread.SetArg(thread.GetId());
Memory.StackMem.Alloc(0x1000);
thread.InitStack();
thread.AddArgv(m_path);
//thread.AddArgv("-emu");
m_rsx_callback = Memory.MainMem.Alloc(0x10) + 4;
Memory.Write32(m_rsx_callback - 4, m_rsx_callback);
thread.Run();
//if(m_memory_viewer && m_memory_viewer->exit) safe_delete(m_memory_viewer);
//m_memory_viewer->SetPC(loader.GetEntry());
//m_memory_viewer->Show();
//m_memory_viewer->ShowPC();
wxGetApp().m_MainFrame->UpdateUI();
if(!m_dbg_console) m_dbg_console = new DbgConsole();
GetGSManager().Init();
if(Ini.CPUDecoderMode.GetValue() != 1)
{
GetCPU().Start();
GetCPU().Exec();
}
}
void Emulator::Pause()
{
if(!IsRunned()) return;
//ConLog.Write("pause...");
m_status = Paused;
wxGetApp().m_MainFrame->UpdateUI();
}
void Emulator::Resume()
{
if(!IsPaused()) return;
//ConLog.Write("resume...");
m_status = Runned;
wxGetApp().m_MainFrame->UpdateUI();
CheckStatus();
if(IsRunned() && Ini.CPUDecoderMode.GetValue() != 1) GetCPU().Exec();
}
void Emulator::Stop()
{
if(IsStopped()) return;
//ConLog.Write("shutdown...");
m_rsx_callback = 0;
m_status = Stopped;
wxGetApp().m_MainFrame->UpdateUI();
GetGSManager().Close();
GetCPU().Close();
SysCallsManager.Close();
GetIdManager().Clear();
GetPadManager().Close();
CurGameInfo.Reset();
Memory.Close();
if(m_dbg_console)
{
GetDbgCon().Close();
m_dbg_console = NULL;
}
//if(m_memory_viewer && m_memory_viewer->IsShown()) m_memory_viewer->Hide();
}
Emulator Emu;

113
rpcs3/Emu/System.h Normal file
View File

@ -0,0 +1,113 @@
#pragma once
#include "Gui/MemoryViewer.h"
#include "Emu/Cell/PPCThreadManager.h"
#include "Emu/Io/Pad.h"
#include "Emu/DbgConsole.h"
#include "Emu/GS/GSManager.h"
#include "Loader/Loader.h"
struct EmuInfo
{
private:
u64 tls_addr;
u64 tls_filesz;
u64 tls_memsz;
sys_process_param_info proc_param;
public:
EmuInfo() { Reset(); }
sys_process_param_info& GetProcParam() { return proc_param; }
void Reset()
{
SetTLSData(0, 0, 0);
memset(&proc_param, 0, sizeof(sys_process_param_info));
proc_param.malloc_pagesize = 0x100000;
proc_param.sdk_version = 0x360001;
//TODO
}
void SetTLSData(const u64 addr, const u64 filesz, const u64 memsz)
{
tls_addr = addr;
tls_filesz = filesz;
tls_memsz = memsz;
}
u64 GetTLSAddr() const { return tls_addr; }
u64 GetTLSFilesz() const { return tls_filesz; }
u64 GetTLSMemsz() const { return tls_memsz; }
};
class Emulator
{
enum Mode
{
DisAsm,
InterpreterDisAsm,
Interpreter,
};
Status m_status;
uint m_mode;
u32 m_rsx_callback;
MemoryViewerPanel* m_memory_viewer;
//ArrayF<CPUThread> m_cpu_threads;
PPCThreadManager m_thread_manager;
PadManager m_pad_manager;
IdManager m_id_manager;
DbgConsole* m_dbg_console;
GSManager m_gs_manager;
EmuInfo m_info;
public:
wxString m_path;
bool IsSelf;
Emulator();
void Init();
virtual void SetSelf(const wxString& path);
virtual void SetElf(const wxString& path);
PPCThreadManager& GetCPU() { return m_thread_manager; }
PadManager& GetPadManager() { return m_pad_manager; }
IdManager& GetIdManager() { return m_id_manager; }
DbgConsole& GetDbgCon() { return *m_dbg_console; }
GSManager& GetGSManager() { return m_gs_manager; }
void SetTLSData(const u64 addr, const u64 filesz, const u64 memsz)
{
m_info.SetTLSData(addr, filesz, memsz);
}
EmuInfo& GetInfo() { return m_info; }
u64 GetTLSAddr() const { return m_info.GetTLSAddr(); }
u64 GetTLSFilesz() const { return m_info.GetTLSFilesz(); }
u64 GetTLSMemsz() const { return m_info.GetTLSMemsz(); }
u32 GetMallocPageSize() { return m_info.GetProcParam().malloc_pagesize; }
u32 GetRSXCallback() const { return m_rsx_callback; }
void CheckStatus();
virtual void Run();
virtual void Pause();
virtual void Resume();
virtual void Stop();
virtual bool IsRunned() const { return m_status == Runned; }
virtual bool IsPaused() const { return m_status == Paused; }
virtual bool IsStopped() const { return m_status == Stopped; }
};
extern Emulator Emu;

2601
rpcs3/Gui/CompilerELF.cpp Normal file

File diff suppressed because it is too large Load Diff

79
rpcs3/Gui/CompilerELF.h Normal file
View File

@ -0,0 +1,79 @@
#pragma once
#include "Emu/Cell/PPUOpcodes.h"
#include "wx/aui/aui.h"
#include "Loader/ELF64.h"
#include <wx/richtext/richtextctrl.h>
void Write8(wxFile& f, const u8 data);
void Write16(wxFile& f, const u16 data);
void Write32(wxFile& f, const u32 data);
void Write64(wxFile& f, const u64 data);
struct SectionInfo
{
Elf64_Shdr shdr;
wxString name;
Array<u8> code;
u32 section_num;
SectionInfo(const wxString& name);
~SectionInfo();
void SetDataSize(u32 size, u32 align = 0);
};
struct ProgramInfo
{
Array<u8> code;
Elf64_Phdr phdr;
bool is_preload;
ProgramInfo()
{
is_preload = false;
code.Clear();
memset(&phdr, 0, sizeof(Elf64_Phdr));
}
};
class CompilerELF : public FrameBase
{
wxAuiManager m_aui_mgr;
wxStatusBar& m_status_bar;
bool m_disable_scroll;
public:
CompilerELF(wxWindow* parent);
~CompilerELF();
wxTextCtrl* asm_list;
wxTextCtrl* hex_list;
wxTextCtrl* err_list;
void MouseWheel(wxMouseEvent& event);
void OnKeyDown(wxKeyEvent& event);
void OnUpdate(wxCommandEvent& event);
void OnScroll(wxScrollWinEvent& event);
void UpdateScroll(bool is_hex, int orient);
void AnalyzeCode(wxCommandEvent& WXUNUSED(event))
{
DoAnalyzeCode(false);
}
void CompileCode(wxCommandEvent& WXUNUSED(event))
{
DoAnalyzeCode(true);
}
void LoadElf(wxCommandEvent& event);
void LoadElf(const wxString& path);
void SetTextStyle(const wxString& text, const wxColour& color, bool bold=false);
void SetOpStyle(const wxString& text, const wxColour& color, bool bold=true);
void DoAnalyzeCode(bool compile);
void UpdateStatus(int offset=0);
};

270
rpcs3/Gui/ConLog.cpp Normal file
View File

@ -0,0 +1,270 @@
#include "stdafx.h"
#include "Gui/ConLog.h"
#include <wx/listctrl.h>
#include "Ini.h"
LogWriter ConLog;
LogFrame* ConLogFrame;
wxMutex mtx_wait;
static const uint max_item_count = 500;
static const uint buffer_size = 1024 * 64;
wxSemaphore m_conlog_sem;
struct LogPacket
{
wxString m_prefix;
wxString m_text;
wxString m_colour;
LogPacket(const wxString& prefix, const wxString& text, const wxString& colour)
: m_prefix(prefix)
, m_text(text)
, m_colour(colour)
{
}
LogPacket()
{
}
};
struct _LogBuffer : public MTPacketBuffer<LogPacket>
{
_LogBuffer() : MTPacketBuffer<LogPacket>(buffer_size)
{
}
void Push(const LogPacket& data)
{
const u32 sprefix = data.m_prefix.Len();
const u32 stext = data.m_text.Len();
const u32 scolour = data.m_colour.Len();
m_buffer.Reserve(
sizeof(u32) + sprefix +
sizeof(u32) + stext +
sizeof(u32) + scolour);
u32 c_put = m_put;
memcpy(&m_buffer[c_put], &sprefix, sizeof(u32));
c_put += sizeof(u32);
memcpy(&m_buffer[c_put], data.m_prefix.c_str(), sprefix);
c_put += sprefix;
memcpy(&m_buffer[c_put], &stext, sizeof(u32));
c_put += sizeof(u32);
memcpy(&m_buffer[c_put], data.m_text.c_str(), stext);
c_put += stext;
memcpy(&m_buffer[c_put], &scolour, sizeof(u32));
c_put += sizeof(u32);
memcpy(&m_buffer[c_put], data.m_colour.c_str(), scolour);
c_put += scolour;
m_put = c_put;
CheckBusy();
}
LogPacket Pop()
{
LogPacket ret;
u32 c_get = m_get;
const u32& sprefix = *(u32*)&m_buffer[c_get];
c_get += sizeof(u32);
if(sprefix) memcpy(wxStringBuffer(ret.m_prefix, sprefix), &m_buffer[c_get], sprefix);
c_get += sprefix;
const u32& stext = *(u32*)&m_buffer[c_get];
c_get += sizeof(u32);
if(stext) memcpy(wxStringBuffer(ret.m_text, stext), &m_buffer[c_get], stext);
c_get += stext;
const u32& scolour = *(u32*)&m_buffer[c_get];
c_get += sizeof(u32);
if(scolour) memcpy(wxStringBuffer(ret.m_colour, scolour), &m_buffer[c_get], scolour);
c_get += scolour;
m_get = c_get;
if(!HasNewPacket()) Flush();
return ret;
}
} LogBuffer;
LogWriter::LogWriter()
{
if(!m_logfile.Open(_PRGNAME_ ".log", wxFile::write))
{
wxMessageBox("Cann't create log file! (" _PRGNAME_ ".log)", wxMessageBoxCaptionStr, wxICON_ERROR);
}
}
void LogWriter::WriteToLog(wxString prefix, wxString value, wxString colour/*, wxColour bgcolour*/)
{
if(m_logfile.IsOpened())
m_logfile.Write((prefix.IsEmpty() ? wxEmptyString : "[" + prefix + "]: ") + value + "\n");
if(!ConLogFrame) return;
wxMutexLocker locker(mtx_wait);
while(LogBuffer.IsBusy()) Sleep(1);
//if(LogBuffer.put == LogBuffer.get) LogBuffer.Flush();
LogBuffer.Push(LogPacket(prefix, value, colour));
}
wxString FormatV(const wxString fmt, va_list args)
{
int length = 256;
wxString str;
for(;;)
{
str.Clear();
wxStringBuffer buf(str, length+1);
memset(buf, 0, length+1);
if(vsnprintf(buf, length, fmt, args) != -1) break;
length *= 2;
}
return str;
}
void LogWriter::Write(const wxString fmt, ...)
{
va_list list;
va_start(list, fmt);
const wxString& frmt = FormatV(fmt, list);
va_end(list);
WriteToLog("!", frmt, "White");
}
void LogWriter::Error(const wxString fmt, ...)
{
va_list list;
va_start(list, fmt);
const wxString& frmt = FormatV(fmt, list);
va_end(list);
WriteToLog("E", frmt, "Red");
}
void LogWriter::Warning(const wxString fmt, ...)
{
va_list list;
va_start(list, fmt);
const wxString& frmt = FormatV(fmt, list);
va_end(list);
WriteToLog("W", frmt, "Yellow");
}
void LogWriter::SkipLn()
{
WriteToLog(wxEmptyString, wxEmptyString, "Black");
}
BEGIN_EVENT_TABLE(LogFrame, FrameBase)
EVT_CLOSE(LogFrame::OnQuit)
END_EVENT_TABLE()
LogFrame::LogFrame()
: FrameBase(NULL, wxID_ANY, "Log Console", wxEmptyString, wxSize(600, 450), wxDefaultPosition)
, ThreadBase(false, "LogThread")
, m_log(*new wxListView(this))
{
wxBoxSizer& s_panel( *new wxBoxSizer(wxHORIZONTAL) );
s_panel.Add(&m_log, wxSizerFlags().Expand());
m_log.InsertColumn(0, wxEmptyString);
m_log.InsertColumn(1, "Log");
m_log.SetBackgroundColour(wxColour("Black"));
m_log.SetColumnWidth(0, 18);
SetSizerAndFit( &s_panel );
Connect( wxEVT_SIZE, wxSizeEventHandler(LogFrame::OnResize) );
Connect( m_log.GetId(), wxEVT_COMMAND_LIST_COL_BEGIN_DRAG, wxListEventHandler( LogFrame::OnColBeginDrag ));
Show();
ThreadBase::Start();
}
LogFrame::~LogFrame()
{
}
bool LogFrame::Close(bool force)
{
Stop();
ConLogFrame = NULL;
return FrameBase::Close(force);
}
void LogFrame::Task()
{
while(!TestDestroy())
{
if(!LogBuffer.HasNewPacket())
{
Sleep(1);
continue;
}
const LogPacket item = LogBuffer.Pop();
while(m_log.GetItemCount() > max_item_count)
{
m_log.DeleteItem(0);
}
const int cur_item = m_log.GetItemCount();
m_log.InsertItem(cur_item, item.m_prefix);
m_log.SetItem(cur_item, 1, item.m_text);
m_log.SetItemTextColour(cur_item, item.m_colour);
::SendMessage((HWND)m_log.GetHWND(), WM_VSCROLL, SB_BOTTOM, 0);
}
LogBuffer.Flush();
}
void LogFrame::OnColBeginDrag(wxListEvent& event)
{
event.Veto();
}
void LogFrame::OnResize(wxSizeEvent& event)
{
const wxSize size( GetClientSize() );
m_log.SetSize( size );
m_log.SetColumnWidth(1, size.GetWidth() - 4 - m_log.GetColumnWidth(0));
event.Skip();
}
void LogFrame::OnQuit(wxCloseEvent& event)
{
Stop();
ConLogFrame = NULL;
event.Skip();
}

48
rpcs3/Gui/ConLog.h Normal file
View File

@ -0,0 +1,48 @@
#pragma once
#include <wx/listctrl.h>
#include "Ini.h"
#include "Gui/FrameBase.h"
class LogWriter
{
wxFile m_logfile;
wxColour m_txtcolour;
wxString m_prefix;
wxString m_value;
virtual void WriteToLog(wxString prefix, wxString value, wxString colour);
public:
LogWriter();
virtual void Write(const wxString fmt, ...);
virtual void Error(const wxString fmt, ...);
virtual void Warning(const wxString fmt, ...);
virtual void SkipLn();
};
class LogFrame
: public FrameBase
, public ThreadBase
{
wxListView& m_log;
public:
LogFrame();
~LogFrame();
bool Close(bool force = false);
private:
virtual void OnColBeginDrag(wxListEvent& event);
virtual void OnResize(wxSizeEvent& event);
virtual void Task();
void OnQuit(wxCloseEvent& event);
DECLARE_EVENT_TABLE();
};
extern LogWriter ConLog;
extern LogFrame* ConLogFrame;

502
rpcs3/Gui/DisAsmFrame.cpp Normal file
View File

@ -0,0 +1,502 @@
#include "stdafx.h"
#include "DisAsmFrame.h"
#include "Emu/Memory/Memory.h"
#include "Emu/Cell/PPCThread.h"
#include "Emu/System.h"
#include "Gui/DisAsmFrame.h"
#include "Emu/Cell/PPUDecoder.h"
#include "Emu/Cell/PPUDisAsm.h"
#include "Emu/Cell/SPUDecoder.h"
#include "Emu/Cell/SPUDisAsm.h"
DisAsmFrame::DisAsmFrame(PPCThread& cpu)
: wxFrame(NULL, wxID_ANY, "DisAsm")
, CPU(cpu)
{
exit = false;
count = 0;
wxBoxSizer& s_panel( *new wxBoxSizer(wxVERTICAL) );
wxBoxSizer& s_b_panel( *new wxBoxSizer(wxHORIZONTAL) );
m_disasm_list = new wxListView(this);
wxButton& b_fprev = *new wxButton(this, wxID_ANY, L"<<");
wxButton& b_prev = *new wxButton(this, wxID_ANY, L"<");
wxButton& b_next = *new wxButton(this, wxID_ANY, L">");
wxButton& b_fnext = *new wxButton(this, wxID_ANY, L">>");
wxButton& b_dump = *new wxButton(this, wxID_ANY, L"Dump code");
wxButton& b_setpc = *new wxButton(this, wxID_ANY, L"Set PC");
s_b_panel.Add(&b_fprev);
s_b_panel.Add(&b_prev);
s_b_panel.AddSpacer(5);
s_b_panel.Add(&b_next);
s_b_panel.Add(&b_fnext);
s_b_panel.AddSpacer(8);
s_b_panel.Add(&b_dump);
s_panel.Add(&s_b_panel);
s_panel.Add(&b_setpc);
s_panel.Add(m_disasm_list);
m_disasm_list->InsertColumn(0, "PC");
m_disasm_list->InsertColumn(1, "ASM");
m_disasm_list->SetColumnWidth( 0, 50 );
for(uint i=0; i<LINES_OPCODES; ++i) m_disasm_list->InsertItem(i, -1);
SetSizerAndFit( &s_panel );
SetSize(50, 660);
Connect( wxEVT_SIZE, wxSizeEventHandler(DisAsmFrame::OnResize) );
wxGetApp().Connect(m_disasm_list->GetId(), wxEVT_MOUSEWHEEL, wxMouseEventHandler(DisAsmFrame::MouseWheel), (wxObject*)0, this);
Connect(b_prev.GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(DisAsmFrame::Prev));
Connect(b_next.GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(DisAsmFrame::Next));
Connect(b_fprev.GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(DisAsmFrame::fPrev));
Connect(b_fnext.GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(DisAsmFrame::fNext));
Connect(b_setpc.GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(DisAsmFrame::SetPc));
Connect(b_dump.GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(DisAsmFrame::Dump));
}
void DisAsmFrame::OnResize(wxSizeEvent& event)
{
const wxSize size(GetClientSize());
m_disasm_list->SetSize( size.GetWidth(), size.GetHeight() - 25 );
m_disasm_list->SetColumnWidth( 1, size.GetWidth() - (m_disasm_list->GetColumnWidth(0) + 8) );
event.Skip();
}
void DisAsmFrame::AddLine(const wxString line)
{
static bool finished = false;
if(finished && Emu.IsRunned())
{
count = 0;
finished = false;
}
else if(count >= LINES_OPCODES || !Emu.IsRunned())
{
if(Emu.IsRunned()) Emu.Pause();
finished = true;
CPU.PrevPc();
return;
}
m_disasm_list->SetItem(count, 0, wxString::Format("%llx", CPU.PC));
m_disasm_list->SetItem(count, 1, line);
++count;
}
void DisAsmFrame::Resume()
{
Emu.Resume();
}
#include <Utilities/MTProgressDialog.h>
#include "Loader/ELF.h"
Array<Elf64_Shdr>* shdr_arr_64 = NULL;
Array<Elf32_Shdr>* shdr_arr_32 = NULL;
ELF64Loader* l_elf64 = NULL;
ELF32Loader* l_elf32 = NULL;
bool ElfType64 = false;
class DumperThread : public ThreadBase
{
volatile uint id;
DisAsm* disasm;
Decoder* decoder;
volatile bool* done;
volatile u8 cores;
MTProgressDialog* prog_dial;
wxArrayString** arr;
public:
DumperThread() : ThreadBase(true, "DumperThread")
{
}
void Set(uint _id, u8 _cores, bool* _done, MTProgressDialog& _prog_dial, wxArrayString** _arr)
{
id = _id;
cores = _cores;
done = _done;
prog_dial = &_prog_dial;
arr = _arr;
*done = false;
if(Emu.GetCPU().GetThreads()[0].IsSPU())
{
SPU_DisAsm& dis_asm = *new SPU_DisAsm(*(PPCThread*)NULL, DumpMode);
decoder = new SPU_Decoder(dis_asm);
disasm = &dis_asm;
}
else
{
PPU_DisAsm& dis_asm = *new PPU_DisAsm(*(PPCThread*)NULL, DumpMode);
decoder = new PPU_Decoder(dis_asm);
disasm = &dis_asm;
}
}
virtual void Task()
{
ConLog.Write("Start dump in thread %d!", (int)id);
const u32 max_value = prog_dial->GetMaxValue(id);
const u32 shdr_count = ElfType64 ? shdr_arr_64->GetCount() : shdr_arr_32->GetCount();
for(u32 sh=0, vsize=0; sh<shdr_count; ++sh)
{
const u64 sh_size = (ElfType64 ? (*shdr_arr_64)[sh].sh_size : (*shdr_arr_32)[sh].sh_size) / 4;
const u64 sh_addr = (ElfType64 ? (*shdr_arr_64)[sh].sh_addr : (*shdr_arr_32)[sh].sh_addr);
u64 d_size = sh_size / cores;
const u64 s_fix = sh_size % cores;
if(id <= s_fix) d_size++;
for(u64 off = id * 4, size=0; size<d_size; vsize++, size++)
{
prog_dial->Update(id, vsize,
wxString::Format("%d thread: %d of %d", (int)id + 1, vsize, max_value));
disasm->dump_pc = sh_addr + off;
decoder->Decode(Memory.Read32(disasm->dump_pc));
arr[id][sh].Add(disasm->last_opcode);
off += (cores - id) * 4;
off += id * 4;
}
}
ConLog.Write("Finish dump in thread %d!", (int)id);
*done = true;
}
void OnExit()
{
ConLog.Write("CleanUp dump thread (%d)!", (int)id);
safe_delete(decoder);
}
};
struct WaitDumperThread : public ThreadBase
{
volatile bool* done;
volatile u8 cores;
wxString patch;
MTProgressDialog& prog_dial;
wxArrayString** arr;
WaitDumperThread(bool* _done, u8 _cores, wxString _patch, MTProgressDialog& _prog_dial, wxArrayString** _arr)
: ThreadBase()
, done(_done)
, cores(_cores)
, patch(_patch)
, prog_dial(_prog_dial)
, arr(_arr)
{
}
~WaitDumperThread()
{
free((bool*)done);
done = NULL;
}
virtual void Task()
{
for(uint i=0; i<cores; i++)
{
while(done[i] == false) Sleep(1);
}
ConLog.Write("Saving dump is started!");
const uint length_for_core = prog_dial.GetMaxValue(0);
const uint length = length_for_core * cores;
prog_dial.Close();
wxArrayLong max;
max.Add(length);
MTProgressDialog& prog_dial2 =
*new MTProgressDialog(NULL, wxDefaultSize, "Saving", "Loading...", max, 1);
wxFile fd;
fd.Open(patch, wxFile::write);
const u32 shdr_count = ElfType64 ? shdr_arr_64->GetCount() : shdr_arr_32->GetCount();
for(uint sh=0, counter=0; sh<shdr_count; ++sh)
{
const u64 sh_size = ElfType64 ? (*shdr_arr_64)[sh].sh_size : (*shdr_arr_32)[sh].sh_size;
if(!sh_size) continue;
const uint c_sh_size = sh_size / 4;
fd.Write(wxString::Format("Start of section header %d (instructions count: %d)\n", sh, c_sh_size));
for(uint i=0, c=0, v=0; i<c_sh_size; i++, c++, counter++)
{
if(c >= cores)
{
c = 0;
v++;
}
prog_dial2.Update(0, counter, wxString::Format("Saving data to file: %d of %d", counter, length));
if(v >= arr[c][sh].GetCount()) continue;
fd.Write("\t");
fd.Write(arr[c][sh][v]);
}
fd.Write(wxString::Format("End of section header %d\n\n", sh));
}
ConLog.Write("CleanUp dump saving!");
for(uint c=0; c<cores; ++c)
{
for(uint sh=0; sh<shdr_count; ++sh) arr[c][sh].Empty();
}
free(arr);
//safe_delete(shdr_arr);
safe_delete(l_elf32);
safe_delete(l_elf64);
prog_dial2.Close();
fd.Close();
wxMessageBox("Dumping done.", "rpcs3 message");
Emu.Stop();
}
};
void DisAsmFrame::Dump(wxCommandEvent& WXUNUSED(event))
{
wxFileDialog ctrl( this, L"Select output file...",
wxEmptyString, "DisAsm.txt", "*.txt", wxFD_SAVE);
if(ctrl.ShowModal() == wxID_CANCEL) return;
wxFile& f_elf = *new wxFile(Emu.m_path);
ConLog.Write("path: %s", Emu.m_path);
Elf_Ehdr ehdr;
ehdr.Load(f_elf);
f_elf.Close();
if(!ehdr.CheckMagic())
{
ConLog.Error("Corrupted ELF!");
return;
}
wxArrayString name_arr;
switch(ehdr.GetClass())
{
case CLASS_ELF64:
ElfType64 = true;
l_elf64 = new ELF64Loader(Emu.m_path);
if(!l_elf64->LoadInfo())
{
delete l_elf64;
return;
}
name_arr = l_elf64->shdr_name_arr;
shdr_arr_64 = &l_elf64->shdr_arr;
if(l_elf64->shdr_arr.GetCount() <= 0) return;
break;
case CLASS_ELF32:
ElfType64 = false;
l_elf32 = new ELF32Loader(Emu.m_path);
if(!l_elf32->LoadInfo())
{
delete l_elf32;
return;
}
name_arr = l_elf32->shdr_name_arr;
shdr_arr_32 = &l_elf32->shdr_arr;
if(l_elf32->shdr_arr.GetCount() <= 0) return;
break;
default: ConLog.Error("Corrupted ELF!"); return;
}
DisAsm* disasm;
Decoder* decoder;
if(Emu.GetCPU().GetThreads()[0].IsSPU())
{
SPU_DisAsm& dis_asm = *new SPU_DisAsm(*(PPCThread*)NULL, DumpMode);
decoder = new SPU_Decoder(dis_asm);
disasm = &dis_asm;
}
else
{
PPU_DisAsm& dis_asm = *new PPU_DisAsm(*(PPCThread*)NULL, DumpMode);
decoder = new PPU_Decoder(dis_asm);
disasm = &dis_asm;
}
const u32 shdr_count = ElfType64 ? shdr_arr_64->GetCount() : shdr_arr_32->GetCount();
u64 max_count = 0;
for(u32 sh=0; sh<shdr_count; ++sh)
{
const u64 sh_size = (ElfType64 ? (*shdr_arr_64)[sh].sh_size : (*shdr_arr_32)[sh].sh_size) / 4;
max_count += sh_size;
}
wxArrayLong max;
max.Add(max_count);
MTProgressDialog& prog_dial = *new MTProgressDialog(NULL, wxDefaultSize, "Saving", "Loading...", max, 1);
max.Clear();
wxFile fd(ctrl.GetPath(), wxFile::write);
for(u32 sh=0, vsize=0; sh<shdr_count; ++sh)
{
const u64 sh_size = (ElfType64 ? (*shdr_arr_64)[sh].sh_size : (*shdr_arr_32)[sh].sh_size) / 4;
const u64 sh_addr = (ElfType64 ? (*shdr_arr_64)[sh].sh_addr : (*shdr_arr_32)[sh].sh_addr);
const wxString name = sh < name_arr.GetCount() ? name_arr[sh] : "Unknown";
fd.Write(wxString::Format("Start of section header %s[%d] (instructions count: %d)\n", name, sh, sh_size));
prog_dial.Update(0, vsize, wxString::Format("Disasm %s section", name));
if(Memory.IsGoodAddr(sh_addr))
{
for(u64 addr=sh_addr; addr<sh_addr+sh_size; addr, vsize++)
{
disasm->dump_pc = addr;
decoder->Decode(Memory.Read32(disasm->dump_pc));
fd.Write("\t");
fd.Write(disasm->last_opcode);
}
}
fd.Write(wxString::Format("End of section header %s[%d]\n\n", name, sh));
}
prog_dial.Close();
Emu.Stop();
/*
SYSTEM_INFO si;
GetSystemInfo(&si);
const uint cores_count =
(si.dwNumberOfProcessors < 1 || si.dwNumberOfProcessors > 8 ? 2 : si.dwNumberOfProcessors);
wxArrayLong max;
max.Clear();
u64 max_count = 0;
if(ElfType64)
{
for(uint sh=0; sh<l_elf64->shdr_arr.GetCount(); ++sh)
{
max_count += l_elf64->shdr_arr[sh].sh_size / 4;
}
}
else
{
for(uint sh=0; sh<l_elf32->shdr_arr.GetCount(); ++sh)
{
max_count += l_elf32->shdr_arr[sh].sh_size / 4;
}
}
for(uint c=0; c<cores_count; ++c) max.Add(max_count / cores_count);
for(uint c=0; c<max_count % cores_count; ++c) max[c]++;
MTProgressDialog& prog_dial = *new MTProgressDialog(this, wxDefaultSize, "Dumping...", "Loading", max, cores_count);
DumperThread* dump = new DumperThread[cores_count];
wxArrayString** arr = new wxArrayString*[cores_count];
bool* threads_done = new bool[cores_count];
for(uint i=0; i<cores_count; ++i)
{
arr[i] = new wxArrayString[ElfType64 ? l_elf64->shdr_arr.GetCount() : l_elf32->shdr_arr.GetCount()];
dump[i].Set(i, cores_count, &threads_done[i], prog_dial, arr);
dump[i].Start();
}
WaitDumperThread& wait_dump =
*new WaitDumperThread(threads_done, cores_count, ctrl.GetPath(), prog_dial, arr);
wait_dump.Start();
*/
}
void DisAsmFrame::Prev (wxCommandEvent& WXUNUSED(event)) { if(Emu.IsPaused()) { CPU.SetPc( CPU.PC - 4*(LINES_OPCODES+1)); Resume(); } }
void DisAsmFrame::Next (wxCommandEvent& WXUNUSED(event)) { if(Emu.IsPaused()) { CPU.SetPc( CPU.PC - 4*(LINES_OPCODES-1)); Resume(); } }
void DisAsmFrame::fPrev(wxCommandEvent& WXUNUSED(event)) { if(Emu.IsPaused()) { CPU.SetPc( CPU.PC - (4*LINES_OPCODES)*2); Resume(); } }
void DisAsmFrame::fNext(wxCommandEvent& WXUNUSED(event)) { if(Emu.IsPaused()) { Resume(); } }
void DisAsmFrame::SetPc(wxCommandEvent& WXUNUSED(event))
{
if(!Emu.IsPaused()) return;
wxDialog diag(this, wxID_ANY, "Set PC", wxDefaultPosition);
wxBoxSizer* s_panel(new wxBoxSizer(wxVERTICAL));
wxBoxSizer* s_b_panel(new wxBoxSizer(wxHORIZONTAL));
wxTextCtrl* p_pc(new wxTextCtrl(&diag, wxID_ANY));
s_panel->Add(p_pc);
s_panel->AddSpacer(8);
s_panel->Add(s_b_panel);
s_b_panel->Add(new wxButton(&diag, wxID_OK), wxLEFT, 0, 5);
s_b_panel->AddSpacer(5);
s_b_panel->Add(new wxButton(&diag, wxID_CANCEL), wxRIGHT, 0, 5);
diag.SetSizerAndFit( s_panel );
p_pc->SetLabel(wxString::Format("%llx", CPU.PC));
if(diag.ShowModal() == wxID_OK)
{
sscanf(p_pc->GetLabel(), "%llx", &CPU.PC);
Resume();
}
}
void DisAsmFrame::MouseWheel(wxMouseEvent& event)
{
if(!Emu.IsPaused())
{
event.Skip();
return;
}
const int value = (event.m_wheelRotation / event.m_wheelDelta);
if(event.ControlDown())
{
CPU.SetPc( CPU.PC - (((4*LINES_OPCODES)*2)*value) );
}
else
{
CPU.SetPc( CPU.PC - 4*(LINES_OPCODES + (value /** event.m_linesPerAction*/)) );
}
Emu.Resume();
event.Skip();
}

32
rpcs3/Gui/DisAsmFrame.h Normal file
View File

@ -0,0 +1,32 @@
#pragma once
class DisAsmFrame : public wxFrame
{
static const uint LINES_OPCODES = 40;
u32 count;
wxListView* m_disasm_list;
PPCThread& CPU;
virtual void OnResize(wxSizeEvent& event);
virtual void Prev (wxCommandEvent& event);
virtual void Next (wxCommandEvent& event);
virtual void fPrev(wxCommandEvent& event);
virtual void fNext(wxCommandEvent& event);
virtual void SetPc(wxCommandEvent& event);
void Dump(wxCommandEvent& event);
void Resume();
void MouseWheel(wxMouseEvent& event);
public:
bool exit;
DisAsmFrame(PPCThread& cpu);
~DisAsmFrame()
{
exit = true;
}
virtual void AddLine(const wxString line);
};

62
rpcs3/Gui/FrameBase.h Normal file
View File

@ -0,0 +1,62 @@
#pragma once
class FrameBase : public wxFrame
{
protected:
IniEntry<WindowInfo> m_ini;
WindowInfo m_default_info;
FrameBase(
wxWindow* parent,
wxWindowID id = wxID_ANY,
const wxString& framename = "UnknownFrame",
const wxString& ininame = wxEmptyString,
wxSize defsize = wxDefaultSize,
wxPoint defposition = wxDefaultPosition,
long style = wxDEFAULT_FRAME_STYLE)
: wxFrame(parent, id, framename, defposition, defsize, style)
, m_default_info(defsize, defposition)
{
m_ini.Init(ininame.IsEmpty() ? framename : ininame, "GuiSettings");
LoadInfo();
Connect(GetId(), wxEVT_CLOSE_WINDOW, wxCloseEventHandler(FrameBase::OnClose));
Connect(GetId(), wxEVT_MOVE, wxMoveEventHandler(FrameBase::OnMove));
Connect(wxEVT_SIZE, wxSizeEventHandler(FrameBase::OnResize));
}
~FrameBase()
{
}
void SetSizerAndFit(wxSizer *sizer, bool deleteOld = true, bool loadinfo = true)
{
wxFrame::SetSizerAndFit(sizer, deleteOld);
if(loadinfo) LoadInfo();
}
void LoadInfo()
{
const WindowInfo& info = m_ini.LoadValue(m_default_info);
SetSize(info.size);
SetPosition(info.position);
}
void OnMove(wxMoveEvent& event)
{
m_ini.SetValue(WindowInfo(m_ini.GetValue().size, GetPosition()));
event.Skip();
}
void OnResize(wxSizeEvent& event)
{
m_ini.SetValue(WindowInfo(GetSize(), m_ini.GetValue().position));
//event.Skip();
}
void OnClose(wxCloseEvent& event)
{
m_ini.Save();
event.Skip();
}
};

112
rpcs3/Gui/GameViewer.cpp Normal file
View File

@ -0,0 +1,112 @@
#include "stdafx.h"
#include "GameViewer.h"
#include "Loader/PSF.h"
static const wxString m_class_name = "GameViewer";
GameViewer::GameViewer(wxWindow* parent) : wxPanel(parent)
{
wxBoxSizer& s_panel( *new wxBoxSizer(wxVERTICAL) );
m_game_list = new wxListView(this);
s_panel.Add(m_game_list);
SetSizerAndFit( &s_panel );
LoadSettings();
m_columns.Show(m_game_list);
m_path = wxGetCwd(); //TODO
Connect(m_game_list->GetId(), wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler(GameViewer::DClick));
Refresh();
}
GameViewer::~GameViewer()
{
SaveSettings();
m_game_list->Destroy();
}
void GameViewer::DoResize(wxSize size)
{
SetSize(size);
m_game_list->SetSize(size);
}
void GameViewer::LoadGames()
{
if(!wxDirExists(m_path)) return;
m_games.Clear();
wxDir dir(m_path);
if(!dir.HasSubDirs()) return;
wxString buf;
if(!dir.GetFirst(&buf)) return;
if(wxDirExists(buf)) m_games.Add(buf);
for(;;)
{
if(!dir.GetNext(&buf)) break;
if(wxDirExists(buf)) m_games.Add(buf);
}
//ConLog.Write("path: %s", m_path);
//ConLog.Write("folders count: %d", m_games.GetCount());
}
void GameViewer::LoadPSF()
{
m_game_data.Clear();
for(uint i=0; i<m_games.GetCount(); ++i)
{
const wxString& path = m_games[i] + "\\" + "PARAM.SFO";
if(!wxFileExists(path)) continue;
PSFLoader psf(path);
if(!psf.Load(false)) continue;
psf.m_info.root = m_games[i];
m_game_data.Add(new GameInfo(psf.m_info));
}
m_columns.Update(m_game_data);
}
void GameViewer::ShowData()
{
m_columns.ShowData(m_game_list);
}
void GameViewer::Refresh()
{
LoadGames();
LoadPSF();
ShowData();
}
void GameViewer::SaveSettings()
{
m_columns.LoadSave(false, m_class_name, m_game_list);
}
void GameViewer::LoadSettings()
{
m_columns.LoadSave(true, m_class_name);
}
void GameViewer::DClick(wxListEvent& event)
{
long i = m_game_list->GetFirstSelected();
if(i < 0) return;
const wxString& path = m_game_data[i].root + "\\" + "USRDIR" + "\\" + "BOOT.BIN";
if(!wxFileExists(path))
{
ConLog.Error("Boot error: elf not found! [%s]", path);
return;
}
Emu.Stop();
Emu.SetElf(path);
Emu.Run();
}

242
rpcs3/Gui/GameViewer.h Normal file
View File

@ -0,0 +1,242 @@
#pragma once
#include <wx/listctrl.h>
#include "Emu/GameInfo.h"
struct Column
{
u32 pos;
u32 width;
bool shown;
wxArrayString data;
const wxString name;
const u32 def_pos;
const u32 def_width;
Column(const u32 _def_pos, const u32 _def_width, const wxString& _name)
: def_pos(_def_pos)
, def_width(_def_width)
, pos(_def_pos)
, width(_def_width)
, shown(true)
, name(_name)
{
data.Clear();
}
};
struct ColumnsArr
{
ArrayF<Column> m_columns;
ColumnsArr()
{
Init();
}
ArrayF<Column>* GetSortedColumnsByPos()
{
static ArrayF<Column>& arr = *new ArrayF<Column>(); arr.ClearF();
for(u32 pos=0; pos<m_columns.GetCount(); pos++)
{
for(u32 c=0; c<m_columns.GetCount(); ++c)
{
if(m_columns[c].pos != pos) continue;
arr.Add(m_columns[c]);
}
}
return &arr;
}
Column* GetColumnByPos(u32 pos)
{
ArrayF<Column>& columns = *GetSortedColumnsByPos();
for(u32 c=0; c<columns.GetCount(); ++c)
{
if(!columns[c].shown)
{
pos++;
continue;
}
if(columns[c].pos != pos) continue;
return &columns[c];
}
return NULL;
}
public:
Column* m_col_name;
Column* m_col_serial;
Column* m_col_fw;
Column* m_col_app_ver;
Column* m_col_category;
Column* m_col_path;
void Init()
{
m_columns.Clear();
#define ADD_COLUMN(x, w, n) x = new Column(m_columns.GetCount(), w, n); m_columns.Add(x);
ADD_COLUMN(m_col_name, 160, "Name");
ADD_COLUMN(m_col_serial, 85, "Serial");
ADD_COLUMN(m_col_fw, 55, "FW");
ADD_COLUMN(m_col_app_ver, 55, "App version");
ADD_COLUMN(m_col_category, 55, "Category");
ADD_COLUMN(m_col_path, 160, "Path");
#undef ADD_COLUMN
}
void Update(ArrayF<GameInfo>& game_data)
{
m_col_name->data.Clear();
m_col_serial->data.Clear();
m_col_fw->data.Clear();
m_col_app_ver->data.Clear();
m_col_category->data.Clear();
m_col_path->data.Clear();
if(m_columns.GetCount() == 0) return;
for(uint i=0; i<game_data.GetCount(); ++i)
{
GameInfo& game = game_data[i];
m_col_name->data.Add(game.name);
m_col_serial->data.Add(game.serial);
m_col_fw->data.Add(game.fw);
m_col_app_ver->data.Add(game.app_ver);
m_col_category->data.Add(game.category);
m_col_path->data.Add(game.root);
}
}
void Show(wxListView* list)
{
list->DeleteAllColumns();
ArrayF<Column>& c_col = *GetSortedColumnsByPos();
for(u32 i=0, c=0; i<c_col.GetCount(); ++i)
{
if(!c_col[i].shown) continue;
list->InsertColumn(c++, c_col[i].name, 0, c_col[i].width);
}
}
void ShowData(wxListView* list)
{
list->DeleteAllItems();
for(int c=0; c<list->GetColumnCount(); ++c)
{
Column* col = GetColumnByPos(c);
if(!col)
{
ConLog.Error("Columns loaded with error!");
return;
}
for(u32 i=0; i<col->data.GetCount(); ++i)
{
if(list->GetItemCount() <= (int)i) list->InsertItem(i, wxEmptyString);
list->SetItem(i, c, col->data[i]);
}
}
}
void LoadSave(bool isLoad, const wxString& path, wxListView* list = NULL)
{
if(isLoad) Init();
else if(list)
{
for(int c=0; c<list->GetColumnCount(); ++c)
{
Column* col = GetColumnByPos(c);
if(col) col->width = list->GetColumnWidth(c);
}
}
#define ADD_COLUMN(v, dv, t, n, isshown) \
{ \
IniEntry<t> ini; \
ini.Init(m_columns[i].name + "_" + n, path); \
if(isLoad) m_columns[i].v = ini.LoadValue(dv); \
else if(isshown ? m_columns[i].shown : 1) \
{ \
ini.SetValue(m_columns[i].v); \
ini.Save(); \
} \
}
for(u32 i=0; i<m_columns.GetCount(); ++i)
{
ADD_COLUMN(pos, m_columns[i].def_pos, int, "position", 1);
ADD_COLUMN(width, m_columns[i].def_width, int, "width", 1);
ADD_COLUMN(shown, true, bool, "shown", 0);
}
if(isLoad)
{
//check for errors
for(u32 c1=0; c1<m_columns.GetCount(); ++c1)
{
for(u32 c2=c1+1; c2<m_columns.GetCount(); ++c2)
{
if(m_columns[c1].pos == m_columns[c2].pos)
{
ConLog.Error("Columns loaded with error!");
Init();
return;
}
}
}
for(u32 p=0; p<m_columns.GetCount(); ++p)
{
bool ishas = false;
for(u32 c=0; c<m_columns.GetCount(); ++c)
{
if(m_columns[c].pos != p) continue;
ishas = true;
break;
}
if(!ishas)
{
ConLog.Error("Columns loaded with error!");
Init();
return;
}
}
}
#undef ADD_COLUMN
}
};
class GameViewer : public wxPanel
{
wxListView* m_game_list;
wxString m_path;
wxArrayString m_games;
ArrayF<GameInfo> m_game_data;
ColumnsArr m_columns;
public:
GameViewer(wxWindow* parent);
~GameViewer();
void DoResize(wxSize size);
void LoadGames();
void LoadPSF();
void ShowData();
void SaveSettings();
void LoadSettings();
void Refresh();
private:
virtual void DClick(wxListEvent& event);
};

View File

@ -0,0 +1,470 @@
#include "stdafx.h"
#include "InterpreterDisAsm.h"
static const int show_lines = 30;
static const wxString& BreakPointsDBName = "BreakPoints.dat";
static const u16 bpdb_version = 0x1000;
u32 FixPc(const u32 pc)
{
return pc - ((show_lines/2)*4);
}
InterpreterDisAsmFrame::InterpreterDisAsmFrame(const wxString& title, PPCThread* cpu)
: FrameBase(NULL, wxID_ANY, title, "InterpreterDisAsmFrame", wxSize(500, 700))
, ThreadBase(false, "DisAsmFrame Thread")
, m_main_panel(*new wxPanel(this))
, CPU(*cpu)
, PC(0)
, m_exec(false)
{
if(CPU.IsSPU())
{
SPU_DisAsm& dis_asm = *new SPU_DisAsm(CPU, InterpreterMode);
decoder = new SPU_Decoder(dis_asm);
disasm = &dis_asm;
}
else
{
PPU_DisAsm& dis_asm = *new PPU_DisAsm(CPU, InterpreterMode);
decoder = new PPU_Decoder(dis_asm);
disasm = &dis_asm;
}
wxBoxSizer& s_p_main = *new wxBoxSizer(wxVERTICAL);
wxBoxSizer& s_b_main = *new wxBoxSizer(wxHORIZONTAL);
m_list = new wxListView(&m_main_panel);
wxButton& b_go_to_addr = *new wxButton(&m_main_panel, wxID_ANY, "Go To Address");
wxButton& b_go_to_pc = *new wxButton(&m_main_panel, wxID_ANY, "Go To PC");
m_btn_step = new wxButton(&m_main_panel, wxID_ANY, "Step");
m_btn_run = new wxButton(&m_main_panel, wxID_ANY, "Run");
m_btn_pause = new wxButton(&m_main_panel, wxID_ANY, "Pause");
s_b_main.Add(&b_go_to_addr, wxSizerFlags().Border(wxALL, 5));
s_b_main.Add(&b_go_to_pc, wxSizerFlags().Border(wxALL, 5));
s_b_main.Add(m_btn_step, wxSizerFlags().Border(wxALL, 5));
s_b_main.Add(m_btn_run, wxSizerFlags().Border(wxALL, 5));
s_b_main.Add(m_btn_pause, wxSizerFlags().Border(wxALL, 5));
m_regs = new wxTextCtrl(&m_main_panel, wxID_ANY, wxEmptyString,
wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_DONTWRAP|wxNO_BORDER|wxTE_RICH2);
m_regs->SetMinSize(wxSize(495, 100));
m_regs->SetEditable(false);
m_list->SetFont(wxFont(8, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL));
m_regs->SetFont(wxFont(8, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL));
wxBoxSizer& s_w_list = *new wxBoxSizer(wxHORIZONTAL);
s_w_list.Add(m_list);
s_w_list.AddSpacer(5);
s_w_list.Add(m_regs);
s_p_main.AddSpacer(5);
s_p_main.Add(&s_b_main);
s_p_main.AddSpacer(5);
s_p_main.Add(&s_w_list);
s_p_main.AddSpacer(5);
wxBoxSizer& s_p_main_h = *new wxBoxSizer(wxVERTICAL);
s_p_main_h.AddSpacer(5);
s_p_main_h.Add(&s_p_main);
s_p_main_h.AddSpacer(5);
m_main_panel.SetSizerAndFit(&s_p_main_h);
wxBoxSizer& s_main = *new wxBoxSizer(wxVERTICAL);
s_main.Add(&m_main_panel);
SetSizerAndFit(&s_main);
m_list->InsertColumn(0, "ASM");
for(uint i=0; i<show_lines; ++i)
{
m_list->InsertItem(m_list->GetItemCount(), wxEmptyString);
}
Connect(m_regs->GetId(), wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler(InterpreterDisAsmFrame::OnUpdate));
Connect(b_go_to_addr.GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(InterpreterDisAsmFrame::Show_Val));
Connect(b_go_to_pc.GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(InterpreterDisAsmFrame::Show_PC));
Connect(m_btn_step->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(InterpreterDisAsmFrame::DoStep));
Connect(m_btn_run->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(InterpreterDisAsmFrame::DoRun));
Connect(m_btn_pause->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(InterpreterDisAsmFrame::DoPause));
Connect(m_list->GetId(), wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler(InterpreterDisAsmFrame::DClick));
Connect(wxEVT_SIZE, wxSizeEventHandler(InterpreterDisAsmFrame::OnResize));
wxGetApp().Connect(m_list->GetId(), wxEVT_MOUSEWHEEL, wxMouseEventHandler(InterpreterDisAsmFrame::MouseWheel), (wxObject*)0, this);
wxGetApp().Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(InterpreterDisAsmFrame::OnKeyDown), (wxObject*)0, this);
m_btn_pause->Disable();
//ShowPc(Loader.entry);
WriteRegs();
ThreadBase::Start();
Load(BreakPointsDBName);
}
InterpreterDisAsmFrame::~InterpreterDisAsmFrame()
{
ThreadBase::Stop();
Save(BreakPointsDBName);
}
void InterpreterDisAsmFrame::Save(const wxString& path)
{
wxFile f(path, wxFile::write);
u32 break_count = m_break_points.GetCount();
u32 marked_count = markedPC.GetCount();
f.Write(&bpdb_version, sizeof(u16));
f.Write(&break_count, sizeof(u32));
f.Write(&marked_count, sizeof(u32));
for(u32 i=0; i<break_count; ++i)
{
f.Write(&m_break_points[i], sizeof(u64));
}
for(u32 i=0; i<marked_count; ++i)
{
f.Write(&markedPC[i], sizeof(u64));
}
}
void InterpreterDisAsmFrame::Load(const wxString& path)
{
if(!wxFileExists(path)) return;
wxFile f(path);
u32 break_count, marked_count;
u16 version;
f.Read(&version, sizeof(u16));
f.Read(&break_count, sizeof(u32));
f.Read(&marked_count, sizeof(u32));
if(version != bpdb_version ||
(sizeof(u16) + break_count * sizeof(u64) + sizeof(u32) + marked_count * sizeof(u64) + sizeof(u32)) != f.Length())
{
ConLog.Error("'%s' is borken", path);
return;
}
if(break_count > 0)
{
m_break_points.SetCount(break_count);
for(u32 i=0; i<break_count; ++i)
{
f.Read(&m_break_points[i], sizeof(u64));
}
}
if(marked_count > 0)
{
markedPC.SetCount(marked_count);
for(u32 i=0; i<marked_count; ++i)
{
f.Read(&markedPC[i], sizeof(u64));
}
}
}
void InterpreterDisAsmFrame::OnKeyDown(wxKeyEvent& event)
{
if(wxGetActiveWindow() != this)
{
event.Skip();
return;
}
if(event.ControlDown())
{
if(event.GetKeyCode() == WXK_SPACE)
{
DoStep(wxCommandEvent());
return;
}
}
else
{
switch(event.GetKeyCode())
{
case WXK_PAGEUP: ShowAddr( PC - (show_lines * 2) * 4 ); return;
case WXK_PAGEDOWN: ShowAddr( PC ); return;
case WXK_UP: ShowAddr( PC - (show_lines + 1) * 4 ); return;
case WXK_DOWN: ShowAddr( PC - (show_lines - 1) * 4 ); return;
}
}
event.Skip();
}
void InterpreterDisAsmFrame::DoUpdate()
{
Show_PC(wxCommandEvent());
WriteRegs();
}
void InterpreterDisAsmFrame::ShowAddr(const u64 addr)
{
PC = addr;
m_list->Freeze();
for(uint i=0; i<show_lines; ++i, PC += 4)
{
if(!Memory.IsGoodAddr(PC, 4))
{
m_list->SetItem(i, 0, wxString::Format("[%08llx] illegal address", PC));
continue;
}
disasm->dump_pc = PC;
decoder->Decode(Memory.Read32(PC));
if(IsBreakPoint(PC))
{
m_list->SetItem(i, 0, ">>> " + disasm->last_opcode);
}
else
{
m_list->SetItem(i, 0, " " + disasm->last_opcode);
}
wxColour colour;
if(PC == CPU.PC)
{
colour = wxColour("Green");
}
else
{
colour = wxColour("White");
for(u32 i=0; i<markedPC.GetCount(); ++i)
{
if(markedPC[i] == PC)
{
colour = wxColour("Wheat");
break;
}
}
}
m_list->SetItemBackgroundColour( i, colour );
}
while(remove_markedPC.GetCount())
{
u32 mpc = remove_markedPC[0];
for(u32 i=0; i<remove_markedPC.GetCount(); ++i)
{
if(remove_markedPC[i] == mpc)
{
remove_markedPC.RemoveAt(i--);
continue;
}
if(remove_markedPC[i] > mpc) remove_markedPC[i]--;
}
markedPC.RemoveAt(mpc);
}
m_list->Thaw();
}
void InterpreterDisAsmFrame::WriteRegs()
{
m_regs->Freeze();
m_regs->Clear();
m_regs->WriteText(CPU.RegsToString());
m_regs->Thaw();
}
void InterpreterDisAsmFrame::OnUpdate(wxCommandEvent& event)
{
//WriteRegs();
}
void InterpreterDisAsmFrame::Show_Val(wxCommandEvent& WXUNUSED(event))
{
wxDialog* diag = new wxDialog(this, wxID_ANY, "Set value", wxDefaultPosition);
wxBoxSizer* s_panel(new wxBoxSizer(wxVERTICAL));
wxBoxSizer* s_b_panel(new wxBoxSizer(wxHORIZONTAL));
wxTextCtrl* p_pc(new wxTextCtrl(diag, wxID_ANY));
s_panel->Add(p_pc);
s_panel->AddSpacer(8);
s_panel->Add(s_b_panel);
s_b_panel->Add(new wxButton(diag, wxID_OK), wxLEFT, 0, 5);
s_b_panel->AddSpacer(5);
s_b_panel->Add(new wxButton(diag, wxID_CANCEL), wxRIGHT, 0, 5);
diag->SetSizerAndFit( s_panel );
p_pc->SetLabel(wxString::Format("%llx", CPU.PC));
if(diag->ShowModal() == wxID_OK)
{
u64 pc = CPU.PC;
sscanf(p_pc->GetLabel(), "%llx", &pc);
remove_markedPC.AddCpy(markedPC.AddCpy(pc));
ShowAddr(FixPc(pc));
}
}
void InterpreterDisAsmFrame::Show_PC(wxCommandEvent& WXUNUSED(event))
{
ShowAddr(FixPc(CPU.PC));
}
extern bool dump_enable;
void InterpreterDisAsmFrame::DoRun(wxCommandEvent& WXUNUSED(event))
{
m_exec = true;
/*
bool dump_status = dump_enable;
if(Emu.IsPaused()) Emu.Run();
while(Emu.IsRunned())
{
CPU.Exec();
if(IsBreakPoint(CPU.PC) || dump_status != dump_enable) break;
}
DoUpdate();
*/
}
void InterpreterDisAsmFrame::DoPause(wxCommandEvent& WXUNUSED(event))
{
Emu.Pause();
}
void InterpreterDisAsmFrame::DoStep(wxCommandEvent& WXUNUSED(event))
{
CPU.Exec();
DoUpdate();
}
void InterpreterDisAsmFrame::DClick(wxListEvent& event)
{
long i = m_list->GetFirstSelected();
if(i < 0) return;
const u64 start_pc = PC - show_lines*4;
const u64 pc = start_pc + i*4;
//ConLog.Write("pc=0x%x", pc);
if(!Memory.IsGoodAddr(pc, 4)) return;
if(IsBreakPoint(pc))
{
RemoveBreakPoint(pc);
}
else
{
AddBreakPoint(pc);
}
ShowAddr(start_pc);
}
void InterpreterDisAsmFrame::OnResize(wxSizeEvent& event)
{
const wxSize& size( GetClientSize() );
wxTextCtrl& regs = *m_regs;
wxListView& list = *m_list;
const int list_size = size.GetWidth() * 0.75;
const int regs_size = size.GetWidth() * 0.25 - 5;
list.SetMinSize(wxSize(list_size, size.GetHeight()-55));
regs.SetMinSize(wxSize(regs_size, size.GetHeight()-55));
m_main_panel.SetSize( size );
m_main_panel.GetSizer()->RecalcSizes();
list.SetColumnWidth(0, list_size-8);
event.Skip();
}
void InterpreterDisAsmFrame::MouseWheel(wxMouseEvent& event)
{
const int value = (event.m_wheelRotation / event.m_wheelDelta);
if(event.ControlDown())
{
ShowAddr( PC - (show_lines * (value + 1)) * 4);
}
else
{
ShowAddr( PC - (show_lines + value) * 4 );
}
event.Skip();
}
bool InterpreterDisAsmFrame::IsBreakPoint(u64 pc)
{
for(u32 i=0; i<m_break_points.GetCount(); ++i)
{
if(m_break_points[i] == pc) return true;
}
return false;
}
void InterpreterDisAsmFrame::AddBreakPoint(u64 pc)
{
for(u32 i=0; i<m_break_points.GetCount(); ++i)
{
if(m_break_points[i] == pc) return;
}
m_break_points.AddCpy(pc);
}
bool InterpreterDisAsmFrame::RemoveBreakPoint(u64 pc)
{
for(u32 i=0; i<m_break_points.GetCount(); ++i)
{
if(m_break_points[i] != pc) continue;
m_break_points.RemoveAt(i);
return true;
}
return false;
}
void InterpreterDisAsmFrame::Task()
{
while(!TestDestroy())
{
Sleep(1);
if(!m_exec) continue;
m_btn_step->Disable();
m_btn_run->Disable();
m_btn_pause->Enable();
bool dump_status = dump_enable;
if(Emu.IsPaused()) Emu.Resume();
while(Emu.IsRunned() && !TestDestroy())
{
CPU.Exec();
if(IsBreakPoint(CPU.PC) || dump_status != dump_enable) break;
}
DoUpdate();
m_btn_step->Enable();
m_btn_run->Enable();
m_btn_pause->Disable();
m_exec = false;
}
}

View File

@ -0,0 +1,54 @@
#pragma once
#include "Emu/Cell/PPCThread.h"
#include "Emu/Cell/PPUDecoder.h"
#include "Emu/Cell/PPUDisAsm.h"
#include "Emu/Cell/SPUDecoder.h"
#include "Emu/Cell/SPUDisAsm.h"
class InterpreterDisAsmFrame
: public FrameBase
, public ThreadBase
{
wxListView* m_list;
wxPanel& m_main_panel;
PPCThread& CPU;
DisAsm* disasm;
Decoder* decoder;
u64 PC;
Array<u64> markedPC;
Array<u32> remove_markedPC;
wxTextCtrl* m_regs;
Array<u64> m_break_points;
wxButton* m_btn_step;
wxButton* m_btn_run;
wxButton* m_btn_pause;
volatile bool m_exec;
public:
InterpreterDisAsmFrame(const wxString& title, PPCThread* cpu);
~InterpreterDisAsmFrame();
void Save(const wxString& path);
void Load(const wxString& path);
virtual void OnKeyDown(wxKeyEvent& event);
void DoUpdate();
void ShowAddr(const u64 addr);
void WriteRegs();
void OnUpdate(wxCommandEvent& event);
void Show_Val(wxCommandEvent& event);
void Show_PC(wxCommandEvent& event);
void DoRun(wxCommandEvent& event);
void DoPause(wxCommandEvent& event);
void DoStep(wxCommandEvent& event);
void DClick(wxListEvent& event);
void OnResize(wxSizeEvent& event);
void MouseWheel(wxMouseEvent& event);
bool IsBreakPoint(u64 pc);
void AddBreakPoint(u64 pc);
bool RemoveBreakPoint(u64 pc);
virtual void Task();
};

390
rpcs3/Gui/MainFrame.cpp Normal file
View File

@ -0,0 +1,390 @@
#include "stdafx.h"
#include "MainFrame.h"
#include "CompilerELF.h"
#include "Emu/System.h"
#include "Ini.h"
#include "svnrev.h"
BEGIN_EVENT_TABLE(MainFrame, FrameBase)
EVT_CLOSE(MainFrame::OnQuit)
END_EVENT_TABLE()
enum IDs
{
id_boot_elf = 0x555,
id_boot_self,
id_boot_game,
id_sys_pause,
id_sys_stop,
id_config_emu,
};
MainFrame::MainFrame() : FrameBase(NULL, wxID_ANY, "", "MainFrame", wxSize(280, 180))
{
SetLabel(wxString::Format(_PRGNAME_ " " _PRGVER_ " r%d" SVN_MOD " (" SVN_DATE ")", SVN_REV));
wxMenuBar& menubar(*new wxMenuBar());
wxMenu& menu_boot(*new wxMenu());
wxMenu& menu_sys(*new wxMenu());
wxMenu& menu_conf(*new wxMenu());
menubar.Append(&menu_boot, "Boot");
menubar.Append(&menu_sys, "System");
menubar.Append(&menu_conf, "Config");
menu_boot.Append(id_boot_game, "Boot game");
menu_boot.AppendSeparator();
menu_boot.Append(id_boot_elf, "Boot Elf");
//menu_boot.Append(id_boot_self, "Boot Self");
menu_sys.Append(id_sys_pause, "Pause");
menu_sys.Append(id_sys_stop, "Stop");
menu_conf.Append(id_config_emu, "Settings");
SetMenuBar(&menubar);
wxBoxSizer& s_panel( *new wxBoxSizer(wxHORIZONTAL) );
m_game_viewer = new GameViewer(this);
s_panel.Add( m_game_viewer, wxSizerFlags().Expand() );
SetSizerAndFit( &s_panel );
Connect(wxEVT_SIZE, wxSizeEventHandler(MainFrame::OnResize));
Connect( id_boot_game, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainFrame::BootGame) );
Connect( id_boot_elf, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainFrame::BootElf) );
Connect( id_boot_self, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainFrame::BootSelf) );
Connect( id_sys_pause, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainFrame::Pause) );
Connect( id_sys_stop, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainFrame::Stop) );
Connect( id_config_emu, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainFrame::Config) );
wxGetApp().Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(MainFrame::OnKeyDown), (wxObject*)0, this);
UpdateUI();
(new CompilerELF(NULL))->Show();
}
void MainFrame::OnResize(wxSizeEvent& event)
{
m_game_viewer->DoResize(GetClientSize());
event.Skip();
}
void MainFrame::BootGame(wxCommandEvent& WXUNUSED(event))
{
bool stoped = false;
if(Emu.IsRunned())
{
Emu.Pause();
stoped = true;
}
wxDirDialog ctrl( this, L"Select game folder", wxEmptyString);
if(ctrl.ShowModal() == wxID_CANCEL)
{
if(stoped) Emu.Resume();
return;
}
Emu.Stop();
const wxString& elf0 = ctrl.GetPath() + "\\PS3_GAME\\USRDIR\\BOOT.BIN";
const wxString& elf1 = ctrl.GetPath() + "\\USRDIR\\BOOT.BIN";
const wxString& elf2 = ctrl.GetPath() + "\\BOOT.BIN";
const wxString& self0 = ctrl.GetPath() + "\\PS3_GAME\\USRDIR\\EBOOT.BIN";
const wxString& self1 = ctrl.GetPath() + "\\USRDIR\\EBOOT.BIN";
const wxString& self2 = ctrl.GetPath() + "\\EBOOT.BIN";
if(wxFile::Access(elf0, wxFile::read))
{
Emu.SetElf(elf0);
ConLog.Write("Elf: booting...");
}
else if(wxFile::Access(elf1, wxFile::read))
{
Emu.SetElf(elf1);
ConLog.Write("Elf: booting...");
}
else if(wxFile::Access(elf2, wxFile::read))
{
Emu.SetElf(elf2);
ConLog.Write("Elf: booting...");
}
else if(wxFile::Access(self0, wxFile::read))
{
goto _ELF_NOT_FOUND_;
Emu.SetSelf(self0);
ConLog.Warning("Self: booting...");
}
else if(wxFile::Access(self1, wxFile::read))
{
goto _ELF_NOT_FOUND_;
Emu.SetSelf(self1);
ConLog.Warning("Self: booting...");
}
else if(wxFile::Access(self2, wxFile::read))
{
goto _ELF_NOT_FOUND_;
Emu.SetSelf(self2);
ConLog.Warning("Self: booting...");
}
else
{
ConLog.Error("Not found ps3 game in selected folder! (%s)", ctrl.GetPath());
return;
}
Emu.Run();
ConLog.Write("Game: boot done.");
return;
_ELF_NOT_FOUND_:
ConLog.Error("Elf not found!");
}
void MainFrame::BootElf(wxCommandEvent& WXUNUSED(event))
{
bool stoped = false;
if(Emu.IsRunned())
{
Emu.Pause();
stoped = true;
}
wxFileDialog ctrl(this, L"Select ELF", wxEmptyString, wxEmptyString, "*.*",
wxFD_OPEN | wxFD_FILE_MUST_EXIST);
if(ctrl.ShowModal() == wxID_CANCEL)
{
if(stoped) Emu.Resume();
return;
}
ConLog.Write("Elf: booting...");
Emu.Stop();
Emu.SetElf(ctrl.GetPath());
Emu.Run();
ConLog.Write("Elf: boot done.");
}
void MainFrame::BootSelf(wxCommandEvent& WXUNUSED(event))
{
bool stoped = false;
if(Emu.IsRunned())
{
Emu.Pause();
stoped = true;
}
wxFileDialog ctrl(this, L"Select SELF", wxEmptyString, wxEmptyString, "*.*",
wxFD_OPEN | wxFD_FILE_MUST_EXIST);
if(ctrl.ShowModal() == wxID_CANCEL)
{
if(stoped) Emu.Resume();
return;
}
ConLog.Write("SELF: booting...");
Emu.Stop();
Emu.SetSelf(ctrl.GetPath());
Emu.Run();
ConLog.Write("SELF: boot done.");
}
void MainFrame::Pause(wxCommandEvent& WXUNUSED(event))
{
if(Emu.IsPaused())
{
Emu.Resume();
}
else if(Emu.IsRunned())
{
Emu.Pause();
}
}
void MainFrame::Stop(wxCommandEvent& WXUNUSED(event))
{
Emu.Stop();
}
void MainFrame::Config(wxCommandEvent& WXUNUSED(event))
{
//TODO
bool paused = false;
if(Emu.IsRunned())
{
Emu.Pause();
paused = true;
}
wxDialog* diag = new wxDialog(this, wxID_ANY, "Settings", wxDefaultPosition);
wxBoxSizer* s_panel(new wxBoxSizer(wxVERTICAL));
wxStaticBoxSizer* s_round_cpu( new wxStaticBoxSizer( wxVERTICAL, diag, _("CPU") ) );
wxStaticBoxSizer* s_round_cpu_decoder( new wxStaticBoxSizer( wxVERTICAL, diag, _("Decoder") ) );
wxStaticBoxSizer* s_round_gs( new wxStaticBoxSizer( wxHORIZONTAL, diag, _("GS") ) );
wxStaticBoxSizer* s_round_gs_render( new wxStaticBoxSizer( wxVERTICAL, diag, _("Render") ) );
wxStaticBoxSizer* s_round_pad( new wxStaticBoxSizer( wxHORIZONTAL, diag, _("Pad") ) );
wxStaticBoxSizer* s_round_pad_handler( new wxStaticBoxSizer( wxVERTICAL, diag, _("Handler") ) );
wxComboBox* cbox_cpu_decoder = new wxComboBox(diag, wxID_ANY);
wxComboBox* cbox_gs_render = new wxComboBox(diag, wxID_ANY);
wxComboBox* cbox_pad_handler = new wxComboBox(diag, wxID_ANY);
//cbox_cpu_decoder->Append("DisAsm");
cbox_cpu_decoder->Append("Interpreter & DisAsm");
cbox_cpu_decoder->Append("Interpreter");
cbox_gs_render->Append("Null");
cbox_gs_render->Append("OpenGL");
//cbox_gs_render->Append("Software");
cbox_pad_handler->Append("Null");
cbox_pad_handler->Append("Windows");
//cbox_pad_handler->Append("DirectInput");
cbox_cpu_decoder->SetSelection(Ini.CPUDecoderMode.GetValue() ? Ini.CPUDecoderMode.GetValue() - 1 : 0);
cbox_gs_render->SetSelection(Ini.GSRenderMode.GetValue());
cbox_pad_handler->SetSelection(Ini.PadHandlerMode.GetValue());
s_round_cpu_decoder->Add(cbox_cpu_decoder);
s_round_cpu->Add(s_round_cpu_decoder);
s_round_gs_render->Add(cbox_gs_render);
s_round_gs->Add(s_round_gs_render);
s_round_pad_handler->Add(cbox_pad_handler);
s_round_pad->Add(s_round_pad_handler);
wxBoxSizer* s_b_panel(new wxBoxSizer(wxHORIZONTAL));
s_b_panel->Add(new wxButton(diag, wxID_OK));
s_b_panel->AddSpacer(5);
s_b_panel->Add(new wxButton(diag, wxID_CANCEL));
s_panel->Add(s_round_cpu);
s_panel->AddSpacer(5);
s_panel->Add(s_round_gs);
s_panel->AddSpacer(5);
s_panel->Add(s_round_pad);
s_panel->AddSpacer(8);
s_panel->Add(s_b_panel, wxRIGHT);
diag->SetSizerAndFit( s_panel );
if(diag->ShowModal() == wxID_OK)
{
Ini.CPUDecoderMode.SetValue(cbox_cpu_decoder->GetSelection() + 1);
Ini.GSRenderMode.SetValue(cbox_gs_render->GetSelection());
Ini.PadHandlerMode.SetValue(cbox_pad_handler->GetSelection());
Ini.Save();
}
delete diag;
if(paused) Emu.Resume();
}
void MainFrame::OnQuit(wxCloseEvent& event)
{
TheApp->Exit();
}
struct state_hdr
{
u32 magic;
u16 version;
u32 mem_count;
u32 mem_offset;
u32 mem_size;
u32 hle_count;
u32 hle_offset;
};
static const u32 state_magic = *(u32*)"R3SS";
static const u32 state_version = 0x1000;
void MakeSaveState(wxFile& f)
{
const ArrayF<MemoryBlock>& mb = Memory.MemoryBlocks;
state_hdr state;
memset(&state, 0, sizeof(state_hdr));
state.magic = state_magic;
state.version = state_version;
state.mem_count = mb.GetCount();
//state.hle_count = mb.GetCount();
state.mem_offset = sizeof(state_hdr) + 4;
f.Seek(state.mem_offset);
for(u32 i=0; i<state.mem_count; ++i)
{
state.mem_size += mb[i].GetSize();
f.Write(mb[i].GetMem(), mb[i].GetSize());
}
state.hle_offset = state.mem_offset + state.mem_size + 4;
f.Seek(0);
f.Write(&state, sizeof(state_hdr));
}
void MainFrame::OnKeyDown(wxKeyEvent& event)
{
if(wxGetActiveWindow() == this && event.ControlDown())
{
switch(event.GetKeyCode())
{
case 'C': case 'c': if(Emu.IsPaused()) Emu.Resume(); return;
case 'S': case 's': if(!Emu.IsStopped()) Emu.Stop(); return;
case 'R': case 'r': if(Emu.m_path.Len()) {Emu.Stop(); Emu.Run();} return;
}
}
event.Skip();
}
void MainFrame::UpdateUI()
{
wxMenuBar& menubar( *GetMenuBar() );
wxMenuItem& pause = *menubar.FindItem( id_sys_pause );
wxMenuItem& stop = *menubar.FindItem( id_sys_stop );
if(Emu.IsRunned())
{
pause.SetText("Pause");
pause.Enable();
stop.Enable();
}
else
{
pause.SetText("Resume");
pause.Enable(Emu.IsPaused());
stop.Enable(Emu.IsPaused());
}
}

Some files were not shown because too many files have changed in this diff Show More