parent
86002b2f44
commit
bedf86d259
|
@ -13,6 +13,6 @@
|
||||||
#include <xenia/cpu/processor.h>
|
#include <xenia/cpu/processor.h>
|
||||||
|
|
||||||
// TODO(benvanik): conditionally include?
|
// TODO(benvanik): conditionally include?
|
||||||
//#include <xenia/cpu/libjit/libjit_backend.h>
|
#include <xenia/cpu/x64/x64_backend.h>
|
||||||
|
|
||||||
#endif // XENIA_CPU_CPU_H_
|
#endif // XENIA_CPU_CPU_H_
|
||||||
|
|
|
@ -20,5 +20,6 @@
|
||||||
'includes': [
|
'includes': [
|
||||||
'ppc/sources.gypi',
|
'ppc/sources.gypi',
|
||||||
'sdb/sources.gypi',
|
'sdb/sources.gypi',
|
||||||
|
'x64/sources.gypi',
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
# Copyright 2013 Ben Vanik. All Rights Reserved.
|
||||||
|
{
|
||||||
|
'sources': [
|
||||||
|
'x64_backend.cc',
|
||||||
|
'x64_backend.h',
|
||||||
|
'x64_emit.h',
|
||||||
|
'x64_emit_alu.cc',
|
||||||
|
'x64_emit_control.cc',
|
||||||
|
'x64_emit_fpu.cc',
|
||||||
|
'x64_emit_memory.cc',
|
||||||
|
'x64_emitter.cc',
|
||||||
|
'x64_emitter.h',
|
||||||
|
'x64_jit.cc',
|
||||||
|
'x64_jit.h',
|
||||||
|
],
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <xenia/cpu/x64/x64_backend.h>
|
||||||
|
|
||||||
|
#include <xenia/cpu/sdb/symbol_table.h>
|
||||||
|
#include <xenia/cpu/x64/x64_emit.h>
|
||||||
|
#include <xenia/cpu/x64/x64_jit.h>
|
||||||
|
|
||||||
|
|
||||||
|
using namespace xe;
|
||||||
|
using namespace xe::cpu;
|
||||||
|
using namespace xe::cpu::sdb;
|
||||||
|
using namespace xe::cpu::x64;
|
||||||
|
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
void InitializeIfNeeded();
|
||||||
|
void CleanupOnShutdown();
|
||||||
|
|
||||||
|
void InitializeIfNeeded() {
|
||||||
|
static bool has_initialized = false;
|
||||||
|
if (has_initialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
has_initialized = true;
|
||||||
|
|
||||||
|
X64RegisterEmitCategoryALU();
|
||||||
|
X64RegisterEmitCategoryControl();
|
||||||
|
X64RegisterEmitCategoryFPU();
|
||||||
|
X64RegisterEmitCategoryMemory();
|
||||||
|
|
||||||
|
atexit(CleanupOnShutdown);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CleanupOnShutdown() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
X64Backend::X64Backend() :
|
||||||
|
Backend() {
|
||||||
|
InitializeIfNeeded();
|
||||||
|
}
|
||||||
|
|
||||||
|
X64Backend::~X64Backend() {
|
||||||
|
}
|
||||||
|
|
||||||
|
JIT* X64Backend::CreateJIT(xe_memory_ref memory, SymbolTable* sym_table) {
|
||||||
|
return new X64JIT(memory, sym_table);
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef XENIA_CPU_X64_X64_BACKEND_H_
|
||||||
|
#define XENIA_CPU_X64_X64_BACKEND_H_
|
||||||
|
|
||||||
|
#include <xenia/common.h>
|
||||||
|
|
||||||
|
#include <xenia/cpu/backend.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace cpu {
|
||||||
|
namespace x64 {
|
||||||
|
|
||||||
|
|
||||||
|
class X64Backend : public Backend {
|
||||||
|
public:
|
||||||
|
X64Backend();
|
||||||
|
virtual ~X64Backend();
|
||||||
|
|
||||||
|
virtual JIT* CreateJIT(xe_memory_ref memory, sdb::SymbolTable* sym_table);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace x64
|
||||||
|
} // namespace cpu
|
||||||
|
} // namespace xe
|
||||||
|
|
||||||
|
|
||||||
|
#endif // XENIA_CPU_X64_X64_BACKEND_H_
|
|
@ -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 XENIA_CPU_X64_X64_EMIT_H_
|
||||||
|
#define XENIA_CPU_X64_X64_EMIT_H_
|
||||||
|
|
||||||
|
#include <xenia/cpu/ppc/instr.h>
|
||||||
|
#include <xenia/cpu/ppc/state.h>
|
||||||
|
#include <xenia/cpu/x64/x64_emitter.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace cpu {
|
||||||
|
namespace x64 {
|
||||||
|
|
||||||
|
|
||||||
|
void X64RegisterEmitCategoryALU();
|
||||||
|
void X64RegisterEmitCategoryControl();
|
||||||
|
void X64RegisterEmitCategoryFPU();
|
||||||
|
void X64RegisterEmitCategoryMemory();
|
||||||
|
|
||||||
|
|
||||||
|
#define XEEMITTER(name, opcode, format) int InstrEmit_##name
|
||||||
|
|
||||||
|
#define XEREGISTERINSTR(name, opcode) \
|
||||||
|
RegisterInstrEmit(opcode, (InstrEmitFn)InstrEmit_##name);
|
||||||
|
|
||||||
|
#define XEINSTRNOTIMPLEMENTED()
|
||||||
|
//#define XEINSTRNOTIMPLEMENTED XEASSERTALWAYS
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace x64
|
||||||
|
} // namespace cpu
|
||||||
|
} // namespace xe
|
||||||
|
|
||||||
|
|
||||||
|
#endif // XENIA_CPU_X64_X64_EMIT_H_
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,686 @@
|
||||||
|
/*
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <xenia/cpu/x64/x64_emit.h>
|
||||||
|
|
||||||
|
#include <xenia/cpu/cpu-private.h>
|
||||||
|
|
||||||
|
|
||||||
|
using namespace xe::cpu;
|
||||||
|
using namespace xe::cpu::ppc;
|
||||||
|
using namespace xe::cpu::sdb;
|
||||||
|
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace cpu {
|
||||||
|
namespace x64 {
|
||||||
|
|
||||||
|
|
||||||
|
int XeEmitIndirectBranchTo(
|
||||||
|
X64Emitter& e, jit_function_t f, const char* src, uint32_t cia,
|
||||||
|
bool lk, uint32_t reg) {
|
||||||
|
// 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!
|
||||||
|
|
||||||
|
// NOTE: we avoid spilling registers until we know that the target is not
|
||||||
|
// a basic block within this function.
|
||||||
|
|
||||||
|
jit_value_t target;
|
||||||
|
switch (reg) {
|
||||||
|
case kXEPPCRegLR:
|
||||||
|
target = e.lr_value();
|
||||||
|
break;
|
||||||
|
case kXEPPCRegCTR:
|
||||||
|
target = e.ctr_value();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
XEASSERTALWAYS();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
jit_value_t lr_cmp = jit_insn_eq(f, target, jit_value_get_param(f, 1));
|
||||||
|
e.branch_to_return_if(lr_cmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defer to the generator, which will do fancy things.
|
||||||
|
bool likely_local = !lk && reg == kXEPPCRegCTR;
|
||||||
|
return e.GenerateIndirectionBranch(cia, target, lk, likely_local);
|
||||||
|
}
|
||||||
|
|
||||||
|
int XeEmitBranchTo(
|
||||||
|
X64Emitter& e, jit_function_t f, const char* src, uint32_t cia,
|
||||||
|
bool lk, jit_value_t condition) {
|
||||||
|
FunctionBlock* fn_block = e.fn_block();
|
||||||
|
|
||||||
|
// Fast-path for branches to other blocks.
|
||||||
|
// Only valid when not tracing branches.
|
||||||
|
if (!FLAGS_trace_branches &&
|
||||||
|
fn_block->outgoing_type == FunctionBlock::kTargetBlock) {
|
||||||
|
e.branch_to_block_if(fn_block->outgoing_address, condition);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only branch of conditionals when we have one.
|
||||||
|
jit_label_t post_jump_label = jit_label_undefined;
|
||||||
|
if (condition) {
|
||||||
|
// TODO(benvanik): add debug info for this?
|
||||||
|
// char name[32];
|
||||||
|
// xesnprintfa(name, XECOUNT(name), "loc_%.8X_bcx", i.address);
|
||||||
|
jit_insn_branch_if_not(f, condition, &post_jump_label);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FLAGS_trace_branches) {
|
||||||
|
e.TraceBranch(cia);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the basic block and switch behavior based on outgoing type.
|
||||||
|
int result = 0;
|
||||||
|
switch (fn_block->outgoing_type) {
|
||||||
|
case FunctionBlock::kTargetBlock:
|
||||||
|
// Taken care of above usually.
|
||||||
|
e.branch_to_block(fn_block->outgoing_address);
|
||||||
|
break;
|
||||||
|
case FunctionBlock::kTargetFunction:
|
||||||
|
{
|
||||||
|
// Spill all registers to memory.
|
||||||
|
// TODO(benvanik): only spill ones used by the target function? Use
|
||||||
|
// calling convention flags on the function to not spill temp
|
||||||
|
// registers?
|
||||||
|
e.SpillRegisters();
|
||||||
|
|
||||||
|
XEASSERTNOTNULL(fn_block->outgoing_function);
|
||||||
|
// TODO(benvanik): check to see if this is the last block in the function.
|
||||||
|
// This would enable tail calls/etc.
|
||||||
|
bool is_end = false;
|
||||||
|
if (!lk || is_end) {
|
||||||
|
// Tail. No need to refill the local register values, just return.
|
||||||
|
// We optimize this by passing in the LR from our parent instead of the
|
||||||
|
// next instruction. This allows the return from our callee to pop
|
||||||
|
// all the way up.
|
||||||
|
e.call_function(fn_block->outgoing_function,
|
||||||
|
jit_value_get_param(f, 1), true);
|
||||||
|
jit_insn_return(f, NULL);
|
||||||
|
} else {
|
||||||
|
// Will return here eventually.
|
||||||
|
// Refill registers from state.
|
||||||
|
e.call_function(fn_block->outgoing_function,
|
||||||
|
e.get_uint64(cia + 4), false);
|
||||||
|
e.FillRegisters();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FunctionBlock::kTargetLR:
|
||||||
|
{
|
||||||
|
// An indirect jump.
|
||||||
|
printf("INDIRECT JUMP VIA LR: %.8X\n", cia);
|
||||||
|
result = XeEmitIndirectBranchTo(e, f, src, cia, lk, kXEPPCRegLR);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FunctionBlock::kTargetCTR:
|
||||||
|
{
|
||||||
|
// An indirect jump.
|
||||||
|
printf("INDIRECT JUMP VIA CTR: %.8X\n", cia);
|
||||||
|
result = XeEmitIndirectBranchTo(e, f, src, cia, lk, kXEPPCRegCTR);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
case FunctionBlock::kTargetNone:
|
||||||
|
XEASSERTALWAYS();
|
||||||
|
result = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (condition) {
|
||||||
|
jit_insn_label(f, &post_jump_label);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
XEEMITTER(bx, 0x48000000, I )(X64Emitter& e, jit_function_t 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 = XEEXTS26(i.I.LI << 2);
|
||||||
|
} else {
|
||||||
|
nia = i.address + XEEXTS26(i.I.LI << 2);
|
||||||
|
}
|
||||||
|
if (i.I.LK) {
|
||||||
|
e.update_lr_value(e.get_uint64(i.address + 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
return XeEmitBranchTo(e, f, "bx", i.address, i.I.LK, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(bcx, 0x40000000, B )(X64Emitter& e, jit_function_t 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)
|
||||||
|
|
||||||
|
// TODO(benvanik): this may be wrong and overwrite LRs when not desired!
|
||||||
|
// The docs say always, though...
|
||||||
|
if (i.B.LK) {
|
||||||
|
e.update_lr_value(e.get_uint64(i.address + 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
jit_value_t ctr_ok = NULL;
|
||||||
|
if (XESELECTBITS(i.B.BO, 2, 2)) {
|
||||||
|
// Ignore ctr.
|
||||||
|
} else {
|
||||||
|
// Decrement counter.
|
||||||
|
jit_value_t ctr = e.ctr_value();
|
||||||
|
ctr = jit_insn_sub(f, ctr, e.get_int64(1));
|
||||||
|
e.update_ctr_value(ctr);
|
||||||
|
|
||||||
|
// Ctr check.
|
||||||
|
if (XESELECTBITS(i.B.BO, 1, 1)) {
|
||||||
|
ctr_ok = jit_insn_eq(f, ctr, e.get_int64(0));
|
||||||
|
} else {
|
||||||
|
ctr_ok = jit_insn_ne(f, ctr, e.get_int64(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jit_value_t cond_ok = NULL;
|
||||||
|
if (XESELECTBITS(i.B.BO, 4, 4)) {
|
||||||
|
// Ignore cond.
|
||||||
|
} else {
|
||||||
|
jit_value_t cr = e.cr_value(i.B.BI >> 2);
|
||||||
|
cr = jit_insn_and(f, cr, e.get_uint32(1 << (i.B.BI & 3)));
|
||||||
|
if (XESELECTBITS(i.B.BO, 3, 3)) {
|
||||||
|
cond_ok = jit_insn_ne(f, cr, e.get_int64(0));
|
||||||
|
} else {
|
||||||
|
cond_ok = jit_insn_eq(f, cr, e.get_int64(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We do a bit of optimization here to make the llvm assembly easier to read.
|
||||||
|
jit_value_t ok = NULL;
|
||||||
|
if (ctr_ok && cond_ok) {
|
||||||
|
ok = jit_insn_and(f, ctr_ok, cond_ok);
|
||||||
|
} else if (ctr_ok) {
|
||||||
|
ok = ctr_ok;
|
||||||
|
} else if (cond_ok) {
|
||||||
|
ok = cond_ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t nia;
|
||||||
|
if (i.B.AA) {
|
||||||
|
nia = XEEXTS26(i.B.BD << 2);
|
||||||
|
} else {
|
||||||
|
nia = i.address + XEEXTS26(i.B.BD << 2);
|
||||||
|
}
|
||||||
|
if (XeEmitBranchTo(e, f, "bcx", i.address, i.B.LK, ok)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(bcctrx, 0x4C000420, XL )(X64Emitter& e, jit_function_t 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)
|
||||||
|
|
||||||
|
// TODO(benvanik): this may be wrong and overwrite LRs when not desired!
|
||||||
|
// The docs say always, though...
|
||||||
|
if (i.XL.LK) {
|
||||||
|
e.update_lr_value(e.get_uint64(i.address + 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
jit_value_t cond_ok = NULL;
|
||||||
|
if (XESELECTBITS(i.XL.BO, 4, 4)) {
|
||||||
|
// Ignore cond.
|
||||||
|
} else {
|
||||||
|
jit_value_t cr = e.cr_value(i.XL.BI >> 2);
|
||||||
|
cr = jit_insn_and(f, cr, e.get_uint64(1 << (i.XL.BI & 3)));
|
||||||
|
if (XESELECTBITS(i.XL.BO, 3, 3)) {
|
||||||
|
cond_ok = jit_insn_ne(f, cr, e.get_int64(0));
|
||||||
|
} else {
|
||||||
|
cond_ok = jit_insn_eq(f, cr, e.get_int64(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We do a bit of optimization here to make the llvm assembly easier to read.
|
||||||
|
jit_value_t ok = NULL;
|
||||||
|
if (cond_ok) {
|
||||||
|
ok = cond_ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (XeEmitBranchTo(e, f, "bcctrx", i.address, i.XL.LK, ok)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(bclrx, 0x4C000020, XL )(X64Emitter& e, jit_function_t 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)
|
||||||
|
|
||||||
|
// TODO(benvanik): this may be wrong and overwrite LRs when not desired!
|
||||||
|
// The docs say always, though...
|
||||||
|
if (i.XL.LK) {
|
||||||
|
e.update_lr_value(e.get_uint64(i.address + 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
jit_value_t ctr_ok = NULL;
|
||||||
|
if (XESELECTBITS(i.XL.BO, 2, 2)) {
|
||||||
|
// Ignore ctr.
|
||||||
|
} else {
|
||||||
|
// Decrement counter.
|
||||||
|
jit_value_t ctr = e.ctr_value();
|
||||||
|
ctr = jit_insn_sub(f, ctr, e.get_int64(1));
|
||||||
|
|
||||||
|
// Ctr check.
|
||||||
|
if (XESELECTBITS(i.XL.BO, 1, 1)) {
|
||||||
|
ctr_ok = jit_insn_eq(f, ctr, e.get_int64(0));
|
||||||
|
} else {
|
||||||
|
ctr_ok = jit_insn_ne(f, ctr, e.get_int64(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jit_value_t cond_ok = NULL;
|
||||||
|
if (XESELECTBITS(i.XL.BO, 4, 4)) {
|
||||||
|
// Ignore cond.
|
||||||
|
} else {
|
||||||
|
jit_value_t cr = e.cr_value(i.XL.BI >> 2);
|
||||||
|
cr = jit_insn_and(f, cr, e.get_uint32(1 << (i.XL.BI & 3)));
|
||||||
|
if (XESELECTBITS(i.XL.BO, 3, 3)) {
|
||||||
|
cond_ok = jit_insn_ne(f, cr, e.get_int64(0));
|
||||||
|
} else {
|
||||||
|
cond_ok = jit_insn_eq(f, cr, e.get_int64(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We do a bit of optimization here to make the llvm assembly easier to read.
|
||||||
|
jit_value_t ok = NULL;
|
||||||
|
if (ctr_ok && cond_ok) {
|
||||||
|
ok = jit_insn_and(f, ctr_ok, cond_ok);
|
||||||
|
} else if (ctr_ok) {
|
||||||
|
ok = ctr_ok;
|
||||||
|
} else if (cond_ok) {
|
||||||
|
ok = cond_ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (XeEmitBranchTo(e, f, "bclrx", i.address, i.XL.LK, ok)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Condition register logical (A-23)
|
||||||
|
|
||||||
|
XEEMITTER(crand, 0x4C000202, XL )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(crandc, 0x4C000102, XL )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(creqv, 0x4C000242, XL )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(crnand, 0x4C0001C2, XL )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(crnor, 0x4C000042, XL )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(cror, 0x4C000382, XL )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(crorc, 0x4C000342, XL )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(crxor, 0x4C000182, XL )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(mcrf, 0x4C000000, XL )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// System linkage (A-24)
|
||||||
|
|
||||||
|
XEEMITTER(sc, 0x44000002, SC )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Trap (A-25)
|
||||||
|
|
||||||
|
int XeEmitTrap(X64Emitter& e, jit_function_t f, InstrData& i,
|
||||||
|
jit_value_t va, jit_value_t 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(benvanik): port from LLVM
|
||||||
|
XEASSERTALWAYS();
|
||||||
|
|
||||||
|
// BasicBlock* after_bb = BasicBlock::Create(*e.context(), "", e.fn(),
|
||||||
|
// e.GetNextBasicBlock());
|
||||||
|
// BasicBlock* trap_bb = BasicBlock::Create(*e.context(), "", e.fn(),
|
||||||
|
// after_bb);
|
||||||
|
|
||||||
|
// // Create the basic blocks (so we can chain).
|
||||||
|
// std::vector<BasicBlock*> bbs;
|
||||||
|
// if (TO & (1 << 4)) {
|
||||||
|
// bbs.push_back(BasicBlock::Create(*e.context(), "", e.fn(), trap_bb));
|
||||||
|
// }
|
||||||
|
// if (TO & (1 << 3)) {
|
||||||
|
// bbs.push_back(BasicBlock::Create(*e.context(), "", e.fn(), trap_bb));
|
||||||
|
// }
|
||||||
|
// if (TO & (1 << 2)) {
|
||||||
|
// bbs.push_back(BasicBlock::Create(*e.context(), "", e.fn(), trap_bb));
|
||||||
|
// }
|
||||||
|
// if (TO & (1 << 1)) {
|
||||||
|
// bbs.push_back(BasicBlock::Create(*e.context(), "", e.fn(), trap_bb));
|
||||||
|
// }
|
||||||
|
// if (TO & (1 << 0)) {
|
||||||
|
// bbs.push_back(BasicBlock::Create(*e.context(), "", e.fn(), trap_bb));
|
||||||
|
// }
|
||||||
|
// bbs.push_back(after_bb);
|
||||||
|
|
||||||
|
// // Jump to the first bb.
|
||||||
|
// b.CreateBr(bbs.front());
|
||||||
|
|
||||||
|
// // Setup each basic block.
|
||||||
|
// std::vector<BasicBlock*>::iterator it = bbs.begin();
|
||||||
|
// if (TO & (1 << 4)) {
|
||||||
|
// // a < b
|
||||||
|
// BasicBlock* bb = *(it++);
|
||||||
|
// b.SetInsertPoint(bb);
|
||||||
|
// jit_value_t cmp = b.CreateICmpSLT(va, vb);
|
||||||
|
// b.CreateCondBr(cmp, trap_bb, *it);
|
||||||
|
// }
|
||||||
|
// if (TO & (1 << 3)) {
|
||||||
|
// // a > b
|
||||||
|
// BasicBlock* bb = *(it++);
|
||||||
|
// b.SetInsertPoint(bb);
|
||||||
|
// jit_value_t cmp = b.CreateICmpSGT(va, vb);
|
||||||
|
// b.CreateCondBr(cmp, trap_bb, *it);
|
||||||
|
// }
|
||||||
|
// if (TO & (1 << 2)) {
|
||||||
|
// // a = b
|
||||||
|
// BasicBlock* bb = *(it++);
|
||||||
|
// b.SetInsertPoint(bb);
|
||||||
|
// jit_value_t cmp = b.CreateICmpEQ(va, vb);
|
||||||
|
// b.CreateCondBr(cmp, trap_bb, *it);
|
||||||
|
// }
|
||||||
|
// if (TO & (1 << 1)) {
|
||||||
|
// // a <u b
|
||||||
|
// BasicBlock* bb = *(it++);
|
||||||
|
// b.SetInsertPoint(bb);
|
||||||
|
// jit_value_t cmp = b.CreateICmpULT(va, vb);
|
||||||
|
// b.CreateCondBr(cmp, trap_bb, *it);
|
||||||
|
// }
|
||||||
|
// if (TO & (1 << 0)) {
|
||||||
|
// // a >u b
|
||||||
|
// BasicBlock* bb = *(it++);
|
||||||
|
// b.SetInsertPoint(bb);
|
||||||
|
// jit_value_t cmp = b.CreateICmpUGT(va, vb);
|
||||||
|
// b.CreateCondBr(cmp, trap_bb, *it);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Create trap BB.
|
||||||
|
// b.SetInsertPoint(trap_bb);
|
||||||
|
// e.SpillRegisters();
|
||||||
|
// // TODO(benvanik): use @llvm.debugtrap? could make debugging better
|
||||||
|
// b.CreateCall2(e.gen_module()->getFunction("XeTrap"),
|
||||||
|
// e.fn()->arg_begin(),
|
||||||
|
// e.get_uint64(i.address));
|
||||||
|
// b.CreateBr(after_bb);
|
||||||
|
|
||||||
|
// // Resume.
|
||||||
|
// b.SetInsertPoint(after_bb);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(td, 0x7C000088, X )(X64Emitter& e, jit_function_t 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
|
||||||
|
return XeEmitTrap(e, f, i,
|
||||||
|
e.gpr_value(i.X.RA),
|
||||||
|
e.gpr_value(i.X.RB),
|
||||||
|
i.X.RT);
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(tdi, 0x08000000, D )(X64Emitter& e, jit_function_t 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
|
||||||
|
return XeEmitTrap(e, f, i,
|
||||||
|
e.gpr_value(i.D.RA),
|
||||||
|
e.get_int64(XEEXTS16(i.D.DS)),
|
||||||
|
i.D.RT);
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(tw, 0x7C000008, X )(X64Emitter& e, jit_function_t 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
|
||||||
|
return XeEmitTrap(e, f, i,
|
||||||
|
e.sign_extend(e.trunc_to_int(e.gpr_value(i.X.RA)),
|
||||||
|
jit_type_nint),
|
||||||
|
e.sign_extend(e.trunc_to_int(e.gpr_value(i.X.RB)),
|
||||||
|
jit_type_nint),
|
||||||
|
i.X.RT);
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(twi, 0x0C000000, D )(X64Emitter& e, jit_function_t 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
|
||||||
|
return XeEmitTrap(e, f, i,
|
||||||
|
e.sign_extend(e.trunc_to_int(e.gpr_value(i.D.RA)),
|
||||||
|
jit_type_nint),
|
||||||
|
e.get_int64(XEEXTS16(i.D.DS)),
|
||||||
|
i.D.RT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Processor control (A-26)
|
||||||
|
|
||||||
|
XEEMITTER(mfcr, 0x7C000026, X )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(mfspr, 0x7C0002A6, XFX)(X64Emitter& e, jit_function_t 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)
|
||||||
|
|
||||||
|
const uint32_t n = ((i.XFX.spr & 0x1F) << 5) | ((i.XFX.spr >> 5) & 0x1F);
|
||||||
|
jit_value_t v = NULL;
|
||||||
|
switch (n) {
|
||||||
|
case 1:
|
||||||
|
// XER
|
||||||
|
v = e.xer_value();
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
// LR
|
||||||
|
v = e.lr_value();
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
// CTR
|
||||||
|
v = e.ctr_value();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.update_gpr_value(i.XFX.RT, v);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(mftb, 0x7C0002E6, XFX)(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(mtcrf, 0x7C000120, XFX)(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(mtspr, 0x7C0003A6, XFX)(X64Emitter& e, jit_function_t 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]
|
||||||
|
|
||||||
|
jit_value_t v = e.gpr_value(i.XFX.RT);
|
||||||
|
|
||||||
|
const uint32_t n = ((i.XFX.spr & 0x1F) << 5) | ((i.XFX.spr >> 5) & 0x1F);
|
||||||
|
switch (n) {
|
||||||
|
case 1:
|
||||||
|
// XER
|
||||||
|
e.update_xer_value(v);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
// LR
|
||||||
|
e.update_lr_value(v);
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
// CTR
|
||||||
|
e.update_ctr_value(v);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void X64RegisterEmitCategoryControl() {
|
||||||
|
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 x64
|
||||||
|
} // namespace cpu
|
||||||
|
} // namespace xe
|
|
@ -0,0 +1,295 @@
|
||||||
|
/*
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <xenia/cpu/x64/x64_emit.h>
|
||||||
|
|
||||||
|
#include <xenia/cpu/cpu-private.h>
|
||||||
|
|
||||||
|
|
||||||
|
using namespace xe::cpu;
|
||||||
|
using namespace xe::cpu::ppc;
|
||||||
|
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace cpu {
|
||||||
|
namespace x64 {
|
||||||
|
|
||||||
|
|
||||||
|
// Floating-point arithmetic (A-8)
|
||||||
|
|
||||||
|
XEEMITTER(faddx, 0xFC00002A, A )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(faddsx, 0xEC00002A, A )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(fdivx, 0xFC000024, A )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(fdivsx, 0xEC000024, A )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(fmulx, 0xFC000032, A )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(fmulsx, 0xEC000032, A )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(fresx, 0xEC000030, A )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(frsqrtex, 0xFC000034, A )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(fsubx, 0xFC000028, A )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(fsubsx, 0xEC000028, A )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(fselx, 0xFC00002E, A )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(fsqrtx, 0xFC00002C, A )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(fsqrtsx, 0xEC00002C, A )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Floating-point multiply-add (A-9)
|
||||||
|
|
||||||
|
XEEMITTER(fmaddx, 0xFC00003A, A )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(fmaddsx, 0xEC00003A, A )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(fmsubx, 0xFC000038, A )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(fmsubsx, 0xEC000038, A )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(fnmaddx, 0xFC00003E, A )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(fnmaddsx, 0xEC00003E, A )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(fnmsubx, 0xFC00003C, A )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(fnmsubsx, 0xEC00003C, A )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Floating-point rounding and conversion (A-10)
|
||||||
|
|
||||||
|
XEEMITTER(fcfidx, 0xFC00069C, X )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(fctidx, 0xFC00065C, X )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(fctidzx, 0xFC00065E, X )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(fctiwx, 0xFC00001C, X )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(fctiwzx, 0xFC00001E, X )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(frspx, 0xFC000018, X )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Floating-point compare (A-11)
|
||||||
|
|
||||||
|
XEEMITTER(fcmpo, 0xFC000040, X )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(fcmpu, 0xFC000000, X )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
// 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
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Floating-point status and control register (A
|
||||||
|
|
||||||
|
XEEMITTER(mcrfs, 0xFC000080, X )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(mffsx, 0xFC00048E, X )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(mtfsb0x, 0xFC00008C, X )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(mtfsb1x, 0xFC00004C, X )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(mtfsfx, 0xFC00058E, XFL)(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(mtfsfix, 0xFC00010C, X )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Floating-point move (A-21)
|
||||||
|
|
||||||
|
XEEMITTER(fabsx, 0xFC000210, X )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(fmrx, 0xFC000090, X )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(fnabsx, 0xFC000110, X )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEEMITTER(fnegx, 0xFC000050, X )(X64Emitter& e, jit_function_t f, InstrData& i) {
|
||||||
|
XEINSTRNOTIMPLEMENTED();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void X64RegisterEmitCategoryFPU() {
|
||||||
|
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 x64
|
||||||
|
} // namespace cpu
|
||||||
|
} // namespace xe
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,154 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef XENIA_CPU_X64_X64_EMITTER_H_
|
||||||
|
#define XENIA_CPU_X64_X64_EMITTER_H_
|
||||||
|
|
||||||
|
#include <xenia/cpu/global_exports.h>
|
||||||
|
#include <xenia/cpu/sdb.h>
|
||||||
|
#include <xenia/cpu/ppc/instr.h>
|
||||||
|
|
||||||
|
#include <asmjit/asmjit.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace cpu {
|
||||||
|
namespace x64 {
|
||||||
|
|
||||||
|
|
||||||
|
class X64Emitter {
|
||||||
|
public:
|
||||||
|
X64Emitter(xe_memory_ref memory, jit_context_t context);
|
||||||
|
~X64Emitter();
|
||||||
|
|
||||||
|
jit_context_t context();
|
||||||
|
|
||||||
|
int PrepareFunction(sdb::FunctionSymbol* symbol);
|
||||||
|
int MakeFunction(sdb::FunctionSymbol* symbol, jit_function_t fn);
|
||||||
|
|
||||||
|
sdb::FunctionSymbol* symbol();
|
||||||
|
jit_function_t fn();
|
||||||
|
sdb::FunctionBlock* fn_block();
|
||||||
|
|
||||||
|
jit_value_t get_int32(int32_t value);
|
||||||
|
jit_value_t get_uint32(uint32_t value);
|
||||||
|
jit_value_t get_int64(int64_t value);
|
||||||
|
jit_value_t get_uint64(uint64_t value);
|
||||||
|
jit_value_t make_signed(jit_value_t value);
|
||||||
|
jit_value_t make_unsigned(jit_value_t value);
|
||||||
|
jit_value_t sign_extend(jit_value_t value, jit_type_t target_type);
|
||||||
|
jit_value_t zero_extend(jit_value_t value, jit_type_t target_type);
|
||||||
|
jit_value_t trunc_to_sbyte(jit_value_t value);
|
||||||
|
jit_value_t trunc_to_ubyte(jit_value_t value);
|
||||||
|
jit_value_t trunc_to_short(jit_value_t value);
|
||||||
|
jit_value_t trunc_to_int(jit_value_t value);
|
||||||
|
|
||||||
|
int branch_to_block(uint32_t address);
|
||||||
|
int branch_to_block_if(uint32_t address, jit_value_t value);
|
||||||
|
int branch_to_block_if_not(uint32_t address, jit_value_t value);
|
||||||
|
int branch_to_return();
|
||||||
|
int branch_to_return_if(jit_value_t value);
|
||||||
|
int branch_to_return_if_not(jit_value_t value);
|
||||||
|
int call_function(sdb::FunctionSymbol* target_symbol, jit_value_t lr,
|
||||||
|
bool tail);
|
||||||
|
|
||||||
|
void TraceBranch(uint32_t cia);
|
||||||
|
int GenerateIndirectionBranch(uint32_t cia, jit_value_t target,
|
||||||
|
bool lk, bool likely_local);
|
||||||
|
|
||||||
|
jit_value_t LoadStateValue(size_t offset, jit_type_t type,
|
||||||
|
const char* name = "");
|
||||||
|
void StoreStateValue(size_t offset, jit_type_t type, jit_value_t value);
|
||||||
|
|
||||||
|
jit_value_t SetupLocal(jit_type_t type, const char* name);
|
||||||
|
void FillRegisters();
|
||||||
|
void SpillRegisters();
|
||||||
|
|
||||||
|
jit_value_t xer_value();
|
||||||
|
void update_xer_value(jit_value_t value);
|
||||||
|
void update_xer_with_overflow(jit_value_t value);
|
||||||
|
void update_xer_with_carry(jit_value_t value);
|
||||||
|
void update_xer_with_overflow_and_carry(jit_value_t value);
|
||||||
|
|
||||||
|
jit_value_t lr_value();
|
||||||
|
void update_lr_value(jit_value_t value);
|
||||||
|
|
||||||
|
jit_value_t ctr_value();
|
||||||
|
void update_ctr_value(jit_value_t value);
|
||||||
|
|
||||||
|
jit_value_t cr_value(uint32_t n);
|
||||||
|
void update_cr_value(uint32_t n, jit_value_t value);
|
||||||
|
void update_cr_with_cond(uint32_t n, jit_value_t lhs, jit_value_t rhs,
|
||||||
|
bool is_signed);
|
||||||
|
|
||||||
|
jit_value_t gpr_value(uint32_t n);
|
||||||
|
void update_gpr_value(uint32_t n, jit_value_t value);
|
||||||
|
jit_value_t fpr_value(uint32_t n);
|
||||||
|
void update_fpr_value(uint32_t n, jit_value_t value);
|
||||||
|
|
||||||
|
jit_value_t TouchMemoryAddress(uint32_t cia, jit_value_t addr);
|
||||||
|
jit_value_t ReadMemory(
|
||||||
|
uint32_t cia, jit_value_t addr, uint32_t size, bool acquire = false);
|
||||||
|
void WriteMemory(
|
||||||
|
uint32_t cia, jit_value_t addr, uint32_t size, jit_value_t value,
|
||||||
|
bool release = false);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int MakeUserFunction();
|
||||||
|
int MakePresentImportFunction();
|
||||||
|
int MakeMissingImportFunction();
|
||||||
|
|
||||||
|
void GenerateBasicBlocks();
|
||||||
|
void GenerateSharedBlocks();
|
||||||
|
int PrepareBasicBlock(sdb::FunctionBlock* block);
|
||||||
|
void GenerateBasicBlock(sdb::FunctionBlock* block);
|
||||||
|
void SetupLocals();
|
||||||
|
|
||||||
|
xe_memory_ref memory_;
|
||||||
|
jit_context_t context_;
|
||||||
|
jit_type_t fn_signature_;
|
||||||
|
jit_type_t shim_signature_;
|
||||||
|
GlobalExports global_exports_;
|
||||||
|
jit_type_t global_export_signature_2_;
|
||||||
|
jit_type_t global_export_signature_3_;
|
||||||
|
jit_type_t global_export_signature_4_;
|
||||||
|
|
||||||
|
sdb::FunctionSymbol* symbol_;
|
||||||
|
jit_function_t fn_;
|
||||||
|
sdb::FunctionBlock* fn_block_;
|
||||||
|
jit_label_t return_block_;
|
||||||
|
jit_label_t internal_indirection_block_;
|
||||||
|
jit_label_t external_indirection_block_;
|
||||||
|
|
||||||
|
std::map<uint32_t, jit_label_t> bbs_;
|
||||||
|
|
||||||
|
// Address of the instruction being generated.
|
||||||
|
uint32_t cia_;
|
||||||
|
|
||||||
|
ppc::InstrAccessBits access_bits_;
|
||||||
|
struct {
|
||||||
|
jit_value_t indirection_target;
|
||||||
|
jit_value_t indirection_cia;
|
||||||
|
|
||||||
|
jit_value_t xer;
|
||||||
|
jit_value_t lr;
|
||||||
|
jit_value_t ctr;
|
||||||
|
jit_value_t cr[8];
|
||||||
|
jit_value_t gpr[32];
|
||||||
|
jit_value_t fpr[32];
|
||||||
|
} locals_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace x64
|
||||||
|
} // namespace cpu
|
||||||
|
} // namespace xe
|
||||||
|
|
||||||
|
|
||||||
|
#endif // XENIA_CPU_X64_X64_EMITTER_H_
|
|
@ -0,0 +1,93 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <xenia/cpu/x64/x64_jit.h>
|
||||||
|
|
||||||
|
#include <xenia/cpu/cpu-private.h>
|
||||||
|
#include <xenia/cpu/exec_module.h>
|
||||||
|
#include <xenia/cpu/sdb.h>
|
||||||
|
|
||||||
|
|
||||||
|
using namespace xe;
|
||||||
|
using namespace xe::cpu;
|
||||||
|
using namespace xe::cpu::sdb;
|
||||||
|
using namespace xe::cpu::x64;
|
||||||
|
|
||||||
|
|
||||||
|
X64JIT::X64JIT(xe_memory_ref memory, SymbolTable* sym_table) :
|
||||||
|
JIT(memory, sym_table),
|
||||||
|
context_(NULL), emitter_(NULL) {
|
||||||
|
}
|
||||||
|
|
||||||
|
X64JIT::~X64JIT() {
|
||||||
|
delete emitter_;
|
||||||
|
if (context_) {
|
||||||
|
jit_context_destroy(context_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int X64JIT::Setup() {
|
||||||
|
int result_code = 1;
|
||||||
|
|
||||||
|
// Shared libjit context.
|
||||||
|
context_ = jit_context_create();
|
||||||
|
XEEXPECTNOTNULL(context_);
|
||||||
|
|
||||||
|
// Create the emitter used to generate functions.
|
||||||
|
emitter_ = new X64Emitter(memory_, context_);
|
||||||
|
|
||||||
|
// Inject global functions/variables/etc.
|
||||||
|
XEEXPECTZERO(InjectGlobals());
|
||||||
|
|
||||||
|
result_code = 0;
|
||||||
|
XECLEANUP:
|
||||||
|
return result_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
int X64JIT::InjectGlobals() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int X64JIT::InitModule(ExecModule* module) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int X64JIT::UninitModule(ExecModule* module) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int X64JIT::Execute(xe_ppc_state_t* ppc_state, FunctionSymbol* fn_symbol) {
|
||||||
|
XELOGCPU("Execute(%.8X): %s...", fn_symbol->start_address, fn_symbol->name());
|
||||||
|
|
||||||
|
// Check function.
|
||||||
|
jit_function_t jit_fn = (jit_function_t)fn_symbol->impl_value;
|
||||||
|
if (!jit_fn) {
|
||||||
|
// Function hasn't been prepped yet - prep it.
|
||||||
|
if (emitter_->PrepareFunction(fn_symbol)) {
|
||||||
|
XELOGCPU("Execute(%.8X): unable to make function %s",
|
||||||
|
fn_symbol->start_address, fn_symbol->name());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
jit_fn = (jit_function_t)fn_symbol->impl_value;
|
||||||
|
XEASSERTNOTNULL(jit_fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call into the function. This will compile it if needed.
|
||||||
|
jit_nuint lr = ppc_state->lr;
|
||||||
|
void* args[] = {&ppc_state, &lr};
|
||||||
|
uint64_t return_value;
|
||||||
|
int apply_result = jit_function_apply(jit_fn, (void**)&args, &return_value);
|
||||||
|
if (!apply_result) {
|
||||||
|
XELOGCPU("Execute(%.8X): apply failed with %d",
|
||||||
|
fn_symbol->start_address, apply_result);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef XENIA_CPU_X64_X64_JIT_H_
|
||||||
|
#define XENIA_CPU_X64_X64_JIT_H_
|
||||||
|
|
||||||
|
#include <xenia/core.h>
|
||||||
|
|
||||||
|
#include <xenia/cpu/jit.h>
|
||||||
|
#include <xenia/cpu/ppc.h>
|
||||||
|
#include <xenia/cpu/sdb.h>
|
||||||
|
#include <xenia/cpu/x64/x64_emitter.h>
|
||||||
|
|
||||||
|
#include <jit/jit.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace cpu {
|
||||||
|
namespace x64 {
|
||||||
|
|
||||||
|
|
||||||
|
class X64JIT : public JIT {
|
||||||
|
public:
|
||||||
|
X64JIT(xe_memory_ref memory, sdb::SymbolTable* sym_table);
|
||||||
|
virtual ~X64JIT();
|
||||||
|
|
||||||
|
virtual int Setup();
|
||||||
|
|
||||||
|
virtual int InitModule(ExecModule* module);
|
||||||
|
virtual int UninitModule(ExecModule* module);
|
||||||
|
|
||||||
|
virtual int Execute(xe_ppc_state_t* ppc_state,
|
||||||
|
sdb::FunctionSymbol* fn_symbol);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int InjectGlobals();
|
||||||
|
|
||||||
|
jit_context_t context_;
|
||||||
|
X64Emitter* emitter_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace x64
|
||||||
|
} // namespace cpu
|
||||||
|
} // namespace xe
|
||||||
|
|
||||||
|
|
||||||
|
#endif // XENIA_CPU_X64_X64_JIT_H_
|
|
@ -46,7 +46,7 @@ int Run::Setup() {
|
||||||
xe_zero_struct(&pal_options, sizeof(pal_options));
|
xe_zero_struct(&pal_options, sizeof(pal_options));
|
||||||
XEEXPECTZERO(xe_pal_init(pal_options));
|
XEEXPECTZERO(xe_pal_init(pal_options));
|
||||||
|
|
||||||
//backend_ = shared_ptr<Backend>(new xe::cpu::libjit::LibjitBackend());
|
backend_ = shared_ptr<Backend>(new xe::cpu::x64::X64Backend());
|
||||||
|
|
||||||
debugger_ = shared_ptr<Debugger>(new Debugger());
|
debugger_ = shared_ptr<Debugger>(new Debugger());
|
||||||
|
|
||||||
|
|
|
@ -120,7 +120,7 @@ int run_test(string& src_file_path) {
|
||||||
memory = xe_memory_create(memory_options);
|
memory = xe_memory_create(memory_options);
|
||||||
XEEXPECTNOTNULL(memory);
|
XEEXPECTNOTNULL(memory);
|
||||||
|
|
||||||
backend_ = shared_ptr<Backend>(new xe::cpu::libjit::LibjitBackend());
|
backend_ = shared_ptr<Backend>(new xe::cpu::x64::X64Backend());
|
||||||
|
|
||||||
processor = shared_ptr<Processor>(new Processor(memory, backend));
|
processor = shared_ptr<Processor>(new Processor(memory, backend));
|
||||||
XEEXPECTZERO(processor->Setup());
|
XEEXPECTZERO(processor->Setup());
|
||||||
|
|
Loading…
Reference in New Issue