Files
Xenia-Canary/src/xenia/cpu/frontend/ppc_frontend.cc
2015-05-25 00:52:21 -07:00

111 lines
3.4 KiB
C++

/**
******************************************************************************
* 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/frontend/ppc_frontend.h"
#include "xenia/cpu/frontend/ppc_context.h"
#include "xenia/cpu/frontend/ppc_disasm.h"
#include "xenia/cpu/frontend/ppc_emit.h"
#include "xenia/cpu/frontend/ppc_translator.h"
#include "xenia/cpu/processor.h"
namespace xe {
namespace cpu {
namespace frontend {
void InitializeIfNeeded();
void CleanupOnShutdown();
void InitializeIfNeeded() {
static bool has_initialized = false;
if (has_initialized) {
return;
}
has_initialized = true;
RegisterEmitCategoryAltivec();
RegisterEmitCategoryALU();
RegisterEmitCategoryControl();
RegisterEmitCategoryFPU();
RegisterEmitCategoryMemory();
atexit(CleanupOnShutdown);
}
void CleanupOnShutdown() {}
PPCFrontend::PPCFrontend(Processor* processor) : processor_(processor) {
InitializeIfNeeded();
std::unique_ptr<ContextInfo> context_info(
new ContextInfo(sizeof(PPCContext), offsetof(PPCContext, thread_state),
offsetof(PPCContext, thread_id)));
// Add fields/etc.
context_info_ = std::move(context_info);
}
PPCFrontend::~PPCFrontend() {
// Force cleanup now before we deinit.
translator_pool_.Reset();
}
Memory* PPCFrontend::memory() const { return processor_->memory(); }
void CheckGlobalLock(PPCContext* ppc_state, void* arg0, void* arg1) {
ppc_state->scratch = 0x8000;
}
void HandleGlobalLock(PPCContext* ppc_state, void* arg0, void* arg1) {
auto global_lock = reinterpret_cast<xe::mutex*>(arg0);
volatile bool* global_lock_taken = reinterpret_cast<bool*>(arg1);
uint64_t value = ppc_state->scratch;
if (value == 0x8000) {
global_lock->unlock();
*global_lock_taken = false;
} else if (value == ppc_state->r[13]) {
global_lock->lock();
*global_lock_taken = true;
}
}
bool PPCFrontend::Initialize() {
void* arg0 = reinterpret_cast<void*>(&builtins_.global_lock);
void* arg1 = reinterpret_cast<void*>(&builtins_.global_lock_taken);
builtins_.check_global_lock = processor_->DefineBuiltin(
"CheckGlobalLock", (FunctionInfo::ExternHandler)CheckGlobalLock, arg0,
arg1);
builtins_.handle_global_lock = processor_->DefineBuiltin(
"HandleGlobalLock", (FunctionInfo::ExternHandler)HandleGlobalLock, arg0,
arg1);
return true;
}
bool PPCFrontend::DeclareFunction(FunctionInfo* symbol_info) {
// Could scan or something here.
// Could also check to see if it's a well-known function type and classify
// for later.
// Could also kick off a precompiler, since we know it's likely the function
// will be demanded soon.
return true;
}
bool PPCFrontend::DefineFunction(FunctionInfo* symbol_info,
uint32_t debug_info_flags,
Function** out_function) {
PPCTranslator* translator = translator_pool_.Allocate(this);
bool result =
translator->Translate(symbol_info, debug_info_flags, out_function);
translator_pool_.Release(translator);
return result;
}
} // namespace frontend
} // namespace cpu
} // namespace xe