Screw convention; moving include files alongside source files.

They now will show up in xcode/etc.
This commit is contained in:
Ben Vanik
2013-02-06 02:19:50 -08:00
parent 3dfd9c4b00
commit 88431eadce
151 changed files with 290 additions and 200 deletions

407
src/xenia/cpu/ppc/instr.cc Normal file
View File

@@ -0,0 +1,407 @@
/**
******************************************************************************
* 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. *
******************************************************************************
*/
#include <xenia/cpu/ppc/instr.h>
#include <sstream>
#include <xenia/cpu/ppc/instr_tables.h>
using namespace xe::cpu::ppc;
void InstrAccessBits::Clear() {
spr = cr = gpr = fpr = 0;
}
void InstrAccessBits::Extend(InstrAccessBits& other) {
spr |= other.spr;
cr |= other.cr;
gpr |= other.gpr;
fpr |= other.fpr;
}
void InstrAccessBits::MarkAccess(InstrRegister& reg) {
uint64_t bits = 0;
if (reg.access & InstrRegister::kRead) {
bits |= 0x1;
}
if (reg.access & InstrRegister::kWrite) {
bits |= 0x2;
}
switch (reg.set) {
case InstrRegister::kXER:
spr |= bits << (2 * 0);
break;
case InstrRegister::kLR:
spr |= bits << (2 * 1);
break;
case InstrRegister::kCTR:
spr |= bits << (2 * 2);
break;
case InstrRegister::kCR:
cr |= bits << (2 * reg.ordinal);
break;
case InstrRegister::kFPSCR:
spr |= bits << (2 * 3);
break;
case InstrRegister::kGPR:
gpr |= bits << (2 * reg.ordinal);
break;
case InstrRegister::kFPR:
fpr |= bits << (2 * reg.ordinal);
break;
default:
case InstrRegister::kVMX:
XEASSERTALWAYS();
break;
}
}
void InstrAccessBits::Dump(std::string& out_str) {
std::stringstream str;
if (spr) {
uint64_t spr_t = spr;
if (spr_t & 0x3) {
str << "XER [";
str << ((spr_t & 1) ? "R" : " ");
str << ((spr_t & 2) ? "W" : " ");
str << "] ";
}
spr_t >>= 2;
if (spr_t & 0x3) {
str << "LR [";
str << ((spr_t & 1) ? "R" : " ");
str << ((spr_t & 2) ? "W" : " ");
str << "] ";
}
spr_t >>= 2;
if (spr_t & 0x3) {
str << "CTR [";
str << ((spr_t & 1) ? "R" : " ");
str << ((spr_t & 2) ? "W" : " ");
str << "] ";
}
spr_t >>= 2;
if (spr_t & 0x3) {
str << "FPCSR [";
str << ((spr_t & 1) ? "R" : " ");
str << ((spr_t & 2) ? "W" : " ");
str << "] ";
}
spr_t >>= 2;
}
if (cr) {
uint64_t cr_t = cr;
for (size_t n = 0; n < 8; n++) {
if (cr_t & 0x3) {
str << "cr" << n << " [";
str << ((cr_t & 1) ? "R" : " ");
str << ((cr_t & 2) ? "W" : " ");
str << "] ";
}
cr_t >>= 2;
}
}
if (gpr) {
uint64_t gpr_t = gpr;
for (size_t n = 0; n < 32; n++) {
if (gpr_t & 0x3) {
str << "r" << n << " [";
str << ((gpr_t & 1) ? "R" : " ");
str << ((gpr_t & 2) ? "W" : " ");
str << "] ";
}
gpr_t >>= 2;
}
}
if (fpr) {
uint64_t fpr_t = fpr;
for (size_t n = 0; n < 32; n++) {
if (fpr_t & 0x3) {
str << "f" << n << " [";
str << ((fpr_t & 1) ? "R" : " ");
str << ((fpr_t & 2) ? "W" : " ");
str << "] ";
}
fpr_t >>= 2;
}
}
out_str = str.str();
}
void InstrDisasm::Init(std::string name, std::string info, uint32_t flags) {
operands.clear();
special_registers.clear();
access_bits.Clear();
if (flags & InstrDisasm::kOE) {
name += "o";
InstrRegister i = {
InstrRegister::kXER, 0, InstrRegister::kReadWrite
};
special_registers.push_back(i);
}
if (flags & InstrDisasm::kRc) {
name += ".";
InstrRegister i = {
InstrRegister::kCR, 0, InstrRegister::kWrite
};
special_registers.push_back(i);
}
if (flags & InstrDisasm::kCA) {
InstrRegister i = {
InstrRegister::kXER, 0, InstrRegister::kReadWrite
};
special_registers.push_back(i);
}
if (flags & InstrDisasm::kLR) {
name += "l";
InstrRegister i = {
InstrRegister::kLR, 0, InstrRegister::kWrite
};
special_registers.push_back(i);
}
XEIGNORE(xestrcpya(this->name, XECOUNT(this->name), name.c_str()));
XEIGNORE(xestrcpya(this->info, XECOUNT(this->info), info.c_str()));
}
void InstrDisasm::AddLR(InstrRegister::Access access) {
InstrRegister i = {
InstrRegister::kLR, 0, access
};
special_registers.push_back(i);
}
void InstrDisasm::AddCTR(InstrRegister::Access access) {
InstrRegister i = {
InstrRegister::kCTR, 0, access
};
special_registers.push_back(i);
}
void InstrDisasm::AddCR(uint32_t bf, InstrRegister::Access access) {
InstrRegister i = {
InstrRegister::kCR, bf, access
};
special_registers.push_back(i);
}
void InstrDisasm::AddRegOperand(
InstrRegister::RegisterSet set, uint32_t ordinal,
InstrRegister::Access access, std::string display) {
InstrRegister i = {
set, ordinal, access
};
InstrOperand o;
o.type = InstrOperand::kRegister;
o.reg = i;
if (!display.size()) {
std::stringstream display_out;
switch (set) {
case InstrRegister::kXER:
display_out << "XER";
break;
case InstrRegister::kLR:
display_out << "LR";
break;
case InstrRegister::kCTR:
display_out << "CTR";
break;
case InstrRegister::kCR:
display_out << "CR";
display_out << ordinal;
break;
case InstrRegister::kFPSCR:
display_out << "FPSCR";
break;
case InstrRegister::kGPR:
display_out << "r";
display_out << ordinal;
break;
case InstrRegister::kFPR:
display_out << "f";
display_out << ordinal;
break;
case InstrRegister::kVMX:
display_out << "v";
display_out << ordinal;
break;
}
display = display_out.str();
}
XEIGNORE(xestrcpya(o.display, XECOUNT(o.display), display.c_str()));
operands.push_back(o);
}
void InstrDisasm::AddSImmOperand(uint64_t value, size_t width,
std::string display) {
InstrOperand o;
o.type = InstrOperand::kImmediate;
o.imm.is_signed = true;
o.imm.value = value;
o.imm.width = value;
if (display.size()) {
XEIGNORE(xestrcpya(o.display, XECOUNT(o.display), display.c_str()));
} else {
const size_t max_count = XECOUNT(o.display);
switch (width) {
case 1:
xesnprintfa(o.display, max_count, "%d", (int32_t)(int8_t)value);
break;
case 2:
xesnprintfa(o.display, max_count, "%d", (int32_t)(int16_t)value);
break;
case 4:
xesnprintfa(o.display, max_count, "%d", (int32_t)value);
break;
case 8:
xesnprintfa(o.display, max_count, "%lld", (int64_t)value);
break;
}
}
operands.push_back(o);
}
void InstrDisasm::AddUImmOperand(uint64_t value, size_t width,
std::string display) {
InstrOperand o;
o.type = InstrOperand::kImmediate;
o.imm.is_signed = false;
o.imm.value = value;
o.imm.width = value;
if (display.size()) {
XEIGNORE(xestrcpya(o.display, XECOUNT(o.display), display.c_str()));
} else {
const size_t max_count = XECOUNT(o.display);
switch (width) {
case 1:
xesnprintfa(o.display, max_count, "0x%.2X", (uint8_t)value);
break;
case 2:
xesnprintfa(o.display, max_count, "0x%.4X", (uint16_t)value);
break;
case 4:
xesnprintfa(o.display, max_count, "0x%.8X", (uint32_t)value);
break;
case 8:
xesnprintfa(o.display, max_count, "0x%.16llX", value);
break;
}
}
operands.push_back(o);
}
int InstrDisasm::Finish() {
for (std::vector<InstrOperand>::iterator it = operands.begin();
it != operands.end(); ++it) {
if (it->type == InstrOperand::kRegister) {
access_bits.MarkAccess(it->reg);
}
}
for (std::vector<InstrRegister>::iterator it = special_registers.begin();
it != special_registers.end(); ++it) {
access_bits.MarkAccess(*it);
}
return 0;
}
void InstrDisasm::Dump(std::string& str, size_t pad) {
str = name;
if (operands.size()) {
if (pad && str.size() < pad) {
str += std::string(pad - str.size(), ' ');
}
for (std::vector<InstrOperand>::iterator it = operands.begin();
it != operands.end(); ++it) {
str += it->display;
if (it + 1 != operands.end()) {
str += ", ";
}
}
}
}
InstrType* xe::cpu::ppc::GetInstrType(uint32_t code) {
InstrType* slot = NULL;
switch (code >> 26) {
case 4:
// Opcode = 4, index = bits 5-0 (6)
slot = &xe::cpu::ppc::tables::instr_table_4[XESELECTBITS(code, 0, 5)];
break;
case 19:
// Opcode = 19, index = bits 10-1 (10)
slot = &xe::cpu::ppc::tables::instr_table_19[XESELECTBITS(code, 1, 10)];
break;
case 30:
// Opcode = 30, index = bits 4-1 (4)
slot = &xe::cpu::ppc::tables::instr_table_30[XESELECTBITS(code, 1, 4)];
break;
case 31:
// Opcode = 31, index = bits 10-1 (10)
slot = &xe::cpu::ppc::tables::instr_table_31[XESELECTBITS(code, 1, 10)];
break;
case 58:
// Opcode = 58, index = bits 1-0 (2)
slot = &xe::cpu::ppc::tables::instr_table_58[XESELECTBITS(code, 0, 1)];
break;
case 59:
// Opcode = 59, index = bits 5-1 (5)
slot = &xe::cpu::ppc::tables::instr_table_59[XESELECTBITS(code, 1, 5)];
break;
case 62:
// Opcode = 62, index = bits 1-0 (2)
slot = &xe::cpu::ppc::tables::instr_table_62[XESELECTBITS(code, 0, 1)];
break;
case 63:
// Opcode = 63, index = bits 10-1 (10)
slot = &xe::cpu::ppc::tables::instr_table_63[XESELECTBITS(code, 1, 10)];
break;
default:
slot = &xe::cpu::ppc::tables::instr_table[XESELECTBITS(code, 26, 31)];
break;
}
if (!slot || !slot->opcode) {
return NULL;
}
return slot;
}
int xe::cpu::ppc::RegisterInstrDisassemble(
uint32_t code, InstrDisassembleFn disassemble) {
InstrType* instr_type = GetInstrType(code);
XEASSERTNOTNULL(instr_type);
if (!instr_type) {
return 1;
}
XEASSERTNULL(instr_type->disassemble);
instr_type->disassemble = disassemble;
return 0;
}
int xe::cpu::ppc::RegisterInstrEmit(uint32_t code, InstrEmitFn emit) {
InstrType* instr_type = GetInstrType(code);
XEASSERTNOTNULL(instr_type);
if (!instr_type) {
return 1;
}
XEASSERTNULL(instr_type->emit);
instr_type->emit = emit;
return 0;
}

328
src/xenia/cpu/ppc/instr.h Normal file
View File

@@ -0,0 +1,328 @@
/**
******************************************************************************
* 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>
#include <string>
#include <vector>
namespace xe {
namespace cpu {
namespace ppc {
// 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,
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;
class InstrType;
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);
}
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;
}
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
// 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
// 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 : 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 : 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;
// kXEPPCInstrFormatVA
// kXEPPCInstrFormatVX
// kXEPPCInstrFormatVXR
};
} 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;
union {
InstrRegister reg;
struct {
bool is_signed;
uint64_t value;
size_t width;
} imm;
};
char display[32];
} InstrOperand;
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);
};
class InstrDisasm {
public:
enum Flags {
kOE = 1 << 0,
kRc = 1 << 1,
kCA = 1 << 2,
kLR = 1 << 4,
};
char name[16];
char info[64];
std::vector<InstrOperand> operands;
std::vector<InstrRegister> special_registers;
InstrAccessBits access_bits;
void Init(std::string name, std::string info, uint32_t flags);
void AddLR(InstrRegister::Access access);
void AddCTR(InstrRegister::Access access);
void AddCR(uint32_t bf, InstrRegister::Access access);
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;
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];
InstrDisassembleFn disassemble;
InstrEmitFn emit;
};
InstrType* GetInstrType(uint32_t code);
int RegisterInstrDisassemble(uint32_t code, InstrDisassembleFn disassemble);
int RegisterInstrEmit(uint32_t code, InstrEmitFn emit);
} // namespace ppc
} // namespace cpu
} // namespace xe
#endif // XENIA_CPU_PPC_INSTR_H_

View File

@@ -0,0 +1,342 @@
/**
******************************************************************************
* 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_TABLE_H_
#define XENIA_CPU_PPC_INSTR_TABLE_H_
#include <xenia/cpu/ppc/instr.h>
namespace xe {
namespace cpu {
namespace ppc {
namespace tables {
static InstrType* instr_table_prep(
InstrType* unprep, int unprep_count, int a, int b) {
int prep_count = pow(2.0, b - a + 1);
InstrType* prep = (InstrType*)xe_calloc(prep_count * sizeof(InstrType));
for (int n = 0; n < unprep_count; n++) {
int ordinal = XESELECTBITS(unprep[n].opcode, a, b);
prep[ordinal] = unprep[n];
}
return prep;
}
#define EMPTY(slot) {0}
#define INSTRUCTION(name, opcode, format, type, flag) { \
opcode, \
kXEPPCInstrFormat##format, \
kXEPPCInstrType##type, \
flag, \
#name, \
}
#define FLAG(t) kXEPPCInstrFlag##t
// This table set is constructed from:
// pem_64bit_v3.0.2005jul15.pdf, A.2
// PowerISA_V2.06B_V2_PUBLIC.pdf
// Opcode = 4, index = bits 5-0 (6)
static InstrType instr_table_4_unprep[] = {
// TODO: all of the vector ops
INSTRUCTION(vperm, 0x1000002B, VA , General , 0),
};
static InstrType* instr_table_4 = instr_table_prep(
instr_table_4_unprep, XECOUNT(instr_table_4_unprep), 0, 5);
// Opcode = 19, index = bits 10-1 (10)
static InstrType instr_table_19_unprep[] = {
INSTRUCTION(mcrf, 0x4C000000, XL , General , 0),
INSTRUCTION(bclrx, 0x4C000020, XL , BranchCond , 0),
INSTRUCTION(crnor, 0x4C000042, XL , General , 0),
INSTRUCTION(crandc, 0x4C000102, XL , General , 0),
INSTRUCTION(isync, 0x4C00012C, XL , General , 0),
INSTRUCTION(crxor, 0x4C000182, XL , General , 0),
INSTRUCTION(crnand, 0x4C0001C2, XL , General , 0),
INSTRUCTION(crand, 0x4C000202, XL , General , 0),
INSTRUCTION(creqv, 0x4C000242, XL , General , 0),
INSTRUCTION(crorc, 0x4C000342, XL , General , 0),
INSTRUCTION(cror, 0x4C000382, XL , General , 0),
INSTRUCTION(bcctrx, 0x4C000420, XL , BranchCond , 0),
};
static InstrType* instr_table_19 = instr_table_prep(
instr_table_19_unprep, XECOUNT(instr_table_19_unprep), 1, 10);
// Opcode = 30, index = bits 4-1 (4)
static InstrType instr_table_30_unprep[] = {
INSTRUCTION(rldiclx, 0x78000000, MD , General , 0),
INSTRUCTION(rldicrx, 0x78000004, MD , General , 0),
INSTRUCTION(rldicx, 0x78000008, MD , General , 0),
INSTRUCTION(rldimix, 0x7800000C, MD , General , 0),
INSTRUCTION(rldclx, 0x78000010, MDS, General , 0),
INSTRUCTION(rldcrx, 0x78000012, MDS, General , 0),
};
static InstrType* instr_table_30 = instr_table_prep(
instr_table_30_unprep, XECOUNT(instr_table_30_unprep), 1, 4);
// Opcode = 31, index = bits 10-1 (10)
static InstrType instr_table_31_unprep[] = {
INSTRUCTION(cmp, 0x7C000000, X , General , 0),
INSTRUCTION(tw, 0x7C000008, X , General , 0),
INSTRUCTION(lvsl, 0x7C00000C, X , General , 0),
INSTRUCTION(lvebx, 0x7C00000E, X , General , 0),
INSTRUCTION(subfcx, 0x7C000010, XO , General , 0),
INSTRUCTION(mulhdux, 0x7C000012, XO , General , 0),
INSTRUCTION(addcx, 0X7C000014, XO , General , 0),
INSTRUCTION(mulhwux, 0x7C000016, XO , General , 0),
INSTRUCTION(mfcr, 0x7C000026, X , General , 0),
INSTRUCTION(lwarx, 0x7C000028, X , General , 0),
INSTRUCTION(ldx, 0x7C00002A, X , General , 0),
INSTRUCTION(lwzx, 0x7C00002E, X , General , 0),
INSTRUCTION(slwx, 0x7C000030, X , General , 0),
INSTRUCTION(cntlzwx, 0x7C000034, X , General , 0),
INSTRUCTION(sldx, 0x7C000036, X , General , 0),
INSTRUCTION(andx, 0x7C000038, X , General , 0),
INSTRUCTION(cmpl, 0x7C000040, X , General , 0),
INSTRUCTION(lvsr, 0x7C00004C, X , General , 0),
INSTRUCTION(lvehx, 0x7C00004E, X , General , 0),
INSTRUCTION(subfx, 0x7C000050, XO , General , 0),
INSTRUCTION(ldux, 0x7C00006A, X , General , 0),
INSTRUCTION(dcbst, 0x7C00006C, X , General , 0),
INSTRUCTION(lwzux, 0x7C00006E, X , General , 0),
INSTRUCTION(cntlzdx, 0x7C000074, X , General , 0),
INSTRUCTION(andcx, 0x7C000078, X , General , 0),
INSTRUCTION(td, 0x7C000088, X , General , 0),
INSTRUCTION(lvewx, 0x7C00008E, X , General , 0),
INSTRUCTION(mulhdx, 0x7C000092, XO , General , 0),
INSTRUCTION(mulhwx, 0x7C000096, XO , General , 0),
INSTRUCTION(ldarx, 0x7C0000A8, X , General , 0),
INSTRUCTION(dcbf, 0x7C0000AC, X , General , 0),
INSTRUCTION(lbzx, 0x7C0000AE, X , General , 0),
INSTRUCTION(lvx, 0x7C0000CE, X , General , 0),
INSTRUCTION(negx, 0x7C0000D0, XO , General , 0),
INSTRUCTION(lbzux, 0x7C0000EE, X , General , 0),
INSTRUCTION(norx, 0x7C0000F8, X , General , 0),
INSTRUCTION(stvebx, 0x7C00010E, X , General , 0),
INSTRUCTION(subfex, 0x7C000110, XO , General , 0),
INSTRUCTION(addex, 0x7C000114, XO , General , 0),
INSTRUCTION(mtcrf, 0x7C000120, XFX, General , 0),
INSTRUCTION(stdx, 0x7C00012A, X , General , 0),
INSTRUCTION(stwcx, 0x7C00012D, X , General , 0),
INSTRUCTION(stwx, 0x7C00012E, X , General , 0),
INSTRUCTION(stvehx, 0x7C00014E, X , General , 0),
INSTRUCTION(stdux, 0x7C00016A, X , General , 0),
INSTRUCTION(stwux, 0x7C00016E, X , General , 0),
INSTRUCTION(stvewx, 0x7C00018E, X , General , 0),
INSTRUCTION(subfzex, 0x7C000190, XO , General , 0),
INSTRUCTION(addzex, 0x7C000194, XO , General , 0),
INSTRUCTION(stdcx, 0x7C0001AD, X , General , 0),
INSTRUCTION(stbx, 0x7C0001AE, X , General , 0),
INSTRUCTION(stvx, 0x7C0001CE, X , General , 0),
INSTRUCTION(subfmex, 0x7C0001D0, XO , General , 0),
INSTRUCTION(mulldx, 0x7C0001D2, XO , General , 0),
INSTRUCTION(addmex, 0x7C0001D4, XO , General , 0),
INSTRUCTION(mullwx, 0x7C0001D6, XO , General , 0),
INSTRUCTION(dcbtst, 0x7C0001EC, X , General , 0),
INSTRUCTION(stbux, 0x7C0001EE, X , General , 0),
INSTRUCTION(addx, 0x7C000214, XO , General , 0),
INSTRUCTION(dcbt, 0x7C00022C, X , General , 0),
INSTRUCTION(lhzx, 0x7C00022E, X , General , 0),
INSTRUCTION(eqvx, 0x7C000238, X , General , 0),
INSTRUCTION(eciwx, 0x7C00026C, X , General , 0),
INSTRUCTION(lhzux, 0x7C00026E, X , General , 0),
INSTRUCTION(xorx, 0x7C000278, X , General , 0),
INSTRUCTION(mfspr, 0x7C0002A6, XFX, General , 0),
INSTRUCTION(lwax, 0x7C0002AA, X , General , 0),
INSTRUCTION(lhax, 0x7C0002AE, X , General , 0),
INSTRUCTION(lvxl, 0x7C0002CE, X , General , 0),
INSTRUCTION(mftb, 0x7C0002E6, XFX, General , 0),
INSTRUCTION(lwaux, 0x7C0002EA, X , General , 0),
INSTRUCTION(lhaux, 0x7C0002EE, X , General , 0),
INSTRUCTION(sthx, 0x7C00032E, X , General , 0),
INSTRUCTION(orcx, 0x7C000338, X , General , 0),
INSTRUCTION(ecowx, 0x7C00036C, X , General , 0),
INSTRUCTION(sthux, 0x7C00036E, X , General , 0),
INSTRUCTION(orx, 0x7C000378, X , General , 0),
INSTRUCTION(divdux, 0x7C000392, XO , General , 0),
INSTRUCTION(divwux, 0x7C000396, XO , General , 0),
INSTRUCTION(mtspr, 0x7C0003A6, XFX, General , 0),
INSTRUCTION(nandx, 0x7C0003B8, X , General , 0),
INSTRUCTION(stvxl, 0x7C0003CE, X , General , 0),
INSTRUCTION(divdx, 0x7C0003D2, XO , General , 0),
INSTRUCTION(divwx, 0x7C0003D6, XO , General , 0),
INSTRUCTION(lvlx, 0x7C00040E, X , General , 0),
INSTRUCTION(ldbrx, 0x7C000428, X , General , 0),
INSTRUCTION(lswx, 0x7C00042A, X , General , 0),
INSTRUCTION(lwbrx, 0x7C00042C, X , General , 0),
INSTRUCTION(lfsx, 0x7C00042E, X , General , 0),
INSTRUCTION(srwx, 0x7C000430, X , General , 0),
INSTRUCTION(srdx, 0x7C000436, X , General , 0),
INSTRUCTION(lfsux, 0x7C00046E, X , General , 0),
INSTRUCTION(lswi, 0x7C0004AA, X , General , 0),
INSTRUCTION(sync, 0x7C0004AC, X , General , 0),
INSTRUCTION(lfdx, 0x7C0004AE, X , General , 0),
INSTRUCTION(lfdux, 0x7C0004EE, X , General , 0),
INSTRUCTION(stdbrx, 0x7C000528, X , General , 0),
INSTRUCTION(stswx, 0x7C00052A, X , General , 0),
INSTRUCTION(stwbrx, 0x7C00052C, X , General , 0),
INSTRUCTION(stfsx, 0x7C00052E, X , General , 0),
INSTRUCTION(stfsux, 0x7C00056E, X , General , 0),
INSTRUCTION(stswi, 0x7C0005AA, X , General , 0),
INSTRUCTION(stfdx, 0x7C0005AE, X , General , 0),
INSTRUCTION(stfdux, 0x7C0005EE, X , General , 0),
INSTRUCTION(lhbrx, 0x7C00062C, X , General , 0),
INSTRUCTION(srawx, 0x7C000630, X , General , 0),
INSTRUCTION(sradx, 0x7C000634, X , General , 0),
INSTRUCTION(srawix, 0x7C000670, X , General , 0),
INSTRUCTION(sradix, 0x7C000674, XS , General , 0), // TODO
INSTRUCTION(eieio, 0x7C0006AC, X , General , 0),
INSTRUCTION(sthbrx, 0x7C00072C, X , General , 0),
INSTRUCTION(extshx, 0x7C000734, X , General , 0),
INSTRUCTION(extsbx, 0x7C000774, X , General , 0),
INSTRUCTION(icbi, 0x7C0007AC, X , General , 0),
INSTRUCTION(stfiwx, 0x7C0007AE, X , General , 0),
INSTRUCTION(extswx, 0x7C0007B4, X , General , 0),
INSTRUCTION(dcbz, 0x7C0007EC, X , General , 0), // 0x7C2007EC = DCBZ128
};
static InstrType* instr_table_31 = instr_table_prep(
instr_table_31_unprep, XECOUNT(instr_table_31_unprep), 1, 10);
// Opcode = 58, index = bits 1-0 (2)
static InstrType instr_table_58_unprep[] = {
INSTRUCTION(ld, 0xE8000000, DS , General , 0),
INSTRUCTION(ldu, 0xE8000001, DS , General , 0),
INSTRUCTION(lwa, 0xE8000002, DS , General , 0),
};
static InstrType* instr_table_58 = instr_table_prep(
instr_table_58_unprep, XECOUNT(instr_table_58_unprep), 0, 1);
// Opcode = 59, index = bits 5-1 (5)
static InstrType instr_table_59_unprep[] = {
INSTRUCTION(fdivsx, 0xEC000024, A , General , 0),
INSTRUCTION(fsubsx, 0xEC000028, A , General , 0),
INSTRUCTION(faddsx, 0xEC00002A, A , General , 0),
INSTRUCTION(fsqrtsx, 0xEC00002C, A , General , 0),
INSTRUCTION(fresx, 0xEC000030, A , General , 0),
INSTRUCTION(fmulsx, 0xEC000032, A , General , 0),
INSTRUCTION(fmsubsx, 0xEC000038, A , General , 0),
INSTRUCTION(fmaddsx, 0xEC00003A, A , General , 0),
INSTRUCTION(fnmsubsx, 0xEC00003C, A , General , 0),
INSTRUCTION(fnmaddsx, 0xEC00003E, A , General , 0),
};
static InstrType* instr_table_59 = instr_table_prep(
instr_table_59_unprep, XECOUNT(instr_table_59_unprep), 1, 5);
// Opcode = 62, index = bits 1-0 (2)
static InstrType instr_table_62_unprep[] = {
INSTRUCTION(std, 0xF8000000, DS , General , 0),
INSTRUCTION(stdu, 0xF8000001, DS , General , 0),
};
static InstrType* instr_table_62 = instr_table_prep(
instr_table_62_unprep, XECOUNT(instr_table_62_unprep), 0, 1);
// Opcode = 63, index = bits 10-1 (10)
static InstrType instr_table_63_unprep[] = {
INSTRUCTION(fcmpu, 0xFC000000, X , General , 0),
INSTRUCTION(frspx, 0xFC000018, X , General , 0),
INSTRUCTION(fctiwx, 0xFC00001C, X , General , 0),
INSTRUCTION(fctiwzx, 0xFC00001E, X , General , 0),
INSTRUCTION(fdivx, 0xFC000024, A , General , 0),
INSTRUCTION(fsubx, 0xFC000028, A , General , 0),
INSTRUCTION(faddx, 0xFC00002A, A , General , 0),
INSTRUCTION(fsqrtx, 0xFC00002C, A , General , 0),
INSTRUCTION(fselx, 0xFC00002E, A , General , 0),
INSTRUCTION(fmulx, 0xFC000032, A , General , 0),
INSTRUCTION(frsqrtex, 0xFC000034, A , General , 0),
INSTRUCTION(fmsubx, 0xFC000038, A , General , 0),
INSTRUCTION(fmaddx, 0xFC00003A, A , General , 0),
INSTRUCTION(fnmsubx, 0xFC00003C, A , General , 0),
INSTRUCTION(fnmaddx, 0xFC00003E, A , General , 0),
INSTRUCTION(fcmpo, 0xFC000040, X , General , 0),
INSTRUCTION(mtfsb1x, 0xFC00004C, X , General , 0),
INSTRUCTION(fnegx, 0xFC000050, X , General , 0),
INSTRUCTION(mcrfs, 0xFC000080, X , General , 0),
INSTRUCTION(mtfsb0x, 0xFC00008C, X , General , 0),
INSTRUCTION(fmrx, 0xFC000090, X , General , 0),
INSTRUCTION(mtfsfix, 0xFC00010C, X , General , 0),
INSTRUCTION(fnabsx, 0xFC000110, X , General , 0),
INSTRUCTION(fabsx, 0xFC000210, X , General , 0),
INSTRUCTION(mffsx, 0xFC00048E, X , General , 0),
INSTRUCTION(mtfsfx, 0xFC00058E, XFL, General , 0),
INSTRUCTION(fctidx, 0xFC00065C, X , General , 0),
INSTRUCTION(fctidzx, 0xFC00065E, X , General , 0),
INSTRUCTION(fcfidx, 0xFC00069C, X , General , 0),
};
static InstrType* instr_table_63 = instr_table_prep(
instr_table_63_unprep, XECOUNT(instr_table_63_unprep), 1, 10);
// Main table, index = bits 31-26 (6) : (code >> 26)
static InstrType instr_table_unprep[64] = {
INSTRUCTION(tdi, 0x08000000, D , General , 0),
INSTRUCTION(twi, 0x0C000000, D , General , 0),
INSTRUCTION(mulli, 0x1C000000, D , General , 0),
INSTRUCTION(subficx, 0x20000000, D , General , 0),
INSTRUCTION(cmpli, 0x28000000, D , General , 0),
INSTRUCTION(cmpi, 0x2C000000, D , General , 0),
INSTRUCTION(addic, 0x30000000, D , General , 0),
INSTRUCTION(addicx, 0x34000000, D , General , 0),
INSTRUCTION(addi, 0x38000000, D , General , 0),
INSTRUCTION(addis, 0x3C000000, D , General , 0),
INSTRUCTION(bcx, 0x40000000, B , BranchCond , 0),
INSTRUCTION(sc, 0x44000002, SC , Syscall , 0),
INSTRUCTION(bx, 0x48000000, I , BranchAlways , 0),
INSTRUCTION(rlwimix, 0x50000000, M , General , 0),
INSTRUCTION(rlwinmx, 0x54000000, M , General , 0),
INSTRUCTION(rlwnmx, 0x5C000000, M , General , 0),
INSTRUCTION(ori, 0x60000000, D , General , 0),
INSTRUCTION(oris, 0x64000000, D , General , 0),
INSTRUCTION(xori, 0x68000000, D , General , 0),
INSTRUCTION(xoris, 0x6C000000, D , General , 0),
INSTRUCTION(andix, 0x70000000, D , General , 0),
INSTRUCTION(andisx, 0x74000000, D , General , 0),
INSTRUCTION(lwz, 0x80000000, D , General , 0),
INSTRUCTION(lwzu, 0x84000000, D , General , 0),
INSTRUCTION(lbz, 0x88000000, D , General , 0),
INSTRUCTION(lbzu, 0x8C000000, D , General , 0),
INSTRUCTION(stw, 0x90000000, D , General , 0),
INSTRUCTION(stwu, 0x94000000, D , General , 0),
INSTRUCTION(stb, 0x98000000, D , General , 0),
INSTRUCTION(stbu, 0x9C000000, D , General , 0),
INSTRUCTION(lhz, 0xA0000000, D , General , 0),
INSTRUCTION(lhzu, 0xA4000000, D , General , 0),
INSTRUCTION(lha, 0xA8000000, D , General , 0),
INSTRUCTION(lhau, 0xAC000000, D , General , 0),
INSTRUCTION(sth, 0xB0000000, D , General , 0),
INSTRUCTION(sthu, 0xB4000000, D , General , 0),
INSTRUCTION(lmw, 0xB8000000, D , General , 0),
INSTRUCTION(stmw, 0xBC000000, D , General , 0),
INSTRUCTION(lfs, 0xC0000000, D , General , 0),
INSTRUCTION(lfsu, 0xC4000000, D , General , 0),
INSTRUCTION(lfd, 0xC8000000, D , General , 0),
INSTRUCTION(lfdu, 0xCC000000, D , General , 0),
INSTRUCTION(stfs, 0xD0000000, D , General , 0),
INSTRUCTION(stfsu, 0xD4000000, D , General , 0),
INSTRUCTION(stfd, 0xD8000000, D , General , 0),
INSTRUCTION(stfdu, 0xDC000000, D , General , 0),
};
static InstrType* instr_table = instr_table_prep(
instr_table_unprep, XECOUNT(instr_table_unprep), 26, 31);
#undef FLAG
#undef INSTRUCTION
#undef EMPTY
} // namespace tables
} // namespace ppc
} // namespace cpu
} // namespace xe
#endif // XENIA_CPU_PPC_INSTR_TABLE_H_

View File

@@ -0,0 +1,10 @@
# Copyright 2013 Ben Vanik. All Rights Reserved.
{
'sources': [
'instr.cc',
'instr.h',
'instr_tables.h',
'state.cc',
'state.h',
],
}

View File

@@ -0,0 +1,47 @@
/**
******************************************************************************
* 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. *
******************************************************************************
*/
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/cpu/ppc/state.h>
namespace {
uint64_t ParseInt64(const char* value) {
return xestrtoulla(value, NULL, 0);
}
}
void xe_ppc_state::SetRegFromString(const char* name, const char* value) {
int n;
if (sscanf(name, "r%d", &n) == 1) {
this->r[n] = ParseInt64(value);
} else {
printf("Unrecognized register name: %s\n", name);
}
}
bool xe_ppc_state::CompareRegWithString(
const char* name, const char* value,
char* out_value, size_t out_value_size) {
int n;
if (sscanf(name, "r%d", &n) == 1) {
uint64_t expected = ParseInt64(value);
if (this->r[n] != expected) {
xesnprintfa(out_value, out_value_size, "%016llX", this->r[n]);
return false;
}
return true;
} else {
printf("Unrecognized register name: %s\n", name);
return false;
}
}

169
src/xenia/cpu/ppc/state.h Normal file
View File

@@ -0,0 +1,169 @@
/**
******************************************************************************
* 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_STATE_H_
#define XENIA_CPU_PPC_STATE_H_
/**
* NOTE: this file is included by xethunk and as such should have a *MINIMAL*
* set of dependencies!
*/
#include <stdint.h>
#ifdef XE_THUNK
#define XECACHEALIGN __attribute__ ((aligned(8)))
#define XECACHEALIGN64 __attribute__ ((aligned(64)))
#endif
// namespace FPRF {
// enum FPRF_e {
// QUIET_NAN = 0x00088000,
// NEG_INFINITY = 0x00090000,
// NEG_NORMALIZED = 0x00010000,
// NEG_DENORMALIZED = 0x00018000,
// NEG_ZERO = 0x00048000,
// POS_ZERO = 0x00040000,
// POS_DENORMALIZED = 0x00028000,
// POS_NORMALIZED = 0x00020000,
// POS_INFINITY = 0x000A0000,
// };
// } // FPRF
#define kXEPPCRegLR 0xFFFF0001
#define kXEPPCRegCTR 0xFFFF0002
typedef struct XECACHEALIGN xe_float4 {
union {
struct {
float x;
float y;
float z;
float w;
};
float f4[4];
struct {
uint64_t low;
uint64_t high;
};
};
} xe_float4_t;
typedef struct XECACHEALIGN64 xe_ppc_state {
uint32_t cia; // Current PC (CIA)
uint32_t nia; // Next PC (NIA)
uint64_t xer; // XER register
uint64_t lr; // Link register
uint64_t ctr; // Count register
uint64_t r[32]; // General purpose registers
xe_float4_t v[128]; // VMX128 vector registers
double f[32]; // Floating-point registers
union {
uint32_t value;
struct {
uint8_t lt :1; // Negative (LT) - result is negative
uint8_t gt :1; // Positive (GT) - result is positive (and not zero)
uint8_t eq :1; // Zero (EQ) - result is zero or a stwcx/stdcx completed successfully
uint8_t so :1; // Summary Overflow (SO) - copy of XER[SO]
} cr0;
struct {
uint8_t fx :1; // FP exception summary - copy of FPSCR[FX]
uint8_t fex :1; // FP enabled exception summary - copy of FPSCR[FEX]
uint8_t vx :1; // FP invalid operation exception summary - copy of FPSCR[VX]
uint8_t ox :1; // FP overflow exception - copy of FPSCR[OX]
} cr1;
struct {
uint8_t value :4;
} cr2;
struct {
uint8_t value :4;
} cr3;
struct {
uint8_t value :4;
} cr4;
struct {
uint8_t value :4;
} cr5;
struct {
uint8_t value :4;
} cr6;
struct {
uint8_t value :4;
} cr7;
} cr; // Condition register
union {
uint32_t value;
struct {
uint8_t fx :1; // FP exception summary -- sticky
uint8_t fex :1; // FP enabled exception summary
uint8_t vx :1; // FP invalid operation exception summary
uint8_t ox :1; // FP overflow exception -- sticky
uint8_t ux :1; // FP underflow exception -- sticky
uint8_t zx :1; // FP zero divide exception -- sticky
uint8_t xx :1; // FP inexact exception -- sticky
uint8_t vxsnan :1; // FP invalid op exception: SNaN -- sticky
uint8_t vxisi :1; // FP invalid op exception: infinity - infinity -- sticky
uint8_t vxidi :1; // FP invalid op exception: infinity / infinity -- sticky
uint8_t vxzdz :1; // FP invalid op exception: 0 / 0 -- sticky
uint8_t vximz :1; // FP invalid op exception: infinity * 0 -- sticky
uint8_t vxvc :1; // FP invalid op exception: invalid compare -- sticky
uint8_t fr :1; // FP fraction rounded
uint8_t fi :1; // FP fraction inexact
uint8_t fprf_c :1; // FP result class
uint8_t fprf_lt :1; // FP result less than or negative (FL or <)
uint8_t fprf_gt :1; // FP result greater than or positive (FG or >)
uint8_t fprf_eq :1; // FP result equal or zero (FE or =)
uint8_t fprf_un :1; // FP result unordered or NaN (FU or ?)
uint8_t reserved :1;
uint8_t vxsoft :1; // FP invalid op exception: software request -- sticky
uint8_t vxsqrt :1; // FP invalid op exception: invalid sqrt -- sticky
uint8_t vxcvi :1; // FP invalid op exception: invalid integer convert -- sticky
uint8_t ve :1; // FP invalid op exception enable
uint8_t oe :1; // IEEE floating-point overflow exception enable
uint8_t ue :1; // IEEE floating-point underflow exception enable
uint8_t ze :1; // IEEE floating-point zero divide exception enable
uint8_t xe :1; // IEEE floating-point inexact exception enable
uint8_t ni :1; // Floating-point non-IEEE mode
uint8_t rn :2; // FP rounding control: 00 = nearest
// 01 = toward zero
// 10 = toward +infinity
// 11 = toward -infinity
} bits;
} fpscr; // Floating-point status and control register
// uint32_t get_fprf() {
// return fpscr.value & 0x000F8000;
// }
// void set_fprf(const uint32_t v) {
// fpscr.value = (fpscr.value & ~0x000F8000) | v;
// }
// Runtime-specific data pointer. Used on callbacks to get access to the
// current runtime and its data.
uint8_t* membase;
void* processor;
void* thread_state;
void* runtime;
void SetRegFromString(const char* name, const char* value);
bool CompareRegWithString(const char* name, const char* value,
char* out_value, size_t out_value_size);
} xe_ppc_state_t;
#endif // XENIA_CPU_PPC_STATE_H_