mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-22 02:32:36 +01:00
This commit is contained in:
parent
de070bf485
commit
a90b5cf37a
11486
GL/glext.h
Normal file
11486
GL/glext.h
Normal file
File diff suppressed because it is too large
Load Diff
267
Utilities/Array.h
Normal file
267
Utilities/Array.h
Normal 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
136
Utilities/IdManager.h
Normal 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;
|
||||
}
|
||||
};
|
98
Utilities/MTProgressDialog.h
Normal file
98
Utilities/MTProgressDialog.h
Normal 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
29
Utilities/Thread.cpp
Normal 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
177
Utilities/Thread.h
Normal 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
47
Utilities/Timer.h
Normal 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;
|
||||
}
|
||||
};
|
BIN
bin/dev_hdd0/game/TEST12345/USRDIR/dump_stack.elf
Normal file
BIN
bin/dev_hdd0/game/TEST12345/USRDIR/dump_stack.elf
Normal file
Binary file not shown.
BIN
bin/dev_hdd0/game/TEST12345/USRDIR/gs_basic_triangle.elf
Normal file
BIN
bin/dev_hdd0/game/TEST12345/USRDIR/gs_basic_triangle.elf
Normal file
Binary file not shown.
BIN
bin/dev_hdd0/game/TEST12345/USRDIR/pad_test.elf
Normal file
BIN
bin/dev_hdd0/game/TEST12345/USRDIR/pad_test.elf
Normal file
Binary file not shown.
BIN
bin/dev_hdd0/game/TEST12345/USRDIR/ppu_thread.elf
Normal file
BIN
bin/dev_hdd0/game/TEST12345/USRDIR/ppu_thread.elf
Normal file
Binary file not shown.
BIN
bin/dev_hdd0/game/TEST12345/USRDIR/pspgame.elf
Normal file
BIN
bin/dev_hdd0/game/TEST12345/USRDIR/pspgame.elf
Normal file
Binary file not shown.
BIN
bin/dev_hdd0/game/TEST12345/USRDIR/rpcsp.elf
Normal file
BIN
bin/dev_hdd0/game/TEST12345/USRDIR/rpcsp.elf
Normal file
Binary file not shown.
BIN
bin/dev_hdd0/game/TEST12345/USRDIR/tetris.elf
Normal file
BIN
bin/dev_hdd0/game/TEST12345/USRDIR/tetris.elf
Normal file
Binary file not shown.
262
rpcs3.sln
Normal file
262
rpcs3.sln
Normal 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
7
rpcs3/Emu/Cell/Decoder.h
Normal 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
277
rpcs3/Emu/Cell/DisAsm.h
Normal 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)));
|
||||
}
|
||||
};
|
204
rpcs3/Emu/Cell/PPCThread.cpp
Normal file
204
rpcs3/Emu/Cell/PPCThread.cpp
Normal 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
133
rpcs3/Emu/Cell/PPCThread.h
Normal 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;
|
||||
};
|
80
rpcs3/Emu/Cell/PPCThreadManager.cpp
Normal file
80
rpcs3/Emu/Cell/PPCThreadManager.cpp
Normal 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();
|
||||
}
|
||||
}
|
26
rpcs3/Emu/Cell/PPCThreadManager.h
Normal file
26
rpcs3/Emu/Cell/PPCThreadManager.h
Normal 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
487
rpcs3/Emu/Cell/PPUDecoder.h
Normal 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 [0–2] 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 [4–7] 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
1091
rpcs3/Emu/Cell/PPUDisAsm.h
Normal file
File diff suppressed because it is too large
Load Diff
1665
rpcs3/Emu/Cell/PPUInterpreter.h
Normal file
1665
rpcs3/Emu/Cell/PPUInterpreter.h
Normal file
File diff suppressed because it is too large
Load Diff
502
rpcs3/Emu/Cell/PPUOpcodes.h
Normal file
502
rpcs3/Emu/Cell/PPUOpcodes.h
Normal 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
|
255
rpcs3/Emu/Cell/PPUThread.cpp
Normal file
255
rpcs3/Emu/Cell/PPUThread.cpp
Normal 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
945
rpcs3/Emu/Cell/PPUThread.h
Normal 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
167
rpcs3/Emu/Cell/SPUDecoder.h
Normal 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
233
rpcs3/Emu/Cell/SPUDisAsm.h
Normal 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
|
338
rpcs3/Emu/Cell/SPUInterpreter.h
Normal file
338
rpcs3/Emu/Cell/SPUInterpreter.h
Normal 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
162
rpcs3/Emu/Cell/SPUOpcodes.h
Normal 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
|
66
rpcs3/Emu/Cell/SPUThread.cpp
Normal file
66
rpcs3/Emu/Cell/SPUThread.cpp
Normal 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
251
rpcs3/Emu/Cell/SPUThread.h
Normal 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
56
rpcs3/Emu/DbgConsole.cpp
Normal 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
90
rpcs3/Emu/DbgConsole.h
Normal 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
1038
rpcs3/Emu/GS/GCM.h
Normal file
File diff suppressed because it is too large
Load Diff
277
rpcs3/Emu/GS/GL/FragmentProgram.cpp
Normal file
277
rpcs3/Emu/GS/GL/FragmentProgram.cpp
Normal 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;
|
||||
}
|
||||
}
|
146
rpcs3/Emu/GS/GL/FragmentProgram.h
Normal file
146
rpcs3/Emu/GS/GL/FragmentProgram.h
Normal 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();
|
||||
};
|
53
rpcs3/Emu/GS/GL/GLBuffers.cpp
Normal file
53
rpcs3/Emu/GS/GL/GLBuffers.cpp
Normal 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);
|
||||
}
|
24
rpcs3/Emu/GS/GL/GLBuffers.h
Normal file
24
rpcs3/Emu/GS/GL/GLBuffers.h
Normal 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();
|
||||
};
|
1089
rpcs3/Emu/GS/GL/GLGSRender.cpp
Normal file
1089
rpcs3/Emu/GS/GL/GLGSRender.cpp
Normal file
File diff suppressed because it is too large
Load Diff
238
rpcs3/Emu/GS/GL/GLGSRender.h
Normal file
238
rpcs3/Emu/GS/GL/GLGSRender.h
Normal 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);
|
||||
};
|
42
rpcs3/Emu/GS/GL/GLProcTable.tbl
Normal file
42
rpcs3/Emu/GS/GL/GLProcTable.tbl
Normal 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);
|
13
rpcs3/Emu/GS/GL/OpenGL.cpp
Normal file
13
rpcs3/Emu/GS/GL/OpenGL.cpp
Normal 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
9
rpcs3/Emu/GS/GL/OpenGL.h
Normal 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();
|
93
rpcs3/Emu/GS/GL/Program.cpp
Normal file
93
rpcs3/Emu/GS/GL/Program.cpp
Normal 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
16
rpcs3/Emu/GS/GL/Program.h
Normal 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();
|
||||
};
|
117
rpcs3/Emu/GS/GL/ProgramBuffer.cpp
Normal file
117
rpcs3/Emu/GS/GL/ProgramBuffer.cpp
Normal 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();
|
||||
}
|
29
rpcs3/Emu/GS/GL/ProgramBuffer.h
Normal file
29
rpcs3/Emu/GS/GL/ProgramBuffer.h
Normal 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();
|
||||
};
|
78
rpcs3/Emu/GS/GL/ShaderParam.h
Normal file
78
rpcs3/Emu/GS/GL/ShaderParam.h
Normal 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 ¶ms[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;
|
||||
}
|
||||
};
|
362
rpcs3/Emu/GS/GL/VertexProgram.cpp
Normal file
362
rpcs3/Emu/GS/GL/VertexProgram.cpp
Normal 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;
|
||||
}
|
177
rpcs3/Emu/GS/GL/VertexProgram.h
Normal file
177
rpcs3/Emu/GS/GL/VertexProgram.h
Normal 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();
|
||||
};
|
45
rpcs3/Emu/GS/GSManager.cpp
Normal file
45
rpcs3/Emu/GS/GSManager.cpp
Normal 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
54
rpcs3/Emu/GS/GSManager.h
Normal 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
94
rpcs3/Emu/GS/GSRender.cpp
Normal 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
47
rpcs3/Emu/GS/GSRender.h
Normal 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);
|
||||
};
|
118
rpcs3/Emu/GS/Null/NullGSRender.h
Normal file
118
rpcs3/Emu/GS/Null/NullGSRender.h
Normal 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;
|
||||
}
|
||||
};
|
84
rpcs3/Emu/GS/RSXThread.cpp
Normal file
84
rpcs3/Emu/GS/RSXThread.cpp
Normal 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
25
rpcs3/Emu/GS/RSXThread.h
Normal 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();
|
||||
};
|
223
rpcs3/Emu/GS/sysutil_video.h
Normal file
223
rpcs3/Emu/GS/sysutil_video.h
Normal 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
42
rpcs3/Emu/GameInfo.h
Normal 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;
|
24
rpcs3/Emu/Io/Null/NullPadHandler.h
Normal file
24
rpcs3/Emu/Io/Null/NullPadHandler.h
Normal 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
38
rpcs3/Emu/Io/Pad.cpp
Normal 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
25
rpcs3/Emu/Io/Pad.h
Normal 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
202
rpcs3/Emu/Io/PadHandler.h
Normal 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; }
|
||||
};
|
58
rpcs3/Emu/Io/Windows/WindowsPadHandler.h
Normal file
58
rpcs3/Emu/Io/Windows/WindowsPadHandler.h
Normal 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
652
rpcs3/Emu/Memory/Memory.cpp
Normal 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
415
rpcs3/Emu/Memory/Memory.h
Normal 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;
|
122
rpcs3/Emu/Memory/MemoryBlock.h
Normal file
122
rpcs3/Emu/Memory/MemoryBlock.h
Normal 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);
|
||||
};
|
66
rpcs3/Emu/SysCalls/ErrorCodes.h
Normal file
66
rpcs3/Emu/SysCalls/ErrorCodes.h
Normal 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,
|
||||
};
|
3701
rpcs3/Emu/SysCalls/FuncList.cpp
Normal file
3701
rpcs3/Emu/SysCalls/FuncList.cpp
Normal file
File diff suppressed because it is too large
Load Diff
333
rpcs3/Emu/SysCalls/SysCalls.h
Normal file
333
rpcs3/Emu/SysCalls/SysCalls.h
Normal 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;
|
367
rpcs3/Emu/SysCalls/lv2/SC_FileSystem.cpp
Normal file
367
rpcs3/Emu/SysCalls/lv2/SC_FileSystem.cpp
Normal 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;
|
||||
}
|
133
rpcs3/Emu/SysCalls/lv2/SC_GCM.cpp
Normal file
133
rpcs3/Emu/SysCalls/lv2/SC_GCM.cpp
Normal 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;
|
||||
}
|
35
rpcs3/Emu/SysCalls/lv2/SC_Heap.cpp
Normal file
35
rpcs3/Emu/SysCalls/lv2/SC_Heap.cpp
Normal 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);
|
||||
}
|
105
rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp
Normal file
105
rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp
Normal 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;
|
||||
}
|
217
rpcs3/Emu/SysCalls/lv2/SC_Memory.cpp
Normal file
217
rpcs3/Emu/SysCalls/lv2/SC_Memory.cpp
Normal 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;
|
||||
}
|
126
rpcs3/Emu/SysCalls/lv2/SC_PPU_Thread.cpp
Normal file
126
rpcs3/Emu/SysCalls/lv2/SC_PPU_Thread.cpp
Normal 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;
|
||||
}
|
176
rpcs3/Emu/SysCalls/lv2/SC_Pad.cpp
Normal file
176
rpcs3/Emu/SysCalls/lv2/SC_Pad.cpp
Normal 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;
|
||||
}
|
89
rpcs3/Emu/SysCalls/lv2/SC_Process.cpp
Normal file
89
rpcs3/Emu/SysCalls/lv2/SC_Process.cpp
Normal 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;
|
||||
}
|
34
rpcs3/Emu/SysCalls/lv2/SC_Resc.cpp
Normal file
34
rpcs3/Emu/SysCalls/lv2/SC_Resc.cpp
Normal 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;
|
||||
}
|
68
rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp
Normal file
68
rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp
Normal 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;
|
||||
}
|
100
rpcs3/Emu/SysCalls/lv2/SC_SysUtil.cpp
Normal file
100
rpcs3/Emu/SysCalls/lv2/SC_SysUtil.cpp
Normal 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;
|
||||
}
|
34
rpcs3/Emu/SysCalls/lv2/SC_TTY.cpp
Normal file
34
rpcs3/Emu/SysCalls/lv2/SC_TTY.cpp
Normal 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;
|
||||
}
|
37
rpcs3/Emu/SysCalls/lv2/SC_Time.cpp
Normal file
37
rpcs3/Emu/SysCalls/lv2/SC_Time.cpp
Normal 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;
|
||||
}
|
21
rpcs3/Emu/SysCalls/lv2/SC_sys_spu.cpp
Normal file
21
rpcs3/Emu/SysCalls/lv2/SC_sys_spu.cpp
Normal 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
195
rpcs3/Emu/System.cpp
Normal 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
113
rpcs3/Emu/System.h
Normal 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
2601
rpcs3/Gui/CompilerELF.cpp
Normal file
File diff suppressed because it is too large
Load Diff
79
rpcs3/Gui/CompilerELF.h
Normal file
79
rpcs3/Gui/CompilerELF.h
Normal 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
270
rpcs3/Gui/ConLog.cpp
Normal 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
48
rpcs3/Gui/ConLog.h
Normal 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
502
rpcs3/Gui/DisAsmFrame.cpp
Normal 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
32
rpcs3/Gui/DisAsmFrame.h
Normal 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
62
rpcs3/Gui/FrameBase.h
Normal 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
112
rpcs3/Gui/GameViewer.cpp
Normal 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
242
rpcs3/Gui/GameViewer.h
Normal 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);
|
||||
};
|
470
rpcs3/Gui/InterpreterDisAsm.cpp
Normal file
470
rpcs3/Gui/InterpreterDisAsm.cpp
Normal 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;
|
||||
}
|
||||
}
|
54
rpcs3/Gui/InterpreterDisAsm.h
Normal file
54
rpcs3/Gui/InterpreterDisAsm.h
Normal 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
390
rpcs3/Gui/MainFrame.cpp
Normal 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
Loading…
Reference in New Issue
Block a user