2013-01-14 05:25:28 +00:00
|
|
|
/**
|
|
|
|
******************************************************************************
|
|
|
|
* Xenia : Xbox 360 Emulator Research Project *
|
|
|
|
******************************************************************************
|
|
|
|
* Copyright 2013 Ben Vanik. All rights reserved. *
|
|
|
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
|
|
|
******************************************************************************
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef XENIA_CPU_PPC_INSTR_H_
|
|
|
|
#define XENIA_CPU_PPC_INSTR_H_
|
|
|
|
|
|
|
|
#include <xenia/common.h>
|
|
|
|
|
2013-01-29 05:37:03 +00:00
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
|
|
|
|
2013-01-14 05:25:28 +00:00
|
|
|
|
2013-01-20 09:13:59 +00:00
|
|
|
namespace xe {
|
|
|
|
namespace cpu {
|
|
|
|
namespace ppc {
|
|
|
|
|
|
|
|
|
|
|
|
// TODO(benvanik): rename these
|
2013-01-14 05:25:28 +00:00
|
|
|
typedef enum {
|
|
|
|
kXEPPCInstrFormatI = 0,
|
|
|
|
kXEPPCInstrFormatB = 1,
|
|
|
|
kXEPPCInstrFormatSC = 2,
|
|
|
|
kXEPPCInstrFormatD = 3,
|
|
|
|
kXEPPCInstrFormatDS = 4,
|
|
|
|
kXEPPCInstrFormatX = 5,
|
|
|
|
kXEPPCInstrFormatXL = 6,
|
|
|
|
kXEPPCInstrFormatXFX = 7,
|
|
|
|
kXEPPCInstrFormatXFL = 8,
|
|
|
|
kXEPPCInstrFormatXS = 9,
|
|
|
|
kXEPPCInstrFormatXO = 10,
|
|
|
|
kXEPPCInstrFormatA = 11,
|
|
|
|
kXEPPCInstrFormatM = 12,
|
|
|
|
kXEPPCInstrFormatMD = 13,
|
|
|
|
kXEPPCInstrFormatMDS = 14,
|
|
|
|
kXEPPCInstrFormatVA = 15,
|
|
|
|
kXEPPCInstrFormatVX = 16,
|
|
|
|
kXEPPCInstrFormatVXR = 17,
|
|
|
|
} xe_ppc_instr_format_e;
|
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
kXEPPCInstrTypeGeneral = (1 << 0),
|
|
|
|
kXEPPCInstrTypeBranch = (1 << 1),
|
|
|
|
kXEPPCInstrTypeBranchCond = kXEPPCInstrTypeBranch | (1 << 2),
|
|
|
|
kXEPPCInstrTypeBranchAlways = kXEPPCInstrTypeBranch | (1 << 3),
|
|
|
|
kXEPPCInstrTypeSyscall = (1 << 4),
|
|
|
|
} xe_ppc_instr_type_e;
|
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
kXEPPCInstrFlagReserved = 0,
|
|
|
|
} xe_ppc_instr_flag_e;
|
|
|
|
|
|
|
|
|
2013-01-20 09:13:59 +00:00
|
|
|
class InstrType;
|
2013-01-14 05:25:28 +00:00
|
|
|
|
|
|
|
|
2013-01-21 00:46:08 +00:00
|
|
|
static inline int32_t XEEXTS16(uint32_t v) {
|
|
|
|
return (int32_t)((int16_t)v);
|
|
|
|
}
|
|
|
|
static inline int32_t XEEXTS26(uint32_t v) {
|
|
|
|
return v & 0x02000000 ? (int32_t)v | 0xFC000000 : (int32_t)(v);
|
|
|
|
}
|
2013-01-26 09:25:31 +00:00
|
|
|
static inline uint64_t XEMASK(uint32_t mstart, uint32_t mstop) {
|
|
|
|
// if mstart ≤ mstop then
|
|
|
|
// mask[mstart:mstop] = ones
|
|
|
|
// mask[all other bits] = zeros
|
|
|
|
// else
|
|
|
|
// mask[mstart:63] = ones
|
|
|
|
// mask[0:mstop] = ones
|
|
|
|
// mask[all other bits] = zeros
|
|
|
|
uint64_t value =
|
|
|
|
(UINT64_MAX >> mstart) ^ ((mstop >= 63) ? 0 : UINT64_MAX >> (mstop + 1));
|
|
|
|
return mstart <= mstop ? value : ~value;
|
|
|
|
}
|
2013-01-21 00:46:08 +00:00
|
|
|
|
|
|
|
|
2013-01-14 05:25:28 +00:00
|
|
|
typedef struct {
|
2013-01-20 09:13:59 +00:00
|
|
|
InstrType* type;
|
|
|
|
uint32_t address;
|
2013-01-14 05:25:28 +00:00
|
|
|
|
|
|
|
union {
|
|
|
|
uint32_t code;
|
|
|
|
|
|
|
|
// kXEPPCInstrFormatI
|
|
|
|
struct {
|
|
|
|
uint32_t LK : 1;
|
|
|
|
uint32_t AA : 1;
|
|
|
|
uint32_t LI : 24;
|
2013-01-26 07:45:13 +00:00
|
|
|
uint32_t : 6;
|
2013-01-14 05:25:28 +00:00
|
|
|
} I;
|
|
|
|
// kXEPPCInstrFormatB
|
|
|
|
struct {
|
|
|
|
uint32_t LK : 1;
|
|
|
|
uint32_t AA : 1;
|
|
|
|
uint32_t BD : 14;
|
|
|
|
uint32_t BI : 5;
|
|
|
|
uint32_t BO : 5;
|
2013-01-26 07:45:13 +00:00
|
|
|
uint32_t : 6;
|
2013-01-14 05:25:28 +00:00
|
|
|
} B;
|
|
|
|
|
|
|
|
// kXEPPCInstrFormatSC
|
2013-01-26 07:32:37 +00:00
|
|
|
// kXEPPCInstrFormatD
|
2013-01-14 05:25:28 +00:00
|
|
|
struct {
|
2013-01-26 07:45:13 +00:00
|
|
|
uint32_t DS : 16;
|
|
|
|
uint32_t RA : 5;
|
|
|
|
uint32_t RT : 5;
|
|
|
|
uint32_t : 6;
|
2013-01-14 05:25:28 +00:00
|
|
|
} D;
|
|
|
|
// kXEPPCInstrFormatDS
|
|
|
|
struct {
|
|
|
|
uint32_t : 2;
|
2013-01-26 07:45:13 +00:00
|
|
|
uint32_t DS : 14;
|
|
|
|
uint32_t RA : 5;
|
|
|
|
uint32_t RT : 5;
|
|
|
|
uint32_t : 6;
|
2013-01-14 05:25:28 +00:00
|
|
|
} DS;
|
|
|
|
// kXEPPCInstrFormatX
|
2013-01-22 08:22:27 +00:00
|
|
|
struct {
|
|
|
|
uint32_t Rc : 1;
|
|
|
|
uint32_t : 10;
|
2013-01-26 07:45:13 +00:00
|
|
|
uint32_t RB : 5;
|
|
|
|
uint32_t RA : 5;
|
|
|
|
uint32_t RT : 5;
|
|
|
|
uint32_t : 6;
|
2013-01-22 08:22:27 +00:00
|
|
|
} X;
|
2013-01-14 05:25:28 +00:00
|
|
|
// kXEPPCInstrFormatXL
|
2013-01-21 00:46:08 +00:00
|
|
|
struct {
|
|
|
|
uint32_t LK : 1;
|
|
|
|
uint32_t : 10;
|
|
|
|
uint32_t BB : 5;
|
|
|
|
uint32_t BI : 5;
|
|
|
|
uint32_t BO : 5;
|
2013-01-26 07:45:13 +00:00
|
|
|
uint32_t : 6;
|
2013-01-21 00:46:08 +00:00
|
|
|
} XL;
|
2013-01-26 07:32:37 +00:00
|
|
|
// kXEPPCInstrFormatXFX
|
2013-01-14 05:25:28 +00:00
|
|
|
struct {
|
|
|
|
uint32_t : 1;
|
|
|
|
uint32_t : 10;
|
|
|
|
uint32_t spr : 10;
|
2013-01-26 07:45:13 +00:00
|
|
|
uint32_t RT : 5;
|
|
|
|
uint32_t : 6;
|
2013-01-14 05:25:28 +00:00
|
|
|
} XFX;
|
|
|
|
// kXEPPCInstrFormatXFL
|
|
|
|
// kXEPPCInstrFormatXS
|
2013-01-29 08:41:39 +00:00
|
|
|
struct {
|
|
|
|
uint32_t Rc : 1;
|
|
|
|
uint32_t SH5 : 1;
|
|
|
|
uint32_t : 9;
|
|
|
|
uint32_t SH : 5;
|
|
|
|
uint32_t RA : 5;
|
|
|
|
uint32_t RT : 5;
|
|
|
|
uint32_t : 6;
|
|
|
|
} XS;
|
2013-01-14 05:25:28 +00:00
|
|
|
// kXEPPCInstrFormatXO
|
2013-01-22 08:22:27 +00:00
|
|
|
struct {
|
|
|
|
uint32_t Rc : 1;
|
2013-01-28 23:31:46 +00:00
|
|
|
uint32_t : 9;
|
2013-01-22 08:22:27 +00:00
|
|
|
uint32_t OE : 1;
|
2013-01-26 07:45:13 +00:00
|
|
|
uint32_t RB : 5;
|
|
|
|
uint32_t RA : 5;
|
|
|
|
uint32_t RT : 5;
|
|
|
|
uint32_t : 6;
|
2013-01-22 08:22:27 +00:00
|
|
|
} XO;
|
2013-01-14 05:25:28 +00:00
|
|
|
// kXEPPCInstrFormatA
|
|
|
|
// kXEPPCInstrFormatM
|
2013-01-26 07:32:37 +00:00
|
|
|
struct {
|
|
|
|
uint32_t Rc : 1;
|
|
|
|
uint32_t ME : 5;
|
|
|
|
uint32_t MB : 5;
|
|
|
|
uint32_t SH : 5;
|
|
|
|
uint32_t RA : 5;
|
2013-01-29 08:41:39 +00:00
|
|
|
uint32_t RT : 5;
|
2013-01-26 07:45:13 +00:00
|
|
|
uint32_t : 6;
|
2013-01-26 07:32:37 +00:00
|
|
|
} M;
|
2013-01-14 05:25:28 +00:00
|
|
|
// kXEPPCInstrFormatMD
|
2013-01-27 05:51:31 +00:00
|
|
|
struct {
|
|
|
|
uint32_t Rc : 1;
|
|
|
|
uint32_t SH5 : 1;
|
|
|
|
uint32_t : 3;
|
|
|
|
uint32_t MB5 : 1;
|
|
|
|
uint32_t MB : 5;
|
|
|
|
uint32_t SH : 5;
|
|
|
|
uint32_t RA : 5;
|
2013-01-29 08:41:39 +00:00
|
|
|
uint32_t RT : 5;
|
2013-01-27 05:51:31 +00:00
|
|
|
uint32_t : 6;
|
|
|
|
} MD;
|
2013-01-14 05:25:28 +00:00
|
|
|
// kXEPPCInstrFormatMDS
|
2013-01-29 08:41:39 +00:00
|
|
|
struct {
|
|
|
|
uint32_t Rc : 1;
|
|
|
|
uint32_t : 4;
|
|
|
|
uint32_t MB5 : 1;
|
|
|
|
uint32_t MB : 5;
|
|
|
|
uint32_t RB : 5;
|
|
|
|
uint32_t RA : 5;
|
|
|
|
uint32_t RT : 5;
|
|
|
|
uint32_t : 6;
|
|
|
|
} MDS;
|
2013-01-14 05:25:28 +00:00
|
|
|
// kXEPPCInstrFormatVA
|
|
|
|
// kXEPPCInstrFormatVX
|
|
|
|
// kXEPPCInstrFormatVXR
|
2013-01-21 00:46:08 +00:00
|
|
|
};
|
2013-01-20 09:13:59 +00:00
|
|
|
} InstrData;
|
2013-01-14 05:25:28 +00:00
|
|
|
|
2013-01-29 05:37:03 +00:00
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
enum RegisterSet {
|
|
|
|
kXER,
|
|
|
|
kLR,
|
|
|
|
kCTR,
|
|
|
|
kCR, // 0-7
|
|
|
|
kFPSCR,
|
|
|
|
kGPR, // 0-31
|
|
|
|
kFPR, // 0-31
|
|
|
|
kVMX, // 0-127
|
|
|
|
};
|
|
|
|
|
|
|
|
enum Access {
|
|
|
|
kRead = 1 << 0,
|
|
|
|
kWrite = 1 << 1,
|
|
|
|
kReadWrite = kRead | kWrite,
|
|
|
|
};
|
|
|
|
|
|
|
|
RegisterSet set;
|
|
|
|
uint32_t ordinal;
|
|
|
|
Access access;
|
|
|
|
} InstrRegister;
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
enum OperandType {
|
|
|
|
kRegister,
|
|
|
|
kImmediate,
|
|
|
|
};
|
|
|
|
|
|
|
|
OperandType type;
|
|
|
|
union {
|
|
|
|
InstrRegister reg;
|
|
|
|
struct {
|
|
|
|
bool is_signed;
|
|
|
|
uint64_t value;
|
|
|
|
size_t width;
|
|
|
|
} imm;
|
|
|
|
};
|
|
|
|
char display[32];
|
|
|
|
} InstrOperand;
|
|
|
|
|
|
|
|
|
2013-01-29 21:07:59 +00:00
|
|
|
class InstrAccessBits {
|
|
|
|
public:
|
|
|
|
InstrAccessBits() : spr(0), cr(0), gpr(0), fpr(0) {}
|
|
|
|
|
|
|
|
// Bitmasks derived from the accesses to registers.
|
|
|
|
// Format is 2 bits for each register, even bits indicating reads and odds
|
|
|
|
// indicating writes.
|
|
|
|
uint64_t spr; // fpcsr/ctr/lr/xer
|
|
|
|
uint64_t cr; // cr7/6/5/4/3/2/1/0
|
|
|
|
uint64_t gpr; // r31-0
|
|
|
|
uint64_t fpr; // f31-0
|
|
|
|
|
|
|
|
void Clear();
|
|
|
|
void Extend(InstrAccessBits& other);
|
|
|
|
void MarkAccess(InstrRegister& reg);
|
|
|
|
void Dump(std::string& out_str);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2013-01-29 05:37:03 +00:00
|
|
|
class InstrDisasm {
|
|
|
|
public:
|
|
|
|
enum Flags {
|
|
|
|
kOE = 1 << 0,
|
|
|
|
kRc = 1 << 1,
|
|
|
|
kCA = 1 << 2,
|
2013-01-29 09:55:03 +00:00
|
|
|
kLR = 1 << 4,
|
2013-01-29 05:37:03 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
char name[16];
|
2013-01-29 08:41:39 +00:00
|
|
|
char info[64];
|
2013-01-29 05:37:03 +00:00
|
|
|
std::vector<InstrOperand> operands;
|
|
|
|
std::vector<InstrRegister> special_registers;
|
2013-01-29 21:07:59 +00:00
|
|
|
InstrAccessBits access_bits;
|
2013-01-29 05:37:03 +00:00
|
|
|
|
2013-01-29 08:41:39 +00:00
|
|
|
void Init(std::string name, std::string info, uint32_t flags);
|
2013-01-29 09:55:03 +00:00
|
|
|
void AddLR(InstrRegister::Access access);
|
|
|
|
void AddCTR(InstrRegister::Access access);
|
2013-01-29 08:41:39 +00:00
|
|
|
void AddCR(uint32_t bf, InstrRegister::Access access);
|
2013-01-29 05:37:03 +00:00
|
|
|
void AddRegOperand(InstrRegister::RegisterSet set, uint32_t ordinal,
|
|
|
|
InstrRegister::Access access, std::string display = "");
|
|
|
|
void AddSImmOperand(uint64_t value, size_t width, std::string display = "");
|
|
|
|
void AddUImmOperand(uint64_t value, size_t width, std::string display = "");
|
|
|
|
int Finish();
|
|
|
|
|
|
|
|
void Dump(std::string& str, size_t pad = 8);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
typedef int (*InstrDisassembleFn)(InstrData& i, InstrDisasm& d);
|
|
|
|
typedef void* InstrEmitFn;
|
|
|
|
|
|
|
|
|
2013-01-20 09:13:59 +00:00
|
|
|
class InstrType {
|
|
|
|
public:
|
|
|
|
uint32_t opcode;
|
|
|
|
uint32_t format; // xe_ppc_instr_format_e
|
|
|
|
uint32_t type; // xe_ppc_instr_type_e
|
|
|
|
uint32_t flags; // xe_ppc_instr_flag_e
|
|
|
|
char name[16];
|
2013-01-14 05:25:28 +00:00
|
|
|
|
2013-01-29 05:37:03 +00:00
|
|
|
InstrDisassembleFn disassemble;
|
|
|
|
InstrEmitFn emit;
|
2013-01-14 05:25:28 +00:00
|
|
|
};
|
|
|
|
|
2013-01-20 09:13:59 +00:00
|
|
|
InstrType* GetInstrType(uint32_t code);
|
2013-01-29 05:37:03 +00:00
|
|
|
int RegisterInstrDisassemble(uint32_t code, InstrDisassembleFn disassemble);
|
|
|
|
int RegisterInstrEmit(uint32_t code, InstrEmitFn emit);
|
2013-01-20 09:13:59 +00:00
|
|
|
|
|
|
|
|
|
|
|
} // namespace ppc
|
|
|
|
} // namespace cpu
|
|
|
|
} // namespace xe
|
|
|
|
|
2013-01-14 05:25:28 +00:00
|
|
|
|
|
|
|
#endif // XENIA_CPU_PPC_INSTR_H_
|
|
|
|
|