Merging Runtime into Processor.
This commit is contained in:
parent
4c8f3501ad
commit
78921c1a7e
|
@ -90,8 +90,7 @@ X_STATUS AudioSystem::Setup() {
|
||||||
registers_.next_context = 1;
|
registers_.next_context = 1;
|
||||||
|
|
||||||
// Setup worker thread state. This lets us make calls into guest code.
|
// Setup worker thread state. This lets us make calls into guest code.
|
||||||
thread_state_ =
|
thread_state_ = new ThreadState(emulator_->processor(), 0, 0, 16 * 1024, 0);
|
||||||
new ThreadState(emulator_->processor()->runtime(), 0, 0, 16 * 1024, 0);
|
|
||||||
thread_state_->set_name("Audio Worker");
|
thread_state_->set_name("Audio Worker");
|
||||||
thread_block_ = memory()->SystemHeapAlloc(2048);
|
thread_block_ = memory()->SystemHeapAlloc(2048);
|
||||||
thread_state_->context()->r[13] = thread_block_;
|
thread_state_->context()->r[13] = thread_block_;
|
||||||
|
|
|
@ -17,7 +17,6 @@ namespace cpu {
|
||||||
class DebugInfo;
|
class DebugInfo;
|
||||||
class Function;
|
class Function;
|
||||||
class FunctionInfo;
|
class FunctionInfo;
|
||||||
class Runtime;
|
|
||||||
namespace hir {
|
namespace hir {
|
||||||
class HIRBuilder;
|
class HIRBuilder;
|
||||||
} // namespace hir
|
} // namespace hir
|
||||||
|
|
|
@ -13,9 +13,7 @@ namespace xe {
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
namespace backend {
|
namespace backend {
|
||||||
|
|
||||||
using xe::cpu::Runtime;
|
Backend::Backend(Processor* processor) : processor_(processor) {
|
||||||
|
|
||||||
Backend::Backend(Runtime* runtime) : runtime_(runtime) {
|
|
||||||
memset(&machine_info_, 0, sizeof(machine_info_));
|
memset(&machine_info_, 0, sizeof(machine_info_));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
class Runtime;
|
class Processor;
|
||||||
} // namespace cpu
|
} // namespace cpu
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
||||||
|
@ -28,10 +28,10 @@ class Assembler;
|
||||||
|
|
||||||
class Backend {
|
class Backend {
|
||||||
public:
|
public:
|
||||||
Backend(Runtime* runtime);
|
Backend(Processor* processor);
|
||||||
virtual ~Backend();
|
virtual ~Backend();
|
||||||
|
|
||||||
Runtime* runtime() const { return runtime_; }
|
Processor* processor() const { return processor_; }
|
||||||
const MachineInfo* machine_info() const { return &machine_info_; }
|
const MachineInfo* machine_info() const { return &machine_info_; }
|
||||||
|
|
||||||
virtual int Initialize();
|
virtual int Initialize();
|
||||||
|
@ -42,7 +42,7 @@ class Backend {
|
||||||
virtual std::unique_ptr<Assembler> CreateAssembler() = 0;
|
virtual std::unique_ptr<Assembler> CreateAssembler() = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Runtime* runtime_;
|
Processor* processor_;
|
||||||
MachineInfo machine_info_;
|
MachineInfo machine_info_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
#include "xenia/cpu/backend/x64/x64_function.h"
|
#include "xenia/cpu/backend/x64/x64_function.h"
|
||||||
#include "xenia/cpu/hir/hir_builder.h"
|
#include "xenia/cpu/hir/hir_builder.h"
|
||||||
#include "xenia/cpu/hir/label.h"
|
#include "xenia/cpu/hir/label.h"
|
||||||
#include "xenia/cpu/runtime.h"
|
#include "xenia/cpu/processor.h"
|
||||||
#include "xenia/profiling.h"
|
#include "xenia/profiling.h"
|
||||||
|
|
||||||
namespace BE {
|
namespace BE {
|
||||||
|
|
|
@ -19,9 +19,8 @@ namespace cpu {
|
||||||
namespace backend {
|
namespace backend {
|
||||||
namespace x64 {
|
namespace x64 {
|
||||||
|
|
||||||
using xe::cpu::Runtime;
|
X64Backend::X64Backend(Processor* processor)
|
||||||
|
: Backend(processor), code_cache_(nullptr) {}
|
||||||
X64Backend::X64Backend(Runtime* runtime) : Backend(runtime), code_cache_(0) {}
|
|
||||||
|
|
||||||
X64Backend::~X64Backend() { delete code_cache_; }
|
X64Backend::~X64Backend() { delete code_cache_; }
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ typedef void* (*GuestToHostThunk)(void* target, void* arg0, void* arg1);
|
||||||
|
|
||||||
class X64Backend : public Backend {
|
class X64Backend : public Backend {
|
||||||
public:
|
public:
|
||||||
X64Backend(Runtime* runtime);
|
X64Backend(Processor* processor);
|
||||||
~X64Backend() override;
|
~X64Backend() override;
|
||||||
|
|
||||||
X64CodeCache* code_cache() const { return code_cache_; }
|
X64CodeCache* code_cache() const { return code_cache_; }
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#include "xenia/cpu/cpu-private.h"
|
#include "xenia/cpu/cpu-private.h"
|
||||||
#include "xenia/cpu/debug_info.h"
|
#include "xenia/cpu/debug_info.h"
|
||||||
#include "xenia/cpu/hir/hir_builder.h"
|
#include "xenia/cpu/hir/hir_builder.h"
|
||||||
#include "xenia/cpu/runtime.h"
|
#include "xenia/cpu/processor.h"
|
||||||
#include "xenia/cpu/symbol_info.h"
|
#include "xenia/cpu/symbol_info.h"
|
||||||
#include "xenia/cpu/thread_state.h"
|
#include "xenia/cpu/thread_state.h"
|
||||||
#include "xenia/profiling.h"
|
#include "xenia/profiling.h"
|
||||||
|
@ -60,7 +60,7 @@ const uint32_t X64Emitter::xmm_reg_map_[X64Emitter::XMM_COUNT] = {
|
||||||
|
|
||||||
X64Emitter::X64Emitter(X64Backend* backend, XbyakAllocator* allocator)
|
X64Emitter::X64Emitter(X64Backend* backend, XbyakAllocator* allocator)
|
||||||
: CodeGenerator(MAX_CODE_SIZE, AutoGrow, allocator),
|
: CodeGenerator(MAX_CODE_SIZE, AutoGrow, allocator),
|
||||||
runtime_(backend->runtime()),
|
processor_(backend->processor()),
|
||||||
backend_(backend),
|
backend_(backend),
|
||||||
code_cache_(backend->code_cache()),
|
code_cache_(backend->code_cache()),
|
||||||
allocator_(allocator),
|
allocator_(allocator),
|
||||||
|
@ -217,7 +217,8 @@ void X64Emitter::MarkSourceOffset(const Instr* i) {
|
||||||
|
|
||||||
void X64Emitter::EmitGetCurrentThreadId() {
|
void X64Emitter::EmitGetCurrentThreadId() {
|
||||||
// rcx must point to context. We could fetch from the stack if needed.
|
// rcx must point to context. We could fetch from the stack if needed.
|
||||||
mov(ax, word[rcx + runtime_->frontend()->context_info()->thread_id_offset()]);
|
mov(ax,
|
||||||
|
word[rcx + processor_->frontend()->context_info()->thread_id_offset()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void X64Emitter::EmitTraceUserCallReturn() {}
|
void X64Emitter::EmitTraceUserCallReturn() {}
|
||||||
|
@ -279,7 +280,7 @@ uint64_t ResolveFunctionSymbol(void* raw_context, uint64_t symbol_info_ptr) {
|
||||||
|
|
||||||
// Resolve function. This will demand compile as required.
|
// Resolve function. This will demand compile as required.
|
||||||
Function* fn = NULL;
|
Function* fn = NULL;
|
||||||
thread_state->runtime()->ResolveFunction(symbol_info->address(), &fn);
|
thread_state->processor()->ResolveFunction(symbol_info->address(), &fn);
|
||||||
assert_not_null(fn);
|
assert_not_null(fn);
|
||||||
auto x64_fn = static_cast<X64Function*>(fn);
|
auto x64_fn = static_cast<X64Function*>(fn);
|
||||||
uint64_t addr = reinterpret_cast<uint64_t>(x64_fn->machine_code());
|
uint64_t addr = reinterpret_cast<uint64_t>(x64_fn->machine_code());
|
||||||
|
@ -361,7 +362,7 @@ uint64_t ResolveFunctionAddress(void* raw_context, uint32_t target_address) {
|
||||||
assert_not_zero(target_address);
|
assert_not_zero(target_address);
|
||||||
|
|
||||||
Function* fn = NULL;
|
Function* fn = NULL;
|
||||||
thread_state->runtime()->ResolveFunction(target_address, &fn);
|
thread_state->processor()->ResolveFunction(target_address, &fn);
|
||||||
assert_not_null(fn);
|
assert_not_null(fn);
|
||||||
auto x64_fn = static_cast<X64Function*>(fn);
|
auto x64_fn = static_cast<X64Function*>(fn);
|
||||||
uint64_t addr = reinterpret_cast<uint64_t>(x64_fn->machine_code());
|
uint64_t addr = reinterpret_cast<uint64_t>(x64_fn->machine_code());
|
||||||
|
|
|
@ -20,7 +20,7 @@ namespace xe {
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
class DebugInfo;
|
class DebugInfo;
|
||||||
class FunctionInfo;
|
class FunctionInfo;
|
||||||
class Runtime;
|
class Processor;
|
||||||
class SymbolInfo;
|
class SymbolInfo;
|
||||||
namespace hir {
|
namespace hir {
|
||||||
class HIRBuilder;
|
class HIRBuilder;
|
||||||
|
@ -101,7 +101,7 @@ class X64Emitter : public Xbyak::CodeGenerator {
|
||||||
X64Emitter(X64Backend* backend, XbyakAllocator* allocator);
|
X64Emitter(X64Backend* backend, XbyakAllocator* allocator);
|
||||||
virtual ~X64Emitter();
|
virtual ~X64Emitter();
|
||||||
|
|
||||||
Runtime* runtime() const { return runtime_; }
|
Processor* processor() const { return processor_; }
|
||||||
X64Backend* backend() const { return backend_; }
|
X64Backend* backend() const { return backend_; }
|
||||||
const Xbyak::util::Cpu* cpu() const { return &cpu_; }
|
const Xbyak::util::Cpu* cpu() const { return &cpu_; }
|
||||||
|
|
||||||
|
@ -187,7 +187,7 @@ class X64Emitter : public Xbyak::CodeGenerator {
|
||||||
void EmitTraceUserCallReturn();
|
void EmitTraceUserCallReturn();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Runtime* runtime_;
|
Processor* processor_;
|
||||||
X64Backend* backend_;
|
X64Backend* backend_;
|
||||||
X64CodeCache* code_cache_;
|
X64CodeCache* code_cache_;
|
||||||
XbyakAllocator* allocator_;
|
XbyakAllocator* allocator_;
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
#include "xenia/cpu/backend/x64/x64_function.h"
|
#include "xenia/cpu/backend/x64/x64_function.h"
|
||||||
|
|
||||||
#include "xenia/cpu/backend/x64/x64_backend.h"
|
#include "xenia/cpu/backend/x64/x64_backend.h"
|
||||||
#include "xenia/cpu/runtime.h"
|
#include "xenia/cpu/processor.h"
|
||||||
#include "xenia/cpu/thread_state.h"
|
#include "xenia/cpu/thread_state.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
@ -35,7 +35,8 @@ int X64Function::AddBreakpointImpl(Breakpoint* breakpoint) { return 0; }
|
||||||
int X64Function::RemoveBreakpointImpl(Breakpoint* breakpoint) { return 0; }
|
int X64Function::RemoveBreakpointImpl(Breakpoint* breakpoint) { return 0; }
|
||||||
|
|
||||||
int X64Function::CallImpl(ThreadState* thread_state, uint32_t return_address) {
|
int X64Function::CallImpl(ThreadState* thread_state, uint32_t return_address) {
|
||||||
auto backend = (X64Backend*)thread_state->runtime()->backend();
|
auto backend =
|
||||||
|
reinterpret_cast<X64Backend*>(thread_state->processor()->backend());
|
||||||
auto thunk = backend->host_to_guest_thunk();
|
auto thunk = backend->host_to_guest_thunk();
|
||||||
thunk(machine_code_, thread_state->context(),
|
thunk(machine_code_, thread_state->context(),
|
||||||
reinterpret_cast<void*>(uintptr_t(return_address)));
|
reinterpret_cast<void*>(uintptr_t(return_address)));
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
#include "xenia/cpu/backend/x64/x64_emitter.h"
|
#include "xenia/cpu/backend/x64/x64_emitter.h"
|
||||||
#include "xenia/cpu/backend/x64/x64_tracers.h"
|
#include "xenia/cpu/backend/x64/x64_tracers.h"
|
||||||
#include "xenia/cpu/hir/hir_builder.h"
|
#include "xenia/cpu/hir/hir_builder.h"
|
||||||
#include "xenia/cpu/runtime.h"
|
#include "xenia/cpu/processor.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
#include "xenia/base/vec128.h"
|
#include "xenia/base/vec128.h"
|
||||||
#include "xenia/cpu/backend/x64/x64_emitter.h"
|
#include "xenia/cpu/backend/x64/x64_emitter.h"
|
||||||
#include "xenia/cpu/runtime.h"
|
#include "xenia/cpu/processor.h"
|
||||||
#include "xenia/cpu/thread_state.h"
|
#include "xenia/cpu/thread_state.h"
|
||||||
|
|
||||||
using namespace xe;
|
using namespace xe;
|
||||||
|
|
|
@ -16,10 +16,7 @@ namespace xe {
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
namespace compiler {
|
namespace compiler {
|
||||||
|
|
||||||
using xe::cpu::hir::HIRBuilder;
|
Compiler::Compiler(Processor* processor) : processor_(processor) {}
|
||||||
using xe::cpu::Runtime;
|
|
||||||
|
|
||||||
Compiler::Compiler(Runtime* runtime) : runtime_(runtime) {}
|
|
||||||
|
|
||||||
Compiler::~Compiler() { Reset(); }
|
Compiler::~Compiler() { Reset(); }
|
||||||
|
|
||||||
|
@ -30,7 +27,7 @@ void Compiler::AddPass(std::unique_ptr<CompilerPass> pass) {
|
||||||
|
|
||||||
void Compiler::Reset() {}
|
void Compiler::Reset() {}
|
||||||
|
|
||||||
int Compiler::Compile(HIRBuilder* builder) {
|
int Compiler::Compile(xe::cpu::hir::HIRBuilder* builder) {
|
||||||
// TODO(benvanik): sophisticated stuff. Run passes in parallel, run until they
|
// TODO(benvanik): sophisticated stuff. Run passes in parallel, run until they
|
||||||
// stop changing things, etc.
|
// stop changing things, etc.
|
||||||
for (size_t i = 0; i < passes_.size(); ++i) {
|
for (size_t i = 0; i < passes_.size(); ++i) {
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
class Runtime;
|
class Processor;
|
||||||
} // namespace cpu
|
} // namespace cpu
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
||||||
|
@ -30,10 +30,10 @@ class CompilerPass;
|
||||||
|
|
||||||
class Compiler {
|
class Compiler {
|
||||||
public:
|
public:
|
||||||
Compiler(Runtime* runtime);
|
Compiler(Processor* processor);
|
||||||
~Compiler();
|
~Compiler();
|
||||||
|
|
||||||
Runtime* runtime() const { return runtime_; }
|
Processor* processor() const { return processor_; }
|
||||||
Arena* scratch_arena() { return &scratch_arena_; }
|
Arena* scratch_arena() { return &scratch_arena_; }
|
||||||
|
|
||||||
void AddPass(std::unique_ptr<CompilerPass> pass);
|
void AddPass(std::unique_ptr<CompilerPass> pass);
|
||||||
|
@ -43,7 +43,7 @@ class Compiler {
|
||||||
int Compile(hir::HIRBuilder* builder);
|
int Compile(hir::HIRBuilder* builder);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Runtime* runtime_;
|
Processor* processor_;
|
||||||
Arena scratch_arena_;
|
Arena scratch_arena_;
|
||||||
|
|
||||||
std::vector<std::unique_ptr<CompilerPass>> passes_;
|
std::vector<std::unique_ptr<CompilerPass>> passes_;
|
||||||
|
|
|
@ -15,12 +15,12 @@ namespace xe {
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
namespace compiler {
|
namespace compiler {
|
||||||
|
|
||||||
CompilerPass::CompilerPass() : runtime_(0), compiler_(0) {}
|
CompilerPass::CompilerPass() : processor_(nullptr), compiler_(nullptr) {}
|
||||||
|
|
||||||
CompilerPass::~CompilerPass() = default;
|
CompilerPass::~CompilerPass() = default;
|
||||||
|
|
||||||
int CompilerPass::Initialize(Compiler* compiler) {
|
int CompilerPass::Initialize(Compiler* compiler) {
|
||||||
runtime_ = compiler->runtime();
|
processor_ = compiler->processor();
|
||||||
compiler_ = compiler;
|
compiler_ = compiler;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
class Runtime;
|
class Processor;
|
||||||
} // namespace cpu
|
} // namespace cpu
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ class CompilerPass {
|
||||||
Arena* scratch_arena() const;
|
Arena* scratch_arena() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Runtime* runtime_;
|
Processor* processor_;
|
||||||
Compiler* compiler_;
|
Compiler* compiler_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
#include "xenia/base/assert.h"
|
#include "xenia/base/assert.h"
|
||||||
#include "xenia/cpu/function.h"
|
#include "xenia/cpu/function.h"
|
||||||
#include "xenia/cpu/runtime.h"
|
#include "xenia/cpu/processor.h"
|
||||||
#include "xenia/profiling.h"
|
#include "xenia/profiling.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
@ -98,7 +98,7 @@ int ConstantPropagationPass::Run(HIRBuilder* builder) {
|
||||||
case OPCODE_CALL_INDIRECT:
|
case OPCODE_CALL_INDIRECT:
|
||||||
if (i->src1.value->IsConstant()) {
|
if (i->src1.value->IsConstant()) {
|
||||||
FunctionInfo* symbol_info;
|
FunctionInfo* symbol_info;
|
||||||
if (runtime_->LookupFunctionInfo(
|
if (processor_->LookupFunctionInfo(
|
||||||
(uint32_t)i->src1.value->constant.i32, &symbol_info)) {
|
(uint32_t)i->src1.value->constant.i32, &symbol_info)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#include <gflags/gflags.h>
|
#include <gflags/gflags.h>
|
||||||
|
|
||||||
#include "xenia/cpu/compiler/compiler.h"
|
#include "xenia/cpu/compiler/compiler.h"
|
||||||
#include "xenia/cpu/runtime.h"
|
#include "xenia/cpu/processor.h"
|
||||||
#include "xenia/profiling.h"
|
#include "xenia/profiling.h"
|
||||||
|
|
||||||
DEFINE_bool(store_all_context_values, false,
|
DEFINE_bool(store_all_context_values, false,
|
||||||
|
@ -42,7 +42,7 @@ int ContextPromotionPass::Initialize(Compiler* compiler) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a terrible implementation.
|
// This is a terrible implementation.
|
||||||
ContextInfo* context_info = runtime_->frontend()->context_info();
|
ContextInfo* context_info = processor_->frontend()->context_info();
|
||||||
context_values_.resize(context_info->size());
|
context_values_.resize(context_info->size());
|
||||||
context_validity_.resize(static_cast<uint32_t>(context_info->size()));
|
context_validity_.resize(static_cast<uint32_t>(context_info->size()));
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
#include "xenia/cpu/backend/backend.h"
|
#include "xenia/cpu/backend/backend.h"
|
||||||
#include "xenia/cpu/compiler/compiler.h"
|
#include "xenia/cpu/compiler/compiler.h"
|
||||||
#include "xenia/cpu/runtime.h"
|
#include "xenia/cpu/processor.h"
|
||||||
#include "xenia/profiling.h"
|
#include "xenia/profiling.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
#include "xenia/cpu/backend/backend.h"
|
#include "xenia/cpu/backend/backend.h"
|
||||||
#include "xenia/cpu/compiler/compiler.h"
|
#include "xenia/cpu/compiler/compiler.h"
|
||||||
#include "xenia/cpu/runtime.h"
|
#include "xenia/cpu/processor.h"
|
||||||
#include "xenia/profiling.h"
|
#include "xenia/profiling.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
#include "xenia/base/platform.h"
|
#include "xenia/base/platform.h"
|
||||||
#include "xenia/cpu/backend/backend.h"
|
#include "xenia/cpu/backend/backend.h"
|
||||||
#include "xenia/cpu/compiler/compiler.h"
|
#include "xenia/cpu/compiler/compiler.h"
|
||||||
#include "xenia/cpu/runtime.h"
|
#include "xenia/cpu/processor.h"
|
||||||
#include "xenia/profiling.h"
|
#include "xenia/profiling.h"
|
||||||
|
|
||||||
#if XE_COMPILER_MSVC
|
#if XE_COMPILER_MSVC
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
#include "xenia/cpu/backend/backend.h"
|
#include "xenia/cpu/backend/backend.h"
|
||||||
#include "xenia/cpu/compiler/compiler.h"
|
#include "xenia/cpu/compiler/compiler.h"
|
||||||
#include "xenia/cpu/runtime.h"
|
#include "xenia/cpu/processor.h"
|
||||||
#include "xenia/profiling.h"
|
#include "xenia/profiling.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#include "xenia/base/assert.h"
|
#include "xenia/base/assert.h"
|
||||||
#include "xenia/cpu/backend/backend.h"
|
#include "xenia/cpu/backend/backend.h"
|
||||||
#include "xenia/cpu/compiler/compiler.h"
|
#include "xenia/cpu/compiler/compiler.h"
|
||||||
#include "xenia/cpu/runtime.h"
|
#include "xenia/cpu/processor.h"
|
||||||
#include "xenia/profiling.h"
|
#include "xenia/profiling.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#include "xenia/base/platform.h"
|
#include "xenia/base/platform.h"
|
||||||
#include "xenia/cpu/backend/backend.h"
|
#include "xenia/cpu/backend/backend.h"
|
||||||
#include "xenia/cpu/compiler/compiler.h"
|
#include "xenia/cpu/compiler/compiler.h"
|
||||||
#include "xenia/cpu/runtime.h"
|
#include "xenia/cpu/processor.h"
|
||||||
#include "xenia/profiling.h"
|
#include "xenia/profiling.h"
|
||||||
|
|
||||||
#if XE_COMPILER_MSVC
|
#if XE_COMPILER_MSVC
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
|
|
||||||
#include <gflags/gflags.h>
|
#include <gflags/gflags.h>
|
||||||
|
|
||||||
|
DECLARE_string(processor_backend);
|
||||||
|
|
||||||
DECLARE_string(load_module_map);
|
DECLARE_string(load_module_map);
|
||||||
|
|
||||||
DECLARE_string(dump_path);
|
DECLARE_string(dump_path);
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
|
|
||||||
#include "xenia/cpu/cpu-private.h"
|
#include "xenia/cpu/cpu-private.h"
|
||||||
|
|
||||||
|
DEFINE_string(processor_backend, "any", "CPU backend [any, x64].");
|
||||||
|
|
||||||
// Debugging:
|
// Debugging:
|
||||||
DEFINE_string(
|
DEFINE_string(
|
||||||
load_module_map, "",
|
load_module_map, "",
|
||||||
|
|
|
@ -13,9 +13,7 @@
|
||||||
#include "xenia/cpu/processor.h"
|
#include "xenia/cpu/processor.h"
|
||||||
#include "xenia/cpu/function.h"
|
#include "xenia/cpu/function.h"
|
||||||
#include "xenia/cpu/module.h"
|
#include "xenia/cpu/module.h"
|
||||||
#include "xenia/cpu/runtime.h"
|
#include "xenia/cpu/processor.h"
|
||||||
#include "xenia/cpu/thread_state.h"
|
|
||||||
#include "xenia/cpu/runtime.h"
|
|
||||||
#include "xenia/cpu/thread_state.h"
|
#include "xenia/cpu/thread_state.h"
|
||||||
#include "xenia/cpu/xex_module.h"
|
#include "xenia/cpu/xex_module.h"
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
#include "xenia/cpu/function.h"
|
#include "xenia/cpu/function.h"
|
||||||
#include "xenia/cpu/runtime.h"
|
#include "xenia/cpu/processor.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
|
@ -22,7 +22,7 @@ Breakpoint::Breakpoint(Type type, uint32_t address)
|
||||||
|
|
||||||
Breakpoint::~Breakpoint() = default;
|
Breakpoint::~Breakpoint() = default;
|
||||||
|
|
||||||
Debugger::Debugger(Runtime* runtime) : runtime_(runtime) {}
|
Debugger::Debugger(Processor* processor) : processor_(processor) {}
|
||||||
|
|
||||||
Debugger::~Debugger() = default;
|
Debugger::~Debugger() = default;
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ int Debugger::AddBreakpoint(Breakpoint* breakpoint) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find all functions that contain the breakpoint address.
|
// Find all functions that contain the breakpoint address.
|
||||||
auto fns = runtime_->FindFunctionsWithAddress(breakpoint->address());
|
auto fns = processor_->FindFunctionsWithAddress(breakpoint->address());
|
||||||
|
|
||||||
// Add.
|
// Add.
|
||||||
for (auto fn : fns) {
|
for (auto fn : fns) {
|
||||||
|
@ -116,7 +116,7 @@ int Debugger::RemoveBreakpoint(Breakpoint* breakpoint) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find all functions that have the breakpoint set.
|
// Find all functions that have the breakpoint set.
|
||||||
auto fns = runtime_->FindFunctionsWithAddress(breakpoint->address());
|
auto fns = processor_->FindFunctionsWithAddress(breakpoint->address());
|
||||||
|
|
||||||
// Remove.
|
// Remove.
|
||||||
for (auto fn : fns) {
|
for (auto fn : fns) {
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace cpu {
|
||||||
class Debugger;
|
class Debugger;
|
||||||
class Function;
|
class Function;
|
||||||
class FunctionInfo;
|
class FunctionInfo;
|
||||||
class Runtime;
|
class Processor;
|
||||||
|
|
||||||
class Breakpoint {
|
class Breakpoint {
|
||||||
public:
|
public:
|
||||||
|
@ -78,10 +78,10 @@ class BreakpointHitEvent : public DebugEvent {
|
||||||
|
|
||||||
class Debugger {
|
class Debugger {
|
||||||
public:
|
public:
|
||||||
Debugger(Runtime* runtime);
|
Debugger(Processor* processor);
|
||||||
~Debugger();
|
~Debugger();
|
||||||
|
|
||||||
Runtime* runtime() const { return runtime_; }
|
Processor* processor() const { return processor_; }
|
||||||
|
|
||||||
int SuspendAllThreads(uint32_t timeout_ms = UINT_MAX);
|
int SuspendAllThreads(uint32_t timeout_ms = UINT_MAX);
|
||||||
int ResumeThread(uint32_t thread_id);
|
int ResumeThread(uint32_t thread_id);
|
||||||
|
@ -107,7 +107,7 @@ class Debugger {
|
||||||
Delegate<BreakpointHitEvent> breakpoint_hit;
|
Delegate<BreakpointHitEvent> breakpoint_hit;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Runtime* runtime_;
|
Processor* processor_;
|
||||||
|
|
||||||
std::mutex threads_lock_;
|
std::mutex threads_lock_;
|
||||||
std::unordered_map<uint32_t, ThreadState*> threads_;
|
std::unordered_map<uint32_t, ThreadState*> threads_;
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
class Runtime;
|
class Processor;
|
||||||
class ThreadState;
|
class ThreadState;
|
||||||
} // namespace cpu
|
} // namespace cpu
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
@ -205,9 +205,9 @@ typedef struct alignas(64) PPCContext_s {
|
||||||
// Used to shuttle data into externs. Contents volatile.
|
// Used to shuttle data into externs. Contents volatile.
|
||||||
uint64_t scratch;
|
uint64_t scratch;
|
||||||
|
|
||||||
// Runtime-specific data pointer. Used on callbacks to get access to the
|
// Processor-specific data pointer. Used on callbacks to get access to the
|
||||||
// current runtime and its data.
|
// current runtime and its data.
|
||||||
Runtime* runtime;
|
Processor* processor;
|
||||||
|
|
||||||
uint8_t* physical_membase;
|
uint8_t* physical_membase;
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
#include "xenia/cpu/frontend/ppc_disasm.h"
|
#include "xenia/cpu/frontend/ppc_disasm.h"
|
||||||
#include "xenia/cpu/frontend/ppc_emit.h"
|
#include "xenia/cpu/frontend/ppc_emit.h"
|
||||||
#include "xenia/cpu/frontend/ppc_translator.h"
|
#include "xenia/cpu/frontend/ppc_translator.h"
|
||||||
#include "xenia/cpu/runtime.h"
|
#include "xenia/cpu/processor.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
|
@ -42,7 +42,7 @@ void InitializeIfNeeded() {
|
||||||
|
|
||||||
void CleanupOnShutdown() {}
|
void CleanupOnShutdown() {}
|
||||||
|
|
||||||
PPCFrontend::PPCFrontend(Runtime* runtime) : runtime_(runtime) {
|
PPCFrontend::PPCFrontend(Processor* processor) : processor_(processor) {
|
||||||
InitializeIfNeeded();
|
InitializeIfNeeded();
|
||||||
|
|
||||||
std::unique_ptr<ContextInfo> context_info(
|
std::unique_ptr<ContextInfo> context_info(
|
||||||
|
@ -57,7 +57,7 @@ PPCFrontend::~PPCFrontend() {
|
||||||
translator_pool_.Reset();
|
translator_pool_.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
Memory* PPCFrontend::memory() const { return runtime_->memory(); }
|
Memory* PPCFrontend::memory() const { return processor_->memory(); }
|
||||||
|
|
||||||
void CheckGlobalLock(PPCContext* ppc_state, void* arg0, void* arg1) {
|
void CheckGlobalLock(PPCContext* ppc_state, void* arg0, void* arg1) {
|
||||||
ppc_state->scratch = 0x8000;
|
ppc_state->scratch = 0x8000;
|
||||||
|
@ -78,10 +78,10 @@ void HandleGlobalLock(PPCContext* ppc_state, void* arg0, void* arg1) {
|
||||||
int PPCFrontend::Initialize() {
|
int PPCFrontend::Initialize() {
|
||||||
void* arg0 = reinterpret_cast<void*>(&builtins_.global_lock);
|
void* arg0 = reinterpret_cast<void*>(&builtins_.global_lock);
|
||||||
void* arg1 = reinterpret_cast<void*>(&builtins_.global_lock_taken);
|
void* arg1 = reinterpret_cast<void*>(&builtins_.global_lock_taken);
|
||||||
builtins_.check_global_lock = runtime_->DefineBuiltin(
|
builtins_.check_global_lock = processor_->DefineBuiltin(
|
||||||
"CheckGlobalLock", (FunctionInfo::ExternHandler)CheckGlobalLock, arg0,
|
"CheckGlobalLock", (FunctionInfo::ExternHandler)CheckGlobalLock, arg0,
|
||||||
arg1);
|
arg1);
|
||||||
builtins_.handle_global_lock = runtime_->DefineBuiltin(
|
builtins_.handle_global_lock = processor_->DefineBuiltin(
|
||||||
"HandleGlobalLock", (FunctionInfo::ExternHandler)HandleGlobalLock, arg0,
|
"HandleGlobalLock", (FunctionInfo::ExternHandler)HandleGlobalLock, arg0,
|
||||||
arg1);
|
arg1);
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
class Runtime;
|
class Processor;
|
||||||
} // namespace cpu
|
} // namespace cpu
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
||||||
|
@ -40,12 +40,12 @@ struct PPCBuiltins {
|
||||||
|
|
||||||
class PPCFrontend {
|
class PPCFrontend {
|
||||||
public:
|
public:
|
||||||
explicit PPCFrontend(Runtime* runtime);
|
explicit PPCFrontend(Processor* processor);
|
||||||
~PPCFrontend();
|
~PPCFrontend();
|
||||||
|
|
||||||
int Initialize();
|
int Initialize();
|
||||||
|
|
||||||
Runtime* runtime() const { return runtime_; }
|
Processor* processor() const { return processor_; }
|
||||||
Memory* memory() const;
|
Memory* memory() const;
|
||||||
ContextInfo* context_info() const { return context_info_.get(); }
|
ContextInfo* context_info() const { return context_info_.get(); }
|
||||||
PPCBuiltins* builtins() { return &builtins_; }
|
PPCBuiltins* builtins() { return &builtins_; }
|
||||||
|
@ -55,7 +55,7 @@ class PPCFrontend {
|
||||||
uint32_t trace_flags, Function** out_function);
|
uint32_t trace_flags, Function** out_function);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Runtime* runtime_;
|
Processor* processor_;
|
||||||
std::unique_ptr<ContextInfo> context_info_;
|
std::unique_ptr<ContextInfo> context_info_;
|
||||||
PPCBuiltins builtins_;
|
PPCBuiltins builtins_;
|
||||||
TypePool<PPCTranslator, PPCFrontend*> translator_pool_;
|
TypePool<PPCTranslator, PPCFrontend*> translator_pool_;
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
#include "xenia/cpu/frontend/ppc_frontend.h"
|
#include "xenia/cpu/frontend/ppc_frontend.h"
|
||||||
#include "xenia/cpu/frontend/ppc_instr.h"
|
#include "xenia/cpu/frontend/ppc_instr.h"
|
||||||
#include "xenia/cpu/hir/label.h"
|
#include "xenia/cpu/hir/label.h"
|
||||||
#include "xenia/cpu/runtime.h"
|
#include "xenia/cpu/processor.h"
|
||||||
#include "xenia/profiling.h"
|
#include "xenia/profiling.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
@ -152,9 +152,9 @@ void PPCHIRBuilder::AnnotateLabel(uint32_t address, Label* label) {
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionInfo* PPCHIRBuilder::LookupFunction(uint32_t address) {
|
FunctionInfo* PPCHIRBuilder::LookupFunction(uint32_t address) {
|
||||||
Runtime* runtime = frontend_->runtime();
|
Processor* processor = frontend_->processor();
|
||||||
FunctionInfo* symbol_info;
|
FunctionInfo* symbol_info;
|
||||||
if (runtime->LookupFunctionInfo(address, &symbol_info)) {
|
if (processor->LookupFunctionInfo(address, &symbol_info)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return symbol_info;
|
return symbol_info;
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
#include "xenia/base/memory.h"
|
#include "xenia/base/memory.h"
|
||||||
#include "xenia/cpu/frontend/ppc_frontend.h"
|
#include "xenia/cpu/frontend/ppc_frontend.h"
|
||||||
#include "xenia/cpu/frontend/ppc_instr.h"
|
#include "xenia/cpu/frontend/ppc_instr.h"
|
||||||
#include "xenia/cpu/runtime.h"
|
#include "xenia/cpu/processor.h"
|
||||||
#include "xenia/profiling.h"
|
#include "xenia/profiling.h"
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -35,7 +35,7 @@ PPCScanner::~PPCScanner() {}
|
||||||
|
|
||||||
bool PPCScanner::IsRestGprLr(uint32_t address) {
|
bool PPCScanner::IsRestGprLr(uint32_t address) {
|
||||||
FunctionInfo* symbol_info;
|
FunctionInfo* symbol_info;
|
||||||
if (frontend_->runtime()->LookupFunctionInfo(address, &symbol_info)) {
|
if (frontend_->processor()->LookupFunctionInfo(address, &symbol_info)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return symbol_info->behavior() == FunctionInfo::BEHAVIOR_EPILOG_RETURN;
|
return symbol_info->behavior() == FunctionInfo::BEHAVIOR_EPILOG_RETURN;
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#include "xenia/cpu/frontend/ppc_hir_builder.h"
|
#include "xenia/cpu/frontend/ppc_hir_builder.h"
|
||||||
#include "xenia/cpu/frontend/ppc_instr.h"
|
#include "xenia/cpu/frontend/ppc_instr.h"
|
||||||
#include "xenia/cpu/frontend/ppc_scanner.h"
|
#include "xenia/cpu/frontend/ppc_scanner.h"
|
||||||
#include "xenia/cpu/runtime.h"
|
#include "xenia/cpu/processor.h"
|
||||||
#include "xenia/profiling.h"
|
#include "xenia/profiling.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
@ -35,11 +35,11 @@ using xe::cpu::compiler::Compiler;
|
||||||
namespace passes = xe::cpu::compiler::passes;
|
namespace passes = xe::cpu::compiler::passes;
|
||||||
|
|
||||||
PPCTranslator::PPCTranslator(PPCFrontend* frontend) : frontend_(frontend) {
|
PPCTranslator::PPCTranslator(PPCFrontend* frontend) : frontend_(frontend) {
|
||||||
Backend* backend = frontend->runtime()->backend();
|
Backend* backend = frontend->processor()->backend();
|
||||||
|
|
||||||
scanner_.reset(new PPCScanner(frontend));
|
scanner_.reset(new PPCScanner(frontend));
|
||||||
builder_.reset(new PPCHIRBuilder(frontend));
|
builder_.reset(new PPCHIRBuilder(frontend));
|
||||||
compiler_.reset(new Compiler(frontend->runtime()));
|
compiler_.reset(new Compiler(frontend->processor()));
|
||||||
assembler_ = std::move(backend->CreateAssembler());
|
assembler_ = std::move(backend->CreateAssembler());
|
||||||
assembler_->Initialize();
|
assembler_->Initialize();
|
||||||
|
|
||||||
|
|
|
@ -175,30 +175,30 @@ class TestRunner {
|
||||||
memory.reset(new Memory());
|
memory.reset(new Memory());
|
||||||
memory->Initialize();
|
memory->Initialize();
|
||||||
|
|
||||||
runtime.reset(new Runtime(memory.get(), nullptr, 0, 0));
|
processor.reset(new Processor(memory.get(), nullptr));
|
||||||
runtime->Initialize(nullptr);
|
processor->Setup();
|
||||||
}
|
}
|
||||||
|
|
||||||
~TestRunner() {
|
~TestRunner() {
|
||||||
thread_state.reset();
|
thread_state.reset();
|
||||||
runtime.reset();
|
processor.reset();
|
||||||
memory.reset();
|
memory.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Setup(TestSuite& suite) {
|
bool Setup(TestSuite& suite) {
|
||||||
// Load the binary module.
|
// Load the binary module.
|
||||||
auto module = std::make_unique<xe::cpu::RawModule>(runtime.get());
|
auto module = std::make_unique<xe::cpu::RawModule>(processor.get());
|
||||||
if (module->LoadFile(START_ADDRESS, suite.bin_file_path)) {
|
if (module->LoadFile(START_ADDRESS, suite.bin_file_path)) {
|
||||||
XELOGE("Unable to load test binary %ls", suite.bin_file_path.c_str());
|
XELOGE("Unable to load test binary %ls", suite.bin_file_path.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
runtime->AddModule(std::move(module));
|
processor->AddModule(std::move(module));
|
||||||
|
|
||||||
// Simulate a thread.
|
// Simulate a thread.
|
||||||
uint32_t stack_size = 64 * 1024;
|
uint32_t stack_size = 64 * 1024;
|
||||||
uint32_t stack_address = START_ADDRESS - stack_size;
|
uint32_t stack_address = START_ADDRESS - stack_size;
|
||||||
uint32_t thread_state_address = stack_address - 0x1000;
|
uint32_t thread_state_address = stack_address - 0x1000;
|
||||||
thread_state.reset(new ThreadState(runtime.get(), 0x100, stack_address,
|
thread_state.reset(new ThreadState(processor.get(), 0x100, stack_address,
|
||||||
stack_size, thread_state_address));
|
stack_size, thread_state_address));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -213,7 +213,7 @@ class TestRunner {
|
||||||
|
|
||||||
// Execute test.
|
// Execute test.
|
||||||
xe::cpu::Function* fn;
|
xe::cpu::Function* fn;
|
||||||
runtime->ResolveFunction(test_case.address, &fn);
|
processor->ResolveFunction(test_case.address, &fn);
|
||||||
if (!fn) {
|
if (!fn) {
|
||||||
XELOGE("Entry function not found");
|
XELOGE("Entry function not found");
|
||||||
return false;
|
return false;
|
||||||
|
@ -313,7 +313,7 @@ class TestRunner {
|
||||||
|
|
||||||
size_t memory_size;
|
size_t memory_size;
|
||||||
std::unique_ptr<Memory> memory;
|
std::unique_ptr<Memory> memory;
|
||||||
std::unique_ptr<Runtime> runtime;
|
std::unique_ptr<Processor> processor;
|
||||||
std::unique_ptr<ThreadState> thread_state;
|
std::unique_ptr<ThreadState> thread_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -11,13 +11,15 @@
|
||||||
|
|
||||||
#include "xenia/memory.h"
|
#include "xenia/memory.h"
|
||||||
#include "xenia/cpu/function.h"
|
#include "xenia/cpu/function.h"
|
||||||
#include "xenia/cpu/runtime.h"
|
#include "xenia/cpu/processor.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
|
|
||||||
Instrument::Instrument(Runtime* runtime)
|
Instrument::Instrument(Processor* processor)
|
||||||
: runtime_(runtime), memory_(runtime->memory()), is_attached_(false) {}
|
: processor_(processor),
|
||||||
|
memory_(processor->memory()),
|
||||||
|
is_attached_(false) {}
|
||||||
|
|
||||||
Instrument::~Instrument() {
|
Instrument::~Instrument() {
|
||||||
if (is_attached_) {
|
if (is_attached_) {
|
||||||
|
@ -43,8 +45,8 @@ bool Instrument::Detach() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionInstrument::FunctionInstrument(Runtime* runtime, Function* function)
|
FunctionInstrument::FunctionInstrument(Processor* processor, Function* function)
|
||||||
: Instrument(runtime), target_(function) {}
|
: Instrument(processor), target_(function) {}
|
||||||
|
|
||||||
bool FunctionInstrument::Attach() {
|
bool FunctionInstrument::Attach() {
|
||||||
if (!Instrument::Attach()) {
|
if (!Instrument::Attach()) {
|
||||||
|
@ -78,9 +80,9 @@ void FunctionInstrument::Exit(ThreadState* thread_state) {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryInstrument::MemoryInstrument(Runtime* runtime, uint32_t address,
|
MemoryInstrument::MemoryInstrument(Processor* processor, uint32_t address,
|
||||||
uint32_t end_address)
|
uint32_t end_address)
|
||||||
: Instrument(runtime), address_(address), end_address_(end_address) {}
|
: Instrument(processor), address_(address), end_address_(end_address) {}
|
||||||
|
|
||||||
bool MemoryInstrument::Attach() {
|
bool MemoryInstrument::Attach() {
|
||||||
if (!Instrument::Attach()) {
|
if (!Instrument::Attach()) {
|
||||||
|
|
|
@ -12,25 +12,20 @@
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
namespace xe {
|
|
||||||
namespace cpu {
|
|
||||||
class Memory;
|
|
||||||
class ThreadState;
|
|
||||||
} // namespace cpu
|
|
||||||
} // namespace xe
|
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
|
|
||||||
class Function;
|
class Function;
|
||||||
class Runtime;
|
class Memory;
|
||||||
|
class Processor;
|
||||||
|
class ThreadState;
|
||||||
|
|
||||||
class Instrument {
|
class Instrument {
|
||||||
public:
|
public:
|
||||||
Instrument(Runtime* runtime);
|
Instrument(Processor* processor);
|
||||||
virtual ~Instrument();
|
virtual ~Instrument();
|
||||||
|
|
||||||
Runtime* runtime() const { return runtime_; }
|
Processor* processor() const { return processor_; }
|
||||||
Memory* memory() const { return memory_; }
|
Memory* memory() const { return memory_; }
|
||||||
bool is_attached() const { return is_attached_; }
|
bool is_attached() const { return is_attached_; }
|
||||||
|
|
||||||
|
@ -38,14 +33,14 @@ class Instrument {
|
||||||
virtual bool Detach();
|
virtual bool Detach();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Runtime* runtime_;
|
Processor* processor_;
|
||||||
Memory* memory_;
|
Memory* memory_;
|
||||||
bool is_attached_;
|
bool is_attached_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class FunctionInstrument : public Instrument {
|
class FunctionInstrument : public Instrument {
|
||||||
public:
|
public:
|
||||||
FunctionInstrument(Runtime* runtime, Function* function);
|
FunctionInstrument(Processor* processor, Function* function);
|
||||||
virtual ~FunctionInstrument() {}
|
virtual ~FunctionInstrument() {}
|
||||||
|
|
||||||
Function* target() const { return target_; }
|
Function* target() const { return target_; }
|
||||||
|
@ -86,7 +81,8 @@ class FunctionInstrument : public Instrument {
|
||||||
|
|
||||||
class MemoryInstrument : public Instrument {
|
class MemoryInstrument : public Instrument {
|
||||||
public:
|
public:
|
||||||
MemoryInstrument(Runtime* runtime, uint32_t address, uint32_t end_address);
|
MemoryInstrument(Processor* processor, uint32_t address,
|
||||||
|
uint32_t end_address);
|
||||||
virtual ~MemoryInstrument() {}
|
virtual ~MemoryInstrument() {}
|
||||||
|
|
||||||
uint64_t address() const { return address_; }
|
uint64_t address() const { return address_; }
|
||||||
|
|
|
@ -13,14 +13,14 @@
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#include "xenia/base/threading.h"
|
#include "xenia/base/threading.h"
|
||||||
#include "xenia/cpu/runtime.h"
|
#include "xenia/cpu/processor.h"
|
||||||
#include "xenia/profiling.h"
|
#include "xenia/profiling.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
|
|
||||||
Module::Module(Runtime* runtime)
|
Module::Module(Processor* processor)
|
||||||
: runtime_(runtime), memory_(runtime->memory()) {}
|
: processor_(processor), memory_(processor->memory()) {}
|
||||||
|
|
||||||
Module::~Module() = default;
|
Module::~Module() = default;
|
||||||
|
|
||||||
|
@ -225,7 +225,7 @@ int Module::ReadMap(const char* file_name) {
|
||||||
if (type_str == "f") {
|
if (type_str == "f") {
|
||||||
// Function.
|
// Function.
|
||||||
FunctionInfo* fn_info;
|
FunctionInfo* fn_info;
|
||||||
if (runtime_->LookupFunctionInfo(this, address, &fn_info)) {
|
if (processor_->LookupFunctionInfo(this, address, &fn_info)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Don't overwrite names we've set elsewhere.
|
// Don't overwrite names we've set elsewhere.
|
||||||
|
|
|
@ -23,11 +23,11 @@ namespace xe {
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
|
|
||||||
class Function;
|
class Function;
|
||||||
class Runtime;
|
class Processor;
|
||||||
|
|
||||||
class Module {
|
class Module {
|
||||||
public:
|
public:
|
||||||
Module(Runtime* runtime);
|
Module(Processor* processor);
|
||||||
virtual ~Module();
|
virtual ~Module();
|
||||||
|
|
||||||
Memory* memory() const { return memory_; }
|
Memory* memory() const { return memory_; }
|
||||||
|
@ -57,7 +57,7 @@ class Module {
|
||||||
SymbolInfo::Status DefineSymbol(SymbolInfo* symbol_info);
|
SymbolInfo::Status DefineSymbol(SymbolInfo* symbol_info);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Runtime* runtime_;
|
Processor* processor_;
|
||||||
Memory* memory_;
|
Memory* memory_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -9,16 +9,24 @@
|
||||||
|
|
||||||
#include "xenia/cpu/processor.h"
|
#include "xenia/cpu/processor.h"
|
||||||
|
|
||||||
|
#include <gflags/gflags.h>
|
||||||
|
|
||||||
|
#include "xenia/base/assert.h"
|
||||||
#include "xenia/base/atomic.h"
|
#include "xenia/base/atomic.h"
|
||||||
#include "xenia/base/byte_order.h"
|
#include "xenia/base/byte_order.h"
|
||||||
#include "xenia/base/logging.h"
|
#include "xenia/base/logging.h"
|
||||||
#include "xenia/base/memory.h"
|
#include "xenia/base/memory.h"
|
||||||
#include "xenia/cpu/cpu-private.h"
|
#include "xenia/cpu/cpu-private.h"
|
||||||
#include "xenia/cpu/export_resolver.h"
|
#include "xenia/cpu/export_resolver.h"
|
||||||
#include "xenia/cpu/runtime.h"
|
#include "xenia/cpu/frontend/ppc_frontend.h"
|
||||||
|
#include "xenia/cpu/module.h"
|
||||||
|
#include "xenia/cpu/thread_state.h"
|
||||||
#include "xenia/cpu/xex_module.h"
|
#include "xenia/cpu/xex_module.h"
|
||||||
#include "xenia/profiling.h"
|
#include "xenia/profiling.h"
|
||||||
|
|
||||||
|
// TODO(benvanik): based on compiler support
|
||||||
|
#include "xenia/cpu/backend/x64/x64_backend.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
|
|
||||||
|
@ -49,11 +57,26 @@ void InitializeIfNeeded() {
|
||||||
|
|
||||||
void CleanupOnShutdown() {}
|
void CleanupOnShutdown() {}
|
||||||
|
|
||||||
|
class BuiltinModule : public Module {
|
||||||
|
public:
|
||||||
|
BuiltinModule(Processor* processor) : Module(processor), name_("builtin") {}
|
||||||
|
const std::string& name() const override { return name_; }
|
||||||
|
bool ContainsAddress(uint32_t address) override {
|
||||||
|
return (address & 0xFFFFFFF0) == 0xFFFFFFF0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string name_;
|
||||||
|
};
|
||||||
|
|
||||||
Processor::Processor(xe::Memory* memory, ExportResolver* export_resolver)
|
Processor::Processor(xe::Memory* memory, ExportResolver* export_resolver)
|
||||||
: export_resolver_(export_resolver),
|
: memory_(memory),
|
||||||
runtime_(0),
|
debug_info_flags_(0),
|
||||||
memory_(memory),
|
trace_flags_(0),
|
||||||
interrupt_thread_state_(NULL),
|
builtin_module_(nullptr),
|
||||||
|
next_builtin_address_(0xFFFF0000ul),
|
||||||
|
export_resolver_(export_resolver),
|
||||||
|
interrupt_thread_state_(nullptr),
|
||||||
interrupt_thread_block_(0) {
|
interrupt_thread_block_(0) {
|
||||||
InitializeIfNeeded();
|
InitializeIfNeeded();
|
||||||
}
|
}
|
||||||
|
@ -64,29 +87,71 @@ Processor::~Processor() {
|
||||||
delete interrupt_thread_state_;
|
delete interrupt_thread_state_;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete runtime_;
|
{
|
||||||
|
std::lock_guard<std::mutex> guard(modules_lock_);
|
||||||
|
modules_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
debugger_.reset();
|
||||||
|
frontend_.reset();
|
||||||
|
backend_.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
int Processor::Setup() {
|
int Processor::Setup() {
|
||||||
assert_null(runtime_);
|
debug_info_flags_ = DEBUG_INFO_DEFAULT;
|
||||||
|
trace_flags_ = 0;
|
||||||
|
|
||||||
uint32_t debug_info_flags = DEBUG_INFO_DEFAULT;
|
auto frontend = std::make_unique<xe::cpu::frontend::PPCFrontend>(this);
|
||||||
uint32_t trace_flags = 0;
|
// TODO(benvanik): set options/etc.
|
||||||
|
|
||||||
runtime_ =
|
// Must be initialized by subclass before calling into this.
|
||||||
new Runtime(memory_, export_resolver_, debug_info_flags, trace_flags);
|
assert_not_null(memory_);
|
||||||
if (!runtime_) {
|
|
||||||
|
// Create debugger first. Other types hook up to it.
|
||||||
|
debugger_.reset(new Debugger(this));
|
||||||
|
|
||||||
|
std::unique_ptr<Module> builtin_module(new BuiltinModule(this));
|
||||||
|
builtin_module_ = builtin_module.get();
|
||||||
|
modules_.push_back(std::move(builtin_module));
|
||||||
|
|
||||||
|
if (frontend_ || backend_) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Backend> backend;
|
std::unique_ptr<xe::cpu::backend::Backend> backend;
|
||||||
// backend.reset(new xe::cpu::backend::x64::X64Backend(runtime));
|
if (!backend) {
|
||||||
int result = runtime_->Initialize(std::move(backend));
|
#if defined(XENIA_HAS_X64_BACKEND) && XENIA_HAS_X64_BACKEND
|
||||||
|
if (FLAGS_processor_backend == "x64") {
|
||||||
|
backend.reset(new xe::cpu::backend::x64::X64Backend(this));
|
||||||
|
}
|
||||||
|
#endif // XENIA_HAS_X64_BACKEND
|
||||||
|
if (FLAGS_processor_backend == "any") {
|
||||||
|
#if defined(XENIA_HAS_X64_BACKEND) && XENIA_HAS_X64_BACKEND
|
||||||
|
if (!backend) {
|
||||||
|
backend.reset(new xe::cpu::backend::x64::X64Backend(this));
|
||||||
|
}
|
||||||
|
#endif // XENIA_HAS_X64_BACKEND
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!backend) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = backend->Initialize();
|
||||||
if (result) {
|
if (result) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
interrupt_thread_state_ = new ThreadState(runtime_, 0, 0, 16 * 1024, 0);
|
result = frontend->Initialize();
|
||||||
|
if (result) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
backend_ = std::move(backend);
|
||||||
|
frontend_ = std::move(frontend);
|
||||||
|
|
||||||
|
interrupt_thread_state_ = new ThreadState(this, 0, 0, 16 * 1024, 0);
|
||||||
interrupt_thread_state_->set_name("Interrupt");
|
interrupt_thread_state_->set_name("Interrupt");
|
||||||
interrupt_thread_block_ = memory_->SystemHeapAlloc(2048);
|
interrupt_thread_block_ = memory_->SystemHeapAlloc(2048);
|
||||||
interrupt_thread_state_->context()->r[13] = interrupt_thread_block_;
|
interrupt_thread_state_->context()->r[13] = interrupt_thread_block_;
|
||||||
|
@ -94,12 +159,173 @@ int Processor::Setup() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Processor::AddModule(std::unique_ptr<Module> module) {
|
||||||
|
std::lock_guard<std::mutex> guard(modules_lock_);
|
||||||
|
modules_.push_back(std::move(module));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Module* Processor::GetModule(const char* name) {
|
||||||
|
std::lock_guard<std::mutex> guard(modules_lock_);
|
||||||
|
for (const auto& module : modules_) {
|
||||||
|
if (module->name() == name) {
|
||||||
|
return module.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Module*> Processor::GetModules() {
|
||||||
|
std::lock_guard<std::mutex> guard(modules_lock_);
|
||||||
|
std::vector<Module*> clone(modules_.size());
|
||||||
|
for (const auto& module : modules_) {
|
||||||
|
clone.push_back(module.get());
|
||||||
|
}
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
|
||||||
|
FunctionInfo* Processor::DefineBuiltin(const std::string& name,
|
||||||
|
FunctionInfo::ExternHandler handler,
|
||||||
|
void* arg0, void* arg1) {
|
||||||
|
uint32_t address = next_builtin_address_;
|
||||||
|
next_builtin_address_ += 4;
|
||||||
|
|
||||||
|
FunctionInfo* fn_info;
|
||||||
|
builtin_module_->DeclareFunction(address, &fn_info);
|
||||||
|
fn_info->set_end_address(address + 4);
|
||||||
|
fn_info->set_name(name);
|
||||||
|
fn_info->SetupExtern(handler, arg0, arg1);
|
||||||
|
fn_info->set_status(SymbolInfo::STATUS_DECLARED);
|
||||||
|
|
||||||
|
return fn_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Function*> Processor::FindFunctionsWithAddress(uint32_t address) {
|
||||||
|
return entry_table_.FindWithAddress(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Processor::ResolveFunction(uint32_t address, Function** out_function) {
|
||||||
|
*out_function = nullptr;
|
||||||
|
Entry* entry;
|
||||||
|
Entry::Status status = entry_table_.GetOrCreate(address, &entry);
|
||||||
|
if (status == Entry::STATUS_NEW) {
|
||||||
|
// Needs to be generated. We have the 'lock' on it and must do so now.
|
||||||
|
|
||||||
|
// Grab symbol declaration.
|
||||||
|
FunctionInfo* symbol_info;
|
||||||
|
int result = LookupFunctionInfo(address, &symbol_info);
|
||||||
|
if (result) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = DemandFunction(symbol_info, &entry->function);
|
||||||
|
if (result) {
|
||||||
|
entry->status = Entry::STATUS_FAILED;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
entry->end_address = symbol_info->end_address();
|
||||||
|
status = entry->status = Entry::STATUS_READY;
|
||||||
|
}
|
||||||
|
if (status == Entry::STATUS_READY) {
|
||||||
|
// Ready to use.
|
||||||
|
*out_function = entry->function;
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
// Failed or bad state.
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int Processor::LookupFunctionInfo(uint32_t address,
|
||||||
|
FunctionInfo** out_symbol_info) {
|
||||||
|
*out_symbol_info = nullptr;
|
||||||
|
|
||||||
|
// TODO(benvanik): fast reject invalid addresses/log errors.
|
||||||
|
|
||||||
|
// Find the module that contains the address.
|
||||||
|
Module* code_module = nullptr;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> guard(modules_lock_);
|
||||||
|
// TODO(benvanik): sort by code address (if contiguous) so can bsearch.
|
||||||
|
// TODO(benvanik): cache last module low/high, as likely to be in there.
|
||||||
|
for (const auto& module : modules_) {
|
||||||
|
if (module->ContainsAddress(address)) {
|
||||||
|
code_module = module.get();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!code_module) {
|
||||||
|
// No module found that could contain the address.
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return LookupFunctionInfo(code_module, address, out_symbol_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Processor::LookupFunctionInfo(Module* module, uint32_t address,
|
||||||
|
FunctionInfo** out_symbol_info) {
|
||||||
|
// Atomic create/lookup symbol in module.
|
||||||
|
// If we get back the NEW flag we must declare it now.
|
||||||
|
FunctionInfo* symbol_info = nullptr;
|
||||||
|
SymbolInfo::Status symbol_status =
|
||||||
|
module->DeclareFunction(address, &symbol_info);
|
||||||
|
if (symbol_status == SymbolInfo::STATUS_NEW) {
|
||||||
|
// Symbol is undeclared, so declare now.
|
||||||
|
int result = frontend_->DeclareFunction(symbol_info);
|
||||||
|
if (result) {
|
||||||
|
symbol_info->set_status(SymbolInfo::STATUS_FAILED);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
symbol_info->set_status(SymbolInfo::STATUS_DECLARED);
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_symbol_info = symbol_info;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Processor::DemandFunction(FunctionInfo* symbol_info,
|
||||||
|
Function** out_function) {
|
||||||
|
*out_function = nullptr;
|
||||||
|
|
||||||
|
// Lock function for generation. If it's already being generated
|
||||||
|
// by another thread this will block and return DECLARED.
|
||||||
|
Module* module = symbol_info->module();
|
||||||
|
SymbolInfo::Status symbol_status = module->DefineFunction(symbol_info);
|
||||||
|
if (symbol_status == SymbolInfo::STATUS_NEW) {
|
||||||
|
// Symbol is undefined, so define now.
|
||||||
|
Function* function = nullptr;
|
||||||
|
int result = frontend_->DefineFunction(symbol_info, debug_info_flags_,
|
||||||
|
trace_flags_, &function);
|
||||||
|
if (result) {
|
||||||
|
symbol_info->set_status(SymbolInfo::STATUS_FAILED);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
symbol_info->set_function(function);
|
||||||
|
|
||||||
|
// Before we give the symbol back to the rest, let the debugger know.
|
||||||
|
debugger_->OnFunctionDefined(symbol_info, function);
|
||||||
|
|
||||||
|
symbol_info->set_status(SymbolInfo::STATUS_DEFINED);
|
||||||
|
symbol_status = symbol_info->status();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (symbol_status == SymbolInfo::STATUS_FAILED) {
|
||||||
|
// Symbol likely failed.
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_function = symbol_info->function();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int Processor::Execute(ThreadState* thread_state, uint32_t address) {
|
int Processor::Execute(ThreadState* thread_state, uint32_t address) {
|
||||||
SCOPE_profile_cpu_f("cpu");
|
SCOPE_profile_cpu_f("cpu");
|
||||||
|
|
||||||
// Attempt to get the function.
|
// Attempt to get the function.
|
||||||
Function* fn;
|
Function* fn;
|
||||||
if (runtime_->ResolveFunction(address, &fn)) {
|
if (ResolveFunction(address, &fn)) {
|
||||||
// Symbol not found in any module.
|
// Symbol not found in any module.
|
||||||
XELOGCPU("Execute(%.8X): failed to find function", address);
|
XELOGCPU("Execute(%.8X): failed to find function", address);
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -13,7 +13,14 @@
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "xenia/cpu/backend/backend.h"
|
||||||
|
#include "xenia/cpu/debugger.h"
|
||||||
|
#include "xenia/cpu/entry_table.h"
|
||||||
#include "xenia/cpu/export_resolver.h"
|
#include "xenia/cpu/export_resolver.h"
|
||||||
|
#include "xenia/cpu/frontend/ppc_frontend.h"
|
||||||
|
#include "xenia/cpu/function.h"
|
||||||
|
#include "xenia/cpu/module.h"
|
||||||
|
#include "xenia/cpu/thread_state.h"
|
||||||
#include "xenia/memory.h"
|
#include "xenia/memory.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
@ -35,12 +42,31 @@ class Processor {
|
||||||
Processor(Memory* memory, ExportResolver* export_resolver);
|
Processor(Memory* memory, ExportResolver* export_resolver);
|
||||||
~Processor();
|
~Processor();
|
||||||
|
|
||||||
ExportResolver* export_resolver() const { return export_resolver_; }
|
|
||||||
Runtime* runtime() const { return runtime_; }
|
|
||||||
Memory* memory() const { return memory_; }
|
Memory* memory() const { return memory_; }
|
||||||
|
Debugger* debugger() const { return debugger_.get(); }
|
||||||
|
frontend::PPCFrontend* frontend() const { return frontend_.get(); }
|
||||||
|
backend::Backend* backend() const { return backend_.get(); }
|
||||||
|
ExportResolver* export_resolver() const { return export_resolver_; }
|
||||||
|
|
||||||
int Setup();
|
int Setup();
|
||||||
|
|
||||||
|
int AddModule(std::unique_ptr<Module> module);
|
||||||
|
Module* GetModule(const char* name);
|
||||||
|
Module* GetModule(const std::string& name) { return GetModule(name.c_str()); }
|
||||||
|
std::vector<Module*> GetModules();
|
||||||
|
|
||||||
|
Module* builtin_module() const { return builtin_module_; }
|
||||||
|
FunctionInfo* DefineBuiltin(const std::string& name,
|
||||||
|
FunctionInfo::ExternHandler handler, void* arg0,
|
||||||
|
void* arg1);
|
||||||
|
|
||||||
|
std::vector<Function*> FindFunctionsWithAddress(uint32_t address);
|
||||||
|
|
||||||
|
int LookupFunctionInfo(uint32_t address, FunctionInfo** out_symbol_info);
|
||||||
|
int LookupFunctionInfo(Module* module, uint32_t address,
|
||||||
|
FunctionInfo** out_symbol_info);
|
||||||
|
int ResolveFunction(uint32_t address, Function** out_function);
|
||||||
|
|
||||||
int Execute(ThreadState* thread_state, uint32_t address);
|
int Execute(ThreadState* thread_state, uint32_t address);
|
||||||
uint64_t Execute(ThreadState* thread_state, uint32_t address, uint64_t args[],
|
uint64_t Execute(ThreadState* thread_state, uint32_t address, uint64_t args[],
|
||||||
size_t arg_count);
|
size_t arg_count);
|
||||||
|
@ -52,10 +78,24 @@ class Processor {
|
||||||
size_t arg_count);
|
size_t arg_count);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
int DemandFunction(FunctionInfo* symbol_info, Function** out_function);
|
||||||
|
|
||||||
|
Memory* memory_;
|
||||||
|
|
||||||
|
uint32_t debug_info_flags_;
|
||||||
|
uint32_t trace_flags_;
|
||||||
|
|
||||||
|
std::unique_ptr<Debugger> debugger_;
|
||||||
|
|
||||||
|
std::unique_ptr<frontend::PPCFrontend> frontend_;
|
||||||
|
std::unique_ptr<backend::Backend> backend_;
|
||||||
ExportResolver* export_resolver_;
|
ExportResolver* export_resolver_;
|
||||||
|
|
||||||
Runtime* runtime_;
|
EntryTable entry_table_;
|
||||||
Memory* memory_;
|
std::mutex modules_lock_;
|
||||||
|
std::vector<std::unique_ptr<Module>> modules_;
|
||||||
|
Module* builtin_module_;
|
||||||
|
uint32_t next_builtin_address_;
|
||||||
|
|
||||||
Irql irql_;
|
Irql irql_;
|
||||||
std::mutex interrupt_thread_lock_;
|
std::mutex interrupt_thread_lock_;
|
||||||
|
|
|
@ -15,8 +15,8 @@
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
|
|
||||||
RawModule::RawModule(Runtime* runtime)
|
RawModule::RawModule(Processor* processor)
|
||||||
: Module(runtime), base_address_(0), low_address_(0), high_address_(0) {}
|
: Module(processor), base_address_(0), low_address_(0), high_address_(0) {}
|
||||||
|
|
||||||
RawModule::~RawModule() {}
|
RawModule::~RawModule() {}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ namespace cpu {
|
||||||
|
|
||||||
class RawModule : public Module {
|
class RawModule : public Module {
|
||||||
public:
|
public:
|
||||||
RawModule(Runtime* runtime);
|
RawModule(Processor* processor);
|
||||||
~RawModule() override;
|
~RawModule() override;
|
||||||
|
|
||||||
int LoadFile(uint32_t base_address, const std::wstring& path);
|
int LoadFile(uint32_t base_address, const std::wstring& path);
|
||||||
|
|
|
@ -1,274 +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. *
|
|
||||||
******************************************************************************
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "xenia/cpu/runtime.h"
|
|
||||||
|
|
||||||
#include <gflags/gflags.h>
|
|
||||||
|
|
||||||
#include "xenia/base/assert.h"
|
|
||||||
#include "xenia/cpu/frontend/ppc_frontend.h"
|
|
||||||
#include "xenia/cpu/module.h"
|
|
||||||
#include "xenia/cpu/thread_state.h"
|
|
||||||
|
|
||||||
// TODO(benvanik): based on compiler support
|
|
||||||
#include "xenia/cpu/backend/x64/x64_backend.h"
|
|
||||||
|
|
||||||
DEFINE_string(runtime_backend, "any", "Runtime backend [any, x64].");
|
|
||||||
|
|
||||||
namespace xe {
|
|
||||||
namespace cpu {
|
|
||||||
|
|
||||||
class BuiltinModule : public Module {
|
|
||||||
public:
|
|
||||||
BuiltinModule(Runtime* runtime) : Module(runtime), name_("builtin") {}
|
|
||||||
const std::string& name() const override { return name_; }
|
|
||||||
bool ContainsAddress(uint32_t address) override {
|
|
||||||
return (address & 0xFFFFFFF0) == 0xFFFFFFF0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string name_;
|
|
||||||
};
|
|
||||||
|
|
||||||
Runtime::Runtime(Memory* memory, ExportResolver* export_resolver,
|
|
||||||
uint32_t debug_info_flags, uint32_t trace_flags)
|
|
||||||
: memory_(memory),
|
|
||||||
debug_info_flags_(debug_info_flags),
|
|
||||||
trace_flags_(trace_flags),
|
|
||||||
builtin_module_(nullptr),
|
|
||||||
next_builtin_address_(0xFFFF0000ul),
|
|
||||||
export_resolver_(export_resolver) {}
|
|
||||||
|
|
||||||
Runtime::~Runtime() {
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> guard(modules_lock_);
|
|
||||||
modules_.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
debugger_.reset();
|
|
||||||
frontend_.reset();
|
|
||||||
backend_.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
int Runtime::Initialize(std::unique_ptr<xe::cpu::backend::Backend> backend) {
|
|
||||||
auto frontend = std::make_unique<xe::cpu::frontend::PPCFrontend>(this);
|
|
||||||
// TODO(benvanik): set options/etc.
|
|
||||||
|
|
||||||
// Must be initialized by subclass before calling into this.
|
|
||||||
assert_not_null(memory_);
|
|
||||||
|
|
||||||
// Create debugger first. Other types hook up to it.
|
|
||||||
debugger_.reset(new Debugger(this));
|
|
||||||
|
|
||||||
std::unique_ptr<Module> builtin_module(new BuiltinModule(this));
|
|
||||||
builtin_module_ = builtin_module.get();
|
|
||||||
modules_.push_back(std::move(builtin_module));
|
|
||||||
|
|
||||||
if (frontend_ || backend_) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!backend) {
|
|
||||||
#if defined(XENIA_HAS_X64_BACKEND) && XENIA_HAS_X64_BACKEND
|
|
||||||
if (FLAGS_runtime_backend == "x64") {
|
|
||||||
backend.reset(new xe::cpu::backend::x64::X64Backend(this));
|
|
||||||
}
|
|
||||||
#endif // XENIA_HAS_X64_BACKEND
|
|
||||||
if (FLAGS_runtime_backend == "any") {
|
|
||||||
#if defined(XENIA_HAS_X64_BACKEND) && XENIA_HAS_X64_BACKEND
|
|
||||||
if (!backend) {
|
|
||||||
backend.reset(new xe::cpu::backend::x64::X64Backend(this));
|
|
||||||
}
|
|
||||||
#endif // XENIA_HAS_X64_BACKEND
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!backend) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int result = backend->Initialize();
|
|
||||||
if (result) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = frontend->Initialize();
|
|
||||||
if (result) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
backend_ = std::move(backend);
|
|
||||||
frontend_ = std::move(frontend);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Runtime::AddModule(std::unique_ptr<Module> module) {
|
|
||||||
std::lock_guard<std::mutex> guard(modules_lock_);
|
|
||||||
modules_.push_back(std::move(module));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Module* Runtime::GetModule(const char* name) {
|
|
||||||
std::lock_guard<std::mutex> guard(modules_lock_);
|
|
||||||
for (const auto& module : modules_) {
|
|
||||||
if (module->name() == name) {
|
|
||||||
return module.get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Module*> Runtime::GetModules() {
|
|
||||||
std::lock_guard<std::mutex> guard(modules_lock_);
|
|
||||||
std::vector<Module*> clone(modules_.size());
|
|
||||||
for (const auto& module : modules_) {
|
|
||||||
clone.push_back(module.get());
|
|
||||||
}
|
|
||||||
return clone;
|
|
||||||
}
|
|
||||||
|
|
||||||
FunctionInfo* Runtime::DefineBuiltin(const std::string& name,
|
|
||||||
FunctionInfo::ExternHandler handler,
|
|
||||||
void* arg0, void* arg1) {
|
|
||||||
uint32_t address = next_builtin_address_;
|
|
||||||
next_builtin_address_ += 4;
|
|
||||||
|
|
||||||
FunctionInfo* fn_info;
|
|
||||||
builtin_module_->DeclareFunction(address, &fn_info);
|
|
||||||
fn_info->set_end_address(address + 4);
|
|
||||||
fn_info->set_name(name);
|
|
||||||
fn_info->SetupExtern(handler, arg0, arg1);
|
|
||||||
fn_info->set_status(SymbolInfo::STATUS_DECLARED);
|
|
||||||
|
|
||||||
return fn_info;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Function*> Runtime::FindFunctionsWithAddress(uint32_t address) {
|
|
||||||
return entry_table_.FindWithAddress(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
int Runtime::ResolveFunction(uint32_t address, Function** out_function) {
|
|
||||||
*out_function = nullptr;
|
|
||||||
Entry* entry;
|
|
||||||
Entry::Status status = entry_table_.GetOrCreate(address, &entry);
|
|
||||||
if (status == Entry::STATUS_NEW) {
|
|
||||||
// Needs to be generated. We have the 'lock' on it and must do so now.
|
|
||||||
|
|
||||||
// Grab symbol declaration.
|
|
||||||
FunctionInfo* symbol_info;
|
|
||||||
int result = LookupFunctionInfo(address, &symbol_info);
|
|
||||||
if (result) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = DemandFunction(symbol_info, &entry->function);
|
|
||||||
if (result) {
|
|
||||||
entry->status = Entry::STATUS_FAILED;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
entry->end_address = symbol_info->end_address();
|
|
||||||
status = entry->status = Entry::STATUS_READY;
|
|
||||||
}
|
|
||||||
if (status == Entry::STATUS_READY) {
|
|
||||||
// Ready to use.
|
|
||||||
*out_function = entry->function;
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
// Failed or bad state.
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int Runtime::LookupFunctionInfo(uint32_t address,
|
|
||||||
FunctionInfo** out_symbol_info) {
|
|
||||||
*out_symbol_info = nullptr;
|
|
||||||
|
|
||||||
// TODO(benvanik): fast reject invalid addresses/log errors.
|
|
||||||
|
|
||||||
// Find the module that contains the address.
|
|
||||||
Module* code_module = nullptr;
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> guard(modules_lock_);
|
|
||||||
// TODO(benvanik): sort by code address (if contiguous) so can bsearch.
|
|
||||||
// TODO(benvanik): cache last module low/high, as likely to be in there.
|
|
||||||
for (const auto& module : modules_) {
|
|
||||||
if (module->ContainsAddress(address)) {
|
|
||||||
code_module = module.get();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!code_module) {
|
|
||||||
// No module found that could contain the address.
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return LookupFunctionInfo(code_module, address, out_symbol_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
int Runtime::LookupFunctionInfo(Module* module, uint32_t address,
|
|
||||||
FunctionInfo** out_symbol_info) {
|
|
||||||
// Atomic create/lookup symbol in module.
|
|
||||||
// If we get back the NEW flag we must declare it now.
|
|
||||||
FunctionInfo* symbol_info = nullptr;
|
|
||||||
SymbolInfo::Status symbol_status =
|
|
||||||
module->DeclareFunction(address, &symbol_info);
|
|
||||||
if (symbol_status == SymbolInfo::STATUS_NEW) {
|
|
||||||
// Symbol is undeclared, so declare now.
|
|
||||||
int result = frontend_->DeclareFunction(symbol_info);
|
|
||||||
if (result) {
|
|
||||||
symbol_info->set_status(SymbolInfo::STATUS_FAILED);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
symbol_info->set_status(SymbolInfo::STATUS_DECLARED);
|
|
||||||
}
|
|
||||||
|
|
||||||
*out_symbol_info = symbol_info;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Runtime::DemandFunction(FunctionInfo* symbol_info,
|
|
||||||
Function** out_function) {
|
|
||||||
*out_function = nullptr;
|
|
||||||
|
|
||||||
// Lock function for generation. If it's already being generated
|
|
||||||
// by another thread this will block and return DECLARED.
|
|
||||||
Module* module = symbol_info->module();
|
|
||||||
SymbolInfo::Status symbol_status = module->DefineFunction(symbol_info);
|
|
||||||
if (symbol_status == SymbolInfo::STATUS_NEW) {
|
|
||||||
// Symbol is undefined, so define now.
|
|
||||||
Function* function = nullptr;
|
|
||||||
int result = frontend_->DefineFunction(symbol_info, debug_info_flags_,
|
|
||||||
trace_flags_, &function);
|
|
||||||
if (result) {
|
|
||||||
symbol_info->set_status(SymbolInfo::STATUS_FAILED);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
symbol_info->set_function(function);
|
|
||||||
|
|
||||||
// Before we give the symbol back to the rest, let the debugger know.
|
|
||||||
debugger_->OnFunctionDefined(symbol_info, function);
|
|
||||||
|
|
||||||
symbol_info->set_status(SymbolInfo::STATUS_DEFINED);
|
|
||||||
symbol_status = symbol_info->status();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (symbol_status == SymbolInfo::STATUS_FAILED) {
|
|
||||||
// Symbol likely failed.
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
*out_function = symbol_info->function();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace cpu
|
|
||||||
} // namespace xe
|
|
|
@ -1,83 +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_RUNTIME_H_
|
|
||||||
#define XENIA_CPU_RUNTIME_H_
|
|
||||||
|
|
||||||
#include "xenia/cpu/backend/backend.h"
|
|
||||||
#include "xenia/cpu/debugger.h"
|
|
||||||
#include "xenia/cpu/entry_table.h"
|
|
||||||
#include "xenia/cpu/export_resolver.h"
|
|
||||||
#include "xenia/cpu/frontend/ppc_frontend.h"
|
|
||||||
#include "xenia/cpu/function.h"
|
|
||||||
#include "xenia/cpu/module.h"
|
|
||||||
#include "xenia/cpu/thread_state.h"
|
|
||||||
#include "xenia/memory.h"
|
|
||||||
|
|
||||||
namespace xe {
|
|
||||||
namespace cpu {
|
|
||||||
|
|
||||||
class Runtime {
|
|
||||||
public:
|
|
||||||
Runtime(Memory* memory, ExportResolver* export_resolver,
|
|
||||||
uint32_t debug_info_flags, uint32_t trace_flags);
|
|
||||||
~Runtime();
|
|
||||||
|
|
||||||
Memory* memory() const { return memory_; }
|
|
||||||
Debugger* debugger() const { return debugger_.get(); }
|
|
||||||
frontend::PPCFrontend* frontend() const { return frontend_.get(); }
|
|
||||||
backend::Backend* backend() const { return backend_.get(); }
|
|
||||||
ExportResolver* export_resolver() const { return export_resolver_; }
|
|
||||||
|
|
||||||
int Initialize(std::unique_ptr<backend::Backend> backend = 0);
|
|
||||||
|
|
||||||
int AddModule(std::unique_ptr<Module> module);
|
|
||||||
Module* GetModule(const char* name);
|
|
||||||
Module* GetModule(const std::string& name) { return GetModule(name.c_str()); }
|
|
||||||
std::vector<Module*> GetModules();
|
|
||||||
|
|
||||||
Module* builtin_module() const { return builtin_module_; }
|
|
||||||
FunctionInfo* DefineBuiltin(const std::string& name,
|
|
||||||
FunctionInfo::ExternHandler handler, void* arg0,
|
|
||||||
void* arg1);
|
|
||||||
|
|
||||||
std::vector<Function*> FindFunctionsWithAddress(uint32_t address);
|
|
||||||
|
|
||||||
int LookupFunctionInfo(uint32_t address, FunctionInfo** out_symbol_info);
|
|
||||||
int LookupFunctionInfo(Module* module, uint32_t address,
|
|
||||||
FunctionInfo** out_symbol_info);
|
|
||||||
int ResolveFunction(uint32_t address, Function** out_function);
|
|
||||||
|
|
||||||
// uint32_t CreateCallback(void (*callback)(void* data), void* data);
|
|
||||||
|
|
||||||
private:
|
|
||||||
int DemandFunction(FunctionInfo* symbol_info, Function** out_function);
|
|
||||||
|
|
||||||
Memory* memory_;
|
|
||||||
|
|
||||||
uint32_t debug_info_flags_;
|
|
||||||
uint32_t trace_flags_;
|
|
||||||
|
|
||||||
std::unique_ptr<Debugger> debugger_;
|
|
||||||
|
|
||||||
std::unique_ptr<frontend::PPCFrontend> frontend_;
|
|
||||||
std::unique_ptr<backend::Backend> backend_;
|
|
||||||
ExportResolver* export_resolver_;
|
|
||||||
|
|
||||||
EntryTable entry_table_;
|
|
||||||
std::mutex modules_lock_;
|
|
||||||
std::vector<std::unique_ptr<Module>> modules_;
|
|
||||||
Module* builtin_module_;
|
|
||||||
uint32_t next_builtin_address_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace cpu
|
|
||||||
} // namespace xe
|
|
||||||
|
|
||||||
#endif // XENIA_CPU_RUNTIME_H_
|
|
|
@ -24,8 +24,6 @@
|
||||||
'processor.h',
|
'processor.h',
|
||||||
'raw_module.cc',
|
'raw_module.cc',
|
||||||
'raw_module.h',
|
'raw_module.h',
|
||||||
'runtime.cc',
|
|
||||||
'runtime.h',
|
|
||||||
'symbol_info.cc',
|
'symbol_info.cc',
|
||||||
'symbol_info.h',
|
'symbol_info.h',
|
||||||
'test_module.cc',
|
'test_module.cc',
|
||||||
|
|
|
@ -38,44 +38,42 @@ class TestFunction {
|
||||||
|
|
||||||
#if XENIA_TEST_X64
|
#if XENIA_TEST_X64
|
||||||
{
|
{
|
||||||
auto runtime = std::make_unique<Runtime>(memory.get(), nullptr, 0, 0);
|
auto processor = std::make_unique<Processor>(memory.get(), nullptr);
|
||||||
auto backend =
|
processor->Setup();
|
||||||
std::make_unique<xe::cpu::backend::x64::X64Backend>(runtime.get());
|
processors.emplace_back(std::move(processor));
|
||||||
runtime->Initialize(std::move(backend));
|
|
||||||
runtimes.emplace_back(std::move(runtime));
|
|
||||||
}
|
}
|
||||||
#endif // XENIA_TEST_X64
|
#endif // XENIA_TEST_X64
|
||||||
|
|
||||||
for (auto& runtime : runtimes) {
|
for (auto& processor : processors) {
|
||||||
auto module = std::make_unique<xe::cpu::TestModule>(
|
auto module = std::make_unique<xe::cpu::TestModule>(
|
||||||
runtime.get(), "Test",
|
processor.get(), "Test",
|
||||||
[](uint64_t address) { return address == 0x1000; },
|
[](uint64_t address) { return address == 0x1000; },
|
||||||
[generator](hir::HIRBuilder& b) {
|
[generator](hir::HIRBuilder& b) {
|
||||||
generator(b);
|
generator(b);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
runtime->AddModule(std::move(module));
|
processor->AddModule(std::move(module));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
~TestFunction() {
|
~TestFunction() {
|
||||||
runtimes.clear();
|
processors.clear();
|
||||||
memory.reset();
|
memory.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Run(std::function<void(PPCContext*)> pre_call,
|
void Run(std::function<void(PPCContext*)> pre_call,
|
||||||
std::function<void(PPCContext*)> post_call) {
|
std::function<void(PPCContext*)> post_call) {
|
||||||
for (auto& runtime : runtimes) {
|
for (auto& processor : processors) {
|
||||||
memory->Zero(0, memory_size);
|
memory->Zero(0, memory_size);
|
||||||
|
|
||||||
xe::cpu::Function* fn;
|
xe::cpu::Function* fn;
|
||||||
runtime->ResolveFunction(0x1000, &fn);
|
processor->ResolveFunction(0x1000, &fn);
|
||||||
|
|
||||||
uint32_t stack_size = 64 * 1024;
|
uint32_t stack_size = 64 * 1024;
|
||||||
uint32_t stack_address = memory_size - stack_size;
|
uint32_t stack_address = memory_size - stack_size;
|
||||||
uint32_t thread_state_address = stack_address - 0x1000;
|
uint32_t thread_state_address = stack_address - 0x1000;
|
||||||
auto thread_state =
|
auto thread_state =
|
||||||
std::make_unique<ThreadState>(runtime.get(), 0x100, stack_address,
|
std::make_unique<ThreadState>(processor.get(), 0x100, stack_address,
|
||||||
stack_size, thread_state_address);
|
stack_size, thread_state_address);
|
||||||
auto ctx = thread_state->context();
|
auto ctx = thread_state->context();
|
||||||
ctx->lr = 0xBEBEBEBE;
|
ctx->lr = 0xBEBEBEBE;
|
||||||
|
@ -90,7 +88,7 @@ class TestFunction {
|
||||||
|
|
||||||
uint32_t memory_size;
|
uint32_t memory_size;
|
||||||
std::unique_ptr<Memory> memory;
|
std::unique_ptr<Memory> memory;
|
||||||
std::vector<std::unique_ptr<Runtime>> runtimes;
|
std::vector<std::unique_ptr<Processor>> processors;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline hir::Value* LoadGPR(hir::HIRBuilder& b, int reg) {
|
inline hir::Value* LoadGPR(hir::HIRBuilder& b, int reg) {
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
#include "xenia/base/reset_scope.h"
|
#include "xenia/base/reset_scope.h"
|
||||||
#include "xenia/base/string.h"
|
#include "xenia/base/string.h"
|
||||||
#include "xenia/cpu/compiler/compiler_passes.h"
|
#include "xenia/cpu/compiler/compiler_passes.h"
|
||||||
#include "xenia/cpu/runtime.h"
|
#include "xenia/cpu/processor.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
|
@ -24,16 +24,16 @@ using xe::cpu::compiler::Compiler;
|
||||||
using xe::cpu::hir::HIRBuilder;
|
using xe::cpu::hir::HIRBuilder;
|
||||||
namespace passes = xe::cpu::compiler::passes;
|
namespace passes = xe::cpu::compiler::passes;
|
||||||
|
|
||||||
TestModule::TestModule(Runtime* runtime, const std::string& name,
|
TestModule::TestModule(Processor* processor, const std::string& name,
|
||||||
std::function<bool(uint32_t)> contains_address,
|
std::function<bool(uint32_t)> contains_address,
|
||||||
std::function<bool(hir::HIRBuilder&)> generate)
|
std::function<bool(hir::HIRBuilder&)> generate)
|
||||||
: Module(runtime),
|
: Module(processor),
|
||||||
name_(name),
|
name_(name),
|
||||||
contains_address_(contains_address),
|
contains_address_(contains_address),
|
||||||
generate_(generate) {
|
generate_(generate) {
|
||||||
builder_.reset(new HIRBuilder());
|
builder_.reset(new HIRBuilder());
|
||||||
compiler_.reset(new Compiler(runtime));
|
compiler_.reset(new Compiler(processor));
|
||||||
assembler_ = std::move(runtime->backend()->CreateAssembler());
|
assembler_ = std::move(processor->backend()->CreateAssembler());
|
||||||
assembler_->Initialize();
|
assembler_->Initialize();
|
||||||
|
|
||||||
// Merge blocks early. This will let us use more context in other passes.
|
// Merge blocks early. This will let us use more context in other passes.
|
||||||
|
@ -59,7 +59,7 @@ TestModule::TestModule(Runtime* runtime, const std::string& name,
|
||||||
// This should be the last pass before finalization, as after this all
|
// This should be the last pass before finalization, as after this all
|
||||||
// registers are assigned and ready to be emitted.
|
// registers are assigned and ready to be emitted.
|
||||||
compiler_->AddPass(std::make_unique<passes::RegisterAllocationPass>(
|
compiler_->AddPass(std::make_unique<passes::RegisterAllocationPass>(
|
||||||
runtime->backend()->machine_info()));
|
processor->backend()->machine_info()));
|
||||||
|
|
||||||
// Must come last. The HIR is not really HIR after this.
|
// Must come last. The HIR is not really HIR after this.
|
||||||
compiler_->AddPass(std::make_unique<passes::FinalizationPass>());
|
compiler_->AddPass(std::make_unique<passes::FinalizationPass>());
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace cpu {
|
||||||
|
|
||||||
class TestModule : public Module {
|
class TestModule : public Module {
|
||||||
public:
|
public:
|
||||||
TestModule(Runtime* runtime, const std::string& name,
|
TestModule(Processor* processor, const std::string& name,
|
||||||
std::function<bool(uint32_t)> contains_address,
|
std::function<bool(uint32_t)> contains_address,
|
||||||
std::function<bool(hir::HIRBuilder&)> generate);
|
std::function<bool(hir::HIRBuilder&)> generate);
|
||||||
~TestModule() override;
|
~TestModule() override;
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
#include "xenia/base/assert.h"
|
#include "xenia/base/assert.h"
|
||||||
#include "xenia/base/threading.h"
|
#include "xenia/base/threading.h"
|
||||||
#include "xenia/cpu/runtime.h"
|
#include "xenia/cpu/processor.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
|
@ -22,11 +22,11 @@ using PPCContext = xe::cpu::frontend::PPCContext;
|
||||||
|
|
||||||
thread_local ThreadState* thread_state_ = nullptr;
|
thread_local ThreadState* thread_state_ = nullptr;
|
||||||
|
|
||||||
ThreadState::ThreadState(Runtime* runtime, uint32_t thread_id,
|
ThreadState::ThreadState(Processor* processor, uint32_t thread_id,
|
||||||
uint32_t stack_address, uint32_t stack_size,
|
uint32_t stack_address, uint32_t stack_size,
|
||||||
uint32_t thread_state_address)
|
uint32_t thread_state_address)
|
||||||
: runtime_(runtime),
|
: processor_(processor),
|
||||||
memory_(runtime->memory()),
|
memory_(processor->memory()),
|
||||||
thread_id_(thread_id),
|
thread_id_(thread_id),
|
||||||
name_(""),
|
name_(""),
|
||||||
backend_data_(0),
|
backend_data_(0),
|
||||||
|
@ -38,7 +38,7 @@ ThreadState::ThreadState(Runtime* runtime, uint32_t thread_id,
|
||||||
uint32_t system_thread_handle = xe::threading::current_thread_id();
|
uint32_t system_thread_handle = xe::threading::current_thread_id();
|
||||||
thread_id_ = 0x80000000 | system_thread_handle;
|
thread_id_ = 0x80000000 | system_thread_handle;
|
||||||
}
|
}
|
||||||
backend_data_ = runtime->backend()->AllocThreadData();
|
backend_data_ = processor->backend()->AllocThreadData();
|
||||||
|
|
||||||
if (!stack_address) {
|
if (!stack_address) {
|
||||||
stack_address_ = memory()->SystemHeapAlloc(stack_size);
|
stack_address_ = memory()->SystemHeapAlloc(stack_size);
|
||||||
|
@ -60,7 +60,7 @@ ThreadState::ThreadState(Runtime* runtime, uint32_t thread_id,
|
||||||
context_->reserve_value = memory_->reserve_value();
|
context_->reserve_value = memory_->reserve_value();
|
||||||
context_->virtual_membase = memory_->virtual_membase();
|
context_->virtual_membase = memory_->virtual_membase();
|
||||||
context_->physical_membase = memory_->physical_membase();
|
context_->physical_membase = memory_->physical_membase();
|
||||||
context_->runtime = runtime;
|
context_->processor = processor_;
|
||||||
context_->thread_state = this;
|
context_->thread_state = this;
|
||||||
context_->thread_id = thread_id_;
|
context_->thread_id = thread_id_;
|
||||||
|
|
||||||
|
@ -72,14 +72,14 @@ ThreadState::ThreadState(Runtime* runtime, uint32_t thread_id,
|
||||||
// 16 to 32b.
|
// 16 to 32b.
|
||||||
context_->r[1] -= 64;
|
context_->r[1] -= 64;
|
||||||
|
|
||||||
runtime_->debugger()->OnThreadCreated(this);
|
processor_->debugger()->OnThreadCreated(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreadState::~ThreadState() {
|
ThreadState::~ThreadState() {
|
||||||
runtime_->debugger()->OnThreadDestroyed(this);
|
processor_->debugger()->OnThreadDestroyed(this);
|
||||||
|
|
||||||
if (backend_data_) {
|
if (backend_data_) {
|
||||||
runtime_->backend()->FreeThreadData(backend_data_);
|
processor_->backend()->FreeThreadData(backend_data_);
|
||||||
}
|
}
|
||||||
if (thread_state_ == this) {
|
if (thread_state_ == this) {
|
||||||
thread_state_ = nullptr;
|
thread_state_ = nullptr;
|
||||||
|
|
|
@ -17,15 +17,15 @@
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
|
|
||||||
class Runtime;
|
class Processor;
|
||||||
|
|
||||||
class ThreadState {
|
class ThreadState {
|
||||||
public:
|
public:
|
||||||
ThreadState(Runtime* runtime, uint32_t thread_id, uint32_t stack_address,
|
ThreadState(Processor* processor, uint32_t thread_id, uint32_t stack_address,
|
||||||
uint32_t stack_size, uint32_t thread_state_address);
|
uint32_t stack_size, uint32_t thread_state_address);
|
||||||
~ThreadState();
|
~ThreadState();
|
||||||
|
|
||||||
Runtime* runtime() const { return runtime_; }
|
Processor* processor() const { return processor_; }
|
||||||
Memory* memory() const { return memory_; }
|
Memory* memory() const { return memory_; }
|
||||||
uint32_t thread_id() const { return thread_id_; }
|
uint32_t thread_id() const { return thread_id_; }
|
||||||
const std::string& name() const { return name_; }
|
const std::string& name() const { return name_; }
|
||||||
|
@ -45,7 +45,7 @@ class ThreadState {
|
||||||
static uint32_t GetThreadID();
|
static uint32_t GetThreadID();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Runtime* runtime_;
|
Processor* processor_;
|
||||||
Memory* memory_;
|
Memory* memory_;
|
||||||
uint32_t thread_id_;
|
uint32_t thread_id_;
|
||||||
std::string name_;
|
std::string name_;
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
#include "xenia/base/memory.h"
|
#include "xenia/base/memory.h"
|
||||||
#include "xenia/cpu/cpu-private.h"
|
#include "xenia/cpu/cpu-private.h"
|
||||||
#include "xenia/cpu/export_resolver.h"
|
#include "xenia/cpu/export_resolver.h"
|
||||||
#include "xenia/cpu/runtime.h"
|
#include "xenia/cpu/processor.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
|
@ -30,9 +30,9 @@ void UndefinedImport(PPCContext* ppc_state, void* arg0, void* arg1) {
|
||||||
XELOGE("call to undefined kernel import");
|
XELOGE("call to undefined kernel import");
|
||||||
}
|
}
|
||||||
|
|
||||||
XexModule::XexModule(Runtime* runtime)
|
XexModule::XexModule(Processor* processor)
|
||||||
: Module(runtime),
|
: Module(processor),
|
||||||
runtime_(runtime),
|
processor_(processor),
|
||||||
xex_(nullptr),
|
xex_(nullptr),
|
||||||
base_address_(0),
|
base_address_(0),
|
||||||
low_address_(0),
|
low_address_(0),
|
||||||
|
@ -93,7 +93,7 @@ int XexModule::Load(const std::string& name, const std::string& path,
|
||||||
}
|
}
|
||||||
|
|
||||||
int XexModule::SetupLibraryImports(const xe_xex2_import_library_t* library) {
|
int XexModule::SetupLibraryImports(const xe_xex2_import_library_t* library) {
|
||||||
ExportResolver* export_resolver = runtime_->export_resolver();
|
ExportResolver* export_resolver = processor_->export_resolver();
|
||||||
|
|
||||||
xe_xex2_import_info_t* import_infos;
|
xe_xex2_import_info_t* import_infos;
|
||||||
size_t import_info_count;
|
size_t import_info_count;
|
||||||
|
|
|
@ -22,7 +22,7 @@ class Runtime;
|
||||||
|
|
||||||
class XexModule : public xe::cpu::Module {
|
class XexModule : public xe::cpu::Module {
|
||||||
public:
|
public:
|
||||||
XexModule(Runtime* runtime);
|
XexModule(Processor* processor);
|
||||||
virtual ~XexModule();
|
virtual ~XexModule();
|
||||||
|
|
||||||
xe_xex2_ref xex() const { return xex_; }
|
xe_xex2_ref xex() const { return xex_; }
|
||||||
|
@ -39,7 +39,7 @@ class XexModule : public xe::cpu::Module {
|
||||||
int FindSaveRest();
|
int FindSaveRest();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Runtime* runtime_;
|
Processor* processor_;
|
||||||
std::string name_;
|
std::string name_;
|
||||||
std::string path_;
|
std::string path_;
|
||||||
xe_xex2_ref xex_;
|
xe_xex2_ref xex_;
|
||||||
|
|
|
@ -182,7 +182,7 @@ X_STATUS XThread::Create() {
|
||||||
// Allocate processor thread state.
|
// Allocate processor thread state.
|
||||||
// This is thread safe.
|
// This is thread safe.
|
||||||
thread_state_ =
|
thread_state_ =
|
||||||
new ThreadState(kernel_state()->processor()->runtime(), thread_id_, 0,
|
new ThreadState(kernel_state()->processor(), thread_id_, 0,
|
||||||
creation_params_.stack_size, thread_state_address_);
|
creation_params_.stack_size, thread_state_address_);
|
||||||
|
|
||||||
X_STATUS return_code = PlatformCreate();
|
X_STATUS return_code = PlatformCreate();
|
||||||
|
|
|
@ -104,7 +104,6 @@ X_STATUS XUserModule::LoadFromFile(const char* path) {
|
||||||
|
|
||||||
X_STATUS XUserModule::LoadFromMemory(const void* addr, const size_t length) {
|
X_STATUS XUserModule::LoadFromMemory(const void* addr, const size_t length) {
|
||||||
Processor* processor = kernel_state()->processor();
|
Processor* processor = kernel_state()->processor();
|
||||||
Runtime* runtime = processor->runtime();
|
|
||||||
|
|
||||||
// Load the XEX into memory and decrypt.
|
// Load the XEX into memory and decrypt.
|
||||||
xe_xex2_options_t xex_options = {0};
|
xe_xex2_options_t xex_options = {0};
|
||||||
|
@ -130,11 +129,11 @@ X_STATUS XUserModule::LoadFromMemory(const void* addr, const size_t length) {
|
||||||
|
|
||||||
// Prepare the module for execution.
|
// Prepare the module for execution.
|
||||||
// Runtime takes ownership.
|
// Runtime takes ownership.
|
||||||
auto xex_module = std::make_unique<XexModule>(runtime);
|
auto xex_module = std::make_unique<XexModule>(processor);
|
||||||
if (xex_module->Load(name_, path_, xex_)) {
|
if (xex_module->Load(name_, path_, xex_)) {
|
||||||
return X_STATUS_UNSUCCESSFUL;
|
return X_STATUS_UNSUCCESSFUL;
|
||||||
}
|
}
|
||||||
if (runtime->AddModule(std::move(xex_module))) {
|
if (processor->AddModule(std::move(xex_module))) {
|
||||||
return X_STATUS_UNSUCCESSFUL;
|
return X_STATUS_UNSUCCESSFUL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue