1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-22 10:42:36 +01:00

- Improved PPCDecoder.

- Improved PPUDecoder.
- Improved Debugger GUI.

CompilerELF:
 - Added all PPU instructions.
 - Fixed analyzer crash.
This commit is contained in:
DH 2013-07-03 19:17:16 +03:00
parent 8ba26db020
commit b35dfdf29b
32 changed files with 4074 additions and 3581 deletions

View File

@ -1,342 +0,0 @@
#pragma once
class Decoder
{
protected:
class instr_caller
{
public:
virtual ~instr_caller()
{
}
virtual void operator ()() = 0;
};
instr_caller* m_instr_decoder;
template<typename TO>
class instr_binder_0 : public instr_caller
{
typedef void (TO::*func_t)();
TO* m_op;
func_t m_func;
public:
instr_binder_0(TO* op, func_t func)
: instr_caller()
, m_op(op)
, m_func(func)
{
}
virtual void operator ()()
{
(m_op->*m_func)();
}
};
template<typename TO, typename TD, typename T1>
class instr_binder_1 : public instr_caller
{
typedef void (TO::*func_t)(T1);
typedef T1 (TD::*arg_1_t)();
TO* m_op;
TD* m_dec;
func_t m_func;
arg_1_t m_arg_func_1;
public:
instr_binder_1(TO* op, TD* dec, func_t func, arg_1_t arg_func_1)
: instr_caller()
, m_op(op)
, m_dec(dec)
, m_func(func)
, m_arg_func_1(arg_func_1)
{
}
virtual void operator ()()
{
(m_op->*m_func)((m_dec->*m_arg_func_1)());
}
};
template<typename TO, typename TD, typename T1, typename T2>
class instr_binder_2 : public instr_caller
{
typedef void (TO::*func_t)(T1, T2);
typedef T1 (TD::*arg_1_t)();
typedef T2 (TD::*arg_2_t)();
TO* m_op;
TD* m_dec;
func_t m_func;
arg_1_t m_arg_func_1;
arg_2_t m_arg_func_2;
public:
instr_binder_2(TO* op, TD* dec, func_t func, arg_1_t arg_func_1, arg_2_t arg_func_2)
: instr_caller()
, m_op(op)
, m_dec(dec)
, m_func(func)
, m_arg_func_1(arg_func_1)
, m_arg_func_2(arg_func_2)
{
}
virtual void operator ()()
{
(m_op->*m_func)(
(m_dec->*m_arg_func_1)(),
(m_dec->*m_arg_func_2)()
);
}
};
template<typename TO, typename TD, typename T1, typename T2, typename T3>
class instr_binder_3 : public instr_caller
{
typedef void (TO::*func_t)(T1, T2, T3);
typedef T1 (TD::*arg_1_t)();
typedef T2 (TD::*arg_2_t)();
typedef T3 (TD::*arg_3_t)();
TO* m_op;
TD* m_dec;
func_t m_func;
arg_1_t m_arg_func_1;
arg_2_t m_arg_func_2;
arg_3_t m_arg_func_3;
public:
instr_binder_3(TO* op, TD* dec, func_t func,
arg_1_t arg_func_1,
arg_2_t arg_func_2,
arg_3_t arg_func_3)
: instr_caller()
, m_op(op)
, m_dec(dec)
, m_func(func)
, m_arg_func_1(arg_func_1)
, m_arg_func_2(arg_func_2)
, m_arg_func_3(arg_func_3)
{
}
virtual void operator ()()
{
(m_op->*m_func)(
(m_dec->*m_arg_func_1)(),
(m_dec->*m_arg_func_2)(),
(m_dec->*m_arg_func_3)()
);
}
};
template<typename TO, typename TD, typename T1, typename T2, typename T3, typename T4>
class instr_binder_4 : public instr_caller
{
typedef void (TO::*func_t)(T1, T2, T3, T4);
typedef T1 (TD::*arg_1_t)();
typedef T2 (TD::*arg_2_t)();
typedef T3 (TD::*arg_3_t)();
typedef T4 (TD::*arg_4_t)();
TO* m_op;
TD* m_dec;
func_t m_func;
arg_1_t m_arg_func_1;
arg_2_t m_arg_func_2;
arg_3_t m_arg_func_3;
arg_4_t m_arg_func_4;
public:
instr_binder_4(TO* op, TD* dec, func_t func,
arg_1_t arg_func_1,
arg_2_t arg_func_2,
arg_3_t arg_func_3,
arg_4_t arg_func_4)
: instr_caller()
, m_op(op)
, m_dec(dec)
, m_func(func)
, m_arg_func_1(arg_func_1)
, m_arg_func_2(arg_func_2)
, m_arg_func_3(arg_func_3)
, m_arg_func_4(arg_func_4)
{
}
virtual void operator ()()
{
(m_op->*m_func)(
(m_dec->*m_arg_func_1)(),
(m_dec->*m_arg_func_2)(),
(m_dec->*m_arg_func_3)(),
(m_dec->*m_arg_func_4)()
);
}
};
template<typename TO, typename TD, typename T1, typename T2, typename T3, typename T4, typename T5>
class instr_binder_5 : public instr_caller
{
typedef void (TO::*func_t)(T1, T2, T3, T4, T5);
typedef T1 (TD::*arg_1_t)();
typedef T2 (TD::*arg_2_t)();
typedef T3 (TD::*arg_3_t)();
typedef T4 (TD::*arg_4_t)();
typedef T5 (TD::*arg_5_t)();
TO* m_op;
TD* m_dec;
func_t m_func;
arg_1_t m_arg_func_1;
arg_2_t m_arg_func_2;
arg_3_t m_arg_func_3;
arg_4_t m_arg_func_4;
arg_5_t m_arg_func_5;
public:
instr_binder_5(TO* op, TD* dec, func_t func,
arg_1_t arg_func_1,
arg_2_t arg_func_2,
arg_3_t arg_func_3,
arg_4_t arg_func_4,
arg_5_t arg_func_5)
: instr_caller()
, m_op(op)
, m_dec(dec)
, m_func(func)
, m_arg_func_1(arg_func_1)
, m_arg_func_2(arg_func_2)
, m_arg_func_3(arg_func_3)
, m_arg_func_4(arg_func_4)
, m_arg_func_5(arg_func_5)
{
}
virtual void operator ()()
{
(m_op->*m_func)(
(m_dec->*m_arg_func_1)(),
(m_dec->*m_arg_func_2)(),
(m_dec->*m_arg_func_3)(),
(m_dec->*m_arg_func_4)(),
(m_dec->*m_arg_func_5)()
);
}
};
template<typename TO, typename TD, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
class instr_binder_6 : public instr_caller
{
typedef void (TO::*func_t)(T1, T2, T3, T4, T5, T6);
typedef T1 (TD::*arg_1_t)();
typedef T2 (TD::*arg_2_t)();
typedef T3 (TD::*arg_3_t)();
typedef T4 (TD::*arg_4_t)();
typedef T5 (TD::*arg_5_t)();
typedef T6 (TD::*arg_6_t)();
TO* m_op;
TD* m_dec;
func_t m_func;
arg_1_t m_arg_func_1;
arg_2_t m_arg_func_2;
arg_3_t m_arg_func_3;
arg_4_t m_arg_func_4;
arg_5_t m_arg_func_5;
arg_6_t m_arg_func_6;
public:
instr_binder_6(TO* op, TD* dec, func_t func,
arg_1_t arg_func_1,
arg_2_t arg_func_2,
arg_3_t arg_func_3,
arg_4_t arg_func_4,
arg_5_t arg_func_5,
arg_6_t arg_func_6)
: instr_caller()
, m_op(op)
, m_dec(dec)
, m_func(func)
, m_arg_func_1(arg_func_1)
, m_arg_func_2(arg_func_2)
, m_arg_func_3(arg_func_3)
, m_arg_func_4(arg_func_4)
, m_arg_func_5(arg_func_5)
, m_arg_func_6(arg_func_6)
{
}
virtual void operator ()()
{
(m_op->*m_func)(
(m_dec->*m_arg_func_1)(),
(m_dec->*m_arg_func_2)(),
(m_dec->*m_arg_func_3)(),
(m_dec->*m_arg_func_4)(),
(m_dec->*m_arg_func_5)(),
(m_dec->*m_arg_func_6)()
);
}
};
template<int count, typename TD, typename T>
class instr_list : public instr_caller
{
typedef T (TD::*func_t)();
TD* m_parent;
func_t m_func;
instr_caller* m_instrs[count];
instr_caller* m_error_func;
public:
instr_list(TD* parent, func_t func, instr_caller* error_func)
: instr_caller()
, m_parent(parent)
, m_func(func)
, m_error_func(error_func)
{
memset(m_instrs, 0, sizeof(instr_caller*) * count);
}
virtual ~instr_list()
{
for(int i=0; i<count; ++i)
{
delete m_instrs[i];
}
delete m_error_func;
}
void set_instr(uint pos, instr_caller* func)
{
assert(pos < count);
m_instrs[pos] = func;
}
virtual void operator ()()
{
instr_caller* instr = m_instrs[(m_parent->*m_func)() & (count - 1)];
if(instr)
{
(*instr)();
}
else if(m_error_func)
{
(*m_error_func)();
}
}
};
template<int count, typename TD, typename T>
instr_list<count, TD, T>* new_list(TD* parent, T (TD::*func)(), instr_caller* error_func)
{
return new instr_list<count, TD, T>(parent, func, error_func);
}
public:
virtual void Decode(const u32 code)=0;
};

899
rpcs3/Emu/Cell/PPCDecoder.h Normal file
View File

@ -0,0 +1,899 @@
#pragma once
#include "PPCInstrTable.h"
#pragma warning( disable : 4800 )
template<typename TO>
class InstrCaller
{
public:
virtual ~InstrCaller()
{
}
virtual void operator ()(TO* op, u32 code) const = 0;
virtual u32 operator [](u32) const
{
return 0;
}
};
class PPC_Decoder
{
protected:
u32 m_code;
public:
u32 GetCode() const { return m_code; }
virtual void Decode(const u32 code)=0;
};
template<typename TO>
class InstrBinder_0 : public InstrCaller<TO>
{
typedef void (TO::*func_t)();
func_t m_func;
public:
InstrBinder_0(func_t func)
: InstrCaller()
, m_func(func)
{
}
virtual void operator ()(TO* op, u32 code) const
{
(op->*m_func)();
}
};
template<typename TO, typename T1>
class InstrBinder_1 : public InstrCaller<TO>
{
typedef void (TO::*func_t)(T1);
func_t m_func;
const CodeFieldBase& m_arg_func_1;
public:
InstrBinder_1(func_t func, const CodeFieldBase& arg_func_1)
: InstrCaller()
, m_func(func)
, m_arg_func_1(arg_func_1)
{
}
virtual void operator ()(TO* op, u32 code) const
{
(op->*m_func)((T1)m_arg_func_1(code));
}
};
template<typename TO, typename T1, typename T2>
class InstrBinder_2 : public InstrCaller<TO>
{
typedef void (TO::*func_t)(T1, T2);
func_t m_func;
const CodeFieldBase& m_arg_func_1;
const CodeFieldBase& m_arg_func_2;
public:
InstrBinder_2(func_t func, const CodeFieldBase& arg_func_1, const CodeFieldBase& arg_func_2)
: InstrCaller()
, m_func(func)
, m_arg_func_1(arg_func_1)
, m_arg_func_2(arg_func_2)
{
}
virtual void operator ()(TO* op, u32 code) const
{
(op->*m_func)(
(T1)m_arg_func_1(code),
(T2)m_arg_func_2(code)
);
}
};
template<typename TO, typename T1, typename T2, typename T3>
class InstrBinder_3 : public InstrCaller<TO>
{
typedef void (TO::*func_t)(T1, T2, T3);
func_t m_func;
const CodeFieldBase& m_arg_func_1;
const CodeFieldBase& m_arg_func_2;
const CodeFieldBase& m_arg_func_3;
public:
InstrBinder_3(func_t func,
const CodeFieldBase& arg_func_1,
const CodeFieldBase& arg_func_2,
const CodeFieldBase& arg_func_3)
: InstrCaller()
, m_func(func)
, m_arg_func_1(arg_func_1)
, m_arg_func_2(arg_func_2)
, m_arg_func_3(arg_func_3)
{
}
virtual void operator ()(TO* op, u32 code) const
{
(op->*m_func)(
(T1)m_arg_func_1(code),
(T2)m_arg_func_2(code),
(T3)m_arg_func_3(code)
);
}
};
template<typename TO, typename T1, typename T2, typename T3, typename T4>
class InstrBinder_4 : public InstrCaller<TO>
{
typedef void (TO::*func_t)(T1, T2, T3, T4);
func_t m_func;
const CodeFieldBase& m_arg_func_1;
const CodeFieldBase& m_arg_func_2;
const CodeFieldBase& m_arg_func_3;
const CodeFieldBase& m_arg_func_4;
public:
InstrBinder_4(func_t func,
const CodeFieldBase& arg_func_1,
const CodeFieldBase& arg_func_2,
const CodeFieldBase& arg_func_3,
const CodeFieldBase& arg_func_4)
: InstrCaller()
, m_func(func)
, m_arg_func_1(arg_func_1)
, m_arg_func_2(arg_func_2)
, m_arg_func_3(arg_func_3)
, m_arg_func_4(arg_func_4)
{
}
virtual void operator ()(TO* op, u32 code) const
{
(op->*m_func)(
(T1)m_arg_func_1(code),
(T2)m_arg_func_2(code),
(T3)m_arg_func_3(code),
(T4)m_arg_func_4(code)
);
}
};
template<typename TO, typename T1, typename T2, typename T3, typename T4, typename T5>
class InstrBinder_5 : public InstrCaller<TO>
{
typedef void (TO::*func_t)(T1, T2, T3, T4, T5);
func_t m_func;
const CodeFieldBase& m_arg_func_1;
const CodeFieldBase& m_arg_func_2;
const CodeFieldBase& m_arg_func_3;
const CodeFieldBase& m_arg_func_4;
const CodeFieldBase& m_arg_func_5;
public:
InstrBinder_5(func_t func,
const CodeFieldBase& arg_func_1,
const CodeFieldBase& arg_func_2,
const CodeFieldBase& arg_func_3,
const CodeFieldBase& arg_func_4,
const CodeFieldBase& arg_func_5)
: InstrCaller()
, m_func(func)
, m_arg_func_1(arg_func_1)
, m_arg_func_2(arg_func_2)
, m_arg_func_3(arg_func_3)
, m_arg_func_4(arg_func_4)
, m_arg_func_5(arg_func_5)
{
}
virtual void operator ()(TO* op, u32 code) const
{
(op->*m_func)(
(T1)m_arg_func_1(code),
(T2)m_arg_func_2(code),
(T3)m_arg_func_3(code),
(T4)m_arg_func_4(code),
(T5)m_arg_func_5(code)
);
}
};
template<typename TO, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
class InstrBinder_6 : public InstrCaller<TO>
{
typedef void (TO::*func_t)(T1, T2, T3, T4, T5, T6);
func_t m_func;
const CodeFieldBase& m_arg_func_1;
const CodeFieldBase& m_arg_func_2;
const CodeFieldBase& m_arg_func_3;
const CodeFieldBase& m_arg_func_4;
const CodeFieldBase& m_arg_func_5;
const CodeFieldBase& m_arg_func_6;
public:
InstrBinder_6(func_t func,
const CodeFieldBase& arg_func_1,
const CodeFieldBase& arg_func_2,
const CodeFieldBase& arg_func_3,
const CodeFieldBase& arg_func_4,
const CodeFieldBase& arg_func_5,
const CodeFieldBase& arg_func_6)
: InstrCaller()
, m_func(func)
, m_arg_func_1(arg_func_1)
, m_arg_func_2(arg_func_2)
, m_arg_func_3(arg_func_3)
, m_arg_func_4(arg_func_4)
, m_arg_func_5(arg_func_5)
, m_arg_func_6(arg_func_6)
{
}
virtual void operator ()(TO* op, u32 code) const
{
(op->*m_func)(
(T1)m_arg_func_1(code),
(T2)m_arg_func_2(code),
(T3)m_arg_func_3(code),
(T4)m_arg_func_4(code),
(T5)m_arg_func_5(code),
(T6)m_arg_func_6(code)
);
}
};
template<typename TO>
InstrCaller<TO>* instr_bind(void (TO::*func)())
{
return new InstrBinder_0<TO>(func);
}
template<typename TO, typename T1>
InstrCaller<TO>* instr_bind(void (TO::*func)(T1), const CodeFieldBase& arg_func_1)
{
return new InstrBinder_1<TO, T1>(func, arg_func_1);
}
template<typename TO, typename T1, typename T2>
InstrCaller<TO>* instr_bind(void (TO::*func)(T1, T2),
const CodeFieldBase& arg_func_1,
const CodeFieldBase& arg_func_2)
{
return new InstrBinder_2<TO, T1, T2>(func, arg_func_1, arg_func_2);
}
template<typename TO, typename T1, typename T2, typename T3>
InstrCaller<TO>* instr_bind(void (TO::*func)(T1, T2, T3),
const CodeFieldBase& arg_func_1,
const CodeFieldBase& arg_func_2,
const CodeFieldBase& arg_func_3)
{
return new InstrBinder_3<TO, T1, T2, T3>(func, arg_func_1, arg_func_2, arg_func_3);
}
template<typename TO, typename T1, typename T2, typename T3, typename T4>
InstrCaller<TO>* instr_bind(void (TO::*func)(T1, T2, T3, T4),
const CodeFieldBase& arg_func_1,
const CodeFieldBase& arg_func_2,
const CodeFieldBase& arg_func_3,
const CodeFieldBase& arg_func_4)
{
return new InstrBinder_4<TO, T1, T2, T3, T4>(func, arg_func_1, arg_func_2, arg_func_3, arg_func_4);
}
template<typename TO, typename T1, typename T2, typename T3, typename T4, typename T5>
InstrCaller<TO>* instr_bind(void (TO::*func)(T1, T2, T3, T4, T5),
const CodeFieldBase& arg_func_1,
const CodeFieldBase& arg_func_2,
const CodeFieldBase& arg_func_3,
const CodeFieldBase& arg_func_4,
const CodeFieldBase& arg_func_5)
{
return new InstrBinder_5<TO, T1, T2, T3, T4, T5>(func, arg_func_1, arg_func_2, arg_func_3, arg_func_4, arg_func_5);
}
template<typename TO, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
InstrCaller<TO>* instr_bind(void (TO::*func)(T1, T2, T3, T4, T5, T6),
const CodeFieldBase& arg_func_1,
const CodeFieldBase& arg_func_2,
const CodeFieldBase& arg_func_3,
const CodeFieldBase& arg_func_4,
const CodeFieldBase& arg_func_5,
const CodeFieldBase& arg_func_6)
{
return new InstrBinder_6<TO, T1, T2, T3, T4, T5, T6>(func, arg_func_1, arg_func_2, arg_func_3, arg_func_4, arg_func_5, arg_func_6);
}
template<typename TO>
class InstrBase : public InstrCaller<TO>
{
protected:
wxString m_name;
const u32 m_opcode;
CodeFieldBase** m_args;
const uint m_args_count;
public:
InstrBase(const wxString& name, int opcode, uint args_count)
: InstrCaller<TO>()
, m_name(name)
, m_opcode(opcode)
, m_args_count(args_count)
, m_args(args_count ? new CodeFieldBase*[args_count] : nullptr)
{
m_name.MakeLower().Replace("_", ".");
}
__forceinline const wxString& GetName() const
{
return m_name;
}
__forceinline const uint GetArgCount() const
{
return m_args_count;
}
__forceinline const CodeFieldBase& GetArg(uint index) const
{
assert(index < m_args_count);
return *m_args[index];
}
void operator ()(TO* op, u32 code) const
{
decode(op, code);
}
u32 operator()(const Array<u32>& args) const
{
return encode(args);
}
virtual void decode(TO* op, u32 code) const=0;
virtual u32 encode(const Array<u32>& args) const=0;
};
template<int _count, typename TO>
class InstrList : public InstrCaller<TO>
{
public:
static const int count = _count;
protected:
const CodeFieldBase& m_func;
InstrCaller<TO>* m_instrs[count];
InstrBase<TO>* m_instrs_info[count];
InstrCaller<TO>* m_error_func;
InstrCaller<TO>* m_parent;
int m_opcode;
public:
InstrList(const CodeFieldBase& func, InstrCaller<TO>* error_func)
: InstrCaller<TO>()
, m_func(func)
, m_error_func(error_func)
, m_parent(nullptr)
, m_opcode(-1)
{
memset(m_instrs, 0, sizeof(InstrCaller<TO>*) * count);
memset(m_instrs_info, 0, sizeof(InstrBase<TO>*) * count);
}
virtual ~InstrList()
{
for(int i=0; i<count; ++i)
{
delete m_instrs[i];
}
delete m_error_func;
}
void set_parent(InstrCaller<TO>* parent, int opcode)
{
m_opcode = opcode;
m_parent = parent;
}
InstrCaller<TO>* get_parent() const
{
return m_parent;
}
u32 get_opcode() const
{
return m_opcode;
}
void set_error_func(InstrCaller<TO>* error_func)
{
m_error_func = error_func;
}
void set_instr(uint pos, InstrCaller<TO>* func, InstrBase<TO>* info = nullptr)
{
assert(pos < count);
m_instrs[pos] = func;
m_instrs_info[pos] = info;
}
InstrCaller<TO>* get_instr(int pos) const
{
assert(pos < count);
return m_instrs[pos];
}
InstrBase<TO>* get_instr_info(int pos) const
{
assert(pos < count);
return m_instrs_info[pos];
}
u32 encode(u32 entry) const
{
return m_func[entry] | (m_parent ? (*m_parent)[m_opcode] : 0);
}
void decode(TO* op, u32 entry, u32 code) const
{
InstrCaller<TO>* instr = m_instrs[entry];
if(instr)
{
(*instr)(op, code);
}
else if(m_error_func)
{
(*m_error_func)(op, code);
}
}
virtual void operator ()(TO* op, u32 code) const
{
decode(op, m_func(code) & (count - 1), code);
}
virtual u32 operator [](u32 entry) const
{
return encode(entry);
}
};
template<int count1, int count2, typename TO>
static InstrList<count2, TO>* connect_list(InstrList<count1, TO>* parent, InstrList<count2, TO>* child, int opcode)
{
parent->set_instr(opcode, child);
child->set_parent(parent, opcode);
return child;
}
template<int count1, int count2, typename TO>
static InstrList<count2, TO>* connect_list(InstrList<count1, TO>* parent, InstrList<count2, TO>* child)
{
parent->set_error_func(child);
child->set_parent(parent->get_parent(), parent->get_opcode());
return child;
}
template<int count, typename TO>
static InstrList<count, TO>* new_list(const CodeFieldBase& func, InstrCaller<TO>* error_func = nullptr)
{
return new InstrList<count, TO>(func, error_func);
}
template<int count1, int count2, typename TO>
static InstrList<count1, TO>* new_list(InstrList<count2, TO>* parent, int opcode, const CodeFieldBase& func, InstrCaller<TO>* error_func = nullptr)
{
return connect_list(parent, new InstrList<count1, TO>(func, error_func), opcode);
}
template<int count1, int count2, typename TO>
static InstrList<count1, TO>* new_list(InstrList<count2, TO>* parent, const CodeFieldBase& func, InstrCaller<TO>* error_func = nullptr)
{
return connect_list(parent, new InstrList<count1, TO>(func, error_func));
}
template<typename TO, int opcode, int count>
class Instr0 : public InstrBase<TO>
{
InstrList<count, TO>& m_list;
public:
Instr0(InstrList<count, TO>* list, const wxString& name,
void (TO::*func)())
: InstrBase(name, opcode, 0)
, m_list(*list)
{
m_list.set_instr(opcode, instr_bind(func), this);
}
virtual void decode(TO* op, u32 code) const
{
m_list.decode(op, opcode, code);
}
virtual u32 encode(const Array<u32>& args) const
{
assert(args.GetCount() == m_args_count);
return m_list.encode(opcode);
}
u32 encode() const
{
return m_list.encode(opcode);
}
u32 operator()() const
{
return encode();
}
};
template<typename TO, int opcode, int count, typename T1>
class Instr1 : public InstrBase<TO>
{
InstrList<count, TO>& m_list;
public:
Instr1(InstrList<count, TO>* list, const wxString& name,
void (TO::*func)(T1),
CodeFieldBase& arg_1)
: InstrBase(name, opcode, 1)
, m_list(*list)
{
m_args[0] = &arg_1;
m_list.set_instr(opcode, instr_bind(func, arg_1), this);
}
virtual void decode(TO* op, u32 code) const
{
m_list.decode(op, opcode, code);
}
virtual u32 encode(const Array<u32>& args) const
{
assert(args.GetCount() == m_args_count);
return m_list.encode(opcode) | (*m_args[0])[args[0]];
}
u32 encode(T1 a1) const
{
return m_list.encode(opcode) | (*m_args[0])[a1];
}
u32 operator()(T1 a1) const
{
return encode(a1);
}
};
template<typename TO, int opcode, int count, typename T1, typename T2>
class Instr2 : public InstrBase<TO>
{
InstrList<count, TO>& m_list;
public:
Instr2(InstrList<count, TO>* list, const wxString& name,
void (TO::*func)(T1, T2),
CodeFieldBase& arg_1,
CodeFieldBase& arg_2)
: InstrBase(name, opcode, 2)
, m_list(*list)
{
m_args[0] = &arg_1;
m_args[1] = &arg_2;
m_list.set_instr(opcode, instr_bind(func, arg_1, arg_2), this);
}
virtual void decode(TO* op, u32 code) const
{
m_list.decode(op, opcode, code);
}
virtual u32 encode(const Array<u32>& args) const
{
assert(args.GetCount() == m_args_count);
return m_list.encode(opcode) | (*m_args[0])[args[0]] | (*m_args[1])[args[1]];
}
u32 encode(T1 a1, T2 a2) const
{
return m_list.encode(opcode) | (*m_args[0])[a1] | (*m_args[1])[a2];
}
u32 operator()(T1 a1, T2 a2) const
{
return encode(a1, a2);
}
};
template<typename TO, int opcode, int count, typename T1, typename T2, typename T3>
class Instr3 : public InstrBase<TO>
{
InstrList<count, TO>& m_list;
public:
Instr3(InstrList<count, TO>* list, const wxString& name,
void (TO::*func)(T1, T2, T3),
CodeFieldBase& arg_1,
CodeFieldBase& arg_2,
CodeFieldBase& arg_3)
: InstrBase(name, opcode, 3)
, m_list(*list)
{
m_args[0] = &arg_1;
m_args[1] = &arg_2;
m_args[2] = &arg_3;
m_list.set_instr(opcode, instr_bind(func, arg_1, arg_2, arg_3), this);
}
virtual void decode(TO* op, u32 code) const
{
m_list.decode(op, opcode, code);
}
virtual u32 encode(const Array<u32>& args) const
{
assert(args.GetCount() == m_args_count);
return m_list.encode(opcode) | (*m_args[0])[args[0]] | (*m_args[1])[args[1]] | (*m_args[2])[args[2]];
}
u32 encode(T1 a1, T2 a2, T3 a3) const
{
return m_list.encode(opcode) | (*m_args[0])[a1] | (*m_args[1])[a2] | (*m_args[2])[a3];
}
u32 operator()(T1 a1, T2 a2, T3 a3) const
{
return encode(a1, a2, a3);
}
};
template<typename TO, int opcode, int count, typename T1, typename T2, typename T3, typename T4>
class Instr4 : public InstrBase<TO>
{
InstrList<count, TO>& m_list;
public:
Instr4(InstrList<count, TO>* list, const wxString& name,
void (TO::*func)(T1, T2, T3, T4),
CodeFieldBase& arg_1,
CodeFieldBase& arg_2,
CodeFieldBase& arg_3,
CodeFieldBase& arg_4)
: InstrBase(name, opcode, 4)
, m_list(*list)
{
m_args[0] = &arg_1;
m_args[1] = &arg_2;
m_args[2] = &arg_3;
m_args[3] = &arg_4;
m_list.set_instr(opcode, instr_bind(func, arg_1, arg_2, arg_3, arg_4), this);
}
virtual void decode(TO* op, u32 code) const
{
m_list.decode(op, opcode, code);
}
virtual u32 encode(const Array<u32>& args) const
{
assert(args.GetCount() == m_args_count);
return m_list.encode(opcode) |
(*m_args[0])[args[0]] |
(*m_args[1])[args[1]] |
(*m_args[2])[args[2]] |
(*m_args[3])[args[3]];
}
u32 encode(T1 a1, T2 a2, T3 a3, T4 a4) const
{
return m_list.encode(opcode) |
(*m_args[0])[a1] |
(*m_args[1])[a2] |
(*m_args[2])[a3] |
(*m_args[3])[a4];
}
u32 operator()(T1 a1, T2 a2, T3 a3, T4 a4) const
{
return encode(a1, a2, a3, a4);
}
};
template<typename TO, int opcode, int count, typename T1, typename T2, typename T3, typename T4, typename T5>
class Instr5 : public InstrBase<TO>
{
InstrList<count, TO>& m_list;
public:
Instr5(InstrList<count, TO>* list, const wxString& name,
void (TO::*func)(T1, T2, T3, T4, T5),
CodeFieldBase& arg_1,
CodeFieldBase& arg_2,
CodeFieldBase& arg_3,
CodeFieldBase& arg_4,
CodeFieldBase& arg_5)
: InstrBase(name, opcode, 5)
, m_list(*list)
{
m_args[0] = &arg_1;
m_args[1] = &arg_2;
m_args[2] = &arg_3;
m_args[3] = &arg_4;
m_args[4] = &arg_5;
m_list.set_instr(opcode, instr_bind(func, arg_1, arg_2, arg_3, arg_4, arg_5), this);
}
virtual void decode(TO* op, u32 code) const
{
m_list.decode(op, opcode, code);
}
virtual u32 encode(const Array<u32>& args) const
{
assert(args.GetCount() == m_args_count);
return m_list.encode(opcode) |
(*m_args[0])[args[0]] |
(*m_args[1])[args[1]] |
(*m_args[2])[args[2]] |
(*m_args[3])[args[3]] |
(*m_args[4])[args[4]];
}
u32 encode(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) const
{
return m_list.encode(opcode) |
(*m_args[0])[a1] |
(*m_args[1])[a2] |
(*m_args[2])[a3] |
(*m_args[3])[a4] |
(*m_args[4])[a5];
}
u32 operator()(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) const
{
return encode(a1, a2, a3, a4, a5);
}
};
template<typename TO, int opcode, int count, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
class Instr6 : public InstrBase<TO>
{
InstrList<count, TO>& m_list;
public:
Instr6(InstrList<count, TO>* list, const wxString& name,
void (TO::*func)(T1, T2, T3, T4, T5, T6),
CodeFieldBase& arg_1,
CodeFieldBase& arg_2,
CodeFieldBase& arg_3,
CodeFieldBase& arg_4,
CodeFieldBase& arg_5,
CodeFieldBase& arg_6)
: InstrBase(name, opcode, 6)
, m_list(*list)
{
m_args[0] = &arg_1;
m_args[1] = &arg_2;
m_args[2] = &arg_3;
m_args[3] = &arg_4;
m_args[4] = &arg_5;
m_args[5] = &arg_6;
m_list.set_instr(opcode, instr_bind(func, arg_1, arg_2, arg_3, arg_4, arg_5, arg_6), this);
}
virtual void decode(TO* op, u32 code) const
{
m_list.decode(op, opcode, code);
}
virtual u32 encode(const Array<u32>& args) const
{
assert(args.GetCount() == m_args_count);
return m_list.encode(opcode) |
(*m_args[0])[args[0]] |
(*m_args[1])[args[1]] |
(*m_args[2])[args[2]] |
(*m_args[3])[args[3]] |
(*m_args[4])[args[4]] |
(*m_args[5])[args[5]];
}
u32 encode(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T5 a6) const
{
return m_list.encode(opcode) |
(*m_args[0])[a1] |
(*m_args[1])[a2] |
(*m_args[2])[a3] |
(*m_args[3])[a4] |
(*m_args[4])[a5] |
(*m_args[5])[a6];
}
u32 operator()(T1 a1, T2 a2, T3 a3, T4 a4, T4 a5, T4 a6) const
{
return encode(a1, a2, a3, a4, a5, a6);
}
};
template<int opcode, typename TO, int count>
static Instr0<TO, opcode, count>& make_instr(InstrList<count, TO>* list, const wxString& name, void (TO::*func)())
{
return *new Instr0<TO, opcode, count>(list, name, func);
}
template<int opcode, typename TO, int count, typename T1>
static Instr1<TO, opcode, count, T1>& make_instr(InstrList<count, TO>* list, const wxString& name,
void (TO::*func)(T1),
CodeFieldBase& arg_1)
{
return *new Instr1<TO, opcode, count, T1>(list, name, func, arg_1);
}
template<int opcode, typename TO, int count, typename T1, typename T2>
static Instr2<TO, opcode, count, T1, T2>& make_instr(InstrList<count, TO>* list, const wxString& name,
void (TO::*func)(T1, T2),
CodeFieldBase& arg_1,
CodeFieldBase& arg_2)
{
return *new Instr2<TO, opcode, count, T1, T2>(list, name, func, arg_1, arg_2);
}
template<int opcode, typename TO, int count, typename T1, typename T2, typename T3>
static Instr3<TO, opcode, count, T1, T2, T3>& make_instr(InstrList<count, TO>* list, const wxString& name,
void (TO::*func)(T1, T2, T3),
CodeFieldBase& arg_1,
CodeFieldBase& arg_2,
CodeFieldBase& arg_3)
{
return *new Instr3<TO, opcode, count, T1, T2, T3>(list, name, func, arg_1, arg_2, arg_3);
}
template<int opcode, typename TO, int count, typename T1, typename T2, typename T3, typename T4>
static Instr4<TO, opcode, count, T1, T2, T3, T4>& make_instr(InstrList<count, TO>* list, const wxString& name,
void (TO::*func)(T1, T2, T3, T4),
CodeFieldBase& arg_1,
CodeFieldBase& arg_2,
CodeFieldBase& arg_3,
CodeFieldBase& arg_4)
{
return *new Instr4<TO, opcode, count, T1, T2, T3, T4>(list, name, func, arg_1, arg_2, arg_3, arg_4);
}
template<int opcode, typename TO, int count, typename T1, typename T2, typename T3, typename T4, typename T5>
static Instr5<TO, opcode, count, T1, T2, T3, T4, T5>& make_instr(InstrList<count, TO>* list, const wxString& name,
void (TO::*func)(T1, T2, T3, T4, T5),
CodeFieldBase& arg_1,
CodeFieldBase& arg_2,
CodeFieldBase& arg_3,
CodeFieldBase& arg_4,
CodeFieldBase& arg_5)
{
return *new Instr5<TO, opcode, count, T1, T2, T3, T4, T5>(list, name, func, arg_1, arg_2, arg_3, arg_4, arg_5);
}
template<int opcode, typename TO, int count, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
static Instr6<TO, opcode, count, T1, T2, T3, T4, T5, T6>& make_instr(InstrList<count, TO>* list, const wxString& name,
void (TO::*func)(T1, T2, T3, T4, T5, T6),
CodeFieldBase& arg_1,
CodeFieldBase& arg_2,
CodeFieldBase& arg_3,
CodeFieldBase& arg_4,
CodeFieldBase& arg_5,
CodeFieldBase& arg_6)
{
return *new Instr6<TO, opcode, count, T1, T2, T3, T4, T5, T6>(list, name, func, arg_1, arg_2, arg_3, arg_4, arg_5, arg_6);
}

View File

@ -11,7 +11,7 @@ enum DisAsmModes
CompilerElfMode,
};
class DisAsm
class PPC_DisAsm
{
protected:
DisAsmFrame* disasm_frame;
@ -58,7 +58,7 @@ public:
uint dump_pc;
protected:
DisAsm(PPCThread& cpu, DisAsmModes mode = NormalMode)
PPC_DisAsm(PPCThread& cpu, DisAsmModes mode = NormalMode)
: m_mode(mode)
, disasm_frame(NULL)
{

View File

@ -0,0 +1,135 @@
#pragma once
template<int size, typename T> __forceinline static T sign(const T value)
{
if(value & (1 << (size - 1)))
{
return value - (1 << size);
}
return value;
}
enum CodeFieldType
{
FIELD_IMM,
FIELD_R_GPR,
FIELD_R_FPR,
FIELD_R_VPR,
FIELD_R_CR,
FIELD_BRANCH,
};
class CodeFieldBase
{
public:
CodeFieldType m_type;
public:
CodeFieldBase(CodeFieldType type = FIELD_IMM) : m_type(type)
{
}
virtual u32 operator ()(u32 data) const=0;
virtual void operator()(u32& data, u32 value) const=0;
virtual u32 operator[](u32 value) const
{
u32 result = 0;
(*this)(result, value);
return result;
}
};
template<uint from, uint to=from>
class CodeField : public CodeFieldBase
{
static_assert(from <= to, "too big 'from' value");
static_assert(to <= 31, "too big 'to' value");
public:
CodeField(CodeFieldType type = FIELD_IMM) : CodeFieldBase(type)
{
}
static const u32 shift = 31 - to;
static const u32 mask = ((1ULL << ((to - from) + 1)) - 1) << shift;
static __forceinline void encode(u32& data, u32 value)
{
data &= ~mask;
data |= (value << shift) & mask;
}
static __forceinline u32 decode(u32 data)
{
return (data & mask) >> shift;
}
virtual u32 operator ()(u32 data) const
{
return decode(data);
}
virtual void operator()(u32& data, u32 value) const
{
encode(data, value);
}
};
template<uint from1, uint to1, uint from2, uint to2 = from2, uint offset = 0>
class DoubleCodeField : public CodeField<from1, to1>
{
static_assert(from2 <= to2, "too big from2 value");
static_assert(to2 <= 31, "too big to2 value");
public:
DoubleCodeField(CodeFieldType type = FIELD_IMM) : CodeField(type)
{
}
static const u32 shift2 = 31 - to2;
static const u32 mask2 = ((1 << ((to2 - from2) + 1)) - 1) << shift2;
static __forceinline void encode(u32& data, u32 value)
{
data &= ~(mask | mask2);
data |= ((value << shift) & mask) | (((value >> offset) << shift2) & mask2);
}
static __forceinline u32 decode(u32 data)
{
return ((data & mask) >> shift) | (((data & mask2) >> shift2) << offset);
}
virtual u32 operator ()(u32 data) const
{
return decode(data);
}
virtual void operator()(u32& data, u32 value) const
{
encode(data, value);
}
};
template<uint from, uint to = from, uint _size = to - from + 1>
class CodeFieldSigned : public CodeField<from, to>
{
public:
CodeFieldSigned(CodeFieldType type = FIELD_IMM) : CodeField(type)
{
}
static const int size = _size;
static __forceinline u32 decode(u32 data)
{
return sign<size>((data & mask) >> shift);
}
virtual u32 operator ()(u32 data) const
{
return decode(data);
}
};

View File

@ -168,6 +168,8 @@ void PPCThread::Run()
return;
}
wxGetApp().SendDbgCommand(DID_START_THREAD, this);
m_status = Runned;
SetPc(entry);
@ -176,49 +178,52 @@ void PPCThread::Run()
DoRun();
Emu.CheckStatus();
wxGetApp().SendDbgCommand(DID_START_THREAD, this);
if(DisAsmFrame) (*(InterpreterDisAsmFrame*)DisAsmFrame).DoUpdate();
wxGetApp().SendDbgCommand(DID_STARTED_THREAD, this);
}
void PPCThread::Resume()
{
if(!IsPaused()) return;
wxGetApp().SendDbgCommand(DID_RESUME_THREAD, this);
m_status = Runned;
DoResume();
Emu.CheckStatus();
wxGetApp().SendDbgCommand(DID_RESUME_THREAD, this);
ThreadBase::Start();
wxGetApp().SendDbgCommand(DID_RESUMED_THREAD, this);
}
void PPCThread::Pause()
{
if(!IsRunned()) return;
wxGetApp().SendDbgCommand(DID_PAUSE_THREAD, this);
m_status = Paused;
DoPause();
Emu.CheckStatus();
wxGetApp().SendDbgCommand(DID_PAUSE_THREAD, this);
ThreadBase::Stop(false);
wxGetApp().SendDbgCommand(DID_PAUSED_THREAD, this);
}
void PPCThread::Stop()
{
if(IsStopped()) return;
wxGetApp().SendDbgCommand(DID_STOP_THREAD, this);
m_status = Stopped;
Reset();
DoStop();
Emu.CheckStatus();
wxGetApp().SendDbgCommand(DID_STOP_THREAD, this);
ThreadBase::Stop();
wxGetApp().SendDbgCommand(DID_STOPED_THREAD, this);
}
void PPCThread::Exec()
@ -237,8 +242,19 @@ void PPCThread::Task()
{
ConLog.Write("%s enter", PPCThread::GetFName());
const Array<u64>& bp = Emu.GetBreakPoints();
try
{
for(uint i=0; i<bp.GetCount(); ++i)
{
if(bp[i] == m_offset + PC)
{
Emu.Pause();
break;
}
}
while(!Emu.IsStopped() && !TestDestroy())
{
if(Emu.IsPaused())
@ -249,6 +265,15 @@ void PPCThread::Task()
DoCode(Memory.Read32(m_offset + PC));
NextPc();
for(uint i=0; i<bp.GetCount(); ++i)
{
if(bp[i] == m_offset + PC)
{
Emu.Pause();
break;
}
}
}
}
catch(const wxString& e)

View File

@ -1,6 +1,6 @@
#pragma once
#include "Emu/Memory/MemoryBlock.h"
#include "Emu/Cell/Decoder.h"
#include "Emu/Cell/PPCDecoder.h"
enum PPCThreadType
{
@ -13,7 +13,7 @@ class PPCThread : public ThreadBase
protected:
u32 m_status;
u32 m_error;
Decoder* m_dec;
PPC_Decoder* m_dec;
wxWindow* DisAsmFrame;
u32 m_id;
PPCThreadType m_type;

View File

@ -1,763 +1,26 @@
#pragma once
#include "Emu/Cell/PPUOpcodes.h"
#include "Emu/Cell/Decoder.h"
#include "Emu/Cell/PPCDecoder.h"
#include "PPUInstrTable.h"
#define START_OPCODES_GROUP(group, reg) \
case(##group##): \
temp=##reg##;\
switch(temp)\
class PPU_Decoder : public PPC_Decoder
{
#define START_OPCODES_SUB_GROUP(reg) \
default:\
temp=##reg##;\
switch(temp)\
{
#define END_OPCODES_GROUP(group) \
default:\
m_op.UNK(m_code, opcode, temp);\
break;\
}\
break
#define END_OPCODES_SUB_GROUP() \
default:\
m_op.UNK(m_code, opcode, temp);\
break;\
}
#define END_OPCODES_ND_GROUP(group) \
} \
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() { 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() { return GetField(21, 25) | (m_code & 0x20); }
//This field is used to specify a shift amount
OP_REG sh() { 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() { return GetField(11, 20); }
//
OP_REG VS() { return GetField(6, 10); }
//
OP_REG VD() { return GetField(6, 10); }
//
OP_REG VA() { return GetField(11, 15); }
//
OP_REG VB() { return GetField(16, 20); }
//
OP_REG VC() { return GetField(21, 25); }
//
OP_uIMM VUIMM() { return GetField(11, 15); }
//
OP_sIMM VSIMM() { int i5 = GetField(11, 15);
if(i5 & 0x10) return i5 - 0x20;
return i5; }
//
OP_uIMM VSH() { return GetField(22, 25); }
//This field is used to specify a GPR to be used as a destination
OP_REG RD() { return GetField(6, 10); }
//This field is used to specify a GPR to be used as a source
OP_REG RS() { return GetField(6, 10); }
//This field is used to specify a GPR to be used as a source or destination
OP_REG RA() { return GetField(11, 15); }
//This field is used to specify a GPR to be used as a source
OP_REG RB() { 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() { 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() { 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() { return GetField(11, 13); }
//This field is used to specify a bit in the CR to be used as a source
OP_REG CRBA() { return GetField(11, 15); }
//This field is used to specify a bit in the CR to be used as a source
OP_REG CRBB() { 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() { return GetField(6, 10); }
//
OP_REG BT() { return GetField(6, 10); }
//
OP_REG BA() { return GetField(11, 15); }
//
OP_REG BB() { return GetField(16, 20); }
//
OP_REG BF() { return GetField(6, 10); }
//This field is used to specify options for the branch conditional instructions
OP_REG BO() { 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() { 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() { return (s32)(s16)GetField(16, 31); }
//
OP_REG BH() { return GetField(19, 20); }
//
OP_REG BFA() { return GetField(11, 13); }
//Field used by the optional data stream variant of the dcbt instruction.
OP_uIMM TH() { return GetField(9, 10); }
//This field is used to specify the conditions on which to trap
OP_uIMM TO() { return GetField(6, 10); }
//
OP_REG MB() { return GetField(21, 25); }
//
OP_REG ME() { return GetField(26, 30); }
//This field is used to specify a shift amount
OP_REG SH() { 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() { return GetField(30); }
//
OP_sIMM LL()
{
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() { return GetField(31); }
//This field is used for extended arithmetic to enable setting OV and SO in the XER
OP_REG OE() { 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_10() { return GetField(10); }
OP_REG L_6() { return GetField(6); }
OP_REG L_9_10() { return GetField(9, 10); }
OP_REG L_11() { return GetField(11); }
//
OP_REG I() { return GetField(16, 19); }
//
OP_REG DQ() { return GetField(16, 27); }
//This field is used to specify an FPR as the destination
OP_REG FRD() { return GetField(6, 10); }
//This field is used to specify an FPR as a source
OP_REG FRS() { return GetField(6, 10); }
//
OP_REG FLM() { return GetField(7, 14); }
//This field is used to specify an FPR as a source
OP_REG FRA() { return GetField(11, 15); }
//This field is used to specify an FPR as a source
OP_REG FRB() { return GetField(16, 20); }
//This field is used to specify an FPR as a source
OP_REG FRC() { return GetField(21, 25); }
//This field mask is used to identify the CR fields that are to be updated by the mtcrf instruction.
OP_REG CRM() { return GetField(12, 19); }
//
OP_sIMM SYS() { 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() { return (s32)(s16)GetField(16, 31); }
//
OP_sIMM DS()
{
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() { return (s32)(s16)m_code; }
//This immediate field is used to specify a 16-bit unsigned integer
OP_uIMM uimm16() { return (u32)(u16)m_code; }
/*
Record bit.
0 Does not update the condition register (CR).
1 Updates the CR to reflect the result of the operation.
For integer instructions, CR bits [02] are set to reflect the result as a signed quantity and CR bit [3]
receives a copy of the summary overflow bit, XER[SO]. The result as an unsigned quantity or a bit
string can be deduced from the EQ bit. For floating-point instructions, CR bits [47] are set to reflect
floating-point exception, floating-point enabled exception, floating-point invalid operation exception,
and floating-point overflow exception.
*/
bool RC() { return m_code & 0x1; }
//Primary opcode field
OP_uIMM OPCD() { return GetField(0, 5); }
OP_uIMM GD_04() { return GetField(26, 31); } //0x3f
OP_uIMM GD_04_0() { return GetField(21, 31); } //0x7ff
OP_uIMM GD_13() { return GetField(21, 30); } //0x3ff
OP_uIMM GD_1e() { return GetField(28, 29); } //0x3
OP_uIMM GD_1f() { return GetField(21, 30); } //0x3ff
OP_uIMM GD_3a() { return GetField(30, 31); } //0x3
OP_uIMM GD_3b() { return GetField(26, 30); } //0x1f
OP_uIMM GD_3e() { return GetField(30, 31); } //0x3
OP_uIMM GD_3f() { return GetField(26, 30); } //0x1f
OP_uIMM GD_3f_0() { return GetField(21, 30); } //0x3ff
OP_uIMM STRM() { return GetField(9, 10); }
OP_uIMM GetCode() { return m_code; }
__forceinline u32 GetField(const u32 p)
{
return (m_code >> (31 - p)) & 0x1;
}
__forceinline u32 GetField(const u32 from, const u32 to)
{
return (m_code >> (31 - to)) & ((1 << ((to - from) + 1)) - 1);
}
PPU_Opcodes* m_op;
public:
template<typename TD, typename TO>
instr_caller* instr_bind(TD* parent, void (TO::*func)())
PPU_Decoder(PPU_Opcodes& op) : m_op(&op)
{
return new instr_binder_0<TO>(parent, func);
}
template<typename TO>
instr_caller* instr_bind(void (TO::*func)())
{
return instr_bind(&m_op, func);
}
template<typename TO, typename TD, typename T1>
instr_caller* instr_bind(void (TO::*func)(T1), T1 (TD::*arg_func_1)())
{
return new instr_binder_1<TO, TD, T1>(&m_op, this, func, arg_func_1);
}
template<typename TO, typename TD, typename T1, typename T2>
instr_caller* instr_bind(void (TO::*func)(T1, T2), T1 (TD::*arg_func_1)(), T2 (TD::*arg_func_2)())
{
return new instr_binder_2<TO, TD, T1, T2>(&m_op, this, func, arg_func_1, arg_func_2);
}
template<typename TO, typename TD, typename T1, typename T2, typename T3>
instr_caller* instr_bind(void (TO::*func)(T1, T2, T3), T1 (TD::*arg_func_1)(), T2 (TD::*arg_func_2)(), T3 (TD::*arg_func_3)())
{
return new instr_binder_3<TO, TD, T1, T2, T3>(&m_op, this, func, arg_func_1, arg_func_2, arg_func_3);
}
template<typename TO, typename TD, typename T1, typename T2, typename T3, typename T4>
instr_caller* instr_bind(void (TO::*func)(T1, T2, T3, T4), T1 (TD::*arg_func_1)(), T2 (TD::*arg_func_2)(), T3 (TD::*arg_func_3)(), T4 (TD::*arg_func_4)())
{
return new instr_binder_4<TO, TD, T1, T2, T3, T4>(&m_op, this, func, arg_func_1, arg_func_2, arg_func_3, arg_func_4);
}
template<typename TO, typename TD, typename T1, typename T2, typename T3, typename T4, typename T5>
instr_caller* instr_bind(void (TO::*func)(T1, T2, T3, T4, T5), T1 (TD::*arg_func_1)(), T2 (TD::*arg_func_2)(), T3 (TD::*arg_func_3)(), T4 (TD::*arg_func_4)(), T5 (TD::*arg_func_5)())
{
return new instr_binder_5<TO, TD, T1, T2, T3, T4, T5>(&m_op, this, func, arg_func_1, arg_func_2, arg_func_3, arg_func_4, arg_func_5);
}
template<typename TO, typename TD, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
instr_caller* instr_bind(void (TO::*func)(T1, T2, T3, T4, T5, T6), T1 (TD::*arg_func_1)(), T2 (TD::*arg_func_2)(), T3 (TD::*arg_func_3)(), T4 (TD::*arg_func_4)(), T5 (TD::*arg_func_5)(), T6 (TD::*arg_func_6)())
{
return new instr_binder_6<TO, TD, T1, T2, T3, T4, T5, T6>(&m_op, this, func, arg_func_1, arg_func_2, arg_func_3, arg_func_4, arg_func_5, arg_func_6);
}
void UNK_MAIN()
{
if(!m_code)
{
m_op.NULL_OP();
}
else
{
u32 opcd = OPCD();
m_op.UNK(m_code, opcd, opcd);
}
}
PPU_Decoder(PPU_Opcodes& op) : m_op(op)
{
#define bind_instr(list, instr, ...) list->set_instr(instr, instr_bind(&PPU_Opcodes::##instr, ##__VA_ARGS__))
using namespace PPU_opcodes;
auto main_list = new_list<0x40>(this, &PPU_Decoder::OPCD, instr_bind(this, &PPU_Decoder::UNK_MAIN));
auto g04_0_list = new_list<0x800>(this, &PPU_Decoder::GD_04_0, instr_bind(&PPU_Opcodes::UNK, &PPU_Decoder::GetCode, &PPU_Decoder::OPCD, &PPU_Decoder::GD_04_0));
auto g04_list = new_list<0x40>(this, &PPU_Decoder::GD_04, g04_0_list);
auto g13_list = new_list<0x400>(this, &PPU_Decoder::GD_13, instr_bind(&PPU_Opcodes::UNK, &PPU_Decoder::GetCode, &PPU_Decoder::OPCD, &PPU_Decoder::GD_13));
auto g1e_list = new_list<0x4>(this, &PPU_Decoder::GD_1e, instr_bind(&PPU_Opcodes::UNK, &PPU_Decoder::GetCode, &PPU_Decoder::OPCD, &PPU_Decoder::GD_1e));
auto g1f_list = new_list<0x400>(this, &PPU_Decoder::GD_1f, instr_bind(&PPU_Opcodes::UNK, &PPU_Decoder::GetCode, &PPU_Decoder::OPCD, &PPU_Decoder::GD_1f));
auto g3a_list = new_list<0x4>(this, &PPU_Decoder::GD_3a, instr_bind(&PPU_Opcodes::UNK, &PPU_Decoder::GetCode, &PPU_Decoder::OPCD, &PPU_Decoder::GD_3a));
auto g3b_list = new_list<0x20>(this, &PPU_Decoder::GD_3b, instr_bind(&PPU_Opcodes::UNK, &PPU_Decoder::GetCode, &PPU_Decoder::OPCD, &PPU_Decoder::GD_3b));
auto g3e_list = new_list<0x4>(this, &PPU_Decoder::GD_3e, instr_bind(&PPU_Opcodes::UNK, &PPU_Decoder::GetCode, &PPU_Decoder::OPCD, &PPU_Decoder::GD_3e));
auto g3f_0_list = new_list<0x400>(this, &PPU_Decoder::GD_3f_0, instr_bind(&PPU_Opcodes::UNK, &PPU_Decoder::GetCode, &PPU_Decoder::OPCD, &PPU_Decoder::GD_3f_0));
auto g3f_list = new_list<0x20>(this, &PPU_Decoder::GD_3f, g3f_0_list);
bind_instr(main_list, TDI, &PPU_Decoder::TO, &PPU_Decoder::RA, &PPU_Decoder::simm16);
bind_instr(main_list, TWI, &PPU_Decoder::TO, &PPU_Decoder::RA, &PPU_Decoder::simm16);
main_list->set_instr(G_04, g04_list);
bind_instr(main_list, MULLI, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::simm16);
bind_instr(main_list, SUBFIC, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::simm16);
bind_instr(main_list, CMPLI, &PPU_Decoder::CRFD, &PPU_Decoder::L_10, &PPU_Decoder::RA, &PPU_Decoder::uimm16);
bind_instr(main_list, CMPI, &PPU_Decoder::CRFD, &PPU_Decoder::L_10, &PPU_Decoder::RA, &PPU_Decoder::simm16);
bind_instr(main_list, ADDIC, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::simm16);
bind_instr(main_list, ADDIC_, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::simm16);
bind_instr(main_list, ADDI, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::simm16);
bind_instr(main_list, ADDIS, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::simm16);
bind_instr(main_list, BC, &PPU_Decoder::BO, &PPU_Decoder::BI, &PPU_Decoder::BD, &PPU_Decoder::AA, &PPU_Decoder::LK);
bind_instr(main_list, SC, &PPU_Decoder::SYS);
bind_instr(main_list, B, &PPU_Decoder::LL, &PPU_Decoder::AA, &PPU_Decoder::LK);
main_list->set_instr(G_13, g13_list);
bind_instr(main_list, RLWIMI, &PPU_Decoder::RA, &PPU_Decoder::RS, &PPU_Decoder::SH, &PPU_Decoder::MB, &PPU_Decoder::ME, &PPU_Decoder::RC);
bind_instr(main_list, RLWINM, &PPU_Decoder::RA, &PPU_Decoder::RS, &PPU_Decoder::SH, &PPU_Decoder::MB, &PPU_Decoder::ME, &PPU_Decoder::RC);
bind_instr(main_list, RLWNM, &PPU_Decoder::RA, &PPU_Decoder::RS, &PPU_Decoder::RB, &PPU_Decoder::MB, &PPU_Decoder::ME, &PPU_Decoder::RC);
bind_instr(main_list, ORI, &PPU_Decoder::RA, &PPU_Decoder::RS, &PPU_Decoder::uimm16);
bind_instr(main_list, ORIS, &PPU_Decoder::RA, &PPU_Decoder::RS, &PPU_Decoder::uimm16);
bind_instr(main_list, XORI, &PPU_Decoder::RA, &PPU_Decoder::RS, &PPU_Decoder::uimm16);
bind_instr(main_list, XORIS, &PPU_Decoder::RA, &PPU_Decoder::RS, &PPU_Decoder::uimm16);
bind_instr(main_list, ANDI_, &PPU_Decoder::RA, &PPU_Decoder::RS, &PPU_Decoder::uimm16);
bind_instr(main_list, ANDIS_, &PPU_Decoder::RA, &PPU_Decoder::RS, &PPU_Decoder::uimm16);
main_list->set_instr(G_1e, g1e_list);
main_list->set_instr(G_1f, g1f_list);
bind_instr(main_list, LWZ, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::D);
bind_instr(main_list, LWZU, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::D);
bind_instr(main_list, LBZ, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::D);
bind_instr(main_list, LBZU, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::D);
bind_instr(main_list, STW, &PPU_Decoder::RS, &PPU_Decoder::RA, &PPU_Decoder::D);
bind_instr(main_list, STWU, &PPU_Decoder::RS, &PPU_Decoder::RA, &PPU_Decoder::D);
bind_instr(main_list, STB, &PPU_Decoder::RS, &PPU_Decoder::RA, &PPU_Decoder::D);
bind_instr(main_list, STBU, &PPU_Decoder::RS, &PPU_Decoder::RA, &PPU_Decoder::D);
bind_instr(main_list, LHZ, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::D);
bind_instr(main_list, LHZU, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::D);
bind_instr(main_list, STH, &PPU_Decoder::RS, &PPU_Decoder::RA, &PPU_Decoder::D);
bind_instr(main_list, STHU, &PPU_Decoder::RS, &PPU_Decoder::RA, &PPU_Decoder::D);
bind_instr(main_list, LMW, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::D);
bind_instr(main_list, STMW, &PPU_Decoder::RS, &PPU_Decoder::RA, &PPU_Decoder::D);
bind_instr(main_list, LFS, &PPU_Decoder::FRD, &PPU_Decoder::RA, &PPU_Decoder::D);
bind_instr(main_list, LFSU, &PPU_Decoder::FRD, &PPU_Decoder::RA, &PPU_Decoder::D);
bind_instr(main_list, LFD, &PPU_Decoder::FRD, &PPU_Decoder::RA, &PPU_Decoder::D);
bind_instr(main_list, LFDU, &PPU_Decoder::FRD, &PPU_Decoder::RA, &PPU_Decoder::D);
bind_instr(main_list, STFS, &PPU_Decoder::FRS, &PPU_Decoder::RA, &PPU_Decoder::D);
bind_instr(main_list, STFSU, &PPU_Decoder::FRS, &PPU_Decoder::RA, &PPU_Decoder::D);
bind_instr(main_list, STFD, &PPU_Decoder::FRS, &PPU_Decoder::RA, &PPU_Decoder::D);
bind_instr(main_list, STFDU, &PPU_Decoder::FRS, &PPU_Decoder::RA, &PPU_Decoder::D);
main_list->set_instr(G_3a, g3a_list);
main_list->set_instr(G_3b, g3b_list);
main_list->set_instr(G_3e, g3e_list);
main_list->set_instr(G_3f, g3f_list);
bind_instr(g04_list, VMADDFP, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB, &PPU_Decoder::VC);
bind_instr(g04_list, VMHADDSHS, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB, &PPU_Decoder::VC);
bind_instr(g04_list, VMHRADDSHS, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB, &PPU_Decoder::VC);
bind_instr(g04_list, VMLADDUHM, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB, &PPU_Decoder::VC);
bind_instr(g04_list, VMSUMMBM, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB, &PPU_Decoder::VC);
bind_instr(g04_list, VMSUMSHM, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB, &PPU_Decoder::VC);
bind_instr(g04_list, VMSUMSHS, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB, &PPU_Decoder::VC);
bind_instr(g04_list, VMSUMUBM, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB, &PPU_Decoder::VC);
bind_instr(g04_list, VMSUMUHM, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB, &PPU_Decoder::VC);
bind_instr(g04_list, VMSUMUHS, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB, &PPU_Decoder::VC);
bind_instr(g04_list, VNMSUBFP, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB, &PPU_Decoder::VC);
bind_instr(g04_list, VPERM, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB, &PPU_Decoder::VC);
bind_instr(g04_list, VSEL, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB, &PPU_Decoder::VC);
bind_instr(g04_list, VSLDOI, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB, &PPU_Decoder::VSH);
bind_instr(g04_0_list, MFVSCR, &PPU_Decoder::VD);
bind_instr(g04_0_list, MTVSCR, &PPU_Decoder::VB);
bind_instr(g04_0_list, VADDCUW, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VADDFP, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VADDSBS, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VADDSHS, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VADDSWS, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VADDUBM, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VADDUBS, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VADDUHM, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VADDUHS, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VADDUWM, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VADDUWS, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VAND, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VANDC, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VAVGSB, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VAVGSH, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VAVGSW, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VAVGUB, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VAVGUH, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VAVGUW, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VCFSX, &PPU_Decoder::VD, &PPU_Decoder::VUIMM, &PPU_Decoder::VB);
bind_instr(g04_0_list, VCFUX, &PPU_Decoder::VD, &PPU_Decoder::VUIMM, &PPU_Decoder::VB);
bind_instr(g04_0_list, VCMPBFP, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VCMPBFP_, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VCMPEQFP, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VCMPEQFP_, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VCMPEQUB, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VCMPEQUB_, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VCMPEQUH, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VCMPEQUH_, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VCMPEQUW, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VCMPEQUW_, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VCMPGEFP, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VCMPGEFP_, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VCMPGTFP, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VCMPGTFP_, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VCMPGTSB, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VCMPGTSB_, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VCMPGTSH, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VCMPGTSH_, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VCMPGTSW, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VCMPGTSW_, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VCMPGTUB, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VCMPGTUB_, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VCMPGTUH, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VCMPGTUH_, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VCMPGTUW, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VCMPGTUW_, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VCTSXS, &PPU_Decoder::VD, &PPU_Decoder::VUIMM, &PPU_Decoder::VB);
bind_instr(g04_0_list, VCTUXS, &PPU_Decoder::VD, &PPU_Decoder::VUIMM, &PPU_Decoder::VB);
bind_instr(g04_0_list, VEXPTEFP, &PPU_Decoder::VD, &PPU_Decoder::VB);
bind_instr(g04_0_list, VLOGEFP, &PPU_Decoder::VD, &PPU_Decoder::VB);
bind_instr(g04_0_list, VMAXFP, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VMAXSB, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VMAXSH, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VMAXSW, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VMAXUB, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VMAXUH, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VMAXUW, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VMINFP, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VMINSB, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VMINSH, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VMINSW, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VMINUB, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VMINUH, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VMINUW, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VMRGHB, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VMRGHH, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VMRGHW, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VMRGLB, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VMRGLH, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VMRGLW, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VMULESB, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VMULESH, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VMULEUB, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VMULEUH, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VMULOSB, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VMULOSH, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VMULOUB, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VMULOUH, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VNOR, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VOR, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VPKPX, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VPKSHSS, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VPKSHUS, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VPKSWSS, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VPKSWUS, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VPKUHUM, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VPKUHUS, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VPKUWUM, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VPKUWUS, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VREFP, &PPU_Decoder::VD, &PPU_Decoder::VB);
bind_instr(g04_0_list, VRFIM, &PPU_Decoder::VD, &PPU_Decoder::VB);
bind_instr(g04_0_list, VRFIN, &PPU_Decoder::VD, &PPU_Decoder::VB);
bind_instr(g04_0_list, VRFIP, &PPU_Decoder::VD, &PPU_Decoder::VB);
bind_instr(g04_0_list, VRFIZ, &PPU_Decoder::VD, &PPU_Decoder::VB);
bind_instr(g04_0_list, VRLB, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VRLH, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VRLW, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VRSQRTEFP, &PPU_Decoder::VD, &PPU_Decoder::VB);
bind_instr(g04_0_list, VSL, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VSLB, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VSLH, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VSLO, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VSLW, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VSPLTB, &PPU_Decoder::VD, &PPU_Decoder::VUIMM, &PPU_Decoder::VB);
bind_instr(g04_0_list, VSPLTH, &PPU_Decoder::VD, &PPU_Decoder::VUIMM, &PPU_Decoder::VB);
bind_instr(g04_0_list, VSPLTISB, &PPU_Decoder::VD, &PPU_Decoder::VSIMM);
bind_instr(g04_0_list, VSPLTISH, &PPU_Decoder::VD, &PPU_Decoder::VSIMM);
bind_instr(g04_0_list, VSPLTISW, &PPU_Decoder::VD, &PPU_Decoder::VSIMM);
bind_instr(g04_0_list, VSPLTW, &PPU_Decoder::VD, &PPU_Decoder::VUIMM, &PPU_Decoder::VB);
bind_instr(g04_0_list, VSR, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VSRAB, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VSRAH, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VSRAW, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VSRB, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VSRH, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VSRO, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VSRW, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VSUBCUW, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VSUBFP, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VSUBSBS, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VSUBSHS, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VSUBSWS, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VSUBUBM, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VSUBUBS, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VSUBUHM, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VSUBUHS, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VSUBUWM, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VSUBUWS, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VSUMSWS, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VSUM2SWS, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VSUM4SBS, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VSUM4SHS, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VSUM4UBS, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g04_0_list, VUPKHPX, &PPU_Decoder::VD, &PPU_Decoder::VB);
bind_instr(g04_0_list, VUPKHSB, &PPU_Decoder::VD, &PPU_Decoder::VB);
bind_instr(g04_0_list, VUPKHSH, &PPU_Decoder::VD, &PPU_Decoder::VB);
bind_instr(g04_0_list, VUPKLPX, &PPU_Decoder::VD, &PPU_Decoder::VB);
bind_instr(g04_0_list, VUPKLSB, &PPU_Decoder::VD, &PPU_Decoder::VB);
bind_instr(g04_0_list, VUPKLSH, &PPU_Decoder::VD, &PPU_Decoder::VB);
bind_instr(g04_0_list, VXOR, &PPU_Decoder::VD, &PPU_Decoder::VA, &PPU_Decoder::VB);
bind_instr(g13_list, MCRF, &PPU_Decoder::CRFD, &PPU_Decoder::CRFS);
bind_instr(g13_list, BCLR, &PPU_Decoder::BO, &PPU_Decoder::BI, &PPU_Decoder::BH, &PPU_Decoder::LK);
bind_instr(g13_list, CRNOR, &PPU_Decoder::CRBD, &PPU_Decoder::CRBA, &PPU_Decoder::CRBB);
bind_instr(g13_list, CRANDC, &PPU_Decoder::CRBD, &PPU_Decoder::CRBA, &PPU_Decoder::CRBB);
bind_instr(g13_list, ISYNC);
bind_instr(g13_list, CRXOR, &PPU_Decoder::CRBD, &PPU_Decoder::CRBA, &PPU_Decoder::CRBB);
bind_instr(g13_list, CRNAND, &PPU_Decoder::CRBD, &PPU_Decoder::CRBA, &PPU_Decoder::CRBB);
bind_instr(g13_list, CRAND, &PPU_Decoder::CRBD, &PPU_Decoder::CRBA, &PPU_Decoder::CRBB);
bind_instr(g13_list, CREQV, &PPU_Decoder::CRBD, &PPU_Decoder::CRBA, &PPU_Decoder::CRBB);
bind_instr(g13_list, CRORC, &PPU_Decoder::CRBD, &PPU_Decoder::CRBA, &PPU_Decoder::CRBB);
bind_instr(g13_list, CROR, &PPU_Decoder::CRBD, &PPU_Decoder::CRBA, &PPU_Decoder::CRBB);
bind_instr(g13_list, BCCTR, &PPU_Decoder::BO, &PPU_Decoder::BI, &PPU_Decoder::BH, &PPU_Decoder::LK);
bind_instr(g1e_list, RLDICL, &PPU_Decoder::RA, &PPU_Decoder::RS, &PPU_Decoder::sh, &PPU_Decoder::mb, &PPU_Decoder::RC);
bind_instr(g1e_list, RLDICR, &PPU_Decoder::RA, &PPU_Decoder::RS, &PPU_Decoder::sh, &PPU_Decoder::me, &PPU_Decoder::RC);
bind_instr(g1e_list, RLDIC, &PPU_Decoder::RA, &PPU_Decoder::RS, &PPU_Decoder::sh, &PPU_Decoder::mb, &PPU_Decoder::RC);
bind_instr(g1e_list, RLDIMI, &PPU_Decoder::RA, &PPU_Decoder::RS, &PPU_Decoder::sh, &PPU_Decoder::mb, &PPU_Decoder::RC);
/*0x000*/bind_instr(g1f_list, CMP, &PPU_Decoder::CRFD, &PPU_Decoder::L_10, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x004*/bind_instr(g1f_list, TW, &PPU_Decoder::TO, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x006*/bind_instr(g1f_list, LVSL, &PPU_Decoder::VD, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x007*/bind_instr(g1f_list, LVEBX, &PPU_Decoder::VD, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x008*/bind_instr(g1f_list, SUBFC, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::RB, &PPU_Decoder::OE, &PPU_Decoder::RC);
/*0x009*/bind_instr(g1f_list, MULHDU, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::RB, &PPU_Decoder::RC);
/*0x00a*/bind_instr(g1f_list, ADDC, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::RB, &PPU_Decoder::OE, &PPU_Decoder::RC);
/*0x00b*/bind_instr(g1f_list, MULHWU, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::RB, &PPU_Decoder::RC);
/*0x013*/bind_instr(g1f_list, MFOCRF, &PPU_Decoder::L_11, &PPU_Decoder::RD, &PPU_Decoder::CRM);
/*0x014*/bind_instr(g1f_list, LWARX, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x015*/bind_instr(g1f_list, LDX, &PPU_Decoder::RA, &PPU_Decoder::RS, &PPU_Decoder::RB);
/*0x017*/bind_instr(g1f_list, LWZX, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x018*/bind_instr(g1f_list, SLW, &PPU_Decoder::RA, &PPU_Decoder::RS, &PPU_Decoder::RB, &PPU_Decoder::RC);
/*0x01a*/bind_instr(g1f_list, CNTLZW, &PPU_Decoder::RA, &PPU_Decoder::RS, &PPU_Decoder::RC);
/*0x01b*/bind_instr(g1f_list, SLD, &PPU_Decoder::RA, &PPU_Decoder::RS, &PPU_Decoder::RB, &PPU_Decoder::RC);
/*0x01c*/bind_instr(g1f_list, AND, &PPU_Decoder::RA, &PPU_Decoder::RS, &PPU_Decoder::RB, &PPU_Decoder::RC);
/*0x020*/bind_instr(g1f_list, CMPL, &PPU_Decoder::CRFD, &PPU_Decoder::L_10, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x026*/bind_instr(g1f_list, LVSR, &PPU_Decoder::VD, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x027*/bind_instr(g1f_list, LVEHX, &PPU_Decoder::VD, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x028*/bind_instr(g1f_list, SUBF, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::RB, &PPU_Decoder::OE, &PPU_Decoder::RC);
/*0x036*/bind_instr(g1f_list, DCBST, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x03a*/bind_instr(g1f_list, CNTLZD, &PPU_Decoder::RA, &PPU_Decoder::RS, &PPU_Decoder::RC);
/*0x03c*/bind_instr(g1f_list, ANDC, &PPU_Decoder::RA, &PPU_Decoder::RS, &PPU_Decoder::RB, &PPU_Decoder::RC);
/*0x047*/bind_instr(g1f_list, LVEWX, &PPU_Decoder::VD, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x049*/bind_instr(g1f_list, MULHD, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::RB, &PPU_Decoder::RC);
/*0x04b*/bind_instr(g1f_list, MULHW, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::RB, &PPU_Decoder::RC);
/*0x054*/bind_instr(g1f_list, LDARX, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x056*/bind_instr(g1f_list, DCBF, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x057*/bind_instr(g1f_list, LBZX, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x067*/bind_instr(g1f_list, LVX, &PPU_Decoder::VD, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x068*/bind_instr(g1f_list, NEG, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::OE, &PPU_Decoder::RC);
/*0x077*/bind_instr(g1f_list, LBZUX, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x07c*/bind_instr(g1f_list, NOR, &PPU_Decoder::RA, &PPU_Decoder::RS, &PPU_Decoder::RB, &PPU_Decoder::RC);
/*0x087*/bind_instr(g1f_list, STVEBX, &PPU_Decoder::VS, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x088*/bind_instr(g1f_list, SUBFE, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::RB, &PPU_Decoder::OE, &PPU_Decoder::RC);
/*0x08a*/bind_instr(g1f_list, ADDE, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::RB, &PPU_Decoder::OE, &PPU_Decoder::RC);
/*0x090*/bind_instr(g1f_list, MTOCRF, &PPU_Decoder::CRM, &PPU_Decoder::RS);
/*0x095*/bind_instr(g1f_list, STDX, &PPU_Decoder::RS, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x096*/bind_instr(g1f_list, STWCX_, &PPU_Decoder::RS, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x097*/bind_instr(g1f_list, STWX, &PPU_Decoder::RS, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x0a7*/bind_instr(g1f_list, STVEHX, &PPU_Decoder::VS, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x0b5*/bind_instr(g1f_list, STDUX, &PPU_Decoder::RS, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x0c7*/bind_instr(g1f_list, STVEWX, &PPU_Decoder::VS, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x0ca*/bind_instr(g1f_list, ADDZE, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::OE, &PPU_Decoder::RC);
/*0x0d6*/bind_instr(g1f_list, STDCX_, &PPU_Decoder::RS, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x0d7*/bind_instr(g1f_list, STBX, &PPU_Decoder::RS, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x0e7*/bind_instr(g1f_list, STVX, &PPU_Decoder::VS, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x0e9*/bind_instr(g1f_list, MULLD, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::RB, &PPU_Decoder::OE, &PPU_Decoder::RC);
/*0x0ea*/bind_instr(g1f_list, ADDME, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::OE, &PPU_Decoder::RC);
/*0x0eb*/bind_instr(g1f_list, MULLW, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::RB, &PPU_Decoder::OE, &PPU_Decoder::RC);
/*0x0f6*/bind_instr(g1f_list, DCBTST, &PPU_Decoder::TH, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x10a*/bind_instr(g1f_list, ADD, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::RB, &PPU_Decoder::OE, &PPU_Decoder::RC);
/*0x116*/bind_instr(g1f_list, DCBT, &PPU_Decoder::RA, &PPU_Decoder::RB, &PPU_Decoder::TH);
/*0x117*/bind_instr(g1f_list, LHZX, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x11c*/bind_instr(g1f_list, EQV, &PPU_Decoder::RA, &PPU_Decoder::RS, &PPU_Decoder::RB, &PPU_Decoder::RC);
/*0x136*/bind_instr(g1f_list, ECIWX, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x137*/bind_instr(g1f_list, LHZUX, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x13c*/bind_instr(g1f_list, XOR, &PPU_Decoder::RA, &PPU_Decoder::RS, &PPU_Decoder::RB, &PPU_Decoder::RC);
/*0x153*/bind_instr(g1f_list, MFSPR, &PPU_Decoder::RD, &PPU_Decoder::SPR);
/*0x156*/bind_instr(g1f_list, DST, &PPU_Decoder::RA, &PPU_Decoder::RB, &PPU_Decoder::STRM, &PPU_Decoder::L_6);
/*0x157*/bind_instr(g1f_list, LHAX, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x167*/bind_instr(g1f_list, LVXL, &PPU_Decoder::VD, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x168*/bind_instr(g1f_list, ABS, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::OE, &PPU_Decoder::RC);
/*0x173*/bind_instr(g1f_list, MFTB, &PPU_Decoder::RD, &PPU_Decoder::SPR);
/*0x176*/bind_instr(g1f_list, DSTST, &PPU_Decoder::RA, &PPU_Decoder::RB, &PPU_Decoder::STRM, &PPU_Decoder::L_6);
/*0x177*/bind_instr(g1f_list, LHAUX, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x197*/bind_instr(g1f_list, STHX, &PPU_Decoder::RS, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x19c*/bind_instr(g1f_list, ORC, &PPU_Decoder::RA, &PPU_Decoder::RS, &PPU_Decoder::RB, &PPU_Decoder::RC);
/*0x1b6*/bind_instr(g1f_list, ECOWX, &PPU_Decoder::RS, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x1bc*/bind_instr(g1f_list, OR, &PPU_Decoder::RA, &PPU_Decoder::RS, &PPU_Decoder::RB, &PPU_Decoder::RC);
/*0x1c9*/bind_instr(g1f_list, DIVDU, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::RB, &PPU_Decoder::OE, &PPU_Decoder::RC);
/*0x1cb*/bind_instr(g1f_list, DIVWU, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::RB, &PPU_Decoder::OE, &PPU_Decoder::RC);
/*0x1d3*/bind_instr(g1f_list, MTSPR, &PPU_Decoder::SPR, &PPU_Decoder::RS);
/*0x1d6*///DCBI
/*0x1dc*/bind_instr(g1f_list, NAND, &PPU_Decoder::RA, &PPU_Decoder::RS, &PPU_Decoder::RB, &PPU_Decoder::RC);
/*0x1e7*/bind_instr(g1f_list, STVXL, &PPU_Decoder::RS, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x1e9*/bind_instr(g1f_list, DIVD, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::RB, &PPU_Decoder::OE, &PPU_Decoder::RC);
/*0x1eb*/bind_instr(g1f_list, DIVW, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::RB, &PPU_Decoder::OE, &PPU_Decoder::RC);
/*0x207*/bind_instr(g1f_list, LVLX, &PPU_Decoder::VD, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x216*/bind_instr(g1f_list, LWBRX, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x217*/bind_instr(g1f_list, LFSX, &PPU_Decoder::FRD, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x218*/bind_instr(g1f_list, SRW, &PPU_Decoder::RA, &PPU_Decoder::RS, &PPU_Decoder::RB, &PPU_Decoder::RC);
/*0x21b*/bind_instr(g1f_list, SRD, &PPU_Decoder::RA, &PPU_Decoder::RS, &PPU_Decoder::RB, &PPU_Decoder::RC);
/*0x227*/bind_instr(g1f_list, LVRX, &PPU_Decoder::VD, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x237*/bind_instr(g1f_list, LFSUX, &PPU_Decoder::FRD, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x256*/bind_instr(g1f_list, SYNC, &PPU_Decoder::L_9_10);
/*0x257*/bind_instr(g1f_list, LFDX, &PPU_Decoder::FRD, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x277*/bind_instr(g1f_list, LFDUX, &PPU_Decoder::FRD, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x287*/bind_instr(g1f_list, STVLX, &PPU_Decoder::VS, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x297*/bind_instr(g1f_list, STFSX, &PPU_Decoder::RS, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x2a7*/bind_instr(g1f_list, STVRX, &PPU_Decoder::VS, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x2d7*/bind_instr(g1f_list, STFDX, &PPU_Decoder::RS, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x307*/bind_instr(g1f_list, LVLXL, &PPU_Decoder::VD, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x316*/bind_instr(g1f_list, LHBRX, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x318*/bind_instr(g1f_list, SRAW, &PPU_Decoder::RA, &PPU_Decoder::RS, &PPU_Decoder::RB, &PPU_Decoder::RC);
/*0x31a*/bind_instr(g1f_list, SRAD, &PPU_Decoder::RA, &PPU_Decoder::RS, &PPU_Decoder::RB, &PPU_Decoder::RC);
/*0x327*/bind_instr(g1f_list, LVRXL, &PPU_Decoder::VD, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x336*/bind_instr(g1f_list, DSS, &PPU_Decoder::STRM, &PPU_Decoder::L_6);
/*0x338*/bind_instr(g1f_list, SRAWI, &PPU_Decoder::RA, &PPU_Decoder::RS, &PPU_Decoder::sh, &PPU_Decoder::RC);
/*0x33a*/bind_instr(g1f_list, SRADI1, &PPU_Decoder::RA, &PPU_Decoder::RS, &PPU_Decoder::sh, &PPU_Decoder::RC);
/*0x33b*/bind_instr(g1f_list, SRADI2, &PPU_Decoder::RA, &PPU_Decoder::RS, &PPU_Decoder::sh, &PPU_Decoder::RC);
/*0x356*/bind_instr(g1f_list, EIEIO);
/*0x39a*/bind_instr(g1f_list, EXTSH, &PPU_Decoder::RA, &PPU_Decoder::RS, &PPU_Decoder::RC);
/*0x3ba*/bind_instr(g1f_list, EXTSB, &PPU_Decoder::RA, &PPU_Decoder::RS, &PPU_Decoder::RC);
/*0x3d7*/bind_instr(g1f_list, STFIWX, &PPU_Decoder::FRS, &PPU_Decoder::RA, &PPU_Decoder::RB);
/*0x3da*/bind_instr(g1f_list, EXTSW, &PPU_Decoder::RA, &PPU_Decoder::RS, &PPU_Decoder::RC);
/*0x3d6*///ICBI
/*0x3f6*/bind_instr(g1f_list, DCBZ, &PPU_Decoder::RA, &PPU_Decoder::RB);
bind_instr(g3a_list, LD, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::D);
bind_instr(g3a_list, LDU, &PPU_Decoder::RD, &PPU_Decoder::RA, &PPU_Decoder::DS);
bind_instr(g3b_list, FDIVS, &PPU_Decoder::FRD, &PPU_Decoder::FRA, &PPU_Decoder::FRB, &PPU_Decoder::RC);
bind_instr(g3b_list, FSUBS, &PPU_Decoder::FRD, &PPU_Decoder::FRA, &PPU_Decoder::FRB, &PPU_Decoder::RC);
bind_instr(g3b_list, FADDS, &PPU_Decoder::FRD, &PPU_Decoder::FRA, &PPU_Decoder::FRB, &PPU_Decoder::RC);
bind_instr(g3b_list, FSQRTS, &PPU_Decoder::FRD, &PPU_Decoder::FRB, &PPU_Decoder::RC);
bind_instr(g3b_list, FRES, &PPU_Decoder::FRD, &PPU_Decoder::FRB, &PPU_Decoder::RC);
bind_instr(g3b_list, FMULS, &PPU_Decoder::FRD, &PPU_Decoder::FRA, &PPU_Decoder::FRC, &PPU_Decoder::RC);
bind_instr(g3b_list, FMADDS, &PPU_Decoder::FRD, &PPU_Decoder::FRA, &PPU_Decoder::FRC, &PPU_Decoder::FRB, &PPU_Decoder::RC);
bind_instr(g3b_list, FMSUBS, &PPU_Decoder::FRD, &PPU_Decoder::FRA, &PPU_Decoder::FRC, &PPU_Decoder::FRB, &PPU_Decoder::RC);
bind_instr(g3b_list, FNMSUBS, &PPU_Decoder::FRD, &PPU_Decoder::FRA, &PPU_Decoder::FRC, &PPU_Decoder::FRB, &PPU_Decoder::RC);
bind_instr(g3b_list, FNMADDS, &PPU_Decoder::FRD, &PPU_Decoder::FRA, &PPU_Decoder::FRC, &PPU_Decoder::FRB, &PPU_Decoder::RC);
bind_instr(g3e_list, STD, &PPU_Decoder::RS, &PPU_Decoder::RA, &PPU_Decoder::D);
bind_instr(g3e_list, STDU, &PPU_Decoder::RS, &PPU_Decoder::RA, &PPU_Decoder::DS);
bind_instr(g3f_list, FSEL, &PPU_Decoder::FRD, &PPU_Decoder::FRA, &PPU_Decoder::FRC, &PPU_Decoder::FRB, &PPU_Decoder::RC);
bind_instr(g3f_list, FMUL, &PPU_Decoder::FRD, &PPU_Decoder::FRA, &PPU_Decoder::FRC, &PPU_Decoder::RC);
bind_instr(g3f_list, FMSUB, &PPU_Decoder::FRD, &PPU_Decoder::FRA, &PPU_Decoder::FRC, &PPU_Decoder::FRB, &PPU_Decoder::RC);
bind_instr(g3f_list, FMADD, &PPU_Decoder::FRD, &PPU_Decoder::FRA, &PPU_Decoder::FRC, &PPU_Decoder::FRB, &PPU_Decoder::RC);
bind_instr(g3f_list, FNMSUB, &PPU_Decoder::FRD, &PPU_Decoder::FRA, &PPU_Decoder::FRC, &PPU_Decoder::FRB, &PPU_Decoder::RC);
bind_instr(g3f_list, FNMADD, &PPU_Decoder::FRD, &PPU_Decoder::FRA, &PPU_Decoder::FRC, &PPU_Decoder::FRB, &PPU_Decoder::RC);
bind_instr(g3f_0_list, FDIV, &PPU_Decoder::FRD, &PPU_Decoder::FRA, &PPU_Decoder::FRB, &PPU_Decoder::RC);
bind_instr(g3f_0_list, FSUB, &PPU_Decoder::FRD, &PPU_Decoder::FRA, &PPU_Decoder::FRB, &PPU_Decoder::RC);
bind_instr(g3f_0_list, FADD, &PPU_Decoder::FRD, &PPU_Decoder::FRA, &PPU_Decoder::FRB, &PPU_Decoder::RC);
bind_instr(g3f_0_list, FSQRT, &PPU_Decoder::FRD, &PPU_Decoder::FRB, &PPU_Decoder::RC);
bind_instr(g3f_0_list, FRSQRTE, &PPU_Decoder::FRD, &PPU_Decoder::FRB, &PPU_Decoder::RC);
bind_instr(g3f_0_list, FCMPU, &PPU_Decoder::CRFD, &PPU_Decoder::FRA, &PPU_Decoder::FRB);
bind_instr(g3f_0_list, FRSP, &PPU_Decoder::FRD, &PPU_Decoder::FRB, &PPU_Decoder::RC);
bind_instr(g3f_0_list, FCTIW, &PPU_Decoder::FRD, &PPU_Decoder::FRB, &PPU_Decoder::RC);
bind_instr(g3f_0_list, FCTIWZ, &PPU_Decoder::FRD, &PPU_Decoder::FRB, &PPU_Decoder::RC);
bind_instr(g3f_0_list, FCMPO, &PPU_Decoder::CRFD, &PPU_Decoder::FRA, &PPU_Decoder::FRB);
bind_instr(g3f_0_list, FNEG, &PPU_Decoder::FRD, &PPU_Decoder::FRB, &PPU_Decoder::RC);
bind_instr(g3f_0_list, FMR, &PPU_Decoder::FRD, &PPU_Decoder::FRB, &PPU_Decoder::RC);
bind_instr(g3f_0_list, FNABS, &PPU_Decoder::FRD, &PPU_Decoder::FRB, &PPU_Decoder::RC);
bind_instr(g3f_0_list, FABS, &PPU_Decoder::FRD, &PPU_Decoder::FRB, &PPU_Decoder::RC);
bind_instr(g3f_0_list, FCFID, &PPU_Decoder::FRD, &PPU_Decoder::FRB, &PPU_Decoder::RC);
bind_instr(g3f_0_list, FCTID, &PPU_Decoder::FRD, &PPU_Decoder::FRB, &PPU_Decoder::RC);
bind_instr(g3f_0_list, FCTIDZ, &PPU_Decoder::FRD, &PPU_Decoder::FRB, &PPU_Decoder::RC);
bind_instr(g3f_0_list, MTFSB1, &PPU_Decoder::BT, &PPU_Decoder::RC);
bind_instr(g3f_0_list, MCRFS, &PPU_Decoder::BF, &PPU_Decoder::BFA);
bind_instr(g3f_0_list, MTFSB0, &PPU_Decoder::BT, &PPU_Decoder::RC);
bind_instr(g3f_0_list, MTFSFI, &PPU_Decoder::CRFD, &PPU_Decoder::I, &PPU_Decoder::RC);
bind_instr(g3f_0_list, MFFS, &PPU_Decoder::FRD, &PPU_Decoder::RC);
bind_instr(g3f_0_list, MTFSF, &PPU_Decoder::FLM, &PPU_Decoder::FRB, &PPU_Decoder::RC);
m_instr_decoder = main_list;
}
~PPU_Decoder()
{
m_op.Exit();
delete m_instr_decoder;
m_op->Exit();
delete m_op;
}
virtual void Decode(const u32 code)
{
m_code = code;
(*m_instr_decoder)();
(*PPU_instr::main_list)(m_op, code);
}
};
#undef START_OPCODES_GROUP
#undef START_OPCODES_SUB_GROUP
#undef ADD_OPCODE
#undef ADD_NULL_OPCODE
#undef END_OPCODES_GROUP
#undef END_OPCODES_ND_GROUP
#undef END_OPCODES_SUB_GROUP

View File

@ -1,7 +1,7 @@
#pragma once
#include "Emu/Cell/PPUOpcodes.h"
#include "Emu/Cell/DisAsm.h"
#include "Emu/Cell/PPCDisAsm.h"
#include "Emu/Cell/PPCThread.h"
#include "Gui/DisAsmFrame.h"
#include "Emu/Memory/Memory.h"
@ -11,19 +11,19 @@
class PPU_DisAsm
: public PPU_Opcodes
, public DisAsm
, public PPC_DisAsm
{
public:
PPCThread& CPU;
PPU_DisAsm()
: DisAsm(*(PPCThread*)NULL, DumpMode)
: PPC_DisAsm(*(PPCThread*)NULL, DumpMode)
, CPU(*(PPCThread*)NULL)
{
}
PPU_DisAsm(PPCThread& cpu, DisAsmModes mode = NormalMode)
: DisAsm(cpu, mode)
: PPC_DisAsm(cpu, mode)
, CPU(cpu)
{
}
@ -937,14 +937,6 @@ private:
case 1: DisAsm_INT3("bcctrl", bo, bi, bh); break;
}
}
void BCTR()
{
Write("bctr");
}
void BCTRL()
{
Write("bctrl");
}
END_OPCODES_GROUP(G_13);

View File

@ -0,0 +1,640 @@
#pragma once
#include "PPCInstrTable.h"
#include "PPCDecoder.h"
#include "PPUOpcodes.h"
namespace PPU_instr
{
//This field is used in rotate instructions to specify the first 1 bit of a 64-bit mask
static DoubleCodeField<21, 25, 26, 26, 5> mb;
//This field is used in rotate instructions to specify the last 1 bit of a 64-bit mask
static DoubleCodeField<21, 25, 26, 26, 5> me;
//This field is used to specify a shift amount
static DoubleCodeField<16, 20, 30, 30, 5> sh;
//This field is used to specify a special-purpose register for the mtspr and mfspr instructions
static CodeField<11, 20> SPR;
//
static CodeField<6, 10> VS(FIELD_R_VPR);
//
static CodeField<6, 10> VD(FIELD_R_VPR);
//
static CodeField<11, 15> VA(FIELD_R_VPR);
//
static CodeField<16, 20> VB(FIELD_R_VPR);
//
static CodeField<21, 25> VC(FIELD_R_VPR);
//
static CodeField<11, 15> VUIMM;
//
static CodeFieldSigned<11, 15> VSIMM;
//
static CodeField<22, 25> VSH;
//This field is used to specify a GPR to be used as a destination
static CodeField<6, 10> RD(FIELD_R_GPR);
//This field is used to specify a GPR to be used as a source
static CodeField<6, 10> RS(FIELD_R_GPR);
//This field is used to specify a GPR to be used as a source or destination
static CodeField<11, 15> RA(FIELD_R_GPR);
//This field is used to specify a GPR to be used as a source
static CodeField<16, 20> RB(FIELD_R_GPR);
//This field is used to specify the number of bytes to move in an immediate string load or store
static CodeField<16, 20> NB;
//This field is used to specify one of the CR fields, or one of the FPSCR fields, as a destination
static CodeField<6, 8> CRFD(FIELD_R_CR);
//This field is used to specify one of the CR fields, or one of the FPSCR fields, as a source
static CodeField<11, 13> CRFS(FIELD_R_CR);
//This field is used to specify a bit in the CR to be used as a source
static CodeField<11, 15> CRBA(FIELD_R_CR);
//This field is used to specify a bit in the CR to be used as a source
static CodeField<16, 20> CRBB(FIELD_R_CR);
//This field is used to specify a bit in the CR, or in the FPSCR, as the destination of the result of an instruction
static CodeField<6, 10> CRBD(FIELD_R_CR);
//
static CodeField<6, 10> BT;
//
static CodeField<11, 15> BA;
//
static CodeField<16, 20> BB;
//
static CodeField<6, 10> BF;
//This field is used to specify options for the branch conditional instructions
static CodeField<6, 10> BO;
//This field is used to specify a bit in the CR to be used as the condition of a branch conditional instruction
static CodeField<11, 13> BI;
//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.
static CodeFieldSigned<16, 31> BD(FIELD_BRANCH);
//
static CodeField<19, 20> BH;
//
static CodeField<11, 13> BFA;
//Field used by the optional data stream variant of the dcbt instruction.
static CodeField<9, 10> TH;
//This field is used to specify the conditions on which to trap
static CodeField<6, 10> TO;
//
static CodeField<21, 25> MB;
//
static CodeField<26, 30> ME;
//This field is used to specify a shift amount
static CodeField<16, 20> SH;
/*
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.
*/
static CodeField<30> AA;
//
static CodeFieldSigned<6, 31> LL(FIELD_BRANCH);
/*
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.
*/
static CodeField<31> LK;
//This field is used for extended arithmetic to enable setting OV and SO in the XER
static CodeField<21> OE;
//Field used to specify whether an integer compare instruction is to compare 64-bit numbers or 32-bit numbers
static CodeField<10> L_10;
static CodeField<6> L_6;
static CodeField<9, 10> L_9_10;
static CodeField<11> L_11;
//
static CodeField<16, 19> I;
//
static CodeField<16, 27> DQ;
//This field is used to specify an FPR as the destination
static CodeField<6, 10> FRD;
//This field is used to specify an FPR as a source
static CodeField<6, 10> FRS;
//
static CodeField<7, 14> FLM;
//This field is used to specify an FPR as a source
static CodeField<11, 15> FRA(FIELD_R_FPR);
//This field is used to specify an FPR as a source
static CodeField<16, 20> FRB(FIELD_R_FPR);
//This field is used to specify an FPR as a source
static CodeField<21, 25> FRC(FIELD_R_FPR);
//This field mask is used to identify the CR fields that are to be updated by the mtcrf instruction.
static CodeField<12, 19> CRM;
//
static CodeField<6, 31> SYS;
//Immediate field specifying a 16-bit signed two's complement integer that is sign-extended to 64 bits
static CodeFieldSigned<16, 31> D;
//
struct : public CodeFieldSigned<16, 31>
{
static __forceinline u32 decode(u32 data)
{
int res = sign<size>((data & mask) >> shift);
if(res < 0) return res - 1;
return res;
}
static __forceinline void encode(u32& data, u32 value)
{
if((s32)value < 0)
{
value++;
}
data &= ~mask;
data |= (value << shift) & mask;
}
virtual u32 operator ()(u32 data) const
{
return decode(data);
}
virtual void operator ()(u32& data, u32 value) const
{
return encode(data, value);
}
} static DS;
//This immediate field is used to specify a 16-bit signed integer
static CodeFieldSigned<16, 31> simm16;
//This immediate field is used to specify a 16-bit unsigned integer
static CodeField<16, 31> uimm16;
/*
Record bit.
0 Does not update the condition register (CR).
1 Updates the CR to reflect the result of the operation.
For integer instructions, CR bits [02] are set to reflect the result as a signed quantity and CR bit [3]
receives a copy of the summary overflow bit, XER[SO]. The result as an unsigned quantity or a bit
string can be deduced from the EQ bit. For floating-point instructions, CR bits [47] are set to reflect
floating-point exception, floating-point enabled exception, floating-point invalid operation exception,
and floating-point overflow exception.
*/
static CodeField<31> RC;
//Primary opcode field
static CodeField<0, 5> OPCD;
static CodeField<26, 31> GD_04; //0x3f
static CodeField<21, 31> GD_04_0;//0x7ff
static CodeField<21, 30> GD_13; //0x3ff
static CodeField<28, 29> GD_1e; //0x3
static CodeField<21, 30> GD_1f; //0x3ff
static CodeField<30, 31> GD_3a; //0x3
static CodeField<26, 30> GD_3b; //0x1f
static CodeField<30, 31> GD_3e; //0x3
static CodeField<26, 30> GD_3f;//0x1f
static CodeField<21, 30> GD_3f_0; //0x3ff
static CodeField<0, 31> GetCode;
static CodeField<9, 10> STRM;
static auto main_list = new_list<0x40>(OPCD, instr_bind(&PPU_Opcodes::UNK, GetCode, OPCD, OPCD));
static auto g04_list = new_list<0x40>(main_list, PPU_opcodes::G_04, GD_04);
static auto g04_0_list = new_list<0x800>(g04_list, GD_04_0, instr_bind(&PPU_Opcodes::UNK, GetCode, OPCD, GD_04_0));
static auto g13_list = new_list<0x400>(main_list, PPU_opcodes::G_13, GD_13, instr_bind(&PPU_Opcodes::UNK, GetCode, OPCD, GD_13));
static auto g1e_list = new_list<0x4>(main_list, PPU_opcodes::G_1e, GD_1e, instr_bind(&PPU_Opcodes::UNK, GetCode, OPCD, GD_1e));
static auto g1f_list = new_list<0x400>(main_list, PPU_opcodes::G_1f, GD_1f, instr_bind(&PPU_Opcodes::UNK, GetCode, OPCD, GD_1f));
static auto g3a_list = new_list<0x4>(main_list, PPU_opcodes::G_3a, GD_3a, instr_bind(&PPU_Opcodes::UNK, GetCode, OPCD, GD_3a));
static auto g3b_list = new_list<0x20>(main_list, PPU_opcodes::G_3b, GD_3b, instr_bind(&PPU_Opcodes::UNK, GetCode, OPCD, GD_3b));
static auto g3e_list = new_list<0x4>(main_list, PPU_opcodes::G_3e, GD_3e, instr_bind(&PPU_Opcodes::UNK, GetCode, OPCD, GD_3e));
static auto g3f_list = new_list<0x20>(main_list, PPU_opcodes::G_3f, GD_3f);
static auto g3f_0_list = new_list<0x400>(g3f_list, GD_3f_0, instr_bind(&PPU_Opcodes::UNK, GetCode, OPCD, GD_3f_0));
#define bind_instr(list, name, ...) \
static const auto& name = make_instr<PPU_opcodes::name>(list, #name, &PPU_Opcodes::name, ##__VA_ARGS__)
bind_instr(main_list, TDI, TO, RA, simm16);
bind_instr(main_list, TWI, TO, RA, simm16);
bind_instr(main_list, MULLI, RD, RA, simm16);
bind_instr(main_list, SUBFIC, RD, RA, simm16);
bind_instr(main_list, CMPLI, CRFD, L_10, RA, uimm16);
bind_instr(main_list, CMPI, CRFD, L_10, RA, simm16);
bind_instr(main_list, ADDIC, RD, RA, simm16);
bind_instr(main_list, ADDIC_, RD, RA, simm16);
bind_instr(main_list, ADDI, RD, RA, simm16);
bind_instr(main_list, ADDIS, RD, RA, simm16);
bind_instr(main_list, BC, BO, BI, BD, AA, LK);
bind_instr(main_list, SC, SYS);
bind_instr(main_list, B, LL, AA, LK);
bind_instr(main_list, RLWIMI, RA, RS, SH, MB, ME, RC);
bind_instr(main_list, RLWINM, RA, RS, SH, MB, ME, RC);
bind_instr(main_list, RLWNM, RA, RS, RB, MB, ME, RC);
bind_instr(main_list, ORI, RA, RS, uimm16);
bind_instr(main_list, ORIS, RA, RS, uimm16);
bind_instr(main_list, XORI, RA, RS, uimm16);
bind_instr(main_list, XORIS, RA, RS, uimm16);
bind_instr(main_list, ANDI_, RA, RS, uimm16);
bind_instr(main_list, ANDIS_, RA, RS, uimm16);
bind_instr(main_list, LWZ, RD, RA, D);
bind_instr(main_list, LWZU, RD, RA, D);
bind_instr(main_list, LBZ, RD, RA, D);
bind_instr(main_list, LBZU, RD, RA, D);
bind_instr(main_list, STW, RS, RA, D);
bind_instr(main_list, STWU, RS, RA, D);
bind_instr(main_list, STB, RS, RA, D);
bind_instr(main_list, STBU, RS, RA, D);
bind_instr(main_list, LHZ, RD, RA, D);
bind_instr(main_list, LHZU, RD, RA, D);
bind_instr(main_list, STH, RS, RA, D);
bind_instr(main_list, STHU, RS, RA, D);
bind_instr(main_list, LMW, RD, RA, D);
bind_instr(main_list, STMW, RS, RA, D);
bind_instr(main_list, LFS, FRD, RA, D);
bind_instr(main_list, LFSU, FRD, RA, D);
bind_instr(main_list, LFD, FRD, RA, D);
bind_instr(main_list, LFDU, FRD, RA, D);
bind_instr(main_list, STFS, FRS, RA, D);
bind_instr(main_list, STFSU, FRS, RA, D);
bind_instr(main_list, STFD, FRS, RA, D);
bind_instr(main_list, STFDU, FRS, RA, D);
bind_instr(g04_list, VMADDFP, VD, VA, VB, VC);
bind_instr(g04_list, VMHADDSHS, VD, VA, VB, VC);
bind_instr(g04_list, VMHRADDSHS, VD, VA, VB, VC);
bind_instr(g04_list, VMLADDUHM, VD, VA, VB, VC);
bind_instr(g04_list, VMSUMMBM, VD, VA, VB, VC);
bind_instr(g04_list, VMSUMSHM, VD, VA, VB, VC);
bind_instr(g04_list, VMSUMSHS, VD, VA, VB, VC);
bind_instr(g04_list, VMSUMUBM, VD, VA, VB, VC);
bind_instr(g04_list, VMSUMUHM, VD, VA, VB, VC);
bind_instr(g04_list, VMSUMUHS, VD, VA, VB, VC);
bind_instr(g04_list, VNMSUBFP, VD, VA, VB, VC);
bind_instr(g04_list, VPERM, VD, VA, VB, VC);
bind_instr(g04_list, VSEL, VD, VA, VB, VC);
bind_instr(g04_list, VSLDOI, VD, VA, VB, VSH);
bind_instr(g04_0_list, MFVSCR, VD);
bind_instr(g04_0_list, MTVSCR, VB);
bind_instr(g04_0_list, VADDCUW, VD, VA, VB);
bind_instr(g04_0_list, VADDFP, VD, VA, VB);
bind_instr(g04_0_list, VADDSBS, VD, VA, VB);
bind_instr(g04_0_list, VADDSHS, VD, VA, VB);
bind_instr(g04_0_list, VADDSWS, VD, VA, VB);
bind_instr(g04_0_list, VADDUBM, VD, VA, VB);
bind_instr(g04_0_list, VADDUBS, VD, VA, VB);
bind_instr(g04_0_list, VADDUHM, VD, VA, VB);
bind_instr(g04_0_list, VADDUHS, VD, VA, VB);
bind_instr(g04_0_list, VADDUWM, VD, VA, VB);
bind_instr(g04_0_list, VADDUWS, VD, VA, VB);
bind_instr(g04_0_list, VAND, VD, VA, VB);
bind_instr(g04_0_list, VANDC, VD, VA, VB);
bind_instr(g04_0_list, VAVGSB, VD, VA, VB);
bind_instr(g04_0_list, VAVGSH, VD, VA, VB);
bind_instr(g04_0_list, VAVGSW, VD, VA, VB);
bind_instr(g04_0_list, VAVGUB, VD, VA, VB);
bind_instr(g04_0_list, VAVGUH, VD, VA, VB);
bind_instr(g04_0_list, VAVGUW, VD, VA, VB);
bind_instr(g04_0_list, VCFSX, VD, VUIMM, VB);
bind_instr(g04_0_list, VCFUX, VD, VUIMM, VB);
bind_instr(g04_0_list, VCMPBFP, VD, VA, VB);
bind_instr(g04_0_list, VCMPBFP_, VD, VA, VB);
bind_instr(g04_0_list, VCMPEQFP, VD, VA, VB);
bind_instr(g04_0_list, VCMPEQFP_, VD, VA, VB);
bind_instr(g04_0_list, VCMPEQUB, VD, VA, VB);
bind_instr(g04_0_list, VCMPEQUB_, VD, VA, VB);
bind_instr(g04_0_list, VCMPEQUH, VD, VA, VB);
bind_instr(g04_0_list, VCMPEQUH_, VD, VA, VB);
bind_instr(g04_0_list, VCMPEQUW, VD, VA, VB);
bind_instr(g04_0_list, VCMPEQUW_, VD, VA, VB);
bind_instr(g04_0_list, VCMPGEFP, VD, VA, VB);
bind_instr(g04_0_list, VCMPGEFP_, VD, VA, VB);
bind_instr(g04_0_list, VCMPGTFP, VD, VA, VB);
bind_instr(g04_0_list, VCMPGTFP_, VD, VA, VB);
bind_instr(g04_0_list, VCMPGTSB, VD, VA, VB);
bind_instr(g04_0_list, VCMPGTSB_, VD, VA, VB);
bind_instr(g04_0_list, VCMPGTSH, VD, VA, VB);
bind_instr(g04_0_list, VCMPGTSH_, VD, VA, VB);
bind_instr(g04_0_list, VCMPGTSW, VD, VA, VB);
bind_instr(g04_0_list, VCMPGTSW_, VD, VA, VB);
bind_instr(g04_0_list, VCMPGTUB, VD, VA, VB);
bind_instr(g04_0_list, VCMPGTUB_, VD, VA, VB);
bind_instr(g04_0_list, VCMPGTUH, VD, VA, VB);
bind_instr(g04_0_list, VCMPGTUH_, VD, VA, VB);
bind_instr(g04_0_list, VCMPGTUW, VD, VA, VB);
bind_instr(g04_0_list, VCMPGTUW_, VD, VA, VB);
bind_instr(g04_0_list, VCTSXS, VD, VUIMM, VB);
bind_instr(g04_0_list, VCTUXS, VD, VUIMM, VB);
bind_instr(g04_0_list, VEXPTEFP, VD, VB);
bind_instr(g04_0_list, VLOGEFP, VD, VB);
bind_instr(g04_0_list, VMAXFP, VD, VA, VB);
bind_instr(g04_0_list, VMAXSB, VD, VA, VB);
bind_instr(g04_0_list, VMAXSH, VD, VA, VB);
bind_instr(g04_0_list, VMAXSW, VD, VA, VB);
bind_instr(g04_0_list, VMAXUB, VD, VA, VB);
bind_instr(g04_0_list, VMAXUH, VD, VA, VB);
bind_instr(g04_0_list, VMAXUW, VD, VA, VB);
bind_instr(g04_0_list, VMINFP, VD, VA, VB);
bind_instr(g04_0_list, VMINSB, VD, VA, VB);
bind_instr(g04_0_list, VMINSH, VD, VA, VB);
bind_instr(g04_0_list, VMINSW, VD, VA, VB);
bind_instr(g04_0_list, VMINUB, VD, VA, VB);
bind_instr(g04_0_list, VMINUH, VD, VA, VB);
bind_instr(g04_0_list, VMINUW, VD, VA, VB);
bind_instr(g04_0_list, VMRGHB, VD, VA, VB);
bind_instr(g04_0_list, VMRGHH, VD, VA, VB);
bind_instr(g04_0_list, VMRGHW, VD, VA, VB);
bind_instr(g04_0_list, VMRGLB, VD, VA, VB);
bind_instr(g04_0_list, VMRGLH, VD, VA, VB);
bind_instr(g04_0_list, VMRGLW, VD, VA, VB);
bind_instr(g04_0_list, VMULESB, VD, VA, VB);
bind_instr(g04_0_list, VMULESH, VD, VA, VB);
bind_instr(g04_0_list, VMULEUB, VD, VA, VB);
bind_instr(g04_0_list, VMULEUH, VD, VA, VB);
bind_instr(g04_0_list, VMULOSB, VD, VA, VB);
bind_instr(g04_0_list, VMULOSH, VD, VA, VB);
bind_instr(g04_0_list, VMULOUB, VD, VA, VB);
bind_instr(g04_0_list, VMULOUH, VD, VA, VB);
bind_instr(g04_0_list, VNOR, VD, VA, VB);
bind_instr(g04_0_list, VOR, VD, VA, VB);
bind_instr(g04_0_list, VPKPX, VD, VA, VB);
bind_instr(g04_0_list, VPKSHSS, VD, VA, VB);
bind_instr(g04_0_list, VPKSHUS, VD, VA, VB);
bind_instr(g04_0_list, VPKSWSS, VD, VA, VB);
bind_instr(g04_0_list, VPKSWUS, VD, VA, VB);
bind_instr(g04_0_list, VPKUHUM, VD, VA, VB);
bind_instr(g04_0_list, VPKUHUS, VD, VA, VB);
bind_instr(g04_0_list, VPKUWUM, VD, VA, VB);
bind_instr(g04_0_list, VPKUWUS, VD, VA, VB);
bind_instr(g04_0_list, VREFP, VD, VB);
bind_instr(g04_0_list, VRFIM, VD, VB);
bind_instr(g04_0_list, VRFIN, VD, VB);
bind_instr(g04_0_list, VRFIP, VD, VB);
bind_instr(g04_0_list, VRFIZ, VD, VB);
bind_instr(g04_0_list, VRLB, VD, VA, VB);
bind_instr(g04_0_list, VRLH, VD, VA, VB);
bind_instr(g04_0_list, VRLW, VD, VA, VB);
bind_instr(g04_0_list, VRSQRTEFP, VD, VB);
bind_instr(g04_0_list, VSL, VD, VA, VB);
bind_instr(g04_0_list, VSLB, VD, VA, VB);
bind_instr(g04_0_list, VSLH, VD, VA, VB);
bind_instr(g04_0_list, VSLO, VD, VA, VB);
bind_instr(g04_0_list, VSLW, VD, VA, VB);
bind_instr(g04_0_list, VSPLTB, VD, VUIMM, VB);
bind_instr(g04_0_list, VSPLTH, VD, VUIMM, VB);
bind_instr(g04_0_list, VSPLTISB, VD, VSIMM);
bind_instr(g04_0_list, VSPLTISH, VD, VSIMM);
bind_instr(g04_0_list, VSPLTISW, VD, VSIMM);
bind_instr(g04_0_list, VSPLTW, VD, VUIMM, VB);
bind_instr(g04_0_list, VSR, VD, VA, VB);
bind_instr(g04_0_list, VSRAB, VD, VA, VB);
bind_instr(g04_0_list, VSRAH, VD, VA, VB);
bind_instr(g04_0_list, VSRAW, VD, VA, VB);
bind_instr(g04_0_list, VSRB, VD, VA, VB);
bind_instr(g04_0_list, VSRH, VD, VA, VB);
bind_instr(g04_0_list, VSRO, VD, VA, VB);
bind_instr(g04_0_list, VSRW, VD, VA, VB);
bind_instr(g04_0_list, VSUBCUW, VD, VA, VB);
bind_instr(g04_0_list, VSUBFP, VD, VA, VB);
bind_instr(g04_0_list, VSUBSBS, VD, VA, VB);
bind_instr(g04_0_list, VSUBSHS, VD, VA, VB);
bind_instr(g04_0_list, VSUBSWS, VD, VA, VB);
bind_instr(g04_0_list, VSUBUBM, VD, VA, VB);
bind_instr(g04_0_list, VSUBUBS, VD, VA, VB);
bind_instr(g04_0_list, VSUBUHM, VD, VA, VB);
bind_instr(g04_0_list, VSUBUHS, VD, VA, VB);
bind_instr(g04_0_list, VSUBUWM, VD, VA, VB);
bind_instr(g04_0_list, VSUBUWS, VD, VA, VB);
bind_instr(g04_0_list, VSUMSWS, VD, VA, VB);
bind_instr(g04_0_list, VSUM2SWS, VD, VA, VB);
bind_instr(g04_0_list, VSUM4SBS, VD, VA, VB);
bind_instr(g04_0_list, VSUM4SHS, VD, VA, VB);
bind_instr(g04_0_list, VSUM4UBS, VD, VA, VB);
bind_instr(g04_0_list, VUPKHPX, VD, VB);
bind_instr(g04_0_list, VUPKHSB, VD, VB);
bind_instr(g04_0_list, VUPKHSH, VD, VB);
bind_instr(g04_0_list, VUPKLPX, VD, VB);
bind_instr(g04_0_list, VUPKLSB, VD, VB);
bind_instr(g04_0_list, VUPKLSH, VD, VB);
bind_instr(g04_0_list, VXOR, VD, VA, VB);
bind_instr(g13_list, MCRF, CRFD, CRFS);
bind_instr(g13_list, BCLR, BO, BI, BH, LK);
bind_instr(g13_list, CRNOR, CRBD, CRBA, CRBB);
bind_instr(g13_list, CRANDC, CRBD, CRBA, CRBB);
bind_instr(g13_list, ISYNC);
bind_instr(g13_list, CRXOR, CRBD, CRBA, CRBB);
bind_instr(g13_list, CRNAND, CRBD, CRBA, CRBB);
bind_instr(g13_list, CRAND, CRBD, CRBA, CRBB);
bind_instr(g13_list, CREQV, CRBD, CRBA, CRBB);
bind_instr(g13_list, CRORC, CRBD, CRBA, CRBB);
bind_instr(g13_list, CROR, CRBD, CRBA, CRBB);
bind_instr(g13_list, BCCTR, BO, BI, BH, LK);
bind_instr(g1e_list, RLDICL, RA, RS, sh, mb, RC);
bind_instr(g1e_list, RLDICR, RA, RS, sh, me, RC);
bind_instr(g1e_list, RLDIC, RA, RS, sh, mb, RC);
bind_instr(g1e_list, RLDIMI, RA, RS, sh, mb, RC);
/*0x000*/bind_instr(g1f_list, CMP, CRFD, L_10, RA, RB);
/*0x004*/bind_instr(g1f_list, TW, TO, RA, RB);
/*0x006*/bind_instr(g1f_list, LVSL, VD, RA, RB);
/*0x007*/bind_instr(g1f_list, LVEBX, VD, RA, RB);
/*0x008*/bind_instr(g1f_list, SUBFC, RD, RA, RB, OE, RC);
/*0x009*/bind_instr(g1f_list, MULHDU, RD, RA, RB, RC);
/*0x00a*/bind_instr(g1f_list, ADDC, RD, RA, RB, OE, RC);
/*0x00b*/bind_instr(g1f_list, MULHWU, RD, RA, RB, RC);
/*0x013*/bind_instr(g1f_list, MFOCRF, L_11, RD, CRM);
/*0x014*/bind_instr(g1f_list, LWARX, RD, RA, RB);
/*0x015*/bind_instr(g1f_list, LDX, RA, RS, RB);
/*0x017*/bind_instr(g1f_list, LWZX, RD, RA, RB);
/*0x018*/bind_instr(g1f_list, SLW, RA, RS, RB, RC);
/*0x01a*/bind_instr(g1f_list, CNTLZW, RA, RS, RC);
/*0x01b*/bind_instr(g1f_list, SLD, RA, RS, RB, RC);
/*0x01c*/bind_instr(g1f_list, AND, RA, RS, RB, RC);
/*0x020*/bind_instr(g1f_list, CMPL, CRFD, L_10, RA, RB);
/*0x026*/bind_instr(g1f_list, LVSR, VD, RA, RB);
/*0x027*/bind_instr(g1f_list, LVEHX, VD, RA, RB);
/*0x028*/bind_instr(g1f_list, SUBF, RD, RA, RB, OE, RC);
/*0x036*/bind_instr(g1f_list, DCBST, RA, RB);
/*0x03a*/bind_instr(g1f_list, CNTLZD, RA, RS, RC);
/*0x03c*/bind_instr(g1f_list, ANDC, RA, RS, RB, RC);
/*0x047*/bind_instr(g1f_list, LVEWX, VD, RA, RB);
/*0x049*/bind_instr(g1f_list, MULHD, RD, RA, RB, RC);
/*0x04b*/bind_instr(g1f_list, MULHW, RD, RA, RB, RC);
/*0x054*/bind_instr(g1f_list, LDARX, RD, RA, RB);
/*0x056*/bind_instr(g1f_list, DCBF, RA, RB);
/*0x057*/bind_instr(g1f_list, LBZX, RD, RA, RB);
/*0x067*/bind_instr(g1f_list, LVX, VD, RA, RB);
/*0x068*/bind_instr(g1f_list, NEG, RD, RA, OE, RC);
/*0x077*/bind_instr(g1f_list, LBZUX, RD, RA, RB);
/*0x07c*/bind_instr(g1f_list, NOR, RA, RS, RB, RC);
/*0x087*/bind_instr(g1f_list, STVEBX, VS, RA, RB);
/*0x088*/bind_instr(g1f_list, SUBFE, RD, RA, RB, OE, RC);
/*0x08a*/bind_instr(g1f_list, ADDE, RD, RA, RB, OE, RC);
/*0x090*/bind_instr(g1f_list, MTOCRF, CRM, RS);
/*0x095*/bind_instr(g1f_list, STDX, RS, RA, RB);
/*0x096*/bind_instr(g1f_list, STWCX_, RS, RA, RB);
/*0x097*/bind_instr(g1f_list, STWX, RS, RA, RB);
/*0x0a7*/bind_instr(g1f_list, STVEHX, VS, RA, RB);
/*0x0b5*/bind_instr(g1f_list, STDUX, RS, RA, RB);
/*0x0c7*/bind_instr(g1f_list, STVEWX, VS, RA, RB);
/*0x0ca*/bind_instr(g1f_list, ADDZE, RD, RA, OE, RC);
/*0x0d6*/bind_instr(g1f_list, STDCX_, RS, RA, RB);
/*0x0d7*/bind_instr(g1f_list, STBX, RS, RA, RB);
/*0x0e7*/bind_instr(g1f_list, STVX, VS, RA, RB);
/*0x0e9*/bind_instr(g1f_list, MULLD, RD, RA, RB, OE, RC);
/*0x0ea*/bind_instr(g1f_list, ADDME, RD, RA, OE, RC);
/*0x0eb*/bind_instr(g1f_list, MULLW, RD, RA, RB, OE, RC);
/*0x0f6*/bind_instr(g1f_list, DCBTST, TH, RA, RB);
/*0x10a*/bind_instr(g1f_list, ADD, RD, RA, RB, OE, RC);
/*0x116*/bind_instr(g1f_list, DCBT, RA, RB, TH);
/*0x117*/bind_instr(g1f_list, LHZX, RD, RA, RB);
/*0x11c*/bind_instr(g1f_list, EQV, RA, RS, RB, RC);
/*0x136*/bind_instr(g1f_list, ECIWX, RD, RA, RB);
/*0x137*/bind_instr(g1f_list, LHZUX, RD, RA, RB);
/*0x13c*/bind_instr(g1f_list, XOR, RA, RS, RB, RC);
/*0x153*/bind_instr(g1f_list, MFSPR, RD, SPR);
/*0x156*/bind_instr(g1f_list, DST, RA, RB, STRM, L_6);
/*0x157*/bind_instr(g1f_list, LHAX, RD, RA, RB);
/*0x167*/bind_instr(g1f_list, LVXL, VD, RA, RB);
/*0x168*/bind_instr(g1f_list, ABS, RD, RA, OE, RC);
/*0x173*/bind_instr(g1f_list, MFTB, RD, SPR);
/*0x176*/bind_instr(g1f_list, DSTST, RA, RB, STRM, L_6);
/*0x177*/bind_instr(g1f_list, LHAUX, RD, RA, RB);
/*0x197*/bind_instr(g1f_list, STHX, RS, RA, RB);
/*0x19c*/bind_instr(g1f_list, ORC, RA, RS, RB, RC);
/*0x1b6*/bind_instr(g1f_list, ECOWX, RS, RA, RB);
/*0x1bc*/bind_instr(g1f_list, OR, RA, RS, RB, RC);
/*0x1c9*/bind_instr(g1f_list, DIVDU, RD, RA, RB, OE, RC);
/*0x1cb*/bind_instr(g1f_list, DIVWU, RD, RA, RB, OE, RC);
/*0x1d3*/bind_instr(g1f_list, MTSPR, SPR, RS);
/*0x1d6*///DCBI
/*0x1dc*/bind_instr(g1f_list, NAND, RA, RS, RB, RC);
/*0x1e7*/bind_instr(g1f_list, STVXL, RS, RA, RB);
/*0x1e9*/bind_instr(g1f_list, DIVD, RD, RA, RB, OE, RC);
/*0x1eb*/bind_instr(g1f_list, DIVW, RD, RA, RB, OE, RC);
/*0x207*/bind_instr(g1f_list, LVLX, VD, RA, RB);
/*0x216*/bind_instr(g1f_list, LWBRX, RD, RA, RB);
/*0x217*/bind_instr(g1f_list, LFSX, FRD, RA, RB);
/*0x218*/bind_instr(g1f_list, SRW, RA, RS, RB, RC);
/*0x21b*/bind_instr(g1f_list, SRD, RA, RS, RB, RC);
/*0x227*/bind_instr(g1f_list, LVRX, VD, RA, RB);
/*0x237*/bind_instr(g1f_list, LFSUX, FRD, RA, RB);
/*0x256*/bind_instr(g1f_list, SYNC, L_9_10);
/*0x257*/bind_instr(g1f_list, LFDX, FRD, RA, RB);
/*0x277*/bind_instr(g1f_list, LFDUX, FRD, RA, RB);
/*0x287*/bind_instr(g1f_list, STVLX, VS, RA, RB);
/*0x297*/bind_instr(g1f_list, STFSX, RS, RA, RB);
/*0x2a7*/bind_instr(g1f_list, STVRX, VS, RA, RB);
/*0x2d7*/bind_instr(g1f_list, STFDX, RS, RA, RB);
/*0x307*/bind_instr(g1f_list, LVLXL, VD, RA, RB);
/*0x316*/bind_instr(g1f_list, LHBRX, RD, RA, RB);
/*0x318*/bind_instr(g1f_list, SRAW, RA, RS, RB, RC);
/*0x31a*/bind_instr(g1f_list, SRAD, RA, RS, RB, RC);
/*0x327*/bind_instr(g1f_list, LVRXL, VD, RA, RB);
/*0x336*/bind_instr(g1f_list, DSS, STRM, L_6);
/*0x338*/bind_instr(g1f_list, SRAWI, RA, RS, sh, RC);
/*0x33a*/bind_instr(g1f_list, SRADI1, RA, RS, sh, RC);
/*0x33b*/bind_instr(g1f_list, SRADI2, RA, RS, sh, RC);
/*0x356*/bind_instr(g1f_list, EIEIO);
/*0x39a*/bind_instr(g1f_list, EXTSH, RA, RS, RC);
/*0x3ba*/bind_instr(g1f_list, EXTSB, RA, RS, RC);
/*0x3d7*/bind_instr(g1f_list, STFIWX, FRS, RA, RB);
/*0x3da*/bind_instr(g1f_list, EXTSW, RA, RS, RC);
/*0x3d6*///ICBI
/*0x3f6*/bind_instr(g1f_list, DCBZ, RA, RB);
bind_instr(g3a_list, LD, RD, RA, D);
bind_instr(g3a_list, LDU, RD, RA, DS);
bind_instr(g3b_list, FDIVS, FRD, FRA, FRB, RC);
bind_instr(g3b_list, FSUBS, FRD, FRA, FRB, RC);
bind_instr(g3b_list, FADDS, FRD, FRA, FRB, RC);
bind_instr(g3b_list, FSQRTS, FRD, FRB, RC);
bind_instr(g3b_list, FRES, FRD, FRB, RC);
bind_instr(g3b_list, FMULS, FRD, FRA, FRC, RC);
bind_instr(g3b_list, FMADDS, FRD, FRA, FRC, FRB, RC);
bind_instr(g3b_list, FMSUBS, FRD, FRA, FRC, FRB, RC);
bind_instr(g3b_list, FNMSUBS, FRD, FRA, FRC, FRB, RC);
bind_instr(g3b_list, FNMADDS, FRD, FRA, FRC, FRB, RC);
bind_instr(g3e_list, STD, RS, RA, D);
bind_instr(g3e_list, STDU, RS, RA, DS);
bind_instr(g3f_list, FSEL, FRD, FRA, FRC, FRB, RC);
bind_instr(g3f_list, FMUL, FRD, FRA, FRC, RC);
bind_instr(g3f_list, FMSUB, FRD, FRA, FRC, FRB, RC);
bind_instr(g3f_list, FMADD, FRD, FRA, FRC, FRB, RC);
bind_instr(g3f_list, FNMSUB, FRD, FRA, FRC, FRB, RC);
bind_instr(g3f_list, FNMADD, FRD, FRA, FRC, FRB, RC);
bind_instr(g3f_0_list, FDIV, FRD, FRA, FRB, RC);
bind_instr(g3f_0_list, FSUB, FRD, FRA, FRB, RC);
bind_instr(g3f_0_list, FADD, FRD, FRA, FRB, RC);
bind_instr(g3f_0_list, FSQRT, FRD, FRB, RC);
bind_instr(g3f_0_list, FRSQRTE, FRD, FRB, RC);
bind_instr(g3f_0_list, FCMPU, CRFD, FRA, FRB);
bind_instr(g3f_0_list, FRSP, FRD, FRB, RC);
bind_instr(g3f_0_list, FCTIW, FRD, FRB, RC);
bind_instr(g3f_0_list, FCTIWZ, FRD, FRB, RC);
bind_instr(g3f_0_list, FCMPO, CRFD, FRA, FRB);
bind_instr(g3f_0_list, FNEG, FRD, FRB, RC);
bind_instr(g3f_0_list, FMR, FRD, FRB, RC);
bind_instr(g3f_0_list, FNABS, FRD, FRB, RC);
bind_instr(g3f_0_list, FABS, FRD, FRB, RC);
bind_instr(g3f_0_list, FCFID, FRD, FRB, RC);
bind_instr(g3f_0_list, FCTID, FRD, FRB, RC);
bind_instr(g3f_0_list, FCTIDZ, FRD, FRB, RC);
bind_instr(g3f_0_list, MTFSB1, BT, RC);
bind_instr(g3f_0_list, MCRFS, BF, BFA);
bind_instr(g3f_0_list, MTFSB0, BT, RC);
bind_instr(g3f_0_list, MTFSFI, CRFD, I, RC);
bind_instr(g3f_0_list, MFFS, FRD, RC);
bind_instr(g3f_0_list, MTFSF, FLM, FRB, RC);
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,192 @@
#pragma once
#include "PPUInstrTable.h"
#include "Loader/ELF64.h"
enum ArgType
{
ARG_ERR = 0,
ARG_NUM = 1 << 0,
ARG_NUM16 = 1 << 1,
ARG_TXT = 1 << 2,
ARG_REG_R = 1 << 3,
ARG_REG_F = 1 << 4,
ARG_REG_V = 1 << 5,
ARG_REG_CR = 1 << 6,
ARG_BRANCH = 1 << 7,
ARG_INSTR = 1 << 8,
ARG_IMM = ARG_NUM | ARG_NUM16 | ARG_BRANCH,
};
struct Arg
{
wxString string;
u32 value;
ArgType type;
Arg(const wxString& _string, const u32 _value = 0, const ArgType _type = ARG_ERR)
: string(_string)
, value(_value)
, type(_type)
{
}
};
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 CompilePPUProgram
{
struct Branch
{
wxString m_name;
s32 m_pos;
s32 m_id;
s32 m_addr;
Branch(const wxString& name, s32 pos)
: m_name(name)
, m_pos(pos)
, m_id(-1)
, m_addr(-1)
{
}
Branch(const wxString& name, u32 id, u32 addr)
: m_name(name)
, m_pos(-1)
, m_id(id)
, m_addr(addr)
{
}
};
bool m_analyze;
s64 p;
u64 m_line;
const wxString& m_asm;
wxTextCtrl* m_asm_list;
wxTextCtrl* m_hex_list;
wxTextCtrl* m_err_list;
bool m_error;
Array<u32> m_code;
bool m_end_args;
Array<Branch> m_branches;
s32 m_branch_pos;
u32 m_text_addr;
wxString m_file_path;
struct SpData
{
wxString m_data;
u32 m_addr;
SpData(const wxString& data, u32 addr)
: m_data(data)
, m_addr(addr)
{
}
};
Array<SpData> m_sp_string;
Array<Arg> m_args;
u32 m_cur_arg;
public:
CompilePPUProgram(
const wxString& asm_,
const wxString& file_path = wxEmptyString,
wxTextCtrl* asm_list = nullptr,
wxTextCtrl* hex_list = nullptr,
wxTextCtrl* err_list = nullptr,
bool analyze = false);
static bool IsSkip(const char c);
static bool IsCommit(const char c);
protected:
bool IsEnd() const;
bool IsEndLn(const char c) const;
void WriteHex(const wxString& text);
void WriteError(const wxString& error);
char NextChar();
void NextLn();
void EndLn();
void FirstChar();
void PrevArg();
bool GetOp(wxString& result);
int GetArg(wxString& result, bool func = false);
bool CheckEnd(bool show_err = true);
void DetectArgInfo(Arg& arg);
void LoadArgs();
u32 GetBranchValue(const wxString& branch);
bool SetNextArgType(u32 types, bool show_err = true);
bool SetNextArgBranch(u8 aa, bool show_err = true);
public:
static bool IsBranchOp(const wxString& op);
static bool IsFuncOp(const wxString& op);
enum SP_TYPE
{
SP_ERR,
SP_INT,
SP_STRING,
SP_STRLEN,
SP_BUF,
SP_SRL,
SP_SRR,
SP_MUL,
SP_DIV,
SP_ADD,
SP_SUB,
SP_AND,
SP_OR,
SP_XOR,
SP_NOT,
SP_NOR,
};
static SP_TYPE GetSpType(const wxString& op);
static wxString GetSpStyle(const SP_TYPE sp);
static bool IsSpOp(const wxString& op);
protected:
Branch& GetBranch(const wxString& name);
void SetSp(const wxString& name, u32 addr, bool create);
void LoadSp(const wxString& op, Elf64_Shdr& s_opd);
public:
void Compile();
};

View File

@ -1,7 +1,7 @@
#pragma once
#include "Emu/Cell/SPUOpcodes.h"
#include "Emu/Cell/Decoder.h"
#include "Emu/Cell/PPCDecoder.h"
#define START_OPCODES_GROUP_(group, reg) \
case(##group##): \
@ -21,7 +21,7 @@
#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
class SPU_Decoder : public PPC_Decoder
{
u32 m_code;
SPU_Opcodes& m_op;

View File

@ -1,7 +1,7 @@
#pragma once
#include "Emu/Cell/SPUOpcodes.h"
#include "Emu/Cell/DisAsm.h"
#include "Emu/Cell/PPCDisAsm.h"
#include "Emu/Cell/SPUThread.h"
#include "Gui/DisAsmFrame.h"
#include "Emu/Memory/Memory.h"
@ -11,19 +11,19 @@
class SPU_DisAsm
: public SPU_Opcodes
, public DisAsm
, public PPC_DisAsm
{
public:
PPCThread& CPU;
SPU_DisAsm()
: DisAsm(*(PPCThread*)NULL, DumpMode)
: PPC_DisAsm(*(PPCThread*)NULL, DumpMode)
, CPU(*(PPCThread*)NULL)
{
}
SPU_DisAsm(PPCThread& cpu, DisAsmModes mode = NormalMode)
: DisAsm(cpu, mode)
: PPC_DisAsm(cpu, mode)
, CPU(cpu)
{
}

View File

@ -1233,7 +1233,7 @@ void GLGSRender::ExecCMD()
if(m_set_viewport_horizontal && m_set_viewport_vertical)
{
glViewport(m_viewport_x, m_viewport_y, m_viewport_w, m_viewport_h);
if(m_frame->GetSize() != wxSize(m_viewport_w, m_viewport_h))
if(m_frame->GetClientSize() != wxSize(m_viewport_w, m_viewport_h))
m_frame->SetClientSize(m_viewport_w, m_viewport_h);
//m_frame->SetViewport(m_viewport_x, m_viewport_y, m_viewport_w, m_viewport_h);
}

View File

@ -188,7 +188,7 @@ int cellSysutilRegisterCallback(int slot, u64 func_addr, u64 userdata)
sc_sysutil.Warning("cellSysutilRegisterCallback(slot=%d, func_addr=0x%llx, userdata=0x%llx)", slot, func_addr, userdata);
Emu.GetCallbackManager().m_exit_callback.Register(slot, func_addr, userdata);
wxGetApp().m_MainFrame->UpdateUI();
wxGetApp().SendDbgCommand(DID_REGISTRED_CALLBACK);
return CELL_OK;
}
@ -198,7 +198,7 @@ int cellSysutilUnregisterCallback(int slot)
sc_sysutil.Warning("cellSysutilUnregisterCallback(slot=%d)", slot);
Emu.GetCallbackManager().m_exit_callback.Unregister(slot);
wxGetApp().m_MainFrame->UpdateUI();
wxGetApp().SendDbgCommand(DID_UNREGISTRED_CALLBACK);
return CELL_OK;
}

View File

@ -6,9 +6,11 @@
#include "Emu/Cell/PPCThreadManager.h"
#include "Emu/Cell/PPUThread.h"
#include "Emu/Cell/SPUThread.h"
#include "Gui/CompilerELF.h"
#include "Emu/Cell/PPUInstrTable.h"
using namespace PPU_instr;
using namespace PPU_opcodes;
static const wxString& BreakPointsDBName = "BreakPoints.dat";
static const u16 bpdb_version = 0x1000;
//SysCalls SysCallsManager;
@ -26,16 +28,9 @@ void Emulator::Init()
//m_memory_viewer = new MemoryViewerPanel(wxGetApp().m_MainFrame);
}
void Emulator::SetSelf(const wxString& path)
void Emulator::SetPath(const wxString& path)
{
m_path = path;
IsSelf = true;
}
void Emulator::SetElf(const wxString& path)
{
m_path = path;
IsSelf = false;
}
void Emulator::CheckStatus()
@ -110,6 +105,7 @@ void Emulator::Load()
return;
}
LoadPoints(BreakPointsDBName);
PPCThread& thread = GetCPU().AddThread(l.GetMachine() == MACHINE_PPC64);
thread.SetEntry(l.GetEntry());
@ -123,22 +119,22 @@ void Emulator::Load()
Memory.Write32(m_rsx_callback - 4, m_rsx_callback);
mem32_t callback_data(m_rsx_callback);
callback_data += ToOpcode(ADDI) | ToRD(11) | ToRA(0) | ToIMM16(0x3ff);
callback_data += ToOpcode(SC) | ToSYS(2);
callback_data += ToOpcode(G_13) | SetField(BCLR, 21, 30) | ToBO(0x10 | 0x04) | ToBI(0) | ToLK(0);
callback_data += ADDI(11, 0, 0x3ff);
callback_data += SC(2);
callback_data += BCLR(0x10 | 0x04, 0, 0, 0);
m_ppu_thr_exit = Memory.MainMem.Alloc(4 * 3);
mem32_t ppu_thr_exit_data(m_ppu_thr_exit);
ppu_thr_exit_data += ToOpcode(ADDI) | ToRD(11) | ToRA(0) | ToIMM16(41);
ppu_thr_exit_data += ToOpcode(SC) | ToSYS(2);
ppu_thr_exit_data += ToOpcode(G_13) | SetField(BCLR, 21, 30) | ToBO(0x10 | 0x04) | ToBI(0) | ToLK(0);
ppu_thr_exit_data += ADDI(11, 0, 41);
ppu_thr_exit_data += SC(2);
ppu_thr_exit_data += BCLR(0x10 | 0x04, 0, 0, 0);
thread.Run();
wxGetApp().m_MainFrame->UpdateUI();
wxCriticalSectionLocker lock(m_cs_status);
m_status = Ready;
wxGetApp().SendDbgCommand(DID_READY_EMU);
}
void Emulator::Run()
@ -156,6 +152,8 @@ void Emulator::Run()
return;
}
wxGetApp().SendDbgCommand(DID_START_EMU);
wxCriticalSectionLocker lock(m_cs_status);
//ConLog.Write("run...");
m_status = Runned;
@ -165,7 +163,13 @@ void Emulator::Run()
m_vfs.Mount("/app_home/", vfsDevice::GetRoot(m_path), new vfsLocalFile());
m_vfs.Mount(vfsDevice::GetRootPs3(m_path), vfsDevice::GetRoot(m_path), new vfsLocalFile());
for(uint i=0; i<m_vfs.m_devices.GetCount(); ++i) ConLog.Write("%s -> %s", m_vfs.m_devices[i].GetPs3Path(), m_vfs.m_devices[i].GetLocalPath());
ConLog.SkipLn();
ConLog.Write("Mount info:");
for(uint i=0; i<m_vfs.m_devices.GetCount(); ++i)
{
ConLog.Write("%s -> %s", m_vfs.m_devices[i].GetPs3Path(), m_vfs.m_devices[i].GetLocalPath());
}
ConLog.SkipLn();
//if(m_memory_viewer && m_memory_viewer->exit) safe_delete(m_memory_viewer);
@ -173,54 +177,57 @@ void Emulator::Run()
//m_memory_viewer->Show();
//m_memory_viewer->ShowPC();
wxGetApp().SendDbgCommand(DID_START_EMU);
wxGetApp().m_MainFrame->UpdateUI();
if(!m_dbg_console) m_dbg_console = new DbgConsole();
if(!m_dbg_console)
m_dbg_console = new DbgConsole();
GetGSManager().Init();
GetCallbackManager().Init();
GetCPU().Exec();
wxGetApp().SendDbgCommand(DID_STARTED_EMU);
}
void Emulator::Pause()
{
if(!IsRunned()) return;
//ConLog.Write("pause...");
wxGetApp().SendDbgCommand(DID_PAUSE_EMU);
wxCriticalSectionLocker lock(m_cs_status);
m_status = Paused;
wxGetApp().SendDbgCommand(DID_PAUSE_EMU);
wxGetApp().m_MainFrame->UpdateUI();
wxGetApp().SendDbgCommand(DID_PAUSED_EMU);
}
void Emulator::Resume()
{
if(!IsPaused()) return;
//ConLog.Write("resume...");
wxGetApp().SendDbgCommand(DID_RESUME_EMU);
wxCriticalSectionLocker lock(m_cs_status);
m_status = Runned;
wxGetApp().SendDbgCommand(DID_RESUME_EMU);
wxGetApp().m_MainFrame->UpdateUI();
CheckStatus();
if(IsRunned() && Ini.CPUDecoderMode.GetValue() != 1) GetCPU().Exec();
wxGetApp().SendDbgCommand(DID_RESUMED_EMU);
}
void Emulator::Stop()
{
if(IsStopped()) return;
//ConLog.Write("shutdown...");
wxGetApp().SendDbgCommand(DID_STOP_EMU);
{
wxCriticalSectionLocker lock(m_cs_status);
m_status = Stopped;
}
m_rsx_callback = 0;
wxGetApp().SendDbgCommand(DID_STOP_EMU);
wxGetApp().m_MainFrame->UpdateUI();
SavePoints(BreakPointsDBName);
m_break_points.Clear();
m_marked_points.Clear();
GetGSManager().Close();
GetCPU().Close();
@ -238,7 +245,63 @@ void Emulator::Stop()
GetDbgCon().Close();
GetDbgCon().Clear();
}
//if(m_memory_viewer && m_memory_viewer->IsShown()) m_memory_viewer->Hide();
wxGetApp().SendDbgCommand(DID_STOPED_EMU);
}
void Emulator::SavePoints(const wxString& path)
{
wxFile f(path, wxFile::write);
u32 break_count = m_break_points.GetCount();
u32 marked_count = m_marked_points.GetCount();
f.Write(&bpdb_version, sizeof(u16));
f.Write(&break_count, sizeof(u32));
f.Write(&marked_count, sizeof(u32));
if(break_count)
{
f.Write(&m_break_points[0], sizeof(u64) * break_count);
}
if(marked_count)
{
f.Write(&m_marked_points[0], sizeof(u64) * marked_count);
}
}
void Emulator::LoadPoints(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);
f.Read(&m_break_points[0], sizeof(u64) * break_count);
}
if(marked_count > 0)
{
m_marked_points.SetCount(marked_count);
f.Read(&m_marked_points[0], sizeof(u64) * marked_count);
}
}
Emulator Emu;

View File

@ -63,6 +63,9 @@ class Emulator
MemoryViewerPanel* m_memory_viewer;
//ArrayF<CPUThread> m_cpu_threads;
Array<u64> m_break_points;
Array<u64> m_marked_points;
PPCThreadManager m_thread_manager;
PadManager m_pad_manager;
IdManager m_id_manager;
@ -75,13 +78,11 @@ class Emulator
public:
wxString m_path;
bool IsSelf;
Emulator();
void Init();
void SetSelf(const wxString& path);
void SetElf(const wxString& path);
void SetPath(const wxString& path);
PPCThreadManager& GetCPU() { return m_thread_manager; }
PadManager& GetPadManager() { return m_pad_manager; }
@ -90,6 +91,8 @@ public:
GSManager& GetGSManager() { return m_gs_manager; }
CallbackManager& GetCallbackManager() { return m_callback_manager; }
VFS& GetVFS() { return m_vfs; }
Array<u64>& GetBreakPoints() { return m_break_points; }
Array<u64>& GetMarkedPoints() { return m_marked_points; }
void SetTLSData(const u64 addr, const u64 filesz, const u64 memsz)
{
@ -115,6 +118,9 @@ public:
void Resume();
void Stop();
void SavePoints(const wxString& path);
void LoadPoints(const wxString& path);
__forceinline bool IsRunned() const { wxCriticalSectionLocker lock(m_cs_status); return m_status == Runned; }
__forceinline bool IsPaused() const { wxCriticalSectionLocker lock(m_cs_status); return m_status == Paused; }
__forceinline bool IsStopped() const { wxCriticalSectionLocker lock(m_cs_status); return m_status == Stopped; }

File diff suppressed because it is too large Load Diff

View File

@ -5,38 +5,6 @@
#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;
@ -78,42 +46,3 @@ public:
void UpdateStatus(int offset=0);
};
static u32 SetField(u32 src, u32 from, u32 to)
{
return (src & ((1 << ((to - from) + 1)) - 1)) << (31 - to);
}
static u32 SetField(s32 src, u32 p)
{
return (src & 0x1) << (31 - p);
}
static u32 ToOpcode(u32 i) { return SetField(i, 0, 5); }
static u32 ToRS(u32 i) { return SetField(i, 6, 10); }
static u32 ToRD(u32 i) { return SetField(i, 6, 10); }
static u32 ToRA(u32 i) { return SetField(i, 11, 15); }
static u32 ToRB(u32 i) { return SetField(i, 16, 20); }
static u32 ToLL(u32 i) { return i & 0x03fffffc; }
static u32 ToAA(u32 i) { return SetField(i, 30); }
static u32 ToLK(u32 i) { return SetField(i, 31); }
static u32 ToIMM16(s32 i) { return SetField(i, 16, 31); }
static u32 ToD(s32 i) { return SetField(i, 16, 31); }
static u32 ToDS(s32 i)
{
if(i < 0) return ToD(i + 1);
return ToD(i);
}
static u32 ToSYS(u32 i) { return SetField(i, 6, 31); }
static u32 ToBF(u32 i) { return SetField(i, 6, 10); }
static u32 ToBO(u32 i) { return SetField(i, 6, 10); }
static u32 ToBI(u32 i) { return SetField(i, 11, 15); }
static u32 ToBD(u32 i) { return i & 0xfffc; }
static u32 ToMB(u32 i) { return SetField(i, 21, 25); }
static u32 ToME(u32 i) { return SetField(i, 26, 30); }
static u32 ToSH(u32 i) { return SetField(i, 16, 20); }
static u32 ToRC(u32 i) { return SetField(i, 31); }
static u32 ToOE(u32 i) { return SetField(i, 21); }
static u32 ToL(u32 i) { return SetField(i, 10); }
static u32 ToCRFD(u32 i) { return SetField(i, 6, 8); }
static u32 ToTO(u32 i) { return SetField(i, 6, 10); }

View File

@ -113,8 +113,8 @@ bool ElfType64 = false;
class DumperThread : public ThreadBase
{
volatile uint id;
DisAsm* disasm;
Decoder* decoder;
PPC_DisAsm* disasm;
PPC_Decoder* decoder;
volatile bool* done;
volatile u8 cores;
MTProgressDialog* prog_dial;
@ -338,8 +338,8 @@ void DisAsmFrame::Dump(wxCommandEvent& WXUNUSED(event))
default: ConLog.Error("Corrupted ELF!"); return;
}
DisAsm* disasm;
Decoder* decoder;
PPC_DisAsm* disasm;
PPC_Decoder* decoder;
if(Emu.GetCPU().GetThreads()[0].IsSPU())
{

View File

@ -99,6 +99,6 @@ void GameViewer::DClick(wxListEvent& event)
}
Emu.Stop();
Emu.SetElf(path);
Emu.SetPath(path);
Emu.Run();
}

View File

@ -2,8 +2,6 @@
#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)
{
@ -85,73 +83,11 @@ InterpreterDisAsmFrame::InterpreterDisAsmFrame(wxWindow* parent, PPCThread* cpu)
m_app_connector.Connect(wxEVT_DBG_COMMAND, wxCommandEventHandler(InterpreterDisAsmFrame::HandleCommand), (wxObject*)0, this);
WriteRegs();
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)
@ -224,9 +160,9 @@ void InterpreterDisAsmFrame::ShowAddr(const u64 addr)
{
colour = wxColour("White");
for(u32 i=0; i<markedPC.GetCount(); ++i)
for(u32 i=0; i<Emu.GetMarkedPoints().GetCount(); ++i)
{
if(markedPC[i] == PC)
if(Emu.GetMarkedPoints()[i] == PC)
{
colour = wxColour("Wheat");
break;
@ -252,7 +188,7 @@ void InterpreterDisAsmFrame::ShowAddr(const u64 addr)
if(remove_markedPC[i] > mpc) remove_markedPC[i]--;
}
markedPC.RemoveAt(mpc);
Emu.GetMarkedPoints().RemoveAt(mpc);
}
m_list->SetColumnWidth(0, -1);
@ -272,35 +208,52 @@ void InterpreterDisAsmFrame::HandleCommand(wxCommandEvent& event)
PPCThread* thr = (PPCThread*)event.GetClientData();
event.Skip();
if(!thr || thr->GetId() != CPU.GetId()) return;
if(!thr)
{
switch(event.GetId())
{
case DID_EXEC_THREAD:
case DID_REMOVE_THREAD:
case DID_RESUME_THREAD:
m_btn_step->Disable();
m_btn_run->Disable();
m_btn_pause->Enable();
break;
case DID_START_THREAD:
case DID_CREATE_THREAD:
case DID_PAUSE_THREAD:
case DID_STOP_THREAD:
m_btn_step->Enable(!Emu.IsReady());
m_btn_run->Enable(!Emu.IsReady());
m_btn_pause->Disable();
DoUpdate();
break;
case DID_STOP_EMU:
case DID_PAUSE_EMU:
DoUpdate();
break;
}
}
else if(thr->GetId() == CPU.GetId())
{
switch(event.GetId())
{
case DID_PAUSE_THREAD:
m_btn_run->Enable();
m_btn_step->Enable();
m_btn_pause->Disable();
case DID_CREATE_THREAD:
DoUpdate();
break;
case DID_START_THREAD:
case DID_EXEC_THREAD:
case DID_RESUME_THREAD:
m_btn_run->Disable();
m_btn_step->Disable();
m_btn_pause->Enable();
if(event.GetId() == DID_START_THREAD)
{
DoUpdate();
}
break;
case DID_REMOVE_THREAD:
case DID_STOP_THREAD:
m_btn_run->Disable();
m_btn_step->Disable();
m_btn_pause->Disable();
break;
}
}
}
void InterpreterDisAsmFrame::OnUpdate(wxCommandEvent& event)
{
@ -331,7 +284,7 @@ void InterpreterDisAsmFrame::Show_Val(wxCommandEvent& WXUNUSED(event))
{
u64 pc = CPU.PC;
sscanf(p_pc->GetLabel(), "%llx", &pc);
remove_markedPC.AddCpy(markedPC.AddCpy(pc));
remove_markedPC.AddCpy(Emu.GetMarkedPoints().AddCpy(pc));
ShowAddr(FixPc(pc));
}
}
@ -395,9 +348,9 @@ void InterpreterDisAsmFrame::MouseWheel(wxMouseEvent& event)
bool InterpreterDisAsmFrame::IsBreakPoint(u64 pc)
{
for(u32 i=0; i<m_break_points.GetCount(); ++i)
for(u32 i=0; i<Emu.GetBreakPoints().GetCount(); ++i)
{
if(m_break_points[i] == pc) return true;
if(Emu.GetBreakPoints()[i] == pc) return true;
}
return false;
@ -405,20 +358,20 @@ bool InterpreterDisAsmFrame::IsBreakPoint(u64 pc)
void InterpreterDisAsmFrame::AddBreakPoint(u64 pc)
{
for(u32 i=0; i<m_break_points.GetCount(); ++i)
for(u32 i=0; i<Emu.GetBreakPoints().GetCount(); ++i)
{
if(m_break_points[i] == pc) return;
if(Emu.GetBreakPoints()[i] == pc) return;
}
m_break_points.AddCpy(pc);
Emu.GetBreakPoints().AddCpy(pc);
}
bool InterpreterDisAsmFrame::RemoveBreakPoint(u64 pc)
{
for(u32 i=0; i<m_break_points.GetCount(); ++i)
for(u32 i=0; i<Emu.GetBreakPoints().GetCount(); ++i)
{
if(m_break_points[i] != pc) continue;
m_break_points.RemoveAt(i);
if(Emu.GetBreakPoints()[i] != pc) continue;
Emu.GetBreakPoints().RemoveAt(i);
return true;
}

View File

@ -10,13 +10,11 @@ class InterpreterDisAsmFrame
, public ThreadBase
{
wxListView* m_list;
DisAsm* disasm;
Decoder* decoder;
PPC_DisAsm* disasm;
PPC_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;
@ -29,9 +27,6 @@ public:
InterpreterDisAsmFrame(wxWindow* parent, PPCThread* cpu);
~InterpreterDisAsmFrame();
void Save(const wxString& path);
void Load(const wxString& path);
void OnKeyDown(wxKeyEvent& event);
void DoUpdate();
void ShowAddr(const u64 addr);

View File

@ -50,10 +50,10 @@ MainFrame::MainFrame()
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\tCtrl + S");
menu_sys.Append(id_sys_pause, "Pause")->Enable(false);
menu_sys.Append(id_sys_stop, "Stop\tCtrl + S")->Enable(false);
menu_sys.AppendSeparator();
menu_sys.Append(id_sys_send_exit, "Send exit cmd");
menu_sys.Append(id_sys_send_exit, "Send exit cmd")->Enable(false);
menu_conf.Append(id_config_emu, "Settings");
@ -73,8 +73,7 @@ MainFrame::MainFrame()
Connect( id_config_emu, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainFrame::Config) );
m_app_connector.Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(MainFrame::OnKeyDown), (wxObject*)0, this);
UpdateUI();
m_app_connector.Connect(wxEVT_DBG_COMMAND, wxCommandEventHandler(MainFrame::UpdateUI), (wxObject*)0, this);
}
MainFrame::~MainFrame()
@ -131,35 +130,35 @@ void MainFrame::BootGame(wxCommandEvent& WXUNUSED(event))
if(wxFile::Access(elf0, wxFile::read))
{
Emu.SetElf(elf0);
Emu.SetPath(elf0);
ConLog.Write("Elf: booting...");
}
else if(wxFile::Access(elf1, wxFile::read))
{
Emu.SetElf(elf1);
Emu.SetPath(elf1);
ConLog.Write("Elf: booting...");
}
else if(wxFile::Access(elf2, wxFile::read))
{
Emu.SetElf(elf2);
Emu.SetPath(elf2);
ConLog.Write("Elf: booting...");
}
else if(wxFile::Access(self0, wxFile::read))
{
goto _ELF_NOT_FOUND_;
Emu.SetSelf(self0);
Emu.SetPath(self0);
ConLog.Warning("Self: booting...");
}
else if(wxFile::Access(self1, wxFile::read))
{
goto _ELF_NOT_FOUND_;
Emu.SetSelf(self1);
Emu.SetPath(self1);
ConLog.Warning("Self: booting...");
}
else if(wxFile::Access(self2, wxFile::read))
{
goto _ELF_NOT_FOUND_;
Emu.SetSelf(self2);
Emu.SetPath(self2);
ConLog.Warning("Self: booting...");
}
else
@ -200,7 +199,7 @@ void MainFrame::BootElf(wxCommandEvent& WXUNUSED(event))
Emu.Stop();
Emu.SetElf(ctrl.GetPath());
Emu.SetPath(ctrl.GetPath());
Emu.Load();
ConLog.Write("Elf: boot done.");
@ -229,7 +228,7 @@ void MainFrame::BootSelf(wxCommandEvent& WXUNUSED(event))
Emu.Stop();
Emu.SetSelf(ctrl.GetPath());
Emu.SetPath(ctrl.GetPath());
Emu.Load();
ConLog.Write("SELF: boot done.");
@ -367,9 +366,79 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event))
if(paused) Emu.Resume();
}
void MainFrame::UpdateUI(wxCommandEvent& WXUNUSED(event))
void MainFrame::UpdateUI(wxCommandEvent& event)
{
wxGetApp().m_debugger_frame->UpdateUI();
event.Skip();
bool is_runned, is_stopped, is_ready;
if(event.GetEventType() == wxEVT_DBG_COMMAND)
{
switch(event.GetId())
{
case DID_START_EMU:
case DID_STARTED_EMU:
is_runned = true;
is_stopped = false;
is_ready = false;
break;
case DID_STOP_EMU:
case DID_STOPED_EMU:
is_runned = false;
is_stopped = true;
is_ready = false;
break;
case DID_PAUSE_EMU:
case DID_PAUSED_EMU:
is_runned = false;
is_stopped = false;
is_ready = false;
break;
case DID_RESUME_EMU:
case DID_RESUMED_EMU:
is_runned = true;
is_stopped = false;
is_ready = false;
break;
case DID_READY_EMU:
is_runned = false;
is_stopped = false;
is_ready = true;
break;
default:
is_runned = Emu.IsRunned();
is_stopped = Emu.IsStopped();
is_ready = Emu.IsReady();
break;
}
}
else
{
is_runned = Emu.IsRunned();
is_stopped = Emu.IsStopped();
is_ready = Emu.IsReady();
}
wxMenuBar& menubar( *GetMenuBar() );
wxMenuItem& pause = *menubar.FindItem( id_sys_pause );
wxMenuItem& stop = *menubar.FindItem( id_sys_stop );
wxMenuItem& send_exit = *menubar.FindItem( id_sys_send_exit );
pause.SetText(is_runned ? "Pause\tCtrl + P" : is_ready ? "Start\tCtrl + C" : "Resume\tCtrl + C");
pause.Enable(!is_stopped);
stop.Enable(!is_stopped);
//send_exit.Enable(false);
send_exit.Enable(!is_stopped && Emu.GetCallbackManager().m_exit_callback.m_callbacks.GetCount());
m_aui_mgr.Update();
//wxCommandEvent refit( wxEVT_COMMAND_MENU_SELECTED, id_update_dbg );
//GetEventHandler()->AddPendingEvent( refit );
}
void MainFrame::OnQuit(wxCloseEvent& event)
@ -434,22 +503,3 @@ void MainFrame::OnKeyDown(wxKeyEvent& event)
event.Skip();
}
void MainFrame::UpdateUI()
{
wxMenuBar& menubar( *GetMenuBar() );
wxMenuItem& pause = *menubar.FindItem( id_sys_pause );
wxMenuItem& stop = *menubar.FindItem( id_sys_stop );
wxMenuItem& send_exit = *menubar.FindItem( id_sys_send_exit );
pause.SetText(Emu.IsRunned() ? "Pause\tCtrl + P" : Emu.IsReady() ? "Start\tCtrl + C" : "Resume\tCtrl + C");
pause.Enable(!Emu.IsStopped());
stop.Enable(!Emu.IsStopped());
//send_exit.Enable(false);
send_exit.Enable(!Emu.IsStopped() && Emu.GetCallbackManager().m_exit_callback.m_callbacks.GetCount());
m_aui_mgr.Update();
wxCommandEvent refit( wxEVT_COMMAND_MENU_SELECTED, id_update_dbg );
GetEventHandler()->AddPendingEvent( refit );
}

View File

@ -28,9 +28,6 @@ private:
void UpdateUI(wxCommandEvent& event);
void OnKeyDown(wxKeyEvent& event);
public:
void UpdateUI();
private:
DECLARE_EVENT_TABLE()
};

View File

@ -1,7 +1,56 @@
#include "stdafx.h"
#include "ELF64.h"
#include "Gui/CompilerELF.h"
using namespace PPU_opcodes;
#include "Emu/Cell/PPUInstrTable.h"
using namespace PPU_instr;
void WriteEhdr(wxFile& f, Elf64_Ehdr& ehdr)
{
Write32(f, ehdr.e_magic);
Write8(f, ehdr.e_class);
Write8(f, ehdr.e_data);
Write8(f, ehdr.e_curver);
Write8(f, ehdr.e_os_abi);
Write64(f, ehdr.e_abi_ver);
Write16(f, ehdr.e_type);
Write16(f, ehdr.e_machine);
Write32(f, ehdr.e_version);
Write64(f, ehdr.e_entry);
Write64(f, ehdr.e_phoff);
Write64(f, ehdr.e_shoff);
Write32(f, ehdr.e_flags);
Write16(f, ehdr.e_ehsize);
Write16(f, ehdr.e_phentsize);
Write16(f, ehdr.e_phnum);
Write16(f, ehdr.e_shentsize);
Write16(f, ehdr.e_shnum);
Write16(f, ehdr.e_shstrndx);
}
void WritePhdr(wxFile& f, Elf64_Phdr& phdr)
{
Write32(f, phdr.p_type);
Write32(f, phdr.p_flags);
Write64(f, phdr.p_offset);
Write64(f, phdr.p_vaddr);
Write64(f, phdr.p_paddr);
Write64(f, phdr.p_filesz);
Write64(f, phdr.p_memsz);
Write64(f, phdr.p_align);
}
void WriteShdr(wxFile& f, Elf64_Shdr& shdr)
{
Write32(f, shdr.sh_name);
Write32(f, shdr.sh_type);
Write64(f, shdr.sh_flags);
Write64(f, shdr.sh_addr);
Write64(f, shdr.sh_offset);
Write64(f, shdr.sh_size);
Write32(f, shdr.sh_link);
Write32(f, shdr.sh_info);
Write64(f, shdr.sh_addralign);
Write64(f, shdr.sh_entsize);
}
ELF64Loader::ELF64Loader(vfsStream& f)
: elf64_f(f)
@ -326,9 +375,9 @@ bool ELF64Loader::LoadPhdrData(u64 offset)
out_tbl += nid;
mem32_t out_dst(dst + i*section);
out_dst += ToOpcode(G_1f) | SetField(OR, 21, 30) | ToRA(11) | ToRS(2) | ToRB(2) | ToRC(0);
out_dst += ToOpcode(SC) | ToSYS(2);
out_dst += ToOpcode(G_13) | SetField(BCLR, 21, 30) | ToBO(0x10 | 0x04) | ToBI(0) | ToLK(0);
out_dst += OR(11, 2, 2, 0);
out_dst += SC(2);
out_dst += BCLR(0x10 | 0x04, 0, 0, 0);
}
}
#ifdef LOADER_DEBUG

View File

@ -185,3 +185,7 @@ private:
//bool LoadImports();
};
void WriteEhdr(wxFile& f, Elf64_Ehdr& ehdr);
void WritePhdr(wxFile& f, Elf64_Phdr& phdr);
void WriteShdr(wxFile& f, Elf64_Shdr& shdr);

View File

@ -58,6 +58,30 @@ __forceinline static u64 Read64(vfsStream& f)
return ((u64)Read32(f) << 32) | (u64)Read32(f);
}
__forceinline static void Write8(wxFile& f, const u8 data)
{
f.Write(&data, 1);
}
__forceinline static void Write16(wxFile& f, const u16 data)
{
Write8(f, data >> 8);
Write8(f, data);
}
__forceinline static void Write32(wxFile& f, const u32 data)
{
Write16(f, data >> 16);
Write16(f, data);
}
__forceinline static void Write64(wxFile& f, const u64 data)
{
Write32(f, data >> 32);
Write32(f, data);
}
const wxString Ehdr_DataToString(const u8 data);
const wxString Ehdr_TypeToString(const u16 type);
const wxString Ehdr_OS_ABIToString(const u8 os_abi);

View File

@ -22,7 +22,15 @@ bool Rpcs3App::OnInit()
SetTopWindow(m_MainFrame);
Emu.Init();
try
{
(new CompilerELF(m_MainFrame))->Show();
}
catch(...)
{
ConLog.Warning("CompilerELF is broken.");
}
m_debugger_frame = new DebuggerPanel(m_MainFrame);
ConLogFrame = new LogFrame(m_MainFrame);

View File

@ -22,17 +22,31 @@ enum DbgCommand
DID_FIRST_COMMAND = 0x500,
DID_START_EMU,
DID_STARTED_EMU,
DID_STOP_EMU,
DID_STOPED_EMU,
DID_PAUSE_EMU,
DID_PAUSED_EMU,
DID_RESUME_EMU,
DID_RESUMED_EMU,
DID_READY_EMU,
DID_CREATE_THREAD,
DID_CREATED_THREAD,
DID_REMOVE_THREAD,
DID_REMOVED_THREAD,
DID_RENAME_THREAD,
DID_RENAMED_THREAD,
DID_START_THREAD,
DID_STARTED_THREAD,
DID_STOP_THREAD,
DID_STOPED_THREAD,
DID_PAUSE_THREAD,
DID_PAUSED_THREAD,
DID_RESUME_THREAD,
DID_RESUMED_THREAD,
DID_EXEC_THREAD,
DID_REGISTRED_CALLBACK,
DID_UNREGISTRED_CALLBACK,
DID_LAST_COMMAND,
};

View File

@ -197,6 +197,7 @@
<ClCompile Include="AppConnector.cpp" />
<ClCompile Include="Emu\Cell\PPCThread.cpp" />
<ClCompile Include="Emu\Cell\PPCThreadManager.cpp" />
<ClCompile Include="Emu\Cell\PPUProgramCompiler.cpp" />
<ClCompile Include="Emu\Cell\PPUThread.cpp" />
<ClCompile Include="Emu\Cell\SPUThread.cpp" />
<ClCompile Include="Emu\DbgConsole.cpp" />
@ -275,13 +276,17 @@
<ClInclude Include="..\Utilities\MTProgressDialog.h" />
<ClInclude Include="..\Utilities\Thread.h" />
<ClInclude Include="..\Utilities\Timer.h" />
<ClInclude Include="Emu\Cell\DisAsm.h" />
<ClInclude Include="Emu\Cell\PPCDecoder.h" />
<ClInclude Include="Emu\Cell\PPCDisAsm.h" />
<ClInclude Include="Emu\Cell\PPCInstrTable.h" />
<ClInclude Include="Emu\Cell\PPCThread.h" />
<ClInclude Include="Emu\Cell\PPCThreadManager.h" />
<ClInclude Include="Emu\Cell\PPUDecoder.h" />
<ClInclude Include="Emu\Cell\PPUDisAsm.h" />
<ClInclude Include="Emu\Cell\PPUInstrTable.h" />
<ClInclude Include="Emu\Cell\PPUInterpreter.h" />
<ClInclude Include="Emu\Cell\PPUOpcodes.h" />
<ClInclude Include="Emu\Cell\PPUProgramCompiler.h" />
<ClInclude Include="Emu\Cell\PPUThread.h" />
<ClInclude Include="Emu\Cell\SPUDecoder.h" />
<ClInclude Include="Emu\Cell\SPUDisAsm.h" />

View File

@ -247,6 +247,9 @@
<ClCompile Include="AppConnector.cpp">
<Filter>rpcs3</Filter>
</ClCompile>
<ClCompile Include="Emu\Cell\PPUProgramCompiler.cpp">
<Filter>Emu\CPU</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="rpcs3.rc" />
@ -270,9 +273,6 @@
<ClInclude Include="Emu\System.h">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="Emu\Cell\DisAsm.h">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="Emu\Cell\PPCThread.h">
<Filter>Include</Filter>
</ClInclude>
@ -402,5 +402,20 @@
<ClInclude Include="..\Utilities\Timer.h">
<Filter>Utilities</Filter>
</ClInclude>
<ClInclude Include="Emu\Cell\PPCDecoder.h">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="Emu\Cell\PPCDisAsm.h">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="Emu\Cell\PPCInstrTable.h">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="Emu\Cell\PPUInstrTable.h">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="Emu\Cell\PPUProgramCompiler.h">
<Filter>Include</Filter>
</ClInclude>
</ItemGroup>
</Project>