xenia-cpu-ppc-tests is now building on linux
This commit is contained in:
parent
11ae05155d
commit
d43e2c7ff8
|
@ -0,0 +1,46 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2017 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xenia/base/clock.h"
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
|
||||||
|
uint64_t Clock::host_tick_frequency() {
|
||||||
|
timespec res;
|
||||||
|
clock_getres(CLOCK_MONOTONIC_RAW, &res);
|
||||||
|
|
||||||
|
return uint64_t(res.tv_sec) + uint64_t(res.tv_nsec) * 1000000000ull;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t Clock::QueryHostTickCount() {
|
||||||
|
timespec res;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC_RAW, &res);
|
||||||
|
|
||||||
|
return uint64_t(res.tv_sec) + uint64_t(res.tv_nsec) * 1000000000ull;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t Clock::QueryHostSystemTime() {
|
||||||
|
struct timeval tv;
|
||||||
|
gettimeofday(&tv, NULL);
|
||||||
|
|
||||||
|
uint64_t ret = tv.tv_usec;
|
||||||
|
ret /= 1000; // usec -> msec
|
||||||
|
|
||||||
|
ret += (tv.tv_sec * 1000); // sec -> msec
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Clock::QueryHostUptimeMillis() {
|
||||||
|
return uint32_t(QueryHostTickCount() / (host_tick_frequency() / 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace xe
|
|
@ -0,0 +1,33 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2017 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xenia/base/debugging.h"
|
||||||
|
|
||||||
|
#include <signal.h>
|
||||||
|
#include "xenia/base/string_buffer.h"
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace debugging {
|
||||||
|
|
||||||
|
bool IsDebuggerAttached() { return false; }
|
||||||
|
void Break() { raise(SIGTRAP); }
|
||||||
|
|
||||||
|
void DebugPrint(const char* fmt, ...) {
|
||||||
|
StringBuffer buff;
|
||||||
|
|
||||||
|
va_list va;
|
||||||
|
va_start(va, fmt);
|
||||||
|
buff.AppendVarargs(fmt, va);
|
||||||
|
va_end(va);
|
||||||
|
|
||||||
|
// OutputDebugStringA(buff.GetString());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace debugging
|
||||||
|
} // namespace xe
|
|
@ -0,0 +1,18 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2017 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xenia/base/exception_handler.h"
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
|
||||||
|
// TODO(DrChat): Exception handling on linux.
|
||||||
|
void ExceptionHandler::Install(Handler fn, void* data) {}
|
||||||
|
void ExceptionHandler::Uninstall(Handler fn, void* data) {}
|
||||||
|
|
||||||
|
} // namespace xe
|
|
@ -0,0 +1,63 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2017 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xenia/base/filesystem.h"
|
||||||
|
#include "xenia/base/logging.h"
|
||||||
|
#include "xenia/base/string.h"
|
||||||
|
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace filesystem {
|
||||||
|
|
||||||
|
bool PathExists(const std::wstring& path) {
|
||||||
|
struct stat st;
|
||||||
|
return stat(xe::to_string(path).c_str(), &st) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE* OpenFile(const std::wstring& path, const char* mode) {
|
||||||
|
auto fixed_path = xe::fix_path_separators(path);
|
||||||
|
return fopen(xe::to_string(fixed_path).c_str(), mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CreateFolder(const std::wstring& path) {
|
||||||
|
return mkdir(xe::to_string(path).c_str(), 0774);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<FileInfo> ListFiles(const std::wstring& path) {
|
||||||
|
std::vector<FileInfo> result;
|
||||||
|
|
||||||
|
DIR* dir = opendir(xe::to_string(path).c_str());
|
||||||
|
if (!dir) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (auto ent = readdir(dir)) {
|
||||||
|
FileInfo info;
|
||||||
|
std::memset(&info, 0, sizeof(info));
|
||||||
|
if (ent->d_type == DT_DIR) {
|
||||||
|
info.type = FileInfo::Type::kDirectory;
|
||||||
|
info.total_size = 0;
|
||||||
|
} else {
|
||||||
|
info.type = FileInfo::Type::kFile;
|
||||||
|
info.total_size = 0; // TODO(DrChat): Find a way to get this
|
||||||
|
}
|
||||||
|
|
||||||
|
info.name = xe::to_wstring(ent->d_name);
|
||||||
|
result.push_back(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace filesystem
|
||||||
|
} // namespace xe
|
|
@ -53,7 +53,6 @@ class Logger {
|
||||||
file_ = xe::filesystem::OpenFile(file_path, "wt");
|
file_ = xe::filesystem::OpenFile(file_path, "wt");
|
||||||
}
|
}
|
||||||
|
|
||||||
flush_event_ = xe::threading::Event::CreateAutoResetEvent(false);
|
|
||||||
write_thread_ =
|
write_thread_ =
|
||||||
xe::threading::Thread::Create({}, [this]() { WriteThread(); });
|
xe::threading::Thread::Create({}, [this]() { WriteThread(); });
|
||||||
write_thread_->set_name("xe::FileLogSink Writer");
|
write_thread_->set_name("xe::FileLogSink Writer");
|
||||||
|
@ -61,7 +60,6 @@ class Logger {
|
||||||
|
|
||||||
~Logger() {
|
~Logger() {
|
||||||
running_ = false;
|
running_ = false;
|
||||||
flush_event_->Set();
|
|
||||||
xe::threading::Wait(write_thread_.get(), true);
|
xe::threading::Wait(write_thread_.get(), true);
|
||||||
fflush(file_);
|
fflush(file_);
|
||||||
fclose(file_);
|
fclose(file_);
|
||||||
|
@ -113,9 +111,6 @@ class Logger {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Kick the consumer thread
|
|
||||||
flush_event_->Set();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -139,6 +134,7 @@ class Logger {
|
||||||
|
|
||||||
void WriteThread() {
|
void WriteThread() {
|
||||||
RingBuffer rb(buffer_, kBufferSize);
|
RingBuffer rb(buffer_, kBufferSize);
|
||||||
|
uint32_t idle_loops = 0;
|
||||||
while (running_) {
|
while (running_) {
|
||||||
bool did_write = false;
|
bool did_write = false;
|
||||||
rb.set_write_offset(write_tail_);
|
rb.set_write_offset(write_tail_);
|
||||||
|
@ -197,9 +193,16 @@ class Logger {
|
||||||
if (FLAGS_flush_log) {
|
if (FLAGS_flush_log) {
|
||||||
fflush(file_);
|
fflush(file_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
idle_loops = 0;
|
||||||
|
} else {
|
||||||
|
if (idle_loops > 1000) {
|
||||||
|
// Introduce a waiting period.
|
||||||
|
xe::threading::Sleep(std::chrono::milliseconds(50));
|
||||||
|
}
|
||||||
|
|
||||||
|
idle_loops++;
|
||||||
}
|
}
|
||||||
xe::threading::Wait(flush_event_.get(), true,
|
|
||||||
std::chrono::milliseconds(1));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,7 +213,6 @@ class Logger {
|
||||||
FILE* file_ = nullptr;
|
FILE* file_ = nullptr;
|
||||||
|
|
||||||
std::atomic<bool> running_;
|
std::atomic<bool> running_;
|
||||||
std::unique_ptr<xe::threading::Event> flush_event_;
|
|
||||||
std::unique_ptr<xe::threading::Thread> write_thread_;
|
std::unique_ptr<xe::threading::Thread> write_thread_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -74,4 +74,10 @@ std::unique_ptr<MappedMemory> MappedMemory::Open(const std::wstring& path,
|
||||||
return std::move(mm);
|
return std::move(mm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<ChunkedMappedMemoryWriter> ChunkedMappedMemoryWriter::Open(
|
||||||
|
const std::wstring& path, size_t chunk_size, bool low_address_space) {
|
||||||
|
// TODO(DrChat)
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2017 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xenia/base/memory.h"
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace memory {
|
||||||
|
|
||||||
|
size_t page_size() { return getpagesize(); }
|
||||||
|
size_t allocation_granularity() { return page_size(); }
|
||||||
|
|
||||||
|
void* AllocFixed(void* base_address, size_t length,
|
||||||
|
AllocationType allocation_type, PageAccess access) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeallocFixed(void* base_address, size_t length,
|
||||||
|
DeallocationType deallocation_type) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Protect(void* base_address, size_t length, PageAccess access,
|
||||||
|
PageAccess* out_old_access) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QueryProtect(void* base_address, size_t& length, PageAccess& access_out) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileMappingHandle CreateFileMappingHandle(std::wstring path, size_t length,
|
||||||
|
PageAccess access, bool commit) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CloseFileMappingHandle(FileMappingHandle handle) {}
|
||||||
|
|
||||||
|
void* MapFileView(FileMappingHandle handle, void* base_address, size_t length,
|
||||||
|
PageAccess access, size_t file_offset) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnmapFileView(FileMappingHandle handle, void* base_address,
|
||||||
|
size_t length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace memory
|
||||||
|
} // namespace xe
|
|
@ -7,20 +7,24 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "xenia/base/assert.h"
|
||||||
|
#include "xenia/base/logging.h"
|
||||||
#include "xenia/base/threading.h"
|
#include "xenia/base/threading.h"
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
#include <sys/syscall.h>
|
||||||
|
#include <sys/types.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace threading {
|
namespace threading {
|
||||||
|
|
||||||
// uint64_t ticks() { return mach_absolute_time(); }
|
// uint64_t ticks() { return mach_absolute_time(); }
|
||||||
|
|
||||||
// uint32_t current_thread_id() {
|
uint32_t current_thread_system_id() {
|
||||||
// mach_port_t tid = pthread_mach_thread_np(pthread_self());
|
return static_cast<uint32_t>(syscall(SYS_gettid));
|
||||||
// return static_cast<uint32_t>(tid);
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
void set_name(const std::string& name) {
|
void set_name(const std::string& name) {
|
||||||
pthread_setname_np(pthread_self(), name.c_str());
|
pthread_setname_np(pthread_self(), name.c_str());
|
||||||
|
@ -36,5 +40,103 @@ void Sleep(std::chrono::microseconds duration) {
|
||||||
// TODO(benvanik): spin while rmtp >0?
|
// TODO(benvanik): spin while rmtp >0?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class PosixHandle : public T {
|
||||||
|
public:
|
||||||
|
explicit PosixHandle(pthread_t handle) : handle_(handle) {}
|
||||||
|
~PosixHandle() override {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void* native_handle() const override {
|
||||||
|
return reinterpret_cast<void*>(handle_);
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_t handle_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PosixThread : public PosixHandle<Thread> {
|
||||||
|
public:
|
||||||
|
explicit PosixThread(pthread_t handle) : PosixHandle(handle) {}
|
||||||
|
~PosixThread() = default;
|
||||||
|
|
||||||
|
void set_name(std::string name) override {
|
||||||
|
// TODO(DrChat)
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t system_id() const override { return 0; }
|
||||||
|
|
||||||
|
// TODO(DrChat)
|
||||||
|
uint64_t affinity_mask() override { return 0; }
|
||||||
|
void set_affinity_mask(uint64_t mask) override { assert_always(); }
|
||||||
|
|
||||||
|
int priority() override {
|
||||||
|
int policy;
|
||||||
|
struct sched_param param;
|
||||||
|
int ret = pthread_getschedparam(handle_, &policy, ¶m);
|
||||||
|
if (ret != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return param.sched_priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_priority(int new_priority) override {
|
||||||
|
struct sched_param param;
|
||||||
|
param.sched_priority = new_priority;
|
||||||
|
int ret = pthread_setschedparam(handle_, SCHED_FIFO, ¶m);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(DrChat)
|
||||||
|
void QueueUserCallback(std::function<void()> callback) override {
|
||||||
|
assert_always();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Resume(uint32_t* out_new_suspend_count = nullptr) override {
|
||||||
|
assert_always();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Suspend(uint32_t* out_previous_suspend_count = nullptr) override {
|
||||||
|
assert_always();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Terminate(int exit_code) override {}
|
||||||
|
};
|
||||||
|
|
||||||
|
thread_local std::unique_ptr<PosixThread> current_thread_ = nullptr;
|
||||||
|
|
||||||
|
struct ThreadStartData {
|
||||||
|
std::function<void()> start_routine;
|
||||||
|
};
|
||||||
|
void* ThreadStartRoutine(void* parameter) {
|
||||||
|
current_thread_ = std::make_unique<PosixThread>(::pthread_self());
|
||||||
|
|
||||||
|
auto start_data = reinterpret_cast<ThreadStartData*>(parameter);
|
||||||
|
start_data->start_routine();
|
||||||
|
delete start_data;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Thread> Thread::Create(CreationParameters params,
|
||||||
|
std::function<void()> start_routine) {
|
||||||
|
auto start_data = new ThreadStartData({std::move(start_routine)});
|
||||||
|
|
||||||
|
assert_false(params.create_suspended);
|
||||||
|
pthread_t handle;
|
||||||
|
pthread_attr_t attr;
|
||||||
|
pthread_attr_init(&attr);
|
||||||
|
int ret = pthread_create(&handle, &attr, ThreadStartRoutine, start_data);
|
||||||
|
if (ret != 0) {
|
||||||
|
// TODO(benvanik): pass back?
|
||||||
|
auto last_error = errno;
|
||||||
|
XELOGE("Unable to pthread_create: %d", last_error);
|
||||||
|
delete start_data;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_unique<PosixThread>(handle);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace threading
|
} // namespace threading
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
|
@ -15,14 +15,13 @@ namespace xe {
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
namespace backend {
|
namespace backend {
|
||||||
|
|
||||||
Backend::Backend(Processor* processor)
|
Backend::Backend() { std::memset(&machine_info_, 0, sizeof(machine_info_)); }
|
||||||
: processor_(processor), code_cache_(nullptr) {
|
|
||||||
std::memset(&machine_info_, 0, sizeof(machine_info_));
|
|
||||||
}
|
|
||||||
|
|
||||||
Backend::~Backend() = default;
|
Backend::~Backend() = default;
|
||||||
|
|
||||||
bool Backend::Initialize() { return true; }
|
bool Backend::Initialize(Processor* processor) {
|
||||||
|
processor_ = processor;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void* Backend::AllocThreadData() { return nullptr; }
|
void* Backend::AllocThreadData() { return nullptr; }
|
||||||
|
|
||||||
|
|
|
@ -34,14 +34,14 @@ class CodeCache;
|
||||||
|
|
||||||
class Backend {
|
class Backend {
|
||||||
public:
|
public:
|
||||||
explicit Backend(Processor* processor);
|
explicit Backend();
|
||||||
virtual ~Backend();
|
virtual ~Backend();
|
||||||
|
|
||||||
Processor* processor() const { return processor_; }
|
Processor* processor() const { return processor_; }
|
||||||
const MachineInfo* machine_info() const { return &machine_info_; }
|
const MachineInfo* machine_info() const { return &machine_info_; }
|
||||||
CodeCache* code_cache() const { return code_cache_; }
|
CodeCache* code_cache() const { return code_cache_; }
|
||||||
|
|
||||||
virtual bool Initialize();
|
virtual bool Initialize(Processor* processor);
|
||||||
|
|
||||||
virtual void* AllocThreadData();
|
virtual void* AllocThreadData();
|
||||||
virtual void FreeThreadData(void* thread_data);
|
virtual void FreeThreadData(void* thread_data);
|
||||||
|
@ -65,9 +65,9 @@ class Backend {
|
||||||
virtual void UninstallBreakpoint(Breakpoint* breakpoint) {}
|
virtual void UninstallBreakpoint(Breakpoint* breakpoint) {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Processor* processor_;
|
Processor* processor_ = nullptr;
|
||||||
MachineInfo machine_info_;
|
MachineInfo machine_info_;
|
||||||
CodeCache* code_cache_;
|
CodeCache* code_cache_ = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace backend
|
} // namespace backend
|
||||||
|
|
|
@ -42,8 +42,7 @@ class X64ThunkEmitter : public X64Emitter {
|
||||||
ResolveFunctionThunk EmitResolveFunctionThunk();
|
ResolveFunctionThunk EmitResolveFunctionThunk();
|
||||||
};
|
};
|
||||||
|
|
||||||
X64Backend::X64Backend(Processor* processor)
|
X64Backend::X64Backend() : Backend(), code_cache_(nullptr) {
|
||||||
: Backend(processor), code_cache_(nullptr) {
|
|
||||||
if (cs_open(CS_ARCH_X86, CS_MODE_64, &capstone_handle_) != CS_ERR_OK) {
|
if (cs_open(CS_ARCH_X86, CS_MODE_64, &capstone_handle_) != CS_ERR_OK) {
|
||||||
assert_always("Failed to initialize capstone");
|
assert_always("Failed to initialize capstone");
|
||||||
}
|
}
|
||||||
|
@ -61,8 +60,8 @@ X64Backend::~X64Backend() {
|
||||||
ExceptionHandler::Uninstall(&ExceptionCallbackThunk, this);
|
ExceptionHandler::Uninstall(&ExceptionCallbackThunk, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool X64Backend::Initialize() {
|
bool X64Backend::Initialize(Processor* processor) {
|
||||||
if (!Backend::Initialize()) {
|
if (!Backend::Initialize(processor)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ class X64Backend : public Backend {
|
||||||
public:
|
public:
|
||||||
static const uint32_t kForceReturnAddress = 0x9FFF0000u;
|
static const uint32_t kForceReturnAddress = 0x9FFF0000u;
|
||||||
|
|
||||||
explicit X64Backend(Processor* processor);
|
explicit X64Backend();
|
||||||
~X64Backend() override;
|
~X64Backend() override;
|
||||||
|
|
||||||
X64CodeCache* code_cache() const { return code_cache_.get(); }
|
X64CodeCache* code_cache() const { return code_cache_.get(); }
|
||||||
|
@ -53,7 +53,7 @@ class X64Backend : public Backend {
|
||||||
return resolve_function_thunk_;
|
return resolve_function_thunk_;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Initialize() override;
|
bool Initialize(Processor* processor) override;
|
||||||
|
|
||||||
void CommitExecutableRange(uint32_t guest_low, uint32_t guest_high) override;
|
void CommitExecutableRange(uint32_t guest_low, uint32_t guest_high) override;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2017 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xenia/cpu/backend/x64/x64_code_cache.h"
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace cpu {
|
||||||
|
namespace backend {
|
||||||
|
namespace x64 {
|
||||||
|
|
||||||
|
class PosixX64CodeCache : public X64CodeCache {
|
||||||
|
public:
|
||||||
|
PosixX64CodeCache();
|
||||||
|
~PosixX64CodeCache() override;
|
||||||
|
|
||||||
|
bool Initialize() override;
|
||||||
|
|
||||||
|
void* LookupUnwindInfo(uint64_t host_pc) override { return nullptr; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
/*
|
||||||
|
UnwindReservation RequestUnwindReservation(uint8_t* entry_address) override;
|
||||||
|
void PlaceCode(uint32_t guest_address, void* machine_code, size_t code_size,
|
||||||
|
size_t stack_size, void* code_address,
|
||||||
|
UnwindReservation unwind_reservation) override;
|
||||||
|
|
||||||
|
void InitializeUnwindEntry(uint8_t* unwind_entry_address,
|
||||||
|
size_t unwind_table_slot, void* code_address,
|
||||||
|
size_t code_size, size_t stack_size);
|
||||||
|
*/
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<X64CodeCache> X64CodeCache::Create() {
|
||||||
|
return std::make_unique<PosixX64CodeCache>();
|
||||||
|
}
|
||||||
|
|
||||||
|
PosixX64CodeCache::PosixX64CodeCache() = default;
|
||||||
|
PosixX64CodeCache::~PosixX64CodeCache() = default;
|
||||||
|
|
||||||
|
bool PosixX64CodeCache::Initialize() { return X64CodeCache::Initialize(); }
|
||||||
|
|
||||||
|
} // namespace x64
|
||||||
|
} // namespace backend
|
||||||
|
} // namespace cpu
|
||||||
|
} // namespace xe
|
|
@ -15,6 +15,7 @@
|
||||||
#include "xenia/base/math.h"
|
#include "xenia/base/math.h"
|
||||||
#include "xenia/base/platform.h"
|
#include "xenia/base/platform.h"
|
||||||
#include "xenia/cpu/backend/x64/x64_backend.h"
|
#include "xenia/cpu/backend/x64/x64_backend.h"
|
||||||
|
#include "xenia/cpu/cpu_flags.h"
|
||||||
#include "xenia/cpu/ppc/ppc_context.h"
|
#include "xenia/cpu/ppc/ppc_context.h"
|
||||||
#include "xenia/cpu/ppc/ppc_frontend.h"
|
#include "xenia/cpu/ppc/ppc_frontend.h"
|
||||||
#include "xenia/cpu/processor.h"
|
#include "xenia/cpu/processor.h"
|
||||||
|
@ -188,9 +189,25 @@ class TestRunner {
|
||||||
// Reset memory.
|
// Reset memory.
|
||||||
memory->Reset();
|
memory->Reset();
|
||||||
|
|
||||||
|
std::unique_ptr<xe::cpu::backend::Backend> backend;
|
||||||
|
if (!backend) {
|
||||||
|
#if defined(XENIA_HAS_X64_BACKEND) && XENIA_HAS_X64_BACKEND
|
||||||
|
if (FLAGS_cpu == "x64") {
|
||||||
|
backend.reset(new xe::cpu::backend::x64::X64Backend());
|
||||||
|
}
|
||||||
|
#endif // XENIA_HAS_X64_BACKEND
|
||||||
|
if (FLAGS_cpu == "any") {
|
||||||
|
#if defined(XENIA_HAS_X64_BACKEND) && XENIA_HAS_X64_BACKEND
|
||||||
|
if (!backend) {
|
||||||
|
backend.reset(new xe::cpu::backend::x64::X64Backend());
|
||||||
|
}
|
||||||
|
#endif // XENIA_HAS_X64_BACKEND
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Setup a fresh processor.
|
// Setup a fresh processor.
|
||||||
processor.reset(new Processor(memory.get(), nullptr));
|
processor.reset(new Processor(memory.get(), nullptr));
|
||||||
processor->Setup();
|
processor->Setup(std::move(backend));
|
||||||
processor->set_debug_info_flags(DebugInfoFlags::kDebugInfoAll);
|
processor->set_debug_info_flags(DebugInfoFlags::kDebugInfoAll);
|
||||||
|
|
||||||
// Load the binary module.
|
// Load the binary module.
|
||||||
|
|
|
@ -7,9 +7,9 @@ project("xenia-cpu-ppc-tests")
|
||||||
kind("ConsoleApp")
|
kind("ConsoleApp")
|
||||||
language("C++")
|
language("C++")
|
||||||
links({
|
links({
|
||||||
|
"xenia-core",
|
||||||
"xenia-cpu-backend-x64",
|
"xenia-cpu-backend-x64",
|
||||||
"xenia-cpu",
|
"xenia-cpu",
|
||||||
"xenia-core",
|
|
||||||
"xenia-base",
|
"xenia-base",
|
||||||
"gflags",
|
"gflags",
|
||||||
"capstone", -- cpu-backend-x64
|
"capstone", -- cpu-backend-x64
|
||||||
|
|
|
@ -95,7 +95,7 @@ Processor::~Processor() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Processor::Setup() {
|
bool Processor::Setup(std::unique_ptr<backend::Backend> backend) {
|
||||||
// TODO(benvanik): query mode from debugger?
|
// TODO(benvanik): query mode from debugger?
|
||||||
debug_info_flags_ = 0;
|
debug_info_flags_ = 0;
|
||||||
|
|
||||||
|
@ -113,26 +113,10 @@ bool Processor::Setup() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<xe::cpu::backend::Backend> backend;
|
|
||||||
if (!backend) {
|
|
||||||
#if defined(XENIA_HAS_X64_BACKEND) && XENIA_HAS_X64_BACKEND
|
|
||||||
if (FLAGS_cpu == "x64") {
|
|
||||||
backend.reset(new xe::cpu::backend::x64::X64Backend(this));
|
|
||||||
}
|
|
||||||
#endif // XENIA_HAS_X64_BACKEND
|
|
||||||
if (FLAGS_cpu == "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) {
|
if (!backend) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!backend->Initialize()) {
|
if (!backend->Initialize(this)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!frontend->Initialize()) {
|
if (!frontend->Initialize()) {
|
||||||
|
|
|
@ -71,7 +71,7 @@ class Processor {
|
||||||
backend::Backend* backend() const { return backend_.get(); }
|
backend::Backend* backend() const { return backend_.get(); }
|
||||||
ExportResolver* export_resolver() const { return export_resolver_; }
|
ExportResolver* export_resolver() const { return export_resolver_; }
|
||||||
|
|
||||||
bool Setup();
|
bool Setup(std::unique_ptr<backend::Backend> backend);
|
||||||
|
|
||||||
// Runs any pre-launch logic once the module and thread have been setup.
|
// Runs any pre-launch logic once the module and thread have been setup.
|
||||||
void PreLaunch();
|
void PreLaunch();
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2017 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xenia/cpu/stack_walker.h"
|
||||||
|
|
||||||
|
#include "xenia/base/logging.h"
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace cpu {
|
||||||
|
|
||||||
|
std::unique_ptr<StackWalker> StackWalker::Create(
|
||||||
|
backend::CodeCache* code_cache) {
|
||||||
|
XELOGD("Stack walker unimplemented on posix");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace cpu
|
||||||
|
} // namespace xe
|
|
@ -39,8 +39,9 @@ class TestFunction {
|
||||||
|
|
||||||
#if XENIA_TEST_X64
|
#if XENIA_TEST_X64
|
||||||
{
|
{
|
||||||
|
auto backend = std::make_unique<xe::cpu::backend::x64::X64Backend>();
|
||||||
auto processor = std::make_unique<Processor>(memory.get(), nullptr);
|
auto processor = std::make_unique<Processor>(memory.get(), nullptr);
|
||||||
processor->Setup();
|
processor->Setup(std::move(backend));
|
||||||
processors.emplace_back(std::move(processor));
|
processors.emplace_back(std::move(processor));
|
||||||
}
|
}
|
||||||
#endif // XENIA_TEST_X64
|
#endif // XENIA_TEST_X64
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
#include "xenia/base/profiling.h"
|
#include "xenia/base/profiling.h"
|
||||||
#include "xenia/base/string.h"
|
#include "xenia/base/string.h"
|
||||||
#include "xenia/cpu/backend/code_cache.h"
|
#include "xenia/cpu/backend/code_cache.h"
|
||||||
|
#include "xenia/cpu/backend/x64/x64_backend.h"
|
||||||
|
#include "xenia/cpu/cpu_flags.h"
|
||||||
#include "xenia/cpu/thread_state.h"
|
#include "xenia/cpu/thread_state.h"
|
||||||
#include "xenia/gpu/graphics_system.h"
|
#include "xenia/gpu/graphics_system.h"
|
||||||
#include "xenia/hid/input_driver.h"
|
#include "xenia/hid/input_driver.h"
|
||||||
|
@ -107,10 +109,26 @@ X_STATUS Emulator::Setup(
|
||||||
// Shared export resolver used to attach and query for HLE exports.
|
// Shared export resolver used to attach and query for HLE exports.
|
||||||
export_resolver_ = std::make_unique<xe::cpu::ExportResolver>();
|
export_resolver_ = std::make_unique<xe::cpu::ExportResolver>();
|
||||||
|
|
||||||
|
std::unique_ptr<xe::cpu::backend::Backend> backend;
|
||||||
|
if (!backend) {
|
||||||
|
#if defined(XENIA_HAS_X64_BACKEND) && XENIA_HAS_X64_BACKEND
|
||||||
|
if (FLAGS_cpu == "x64") {
|
||||||
|
backend.reset(new xe::cpu::backend::x64::X64Backend());
|
||||||
|
}
|
||||||
|
#endif // XENIA_HAS_X64_BACKEND
|
||||||
|
if (FLAGS_cpu == "any") {
|
||||||
|
#if defined(XENIA_HAS_X64_BACKEND) && XENIA_HAS_X64_BACKEND
|
||||||
|
if (!backend) {
|
||||||
|
backend.reset(new xe::cpu::backend::x64::X64Backend());
|
||||||
|
}
|
||||||
|
#endif // XENIA_HAS_X64_BACKEND
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize the CPU.
|
// Initialize the CPU.
|
||||||
processor_ = std::make_unique<xe::cpu::Processor>(memory_.get(),
|
processor_ = std::make_unique<xe::cpu::Processor>(memory_.get(),
|
||||||
export_resolver_.get());
|
export_resolver_.get());
|
||||||
if (!processor_->Setup()) {
|
if (!processor_->Setup(std::move(backend))) {
|
||||||
return X_STATUS_UNSUCCESSFUL;
|
return X_STATUS_UNSUCCESSFUL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue