Screw convention; moving include files alongside source files.
They now will show up in xcode/etc.
This commit is contained in:
407
src/xenia/cpu/ppc/instr.cc
Normal file
407
src/xenia/cpu/ppc/instr.cc
Normal 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
328
src/xenia/cpu/ppc/instr.h
Normal 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_
|
||||
|
||||
342
src/xenia/cpu/ppc/instr_tables.h
Normal file
342
src/xenia/cpu/ppc/instr_tables.h
Normal 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_
|
||||
10
src/xenia/cpu/ppc/sources.gypi
Normal file
10
src/xenia/cpu/ppc/sources.gypi
Normal file
@@ -0,0 +1,10 @@
|
||||
# Copyright 2013 Ben Vanik. All Rights Reserved.
|
||||
{
|
||||
'sources': [
|
||||
'instr.cc',
|
||||
'instr.h',
|
||||
'instr_tables.h',
|
||||
'state.cc',
|
||||
'state.h',
|
||||
],
|
||||
}
|
||||
47
src/xenia/cpu/ppc/state.cc
Normal file
47
src/xenia/cpu/ppc/state.cc
Normal 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
169
src/xenia/cpu/ppc/state.h
Normal 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_
|
||||
Reference in New Issue
Block a user