Initial libjit skeleton.

Not currently generating instructions, but most of the flow is right up to
that point. A lot of work required to refactor the emitter, but wanted to
get this checked in.
This commit is contained in:
Ben Vanik 2013-05-21 15:36:58 -07:00
parent 94e3e592dd
commit 85804f7415
44 changed files with 5272 additions and 274 deletions

View File

@ -31,25 +31,19 @@ Install both and add Python to your PATH (`C:\Python27\`).
Depending on your Visual Studio version you'll need to use one of the provided Depending on your Visual Studio version you'll need to use one of the provided
command prompts (until I write my own) to perform all `xenia-build` tasks. command prompts (until I write my own) to perform all `xenia-build` tasks.
#### Visual Studio 2010
The build has been most tested with 2010.
Use the `Visual Studio 2010 x64 Command Prompt` as your shell.
* Visual Studio 2010 (not sure Express will work)
* [Visual Studio 2010 SP1](http://msdn.microsoft.com/en-us/vstudio/aa718359)
* [Windows SDK](http://www.microsoft.com/download/en/details.aspx?id=8279)
* [DirectX SDK](http://msdn.microsoft.com/en-us/directx/)
#### Visual Studio 2012 (Express) #### Visual Studio 2012 (Express)
Basic testing has been done with 2012 Express (all I have access to). Since it's Basic testing has been done with 2012 Express (all I have access to).
newer and shinier, I may end up deprecating the 2010 support.
Use the `VS2012 x64 Cross Tools Command Prompt` as your shell. Use the `VS2012 x64 Cross Tools Command Prompt` as your shell.
* [Windows 8 SDK](http://msdn.microsoft.com/en-us/windows/desktop/aa904949.aspx) * [Windows 8 SDK](http://msdn.microsoft.com/en-us/windows/desktop/aa904949.aspx)
* [Visual Studio 2012 Express for Desktop](http://go.microsoft.com/?linkid=9816758) * [Visual Studio 2012 Express for Desktop](http://go.microsoft.com/?linkid=9816758)
VS2012 behaves oddly with the debug paths. Open the xenia-run project properties
and set the 'Command' to `$(ProjectDir)$(OutputPath)$(TargetFileName)` and the
'Working Directory' to `$(SolutionDir)..\..`. You can specify flags and
the file to run in the 'Command Arguments' field.
## xenia-build ## xenia-build
A simple build script is included to manage basic tasks such as building A simple build script is included to manage basic tasks such as building

View File

@ -19,22 +19,21 @@ namespace xe {
namespace cpu { namespace cpu {
class CodeUnitBuilder;
class FunctionTable;
class JIT; class JIT;
class LibraryLinker;
class LibraryLoader; class LibraryLoader;
namespace sdb {
class SymbolTable;
} // namespace sdb
class Backend { class Backend {
public: public:
virtual ~Backend() {} virtual ~Backend() {}
virtual CodeUnitBuilder* CreateCodeUnitBuilder() = 0;
virtual LibraryLinker* CreateLibraryLinker() = 0;
virtual LibraryLoader* CreateLibraryLoader() = 0; virtual LibraryLoader* CreateLibraryLoader() = 0;
virtual JIT* CreateJIT(xe_memory_ref memory, FunctionTable* fn_table) = 0; virtual JIT* CreateJIT(xe_memory_ref memory, sdb::SymbolTable* sym_table) = 0;
protected: protected:
Backend() {} Backend() {}

View File

@ -1,51 +0,0 @@
/**
******************************************************************************
* 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_CODE_UNIT_BUILDER_H_
#define XENIA_CPU_CODE_UNIT_BUILDER_H_
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/core/memory.h>
#include <xenia/cpu/sdb.h>
#include <xenia/kernel/export.h>
namespace xe {
namespace cpu {
class CodeUnitBuilder {
public:
virtual ~CodeUnitBuilder() {
xe_memory_release(memory_);
}
virtual int Init(const char* module_name, const char* module_path) = 0;
virtual int MakeFunction(sdb::FunctionSymbol* symbol) = 0;
virtual int Finalize() = 0;
virtual void Reset() = 0;
// TODO(benvanik): write to file/etc
protected:
CodeUnitBuilder(xe_memory_ref memory) {
memory_ = xe_memory_retain(memory);
}
xe_memory_ref memory_;
};
} // namespace cpu
} // namespace xe
#endif // XENIA_CPU_CODE_UNIT_BUILDER_H_

View File

@ -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/llvmbe/llvm_backend.h> #include <xenia/cpu/libjit/libjit_backend.h>
#endif // XENIA_CPU_CPU_H_ #endif // XENIA_CPU_CPU_H_

View File

@ -21,11 +21,11 @@ using namespace xe::kernel;
ExecModule::ExecModule( ExecModule::ExecModule(
xe_memory_ref memory, shared_ptr<ExportResolver> export_resolver, xe_memory_ref memory, shared_ptr<ExportResolver> export_resolver,
FunctionTable* fn_table, SymbolTable* sym_table,
const char* module_name, const char* module_path) { const char* module_name, const char* module_path) {
memory_ = xe_memory_retain(memory); memory_ = xe_memory_retain(memory);
export_resolver_ = export_resolver; export_resolver_ = export_resolver;
fn_table_ = fn_table; sym_table_ = sym_table;
module_name_ = xestrdupa(module_name); module_name_ = xestrdupa(module_name);
module_path_ = xestrdupa(module_path); module_path_ = xestrdupa(module_path);
} }
@ -43,7 +43,7 @@ SymbolDatabase* ExecModule::sdb() {
int ExecModule::PrepareRawBinary(uint32_t start_address, uint32_t end_address) { int ExecModule::PrepareRawBinary(uint32_t start_address, uint32_t end_address) {
sdb_ = shared_ptr<sdb::SymbolDatabase>( sdb_ = shared_ptr<sdb::SymbolDatabase>(
new sdb::RawSymbolDatabase(memory_, export_resolver_.get(), new sdb::RawSymbolDatabase(memory_, export_resolver_.get(),
start_address, end_address)); sym_table_, start_address, end_address));
code_addr_low_ = start_address; code_addr_low_ = start_address;
code_addr_high_ = end_address; code_addr_high_ = end_address;
@ -53,7 +53,8 @@ int ExecModule::PrepareRawBinary(uint32_t start_address, uint32_t end_address) {
int ExecModule::PrepareXexModule(xe_xex2_ref xex) { int ExecModule::PrepareXexModule(xe_xex2_ref xex) {
sdb_ = shared_ptr<sdb::SymbolDatabase>( sdb_ = shared_ptr<sdb::SymbolDatabase>(
new sdb::XexSymbolDatabase(memory_, export_resolver_.get(), xex)); new sdb::XexSymbolDatabase(memory_, export_resolver_.get(),
sym_table_, xex));
code_addr_low_ = 0; code_addr_low_ = 0;
code_addr_high_ = 0; code_addr_high_ = 0;
@ -65,8 +66,8 @@ int ExecModule::PrepareXexModule(xe_xex2_ref xex) {
const size_t end_address = const size_t end_address =
start_address + (section->info.page_count * xe_xex2_section_length); start_address + (section->info.page_count * xe_xex2_section_length);
if (section->info.type == XEX_SECTION_CODE) { if (section->info.type == XEX_SECTION_CODE) {
code_addr_low_ = MIN(code_addr_low_, start_address); code_addr_low_ = (uint32_t)MIN(code_addr_low_, start_address);
code_addr_high_ = MAX(code_addr_high_, end_address); code_addr_high_ = (uint32_t)MAX(code_addr_high_, end_address);
} }
i += section->info.page_count; i += section->info.page_count;
} }

View File

@ -13,7 +13,6 @@
#include <xenia/common.h> #include <xenia/common.h>
#include <xenia/core.h> #include <xenia/core.h>
#include <xenia/cpu/function_table.h>
#include <xenia/cpu/sdb.h> #include <xenia/cpu/sdb.h>
#include <xenia/kernel/export.h> #include <xenia/kernel/export.h>
#include <xenia/kernel/xex2.h> #include <xenia/kernel/xex2.h>
@ -27,7 +26,7 @@ class ExecModule {
public: public:
ExecModule( ExecModule(
xe_memory_ref memory, shared_ptr<kernel::ExportResolver> export_resolver, xe_memory_ref memory, shared_ptr<kernel::ExportResolver> export_resolver,
FunctionTable* fn_table, sdb::SymbolTable* sym_table,
const char* module_name, const char* module_path); const char* module_name, const char* module_path);
~ExecModule(); ~ExecModule();
@ -46,7 +45,7 @@ private:
xe_memory_ref memory_; xe_memory_ref memory_;
shared_ptr<kernel::ExportResolver> export_resolver_; shared_ptr<kernel::ExportResolver> export_resolver_;
FunctionTable* fn_table_; sdb::SymbolTable* sym_table_;
char* module_name_; char* module_name_;
char* module_path_; char* module_path_;

View File

@ -24,18 +24,24 @@ using namespace xe::kernel;
namespace { namespace {
void XeTrap(xe_ppc_state_t* state, uint32_t cia) { void _cdecl XeTrap(
xe_ppc_state_t* state, uint64_t cia, uint64_t unused1,
void* unused2) {
XELOGE("TRAP"); XELOGE("TRAP");
XEASSERTALWAYS(); XEASSERTALWAYS();
} }
void XeIndirectBranch(xe_ppc_state_t* state, uint64_t target, uint64_t br_ia) { void _cdecl XeIndirectBranch(
xe_ppc_state_t* state, uint64_t target, uint64_t br_ia,
void* unused) {
XELOGCPU("INDIRECT BRANCH %.8X -> %.8X", XELOGCPU("INDIRECT BRANCH %.8X -> %.8X",
(uint32_t)br_ia, (uint32_t)target); (uint32_t)br_ia, (uint32_t)target);
XEASSERTALWAYS(); XEASSERTALWAYS();
} }
void XeInvalidInstruction(xe_ppc_state_t* state, uint32_t cia, uint32_t data) { void _cdecl XeInvalidInstruction(
xe_ppc_state_t* state, uint64_t cia, uint64_t data,
void* unused) {
ppc::InstrData i; ppc::InstrData i;
i.address = cia; i.address = cia;
i.code = data; i.code = data;
@ -57,26 +63,32 @@ void XeInvalidInstruction(xe_ppc_state_t* state, uint32_t cia, uint32_t data) {
} }
} }
void XeAccessViolation(xe_ppc_state_t* state, uint32_t cia, uint64_t ea) { void _cdecl XeAccessViolation(
xe_ppc_state_t* state, uint64_t cia, uint64_t ea,
void* unused) {
XELOGE("INVALID ACCESS %.8X: tried to touch %.8X", XELOGE("INVALID ACCESS %.8X: tried to touch %.8X",
cia, (uint32_t)ea); cia, (uint32_t)ea);
XEASSERTALWAYS(); XEASSERTALWAYS();
} }
void XeTraceKernelCall(xe_ppc_state_t* state, uint64_t cia, uint64_t call_ia, void _cdecl XeTraceKernelCall(
KernelExport* kernel_export) { xe_ppc_state_t* state, uint64_t cia, uint64_t call_ia,
KernelExport* kernel_export) {
XELOGCPU("TRACE: %.8X -> k.%.8X (%s)", XELOGCPU("TRACE: %.8X -> k.%.8X (%s)",
(uint32_t)call_ia - 4, (uint32_t)cia, (uint32_t)call_ia - 4, (uint32_t)cia,
kernel_export ? kernel_export->name : "unknown"); kernel_export ? kernel_export->name : "unknown");
} }
void XeTraceUserCall(xe_ppc_state_t* state, uint64_t cia, uint64_t call_ia, void _cdecl XeTraceUserCall(
FunctionSymbol* fn) { xe_ppc_state_t* state, uint64_t cia, uint64_t call_ia,
FunctionSymbol* fn) {
XELOGCPU("TRACE: %.8X -> u.%.8X (%s)", XELOGCPU("TRACE: %.8X -> u.%.8X (%s)",
(uint32_t)call_ia - 4, (uint32_t)cia, fn->name()); (uint32_t)call_ia - 4, (uint32_t)cia, fn->name());
} }
void XeTraceInstruction(xe_ppc_state_t* state, uint32_t cia, uint32_t data) { void _cdecl XeTraceInstruction(
xe_ppc_state_t* state, uint64_t cia, uint64_t data,
void* unused) {
ppc::InstrType* type = ppc::GetInstrType(data); ppc::InstrType* type = ppc::GetInstrType(data);
XELOGCPU("TRACE: %.8X %.8X %s %s", XELOGCPU("TRACE: %.8X %.8X %s %s",
cia, data, cia, data,

View File

@ -23,22 +23,22 @@ namespace cpu {
typedef struct { typedef struct {
void (*XeTrap)( void (_cdecl *XeTrap)(
xe_ppc_state_t* state, uint32_t cia); xe_ppc_state_t* state, uint64_t cia, uint64_t unused1, void* unused2);
void (*XeIndirectBranch)( void (_cdecl *XeIndirectBranch)(
xe_ppc_state_t* state, uint64_t target, uint64_t br_ia); xe_ppc_state_t* state, uint64_t target, uint64_t br_ia, void* unused);
void (*XeInvalidInstruction)( void (_cdecl *XeInvalidInstruction)(
xe_ppc_state_t* state, uint32_t cia, uint32_t data); xe_ppc_state_t* state, uint64_t cia, uint64_t data, void* unused);
void (*XeAccessViolation)( void (_cdecl *XeAccessViolation)(
xe_ppc_state_t* state, uint32_t cia, uint64_t ea); xe_ppc_state_t* state, uint64_t cia, uint64_t ea, void* unused);
void (*XeTraceKernelCall)( void (_cdecl *XeTraceKernelCall)(
xe_ppc_state_t* state, uint64_t cia, uint64_t call_ia, xe_ppc_state_t* state, uint64_t cia, uint64_t call_ia,
kernel::KernelExport* kernel_export); kernel::KernelExport* kernel_export);
void (*XeTraceUserCall)( void (_cdecl *XeTraceUserCall)(
xe_ppc_state_t* state, uint64_t cia, uint64_t call_ia, xe_ppc_state_t* state, uint64_t cia, uint64_t call_ia,
sdb::FunctionSymbol* fn); sdb::FunctionSymbol* fn);
void (*XeTraceInstruction)( void (_cdecl *XeTraceInstruction)(
xe_ppc_state_t* state, uint32_t cia, uint32_t data); xe_ppc_state_t* state, uint64_t cia, uint64_t data, void* unused);
} GlobalExports; } GlobalExports;

View File

@ -12,7 +12,6 @@
#include <xenia/core.h> #include <xenia/core.h>
#include <xenia/cpu/function_table.h>
#include <xenia/cpu/ppc.h> #include <xenia/cpu/ppc.h>
#include <xenia/cpu/sdb.h> #include <xenia/cpu/sdb.h>
@ -35,16 +34,17 @@ public:
virtual int InitModule(ExecModule* module) = 0; virtual int InitModule(ExecModule* module) = 0;
virtual int UninitModule(ExecModule* module) = 0; virtual int UninitModule(ExecModule* module) = 0;
virtual FunctionPointer GenerateFunction(sdb::FunctionSymbol* symbol) = 0; virtual int Execute(xe_ppc_state_t* ppc_state,
sdb::FunctionSymbol* fn_symbol) = 0;
protected: protected:
JIT(xe_memory_ref memory, FunctionTable* fn_table) { JIT(xe_memory_ref memory, sdb::SymbolTable* sym_table) {
memory_ = xe_memory_retain(memory); memory_ = xe_memory_retain(memory);
fn_table_ = fn_table; sym_table_ = sym_table;
} }
xe_memory_ref memory_; xe_memory_ref memory_;
FunctionTable* fn_table_; sdb::SymbolTable* sym_table_;
}; };

View File

@ -0,0 +1,61 @@
/**
******************************************************************************
* 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/libjit/libjit_backend.h>
#include <xenia/cpu/libjit/libjit_emit.h>
#include <xenia/cpu/libjit/libjit_jit.h>
#include <xenia/cpu/sdb/symbol_table.h>
using namespace xe;
using namespace xe::cpu;
using namespace xe::cpu::libjit;
using namespace xe::cpu::sdb;
namespace {
void InitializeIfNeeded();
void CleanupOnShutdown();
void InitializeIfNeeded() {
static bool has_initialized = false;
if (has_initialized) {
return;
}
has_initialized = true;
libjit::LibjitRegisterEmitCategoryALU();
libjit::LibjitRegisterEmitCategoryControl();
libjit::LibjitRegisterEmitCategoryFPU();
libjit::LibjitRegisterEmitCategoryMemory();
atexit(CleanupOnShutdown);
}
void CleanupOnShutdown() {
}
}
LibjitBackend::LibjitBackend() :
Backend() {
InitializeIfNeeded();
}
LibjitBackend::~LibjitBackend() {
}
LibraryLoader* LibjitBackend::CreateLibraryLoader() {
return NULL;
}
JIT* LibjitBackend::CreateJIT(xe_memory_ref memory, SymbolTable* sym_table) {
return new LibjitJIT(memory, sym_table);
}

View File

@ -0,0 +1,41 @@
/**
******************************************************************************
* 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_LIBJIT_LIBJIT_BACKEND_H_
#define XENIA_CPU_LIBJIT_LIBJIT_BACKEND_H_
#include <xenia/common.h>
#include <xenia/cpu/backend.h>
namespace xe {
namespace cpu {
namespace libjit {
class LibjitBackend : public Backend {
public:
LibjitBackend();
virtual ~LibjitBackend();
virtual LibraryLoader* CreateLibraryLoader();
virtual JIT* CreateJIT(xe_memory_ref memory, sdb::SymbolTable* sym_table);
protected:
};
} // namespace libjit
} // namespace cpu
} // namespace xe
#endif // XENIA_CPU_LIBJIT_LIBJIT_BACKEND_H_

View 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 XENIA_CPU_LIBJIT_LIBJIT_EMIT_H_
#define XENIA_CPU_LIBJIT_LIBJIT_EMIT_H_
#include <xenia/cpu/libjit/libjit_emitter.h>
#include <xenia/cpu/ppc/instr.h>
#include <xenia/cpu/ppc/state.h>
namespace xe {
namespace cpu {
namespace libjit {
void LibjitRegisterEmitCategoryALU();
void LibjitRegisterEmitCategoryControl();
void LibjitRegisterEmitCategoryFPU();
void LibjitRegisterEmitCategoryMemory();
#define XEEMITTER(name, opcode, format) int InstrEmit_##name
#define XEREGISTERINSTR(name, opcode) \
RegisterInstrEmit(opcode, (InstrEmitFn)InstrEmit_##name);
#define XEINSTRNOTIMPLEMENTED()
//#define XEINSTRNOTIMPLEMENTED XEASSERTALWAYS
} // namespace libjit
} // namespace cpu
} // namespace xe
#endif // XENIA_CPU_LIBJIT_LIBJIT_EMIT_H_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,709 @@
/*
******************************************************************************
* 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/libjit/libjit_emit.h>
using namespace xe::cpu;
using namespace xe::cpu::ppc;
using namespace xe::cpu::sdb;
namespace xe {
namespace cpu {
namespace libjit {
// int XeEmitIndirectBranchTo(
// LibjitEmitter& 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.
// Value* 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) {
// BasicBlock* next_block = e.GetNextBasicBlock();
// BasicBlock* mismatch_bb = BasicBlock::Create(*e.context(), "lr_mismatch",
// e.gen_fn(), next_block);
// Value* lr_cmp = b.CreateICmpEQ(target, ++(e.gen_fn()->arg_begin()));
// // The return block will spill registers for us.
// b.CreateCondBr(lr_cmp, e.GetReturnBasicBlock(), mismatch_bb);
// b.SetInsertPoint(mismatch_bb);
// }
// // 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(
// LibjitEmitter& e, jit_function_t f, const char* src, uint32_t cia,
// bool lk) {
// // Get the basic block and switch behavior based on outgoing type.
// FunctionBlock* fn_block = e.fn_block();
// switch (fn_block->outgoing_type) {
// case FunctionBlock::kTargetBlock:
// {
// BasicBlock* target_bb = e.GetBasicBlock(fn_block->outgoing_address);
// XEASSERTNOTNULL(target_bb);
// b.CreateBr(target_bb);
// 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);
// Function* target_fn = e.GetFunction(fn_block->outgoing_function);
// Function::arg_iterator args = e.gen_fn()->arg_begin();
// Value* state_ptr = args;
// BasicBlock* next_bb = e.GetNextBasicBlock();
// if (!lk || !next_bb) {
// // 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.
// b.CreateCall2(target_fn, state_ptr, ++args);
// b.CreateRetVoid();
// } else {
// // Will return here eventually.
// // Refill registers from state.
// b.CreateCall2(target_fn, state_ptr, b.getInt64(cia + 4));
// e.FillRegisters();
// b.CreateBr(next_bb);
// }
// break;
// }
// case FunctionBlock::kTargetLR:
// {
// // An indirect jump.
// printf("INDIRECT JUMP VIA LR: %.8X\n", cia);
// return XeEmitIndirectBranchTo(e, b, src, cia, lk, kXEPPCRegLR);
// }
// case FunctionBlock::kTargetCTR:
// {
// // An indirect jump.
// printf("INDIRECT JUMP VIA CTR: %.8X\n", cia);
// return XeEmitIndirectBranchTo(e, b, src, cia, lk, kXEPPCRegCTR);
// }
// default:
// case FunctionBlock::kTargetNone:
// XEASSERTALWAYS();
// return 1;
// }
// return 0;
// }
// XEEMITTER(bx, 0x48000000, I )(LibjitEmitter& 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(b.getInt32(i.address + 4));
// }
// return XeEmitBranchTo(e, b, "bx", i.address, i.I.LK);
// }
// XEEMITTER(bcx, 0x40000000, B )(LibjitEmitter& 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(b.getInt32(i.address + 4));
// }
// Value* ctr_ok = NULL;
// if (XESELECTBITS(i.B.BO, 2, 2)) {
// // Ignore ctr.
// } else {
// // Decrement counter.
// Value* ctr = e.ctr_value();
// ctr = b.CreateSub(ctr, b.getInt64(1));
// e.update_ctr_value(ctr);
// // Ctr check.
// if (XESELECTBITS(i.B.BO, 1, 1)) {
// ctr_ok = b.CreateICmpEQ(ctr, b.getInt64(0));
// } else {
// ctr_ok = b.CreateICmpNE(ctr, b.getInt64(0));
// }
// }
// Value* cond_ok = NULL;
// if (XESELECTBITS(i.B.BO, 4, 4)) {
// // Ignore cond.
// } else {
// Value* cr = e.cr_value(i.B.BI >> 2);
// cr = b.CreateAnd(cr, 1 << (i.B.BI & 3));
// if (XESELECTBITS(i.B.BO, 3, 3)) {
// cond_ok = b.CreateICmpNE(cr, b.getInt64(0));
// } else {
// cond_ok = b.CreateICmpEQ(cr, b.getInt64(0));
// }
// }
// // We do a bit of optimization here to make the llvm assembly easier to read.
// Value* ok = NULL;
// if (ctr_ok && cond_ok) {
// ok = b.CreateAnd(ctr_ok, cond_ok);
// } else if (ctr_ok) {
// ok = ctr_ok;
// } else if (cond_ok) {
// ok = cond_ok;
// }
// // Handle unconditional branches without extra fluff.
// BasicBlock* original_bb = b.GetInsertBlock();
// if (ok) {
// char name[32];
// xesnprintfa(name, XECOUNT(name), "loc_%.8X_bcx", i.address);
// BasicBlock* next_block = e.GetNextBasicBlock();
// BasicBlock* branch_bb = BasicBlock::Create(*e.context(), name, e.gen_fn(),
// next_block);
// b.CreateCondBr(ok, branch_bb, next_block);
// b.SetInsertPoint(branch_bb);
// }
// // Note that this occurs entirely within the branch true block.
// 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, b, "bcx", i.address, i.B.LK)) {
// return 1;
// }
// b.SetInsertPoint(original_bb);
// return 0;
// }
// XEEMITTER(bcctrx, 0x4C000420, XL )(LibjitEmitter& 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(b.getInt32(i.address + 4));
// }
// Value* cond_ok = NULL;
// if (XESELECTBITS(i.XL.BO, 4, 4)) {
// // Ignore cond.
// } else {
// Value* cr = e.cr_value(i.XL.BI >> 2);
// cr = b.CreateAnd(cr, 1 << (i.XL.BI & 3));
// if (XESELECTBITS(i.XL.BO, 3, 3)) {
// cond_ok = b.CreateICmpNE(cr, b.getInt64(0));
// } else {
// cond_ok = b.CreateICmpEQ(cr, b.getInt64(0));
// }
// }
// // We do a bit of optimization here to make the llvm assembly easier to read.
// Value* ok = NULL;
// if (cond_ok) {
// ok = cond_ok;
// }
// // Handle unconditional branches without extra fluff.
// BasicBlock* original_bb = b.GetInsertBlock();
// if (ok) {
// char name[32];
// xesnprintfa(name, XECOUNT(name), "loc_%.8X_bcctrx", i.address);
// BasicBlock* next_block = e.GetNextBasicBlock();
// XEASSERTNOTNULL(next_block);
// BasicBlock* branch_bb = BasicBlock::Create(*e.context(), name, e.gen_fn(),
// next_block);
// b.CreateCondBr(ok, branch_bb, next_block);
// b.SetInsertPoint(branch_bb);
// }
// // Note that this occurs entirely within the branch true block.
// if (XeEmitBranchTo(e, b, "bcctrx", i.address, i.XL.LK)) {
// return 1;
// }
// b.SetInsertPoint(original_bb);
// return 0;
// }
// XEEMITTER(bclrx, 0x4C000020, XL )(LibjitEmitter& 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(b.getInt32(i.address + 4));
// }
// Value* ctr_ok = NULL;
// if (XESELECTBITS(i.XL.BO, 2, 2)) {
// // Ignore ctr.
// } else {
// // Decrement counter.
// Value* ctr = e.ctr_value();
// ctr = b.CreateSub(ctr, b.getInt64(1));
// // Ctr check.
// if (XESELECTBITS(i.XL.BO, 1, 1)) {
// ctr_ok = b.CreateICmpEQ(ctr, b.getInt64(0));
// } else {
// ctr_ok = b.CreateICmpNE(ctr, b.getInt64(0));
// }
// }
// Value* cond_ok = NULL;
// if (XESELECTBITS(i.XL.BO, 4, 4)) {
// // Ignore cond.
// } else {
// Value* cr = e.cr_value(i.XL.BI >> 2);
// cr = b.CreateAnd(cr, 1 << (i.XL.BI & 3));
// if (XESELECTBITS(i.XL.BO, 3, 3)) {
// cond_ok = b.CreateICmpNE(cr, b.getInt64(0));
// } else {
// cond_ok = b.CreateICmpEQ(cr, b.getInt64(0));
// }
// }
// // We do a bit of optimization here to make the llvm assembly easier to read.
// Value* ok = NULL;
// if (ctr_ok && cond_ok) {
// ok = b.CreateAnd(ctr_ok, cond_ok);
// } else if (ctr_ok) {
// ok = ctr_ok;
// } else if (cond_ok) {
// ok = cond_ok;
// }
// // Handle unconditional branches without extra fluff.
// BasicBlock* original_bb = b.GetInsertBlock();
// if (ok) {
// char name[32];
// xesnprintfa(name, XECOUNT(name), "loc_%.8X_bclrx", i.address);
// BasicBlock* next_block = e.GetNextBasicBlock();
// XEASSERTNOTNULL(next_block);
// BasicBlock* branch_bb = BasicBlock::Create(*e.context(), name, e.gen_fn(),
// next_block);
// b.CreateCondBr(ok, branch_bb, next_block);
// b.SetInsertPoint(branch_bb);
// }
// // Note that this occurs entirely within the branch true block.
// if (XeEmitBranchTo(e, b, "bclrx", i.address, i.XL.LK)) {
// return 1;
// }
// b.SetInsertPoint(original_bb);
// return 0;
// }
// // Condition register logical (A-23)
// XEEMITTER(crand, 0x4C000202, XL )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
// XEINSTRNOTIMPLEMENTED();
// return 1;
// }
// XEEMITTER(crandc, 0x4C000102, XL )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
// XEINSTRNOTIMPLEMENTED();
// return 1;
// }
// XEEMITTER(creqv, 0x4C000242, XL )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
// XEINSTRNOTIMPLEMENTED();
// return 1;
// }
// XEEMITTER(crnand, 0x4C0001C2, XL )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
// XEINSTRNOTIMPLEMENTED();
// return 1;
// }
// XEEMITTER(crnor, 0x4C000042, XL )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
// XEINSTRNOTIMPLEMENTED();
// return 1;
// }
// XEEMITTER(cror, 0x4C000382, XL )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
// XEINSTRNOTIMPLEMENTED();
// return 1;
// }
// XEEMITTER(crorc, 0x4C000342, XL )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
// XEINSTRNOTIMPLEMENTED();
// return 1;
// }
// XEEMITTER(crxor, 0x4C000182, XL )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
// XEINSTRNOTIMPLEMENTED();
// return 1;
// }
// XEEMITTER(mcrf, 0x4C000000, XL )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
// XEINSTRNOTIMPLEMENTED();
// return 1;
// }
// // System linkage (A-24)
// XEEMITTER(sc, 0x44000002, SC )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
// XEINSTRNOTIMPLEMENTED();
// return 1;
// }
// // Trap (A-25)
// int XeEmitTrap(LibjitEmitter& e, jit_function_t 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;
// }
// BasicBlock* after_bb = BasicBlock::Create(*e.context(), "", e.gen_fn(),
// e.GetNextBasicBlock());
// BasicBlock* trap_bb = BasicBlock::Create(*e.context(), "", e.gen_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.gen_fn(), trap_bb));
// }
// if (TO & (1 << 3)) {
// bbs.push_back(BasicBlock::Create(*e.context(), "", e.gen_fn(), trap_bb));
// }
// if (TO & (1 << 2)) {
// bbs.push_back(BasicBlock::Create(*e.context(), "", e.gen_fn(), trap_bb));
// }
// if (TO & (1 << 1)) {
// bbs.push_back(BasicBlock::Create(*e.context(), "", e.gen_fn(), trap_bb));
// }
// if (TO & (1 << 0)) {
// bbs.push_back(BasicBlock::Create(*e.context(), "", e.gen_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);
// Value* cmp = b.CreateICmpSLT(va, vb);
// b.CreateCondBr(cmp, trap_bb, *it);
// }
// if (TO & (1 << 3)) {
// // a > b
// BasicBlock* bb = *(it++);
// b.SetInsertPoint(bb);
// Value* cmp = b.CreateICmpSGT(va, vb);
// b.CreateCondBr(cmp, trap_bb, *it);
// }
// if (TO & (1 << 2)) {
// // a = b
// BasicBlock* bb = *(it++);
// b.SetInsertPoint(bb);
// Value* cmp = b.CreateICmpEQ(va, vb);
// b.CreateCondBr(cmp, trap_bb, *it);
// }
// if (TO & (1 << 1)) {
// // a <u b
// BasicBlock* bb = *(it++);
// b.SetInsertPoint(bb);
// Value* cmp = b.CreateICmpULT(va, vb);
// b.CreateCondBr(cmp, trap_bb, *it);
// }
// if (TO & (1 << 0)) {
// // a >u b
// BasicBlock* bb = *(it++);
// b.SetInsertPoint(bb);
// Value* 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.gen_fn()->arg_begin(),
// b.getInt32(i.address));
// b.CreateBr(after_bb);
// // Resume.
// b.SetInsertPoint(after_bb);
// return 0;
// }
// XEEMITTER(td, 0x7C000088, X )(LibjitEmitter& 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, b, i,
// e.gpr_value(i.X.RA),
// e.gpr_value(i.X.RB),
// i.X.RT);
// }
// XEEMITTER(tdi, 0x08000000, D )(LibjitEmitter& 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, b, i,
// e.gpr_value(i.D.RA),
// b.getInt64(XEEXTS16(i.D.DS)),
// i.D.RT);
// }
// XEEMITTER(tw, 0x7C000008, X )(LibjitEmitter& 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, b, i,
// b.CreateSExt(b.CreateTrunc(e.gpr_value(i.X.RA),
// b.getInt32Ty()),
// b.getInt64Ty()),
// b.CreateSExt(b.CreateTrunc(e.gpr_value(i.X.RB),
// b.getInt32Ty()),
// b.getInt64Ty()),
// i.X.RT);
// }
// XEEMITTER(twi, 0x0C000000, D )(LibjitEmitter& 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, b, i,
// b.CreateSExt(b.CreateTrunc(e.gpr_value(i.D.RA),
// b.getInt32Ty()),
// b.getInt64Ty()),
// b.getInt64(XEEXTS16(i.D.DS)),
// i.D.RT);
// }
// // Processor control (A-26)
// XEEMITTER(mfcr, 0x7C000026, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
// XEINSTRNOTIMPLEMENTED();
// return 1;
// }
// XEEMITTER(mfspr, 0x7C0002A6, XFX)(LibjitEmitter& 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);
// Value* 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)(LibjitEmitter& e, jit_function_t f, InstrData& i) {
// XEINSTRNOTIMPLEMENTED();
// return 1;
// }
// XEEMITTER(mtcrf, 0x7C000120, XFX)(LibjitEmitter& e, jit_function_t f, InstrData& i) {
// XEINSTRNOTIMPLEMENTED();
// return 1;
// }
// XEEMITTER(mtspr, 0x7C0003A6, XFX)(LibjitEmitter& 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]
// Value* 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 LibjitRegisterEmitCategoryControl() {
// 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 libjit
} // namespace cpu
} // namespace xe

View File

@ -0,0 +1,293 @@
/*
******************************************************************************
* 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/libjit/libjit_emit.h>
using namespace xe::cpu;
using namespace xe::cpu::ppc;
namespace xe {
namespace cpu {
namespace libjit {
// Floating-point arithmetic (A-8)
XEEMITTER(faddx, 0xFC00002A, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(faddsx, 0xEC00002A, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fdivx, 0xFC000024, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fdivsx, 0xEC000024, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fmulx, 0xFC000032, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fmulsx, 0xEC000032, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fresx, 0xEC000030, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(frsqrtex, 0xFC000034, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fsubx, 0xFC000028, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fsubsx, 0xEC000028, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fselx, 0xFC00002E, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fsqrtx, 0xFC00002C, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fsqrtsx, 0xEC00002C, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
// Floating-point multiply-add (A-9)
XEEMITTER(fmaddx, 0xFC00003A, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fmaddsx, 0xEC00003A, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fmsubx, 0xFC000038, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fmsubsx, 0xEC000038, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fnmaddx, 0xFC00003E, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fnmaddsx, 0xEC00003E, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fnmsubx, 0xFC00003C, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fnmsubsx, 0xEC00003C, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
// Floating-point rounding and conversion (A-10)
XEEMITTER(fcfidx, 0xFC00069C, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fctidx, 0xFC00065C, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fctidzx, 0xFC00065E, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fctiwx, 0xFC00001C, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fctiwzx, 0xFC00001E, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(frspx, 0xFC000018, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
// Floating-point compare (A-11)
XEEMITTER(fcmpo, 0xFC000040, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fcmpu, 0xFC000000, X )(LibjitEmitter& 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 )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(mffsx, 0xFC00048E, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(mtfsb0x, 0xFC00008C, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(mtfsb1x, 0xFC00004C, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(mtfsfx, 0xFC00058E, XFL)(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(mtfsfix, 0xFC00010C, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
// Floating-point move (A-21)
XEEMITTER(fabsx, 0xFC000210, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fmrx, 0xFC000090, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fnabsx, 0xFC000110, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fnegx, 0xFC000050, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
void LibjitRegisterEmitCategoryFPU() {
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 libjit
} // namespace cpu
} // namespace xe

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,143 @@
/**
******************************************************************************
* 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_LIBJIT_LIBJIT_EMITTER_H_
#define XENIA_CPU_LIBJIT_LIBJIT_EMITTER_H_
#include <xenia/cpu/global_exports.h>
#include <xenia/cpu/sdb.h>
#include <xenia/cpu/ppc/instr.h>
#include <jit/jit.h>
namespace xe {
namespace cpu {
namespace libjit {
class LibjitEmitter {
public:
LibjitEmitter(xe_memory_ref memory, jit_context_t context);
~LibjitEmitter();
jit_context_t context();
jit_type_t fn_signature();
int PrepareFunction(sdb::FunctionSymbol* symbol);
int MakeFunction(sdb::FunctionSymbol* symbol, jit_function_t fn);
sdb::FunctionSymbol* fn();
jit_function_t gen_fn();
sdb::FunctionBlock* fn_block();
void PushInsertPoint();
void PopInsertPoint();
void GenerateBasicBlocks();
// llvm::BasicBlock* GetBasicBlock(uint32_t address);
// llvm::BasicBlock* GetNextBasicBlock();
// llvm::BasicBlock* GetReturnBasicBlock();
int GenerateIndirectionBranch(uint32_t cia, jit_value_t target,
bool lk, bool likely_local);
jit_value_t LoadStateValue(uint32_t offset, jit_type_t type,
const char* name = "");
void StoreStateValue(uint32_t offset, jit_type_t type, jit_value_t value);
jit_value_t cia_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 GetMembase();
jit_value_t GetMemoryAddress(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 GenerateSharedBlocks();
int PrepareBasicBlock(sdb::FunctionBlock* block);
void GenerateBasicBlock(sdb::FunctionBlock* block);
void SetupLocals();
xe_memory_ref memory_;
jit_context_t context_;
GlobalExports global_exports_;
jit_type_t fn_signature_;
jit_type_t global_export_signature_;
sdb::FunctionSymbol* fn_;
jit_function_t gen_fn_;
sdb::FunctionBlock* fn_block_;
// llvm::BasicBlock* return_block_;
// llvm::BasicBlock* internal_indirection_block_;
// llvm::BasicBlock* external_indirection_block_;
// llvm::BasicBlock* bb_;
// std::vector<std::pair<llvm::BasicBlock*, llvm::BasicBlock::iterator> >
// insert_points_;
//std::map<uint32_t, llvm::BasicBlock*> 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 libjit
} // namespace cpu
} // namespace xe
#endif // XENIA_CPU_LIBJIT_LIBJIT_EMITTER_H_

View File

@ -0,0 +1,113 @@
/**
******************************************************************************
* 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/libjit/libjit_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::libjit;
using namespace xe::cpu::sdb;
LibjitJIT::LibjitJIT(xe_memory_ref memory, SymbolTable* sym_table) :
JIT(memory, sym_table),
context_(NULL), emitter_(NULL) {
}
LibjitJIT::~LibjitJIT() {
delete emitter_;
if (context_) {
jit_context_destroy(context_);
}
}
int LibjitJIT::Setup() {
int result_code = 1;
// Shared libjit context.
context_ = jit_context_create();
XEEXPECTNOTNULL(context_);
// Create the emitter used to generate functions.
emitter_ = new LibjitEmitter(memory_, context_);
// Inject global functions/variables/etc.
XEEXPECTZERO(InjectGlobals());
result_code = 0;
XECLEANUP:
return result_code;
}
int LibjitJIT::InjectGlobals() {
// LLVMContext& context = *context_;
// const DataLayout* dl = engine_->getDataLayout();
// Type* intPtrTy = dl->getIntPtrType(context);
// Type* int8PtrTy = PointerType::getUnqual(Type::getInt8Ty(context));
// GlobalVariable* gv;
// // xe_memory_base
// // This is the base void* pointer to the memory space.
// gv = new GlobalVariable(
// *module_,
// int8PtrTy,
// true,
// GlobalValue::ExternalLinkage,
// 0,
// "xe_memory_base");
// // Align to 64b - this makes SSE faster.
// gv->setAlignment(64);
// gv->setInitializer(ConstantExpr::getIntToPtr(
// ConstantInt::get(intPtrTy, (uintptr_t)xe_memory_addr(memory_, 0)),
// int8PtrTy));
return 0;
}
int LibjitJIT::InitModule(ExecModule* module) {
return 0;
}
int LibjitJIT::UninitModule(ExecModule* module) {
return 0;
}
int LibjitJIT::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);
}
// TODO(benvanik): replace generic apply with special trampoline.
void* args[] = {&ppc_state, &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;
}

View File

@ -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_LIBJIT_LIBJIT_JIT_H_
#define XENIA_CPU_LIBJIT_LIBJIT_JIT_H_
#include <xenia/core.h>
#include <xenia/cpu/jit.h>
#include <xenia/cpu/ppc.h>
#include <xenia/cpu/sdb.h>
#include <xenia/cpu/libjit/libjit_emitter.h>
#include <jit/jit.h>
namespace xe {
namespace cpu {
namespace libjit {
class LibjitJIT : public JIT {
public:
LibjitJIT(xe_memory_ref memory, sdb::SymbolTable* sym_table);
virtual ~LibjitJIT();
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_;
LibjitEmitter* emitter_;
};
} // namespace libjit
} // namespace cpu
} // namespace xe
#endif // XENIA_CPU_LIBJIT_LIBJIT_JIT_H_

View File

@ -0,0 +1,24 @@
/**
******************************************************************************
* 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/libjit/libjit_library_loader.h>
using namespace xe;
using namespace xe::cpu;
using namespace xe::cpu::libjit;
LibjitLibraryLoader::LibjitLibraryLoader(
xe_memory_ref memory, kernel::ExportResolver* export_resolver) :
LibraryLoader(memory, export_resolver) {
}
LibjitLibraryLoader::~LibjitLibraryLoader() {
}

View File

@ -0,0 +1,37 @@
/**
******************************************************************************
* 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_LIBJIT_LIBJIT_LIBRARY_LOADER_H_
#define XENIA_CPU_LIBJIT_LIBJIT_LIBRARY_LOADER_H_
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/cpu/library_loader.h>
namespace xe {
namespace cpu {
namespace libjit {
class LibjitLibraryLoader : public LibraryLoader {
public:
LibjitLibraryLoader(xe_memory_ref memory,
kernel::ExportResolver* export_resolver);
virtual ~LibjitLibraryLoader();
};
} // namespace libjit
} // namespace cpu
} // namespace xe
#endif // XENIA_CPU_LIBJIT_LIBJIT_LIBRARY_LOADER_H_

View File

@ -0,0 +1,18 @@
# Copyright 2013 Ben Vanik. All Rights Reserved.
{
'sources': [
'libjit_backend.cc',
'libjit_backend.h',
'libjit_emit.h',
'libjit_emit_alu.cc',
'libjit_emit_control.cc',
'libjit_emit_fpu.cc',
'libjit_emit_memory.cc',
'libjit_emitter.cc',
'libjit_emitter.h',
'libjit_jit.cc',
'libjit_jit.h',
'libjit_library_loader.cc',
'libjit_library_loader.h',
],
}

View File

@ -69,10 +69,6 @@ CodeUnitBuilder* LLVMBackend::CreateCodeUnitBuilder() {
return NULL; return NULL;
} }
LibraryLinker* LLVMBackend::CreateLibraryLinker() {
return NULL;
}
LibraryLoader* LLVMBackend::CreateLibraryLoader() { LibraryLoader* LLVMBackend::CreateLibraryLoader() {
return NULL; return NULL;
} }

View File

@ -21,7 +21,7 @@ namespace tables {
static InstrType* instr_table_prep( static InstrType* instr_table_prep(
InstrType* unprep, int unprep_count, int a, int b) { InstrType* unprep, int unprep_count, int a, int b) {
int prep_count = pow(2.0, b - a + 1); int prep_count = (int)pow(2, b - a + 1);
InstrType* prep = (InstrType*)xe_calloc(prep_count * sizeof(InstrType)); InstrType* prep = (InstrType*)xe_calloc(prep_count * sizeof(InstrType));
for (int n = 0; n < unprep_count; n++) { for (int n = 0; n < unprep_count; n++) {
int ordinal = XESELECTBITS(unprep[n].opcode, a, b); int ordinal = XESELECTBITS(unprep[n].opcode, a, b);

View File

@ -15,6 +15,7 @@
using namespace xe; using namespace xe;
using namespace xe::cpu; using namespace xe::cpu;
using namespace xe::cpu::sdb;
using namespace xe::kernel; using namespace xe::kernel;
@ -43,7 +44,7 @@ namespace {
Processor::Processor(xe_memory_ref memory, shared_ptr<Backend> backend) : Processor::Processor(xe_memory_ref memory, shared_ptr<Backend> backend) :
fn_table_(NULL), jit_(NULL) { sym_table_(NULL), jit_(NULL) {
memory_ = xe_memory_retain(memory); memory_ = xe_memory_retain(memory);
backend_ = backend; backend_ = backend;
@ -63,7 +64,7 @@ Processor::~Processor() {
modules_.clear(); modules_.clear();
delete jit_; delete jit_;
delete fn_table_; delete sym_table_;
export_resolver_.reset(); export_resolver_.reset();
backend_.reset(); backend_.reset();
@ -86,9 +87,9 @@ void Processor::set_export_resolver(
int Processor::Setup() { int Processor::Setup() {
XEASSERTNULL(jit_); XEASSERTNULL(jit_);
fn_table_ = new FunctionTable(); sym_table_ = new SymbolTable();
jit_ = backend_->CreateJIT(memory_, fn_table_); jit_ = backend_->CreateJIT(memory_, sym_table_);
if (jit_->Setup()) { if (jit_->Setup()) {
XELOGE("Unable to create JIT"); XELOGE("Unable to create JIT");
return 1; return 1;
@ -125,7 +126,7 @@ int Processor::LoadRawBinary(const xechar_t* path, uint32_t start_address) {
// This will analyze it, generate code (if needed), and adds methods to // This will analyze it, generate code (if needed), and adds methods to
// the function table. // the function table.
exec_module = new ExecModule( exec_module = new ExecModule(
memory_, export_resolver_, fn_table_, name_a, path_a); memory_, export_resolver_, sym_table_, name_a, path_a);
XEEXPECTZERO(exec_module->PrepareRawBinary( XEEXPECTZERO(exec_module->PrepareRawBinary(
start_address, start_address + (uint32_t)length)); start_address, start_address + (uint32_t)length));
@ -151,7 +152,7 @@ int Processor::LoadXexModule(const char* name, const char* path,
// This will analyze it, generate code (if needed), and adds methods to // This will analyze it, generate code (if needed), and adds methods to
// the function table. // the function table.
ExecModule* exec_module = new ExecModule( ExecModule* exec_module = new ExecModule(
memory_, export_resolver_, fn_table_, name, path); memory_, export_resolver_, sym_table_, name, path);
XEEXPECTZERO(exec_module->PrepareXexModule(xex)); XEEXPECTZERO(exec_module->PrepareXexModule(xex));
// Initialize the module and prepare it for execution. // Initialize the module and prepare it for execution.
@ -183,34 +184,30 @@ void Processor::DeallocThread(ThreadState* thread_state) {
delete thread_state; delete thread_state;
} }
FunctionPointer Processor::GenerateFunction(uint32_t address) { int Processor::Execute(ThreadState* thread_state, uint32_t address) {
// Search all modules for the function symbol. // Attempt to grab the function symbol from the global lookup table.
// Each module will see if the address is within its code range and if the FunctionSymbol* fn_symbol = sym_table_->GetFunction(address);
// symbol is not found (likely) it will do analysis on it. if (!fn_symbol) {
// TODO(benvanik): make this more efficient. Could use a binary search or // Search all modules for the function symbol.
// something more clever. // Each module will see if the address is within its code range and if the
sdb::FunctionSymbol* fn_symbol = NULL; // symbol is not found (likely) it will do analysis on it.
for (std::vector<ExecModule*>::iterator it = modules_.begin(); // TODO(benvanik): make this more efficient. Could use a binary search or
it != modules_.end(); ++it) { // something more clever.
fn_symbol = (*it)->FindFunctionSymbol(address); sdb::FunctionSymbol* fn_symbol = NULL;
if (fn_symbol) { for (std::vector<ExecModule*>::iterator it = modules_.begin();
break; it != modules_.end(); ++it) {
fn_symbol = (*it)->FindFunctionSymbol(address);
if (fn_symbol) {
break;
}
}
if (!fn_symbol) {
// Symbol not found in any module.
XELOGCPU("Execute(%.8X): failed to find function", address);
return NULL;
} }
} }
if (!fn_symbol) {
return NULL;
}
// JIT the function.
FunctionPointer f = jit_->GenerateFunction(fn_symbol);
if (!f) {
return NULL;
}
return f;
}
int Processor::Execute(ThreadState* thread_state, uint32_t address) {
xe_ppc_state_t* ppc_state = thread_state->ppc_state(); xe_ppc_state_t* ppc_state = thread_state->ppc_state();
// This could be set to anything to give us a unique identifier to track // This could be set to anything to give us a unique identifier to track
@ -220,25 +217,8 @@ int Processor::Execute(ThreadState* thread_state, uint32_t address) {
// Setup registers. // Setup registers.
ppc_state->lr = lr; ppc_state->lr = lr;
// Find the function to execute. // Execute the function.
FunctionPointer f = fn_table_->GetFunction(address); return jit_->Execute(ppc_state, fn_symbol);
// JIT, if needed.
if (!f) {
f = this->GenerateFunction(address);
}
// If JIT failed, die.
if (!f) {
XELOGCPU("Execute(%.8X): failed to find function", address);
return 1;
}
// Execute the function pointer.
// Messes with the stack in such a way as to cause Xcode to behave oddly.
f(ppc_state, lr);
return 0;
} }
uint64_t Processor::Execute(ThreadState* thread_state, uint32_t address, uint64_t Processor::Execute(ThreadState* thread_state, uint32_t address,

View File

@ -16,8 +16,8 @@
#include <xenia/cpu/backend.h> #include <xenia/cpu/backend.h>
#include <xenia/cpu/exec_module.h> #include <xenia/cpu/exec_module.h>
#include <xenia/cpu/function_table.h>
#include <xenia/cpu/thread_state.h> #include <xenia/cpu/thread_state.h>
#include <xenia/cpu/sdb/symbol_table.h>
#include <xenia/kernel/export.h> #include <xenia/kernel/export.h>
#include <xenia/kernel/xex2.h> #include <xenia/kernel/xex2.h>
@ -50,14 +50,12 @@ public:
uint64_t Execute(ThreadState* thread_state, uint32_t address, uint64_t arg0); uint64_t Execute(ThreadState* thread_state, uint32_t address, uint64_t arg0);
private: private:
FunctionPointer GenerateFunction(uint32_t address);
xe_memory_ref memory_; xe_memory_ref memory_;
shared_ptr<Backend> backend_; shared_ptr<Backend> backend_;
shared_ptr<kernel::ExportResolver> export_resolver_; shared_ptr<kernel::ExportResolver> export_resolver_;
FunctionTable* fn_table_; sdb::SymbolTable* sym_table_;
JIT* jit_; JIT* jit_;
std::vector<ExecModule*> modules_; std::vector<ExecModule*> modules_;
}; };

View File

@ -13,6 +13,7 @@
#include <xenia/cpu/sdb/raw_symbol_database.h> #include <xenia/cpu/sdb/raw_symbol_database.h>
#include <xenia/cpu/sdb/symbol.h> #include <xenia/cpu/sdb/symbol.h>
#include <xenia/cpu/sdb/symbol_database.h> #include <xenia/cpu/sdb/symbol_database.h>
#include <xenia/cpu/sdb/symbol_table.h>
#include <xenia/cpu/sdb/xex_symbol_database.h> #include <xenia/cpu/sdb/xex_symbol_database.h>
#endif // XENIA_CPU_SDB_H_ #endif // XENIA_CPU_SDB_H_

View File

@ -22,8 +22,9 @@ using namespace xe::kernel;
RawSymbolDatabase::RawSymbolDatabase( RawSymbolDatabase::RawSymbolDatabase(
xe_memory_ref memory, ExportResolver* export_resolver, xe_memory_ref memory, ExportResolver* export_resolver,
SymbolTable* sym_table,
uint32_t start_address, uint32_t end_address) : uint32_t start_address, uint32_t end_address) :
SymbolDatabase(memory, export_resolver) { SymbolDatabase(memory, export_resolver, sym_table) {
start_address_ = start_address; start_address_ = start_address;
end_address_ = end_address; end_address_ = end_address;
} }

View File

@ -22,6 +22,7 @@ class RawSymbolDatabase : public SymbolDatabase {
public: public:
RawSymbolDatabase(xe_memory_ref memory, RawSymbolDatabase(xe_memory_ref memory,
kernel::ExportResolver* export_resolver, kernel::ExportResolver* export_resolver,
SymbolTable* sym_table,
uint32_t start_address, uint32_t end_address); uint32_t start_address, uint32_t end_address);
virtual ~RawSymbolDatabase(); virtual ~RawSymbolDatabase();

View File

@ -7,6 +7,8 @@
'symbol.h', 'symbol.h',
'symbol_database.cc', 'symbol_database.cc',
'symbol_database.h', 'symbol_database.h',
'symbol_table.cc',
'symbol_table.h',
'xex_symbol_database.cc', 'xex_symbol_database.cc',
'xex_symbol_database.h', 'xex_symbol_database.h',
] ]

View File

@ -57,7 +57,8 @@ FunctionSymbol::FunctionSymbol() :
Symbol(Function), Symbol(Function),
start_address(0), end_address(0), start_address(0), end_address(0),
type(Unknown), flags(0), type(Unknown), flags(0),
kernel_export(0), ee(0) { kernel_export(0), ee(0),
impl_value(NULL) {
} }
FunctionSymbol::~FunctionSymbol() { FunctionSymbol::~FunctionSymbol() {

View File

@ -124,6 +124,10 @@ public:
kernel::KernelExport* kernel_export; kernel::KernelExport* kernel_export;
ExceptionEntrySymbol* ee; ExceptionEntrySymbol* ee;
// Implementation-specific value. This could be a JIT'ed function ref
// or some other structure. Never freed.
void* impl_value;
std::vector<FunctionCall> incoming_calls; std::vector<FunctionCall> incoming_calls;
std::vector<FunctionCall> outgoing_calls; std::vector<FunctionCall> outgoing_calls;
std::vector<VariableAccess> variable_accesses; std::vector<VariableAccess> variable_accesses;

View File

@ -24,9 +24,11 @@ using namespace xe::kernel;
SymbolDatabase::SymbolDatabase(xe_memory_ref memory, SymbolDatabase::SymbolDatabase(xe_memory_ref memory,
ExportResolver* export_resolver) { ExportResolver* export_resolver,
SymbolTable* sym_table) {
memory_ = xe_memory_retain(memory); memory_ = xe_memory_retain(memory);
export_resolver_ = export_resolver; export_resolver_ = export_resolver;
sym_table_ = sym_table;
} }
SymbolDatabase::~SymbolDatabase() { SymbolDatabase::~SymbolDatabase() {
@ -150,7 +152,18 @@ FunctionSymbol* SymbolDatabase::GetFunction(uint32_t address) {
if (i != symbols_.end() && i->second->symbol_type == Symbol::Function) { if (i != symbols_.end() && i->second->symbol_type == Symbol::Function) {
return static_cast<FunctionSymbol*>(i->second); return static_cast<FunctionSymbol*>(i->second);
} }
return NULL;
// Missing function - analyze on demand.
// TODO(benvanik): track this for statistics.
FunctionSymbol* fn = new FunctionSymbol();
fn->start_address = address;
function_count_++;
symbols_.insert(SymbolMap::value_type(address, fn));
scan_queue_.push_back(fn);
FlushQueue();
return fn;
} }
VariableSymbol* SymbolDatabase::GetVariable(uint32_t address) { VariableSymbol* SymbolDatabase::GetVariable(uint32_t address) {
@ -432,6 +445,9 @@ int SymbolDatabase::AnalyzeFunction(FunctionSymbol* fn) {
// - if present, flag function as needing a stack // - if present, flag function as needing a stack
// - record prolog/epilog lengths/stack size/etc // - record prolog/epilog lengths/stack size/etc
// TODO(benvanik): queue for add without expensive locks?
sym_table_->AddFunction(fn->start_address, fn);
XELOGSDB("Finished analyzing %.8X", fn->start_address); XELOGSDB("Finished analyzing %.8X", fn->start_address);
return 0; return 0;
} }
@ -649,7 +665,7 @@ void SymbolDatabase::ReadMap(const char* file_name) {
sstream >> std::ws; sstream >> std::ws;
sstream >> type_str; sstream >> type_str;
uint32_t addr = (uint32_t)strtol(addr_str.c_str(), NULL, 16); uint32_t addr = (uint32_t)strtoul(addr_str.c_str(), NULL, 16);
if (!addr) { if (!addr) {
continue; continue;
} }

View File

@ -18,6 +18,7 @@
#include <xenia/kernel/export.h> #include <xenia/kernel/export.h>
#include <xenia/cpu/sdb/symbol.h> #include <xenia/cpu/sdb/symbol.h>
#include <xenia/cpu/sdb/symbol_table.h>
namespace xe { namespace xe {
@ -27,7 +28,8 @@ namespace sdb {
class SymbolDatabase { class SymbolDatabase {
public: public:
SymbolDatabase(xe_memory_ref memory, kernel::ExportResolver* export_resolver); SymbolDatabase(xe_memory_ref memory, kernel::ExportResolver* export_resolver,
SymbolTable* sym_table);
virtual ~SymbolDatabase(); virtual ~SymbolDatabase();
virtual int Analyze(); virtual int Analyze();
@ -63,6 +65,7 @@ protected:
xe_memory_ref memory_; xe_memory_ref memory_;
kernel::ExportResolver* export_resolver_; kernel::ExportResolver* export_resolver_;
SymbolTable* sym_table_;
size_t function_count_; size_t function_count_;
size_t variable_count_; size_t variable_count_;
SymbolMap symbols_; SymbolMap symbols_;

View File

@ -7,38 +7,26 @@
****************************************************************************** ******************************************************************************
*/ */
#include <xenia/cpu/function_table.h> #include <xenia/cpu/sdb/symbol_table.h>
using namespace xe; using namespace xe;
using namespace xe::cpu; using namespace xe::cpu;
using namespace xe::cpu::sdb;
FunctionTable::FunctionTable() { SymbolTable::SymbolTable() {
} }
FunctionTable::~FunctionTable() { SymbolTable::~SymbolTable() {
} }
int FunctionTable::AddCodeRange(uint32_t low_address, uint32_t high_address) { int SymbolTable::AddFunction(uint32_t address, FunctionSymbol* symbol) {
map_[address] = symbol;
return 0; return 0;
} }
FunctionPointer FunctionTable::BeginAddFunction(uint32_t address) { FunctionSymbol* SymbolTable::GetFunction(uint32_t address) {
FunctionPointer ptr = map_[address];
if (ptr) {
return ptr;
}
map_[address] = reinterpret_cast<FunctionPointer>(0x1);
return NULL;
}
int FunctionTable::AddFunction(uint32_t address, FunctionPointer ptr) {
map_[address] = ptr;
return 0;
}
FunctionPointer FunctionTable::GetFunction(uint32_t address) {
FunctionMap::const_iterator it = map_.find(address); FunctionMap::const_iterator it = map_.find(address);
return it != map_.end() ? it->second : NULL; return it != map_.end() ? it->second : NULL;
} }

View File

@ -7,39 +7,36 @@
****************************************************************************** ******************************************************************************
*/ */
#ifndef XENIA_CPU_FUNCTION_TABLE_H_ #ifndef XENIA_CPU_SDB_SYMBOL_TABLE_H_
#define XENIA_CPU_FUNCTION_TABLE_H_ #define XENIA_CPU_SDB_SYMBOL_TABLE_H_
#include <xenia/core.h> #include <xenia/core.h>
#include <xenia/cpu/ppc.h> #include <xenia/cpu/sdb/symbol.h>
namespace xe { namespace xe {
namespace cpu { namespace cpu {
namespace sdb {
typedef void (*FunctionPointer)(xe_ppc_state_t*, uint64_t); class SymbolTable {
class FunctionTable {
public: public:
FunctionTable(); SymbolTable();
~FunctionTable(); ~SymbolTable();
int AddCodeRange(uint32_t low_address, uint32_t high_address); int AddFunction(uint32_t address, sdb::FunctionSymbol* symbol);
FunctionPointer BeginAddFunction(uint32_t address); sdb::FunctionSymbol* GetFunction(uint32_t address);
int AddFunction(uint32_t address, FunctionPointer ptr);
FunctionPointer GetFunction(uint32_t address);
private: private:
typedef std::tr1::unordered_map<uint32_t, FunctionPointer> FunctionMap; typedef std::tr1::unordered_map<uint32_t, sdb::FunctionSymbol*> FunctionMap;
FunctionMap map_; FunctionMap map_;
}; };
} // namespace sdb
} // namespace cpu } // namespace cpu
} // namespace xe } // namespace xe
#endif // XENIA_CPU_FUNCTION_TABLE_H_ #endif // XENIA_CPU_SDB_SYMBOL_TABLE_H_

View File

@ -51,8 +51,9 @@ public:
XexSymbolDatabase::XexSymbolDatabase( XexSymbolDatabase::XexSymbolDatabase(
xe_memory_ref memory, ExportResolver* export_resolver, xe_xex2_ref xex) : xe_memory_ref memory, ExportResolver* export_resolver,
SymbolDatabase(memory, export_resolver) { SymbolTable* sym_table, xe_xex2_ref xex) :
SymbolDatabase(memory, export_resolver, sym_table) {
xex_ = xe_xex2_retain(xex); xex_ = xe_xex2_retain(xex);
} }

View File

@ -24,7 +24,7 @@ class XexSymbolDatabase : public SymbolDatabase {
public: public:
XexSymbolDatabase(xe_memory_ref memory, XexSymbolDatabase(xe_memory_ref memory,
kernel::ExportResolver* export_resolver, kernel::ExportResolver* export_resolver,
xe_xex2_ref xex); SymbolTable* sym_table, xe_xex2_ref xex);
virtual ~XexSymbolDatabase(); virtual ~XexSymbolDatabase();
virtual int Analyze(); virtual int Analyze();

View File

@ -2,14 +2,11 @@
{ {
'sources': [ 'sources': [
'backend.h', 'backend.h',
'code_unit_builder.h',
'cpu-private.h', 'cpu-private.h',
'cpu.cc', 'cpu.cc',
'cpu.h', 'cpu.h',
'exec_module.cc', 'exec_module.cc',
'exec_module.h', 'exec_module.h',
'function_table.cc',
'function_table.h',
'global_exports.cc', 'global_exports.cc',
'global_exports.h', 'global_exports.h',
'jit.h', 'jit.h',
@ -23,7 +20,7 @@
], ],
'includes': [ 'includes': [
#'llvmbe/sources.gypi', 'libjit/sources.gypi',
'ppc/sources.gypi', 'ppc/sources.gypi',
'sdb/sources.gypi', 'sdb/sources.gypi',
], ],

2
third_party/libjit vendored

@ -1 +1 @@
Subproject commit 833b8e9d972cd410e800881e0e90a500c8541db0 Subproject commit 542a478da976013a748f37e83825c95d45a965ec

View File

@ -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::llvmbe::LLVMBackend()); backend_ = shared_ptr<Backend>(new xe::cpu::libjit::LibjitBackend());
debugger_ = shared_ptr<Debugger>(new Debugger()); debugger_ = shared_ptr<Debugger>(new Debugger());
@ -116,8 +116,6 @@ int xenia_run(int argc, xechar_t **argv) {
result_code = run->Setup(); result_code = run->Setup();
XEEXPECTZERO(result_code); XEEXPECTZERO(result_code);
//xe_module_dump(run->module);
run->Launch(path); run->Launch(path);
result_code = 0; result_code = 0;

View File

@ -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::llvmbe::LLVMBackend()); backend_ = shared_ptr<Backend>(new xe::cpu::libjit::LibjitBackend());
processor = shared_ptr<Processor>(new Processor(memory, backend)); processor = shared_ptr<Processor>(new Processor(memory, backend));
XEEXPECTZERO(processor->Setup()); XEEXPECTZERO(processor->Setup());

View File

@ -300,7 +300,7 @@ def run_gyp(format):
'-f %s' % (format), '-f %s' % (format),
# Set the VS version. # Set the VS version.
# TODO(benvanik): allow user to set? # TODO(benvanik): allow user to set?
'-G msvs_version=2010', '-G msvs_version=2012e',
# Removes the out/ from ninja builds. # Removes the out/ from ninja builds.
'-G output_dir=.', '-G output_dir=.',
'--depth=.', '--depth=.',