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:
parent
94e3e592dd
commit
85804f7415
|
@ -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
|
||||||
|
|
|
@ -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() {}
|
||||||
|
|
|
@ -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_
|
|
|
@ -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_
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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_;
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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_
|
|
@ -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
|
@ -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
|
|
@ -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
|
@ -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_
|
|
@ -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;
|
||||||
|
}
|
|
@ -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_
|
|
@ -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() {
|
||||||
|
}
|
|
@ -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_
|
|
@ -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',
|
||||||
|
],
|
||||||
|
}
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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_
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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',
|
||||||
]
|
]
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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_;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
|
@ -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_
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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',
|
||||||
],
|
],
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 833b8e9d972cd410e800881e0e90a500c8541db0
|
Subproject commit 542a478da976013a748f37e83825c95d45a965ec
|
|
@ -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;
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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=.',
|
||||||
|
|
Loading…
Reference in New Issue