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;
|
||||
|
||||
// Setup worker thread state. This lets us make calls into guest code.
|
||||
thread_state_ =
|
||||
new ThreadState(emulator_->processor()->runtime(), 0, 0, 16 * 1024, 0);
|
||||
thread_state_ = new ThreadState(emulator_->processor(), 0, 0, 16 * 1024, 0);
|
||||
thread_state_->set_name("Audio Worker");
|
||||
thread_block_ = memory()->SystemHeapAlloc(2048);
|
||||
thread_state_->context()->r[13] = thread_block_;
|
||||
|
|
|
@ -17,7 +17,6 @@ namespace cpu {
|
|||
class DebugInfo;
|
||||
class Function;
|
||||
class FunctionInfo;
|
||||
class Runtime;
|
||||
namespace hir {
|
||||
class HIRBuilder;
|
||||
} // namespace hir
|
||||
|
|
|
@ -13,9 +13,7 @@ namespace xe {
|
|||
namespace cpu {
|
||||
namespace backend {
|
||||
|
||||
using xe::cpu::Runtime;
|
||||
|
||||
Backend::Backend(Runtime* runtime) : runtime_(runtime) {
|
||||
Backend::Backend(Processor* processor) : processor_(processor) {
|
||||
memset(&machine_info_, 0, sizeof(machine_info_));
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
class Runtime;
|
||||
class Processor;
|
||||
} // namespace cpu
|
||||
} // namespace xe
|
||||
|
||||
|
@ -28,10 +28,10 @@ class Assembler;
|
|||
|
||||
class Backend {
|
||||
public:
|
||||
Backend(Runtime* runtime);
|
||||
Backend(Processor* processor);
|
||||
virtual ~Backend();
|
||||
|
||||
Runtime* runtime() const { return runtime_; }
|
||||
Processor* processor() const { return processor_; }
|
||||
const MachineInfo* machine_info() const { return &machine_info_; }
|
||||
|
||||
virtual int Initialize();
|
||||
|
@ -42,7 +42,7 @@ class Backend {
|
|||
virtual std::unique_ptr<Assembler> CreateAssembler() = 0;
|
||||
|
||||
protected:
|
||||
Runtime* runtime_;
|
||||
Processor* processor_;
|
||||
MachineInfo machine_info_;
|
||||
};
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include "xenia/cpu/backend/x64/x64_function.h"
|
||||
#include "xenia/cpu/hir/hir_builder.h"
|
||||
#include "xenia/cpu/hir/label.h"
|
||||
#include "xenia/cpu/runtime.h"
|
||||
#include "xenia/cpu/processor.h"
|
||||
#include "xenia/profiling.h"
|
||||
|
||||
namespace BE {
|
||||
|
|
|
@ -19,9 +19,8 @@ namespace cpu {
|
|||
namespace backend {
|
||||
namespace x64 {
|
||||
|
||||
using xe::cpu::Runtime;
|
||||
|
||||
X64Backend::X64Backend(Runtime* runtime) : Backend(runtime), code_cache_(0) {}
|
||||
X64Backend::X64Backend(Processor* processor)
|
||||
: Backend(processor), code_cache_(nullptr) {}
|
||||
|
||||
X64Backend::~X64Backend() { delete code_cache_; }
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ typedef void* (*GuestToHostThunk)(void* target, void* arg0, void* arg1);
|
|||
|
||||
class X64Backend : public Backend {
|
||||
public:
|
||||
X64Backend(Runtime* runtime);
|
||||
X64Backend(Processor* processor);
|
||||
~X64Backend() override;
|
||||
|
||||
X64CodeCache* code_cache() const { return code_cache_; }
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include "xenia/cpu/cpu-private.h"
|
||||
#include "xenia/cpu/debug_info.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/thread_state.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)
|
||||
: CodeGenerator(MAX_CODE_SIZE, AutoGrow, allocator),
|
||||
runtime_(backend->runtime()),
|
||||
processor_(backend->processor()),
|
||||
backend_(backend),
|
||||
code_cache_(backend->code_cache()),
|
||||
allocator_(allocator),
|
||||
|
@ -217,7 +217,8 @@ void X64Emitter::MarkSourceOffset(const Instr* i) {
|
|||
|
||||
void X64Emitter::EmitGetCurrentThreadId() {
|
||||
// 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() {}
|
||||
|
@ -279,7 +280,7 @@ uint64_t ResolveFunctionSymbol(void* raw_context, uint64_t symbol_info_ptr) {
|
|||
|
||||
// Resolve function. This will demand compile as required.
|
||||
Function* fn = NULL;
|
||||
thread_state->runtime()->ResolveFunction(symbol_info->address(), &fn);
|
||||
thread_state->processor()->ResolveFunction(symbol_info->address(), &fn);
|
||||
assert_not_null(fn);
|
||||
auto x64_fn = static_cast<X64Function*>(fn);
|
||||
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);
|
||||
|
||||
Function* fn = NULL;
|
||||
thread_state->runtime()->ResolveFunction(target_address, &fn);
|
||||
thread_state->processor()->ResolveFunction(target_address, &fn);
|
||||
assert_not_null(fn);
|
||||
auto x64_fn = static_cast<X64Function*>(fn);
|
||||
uint64_t addr = reinterpret_cast<uint64_t>(x64_fn->machine_code());
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace xe {
|
|||
namespace cpu {
|
||||
class DebugInfo;
|
||||
class FunctionInfo;
|
||||
class Runtime;
|
||||
class Processor;
|
||||
class SymbolInfo;
|
||||
namespace hir {
|
||||
class HIRBuilder;
|
||||
|
@ -101,7 +101,7 @@ class X64Emitter : public Xbyak::CodeGenerator {
|
|||
X64Emitter(X64Backend* backend, XbyakAllocator* allocator);
|
||||
virtual ~X64Emitter();
|
||||
|
||||
Runtime* runtime() const { return runtime_; }
|
||||
Processor* processor() const { return processor_; }
|
||||
X64Backend* backend() const { return backend_; }
|
||||
const Xbyak::util::Cpu* cpu() const { return &cpu_; }
|
||||
|
||||
|
@ -187,7 +187,7 @@ class X64Emitter : public Xbyak::CodeGenerator {
|
|||
void EmitTraceUserCallReturn();
|
||||
|
||||
protected:
|
||||
Runtime* runtime_;
|
||||
Processor* processor_;
|
||||
X64Backend* backend_;
|
||||
X64CodeCache* code_cache_;
|
||||
XbyakAllocator* allocator_;
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "xenia/cpu/backend/x64/x64_function.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"
|
||||
|
||||
namespace xe {
|
||||
|
@ -35,7 +35,8 @@ int X64Function::AddBreakpointImpl(Breakpoint* breakpoint) { return 0; }
|
|||
int X64Function::RemoveBreakpointImpl(Breakpoint* breakpoint) { return 0; }
|
||||
|
||||
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();
|
||||
thunk(machine_code_, thread_state->context(),
|
||||
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_tracers.h"
|
||||
#include "xenia/cpu/hir/hir_builder.h"
|
||||
#include "xenia/cpu/runtime.h"
|
||||
#include "xenia/cpu/processor.h"
|
||||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
#include "xenia/base/vec128.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"
|
||||
|
||||
using namespace xe;
|
||||
|
|
|
@ -16,10 +16,7 @@ namespace xe {
|
|||
namespace cpu {
|
||||
namespace compiler {
|
||||
|
||||
using xe::cpu::hir::HIRBuilder;
|
||||
using xe::cpu::Runtime;
|
||||
|
||||
Compiler::Compiler(Runtime* runtime) : runtime_(runtime) {}
|
||||
Compiler::Compiler(Processor* processor) : processor_(processor) {}
|
||||
|
||||
Compiler::~Compiler() { Reset(); }
|
||||
|
||||
|
@ -30,7 +27,7 @@ void Compiler::AddPass(std::unique_ptr<CompilerPass> pass) {
|
|||
|
||||
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
|
||||
// stop changing things, etc.
|
||||
for (size_t i = 0; i < passes_.size(); ++i) {
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
class Runtime;
|
||||
class Processor;
|
||||
} // namespace cpu
|
||||
} // namespace xe
|
||||
|
||||
|
@ -30,10 +30,10 @@ class CompilerPass;
|
|||
|
||||
class Compiler {
|
||||
public:
|
||||
Compiler(Runtime* runtime);
|
||||
Compiler(Processor* processor);
|
||||
~Compiler();
|
||||
|
||||
Runtime* runtime() const { return runtime_; }
|
||||
Processor* processor() const { return processor_; }
|
||||
Arena* scratch_arena() { return &scratch_arena_; }
|
||||
|
||||
void AddPass(std::unique_ptr<CompilerPass> pass);
|
||||
|
@ -43,7 +43,7 @@ class Compiler {
|
|||
int Compile(hir::HIRBuilder* builder);
|
||||
|
||||
private:
|
||||
Runtime* runtime_;
|
||||
Processor* processor_;
|
||||
Arena scratch_arena_;
|
||||
|
||||
std::vector<std::unique_ptr<CompilerPass>> passes_;
|
||||
|
|
|
@ -15,12 +15,12 @@ namespace xe {
|
|||
namespace cpu {
|
||||
namespace compiler {
|
||||
|
||||
CompilerPass::CompilerPass() : runtime_(0), compiler_(0) {}
|
||||
CompilerPass::CompilerPass() : processor_(nullptr), compiler_(nullptr) {}
|
||||
|
||||
CompilerPass::~CompilerPass() = default;
|
||||
|
||||
int CompilerPass::Initialize(Compiler* compiler) {
|
||||
runtime_ = compiler->runtime();
|
||||
processor_ = compiler->processor();
|
||||
compiler_ = compiler;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
class Runtime;
|
||||
class Processor;
|
||||
} // namespace cpu
|
||||
} // namespace xe
|
||||
|
||||
|
@ -38,7 +38,7 @@ class CompilerPass {
|
|||
Arena* scratch_arena() const;
|
||||
|
||||
protected:
|
||||
Runtime* runtime_;
|
||||
Processor* processor_;
|
||||
Compiler* compiler_;
|
||||
};
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/cpu/function.h"
|
||||
#include "xenia/cpu/runtime.h"
|
||||
#include "xenia/cpu/processor.h"
|
||||
#include "xenia/profiling.h"
|
||||
|
||||
namespace xe {
|
||||
|
@ -98,7 +98,7 @@ int ConstantPropagationPass::Run(HIRBuilder* builder) {
|
|||
case OPCODE_CALL_INDIRECT:
|
||||
if (i->src1.value->IsConstant()) {
|
||||
FunctionInfo* symbol_info;
|
||||
if (runtime_->LookupFunctionInfo(
|
||||
if (processor_->LookupFunctionInfo(
|
||||
(uint32_t)i->src1.value->constant.i32, &symbol_info)) {
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include <gflags/gflags.h>
|
||||
|
||||
#include "xenia/cpu/compiler/compiler.h"
|
||||
#include "xenia/cpu/runtime.h"
|
||||
#include "xenia/cpu/processor.h"
|
||||
#include "xenia/profiling.h"
|
||||
|
||||
DEFINE_bool(store_all_context_values, false,
|
||||
|
@ -42,7 +42,7 @@ int ContextPromotionPass::Initialize(Compiler* compiler) {
|
|||
}
|
||||
|
||||
// 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_validity_.resize(static_cast<uint32_t>(context_info->size()));
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
#include "xenia/cpu/backend/backend.h"
|
||||
#include "xenia/cpu/compiler/compiler.h"
|
||||
#include "xenia/cpu/runtime.h"
|
||||
#include "xenia/cpu/processor.h"
|
||||
#include "xenia/profiling.h"
|
||||
|
||||
namespace xe {
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
#include "xenia/cpu/backend/backend.h"
|
||||
#include "xenia/cpu/compiler/compiler.h"
|
||||
#include "xenia/cpu/runtime.h"
|
||||
#include "xenia/cpu/processor.h"
|
||||
#include "xenia/profiling.h"
|
||||
|
||||
namespace xe {
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include "xenia/base/platform.h"
|
||||
#include "xenia/cpu/backend/backend.h"
|
||||
#include "xenia/cpu/compiler/compiler.h"
|
||||
#include "xenia/cpu/runtime.h"
|
||||
#include "xenia/cpu/processor.h"
|
||||
#include "xenia/profiling.h"
|
||||
|
||||
#if XE_COMPILER_MSVC
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
#include "xenia/cpu/backend/backend.h"
|
||||
#include "xenia/cpu/compiler/compiler.h"
|
||||
#include "xenia/cpu/runtime.h"
|
||||
#include "xenia/cpu/processor.h"
|
||||
#include "xenia/profiling.h"
|
||||
|
||||
namespace xe {
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include "xenia/base/assert.h"
|
||||
#include "xenia/cpu/backend/backend.h"
|
||||
#include "xenia/cpu/compiler/compiler.h"
|
||||
#include "xenia/cpu/runtime.h"
|
||||
#include "xenia/cpu/processor.h"
|
||||
#include "xenia/profiling.h"
|
||||
|
||||
namespace xe {
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include "xenia/base/platform.h"
|
||||
#include "xenia/cpu/backend/backend.h"
|
||||
#include "xenia/cpu/compiler/compiler.h"
|
||||
#include "xenia/cpu/runtime.h"
|
||||
#include "xenia/cpu/processor.h"
|
||||
#include "xenia/profiling.h"
|
||||
|
||||
#if XE_COMPILER_MSVC
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
|
||||
#include <gflags/gflags.h>
|
||||
|
||||
DECLARE_string(processor_backend);
|
||||
|
||||
DECLARE_string(load_module_map);
|
||||
|
||||
DECLARE_string(dump_path);
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
#include "xenia/cpu/cpu-private.h"
|
||||
|
||||
DEFINE_string(processor_backend, "any", "CPU backend [any, x64].");
|
||||
|
||||
// Debugging:
|
||||
DEFINE_string(
|
||||
load_module_map, "",
|
||||
|
|
|
@ -13,9 +13,7 @@
|
|||
#include "xenia/cpu/processor.h"
|
||||
#include "xenia/cpu/function.h"
|
||||
#include "xenia/cpu/module.h"
|
||||
#include "xenia/cpu/runtime.h"
|
||||
#include "xenia/cpu/thread_state.h"
|
||||
#include "xenia/cpu/runtime.h"
|
||||
#include "xenia/cpu/processor.h"
|
||||
#include "xenia/cpu/thread_state.h"
|
||||
#include "xenia/cpu/xex_module.h"
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include <mutex>
|
||||
|
||||
#include "xenia/cpu/function.h"
|
||||
#include "xenia/cpu/runtime.h"
|
||||
#include "xenia/cpu/processor.h"
|
||||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
|
@ -22,7 +22,7 @@ Breakpoint::Breakpoint(Type type, uint32_t address)
|
|||
|
||||
Breakpoint::~Breakpoint() = default;
|
||||
|
||||
Debugger::Debugger(Runtime* runtime) : runtime_(runtime) {}
|
||||
Debugger::Debugger(Processor* processor) : processor_(processor) {}
|
||||
|
||||
Debugger::~Debugger() = default;
|
||||
|
||||
|
@ -82,7 +82,7 @@ int Debugger::AddBreakpoint(Breakpoint* breakpoint) {
|
|||
}
|
||||
|
||||
// Find all functions that contain the breakpoint address.
|
||||
auto fns = runtime_->FindFunctionsWithAddress(breakpoint->address());
|
||||
auto fns = processor_->FindFunctionsWithAddress(breakpoint->address());
|
||||
|
||||
// Add.
|
||||
for (auto fn : fns) {
|
||||
|
@ -116,7 +116,7 @@ int Debugger::RemoveBreakpoint(Breakpoint* breakpoint) {
|
|||
}
|
||||
|
||||
// Find all functions that have the breakpoint set.
|
||||
auto fns = runtime_->FindFunctionsWithAddress(breakpoint->address());
|
||||
auto fns = processor_->FindFunctionsWithAddress(breakpoint->address());
|
||||
|
||||
// Remove.
|
||||
for (auto fn : fns) {
|
||||
|
|
|
@ -24,7 +24,7 @@ namespace cpu {
|
|||
class Debugger;
|
||||
class Function;
|
||||
class FunctionInfo;
|
||||
class Runtime;
|
||||
class Processor;
|
||||
|
||||
class Breakpoint {
|
||||
public:
|
||||
|
@ -78,10 +78,10 @@ class BreakpointHitEvent : public DebugEvent {
|
|||
|
||||
class Debugger {
|
||||
public:
|
||||
Debugger(Runtime* runtime);
|
||||
Debugger(Processor* processor);
|
||||
~Debugger();
|
||||
|
||||
Runtime* runtime() const { return runtime_; }
|
||||
Processor* processor() const { return processor_; }
|
||||
|
||||
int SuspendAllThreads(uint32_t timeout_ms = UINT_MAX);
|
||||
int ResumeThread(uint32_t thread_id);
|
||||
|
@ -107,7 +107,7 @@ class Debugger {
|
|||
Delegate<BreakpointHitEvent> breakpoint_hit;
|
||||
|
||||
private:
|
||||
Runtime* runtime_;
|
||||
Processor* processor_;
|
||||
|
||||
std::mutex threads_lock_;
|
||||
std::unordered_map<uint32_t, ThreadState*> threads_;
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
class Runtime;
|
||||
class Processor;
|
||||
class ThreadState;
|
||||
} // namespace cpu
|
||||
} // namespace xe
|
||||
|
@ -205,9 +205,9 @@ typedef struct alignas(64) PPCContext_s {
|
|||
// Used to shuttle data into externs. Contents volatile.
|
||||
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.
|
||||
Runtime* runtime;
|
||||
Processor* processor;
|
||||
|
||||
uint8_t* physical_membase;
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include "xenia/cpu/frontend/ppc_disasm.h"
|
||||
#include "xenia/cpu/frontend/ppc_emit.h"
|
||||
#include "xenia/cpu/frontend/ppc_translator.h"
|
||||
#include "xenia/cpu/runtime.h"
|
||||
#include "xenia/cpu/processor.h"
|
||||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
|
@ -42,7 +42,7 @@ void InitializeIfNeeded() {
|
|||
|
||||
void CleanupOnShutdown() {}
|
||||
|
||||
PPCFrontend::PPCFrontend(Runtime* runtime) : runtime_(runtime) {
|
||||
PPCFrontend::PPCFrontend(Processor* processor) : processor_(processor) {
|
||||
InitializeIfNeeded();
|
||||
|
||||
std::unique_ptr<ContextInfo> context_info(
|
||||
|
@ -57,7 +57,7 @@ PPCFrontend::~PPCFrontend() {
|
|||
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) {
|
||||
ppc_state->scratch = 0x8000;
|
||||
|
@ -78,10 +78,10 @@ void HandleGlobalLock(PPCContext* ppc_state, void* arg0, void* arg1) {
|
|||
int PPCFrontend::Initialize() {
|
||||
void* arg0 = reinterpret_cast<void*>(&builtins_.global_lock);
|
||||
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,
|
||||
arg1);
|
||||
builtins_.handle_global_lock = runtime_->DefineBuiltin(
|
||||
builtins_.handle_global_lock = processor_->DefineBuiltin(
|
||||
"HandleGlobalLock", (FunctionInfo::ExternHandler)HandleGlobalLock, arg0,
|
||||
arg1);
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
class Runtime;
|
||||
class Processor;
|
||||
} // namespace cpu
|
||||
} // namespace xe
|
||||
|
||||
|
@ -40,12 +40,12 @@ struct PPCBuiltins {
|
|||
|
||||
class PPCFrontend {
|
||||
public:
|
||||
explicit PPCFrontend(Runtime* runtime);
|
||||
explicit PPCFrontend(Processor* processor);
|
||||
~PPCFrontend();
|
||||
|
||||
int Initialize();
|
||||
|
||||
Runtime* runtime() const { return runtime_; }
|
||||
Processor* processor() const { return processor_; }
|
||||
Memory* memory() const;
|
||||
ContextInfo* context_info() const { return context_info_.get(); }
|
||||
PPCBuiltins* builtins() { return &builtins_; }
|
||||
|
@ -55,7 +55,7 @@ class PPCFrontend {
|
|||
uint32_t trace_flags, Function** out_function);
|
||||
|
||||
private:
|
||||
Runtime* runtime_;
|
||||
Processor* processor_;
|
||||
std::unique_ptr<ContextInfo> context_info_;
|
||||
PPCBuiltins builtins_;
|
||||
TypePool<PPCTranslator, PPCFrontend*> translator_pool_;
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include "xenia/cpu/frontend/ppc_frontend.h"
|
||||
#include "xenia/cpu/frontend/ppc_instr.h"
|
||||
#include "xenia/cpu/hir/label.h"
|
||||
#include "xenia/cpu/runtime.h"
|
||||
#include "xenia/cpu/processor.h"
|
||||
#include "xenia/profiling.h"
|
||||
|
||||
namespace xe {
|
||||
|
@ -152,9 +152,9 @@ void PPCHIRBuilder::AnnotateLabel(uint32_t address, Label* label) {
|
|||
}
|
||||
|
||||
FunctionInfo* PPCHIRBuilder::LookupFunction(uint32_t address) {
|
||||
Runtime* runtime = frontend_->runtime();
|
||||
Processor* processor = frontend_->processor();
|
||||
FunctionInfo* symbol_info;
|
||||
if (runtime->LookupFunctionInfo(address, &symbol_info)) {
|
||||
if (processor->LookupFunctionInfo(address, &symbol_info)) {
|
||||
return NULL;
|
||||
}
|
||||
return symbol_info;
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include "xenia/base/memory.h"
|
||||
#include "xenia/cpu/frontend/ppc_frontend.h"
|
||||
#include "xenia/cpu/frontend/ppc_instr.h"
|
||||
#include "xenia/cpu/runtime.h"
|
||||
#include "xenia/cpu/processor.h"
|
||||
#include "xenia/profiling.h"
|
||||
|
||||
#if 0
|
||||
|
@ -35,7 +35,7 @@ PPCScanner::~PPCScanner() {}
|
|||
|
||||
bool PPCScanner::IsRestGprLr(uint32_t address) {
|
||||
FunctionInfo* symbol_info;
|
||||
if (frontend_->runtime()->LookupFunctionInfo(address, &symbol_info)) {
|
||||
if (frontend_->processor()->LookupFunctionInfo(address, &symbol_info)) {
|
||||
return false;
|
||||
}
|
||||
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_instr.h"
|
||||
#include "xenia/cpu/frontend/ppc_scanner.h"
|
||||
#include "xenia/cpu/runtime.h"
|
||||
#include "xenia/cpu/processor.h"
|
||||
#include "xenia/profiling.h"
|
||||
|
||||
namespace xe {
|
||||
|
@ -35,11 +35,11 @@ using xe::cpu::compiler::Compiler;
|
|||
namespace passes = xe::cpu::compiler::passes;
|
||||
|
||||
PPCTranslator::PPCTranslator(PPCFrontend* frontend) : frontend_(frontend) {
|
||||
Backend* backend = frontend->runtime()->backend();
|
||||
Backend* backend = frontend->processor()->backend();
|
||||
|
||||
scanner_.reset(new PPCScanner(frontend));
|
||||
builder_.reset(new PPCHIRBuilder(frontend));
|
||||
compiler_.reset(new Compiler(frontend->runtime()));
|
||||
compiler_.reset(new Compiler(frontend->processor()));
|
||||
assembler_ = std::move(backend->CreateAssembler());
|
||||
assembler_->Initialize();
|
||||
|
||||
|
|
|
@ -175,30 +175,30 @@ class TestRunner {
|
|||
memory.reset(new Memory());
|
||||
memory->Initialize();
|
||||
|
||||
runtime.reset(new Runtime(memory.get(), nullptr, 0, 0));
|
||||
runtime->Initialize(nullptr);
|
||||
processor.reset(new Processor(memory.get(), nullptr));
|
||||
processor->Setup();
|
||||
}
|
||||
|
||||
~TestRunner() {
|
||||
thread_state.reset();
|
||||
runtime.reset();
|
||||
processor.reset();
|
||||
memory.reset();
|
||||
}
|
||||
|
||||
bool Setup(TestSuite& suite) {
|
||||
// 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)) {
|
||||
XELOGE("Unable to load test binary %ls", suite.bin_file_path.c_str());
|
||||
return false;
|
||||
}
|
||||
runtime->AddModule(std::move(module));
|
||||
processor->AddModule(std::move(module));
|
||||
|
||||
// Simulate a thread.
|
||||
uint32_t stack_size = 64 * 1024;
|
||||
uint32_t stack_address = START_ADDRESS - stack_size;
|
||||
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));
|
||||
|
||||
return true;
|
||||
|
@ -213,7 +213,7 @@ class TestRunner {
|
|||
|
||||
// Execute test.
|
||||
xe::cpu::Function* fn;
|
||||
runtime->ResolveFunction(test_case.address, &fn);
|
||||
processor->ResolveFunction(test_case.address, &fn);
|
||||
if (!fn) {
|
||||
XELOGE("Entry function not found");
|
||||
return false;
|
||||
|
@ -313,7 +313,7 @@ class TestRunner {
|
|||
|
||||
size_t memory_size;
|
||||
std::unique_ptr<Memory> memory;
|
||||
std::unique_ptr<Runtime> runtime;
|
||||
std::unique_ptr<Processor> processor;
|
||||
std::unique_ptr<ThreadState> thread_state;
|
||||
};
|
||||
|
||||
|
|
|
@ -11,13 +11,15 @@
|
|||
|
||||
#include "xenia/memory.h"
|
||||
#include "xenia/cpu/function.h"
|
||||
#include "xenia/cpu/runtime.h"
|
||||
#include "xenia/cpu/processor.h"
|
||||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
|
||||
Instrument::Instrument(Runtime* runtime)
|
||||
: runtime_(runtime), memory_(runtime->memory()), is_attached_(false) {}
|
||||
Instrument::Instrument(Processor* processor)
|
||||
: processor_(processor),
|
||||
memory_(processor->memory()),
|
||||
is_attached_(false) {}
|
||||
|
||||
Instrument::~Instrument() {
|
||||
if (is_attached_) {
|
||||
|
@ -43,8 +45,8 @@ bool Instrument::Detach() {
|
|||
return true;
|
||||
}
|
||||
|
||||
FunctionInstrument::FunctionInstrument(Runtime* runtime, Function* function)
|
||||
: Instrument(runtime), target_(function) {}
|
||||
FunctionInstrument::FunctionInstrument(Processor* processor, Function* function)
|
||||
: Instrument(processor), target_(function) {}
|
||||
|
||||
bool FunctionInstrument::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)
|
||||
: Instrument(runtime), address_(address), end_address_(end_address) {}
|
||||
: Instrument(processor), address_(address), end_address_(end_address) {}
|
||||
|
||||
bool MemoryInstrument::Attach() {
|
||||
if (!Instrument::Attach()) {
|
||||
|
|
|
@ -12,25 +12,20 @@
|
|||
|
||||
#include <cstdint>
|
||||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
class Memory;
|
||||
class ThreadState;
|
||||
} // namespace cpu
|
||||
} // namespace xe
|
||||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
|
||||
class Function;
|
||||
class Runtime;
|
||||
class Memory;
|
||||
class Processor;
|
||||
class ThreadState;
|
||||
|
||||
class Instrument {
|
||||
public:
|
||||
Instrument(Runtime* runtime);
|
||||
Instrument(Processor* processor);
|
||||
virtual ~Instrument();
|
||||
|
||||
Runtime* runtime() const { return runtime_; }
|
||||
Processor* processor() const { return processor_; }
|
||||
Memory* memory() const { return memory_; }
|
||||
bool is_attached() const { return is_attached_; }
|
||||
|
||||
|
@ -38,14 +33,14 @@ class Instrument {
|
|||
virtual bool Detach();
|
||||
|
||||
private:
|
||||
Runtime* runtime_;
|
||||
Processor* processor_;
|
||||
Memory* memory_;
|
||||
bool is_attached_;
|
||||
};
|
||||
|
||||
class FunctionInstrument : public Instrument {
|
||||
public:
|
||||
FunctionInstrument(Runtime* runtime, Function* function);
|
||||
FunctionInstrument(Processor* processor, Function* function);
|
||||
virtual ~FunctionInstrument() {}
|
||||
|
||||
Function* target() const { return target_; }
|
||||
|
@ -86,7 +81,8 @@ class FunctionInstrument : public Instrument {
|
|||
|
||||
class MemoryInstrument : public Instrument {
|
||||
public:
|
||||
MemoryInstrument(Runtime* runtime, uint32_t address, uint32_t end_address);
|
||||
MemoryInstrument(Processor* processor, uint32_t address,
|
||||
uint32_t end_address);
|
||||
virtual ~MemoryInstrument() {}
|
||||
|
||||
uint64_t address() const { return address_; }
|
||||
|
|
|
@ -13,14 +13,14 @@
|
|||
#include <sstream>
|
||||
|
||||
#include "xenia/base/threading.h"
|
||||
#include "xenia/cpu/runtime.h"
|
||||
#include "xenia/cpu/processor.h"
|
||||
#include "xenia/profiling.h"
|
||||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
|
||||
Module::Module(Runtime* runtime)
|
||||
: runtime_(runtime), memory_(runtime->memory()) {}
|
||||
Module::Module(Processor* processor)
|
||||
: processor_(processor), memory_(processor->memory()) {}
|
||||
|
||||
Module::~Module() = default;
|
||||
|
||||
|
@ -225,7 +225,7 @@ int Module::ReadMap(const char* file_name) {
|
|||
if (type_str == "f") {
|
||||
// Function.
|
||||
FunctionInfo* fn_info;
|
||||
if (runtime_->LookupFunctionInfo(this, address, &fn_info)) {
|
||||
if (processor_->LookupFunctionInfo(this, address, &fn_info)) {
|
||||
continue;
|
||||
}
|
||||
// Don't overwrite names we've set elsewhere.
|
||||
|
|
|
@ -23,11 +23,11 @@ namespace xe {
|
|||
namespace cpu {
|
||||
|
||||
class Function;
|
||||
class Runtime;
|
||||
class Processor;
|
||||
|
||||
class Module {
|
||||
public:
|
||||
Module(Runtime* runtime);
|
||||
Module(Processor* processor);
|
||||
virtual ~Module();
|
||||
|
||||
Memory* memory() const { return memory_; }
|
||||
|
@ -57,7 +57,7 @@ class Module {
|
|||
SymbolInfo::Status DefineSymbol(SymbolInfo* symbol_info);
|
||||
|
||||
protected:
|
||||
Runtime* runtime_;
|
||||
Processor* processor_;
|
||||
Memory* memory_;
|
||||
|
||||
private:
|
||||
|
|
|
@ -9,16 +9,24 @@
|
|||
|
||||
#include "xenia/cpu/processor.h"
|
||||
|
||||
#include <gflags/gflags.h>
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/atomic.h"
|
||||
#include "xenia/base/byte_order.h"
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/base/memory.h"
|
||||
#include "xenia/cpu/cpu-private.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/profiling.h"
|
||||
|
||||
// TODO(benvanik): based on compiler support
|
||||
#include "xenia/cpu/backend/x64/x64_backend.h"
|
||||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
|
||||
|
@ -49,11 +57,26 @@ void InitializeIfNeeded() {
|
|||
|
||||
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)
|
||||
: export_resolver_(export_resolver),
|
||||
runtime_(0),
|
||||
memory_(memory),
|
||||
interrupt_thread_state_(NULL),
|
||||
: memory_(memory),
|
||||
debug_info_flags_(0),
|
||||
trace_flags_(0),
|
||||
builtin_module_(nullptr),
|
||||
next_builtin_address_(0xFFFF0000ul),
|
||||
export_resolver_(export_resolver),
|
||||
interrupt_thread_state_(nullptr),
|
||||
interrupt_thread_block_(0) {
|
||||
InitializeIfNeeded();
|
||||
}
|
||||
|
@ -64,29 +87,71 @@ Processor::~Processor() {
|
|||
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() {
|
||||
assert_null(runtime_);
|
||||
debug_info_flags_ = DEBUG_INFO_DEFAULT;
|
||||
trace_flags_ = 0;
|
||||
|
||||
uint32_t debug_info_flags = DEBUG_INFO_DEFAULT;
|
||||
uint32_t trace_flags = 0;
|
||||
auto frontend = std::make_unique<xe::cpu::frontend::PPCFrontend>(this);
|
||||
// TODO(benvanik): set options/etc.
|
||||
|
||||
runtime_ =
|
||||
new Runtime(memory_, export_resolver_, debug_info_flags, trace_flags);
|
||||
if (!runtime_) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
std::unique_ptr<Backend> backend;
|
||||
// backend.reset(new xe::cpu::backend::x64::X64Backend(runtime));
|
||||
int result = runtime_->Initialize(std::move(backend));
|
||||
std::unique_ptr<xe::cpu::backend::Backend> backend;
|
||||
if (!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) {
|
||||
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_block_ = memory_->SystemHeapAlloc(2048);
|
||||
interrupt_thread_state_->context()->r[13] = interrupt_thread_block_;
|
||||
|
@ -94,12 +159,173 @@ int Processor::Setup() {
|
|||
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) {
|
||||
SCOPE_profile_cpu_f("cpu");
|
||||
|
||||
// Attempt to get the function.
|
||||
Function* fn;
|
||||
if (runtime_->ResolveFunction(address, &fn)) {
|
||||
if (ResolveFunction(address, &fn)) {
|
||||
// Symbol not found in any module.
|
||||
XELOGCPU("Execute(%.8X): failed to find function", address);
|
||||
return 1;
|
||||
|
|
|
@ -13,7 +13,14 @@
|
|||
#include <mutex>
|
||||
#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/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 {
|
||||
|
@ -35,12 +42,31 @@ class Processor {
|
|||
Processor(Memory* memory, ExportResolver* export_resolver);
|
||||
~Processor();
|
||||
|
||||
ExportResolver* export_resolver() const { return export_resolver_; }
|
||||
Runtime* runtime() const { return 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 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);
|
||||
uint64_t Execute(ThreadState* thread_state, uint32_t address, uint64_t args[],
|
||||
size_t arg_count);
|
||||
|
@ -52,10 +78,24 @@ class Processor {
|
|||
size_t arg_count);
|
||||
|
||||
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_;
|
||||
|
||||
Runtime* runtime_;
|
||||
Memory* memory_;
|
||||
EntryTable entry_table_;
|
||||
std::mutex modules_lock_;
|
||||
std::vector<std::unique_ptr<Module>> modules_;
|
||||
Module* builtin_module_;
|
||||
uint32_t next_builtin_address_;
|
||||
|
||||
Irql irql_;
|
||||
std::mutex interrupt_thread_lock_;
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
namespace xe {
|
||||
namespace cpu {
|
||||
|
||||
RawModule::RawModule(Runtime* runtime)
|
||||
: Module(runtime), base_address_(0), low_address_(0), high_address_(0) {}
|
||||
RawModule::RawModule(Processor* processor)
|
||||
: Module(processor), base_address_(0), low_address_(0), high_address_(0) {}
|
||||
|
||||
RawModule::~RawModule() {}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace cpu {
|
|||
|
||||
class RawModule : public Module {
|
||||
public:
|
||||
RawModule(Runtime* runtime);
|
||||
RawModule(Processor* processor);
|
||||
~RawModule() override;
|
||||
|
||||
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',
|
||||
'raw_module.cc',
|
||||
'raw_module.h',
|
||||
'runtime.cc',
|
||||
'runtime.h',
|
||||
'symbol_info.cc',
|
||||
'symbol_info.h',
|
||||
'test_module.cc',
|
||||
|
|
|
@ -38,44 +38,42 @@ class TestFunction {
|
|||
|
||||
#if XENIA_TEST_X64
|
||||
{
|
||||
auto runtime = std::make_unique<Runtime>(memory.get(), nullptr, 0, 0);
|
||||
auto backend =
|
||||
std::make_unique<xe::cpu::backend::x64::X64Backend>(runtime.get());
|
||||
runtime->Initialize(std::move(backend));
|
||||
runtimes.emplace_back(std::move(runtime));
|
||||
auto processor = std::make_unique<Processor>(memory.get(), nullptr);
|
||||
processor->Setup();
|
||||
processors.emplace_back(std::move(processor));
|
||||
}
|
||||
#endif // XENIA_TEST_X64
|
||||
|
||||
for (auto& runtime : runtimes) {
|
||||
for (auto& processor : processors) {
|
||||
auto module = std::make_unique<xe::cpu::TestModule>(
|
||||
runtime.get(), "Test",
|
||||
processor.get(), "Test",
|
||||
[](uint64_t address) { return address == 0x1000; },
|
||||
[generator](hir::HIRBuilder& b) {
|
||||
generator(b);
|
||||
return true;
|
||||
});
|
||||
runtime->AddModule(std::move(module));
|
||||
processor->AddModule(std::move(module));
|
||||
}
|
||||
}
|
||||
|
||||
~TestFunction() {
|
||||
runtimes.clear();
|
||||
processors.clear();
|
||||
memory.reset();
|
||||
}
|
||||
|
||||
void Run(std::function<void(PPCContext*)> pre_call,
|
||||
std::function<void(PPCContext*)> post_call) {
|
||||
for (auto& runtime : runtimes) {
|
||||
for (auto& processor : processors) {
|
||||
memory->Zero(0, memory_size);
|
||||
|
||||
xe::cpu::Function* fn;
|
||||
runtime->ResolveFunction(0x1000, &fn);
|
||||
processor->ResolveFunction(0x1000, &fn);
|
||||
|
||||
uint32_t stack_size = 64 * 1024;
|
||||
uint32_t stack_address = memory_size - stack_size;
|
||||
uint32_t thread_state_address = stack_address - 0x1000;
|
||||
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);
|
||||
auto ctx = thread_state->context();
|
||||
ctx->lr = 0xBEBEBEBE;
|
||||
|
@ -90,7 +88,7 @@ class TestFunction {
|
|||
|
||||
uint32_t memory_size;
|
||||
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) {
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include "xenia/base/reset_scope.h"
|
||||
#include "xenia/base/string.h"
|
||||
#include "xenia/cpu/compiler/compiler_passes.h"
|
||||
#include "xenia/cpu/runtime.h"
|
||||
#include "xenia/cpu/processor.h"
|
||||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
|
@ -24,16 +24,16 @@ using xe::cpu::compiler::Compiler;
|
|||
using xe::cpu::hir::HIRBuilder;
|
||||
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(hir::HIRBuilder&)> generate)
|
||||
: Module(runtime),
|
||||
: Module(processor),
|
||||
name_(name),
|
||||
contains_address_(contains_address),
|
||||
generate_(generate) {
|
||||
builder_.reset(new HIRBuilder());
|
||||
compiler_.reset(new Compiler(runtime));
|
||||
assembler_ = std::move(runtime->backend()->CreateAssembler());
|
||||
compiler_.reset(new Compiler(processor));
|
||||
assembler_ = std::move(processor->backend()->CreateAssembler());
|
||||
assembler_->Initialize();
|
||||
|
||||
// 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
|
||||
// registers are assigned and ready to be emitted.
|
||||
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.
|
||||
compiler_->AddPass(std::make_unique<passes::FinalizationPass>());
|
||||
|
|
|
@ -24,7 +24,7 @@ namespace cpu {
|
|||
|
||||
class TestModule : public Module {
|
||||
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(hir::HIRBuilder&)> generate);
|
||||
~TestModule() override;
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/threading.h"
|
||||
#include "xenia/cpu/runtime.h"
|
||||
#include "xenia/cpu/processor.h"
|
||||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
|
@ -22,11 +22,11 @@ using PPCContext = xe::cpu::frontend::PPCContext;
|
|||
|
||||
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 thread_state_address)
|
||||
: runtime_(runtime),
|
||||
memory_(runtime->memory()),
|
||||
: processor_(processor),
|
||||
memory_(processor->memory()),
|
||||
thread_id_(thread_id),
|
||||
name_(""),
|
||||
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();
|
||||
thread_id_ = 0x80000000 | system_thread_handle;
|
||||
}
|
||||
backend_data_ = runtime->backend()->AllocThreadData();
|
||||
backend_data_ = processor->backend()->AllocThreadData();
|
||||
|
||||
if (!stack_address) {
|
||||
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_->virtual_membase = memory_->virtual_membase();
|
||||
context_->physical_membase = memory_->physical_membase();
|
||||
context_->runtime = runtime;
|
||||
context_->processor = processor_;
|
||||
context_->thread_state = this;
|
||||
context_->thread_id = thread_id_;
|
||||
|
||||
|
@ -72,14 +72,14 @@ ThreadState::ThreadState(Runtime* runtime, uint32_t thread_id,
|
|||
// 16 to 32b.
|
||||
context_->r[1] -= 64;
|
||||
|
||||
runtime_->debugger()->OnThreadCreated(this);
|
||||
processor_->debugger()->OnThreadCreated(this);
|
||||
}
|
||||
|
||||
ThreadState::~ThreadState() {
|
||||
runtime_->debugger()->OnThreadDestroyed(this);
|
||||
processor_->debugger()->OnThreadDestroyed(this);
|
||||
|
||||
if (backend_data_) {
|
||||
runtime_->backend()->FreeThreadData(backend_data_);
|
||||
processor_->backend()->FreeThreadData(backend_data_);
|
||||
}
|
||||
if (thread_state_ == this) {
|
||||
thread_state_ = nullptr;
|
||||
|
|
|
@ -17,15 +17,15 @@
|
|||
namespace xe {
|
||||
namespace cpu {
|
||||
|
||||
class Runtime;
|
||||
class Processor;
|
||||
|
||||
class ThreadState {
|
||||
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);
|
||||
~ThreadState();
|
||||
|
||||
Runtime* runtime() const { return runtime_; }
|
||||
Processor* processor() const { return processor_; }
|
||||
Memory* memory() const { return memory_; }
|
||||
uint32_t thread_id() const { return thread_id_; }
|
||||
const std::string& name() const { return name_; }
|
||||
|
@ -45,7 +45,7 @@ class ThreadState {
|
|||
static uint32_t GetThreadID();
|
||||
|
||||
private:
|
||||
Runtime* runtime_;
|
||||
Processor* processor_;
|
||||
Memory* memory_;
|
||||
uint32_t thread_id_;
|
||||
std::string name_;
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#include "xenia/base/memory.h"
|
||||
#include "xenia/cpu/cpu-private.h"
|
||||
#include "xenia/cpu/export_resolver.h"
|
||||
#include "xenia/cpu/runtime.h"
|
||||
#include "xenia/cpu/processor.h"
|
||||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
|
@ -30,9 +30,9 @@ void UndefinedImport(PPCContext* ppc_state, void* arg0, void* arg1) {
|
|||
XELOGE("call to undefined kernel import");
|
||||
}
|
||||
|
||||
XexModule::XexModule(Runtime* runtime)
|
||||
: Module(runtime),
|
||||
runtime_(runtime),
|
||||
XexModule::XexModule(Processor* processor)
|
||||
: Module(processor),
|
||||
processor_(processor),
|
||||
xex_(nullptr),
|
||||
base_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) {
|
||||
ExportResolver* export_resolver = runtime_->export_resolver();
|
||||
ExportResolver* export_resolver = processor_->export_resolver();
|
||||
|
||||
xe_xex2_import_info_t* import_infos;
|
||||
size_t import_info_count;
|
||||
|
|
|
@ -22,7 +22,7 @@ class Runtime;
|
|||
|
||||
class XexModule : public xe::cpu::Module {
|
||||
public:
|
||||
XexModule(Runtime* runtime);
|
||||
XexModule(Processor* processor);
|
||||
virtual ~XexModule();
|
||||
|
||||
xe_xex2_ref xex() const { return xex_; }
|
||||
|
@ -39,7 +39,7 @@ class XexModule : public xe::cpu::Module {
|
|||
int FindSaveRest();
|
||||
|
||||
private:
|
||||
Runtime* runtime_;
|
||||
Processor* processor_;
|
||||
std::string name_;
|
||||
std::string path_;
|
||||
xe_xex2_ref xex_;
|
||||
|
|
|
@ -182,7 +182,7 @@ X_STATUS XThread::Create() {
|
|||
// Allocate processor thread state.
|
||||
// This is thread safe.
|
||||
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_);
|
||||
|
||||
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) {
|
||||
Processor* processor = kernel_state()->processor();
|
||||
Runtime* runtime = processor->runtime();
|
||||
|
||||
// Load the XEX into memory and decrypt.
|
||||
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.
|
||||
// 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_)) {
|
||||
return X_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
if (runtime->AddModule(std::move(xex_module))) {
|
||||
if (processor->AddModule(std::move(xex_module))) {
|
||||
return X_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue