xenia-cpu-ppc-tests is now building on linux

This commit is contained in:
DrChat 2017-02-10 23:54:10 -06:00
parent 11ae05155d
commit d43e2c7ff8
21 changed files with 471 additions and 51 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -53,7 +53,6 @@ class Logger {
file_ = xe::filesystem::OpenFile(file_path, "wt");
}
flush_event_ = xe::threading::Event::CreateAutoResetEvent(false);
write_thread_ =
xe::threading::Thread::Create({}, [this]() { WriteThread(); });
write_thread_->set_name("xe::FileLogSink Writer");
@ -61,7 +60,6 @@ class Logger {
~Logger() {
running_ = false;
flush_event_->Set();
xe::threading::Wait(write_thread_.get(), true);
fflush(file_);
fclose(file_);
@ -113,9 +111,6 @@ class Logger {
continue;
}
}
// Kick the consumer thread
flush_event_->Set();
}
private:
@ -139,6 +134,7 @@ class Logger {
void WriteThread() {
RingBuffer rb(buffer_, kBufferSize);
uint32_t idle_loops = 0;
while (running_) {
bool did_write = false;
rb.set_write_offset(write_tail_);
@ -197,9 +193,16 @@ class Logger {
if (FLAGS_flush_log) {
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;
std::atomic<bool> running_;
std::unique_ptr<xe::threading::Event> flush_event_;
std::unique_ptr<xe::threading::Thread> write_thread_;
};

View File

@ -74,4 +74,10 @@ std::unique_ptr<MappedMemory> MappedMemory::Open(const std::wstring& path,
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

View File

@ -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

View File

View File

@ -7,20 +7,24 @@
******************************************************************************
*/
#include "xenia/base/assert.h"
#include "xenia/base/logging.h"
#include "xenia/base/threading.h"
#include <pthread.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
namespace xe {
namespace threading {
// uint64_t ticks() { return mach_absolute_time(); }
// uint32_t current_thread_id() {
// mach_port_t tid = pthread_mach_thread_np(pthread_self());
// return static_cast<uint32_t>(tid);
// }
uint32_t current_thread_system_id() {
return static_cast<uint32_t>(syscall(SYS_gettid));
}
void set_name(const std::string& name) {
pthread_setname_np(pthread_self(), name.c_str());
@ -36,5 +40,103 @@ void Sleep(std::chrono::microseconds duration) {
// 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, &param);
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, &param);
}
// 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 xe

View File

@ -15,14 +15,13 @@ namespace xe {
namespace cpu {
namespace backend {
Backend::Backend(Processor* processor)
: processor_(processor), code_cache_(nullptr) {
std::memset(&machine_info_, 0, sizeof(machine_info_));
}
Backend::Backend() { std::memset(&machine_info_, 0, sizeof(machine_info_)); }
Backend::~Backend() = default;
bool Backend::Initialize() { return true; }
bool Backend::Initialize(Processor* processor) {
processor_ = processor;
return true;
}
void* Backend::AllocThreadData() { return nullptr; }

View File

@ -34,14 +34,14 @@ class CodeCache;
class Backend {
public:
explicit Backend(Processor* processor);
explicit Backend();
virtual ~Backend();
Processor* processor() const { return processor_; }
const MachineInfo* machine_info() const { return &machine_info_; }
CodeCache* code_cache() const { return code_cache_; }
virtual bool Initialize();
virtual bool Initialize(Processor* processor);
virtual void* AllocThreadData();
virtual void FreeThreadData(void* thread_data);
@ -65,9 +65,9 @@ class Backend {
virtual void UninstallBreakpoint(Breakpoint* breakpoint) {}
protected:
Processor* processor_;
Processor* processor_ = nullptr;
MachineInfo machine_info_;
CodeCache* code_cache_;
CodeCache* code_cache_ = nullptr;
};
} // namespace backend

View File

@ -42,8 +42,7 @@ class X64ThunkEmitter : public X64Emitter {
ResolveFunctionThunk EmitResolveFunctionThunk();
};
X64Backend::X64Backend(Processor* processor)
: Backend(processor), code_cache_(nullptr) {
X64Backend::X64Backend() : Backend(), code_cache_(nullptr) {
if (cs_open(CS_ARCH_X86, CS_MODE_64, &capstone_handle_) != CS_ERR_OK) {
assert_always("Failed to initialize capstone");
}
@ -61,8 +60,8 @@ X64Backend::~X64Backend() {
ExceptionHandler::Uninstall(&ExceptionCallbackThunk, this);
}
bool X64Backend::Initialize() {
if (!Backend::Initialize()) {
bool X64Backend::Initialize(Processor* processor) {
if (!Backend::Initialize(processor)) {
return false;
}

View File

@ -38,7 +38,7 @@ class X64Backend : public Backend {
public:
static const uint32_t kForceReturnAddress = 0x9FFF0000u;
explicit X64Backend(Processor* processor);
explicit X64Backend();
~X64Backend() override;
X64CodeCache* code_cache() const { return code_cache_.get(); }
@ -53,7 +53,7 @@ class X64Backend : public Backend {
return resolve_function_thunk_;
}
bool Initialize() override;
bool Initialize(Processor* processor) override;
void CommitExecutableRange(uint32_t guest_low, uint32_t guest_high) override;

View File

@ -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

View File

@ -15,6 +15,7 @@
#include "xenia/base/math.h"
#include "xenia/base/platform.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_frontend.h"
#include "xenia/cpu/processor.h"
@ -188,9 +189,25 @@ class TestRunner {
// Reset memory.
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.
processor.reset(new Processor(memory.get(), nullptr));
processor->Setup();
processor->Setup(std::move(backend));
processor->set_debug_info_flags(DebugInfoFlags::kDebugInfoAll);
// Load the binary module.

View File

@ -7,9 +7,9 @@ project("xenia-cpu-ppc-tests")
kind("ConsoleApp")
language("C++")
links({
"xenia-core",
"xenia-cpu-backend-x64",
"xenia-cpu",
"xenia-core",
"xenia-base",
"gflags",
"capstone", -- cpu-backend-x64

View File

@ -95,7 +95,7 @@ Processor::~Processor() {
}
}
bool Processor::Setup() {
bool Processor::Setup(std::unique_ptr<backend::Backend> backend) {
// TODO(benvanik): query mode from debugger?
debug_info_flags_ = 0;
@ -113,26 +113,10 @@ bool Processor::Setup() {
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) {
return false;
}
if (!backend->Initialize()) {
if (!backend->Initialize(this)) {
return false;
}
if (!frontend->Initialize()) {

View File

@ -71,7 +71,7 @@ class Processor {
backend::Backend* backend() const { return backend_.get(); }
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.
void PreLaunch();

View File

@ -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

View File

@ -39,8 +39,9 @@ class TestFunction {
#if XENIA_TEST_X64
{
auto backend = std::make_unique<xe::cpu::backend::x64::X64Backend>();
auto processor = std::make_unique<Processor>(memory.get(), nullptr);
processor->Setup();
processor->Setup(std::move(backend));
processors.emplace_back(std::move(processor));
}
#endif // XENIA_TEST_X64

View File

@ -23,6 +23,8 @@
#include "xenia/base/profiling.h"
#include "xenia/base/string.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/gpu/graphics_system.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.
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.
processor_ = std::make_unique<xe::cpu::Processor>(memory_.get(),
export_resolver_.get());
if (!processor_->Setup()) {
if (!processor_->Setup(std::move(backend))) {
return X_STATUS_UNSUCCESSFUL;
}