Files
Xenia-Canary/src/xenia/cpu/frontend/ppc_instr.h
2015-05-03 22:01:31 -07:00

576 lines
13 KiB
C++

/**
******************************************************************************
* 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_FRONTEND_PPC_INSTR_H_
#define XENIA_FRONTEND_PPC_INSTR_H_
#include <cstdint>
#include <string>
#include <vector>
#include "xenia/base/string_buffer.h"
namespace xe {
namespace cpu {
namespace frontend {
inline uint32_t make_bitmask(uint32_t a, uint32_t b) {
return (static_cast<uint32_t>(-1) >> (31 - b)) & ~((1u << a) - 1);
}
inline uint32_t select_bits(uint32_t value, uint32_t a, uint32_t b) {
return (value & make_bitmask(a, b)) >> a;
}
// TODO(benvanik): rename these
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,
kXEPPCInstrFormatVXA = 15,
kXEPPCInstrFormatVX = 16,
kXEPPCInstrFormatVXR = 17,
kXEPPCInstrFormatVX128 = 18,
kXEPPCInstrFormatVX128_1 = 19,
kXEPPCInstrFormatVX128_2 = 20,
kXEPPCInstrFormatVX128_3 = 21,
kXEPPCInstrFormatVX128_4 = 22,
kXEPPCInstrFormatVX128_5 = 23,
kXEPPCInstrFormatVX128_P = 24,
kXEPPCInstrFormatVX128_R = 25,
kXEPPCInstrFormatXDSS = 26,
} xe_ppc_instr_format_e;
enum xe_ppc_instr_mask_e : uint32_t {
kXEPPCInstrMaskVXR = 0xFC0003FF,
kXEPPCInstrMaskVXA = 0xFC00003F,
kXEPPCInstrMaskVX128 = 0xFC0003D0,
kXEPPCInstrMaskVX128_1 = 0xFC0007F3,
kXEPPCInstrMaskVX128_2 = 0xFC000210,
kXEPPCInstrMaskVX128_3 = 0xFC0007F0,
kXEPPCInstrMaskVX128_4 = 0xFC000730,
kXEPPCInstrMaskVX128_5 = 0xFC000010,
kXEPPCInstrMaskVX128_P = 0xFC000630,
kXEPPCInstrMaskVX128_R = 0xFC000390,
};
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;
class InstrType;
static inline int64_t XEEXTS16(uint32_t v) { return (int64_t)((int16_t)v); }
static inline int64_t XEEXTS26(uint32_t v) {
return (int64_t)(v & 0x02000000 ? (int32_t)v | 0xFC000000 : (int32_t)(v));
}
static inline uint64_t XEEXTZ16(uint32_t v) { return (uint64_t)((uint16_t)v); }
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
mstart &= 0x3F;
mstop &= 0x3F;
uint64_t value =
(UINT64_MAX >> mstart) ^ ((mstop >= 63) ? 0 : UINT64_MAX >> (mstop + 1));
return mstart <= mstop ? value : ~value;
}
typedef struct {
InstrType* type;
uint32_t address;
union {
uint32_t code;
// kXEPPCInstrFormatI
struct {
uint32_t LK : 1;
uint32_t AA : 1;
uint32_t LI : 24;
uint32_t:
6;
} I;
// kXEPPCInstrFormatB
struct {
uint32_t LK : 1;
uint32_t AA : 1;
uint32_t BD : 14;
uint32_t BI : 5;
uint32_t BO : 5;
uint32_t:
6;
} B;
// kXEPPCInstrFormatSC
// kXEPPCInstrFormatD
struct {
uint32_t DS : 16;
uint32_t RA : 5;
uint32_t RT : 5;
uint32_t:
6;
} D;
// kXEPPCInstrFormatDS
struct {
uint32_t:
2;
uint32_t DS : 14;
uint32_t RA : 5;
uint32_t RT : 5;
uint32_t:
6;
} DS;
// kXEPPCInstrFormatX
struct {
uint32_t Rc : 1;
uint32_t:
10;
uint32_t RB : 5;
uint32_t RA : 5;
uint32_t RT : 5;
uint32_t:
6;
} X;
// kXEPPCInstrFormatXL
struct {
uint32_t LK : 1;
uint32_t:
10;
uint32_t BB : 5;
uint32_t BI : 5;
uint32_t BO : 5;
uint32_t:
6;
} XL;
// kXEPPCInstrFormatXFX
struct {
uint32_t:
1;
uint32_t:
10;
uint32_t spr : 10;
uint32_t RT : 5;
uint32_t:
6;
} XFX;
// kXEPPCInstrFormatXFL
struct {
uint32_t Rc : 1;
uint32_t:
10;
uint32_t RB : 5;
uint32_t W : 1;
uint32_t FM : 8;
uint32_t L : 1;
uint32_t:
6;
} XFL;
// kXEPPCInstrFormatXS
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;
// kXEPPCInstrFormatXO
struct {
uint32_t Rc : 1;
uint32_t:
9;
uint32_t OE : 1;
uint32_t RB : 5;
uint32_t RA : 5;
uint32_t RT : 5;
uint32_t:
6;
} XO;
// kXEPPCInstrFormatA
struct {
uint32_t Rc : 1;
uint32_t XO : 5;
uint32_t FRC : 5;
uint32_t FRB : 5;
uint32_t FRA : 5;
uint32_t FRT : 5;
uint32_t:
6;
} A;
// kXEPPCInstrFormatM
struct {
uint32_t Rc : 1;
uint32_t ME : 5;
uint32_t MB : 5;
uint32_t SH : 5;
uint32_t RA : 5;
uint32_t RT : 5;
uint32_t:
6;
} M;
// kXEPPCInstrFormatMD
struct {
uint32_t Rc : 1;
uint32_t SH5 : 1;
uint32_t idx : 3;
uint32_t MB5 : 1;
uint32_t MB : 5;
uint32_t SH : 5;
uint32_t RA : 5;
uint32_t RT : 5;
uint32_t:
6;
} MD;
// kXEPPCInstrFormatMDS
struct {
uint32_t Rc : 1;
uint32_t idx : 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;
// kXEPPCInstrFormatVXA
struct {
uint32_t:
6;
uint32_t VC : 5;
uint32_t VB : 5;
uint32_t VA : 5;
uint32_t VD : 5;
uint32_t:
6;
} VXA;
// kXEPPCInstrFormatVX
struct {
uint32_t:
11;
uint32_t VB : 5;
uint32_t VA : 5;
uint32_t VD : 5;
uint32_t:
6;
} VX;
// kXEPPCInstrFormatVXR
struct {
uint32_t:
10;
uint32_t Rc : 1;
uint32_t VB : 5;
uint32_t VA : 5;
uint32_t VD : 5;
uint32_t:
6;
} VXR;
// kXEPPCInstrFormatVX128
struct {
// VD128 = VD128l | (VD128h << 5)
// VA128 = VA128l | (VA128h << 5) | (VA128H << 6)
// VB128 = VB128l | (VB128h << 5)
uint32_t VB128h : 2;
uint32_t VD128h : 2;
uint32_t:
1;
uint32_t VA128h : 1;
uint32_t:
4;
uint32_t VA128H : 1;
uint32_t VB128l : 5;
uint32_t VA128l : 5;
uint32_t VD128l : 5;
uint32_t:
6;
} VX128;
// kXEPPCInstrFormatVX128_1
struct {
// VD128 = VD128l | (VD128h << 5)
uint32_t:
2;
uint32_t VD128h : 2;
uint32_t:
7;
uint32_t RB : 5;
uint32_t RA : 5;
uint32_t VD128l : 5;
uint32_t:
6;
} VX128_1;
// kXEPPCInstrFormatVX128_2
struct {
// VD128 = VD128l | (VD128h << 5)
// VA128 = VA128l | (VA128h << 5) | (VA128H << 6)
// VB128 = VB128l | (VB128h << 5)
uint32_t VB128h : 2;
uint32_t VD128h : 2;
uint32_t:
1;
uint32_t VA128h : 1;
uint32_t VC : 3;
uint32_t:
1;
uint32_t VA128H : 1;
uint32_t VB128l : 5;
uint32_t VA128l : 5;
uint32_t VD128l : 5;
uint32_t:
6;
} VX128_2;
// kXEPPCInstrFormatVX128_3
struct {
// VD128 = VD128l | (VD128h << 5)
// VB128 = VB128l | (VB128h << 5)
uint32_t VB128h : 2;
uint32_t VD128h : 2;
uint32_t:
7;
uint32_t VB128l : 5;
uint32_t IMM : 5;
uint32_t VD128l : 5;
uint32_t:
6;
} VX128_3;
// kXEPPCInstrFormatVX128_4
struct {
// VD128 = VD128l | (VD128h << 5)
// VB128 = VB128l | (VB128h << 5)
uint32_t VB128h : 2;
uint32_t VD128h : 2;
uint32_t:
2;
uint32_t z : 2;
uint32_t:
3;
uint32_t VB128l : 5;
uint32_t IMM : 5;
uint32_t VD128l : 5;
uint32_t:
6;
} VX128_4;
// kXEPPCInstrFormatVX128_5
struct {
// VD128 = VD128l | (VD128h << 5)
// VA128 = VA128l | (VA128h << 5) | (VA128H << 6)
// VB128 = VB128l | (VB128h << 5)
uint32_t VB128h : 2;
uint32_t VD128h : 2;
uint32_t:
1;
uint32_t VA128h : 1;
uint32_t SH : 4;
uint32_t VA128H : 1;
uint32_t VB128l : 5;
uint32_t VA128l : 5;
uint32_t VD128l : 5;
uint32_t:
6;
} VX128_5;
// kXEPPCInstrFormatVX128_P
struct {
// VD128 = VD128l | (VD128h << 5)
// VB128 = VB128l | (VB128h << 5)
// PERM = PERMl | (PERMh << 5)
uint32_t VB128h : 2;
uint32_t VD128h : 2;
uint32_t:
2;
uint32_t PERMh : 3;
uint32_t:
2;
uint32_t VB128l : 5;
uint32_t PERMl : 5;
uint32_t VD128l : 5;
uint32_t:
6;
} VX128_P;
// kXEPPCInstrFormatVX128_R
struct {
// VD128 = VD128l | (VD128h << 5)
// VA128 = VA128l | (VA128h << 5) | (VA128H << 6)
// VB128 = VB128l | (VB128h << 5)
uint32_t VB128h : 2;
uint32_t VD128h : 2;
uint32_t:
1;
uint32_t VA128h : 1;
uint32_t Rc : 1;
uint32_t:
3;
uint32_t VA128H : 1;
uint32_t VB128l : 5;
uint32_t VA128l : 5;
uint32_t VD128l : 5;
uint32_t:
6;
} VX128_R;
// kXEPPCInstrFormatXDSS
struct {
} XDSS;
};
} InstrData;
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;
const char* display;
union {
InstrRegister reg;
struct {
bool is_signed;
uint64_t value;
size_t width;
} imm;
};
void Dump(std::string& out_str);
} InstrOperand;
class InstrAccessBits {
public:
InstrAccessBits()
: spr(0),
cr(0),
gpr(0),
fpr(0),
vr31_0(0),
vr63_32(0),
vr95_64(0),
vr127_96(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
uint64_t vr31_0;
uint64_t vr63_32;
uint64_t vr95_64;
uint64_t vr127_96;
void Clear();
void Extend(InstrAccessBits& other);
void MarkAccess(InstrRegister& reg);
void Dump(std::string& out_str);
};
class InstrDisasm {
public:
enum Flags {
kOE = 1 << 0,
kRc = 1 << 1,
kCA = 1 << 2,
kLR = 1 << 4,
kFP = 1 << 5,
kVMX = 1 << 6,
};
const char* name;
const char* info;
uint32_t flags;
void Init(const char* name, const char* info, uint32_t flags);
void AddLR(InstrRegister::Access access);
void AddCTR(InstrRegister::Access access);
void AddCR(uint32_t bf, InstrRegister::Access access);
void AddFPSCR(InstrRegister::Access access);
void AddRegOperand(InstrRegister::RegisterSet set, uint32_t ordinal,
InstrRegister::Access access, const char* display = NULL);
void AddSImmOperand(uint64_t value, size_t width, const char* display = NULL);
void AddUImmOperand(uint64_t value, size_t width, const char* display = NULL);
int Finish();
void Dump(std::string& out_str, size_t pad = 13);
};
typedef void (*InstrDisasmFn)(InstrData& i, StringBuffer* str);
typedef void* InstrEmitFn;
class InstrType {
public:
uint32_t opcode;
uint32_t opcode_mask; // Only used for certain opcodes (altivec, etc).
uint32_t format; // xe_ppc_instr_format_e
uint32_t type; // xe_ppc_instr_type_e
uint32_t flags; // xe_ppc_instr_flag_e
InstrDisasmFn disasm;
char name[16];
uint32_t translation_count;
InstrEmitFn emit;
};
void DumpAllInstrCounts();
InstrType* GetInstrType(uint32_t code);
int RegisterInstrEmit(uint32_t code, InstrEmitFn emit);
} // namespace frontend
} // namespace cpu
} // namespace xe
#endif // XENIA_FRONTEND_PPC_INSTR_H_