113 lines
3.7 KiB
C++
113 lines
3.7 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/ppc/ppc_frontend.h"
|
|
|
|
#include "xenia/base/atomic.h"
|
|
#include "xenia/cpu/ppc/ppc_context.h"
|
|
#include "xenia/cpu/ppc/ppc_emit.h"
|
|
#include "xenia/cpu/ppc/ppc_opcode_info.h"
|
|
#include "xenia/cpu/ppc/ppc_translator.h"
|
|
#include "xenia/cpu/processor.h"
|
|
|
|
namespace xe {
|
|
namespace cpu {
|
|
namespace ppc {
|
|
|
|
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();
|
|
}
|
|
|
|
PPCFrontend::~PPCFrontend() {
|
|
// Force cleanup now before we deinit.
|
|
translator_pool_.Reset();
|
|
}
|
|
|
|
Memory* PPCFrontend::memory() const { return processor_->memory(); }
|
|
|
|
// Checks the state of the global lock and sets scratch to the current MSR
|
|
// value.
|
|
void CheckGlobalLock(PPCContext* ppc_context, void* arg0, void* arg1) {
|
|
auto global_mutex = reinterpret_cast<std::recursive_mutex*>(arg0);
|
|
auto global_lock_count = reinterpret_cast<int32_t*>(arg1);
|
|
std::lock_guard<std::recursive_mutex> lock(*global_mutex);
|
|
ppc_context->scratch = *global_lock_count ? 0 : 0x8000;
|
|
}
|
|
|
|
// Enters the global lock. Safe to recursion.
|
|
void EnterGlobalLock(PPCContext* ppc_context, void* arg0, void* arg1) {
|
|
auto global_mutex = reinterpret_cast<std::recursive_mutex*>(arg0);
|
|
auto global_lock_count = reinterpret_cast<int32_t*>(arg1);
|
|
global_mutex->lock();
|
|
xe::atomic_inc(global_lock_count);
|
|
}
|
|
|
|
// Leaves the global lock. Safe to recursion.
|
|
void LeaveGlobalLock(PPCContext* ppc_context, void* arg0, void* arg1) {
|
|
auto global_mutex = reinterpret_cast<std::recursive_mutex*>(arg0);
|
|
auto global_lock_count = reinterpret_cast<int32_t*>(arg1);
|
|
auto new_lock_count = xe::atomic_dec(global_lock_count);
|
|
assert_true(new_lock_count >= 0);
|
|
global_mutex->unlock();
|
|
}
|
|
|
|
bool PPCFrontend::Initialize() {
|
|
void* arg0 = reinterpret_cast<void*>(&xe::global_critical_region::mutex());
|
|
void* arg1 = reinterpret_cast<void*>(&builtins_.global_lock_count);
|
|
builtins_.check_global_lock =
|
|
processor_->DefineBuiltin("CheckGlobalLock", CheckGlobalLock, arg0, arg1);
|
|
builtins_.enter_global_lock =
|
|
processor_->DefineBuiltin("EnterGlobalLock", EnterGlobalLock, arg0, arg1);
|
|
builtins_.leave_global_lock =
|
|
processor_->DefineBuiltin("LeaveGlobalLock", LeaveGlobalLock, arg0, arg1);
|
|
return true;
|
|
}
|
|
|
|
bool PPCFrontend::DeclareFunction(GuestFunction* function) {
|
|
// 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(GuestFunction* function,
|
|
uint32_t debug_info_flags) {
|
|
auto translator = translator_pool_.Allocate(this);
|
|
bool result = translator->Translate(function, debug_info_flags);
|
|
translator_pool_.Release(translator);
|
|
return result;
|
|
}
|
|
|
|
} // namespace ppc
|
|
} // namespace cpu
|
|
} // namespace xe
|