Skip to content

Instantly share code, notes, and snippets.

@unknownbrackets
Last active April 2, 2018 23:23
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save unknownbrackets/d01ac5cd2598e76a146e to your computer and use it in GitHub Desktop.
Save unknownbrackets/d01ac5cd2598e76a146e to your computer and use it in GitHub Desktop.
New, virtual function-less initial concept (untested)
#include "stdafx.h"
// Aren't these just PPC opcodes?
#include "Emu/Cell/PPUOpcodes.h"
// Design plan:
// Get to the interp/jit/etc. func as quick as possible.
// Individual interp/jit/disasm funcs should be short and direct as possible.
// Needs to take native byte order - too many args to win by using BE.
namespace PPC
{
typedef u32 Opcode;
class Int {
public:
__forceinline void TDI(u32 to, u32 ra, s32 simm)
{
// TODO
}
template <typename A0, typename A1, typename A2, void (Int::*Func)(typename A0::Type, typename A1::Type, typename A2::Type)>
void InstructionProxy(Opcode op)
{
return (this->*Func)(A0::Decode(op), A1::Decode(op), A2::Decode(op));
}
};
class Comp {
public:
__forceinline void TDI(u32 to, u32 ra, s32 simm)
{
// TODO
}
template <typename A0, typename A1, typename A2, void (Comp::*Func)(typename A0::Type, typename A1::Type, typename A2::Type)>
void InstructionProxy(Opcode op)
{
return (this->*Func)(A0::Decode(op), A1::Decode(op), A2::Decode(op));
}
};
class Dis {
public:
__forceinline void TDI(u32 to, u32 ra, s32 simm)
{
// TODO
}
template <typename A0, typename A1, typename A2, void (Dis::*Func)(typename A0::Type, typename A1::Type, typename A2::Type)>
void InstructionProxy(Opcode op)
{
return (this->*Func)(A0::Decode(op), A1::Decode(op), A2::Decode(op));
}
};
// TODO: Change to class methods.
typedef void (Int::*InterpretFunc)(Opcode op);
typedef void (Comp::*CompileFunc)(Opcode op);
typedef void (Dis::*DisasmFunc)(Opcode op);
enum InstructionFlags
{
// TODO
};
struct Instruction;
inline static u8 FlipShift(u8 v)
{
return 31 - v;
}
inline static u32 MakeMask(u8 from, u8 to)
{
const u8 numBits = to - from + 1;
return (1 << numBits) - 1;
}
struct InstructionTable
{
const u8 shift;
const u32 mask;
std::vector<Instruction> instructions;
// From / to in big endian order.
InstructionTable(u8 from, u8 to)
: shift(FlipShift(to)), mask(MakeMask(from, to))
{
// This will truncate/pad with invalid.
instructions.resize(mask);
}
void Add(u32 index, const Instruction &&instr);
const Instruction *Lookup(Opcode op) const
{
return &instructions[(op >> shift) & mask];
}
const Instruction *operator[](u32 index) const
{
return &instructions[index];
}
};
struct Instruction
{
const InstructionTable *subTable;
InterpretFunc interpret;
CompileFunc compile;
DisasmFunc disasm;
std::string name;
u32 flags;
Instruction()
: subTable(nullptr), interpret(nullptr), compile(nullptr), disasm(nullptr), name(), flags(0)
{
}
Instruction(const Instruction &other)
: subTable(other.subTable), interpret(other.interpret),
compile(other.compile), disasm(other.disasm), name(other.name), flags(other.flags)
{
}
explicit Instruction(InterpretFunc i, CompileFunc c, DisasmFunc d, const std::string &n, u32 f = 0)
: subTable(nullptr), interpret(i), compile(c), disasm(d), name(n), flags(f)
{
}
explicit Instruction(const InstructionTable *t)
: subTable(t), interpret(nullptr), compile(nullptr), disasm(nullptr), name(), flags(0)
{
}
};
void InstructionTable::Add(u32 index, const Instruction &&instr)
{
instructions[index] = instr;
}
inline static Instruction Invalid()
{
return Instruction();
}
template <typename A0, typename A1, typename A2, void (Int::*Interpret)(typename A0::Type, typename A1::Type, typename A2::Type), void (Comp::*Compile)(typename A0::Type, typename A1::Type, typename A2::Type), void (Dis::*Disasm)(typename A0::Type, typename A1::Type, typename A2::Type)>
inline static Instruction Instr(const std::string &n, u32 flags = 0)
{
flags |= A0::flags | A1::flags | A2::flags;
const InterpretFunc interpret = &Int::InstructionProxy<A0, A1, A2, Interpret>;
// TODO: Hmm, this will be more complicated as a method...
const CompileFunc compile = &Comp::InstructionProxy<A0, A1, A2, Compile>;
const DisasmFunc disasm = &Dis::InstructionProxy<A0, A1, A2, Disasm>;
return Instruction(interpret, compile, disasm, n, flags);
}
template <u8 from, u8 to, u32 flags = 0>
struct CodeField
{
static const u32 size = to - from + 1;
static const u32 shift = 31 - to;
static const u32 mask = (1 << (to - from + 1)) - 1;
static const u32 flags = flags;
typedef u32 Type;
static Type Decode(Opcode data)
{
return (data >> shift) & mask;
}
};
template <u8 from, u8 to, u32 flags = 0>
struct CodeFieldSigned : public CodeField<from, to, flags>
{
typedef s32 Type;
static Type Decode(Opcode data)
{
u32 uval = CodeField<from, to, flags>::Decode(data);
// If it's negative, fill all the sign bits.
if (uval & (1 << size))
uval |= 0xFFFFFFFF << size;
return uval;
}
};
typedef CodeField<6, 10> TO;
typedef CodeField<11, 15> RA;
typedef CodeField<16, 31> uimm16;
typedef CodeFieldSigned<16, 31> simm16;
struct MainInstructionTable : public InstructionTable
{
MainInstructionTable();
};
static const MainInstructionTable mainTable;
#define INSTR(name, ...) Add(PPU_opcodes::name, Instr<##__VA_ARGS__, &Int::name, &Comp::name, &Dis::name>(#name))
#define TABLE(index, list) Add(PPU_opcodes::index, Instruction(list))
MainInstructionTable::MainInstructionTable() : InstructionTable(0, 5)
{
INSTR(TDI, TO, RA, simm16);
}
#undef INSTR
#undef TABLE
Instruction GetInstruction(Opcode op)
{
// Hardcoded the first shift for speed. See mainTable.
const Instruction *instr = mainTable[op >> (31 - 5)];
while (instr->subTable)
instr = instr->subTable->Lookup(op);
return *instr;
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment