Initial Alloy implementation.
This is a regression in functionality and performance, but a much better foundation for the future of the project (I think). It can run basic apps under an SSA interpreter but doesn't support some of the features required to do real 360 apps yet.
This commit is contained in:
33
src/alloy/frontend/frontend.cc
Normal file
33
src/alloy/frontend/frontend.cc
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 <alloy/frontend/frontend.h>
|
||||
|
||||
#include <alloy/frontend/tracing.h>
|
||||
#include <alloy/runtime/runtime.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::frontend;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
|
||||
Frontend::Frontend(Runtime* runtime) :
|
||||
runtime_(runtime) {
|
||||
}
|
||||
|
||||
Frontend::~Frontend() {
|
||||
}
|
||||
|
||||
Memory* Frontend::memory() const {
|
||||
return runtime_->memory();
|
||||
}
|
||||
|
||||
int Frontend::Initialize() {
|
||||
return 0;
|
||||
}
|
||||
52
src/alloy/frontend/frontend.h
Normal file
52
src/alloy/frontend/frontend.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_FRONTEND_FRONTEND_H_
|
||||
#define ALLOY_FRONTEND_FRONTEND_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
#include <alloy/memory.h>
|
||||
#include <alloy/runtime/function.h>
|
||||
#include <alloy/runtime/symbol_info.h>
|
||||
|
||||
|
||||
namespace alloy { namespace runtime {
|
||||
class Runtime;
|
||||
} }
|
||||
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
|
||||
|
||||
class Frontend {
|
||||
public:
|
||||
Frontend(runtime::Runtime* runtime);
|
||||
virtual ~Frontend();
|
||||
|
||||
runtime::Runtime* runtime() const { return runtime_; }
|
||||
Memory* memory() const;
|
||||
|
||||
virtual int Initialize();
|
||||
|
||||
virtual int DeclareFunction(
|
||||
runtime::FunctionInfo* symbol_info) = 0;
|
||||
virtual int DefineFunction(
|
||||
runtime::FunctionInfo* symbol_info,
|
||||
runtime::Function** out_function) = 0;
|
||||
|
||||
protected:
|
||||
runtime::Runtime* runtime_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_FRONTEND_FRONTEND_H_
|
||||
50
src/alloy/frontend/ppc/ppc_context.cc
Normal file
50
src/alloy/frontend/ppc/ppc_context.cc
Normal file
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 <alloy/frontend/ppc/ppc_context.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::frontend;
|
||||
using namespace alloy::frontend::ppc;
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
uint64_t ParseInt64(const char* value) {
|
||||
return xestrtoulla(value, NULL, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void PPCContext::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 PPCContext::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;
|
||||
}
|
||||
}
|
||||
206
src/alloy/frontend/ppc/ppc_context.h
Normal file
206
src/alloy/frontend/ppc/ppc_context.h
Normal file
@@ -0,0 +1,206 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_FRONTEND_PPC_PPC_CONTEXT_H_
|
||||
#define ALLOY_FRONTEND_PPC_PPC_CONTEXT_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
|
||||
|
||||
namespace alloy { namespace runtime {
|
||||
class Runtime;
|
||||
class ThreadState;
|
||||
} }
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
namespace ppc {
|
||||
|
||||
|
||||
using vec128_t = alloy::vec128_t;
|
||||
|
||||
|
||||
typedef 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;
|
||||
} PPCCR;
|
||||
|
||||
|
||||
#pragma pack(push, 4)
|
||||
typedef struct XECACHEALIGN64 PPCContext_s {
|
||||
// Most frequently used registers first.
|
||||
uint64_t r[32]; // General purpose registers
|
||||
uint64_t lr; // Link register
|
||||
uint64_t ctr; // Count register
|
||||
|
||||
// XER register
|
||||
// Split to make it easier to do individual updates.
|
||||
uint8_t xer_ca;
|
||||
uint8_t xer_ov;
|
||||
uint8_t xer_so;
|
||||
|
||||
// Condition registers
|
||||
// These are split to make it easier to do DCE on unused stores.
|
||||
union {
|
||||
uint32_t value;
|
||||
struct {
|
||||
uint8_t cr0_lt; // Negative (LT) - result is negative
|
||||
uint8_t cr0_gt; // Positive (GT) - result is positive (and not zero)
|
||||
uint8_t cr0_eq; // Zero (EQ) - result is zero or a stwcx/stdcx completed successfully
|
||||
uint8_t cr0_so; // Summary Overflow (SO) - copy of XER[SO]
|
||||
};
|
||||
} cr0;
|
||||
union {
|
||||
uint32_t value;
|
||||
struct {
|
||||
uint8_t cr1_fx; // FP exception summary - copy of FPSCR[FX]
|
||||
uint8_t cr1_fex; // FP enabled exception summary - copy of FPSCR[FEX]
|
||||
uint8_t cr1_vx; // FP invalid operation exception summary - copy of FPSCR[VX]
|
||||
uint8_t cr1_ox; // FP overflow exception - copy of FPSCR[OX]
|
||||
};
|
||||
} cr1;
|
||||
union {
|
||||
uint32_t value;
|
||||
struct {
|
||||
uint8_t cr2_0; uint8_t cr2_1; uint8_t cr2_2; uint8_t cr2_3;
|
||||
};
|
||||
} cr2;
|
||||
union {
|
||||
uint32_t value;
|
||||
struct {
|
||||
uint8_t cr3_0; uint8_t cr3_1; uint8_t cr3_2; uint8_t cr3_3;
|
||||
};
|
||||
} cr3;
|
||||
union {
|
||||
uint32_t value;
|
||||
struct {
|
||||
uint8_t cr4_0; uint8_t cr4_1; uint8_t cr4_2; uint8_t cr4_3;
|
||||
};
|
||||
} cr4;
|
||||
union {
|
||||
uint32_t value;
|
||||
struct {
|
||||
uint8_t cr5_0; uint8_t cr5_1; uint8_t cr5_2; uint8_t cr5_3;
|
||||
};
|
||||
} cr5;
|
||||
union {
|
||||
uint32_t value;
|
||||
struct {
|
||||
uint8_t cr6_0;
|
||||
uint8_t cr6_none_equal;
|
||||
uint8_t cr6_2;
|
||||
uint8_t cr6_all_equal;
|
||||
};
|
||||
} cr6;
|
||||
union {
|
||||
uint32_t value;
|
||||
struct {
|
||||
uint8_t cr7_0; uint8_t cr7_1; uint8_t cr7_2; uint8_t cr7_3;
|
||||
};
|
||||
} cr7;
|
||||
|
||||
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
|
||||
|
||||
double f[32]; // Floating-point registers
|
||||
vec128_t v[128]; // VMX128 vector registers
|
||||
|
||||
// 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;
|
||||
runtime::Runtime* runtime;
|
||||
runtime::ThreadState* thread_state;
|
||||
|
||||
void SetRegFromString(const char* name, const char* value);
|
||||
bool CompareRegWithString(const char* name, const char* value,
|
||||
char* out_value, size_t out_value_size);
|
||||
} PPCContext;
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
} // namespace ppc
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_FRONTEND_PPC_PPC_CONTEXT_H_
|
||||
36
src/alloy/frontend/ppc/ppc_disasm-private.h
Normal file
36
src/alloy/frontend/ppc/ppc_disasm-private.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_FRONTEND_PPC_PPC_DISASM_PRIVATE_H_
|
||||
#define ALLOY_FRONTEND_PPC_PPC_DISASM_PRIVATE_H_
|
||||
|
||||
#include <alloy/frontend/ppc/ppc_disasm.h>
|
||||
#include <alloy/frontend/ppc/ppc_instr.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
namespace ppc {
|
||||
|
||||
|
||||
#define XEDISASMR(name, opcode, format) int InstrDisasm_##name
|
||||
|
||||
#define XEREGISTERINSTR(name, opcode) \
|
||||
RegisterInstrDisassemble(opcode, (InstrDisassembleFn)InstrDisasm_##name);
|
||||
|
||||
//#define XEINSTRNOTIMPLEMENTED()
|
||||
#define XEINSTRNOTIMPLEMENTED XEASSERTALWAYS
|
||||
|
||||
|
||||
} // namespace ppc
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_FRONTEND_PPC_PPC_DISASM_PRIVATE_H_
|
||||
33
src/alloy/frontend/ppc/ppc_disasm.h
Normal file
33
src/alloy/frontend/ppc/ppc_disasm.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_FRONTEND_PPC_PPC_DISASM_H_
|
||||
#define ALLOY_FRONTEND_PPC_PPC_DISASM_H_
|
||||
|
||||
#include <alloy/frontend/ppc/ppc_instr.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
namespace ppc {
|
||||
|
||||
|
||||
void RegisterDisasmCategoryAltivec();
|
||||
void RegisterDisasmCategoryALU();
|
||||
void RegisterDisasmCategoryControl();
|
||||
void RegisterDisasmCategoryFPU();
|
||||
void RegisterDisasmCategoryMemory();
|
||||
|
||||
|
||||
} // namespace ppc
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_FRONTEND_PPC_PPC_DISASM_H_
|
||||
1895
src/alloy/frontend/ppc/ppc_disasm_altivec.cc
Normal file
1895
src/alloy/frontend/ppc/ppc_disasm_altivec.cc
Normal file
File diff suppressed because it is too large
Load Diff
728
src/alloy/frontend/ppc/ppc_disasm_alu.cc
Normal file
728
src/alloy/frontend/ppc/ppc_disasm_alu.cc
Normal file
@@ -0,0 +1,728 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
* 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 <alloy/frontend/ppc/ppc_disasm-private.h>
|
||||
|
||||
|
||||
using namespace alloy::frontend::ppc;
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
namespace ppc {
|
||||
|
||||
|
||||
// Integer arithmetic (A-3)
|
||||
|
||||
XEDISASMR(addx, 0x7C000214, XO )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("add", "Add",
|
||||
(i.XO.OE ? InstrDisasm::kOE : 0) | (i.XO.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(addcx, 0x7C000014, XO )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("addc", "Add Carrying",
|
||||
(i.XO.OE ? InstrDisasm::kOE : 0) | (i.XO.Rc ? InstrDisasm::kRc : 0) |
|
||||
InstrDisasm::kCA);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(addex, 0x7C000114, XO )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("adde", "Add Extended",
|
||||
(i.XO.OE ? InstrDisasm::kOE : 0) | (i.XO.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(addi, 0x38000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("addi", "Add Immediate", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RT, InstrRegister::kWrite);
|
||||
if (i.D.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddSImmOperand(0, 4);
|
||||
}
|
||||
d.AddSImmOperand(XEEXTS16(i.D.DS), 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(addic, 0x30000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("addic", "Add Immediate Carrying", InstrDisasm::kCA);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kRead);
|
||||
d.AddSImmOperand(XEEXTS16(i.D.DS), 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(addicx, 0x34000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("addic", "Add Immediate Carrying and Record",
|
||||
InstrDisasm::kRc | InstrDisasm::kCA);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kRead);
|
||||
d.AddSImmOperand(XEEXTS16(i.D.DS), 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(addis, 0x3C000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("addis", "Add Immediate Shifted", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RT, InstrRegister::kWrite);
|
||||
if (i.D.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddSImmOperand(0, 4);
|
||||
}
|
||||
d.AddSImmOperand(XEEXTS16(i.D.DS), 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(addmex, 0x7C0001D4, XO )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("addme", "Add to Minus One Extended",
|
||||
(i.XO.OE ? InstrDisasm::kOE : 0) | (i.XO.Rc ? InstrDisasm::kRc : 0) |
|
||||
InstrDisasm::kCA);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RA, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(addzex, 0x7C000194, XO )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("addze", "Add to Zero Extended",
|
||||
(i.XO.OE ? InstrDisasm::kOE : 0) | (i.XO.Rc ? InstrDisasm::kRc : 0) |
|
||||
InstrDisasm::kCA);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RA, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(divdx, 0x7C0003D2, XO )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("divd", "Divide Doubleword",
|
||||
(i.XO.OE ? InstrDisasm::kOE : 0) | (i.XO.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(divdux, 0x7C000392, XO )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("divdu", "Divide Doubleword Unsigned",
|
||||
(i.XO.OE ? InstrDisasm::kOE : 0) | (i.XO.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(divwx, 0x7C0003D6, XO )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("divw", "Divide Word",
|
||||
(i.XO.OE ? InstrDisasm::kOE : 0) | (i.XO.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(divwux, 0x7C000396, XO )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("divwu", "Divide Word Unsigned",
|
||||
(i.XO.OE ? InstrDisasm::kOE : 0) | (i.XO.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(mulhdx, 0x7C000092, XO )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("mulhd", "Multiply High Doubleword", i.XO.Rc ? InstrDisasm::kRc : 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(mulhdux, 0x7C000012, XO )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("mulhdu", "Multiply High Doubleword Unsigned",
|
||||
i.XO.Rc ? InstrDisasm::kRc : 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(mulhwx, 0x7C000096, XO )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("mulhw", "Multiply High Word", i.XO.Rc ? InstrDisasm::kRc : 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(mulhwux, 0x7C000016, XO )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("mulhwu", "Multiply High Word Unsigned",
|
||||
i.XO.Rc ? InstrDisasm::kRc : 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(mulldx, 0x7C0001D2, XO )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("mulld", "Multiply Low Doubleword",
|
||||
(i.XO.OE ? InstrDisasm::kOE : 0) | (i.XO.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(mulli, 0x1C000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("mulli", "Multiply Low Immediate", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kRead);
|
||||
d.AddSImmOperand(XEEXTS16(i.D.DS), 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(mullwx, 0x7C0001D6, XO )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("mullw", "Multiply Low Word",
|
||||
(i.XO.OE ? InstrDisasm::kOE : 0) | (i.XO.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(negx, 0x7C0000D0, XO )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("neg", "Negate",
|
||||
(i.XO.OE ? InstrDisasm::kOE : 0) | (i.XO.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RA, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(subfx, 0x7C000050, XO )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("subf", "Subtract From",
|
||||
(i.XO.OE ? InstrDisasm::kOE : 0) | (i.XO.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(subfcx, 0x7C000010, XO )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("subfc", "Subtract From Carrying",
|
||||
(i.XO.OE ? InstrDisasm::kOE : 0) | (i.XO.Rc ? InstrDisasm::kRc : 0) |
|
||||
InstrDisasm::kCA);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(subficx, 0x20000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("subfic", "Subtract From Immediate Carrying", InstrDisasm::kCA);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kRead);
|
||||
d.AddSImmOperand(XEEXTS16(i.D.DS), 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(subfex, 0x7C000110, XO )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("subfe", "Subtract From Extended",
|
||||
(i.XO.OE ? InstrDisasm::kOE : 0) | (i.XO.Rc ? InstrDisasm::kRc : 0) |
|
||||
InstrDisasm::kCA);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(subfmex, 0x7C0001D0, XO )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("subfme", "Subtract From Minus One Extended",
|
||||
(i.XO.OE ? InstrDisasm::kOE : 0) | (i.XO.Rc ? InstrDisasm::kRc : 0) |
|
||||
InstrDisasm::kCA);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RA, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(subfzex, 0x7C000190, XO )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("subfze", "Subtract From Zero Extended",
|
||||
(i.XO.OE ? InstrDisasm::kOE : 0) | (i.XO.Rc ? InstrDisasm::kRc : 0) |
|
||||
InstrDisasm::kCA);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XO.RA, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
|
||||
// Integer compare (A-4)
|
||||
|
||||
XEDISASMR(cmp, 0x7C000000, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("cmp", "Compare", 0);
|
||||
d.AddCR(i.X.RT >> 2, InstrRegister::kWrite);
|
||||
d.AddUImmOperand(i.X.RT >> 2, 1);
|
||||
d.AddUImmOperand(i.X.RT & 1, 1);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(cmpi, 0x2C000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("cmpi", "Compare Immediate", 0);
|
||||
d.AddCR(i.D.RT >> 2, InstrRegister::kWrite);
|
||||
d.AddUImmOperand(i.D.RT >> 2, 1);
|
||||
d.AddUImmOperand(i.D.RT & 1, 1);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kRead);
|
||||
d.AddSImmOperand(XEEXTS16(i.D.DS), 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(cmpl, 0x7C000040, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("cmpl", "Compare Logical", 0);
|
||||
d.AddCR(i.X.RT >> 2, InstrRegister::kWrite);
|
||||
d.AddUImmOperand(i.X.RT >> 2, 1);
|
||||
d.AddUImmOperand(i.X.RT & 1, 1);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(cmpli, 0x28000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("cmpli", "Compare Logical Immediate", 0);
|
||||
d.AddCR(i.D.RT >> 2, InstrRegister::kWrite);
|
||||
d.AddUImmOperand(i.D.RT >> 2, 1);
|
||||
d.AddUImmOperand(i.D.RT & 1, 1);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kRead);
|
||||
d.AddSImmOperand(i.D.DS, 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
|
||||
// Integer logical (A-5)
|
||||
|
||||
XEDISASMR(andx, 0x7C000038, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("and", "AND", i.X.Rc ? InstrDisasm::kRc : 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(andcx, 0x7C000078, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("andc", "AND with Complement", i.X.Rc ? InstrDisasm::kRc : 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(andix, 0x70000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("andi", "AND Immediate", 0);
|
||||
d.AddCR(0, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RT, InstrRegister::kRead);
|
||||
d.AddUImmOperand(i.D.DS, 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(andisx, 0x74000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("andi", "AND Immediate Shifted", 0);
|
||||
d.AddCR(0, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RT, InstrRegister::kRead);
|
||||
d.AddUImmOperand(i.D.DS, 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(cntlzdx, 0x7C000074, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("cntlzd", "Count Leading Zeros Doubleword",
|
||||
i.X.Rc ? InstrDisasm::kRc : 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(cntlzwx, 0x7C000034, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("cntlzw", "Count Leading Zeros Word",
|
||||
i.X.Rc ? InstrDisasm::kRc : 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(eqvx, 0x7C000238, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("eqv", "Equivalent", i.X.Rc ? InstrDisasm::kRc : 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(extsbx, 0x7C000774, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("extsb", "Extend Sign Byte", i.X.Rc ? InstrDisasm::kRc : 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(extshx, 0x7C000734, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("extsh", "Extend Sign Halfword", i.X.Rc ? InstrDisasm::kRc : 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(extswx, 0x7C0007B4, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("extsw", "Extend Sign Word", i.X.Rc ? InstrDisasm::kRc : 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(nandx, 0x7C0003B8, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("nand", "NAND", i.X.Rc ? InstrDisasm::kRc : 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(norx, 0x7C0000F8, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("nor", "NOR", i.X.Rc ? InstrDisasm::kRc : 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(orx, 0x7C000378, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("or", "OR", i.X.Rc ? InstrDisasm::kRc : 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(orcx, 0x7C000338, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("orc", "OR with Complement", i.X.Rc ? InstrDisasm::kRc : 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(ori, 0x60000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
if (!i.D.RA && !i.D.RT && !i.D.DS) {
|
||||
d.Init("no-op", "OR Immediate", 0);
|
||||
} else {
|
||||
d.Init("ori", "OR Immediate", 0);
|
||||
}
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RT, InstrRegister::kRead);
|
||||
d.AddUImmOperand(i.D.DS, 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(oris, 0x64000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("oris", "OR Immediate Shifted", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RT, InstrRegister::kRead);
|
||||
d.AddUImmOperand(i.D.DS, 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(xorx, 0x7C000278, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("xor", "XOR", i.X.Rc ? InstrDisasm::kRc : 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(xori, 0x68000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
if (!i.D.RA && !i.D.RT && !i.D.DS) {
|
||||
d.Init("xnop", "XOR Immediate", 0);
|
||||
} else {
|
||||
d.Init("xori", "XOR Immediate", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RT, InstrRegister::kRead);
|
||||
d.AddUImmOperand(i.D.DS, 2);
|
||||
}
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(xoris, 0x6C000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("xoris", "XOR Immediate Shifted", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RT, InstrRegister::kRead);
|
||||
d.AddUImmOperand(i.D.DS, 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
|
||||
// Integer rotate (A-6)
|
||||
|
||||
XEDISASMR(rld, 0x78000000, MDS)(InstrData& i, InstrDisasm& d) {
|
||||
if (i.MD.idx == 0) {
|
||||
// XEDISASMR(rldiclx, 0x78000000, MD )
|
||||
d.Init("rldicl", "Rotate Left Doubleword Immediate then Clear Left",
|
||||
i.MD.Rc ? InstrDisasm::kRc : 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.MD.RA, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.MD.RT, InstrRegister::kRead);
|
||||
d.AddUImmOperand((i.MD.SH5 << 5) | i.MD.SH, 1);
|
||||
d.AddUImmOperand((i.MD.MB5 << 5) | i.MD.MB, 1);
|
||||
return d.Finish();
|
||||
} else if (i.MD.idx == 1) {
|
||||
// XEDISASMR(rldicrx, 0x78000004, MD )
|
||||
d.Init("rldicr", "Rotate Left Doubleword Immediate then Clear Right",
|
||||
i.MD.Rc ? InstrDisasm::kRc : 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.MD.RA, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.MD.RT, InstrRegister::kRead);
|
||||
d.AddUImmOperand((i.MD.SH5 << 5) | i.MD.SH, 1);
|
||||
d.AddUImmOperand((i.MD.MB5 << 5) | i.MD.MB, 1);
|
||||
return d.Finish();
|
||||
} else if (i.MD.idx == 2) {
|
||||
// XEDISASMR(rldicx, 0x78000008, MD )
|
||||
const char* name;
|
||||
const char* desc;
|
||||
uint32_t sh = (i.MD.SH5 << 5) | i.MD.SH;
|
||||
uint32_t mb = (i.MD.MB5 << 5) | i.MD.MB;
|
||||
if (mb == 0x3E) {
|
||||
name = "sldi";
|
||||
desc = "Shift Left Immediate";
|
||||
} else {
|
||||
name = "rldic";
|
||||
desc = "Rotate Left Doubleword Immediate then Clear";
|
||||
}
|
||||
d.Init(name, desc,
|
||||
i.MD.Rc ? InstrDisasm::kRc : 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.MD.RA, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.MD.RT, InstrRegister::kRead);
|
||||
d.AddUImmOperand(sh, 1);
|
||||
d.AddUImmOperand(mb, 1);
|
||||
return d.Finish();
|
||||
} else if (i.MDS.idx == 8) {
|
||||
// XEDISASMR(rldclx, 0x78000010, MDS)
|
||||
d.Init("rldcl", "Rotate Left Doubleword then Clear Left",
|
||||
i.MDS.Rc ? InstrDisasm::kRc : 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.MDS.RA, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.MDS.RT, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.MDS.RB, InstrRegister::kRead);
|
||||
d.AddUImmOperand((i.MDS.MB5 << 5) | i.MDS.MB, 1);
|
||||
return d.Finish();
|
||||
} else if (i.MDS.idx == 9) {
|
||||
// XEDISASMR(rldcrx, 0x78000012, MDS)
|
||||
d.Init("rldcr", "Rotate Left Doubleword then Clear Right",
|
||||
i.MDS.Rc ? InstrDisasm::kRc : 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.MDS.RA, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.MDS.RT, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.MDS.RB, InstrRegister::kRead);
|
||||
d.AddUImmOperand((i.MDS.MB5 << 5) | i.MDS.MB, 1);
|
||||
return d.Finish();
|
||||
} else if (i.MD.idx == 3) {
|
||||
// XEDISASMR(rldimix, 0x7800000C, MD )
|
||||
d.Init("rldimi", "Rotate Left Doubleword Immediate then Mask Insert",
|
||||
i.MD.Rc ? InstrDisasm::kRc : 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.MD.RA, InstrRegister::kReadWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.MD.RT, InstrRegister::kRead);
|
||||
d.AddUImmOperand((i.MD.SH5 << 5) | i.MD.SH, 1);
|
||||
d.AddUImmOperand((i.MD.MB5 << 5) | i.MD.MB, 1);
|
||||
return d.Finish();
|
||||
} else {
|
||||
XEASSERTALWAYS();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
XEDISASMR(rlwimix, 0x50000000, M )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("rlwimi", "Rotate Left Word Immediate then Mask Insert",
|
||||
i.M.Rc ? InstrDisasm::kRc : 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.M.RA, InstrRegister::kReadWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.M.RT, InstrRegister::kRead);
|
||||
d.AddUImmOperand(i.M.SH, 1);
|
||||
d.AddUImmOperand(i.M.MB, 1);
|
||||
d.AddUImmOperand(i.M.ME, 1);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(rlwinmx, 0x54000000, M )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("rlwinm", "Rotate Left Word Immediate then AND with Mask",
|
||||
i.M.Rc ? InstrDisasm::kRc : 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.M.RA, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.M.RT, InstrRegister::kRead);
|
||||
d.AddUImmOperand(i.M.SH, 1);
|
||||
d.AddUImmOperand(i.M.MB, 1);
|
||||
d.AddUImmOperand(i.M.ME, 1);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(rlwnmx, 0x5C000000, M )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("rlwnm", "Rotate Left Word then AND with Mask",
|
||||
i.M.Rc ? InstrDisasm::kRc : 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.M.RA, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.M.RT, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.M.SH, InstrRegister::kRead);
|
||||
d.AddUImmOperand(i.M.MB, 1);
|
||||
d.AddUImmOperand(i.M.ME, 1);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
|
||||
// Integer shift (A-7)
|
||||
|
||||
XEDISASMR(sldx, 0x7C000036, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("sld", "Shift Left Doubleword", i.X.Rc ? InstrDisasm::kRc : 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(slwx, 0x7C000030, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("slw", "Shift Left Word", i.X.Rc ? InstrDisasm::kRc : 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(sradx, 0x7C000634, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("srad", "Shift Right Algebraic Doubleword",
|
||||
i.X.Rc ? InstrDisasm::kRc : 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(sradix, 0x7C000674, XS )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("sradi", "Shift Right Algebraic Doubleword Immediate",
|
||||
(i.XS.Rc ? InstrDisasm::kRc : 0) | InstrDisasm::kCA);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XS.RA, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XS.RT, InstrRegister::kRead);
|
||||
d.AddUImmOperand((i.XS.SH5 << 5) | i.XS.SH, 1);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(srawx, 0x7C000630, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("sraw", "Shift Right Algebraic Word",
|
||||
(i.X.Rc ? InstrDisasm::kRc : 0) | InstrDisasm::kCA);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(srawix, 0x7C000670, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("srawi", "Shift Right Algebraic Word Immediate",
|
||||
(i.X.Rc ? InstrDisasm::kRc : 0) | InstrDisasm::kCA);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead);
|
||||
d.AddUImmOperand(i.X.RB, 1);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(srdx, 0x7C000436, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("srd", "Shift Right Doubleword", i.X.Rc ? InstrDisasm::kRc : 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(srwx, 0x7C000430, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("srw", "Shift Right Word", i.X.Rc ? InstrDisasm::kRc : 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
|
||||
void RegisterDisasmCategoryALU() {
|
||||
XEREGISTERINSTR(addx, 0x7C000214);
|
||||
XEREGISTERINSTR(addcx, 0X7C000014);
|
||||
XEREGISTERINSTR(addex, 0x7C000114);
|
||||
XEREGISTERINSTR(addi, 0x38000000);
|
||||
XEREGISTERINSTR(addic, 0x30000000);
|
||||
XEREGISTERINSTR(addicx, 0x34000000);
|
||||
XEREGISTERINSTR(addis, 0x3C000000);
|
||||
XEREGISTERINSTR(addmex, 0x7C0001D4);
|
||||
XEREGISTERINSTR(addzex, 0x7C000194);
|
||||
XEREGISTERINSTR(divdx, 0x7C0003D2);
|
||||
XEREGISTERINSTR(divdux, 0x7C000392);
|
||||
XEREGISTERINSTR(divwx, 0x7C0003D6);
|
||||
XEREGISTERINSTR(divwux, 0x7C000396);
|
||||
XEREGISTERINSTR(mulhdx, 0x7C000092);
|
||||
XEREGISTERINSTR(mulhdux, 0x7C000012);
|
||||
XEREGISTERINSTR(mulhwx, 0x7C000096);
|
||||
XEREGISTERINSTR(mulhwux, 0x7C000016);
|
||||
XEREGISTERINSTR(mulldx, 0x7C0001D2);
|
||||
XEREGISTERINSTR(mulli, 0x1C000000);
|
||||
XEREGISTERINSTR(mullwx, 0x7C0001D6);
|
||||
XEREGISTERINSTR(negx, 0x7C0000D0);
|
||||
XEREGISTERINSTR(subfx, 0x7C000050);
|
||||
XEREGISTERINSTR(subfcx, 0x7C000010);
|
||||
XEREGISTERINSTR(subficx, 0x20000000);
|
||||
XEREGISTERINSTR(subfex, 0x7C000110);
|
||||
XEREGISTERINSTR(subfmex, 0x7C0001D0);
|
||||
XEREGISTERINSTR(subfzex, 0x7C000190);
|
||||
XEREGISTERINSTR(cmp, 0x7C000000);
|
||||
XEREGISTERINSTR(cmpi, 0x2C000000);
|
||||
XEREGISTERINSTR(cmpl, 0x7C000040);
|
||||
XEREGISTERINSTR(cmpli, 0x28000000);
|
||||
XEREGISTERINSTR(andx, 0x7C000038);
|
||||
XEREGISTERINSTR(andcx, 0x7C000078);
|
||||
XEREGISTERINSTR(andix, 0x70000000);
|
||||
XEREGISTERINSTR(andisx, 0x74000000);
|
||||
XEREGISTERINSTR(cntlzdx, 0x7C000074);
|
||||
XEREGISTERINSTR(cntlzwx, 0x7C000034);
|
||||
XEREGISTERINSTR(eqvx, 0x7C000238);
|
||||
XEREGISTERINSTR(extsbx, 0x7C000774);
|
||||
XEREGISTERINSTR(extshx, 0x7C000734);
|
||||
XEREGISTERINSTR(extswx, 0x7C0007B4);
|
||||
XEREGISTERINSTR(nandx, 0x7C0003B8);
|
||||
XEREGISTERINSTR(norx, 0x7C0000F8);
|
||||
XEREGISTERINSTR(orx, 0x7C000378);
|
||||
XEREGISTERINSTR(orcx, 0x7C000338);
|
||||
XEREGISTERINSTR(ori, 0x60000000);
|
||||
XEREGISTERINSTR(oris, 0x64000000);
|
||||
XEREGISTERINSTR(xorx, 0x7C000278);
|
||||
XEREGISTERINSTR(xori, 0x68000000);
|
||||
XEREGISTERINSTR(xoris, 0x6C000000);
|
||||
XEREGISTERINSTR(rld, 0x78000000);
|
||||
// XEREGISTERINSTR(rldclx, 0x78000010);
|
||||
// XEREGISTERINSTR(rldcrx, 0x78000012);
|
||||
// XEREGISTERINSTR(rldicx, 0x78000008);
|
||||
// XEREGISTERINSTR(rldiclx, 0x78000000);
|
||||
// XEREGISTERINSTR(rldicrx, 0x78000004);
|
||||
// XEREGISTERINSTR(rldimix, 0x7800000C);
|
||||
XEREGISTERINSTR(rlwimix, 0x50000000);
|
||||
XEREGISTERINSTR(rlwinmx, 0x54000000);
|
||||
XEREGISTERINSTR(rlwnmx, 0x5C000000);
|
||||
XEREGISTERINSTR(sldx, 0x7C000036);
|
||||
XEREGISTERINSTR(slwx, 0x7C000030);
|
||||
XEREGISTERINSTR(sradx, 0x7C000634);
|
||||
XEREGISTERINSTR(sradix, 0x7C000674);
|
||||
XEREGISTERINSTR(srawx, 0x7C000630);
|
||||
XEREGISTERINSTR(srawix, 0x7C000670);
|
||||
XEREGISTERINSTR(srdx, 0x7C000436);
|
||||
XEREGISTERINSTR(srwx, 0x7C000430);
|
||||
}
|
||||
|
||||
|
||||
} // namespace ppc
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
||||
283
src/alloy/frontend/ppc/ppc_disasm_control.cc
Normal file
283
src/alloy/frontend/ppc/ppc_disasm_control.cc
Normal file
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
* 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 <alloy/frontend/ppc/ppc_disasm-private.h>
|
||||
|
||||
|
||||
using namespace alloy::frontend::ppc;
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
namespace ppc {
|
||||
|
||||
|
||||
XEDISASMR(bx, 0x48000000, I )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("b", "Branch", i.I.LK ? InstrDisasm::kLR : 0);
|
||||
uint32_t nia;
|
||||
if (i.I.AA) {
|
||||
nia = (uint32_t)XEEXTS26(i.I.LI << 2);
|
||||
} else {
|
||||
nia = (uint32_t)(i.address + XEEXTS26(i.I.LI << 2));
|
||||
}
|
||||
d.AddUImmOperand(nia, 4);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(bcx, 0x40000000, B )(InstrData& i, InstrDisasm& d) {
|
||||
// TODO(benvanik): mnemonics
|
||||
d.Init("bc", "Branch Conditional", i.B.LK ? InstrDisasm::kLR : 0);
|
||||
if (!XESELECTBITS(i.B.BO, 2, 2)) {
|
||||
d.AddCTR(InstrRegister::kReadWrite);
|
||||
}
|
||||
if (!XESELECTBITS(i.B.BO, 4, 4)) {
|
||||
d.AddCR(i.B.BI >> 2, InstrRegister::kRead);
|
||||
}
|
||||
d.AddUImmOperand(i.B.BO, 1);
|
||||
d.AddUImmOperand(i.B.BI, 1);
|
||||
uint32_t nia;
|
||||
if (i.B.AA) {
|
||||
nia = (uint32_t)XEEXTS16(i.B.BD << 2);
|
||||
} else {
|
||||
nia = (uint32_t)(i.address + XEEXTS16(i.B.BD << 2));
|
||||
}
|
||||
d.AddUImmOperand(nia, 4);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(bcctrx, 0x4C000420, XL )(InstrData& i, InstrDisasm& d) {
|
||||
// TODO(benvanik): mnemonics
|
||||
d.Init("bcctr", "Branch Conditional to Count Register",
|
||||
i.XL.LK ? InstrDisasm::kLR : 0);
|
||||
if (!XESELECTBITS(i.XL.BO, 4, 4)) {
|
||||
d.AddCR(i.XL.BI >> 2, InstrRegister::kRead);
|
||||
}
|
||||
d.AddUImmOperand(i.XL.BO, 1);
|
||||
d.AddUImmOperand(i.XL.BI, 1);
|
||||
d.AddCTR(InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(bclrx, 0x4C000020, XL )(InstrData& i, InstrDisasm& d) {
|
||||
const char* name = "bclr";
|
||||
if (i.code == 0x4E800020) {
|
||||
name = "blr";
|
||||
}
|
||||
d.Init(name, "Branch Conditional to Link Register",
|
||||
i.XL.LK ? InstrDisasm::kLR : 0);
|
||||
if (!XESELECTBITS(i.B.BO, 2, 2)) {
|
||||
d.AddCTR(InstrRegister::kReadWrite);
|
||||
}
|
||||
if (!XESELECTBITS(i.B.BO, 4, 4)) {
|
||||
d.AddCR(i.B.BI >> 2, InstrRegister::kRead);
|
||||
}
|
||||
d.AddUImmOperand(i.XL.BO, 1);
|
||||
d.AddUImmOperand(i.XL.BI, 1);
|
||||
d.AddLR(InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
|
||||
// Condition register logical (A-23)
|
||||
|
||||
XEDISASMR(crand, 0x4C000202, XL )(InstrData& i, InstrDisasm& d) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEDISASMR(crandc, 0x4C000102, XL )(InstrData& i, InstrDisasm& d) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEDISASMR(creqv, 0x4C000242, XL )(InstrData& i, InstrDisasm& d) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEDISASMR(crnand, 0x4C0001C2, XL )(InstrData& i, InstrDisasm& d) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEDISASMR(crnor, 0x4C000042, XL )(InstrData& i, InstrDisasm& d) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEDISASMR(cror, 0x4C000382, XL )(InstrData& i, InstrDisasm& d) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEDISASMR(crorc, 0x4C000342, XL )(InstrData& i, InstrDisasm& d) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEDISASMR(crxor, 0x4C000182, XL )(InstrData& i, InstrDisasm& d) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEDISASMR(mcrf, 0x4C000000, XL )(InstrData& i, InstrDisasm& d) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// System linkage (A-24)
|
||||
|
||||
XEDISASMR(sc, 0x44000002, SC )(InstrData& i, InstrDisasm& d) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// Trap (A-25)
|
||||
|
||||
XEDISASMR(td, 0x7C000088, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("td", "Trap Doubleword", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(tdi, 0x08000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("tdi", "Trap Doubleword Immediate", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(tw, 0x7C000008, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("tw", "Trap Word", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(twi, 0x0C000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("twi", "Trap Word Immediate", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
|
||||
// Processor control (A-26)
|
||||
|
||||
XEDISASMR(mfcr, 0x7C000026, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("mfcr", "Move From Condition Register", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kWrite);
|
||||
for (int n = 0; n < 8; n++) {
|
||||
d.AddCR(0, InstrRegister::kRead);
|
||||
}
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(mfspr, 0x7C0002A6, XFX)(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("mfspr", "Move From Special Purpose Register", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XFX.RT, InstrRegister::kWrite);
|
||||
const uint32_t n = ((i.XFX.spr & 0x1F) << 5) | ((i.XFX.spr >> 5) & 0x1F);
|
||||
switch (n) {
|
||||
case 1:
|
||||
d.AddRegOperand(InstrRegister::kXER, 0, InstrRegister::kRead);
|
||||
break;
|
||||
case 8:
|
||||
d.AddRegOperand(InstrRegister::kLR, 0, InstrRegister::kRead);
|
||||
break;
|
||||
case 9:
|
||||
d.AddRegOperand(InstrRegister::kCTR, 0, InstrRegister::kRead);
|
||||
break;
|
||||
}
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(mftb, 0x7C0002E6, XFX)(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("mftb", "Move From Time Base", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XFX.RT, InstrRegister::kWrite);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(mtcrf, 0x7C000120, XFX)(InstrData& i, InstrDisasm& d) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEDISASMR(mtspr, 0x7C0003A6, XFX)(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("mtspr", "Move To Special Purpose Register", 0);
|
||||
const uint32_t n = ((i.XFX.spr & 0x1F) << 5) | ((i.XFX.spr >> 5) & 0x1F);
|
||||
switch (n) {
|
||||
case 1:
|
||||
d.AddRegOperand(InstrRegister::kXER, 0, InstrRegister::kWrite);
|
||||
break;
|
||||
case 8:
|
||||
d.AddRegOperand(InstrRegister::kLR, 0, InstrRegister::kWrite);
|
||||
break;
|
||||
case 9:
|
||||
d.AddRegOperand(InstrRegister::kCTR, 0, InstrRegister::kWrite);
|
||||
break;
|
||||
}
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.XFX.RT, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(mfmsr, 0x7C0000A6, X)(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("mfmsr", "Move From Machine State Register", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kWrite);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(mtmsr, 0x7C000124, X)(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("mtmsr", "Move To Machine State Register", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead);
|
||||
d.AddSImmOperand((i.X.RA & 16) ? 1 : 0, 1);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(mtmsrd, 0x7C000164, X)(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("mtmsrd", "Move To Machine State Register Doubleword", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead);
|
||||
d.AddSImmOperand((i.X.RA & 16) ? 1 : 0, 1);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
|
||||
void RegisterDisasmCategoryControl() {
|
||||
XEREGISTERINSTR(bx, 0x48000000);
|
||||
XEREGISTERINSTR(bcx, 0x40000000);
|
||||
XEREGISTERINSTR(bcctrx, 0x4C000420);
|
||||
XEREGISTERINSTR(bclrx, 0x4C000020);
|
||||
XEREGISTERINSTR(crand, 0x4C000202);
|
||||
XEREGISTERINSTR(crandc, 0x4C000102);
|
||||
XEREGISTERINSTR(creqv, 0x4C000242);
|
||||
XEREGISTERINSTR(crnand, 0x4C0001C2);
|
||||
XEREGISTERINSTR(crnor, 0x4C000042);
|
||||
XEREGISTERINSTR(cror, 0x4C000382);
|
||||
XEREGISTERINSTR(crorc, 0x4C000342);
|
||||
XEREGISTERINSTR(crxor, 0x4C000182);
|
||||
XEREGISTERINSTR(mcrf, 0x4C000000);
|
||||
XEREGISTERINSTR(sc, 0x44000002);
|
||||
XEREGISTERINSTR(td, 0x7C000088);
|
||||
XEREGISTERINSTR(tdi, 0x08000000);
|
||||
XEREGISTERINSTR(tw, 0x7C000008);
|
||||
XEREGISTERINSTR(twi, 0x0C000000);
|
||||
XEREGISTERINSTR(mfcr, 0x7C000026);
|
||||
XEREGISTERINSTR(mfspr, 0x7C0002A6);
|
||||
XEREGISTERINSTR(mftb, 0x7C0002E6);
|
||||
XEREGISTERINSTR(mtcrf, 0x7C000120);
|
||||
XEREGISTERINSTR(mtspr, 0x7C0003A6);
|
||||
XEREGISTERINSTR(mfmsr, 0x7C0000A6);
|
||||
XEREGISTERINSTR(mtmsr, 0x7C000124);
|
||||
XEREGISTERINSTR(mtmsrd, 0x7C000164);
|
||||
}
|
||||
|
||||
|
||||
} // namespace ppc
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
||||
413
src/alloy/frontend/ppc/ppc_disasm_fpu.cc
Normal file
413
src/alloy/frontend/ppc/ppc_disasm_fpu.cc
Normal file
@@ -0,0 +1,413 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
* 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 <alloy/frontend/ppc/ppc_disasm-private.h>
|
||||
|
||||
|
||||
using namespace alloy::frontend::ppc;
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
namespace ppc {
|
||||
|
||||
|
||||
// Floating-point arithmetic (A-8)
|
||||
|
||||
XEDISASMR(faddx, 0xFC00002A, A )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("fadd", "Floating Add [Single]",
|
||||
InstrDisasm::kFP | (i.A.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(faddsx, 0xEC00002A, A )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("fadds", "Floating Add [Single]",
|
||||
InstrDisasm::kFP | (i.A.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(fdivx, 0xFC000024, A )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("fdiv", "Floating Divide [Single]",
|
||||
InstrDisasm::kFP | (i.A.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(fdivsx, 0xEC000024, A )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("fdivs", "Floating Divide [Single]",
|
||||
InstrDisasm::kFP | (i.A.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(fmulx, 0xFC000032, A )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("fmul", "Floating Multiply [Single]",
|
||||
InstrDisasm::kFP | (i.A.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRC, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(fmulsx, 0xEC000032, A )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("fmuls", "Floating Multiply [Single]",
|
||||
InstrDisasm::kFP | (i.A.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRC, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(fresx, 0xEC000030, A )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("fres", "Floating Reciprocal Estimate [Single]",
|
||||
InstrDisasm::kFP | (i.A.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(frsqrtex, 0xFC000034, A )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("frsqrte", "Floating Reciprocal Square Root Estimate [Single]",
|
||||
InstrDisasm::kFP | (i.A.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(fsubx, 0xFC000028, A )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("fsub", "Floating Subtract [Single]",
|
||||
InstrDisasm::kFP | (i.A.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(fsubsx, 0xEC000028, A )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("fsubs", "Floating Subtract [Single]",
|
||||
InstrDisasm::kFP | (i.A.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(fselx, 0xFC00002E, A )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("fsel", "Floating Select",
|
||||
InstrDisasm::kFP | (i.A.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRB, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRC, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(fsqrtx, 0xFC00002C, A )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("fsqrt", "Floating Square Root [Single]",
|
||||
InstrDisasm::kFP | (i.A.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(fsqrtsx, 0xEC00002C, A )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("fsqrts", "Floating Square Root [Single]",
|
||||
InstrDisasm::kFP | (i.A.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
|
||||
// Floating-point multiply-add (A-9)
|
||||
|
||||
XEDISASMR(fmaddx, 0xFC00003A, A )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("fmadd", "Floating Multiply-Add [Single]",
|
||||
InstrDisasm::kFP | (i.A.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRB, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRC, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(fmaddsx, 0xEC00003A, A )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("fmadds", "Floating Multiply-Add [Single]",
|
||||
InstrDisasm::kFP | (i.A.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRB, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRC, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(fmsubx, 0xFC000038, A )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("fmsub", "Floating Multiply-Subtract[Single]",
|
||||
InstrDisasm::kFP | (i.A.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRB, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRC, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(fmsubsx, 0xEC000038, A )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("fmsubs", "Floating Multiply-Subtract [Single]",
|
||||
InstrDisasm::kFP | (i.A.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRB, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRC, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(fnmaddx, 0xFC00003E, A )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("fnmadd", "Floating Negative Multiply-Add [Single]",
|
||||
InstrDisasm::kFP | (i.A.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRB, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRC, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(fnmaddsx, 0xEC00003E, A )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("fnmadds", "Floating Negative Multiply-Add [Single]",
|
||||
InstrDisasm::kFP | (i.A.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRB, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRC, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(fnmsubx, 0xFC00003C, A )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("fnmsub", "Floating Negative Multiply-Subtract [Single]",
|
||||
InstrDisasm::kFP | (i.A.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRB, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRC, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(fnmsubsx, 0xEC00003C, A )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("fnmsubs", "Floating Negative Multiply-Add [Single]",
|
||||
InstrDisasm::kFP | (i.A.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRB, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.A.FRC, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
|
||||
// Floating-point rounding and conversion (A-10)
|
||||
|
||||
XEDISASMR(fcfidx, 0xFC00069C, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("fcfid", "Floating Convert From Integer Doubleword",
|
||||
InstrDisasm::kFP | (i.X.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.X.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(fctidx, 0xFC00065C, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("fctid", "Floating Convert To Integer Doubleword",
|
||||
InstrDisasm::kFP | (i.X.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.X.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(fctidzx, 0xFC00065E, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("fctidz",
|
||||
"Floating Convert To Integer Doubleword with round toward Zero",
|
||||
InstrDisasm::kFP | (i.X.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.X.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(fctiwx, 0xFC00001C, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("fctiw", "Floating Convert To Integer Word",
|
||||
InstrDisasm::kFP | (i.X.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.X.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(fctiwzx, 0xFC00001E, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("fctiwz", "Floating Convert To Integer Word with round toward Zero",
|
||||
InstrDisasm::kFP | (i.X.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.X.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(frspx, 0xFC000018, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("frsp", "Floating Round to Single-Precision",
|
||||
InstrDisasm::kFP | (i.X.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.X.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
|
||||
// Floating-point compare (A-11)
|
||||
|
||||
XEDISASMR(fcmpo, 0xFC000040, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("fcmpo", "Floating Compare Ordered", 0);
|
||||
d.AddCR(i.X.RT >> 2, InstrRegister::kWrite);
|
||||
d.AddUImmOperand(i.X.RT >> 2, 1);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.X.RA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(fcmpu, 0xFC000000, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("fcmpu", "Floating Compare Unordered", 0);
|
||||
d.AddCR(i.X.RT >> 2, InstrRegister::kWrite);
|
||||
d.AddUImmOperand(i.X.RT >> 2, 1);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.X.RA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
|
||||
// Floating-point status and control register (A
|
||||
|
||||
XEDISASMR(mcrfs, 0xFC000080, X )(InstrData& i, InstrDisasm& d) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEDISASMR(mffsx, 0xFC00048E, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("mffs", "Move from FPSCR",
|
||||
InstrDisasm::kFP | (i.X.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddFPSCR(InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.X.RT, InstrRegister::kWrite);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(mtfsb0x, 0xFC00008C, X )(InstrData& i, InstrDisasm& d) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEDISASMR(mtfsb1x, 0xFC00004C, X )(InstrData& i, InstrDisasm& d) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEDISASMR(mtfsfx, 0xFC00058E, XFL)(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("mtfsf", "Move to FPSCR Fields",
|
||||
InstrDisasm::kFP | (i.XFL.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddFPSCR(InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.XFL.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(mtfsfix, 0xFC00010C, X )(InstrData& i, InstrDisasm& d) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// Floating-point move (A-21)
|
||||
|
||||
XEDISASMR(fabsx, 0xFC000210, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("fabs", "Floating Absolute Value",
|
||||
InstrDisasm::kFP | (i.X.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.X.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(fmrx, 0xFC000090, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("fmr", "Floating Move Register",
|
||||
InstrDisasm::kFP | (i.X.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.X.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(fnabsx, 0xFC000110, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("fnabs", "Floating Negative Absolute Value",
|
||||
InstrDisasm::kFP | (i.X.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.X.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(fnegx, 0xFC000050, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("fneg", "Floating Negate",
|
||||
InstrDisasm::kFP | (i.X.Rc ? InstrDisasm::kRc : 0));
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.X.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
|
||||
void RegisterDisasmCategoryFPU() {
|
||||
XEREGISTERINSTR(faddx, 0xFC00002A);
|
||||
XEREGISTERINSTR(faddsx, 0xEC00002A);
|
||||
XEREGISTERINSTR(fdivx, 0xFC000024);
|
||||
XEREGISTERINSTR(fdivsx, 0xEC000024);
|
||||
XEREGISTERINSTR(fmulx, 0xFC000032);
|
||||
XEREGISTERINSTR(fmulsx, 0xEC000032);
|
||||
XEREGISTERINSTR(fresx, 0xEC000030);
|
||||
XEREGISTERINSTR(frsqrtex, 0xFC000034);
|
||||
XEREGISTERINSTR(fsubx, 0xFC000028);
|
||||
XEREGISTERINSTR(fsubsx, 0xEC000028);
|
||||
XEREGISTERINSTR(fselx, 0xFC00002E);
|
||||
XEREGISTERINSTR(fsqrtx, 0xFC00002C);
|
||||
XEREGISTERINSTR(fsqrtsx, 0xEC00002C);
|
||||
XEREGISTERINSTR(fmaddx, 0xFC00003A);
|
||||
XEREGISTERINSTR(fmaddsx, 0xEC00003A);
|
||||
XEREGISTERINSTR(fmsubx, 0xFC000038);
|
||||
XEREGISTERINSTR(fmsubsx, 0xEC000038);
|
||||
XEREGISTERINSTR(fnmaddx, 0xFC00003E);
|
||||
XEREGISTERINSTR(fnmaddsx, 0xEC00003E);
|
||||
XEREGISTERINSTR(fnmsubx, 0xFC00003C);
|
||||
XEREGISTERINSTR(fnmsubsx, 0xEC00003C);
|
||||
XEREGISTERINSTR(fcfidx, 0xFC00069C);
|
||||
XEREGISTERINSTR(fctidx, 0xFC00065C);
|
||||
XEREGISTERINSTR(fctidzx, 0xFC00065E);
|
||||
XEREGISTERINSTR(fctiwx, 0xFC00001C);
|
||||
XEREGISTERINSTR(fctiwzx, 0xFC00001E);
|
||||
XEREGISTERINSTR(frspx, 0xFC000018);
|
||||
XEREGISTERINSTR(fcmpo, 0xFC000040);
|
||||
XEREGISTERINSTR(fcmpu, 0xFC000000);
|
||||
XEREGISTERINSTR(mcrfs, 0xFC000080);
|
||||
XEREGISTERINSTR(mffsx, 0xFC00048E);
|
||||
XEREGISTERINSTR(mtfsb0x, 0xFC00008C);
|
||||
XEREGISTERINSTR(mtfsb1x, 0xFC00004C);
|
||||
XEREGISTERINSTR(mtfsfx, 0xFC00058E);
|
||||
XEREGISTERINSTR(mtfsfix, 0xFC00010C);
|
||||
XEREGISTERINSTR(fabsx, 0xFC000210);
|
||||
XEREGISTERINSTR(fmrx, 0xFC000090);
|
||||
XEREGISTERINSTR(fnabsx, 0xFC000110);
|
||||
XEREGISTERINSTR(fnegx, 0xFC000050);
|
||||
}
|
||||
|
||||
|
||||
} // namespace ppc
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
||||
930
src/alloy/frontend/ppc/ppc_disasm_memory.cc
Normal file
930
src/alloy/frontend/ppc/ppc_disasm_memory.cc
Normal file
@@ -0,0 +1,930 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
* 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 <alloy/frontend/ppc/ppc_disasm-private.h>
|
||||
|
||||
|
||||
using namespace alloy::frontend::ppc;
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
namespace ppc {
|
||||
|
||||
|
||||
// Integer load (A-13)
|
||||
|
||||
XEDISASMR(lbz, 0x88000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("lbz", "Load Byte and Zero", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RT, InstrRegister::kWrite);
|
||||
if (i.D.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddSImmOperand(XEEXTS16(i.D.DS), 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(lbzu, 0x8C000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("lbzu", "Load Byte and Zero with Update", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kReadWrite);
|
||||
d.AddSImmOperand(XEEXTS16(i.D.DS), 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(lbzux, 0x7C0000EE, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("lbzux", "Load Byte and Zero with Update Indexed", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kReadWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(lbzx, 0x7C0000AE, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("lbzx", "Load Byte and Zero Indexed", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kWrite);
|
||||
if (i.X.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(ld, 0xE8000000, DS )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("ld", "Load Doubleword", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.DS.RT, InstrRegister::kWrite);
|
||||
if (i.DS.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.DS.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddSImmOperand(XEEXTS16(i.DS.DS << 2), 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(ldu, 0xE8000001, DS )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("ldu", "Load Doubleword with Update", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.DS.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.DS.RA, InstrRegister::kReadWrite);
|
||||
d.AddSImmOperand(XEEXTS16(i.DS.DS << 2), 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(ldux, 0x7C00006A, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("ldux", "Load Doubleword with Update Indexed", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kReadWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(ldx, 0x7C00002A, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("ldx", "Load Doubleword Indexed", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kWrite);
|
||||
if (i.X.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(lha, 0xA8000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("lha", "Load Halfword Algebraic", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RT, InstrRegister::kWrite);
|
||||
if (i.D.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddSImmOperand(XEEXTS16(i.D.DS), 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(lhau, 0xAC000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEDISASMR(lhaux, 0x7C0002EE, X )(InstrData& i, InstrDisasm& d) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEDISASMR(lhax, 0x7C0002AE, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("lhax", "Load Halfword Algebraic Indexed", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kWrite);
|
||||
if (i.X.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(lhz, 0xA0000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("lhz", "Load Halfword and Zero", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RT, InstrRegister::kWrite);
|
||||
if (i.D.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddSImmOperand(XEEXTS16(i.D.DS), 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(lhzu, 0xA4000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("lhzu", "Load Halfword and Zero with Update", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kReadWrite);
|
||||
d.AddSImmOperand(XEEXTS16(i.D.DS), 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(lhzux, 0x7C00026E, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("lhzux", "Load Halfword and Zero with Update Indexed", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kReadWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(lhzx, 0x7C00022E, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("lhzx", "Load Halfword and Zero Indexed", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kWrite);
|
||||
if (i.X.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(lwa, 0xE8000002, DS )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("lwa", "Load Word Algebraic", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.DS.RT, InstrRegister::kWrite);
|
||||
if (i.D.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.DS.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddSImmOperand(XEEXTS16(i.DS.DS << 2), 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(lwaux, 0x7C0002EA, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("lwaux", "Load Word Algebraic with Update Indexed", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kReadWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(lwax, 0x7C0002AA, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("lwax", "Load Word Algebraic Indexed", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kWrite);
|
||||
if (i.X.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(lwz, 0x80000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("lwz", "Load Word and Zero", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RT, InstrRegister::kWrite);
|
||||
if (i.D.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddSImmOperand(XEEXTS16(i.D.DS), 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(lwzu, 0x84000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("lwzu", "Load Word and Zero with Udpate", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kReadWrite);
|
||||
d.AddSImmOperand(XEEXTS16(i.D.DS), 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(lwzux, 0x7C00006E, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("lwzux", "Load Word and Zero with Update Indexed", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kReadWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(lwzx, 0x7C00002E, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("lwzx", "Load Word and Zero Indexed", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kWrite);
|
||||
if (i.X.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
|
||||
// Integer store (A-14)
|
||||
|
||||
XEDISASMR(stb, 0x98000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("stb", "Store Byte", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RT, InstrRegister::kRead);
|
||||
if (i.D.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddSImmOperand(XEEXTS16(i.D.DS), 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(stbu, 0x9C000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("stbu", "Store Byte with Update", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RT, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kReadWrite);
|
||||
d.AddSImmOperand(XEEXTS16(i.D.DS), 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(stbux, 0x7C0001EE, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("stbux", "Store Byte with Update Indexed", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kReadWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(stbx, 0x7C0001AE, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("stbx", "Store Byte Indexed", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead);
|
||||
if (i.DS.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(std, 0xF8000000, DS )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("std", "Store Doubleword", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.DS.RT, InstrRegister::kRead);
|
||||
if (i.DS.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.DS.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddSImmOperand(XEEXTS16(i.DS.DS << 2), 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(stdu, 0xF8000001, DS )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("stdu", "Store Doubleword with Update", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.DS.RT, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.DS.RA, InstrRegister::kReadWrite);
|
||||
d.AddSImmOperand(XEEXTS16(i.DS.DS << 2), 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(stdux, 0x7C00016A, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("stdux", "Store Doubleword with Update Indexed", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kReadWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(stdx, 0x7C00012A, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("stdx", "Store Doubleword Indexed", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead);
|
||||
if (i.X.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(sth, 0xB0000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("sth", "Store Halfword", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RT, InstrRegister::kRead);
|
||||
if (i.D.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddSImmOperand(XEEXTS16(i.D.DS), 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(sthu, 0xB4000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("sthu", "Store Halfword with Update", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RT, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kReadWrite);
|
||||
d.AddSImmOperand(XEEXTS16(i.D.DS), 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(sthux, 0x7C00036E, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("sthux", "Store Halfword with Update Indexed", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kReadWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(sthx, 0x7C00032E, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("sth", "Store Halfword Indexed", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead);
|
||||
if (i.X.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(stw, 0x90000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("stw", "Store Word", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RT, InstrRegister::kRead);
|
||||
if (i.D.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddSImmOperand(XEEXTS16(i.D.DS), 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(stwu, 0x94000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("stwu", "Store Word with Update", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RT, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kReadWrite);
|
||||
d.AddSImmOperand(XEEXTS16(i.D.DS), 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(stwux, 0x7C00016E, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("stwux", "Store Word with Update Indexed", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kReadWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(stwx, 0x7C00012E, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("stwx", "Store Word Indexed", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead);
|
||||
if (i.X.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
|
||||
// Integer load and store with byte reverse (A-1
|
||||
|
||||
XEDISASMR(lhbrx, 0x7C00062C, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("lhbrx", "Load Halfword Byte-Reverse Indexed", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kWrite);
|
||||
if (i.X.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(lwbrx, 0x7C00042C, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("lwbrx", "Load Word Byte-Reverse Indexed", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kWrite);
|
||||
if (i.X.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(ldbrx, 0x7C000428, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("ldbrx", "Load Doubleword Byte-Reverse Indexed", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kWrite);
|
||||
if (i.X.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(sthbrx, 0x7C00072C, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("sthbrx", "Store Halfword Byte-Reverse Indexed", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead);
|
||||
if (i.X.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(stwbrx, 0x7C00052C, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("stwbrx", "Store Word Byte-Reverse Indexed", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead);
|
||||
if (i.X.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(stdbrx, 0x7C000528, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("stdbrx", "Store Doubleword Byte-Reverse Indexed", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead);
|
||||
if (i.X.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
|
||||
// Integer load and store multiple (A-16)
|
||||
|
||||
XEDISASMR(lmw, 0xB8000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEDISASMR(stmw, 0xBC000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// Integer load and store string (A-17)
|
||||
|
||||
XEDISASMR(lswi, 0x7C0004AA, X )(InstrData& i, InstrDisasm& d) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEDISASMR(lswx, 0x7C00042A, X )(InstrData& i, InstrDisasm& d) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEDISASMR(stswi, 0x7C0005AA, X )(InstrData& i, InstrDisasm& d) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEDISASMR(stswx, 0x7C00052A, X )(InstrData& i, InstrDisasm& d) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// Memory synchronization (A-18)
|
||||
|
||||
XEDISASMR(eieio, 0x7C0006AC, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("eieio", "Enforce In-Order Execution of I/O Instruction", 0);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(isync, 0x4C00012C, XL )(InstrData& i, InstrDisasm& d) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEDISASMR(ldarx, 0x7C0000A8, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("ldarx", "Load Doubleword And Reserve Indexed", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kWrite);
|
||||
if (i.X.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(lwarx, 0x7C000028, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("lwarx", "Load Word And Reserve Indexed", 0);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kWrite);
|
||||
if (i.X.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(stdcx, 0x7C0001AD, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("stdcx", "Store Doubleword Conditional Indexed",
|
||||
InstrDisasm::kRc);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead);
|
||||
if (i.D.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(stwcx, 0x7C00012D, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("stwcx", "Store Word Conditional Indexed",
|
||||
InstrDisasm::kRc);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead);
|
||||
if (i.D.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(sync, 0x7C0004AC, X )(InstrData& i, InstrDisasm& d) {
|
||||
const char* name;
|
||||
const char* desc;
|
||||
int L = i.X.RT & 3;
|
||||
switch (L) {
|
||||
case 0:
|
||||
name = "hwsync";
|
||||
desc = "Synchronize (heavyweight)";
|
||||
break;
|
||||
case 1:
|
||||
name = "lwsync";
|
||||
desc = "Synchronize (lightweight)";
|
||||
break;
|
||||
default:
|
||||
case 2:
|
||||
case 3:
|
||||
name = "sync";
|
||||
desc = "Synchronize";
|
||||
break;
|
||||
}
|
||||
d.Init(name, desc, 0);
|
||||
d.AddUImmOperand(L, 1);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
|
||||
// Floating-point load (A-19)
|
||||
|
||||
XEDISASMR(lfd, 0xC8000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("lfd", "Load Floating-Point Double", 0);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.D.RT, InstrRegister::kWrite);
|
||||
if (i.D.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddSImmOperand(XEEXTS16(i.D.DS), 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(lfdu, 0xCC000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("lfdu", "Load Floating-Point Double with Update", 0);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.D.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kReadWrite);
|
||||
d.AddSImmOperand(XEEXTS16(i.D.DS), 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(lfdux, 0x7C0004EE, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("lfdux", "Load Floating-Point Double with Update Indexed", 0);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.X.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kReadWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(lfdx, 0x7C0004AE, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("lfdx", "Load Floating-Point Double Indexed", 0);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.X.RT, InstrRegister::kWrite);
|
||||
if (i.X.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(lfs, 0xC0000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("lfs", "Load Floating-Point Single", 0);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.D.RT, InstrRegister::kWrite);
|
||||
if (i.D.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddSImmOperand(XEEXTS16(i.D.DS), 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(lfsu, 0xC4000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("lfsu", "Load Floating-Point Single with Update", 0);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.D.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kReadWrite);
|
||||
d.AddSImmOperand(XEEXTS16(i.D.DS), 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(lfsux, 0x7C00046E, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("lfsux", "Load Floating-Point Single with Update Indexed", 0);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.X.RT, InstrRegister::kWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kReadWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(lfsx, 0x7C00042E, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("lfsx", "Load Floating-Point Single Indexed", 0);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.X.RT, InstrRegister::kWrite);
|
||||
if (i.X.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
|
||||
// Floating-point store (A-20)
|
||||
|
||||
XEDISASMR(stfd, 0xD8000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("stfd", "Store Floating-Point Double", 0);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.D.RT, InstrRegister::kRead);
|
||||
if (i.D.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddSImmOperand(XEEXTS16(i.D.DS), 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(stfdu, 0xDC000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("stfdu", "Store Floating-Point Double with Update", 0);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.D.RT, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kReadWrite);
|
||||
d.AddSImmOperand(XEEXTS16(i.D.DS), 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(stfdux, 0x7C0005EE, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("stfdux", "Store Floating-Point Double with Update Indexed", 0);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.X.RT, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kReadWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(stfdx, 0x7C0005AE, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("stfdx", "Store Floating-Point Double Indexed", 0);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.X.RT, InstrRegister::kRead);
|
||||
if (i.X.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(stfiwx, 0x7C0007AE, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("stfiwx", "Store Floating-Point as Integer Word Indexed", 0);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.X.RT, InstrRegister::kRead);
|
||||
if (i.X.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(stfs, 0xD0000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("stfs", "Store Floating-Point Single", 0);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.D.RT, InstrRegister::kRead);
|
||||
if (i.D.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddSImmOperand(XEEXTS16(i.D.DS), 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(stfsu, 0xD4000000, D )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("stfsu", "Store Floating-Point Single with Update", 0);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.D.RT, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kReadWrite);
|
||||
d.AddSImmOperand(XEEXTS16(i.D.DS), 2);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(stfsux, 0x7C00056E, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("stfsux", "Store Floating-Point Single with Update Indexed", 0);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.X.RT, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kReadWrite);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(stfsx, 0x7C00052E, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("stfsx", "Store Floating-Point Single Indexed", 0);
|
||||
d.AddRegOperand(InstrRegister::kFPR, i.X.RT, InstrRegister::kRead);
|
||||
if (i.X.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
|
||||
// Cache management (A-27)
|
||||
|
||||
XEDISASMR(dcbf, 0x7C0000AC, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("dcbf", "Data Cache Block Flush", 0);
|
||||
/*
|
||||
switch (i.X.RT & 3)
|
||||
{
|
||||
case 0: "dcbf";
|
||||
case 1: "dcbfl"
|
||||
case 2: RESERVED
|
||||
case 3: "dcbflp"
|
||||
}
|
||||
*/
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead);
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(dcbst, 0x7C00006C, X )(InstrData& i, InstrDisasm& d) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEDISASMR(dcbt, 0x7C00022C, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("dcbt", "Data Cache Block Touch", 0);
|
||||
// TODO
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(dcbtst, 0x7C0001EC, X )(InstrData& i, InstrDisasm& d) {
|
||||
d.Init("dcbtst", "Data Cache Block Touch for Store", 0);
|
||||
// TODO
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(dcbz, 0x7C0007EC, X )(InstrData& i, InstrDisasm& d) {
|
||||
// or dcbz128 0x7C2007EC
|
||||
d.Init("dcbz", "Data Cache Block set to Zero", 0);
|
||||
if (i.X.RA) {
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead);
|
||||
} else {
|
||||
d.AddUImmOperand(0, 1);
|
||||
}
|
||||
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
XEDISASMR(icbi, 0x7C0007AC, X )(InstrData& i, InstrDisasm& d) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void RegisterDisasmCategoryMemory() {
|
||||
XEREGISTERINSTR(lbz, 0x88000000);
|
||||
XEREGISTERINSTR(lbzu, 0x8C000000);
|
||||
XEREGISTERINSTR(lbzux, 0x7C0000EE);
|
||||
XEREGISTERINSTR(lbzx, 0x7C0000AE);
|
||||
XEREGISTERINSTR(ld, 0xE8000000);
|
||||
XEREGISTERINSTR(ldu, 0xE8000001);
|
||||
XEREGISTERINSTR(ldux, 0x7C00006A);
|
||||
XEREGISTERINSTR(ldx, 0x7C00002A);
|
||||
XEREGISTERINSTR(lha, 0xA8000000);
|
||||
XEREGISTERINSTR(lhau, 0xAC000000);
|
||||
XEREGISTERINSTR(lhaux, 0x7C0002EE);
|
||||
XEREGISTERINSTR(lhax, 0x7C0002AE);
|
||||
XEREGISTERINSTR(lhz, 0xA0000000);
|
||||
XEREGISTERINSTR(lhzu, 0xA4000000);
|
||||
XEREGISTERINSTR(lhzux, 0x7C00026E);
|
||||
XEREGISTERINSTR(lhzx, 0x7C00022E);
|
||||
XEREGISTERINSTR(lwa, 0xE8000002);
|
||||
XEREGISTERINSTR(lwaux, 0x7C0002EA);
|
||||
XEREGISTERINSTR(lwax, 0x7C0002AA);
|
||||
XEREGISTERINSTR(lwz, 0x80000000);
|
||||
XEREGISTERINSTR(lwzu, 0x84000000);
|
||||
XEREGISTERINSTR(lwzux, 0x7C00006E);
|
||||
XEREGISTERINSTR(lwzx, 0x7C00002E);
|
||||
XEREGISTERINSTR(stb, 0x98000000);
|
||||
XEREGISTERINSTR(stbu, 0x9C000000);
|
||||
XEREGISTERINSTR(stbux, 0x7C0001EE);
|
||||
XEREGISTERINSTR(stbx, 0x7C0001AE);
|
||||
XEREGISTERINSTR(std, 0xF8000000);
|
||||
XEREGISTERINSTR(stdu, 0xF8000001);
|
||||
XEREGISTERINSTR(stdux, 0x7C00016A);
|
||||
XEREGISTERINSTR(stdx, 0x7C00012A);
|
||||
XEREGISTERINSTR(sth, 0xB0000000);
|
||||
XEREGISTERINSTR(sthu, 0xB4000000);
|
||||
XEREGISTERINSTR(sthux, 0x7C00036E);
|
||||
XEREGISTERINSTR(sthx, 0x7C00032E);
|
||||
XEREGISTERINSTR(stw, 0x90000000);
|
||||
XEREGISTERINSTR(stwu, 0x94000000);
|
||||
XEREGISTERINSTR(stwux, 0x7C00016E);
|
||||
XEREGISTERINSTR(stwx, 0x7C00012E);
|
||||
XEREGISTERINSTR(lhbrx, 0x7C00062C);
|
||||
XEREGISTERINSTR(lwbrx, 0x7C00042C);
|
||||
XEREGISTERINSTR(ldbrx, 0x7C000428);
|
||||
XEREGISTERINSTR(sthbrx, 0x7C00072C);
|
||||
XEREGISTERINSTR(stwbrx, 0x7C00052C);
|
||||
XEREGISTERINSTR(stdbrx, 0x7C000528);
|
||||
XEREGISTERINSTR(lmw, 0xB8000000);
|
||||
XEREGISTERINSTR(stmw, 0xBC000000);
|
||||
XEREGISTERINSTR(lswi, 0x7C0004AA);
|
||||
XEREGISTERINSTR(lswx, 0x7C00042A);
|
||||
XEREGISTERINSTR(stswi, 0x7C0005AA);
|
||||
XEREGISTERINSTR(stswx, 0x7C00052A);
|
||||
XEREGISTERINSTR(eieio, 0x7C0006AC);
|
||||
XEREGISTERINSTR(isync, 0x4C00012C);
|
||||
XEREGISTERINSTR(ldarx, 0x7C0000A8);
|
||||
XEREGISTERINSTR(lwarx, 0x7C000028);
|
||||
XEREGISTERINSTR(stdcx, 0x7C0001AD);
|
||||
XEREGISTERINSTR(stwcx, 0x7C00012D);
|
||||
XEREGISTERINSTR(sync, 0x7C0004AC);
|
||||
XEREGISTERINSTR(lfd, 0xC8000000);
|
||||
XEREGISTERINSTR(lfdu, 0xCC000000);
|
||||
XEREGISTERINSTR(lfdux, 0x7C0004EE);
|
||||
XEREGISTERINSTR(lfdx, 0x7C0004AE);
|
||||
XEREGISTERINSTR(lfs, 0xC0000000);
|
||||
XEREGISTERINSTR(lfsu, 0xC4000000);
|
||||
XEREGISTERINSTR(lfsux, 0x7C00046E);
|
||||
XEREGISTERINSTR(lfsx, 0x7C00042E);
|
||||
XEREGISTERINSTR(stfd, 0xD8000000);
|
||||
XEREGISTERINSTR(stfdu, 0xDC000000);
|
||||
XEREGISTERINSTR(stfdux, 0x7C0005EE);
|
||||
XEREGISTERINSTR(stfdx, 0x7C0005AE);
|
||||
XEREGISTERINSTR(stfiwx, 0x7C0007AE);
|
||||
XEREGISTERINSTR(stfs, 0xD0000000);
|
||||
XEREGISTERINSTR(stfsu, 0xD4000000);
|
||||
XEREGISTERINSTR(stfsux, 0x7C00056E);
|
||||
XEREGISTERINSTR(stfsx, 0x7C00052E);
|
||||
XEREGISTERINSTR(dcbf, 0x7C0000AC);
|
||||
XEREGISTERINSTR(dcbst, 0x7C00006C);
|
||||
XEREGISTERINSTR(dcbt, 0x7C00022C);
|
||||
XEREGISTERINSTR(dcbtst, 0x7C0001EC);
|
||||
XEREGISTERINSTR(dcbz, 0x7C0007EC);
|
||||
XEREGISTERINSTR(icbi, 0x7C0007AC);
|
||||
}
|
||||
|
||||
|
||||
} // namespace ppc
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
||||
36
src/alloy/frontend/ppc/ppc_emit-private.h
Normal file
36
src/alloy/frontend/ppc/ppc_emit-private.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_FRONTEND_PPC_PPC_EMIT_PRIVATE_H_
|
||||
#define ALLOY_FRONTEND_PPC_PPC_EMIT_PRIVATE_H_
|
||||
|
||||
#include <alloy/frontend/ppc/ppc_emit.h>
|
||||
#include <alloy/frontend/ppc/ppc_instr.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
namespace ppc {
|
||||
|
||||
|
||||
#define XEEMITTER(name, opcode, format) int InstrEmit_##name
|
||||
|
||||
#define XEREGISTERINSTR(name, opcode) \
|
||||
RegisterInstrEmit(opcode, (InstrEmitFn)InstrEmit_##name);
|
||||
|
||||
//#define XEINSTRNOTIMPLEMENTED()
|
||||
#define XEINSTRNOTIMPLEMENTED XEASSERTALWAYS
|
||||
|
||||
|
||||
} // namespace ppc
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_FRONTEND_PPC_PPC_EMIT_PRIVATE_H_
|
||||
33
src/alloy/frontend/ppc/ppc_emit.h
Normal file
33
src/alloy/frontend/ppc/ppc_emit.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_FRONTEND_PPC_PPC_EMIT_H_
|
||||
#define ALLOY_FRONTEND_PPC_PPC_EMIT_H_
|
||||
|
||||
#include <alloy/frontend/ppc/ppc_instr.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
namespace ppc {
|
||||
|
||||
|
||||
void RegisterEmitCategoryAltivec();
|
||||
void RegisterEmitCategoryALU();
|
||||
void RegisterEmitCategoryControl();
|
||||
void RegisterEmitCategoryFPU();
|
||||
void RegisterEmitCategoryMemory();
|
||||
|
||||
|
||||
} // namespace ppc
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_FRONTEND_PPC_PPC_EMIT_H_
|
||||
2170
src/alloy/frontend/ppc/ppc_emit_altivec.cc
Normal file
2170
src/alloy/frontend/ppc/ppc_emit_altivec.cc
Normal file
File diff suppressed because it is too large
Load Diff
1394
src/alloy/frontend/ppc/ppc_emit_alu.cc
Normal file
1394
src/alloy/frontend/ppc/ppc_emit_alu.cc
Normal file
File diff suppressed because it is too large
Load Diff
577
src/alloy/frontend/ppc/ppc_emit_control.cc
Normal file
577
src/alloy/frontend/ppc/ppc_emit_control.cc
Normal file
@@ -0,0 +1,577 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
* 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 <alloy/frontend/ppc/ppc_emit-private.h>
|
||||
|
||||
#include <alloy/frontend/ppc/ppc_context.h>
|
||||
#include <alloy/frontend/ppc/ppc_function_builder.h>
|
||||
|
||||
|
||||
using namespace alloy::frontend::ppc;
|
||||
using namespace alloy::hir;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
namespace ppc {
|
||||
|
||||
|
||||
int InstrEmit_branch(
|
||||
PPCFunctionBuilder& f, const char* src, uint64_t cia,
|
||||
Value* nia, bool lk, Value* cond = NULL, bool expect_true = true) {
|
||||
uint32_t call_flags = 0;
|
||||
|
||||
// TODO(benvanik): this may be wrong and overwrite LRs when not desired!
|
||||
// The docs say always, though...
|
||||
// Note that we do the update before we branch/call as we need it to
|
||||
// be correct for returns.
|
||||
if (lk) {
|
||||
f.StoreLR(f.LoadConstant(cia + 4));
|
||||
}
|
||||
|
||||
if (!lk) {
|
||||
// If LR is not set this call will never return here.
|
||||
call_flags |= CALL_TAIL;
|
||||
}
|
||||
|
||||
// TODO(benvanik): set CALL_TAIL if !lk and the last block in the fn.
|
||||
// This is almost always a jump to restore gpr.
|
||||
|
||||
// TODO(benvanik): detect call-self.
|
||||
|
||||
if (nia->IsConstant()) {
|
||||
// Direct branch to address.
|
||||
// If it's a block inside of ourself, setup a fast jump.
|
||||
uint64_t nia_value = nia->AsUint64() & 0xFFFFFFFF;
|
||||
Label* label = f.LookupLabel(nia_value);
|
||||
if (label) {
|
||||
// Branch to label.
|
||||
uint32_t branch_flags = 0;
|
||||
if (cond) {
|
||||
if (expect_true) {
|
||||
f.BranchTrue(cond, label, branch_flags);
|
||||
} else {
|
||||
f.BranchFalse(cond, label, branch_flags);
|
||||
}
|
||||
} else {
|
||||
f.Branch(label, branch_flags);
|
||||
}
|
||||
} else {
|
||||
// Call function.
|
||||
FunctionInfo* symbol_info = f.LookupFunction(nia_value);
|
||||
if (cond) {
|
||||
if (!expect_true) {
|
||||
cond = f.IsFalse(cond);
|
||||
}
|
||||
f.CallTrue(cond, symbol_info, call_flags);
|
||||
} else {
|
||||
f.Call(symbol_info, call_flags);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Indirect branch to pointer.
|
||||
if (cond) {
|
||||
if (!expect_true) {
|
||||
cond = f.IsFalse(cond);
|
||||
}
|
||||
f.CallIndirectTrue(cond, nia, call_flags);
|
||||
} else {
|
||||
f.CallIndirect(nia, call_flags);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
XEEMITTER(bx, 0x48000000, I )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// if AA then
|
||||
// NIA <- EXTS(LI || 0b00)
|
||||
// else
|
||||
// NIA <- CIA + EXTS(LI || 0b00)
|
||||
// if LK then
|
||||
// LR <- CIA + 4
|
||||
|
||||
uint32_t nia;
|
||||
if (i.I.AA) {
|
||||
nia = (uint32_t)XEEXTS26(i.I.LI << 2);
|
||||
} else {
|
||||
nia = (uint32_t)(i.address + XEEXTS26(i.I.LI << 2));
|
||||
}
|
||||
|
||||
return InstrEmit_branch(
|
||||
f, "bx", i.address, f.LoadConstant(nia), i.I.LK);
|
||||
}
|
||||
|
||||
XEEMITTER(bcx, 0x40000000, B )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// if ¬BO[2] then
|
||||
// CTR <- CTR - 1
|
||||
// ctr_ok <- BO[2] | ((CTR[0:63] != 0) XOR BO[3])
|
||||
// cond_ok <- BO[0] | (CR[BI+32] ≡ BO[1])
|
||||
// if ctr_ok & cond_ok then
|
||||
// if AA then
|
||||
// NIA <- EXTS(BD || 0b00)
|
||||
// else
|
||||
// NIA <- CIA + EXTS(BD || 0b00)
|
||||
// if LK then
|
||||
// LR <- CIA + 4
|
||||
|
||||
// NOTE: the condition bits are reversed!
|
||||
// 01234 (docs)
|
||||
// 43210 (real)
|
||||
|
||||
Value* ctr_ok = NULL;
|
||||
if (XESELECTBITS(i.B.BO, 2, 2)) {
|
||||
// Ignore ctr.
|
||||
} else {
|
||||
// Decrement counter.
|
||||
Value* ctr = f.LoadCTR();
|
||||
ctr = f.Sub(ctr, f.LoadConstant((int64_t)1));
|
||||
f.StoreCTR(ctr);
|
||||
// Ctr check.
|
||||
// TODO(benvanik): could do something similar to cond and avoid the
|
||||
// is_true/branch_true pairing.
|
||||
if (XESELECTBITS(i.B.BO, 1, 1)) {
|
||||
ctr_ok = f.IsFalse(ctr);
|
||||
} else {
|
||||
ctr_ok = f.IsTrue(ctr);
|
||||
}
|
||||
}
|
||||
|
||||
Value* cond_ok = NULL;
|
||||
bool not_cond_ok = false;
|
||||
if (XESELECTBITS(i.B.BO, 4, 4)) {
|
||||
// Ignore cond.
|
||||
} else {
|
||||
Value* cr = f.LoadCRField(i.B.BI >> 2, i.B.BI & 3);
|
||||
cond_ok = cr;
|
||||
if (XESELECTBITS(i.B.BO, 3, 3)) {
|
||||
// Expect true.
|
||||
not_cond_ok = false;
|
||||
} else {
|
||||
// Expect false.
|
||||
not_cond_ok = true;
|
||||
}
|
||||
}
|
||||
|
||||
// We do a bit of optimization here to make the llvm assembly easier to read.
|
||||
Value* ok = NULL;
|
||||
bool expect_true = true;
|
||||
if (ctr_ok && cond_ok) {
|
||||
if (not_cond_ok) {
|
||||
cond_ok = f.IsFalse(cond_ok);
|
||||
}
|
||||
ok = f.And(ctr_ok, cond_ok);
|
||||
} else if (ctr_ok) {
|
||||
ok = ctr_ok;
|
||||
} else if (cond_ok) {
|
||||
ok = cond_ok;
|
||||
expect_true = !not_cond_ok;
|
||||
}
|
||||
|
||||
uint32_t nia;
|
||||
if (i.B.AA) {
|
||||
nia = (uint32_t)XEEXTS16(i.B.BD << 2);
|
||||
} else {
|
||||
nia = (uint32_t)(i.address + XEEXTS16(i.B.BD << 2));
|
||||
}
|
||||
return InstrEmit_branch(
|
||||
f, "bcx", i.address, f.LoadConstant(nia), i.B.LK, ok, expect_true);
|
||||
}
|
||||
|
||||
XEEMITTER(bcctrx, 0x4C000420, XL )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// cond_ok <- BO[0] | (CR[BI+32] ≡ BO[1])
|
||||
// if cond_ok then
|
||||
// NIA <- CTR[0:61] || 0b00
|
||||
// if LK then
|
||||
// LR <- CIA + 4
|
||||
|
||||
// NOTE: the condition bits are reversed!
|
||||
// 01234 (docs)
|
||||
// 43210 (real)
|
||||
|
||||
Value* cond_ok = NULL;
|
||||
bool not_cond_ok = false;
|
||||
if (XESELECTBITS(i.XL.BO, 4, 4)) {
|
||||
// Ignore cond.
|
||||
} else {
|
||||
Value* cr = f.LoadCRField(i.XL.BI >> 2, i.XL.BI & 3);
|
||||
cond_ok = cr;
|
||||
if (XESELECTBITS(i.XL.BO, 3, 3)) {
|
||||
// Expect true.
|
||||
not_cond_ok = false;
|
||||
} else {
|
||||
// Expect false.
|
||||
not_cond_ok = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool expect_true = !not_cond_ok;
|
||||
return InstrEmit_branch(
|
||||
f, "bcctrx", i.address, f.LoadCTR(), i.XL.LK, cond_ok, expect_true);
|
||||
}
|
||||
|
||||
XEEMITTER(bclrx, 0x4C000020, XL )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// if ¬BO[2] then
|
||||
// CTR <- CTR - 1
|
||||
// ctr_ok <- BO[2] | ((CTR[0:63] != 0) XOR BO[3]
|
||||
// cond_ok <- BO[0] | (CR[BI+32] ≡ BO[1])
|
||||
// if ctr_ok & cond_ok then
|
||||
// NIA <- LR[0:61] || 0b00
|
||||
// if LK then
|
||||
// LR <- CIA + 4
|
||||
|
||||
// NOTE: the condition bits are reversed!
|
||||
// 01234 (docs)
|
||||
// 43210 (real)
|
||||
|
||||
Value* ctr_ok = NULL;
|
||||
if (XESELECTBITS(i.XL.BO, 2, 2)) {
|
||||
// Ignore ctr.
|
||||
} else {
|
||||
// Decrement counter.
|
||||
Value* ctr = f.LoadCTR();
|
||||
ctr = f.Sub(ctr, f.LoadConstant((int64_t)1));
|
||||
f.StoreCTR(ctr);
|
||||
// Ctr check.
|
||||
// TODO(benvanik): could do something similar to cond and avoid the
|
||||
// is_true/branch_true pairing.
|
||||
if (XESELECTBITS(i.XL.BO, 1, 1)) {
|
||||
ctr_ok = f.IsFalse(ctr);
|
||||
} else {
|
||||
ctr_ok = f.IsTrue(ctr);
|
||||
}
|
||||
}
|
||||
|
||||
Value* cond_ok = NULL;
|
||||
bool not_cond_ok = false;
|
||||
if (XESELECTBITS(i.XL.BO, 4, 4)) {
|
||||
// Ignore cond.
|
||||
} else {
|
||||
Value* cr = f.LoadCRField(i.XL.BI >> 2, i.XL.BI & 3);
|
||||
cond_ok = cr;
|
||||
if (XESELECTBITS(i.XL.BO, 3, 3)) {
|
||||
// Expect true.
|
||||
not_cond_ok = false;
|
||||
} else {
|
||||
// Expect false.
|
||||
not_cond_ok = true;
|
||||
}
|
||||
}
|
||||
|
||||
// We do a bit of optimization here to make the llvm assembly easier to read.
|
||||
Value* ok = NULL;
|
||||
bool expect_true = true;
|
||||
if (ctr_ok && cond_ok) {
|
||||
if (not_cond_ok) {
|
||||
cond_ok = f.IsFalse(cond_ok);
|
||||
}
|
||||
ok = f.And(ctr_ok, cond_ok);
|
||||
} else if (ctr_ok) {
|
||||
ok = ctr_ok;
|
||||
} else if (cond_ok) {
|
||||
ok = cond_ok;
|
||||
expect_true = !not_cond_ok;
|
||||
}
|
||||
|
||||
// TODO(benvanik): run a DFA pass to see if we can detect whether this is
|
||||
// a normal function return that is pulling the LR from the stack that
|
||||
// it set in the prolog. If so, we can omit the dynamic check!
|
||||
|
||||
//// Dynamic test when branching to LR, which is usually used for the return.
|
||||
//// We only do this if LK=0 as returns wouldn't set LR.
|
||||
//// Ideally it's a return and we can just do a simple ret and be done.
|
||||
//// If it's not, we fall through to the full indirection logic.
|
||||
//if (!lk && reg == kXEPPCRegLR) {
|
||||
// // The return block will spill registers for us.
|
||||
// // TODO(benvanik): 'lr_mismatch' debug info.
|
||||
// // Note: we need to test on *only* the 32-bit target, as the target ptr may
|
||||
// // have garbage in the upper 32 bits.
|
||||
// c.cmp(target.r32(), c.getGpArg(1).r32());
|
||||
// // TODO(benvanik): evaluate hint here.
|
||||
// c.je(e.GetReturnLabel(), kCondHintLikely);
|
||||
//}
|
||||
if (!i.XL.LK && !ok) {
|
||||
// Return (most likely).
|
||||
// TODO(benvanik): test? ReturnCheck()?
|
||||
f.Return();
|
||||
return 0;
|
||||
}
|
||||
|
||||
return InstrEmit_branch(
|
||||
f, "bclrx", i.address, f.LoadLR(), i.XL.LK, ok, expect_true);
|
||||
}
|
||||
|
||||
|
||||
// Condition register logical (A-23)
|
||||
|
||||
XEEMITTER(crand, 0x4C000202, XL )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(crandc, 0x4C000102, XL )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(creqv, 0x4C000242, XL )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(crnand, 0x4C0001C2, XL )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(crnor, 0x4C000042, XL )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(cror, 0x4C000382, XL )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(crorc, 0x4C000342, XL )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(crxor, 0x4C000182, XL )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(mcrf, 0x4C000000, XL )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// System linkage (A-24)
|
||||
|
||||
XEEMITTER(sc, 0x44000002, SC )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// Trap (A-25)
|
||||
|
||||
int InstrEmit_trap(PPCFunctionBuilder& f, InstrData& i,
|
||||
Value* va, Value* vb, uint32_t TO) {
|
||||
// if (a < b) & TO[0] then TRAP
|
||||
// if (a > b) & TO[1] then TRAP
|
||||
// if (a = b) & TO[2] then TRAP
|
||||
// if (a <u b) & TO[3] then TRAP
|
||||
// if (a >u b) & TO[4] then TRAP
|
||||
// Bits swapped:
|
||||
// 01234
|
||||
// 43210
|
||||
if (!TO) {
|
||||
return 0;
|
||||
}
|
||||
if (TO & (1 << 4)) {
|
||||
// a < b
|
||||
f.TrapTrue(f.CompareSLT(va, vb));
|
||||
}
|
||||
if (TO & (1 << 3)) {
|
||||
// a > b
|
||||
f.TrapTrue(f.CompareSGT(va, vb));
|
||||
}
|
||||
if (TO & (1 << 2)) {
|
||||
// a = b
|
||||
f.TrapTrue(f.CompareEQ(va, vb));
|
||||
}
|
||||
if (TO & (1 << 1)) {
|
||||
// a <u b
|
||||
f.TrapTrue(f.CompareULT(va, vb));
|
||||
}
|
||||
if (TO & (1 << 0)) {
|
||||
// a >u b
|
||||
f.TrapTrue(f.CompareUGT(va, vb));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(td, 0x7C000088, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// a <- (RA)
|
||||
// b <- (RB)
|
||||
// if (a < b) & TO[0] then TRAP
|
||||
// if (a > b) & TO[1] then TRAP
|
||||
// if (a = b) & TO[2] then TRAP
|
||||
// if (a <u b) & TO[3] then TRAP
|
||||
// if (a >u b) & TO[4] then TRAP
|
||||
Value* ra = f.LoadGPR(i.X.RA);
|
||||
Value* rb = f.LoadGPR(i.X.RB);
|
||||
return InstrEmit_trap(f, i, ra, rb, i.X.RT);
|
||||
}
|
||||
|
||||
XEEMITTER(tdi, 0x08000000, D )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// a <- (RA)
|
||||
// if (a < EXTS(SI)) & TO[0] then TRAP
|
||||
// if (a > EXTS(SI)) & TO[1] then TRAP
|
||||
// if (a = EXTS(SI)) & TO[2] then TRAP
|
||||
// if (a <u EXTS(SI)) & TO[3] then TRAP
|
||||
// if (a >u EXTS(SI)) & TO[4] then TRAP
|
||||
Value* ra = f.LoadGPR(i.D.RA);
|
||||
Value* rb = f.LoadConstant(XEEXTS16(i.D.DS));
|
||||
return InstrEmit_trap(f, i, ra, rb, i.D.RT);
|
||||
}
|
||||
|
||||
XEEMITTER(tw, 0x7C000008, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// a <- EXTS((RA)[32:63])
|
||||
// b <- EXTS((RB)[32:63])
|
||||
// if (a < b) & TO[0] then TRAP
|
||||
// if (a > b) & TO[1] then TRAP
|
||||
// if (a = b) & TO[2] then TRAP
|
||||
// if (a <u b) & TO[3] then TRAP
|
||||
// if (a >u b) & TO[4] then TRAP
|
||||
Value* ra = f.SignExtend(f.Truncate(
|
||||
f.LoadGPR(i.X.RA), INT32_TYPE), INT64_TYPE);
|
||||
Value* rb = f.SignExtend(f.Truncate(
|
||||
f.LoadGPR(i.X.RB), INT32_TYPE), INT64_TYPE);
|
||||
return InstrEmit_trap(f, i, ra, rb, i.X.RT);
|
||||
}
|
||||
|
||||
XEEMITTER(twi, 0x0C000000, D )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// a <- EXTS((RA)[32:63])
|
||||
// if (a < EXTS(SI)) & TO[0] then TRAP
|
||||
// if (a > EXTS(SI)) & TO[1] then TRAP
|
||||
// if (a = EXTS(SI)) & TO[2] then TRAP
|
||||
// if (a <u EXTS(SI)) & TO[3] then TRAP
|
||||
// if (a >u EXTS(SI)) & TO[4] then TRAP
|
||||
Value* ra = f.SignExtend(f.Truncate(
|
||||
f.LoadGPR(i.D.RA), INT32_TYPE), INT64_TYPE);
|
||||
Value* rb = f.LoadConstant(XEEXTS16(i.D.DS));
|
||||
return InstrEmit_trap(f, i, ra, rb, i.D.RT);
|
||||
}
|
||||
|
||||
|
||||
// Processor control (A-26)
|
||||
|
||||
XEEMITTER(mfcr, 0x7C000026, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(mfspr, 0x7C0002A6, XFX)(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// n <- spr[5:9] || spr[0:4]
|
||||
// if length(SPR(n)) = 64 then
|
||||
// RT <- SPR(n)
|
||||
// else
|
||||
// RT <- i32.0 || SPR(n)
|
||||
Value* v;
|
||||
const uint32_t n = ((i.XFX.spr & 0x1F) << 5) | ((i.XFX.spr >> 5) & 0x1F);
|
||||
switch (n) {
|
||||
case 1:
|
||||
// XER
|
||||
v = f.LoadXER();
|
||||
break;
|
||||
case 8:
|
||||
// LR
|
||||
v = f.LoadLR();
|
||||
break;
|
||||
case 9:
|
||||
// CTR
|
||||
v = f.LoadCTR();
|
||||
break;
|
||||
// 268 + 269 = TB + TBU
|
||||
default:
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
f.StoreGPR(i.XFX.RT, v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(mftb, 0x7C0002E6, XFX)(PPCFunctionBuilder& f, InstrData& i) {
|
||||
Value* time;
|
||||
LARGE_INTEGER counter;
|
||||
if (QueryPerformanceCounter(&counter)) {
|
||||
time = f.LoadConstant(counter.QuadPart);
|
||||
} else {
|
||||
time = f.LoadZero(INT64_TYPE);
|
||||
}
|
||||
f.StoreGPR(i.XFX.RT, time);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(mtcrf, 0x7C000120, XFX)(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(mtspr, 0x7C0003A6, XFX)(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// n <- spr[5:9] || spr[0:4]
|
||||
// if length(SPR(n)) = 64 then
|
||||
// SPR(n) <- (RS)
|
||||
// else
|
||||
// SPR(n) <- (RS)[32:63]
|
||||
|
||||
Value* rt = f.LoadGPR(i.XFX.RT);
|
||||
|
||||
const uint32_t n = ((i.XFX.spr & 0x1F) << 5) | ((i.XFX.spr >> 5) & 0x1F);
|
||||
switch (n) {
|
||||
case 1:
|
||||
// XER
|
||||
f.StoreXER(rt);
|
||||
break;
|
||||
case 8:
|
||||
// LR
|
||||
f.StoreLR(rt);
|
||||
break;
|
||||
case 9:
|
||||
// CTR
|
||||
f.StoreCTR(rt);
|
||||
break;
|
||||
default:
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void RegisterEmitCategoryControl() {
|
||||
XEREGISTERINSTR(bx, 0x48000000);
|
||||
XEREGISTERINSTR(bcx, 0x40000000);
|
||||
XEREGISTERINSTR(bcctrx, 0x4C000420);
|
||||
XEREGISTERINSTR(bclrx, 0x4C000020);
|
||||
XEREGISTERINSTR(crand, 0x4C000202);
|
||||
XEREGISTERINSTR(crandc, 0x4C000102);
|
||||
XEREGISTERINSTR(creqv, 0x4C000242);
|
||||
XEREGISTERINSTR(crnand, 0x4C0001C2);
|
||||
XEREGISTERINSTR(crnor, 0x4C000042);
|
||||
XEREGISTERINSTR(cror, 0x4C000382);
|
||||
XEREGISTERINSTR(crorc, 0x4C000342);
|
||||
XEREGISTERINSTR(crxor, 0x4C000182);
|
||||
XEREGISTERINSTR(mcrf, 0x4C000000);
|
||||
XEREGISTERINSTR(sc, 0x44000002);
|
||||
XEREGISTERINSTR(td, 0x7C000088);
|
||||
XEREGISTERINSTR(tdi, 0x08000000);
|
||||
XEREGISTERINSTR(tw, 0x7C000008);
|
||||
XEREGISTERINSTR(twi, 0x0C000000);
|
||||
XEREGISTERINSTR(mfcr, 0x7C000026);
|
||||
XEREGISTERINSTR(mfspr, 0x7C0002A6);
|
||||
XEREGISTERINSTR(mftb, 0x7C0002E6);
|
||||
XEREGISTERINSTR(mtcrf, 0x7C000120);
|
||||
XEREGISTERINSTR(mtspr, 0x7C0003A6);
|
||||
}
|
||||
|
||||
|
||||
} // namespace ppc
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
||||
543
src/alloy/frontend/ppc/ppc_emit_fpu.cc
Normal file
543
src/alloy/frontend/ppc/ppc_emit_fpu.cc
Normal file
@@ -0,0 +1,543 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
* 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 <alloy/frontend/ppc/ppc_emit-private.h>
|
||||
|
||||
#include <alloy/frontend/ppc/ppc_context.h>
|
||||
#include <alloy/frontend/ppc/ppc_function_builder.h>
|
||||
|
||||
|
||||
using namespace alloy::frontend::ppc;
|
||||
using namespace alloy::hir;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
namespace ppc {
|
||||
|
||||
|
||||
// Good source of information:
|
||||
// http://mamedev.org/source/src/emu/cpu/powerpc/ppc_ops.c
|
||||
// The correctness of that code is not reflected here yet -_-
|
||||
|
||||
|
||||
// Enable rounding numbers to single precision as required.
|
||||
// This adds a bunch of work per operation and I'm not sure it's required.
|
||||
#define ROUND_TO_SINGLE
|
||||
|
||||
|
||||
// Floating-point arithmetic (A-8)
|
||||
|
||||
XEEMITTER(faddx, 0xFC00002A, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- (frA) + (frB)
|
||||
Value* v = f.Add(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRB));
|
||||
f.StoreFPR(i.A.FRT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(faddsx, 0xEC00002A, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- (frA) + (frB)
|
||||
Value* v = f.Add(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRB));
|
||||
v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE);
|
||||
f.StoreFPR(i.A.FRT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fdivx, 0xFC000024, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- frA / frB
|
||||
Value* v = f.Div(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRB));
|
||||
f.StoreFPR(i.A.FRT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fdivsx, 0xEC000024, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- frA / frB
|
||||
Value* v = f.Div(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRB));
|
||||
v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE);
|
||||
f.StoreFPR(i.A.FRT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fmulx, 0xFC000032, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- (frA) x (frC)
|
||||
Value* v = f.Mul(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRC));
|
||||
f.StoreFPR(i.A.FRT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fmulsx, 0xEC000032, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- (frA) x (frC)
|
||||
Value* v = f.Mul(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRC));
|
||||
v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE);
|
||||
f.StoreFPR(i.A.FRT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fresx, 0xEC000030, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(frsqrtex, 0xFC000034, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(fsubx, 0xFC000028, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- (frA) - (frB)
|
||||
Value* v = f.Sub(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRB));
|
||||
f.StoreFPR(i.A.FRT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fsubsx, 0xEC000028, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- (frA) - (frB)
|
||||
Value* v = f.Sub(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRB));
|
||||
v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE);
|
||||
f.StoreFPR(i.A.FRT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fselx, 0xFC00002E, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// if (frA) >= 0.0
|
||||
// then frD <- (frC)
|
||||
// else frD <- (frB)
|
||||
Value* ge = f.CompareSGE(f.LoadFPR(i.A.FRA), f.LoadConstant(0.0));
|
||||
Value* v = f.Select(ge, f.LoadFPR(i.A.FRC), f.LoadFPR(i.A.FRB));
|
||||
f.StoreFPR(i.A.FRT, v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fsqrtx, 0xFC00002C, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// Double precision:
|
||||
// frD <- sqrt(frB)
|
||||
Value* v = f.Sqrt(f.LoadFPR(i.A.FRA));
|
||||
f.StoreFPR(i.A.FRT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fsqrtsx, 0xEC00002C, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// Single precision:
|
||||
// frD <- sqrt(frB)
|
||||
Value* v = f.Sqrt(f.LoadFPR(i.A.FRA));
|
||||
v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE);
|
||||
f.StoreFPR(i.A.FRT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Floating-point multiply-add (A-9)
|
||||
|
||||
XEEMITTER(fmaddx, 0xFC00003A, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- (frA x frC) + frB
|
||||
Value* v = f.MulAdd(
|
||||
f.LoadFPR(i.A.FRA),
|
||||
f.LoadFPR(i.A.FRC),
|
||||
f.LoadFPR(i.A.FRB));
|
||||
f.StoreFPR(i.A.FRT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fmaddsx, 0xEC00003A, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- (frA x frC) + frB
|
||||
Value* v = f.MulAdd(
|
||||
f.LoadFPR(i.A.FRA),
|
||||
f.LoadFPR(i.A.FRC),
|
||||
f.LoadFPR(i.A.FRB));
|
||||
v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE);
|
||||
f.StoreFPR(i.A.FRT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fmsubx, 0xFC000038, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- (frA x frC) - frB
|
||||
Value* v = f.MulSub(
|
||||
f.LoadFPR(i.A.FRA),
|
||||
f.LoadFPR(i.A.FRC),
|
||||
f.LoadFPR(i.A.FRB));
|
||||
f.StoreFPR(i.A.FRT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fmsubsx, 0xEC000038, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- (frA x frC) - frB
|
||||
Value* v = f.MulSub(
|
||||
f.LoadFPR(i.A.FRA),
|
||||
f.LoadFPR(i.A.FRC),
|
||||
f.LoadFPR(i.A.FRB));
|
||||
v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE);
|
||||
f.StoreFPR(i.A.FRT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fnmaddx, 0xFC00003E, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(fnmaddsx, 0xEC00003E, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(fnmsubx, 0xFC00003C, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- -([frA x frC] - frB)
|
||||
Value* v = f.Neg(f.MulSub(
|
||||
f.LoadFPR(i.A.FRA),
|
||||
f.LoadFPR(i.A.FRC),
|
||||
f.LoadFPR(i.A.FRB)));
|
||||
f.StoreFPR(i.A.FRT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fnmsubsx, 0xEC00003C, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- -([frA x frC] - frB)
|
||||
Value* v = f.Neg(f.MulSub(
|
||||
f.LoadFPR(i.A.FRA),
|
||||
f.LoadFPR(i.A.FRC),
|
||||
f.LoadFPR(i.A.FRB)));
|
||||
v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE);
|
||||
f.StoreFPR(i.A.FRT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Floating-point rounding and conversion (A-10)
|
||||
|
||||
XEEMITTER(fcfidx, 0xFC00069C, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- signed_int64_to_double( frB )
|
||||
Value* v = f.Convert(
|
||||
f.Cast(f.LoadFPR(i.A.FRB), INT64_TYPE),
|
||||
FLOAT64_TYPE);
|
||||
f.StoreFPR(i.A.FRT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fctidx, 0xFC00065C, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- double_to_signed_int64( frB )
|
||||
// TODO(benvanik): pull from FPSCR[RN]
|
||||
RoundMode round_mode = ROUND_TO_ZERO;
|
||||
Value* v = f.Convert(f.LoadFPR(i.X.RB), INT64_TYPE, round_mode);
|
||||
v = f.Cast(v, FLOAT64_TYPE);
|
||||
f.StoreFPR(i.X.RT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.X.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fctidzx, 0xFC00065E, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// TODO(benvanik): assuming round to zero is always set, is that ok?
|
||||
return InstrEmit_fctidx(f, i);
|
||||
}
|
||||
|
||||
XEEMITTER(fctiwx, 0xFC00001C, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- double_to_signed_int32( frB )
|
||||
// TODO(benvanik): pull from FPSCR[RN]
|
||||
RoundMode round_mode = ROUND_TO_ZERO;
|
||||
Value* v = f.Convert(f.LoadFPR(i.X.RB), INT32_TYPE, round_mode);
|
||||
v = f.Cast(f.ZeroExtend(v, INT64_TYPE), FLOAT64_TYPE);
|
||||
f.StoreFPR(i.X.RT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fctiwzx, 0xFC00001E, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// TODO(benvanik): assuming round to zero is always set, is that ok?
|
||||
return InstrEmit_fctiwx(f, i);
|
||||
}
|
||||
|
||||
XEEMITTER(frspx, 0xFC000018, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- Round_single(frB)
|
||||
// TODO(benvanik): pull from FPSCR[RN]
|
||||
RoundMode round_mode = ROUND_TO_ZERO;
|
||||
Value* v = f.Convert(f.LoadFPR(i.X.RB), FLOAT32_TYPE, round_mode);
|
||||
v = f.Convert(v, FLOAT64_TYPE);
|
||||
f.StoreFPR(i.X.RT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.X.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Floating-point compare (A-11)
|
||||
|
||||
int InstrEmit_fcmpx_(PPCFunctionBuilder& f, InstrData& i, bool ordered) {
|
||||
// if (FRA) is a NaN or (FRB) is a NaN then
|
||||
// c <- 0b0001
|
||||
// else if (FRA) < (FRB) then
|
||||
// c <- 0b1000
|
||||
// else if (FRA) > (FRB) then
|
||||
// c <- 0b0100
|
||||
// else {
|
||||
// c <- 0b0010
|
||||
// }
|
||||
// FPCC <- c
|
||||
// CR[4*BF:4*BF+3] <- c
|
||||
// if (FRA) is an SNaN or (FRB) is an SNaN then
|
||||
// VXSNAN <- 1
|
||||
|
||||
// TODO(benvanik): update FPCC for mffsx/etc
|
||||
// TODO(benvanik): update VXSNAN
|
||||
const uint32_t crf = i.X.RT >> 2;
|
||||
// f.UpdateFPRF(v);
|
||||
f.UpdateCR(crf, f.LoadFPR(i.X.RA), f.LoadFPR(i.X.RB), true);
|
||||
return 0;
|
||||
}
|
||||
XEEMITTER(fcmpo, 0xFC000040, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
return InstrEmit_fcmpx_(f, i, true);
|
||||
}
|
||||
XEEMITTER(fcmpu, 0xFC000000, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
return InstrEmit_fcmpx_(f, i, false);
|
||||
}
|
||||
|
||||
|
||||
// Floating-point status and control register (A
|
||||
|
||||
XEEMITTER(mcrfs, 0xFC000080, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(mffsx, 0xFC00048E, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(mtfsb0x, 0xFC00008C, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(mtfsb1x, 0xFC00004C, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(mtfsfx, 0xFC00058E, XFL)(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(mtfsfix, 0xFC00010C, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// Floating-point move (A-21)
|
||||
|
||||
XEEMITTER(fabsx, 0xFC000210, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- abs(frB)
|
||||
Value* v = f.Abs(f.LoadFPR(i.X.RB));
|
||||
f.StoreFPR(i.X.RT, v);
|
||||
if (i.X.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fmrx, 0xFC000090, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- (frB)
|
||||
Value* v = f.LoadFPR(i.X.RB);
|
||||
f.StoreFPR(i.X.RT, v);
|
||||
if (i.X.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fnabsx, 0xFC000110, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(fnegx, 0xFC000050, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- ¬ frB[0] || frB[1-63]
|
||||
Value* v = f.Neg(f.LoadFPR(i.X.RB));
|
||||
f.StoreFPR(i.X.RT, v);
|
||||
if (i.X.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void RegisterEmitCategoryFPU() {
|
||||
XEREGISTERINSTR(faddx, 0xFC00002A);
|
||||
XEREGISTERINSTR(faddsx, 0xEC00002A);
|
||||
XEREGISTERINSTR(fdivx, 0xFC000024);
|
||||
XEREGISTERINSTR(fdivsx, 0xEC000024);
|
||||
XEREGISTERINSTR(fmulx, 0xFC000032);
|
||||
XEREGISTERINSTR(fmulsx, 0xEC000032);
|
||||
XEREGISTERINSTR(fresx, 0xEC000030);
|
||||
XEREGISTERINSTR(frsqrtex, 0xFC000034);
|
||||
XEREGISTERINSTR(fsubx, 0xFC000028);
|
||||
XEREGISTERINSTR(fsubsx, 0xEC000028);
|
||||
XEREGISTERINSTR(fselx, 0xFC00002E);
|
||||
XEREGISTERINSTR(fsqrtx, 0xFC00002C);
|
||||
XEREGISTERINSTR(fsqrtsx, 0xEC00002C);
|
||||
XEREGISTERINSTR(fmaddx, 0xFC00003A);
|
||||
XEREGISTERINSTR(fmaddsx, 0xEC00003A);
|
||||
XEREGISTERINSTR(fmsubx, 0xFC000038);
|
||||
XEREGISTERINSTR(fmsubsx, 0xEC000038);
|
||||
XEREGISTERINSTR(fnmaddx, 0xFC00003E);
|
||||
XEREGISTERINSTR(fnmaddsx, 0xEC00003E);
|
||||
XEREGISTERINSTR(fnmsubx, 0xFC00003C);
|
||||
XEREGISTERINSTR(fnmsubsx, 0xEC00003C);
|
||||
XEREGISTERINSTR(fcfidx, 0xFC00069C);
|
||||
XEREGISTERINSTR(fctidx, 0xFC00065C);
|
||||
XEREGISTERINSTR(fctidzx, 0xFC00065E);
|
||||
XEREGISTERINSTR(fctiwx, 0xFC00001C);
|
||||
XEREGISTERINSTR(fctiwzx, 0xFC00001E);
|
||||
XEREGISTERINSTR(frspx, 0xFC000018);
|
||||
XEREGISTERINSTR(fcmpo, 0xFC000040);
|
||||
XEREGISTERINSTR(fcmpu, 0xFC000000);
|
||||
XEREGISTERINSTR(mcrfs, 0xFC000080);
|
||||
XEREGISTERINSTR(mffsx, 0xFC00048E);
|
||||
XEREGISTERINSTR(mtfsb0x, 0xFC00008C);
|
||||
XEREGISTERINSTR(mtfsb1x, 0xFC00004C);
|
||||
XEREGISTERINSTR(mtfsfx, 0xFC00058E);
|
||||
XEREGISTERINSTR(mtfsfix, 0xFC00010C);
|
||||
XEREGISTERINSTR(fabsx, 0xFC000210);
|
||||
XEREGISTERINSTR(fmrx, 0xFC000090);
|
||||
XEREGISTERINSTR(fnabsx, 0xFC000110);
|
||||
XEREGISTERINSTR(fnegx, 0xFC000050);
|
||||
}
|
||||
|
||||
|
||||
} // namespace ppc
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
||||
1349
src/alloy/frontend/ppc/ppc_emit_memory.cc
Normal file
1349
src/alloy/frontend/ppc/ppc_emit_memory.cc
Normal file
File diff suppressed because it is too large
Load Diff
96
src/alloy/frontend/ppc/ppc_frontend.cc
Normal file
96
src/alloy/frontend/ppc/ppc_frontend.cc
Normal file
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 <alloy/frontend/ppc/ppc_frontend.h>
|
||||
|
||||
#include <alloy/frontend/tracing.h>
|
||||
#include <alloy/frontend/ppc/ppc_disasm.h>
|
||||
#include <alloy/frontend/ppc/ppc_emit.h>
|
||||
#include <alloy/frontend/ppc/ppc_translator.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::frontend;
|
||||
using namespace alloy::frontend::ppc;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
|
||||
namespace {
|
||||
void InitializeIfNeeded();
|
||||
void CleanupOnShutdown();
|
||||
|
||||
void InitializeIfNeeded() {
|
||||
static bool has_initialized = false;
|
||||
if (has_initialized) {
|
||||
return;
|
||||
}
|
||||
has_initialized = true;
|
||||
|
||||
RegisterDisasmCategoryAltivec();
|
||||
RegisterDisasmCategoryALU();
|
||||
RegisterDisasmCategoryControl();
|
||||
RegisterDisasmCategoryFPU();
|
||||
RegisterDisasmCategoryMemory();
|
||||
|
||||
RegisterEmitCategoryAltivec();
|
||||
RegisterEmitCategoryALU();
|
||||
RegisterEmitCategoryControl();
|
||||
RegisterEmitCategoryFPU();
|
||||
RegisterEmitCategoryMemory();
|
||||
|
||||
atexit(CleanupOnShutdown);
|
||||
}
|
||||
|
||||
void CleanupOnShutdown() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PPCFrontend::PPCFrontend(Runtime* runtime) :
|
||||
Frontend(runtime) {
|
||||
InitializeIfNeeded();
|
||||
}
|
||||
|
||||
PPCFrontend::~PPCFrontend() {
|
||||
// Force cleanup now before we deinit.
|
||||
translator_pool_.Reset();
|
||||
|
||||
alloy::tracing::WriteEvent(EventType::Deinit({
|
||||
}));
|
||||
}
|
||||
|
||||
int PPCFrontend::Initialize() {
|
||||
int result = Frontend::Initialize();
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
alloy::tracing::WriteEvent(EventType::Init({
|
||||
}));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int PPCFrontend::DeclareFunction(
|
||||
FunctionInfo* symbol_info) {
|
||||
// Could scan or something here.
|
||||
// Could also check to see if it's a well-known function type and classify
|
||||
// for later.
|
||||
// Could also kick off a precompiler, since we know it's likely the function
|
||||
// will be demanded soon.
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PPCFrontend::DefineFunction(
|
||||
FunctionInfo* symbol_info,
|
||||
Function** out_function) {
|
||||
PPCTranslator* translator = translator_pool_.Allocate(this);
|
||||
int result = translator->Translate(symbol_info, out_function);
|
||||
translator_pool_.Release(translator);
|
||||
return result;
|
||||
}
|
||||
48
src/alloy/frontend/ppc/ppc_frontend.h
Normal file
48
src/alloy/frontend/ppc/ppc_frontend.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_FRONTEND_PPC_PPC_FRONTEND_H_
|
||||
#define ALLOY_FRONTEND_PPC_PPC_FRONTEND_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
#include <alloy/type_pool.h>
|
||||
|
||||
#include <alloy/frontend/frontend.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
namespace ppc {
|
||||
|
||||
class PPCTranslator;
|
||||
|
||||
class PPCFrontend : public Frontend {
|
||||
public:
|
||||
PPCFrontend(runtime::Runtime* runtime);
|
||||
virtual ~PPCFrontend();
|
||||
|
||||
virtual int Initialize();
|
||||
|
||||
virtual int DeclareFunction(
|
||||
runtime::FunctionInfo* symbol_info);
|
||||
virtual int DefineFunction(
|
||||
runtime::FunctionInfo* symbol_info,
|
||||
runtime::Function** out_function);
|
||||
|
||||
private:
|
||||
TypePool<PPCTranslator, PPCFrontend*> translator_pool_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace ppc
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_FRONTEND_PPC_PPC_FRONTEND_H_
|
||||
306
src/alloy/frontend/ppc/ppc_function_builder.cc
Normal file
306
src/alloy/frontend/ppc/ppc_function_builder.cc
Normal file
@@ -0,0 +1,306 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 <alloy/frontend/ppc/ppc_function_builder.h>
|
||||
|
||||
#include <alloy/frontend/tracing.h>
|
||||
#include <alloy/frontend/ppc/ppc_context.h>
|
||||
#include <alloy/frontend/ppc/ppc_frontend.h>
|
||||
#include <alloy/frontend/ppc/ppc_instr.h>
|
||||
#include <alloy/hir/label.h>
|
||||
#include <alloy/runtime/runtime.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::frontend;
|
||||
using namespace alloy::frontend::ppc;
|
||||
using namespace alloy::hir;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
|
||||
PPCFunctionBuilder::PPCFunctionBuilder(PPCFrontend* frontend) :
|
||||
frontend_(frontend),
|
||||
FunctionBuilder() {
|
||||
}
|
||||
|
||||
PPCFunctionBuilder::~PPCFunctionBuilder() {
|
||||
}
|
||||
|
||||
void PPCFunctionBuilder::Reset() {
|
||||
start_address_ = 0;
|
||||
instr_offset_list_ = NULL;
|
||||
label_list_ = NULL;
|
||||
FunctionBuilder::Reset();
|
||||
}
|
||||
|
||||
const bool FLAGS_annotate_disassembly = true;
|
||||
|
||||
int PPCFunctionBuilder::Emit(FunctionInfo* symbol_info) {
|
||||
Memory* memory = frontend_->memory();
|
||||
const uint8_t* p = memory->membase();
|
||||
|
||||
symbol_info_ = symbol_info;
|
||||
start_address_ = symbol_info->address();
|
||||
instr_count_ =
|
||||
(symbol_info->end_address() - symbol_info->address()) / 4 + 1;
|
||||
|
||||
// TODO(benvanik): get/make up symbol name.
|
||||
Comment("%s fn %.8X-%.8X %s",
|
||||
symbol_info->module()->name(),
|
||||
symbol_info->address(), symbol_info->end_address(),
|
||||
"(symbol name)");
|
||||
|
||||
// Allocate offset list.
|
||||
// This is used to quickly map labels to instructions.
|
||||
// The list is built as the instructions are traversed, with the values
|
||||
// being the previous HIR Instr before the given instruction. An
|
||||
// instruction may have a label assigned to it if it hasn't been hit
|
||||
// yet.
|
||||
size_t list_size = instr_count_ * sizeof(void*);
|
||||
instr_offset_list_ = (Instr**)arena_->Alloc(list_size);
|
||||
label_list_ = (Label**)arena_->Alloc(list_size);
|
||||
xe_zero_struct(instr_offset_list_, list_size);
|
||||
xe_zero_struct(label_list_, list_size);
|
||||
|
||||
// Always mark entry with label.
|
||||
label_list_[0] = NewLabel();
|
||||
|
||||
uint64_t start_address = symbol_info->address();
|
||||
uint64_t end_address = symbol_info->end_address();
|
||||
InstrData i;
|
||||
for (uint64_t address = start_address, offset = 0; address <= end_address;
|
||||
address += 4, offset++) {
|
||||
i.address = address;
|
||||
i.code = XEGETUINT32BE(p + address);
|
||||
// TODO(benvanik): find a way to avoid using the opcode tables.
|
||||
i.type = GetInstrType(i.code);
|
||||
|
||||
// Stash instruction offset.
|
||||
instr_offset_list_[offset] = last_instr();
|
||||
|
||||
// Mark label, if we were assigned one earlier on in the walk.
|
||||
// We may still get a label, but it'll be inserted by LookupLabel
|
||||
// as needed.
|
||||
Label* label = label_list_[offset];
|
||||
if (label) {
|
||||
MarkLabel(label);
|
||||
}
|
||||
|
||||
if (FLAGS_annotate_disassembly) {
|
||||
if (label) {
|
||||
AnnotateLabel(address, label);
|
||||
}
|
||||
if (!i.type) {
|
||||
Comment("%.8X: %.8X ???", address, i.code);
|
||||
} else if (i.type->disassemble) {
|
||||
ppc::InstrDisasm d;
|
||||
i.type->disassemble(i, d);
|
||||
std::string disasm;
|
||||
d.Dump(disasm);
|
||||
Comment("%.8X: %.8X %s", address, i.code, disasm.c_str());
|
||||
} else {
|
||||
Comment("%.8X: %.8X %s ???", address, i.code, i.type->name);
|
||||
}
|
||||
}
|
||||
|
||||
if (!i.type) {
|
||||
XELOGCPU("Invalid instruction %.8X %.8X", i.address, i.code);
|
||||
Comment("INVALID!");
|
||||
//TraceInvalidInstruction(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
typedef int (*InstrEmitter)(PPCFunctionBuilder& f, InstrData& i);
|
||||
InstrEmitter emit = (InstrEmitter)i.type->emit;
|
||||
|
||||
/*if (i.address == FLAGS_break_on_instruction) {
|
||||
Comment("--break-on-instruction target");
|
||||
DebugBreak();
|
||||
}*/
|
||||
|
||||
if (!i.type->emit || emit(*this, i)) {
|
||||
XELOGCPU("Unimplemented instr %.8X %.8X %s",
|
||||
i.address, i.code, i.type->name);
|
||||
Comment("UNIMPLEMENTED!");
|
||||
DebugBreak();
|
||||
//TraceInvalidInstruction(i);
|
||||
|
||||
// This printf is handy for sort/uniquify to find instructions.
|
||||
printf("unimplinstr %s\n", i.type->name);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PPCFunctionBuilder::AnnotateLabel(uint64_t address, Label* label) {
|
||||
char name_buffer[13];
|
||||
xesnprintfa(name_buffer, XECOUNT(name_buffer), "loc_%.8X", address);
|
||||
label->name = (char*)arena_->Alloc(sizeof(name_buffer));
|
||||
xe_copy_struct(label->name, name_buffer, sizeof(name_buffer));
|
||||
}
|
||||
|
||||
FunctionInfo* PPCFunctionBuilder::LookupFunction(uint64_t address) {
|
||||
Runtime* runtime = frontend_->runtime();
|
||||
FunctionInfo* symbol_info;
|
||||
if (runtime->LookupFunctionInfo(address, &symbol_info)) {
|
||||
return NULL;
|
||||
}
|
||||
return symbol_info;
|
||||
}
|
||||
|
||||
Label* PPCFunctionBuilder::LookupLabel(uint64_t address) {
|
||||
if (address < start_address_) {
|
||||
return NULL;
|
||||
}
|
||||
size_t offset = (address - start_address_) / 4;
|
||||
if (offset >= instr_count_) {
|
||||
return NULL;
|
||||
}
|
||||
Label* label = label_list_[offset];
|
||||
if (label) {
|
||||
return label;
|
||||
}
|
||||
// No label. If we haven't yet hit the instruction in the walk
|
||||
// then create a label. Otherwise, we must go back and insert
|
||||
// the label.
|
||||
label = NewLabel();
|
||||
label_list_[offset] = label;
|
||||
Instr* prev_instr = instr_offset_list_[offset];
|
||||
if (prev_instr) {
|
||||
// Insert label, breaking up existing instructions.
|
||||
InsertLabel(label, prev_instr);
|
||||
|
||||
// Annotate the label, as we won't do it later.
|
||||
if (FLAGS_annotate_disassembly) {
|
||||
AnnotateLabel(address, label);
|
||||
}
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
//Value* PPCFunctionBuilder::LoadXER() {
|
||||
//}
|
||||
//
|
||||
//void PPCFunctionBuilder::StoreXER(Value* value) {
|
||||
//}
|
||||
|
||||
Value* PPCFunctionBuilder::LoadLR() {
|
||||
return LoadContext(offsetof(PPCContext, lr), INT64_TYPE);
|
||||
}
|
||||
|
||||
void PPCFunctionBuilder::StoreLR(Value* value) {
|
||||
XEASSERT(value->type == INT64_TYPE);
|
||||
StoreContext(offsetof(PPCContext, lr), value);
|
||||
}
|
||||
|
||||
Value* PPCFunctionBuilder::LoadCTR() {
|
||||
return LoadContext(offsetof(PPCContext, ctr), INT64_TYPE);
|
||||
}
|
||||
|
||||
void PPCFunctionBuilder::StoreCTR(Value* value) {
|
||||
XEASSERT(value->type == INT64_TYPE);
|
||||
StoreContext(offsetof(PPCContext, ctr), value);
|
||||
}
|
||||
|
||||
Value* PPCFunctionBuilder::LoadCR(uint32_t n) {
|
||||
XEASSERTALWAYS();
|
||||
return 0;
|
||||
}
|
||||
|
||||
Value* PPCFunctionBuilder::LoadCRField(uint32_t n, uint32_t bit) {
|
||||
return LoadContext(offsetof(PPCContext, cr0) + (4 * n) + bit, INT8_TYPE);
|
||||
}
|
||||
|
||||
void PPCFunctionBuilder::StoreCR(uint32_t n, Value* value) {
|
||||
// TODO(benvanik): split bits out and store in values.
|
||||
XEASSERTALWAYS();
|
||||
}
|
||||
|
||||
void PPCFunctionBuilder::UpdateCR(
|
||||
uint32_t n, Value* lhs, bool is_signed) {
|
||||
UpdateCR(n, lhs, LoadZero(lhs->type), is_signed);
|
||||
}
|
||||
|
||||
void PPCFunctionBuilder::UpdateCR(
|
||||
uint32_t n, Value* lhs, Value* rhs, bool is_signed) {
|
||||
Value* lt;
|
||||
Value* gt;
|
||||
if (is_signed) {
|
||||
lt = CompareSLT(lhs, rhs);
|
||||
gt = CompareSGT(lhs, rhs);
|
||||
} else {
|
||||
lt = CompareULT(lhs, rhs);
|
||||
gt = CompareUGT(lhs, rhs);
|
||||
}
|
||||
Value* eq = CompareEQ(lhs, rhs);
|
||||
StoreContext(offsetof(PPCContext, cr0) + (4 * n) + 0, lt);
|
||||
StoreContext(offsetof(PPCContext, cr0) + (4 * n) + 1, gt);
|
||||
StoreContext(offsetof(PPCContext, cr0) + (4 * n) + 2, eq);
|
||||
|
||||
// Value* so = AllocValue(UINT8_TYPE);
|
||||
// StoreContext(offsetof(PPCContext, cr) + (4 * n) + 3, so);
|
||||
}
|
||||
|
||||
void PPCFunctionBuilder::UpdateCR6(Value* src_value) {
|
||||
// Testing for all 1's and all 0's.
|
||||
// if (Rc) CR6 = all_equal | 0 | none_equal | 0
|
||||
// TODO(benvanik): efficient instruction?
|
||||
StoreContext(offsetof(PPCContext, cr6.cr6_all_equal), IsFalse(Not(src_value)));
|
||||
StoreContext(offsetof(PPCContext, cr6.cr6_none_equal), IsFalse(src_value));
|
||||
}
|
||||
|
||||
Value* PPCFunctionBuilder::LoadXER() {
|
||||
XEASSERTALWAYS();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void PPCFunctionBuilder::StoreXER(Value* value) {
|
||||
XEASSERTALWAYS();
|
||||
}
|
||||
|
||||
Value* PPCFunctionBuilder::LoadCA() {
|
||||
return LoadContext(offsetof(PPCContext, xer_ca), INT8_TYPE);
|
||||
}
|
||||
|
||||
void PPCFunctionBuilder::StoreCA(Value* value) {
|
||||
StoreContext(offsetof(PPCContext, xer_ca), value);
|
||||
}
|
||||
|
||||
Value* PPCFunctionBuilder::LoadGPR(uint32_t reg) {
|
||||
return LoadContext(
|
||||
offsetof(PPCContext, r) + reg * 8, INT64_TYPE);
|
||||
}
|
||||
|
||||
void PPCFunctionBuilder::StoreGPR(uint32_t reg, Value* value) {
|
||||
XEASSERT(value->type == INT64_TYPE);
|
||||
StoreContext(
|
||||
offsetof(PPCContext, r) + reg * 8, value);
|
||||
}
|
||||
|
||||
Value* PPCFunctionBuilder::LoadFPR(uint32_t reg) {
|
||||
return LoadContext(
|
||||
offsetof(PPCContext, f) + reg * 8, FLOAT64_TYPE);
|
||||
}
|
||||
|
||||
void PPCFunctionBuilder::StoreFPR(uint32_t reg, Value* value) {
|
||||
XEASSERT(value->type == FLOAT64_TYPE);
|
||||
StoreContext(
|
||||
offsetof(PPCContext, f) + reg * 8, value);
|
||||
}
|
||||
|
||||
Value* PPCFunctionBuilder::LoadVR(uint32_t reg) {
|
||||
return LoadContext(
|
||||
offsetof(PPCContext, v) + reg * 16, VEC128_TYPE);
|
||||
}
|
||||
|
||||
void PPCFunctionBuilder::StoreVR(uint32_t reg, Value* value) {
|
||||
XEASSERT(value->type == VEC128_TYPE);
|
||||
StoreContext(
|
||||
offsetof(PPCContext, v) + reg * 16, value);
|
||||
}
|
||||
86
src/alloy/frontend/ppc/ppc_function_builder.h
Normal file
86
src/alloy/frontend/ppc/ppc_function_builder.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_FRONTEND_PPC_PPC_FUNCTION_BUILDER_H_
|
||||
#define ALLOY_FRONTEND_PPC_PPC_FUNCTION_BUILDER_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
#include <alloy/hir/function_builder.h>
|
||||
#include <alloy/runtime/function.h>
|
||||
#include <alloy/runtime/symbol_info.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
namespace ppc {
|
||||
|
||||
class PPCFrontend;
|
||||
|
||||
|
||||
class PPCFunctionBuilder : public hir::FunctionBuilder {
|
||||
using Instr = alloy::hir::Instr;
|
||||
using Label = alloy::hir::Label;
|
||||
using Value = alloy::hir::Value;
|
||||
public:
|
||||
PPCFunctionBuilder(PPCFrontend* frontend);
|
||||
virtual ~PPCFunctionBuilder();
|
||||
|
||||
virtual void Reset();
|
||||
|
||||
int Emit(runtime::FunctionInfo* symbol_info);
|
||||
|
||||
runtime::FunctionInfo* LookupFunction(uint64_t address);
|
||||
Label* LookupLabel(uint64_t address);
|
||||
|
||||
Value* LoadLR();
|
||||
void StoreLR(Value* value);
|
||||
Value* LoadCTR();
|
||||
void StoreCTR(Value* value);
|
||||
Value* LoadCR(uint32_t n);
|
||||
Value* LoadCRField(uint32_t n, uint32_t bit);
|
||||
void StoreCR(uint32_t n, Value* value);
|
||||
void UpdateCR(uint32_t n, Value* lhs, bool is_signed = true);
|
||||
void UpdateCR(uint32_t n, Value* lhs, Value* rhs, bool is_signed = true);
|
||||
void UpdateCR6(Value* src_value);
|
||||
Value* LoadXER();
|
||||
void StoreXER(Value* value);
|
||||
//void UpdateXERWithOverflow();
|
||||
//void UpdateXERWithOverflowAndCarry();
|
||||
//void StoreOV(Value* value);
|
||||
Value* LoadCA();
|
||||
void StoreCA(Value* value);
|
||||
|
||||
Value* LoadGPR(uint32_t reg);
|
||||
void StoreGPR(uint32_t reg, Value* value);
|
||||
Value* LoadFPR(uint32_t reg);
|
||||
void StoreFPR(uint32_t reg, Value* value);
|
||||
Value* LoadVR(uint32_t reg);
|
||||
void StoreVR(uint32_t reg, Value* value);
|
||||
|
||||
private:
|
||||
void AnnotateLabel(uint64_t address, Label* label);
|
||||
|
||||
private:
|
||||
PPCFrontend* frontend_;
|
||||
|
||||
// Reset each Emit:
|
||||
runtime::FunctionInfo* symbol_info_;
|
||||
uint64_t start_address_;
|
||||
uint64_t instr_count_;
|
||||
Instr** instr_offset_list_;
|
||||
Label** label_list_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace ppc
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_FRONTEND_PPC_PPC_FUNCTION_BUILDER_H_
|
||||
504
src/alloy/frontend/ppc/ppc_instr.cc
Normal file
504
src/alloy/frontend/ppc/ppc_instr.cc
Normal file
@@ -0,0 +1,504 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 <alloy/frontend/ppc/ppc_instr.h>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <alloy/frontend/ppc/ppc_instr_tables.h>
|
||||
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::frontend;
|
||||
using namespace alloy::frontend::ppc;
|
||||
|
||||
|
||||
void InstrOperand::Dump(std::string& out_str) {
|
||||
if (display) {
|
||||
out_str += display;
|
||||
return;
|
||||
}
|
||||
|
||||
char buffer[32];
|
||||
const size_t max_count = XECOUNT(buffer);
|
||||
switch (type) {
|
||||
case InstrOperand::kRegister:
|
||||
switch (reg.set) {
|
||||
case InstrRegister::kXER:
|
||||
xesnprintfa(buffer, max_count, "XER");
|
||||
break;
|
||||
case InstrRegister::kLR:
|
||||
xesnprintfa(buffer, max_count, "LR");
|
||||
break;
|
||||
case InstrRegister::kCTR:
|
||||
xesnprintfa(buffer, max_count, "CTR");
|
||||
break;
|
||||
case InstrRegister::kCR:
|
||||
xesnprintfa(buffer, max_count, "CR%d", reg.ordinal);
|
||||
break;
|
||||
case InstrRegister::kFPSCR:
|
||||
xesnprintfa(buffer, max_count, "FPSCR");
|
||||
break;
|
||||
case InstrRegister::kGPR:
|
||||
xesnprintfa(buffer, max_count, "r%d", reg.ordinal);
|
||||
break;
|
||||
case InstrRegister::kFPR:
|
||||
xesnprintfa(buffer, max_count, "f%d", reg.ordinal);
|
||||
break;
|
||||
case InstrRegister::kVMX:
|
||||
xesnprintfa(buffer, max_count, "vr%d", reg.ordinal);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case InstrOperand::kImmediate:
|
||||
switch (imm.width) {
|
||||
case 1:
|
||||
if (imm.is_signed) {
|
||||
xesnprintfa(buffer, max_count, "%d", (int32_t)(int8_t)imm.value);
|
||||
} else {
|
||||
xesnprintfa(buffer, max_count, "0x%.2X", (uint8_t)imm.value);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (imm.is_signed) {
|
||||
xesnprintfa(buffer, max_count, "%d", (int32_t)(int16_t)imm.value);
|
||||
} else {
|
||||
xesnprintfa(buffer, max_count, "0x%.4X", (uint16_t)imm.value);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
if (imm.is_signed) {
|
||||
xesnprintfa(buffer, max_count, "%d", (int32_t)imm.value);
|
||||
} else {
|
||||
xesnprintfa(buffer, max_count, "0x%.8X", (uint32_t)imm.value);
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
if (imm.is_signed) {
|
||||
xesnprintfa(buffer, max_count, "%lld", (int64_t)imm.value);
|
||||
} else {
|
||||
xesnprintfa(buffer, max_count, "0x%.16llX", imm.value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
out_str += buffer;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
vr31_0 |= other.vr31_0;
|
||||
vr63_32 |= other.vr63_32;
|
||||
vr95_64 |= other.vr95_64;
|
||||
vr127_96 |= other.vr127_96;
|
||||
}
|
||||
|
||||
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;
|
||||
case InstrRegister::kVMX:
|
||||
if (reg.ordinal < 32) {
|
||||
vr31_0 |= bits << (2 * reg.ordinal);
|
||||
} else if (reg.ordinal < 64) {
|
||||
vr63_32 |= bits << (2 * (reg.ordinal - 32));
|
||||
} else if (reg.ordinal < 96) {
|
||||
vr95_64 |= bits << (2 * (reg.ordinal - 64));
|
||||
} else {
|
||||
vr127_96 |= bits << (2 * (reg.ordinal - 96));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (vr31_0) {
|
||||
uint64_t vr31_0_t = vr31_0;
|
||||
for (size_t n = 0; n < 32; n++) {
|
||||
if (vr31_0_t & 0x3) {
|
||||
str << "vr" << n << " [";
|
||||
str << ((vr31_0_t & 1) ? "R" : " ");
|
||||
str << ((vr31_0_t & 2) ? "W" : " ");
|
||||
str << "] ";
|
||||
}
|
||||
vr31_0_t >>= 2;
|
||||
}
|
||||
}
|
||||
if (vr63_32) {
|
||||
uint64_t vr63_32_t = vr63_32;
|
||||
for (size_t n = 0; n < 32; n++) {
|
||||
if (vr63_32_t & 0x3) {
|
||||
str << "vr" << (n + 32) << " [";
|
||||
str << ((vr63_32_t & 1) ? "R" : " ");
|
||||
str << ((vr63_32_t & 2) ? "W" : " ");
|
||||
str << "] ";
|
||||
}
|
||||
vr63_32_t >>= 2;
|
||||
}
|
||||
}
|
||||
if (vr95_64) {
|
||||
uint64_t vr95_64_t = vr95_64;
|
||||
for (size_t n = 0; n < 32; n++) {
|
||||
if (vr95_64_t & 0x3) {
|
||||
str << "vr" << (n + 64) << " [";
|
||||
str << ((vr95_64_t & 1) ? "R" : " ");
|
||||
str << ((vr95_64_t & 2) ? "W" : " ");
|
||||
str << "] ";
|
||||
}
|
||||
vr95_64_t >>= 2;
|
||||
}
|
||||
}
|
||||
if (vr127_96) {
|
||||
uint64_t vr127_96_t = vr127_96;
|
||||
for (size_t n = 0; n < 32; n++) {
|
||||
if (vr127_96_t & 0x3) {
|
||||
str << "vr" << (n + 96) << " [";
|
||||
str << ((vr127_96_t & 1) ? "R" : " ");
|
||||
str << ((vr127_96_t & 2) ? "W" : " ");
|
||||
str << "] ";
|
||||
}
|
||||
vr127_96_t >>= 2;
|
||||
}
|
||||
}
|
||||
|
||||
out_str = str.str();
|
||||
}
|
||||
|
||||
|
||||
void InstrDisasm::Init(const char* name, const char* info, uint32_t flags) {
|
||||
operands.clear();
|
||||
special_registers.clear();
|
||||
access_bits.Clear();
|
||||
|
||||
this->name = name;
|
||||
this->info = info;
|
||||
this->flags = flags;
|
||||
|
||||
if (flags & InstrDisasm::kOE) {
|
||||
InstrRegister i = {
|
||||
InstrRegister::kXER, 0, InstrRegister::kReadWrite
|
||||
};
|
||||
special_registers.push_back(i);
|
||||
}
|
||||
if (flags & InstrDisasm::kRc) {
|
||||
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) {
|
||||
InstrRegister i = {
|
||||
InstrRegister::kLR, 0, InstrRegister::kWrite
|
||||
};
|
||||
special_registers.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
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::AddFPSCR(InstrRegister::Access access) {
|
||||
InstrRegister i = {
|
||||
InstrRegister::kFPSCR, 0, access
|
||||
};
|
||||
special_registers.push_back(i);
|
||||
}
|
||||
|
||||
void InstrDisasm::AddRegOperand(
|
||||
InstrRegister::RegisterSet set, uint32_t ordinal,
|
||||
InstrRegister::Access access, const char* display) {
|
||||
InstrRegister i = {
|
||||
set, ordinal, access
|
||||
};
|
||||
InstrOperand o;
|
||||
o.type = InstrOperand::kRegister;
|
||||
o.reg = i;
|
||||
o.display = display;
|
||||
operands.push_back(o);
|
||||
}
|
||||
|
||||
void InstrDisasm::AddSImmOperand(uint64_t value, size_t width,
|
||||
const char* display) {
|
||||
InstrOperand o;
|
||||
o.type = InstrOperand::kImmediate;
|
||||
o.imm.is_signed = true;
|
||||
o.imm.value = value;
|
||||
o.imm.width = width;
|
||||
o.display = display;
|
||||
operands.push_back(o);
|
||||
}
|
||||
|
||||
void InstrDisasm::AddUImmOperand(uint64_t value, size_t width,
|
||||
const char* display) {
|
||||
InstrOperand o;
|
||||
o.type = InstrOperand::kImmediate;
|
||||
o.imm.is_signed = false;
|
||||
o.imm.value = value;
|
||||
o.imm.width = width;
|
||||
o.display = display;
|
||||
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& out_str, size_t pad) {
|
||||
out_str = name;
|
||||
if (flags & InstrDisasm::kOE) {
|
||||
out_str += "o";
|
||||
}
|
||||
if (flags & InstrDisasm::kRc) {
|
||||
out_str += ".";
|
||||
}
|
||||
if (flags & InstrDisasm::kLR) {
|
||||
out_str += "l";
|
||||
}
|
||||
|
||||
if (operands.size()) {
|
||||
if (pad && out_str.size() < pad) {
|
||||
out_str += std::string(pad - out_str.size(), ' ');
|
||||
}
|
||||
for (std::vector<InstrOperand>::iterator it = operands.begin();
|
||||
it != operands.end(); ++it) {
|
||||
it->Dump(out_str);
|
||||
if (it + 1 != operands.end()) {
|
||||
out_str += ", ";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
InstrType* alloy::frontend::ppc::GetInstrType(uint32_t code) {
|
||||
// Fast lookup via tables.
|
||||
InstrType* slot = NULL;
|
||||
switch (code >> 26) {
|
||||
case 4:
|
||||
// Opcode = 4, index = bits 10-0 (10)
|
||||
slot = alloy::frontend::ppc::tables::instr_table_4[XESELECTBITS(code, 0, 10)];
|
||||
break;
|
||||
case 19:
|
||||
// Opcode = 19, index = bits 10-1 (10)
|
||||
slot = alloy::frontend::ppc::tables::instr_table_19[XESELECTBITS(code, 1, 10)];
|
||||
break;
|
||||
case 30:
|
||||
// Opcode = 30, index = bits 4-1 (4)
|
||||
// Special cased to an uber instruction.
|
||||
slot = alloy::frontend::ppc::tables::instr_table_30[XESELECTBITS(code, 0, 0)];
|
||||
break;
|
||||
case 31:
|
||||
// Opcode = 31, index = bits 10-1 (10)
|
||||
slot = alloy::frontend::ppc::tables::instr_table_31[XESELECTBITS(code, 1, 10)];
|
||||
break;
|
||||
case 58:
|
||||
// Opcode = 58, index = bits 1-0 (2)
|
||||
slot = alloy::frontend::ppc::tables::instr_table_58[XESELECTBITS(code, 0, 1)];
|
||||
break;
|
||||
case 59:
|
||||
// Opcode = 59, index = bits 5-1 (5)
|
||||
slot = alloy::frontend::ppc::tables::instr_table_59[XESELECTBITS(code, 1, 5)];
|
||||
break;
|
||||
case 62:
|
||||
// Opcode = 62, index = bits 1-0 (2)
|
||||
slot = alloy::frontend::ppc::tables::instr_table_62[XESELECTBITS(code, 0, 1)];
|
||||
break;
|
||||
case 63:
|
||||
// Opcode = 63, index = bits 10-1 (10)
|
||||
slot = alloy::frontend::ppc::tables::instr_table_63[XESELECTBITS(code, 1, 10)];
|
||||
break;
|
||||
default:
|
||||
slot = alloy::frontend::ppc::tables::instr_table[XESELECTBITS(code, 26, 31)];
|
||||
break;
|
||||
}
|
||||
if (slot && slot->opcode) {
|
||||
return slot;
|
||||
}
|
||||
|
||||
// Slow lookup via linear scan.
|
||||
// This is primarily due to laziness. It could be made fast like the others.
|
||||
for (size_t n = 0;
|
||||
n < XECOUNT(alloy::frontend::ppc::tables::instr_table_scan);
|
||||
n++) {
|
||||
slot = &(alloy::frontend::ppc::tables::instr_table_scan[n]);
|
||||
if (slot->opcode == (code & slot->opcode_mask)) {
|
||||
return slot;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int alloy::frontend::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 alloy::frontend::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;
|
||||
}
|
||||
531
src/alloy/frontend/ppc/ppc_instr.h
Normal file
531
src/alloy/frontend/ppc/ppc_instr.h
Normal file
@@ -0,0 +1,531 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_FRONTEND_PPC_PPC_INSTR_H_
|
||||
#define ALLOY_FRONTEND_PPC_PPC_INSTR_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
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,
|
||||
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;
|
||||
|
||||
typedef enum {
|
||||
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,
|
||||
} xe_ppc_instr_mask_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 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;
|
||||
uint64_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 : 1;
|
||||
uint32_t FM : 8;
|
||||
uint32_t : 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;
|
||||
std::vector<InstrOperand> operands;
|
||||
std::vector<InstrRegister> special_registers;
|
||||
InstrAccessBits access_bits;
|
||||
|
||||
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 int (*InstrDisassembleFn)(InstrData& i, InstrDisasm& d);
|
||||
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
|
||||
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 frontend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_FRONTEND_PPC_PPC_INSTR_H_
|
||||
|
||||
643
src/alloy/frontend/ppc/ppc_instr_tables.h
Normal file
643
src/alloy/frontend/ppc/ppc_instr_tables.h
Normal file
@@ -0,0 +1,643 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_FRONTEND_PPC_PPC_INSTR_TABLES_H_
|
||||
#define ALLOY_FRONTEND_PPC_PPC_INSTR_TABLES_H_
|
||||
|
||||
#include <alloy/frontend/ppc/ppc_instr.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
namespace ppc {
|
||||
namespace tables {
|
||||
|
||||
|
||||
static InstrType** instr_table_prep(
|
||||
InstrType* unprep, int unprep_count, int a, int b) {
|
||||
int prep_count = (int)pow(2.0, b - a + 1);
|
||||
InstrType** prep = (InstrType**)xe_calloc(prep_count * sizeof(void*));
|
||||
for (int n = 0; n < unprep_count; n++) {
|
||||
int ordinal = XESELECTBITS(unprep[n].opcode, a, b);
|
||||
prep[ordinal] = &unprep[n];
|
||||
}
|
||||
return prep;
|
||||
}
|
||||
|
||||
static InstrType** instr_table_prep_63(
|
||||
InstrType* unprep, int unprep_count, int a, int b) {
|
||||
// Special handling for A format instructions.
|
||||
int prep_count = (int)pow(2.0, b - a + 1);
|
||||
InstrType** prep = (InstrType**)xe_calloc(prep_count * sizeof(void*));
|
||||
for (int n = 0; n < unprep_count; n++) {
|
||||
int ordinal = XESELECTBITS(unprep[n].opcode, a, b);
|
||||
if (unprep[n].format == kXEPPCInstrFormatA) {
|
||||
// Must splat this into all of the slots that it could be in.
|
||||
for (int m = 0; m < 32; m++) {
|
||||
prep[ordinal + (m << 5)] = &unprep[n];
|
||||
}
|
||||
} else {
|
||||
prep[ordinal] = &unprep[n];
|
||||
}
|
||||
}
|
||||
return prep;
|
||||
}
|
||||
|
||||
|
||||
#define EMPTY(slot) {0}
|
||||
#define INSTRUCTION(name, opcode, format, type, flag) { \
|
||||
opcode, \
|
||||
0, \
|
||||
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 11-0 (6)
|
||||
static InstrType instr_table_4_unprep[] = {
|
||||
// TODO: all of the vector ops
|
||||
INSTRUCTION(mfvscr, 0x10000604, VX , General , 0),
|
||||
INSTRUCTION(mtvscr, 0x10000644, VX , General , 0),
|
||||
INSTRUCTION(vaddcuw, 0x10000180, VX , General , 0),
|
||||
INSTRUCTION(vaddfp, 0x1000000A, VX , General , 0),
|
||||
INSTRUCTION(vaddsbs, 0x10000300, VX , General , 0),
|
||||
INSTRUCTION(vaddshs, 0x10000340, VX , General , 0),
|
||||
INSTRUCTION(vaddsws, 0x10000380, VX , General , 0),
|
||||
INSTRUCTION(vaddubm, 0x10000000, VX , General , 0),
|
||||
INSTRUCTION(vaddubs, 0x10000200, VX , General , 0),
|
||||
INSTRUCTION(vadduhm, 0x10000040, VX , General , 0),
|
||||
INSTRUCTION(vadduhs, 0x10000240, VX , General , 0),
|
||||
INSTRUCTION(vadduwm, 0x10000080, VX , General , 0),
|
||||
INSTRUCTION(vadduws, 0x10000280, VX , General , 0),
|
||||
INSTRUCTION(vand, 0x10000404, VX , General , 0),
|
||||
INSTRUCTION(vandc, 0x10000444, VX , General , 0),
|
||||
INSTRUCTION(vavgsb, 0x10000502, VX , General , 0),
|
||||
INSTRUCTION(vavgsh, 0x10000542, VX , General , 0),
|
||||
INSTRUCTION(vavgsw, 0x10000582, VX , General , 0),
|
||||
INSTRUCTION(vavgub, 0x10000402, VX , General , 0),
|
||||
INSTRUCTION(vavguh, 0x10000442, VX , General , 0),
|
||||
INSTRUCTION(vavguw, 0x10000482, VX , General , 0),
|
||||
INSTRUCTION(vcfsx, 0x1000034A, VX , General , 0),
|
||||
INSTRUCTION(vcfux, 0x1000030A, VX , General , 0),
|
||||
INSTRUCTION(vctsxs, 0x100003CA, VX , General , 0),
|
||||
INSTRUCTION(vctuxs, 0x1000038A, VX , General , 0),
|
||||
INSTRUCTION(vexptefp, 0x1000018A, VX , General , 0),
|
||||
INSTRUCTION(vlogefp, 0x100001CA, VX , General , 0),
|
||||
INSTRUCTION(vmaxfp, 0x1000040A, VX , General , 0),
|
||||
INSTRUCTION(vmaxsb, 0x10000102, VX , General , 0),
|
||||
INSTRUCTION(vmaxsh, 0x10000142, VX , General , 0),
|
||||
INSTRUCTION(vmaxsw, 0x10000182, VX , General , 0),
|
||||
INSTRUCTION(vmaxub, 0x10000002, VX , General , 0),
|
||||
INSTRUCTION(vmaxuh, 0x10000042, VX , General , 0),
|
||||
INSTRUCTION(vmaxuw, 0x10000082, VX , General , 0),
|
||||
INSTRUCTION(vminfp, 0x1000044A, VX , General , 0),
|
||||
INSTRUCTION(vminsb, 0x10000302, VX , General , 0),
|
||||
INSTRUCTION(vminsh, 0x10000342, VX , General , 0),
|
||||
INSTRUCTION(vminsw, 0x10000382, VX , General , 0),
|
||||
INSTRUCTION(vminub, 0x10000202, VX , General , 0),
|
||||
INSTRUCTION(vminuh, 0x10000242, VX , General , 0),
|
||||
INSTRUCTION(vminuw, 0x10000282, VX , General , 0),
|
||||
INSTRUCTION(vmrghb, 0x1000000C, VX , General , 0),
|
||||
INSTRUCTION(vmrghh, 0x1000004C, VX , General , 0),
|
||||
INSTRUCTION(vmrghw, 0x1000008C, VX , General , 0),
|
||||
INSTRUCTION(vmrglb, 0x1000010C, VX , General , 0),
|
||||
INSTRUCTION(vmrglh, 0x1000014C, VX , General , 0),
|
||||
INSTRUCTION(vmrglw, 0x1000018C, VX , General , 0),
|
||||
INSTRUCTION(vmulesb, 0x10000308, VX , General , 0),
|
||||
INSTRUCTION(vmulesh, 0x10000348, VX , General , 0),
|
||||
INSTRUCTION(vmuleub, 0x10000208, VX , General , 0),
|
||||
INSTRUCTION(vmuleuh, 0x10000248, VX , General , 0),
|
||||
INSTRUCTION(vmulosb, 0x10000108, VX , General , 0),
|
||||
INSTRUCTION(vmulosh, 0x10000148, VX , General , 0),
|
||||
INSTRUCTION(vmuloub, 0x10000008, VX , General , 0),
|
||||
INSTRUCTION(vmulouh, 0x10000048, VX , General , 0),
|
||||
INSTRUCTION(vnor, 0x10000504, VX , General , 0),
|
||||
INSTRUCTION(vor, 0x10000484, VX , General , 0),
|
||||
INSTRUCTION(vpkpx, 0x1000030E, VX , General , 0),
|
||||
INSTRUCTION(vpkshss, 0x1000018E, VX , General , 0),
|
||||
INSTRUCTION(vpkshus, 0x1000010E, VX , General , 0),
|
||||
INSTRUCTION(vpkswss, 0x100001CE, VX , General , 0),
|
||||
INSTRUCTION(vpkswus, 0x1000014E, VX , General , 0),
|
||||
INSTRUCTION(vpkuhum, 0x1000000E, VX , General , 0),
|
||||
INSTRUCTION(vpkuhus, 0x1000008E, VX , General , 0),
|
||||
INSTRUCTION(vpkuwum, 0x1000004E, VX , General , 0),
|
||||
INSTRUCTION(vpkuwus, 0x100000CE, VX , General , 0),
|
||||
INSTRUCTION(vrefp, 0x1000010A, VX , General , 0),
|
||||
INSTRUCTION(vrfim, 0x100002CA, VX , General , 0),
|
||||
INSTRUCTION(vrfin, 0x1000020A, VX , General , 0),
|
||||
INSTRUCTION(vrfip, 0x1000028A, VX , General , 0),
|
||||
INSTRUCTION(vrfiz, 0x1000024A, VX , General , 0),
|
||||
INSTRUCTION(vrlb, 0x10000004, VX , General , 0),
|
||||
INSTRUCTION(vrlh, 0x10000044, VX , General , 0),
|
||||
INSTRUCTION(vrlw, 0x10000084, VX , General , 0),
|
||||
INSTRUCTION(vrsqrtefp, 0x1000014A, VX , General , 0),
|
||||
INSTRUCTION(vsl, 0x100001C4, VX , General , 0),
|
||||
INSTRUCTION(vslb, 0x10000104, VX , General , 0),
|
||||
INSTRUCTION(vslh, 0x10000144, VX , General , 0),
|
||||
INSTRUCTION(vslo, 0x1000040C, VX , General , 0),
|
||||
INSTRUCTION(vslw, 0x10000184, VX , General , 0),
|
||||
INSTRUCTION(vspltb, 0x1000020C, VX , General , 0),
|
||||
INSTRUCTION(vsplth, 0x1000024C, VX , General , 0),
|
||||
INSTRUCTION(vspltisb, 0x1000030C, VX , General , 0),
|
||||
INSTRUCTION(vspltish, 0x1000034C, VX , General , 0),
|
||||
INSTRUCTION(vspltisw, 0x1000038C, VX , General , 0),
|
||||
INSTRUCTION(vspltw, 0x1000028C, VX , General , 0),
|
||||
INSTRUCTION(vsr, 0x100002C4, VX , General , 0),
|
||||
INSTRUCTION(vsrab, 0x10000304, VX , General , 0),
|
||||
INSTRUCTION(vsrah, 0x10000344, VX , General , 0),
|
||||
INSTRUCTION(vsraw, 0x10000384, VX , General , 0),
|
||||
INSTRUCTION(vsrb, 0x10000204, VX , General , 0),
|
||||
INSTRUCTION(vsrh, 0x10000244, VX , General , 0),
|
||||
INSTRUCTION(vsro, 0x1000044C, VX , General , 0),
|
||||
INSTRUCTION(vsrw, 0x10000284, VX , General , 0),
|
||||
INSTRUCTION(vsubcuw, 0x10000580, VX , General , 0),
|
||||
INSTRUCTION(vsubfp, 0x1000004A, VX , General , 0),
|
||||
INSTRUCTION(vsubsbs, 0x10000700, VX , General , 0),
|
||||
INSTRUCTION(vsubshs, 0x10000740, VX , General , 0),
|
||||
INSTRUCTION(vsubsws, 0x10000780, VX , General , 0),
|
||||
INSTRUCTION(vsububm, 0x10000400, VX , General , 0),
|
||||
INSTRUCTION(vsububs, 0x10000600, VX , General , 0),
|
||||
INSTRUCTION(vsubuhm, 0x10000440, VX , General , 0),
|
||||
INSTRUCTION(vsubuhs, 0x10000640, VX , General , 0),
|
||||
INSTRUCTION(vsubuwm, 0x10000480, VX , General , 0),
|
||||
INSTRUCTION(vsubuws, 0x10000680, VX , General , 0),
|
||||
INSTRUCTION(vsumsws, 0x10000788, VX , General , 0),
|
||||
INSTRUCTION(vsum2sws, 0x10000688, VX , General , 0),
|
||||
INSTRUCTION(vsum4sbs, 0x10000708, VX , General , 0),
|
||||
INSTRUCTION(vsum4shs, 0x10000648, VX , General , 0),
|
||||
INSTRUCTION(vsum4ubs, 0x10000608, VX , General , 0),
|
||||
INSTRUCTION(vupkhpx, 0x1000034E, VX , General , 0),
|
||||
INSTRUCTION(vupkhsb, 0x1000020E, VX , General , 0),
|
||||
INSTRUCTION(vupkhsh, 0x1000024E, VX , General , 0),
|
||||
INSTRUCTION(vupklpx, 0x100003CE, VX , General , 0),
|
||||
INSTRUCTION(vupklsb, 0x1000028E, VX , General , 0),
|
||||
INSTRUCTION(vupklsh, 0x100002CE, VX , General , 0),
|
||||
INSTRUCTION(vxor, 0x100004C4, VX , General , 0),
|
||||
};
|
||||
static InstrType** instr_table_4 = instr_table_prep(
|
||||
instr_table_4_unprep, XECOUNT(instr_table_4_unprep), 0, 11);
|
||||
|
||||
// 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[] = {
|
||||
// Decoding these instrunctions in this table is difficult because the
|
||||
// index bits are kind of random. This is special cased by an uber
|
||||
// instruction handler.
|
||||
INSTRUCTION(rld, 0x78000000, MD , General , 0),
|
||||
// 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), 0, 0);
|
||||
|
||||
// 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(mfmsr, 0x7C0000A6, X , 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(mtmsr, 0x7C000124, X , 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(mtmsrd, 0x7C000164, 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
|
||||
INSTRUCTION(dst, 0x7C0002AC, XDSS, General , 0),
|
||||
INSTRUCTION(dstst, 0x7C0002EC, XDSS, General , 0),
|
||||
INSTRUCTION(dss, 0x7C00066C, XDSS, General , 0),
|
||||
INSTRUCTION(lvebx, 0x7C00000E, X , General , 0),
|
||||
INSTRUCTION(lvehx, 0x7C00004E, X , General , 0),
|
||||
INSTRUCTION(lvewx, 0x7C00008E, X , General , 0),
|
||||
INSTRUCTION(lvsl, 0x7C00000C, X , General , 0),
|
||||
INSTRUCTION(lvsr, 0x7C00004C, X , General , 0),
|
||||
INSTRUCTION(lvx, 0x7C0000CE, X , General , 0),
|
||||
INSTRUCTION(lvxl, 0x7C0002CE, X , General , 0),
|
||||
INSTRUCTION(stvebx, 0x7C00010E, X , General , 0),
|
||||
INSTRUCTION(stvehx, 0x7C00014E, X , General , 0),
|
||||
INSTRUCTION(stvewx, 0x7C00018E, X , General , 0),
|
||||
INSTRUCTION(stvx, 0x7C0001CE, X , General , 0),
|
||||
INSTRUCTION(stvxl, 0x7C0003CE, X , General , 0),
|
||||
INSTRUCTION(lvlx, 0x7C00040E, X , General , 0),
|
||||
INSTRUCTION(lvlxl, 0x7C00060E, X , General , 0),
|
||||
INSTRUCTION(lvrx, 0x7C00044E, X , General , 0),
|
||||
INSTRUCTION(lvrxl, 0x7C00064E, X , General , 0),
|
||||
INSTRUCTION(stvlx, 0x7C00050E, X , General , 0),
|
||||
INSTRUCTION(stvlxl, 0x7C00070E, X , General , 0),
|
||||
INSTRUCTION(stvrx, 0x7C00054E, X , General , 0),
|
||||
INSTRUCTION(stvrxl, 0x7C00074E, X , General , 0),
|
||||
};
|
||||
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)
|
||||
// NOTE: the A format instructions need some special handling because
|
||||
// they only use 6bits to identify their index.
|
||||
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_63(
|
||||
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);
|
||||
|
||||
// Altivec instructions.
|
||||
// TODO(benvanik): build a table like the other instructions.
|
||||
// This table is looked up via linear scan of opcodes.
|
||||
#define SCAN_INSTRUCTION(name, opcode, format, type, flag) { \
|
||||
opcode, \
|
||||
kXEPPCInstrMask##format, \
|
||||
kXEPPCInstrFormat##format, \
|
||||
kXEPPCInstrType##type, \
|
||||
flag, \
|
||||
#name, \
|
||||
}
|
||||
#define OP(x) ((((uint32_t)(x)) & 0x3f) << 26)
|
||||
#define VX128(op, xop) (OP(op) | (((uint32_t)(xop)) & 0x3d0))
|
||||
#define VX128_1(op, xop) (OP(op) | (((uint32_t)(xop)) & 0x7f3))
|
||||
#define VX128_2(op, xop) (OP(op) | (((uint32_t)(xop)) & 0x210))
|
||||
#define VX128_3(op, xop) (OP(op) | (((uint32_t)(xop)) & 0x7f0))
|
||||
#define VX128_4(op, xop) (OP(op) | (((uint32_t)(xop)) & 0x730))
|
||||
#define VX128_5(op, xop) (OP(op) | (((uint32_t)(xop)) & 0x10))
|
||||
#define VX128_P(op, xop) (OP(op) | (((uint32_t)(xop)) & 0x630))
|
||||
#define VX128_R(op, xop) (OP(op) | (((uint32_t)(xop)) & 0x390))
|
||||
static InstrType instr_table_scan[] = {
|
||||
SCAN_INSTRUCTION(vcmpbfp, 0x100003C6, VXR , General , 0),
|
||||
SCAN_INSTRUCTION(vcmpeqfp, 0x100000C6, VXR , General , 0),
|
||||
SCAN_INSTRUCTION(vcmpequb, 0x10000006, VXR , General , 0),
|
||||
SCAN_INSTRUCTION(vcmpequh, 0x10000046, VXR , General , 0),
|
||||
SCAN_INSTRUCTION(vcmpequw, 0x10000086, VXR , General , 0),
|
||||
SCAN_INSTRUCTION(vcmpgefp, 0x100001C6, VXR , General , 0),
|
||||
SCAN_INSTRUCTION(vcmpgtfp, 0x100002C6, VXR , General , 0),
|
||||
SCAN_INSTRUCTION(vcmpgtsb, 0x10000306, VXR , General , 0),
|
||||
SCAN_INSTRUCTION(vcmpgtsh, 0x10000346, VXR , General , 0),
|
||||
SCAN_INSTRUCTION(vcmpgtsw, 0x10000386, VXR , General , 0),
|
||||
SCAN_INSTRUCTION(vcmpgtub, 0x10000206, VXR , General , 0),
|
||||
SCAN_INSTRUCTION(vcmpgtuh, 0x10000246, VXR , General , 0),
|
||||
SCAN_INSTRUCTION(vcmpgtuw, 0x10000286, VXR , General , 0),
|
||||
SCAN_INSTRUCTION(vmaddfp, 0x1000002E, VXA , General , 0),
|
||||
SCAN_INSTRUCTION(vmhaddshs, 0x10000020, VXA , General , 0),
|
||||
SCAN_INSTRUCTION(vmhraddshs, 0x10000021, VXA , General , 0),
|
||||
SCAN_INSTRUCTION(vmladduhm, 0x10000022, VXA , General , 0),
|
||||
SCAN_INSTRUCTION(vmsummbm, 0x10000025, VXA , General , 0),
|
||||
SCAN_INSTRUCTION(vmsumshm, 0x10000028, VXA , General , 0),
|
||||
SCAN_INSTRUCTION(vmsumshs, 0x10000029, VXA , General , 0),
|
||||
SCAN_INSTRUCTION(vmsumubm, 0x10000024, VXA , General , 0),
|
||||
SCAN_INSTRUCTION(vmsumuhm, 0x10000026, VXA , General , 0),
|
||||
SCAN_INSTRUCTION(vmsumuhs, 0x10000027, VXA , General , 0),
|
||||
SCAN_INSTRUCTION(vnmsubfp, 0x1000002F, VXA , General , 0),
|
||||
SCAN_INSTRUCTION(vperm, 0x1000002B, VXA , General , 0),
|
||||
SCAN_INSTRUCTION(vsel, 0x1000002A, VXA , General , 0),
|
||||
SCAN_INSTRUCTION(vsldoi, 0x1000002C, VXA , General , 0),
|
||||
SCAN_INSTRUCTION(lvsl128, VX128_1(4, 3), VX128_1 , General , 0),
|
||||
SCAN_INSTRUCTION(lvsr128, VX128_1(4, 67), VX128_1 , General , 0),
|
||||
SCAN_INSTRUCTION(lvewx128, VX128_1(4, 131), VX128_1 , General , 0),
|
||||
SCAN_INSTRUCTION(lvx128, VX128_1(4, 195), VX128_1 , General , 0),
|
||||
SCAN_INSTRUCTION(stvewx128, VX128_1(4, 387), VX128_1 , General , 0),
|
||||
SCAN_INSTRUCTION(stvx128, VX128_1(4, 451), VX128_1 , General , 0),
|
||||
SCAN_INSTRUCTION(lvxl128, VX128_1(4, 707), VX128_1 , General , 0),
|
||||
SCAN_INSTRUCTION(stvxl128, VX128_1(4, 963), VX128_1 , General , 0),
|
||||
SCAN_INSTRUCTION(lvlx128, VX128_1(4, 1027), VX128_1 , General , 0),
|
||||
SCAN_INSTRUCTION(lvrx128, VX128_1(4, 1091), VX128_1 , General , 0),
|
||||
SCAN_INSTRUCTION(stvlx128, VX128_1(4, 1283), VX128_1 , General , 0),
|
||||
SCAN_INSTRUCTION(stvrx128, VX128_1(4, 1347), VX128_1 , General , 0),
|
||||
SCAN_INSTRUCTION(lvlxl128, VX128_1(4, 1539), VX128_1 , General , 0),
|
||||
SCAN_INSTRUCTION(lvrxl128, VX128_1(4, 1603), VX128_1 , General , 0),
|
||||
SCAN_INSTRUCTION(stvlxl128, VX128_1(4, 1795), VX128_1 , General , 0),
|
||||
SCAN_INSTRUCTION(stvrxl128, VX128_1(4, 1859), VX128_1 , General , 0),
|
||||
SCAN_INSTRUCTION(vsldoi128, VX128_5(4, 16), VX128_5 , General , 0),
|
||||
SCAN_INSTRUCTION(vperm128, VX128_2(5, 0), VX128_2 , General , 0),
|
||||
SCAN_INSTRUCTION(vaddfp128, VX128(5, 16), VX128 , General , 0),
|
||||
SCAN_INSTRUCTION(vsubfp128, VX128(5, 80), VX128 , General , 0),
|
||||
SCAN_INSTRUCTION(vmulfp128, VX128(5, 144), VX128 , General , 0),
|
||||
SCAN_INSTRUCTION(vmaddfp128, VX128(5, 208), VX128 , General , 0),
|
||||
SCAN_INSTRUCTION(vmaddcfp128, VX128(5, 272), VX128 , General , 0),
|
||||
SCAN_INSTRUCTION(vnmsubfp128, VX128(5, 336), VX128 , General , 0),
|
||||
SCAN_INSTRUCTION(vmsum3fp128, VX128(5, 400), VX128 , General , 0),
|
||||
SCAN_INSTRUCTION(vmsum4fp128, VX128(5, 464), VX128 , General , 0),
|
||||
SCAN_INSTRUCTION(vpkshss128, VX128(5, 512), VX128 , General , 0),
|
||||
SCAN_INSTRUCTION(vand128, VX128(5, 528), VX128 , General , 0),
|
||||
SCAN_INSTRUCTION(vpkshus128, VX128(5, 576), VX128 , General , 0),
|
||||
SCAN_INSTRUCTION(vandc128, VX128(5, 592), VX128 , General , 0),
|
||||
SCAN_INSTRUCTION(vpkswss128, VX128(5, 640), VX128 , General , 0),
|
||||
SCAN_INSTRUCTION(vnor128, VX128(5, 656), VX128 , General , 0),
|
||||
SCAN_INSTRUCTION(vpkswus128, VX128(5, 704), VX128 , General , 0),
|
||||
SCAN_INSTRUCTION(vor128, VX128(5, 720), VX128 , General , 0),
|
||||
SCAN_INSTRUCTION(vpkuhum128, VX128(5, 768), VX128 , General , 0),
|
||||
SCAN_INSTRUCTION(vxor128, VX128(5, 784), VX128 , General , 0),
|
||||
SCAN_INSTRUCTION(vpkuhus128, VX128(5, 832), VX128 , General , 0),
|
||||
SCAN_INSTRUCTION(vsel128, VX128(5, 848), VX128 , General , 0),
|
||||
SCAN_INSTRUCTION(vpkuwum128, VX128(5, 896), VX128 , General , 0),
|
||||
SCAN_INSTRUCTION(vslo128, VX128(5, 912), VX128 , General , 0),
|
||||
SCAN_INSTRUCTION(vpkuwus128, VX128(5, 960), VX128 , General , 0),
|
||||
SCAN_INSTRUCTION(vsro128, VX128(5, 976), VX128 , General , 0),
|
||||
SCAN_INSTRUCTION(vpermwi128, VX128_P(6, 528), VX128_P , General , 0),
|
||||
SCAN_INSTRUCTION(vcfpsxws128, VX128_3(6, 560), VX128_3 , General , 0),
|
||||
SCAN_INSTRUCTION(vcfpuxws128, VX128_3(6, 624), VX128_3 , General , 0),
|
||||
SCAN_INSTRUCTION(vcsxwfp128, VX128_3(6, 688), VX128_3 , General , 0),
|
||||
SCAN_INSTRUCTION(vcuxwfp128, VX128_3(6, 752), VX128_3 , General , 0),
|
||||
SCAN_INSTRUCTION(vrfim128, VX128_3(6, 816), VX128_3 , General , 0),
|
||||
SCAN_INSTRUCTION(vrfin128, VX128_3(6, 880), VX128_3 , General , 0),
|
||||
SCAN_INSTRUCTION(vrfip128, VX128_3(6, 944), VX128_3 , General , 0),
|
||||
SCAN_INSTRUCTION(vrfiz128, VX128_3(6, 1008), VX128_3 , General , 0),
|
||||
SCAN_INSTRUCTION(vpkd3d128, VX128_4(6, 1552), VX128_4 , General , 0),
|
||||
SCAN_INSTRUCTION(vrefp128, VX128_3(6, 1584), VX128_3 , General , 0),
|
||||
SCAN_INSTRUCTION(vrsqrtefp128, VX128_3(6, 1648), VX128_3 , General , 0),
|
||||
SCAN_INSTRUCTION(vexptefp128, VX128_3(6, 1712), VX128_3 , General , 0),
|
||||
SCAN_INSTRUCTION(vlogefp128, VX128_3(6, 1776), VX128_3 , General , 0),
|
||||
SCAN_INSTRUCTION(vrlimi128, VX128_4(6, 1808), VX128_4 , General , 0),
|
||||
SCAN_INSTRUCTION(vspltw128, VX128_3(6, 1840), VX128_3 , General , 0),
|
||||
SCAN_INSTRUCTION(vspltisw128, VX128_3(6, 1904), VX128_3 , General , 0),
|
||||
SCAN_INSTRUCTION(vupkd3d128, VX128_3(6, 2032), VX128_3 , General , 0),
|
||||
SCAN_INSTRUCTION(vcmpeqfp128, VX128_R(6, 0), VX128_R , General , 0),
|
||||
SCAN_INSTRUCTION(vrlw128, VX128(6, 80), VX128 , General , 0),
|
||||
SCAN_INSTRUCTION(vcmpgefp128, VX128_R(6, 128), VX128_R , General , 0),
|
||||
SCAN_INSTRUCTION(vslw128, VX128(6, 208), VX128 , General , 0),
|
||||
SCAN_INSTRUCTION(vcmpgtfp128, VX128_R(6, 256), VX128_R , General , 0),
|
||||
SCAN_INSTRUCTION(vsraw128, VX128(6, 336), VX128 , General , 0),
|
||||
SCAN_INSTRUCTION(vcmpbfp128, VX128_R(6, 384), VX128_R , General , 0),
|
||||
SCAN_INSTRUCTION(vsrw128, VX128(6, 464), VX128 , General , 0),
|
||||
SCAN_INSTRUCTION(vcmpequw128, VX128_R(6, 512), VX128_R , General , 0),
|
||||
SCAN_INSTRUCTION(vmaxfp128, VX128(6, 640), VX128 , General , 0),
|
||||
SCAN_INSTRUCTION(vminfp128, VX128(6, 704), VX128 , General , 0),
|
||||
SCAN_INSTRUCTION(vmrghw128, VX128(6, 768), VX128 , General , 0),
|
||||
SCAN_INSTRUCTION(vmrglw128, VX128(6, 832), VX128 , General , 0),
|
||||
SCAN_INSTRUCTION(vupkhsb128, VX128(6, 896), VX128 , General , 0),
|
||||
SCAN_INSTRUCTION(vupklsb128, VX128(6, 960), VX128 , General , 0),
|
||||
};
|
||||
#undef OP
|
||||
#undef VX128
|
||||
#undef VX128_1
|
||||
#undef VX128_2
|
||||
#undef VX128_3
|
||||
#undef VX128_4
|
||||
#undef VX128_5
|
||||
#undef VX128_P
|
||||
|
||||
|
||||
#undef FLAG
|
||||
#undef INSTRUCTION
|
||||
#undef EMPTY
|
||||
|
||||
|
||||
} // namespace tables
|
||||
} // namespace ppc
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_FRONTEND_PPC_PPC_INSTR_TABLES_H_
|
||||
278
src/alloy/frontend/ppc/ppc_scanner.cc
Normal file
278
src/alloy/frontend/ppc/ppc_scanner.cc
Normal file
@@ -0,0 +1,278 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 <alloy/frontend/ppc/ppc_scanner.h>
|
||||
|
||||
#include <alloy/frontend/tracing.h>
|
||||
#include <alloy/frontend/ppc/ppc_frontend.h>
|
||||
#include <alloy/frontend/ppc/ppc_instr.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::frontend;
|
||||
using namespace alloy::frontend::ppc;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
|
||||
PPCScanner::PPCScanner(PPCFrontend* frontend) :
|
||||
frontend_(frontend) {
|
||||
}
|
||||
|
||||
PPCScanner::~PPCScanner() {
|
||||
}
|
||||
|
||||
bool PPCScanner::IsRestGprLr(uint64_t address) {
|
||||
// TODO(benvanik): detect type.
|
||||
/*FunctionSymbol* fn = GetFunction(addr);
|
||||
return fn && (fn->flags & FunctionSymbol::kFlagRestGprLr);*/
|
||||
return false;
|
||||
}
|
||||
|
||||
int PPCScanner::FindExtents(FunctionInfo* symbol_info) {
|
||||
// This is a simple basic block analyizer. It walks the start address to the
|
||||
// end address looking for branches. Each span of instructions between
|
||||
// branches is considered a basic block. When the last blr (that has no
|
||||
// branches to after it) is found the function is considered ended. If this
|
||||
// is before the expected end address then the function address range is
|
||||
// split up and the second half is treated as another function.
|
||||
|
||||
Memory* memory = frontend_->memory();
|
||||
const uint8_t* p = memory->membase();
|
||||
|
||||
XELOGSDB("Analyzing function %.8X...", symbol_info->address());
|
||||
|
||||
uint64_t start_address = symbol_info->address();
|
||||
uint64_t end_address = symbol_info->end_address();
|
||||
uint64_t address = start_address;
|
||||
uint64_t furthest_target = start_address;
|
||||
size_t blocks_found = 0;
|
||||
bool in_block = false;
|
||||
bool starts_with_mfspr_lr = false;
|
||||
InstrData i;
|
||||
while (true) {
|
||||
i.address = address;
|
||||
i.code = XEGETUINT32BE(p + address);
|
||||
|
||||
// If we fetched 0 assume that we somehow hit one of the awesome
|
||||
// 'no really we meant to end after that bl' functions.
|
||||
if (!i.code) {
|
||||
XELOGSDB("function end %.8X (0x00000000 read)", address);
|
||||
// Don't include the 0's.
|
||||
address -= 4;
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO(benvanik): find a way to avoid using the opcode tables.
|
||||
// This lookup is *expensive* and should be avoided when scanning.
|
||||
i.type = GetInstrType(i.code);
|
||||
|
||||
// Check if the function starts with a mfspr lr, as that's a good indication
|
||||
// of whether or not this is a normal function with a prolog/epilog.
|
||||
// Some valid leaf functions won't have this, but most will.
|
||||
if (address == start_address &&
|
||||
i.type &&
|
||||
i.type->opcode == 0x7C0002A6 &&
|
||||
(((i.XFX.spr & 0x1F) << 5) | ((i.XFX.spr >> 5) & 0x1F)) == 8) {
|
||||
starts_with_mfspr_lr = true;
|
||||
}
|
||||
|
||||
if (!in_block) {
|
||||
in_block = true;
|
||||
blocks_found++;
|
||||
}
|
||||
|
||||
bool ends_fn = false;
|
||||
bool ends_block = false;
|
||||
if (!i.type) {
|
||||
// Invalid instruction.
|
||||
// We can just ignore it because there's (very little)/no chance it'll
|
||||
// affect flow control.
|
||||
XELOGSDB("Invalid instruction at %.8X: %.8X", address, i.code);
|
||||
} else if (i.code == 0x4E800020) {
|
||||
// blr -- unconditional branch to LR.
|
||||
// This is generally a return.
|
||||
if (furthest_target > address) {
|
||||
// Remaining targets within function, not end.
|
||||
XELOGSDB("ignoring blr %.8X (branch to %.8X)",
|
||||
address, furthest_target);
|
||||
} else {
|
||||
// Function end point.
|
||||
XELOGSDB("function end %.8X", address);
|
||||
ends_fn = true;
|
||||
}
|
||||
ends_block = true;
|
||||
} else if (i.code == 0x4E800420) {
|
||||
// bctr -- unconditional branch to CTR.
|
||||
// This is generally a jump to a function pointer (non-return).
|
||||
if (furthest_target > address) {
|
||||
// Remaining targets within function, not end.
|
||||
XELOGSDB("ignoring bctr %.8X (branch to %.8X)", address,
|
||||
furthest_target);
|
||||
} else {
|
||||
// Function end point.
|
||||
XELOGSDB("function end %.8X", address);
|
||||
ends_fn = true;
|
||||
}
|
||||
ends_block = true;
|
||||
} else if (i.type->opcode == 0x48000000) {
|
||||
// b/ba/bl/bla
|
||||
uint32_t target =
|
||||
(uint32_t)XEEXTS26(i.I.LI << 2) + (i.I.AA ? 0 : (int32_t)address);
|
||||
|
||||
if (i.I.LK) {
|
||||
XELOGSDB("bl %.8X -> %.8X", address, target);
|
||||
// Queue call target if needed.
|
||||
// GetOrInsertFunction(target);
|
||||
} else {
|
||||
XELOGSDB("b %.8X -> %.8X", address, target);
|
||||
|
||||
// If the target is back into the function and there's no further target
|
||||
// we are at the end of a function.
|
||||
// (Indirect branches may still go beyond, but no way of knowing).
|
||||
if (target >= start_address &&
|
||||
target < address && furthest_target <= address) {
|
||||
XELOGSDB("function end %.8X (back b)", addr);
|
||||
ends_fn = true;
|
||||
}
|
||||
|
||||
// If the target is not a branch and it goes to before the current
|
||||
// address it's definitely a tail call.
|
||||
if (!ends_fn &&
|
||||
target < start_address && furthest_target <= address) {
|
||||
XELOGSDB("function end %.8X (back b before addr)", addr);
|
||||
ends_fn = true;
|
||||
}
|
||||
|
||||
// If the target is a __restgprlr_* method it's the end of a function.
|
||||
// Note that sometimes functions stick this in a basic block *inside*
|
||||
// of the function somewhere, so ensure we don't have any branches over
|
||||
// it.
|
||||
if (!ends_fn &&
|
||||
furthest_target <= address &&
|
||||
IsRestGprLr(target)) {
|
||||
XELOGSDB("function end %.8X (__restgprlr_*)", addr);
|
||||
ends_fn = true;
|
||||
}
|
||||
|
||||
// Heuristic: if there's an unconditional branch in the first block of
|
||||
// the function it's likely a thunk.
|
||||
// Ex:
|
||||
// li r3, 0
|
||||
// b KeBugCheck
|
||||
// This check may hit on functions that jump over data code, so only
|
||||
// trigger this check in leaf functions (no mfspr lr/prolog).
|
||||
if (!ends_fn &&
|
||||
!starts_with_mfspr_lr &&
|
||||
blocks_found == 1) {
|
||||
XELOGSDB("HEURISTIC: ending at simple leaf thunk %.8X", address);
|
||||
ends_fn = true;
|
||||
}
|
||||
|
||||
// Heuristic: if this is an unconditional branch at the end of the
|
||||
// function (nothing jumps over us) and we are jumping forward there's
|
||||
// a good chance it's a tail call.
|
||||
// This may not be true if the code is jumping over data/etc.
|
||||
// TODO(benvanik): figure out how to do this reliably. This check as is
|
||||
// is too aggressive and turns a lot of valid branches into tail calls.
|
||||
// It seems like a lot of functions end up with some prologue bit then
|
||||
// jump deep inside only to jump back towards the top soon after. May
|
||||
// need something more complex than just a simple 1-pass system to
|
||||
// detect these, unless more signals can be found.
|
||||
/*
|
||||
if (!ends_fn &&
|
||||
target > addr &&
|
||||
furthest_target < addr) {
|
||||
XELOGSDB("HEURISTIC: ending at tail call branch %.8X", addr);
|
||||
ends_fn = true;
|
||||
}
|
||||
*/
|
||||
|
||||
if (!ends_fn) {
|
||||
furthest_target = MAX(furthest_target, target);
|
||||
|
||||
// TODO(benvanik): perhaps queue up for a speculative check? I think
|
||||
// we are running over tail-call functions here that branch to
|
||||
// somewhere else.
|
||||
//GetOrInsertFunction(target);
|
||||
}
|
||||
}
|
||||
ends_block = true;
|
||||
} else if (i.type->opcode == 0x40000000) {
|
||||
// bc/bca/bcl/bcla
|
||||
uint32_t target =
|
||||
(uint32_t)XEEXTS16(i.B.BD << 2) + (i.B.AA ? 0 : (int32_t)address);
|
||||
if (i.B.LK) {
|
||||
XELOGSDB("bcl %.8X -> %.8X", address, target);
|
||||
|
||||
// Queue call target if needed.
|
||||
// TODO(benvanik): see if this is correct - not sure anyone makes
|
||||
// function calls with bcl.
|
||||
//GetOrInsertFunction(target);
|
||||
} else {
|
||||
XELOGSDB("bc %.8X -> %.8X", address, target);
|
||||
|
||||
// TODO(benvanik): GetOrInsertFunction? it's likely a BB
|
||||
|
||||
furthest_target = MAX(furthest_target, target);
|
||||
}
|
||||
ends_block = true;
|
||||
} else if (i.type->opcode == 0x4C000020) {
|
||||
// bclr/bclrl
|
||||
if (i.XL.LK) {
|
||||
XELOGSDB("bclrl %.8X", addr);
|
||||
} else {
|
||||
XELOGSDB("bclr %.8X", addr);
|
||||
}
|
||||
ends_block = true;
|
||||
} else if (i.type->opcode == 0x4C000420) {
|
||||
// bcctr/bcctrl
|
||||
if (i.XL.LK) {
|
||||
XELOGSDB("bcctrl %.8X", addr);
|
||||
} else {
|
||||
XELOGSDB("bcctr %.8X", addr);
|
||||
}
|
||||
ends_block = true;
|
||||
}
|
||||
|
||||
if (ends_block) {
|
||||
in_block = false;
|
||||
}
|
||||
if (ends_fn) {
|
||||
break;
|
||||
}
|
||||
|
||||
address += 4;
|
||||
if (end_address && address > end_address) {
|
||||
// Hmm....
|
||||
XELOGSDB("Ran over function bounds! %.8X-%.8X",
|
||||
start_address, end_address);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (end_address && address + 4 < end_address) {
|
||||
// Ran under the expected value - since we probably got the initial bounds
|
||||
// from someplace valid (like method hints) this may indicate an error.
|
||||
// It's also possible that we guessed in hole-filling and there's another
|
||||
// function below this one.
|
||||
XELOGSDB("Function ran under: %.8X-%.8X ended at %.8X",
|
||||
start_address, end_address, address + 4);
|
||||
}
|
||||
symbol_info->set_end_address(address);
|
||||
|
||||
// If there's spare bits at the end, split the function.
|
||||
// TODO(benvanik): splitting?
|
||||
|
||||
// TODO(benvanik): find and record stack information
|
||||
// - look for __savegprlr_* and __restgprlr_*
|
||||
// - if present, flag function as needing a stack
|
||||
// - record prolog/epilog lengths/stack size/etc
|
||||
|
||||
XELOGSDB("Finished analyzing %.8X", start_address);
|
||||
return 0;
|
||||
}
|
||||
44
src/alloy/frontend/ppc/ppc_scanner.h
Normal file
44
src/alloy/frontend/ppc/ppc_scanner.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_FRONTEND_PPC_PPC_SCANNER_H_
|
||||
#define ALLOY_FRONTEND_PPC_PPC_SCANNER_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
#include <alloy/runtime/symbol_info.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
namespace ppc {
|
||||
|
||||
class PPCFrontend;
|
||||
|
||||
|
||||
class PPCScanner {
|
||||
public:
|
||||
PPCScanner(PPCFrontend* frontend);
|
||||
~PPCScanner();
|
||||
|
||||
int FindExtents(runtime::FunctionInfo* symbol_info);
|
||||
|
||||
private:
|
||||
bool IsRestGprLr(uint64_t address);
|
||||
|
||||
private:
|
||||
PPCFrontend* frontend_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace ppc
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_FRONTEND_PPC_PPC_SCANNER_H_
|
||||
101
src/alloy/frontend/ppc/ppc_translator.cc
Normal file
101
src/alloy/frontend/ppc/ppc_translator.cc
Normal file
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 <alloy/frontend/ppc/ppc_translator.h>
|
||||
|
||||
#include <alloy/compiler/passes.h>
|
||||
#include <alloy/frontend/tracing.h>
|
||||
#include <alloy/frontend/ppc/ppc_frontend.h>
|
||||
#include <alloy/frontend/ppc/ppc_function_builder.h>
|
||||
#include <alloy/frontend/ppc/ppc_scanner.h>
|
||||
#include <alloy/runtime/runtime.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::backend;
|
||||
using namespace alloy::compiler;
|
||||
using namespace alloy::frontend;
|
||||
using namespace alloy::frontend::ppc;
|
||||
using namespace alloy::hir;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
|
||||
PPCTranslator::PPCTranslator(PPCFrontend* frontend) :
|
||||
frontend_(frontend) {
|
||||
scanner_ = new PPCScanner(frontend);
|
||||
builder_ = new PPCFunctionBuilder(frontend);
|
||||
|
||||
compiler_ = new Compiler();
|
||||
|
||||
// TODO(benvanik): passes in a sensible order/etc.
|
||||
compiler_->AddPass(new passes::Mem2RegPass());
|
||||
|
||||
Backend* backend = frontend->runtime()->backend();
|
||||
assembler_ = backend->CreateAssembler();
|
||||
}
|
||||
|
||||
PPCTranslator::~PPCTranslator() {
|
||||
delete assembler_;
|
||||
delete compiler_;
|
||||
delete builder_;
|
||||
delete scanner_;
|
||||
}
|
||||
|
||||
int PPCTranslator::Translate(
|
||||
FunctionInfo* symbol_info,
|
||||
Function** out_function) {
|
||||
char* pre_ir = NULL;
|
||||
char* post_ir = NULL;
|
||||
|
||||
// Scan the function to find its extents. We only need to do this if we
|
||||
// haven't already been provided with them from some other source.
|
||||
if (!symbol_info->has_end_address()) {
|
||||
// TODO(benvanik): find a way to remove the need for the scan. A fixup
|
||||
// scheme acting on branches could go back and modify calls to branches
|
||||
// if they are within the extents.
|
||||
int result = scanner_->FindExtents(symbol_info);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Emit function.
|
||||
int result = builder_->Emit(symbol_info);
|
||||
XEEXPECTZERO(result);
|
||||
|
||||
if (true) {
|
||||
builder_->Dump(&string_buffer_);
|
||||
pre_ir = string_buffer_.ToString();
|
||||
string_buffer_.Reset();
|
||||
}
|
||||
|
||||
// Compile/optimize/etc.
|
||||
result = compiler_->Compile(builder_);
|
||||
XEEXPECTZERO(result);
|
||||
|
||||
if (true) {
|
||||
builder_->Dump(&string_buffer_);
|
||||
post_ir = string_buffer_.ToString();
|
||||
string_buffer_.Reset();
|
||||
}
|
||||
|
||||
// Assemble to backend machine code.
|
||||
result = assembler_->Assemble(symbol_info, builder_, out_function);
|
||||
XEEXPECTZERO(result);
|
||||
|
||||
result = 0;
|
||||
|
||||
XECLEANUP:
|
||||
if (pre_ir) xe_free(pre_ir);
|
||||
if (post_ir) xe_free(post_ir);
|
||||
builder_->Reset();
|
||||
compiler_->Reset();
|
||||
assembler_->Reset();
|
||||
string_buffer_.Reset();
|
||||
return result;
|
||||
};
|
||||
52
src/alloy/frontend/ppc/ppc_translator.h
Normal file
52
src/alloy/frontend/ppc/ppc_translator.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_FRONTEND_PPC_PPC_TRANSLATOR_H_
|
||||
#define ALLOY_FRONTEND_PPC_PPC_TRANSLATOR_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
#include <alloy/backend/assembler.h>
|
||||
#include <alloy/compiler/compiler.h>
|
||||
#include <alloy/runtime/symbol_info.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
namespace ppc {
|
||||
|
||||
class PPCFrontend;
|
||||
class PPCFunctionBuilder;
|
||||
class PPCScanner;
|
||||
|
||||
|
||||
class PPCTranslator {
|
||||
public:
|
||||
PPCTranslator(PPCFrontend* frontend);
|
||||
~PPCTranslator();
|
||||
|
||||
int Translate(runtime::FunctionInfo* symbol_info,
|
||||
runtime::Function** out_function);
|
||||
|
||||
private:
|
||||
PPCFrontend* frontend_;
|
||||
PPCScanner* scanner_;
|
||||
PPCFunctionBuilder* builder_;
|
||||
compiler::Compiler* compiler_;
|
||||
backend::Assembler* assembler_;
|
||||
|
||||
StringBuffer string_buffer_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace ppc
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_FRONTEND_PPC_PPC_TRANSLATOR_H_
|
||||
32
src/alloy/frontend/ppc/sources.gypi
Normal file
32
src/alloy/frontend/ppc/sources.gypi
Normal file
@@ -0,0 +1,32 @@
|
||||
# Copyright 2013 Ben Vanik. All Rights Reserved.
|
||||
{
|
||||
'sources': [
|
||||
'ppc_context.cc',
|
||||
'ppc_context.h',
|
||||
'ppc_disasm-private.h',
|
||||
'ppc_disasm.h',
|
||||
'ppc_disasm_altivec.cc',
|
||||
'ppc_disasm_alu.cc',
|
||||
'ppc_disasm_control.cc',
|
||||
'ppc_disasm_fpu.cc',
|
||||
'ppc_disasm_memory.cc',
|
||||
'ppc_emit-private.h',
|
||||
'ppc_emit.h',
|
||||
'ppc_emit_altivec.cc',
|
||||
'ppc_emit_alu.cc',
|
||||
'ppc_emit_control.cc',
|
||||
'ppc_emit_fpu.cc',
|
||||
'ppc_emit_memory.cc',
|
||||
'ppc_frontend.cc',
|
||||
'ppc_frontend.h',
|
||||
'ppc_function_builder.cc',
|
||||
'ppc_function_builder.h',
|
||||
'ppc_instr.cc',
|
||||
'ppc_instr.h',
|
||||
'ppc_instr_tables.h',
|
||||
'ppc_scanner.cc',
|
||||
'ppc_scanner.h',
|
||||
'ppc_translator.cc',
|
||||
'ppc_translator.h',
|
||||
],
|
||||
}
|
||||
12
src/alloy/frontend/sources.gypi
Normal file
12
src/alloy/frontend/sources.gypi
Normal file
@@ -0,0 +1,12 @@
|
||||
# Copyright 2013 Ben Vanik. All Rights Reserved.
|
||||
{
|
||||
'sources': [
|
||||
'frontend.cc',
|
||||
'frontend.h',
|
||||
'tracing.h',
|
||||
],
|
||||
|
||||
'includes': [
|
||||
'ppc/sources.gypi',
|
||||
],
|
||||
}
|
||||
43
src/alloy/frontend/tracing.h
Normal file
43
src/alloy/frontend/tracing.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_FRONTEND_TRACING_H_
|
||||
#define ALLOY_FRONTEND_TRACING_H_
|
||||
|
||||
#include <alloy/tracing/tracing.h>
|
||||
#include <alloy/tracing/event_type.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
|
||||
const uint32_t ALLOY_FRONTEND = alloy::tracing::EventType::ALLOY_FRONTEND;
|
||||
|
||||
|
||||
class EventType {
|
||||
public:
|
||||
enum {
|
||||
ALLOY_FRONTEND_INIT = ALLOY_FRONTEND | (1),
|
||||
ALLOY_FRONTEND_DEINIT = ALLOY_FRONTEND | (2),
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
static const uint32_t event_type = ALLOY_FRONTEND_INIT;
|
||||
} Init;
|
||||
typedef struct {
|
||||
static const uint32_t event_type = ALLOY_FRONTEND_DEINIT;
|
||||
} Deinit;
|
||||
};
|
||||
|
||||
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_FRONTEND_TRACING_H_
|
||||
Reference in New Issue
Block a user