Initial Alloy implementation.
This is a regression in functionality and performance, but a much better foundation for the future of the project (I think). It can run basic apps under an SSA interpreter but doesn't support some of the features required to do real 360 apps yet.
This commit is contained in:
parent
68b8737a58
commit
fdb6a5cfa3
|
@ -7,13 +7,15 @@
|
|||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_CPU_PPC_H_
|
||||
#define XENIA_CPU_PPC_H_
|
||||
#ifndef ALLOY_ALLOY_PRIVATE_H_
|
||||
#define ALLOY_ALLOY_PRIVATE_H_
|
||||
|
||||
#include <xenia/common.h>
|
||||
#include <alloy/core.h>
|
||||
|
||||
#include <xenia/cpu/ppc/instr.h>
|
||||
#include <xenia/cpu/ppc/registers.h>
|
||||
#include <xenia/cpu/ppc/state.h>
|
||||
|
||||
#endif // XENIA_CPU_PPC_H_
|
||||
namespace alloy {
|
||||
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_ALLOY_PRIVATE_H_
|
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_ALLOY_H_
|
||||
#define ALLOY_ALLOY_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
|
||||
#include <alloy/runtime/function.h>
|
||||
#include <alloy/runtime/module.h>
|
||||
#include <alloy/runtime/runtime.h>
|
||||
#include <alloy/runtime/thread_state.h>
|
||||
#include <alloy/tracing/tracing.h>
|
||||
|
||||
|
||||
// TODO(benvanik): based on platform/config/etc.
|
||||
#include <alloy/backend/ivm/ivm_backend.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_ALLOY_H_
|
|
@ -0,0 +1,92 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 <alloy/arena.h>
|
||||
|
||||
using namespace alloy;
|
||||
|
||||
|
||||
Arena::Arena(size_t chunk_size) :
|
||||
chunk_size_(chunk_size),
|
||||
head_chunk_(NULL), active_chunk_(NULL) {
|
||||
}
|
||||
|
||||
Arena::~Arena() {
|
||||
Reset();
|
||||
Chunk* chunk = head_chunk_;
|
||||
while (chunk) {
|
||||
Chunk* next = chunk->next;
|
||||
delete chunk;
|
||||
chunk = next;
|
||||
}
|
||||
head_chunk_ = NULL;
|
||||
}
|
||||
|
||||
void Arena::Reset() {
|
||||
active_chunk_ = head_chunk_;
|
||||
if (active_chunk_) {
|
||||
active_chunk_->offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void* Arena::Alloc(size_t size) {
|
||||
if (active_chunk_) {
|
||||
if (active_chunk_->capacity - active_chunk_->offset < size) {
|
||||
Chunk* next = active_chunk_->next;
|
||||
if (!next) {
|
||||
XEASSERT(size < size); // need to support larger chunks
|
||||
next = new Chunk(chunk_size_);
|
||||
active_chunk_->next = next;
|
||||
}
|
||||
active_chunk_ = next;
|
||||
}
|
||||
} else {
|
||||
head_chunk_ = active_chunk_ = new Chunk(chunk_size_);
|
||||
}
|
||||
|
||||
uint8_t* p = active_chunk_->buffer + active_chunk_->offset;
|
||||
active_chunk_->offset += size;
|
||||
return p;
|
||||
}
|
||||
|
||||
void* Arena::CloneContents() {
|
||||
size_t total_length = 0;
|
||||
Chunk* chunk = head_chunk_;
|
||||
while (chunk) {
|
||||
total_length += chunk->offset;
|
||||
if (chunk == active_chunk_) {
|
||||
break;
|
||||
}
|
||||
chunk = chunk->next;
|
||||
}
|
||||
void* result = xe_malloc(total_length);
|
||||
uint8_t* p = (uint8_t*)result;
|
||||
chunk = head_chunk_;
|
||||
while (chunk) {
|
||||
xe_copy_struct(p, chunk->buffer, chunk->offset);
|
||||
p += chunk->offset;
|
||||
if (chunk == active_chunk_) {
|
||||
break;
|
||||
}
|
||||
chunk = chunk->next;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Arena::Chunk::Chunk(size_t chunk_size) :
|
||||
next(NULL),
|
||||
capacity(chunk_size), buffer(0), offset(0) {
|
||||
buffer = (uint8_t*)xe_malloc(capacity);
|
||||
}
|
||||
|
||||
Arena::Chunk::~Chunk() {
|
||||
if (buffer) {
|
||||
xe_free(buffer);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_ARENA_H_
|
||||
#define ALLOY_ARENA_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
|
||||
|
||||
class Arena {
|
||||
public:
|
||||
Arena(size_t chunk_size = 4 * 1024 * 1024);
|
||||
~Arena();
|
||||
|
||||
void Reset();
|
||||
|
||||
void* Alloc(size_t size);
|
||||
template<typename T> T* Alloc() {
|
||||
return (T*)Alloc(sizeof(T));
|
||||
}
|
||||
|
||||
void* CloneContents();
|
||||
|
||||
private:
|
||||
class Chunk {
|
||||
public:
|
||||
Chunk(size_t chunk_size);
|
||||
~Chunk();
|
||||
|
||||
Chunk* next;
|
||||
|
||||
size_t capacity;
|
||||
uint8_t* buffer;
|
||||
size_t offset;
|
||||
};
|
||||
|
||||
private:
|
||||
size_t chunk_size_;
|
||||
Chunk* head_chunk_;
|
||||
Chunk* active_chunk_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_ARENA_H_
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 <alloy/backend/assembler.h>
|
||||
|
||||
#include <alloy/backend/tracing.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::backend;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
|
||||
Assembler::Assembler(Backend* backend) :
|
||||
backend_(backend) {
|
||||
}
|
||||
|
||||
Assembler::~Assembler() {
|
||||
Reset();
|
||||
}
|
||||
|
||||
int Assembler::Initialize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Assembler::Reset() {
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_BACKEND_ASSEMBLER_H_
|
||||
#define ALLOY_BACKEND_ASSEMBLER_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace hir {
|
||||
class FunctionBuilder;
|
||||
}
|
||||
namespace runtime {
|
||||
class Function;
|
||||
class FunctionInfo;
|
||||
class Runtime;
|
||||
}
|
||||
}
|
||||
|
||||
namespace alloy {
|
||||
namespace backend {
|
||||
|
||||
class Backend;
|
||||
|
||||
|
||||
class Assembler {
|
||||
public:
|
||||
Assembler(Backend* backend);
|
||||
virtual ~Assembler();
|
||||
|
||||
virtual int Initialize();
|
||||
|
||||
virtual void Reset();
|
||||
|
||||
virtual int Assemble(
|
||||
runtime::FunctionInfo* symbol_info, hir::FunctionBuilder* builder,
|
||||
runtime::Function** out_function) = 0;
|
||||
|
||||
protected:
|
||||
Backend* backend_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace backend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_BACKEND_ASSEMBLER_H_
|
|
@ -0,0 +1,35 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 <alloy/backend/backend.h>
|
||||
|
||||
#include <alloy/backend/tracing.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::backend;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
|
||||
Backend::Backend(Runtime* runtime) :
|
||||
runtime_(runtime) {
|
||||
}
|
||||
|
||||
Backend::~Backend() {
|
||||
}
|
||||
|
||||
int Backend::Initialize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* Backend::AllocThreadData() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Backend::FreeThreadData(void* thread_data) {
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_BACKEND_BACKEND_H_
|
||||
#define ALLOY_BACKEND_BACKEND_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
|
||||
|
||||
namespace alloy { namespace runtime { class Runtime; } }
|
||||
|
||||
namespace alloy {
|
||||
namespace backend {
|
||||
|
||||
class Assembler;
|
||||
|
||||
|
||||
class Backend {
|
||||
public:
|
||||
Backend(runtime::Runtime* runtime);
|
||||
virtual ~Backend();
|
||||
|
||||
virtual int Initialize();
|
||||
|
||||
virtual void* AllocThreadData();
|
||||
virtual void FreeThreadData(void* thread_data);
|
||||
|
||||
virtual Assembler* CreateAssembler() = 0;
|
||||
|
||||
protected:
|
||||
runtime::Runtime* runtime_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace backend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_BACKEND_BACKEND_H_
|
|
@ -0,0 +1,95 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 <alloy/backend/ivm/ivm_assembler.h>
|
||||
|
||||
#include <alloy/backend/tracing.h>
|
||||
#include <alloy/backend/ivm/ivm_intcode.h>
|
||||
#include <alloy/backend/ivm/ivm_function.h>
|
||||
#include <alloy/hir/function_builder.h>
|
||||
#include <alloy/hir/label.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::backend;
|
||||
using namespace alloy::backend::ivm;
|
||||
using namespace alloy::hir;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
|
||||
IVMAssembler::IVMAssembler(Backend* backend) :
|
||||
Assembler(backend) {
|
||||
}
|
||||
|
||||
IVMAssembler::~IVMAssembler() {
|
||||
alloy::tracing::WriteEvent(EventType::AssemblerDeinit({
|
||||
}));
|
||||
}
|
||||
|
||||
int IVMAssembler::Initialize() {
|
||||
int result = Assembler::Initialize();
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
alloy::tracing::WriteEvent(EventType::AssemblerInit({
|
||||
}));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void IVMAssembler::Reset() {
|
||||
intcode_arena_.Reset();
|
||||
scratch_arena_.Reset();
|
||||
Assembler::Reset();
|
||||
}
|
||||
|
||||
int IVMAssembler::Assemble(
|
||||
FunctionInfo* symbol_info, FunctionBuilder* builder,
|
||||
Function** out_function) {
|
||||
IVMFunction* fn = new IVMFunction(symbol_info);
|
||||
|
||||
TranslationContext ctx;
|
||||
ctx.register_count = 0;
|
||||
ctx.intcode_count = 0;
|
||||
ctx.intcode_arena = &intcode_arena_;
|
||||
ctx.scratch_arena = &scratch_arena_;
|
||||
ctx.label_ref_head = NULL;
|
||||
|
||||
// Function prologue.
|
||||
|
||||
Block* block = builder->first_block();
|
||||
while (block) {
|
||||
Label* label = block->label_head;
|
||||
while (label) {
|
||||
label->tag = (void*)(0x80000000 | ctx.intcode_count);
|
||||
label = label->next;
|
||||
}
|
||||
|
||||
Instr* i = block->instr_head;
|
||||
while (i) {
|
||||
int result = TranslateIntCodes(ctx, i);
|
||||
i = i->next;
|
||||
}
|
||||
block = block->next;
|
||||
}
|
||||
|
||||
// Function epilogue.
|
||||
|
||||
// Fixup label references.
|
||||
LabelRef* label_ref = ctx.label_ref_head;
|
||||
while (label_ref) {
|
||||
label_ref->instr->src1_reg = (uint32_t)label_ref->label->tag & ~0x80000000;
|
||||
label_ref = label_ref->next;
|
||||
}
|
||||
|
||||
fn->Setup(ctx);
|
||||
|
||||
*out_function = fn;
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_BACKEND_IVM_IVM_ASSEMBLER_H_
|
||||
#define ALLOY_BACKEND_IVM_IVM_ASSEMBLER_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
|
||||
#include <alloy/backend/assembler.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace backend {
|
||||
namespace ivm {
|
||||
|
||||
|
||||
class IVMAssembler : public Assembler {
|
||||
public:
|
||||
IVMAssembler(Backend* backend);
|
||||
virtual ~IVMAssembler();
|
||||
|
||||
virtual int Initialize();
|
||||
|
||||
virtual void Reset();
|
||||
|
||||
virtual int Assemble(
|
||||
runtime::FunctionInfo* symbol_info, hir::FunctionBuilder* builder,
|
||||
runtime::Function** out_function);
|
||||
|
||||
private:
|
||||
Arena intcode_arena_;
|
||||
Arena scratch_arena_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace ivm
|
||||
} // namespace backend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_BACKEND_IVM_IVM_ASSEMBLER_H_
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 <alloy/backend/ivm/ivm_backend.h>
|
||||
|
||||
#include <alloy/backend/tracing.h>
|
||||
#include <alloy/backend/ivm/ivm_assembler.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::backend;
|
||||
using namespace alloy::backend::ivm;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
|
||||
IVMBackend::IVMBackend(Runtime* runtime) :
|
||||
Backend(runtime) {
|
||||
}
|
||||
|
||||
IVMBackend::~IVMBackend() {
|
||||
alloy::tracing::WriteEvent(EventType::Deinit({
|
||||
}));
|
||||
}
|
||||
|
||||
int IVMBackend::Initialize() {
|
||||
int result = Backend::Initialize();
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
alloy::tracing::WriteEvent(EventType::Init({
|
||||
}));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Assembler* IVMBackend::CreateAssembler() {
|
||||
return new IVMAssembler(this);
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_BACKEND_IVM_IVM_BACKEND_H_
|
||||
#define ALLOY_BACKEND_IVM_IVM_BACKEND_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
|
||||
#include <alloy/backend/backend.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace backend {
|
||||
namespace ivm {
|
||||
|
||||
|
||||
#define ALLOY_HAS_IVM_BACKEND 1
|
||||
|
||||
|
||||
class IVMBackend : public Backend {
|
||||
public:
|
||||
IVMBackend(runtime::Runtime* runtime);
|
||||
virtual ~IVMBackend();
|
||||
|
||||
virtual int Initialize();
|
||||
|
||||
virtual Assembler* CreateAssembler();
|
||||
};
|
||||
|
||||
|
||||
} // namespace ivm
|
||||
} // namespace backend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_BACKEND_IVM_IVM_BACKEND_H_
|
|
@ -0,0 +1,66 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 <alloy/backend/ivm/ivm_function.h>
|
||||
|
||||
#include <alloy/backend/tracing.h>
|
||||
#include <alloy/runtime/thread_state.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::backend;
|
||||
using namespace alloy::backend::ivm;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
|
||||
IVMFunction::IVMFunction(FunctionInfo* symbol_info) :
|
||||
register_count_(0), intcode_count_(0), intcodes_(0),
|
||||
GuestFunction(symbol_info) {
|
||||
}
|
||||
|
||||
IVMFunction::~IVMFunction() {
|
||||
xe_free(intcodes_);
|
||||
}
|
||||
|
||||
void IVMFunction::Setup(TranslationContext& ctx) {
|
||||
register_count_ = ctx.register_count;
|
||||
intcode_count_ = ctx.intcode_count;
|
||||
intcodes_ = (IntCode*)ctx.intcode_arena->CloneContents();
|
||||
}
|
||||
|
||||
int IVMFunction::CallImpl(ThreadState* thread_state) {
|
||||
// Setup register file on stack.
|
||||
size_t register_file_size = register_count_ * sizeof(Register);
|
||||
Register* register_file = (Register*)alloca(register_file_size);
|
||||
|
||||
IntCodeState ics;
|
||||
ics.rf = register_file;
|
||||
ics.context = (uint8_t*)thread_state->raw_context();
|
||||
ics.membase = thread_state->memory()->membase();
|
||||
ics.did_carry = 0;
|
||||
ics.thread_state = thread_state;
|
||||
ics.return_address = 0xBEBEBEBE;
|
||||
|
||||
// TODO(benvanik): DID_CARRY -- need HIR to set a OPCODE_FLAG_SET_CARRY
|
||||
// or something so the fns can set an ics flag.
|
||||
|
||||
uint32_t ia = 0;
|
||||
while (true) {
|
||||
const IntCode* i = &intcodes_[ia];
|
||||
uint32_t new_ia = i->intcode_fn(ics, i);
|
||||
if (new_ia == IA_NEXT) {
|
||||
ia++;
|
||||
} else if (new_ia == IA_RETURN) {
|
||||
break;
|
||||
} else {
|
||||
ia = new_ia;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_BACKEND_IVM_IVM_FUNCTION_H_
|
||||
#define ALLOY_BACKEND_IVM_IVM_FUNCTION_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
#include <alloy/backend/ivm/ivm_intcode.h>
|
||||
#include <alloy/runtime/function.h>
|
||||
#include <alloy/runtime/symbol_info.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace backend {
|
||||
namespace ivm {
|
||||
|
||||
|
||||
class IVMFunction : public runtime::GuestFunction {
|
||||
public:
|
||||
IVMFunction(runtime::FunctionInfo* symbol_info);
|
||||
virtual ~IVMFunction();
|
||||
|
||||
void Setup(TranslationContext& ctx);
|
||||
|
||||
protected:
|
||||
virtual int CallImpl(runtime::ThreadState* thread_state);
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
size_t register_count_;
|
||||
Register* constant_regiters_;
|
||||
size_t intcode_count_;
|
||||
IntCode* intcodes_;
|
||||
// ... source_map_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace ivm
|
||||
} // namespace backend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_BACKEND_IVM_IVM_FUNCTION_H_
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,104 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_BACKEND_IVM_INTCODE_H_
|
||||
#define ALLOY_BACKEND_IVM_INTCODE_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
|
||||
#include <alloy/hir/instr.h>
|
||||
#include <alloy/hir/opcodes.h>
|
||||
|
||||
namespace alloy { namespace runtime { class ThreadState; } }
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace backend {
|
||||
namespace ivm {
|
||||
|
||||
|
||||
typedef union {
|
||||
int8_t i8;
|
||||
uint8_t u8;
|
||||
int16_t i16;
|
||||
uint16_t u16;
|
||||
int32_t i32;
|
||||
uint32_t u32;
|
||||
int64_t i64;
|
||||
uint64_t u64;
|
||||
float f32;
|
||||
double f64;
|
||||
vec128_t v128;
|
||||
} Register;
|
||||
|
||||
|
||||
typedef struct {
|
||||
Register* rf;
|
||||
uint8_t* context;
|
||||
uint8_t* membase;
|
||||
int8_t did_carry;
|
||||
runtime::ThreadState* thread_state;
|
||||
uint64_t return_address;
|
||||
} IntCodeState;
|
||||
|
||||
|
||||
struct IntCode_s;
|
||||
typedef uint32_t (*IntCodeFn)(
|
||||
IntCodeState& ics, const struct IntCode_s* i);
|
||||
|
||||
#define IA_RETURN 0xA0000000
|
||||
#define IA_NEXT 0xB0000000
|
||||
|
||||
|
||||
typedef struct IntCode_s {
|
||||
IntCodeFn intcode_fn;
|
||||
uint16_t flags;
|
||||
|
||||
uint32_t dest_reg;
|
||||
union {
|
||||
struct {
|
||||
uint32_t src1_reg;
|
||||
uint32_t src2_reg;
|
||||
uint32_t src3_reg;
|
||||
// <4 bytes available>
|
||||
};
|
||||
struct {
|
||||
Register constant;
|
||||
};
|
||||
};
|
||||
|
||||
// debugging info/etc
|
||||
} IntCode;
|
||||
|
||||
|
||||
typedef struct LabelRef_s {
|
||||
hir::Label* label;
|
||||
IntCode* instr;
|
||||
LabelRef_s* next;
|
||||
} LabelRef;
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32_t register_count;
|
||||
size_t intcode_count;
|
||||
Arena* intcode_arena;
|
||||
Arena* scratch_arena;
|
||||
LabelRef* label_ref_head;
|
||||
} TranslationContext;
|
||||
|
||||
|
||||
int TranslateIntCodes(TranslationContext& ctx, hir::Instr* i);
|
||||
|
||||
|
||||
} // namespace ivm
|
||||
} // namespace backend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_BACKEND_IVM_INTCODE_H_
|
|
@ -0,0 +1,13 @@
|
|||
# Copyright 2013 Ben Vanik. All Rights Reserved.
|
||||
{
|
||||
'sources': [
|
||||
'ivm_intcode.cc',
|
||||
'ivm_intcode.h',
|
||||
'ivm_assembler.cc',
|
||||
'ivm_assembler.h',
|
||||
'ivm_backend.cc',
|
||||
'ivm_backend.h',
|
||||
'ivm_function.cc',
|
||||
'ivm_function.h',
|
||||
],
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
# Copyright 2013 Ben Vanik. All Rights Reserved.
|
||||
{
|
||||
'sources': [
|
||||
'assembler.cc',
|
||||
'assembler.h',
|
||||
'backend.cc',
|
||||
'backend.h',
|
||||
'tracing.h',
|
||||
],
|
||||
|
||||
'includes': [
|
||||
'ivm/sources.gypi',
|
||||
'x64/sources.gypi',
|
||||
],
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_BACKEND_TRACING_H_
|
||||
#define ALLOY_BACKEND_TRACING_H_
|
||||
|
||||
#include <alloy/tracing/tracing.h>
|
||||
#include <alloy/tracing/event_type.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace backend {
|
||||
|
||||
const uint32_t ALLOY_BACKEND = alloy::tracing::EventType::ALLOY_BACKEND;
|
||||
|
||||
|
||||
class EventType {
|
||||
public:
|
||||
enum {
|
||||
ALLOY_BACKEND_INIT = ALLOY_BACKEND | (1),
|
||||
ALLOY_BACKEND_DEINIT = ALLOY_BACKEND | (2),
|
||||
|
||||
ALLOY_BACKEND_ASSEMBLER = ALLOY_BACKEND | (1 << 25),
|
||||
ALLOY_BACKEND_ASSEMBLER_INIT = ALLOY_BACKEND_ASSEMBLER | (1),
|
||||
ALLOY_BACKEND_ASSEMBLER_DEINIT = ALLOY_BACKEND_ASSEMBLER | (2),
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
static const uint32_t event_type = ALLOY_BACKEND_INIT;
|
||||
} Init;
|
||||
typedef struct {
|
||||
static const uint32_t event_type = ALLOY_BACKEND_DEINIT;
|
||||
} Deinit;
|
||||
|
||||
typedef struct {
|
||||
static const uint32_t event_type = ALLOY_BACKEND_ASSEMBLER_INIT;
|
||||
} AssemblerInit;
|
||||
typedef struct {
|
||||
static const uint32_t event_type = ALLOY_BACKEND_ASSEMBLER_DEINIT;
|
||||
} AssemblerDeinit;
|
||||
};
|
||||
|
||||
|
||||
} // namespace backend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_BACKEND_TRACING_H_
|
|
@ -0,0 +1,5 @@
|
|||
# Copyright 2013 Ben Vanik. All Rights Reserved.
|
||||
{
|
||||
'sources': [
|
||||
],
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 <alloy/compiler/compiler.h>
|
||||
|
||||
#include <alloy/compiler/pass.h>
|
||||
#include <alloy/compiler/tracing.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::compiler;
|
||||
using namespace alloy::hir;
|
||||
|
||||
|
||||
Compiler::Compiler() {
|
||||
alloy::tracing::WriteEvent(EventType::Init({
|
||||
}));
|
||||
}
|
||||
|
||||
Compiler::~Compiler() {
|
||||
Reset();
|
||||
|
||||
for (PassList::iterator it = passes_.begin(); it != passes_.end(); ++it) {
|
||||
Pass* pass = *it;
|
||||
delete pass;
|
||||
}
|
||||
|
||||
alloy::tracing::WriteEvent(EventType::Deinit({
|
||||
}));
|
||||
}
|
||||
|
||||
void Compiler::AddPass(Pass* pass) {
|
||||
passes_.push_back(pass);
|
||||
}
|
||||
|
||||
void Compiler::Reset() {
|
||||
}
|
||||
|
||||
int Compiler::Compile(FunctionBuilder* builder) {
|
||||
// TODO(benvanik): sophisticated stuff. Run passes in parallel, run until they
|
||||
// stop changing things, etc.
|
||||
for (PassList::iterator it = passes_.begin(); it != passes_.end(); ++it) {
|
||||
Pass* pass = *it;
|
||||
//
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_COMPILER_COMPILER_H_
|
||||
#define ALLOY_COMPILER_COMPILER_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
#include <alloy/hir/function_builder.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace compiler {
|
||||
|
||||
class Pass;
|
||||
|
||||
|
||||
class Compiler {
|
||||
public:
|
||||
Compiler();
|
||||
~Compiler();
|
||||
|
||||
void AddPass(Pass* pass);
|
||||
|
||||
void Reset();
|
||||
|
||||
int Compile(hir::FunctionBuilder* builder);
|
||||
|
||||
private:
|
||||
typedef std::vector<Pass*> PassList;
|
||||
PassList passes_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_COMPILER_COMPILER_H_
|
|
@ -7,13 +7,14 @@
|
|||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_CPU_SDB_H_
|
||||
#define XENIA_CPU_SDB_H_
|
||||
#include <alloy/compiler/pass.h>
|
||||
|
||||
#include <xenia/cpu/sdb/raw_symbol_database.h>
|
||||
#include <xenia/cpu/sdb/symbol.h>
|
||||
#include <xenia/cpu/sdb/symbol_database.h>
|
||||
#include <xenia/cpu/sdb/symbol_table.h>
|
||||
#include <xenia/cpu/sdb/xex_symbol_database.h>
|
||||
using namespace alloy;
|
||||
using namespace alloy::compiler;
|
||||
|
||||
#endif // XENIA_CPU_SDB_H_
|
||||
|
||||
Pass::Pass() {
|
||||
}
|
||||
|
||||
Pass::~Pass() {
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_COMPILER_PASS_H_
|
||||
#define ALLOY_COMPILER_PASS_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace compiler {
|
||||
|
||||
|
||||
class Pass {
|
||||
public:
|
||||
Pass();
|
||||
virtual ~Pass();
|
||||
};
|
||||
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_COMPILER_PASS_H_
|
|
@ -0,0 +1,15 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_COMPILER_PASSES_H_
|
||||
#define ALLOY_COMPILER_PASSES_H_
|
||||
|
||||
#include <alloy/compiler/passes/mem2reg_pass.h>
|
||||
|
||||
#endif // ALLOY_COMPILER_PASSES_H_
|
|
@ -0,0 +1,22 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 <alloy/compiler/passes/mem2reg_pass.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::compiler;
|
||||
using namespace alloy::compiler::passes;
|
||||
|
||||
|
||||
Mem2RegPass::Mem2RegPass() :
|
||||
Pass() {
|
||||
}
|
||||
|
||||
Mem2RegPass::~Mem2RegPass() {
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_COMPILER_PASSES_MEM2REG_PASS_H_
|
||||
#define ALLOY_COMPILER_PASSES_MEM2REG_PASS_H_
|
||||
|
||||
#include <alloy/compiler/pass.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace compiler {
|
||||
namespace passes {
|
||||
|
||||
|
||||
class Mem2RegPass : public Pass {
|
||||
public:
|
||||
Mem2RegPass();
|
||||
virtual ~Mem2RegPass();
|
||||
};
|
||||
|
||||
|
||||
} // namespace passes
|
||||
} // namespace compiler
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_COMPILER_PASSES_MEM2REG_PASS_H_
|
|
@ -0,0 +1,7 @@
|
|||
# Copyright 2013 Ben Vanik. All Rights Reserved.
|
||||
{
|
||||
'sources': [
|
||||
'mem2reg_pass.cc',
|
||||
'mem2reg_pass.h',
|
||||
],
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
# Copyright 2013 Ben Vanik. All Rights Reserved.
|
||||
{
|
||||
'sources': [
|
||||
'compiler.cc',
|
||||
'compiler.h',
|
||||
'pass.cc',
|
||||
'pass.h',
|
||||
'passes.h',
|
||||
'tracing.h',
|
||||
],
|
||||
|
||||
'includes': [
|
||||
'passes/sources.gypi',
|
||||
],
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_COMPILER_TRACING_H_
|
||||
#define ALLOY_COMPILER_TRACING_H_
|
||||
|
||||
#include <alloy/tracing/tracing.h>
|
||||
#include <alloy/tracing/event_type.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace compiler {
|
||||
|
||||
const uint32_t ALLOY_COMPILER = alloy::tracing::EventType::ALLOY_COMPILER;
|
||||
|
||||
|
||||
class EventType {
|
||||
public:
|
||||
enum {
|
||||
ALLOY_COMPILER_INIT = ALLOY_COMPILER | (1),
|
||||
ALLOY_COMPILER_DEINIT = ALLOY_COMPILER | (2),
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
static const uint32_t event_type = ALLOY_COMPILER_INIT;
|
||||
} Init;
|
||||
typedef struct {
|
||||
static const uint32_t event_type = ALLOY_COMPILER_DEINIT;
|
||||
} Deinit;
|
||||
};
|
||||
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_COMPILER_TRACING_H_
|
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_CORE_H_
|
||||
#define ALLOY_CORE_H_
|
||||
|
||||
// TODO(benvanik): move the common stuff into here?
|
||||
#include <xenia/common.h>
|
||||
|
||||
#include <alloy/arena.h>
|
||||
#include <alloy/mutex.h>
|
||||
#include <alloy/string_buffer.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
|
||||
typedef struct XECACHEALIGN vec128_s {
|
||||
union {
|
||||
struct {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float w;
|
||||
};
|
||||
struct {
|
||||
uint32_t ix;
|
||||
uint32_t iy;
|
||||
uint32_t iz;
|
||||
uint32_t iw;
|
||||
};
|
||||
float f4[4];
|
||||
uint32_t i4[4];
|
||||
uint16_t s8[8];
|
||||
uint8_t b16[16];
|
||||
struct {
|
||||
uint64_t low;
|
||||
uint64_t high;
|
||||
};
|
||||
};
|
||||
} vec128_t;
|
||||
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_CORE_H_
|
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 <alloy/frontend/frontend.h>
|
||||
|
||||
#include <alloy/frontend/tracing.h>
|
||||
#include <alloy/runtime/runtime.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::frontend;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
|
||||
Frontend::Frontend(Runtime* runtime) :
|
||||
runtime_(runtime) {
|
||||
}
|
||||
|
||||
Frontend::~Frontend() {
|
||||
}
|
||||
|
||||
Memory* Frontend::memory() const {
|
||||
return runtime_->memory();
|
||||
}
|
||||
|
||||
int Frontend::Initialize() {
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_FRONTEND_FRONTEND_H_
|
||||
#define ALLOY_FRONTEND_FRONTEND_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
#include <alloy/memory.h>
|
||||
#include <alloy/runtime/function.h>
|
||||
#include <alloy/runtime/symbol_info.h>
|
||||
|
||||
|
||||
namespace alloy { namespace runtime {
|
||||
class Runtime;
|
||||
} }
|
||||
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
|
||||
|
||||
class Frontend {
|
||||
public:
|
||||
Frontend(runtime::Runtime* runtime);
|
||||
virtual ~Frontend();
|
||||
|
||||
runtime::Runtime* runtime() const { return runtime_; }
|
||||
Memory* memory() const;
|
||||
|
||||
virtual int Initialize();
|
||||
|
||||
virtual int DeclareFunction(
|
||||
runtime::FunctionInfo* symbol_info) = 0;
|
||||
virtual int DefineFunction(
|
||||
runtime::FunctionInfo* symbol_info,
|
||||
runtime::Function** out_function) = 0;
|
||||
|
||||
protected:
|
||||
runtime::Runtime* runtime_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_FRONTEND_FRONTEND_H_
|
|
@ -7,9 +7,11 @@
|
|||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include <xenia/common.h>
|
||||
#include <xenia/core.h>
|
||||
#include <xenia/cpu/ppc/state.h>
|
||||
#include <alloy/frontend/ppc/ppc_context.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::frontend;
|
||||
using namespace alloy::frontend::ppc;
|
||||
|
||||
|
||||
namespace {
|
||||
|
@ -20,7 +22,8 @@ uint64_t ParseInt64(const char* value) {
|
|||
|
||||
}
|
||||
|
||||
void xe_ppc_state::SetRegFromString(const char* name, const char* value) {
|
||||
|
||||
void PPCContext::SetRegFromString(const char* name, const char* value) {
|
||||
int n;
|
||||
if (sscanf(name, "r%d", &n) == 1) {
|
||||
this->r[n] = ParseInt64(value);
|
||||
|
@ -29,7 +32,7 @@ void xe_ppc_state::SetRegFromString(const char* name, const char* value) {
|
|||
}
|
||||
}
|
||||
|
||||
bool xe_ppc_state::CompareRegWithString(
|
||||
bool PPCContext::CompareRegWithString(
|
||||
const char* name, const char* value,
|
||||
char* out_value, size_t out_value_size) {
|
||||
int n;
|
|
@ -7,99 +7,133 @@
|
|||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_CPU_PPC_STATE_H_
|
||||
#define XENIA_CPU_PPC_STATE_H_
|
||||
#ifndef ALLOY_FRONTEND_PPC_PPC_CONTEXT_H_
|
||||
#define ALLOY_FRONTEND_PPC_PPC_CONTEXT_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <alloy/core.h>
|
||||
|
||||
|
||||
XEDECLARECLASS2(xe, cpu, Processor);
|
||||
XEDECLARECLASS2(xe, cpu, ThreadState);
|
||||
namespace alloy { namespace runtime {
|
||||
class Runtime;
|
||||
class ThreadState;
|
||||
} }
|
||||
|
||||
|
||||
// namespace FPRF {
|
||||
// enum FPRF_e {
|
||||
// QUIET_NAN = 0x00088000,
|
||||
// NEG_INFINITY = 0x00090000,
|
||||
// NEG_NORMALIZED = 0x00010000,
|
||||
// NEG_DENORMALIZED = 0x00018000,
|
||||
// NEG_ZERO = 0x00048000,
|
||||
// POS_ZERO = 0x00040000,
|
||||
// POS_DENORMALIZED = 0x00028000,
|
||||
// POS_NORMALIZED = 0x00020000,
|
||||
// POS_INFINITY = 0x000A0000,
|
||||
// };
|
||||
// } // FPRF
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
namespace ppc {
|
||||
|
||||
|
||||
#define kXEPPCRegLR 0xFFFF0001
|
||||
#define kXEPPCRegCTR 0xFFFF0002
|
||||
using vec128_t = alloy::vec128_t;
|
||||
|
||||
|
||||
typedef struct XECACHEALIGN xe_float4 {
|
||||
union {
|
||||
struct {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float w;
|
||||
};
|
||||
struct {
|
||||
uint32_t ix;
|
||||
uint32_t iy;
|
||||
uint32_t iz;
|
||||
uint32_t iw;
|
||||
};
|
||||
float f4[4];
|
||||
uint32_t i4[4];
|
||||
struct {
|
||||
uint64_t low;
|
||||
uint64_t high;
|
||||
};
|
||||
};
|
||||
} xe_float4_t;
|
||||
typedef union {
|
||||
uint32_t value;
|
||||
struct {
|
||||
uint8_t lt :1; // Negative (LT) - result is negative
|
||||
uint8_t gt :1; // Positive (GT) - result is positive (and not zero)
|
||||
uint8_t eq :1; // Zero (EQ) - result is zero or a stwcx/stdcx completed successfully
|
||||
uint8_t so :1; // Summary Overflow (SO) - copy of XER[SO]
|
||||
} cr0;
|
||||
struct {
|
||||
uint8_t fx :1; // FP exception summary - copy of FPSCR[FX]
|
||||
uint8_t fex :1; // FP enabled exception summary - copy of FPSCR[FEX]
|
||||
uint8_t vx :1; // FP invalid operation exception summary - copy of FPSCR[VX]
|
||||
uint8_t ox :1; // FP overflow exception - copy of FPSCR[OX]
|
||||
} cr1;
|
||||
struct {
|
||||
uint8_t value :4;
|
||||
} cr2;
|
||||
struct {
|
||||
uint8_t value :4;
|
||||
} cr3;
|
||||
struct {
|
||||
uint8_t value :4;
|
||||
} cr4;
|
||||
struct {
|
||||
uint8_t value :4;
|
||||
} cr5;
|
||||
struct {
|
||||
uint8_t value :4;
|
||||
} cr6;
|
||||
struct {
|
||||
uint8_t value :4;
|
||||
} cr7;
|
||||
} PPCCR;
|
||||
|
||||
|
||||
typedef struct XECACHEALIGN64 xe_ppc_state {
|
||||
uint32_t cia; // Current PC (CIA)
|
||||
uint32_t nia; // Next PC (NIA)
|
||||
uint64_t xer; // XER register
|
||||
#pragma pack(push, 4)
|
||||
typedef struct XECACHEALIGN64 PPCContext_s {
|
||||
// Most frequently used registers first.
|
||||
uint64_t r[32]; // General purpose registers
|
||||
uint64_t lr; // Link register
|
||||
uint64_t ctr; // Count register
|
||||
|
||||
// XER register
|
||||
// Split to make it easier to do individual updates.
|
||||
uint8_t xer_ca;
|
||||
uint8_t xer_ov;
|
||||
uint8_t xer_so;
|
||||
|
||||
// Condition registers
|
||||
// These are split to make it easier to do DCE on unused stores.
|
||||
union {
|
||||
uint32_t value;
|
||||
struct {
|
||||
uint8_t lt :1; // Negative (LT) - result is negative
|
||||
uint8_t gt :1; // Positive (GT) - result is positive (and not zero)
|
||||
uint8_t eq :1; // Zero (EQ) - result is zero or a stwcx/stdcx completed successfully
|
||||
uint8_t so :1; // Summary Overflow (SO) - copy of XER[SO]
|
||||
} cr0;
|
||||
uint8_t cr0_lt; // Negative (LT) - result is negative
|
||||
uint8_t cr0_gt; // Positive (GT) - result is positive (and not zero)
|
||||
uint8_t cr0_eq; // Zero (EQ) - result is zero or a stwcx/stdcx completed successfully
|
||||
uint8_t cr0_so; // Summary Overflow (SO) - copy of XER[SO]
|
||||
};
|
||||
} cr0;
|
||||
union {
|
||||
uint32_t value;
|
||||
struct {
|
||||
uint8_t fx :1; // FP exception summary - copy of FPSCR[FX]
|
||||
uint8_t fex :1; // FP enabled exception summary - copy of FPSCR[FEX]
|
||||
uint8_t vx :1; // FP invalid operation exception summary - copy of FPSCR[VX]
|
||||
uint8_t ox :1; // FP overflow exception - copy of FPSCR[OX]
|
||||
} cr1;
|
||||
uint8_t cr1_fx; // FP exception summary - copy of FPSCR[FX]
|
||||
uint8_t cr1_fex; // FP enabled exception summary - copy of FPSCR[FEX]
|
||||
uint8_t cr1_vx; // FP invalid operation exception summary - copy of FPSCR[VX]
|
||||
uint8_t cr1_ox; // FP overflow exception - copy of FPSCR[OX]
|
||||
};
|
||||
} cr1;
|
||||
union {
|
||||
uint32_t value;
|
||||
struct {
|
||||
uint8_t value :4;
|
||||
} cr2;
|
||||
uint8_t cr2_0; uint8_t cr2_1; uint8_t cr2_2; uint8_t cr2_3;
|
||||
};
|
||||
} cr2;
|
||||
union {
|
||||
uint32_t value;
|
||||
struct {
|
||||
uint8_t value :4;
|
||||
} cr3;
|
||||
uint8_t cr3_0; uint8_t cr3_1; uint8_t cr3_2; uint8_t cr3_3;
|
||||
};
|
||||
} cr3;
|
||||
union {
|
||||
uint32_t value;
|
||||
struct {
|
||||
uint8_t value :4;
|
||||
} cr4;
|
||||
uint8_t cr4_0; uint8_t cr4_1; uint8_t cr4_2; uint8_t cr4_3;
|
||||
};
|
||||
} cr4;
|
||||
union {
|
||||
uint32_t value;
|
||||
struct {
|
||||
uint8_t value :4;
|
||||
} cr5;
|
||||
uint8_t cr5_0; uint8_t cr5_1; uint8_t cr5_2; uint8_t cr5_3;
|
||||
};
|
||||
} cr5;
|
||||
union {
|
||||
uint32_t value;
|
||||
struct {
|
||||
uint8_t value :4;
|
||||
} cr6;
|
||||
uint8_t cr6_0;
|
||||
uint8_t cr6_none_equal;
|
||||
uint8_t cr6_2;
|
||||
uint8_t cr6_all_equal;
|
||||
};
|
||||
} cr6;
|
||||
union {
|
||||
uint32_t value;
|
||||
struct {
|
||||
uint8_t value :4;
|
||||
} cr7;
|
||||
} cr; // Condition register
|
||||
uint8_t cr7_0; uint8_t cr7_1; uint8_t cr7_2; uint8_t cr7_3;
|
||||
};
|
||||
} cr7;
|
||||
|
||||
union {
|
||||
uint32_t value;
|
||||
|
@ -141,9 +175,8 @@ typedef struct XECACHEALIGN64 xe_ppc_state {
|
|||
} bits;
|
||||
} fpscr; // Floating-point status and control register
|
||||
|
||||
uint64_t r[32]; // General purpose registers
|
||||
xe_float4_t v[128]; // VMX128 vector registers
|
||||
double f[32]; // Floating-point registers
|
||||
double f[32]; // Floating-point registers
|
||||
vec128_t v[128]; // VMX128 vector registers
|
||||
|
||||
// uint32_t get_fprf() {
|
||||
// return fpscr.value & 0x000F8000;
|
||||
|
@ -154,14 +187,20 @@ typedef struct XECACHEALIGN64 xe_ppc_state {
|
|||
|
||||
// Runtime-specific data pointer. Used on callbacks to get access to the
|
||||
// current runtime and its data.
|
||||
uint8_t* membase;
|
||||
xe::cpu::Processor* processor;
|
||||
xe::cpu::ThreadState* thread_state;
|
||||
uint8_t* membase;
|
||||
runtime::Runtime* runtime;
|
||||
runtime::ThreadState* thread_state;
|
||||
|
||||
void SetRegFromString(const char* name, const char* value);
|
||||
bool CompareRegWithString(const char* name, const char* value,
|
||||
char* out_value, size_t out_value_size);
|
||||
} xe_ppc_state_t;
|
||||
} PPCContext;
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
#endif // XENIA_CPU_PPC_STATE_H_
|
||||
} // namespace ppc
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_FRONTEND_PPC_PPC_CONTEXT_H_
|
|
@ -7,36 +7,30 @@
|
|||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_CPU_PPC_DISASM_H_
|
||||
#define XENIA_CPU_PPC_DISASM_H_
|
||||
#ifndef ALLOY_FRONTEND_PPC_PPC_DISASM_PRIVATE_H_
|
||||
#define ALLOY_FRONTEND_PPC_PPC_DISASM_PRIVATE_H_
|
||||
|
||||
#include <xenia/cpu/ppc/instr.h>
|
||||
#include <alloy/frontend/ppc/ppc_disasm.h>
|
||||
#include <alloy/frontend/ppc/ppc_instr.h>
|
||||
|
||||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
namespace ppc {
|
||||
|
||||
|
||||
void RegisterDisasmCategoryAltivec();
|
||||
void RegisterDisasmCategoryALU();
|
||||
void RegisterDisasmCategoryControl();
|
||||
void RegisterDisasmCategoryFPU();
|
||||
void RegisterDisasmCategoryMemory();
|
||||
|
||||
|
||||
#define XEDISASMR(name, opcode, format) int InstrDisasm_##name
|
||||
|
||||
#define XEREGISTERINSTR(name, opcode) \
|
||||
RegisterInstrDisassemble(opcode, (InstrDisassembleFn)InstrDisasm_##name);
|
||||
|
||||
#define XEINSTRNOTIMPLEMENTED()
|
||||
//#define XEINSTRNOTIMPLEMENTED XEASSERTALWAYS
|
||||
//#define XEINSTRNOTIMPLEMENTED()
|
||||
#define XEINSTRNOTIMPLEMENTED XEASSERTALWAYS
|
||||
|
||||
|
||||
} // namespace ppc
|
||||
} // namespace cpu
|
||||
} // namespace xe
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // XENIA_CPU_PPC_DISASM_H_
|
||||
#endif // ALLOY_FRONTEND_PPC_PPC_DISASM_PRIVATE_H_
|
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_FRONTEND_PPC_PPC_DISASM_H_
|
||||
#define ALLOY_FRONTEND_PPC_PPC_DISASM_H_
|
||||
|
||||
#include <alloy/frontend/ppc/ppc_instr.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
namespace ppc {
|
||||
|
||||
|
||||
void RegisterDisasmCategoryAltivec();
|
||||
void RegisterDisasmCategoryALU();
|
||||
void RegisterDisasmCategoryControl();
|
||||
void RegisterDisasmCategoryFPU();
|
||||
void RegisterDisasmCategoryMemory();
|
||||
|
||||
|
||||
} // namespace ppc
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_FRONTEND_PPC_PPC_DISASM_H_
|
File diff suppressed because it is too large
Load Diff
|
@ -7,14 +7,14 @@
|
|||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include <xenia/cpu/ppc/disasm.h>
|
||||
#include <alloy/frontend/ppc/ppc_disasm-private.h>
|
||||
|
||||
|
||||
using namespace xe::cpu::ppc;
|
||||
using namespace alloy::frontend::ppc;
|
||||
|
||||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
namespace ppc {
|
||||
|
||||
|
||||
|
@ -724,5 +724,5 @@ void RegisterDisasmCategoryALU() {
|
|||
|
||||
|
||||
} // namespace ppc
|
||||
} // namespace cpu
|
||||
} // namespace xe
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
|
@ -7,14 +7,14 @@
|
|||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include <xenia/cpu/ppc/disasm.h>
|
||||
#include <alloy/frontend/ppc/ppc_disasm-private.h>
|
||||
|
||||
|
||||
using namespace xe::cpu::ppc;
|
||||
using namespace alloy::frontend::ppc;
|
||||
|
||||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
namespace ppc {
|
||||
|
||||
|
||||
|
@ -22,9 +22,9 @@ XEDISASMR(bx, 0x48000000, I )(InstrData& i, InstrDisasm& d) {
|
|||
d.Init("b", "Branch", i.I.LK ? InstrDisasm::kLR : 0);
|
||||
uint32_t nia;
|
||||
if (i.I.AA) {
|
||||
nia = XEEXTS26(i.I.LI << 2);
|
||||
nia = (uint32_t)XEEXTS26(i.I.LI << 2);
|
||||
} else {
|
||||
nia = i.address + XEEXTS26(i.I.LI << 2);
|
||||
nia = (uint32_t)(i.address + XEEXTS26(i.I.LI << 2));
|
||||
}
|
||||
d.AddUImmOperand(nia, 4);
|
||||
return d.Finish();
|
||||
|
@ -41,6 +41,13 @@ XEDISASMR(bcx, 0x40000000, B )(InstrData& i, InstrDisasm& d) {
|
|||
}
|
||||
d.AddUImmOperand(i.B.BO, 1);
|
||||
d.AddUImmOperand(i.B.BI, 1);
|
||||
uint32_t nia;
|
||||
if (i.B.AA) {
|
||||
nia = (uint32_t)XEEXTS16(i.B.BD << 2);
|
||||
} else {
|
||||
nia = (uint32_t)(i.address + XEEXTS16(i.B.BD << 2));
|
||||
}
|
||||
d.AddUImmOperand(nia, 4);
|
||||
return d.Finish();
|
||||
}
|
||||
|
||||
|
@ -272,5 +279,5 @@ void RegisterDisasmCategoryControl() {
|
|||
|
||||
|
||||
} // namespace ppc
|
||||
} // namespace cpu
|
||||
} // namespace xe
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
|
@ -7,14 +7,14 @@
|
|||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include <xenia/cpu/ppc/disasm.h>
|
||||
#include <alloy/frontend/ppc/ppc_disasm-private.h>
|
||||
|
||||
|
||||
using namespace xe::cpu::ppc;
|
||||
using namespace alloy::frontend::ppc;
|
||||
|
||||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
namespace ppc {
|
||||
|
||||
|
||||
|
@ -409,5 +409,5 @@ void RegisterDisasmCategoryFPU() {
|
|||
|
||||
|
||||
} // namespace ppc
|
||||
} // namespace cpu
|
||||
} // namespace xe
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
|
@ -7,14 +7,14 @@
|
|||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include <xenia/cpu/ppc/disasm.h>
|
||||
#include <alloy/frontend/ppc/ppc_disasm-private.h>
|
||||
|
||||
|
||||
using namespace xe::cpu::ppc;
|
||||
using namespace alloy::frontend::ppc;
|
||||
|
||||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
namespace ppc {
|
||||
|
||||
|
||||
|
@ -926,5 +926,5 @@ void RegisterDisasmCategoryMemory() {
|
|||
|
||||
|
||||
} // namespace ppc
|
||||
} // namespace cpu
|
||||
} // namespace xe
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
|
@ -7,24 +7,16 @@
|
|||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_CPU_X64_X64_EMIT_H_
|
||||
#define XENIA_CPU_X64_X64_EMIT_H_
|
||||
#ifndef ALLOY_FRONTEND_PPC_PPC_EMIT_PRIVATE_H_
|
||||
#define ALLOY_FRONTEND_PPC_PPC_EMIT_PRIVATE_H_
|
||||
|
||||
#include <xenia/cpu/ppc/instr.h>
|
||||
#include <xenia/cpu/ppc/state.h>
|
||||
#include <xenia/cpu/x64/x64_emitter.h>
|
||||
#include <alloy/frontend/ppc/ppc_emit.h>
|
||||
#include <alloy/frontend/ppc/ppc_instr.h>
|
||||
|
||||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
namespace x64 {
|
||||
|
||||
|
||||
void X64RegisterEmitCategoryAltivec();
|
||||
void X64RegisterEmitCategoryALU();
|
||||
void X64RegisterEmitCategoryControl();
|
||||
void X64RegisterEmitCategoryFPU();
|
||||
void X64RegisterEmitCategoryMemory();
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
namespace ppc {
|
||||
|
||||
|
||||
#define XEEMITTER(name, opcode, format) int InstrEmit_##name
|
||||
|
@ -32,13 +24,13 @@ void X64RegisterEmitCategoryMemory();
|
|||
#define XEREGISTERINSTR(name, opcode) \
|
||||
RegisterInstrEmit(opcode, (InstrEmitFn)InstrEmit_##name);
|
||||
|
||||
#define XEINSTRNOTIMPLEMENTED()
|
||||
//#define XEINSTRNOTIMPLEMENTED XEASSERTALWAYS
|
||||
//#define XEINSTRNOTIMPLEMENTED()
|
||||
#define XEINSTRNOTIMPLEMENTED XEASSERTALWAYS
|
||||
|
||||
|
||||
} // namespace x64
|
||||
} // namespace cpu
|
||||
} // namespace xe
|
||||
} // namespace ppc
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // XENIA_CPU_X64_X64_EMIT_H_
|
||||
#endif // ALLOY_FRONTEND_PPC_PPC_EMIT_PRIVATE_H_
|
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_FRONTEND_PPC_PPC_EMIT_H_
|
||||
#define ALLOY_FRONTEND_PPC_PPC_EMIT_H_
|
||||
|
||||
#include <alloy/frontend/ppc/ppc_instr.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
namespace ppc {
|
||||
|
||||
|
||||
void RegisterEmitCategoryAltivec();
|
||||
void RegisterEmitCategoryALU();
|
||||
void RegisterEmitCategoryControl();
|
||||
void RegisterEmitCategoryFPU();
|
||||
void RegisterEmitCategoryMemory();
|
||||
|
||||
|
||||
} // namespace ppc
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_FRONTEND_PPC_PPC_EMIT_H_
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,577 @@
|
|||
/*
|
||||
******************************************************************************
|
||||
* 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 <alloy/frontend/ppc/ppc_emit-private.h>
|
||||
|
||||
#include <alloy/frontend/ppc/ppc_context.h>
|
||||
#include <alloy/frontend/ppc/ppc_function_builder.h>
|
||||
|
||||
|
||||
using namespace alloy::frontend::ppc;
|
||||
using namespace alloy::hir;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
namespace ppc {
|
||||
|
||||
|
||||
int InstrEmit_branch(
|
||||
PPCFunctionBuilder& f, const char* src, uint64_t cia,
|
||||
Value* nia, bool lk, Value* cond = NULL, bool expect_true = true) {
|
||||
uint32_t call_flags = 0;
|
||||
|
||||
// TODO(benvanik): this may be wrong and overwrite LRs when not desired!
|
||||
// The docs say always, though...
|
||||
// Note that we do the update before we branch/call as we need it to
|
||||
// be correct for returns.
|
||||
if (lk) {
|
||||
f.StoreLR(f.LoadConstant(cia + 4));
|
||||
}
|
||||
|
||||
if (!lk) {
|
||||
// If LR is not set this call will never return here.
|
||||
call_flags |= CALL_TAIL;
|
||||
}
|
||||
|
||||
// TODO(benvanik): set CALL_TAIL if !lk and the last block in the fn.
|
||||
// This is almost always a jump to restore gpr.
|
||||
|
||||
// TODO(benvanik): detect call-self.
|
||||
|
||||
if (nia->IsConstant()) {
|
||||
// Direct branch to address.
|
||||
// If it's a block inside of ourself, setup a fast jump.
|
||||
uint64_t nia_value = nia->AsUint64() & 0xFFFFFFFF;
|
||||
Label* label = f.LookupLabel(nia_value);
|
||||
if (label) {
|
||||
// Branch to label.
|
||||
uint32_t branch_flags = 0;
|
||||
if (cond) {
|
||||
if (expect_true) {
|
||||
f.BranchTrue(cond, label, branch_flags);
|
||||
} else {
|
||||
f.BranchFalse(cond, label, branch_flags);
|
||||
}
|
||||
} else {
|
||||
f.Branch(label, branch_flags);
|
||||
}
|
||||
} else {
|
||||
// Call function.
|
||||
FunctionInfo* symbol_info = f.LookupFunction(nia_value);
|
||||
if (cond) {
|
||||
if (!expect_true) {
|
||||
cond = f.IsFalse(cond);
|
||||
}
|
||||
f.CallTrue(cond, symbol_info, call_flags);
|
||||
} else {
|
||||
f.Call(symbol_info, call_flags);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Indirect branch to pointer.
|
||||
if (cond) {
|
||||
if (!expect_true) {
|
||||
cond = f.IsFalse(cond);
|
||||
}
|
||||
f.CallIndirectTrue(cond, nia, call_flags);
|
||||
} else {
|
||||
f.CallIndirect(nia, call_flags);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
XEEMITTER(bx, 0x48000000, I )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// if AA then
|
||||
// NIA <- EXTS(LI || 0b00)
|
||||
// else
|
||||
// NIA <- CIA + EXTS(LI || 0b00)
|
||||
// if LK then
|
||||
// LR <- CIA + 4
|
||||
|
||||
uint32_t nia;
|
||||
if (i.I.AA) {
|
||||
nia = (uint32_t)XEEXTS26(i.I.LI << 2);
|
||||
} else {
|
||||
nia = (uint32_t)(i.address + XEEXTS26(i.I.LI << 2));
|
||||
}
|
||||
|
||||
return InstrEmit_branch(
|
||||
f, "bx", i.address, f.LoadConstant(nia), i.I.LK);
|
||||
}
|
||||
|
||||
XEEMITTER(bcx, 0x40000000, B )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// if ¬BO[2] then
|
||||
// CTR <- CTR - 1
|
||||
// ctr_ok <- BO[2] | ((CTR[0:63] != 0) XOR BO[3])
|
||||
// cond_ok <- BO[0] | (CR[BI+32] ≡ BO[1])
|
||||
// if ctr_ok & cond_ok then
|
||||
// if AA then
|
||||
// NIA <- EXTS(BD || 0b00)
|
||||
// else
|
||||
// NIA <- CIA + EXTS(BD || 0b00)
|
||||
// if LK then
|
||||
// LR <- CIA + 4
|
||||
|
||||
// NOTE: the condition bits are reversed!
|
||||
// 01234 (docs)
|
||||
// 43210 (real)
|
||||
|
||||
Value* ctr_ok = NULL;
|
||||
if (XESELECTBITS(i.B.BO, 2, 2)) {
|
||||
// Ignore ctr.
|
||||
} else {
|
||||
// Decrement counter.
|
||||
Value* ctr = f.LoadCTR();
|
||||
ctr = f.Sub(ctr, f.LoadConstant((int64_t)1));
|
||||
f.StoreCTR(ctr);
|
||||
// Ctr check.
|
||||
// TODO(benvanik): could do something similar to cond and avoid the
|
||||
// is_true/branch_true pairing.
|
||||
if (XESELECTBITS(i.B.BO, 1, 1)) {
|
||||
ctr_ok = f.IsFalse(ctr);
|
||||
} else {
|
||||
ctr_ok = f.IsTrue(ctr);
|
||||
}
|
||||
}
|
||||
|
||||
Value* cond_ok = NULL;
|
||||
bool not_cond_ok = false;
|
||||
if (XESELECTBITS(i.B.BO, 4, 4)) {
|
||||
// Ignore cond.
|
||||
} else {
|
||||
Value* cr = f.LoadCRField(i.B.BI >> 2, i.B.BI & 3);
|
||||
cond_ok = cr;
|
||||
if (XESELECTBITS(i.B.BO, 3, 3)) {
|
||||
// Expect true.
|
||||
not_cond_ok = false;
|
||||
} else {
|
||||
// Expect false.
|
||||
not_cond_ok = true;
|
||||
}
|
||||
}
|
||||
|
||||
// We do a bit of optimization here to make the llvm assembly easier to read.
|
||||
Value* ok = NULL;
|
||||
bool expect_true = true;
|
||||
if (ctr_ok && cond_ok) {
|
||||
if (not_cond_ok) {
|
||||
cond_ok = f.IsFalse(cond_ok);
|
||||
}
|
||||
ok = f.And(ctr_ok, cond_ok);
|
||||
} else if (ctr_ok) {
|
||||
ok = ctr_ok;
|
||||
} else if (cond_ok) {
|
||||
ok = cond_ok;
|
||||
expect_true = !not_cond_ok;
|
||||
}
|
||||
|
||||
uint32_t nia;
|
||||
if (i.B.AA) {
|
||||
nia = (uint32_t)XEEXTS16(i.B.BD << 2);
|
||||
} else {
|
||||
nia = (uint32_t)(i.address + XEEXTS16(i.B.BD << 2));
|
||||
}
|
||||
return InstrEmit_branch(
|
||||
f, "bcx", i.address, f.LoadConstant(nia), i.B.LK, ok, expect_true);
|
||||
}
|
||||
|
||||
XEEMITTER(bcctrx, 0x4C000420, XL )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// cond_ok <- BO[0] | (CR[BI+32] ≡ BO[1])
|
||||
// if cond_ok then
|
||||
// NIA <- CTR[0:61] || 0b00
|
||||
// if LK then
|
||||
// LR <- CIA + 4
|
||||
|
||||
// NOTE: the condition bits are reversed!
|
||||
// 01234 (docs)
|
||||
// 43210 (real)
|
||||
|
||||
Value* cond_ok = NULL;
|
||||
bool not_cond_ok = false;
|
||||
if (XESELECTBITS(i.XL.BO, 4, 4)) {
|
||||
// Ignore cond.
|
||||
} else {
|
||||
Value* cr = f.LoadCRField(i.XL.BI >> 2, i.XL.BI & 3);
|
||||
cond_ok = cr;
|
||||
if (XESELECTBITS(i.XL.BO, 3, 3)) {
|
||||
// Expect true.
|
||||
not_cond_ok = false;
|
||||
} else {
|
||||
// Expect false.
|
||||
not_cond_ok = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool expect_true = !not_cond_ok;
|
||||
return InstrEmit_branch(
|
||||
f, "bcctrx", i.address, f.LoadCTR(), i.XL.LK, cond_ok, expect_true);
|
||||
}
|
||||
|
||||
XEEMITTER(bclrx, 0x4C000020, XL )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// if ¬BO[2] then
|
||||
// CTR <- CTR - 1
|
||||
// ctr_ok <- BO[2] | ((CTR[0:63] != 0) XOR BO[3]
|
||||
// cond_ok <- BO[0] | (CR[BI+32] ≡ BO[1])
|
||||
// if ctr_ok & cond_ok then
|
||||
// NIA <- LR[0:61] || 0b00
|
||||
// if LK then
|
||||
// LR <- CIA + 4
|
||||
|
||||
// NOTE: the condition bits are reversed!
|
||||
// 01234 (docs)
|
||||
// 43210 (real)
|
||||
|
||||
Value* ctr_ok = NULL;
|
||||
if (XESELECTBITS(i.XL.BO, 2, 2)) {
|
||||
// Ignore ctr.
|
||||
} else {
|
||||
// Decrement counter.
|
||||
Value* ctr = f.LoadCTR();
|
||||
ctr = f.Sub(ctr, f.LoadConstant((int64_t)1));
|
||||
f.StoreCTR(ctr);
|
||||
// Ctr check.
|
||||
// TODO(benvanik): could do something similar to cond and avoid the
|
||||
// is_true/branch_true pairing.
|
||||
if (XESELECTBITS(i.XL.BO, 1, 1)) {
|
||||
ctr_ok = f.IsFalse(ctr);
|
||||
} else {
|
||||
ctr_ok = f.IsTrue(ctr);
|
||||
}
|
||||
}
|
||||
|
||||
Value* cond_ok = NULL;
|
||||
bool not_cond_ok = false;
|
||||
if (XESELECTBITS(i.XL.BO, 4, 4)) {
|
||||
// Ignore cond.
|
||||
} else {
|
||||
Value* cr = f.LoadCRField(i.XL.BI >> 2, i.XL.BI & 3);
|
||||
cond_ok = cr;
|
||||
if (XESELECTBITS(i.XL.BO, 3, 3)) {
|
||||
// Expect true.
|
||||
not_cond_ok = false;
|
||||
} else {
|
||||
// Expect false.
|
||||
not_cond_ok = true;
|
||||
}
|
||||
}
|
||||
|
||||
// We do a bit of optimization here to make the llvm assembly easier to read.
|
||||
Value* ok = NULL;
|
||||
bool expect_true = true;
|
||||
if (ctr_ok && cond_ok) {
|
||||
if (not_cond_ok) {
|
||||
cond_ok = f.IsFalse(cond_ok);
|
||||
}
|
||||
ok = f.And(ctr_ok, cond_ok);
|
||||
} else if (ctr_ok) {
|
||||
ok = ctr_ok;
|
||||
} else if (cond_ok) {
|
||||
ok = cond_ok;
|
||||
expect_true = !not_cond_ok;
|
||||
}
|
||||
|
||||
// TODO(benvanik): run a DFA pass to see if we can detect whether this is
|
||||
// a normal function return that is pulling the LR from the stack that
|
||||
// it set in the prolog. If so, we can omit the dynamic check!
|
||||
|
||||
//// Dynamic test when branching to LR, which is usually used for the return.
|
||||
//// We only do this if LK=0 as returns wouldn't set LR.
|
||||
//// Ideally it's a return and we can just do a simple ret and be done.
|
||||
//// If it's not, we fall through to the full indirection logic.
|
||||
//if (!lk && reg == kXEPPCRegLR) {
|
||||
// // The return block will spill registers for us.
|
||||
// // TODO(benvanik): 'lr_mismatch' debug info.
|
||||
// // Note: we need to test on *only* the 32-bit target, as the target ptr may
|
||||
// // have garbage in the upper 32 bits.
|
||||
// c.cmp(target.r32(), c.getGpArg(1).r32());
|
||||
// // TODO(benvanik): evaluate hint here.
|
||||
// c.je(e.GetReturnLabel(), kCondHintLikely);
|
||||
//}
|
||||
if (!i.XL.LK && !ok) {
|
||||
// Return (most likely).
|
||||
// TODO(benvanik): test? ReturnCheck()?
|
||||
f.Return();
|
||||
return 0;
|
||||
}
|
||||
|
||||
return InstrEmit_branch(
|
||||
f, "bclrx", i.address, f.LoadLR(), i.XL.LK, ok, expect_true);
|
||||
}
|
||||
|
||||
|
||||
// Condition register logical (A-23)
|
||||
|
||||
XEEMITTER(crand, 0x4C000202, XL )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(crandc, 0x4C000102, XL )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(creqv, 0x4C000242, XL )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(crnand, 0x4C0001C2, XL )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(crnor, 0x4C000042, XL )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(cror, 0x4C000382, XL )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(crorc, 0x4C000342, XL )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(crxor, 0x4C000182, XL )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(mcrf, 0x4C000000, XL )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// System linkage (A-24)
|
||||
|
||||
XEEMITTER(sc, 0x44000002, SC )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// Trap (A-25)
|
||||
|
||||
int InstrEmit_trap(PPCFunctionBuilder& f, InstrData& i,
|
||||
Value* va, Value* vb, uint32_t TO) {
|
||||
// if (a < b) & TO[0] then TRAP
|
||||
// if (a > b) & TO[1] then TRAP
|
||||
// if (a = b) & TO[2] then TRAP
|
||||
// if (a <u b) & TO[3] then TRAP
|
||||
// if (a >u b) & TO[4] then TRAP
|
||||
// Bits swapped:
|
||||
// 01234
|
||||
// 43210
|
||||
if (!TO) {
|
||||
return 0;
|
||||
}
|
||||
if (TO & (1 << 4)) {
|
||||
// a < b
|
||||
f.TrapTrue(f.CompareSLT(va, vb));
|
||||
}
|
||||
if (TO & (1 << 3)) {
|
||||
// a > b
|
||||
f.TrapTrue(f.CompareSGT(va, vb));
|
||||
}
|
||||
if (TO & (1 << 2)) {
|
||||
// a = b
|
||||
f.TrapTrue(f.CompareEQ(va, vb));
|
||||
}
|
||||
if (TO & (1 << 1)) {
|
||||
// a <u b
|
||||
f.TrapTrue(f.CompareULT(va, vb));
|
||||
}
|
||||
if (TO & (1 << 0)) {
|
||||
// a >u b
|
||||
f.TrapTrue(f.CompareUGT(va, vb));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(td, 0x7C000088, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// a <- (RA)
|
||||
// b <- (RB)
|
||||
// if (a < b) & TO[0] then TRAP
|
||||
// if (a > b) & TO[1] then TRAP
|
||||
// if (a = b) & TO[2] then TRAP
|
||||
// if (a <u b) & TO[3] then TRAP
|
||||
// if (a >u b) & TO[4] then TRAP
|
||||
Value* ra = f.LoadGPR(i.X.RA);
|
||||
Value* rb = f.LoadGPR(i.X.RB);
|
||||
return InstrEmit_trap(f, i, ra, rb, i.X.RT);
|
||||
}
|
||||
|
||||
XEEMITTER(tdi, 0x08000000, D )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// a <- (RA)
|
||||
// if (a < EXTS(SI)) & TO[0] then TRAP
|
||||
// if (a > EXTS(SI)) & TO[1] then TRAP
|
||||
// if (a = EXTS(SI)) & TO[2] then TRAP
|
||||
// if (a <u EXTS(SI)) & TO[3] then TRAP
|
||||
// if (a >u EXTS(SI)) & TO[4] then TRAP
|
||||
Value* ra = f.LoadGPR(i.D.RA);
|
||||
Value* rb = f.LoadConstant(XEEXTS16(i.D.DS));
|
||||
return InstrEmit_trap(f, i, ra, rb, i.D.RT);
|
||||
}
|
||||
|
||||
XEEMITTER(tw, 0x7C000008, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// a <- EXTS((RA)[32:63])
|
||||
// b <- EXTS((RB)[32:63])
|
||||
// if (a < b) & TO[0] then TRAP
|
||||
// if (a > b) & TO[1] then TRAP
|
||||
// if (a = b) & TO[2] then TRAP
|
||||
// if (a <u b) & TO[3] then TRAP
|
||||
// if (a >u b) & TO[4] then TRAP
|
||||
Value* ra = f.SignExtend(f.Truncate(
|
||||
f.LoadGPR(i.X.RA), INT32_TYPE), INT64_TYPE);
|
||||
Value* rb = f.SignExtend(f.Truncate(
|
||||
f.LoadGPR(i.X.RB), INT32_TYPE), INT64_TYPE);
|
||||
return InstrEmit_trap(f, i, ra, rb, i.X.RT);
|
||||
}
|
||||
|
||||
XEEMITTER(twi, 0x0C000000, D )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// a <- EXTS((RA)[32:63])
|
||||
// if (a < EXTS(SI)) & TO[0] then TRAP
|
||||
// if (a > EXTS(SI)) & TO[1] then TRAP
|
||||
// if (a = EXTS(SI)) & TO[2] then TRAP
|
||||
// if (a <u EXTS(SI)) & TO[3] then TRAP
|
||||
// if (a >u EXTS(SI)) & TO[4] then TRAP
|
||||
Value* ra = f.SignExtend(f.Truncate(
|
||||
f.LoadGPR(i.D.RA), INT32_TYPE), INT64_TYPE);
|
||||
Value* rb = f.LoadConstant(XEEXTS16(i.D.DS));
|
||||
return InstrEmit_trap(f, i, ra, rb, i.D.RT);
|
||||
}
|
||||
|
||||
|
||||
// Processor control (A-26)
|
||||
|
||||
XEEMITTER(mfcr, 0x7C000026, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(mfspr, 0x7C0002A6, XFX)(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// n <- spr[5:9] || spr[0:4]
|
||||
// if length(SPR(n)) = 64 then
|
||||
// RT <- SPR(n)
|
||||
// else
|
||||
// RT <- i32.0 || SPR(n)
|
||||
Value* v;
|
||||
const uint32_t n = ((i.XFX.spr & 0x1F) << 5) | ((i.XFX.spr >> 5) & 0x1F);
|
||||
switch (n) {
|
||||
case 1:
|
||||
// XER
|
||||
v = f.LoadXER();
|
||||
break;
|
||||
case 8:
|
||||
// LR
|
||||
v = f.LoadLR();
|
||||
break;
|
||||
case 9:
|
||||
// CTR
|
||||
v = f.LoadCTR();
|
||||
break;
|
||||
// 268 + 269 = TB + TBU
|
||||
default:
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
f.StoreGPR(i.XFX.RT, v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(mftb, 0x7C0002E6, XFX)(PPCFunctionBuilder& f, InstrData& i) {
|
||||
Value* time;
|
||||
LARGE_INTEGER counter;
|
||||
if (QueryPerformanceCounter(&counter)) {
|
||||
time = f.LoadConstant(counter.QuadPart);
|
||||
} else {
|
||||
time = f.LoadZero(INT64_TYPE);
|
||||
}
|
||||
f.StoreGPR(i.XFX.RT, time);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(mtcrf, 0x7C000120, XFX)(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(mtspr, 0x7C0003A6, XFX)(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// n <- spr[5:9] || spr[0:4]
|
||||
// if length(SPR(n)) = 64 then
|
||||
// SPR(n) <- (RS)
|
||||
// else
|
||||
// SPR(n) <- (RS)[32:63]
|
||||
|
||||
Value* rt = f.LoadGPR(i.XFX.RT);
|
||||
|
||||
const uint32_t n = ((i.XFX.spr & 0x1F) << 5) | ((i.XFX.spr >> 5) & 0x1F);
|
||||
switch (n) {
|
||||
case 1:
|
||||
// XER
|
||||
f.StoreXER(rt);
|
||||
break;
|
||||
case 8:
|
||||
// LR
|
||||
f.StoreLR(rt);
|
||||
break;
|
||||
case 9:
|
||||
// CTR
|
||||
f.StoreCTR(rt);
|
||||
break;
|
||||
default:
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void RegisterEmitCategoryControl() {
|
||||
XEREGISTERINSTR(bx, 0x48000000);
|
||||
XEREGISTERINSTR(bcx, 0x40000000);
|
||||
XEREGISTERINSTR(bcctrx, 0x4C000420);
|
||||
XEREGISTERINSTR(bclrx, 0x4C000020);
|
||||
XEREGISTERINSTR(crand, 0x4C000202);
|
||||
XEREGISTERINSTR(crandc, 0x4C000102);
|
||||
XEREGISTERINSTR(creqv, 0x4C000242);
|
||||
XEREGISTERINSTR(crnand, 0x4C0001C2);
|
||||
XEREGISTERINSTR(crnor, 0x4C000042);
|
||||
XEREGISTERINSTR(cror, 0x4C000382);
|
||||
XEREGISTERINSTR(crorc, 0x4C000342);
|
||||
XEREGISTERINSTR(crxor, 0x4C000182);
|
||||
XEREGISTERINSTR(mcrf, 0x4C000000);
|
||||
XEREGISTERINSTR(sc, 0x44000002);
|
||||
XEREGISTERINSTR(td, 0x7C000088);
|
||||
XEREGISTERINSTR(tdi, 0x08000000);
|
||||
XEREGISTERINSTR(tw, 0x7C000008);
|
||||
XEREGISTERINSTR(twi, 0x0C000000);
|
||||
XEREGISTERINSTR(mfcr, 0x7C000026);
|
||||
XEREGISTERINSTR(mfspr, 0x7C0002A6);
|
||||
XEREGISTERINSTR(mftb, 0x7C0002E6);
|
||||
XEREGISTERINSTR(mtcrf, 0x7C000120);
|
||||
XEREGISTERINSTR(mtspr, 0x7C0003A6);
|
||||
}
|
||||
|
||||
|
||||
} // namespace ppc
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
|
@ -0,0 +1,543 @@
|
|||
/*
|
||||
******************************************************************************
|
||||
* 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 <alloy/frontend/ppc/ppc_emit-private.h>
|
||||
|
||||
#include <alloy/frontend/ppc/ppc_context.h>
|
||||
#include <alloy/frontend/ppc/ppc_function_builder.h>
|
||||
|
||||
|
||||
using namespace alloy::frontend::ppc;
|
||||
using namespace alloy::hir;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
namespace ppc {
|
||||
|
||||
|
||||
// Good source of information:
|
||||
// http://mamedev.org/source/src/emu/cpu/powerpc/ppc_ops.c
|
||||
// The correctness of that code is not reflected here yet -_-
|
||||
|
||||
|
||||
// Enable rounding numbers to single precision as required.
|
||||
// This adds a bunch of work per operation and I'm not sure it's required.
|
||||
#define ROUND_TO_SINGLE
|
||||
|
||||
|
||||
// Floating-point arithmetic (A-8)
|
||||
|
||||
XEEMITTER(faddx, 0xFC00002A, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- (frA) + (frB)
|
||||
Value* v = f.Add(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRB));
|
||||
f.StoreFPR(i.A.FRT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(faddsx, 0xEC00002A, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- (frA) + (frB)
|
||||
Value* v = f.Add(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRB));
|
||||
v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE);
|
||||
f.StoreFPR(i.A.FRT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fdivx, 0xFC000024, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- frA / frB
|
||||
Value* v = f.Div(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRB));
|
||||
f.StoreFPR(i.A.FRT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fdivsx, 0xEC000024, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- frA / frB
|
||||
Value* v = f.Div(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRB));
|
||||
v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE);
|
||||
f.StoreFPR(i.A.FRT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fmulx, 0xFC000032, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- (frA) x (frC)
|
||||
Value* v = f.Mul(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRC));
|
||||
f.StoreFPR(i.A.FRT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fmulsx, 0xEC000032, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- (frA) x (frC)
|
||||
Value* v = f.Mul(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRC));
|
||||
v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE);
|
||||
f.StoreFPR(i.A.FRT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fresx, 0xEC000030, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(frsqrtex, 0xFC000034, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(fsubx, 0xFC000028, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- (frA) - (frB)
|
||||
Value* v = f.Sub(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRB));
|
||||
f.StoreFPR(i.A.FRT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fsubsx, 0xEC000028, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- (frA) - (frB)
|
||||
Value* v = f.Sub(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRB));
|
||||
v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE);
|
||||
f.StoreFPR(i.A.FRT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fselx, 0xFC00002E, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// if (frA) >= 0.0
|
||||
// then frD <- (frC)
|
||||
// else frD <- (frB)
|
||||
Value* ge = f.CompareSGE(f.LoadFPR(i.A.FRA), f.LoadConstant(0.0));
|
||||
Value* v = f.Select(ge, f.LoadFPR(i.A.FRC), f.LoadFPR(i.A.FRB));
|
||||
f.StoreFPR(i.A.FRT, v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fsqrtx, 0xFC00002C, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// Double precision:
|
||||
// frD <- sqrt(frB)
|
||||
Value* v = f.Sqrt(f.LoadFPR(i.A.FRA));
|
||||
f.StoreFPR(i.A.FRT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fsqrtsx, 0xEC00002C, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// Single precision:
|
||||
// frD <- sqrt(frB)
|
||||
Value* v = f.Sqrt(f.LoadFPR(i.A.FRA));
|
||||
v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE);
|
||||
f.StoreFPR(i.A.FRT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Floating-point multiply-add (A-9)
|
||||
|
||||
XEEMITTER(fmaddx, 0xFC00003A, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- (frA x frC) + frB
|
||||
Value* v = f.MulAdd(
|
||||
f.LoadFPR(i.A.FRA),
|
||||
f.LoadFPR(i.A.FRC),
|
||||
f.LoadFPR(i.A.FRB));
|
||||
f.StoreFPR(i.A.FRT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fmaddsx, 0xEC00003A, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- (frA x frC) + frB
|
||||
Value* v = f.MulAdd(
|
||||
f.LoadFPR(i.A.FRA),
|
||||
f.LoadFPR(i.A.FRC),
|
||||
f.LoadFPR(i.A.FRB));
|
||||
v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE);
|
||||
f.StoreFPR(i.A.FRT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fmsubx, 0xFC000038, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- (frA x frC) - frB
|
||||
Value* v = f.MulSub(
|
||||
f.LoadFPR(i.A.FRA),
|
||||
f.LoadFPR(i.A.FRC),
|
||||
f.LoadFPR(i.A.FRB));
|
||||
f.StoreFPR(i.A.FRT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fmsubsx, 0xEC000038, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- (frA x frC) - frB
|
||||
Value* v = f.MulSub(
|
||||
f.LoadFPR(i.A.FRA),
|
||||
f.LoadFPR(i.A.FRC),
|
||||
f.LoadFPR(i.A.FRB));
|
||||
v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE);
|
||||
f.StoreFPR(i.A.FRT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fnmaddx, 0xFC00003E, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(fnmaddsx, 0xEC00003E, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(fnmsubx, 0xFC00003C, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- -([frA x frC] - frB)
|
||||
Value* v = f.Neg(f.MulSub(
|
||||
f.LoadFPR(i.A.FRA),
|
||||
f.LoadFPR(i.A.FRC),
|
||||
f.LoadFPR(i.A.FRB)));
|
||||
f.StoreFPR(i.A.FRT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fnmsubsx, 0xEC00003C, A )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- -([frA x frC] - frB)
|
||||
Value* v = f.Neg(f.MulSub(
|
||||
f.LoadFPR(i.A.FRA),
|
||||
f.LoadFPR(i.A.FRC),
|
||||
f.LoadFPR(i.A.FRB)));
|
||||
v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE);
|
||||
f.StoreFPR(i.A.FRT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Floating-point rounding and conversion (A-10)
|
||||
|
||||
XEEMITTER(fcfidx, 0xFC00069C, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- signed_int64_to_double( frB )
|
||||
Value* v = f.Convert(
|
||||
f.Cast(f.LoadFPR(i.A.FRB), INT64_TYPE),
|
||||
FLOAT64_TYPE);
|
||||
f.StoreFPR(i.A.FRT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fctidx, 0xFC00065C, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- double_to_signed_int64( frB )
|
||||
// TODO(benvanik): pull from FPSCR[RN]
|
||||
RoundMode round_mode = ROUND_TO_ZERO;
|
||||
Value* v = f.Convert(f.LoadFPR(i.X.RB), INT64_TYPE, round_mode);
|
||||
v = f.Cast(v, FLOAT64_TYPE);
|
||||
f.StoreFPR(i.X.RT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.X.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fctidzx, 0xFC00065E, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// TODO(benvanik): assuming round to zero is always set, is that ok?
|
||||
return InstrEmit_fctidx(f, i);
|
||||
}
|
||||
|
||||
XEEMITTER(fctiwx, 0xFC00001C, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- double_to_signed_int32( frB )
|
||||
// TODO(benvanik): pull from FPSCR[RN]
|
||||
RoundMode round_mode = ROUND_TO_ZERO;
|
||||
Value* v = f.Convert(f.LoadFPR(i.X.RB), INT32_TYPE, round_mode);
|
||||
v = f.Cast(f.ZeroExtend(v, INT64_TYPE), FLOAT64_TYPE);
|
||||
f.StoreFPR(i.X.RT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.A.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fctiwzx, 0xFC00001E, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// TODO(benvanik): assuming round to zero is always set, is that ok?
|
||||
return InstrEmit_fctiwx(f, i);
|
||||
}
|
||||
|
||||
XEEMITTER(frspx, 0xFC000018, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- Round_single(frB)
|
||||
// TODO(benvanik): pull from FPSCR[RN]
|
||||
RoundMode round_mode = ROUND_TO_ZERO;
|
||||
Value* v = f.Convert(f.LoadFPR(i.X.RB), FLOAT32_TYPE, round_mode);
|
||||
v = f.Convert(v, FLOAT64_TYPE);
|
||||
f.StoreFPR(i.X.RT, v);
|
||||
// f.UpdateFPRF(v);
|
||||
if (i.X.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Floating-point compare (A-11)
|
||||
|
||||
int InstrEmit_fcmpx_(PPCFunctionBuilder& f, InstrData& i, bool ordered) {
|
||||
// if (FRA) is a NaN or (FRB) is a NaN then
|
||||
// c <- 0b0001
|
||||
// else if (FRA) < (FRB) then
|
||||
// c <- 0b1000
|
||||
// else if (FRA) > (FRB) then
|
||||
// c <- 0b0100
|
||||
// else {
|
||||
// c <- 0b0010
|
||||
// }
|
||||
// FPCC <- c
|
||||
// CR[4*BF:4*BF+3] <- c
|
||||
// if (FRA) is an SNaN or (FRB) is an SNaN then
|
||||
// VXSNAN <- 1
|
||||
|
||||
// TODO(benvanik): update FPCC for mffsx/etc
|
||||
// TODO(benvanik): update VXSNAN
|
||||
const uint32_t crf = i.X.RT >> 2;
|
||||
// f.UpdateFPRF(v);
|
||||
f.UpdateCR(crf, f.LoadFPR(i.X.RA), f.LoadFPR(i.X.RB), true);
|
||||
return 0;
|
||||
}
|
||||
XEEMITTER(fcmpo, 0xFC000040, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
return InstrEmit_fcmpx_(f, i, true);
|
||||
}
|
||||
XEEMITTER(fcmpu, 0xFC000000, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
return InstrEmit_fcmpx_(f, i, false);
|
||||
}
|
||||
|
||||
|
||||
// Floating-point status and control register (A
|
||||
|
||||
XEEMITTER(mcrfs, 0xFC000080, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(mffsx, 0xFC00048E, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(mtfsb0x, 0xFC00008C, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(mtfsb1x, 0xFC00004C, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(mtfsfx, 0xFC00058E, XFL)(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(mtfsfix, 0xFC00010C, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// Floating-point move (A-21)
|
||||
|
||||
XEEMITTER(fabsx, 0xFC000210, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- abs(frB)
|
||||
Value* v = f.Abs(f.LoadFPR(i.X.RB));
|
||||
f.StoreFPR(i.X.RT, v);
|
||||
if (i.X.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fmrx, 0xFC000090, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- (frB)
|
||||
Value* v = f.LoadFPR(i.X.RB);
|
||||
f.StoreFPR(i.X.RT, v);
|
||||
if (i.X.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(fnabsx, 0xFC000110, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
XEEMITTER(fnegx, 0xFC000050, X )(PPCFunctionBuilder& f, InstrData& i) {
|
||||
// frD <- ¬ frB[0] || frB[1-63]
|
||||
Value* v = f.Neg(f.LoadFPR(i.X.RB));
|
||||
f.StoreFPR(i.X.RT, v);
|
||||
if (i.X.Rc) {
|
||||
//e.update_cr_with_cond(1, v);
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void RegisterEmitCategoryFPU() {
|
||||
XEREGISTERINSTR(faddx, 0xFC00002A);
|
||||
XEREGISTERINSTR(faddsx, 0xEC00002A);
|
||||
XEREGISTERINSTR(fdivx, 0xFC000024);
|
||||
XEREGISTERINSTR(fdivsx, 0xEC000024);
|
||||
XEREGISTERINSTR(fmulx, 0xFC000032);
|
||||
XEREGISTERINSTR(fmulsx, 0xEC000032);
|
||||
XEREGISTERINSTR(fresx, 0xEC000030);
|
||||
XEREGISTERINSTR(frsqrtex, 0xFC000034);
|
||||
XEREGISTERINSTR(fsubx, 0xFC000028);
|
||||
XEREGISTERINSTR(fsubsx, 0xEC000028);
|
||||
XEREGISTERINSTR(fselx, 0xFC00002E);
|
||||
XEREGISTERINSTR(fsqrtx, 0xFC00002C);
|
||||
XEREGISTERINSTR(fsqrtsx, 0xEC00002C);
|
||||
XEREGISTERINSTR(fmaddx, 0xFC00003A);
|
||||
XEREGISTERINSTR(fmaddsx, 0xEC00003A);
|
||||
XEREGISTERINSTR(fmsubx, 0xFC000038);
|
||||
XEREGISTERINSTR(fmsubsx, 0xEC000038);
|
||||
XEREGISTERINSTR(fnmaddx, 0xFC00003E);
|
||||
XEREGISTERINSTR(fnmaddsx, 0xEC00003E);
|
||||
XEREGISTERINSTR(fnmsubx, 0xFC00003C);
|
||||
XEREGISTERINSTR(fnmsubsx, 0xEC00003C);
|
||||
XEREGISTERINSTR(fcfidx, 0xFC00069C);
|
||||
XEREGISTERINSTR(fctidx, 0xFC00065C);
|
||||
XEREGISTERINSTR(fctidzx, 0xFC00065E);
|
||||
XEREGISTERINSTR(fctiwx, 0xFC00001C);
|
||||
XEREGISTERINSTR(fctiwzx, 0xFC00001E);
|
||||
XEREGISTERINSTR(frspx, 0xFC000018);
|
||||
XEREGISTERINSTR(fcmpo, 0xFC000040);
|
||||
XEREGISTERINSTR(fcmpu, 0xFC000000);
|
||||
XEREGISTERINSTR(mcrfs, 0xFC000080);
|
||||
XEREGISTERINSTR(mffsx, 0xFC00048E);
|
||||
XEREGISTERINSTR(mtfsb0x, 0xFC00008C);
|
||||
XEREGISTERINSTR(mtfsb1x, 0xFC00004C);
|
||||
XEREGISTERINSTR(mtfsfx, 0xFC00058E);
|
||||
XEREGISTERINSTR(mtfsfix, 0xFC00010C);
|
||||
XEREGISTERINSTR(fabsx, 0xFC000210);
|
||||
XEREGISTERINSTR(fmrx, 0xFC000090);
|
||||
XEREGISTERINSTR(fnabsx, 0xFC000110);
|
||||
XEREGISTERINSTR(fnegx, 0xFC000050);
|
||||
}
|
||||
|
||||
|
||||
} // namespace ppc
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,96 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 <alloy/frontend/ppc/ppc_frontend.h>
|
||||
|
||||
#include <alloy/frontend/tracing.h>
|
||||
#include <alloy/frontend/ppc/ppc_disasm.h>
|
||||
#include <alloy/frontend/ppc/ppc_emit.h>
|
||||
#include <alloy/frontend/ppc/ppc_translator.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::frontend;
|
||||
using namespace alloy::frontend::ppc;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
|
||||
namespace {
|
||||
void InitializeIfNeeded();
|
||||
void CleanupOnShutdown();
|
||||
|
||||
void InitializeIfNeeded() {
|
||||
static bool has_initialized = false;
|
||||
if (has_initialized) {
|
||||
return;
|
||||
}
|
||||
has_initialized = true;
|
||||
|
||||
RegisterDisasmCategoryAltivec();
|
||||
RegisterDisasmCategoryALU();
|
||||
RegisterDisasmCategoryControl();
|
||||
RegisterDisasmCategoryFPU();
|
||||
RegisterDisasmCategoryMemory();
|
||||
|
||||
RegisterEmitCategoryAltivec();
|
||||
RegisterEmitCategoryALU();
|
||||
RegisterEmitCategoryControl();
|
||||
RegisterEmitCategoryFPU();
|
||||
RegisterEmitCategoryMemory();
|
||||
|
||||
atexit(CleanupOnShutdown);
|
||||
}
|
||||
|
||||
void CleanupOnShutdown() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PPCFrontend::PPCFrontend(Runtime* runtime) :
|
||||
Frontend(runtime) {
|
||||
InitializeIfNeeded();
|
||||
}
|
||||
|
||||
PPCFrontend::~PPCFrontend() {
|
||||
// Force cleanup now before we deinit.
|
||||
translator_pool_.Reset();
|
||||
|
||||
alloy::tracing::WriteEvent(EventType::Deinit({
|
||||
}));
|
||||
}
|
||||
|
||||
int PPCFrontend::Initialize() {
|
||||
int result = Frontend::Initialize();
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
alloy::tracing::WriteEvent(EventType::Init({
|
||||
}));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int 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 0;
|
||||
}
|
||||
|
||||
int PPCFrontend::DefineFunction(
|
||||
FunctionInfo* symbol_info,
|
||||
Function** out_function) {
|
||||
PPCTranslator* translator = translator_pool_.Allocate(this);
|
||||
int result = translator->Translate(symbol_info, out_function);
|
||||
translator_pool_.Release(translator);
|
||||
return result;
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_FRONTEND_PPC_PPC_FRONTEND_H_
|
||||
#define ALLOY_FRONTEND_PPC_PPC_FRONTEND_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
#include <alloy/type_pool.h>
|
||||
|
||||
#include <alloy/frontend/frontend.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
namespace ppc {
|
||||
|
||||
class PPCTranslator;
|
||||
|
||||
class PPCFrontend : public Frontend {
|
||||
public:
|
||||
PPCFrontend(runtime::Runtime* runtime);
|
||||
virtual ~PPCFrontend();
|
||||
|
||||
virtual int Initialize();
|
||||
|
||||
virtual int DeclareFunction(
|
||||
runtime::FunctionInfo* symbol_info);
|
||||
virtual int DefineFunction(
|
||||
runtime::FunctionInfo* symbol_info,
|
||||
runtime::Function** out_function);
|
||||
|
||||
private:
|
||||
TypePool<PPCTranslator, PPCFrontend*> translator_pool_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace ppc
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_FRONTEND_PPC_PPC_FRONTEND_H_
|
|
@ -0,0 +1,306 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 <alloy/frontend/ppc/ppc_function_builder.h>
|
||||
|
||||
#include <alloy/frontend/tracing.h>
|
||||
#include <alloy/frontend/ppc/ppc_context.h>
|
||||
#include <alloy/frontend/ppc/ppc_frontend.h>
|
||||
#include <alloy/frontend/ppc/ppc_instr.h>
|
||||
#include <alloy/hir/label.h>
|
||||
#include <alloy/runtime/runtime.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::frontend;
|
||||
using namespace alloy::frontend::ppc;
|
||||
using namespace alloy::hir;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
|
||||
PPCFunctionBuilder::PPCFunctionBuilder(PPCFrontend* frontend) :
|
||||
frontend_(frontend),
|
||||
FunctionBuilder() {
|
||||
}
|
||||
|
||||
PPCFunctionBuilder::~PPCFunctionBuilder() {
|
||||
}
|
||||
|
||||
void PPCFunctionBuilder::Reset() {
|
||||
start_address_ = 0;
|
||||
instr_offset_list_ = NULL;
|
||||
label_list_ = NULL;
|
||||
FunctionBuilder::Reset();
|
||||
}
|
||||
|
||||
const bool FLAGS_annotate_disassembly = true;
|
||||
|
||||
int PPCFunctionBuilder::Emit(FunctionInfo* symbol_info) {
|
||||
Memory* memory = frontend_->memory();
|
||||
const uint8_t* p = memory->membase();
|
||||
|
||||
symbol_info_ = symbol_info;
|
||||
start_address_ = symbol_info->address();
|
||||
instr_count_ =
|
||||
(symbol_info->end_address() - symbol_info->address()) / 4 + 1;
|
||||
|
||||
// TODO(benvanik): get/make up symbol name.
|
||||
Comment("%s fn %.8X-%.8X %s",
|
||||
symbol_info->module()->name(),
|
||||
symbol_info->address(), symbol_info->end_address(),
|
||||
"(symbol name)");
|
||||
|
||||
// Allocate offset list.
|
||||
// This is used to quickly map labels to instructions.
|
||||
// The list is built as the instructions are traversed, with the values
|
||||
// being the previous HIR Instr before the given instruction. An
|
||||
// instruction may have a label assigned to it if it hasn't been hit
|
||||
// yet.
|
||||
size_t list_size = instr_count_ * sizeof(void*);
|
||||
instr_offset_list_ = (Instr**)arena_->Alloc(list_size);
|
||||
label_list_ = (Label**)arena_->Alloc(list_size);
|
||||
xe_zero_struct(instr_offset_list_, list_size);
|
||||
xe_zero_struct(label_list_, list_size);
|
||||
|
||||
// Always mark entry with label.
|
||||
label_list_[0] = NewLabel();
|
||||
|
||||
uint64_t start_address = symbol_info->address();
|
||||
uint64_t end_address = symbol_info->end_address();
|
||||
InstrData i;
|
||||
for (uint64_t address = start_address, offset = 0; address <= end_address;
|
||||
address += 4, offset++) {
|
||||
i.address = address;
|
||||
i.code = XEGETUINT32BE(p + address);
|
||||
// TODO(benvanik): find a way to avoid using the opcode tables.
|
||||
i.type = GetInstrType(i.code);
|
||||
|
||||
// Stash instruction offset.
|
||||
instr_offset_list_[offset] = last_instr();
|
||||
|
||||
// Mark label, if we were assigned one earlier on in the walk.
|
||||
// We may still get a label, but it'll be inserted by LookupLabel
|
||||
// as needed.
|
||||
Label* label = label_list_[offset];
|
||||
if (label) {
|
||||
MarkLabel(label);
|
||||
}
|
||||
|
||||
if (FLAGS_annotate_disassembly) {
|
||||
if (label) {
|
||||
AnnotateLabel(address, label);
|
||||
}
|
||||
if (!i.type) {
|
||||
Comment("%.8X: %.8X ???", address, i.code);
|
||||
} else if (i.type->disassemble) {
|
||||
ppc::InstrDisasm d;
|
||||
i.type->disassemble(i, d);
|
||||
std::string disasm;
|
||||
d.Dump(disasm);
|
||||
Comment("%.8X: %.8X %s", address, i.code, disasm.c_str());
|
||||
} else {
|
||||
Comment("%.8X: %.8X %s ???", address, i.code, i.type->name);
|
||||
}
|
||||
}
|
||||
|
||||
if (!i.type) {
|
||||
XELOGCPU("Invalid instruction %.8X %.8X", i.address, i.code);
|
||||
Comment("INVALID!");
|
||||
//TraceInvalidInstruction(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
typedef int (*InstrEmitter)(PPCFunctionBuilder& f, InstrData& i);
|
||||
InstrEmitter emit = (InstrEmitter)i.type->emit;
|
||||
|
||||
/*if (i.address == FLAGS_break_on_instruction) {
|
||||
Comment("--break-on-instruction target");
|
||||
DebugBreak();
|
||||
}*/
|
||||
|
||||
if (!i.type->emit || emit(*this, i)) {
|
||||
XELOGCPU("Unimplemented instr %.8X %.8X %s",
|
||||
i.address, i.code, i.type->name);
|
||||
Comment("UNIMPLEMENTED!");
|
||||
DebugBreak();
|
||||
//TraceInvalidInstruction(i);
|
||||
|
||||
// This printf is handy for sort/uniquify to find instructions.
|
||||
printf("unimplinstr %s\n", i.type->name);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PPCFunctionBuilder::AnnotateLabel(uint64_t address, Label* label) {
|
||||
char name_buffer[13];
|
||||
xesnprintfa(name_buffer, XECOUNT(name_buffer), "loc_%.8X", address);
|
||||
label->name = (char*)arena_->Alloc(sizeof(name_buffer));
|
||||
xe_copy_struct(label->name, name_buffer, sizeof(name_buffer));
|
||||
}
|
||||
|
||||
FunctionInfo* PPCFunctionBuilder::LookupFunction(uint64_t address) {
|
||||
Runtime* runtime = frontend_->runtime();
|
||||
FunctionInfo* symbol_info;
|
||||
if (runtime->LookupFunctionInfo(address, &symbol_info)) {
|
||||
return NULL;
|
||||
}
|
||||
return symbol_info;
|
||||
}
|
||||
|
||||
Label* PPCFunctionBuilder::LookupLabel(uint64_t address) {
|
||||
if (address < start_address_) {
|
||||
return NULL;
|
||||
}
|
||||
size_t offset = (address - start_address_) / 4;
|
||||
if (offset >= instr_count_) {
|
||||
return NULL;
|
||||
}
|
||||
Label* label = label_list_[offset];
|
||||
if (label) {
|
||||
return label;
|
||||
}
|
||||
// No label. If we haven't yet hit the instruction in the walk
|
||||
// then create a label. Otherwise, we must go back and insert
|
||||
// the label.
|
||||
label = NewLabel();
|
||||
label_list_[offset] = label;
|
||||
Instr* prev_instr = instr_offset_list_[offset];
|
||||
if (prev_instr) {
|
||||
// Insert label, breaking up existing instructions.
|
||||
InsertLabel(label, prev_instr);
|
||||
|
||||
// Annotate the label, as we won't do it later.
|
||||
if (FLAGS_annotate_disassembly) {
|
||||
AnnotateLabel(address, label);
|
||||
}
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
//Value* PPCFunctionBuilder::LoadXER() {
|
||||
//}
|
||||
//
|
||||
//void PPCFunctionBuilder::StoreXER(Value* value) {
|
||||
//}
|
||||
|
||||
Value* PPCFunctionBuilder::LoadLR() {
|
||||
return LoadContext(offsetof(PPCContext, lr), INT64_TYPE);
|
||||
}
|
||||
|
||||
void PPCFunctionBuilder::StoreLR(Value* value) {
|
||||
XEASSERT(value->type == INT64_TYPE);
|
||||
StoreContext(offsetof(PPCContext, lr), value);
|
||||
}
|
||||
|
||||
Value* PPCFunctionBuilder::LoadCTR() {
|
||||
return LoadContext(offsetof(PPCContext, ctr), INT64_TYPE);
|
||||
}
|
||||
|
||||
void PPCFunctionBuilder::StoreCTR(Value* value) {
|
||||
XEASSERT(value->type == INT64_TYPE);
|
||||
StoreContext(offsetof(PPCContext, ctr), value);
|
||||
}
|
||||
|
||||
Value* PPCFunctionBuilder::LoadCR(uint32_t n) {
|
||||
XEASSERTALWAYS();
|
||||
return 0;
|
||||
}
|
||||
|
||||
Value* PPCFunctionBuilder::LoadCRField(uint32_t n, uint32_t bit) {
|
||||
return LoadContext(offsetof(PPCContext, cr0) + (4 * n) + bit, INT8_TYPE);
|
||||
}
|
||||
|
||||
void PPCFunctionBuilder::StoreCR(uint32_t n, Value* value) {
|
||||
// TODO(benvanik): split bits out and store in values.
|
||||
XEASSERTALWAYS();
|
||||
}
|
||||
|
||||
void PPCFunctionBuilder::UpdateCR(
|
||||
uint32_t n, Value* lhs, bool is_signed) {
|
||||
UpdateCR(n, lhs, LoadZero(lhs->type), is_signed);
|
||||
}
|
||||
|
||||
void PPCFunctionBuilder::UpdateCR(
|
||||
uint32_t n, Value* lhs, Value* rhs, bool is_signed) {
|
||||
Value* lt;
|
||||
Value* gt;
|
||||
if (is_signed) {
|
||||
lt = CompareSLT(lhs, rhs);
|
||||
gt = CompareSGT(lhs, rhs);
|
||||
} else {
|
||||
lt = CompareULT(lhs, rhs);
|
||||
gt = CompareUGT(lhs, rhs);
|
||||
}
|
||||
Value* eq = CompareEQ(lhs, rhs);
|
||||
StoreContext(offsetof(PPCContext, cr0) + (4 * n) + 0, lt);
|
||||
StoreContext(offsetof(PPCContext, cr0) + (4 * n) + 1, gt);
|
||||
StoreContext(offsetof(PPCContext, cr0) + (4 * n) + 2, eq);
|
||||
|
||||
// Value* so = AllocValue(UINT8_TYPE);
|
||||
// StoreContext(offsetof(PPCContext, cr) + (4 * n) + 3, so);
|
||||
}
|
||||
|
||||
void PPCFunctionBuilder::UpdateCR6(Value* src_value) {
|
||||
// Testing for all 1's and all 0's.
|
||||
// if (Rc) CR6 = all_equal | 0 | none_equal | 0
|
||||
// TODO(benvanik): efficient instruction?
|
||||
StoreContext(offsetof(PPCContext, cr6.cr6_all_equal), IsFalse(Not(src_value)));
|
||||
StoreContext(offsetof(PPCContext, cr6.cr6_none_equal), IsFalse(src_value));
|
||||
}
|
||||
|
||||
Value* PPCFunctionBuilder::LoadXER() {
|
||||
XEASSERTALWAYS();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void PPCFunctionBuilder::StoreXER(Value* value) {
|
||||
XEASSERTALWAYS();
|
||||
}
|
||||
|
||||
Value* PPCFunctionBuilder::LoadCA() {
|
||||
return LoadContext(offsetof(PPCContext, xer_ca), INT8_TYPE);
|
||||
}
|
||||
|
||||
void PPCFunctionBuilder::StoreCA(Value* value) {
|
||||
StoreContext(offsetof(PPCContext, xer_ca), value);
|
||||
}
|
||||
|
||||
Value* PPCFunctionBuilder::LoadGPR(uint32_t reg) {
|
||||
return LoadContext(
|
||||
offsetof(PPCContext, r) + reg * 8, INT64_TYPE);
|
||||
}
|
||||
|
||||
void PPCFunctionBuilder::StoreGPR(uint32_t reg, Value* value) {
|
||||
XEASSERT(value->type == INT64_TYPE);
|
||||
StoreContext(
|
||||
offsetof(PPCContext, r) + reg * 8, value);
|
||||
}
|
||||
|
||||
Value* PPCFunctionBuilder::LoadFPR(uint32_t reg) {
|
||||
return LoadContext(
|
||||
offsetof(PPCContext, f) + reg * 8, FLOAT64_TYPE);
|
||||
}
|
||||
|
||||
void PPCFunctionBuilder::StoreFPR(uint32_t reg, Value* value) {
|
||||
XEASSERT(value->type == FLOAT64_TYPE);
|
||||
StoreContext(
|
||||
offsetof(PPCContext, f) + reg * 8, value);
|
||||
}
|
||||
|
||||
Value* PPCFunctionBuilder::LoadVR(uint32_t reg) {
|
||||
return LoadContext(
|
||||
offsetof(PPCContext, v) + reg * 16, VEC128_TYPE);
|
||||
}
|
||||
|
||||
void PPCFunctionBuilder::StoreVR(uint32_t reg, Value* value) {
|
||||
XEASSERT(value->type == VEC128_TYPE);
|
||||
StoreContext(
|
||||
offsetof(PPCContext, v) + reg * 16, value);
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_FRONTEND_PPC_PPC_FUNCTION_BUILDER_H_
|
||||
#define ALLOY_FRONTEND_PPC_PPC_FUNCTION_BUILDER_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
#include <alloy/hir/function_builder.h>
|
||||
#include <alloy/runtime/function.h>
|
||||
#include <alloy/runtime/symbol_info.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
namespace ppc {
|
||||
|
||||
class PPCFrontend;
|
||||
|
||||
|
||||
class PPCFunctionBuilder : public hir::FunctionBuilder {
|
||||
using Instr = alloy::hir::Instr;
|
||||
using Label = alloy::hir::Label;
|
||||
using Value = alloy::hir::Value;
|
||||
public:
|
||||
PPCFunctionBuilder(PPCFrontend* frontend);
|
||||
virtual ~PPCFunctionBuilder();
|
||||
|
||||
virtual void Reset();
|
||||
|
||||
int Emit(runtime::FunctionInfo* symbol_info);
|
||||
|
||||
runtime::FunctionInfo* LookupFunction(uint64_t address);
|
||||
Label* LookupLabel(uint64_t address);
|
||||
|
||||
Value* LoadLR();
|
||||
void StoreLR(Value* value);
|
||||
Value* LoadCTR();
|
||||
void StoreCTR(Value* value);
|
||||
Value* LoadCR(uint32_t n);
|
||||
Value* LoadCRField(uint32_t n, uint32_t bit);
|
||||
void StoreCR(uint32_t n, Value* value);
|
||||
void UpdateCR(uint32_t n, Value* lhs, bool is_signed = true);
|
||||
void UpdateCR(uint32_t n, Value* lhs, Value* rhs, bool is_signed = true);
|
||||
void UpdateCR6(Value* src_value);
|
||||
Value* LoadXER();
|
||||
void StoreXER(Value* value);
|
||||
//void UpdateXERWithOverflow();
|
||||
//void UpdateXERWithOverflowAndCarry();
|
||||
//void StoreOV(Value* value);
|
||||
Value* LoadCA();
|
||||
void StoreCA(Value* value);
|
||||
|
||||
Value* LoadGPR(uint32_t reg);
|
||||
void StoreGPR(uint32_t reg, Value* value);
|
||||
Value* LoadFPR(uint32_t reg);
|
||||
void StoreFPR(uint32_t reg, Value* value);
|
||||
Value* LoadVR(uint32_t reg);
|
||||
void StoreVR(uint32_t reg, Value* value);
|
||||
|
||||
private:
|
||||
void AnnotateLabel(uint64_t address, Label* label);
|
||||
|
||||
private:
|
||||
PPCFrontend* frontend_;
|
||||
|
||||
// Reset each Emit:
|
||||
runtime::FunctionInfo* symbol_info_;
|
||||
uint64_t start_address_;
|
||||
uint64_t instr_count_;
|
||||
Instr** instr_offset_list_;
|
||||
Label** label_list_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace ppc
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_FRONTEND_PPC_PPC_FUNCTION_BUILDER_H_
|
|
@ -7,14 +7,16 @@
|
|||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include <xenia/cpu/ppc/instr.h>
|
||||
#include <alloy/frontend/ppc/ppc_instr.h>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <xenia/cpu/ppc/instr_tables.h>
|
||||
#include <alloy/frontend/ppc/ppc_instr_tables.h>
|
||||
|
||||
|
||||
using namespace xe::cpu::ppc;
|
||||
using namespace alloy;
|
||||
using namespace alloy::frontend;
|
||||
using namespace alloy::frontend::ppc;
|
||||
|
||||
|
||||
void InstrOperand::Dump(std::string& out_str) {
|
||||
|
@ -419,46 +421,45 @@ void InstrDisasm::Dump(std::string& out_str, size_t pad) {
|
|||
}
|
||||
|
||||
|
||||
InstrType* xe::cpu::ppc::GetInstrType(uint32_t code) {
|
||||
InstrType* alloy::frontend::ppc::GetInstrType(uint32_t code) {
|
||||
// Fast lookup via tables.
|
||||
InstrType* slot = NULL;
|
||||
switch (code >> 26) {
|
||||
case 4:
|
||||
// Opcode = 4, index = bits 10-0 (10)
|
||||
slot = xe::cpu::ppc::tables::instr_table_4[XESELECTBITS(code, 0, 10)];
|
||||
slot = alloy::frontend::ppc::tables::instr_table_4[XESELECTBITS(code, 0, 10)];
|
||||
break;
|
||||
case 19:
|
||||
// Opcode = 19, index = bits 10-1 (10)
|
||||
slot = xe::cpu::ppc::tables::instr_table_19[XESELECTBITS(code, 1, 10)];
|
||||
slot = alloy::frontend::ppc::tables::instr_table_19[XESELECTBITS(code, 1, 10)];
|
||||
break;
|
||||
case 30:
|
||||
// Opcode = 30, index = bits 4-1 (4)
|
||||
// Special cased to an uber instruction.
|
||||
slot = xe::cpu::ppc::tables::instr_table_30[XESELECTBITS(code, 0, 0)];
|
||||
// slot = &xe::cpu::ppc::tables::instr_table_30[XESELECTBITS(code, 1, 4)];
|
||||
slot = alloy::frontend::ppc::tables::instr_table_30[XESELECTBITS(code, 0, 0)];
|
||||
break;
|
||||
case 31:
|
||||
// Opcode = 31, index = bits 10-1 (10)
|
||||
slot = xe::cpu::ppc::tables::instr_table_31[XESELECTBITS(code, 1, 10)];
|
||||
slot = alloy::frontend::ppc::tables::instr_table_31[XESELECTBITS(code, 1, 10)];
|
||||
break;
|
||||
case 58:
|
||||
// Opcode = 58, index = bits 1-0 (2)
|
||||
slot = xe::cpu::ppc::tables::instr_table_58[XESELECTBITS(code, 0, 1)];
|
||||
slot = alloy::frontend::ppc::tables::instr_table_58[XESELECTBITS(code, 0, 1)];
|
||||
break;
|
||||
case 59:
|
||||
// Opcode = 59, index = bits 5-1 (5)
|
||||
slot = xe::cpu::ppc::tables::instr_table_59[XESELECTBITS(code, 1, 5)];
|
||||
slot = alloy::frontend::ppc::tables::instr_table_59[XESELECTBITS(code, 1, 5)];
|
||||
break;
|
||||
case 62:
|
||||
// Opcode = 62, index = bits 1-0 (2)
|
||||
slot = xe::cpu::ppc::tables::instr_table_62[XESELECTBITS(code, 0, 1)];
|
||||
slot = alloy::frontend::ppc::tables::instr_table_62[XESELECTBITS(code, 0, 1)];
|
||||
break;
|
||||
case 63:
|
||||
// Opcode = 63, index = bits 10-1 (10)
|
||||
slot = xe::cpu::ppc::tables::instr_table_63[XESELECTBITS(code, 1, 10)];
|
||||
slot = alloy::frontend::ppc::tables::instr_table_63[XESELECTBITS(code, 1, 10)];
|
||||
break;
|
||||
default:
|
||||
slot = xe::cpu::ppc::tables::instr_table[XESELECTBITS(code, 26, 31)];
|
||||
slot = alloy::frontend::ppc::tables::instr_table[XESELECTBITS(code, 26, 31)];
|
||||
break;
|
||||
}
|
||||
if (slot && slot->opcode) {
|
||||
|
@ -467,9 +468,10 @@ InstrType* xe::cpu::ppc::GetInstrType(uint32_t code) {
|
|||
|
||||
// Slow lookup via linear scan.
|
||||
// This is primarily due to laziness. It could be made fast like the others.
|
||||
for (size_t n = 0; n < XECOUNT(xe::cpu::ppc::tables::instr_table_scan);
|
||||
for (size_t n = 0;
|
||||
n < XECOUNT(alloy::frontend::ppc::tables::instr_table_scan);
|
||||
n++) {
|
||||
slot = &(xe::cpu::ppc::tables::instr_table_scan[n]);
|
||||
slot = &(alloy::frontend::ppc::tables::instr_table_scan[n]);
|
||||
if (slot->opcode == (code & slot->opcode_mask)) {
|
||||
return slot;
|
||||
}
|
||||
|
@ -478,7 +480,7 @@ InstrType* xe::cpu::ppc::GetInstrType(uint32_t code) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
int xe::cpu::ppc::RegisterInstrDisassemble(
|
||||
int alloy::frontend::ppc::RegisterInstrDisassemble(
|
||||
uint32_t code, InstrDisassembleFn disassemble) {
|
||||
InstrType* instr_type = GetInstrType(code);
|
||||
XEASSERTNOTNULL(instr_type);
|
||||
|
@ -490,7 +492,7 @@ int xe::cpu::ppc::RegisterInstrDisassemble(
|
|||
return 0;
|
||||
}
|
||||
|
||||
int xe::cpu::ppc::RegisterInstrEmit(uint32_t code, InstrEmitFn emit) {
|
||||
int alloy::frontend::ppc::RegisterInstrEmit(uint32_t code, InstrEmitFn emit) {
|
||||
InstrType* instr_type = GetInstrType(code);
|
||||
XEASSERTNOTNULL(instr_type);
|
||||
if (!instr_type) {
|
|
@ -7,17 +7,17 @@
|
|||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_CPU_PPC_INSTR_H_
|
||||
#define XENIA_CPU_PPC_INSTR_H_
|
||||
#ifndef ALLOY_FRONTEND_PPC_PPC_INSTR_H_
|
||||
#define ALLOY_FRONTEND_PPC_PPC_INSTR_H_
|
||||
|
||||
#include <xenia/common.h>
|
||||
#include <alloy/core.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
namespace ppc {
|
||||
|
||||
|
||||
|
@ -81,14 +81,14 @@ typedef enum {
|
|||
class InstrType;
|
||||
|
||||
|
||||
static inline int32_t XEEXTS16(uint32_t v) {
|
||||
return (int32_t)((int16_t)v);
|
||||
static inline int64_t XEEXTS16(uint32_t v) {
|
||||
return (int64_t)((int16_t)v);
|
||||
}
|
||||
static inline int32_t XEEXTS26(uint32_t v) {
|
||||
return v & 0x02000000 ? (int32_t)v | 0xFC000000 : (int32_t)(v);
|
||||
static inline int64_t XEEXTS26(uint32_t v) {
|
||||
return (int64_t)(v & 0x02000000 ? (int32_t)v | 0xFC000000 : (int32_t)(v));
|
||||
}
|
||||
static inline uint32_t XEEXTZ16(uint32_t v) {
|
||||
return (uint32_t)((uint16_t)v);
|
||||
static inline uint64_t XEEXTZ16(uint32_t v) {
|
||||
return (uint64_t)((uint16_t)v);
|
||||
}
|
||||
static inline uint64_t XEMASK(uint32_t mstart, uint32_t mstop) {
|
||||
// if mstart ≤ mstop then
|
||||
|
@ -108,7 +108,7 @@ static inline uint64_t XEMASK(uint32_t mstart, uint32_t mstop) {
|
|||
|
||||
typedef struct {
|
||||
InstrType* type;
|
||||
uint32_t address;
|
||||
uint64_t address;
|
||||
|
||||
union {
|
||||
uint32_t code;
|
||||
|
@ -523,9 +523,9 @@ int RegisterInstrEmit(uint32_t code, InstrEmitFn emit);
|
|||
|
||||
|
||||
} // namespace ppc
|
||||
} // namespace cpu
|
||||
} // namespace xe
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // XENIA_CPU_PPC_INSTR_H_
|
||||
#endif // ALLOY_FRONTEND_PPC_PPC_INSTR_H_
|
||||
|
|
@ -7,14 +7,14 @@
|
|||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_CPU_PPC_INSTR_TABLE_H_
|
||||
#define XENIA_CPU_PPC_INSTR_TABLE_H_
|
||||
#ifndef ALLOY_FRONTEND_PPC_PPC_INSTR_TABLES_H_
|
||||
#define ALLOY_FRONTEND_PPC_PPC_INSTR_TABLES_H_
|
||||
|
||||
#include <xenia/cpu/ppc/instr.h>
|
||||
#include <alloy/frontend/ppc/ppc_instr.h>
|
||||
|
||||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
namespace ppc {
|
||||
namespace tables {
|
||||
|
||||
|
@ -636,8 +636,8 @@ static InstrType instr_table_scan[] = {
|
|||
|
||||
} // namespace tables
|
||||
} // namespace ppc
|
||||
} // namespace cpu
|
||||
} // namespace xe
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // XENIA_CPU_PPC_INSTR_TABLE_H_
|
||||
#endif // ALLOY_FRONTEND_PPC_PPC_INSTR_TABLES_H_
|
|
@ -0,0 +1,278 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 <alloy/frontend/ppc/ppc_scanner.h>
|
||||
|
||||
#include <alloy/frontend/tracing.h>
|
||||
#include <alloy/frontend/ppc/ppc_frontend.h>
|
||||
#include <alloy/frontend/ppc/ppc_instr.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::frontend;
|
||||
using namespace alloy::frontend::ppc;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
|
||||
PPCScanner::PPCScanner(PPCFrontend* frontend) :
|
||||
frontend_(frontend) {
|
||||
}
|
||||
|
||||
PPCScanner::~PPCScanner() {
|
||||
}
|
||||
|
||||
bool PPCScanner::IsRestGprLr(uint64_t address) {
|
||||
// TODO(benvanik): detect type.
|
||||
/*FunctionSymbol* fn = GetFunction(addr);
|
||||
return fn && (fn->flags & FunctionSymbol::kFlagRestGprLr);*/
|
||||
return false;
|
||||
}
|
||||
|
||||
int PPCScanner::FindExtents(FunctionInfo* symbol_info) {
|
||||
// This is a simple basic block analyizer. It walks the start address to the
|
||||
// end address looking for branches. Each span of instructions between
|
||||
// branches is considered a basic block. When the last blr (that has no
|
||||
// branches to after it) is found the function is considered ended. If this
|
||||
// is before the expected end address then the function address range is
|
||||
// split up and the second half is treated as another function.
|
||||
|
||||
Memory* memory = frontend_->memory();
|
||||
const uint8_t* p = memory->membase();
|
||||
|
||||
XELOGSDB("Analyzing function %.8X...", symbol_info->address());
|
||||
|
||||
uint64_t start_address = symbol_info->address();
|
||||
uint64_t end_address = symbol_info->end_address();
|
||||
uint64_t address = start_address;
|
||||
uint64_t furthest_target = start_address;
|
||||
size_t blocks_found = 0;
|
||||
bool in_block = false;
|
||||
bool starts_with_mfspr_lr = false;
|
||||
InstrData i;
|
||||
while (true) {
|
||||
i.address = address;
|
||||
i.code = XEGETUINT32BE(p + address);
|
||||
|
||||
// If we fetched 0 assume that we somehow hit one of the awesome
|
||||
// 'no really we meant to end after that bl' functions.
|
||||
if (!i.code) {
|
||||
XELOGSDB("function end %.8X (0x00000000 read)", address);
|
||||
// Don't include the 0's.
|
||||
address -= 4;
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO(benvanik): find a way to avoid using the opcode tables.
|
||||
// This lookup is *expensive* and should be avoided when scanning.
|
||||
i.type = GetInstrType(i.code);
|
||||
|
||||
// Check if the function starts with a mfspr lr, as that's a good indication
|
||||
// of whether or not this is a normal function with a prolog/epilog.
|
||||
// Some valid leaf functions won't have this, but most will.
|
||||
if (address == start_address &&
|
||||
i.type &&
|
||||
i.type->opcode == 0x7C0002A6 &&
|
||||
(((i.XFX.spr & 0x1F) << 5) | ((i.XFX.spr >> 5) & 0x1F)) == 8) {
|
||||
starts_with_mfspr_lr = true;
|
||||
}
|
||||
|
||||
if (!in_block) {
|
||||
in_block = true;
|
||||
blocks_found++;
|
||||
}
|
||||
|
||||
bool ends_fn = false;
|
||||
bool ends_block = false;
|
||||
if (!i.type) {
|
||||
// Invalid instruction.
|
||||
// We can just ignore it because there's (very little)/no chance it'll
|
||||
// affect flow control.
|
||||
XELOGSDB("Invalid instruction at %.8X: %.8X", address, i.code);
|
||||
} else if (i.code == 0x4E800020) {
|
||||
// blr -- unconditional branch to LR.
|
||||
// This is generally a return.
|
||||
if (furthest_target > address) {
|
||||
// Remaining targets within function, not end.
|
||||
XELOGSDB("ignoring blr %.8X (branch to %.8X)",
|
||||
address, furthest_target);
|
||||
} else {
|
||||
// Function end point.
|
||||
XELOGSDB("function end %.8X", address);
|
||||
ends_fn = true;
|
||||
}
|
||||
ends_block = true;
|
||||
} else if (i.code == 0x4E800420) {
|
||||
// bctr -- unconditional branch to CTR.
|
||||
// This is generally a jump to a function pointer (non-return).
|
||||
if (furthest_target > address) {
|
||||
// Remaining targets within function, not end.
|
||||
XELOGSDB("ignoring bctr %.8X (branch to %.8X)", address,
|
||||
furthest_target);
|
||||
} else {
|
||||
// Function end point.
|
||||
XELOGSDB("function end %.8X", address);
|
||||
ends_fn = true;
|
||||
}
|
||||
ends_block = true;
|
||||
} else if (i.type->opcode == 0x48000000) {
|
||||
// b/ba/bl/bla
|
||||
uint32_t target =
|
||||
(uint32_t)XEEXTS26(i.I.LI << 2) + (i.I.AA ? 0 : (int32_t)address);
|
||||
|
||||
if (i.I.LK) {
|
||||
XELOGSDB("bl %.8X -> %.8X", address, target);
|
||||
// Queue call target if needed.
|
||||
// GetOrInsertFunction(target);
|
||||
} else {
|
||||
XELOGSDB("b %.8X -> %.8X", address, target);
|
||||
|
||||
// If the target is back into the function and there's no further target
|
||||
// we are at the end of a function.
|
||||
// (Indirect branches may still go beyond, but no way of knowing).
|
||||
if (target >= start_address &&
|
||||
target < address && furthest_target <= address) {
|
||||
XELOGSDB("function end %.8X (back b)", addr);
|
||||
ends_fn = true;
|
||||
}
|
||||
|
||||
// If the target is not a branch and it goes to before the current
|
||||
// address it's definitely a tail call.
|
||||
if (!ends_fn &&
|
||||
target < start_address && furthest_target <= address) {
|
||||
XELOGSDB("function end %.8X (back b before addr)", addr);
|
||||
ends_fn = true;
|
||||
}
|
||||
|
||||
// If the target is a __restgprlr_* method it's the end of a function.
|
||||
// Note that sometimes functions stick this in a basic block *inside*
|
||||
// of the function somewhere, so ensure we don't have any branches over
|
||||
// it.
|
||||
if (!ends_fn &&
|
||||
furthest_target <= address &&
|
||||
IsRestGprLr(target)) {
|
||||
XELOGSDB("function end %.8X (__restgprlr_*)", addr);
|
||||
ends_fn = true;
|
||||
}
|
||||
|
||||
// Heuristic: if there's an unconditional branch in the first block of
|
||||
// the function it's likely a thunk.
|
||||
// Ex:
|
||||
// li r3, 0
|
||||
// b KeBugCheck
|
||||
// This check may hit on functions that jump over data code, so only
|
||||
// trigger this check in leaf functions (no mfspr lr/prolog).
|
||||
if (!ends_fn &&
|
||||
!starts_with_mfspr_lr &&
|
||||
blocks_found == 1) {
|
||||
XELOGSDB("HEURISTIC: ending at simple leaf thunk %.8X", address);
|
||||
ends_fn = true;
|
||||
}
|
||||
|
||||
// Heuristic: if this is an unconditional branch at the end of the
|
||||
// function (nothing jumps over us) and we are jumping forward there's
|
||||
// a good chance it's a tail call.
|
||||
// This may not be true if the code is jumping over data/etc.
|
||||
// TODO(benvanik): figure out how to do this reliably. This check as is
|
||||
// is too aggressive and turns a lot of valid branches into tail calls.
|
||||
// It seems like a lot of functions end up with some prologue bit then
|
||||
// jump deep inside only to jump back towards the top soon after. May
|
||||
// need something more complex than just a simple 1-pass system to
|
||||
// detect these, unless more signals can be found.
|
||||
/*
|
||||
if (!ends_fn &&
|
||||
target > addr &&
|
||||
furthest_target < addr) {
|
||||
XELOGSDB("HEURISTIC: ending at tail call branch %.8X", addr);
|
||||
ends_fn = true;
|
||||
}
|
||||
*/
|
||||
|
||||
if (!ends_fn) {
|
||||
furthest_target = MAX(furthest_target, target);
|
||||
|
||||
// TODO(benvanik): perhaps queue up for a speculative check? I think
|
||||
// we are running over tail-call functions here that branch to
|
||||
// somewhere else.
|
||||
//GetOrInsertFunction(target);
|
||||
}
|
||||
}
|
||||
ends_block = true;
|
||||
} else if (i.type->opcode == 0x40000000) {
|
||||
// bc/bca/bcl/bcla
|
||||
uint32_t target =
|
||||
(uint32_t)XEEXTS16(i.B.BD << 2) + (i.B.AA ? 0 : (int32_t)address);
|
||||
if (i.B.LK) {
|
||||
XELOGSDB("bcl %.8X -> %.8X", address, target);
|
||||
|
||||
// Queue call target if needed.
|
||||
// TODO(benvanik): see if this is correct - not sure anyone makes
|
||||
// function calls with bcl.
|
||||
//GetOrInsertFunction(target);
|
||||
} else {
|
||||
XELOGSDB("bc %.8X -> %.8X", address, target);
|
||||
|
||||
// TODO(benvanik): GetOrInsertFunction? it's likely a BB
|
||||
|
||||
furthest_target = MAX(furthest_target, target);
|
||||
}
|
||||
ends_block = true;
|
||||
} else if (i.type->opcode == 0x4C000020) {
|
||||
// bclr/bclrl
|
||||
if (i.XL.LK) {
|
||||
XELOGSDB("bclrl %.8X", addr);
|
||||
} else {
|
||||
XELOGSDB("bclr %.8X", addr);
|
||||
}
|
||||
ends_block = true;
|
||||
} else if (i.type->opcode == 0x4C000420) {
|
||||
// bcctr/bcctrl
|
||||
if (i.XL.LK) {
|
||||
XELOGSDB("bcctrl %.8X", addr);
|
||||
} else {
|
||||
XELOGSDB("bcctr %.8X", addr);
|
||||
}
|
||||
ends_block = true;
|
||||
}
|
||||
|
||||
if (ends_block) {
|
||||
in_block = false;
|
||||
}
|
||||
if (ends_fn) {
|
||||
break;
|
||||
}
|
||||
|
||||
address += 4;
|
||||
if (end_address && address > end_address) {
|
||||
// Hmm....
|
||||
XELOGSDB("Ran over function bounds! %.8X-%.8X",
|
||||
start_address, end_address);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (end_address && address + 4 < end_address) {
|
||||
// Ran under the expected value - since we probably got the initial bounds
|
||||
// from someplace valid (like method hints) this may indicate an error.
|
||||
// It's also possible that we guessed in hole-filling and there's another
|
||||
// function below this one.
|
||||
XELOGSDB("Function ran under: %.8X-%.8X ended at %.8X",
|
||||
start_address, end_address, address + 4);
|
||||
}
|
||||
symbol_info->set_end_address(address);
|
||||
|
||||
// If there's spare bits at the end, split the function.
|
||||
// TODO(benvanik): splitting?
|
||||
|
||||
// TODO(benvanik): find and record stack information
|
||||
// - look for __savegprlr_* and __restgprlr_*
|
||||
// - if present, flag function as needing a stack
|
||||
// - record prolog/epilog lengths/stack size/etc
|
||||
|
||||
XELOGSDB("Finished analyzing %.8X", start_address);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_FRONTEND_PPC_PPC_SCANNER_H_
|
||||
#define ALLOY_FRONTEND_PPC_PPC_SCANNER_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
#include <alloy/runtime/symbol_info.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
namespace ppc {
|
||||
|
||||
class PPCFrontend;
|
||||
|
||||
|
||||
class PPCScanner {
|
||||
public:
|
||||
PPCScanner(PPCFrontend* frontend);
|
||||
~PPCScanner();
|
||||
|
||||
int FindExtents(runtime::FunctionInfo* symbol_info);
|
||||
|
||||
private:
|
||||
bool IsRestGprLr(uint64_t address);
|
||||
|
||||
private:
|
||||
PPCFrontend* frontend_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace ppc
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_FRONTEND_PPC_PPC_SCANNER_H_
|
|
@ -0,0 +1,101 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 <alloy/frontend/ppc/ppc_translator.h>
|
||||
|
||||
#include <alloy/compiler/passes.h>
|
||||
#include <alloy/frontend/tracing.h>
|
||||
#include <alloy/frontend/ppc/ppc_frontend.h>
|
||||
#include <alloy/frontend/ppc/ppc_function_builder.h>
|
||||
#include <alloy/frontend/ppc/ppc_scanner.h>
|
||||
#include <alloy/runtime/runtime.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::backend;
|
||||
using namespace alloy::compiler;
|
||||
using namespace alloy::frontend;
|
||||
using namespace alloy::frontend::ppc;
|
||||
using namespace alloy::hir;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
|
||||
PPCTranslator::PPCTranslator(PPCFrontend* frontend) :
|
||||
frontend_(frontend) {
|
||||
scanner_ = new PPCScanner(frontend);
|
||||
builder_ = new PPCFunctionBuilder(frontend);
|
||||
|
||||
compiler_ = new Compiler();
|
||||
|
||||
// TODO(benvanik): passes in a sensible order/etc.
|
||||
compiler_->AddPass(new passes::Mem2RegPass());
|
||||
|
||||
Backend* backend = frontend->runtime()->backend();
|
||||
assembler_ = backend->CreateAssembler();
|
||||
}
|
||||
|
||||
PPCTranslator::~PPCTranslator() {
|
||||
delete assembler_;
|
||||
delete compiler_;
|
||||
delete builder_;
|
||||
delete scanner_;
|
||||
}
|
||||
|
||||
int PPCTranslator::Translate(
|
||||
FunctionInfo* symbol_info,
|
||||
Function** out_function) {
|
||||
char* pre_ir = NULL;
|
||||
char* post_ir = NULL;
|
||||
|
||||
// Scan the function to find its extents. We only need to do this if we
|
||||
// haven't already been provided with them from some other source.
|
||||
if (!symbol_info->has_end_address()) {
|
||||
// TODO(benvanik): find a way to remove the need for the scan. A fixup
|
||||
// scheme acting on branches could go back and modify calls to branches
|
||||
// if they are within the extents.
|
||||
int result = scanner_->FindExtents(symbol_info);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Emit function.
|
||||
int result = builder_->Emit(symbol_info);
|
||||
XEEXPECTZERO(result);
|
||||
|
||||
if (true) {
|
||||
builder_->Dump(&string_buffer_);
|
||||
pre_ir = string_buffer_.ToString();
|
||||
string_buffer_.Reset();
|
||||
}
|
||||
|
||||
// Compile/optimize/etc.
|
||||
result = compiler_->Compile(builder_);
|
||||
XEEXPECTZERO(result);
|
||||
|
||||
if (true) {
|
||||
builder_->Dump(&string_buffer_);
|
||||
post_ir = string_buffer_.ToString();
|
||||
string_buffer_.Reset();
|
||||
}
|
||||
|
||||
// Assemble to backend machine code.
|
||||
result = assembler_->Assemble(symbol_info, builder_, out_function);
|
||||
XEEXPECTZERO(result);
|
||||
|
||||
result = 0;
|
||||
|
||||
XECLEANUP:
|
||||
if (pre_ir) xe_free(pre_ir);
|
||||
if (post_ir) xe_free(post_ir);
|
||||
builder_->Reset();
|
||||
compiler_->Reset();
|
||||
assembler_->Reset();
|
||||
string_buffer_.Reset();
|
||||
return result;
|
||||
};
|
|
@ -0,0 +1,52 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_FRONTEND_PPC_PPC_TRANSLATOR_H_
|
||||
#define ALLOY_FRONTEND_PPC_PPC_TRANSLATOR_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
#include <alloy/backend/assembler.h>
|
||||
#include <alloy/compiler/compiler.h>
|
||||
#include <alloy/runtime/symbol_info.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
namespace ppc {
|
||||
|
||||
class PPCFrontend;
|
||||
class PPCFunctionBuilder;
|
||||
class PPCScanner;
|
||||
|
||||
|
||||
class PPCTranslator {
|
||||
public:
|
||||
PPCTranslator(PPCFrontend* frontend);
|
||||
~PPCTranslator();
|
||||
|
||||
int Translate(runtime::FunctionInfo* symbol_info,
|
||||
runtime::Function** out_function);
|
||||
|
||||
private:
|
||||
PPCFrontend* frontend_;
|
||||
PPCScanner* scanner_;
|
||||
PPCFunctionBuilder* builder_;
|
||||
compiler::Compiler* compiler_;
|
||||
backend::Assembler* assembler_;
|
||||
|
||||
StringBuffer string_buffer_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace ppc
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_FRONTEND_PPC_PPC_TRANSLATOR_H_
|
|
@ -0,0 +1,32 @@
|
|||
# Copyright 2013 Ben Vanik. All Rights Reserved.
|
||||
{
|
||||
'sources': [
|
||||
'ppc_context.cc',
|
||||
'ppc_context.h',
|
||||
'ppc_disasm-private.h',
|
||||
'ppc_disasm.h',
|
||||
'ppc_disasm_altivec.cc',
|
||||
'ppc_disasm_alu.cc',
|
||||
'ppc_disasm_control.cc',
|
||||
'ppc_disasm_fpu.cc',
|
||||
'ppc_disasm_memory.cc',
|
||||
'ppc_emit-private.h',
|
||||
'ppc_emit.h',
|
||||
'ppc_emit_altivec.cc',
|
||||
'ppc_emit_alu.cc',
|
||||
'ppc_emit_control.cc',
|
||||
'ppc_emit_fpu.cc',
|
||||
'ppc_emit_memory.cc',
|
||||
'ppc_frontend.cc',
|
||||
'ppc_frontend.h',
|
||||
'ppc_function_builder.cc',
|
||||
'ppc_function_builder.h',
|
||||
'ppc_instr.cc',
|
||||
'ppc_instr.h',
|
||||
'ppc_instr_tables.h',
|
||||
'ppc_scanner.cc',
|
||||
'ppc_scanner.h',
|
||||
'ppc_translator.cc',
|
||||
'ppc_translator.h',
|
||||
],
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
# Copyright 2013 Ben Vanik. All Rights Reserved.
|
||||
{
|
||||
'sources': [
|
||||
'frontend.cc',
|
||||
'frontend.h',
|
||||
'tracing.h',
|
||||
],
|
||||
|
||||
'includes': [
|
||||
'ppc/sources.gypi',
|
||||
],
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_FRONTEND_TRACING_H_
|
||||
#define ALLOY_FRONTEND_TRACING_H_
|
||||
|
||||
#include <alloy/tracing/tracing.h>
|
||||
#include <alloy/tracing/event_type.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace frontend {
|
||||
|
||||
const uint32_t ALLOY_FRONTEND = alloy::tracing::EventType::ALLOY_FRONTEND;
|
||||
|
||||
|
||||
class EventType {
|
||||
public:
|
||||
enum {
|
||||
ALLOY_FRONTEND_INIT = ALLOY_FRONTEND | (1),
|
||||
ALLOY_FRONTEND_DEINIT = ALLOY_FRONTEND | (2),
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
static const uint32_t event_type = ALLOY_FRONTEND_INIT;
|
||||
} Init;
|
||||
typedef struct {
|
||||
static const uint32_t event_type = ALLOY_FRONTEND_DEINIT;
|
||||
} Deinit;
|
||||
};
|
||||
|
||||
|
||||
} // namespace frontend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_FRONTEND_TRACING_H_
|
|
@ -0,0 +1,13 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 <alloy/hir/block.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::hir;
|
|
@ -7,33 +7,34 @@
|
|||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_CPU_X64_X64_BACKEND_H_
|
||||
#define XENIA_CPU_X64_X64_BACKEND_H_
|
||||
#ifndef ALLOY_HIR_BLOCK_H_
|
||||
#define ALLOY_HIR_BLOCK_H_
|
||||
|
||||
#include <xenia/common.h>
|
||||
|
||||
#include <xenia/cpu/backend.h>
|
||||
#include <alloy/core.h>
|
||||
|
||||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
namespace x64 {
|
||||
namespace alloy {
|
||||
namespace hir {
|
||||
|
||||
class Instr;
|
||||
class Label;
|
||||
|
||||
|
||||
class X64Backend : public Backend {
|
||||
class Block {
|
||||
public:
|
||||
X64Backend();
|
||||
virtual ~X64Backend();
|
||||
Block* next;
|
||||
Block* prev;
|
||||
|
||||
virtual JIT* CreateJIT(xe_memory_ref memory, sdb::SymbolTable* sym_table);
|
||||
Label* label_head;
|
||||
Label* label_tail;
|
||||
|
||||
protected:
|
||||
Instr* instr_head;
|
||||
Instr* instr_tail;
|
||||
};
|
||||
|
||||
|
||||
} // namespace x64
|
||||
} // namespace cpu
|
||||
} // namespace xe
|
||||
} // namespace hir
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // XENIA_CPU_X64_X64_BACKEND_H_
|
||||
#endif // ALLOY_HIR_BLOCK_H_
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,225 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_HIR_FUNCTION_BUILDER_H_
|
||||
#define ALLOY_HIR_FUNCTION_BUILDER_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
#include <alloy/hir/block.h>
|
||||
#include <alloy/hir/instr.h>
|
||||
#include <alloy/hir/opcodes.h>
|
||||
#include <alloy/hir/value.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace hir {
|
||||
|
||||
enum FunctionAttributes {
|
||||
FUNCTION_ATTRIB_INLINE = (1 << 1),
|
||||
};
|
||||
|
||||
|
||||
class FunctionBuilder {
|
||||
public:
|
||||
FunctionBuilder();
|
||||
virtual ~FunctionBuilder();
|
||||
|
||||
virtual void Reset();
|
||||
|
||||
void Dump(StringBuffer* str);
|
||||
|
||||
uint32_t attributes() const { return attributes_; }
|
||||
void set_attributes(uint32_t value) { attributes_ = value; }
|
||||
|
||||
Block* first_block() const { return block_head_; }
|
||||
Block* current_block() const;
|
||||
Instr* last_instr() const;
|
||||
|
||||
Label* NewLabel();
|
||||
void MarkLabel(Label* label);
|
||||
void InsertLabel(Label* label, Instr* prev_instr);
|
||||
|
||||
// static allocations:
|
||||
// Value* AllocStatic(size_t length);
|
||||
|
||||
// stack allocations:
|
||||
// Value* AllocLocal(TypeName type);
|
||||
|
||||
void Comment(const char* format, ...);
|
||||
|
||||
void Nop();
|
||||
|
||||
// trace info/etc
|
||||
void DebugBreak();
|
||||
void DebugBreakTrue(Value* cond);
|
||||
|
||||
void Trap();
|
||||
void TrapTrue(Value* cond);
|
||||
|
||||
void Call(runtime::FunctionInfo* symbol_info, uint32_t call_flags = 0);
|
||||
void CallTrue(Value* cond, runtime::FunctionInfo* symbol_info,
|
||||
uint32_t call_flags = 0);
|
||||
void CallIndirect(Value* value, uint32_t call_flags = 0);
|
||||
void CallIndirectTrue(Value* cond, Value* value, uint32_t call_flags = 0);
|
||||
void Return();
|
||||
|
||||
void Branch(Label* label, uint32_t branch_flags = 0);
|
||||
void BranchIf(Value* cond, Label* true_label, Label* false_label,
|
||||
uint32_t branch_flags = 0);
|
||||
void BranchTrue(Value* cond, Label* label,
|
||||
uint32_t branch_flags = 0);
|
||||
void BranchFalse(Value* cond, Label* label,
|
||||
uint32_t branch_flags = 0);
|
||||
|
||||
// phi type_name, Block* b1, Value* v1, Block* b2, Value* v2, etc
|
||||
|
||||
Value* Assign(Value* value);
|
||||
Value* Cast(Value* value, TypeName target_type);
|
||||
Value* ZeroExtend(Value* value, TypeName target_type);
|
||||
Value* SignExtend(Value* value, TypeName target_type);
|
||||
Value* Truncate(Value* value, TypeName target_type);
|
||||
Value* Convert(Value* value, TypeName target_type,
|
||||
RoundMode round_mode = ROUND_TO_ZERO);
|
||||
Value* Round(Value* value, RoundMode round_mode);
|
||||
|
||||
// TODO(benvanik): make this cleaner -- not happy with it.
|
||||
// It'd be nice if Convert() supported this, however then we'd need a
|
||||
// VEC128_INT32_TYPE or something.
|
||||
Value* VectorConvertI2F(Value* value);
|
||||
Value* VectorConvertF2I(Value* value, RoundMode round_mode = ROUND_TO_ZERO);
|
||||
|
||||
Value* LoadZero(TypeName type);
|
||||
Value* LoadConstant(int8_t value);
|
||||
Value* LoadConstant(uint8_t value);
|
||||
Value* LoadConstant(int16_t value);
|
||||
Value* LoadConstant(uint16_t value);
|
||||
Value* LoadConstant(int32_t value);
|
||||
Value* LoadConstant(uint32_t value);
|
||||
Value* LoadConstant(int64_t value);
|
||||
Value* LoadConstant(uint64_t value);
|
||||
Value* LoadConstant(float value);
|
||||
Value* LoadConstant(double value);
|
||||
Value* LoadConstant(const vec128_t& value);
|
||||
|
||||
Value* LoadContext(size_t offset, TypeName type);
|
||||
void StoreContext(size_t offset, Value* value);
|
||||
|
||||
Value* Load(Value* address, TypeName type, uint32_t load_flags = 0);
|
||||
Value* LoadAcquire(Value* address, TypeName type, uint32_t load_flags = 0);
|
||||
void Store(Value* address, Value* value, uint32_t store_flags = 0);
|
||||
Value* StoreRelease(Value* address, Value* value, uint32_t store_flags = 0);
|
||||
void Prefetch(Value* address, size_t length, uint32_t prefetch_flags = 0);
|
||||
|
||||
Value* Max(Value* value1, Value* value2);
|
||||
Value* Min(Value* value1, Value* value2);
|
||||
Value* Select(Value* cond, Value* value1, Value* value2);
|
||||
Value* IsTrue(Value* value);
|
||||
Value* IsFalse(Value* value);
|
||||
Value* CompareEQ(Value* value1, Value* value2);
|
||||
Value* CompareNE(Value* value1, Value* value2);
|
||||
Value* CompareSLT(Value* value1, Value* value2);
|
||||
Value* CompareSLE(Value* value1, Value* value2);
|
||||
Value* CompareSGT(Value* value1, Value* value2);
|
||||
Value* CompareSGE(Value* value1, Value* value2);
|
||||
Value* CompareULT(Value* value1, Value* value2);
|
||||
Value* CompareULE(Value* value1, Value* value2);
|
||||
Value* CompareUGT(Value* value1, Value* value2);
|
||||
Value* CompareUGE(Value* value1, Value* value2);
|
||||
Value* DidCarry(Value* value);
|
||||
Value* DidOverflow(Value* value);
|
||||
Value* VectorCompareEQ(Value* value1, Value* value2, TypeName part_type);
|
||||
Value* VectorCompareSGT(Value* value1, Value* value2, TypeName part_type);
|
||||
Value* VectorCompareSGE(Value* value1, Value* value2, TypeName part_type);
|
||||
Value* VectorCompareUGT(Value* value1, Value* value2, TypeName part_type);
|
||||
Value* VectorCompareUGE(Value* value1, Value* value2, TypeName part_type);
|
||||
|
||||
Value* Add(Value* value1, Value* value2, uint32_t arithmetic_flags = 0);
|
||||
Value* AddWithCarry(Value* value1, Value* value2, Value* value3,
|
||||
uint32_t arithmetic_flags = 0);
|
||||
Value* Sub(Value* value1, Value* value2,
|
||||
uint32_t arithmetic_flags = 0);
|
||||
Value* Mul(Value* value1, Value* value2);
|
||||
Value* Div(Value* value1, Value* value2);
|
||||
Value* Rem(Value* value1, Value* value2);
|
||||
Value* MulAdd(Value* value1, Value* value2, Value* value3); // (1 * 2) + 3
|
||||
Value* MulSub(Value* value1, Value* value2, Value* value3); // (1 * 2) - 3
|
||||
Value* Neg(Value* value);
|
||||
Value* Abs(Value* value);
|
||||
Value* Sqrt(Value* value);
|
||||
Value* RSqrt(Value* value);
|
||||
Value* DotProduct3(Value* value1, Value* value2);
|
||||
Value* DotProduct4(Value* value1, Value* value2);
|
||||
|
||||
Value* And(Value* value1, Value* value2);
|
||||
Value* Or(Value* value1, Value* value2);
|
||||
Value* Xor(Value* value1, Value* value2);
|
||||
Value* Not(Value* value);
|
||||
Value* Shl(Value* value1, Value* value2);
|
||||
Value* VectorShl(Value* value1, Value* value2, TypeName part_type);
|
||||
Value* Shl(Value* value1, int8_t value2);
|
||||
Value* Shr(Value* value1, Value* value2);
|
||||
Value* Shr(Value* value1, int8_t value2);
|
||||
Value* Sha(Value* value1, Value* value2);
|
||||
Value* Sha(Value* value1, int8_t value2);
|
||||
Value* RotateLeft(Value* value1, Value* value2);
|
||||
Value* ByteSwap(Value* value);
|
||||
Value* CountLeadingZeros(Value* value);
|
||||
Value* Insert(Value* value, uint32_t index, Value* part);
|
||||
Value* Extract(Value* value, uint32_t index, TypeName target_type);
|
||||
// i8->i16/i32/... (i8|i8 / i8|i8|i8|i8 / ...)
|
||||
// i8/i16/i32 -> vec128
|
||||
Value* Splat(Value* value, TypeName target_type);
|
||||
Value* Permute(Value* control, Value* value1, Value* value2,
|
||||
TypeName part_type);
|
||||
Value* Swizzle(Value* value, TypeName part_type, uint32_t swizzle_mask);
|
||||
// SelectBits(cond, value1, value2)
|
||||
// pack/unpack/etc
|
||||
|
||||
Value* CompareExchange(Value* address,
|
||||
Value* compare_value, Value* exchange_value);
|
||||
Value* AtomicAdd(Value* address, Value* value);
|
||||
Value* AtomicSub(Value* address, Value* value);
|
||||
|
||||
protected:
|
||||
void DumpValue(StringBuffer* str, Value* value);
|
||||
void DumpOp(
|
||||
StringBuffer* str, OpcodeSignatureType sig_type, Instr::Op* op);
|
||||
|
||||
Value* AllocValue(TypeName type = INT64_TYPE);
|
||||
Value* CloneValue(Value* source);
|
||||
|
||||
private:
|
||||
Block* AppendBlock();
|
||||
void EndBlock();
|
||||
Instr* AppendInstr(const OpcodeInfo& opcode, uint16_t flags,
|
||||
Value* dest = 0);
|
||||
Value* CompareXX(const OpcodeInfo& opcode, Value* value1, Value* value2);
|
||||
Value* VectorCompareXX(
|
||||
const OpcodeInfo& opcode, Value* value1, Value* value2, TypeName part_type);
|
||||
|
||||
protected:
|
||||
Arena* arena_;
|
||||
|
||||
private:
|
||||
uint32_t attributes_;
|
||||
|
||||
uint32_t next_label_id_;
|
||||
uint32_t next_value_ordinal_;
|
||||
|
||||
Block* block_head_;
|
||||
Block* block_tail_;
|
||||
Block* current_block_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace hir
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_HIR_FUNCTION_BUILDER_H_
|
|
@ -0,0 +1,13 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 <alloy/hir/instr.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::hir;
|
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_HIR_INSTR_H_
|
||||
#define ALLOY_HIR_INSTR_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
#include <alloy/hir/opcodes.h>
|
||||
#include <alloy/hir/value.h>
|
||||
|
||||
|
||||
namespace alloy { namespace runtime { class FunctionInfo; } }
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace hir {
|
||||
|
||||
class Block;
|
||||
class Label;
|
||||
|
||||
|
||||
class Instr {
|
||||
public:
|
||||
Block* block;
|
||||
Instr* next;
|
||||
Instr* prev;
|
||||
|
||||
const OpcodeInfo* opcode;
|
||||
uint16_t flags;
|
||||
|
||||
typedef union {
|
||||
runtime::FunctionInfo* symbol_info;
|
||||
Label* label;
|
||||
Value* value;
|
||||
uint64_t offset;
|
||||
} Op;
|
||||
|
||||
Value* dest;
|
||||
Op src1;
|
||||
Op src2;
|
||||
Op src3;
|
||||
};
|
||||
|
||||
|
||||
} // namespace hir
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_HIR_INSTR_H_
|
|
@ -0,0 +1,13 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 <alloy/hir/label.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::hir;
|
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_HIR_LABEL_H_
|
||||
#define ALLOY_HIR_LABEL_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace hir {
|
||||
|
||||
class Block;
|
||||
|
||||
|
||||
class Label {
|
||||
public:
|
||||
Block* block;
|
||||
Label* next;
|
||||
Label* prev;
|
||||
|
||||
uint32_t id;
|
||||
char* name;
|
||||
|
||||
void* tag;
|
||||
};
|
||||
|
||||
|
||||
} // namespace hir
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_HIR_LABEL_H_
|
|
@ -0,0 +1,219 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_HIR_OPCODES_H_
|
||||
#define ALLOY_HIR_OPCODES_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace hir {
|
||||
|
||||
|
||||
enum CallFlags {
|
||||
CALL_TAIL = (1 << 1),
|
||||
};
|
||||
enum BranchFlags {
|
||||
BRANCH_LIKELY = (1 << 1),
|
||||
BRANCH_UNLIKELY = (1 << 2),
|
||||
};
|
||||
enum RoundMode {
|
||||
// to zero/nearest/etc
|
||||
ROUND_TO_ZERO = 0,
|
||||
ROUND_TO_NEAREST,
|
||||
};
|
||||
enum LoadFlags {
|
||||
LOAD_NO_ALIAS = (1 << 1),
|
||||
LOAD_ALIGNED = (1 << 2),
|
||||
LOAD_UNALIGNED = (1 << 3),
|
||||
LOAD_VOLATILE = (1 << 4),
|
||||
};
|
||||
enum StoreFlags {
|
||||
STORE_NO_ALIAS = (1 << 1),
|
||||
STORE_ALIGNED = (1 << 2),
|
||||
STORE_UNALIGNED = (1 << 3),
|
||||
STORE_VOLATILE = (1 << 4),
|
||||
};
|
||||
enum PrefetchFlags {
|
||||
PREFETCH_LOAD = (1 << 1),
|
||||
PREFETCH_STORE = (1 << 2),
|
||||
};
|
||||
enum ArithmeticFlags {
|
||||
ARITHMETIC_SET_CARRY = (1 << 1),
|
||||
};
|
||||
enum Permutes {
|
||||
PERMUTE_XY_ZW = 0x05040100,
|
||||
};
|
||||
enum Swizzles {
|
||||
SWIZZLE_XYZW_TO_XYZW = 0xE4,
|
||||
SWIZZLE_XYZW_TO_YZWX = 0x39,
|
||||
SWIZZLE_XYZW_TO_ZWXY = 0x4E,
|
||||
SWIZZLE_XYZW_TO_WXYZ = 0x93,
|
||||
};
|
||||
|
||||
|
||||
enum Opcode {
|
||||
OPCODE_COMMENT,
|
||||
|
||||
OPCODE_NOP,
|
||||
|
||||
OPCODE_DEBUG_BREAK,
|
||||
OPCODE_DEBUG_BREAK_TRUE,
|
||||
|
||||
OPCODE_TRAP,
|
||||
OPCODE_TRAP_TRUE,
|
||||
|
||||
OPCODE_CALL,
|
||||
OPCODE_CALL_TRUE,
|
||||
OPCODE_CALL_INDIRECT,
|
||||
OPCODE_CALL_INDIRECT_TRUE,
|
||||
OPCODE_RETURN,
|
||||
|
||||
OPCODE_BRANCH,
|
||||
OPCODE_BRANCH_IF,
|
||||
OPCODE_BRANCH_TRUE,
|
||||
OPCODE_BRANCH_FALSE,
|
||||
|
||||
OPCODE_ASSIGN,
|
||||
OPCODE_CAST,
|
||||
OPCODE_ZERO_EXTEND,
|
||||
OPCODE_SIGN_EXTEND,
|
||||
OPCODE_TRUNCATE,
|
||||
OPCODE_CONVERT,
|
||||
OPCODE_ROUND,
|
||||
OPCODE_VECTOR_CONVERT_I2F,
|
||||
OPCODE_VECTOR_CONVERT_F2I,
|
||||
|
||||
OPCODE_LOAD_CONTEXT,
|
||||
OPCODE_STORE_CONTEXT,
|
||||
|
||||
OPCODE_LOAD,
|
||||
OPCODE_LOAD_ACQUIRE,
|
||||
OPCODE_STORE,
|
||||
OPCODE_STORE_RELEASE,
|
||||
OPCODE_PREFETCH,
|
||||
|
||||
OPCODE_MAX,
|
||||
OPCODE_MIN,
|
||||
OPCODE_SELECT,
|
||||
OPCODE_IS_TRUE,
|
||||
OPCODE_IS_FALSE,
|
||||
OPCODE_COMPARE_EQ,
|
||||
OPCODE_COMPARE_NE,
|
||||
OPCODE_COMPARE_SLT,
|
||||
OPCODE_COMPARE_SLE,
|
||||
OPCODE_COMPARE_SGT,
|
||||
OPCODE_COMPARE_SGE,
|
||||
OPCODE_COMPARE_ULT,
|
||||
OPCODE_COMPARE_ULE,
|
||||
OPCODE_COMPARE_UGT,
|
||||
OPCODE_COMPARE_UGE,
|
||||
OPCODE_DID_CARRY,
|
||||
OPCODE_DID_OVERFLOW,
|
||||
OPCODE_VECTOR_COMPARE_EQ,
|
||||
OPCODE_VECTOR_COMPARE_SGT,
|
||||
OPCODE_VECTOR_COMPARE_SGE,
|
||||
OPCODE_VECTOR_COMPARE_UGT,
|
||||
OPCODE_VECTOR_COMPARE_UGE,
|
||||
|
||||
OPCODE_ADD,
|
||||
OPCODE_ADD_CARRY,
|
||||
OPCODE_SUB,
|
||||
OPCODE_MUL,
|
||||
OPCODE_DIV,
|
||||
OPCODE_REM,
|
||||
OPCODE_MULADD,
|
||||
OPCODE_MULSUB,
|
||||
OPCODE_NEG,
|
||||
OPCODE_ABS,
|
||||
OPCODE_SQRT,
|
||||
OPCODE_RSQRT,
|
||||
OPCODE_DOT_PRODUCT_3,
|
||||
OPCODE_DOT_PRODUCT_4,
|
||||
|
||||
OPCODE_AND,
|
||||
OPCODE_OR,
|
||||
OPCODE_XOR,
|
||||
OPCODE_NOT,
|
||||
OPCODE_SHL,
|
||||
OPCODE_VECTOR_SHL,
|
||||
OPCODE_SHR,
|
||||
OPCODE_SHA,
|
||||
OPCODE_ROTATE_LEFT,
|
||||
OPCODE_BYTE_SWAP,
|
||||
OPCODE_CNTLZ,
|
||||
OPCODE_INSERT,
|
||||
OPCODE_EXTRACT,
|
||||
OPCODE_SPLAT,
|
||||
OPCODE_PERMUTE,
|
||||
OPCODE_SWIZZLE,
|
||||
|
||||
OPCODE_COMPARE_EXCHANGE,
|
||||
OPCODE_ATOMIC_ADD,
|
||||
OPCODE_ATOMIC_SUB,
|
||||
};
|
||||
|
||||
enum OpcodeFlags {
|
||||
OPCODE_FLAG_BRANCH = (1 << 1),
|
||||
OPCODE_FLAG_MEMORY = (1 << 2),
|
||||
OPCODE_FLAG_COMMUNATIVE = (1 << 3),
|
||||
OPCODE_FLAG_VOLATILE = (1 << 4),
|
||||
OPCODE_FLAG_IGNORE = (1 << 5),
|
||||
};
|
||||
|
||||
enum OpcodeSignatureType {
|
||||
// 3 bits max (0-7)
|
||||
OPCODE_SIG_TYPE_X = 0,
|
||||
OPCODE_SIG_TYPE_L = 1,
|
||||
OPCODE_SIG_TYPE_O = 2,
|
||||
OPCODE_SIG_TYPE_S = 3,
|
||||
OPCODE_SIG_TYPE_V = 4,
|
||||
};
|
||||
|
||||
enum OpcodeSignature {
|
||||
OPCODE_SIG_X = (OPCODE_SIG_TYPE_X),
|
||||
OPCODE_SIG_X_L = (OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_L << 3),
|
||||
OPCODE_SIG_X_O_V = (OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_O << 3) | (OPCODE_SIG_TYPE_V << 6),
|
||||
OPCODE_SIG_X_S = (OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_S << 3),
|
||||
OPCODE_SIG_X_V = (OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_V << 3),
|
||||
OPCODE_SIG_X_V_L = (OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_V << 3) | (OPCODE_SIG_TYPE_L << 6),
|
||||
OPCODE_SIG_X_V_L_L = (OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_V << 3) | (OPCODE_SIG_TYPE_L << 6) | (OPCODE_SIG_TYPE_L << 9),
|
||||
OPCODE_SIG_X_V_O = (OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_V << 3) | (OPCODE_SIG_TYPE_O << 6),
|
||||
OPCODE_SIG_X_V_S = (OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_V << 3) | (OPCODE_SIG_TYPE_S << 6),
|
||||
OPCODE_SIG_X_V_V = (OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_V << 3) | (OPCODE_SIG_TYPE_V << 6),
|
||||
OPCODE_SIG_X_V_V_V = (OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_V << 3) | (OPCODE_SIG_TYPE_V << 6) | (OPCODE_SIG_TYPE_V << 9),
|
||||
OPCODE_SIG_V = (OPCODE_SIG_TYPE_V),
|
||||
OPCODE_SIG_V_O = (OPCODE_SIG_TYPE_V) | (OPCODE_SIG_TYPE_O << 3),
|
||||
OPCODE_SIG_V_V = (OPCODE_SIG_TYPE_V) | (OPCODE_SIG_TYPE_V << 3),
|
||||
OPCODE_SIG_V_V_O = (OPCODE_SIG_TYPE_V) | (OPCODE_SIG_TYPE_V << 3) | (OPCODE_SIG_TYPE_O << 6),
|
||||
OPCODE_SIG_V_V_O_V = (OPCODE_SIG_TYPE_V) | (OPCODE_SIG_TYPE_V << 3) | (OPCODE_SIG_TYPE_O << 6) | (OPCODE_SIG_TYPE_V << 9),
|
||||
OPCODE_SIG_V_V_V = (OPCODE_SIG_TYPE_V) | (OPCODE_SIG_TYPE_V << 3) | (OPCODE_SIG_TYPE_V << 6),
|
||||
OPCODE_SIG_V_V_V_O = (OPCODE_SIG_TYPE_V) | (OPCODE_SIG_TYPE_V << 3) | (OPCODE_SIG_TYPE_V << 6) | (OPCODE_SIG_TYPE_O << 9),
|
||||
OPCODE_SIG_V_V_V_V = (OPCODE_SIG_TYPE_V) | (OPCODE_SIG_TYPE_V << 3) | (OPCODE_SIG_TYPE_V << 6) | (OPCODE_SIG_TYPE_V << 9),
|
||||
};
|
||||
|
||||
#define GET_OPCODE_SIG_TYPE_DEST(sig) (OpcodeSignatureType)(sig & 0x7)
|
||||
#define GET_OPCODE_SIG_TYPE_SRC1(sig) (OpcodeSignatureType)((sig >> 3) & 0x7)
|
||||
#define GET_OPCODE_SIG_TYPE_SRC2(sig) (OpcodeSignatureType)((sig >> 6) & 0x7)
|
||||
#define GET_OPCODE_SIG_TYPE_SRC3(sig) (OpcodeSignatureType)((sig >> 9) & 0x7)
|
||||
|
||||
typedef struct {
|
||||
uint32_t flags;
|
||||
uint32_t signature;
|
||||
const char* name;
|
||||
Opcode num;
|
||||
} OpcodeInfo;
|
||||
|
||||
|
||||
} // namespace hir
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_HIR_OPCODES_H_
|
|
@ -0,0 +1,17 @@
|
|||
# Copyright 2013 Ben Vanik. All Rights Reserved.
|
||||
{
|
||||
'sources': [
|
||||
'block.cc',
|
||||
'block.h',
|
||||
'function_builder.cc',
|
||||
'function_builder.h',
|
||||
'instr.cc',
|
||||
'instr.h',
|
||||
'label.cc',
|
||||
'label.h',
|
||||
'opcodes.h',
|
||||
'tracing.h',
|
||||
'value.cc',
|
||||
'value.h',
|
||||
],
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_HIR_TRACING_H_
|
||||
#define ALLOY_HIR_TRACING_H_
|
||||
|
||||
#include <alloy/tracing/tracing.h>
|
||||
#include <alloy/tracing/event_type.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace hir {
|
||||
|
||||
const uint32_t ALLOY_HIR = alloy::tracing::EventType::ALLOY_HIR;
|
||||
|
||||
|
||||
class EventType {
|
||||
public:
|
||||
enum {
|
||||
ALLOY_HIR_FOO = ALLOY_HIR | (0),
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
} // namespace hir
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_HIR_TRACING_H_
|
|
@ -0,0 +1,195 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 <alloy/hir/value.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::hir;
|
||||
|
||||
|
||||
uint64_t Value::AsUint64() {
|
||||
XEASSERT(IsConstant());
|
||||
switch (type) {
|
||||
case INT8_TYPE:
|
||||
return constant.i8;
|
||||
case INT16_TYPE:
|
||||
return constant.i16;
|
||||
case INT32_TYPE:
|
||||
return constant.i32;
|
||||
case INT64_TYPE:
|
||||
return constant.i64;
|
||||
default:
|
||||
XEASSERTALWAYS();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Value::Cast(TypeName target_type) {
|
||||
// TODO(benvanik): big matrix.
|
||||
XEASSERTALWAYS();
|
||||
}
|
||||
|
||||
void Value::ZeroExtend(TypeName target_type) {
|
||||
// TODO(benvanik): big matrix.
|
||||
XEASSERTALWAYS();
|
||||
}
|
||||
|
||||
void Value::SignExtend(TypeName target_type) {
|
||||
// TODO(benvanik): big matrix.
|
||||
XEASSERTALWAYS();
|
||||
}
|
||||
|
||||
void Value::Truncate(TypeName target_type) {
|
||||
switch (type) {
|
||||
case INT16_TYPE:
|
||||
switch (target_type) {
|
||||
case INT8_TYPE:
|
||||
type = target_type;
|
||||
constant.i64 = constant.i64 & 0xFF;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case INT32_TYPE:
|
||||
switch (target_type) {
|
||||
case INT8_TYPE:
|
||||
type = target_type;
|
||||
constant.i64 = constant.i64 & 0xFF;
|
||||
return;
|
||||
case INT16_TYPE:
|
||||
type = target_type;
|
||||
constant.i64 = constant.i64 & 0xFFFF;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case INT64_TYPE:
|
||||
switch (target_type) {
|
||||
case INT8_TYPE:
|
||||
type = target_type;
|
||||
constant.i64 = constant.i64 & 0xFF;
|
||||
return;
|
||||
case INT16_TYPE:
|
||||
type = target_type;
|
||||
constant.i64 = constant.i64 & 0xFFFF;
|
||||
return;
|
||||
case INT32_TYPE:
|
||||
type = target_type;
|
||||
constant.i64 = constant.i64 & 0xFFFFFFFF;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Unsupported types.
|
||||
XEASSERTALWAYS();
|
||||
}
|
||||
|
||||
void Value::Convert(TypeName target_type, RoundMode round_mode) {
|
||||
// TODO(benvanik): big matrix.
|
||||
XEASSERTALWAYS();
|
||||
}
|
||||
|
||||
void Value::Round(RoundMode round_mode) {
|
||||
// TODO(benvanik): big matrix.
|
||||
XEASSERTALWAYS();
|
||||
}
|
||||
|
||||
void Value::Add(Value* other) {
|
||||
// TODO(benvanik): big matrix.
|
||||
XEASSERTALWAYS();
|
||||
}
|
||||
|
||||
void Value::Sub(Value* other) {
|
||||
// TODO(benvanik): big matrix.
|
||||
XEASSERTALWAYS();
|
||||
}
|
||||
|
||||
void Value::Mul(Value* other) {
|
||||
// TODO(benvanik): big matrix.
|
||||
XEASSERTALWAYS();
|
||||
}
|
||||
|
||||
void Value::Div(Value* other) {
|
||||
// TODO(benvanik): big matrix.
|
||||
XEASSERTALWAYS();
|
||||
}
|
||||
|
||||
void Value::Rem(Value* other) {
|
||||
// TODO(benvanik): big matrix.
|
||||
XEASSERTALWAYS();
|
||||
}
|
||||
|
||||
void Value::MulAdd(Value* dest, Value* value1, Value* value2, Value* value3) {
|
||||
// TODO(benvanik): big matrix.
|
||||
XEASSERTALWAYS();
|
||||
}
|
||||
|
||||
void Value::MulSub(Value* dest, Value* value1, Value* value2, Value* value3) {
|
||||
// TODO(benvanik): big matrix.
|
||||
XEASSERTALWAYS();
|
||||
}
|
||||
|
||||
void Value::Neg() {
|
||||
// TODO(benvanik): big matrix.
|
||||
XEASSERTALWAYS();
|
||||
}
|
||||
|
||||
void Value::Abs() {
|
||||
// TODO(benvanik): big matrix.
|
||||
XEASSERTALWAYS();
|
||||
}
|
||||
|
||||
void Value::Sqrt() {
|
||||
// TODO(benvanik): big matrix.
|
||||
XEASSERTALWAYS();
|
||||
}
|
||||
|
||||
void Value::And(Value* other) {
|
||||
// TODO(benvanik): big matrix.
|
||||
XEASSERTALWAYS();
|
||||
}
|
||||
|
||||
void Value::Or(Value* other) {
|
||||
// TODO(benvanik): big matrix.
|
||||
XEASSERTALWAYS();
|
||||
}
|
||||
|
||||
void Value::Xor(Value* other) {
|
||||
// TODO(benvanik): big matrix.
|
||||
XEASSERTALWAYS();
|
||||
}
|
||||
|
||||
void Value::Not() {
|
||||
// TODO(benvanik): big matrix.
|
||||
XEASSERTALWAYS();
|
||||
}
|
||||
|
||||
void Value::Shl(Value* other) {
|
||||
// TODO(benvanik): big matrix.
|
||||
XEASSERTALWAYS();
|
||||
}
|
||||
|
||||
void Value::Shr(Value* other) {
|
||||
// TODO(benvanik): big matrix.
|
||||
XEASSERTALWAYS();
|
||||
}
|
||||
|
||||
void Value::Sha(Value* other) {
|
||||
// TODO(benvanik): big matrix.
|
||||
XEASSERTALWAYS();
|
||||
}
|
||||
|
||||
void Value::ByteSwap() {
|
||||
// TODO(benvanik): big matrix.
|
||||
XEASSERTALWAYS();
|
||||
}
|
||||
|
||||
bool Value::Compare(Opcode opcode, Value* other) {
|
||||
// TODO(benvanik): big matrix.
|
||||
XEASSERTALWAYS();
|
||||
return false;
|
||||
}
|
|
@ -0,0 +1,188 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_HIR_VALUE_H_
|
||||
#define ALLOY_HIR_VALUE_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
#include <alloy/hir/opcodes.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace hir {
|
||||
|
||||
|
||||
enum TypeName {
|
||||
INT8_TYPE,
|
||||
INT16_TYPE,
|
||||
INT32_TYPE,
|
||||
INT64_TYPE,
|
||||
FLOAT32_TYPE,
|
||||
FLOAT64_TYPE,
|
||||
VEC128_TYPE,
|
||||
|
||||
MAX_TYPENAME,
|
||||
};
|
||||
|
||||
enum ValueFlags {
|
||||
VALUE_IS_CONSTANT = (1 << 1),
|
||||
};
|
||||
|
||||
|
||||
class Value {
|
||||
public:
|
||||
uint32_t ordinal;
|
||||
TypeName type;
|
||||
|
||||
uint32_t flags;
|
||||
union {
|
||||
int8_t i8;
|
||||
int16_t i16;
|
||||
int32_t i32;
|
||||
int64_t i64;
|
||||
float f32;
|
||||
double f64;
|
||||
vec128_t v128;
|
||||
} constant;
|
||||
|
||||
void* tag;
|
||||
|
||||
void set_zero(TypeName type) {
|
||||
this->type = type;
|
||||
flags |= VALUE_IS_CONSTANT;
|
||||
constant.v128.low = constant.v128.high = 0;
|
||||
}
|
||||
void set_constant(int8_t value) {
|
||||
type = INT8_TYPE;
|
||||
flags |= VALUE_IS_CONSTANT;
|
||||
constant.i8 = value;
|
||||
}
|
||||
void set_constant(uint8_t value) {
|
||||
type = INT8_TYPE;
|
||||
flags |= VALUE_IS_CONSTANT;
|
||||
constant.i8 = value;
|
||||
}
|
||||
void set_constant(int16_t value) {
|
||||
type = INT16_TYPE;
|
||||
flags |= VALUE_IS_CONSTANT;
|
||||
constant.i16 = value;
|
||||
}
|
||||
void set_constant(uint16_t value) {
|
||||
type = INT16_TYPE;
|
||||
flags |= VALUE_IS_CONSTANT;
|
||||
constant.i16 = value;
|
||||
}
|
||||
void set_constant(int32_t value) {
|
||||
type = INT32_TYPE;
|
||||
flags |= VALUE_IS_CONSTANT;
|
||||
constant.i32 = value;
|
||||
}
|
||||
void set_constant(uint32_t value) {
|
||||
type = INT32_TYPE;
|
||||
flags |= VALUE_IS_CONSTANT;
|
||||
constant.i32 = value;
|
||||
}
|
||||
void set_constant(int64_t value) {
|
||||
type = INT64_TYPE;
|
||||
flags |= VALUE_IS_CONSTANT;
|
||||
constant.i64 = value;
|
||||
}
|
||||
void set_constant(uint64_t value) {
|
||||
type = INT64_TYPE;
|
||||
flags |= VALUE_IS_CONSTANT;
|
||||
constant.i64 = value;
|
||||
}
|
||||
void set_constant(float value) {
|
||||
type = FLOAT32_TYPE;
|
||||
flags |= VALUE_IS_CONSTANT;
|
||||
constant.f32 = value;
|
||||
}
|
||||
void set_constant(double value) {
|
||||
type = FLOAT64_TYPE;
|
||||
flags |= VALUE_IS_CONSTANT;
|
||||
constant.f64 = value;
|
||||
}
|
||||
void set_constant(const vec128_t& value) {
|
||||
type = VEC128_TYPE;
|
||||
flags |= VALUE_IS_CONSTANT;
|
||||
constant.v128 = value;
|
||||
}
|
||||
|
||||
inline bool IsConstant() const {
|
||||
return !!(flags & VALUE_IS_CONSTANT);
|
||||
}
|
||||
bool IsConstantTrue() const {
|
||||
if (type == VEC128_TYPE) {
|
||||
return false;
|
||||
}
|
||||
return (flags & VALUE_IS_CONSTANT) && !!constant.i64;
|
||||
}
|
||||
bool IsConstantFalse() const {
|
||||
if (type == VEC128_TYPE) {
|
||||
return false;
|
||||
}
|
||||
return (flags & VALUE_IS_CONSTANT) && !constant.i64;
|
||||
}
|
||||
bool IsConstantZero() const {
|
||||
if (type == VEC128_TYPE) {
|
||||
return false;
|
||||
}
|
||||
return (flags & VALUE_IS_CONSTANT) && !constant.i64;
|
||||
}
|
||||
bool IsConstantEQ(Value* other) const {
|
||||
if (type == VEC128_TYPE) {
|
||||
return false;
|
||||
}
|
||||
return (flags & VALUE_IS_CONSTANT) &&
|
||||
(other->flags & VALUE_IS_CONSTANT) &&
|
||||
constant.i64 == other->constant.i64;
|
||||
}
|
||||
bool IsConstantNE(Value* other) const {
|
||||
if (type == VEC128_TYPE) {
|
||||
return false;
|
||||
}
|
||||
return (flags & VALUE_IS_CONSTANT) &&
|
||||
(other->flags & VALUE_IS_CONSTANT) &&
|
||||
constant.i64 != other->constant.i64;
|
||||
}
|
||||
uint64_t AsUint64();
|
||||
|
||||
void Cast(TypeName target_type);
|
||||
void ZeroExtend(TypeName target_type);
|
||||
void SignExtend(TypeName target_type);
|
||||
void Truncate(TypeName target_type);
|
||||
void Convert(TypeName target_type, RoundMode round_mode);
|
||||
void Round(RoundMode round_mode);
|
||||
void Add(Value* other);
|
||||
void Sub(Value* other);
|
||||
void Mul(Value* other);
|
||||
void Div(Value* other);
|
||||
void Rem(Value* other);
|
||||
static void MulAdd(Value* dest, Value* value1, Value* value2, Value* value3);
|
||||
static void MulSub(Value* dest, Value* value1, Value* value2, Value* value3);
|
||||
void Neg();
|
||||
void Abs();
|
||||
void Sqrt();
|
||||
void And(Value* other);
|
||||
void Or(Value* other);
|
||||
void Xor(Value* other);
|
||||
void Not();
|
||||
void Shl(Value* other);
|
||||
void Shr(Value* other);
|
||||
void Sha(Value* other);
|
||||
void ByteSwap();
|
||||
bool Compare(Opcode opcode, Value* other);
|
||||
};
|
||||
|
||||
|
||||
} // namespace hir
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_HIR_VALUE_H_
|
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 <alloy/memory.h>
|
||||
|
||||
using namespace alloy;
|
||||
|
||||
|
||||
Memory::Memory() :
|
||||
membase_(0) {
|
||||
SYSTEM_INFO si;
|
||||
GetSystemInfo(&si);
|
||||
system_page_size_ = si.dwPageSize;
|
||||
}
|
||||
|
||||
Memory::~Memory() {
|
||||
}
|
||||
|
||||
int Memory::Initialize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Memory::Zero(uint64_t address, size_t size) {
|
||||
uint8_t* p = membase_ + address;
|
||||
XEIGNORE(xe_zero_memory(p, size, 0, size));
|
||||
}
|
||||
|
||||
void Memory::Fill(uint64_t address, size_t size, uint8_t value) {
|
||||
uint8_t* p = membase_ + address;
|
||||
memset(p, value, size);
|
||||
}
|
||||
|
||||
void Memory::Copy(uint64_t dest, uint64_t src, size_t size) {
|
||||
uint8_t* pdest = membase_ + dest;
|
||||
uint8_t* psrc = membase_ + src;
|
||||
XEIGNORE(xe_copy_memory(pdest, size, psrc, size));
|
||||
}
|
||||
|
||||
uint64_t Memory::SearchAligned(
|
||||
uint64_t start, uint64_t end,
|
||||
const uint32_t* values, size_t value_count) {
|
||||
XEASSERT(start <= end);
|
||||
const uint32_t *p = (const uint32_t*)(membase_ + start);
|
||||
const uint32_t *pe = (const uint32_t*)(membase_ + end);
|
||||
while (p != pe) {
|
||||
if (*p == values[0]) {
|
||||
const uint32_t *pc = p + 1;
|
||||
size_t matched = 1;
|
||||
for (size_t n = 1; n < value_count; n++, pc++) {
|
||||
if (*pc != values[n]) {
|
||||
break;
|
||||
}
|
||||
matched++;
|
||||
}
|
||||
if (matched == value_count) {
|
||||
return (uint64_t)((uint8_t*)p - membase_);
|
||||
}
|
||||
}
|
||||
p++;
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_MEMORY_H_
|
||||
#define ALLOY_MEMORY_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
|
||||
|
||||
enum {
|
||||
MEMORY_FLAG_64KB_PAGES = (1 << 1),
|
||||
MEMORY_FLAG_ZERO = (1 << 2),
|
||||
MEMORY_FLAG_PHYSICAL = (1 << 3),
|
||||
};
|
||||
|
||||
|
||||
class Memory {
|
||||
public:
|
||||
Memory();
|
||||
virtual ~Memory();
|
||||
|
||||
inline uint8_t* membase() const { return membase_; }
|
||||
inline uint8_t* Translate(uint64_t guest_address) const {
|
||||
return membase_ + guest_address;
|
||||
};
|
||||
|
||||
virtual int Initialize();
|
||||
|
||||
void Zero(uint64_t address, size_t size);
|
||||
void Fill(uint64_t address, size_t size, uint8_t value);
|
||||
void Copy(uint64_t dest, uint64_t src, size_t size);
|
||||
|
||||
uint64_t SearchAligned(uint64_t start, uint64_t end,
|
||||
const uint32_t* values, size_t value_count);
|
||||
|
||||
virtual uint64_t HeapAlloc(
|
||||
uint64_t base_address, size_t size, uint32_t flags,
|
||||
uint32_t alignment = 0x20) = 0;
|
||||
virtual int HeapFree(uint64_t address, size_t size) = 0;
|
||||
|
||||
virtual int Protect(uint64_t address, size_t size, uint32_t access) = 0;
|
||||
virtual uint32_t QueryProtect(uint64_t address) = 0;
|
||||
|
||||
protected:
|
||||
size_t system_page_size_;
|
||||
uint8_t* membase_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_MEMORY_H_
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_MUTEX_H_
|
||||
#define ALLOY_MUTEX_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
|
||||
|
||||
typedef struct Mutex_t Mutex;
|
||||
|
||||
Mutex* AllocMutex(uint32_t spin_count = 10000);
|
||||
void FreeMutex(Mutex* mutex);
|
||||
|
||||
int LockMutex(Mutex* mutex);
|
||||
int TryLockMutex(Mutex* mutex);
|
||||
int UnlockMutex(Mutex* mutex);
|
||||
|
||||
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_MUTEX_H_
|
|
@ -0,0 +1,65 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 <alloy/mutex.h>
|
||||
|
||||
using namespace alloy;
|
||||
|
||||
|
||||
namespace alloy {
|
||||
struct Mutex_t {
|
||||
pthread_mutex_t value;
|
||||
};
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
Mutex* alloy::AllocMutex(uint32_t spin_count) {
|
||||
Mutex* mutex = (Mutex*)calloc(1, sizeof(Mutex));
|
||||
|
||||
int result = pthread_mutex_init(&mutex->value, NULL);
|
||||
switch (result) {
|
||||
case ENOMEM:
|
||||
case EINVAL:
|
||||
xe_free(mutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return mutex;
|
||||
}
|
||||
|
||||
void alloy::FreeMutex(Mutex* mutex) {
|
||||
int result = pthread_mutex_destroy(&mutex->value);
|
||||
switch (result) {
|
||||
case EBUSY:
|
||||
case EINVAL:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
free(mutex);
|
||||
}
|
||||
|
||||
int alloy::LockMutex(Mutex* mutex) {
|
||||
return pthread_mutex_lock(&mutex->value) == EINVAL ? 1 : 0;
|
||||
}
|
||||
|
||||
int alloy::TryLockMutex(Mutex* mutex) {
|
||||
int result = pthread_mutex_trylock(&mutex->value);
|
||||
switch (result) {
|
||||
case EBUSY:
|
||||
case EINVAL:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int alloy::UnlockMutex(Mutex* mutex) {
|
||||
return pthread_mutex_unlock(&mutex->value) == EINVAL ? 1 : 0;
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 <alloy/mutex.h>
|
||||
|
||||
using namespace alloy;
|
||||
|
||||
|
||||
namespace alloy {
|
||||
struct Mutex_t {
|
||||
CRITICAL_SECTION value;
|
||||
};
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
Mutex* alloy::AllocMutex(uint32_t spin_count) {
|
||||
Mutex* mutex = (Mutex*)calloc(1, sizeof(Mutex));
|
||||
|
||||
if (spin_count) {
|
||||
InitializeCriticalSectionAndSpinCount(&mutex->value, spin_count);
|
||||
} else {
|
||||
InitializeCriticalSection(&mutex->value);
|
||||
}
|
||||
|
||||
return mutex;
|
||||
}
|
||||
|
||||
void alloy::FreeMutex(Mutex* mutex) {
|
||||
DeleteCriticalSection(&mutex->value);
|
||||
free(mutex);
|
||||
}
|
||||
|
||||
int alloy::LockMutex(Mutex* mutex) {
|
||||
EnterCriticalSection(&mutex->value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int alloy::TryLockMutex(Mutex* mutex) {
|
||||
if (TryEnterCriticalSection(&mutex->value) == TRUE) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int alloy::UnlockMutex(Mutex* mutex) {
|
||||
LeaveCriticalSection(&mutex->value);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 <alloy/runtime/entry_table.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
|
||||
EntryTable::EntryTable() {
|
||||
lock_ = AllocMutex(10000);
|
||||
}
|
||||
|
||||
EntryTable::~EntryTable() {
|
||||
LockMutex(lock_);
|
||||
EntryMap::iterator it = map_.begin();
|
||||
for (; it != map_.end(); ++it) {
|
||||
Entry* entry = it->second;
|
||||
delete entry;
|
||||
}
|
||||
UnlockMutex(lock_);
|
||||
FreeMutex(lock_);
|
||||
}
|
||||
|
||||
Entry* EntryTable::Get(uint64_t address) {
|
||||
LockMutex(lock_);
|
||||
EntryMap::const_iterator it = map_.find(address);
|
||||
Entry* entry = it != map_.end() ? it->second : NULL;
|
||||
if (entry) {
|
||||
// TODO(benvanik): wait if needed?
|
||||
if (entry->status != Entry::STATUS_READY) {
|
||||
entry = NULL;
|
||||
}
|
||||
}
|
||||
UnlockMutex(lock_);
|
||||
return entry;
|
||||
}
|
||||
|
||||
Entry::Status EntryTable::GetOrCreate(uint64_t address, Entry** out_entry) {
|
||||
LockMutex(lock_);
|
||||
EntryMap::const_iterator it = map_.find(address);
|
||||
Entry* entry = it != map_.end() ? it->second : NULL;
|
||||
Entry::Status status;
|
||||
if (entry) {
|
||||
// If we aren't ready yet spin and wait.
|
||||
if (entry->status == Entry::STATUS_COMPILING) {
|
||||
// Still compiling, so spin.
|
||||
do {
|
||||
UnlockMutex(lock_);
|
||||
// TODO(benvanik): sleep for less time?
|
||||
Sleep(0);
|
||||
LockMutex(lock_);
|
||||
} while (entry->status == Entry::STATUS_COMPILING);
|
||||
}
|
||||
status = entry->status;
|
||||
} else {
|
||||
// Create and return for initialization.
|
||||
entry = new Entry();
|
||||
entry->address = address;
|
||||
entry->status = Entry::STATUS_COMPILING;
|
||||
entry->function = 0;
|
||||
map_[address] = entry;
|
||||
status = Entry::STATUS_NEW;
|
||||
}
|
||||
UnlockMutex(lock_);
|
||||
*out_entry = entry;
|
||||
return status;
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_RUNTIME_ENTRY_TABLE_H_
|
||||
#define ALLOY_RUNTIME_ENTRY_TABLE_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace runtime {
|
||||
|
||||
class Function;
|
||||
|
||||
|
||||
typedef struct Entry_t {
|
||||
typedef enum {
|
||||
STATUS_NEW = 0,
|
||||
STATUS_COMPILING,
|
||||
STATUS_READY,
|
||||
STATUS_FAILED,
|
||||
} Status;
|
||||
|
||||
uint64_t address;
|
||||
Status status;
|
||||
Function* function;
|
||||
} Entry;
|
||||
|
||||
|
||||
class EntryTable {
|
||||
public:
|
||||
EntryTable();
|
||||
~EntryTable();
|
||||
|
||||
Entry* Get(uint64_t address);
|
||||
Entry::Status GetOrCreate(uint64_t address, Entry** out_entry);
|
||||
|
||||
private:
|
||||
// TODO(benvanik): replace with a better data structure.
|
||||
Mutex* lock_;
|
||||
typedef std::tr1::unordered_map<uint64_t, Entry*> EntryMap;
|
||||
EntryMap map_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace runtime
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_RUNTIME_ENTRY_TABLE_H_
|
|
@ -0,0 +1,62 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 <alloy/runtime/function.h>
|
||||
|
||||
#include <alloy/runtime/symbol_info.h>
|
||||
#include <alloy/runtime/thread_state.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
|
||||
Function::Function(Type type, uint64_t address) :
|
||||
type_(type), address_(address) {
|
||||
}
|
||||
|
||||
Function::~Function() {
|
||||
}
|
||||
|
||||
int Function::Call(ThreadState* thread_state) {
|
||||
ThreadState* original_thread_state = ThreadState::Get();
|
||||
if (original_thread_state != thread_state) {
|
||||
ThreadState::Bind(thread_state);
|
||||
}
|
||||
int result = CallImpl(thread_state);
|
||||
if (original_thread_state != thread_state) {
|
||||
ThreadState::Bind(original_thread_state);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ExternFunction::ExternFunction(
|
||||
uint64_t address, Handler handler, void* arg0, void* arg1) :
|
||||
handler_(handler), arg0_(arg0), arg1_(arg1),
|
||||
Function(Function::EXTERN_FUNCTION, address) {
|
||||
}
|
||||
|
||||
ExternFunction::~ExternFunction() {
|
||||
}
|
||||
|
||||
int ExternFunction::CallImpl(ThreadState* thread_state) {
|
||||
if (!handler_) {
|
||||
XELOGW("undefined extern call to %.8X", address());
|
||||
return 0;
|
||||
}
|
||||
handler_(thread_state->raw_context(), arg0_, arg1_);
|
||||
return 0;
|
||||
}
|
||||
|
||||
GuestFunction::GuestFunction(FunctionInfo* symbol_info) :
|
||||
symbol_info_(symbol_info),
|
||||
Function(Function::USER_FUNCTION, symbol_info->address()) {
|
||||
}
|
||||
|
||||
GuestFunction::~GuestFunction() {
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_RUNTIME_FUNCTION_H_
|
||||
#define ALLOY_RUNTIME_FUNCTION_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace runtime {
|
||||
|
||||
class FunctionInfo;
|
||||
class ThreadState;
|
||||
|
||||
|
||||
class Function {
|
||||
public:
|
||||
enum Type {
|
||||
UNKNOWN_FUNCTION = 0,
|
||||
EXTERN_FUNCTION,
|
||||
USER_FUNCTION,
|
||||
};
|
||||
public:
|
||||
Function(Type type, uint64_t address);
|
||||
virtual ~Function();
|
||||
|
||||
Type type() const { return type_; }
|
||||
uint64_t address() const { return address_; }
|
||||
|
||||
int Call(ThreadState* thread_state);
|
||||
|
||||
protected:
|
||||
virtual int CallImpl(ThreadState* thread_state) = 0;
|
||||
|
||||
protected:
|
||||
Type type_;
|
||||
uint64_t address_;
|
||||
};
|
||||
|
||||
|
||||
class ExternFunction : public Function {
|
||||
public:
|
||||
typedef void(*Handler)(void* context, void* arg0, void* arg1);
|
||||
public:
|
||||
ExternFunction(uint64_t address, Handler handler, void* arg0, void* arg1);
|
||||
virtual ~ExternFunction();
|
||||
|
||||
Handler handler() const { return handler_; }
|
||||
void* arg0() const { return arg0_; }
|
||||
void* arg1() const { return arg1_; }
|
||||
|
||||
protected:
|
||||
virtual int CallImpl(ThreadState* thread_state);
|
||||
|
||||
protected:
|
||||
Handler handler_;
|
||||
void* arg0_;
|
||||
void* arg1_;
|
||||
};
|
||||
|
||||
|
||||
class GuestFunction : public Function {
|
||||
public:
|
||||
GuestFunction(FunctionInfo* symbol_info);
|
||||
virtual ~GuestFunction();
|
||||
|
||||
FunctionInfo* symbol_info() const { return symbol_info_; }
|
||||
|
||||
protected:
|
||||
FunctionInfo* symbol_info_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace runtime
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_RUNTIME_FUNCTION_H_
|
|
@ -0,0 +1,154 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 <alloy/runtime/module.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
|
||||
Module::Module(Memory* memory) :
|
||||
memory_(memory) {
|
||||
lock_ = AllocMutex(10000);
|
||||
}
|
||||
|
||||
Module::~Module() {
|
||||
LockMutex(lock_);
|
||||
SymbolMap::iterator it = map_.begin();
|
||||
for (; it != map_.end(); ++it) {
|
||||
SymbolInfo* symbol_info = it->second;
|
||||
delete symbol_info;
|
||||
}
|
||||
UnlockMutex(lock_);
|
||||
FreeMutex(lock_);
|
||||
}
|
||||
|
||||
bool Module::ContainsAddress(uint64_t address) {
|
||||
return true;
|
||||
}
|
||||
|
||||
SymbolInfo* Module::LookupSymbol(uint64_t address, bool wait) {
|
||||
LockMutex(lock_);
|
||||
SymbolMap::const_iterator it = map_.find(address);
|
||||
SymbolInfo* symbol_info = it != map_.end() ? it->second : NULL;
|
||||
if (symbol_info) {
|
||||
if (symbol_info->status() == SymbolInfo::STATUS_DECLARING) {
|
||||
// Some other thread is declaring the symbol - wait.
|
||||
if (wait) {
|
||||
do {
|
||||
UnlockMutex(lock_);
|
||||
// TODO(benvanik): sleep for less time?
|
||||
Sleep(0);
|
||||
LockMutex(lock_);
|
||||
} while (symbol_info->status() == SymbolInfo::STATUS_DECLARING);
|
||||
} else {
|
||||
// Immediate request, just return.
|
||||
symbol_info = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
UnlockMutex(lock_);
|
||||
return symbol_info;
|
||||
}
|
||||
|
||||
SymbolInfo::Status Module::DeclareSymbol(
|
||||
SymbolInfo::Type type, uint64_t address, SymbolInfo** out_symbol_info) {
|
||||
*out_symbol_info = NULL;
|
||||
LockMutex(lock_);
|
||||
SymbolMap::const_iterator it = map_.find(address);
|
||||
SymbolInfo* symbol_info = it != map_.end() ? it->second : NULL;
|
||||
SymbolInfo::Status status;
|
||||
if (symbol_info) {
|
||||
// If we exist but are the wrong type, die.
|
||||
if (symbol_info->type() != type) {
|
||||
UnlockMutex(lock_);
|
||||
return SymbolInfo::STATUS_FAILED;
|
||||
}
|
||||
// If we aren't ready yet spin and wait.
|
||||
if (symbol_info->status() == SymbolInfo::STATUS_DECLARING) {
|
||||
// Still declaring, so spin.
|
||||
do {
|
||||
UnlockMutex(lock_);
|
||||
// TODO(benvanik): sleep for less time?
|
||||
Sleep(0);
|
||||
LockMutex(lock_);
|
||||
} while (symbol_info->status() == SymbolInfo::STATUS_DECLARING);
|
||||
}
|
||||
status = symbol_info->status();
|
||||
} else {
|
||||
// Create and return for initialization.
|
||||
switch (type) {
|
||||
case SymbolInfo::TYPE_FUNCTION:
|
||||
symbol_info = new FunctionInfo(this, address);
|
||||
break;
|
||||
case SymbolInfo::TYPE_VARIABLE:
|
||||
symbol_info = new VariableInfo(this, address);
|
||||
break;
|
||||
}
|
||||
map_[address] = symbol_info;
|
||||
status = SymbolInfo::STATUS_NEW;
|
||||
}
|
||||
UnlockMutex(lock_);
|
||||
*out_symbol_info = symbol_info;
|
||||
|
||||
// Get debug info from providers, if this is new.
|
||||
if (status == SymbolInfo::STATUS_NEW) {
|
||||
// TODO(benvanik): lookup in map data/dwarf/etc?
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SymbolInfo::Status Module::DeclareFunction(
|
||||
uint64_t address, FunctionInfo** out_symbol_info) {
|
||||
SymbolInfo* symbol_info;
|
||||
SymbolInfo::Status status = DeclareSymbol(
|
||||
SymbolInfo::TYPE_FUNCTION, address, &symbol_info);
|
||||
*out_symbol_info = (FunctionInfo*)symbol_info;
|
||||
return status;
|
||||
}
|
||||
|
||||
SymbolInfo::Status Module::DeclareVariable(
|
||||
uint64_t address, VariableInfo** out_symbol_info) {
|
||||
SymbolInfo* symbol_info;
|
||||
SymbolInfo::Status status = DeclareSymbol(
|
||||
SymbolInfo::TYPE_VARIABLE, address, &symbol_info);
|
||||
*out_symbol_info = (VariableInfo*)symbol_info;
|
||||
return status;
|
||||
}
|
||||
|
||||
SymbolInfo::Status Module::DefineSymbol(SymbolInfo* symbol_info) {
|
||||
LockMutex(lock_);
|
||||
SymbolInfo::Status status;
|
||||
if (symbol_info->status() == SymbolInfo::STATUS_DECLARED) {
|
||||
// Declared but undefined, so request caller define it.
|
||||
symbol_info->set_status(SymbolInfo::STATUS_DEFINING);
|
||||
status = SymbolInfo::STATUS_NEW;
|
||||
} else if (symbol_info->status() == SymbolInfo::STATUS_DEFINING) {
|
||||
// Still defining, so spin.
|
||||
do {
|
||||
UnlockMutex(lock_);
|
||||
// TODO(benvanik): sleep for less time?
|
||||
Sleep(0);
|
||||
LockMutex(lock_);
|
||||
} while (symbol_info->status() == SymbolInfo::STATUS_DEFINING);
|
||||
} else {
|
||||
status = symbol_info->status();
|
||||
}
|
||||
UnlockMutex(lock_);
|
||||
return status;
|
||||
}
|
||||
|
||||
SymbolInfo::Status Module::DefineFunction(FunctionInfo* symbol_info) {
|
||||
return DefineSymbol((SymbolInfo*)symbol_info);
|
||||
}
|
||||
|
||||
SymbolInfo::Status Module::DefineVariable(VariableInfo* symbol_info) {
|
||||
return DefineSymbol((SymbolInfo*)symbol_info);
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_RUNTIME_MODULE_H_
|
||||
#define ALLOY_RUNTIME_MODULE_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
#include <alloy/memory.h>
|
||||
#include <alloy/runtime/symbol_info.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace runtime {
|
||||
|
||||
class Function;
|
||||
|
||||
|
||||
class Module {
|
||||
public:
|
||||
Module(Memory* memory);
|
||||
virtual ~Module();
|
||||
|
||||
Memory* memory() const { return memory_; }
|
||||
|
||||
virtual const char* name() const = 0;
|
||||
|
||||
virtual bool ContainsAddress(uint64_t address);
|
||||
|
||||
SymbolInfo* LookupSymbol(uint64_t address, bool wait = true);
|
||||
SymbolInfo::Status DeclareFunction(
|
||||
uint64_t address, FunctionInfo** out_symbol_info);
|
||||
SymbolInfo::Status DeclareVariable(
|
||||
uint64_t address, VariableInfo** out_symbol_info);
|
||||
|
||||
SymbolInfo::Status DefineFunction(FunctionInfo* symbol_info);
|
||||
SymbolInfo::Status DefineVariable(VariableInfo* symbol_info);
|
||||
|
||||
private:
|
||||
SymbolInfo::Status DeclareSymbol(
|
||||
SymbolInfo::Type type, uint64_t address, SymbolInfo** out_symbol_info);
|
||||
SymbolInfo::Status DefineSymbol(SymbolInfo* symbol_info);
|
||||
|
||||
protected:
|
||||
Memory* memory_;
|
||||
|
||||
private:
|
||||
// TODO(benvanik): replace with a better data structure.
|
||||
Mutex* lock_;
|
||||
typedef std::tr1::unordered_map<uint64_t, SymbolInfo*> SymbolMap;
|
||||
SymbolMap map_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace runtime
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_RUNTIME_MODULE_H_
|
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 <alloy/runtime/raw_module.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
|
||||
RawModule::RawModule(Memory* memory) :
|
||||
name_(0),
|
||||
base_address_(0), low_address_(0), high_address_(0),
|
||||
Module(memory) {
|
||||
}
|
||||
|
||||
RawModule::~RawModule() {
|
||||
if (base_address_) {
|
||||
memory_->HeapFree(base_address_, high_address_ - low_address_);
|
||||
}
|
||||
xe_free(name_);
|
||||
}
|
||||
|
||||
int RawModule::LoadFile(uint64_t base_address, const char* path) {
|
||||
FILE* file = fopen(path, "rb");
|
||||
fseek(file, 0, SEEK_END);
|
||||
size_t file_length = ftell(file);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
|
||||
// Allocate memory.
|
||||
base_address_ = memory_->HeapAlloc(
|
||||
base_address, file_length, MEMORY_FLAG_ZERO);
|
||||
if (!base_address_) {
|
||||
fclose(file);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Read into memory.
|
||||
uint8_t* p = memory_->Translate(base_address_);
|
||||
fread(p, file_length, 1, file);
|
||||
|
||||
fclose(file);
|
||||
|
||||
// Setup debug info.
|
||||
const char* name = xestrrchra(path, XE_PATH_SEPARATOR) + 1;
|
||||
name_ = xestrdupa(name);
|
||||
// TODO(benvanik): debug info
|
||||
|
||||
low_address_ = base_address;
|
||||
high_address_ = base_address + file_length;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool RawModule::ContainsAddress(uint64_t address) {
|
||||
return address >= low_address_ && address < high_address_;
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_RUNTIME_RAW_MODULE_H_
|
||||
#define ALLOY_RUNTIME_RAW_MODULE_H_
|
||||
|
||||
#include <alloy/runtime/module.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace runtime {
|
||||
|
||||
|
||||
class RawModule : public Module {
|
||||
public:
|
||||
RawModule(Memory* memory);
|
||||
virtual ~RawModule();
|
||||
|
||||
int LoadFile(uint64_t base_address, const char* path);
|
||||
|
||||
virtual const char* name() const { return name_; }
|
||||
|
||||
virtual bool ContainsAddress(uint64_t address);
|
||||
|
||||
private:
|
||||
char* name_;
|
||||
uint64_t base_address_;
|
||||
uint64_t low_address_;
|
||||
uint64_t high_address_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace runtime
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_RUNTIME_RAW_MODULE_H_
|
|
@ -7,23 +7,20 @@
|
|||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_CPU_PPC_REGISTERS_H_
|
||||
#define XENIA_CPU_PPC_REGISTERS_H_
|
||||
#ifndef ALLOY_RUNTIME_REGISTER_ACCESS_H_
|
||||
#define ALLOY_RUNTIME_REGISTER_ACCESS_H_
|
||||
|
||||
#include <xenia/common.h>
|
||||
#include <alloy/core.h>
|
||||
|
||||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
namespace ppc {
|
||||
namespace alloy {
|
||||
namespace runtime {
|
||||
|
||||
|
||||
typedef bool (*RegisterHandlesCallback)(void* context, uint32_t addr);
|
||||
typedef uint64_t (*RegisterReadCallback)(void* context, uint32_t addr);
|
||||
typedef void (*RegisterWriteCallback)(void* context, uint32_t addr,
|
||||
typedef bool (*RegisterHandlesCallback)(void* context, uint64_t addr);
|
||||
typedef uint64_t (*RegisterReadCallback)(void* context, uint64_t addr);
|
||||
typedef void (*RegisterWriteCallback)(void* context, uint64_t addr,
|
||||
uint64_t value);
|
||||
|
||||
|
||||
typedef struct {
|
||||
void* context;
|
||||
RegisterHandlesCallback handles;
|
||||
|
@ -32,9 +29,8 @@ typedef struct {
|
|||
} RegisterAccessCallbacks;
|
||||
|
||||
|
||||
} // namespace ppc
|
||||
} // namespace cpu
|
||||
} // namespace xe
|
||||
} // namespace runtime
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // XENIA_CPU_PPC_REGISTERS_H_
|
||||
#endif // ALLOY_RUNTIME_REGISTER_ACCESS_H_
|
|
@ -0,0 +1,218 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 <alloy/runtime/runtime.h>
|
||||
|
||||
#include <gflags/gflags.h>
|
||||
|
||||
#include <alloy/runtime/module.h>
|
||||
#include <alloy/runtime/tracing.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::backend;
|
||||
using namespace alloy::frontend;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
|
||||
DEFINE_string(runtime_backend, "any",
|
||||
"Runtime backend [any, ivm, x64].");
|
||||
|
||||
|
||||
Runtime::Runtime(Memory* memory) :
|
||||
memory_(memory), backend_(0), frontend_(0) {
|
||||
tracing::Initialize();
|
||||
modules_lock_ = AllocMutex(10000);
|
||||
}
|
||||
|
||||
Runtime::~Runtime() {
|
||||
LockMutex(modules_lock_);
|
||||
for (ModuleList::iterator it = modules_.begin();
|
||||
it != modules_.end(); ++it) {
|
||||
Module* module = *it;
|
||||
delete module;
|
||||
}
|
||||
UnlockMutex(modules_lock_);
|
||||
FreeMutex(modules_lock_);
|
||||
|
||||
delete frontend_;
|
||||
delete backend_;
|
||||
|
||||
tracing::Flush();
|
||||
}
|
||||
|
||||
// TODO(benvanik): based on compiler support
|
||||
#include <alloy/backend/ivm/ivm_backend.h>
|
||||
|
||||
int Runtime::Initialize(Frontend* frontend, Backend* backend) {
|
||||
// Must be initialized by subclass before calling into this.
|
||||
XEASSERTNOTNULL(memory_);
|
||||
|
||||
int result = memory_->Initialize();
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (frontend_ || backend_) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!backend) {
|
||||
#if defined(ALLOY_HAS_IVM_BACKEND) && ALLOY_HAS_IVM_BACKEND
|
||||
if (FLAGS_runtime_backend == "ivm") {
|
||||
backend = new alloy::backend::ivm::IVMBackend(
|
||||
this);
|
||||
}
|
||||
#endif
|
||||
// x64/etc
|
||||
if (FLAGS_runtime_backend == "any") {
|
||||
// x64/etc
|
||||
#if defined(ALLOY_HAS_IVM_BACKEND) && ALLOY_HAS_IVM_BACKEND
|
||||
if (!backend) {
|
||||
backend = new alloy::backend::ivm::IVMBackend(
|
||||
this);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (!backend) {
|
||||
return 1;
|
||||
}
|
||||
backend_ = backend;
|
||||
frontend_ = frontend;
|
||||
|
||||
result = backend_->Initialize();
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = frontend_->Initialize();
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Runtime::AddModule(Module* module) {
|
||||
LockMutex(modules_lock_);
|
||||
modules_.push_back(module);
|
||||
UnlockMutex(modules_lock_);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Runtime::ResolveFunction(uint64_t address, Function** out_function) {
|
||||
*out_function = NULL;
|
||||
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;
|
||||
}
|
||||
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(
|
||||
uint64_t address, FunctionInfo** out_symbol_info) {
|
||||
*out_symbol_info = NULL;
|
||||
|
||||
// TODO(benvanik): fast reject invalid addresses/log errors.
|
||||
|
||||
// Find the module that contains the address.
|
||||
Module* code_module = NULL;
|
||||
LockMutex(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 (ModuleList::const_iterator it = modules_.begin();
|
||||
it != modules_.end(); ++it) {
|
||||
Module* module = *it;
|
||||
if (module->ContainsAddress(address)) {
|
||||
code_module = module;
|
||||
break;
|
||||
}
|
||||
}
|
||||
UnlockMutex(modules_lock_);
|
||||
if (!code_module) {
|
||||
// No module found that could contain the address.
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Atomic create/lookup symbol in module.
|
||||
// If we get back the NEW flag we must declare it now.
|
||||
FunctionInfo* symbol_info = NULL;
|
||||
SymbolInfo::Status symbol_status =
|
||||
code_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 = NULL;
|
||||
|
||||
// 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 = NULL;
|
||||
int result = frontend_->DefineFunction(symbol_info, &function);
|
||||
if (result) {
|
||||
symbol_info->set_status(SymbolInfo::STATUS_FAILED);
|
||||
return result;
|
||||
}
|
||||
symbol_info->set_function(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;
|
||||
}
|
||||
|
||||
void Runtime::AddRegisterAccessCallbacks(RegisterAccessCallbacks callbacks) {
|
||||
//
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_RUNTIME_RUNTIME_H_
|
||||
#define ALLOY_RUNTIME_RUNTIME_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
#include <alloy/memory.h>
|
||||
#include <alloy/backend/backend.h>
|
||||
#include <alloy/frontend/frontend.h>
|
||||
#include <alloy/runtime/entry_table.h>
|
||||
#include <alloy/runtime/module.h>
|
||||
#include <alloy/runtime/register_access.h>
|
||||
#include <alloy/runtime/symbol_info.h>
|
||||
#include <alloy/runtime/thread_state.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace runtime {
|
||||
|
||||
|
||||
class Runtime {
|
||||
public:
|
||||
Runtime(Memory* memory);
|
||||
virtual ~Runtime();
|
||||
|
||||
Memory* memory() const { return memory_; }
|
||||
frontend::Frontend* frontend() const { return frontend_; }
|
||||
backend::Backend* backend() const { return backend_; }
|
||||
|
||||
int Initialize(frontend::Frontend* frontend, backend::Backend* backend = 0);
|
||||
|
||||
int AddModule(Module* module);
|
||||
|
||||
int LookupFunctionInfo(uint64_t address, FunctionInfo** out_symbol_info);
|
||||
int ResolveFunction(uint64_t address, Function** out_function);
|
||||
|
||||
void AddRegisterAccessCallbacks(RegisterAccessCallbacks callbacks);
|
||||
|
||||
//uint32_t CreateCallback(void (*callback)(void* data), void* data);
|
||||
|
||||
private:
|
||||
int DemandFunction(FunctionInfo* symbol_info, Function** out_function);
|
||||
|
||||
protected:
|
||||
Memory* memory_;
|
||||
|
||||
frontend::Frontend* frontend_;
|
||||
backend::Backend* backend_;
|
||||
|
||||
EntryTable entry_table_;
|
||||
Mutex* modules_lock_;
|
||||
typedef std::vector<Module*> ModuleList;
|
||||
ModuleList modules_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace runtime
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_RUNTIME_RUNTIME_H_
|
|
@ -0,0 +1,13 @@
|
|||
# Copyright 2013 Ben Vanik. All Rights Reserved.
|
||||
{
|
||||
'sources': [
|
||||
'simple_context.cc',
|
||||
'simple_context.h',
|
||||
'simple_memory.cc',
|
||||
'simple_memory.h',
|
||||
'simple_runtime.cc',
|
||||
'simple_runtime.h',
|
||||
'simple_thread_state.cc',
|
||||
'simple_thread_state.h',
|
||||
],
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
# Copyright 2013 Ben Vanik. All Rights Reserved.
|
||||
{
|
||||
'sources': [
|
||||
'entry_table.cc',
|
||||
'entry_table.h',
|
||||
'function.cc',
|
||||
'function.h',
|
||||
'module.cc',
|
||||
'module.h',
|
||||
'raw_module.cc',
|
||||
'raw_module.h',
|
||||
'register_access.h',
|
||||
'runtime.cc',
|
||||
'runtime.h',
|
||||
'symbol_info.cc',
|
||||
'symbol_info.h',
|
||||
'thread_state.cc',
|
||||
'thread_state.h',
|
||||
'tracing.h',
|
||||
],
|
||||
|
||||
'includes': [
|
||||
#'simple/sources.gypi',
|
||||
],
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 <alloy/runtime/symbol_info.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
|
||||
SymbolInfo::SymbolInfo(Type type, Module* module, uint64_t address) :
|
||||
type_(type), status_(STATUS_DEFINING),
|
||||
module_(module), address_(address) {
|
||||
}
|
||||
|
||||
SymbolInfo::~SymbolInfo() {
|
||||
}
|
||||
|
||||
FunctionInfo::FunctionInfo(Module* module, uint64_t address) :
|
||||
end_address_(0), function_(0),
|
||||
SymbolInfo(SymbolInfo::TYPE_FUNCTION, module, address) {
|
||||
}
|
||||
|
||||
FunctionInfo::~FunctionInfo() {
|
||||
}
|
||||
|
||||
VariableInfo::VariableInfo(Module* module, uint64_t address) :
|
||||
SymbolInfo(SymbolInfo::TYPE_VARIABLE, module, address) {
|
||||
}
|
||||
|
||||
VariableInfo::~VariableInfo() {
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_RUNTIME_SYMBOL_INFO_H_
|
||||
#define ALLOY_RUNTIME_SYMBOL_INFO_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace runtime {
|
||||
|
||||
class Function;
|
||||
class Module;
|
||||
|
||||
|
||||
class SymbolInfo {
|
||||
public:
|
||||
enum Type {
|
||||
TYPE_FUNCTION,
|
||||
TYPE_VARIABLE,
|
||||
};
|
||||
enum Status {
|
||||
STATUS_NEW,
|
||||
STATUS_DECLARING,
|
||||
STATUS_DECLARED,
|
||||
STATUS_DEFINING,
|
||||
STATUS_DEFINED,
|
||||
STATUS_FAILED,
|
||||
};
|
||||
public:
|
||||
SymbolInfo(Type type, Module* module, uint64_t address);
|
||||
virtual ~SymbolInfo();
|
||||
|
||||
Type type() const { return type_; }
|
||||
Module* module() const { return module_; }
|
||||
Status status() const { return status_; }
|
||||
void set_status(Status value) { status_ = value; }
|
||||
uint64_t address() const { return address_; }
|
||||
|
||||
protected:
|
||||
Type type_;
|
||||
Module* module_;
|
||||
Status status_;
|
||||
uint64_t address_;
|
||||
};
|
||||
|
||||
class FunctionInfo : public SymbolInfo {
|
||||
public:
|
||||
FunctionInfo(Module* module, uint64_t address);
|
||||
virtual ~FunctionInfo();
|
||||
|
||||
bool has_end_address() const { return end_address_ > 0; }
|
||||
uint64_t end_address() const { return end_address_; }
|
||||
void set_end_address(uint64_t value) { end_address_ = value; }
|
||||
|
||||
Function* function() const { return function_; }
|
||||
void set_function(Function* value) { function_ = value; }
|
||||
|
||||
private:
|
||||
uint64_t end_address_;
|
||||
Function* function_;
|
||||
};
|
||||
|
||||
class VariableInfo : public SymbolInfo {
|
||||
public:
|
||||
VariableInfo(Module* module, uint64_t address);
|
||||
virtual ~VariableInfo();
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
} // namespace runtime
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_RUNTIME_SYMBOL_INFO_H_
|
|
@ -0,0 +1,56 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 <alloy/runtime/thread_state.h>
|
||||
|
||||
#include <alloy/runtime/runtime.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
|
||||
namespace {
|
||||
__declspec(thread) ThreadState* thread_state_ = NULL;
|
||||
}
|
||||
|
||||
|
||||
ThreadState::ThreadState(Runtime* runtime, uint32_t thread_id) :
|
||||
runtime_(runtime), memory_(runtime->memory()),
|
||||
thread_id_(thread_id),
|
||||
backend_data_(0), raw_context_(0) {
|
||||
if (thread_id_ == UINT_MAX) {
|
||||
// System thread. Assign the system thread ID with a high bit
|
||||
// set so people know what's up.
|
||||
uint32_t system_thread_handle = GetCurrentThreadId();
|
||||
thread_id_ = 0x80000000 | system_thread_handle;
|
||||
}
|
||||
backend_data_ = runtime->backend()->AllocThreadData();
|
||||
}
|
||||
|
||||
ThreadState::~ThreadState() {
|
||||
if (backend_data_) {
|
||||
runtime_->backend()->FreeThreadData(backend_data_);
|
||||
}
|
||||
if (thread_state_ == this) {
|
||||
thread_state_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadState::Bind(ThreadState* thread_state) {
|
||||
thread_state_ = thread_state;
|
||||
}
|
||||
|
||||
ThreadState* ThreadState::Get() {
|
||||
return thread_state_;
|
||||
}
|
||||
|
||||
uint32_t ThreadState::GetThreadID() {
|
||||
XEASSERT(thread_state_);
|
||||
return thread_state_->thread_id_;
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_RUNTIME_THREAD_STATE_H_
|
||||
#define ALLOY_RUNTIME_THREAD_STATE_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
|
||||
#include <alloy/memory.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace runtime {
|
||||
|
||||
class Runtime;
|
||||
|
||||
|
||||
class ThreadState {
|
||||
public:
|
||||
ThreadState(Runtime* runtime, uint32_t thread_id);
|
||||
virtual ~ThreadState();
|
||||
|
||||
Runtime* runtime() const { return runtime_; }
|
||||
Memory* memory() const { return memory_; }
|
||||
uint32_t thread_id() const { return thread_id_; }
|
||||
void* backend_data() const { return backend_data_; }
|
||||
void* raw_context() const { return raw_context_; }
|
||||
|
||||
static void Bind(ThreadState* thread_state);
|
||||
static ThreadState* Get();
|
||||
static uint32_t GetThreadID();
|
||||
|
||||
protected:
|
||||
Runtime* runtime_;
|
||||
Memory* memory_;
|
||||
uint32_t thread_id_;
|
||||
void* backend_data_;
|
||||
void* raw_context_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace runtime
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_RUNTIME_THREAD_STATE_H_
|
|
@ -0,0 +1,94 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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 ALLOY_RUNTIME_TRACING_H_
|
||||
#define ALLOY_RUNTIME_TRACING_H_
|
||||
|
||||
#include <alloy/tracing/tracing.h>
|
||||
#include <alloy/tracing/event_type.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace runtime {
|
||||
|
||||
const uint32_t ALLOY_RUNTIME = alloy::tracing::EventType::ALLOY_RUNTIME;
|
||||
|
||||
|
||||
class EventType {
|
||||
public:
|
||||
enum {
|
||||
ALLOY_RUNTIME_INIT = ALLOY_RUNTIME | (1),
|
||||
ALLOY_RUNTIME_DEINIT = ALLOY_RUNTIME | (2),
|
||||
|
||||
ALLOY_RUNTIME_THREAD = ALLOY_RUNTIME | (1 << 25),
|
||||
ALLOY_RUNTIME_THREAD_INIT = ALLOY_RUNTIME_THREAD | (1),
|
||||
ALLOY_RUNTIME_THREAD_DEINIT = ALLOY_RUNTIME_THREAD | (2),
|
||||
|
||||
ALLOY_RUNTIME_MEMORY = ALLOY_RUNTIME | (2 << 25),
|
||||
ALLOY_RUNTIME_MEMORY_INIT = ALLOY_RUNTIME_MEMORY | (1),
|
||||
ALLOY_RUNTIME_MEMORY_DEINIT = ALLOY_RUNTIME_MEMORY | (2),
|
||||
ALLOY_RUNTIME_MEMORY_HEAP = ALLOY_RUNTIME_MEMORY | (1000),
|
||||
ALLOY_RUNTIME_MEMORY_HEAP_INIT = ALLOY_RUNTIME_MEMORY_HEAP | (1),
|
||||
ALLOY_RUNTIME_MEMORY_HEAP_DEINIT = ALLOY_RUNTIME_MEMORY | (2),
|
||||
ALLOY_RUNTIME_MEMORY_HEAP_ALLOC = ALLOY_RUNTIME_MEMORY | (3),
|
||||
ALLOY_RUNTIME_MEMORY_HEAP_FREE = ALLOY_RUNTIME_MEMORY | (4),
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
static const uint32_t event_type = ALLOY_RUNTIME_INIT;
|
||||
} Init;
|
||||
typedef struct {
|
||||
static const uint32_t event_type = ALLOY_RUNTIME_DEINIT;
|
||||
} Deinit;
|
||||
|
||||
typedef struct {
|
||||
static const uint32_t event_type = ALLOY_RUNTIME_THREAD_INIT;
|
||||
} ThreadInit;
|
||||
typedef struct {
|
||||
static const uint32_t event_type = ALLOY_RUNTIME_THREAD_DEINIT;
|
||||
} ThreadDeinit;
|
||||
|
||||
typedef struct {
|
||||
static const uint32_t event_type = ALLOY_RUNTIME_MEMORY_INIT;
|
||||
// map of memory, etc?
|
||||
} MemoryInit;
|
||||
typedef struct {
|
||||
static const uint32_t event_type = ALLOY_RUNTIME_MEMORY_DEINIT;
|
||||
} MemoryDeinit;
|
||||
typedef struct {
|
||||
static const uint32_t event_type = ALLOY_RUNTIME_MEMORY_HEAP_INIT;
|
||||
uint32_t heap_id;
|
||||
uint64_t low_address;
|
||||
uint64_t high_address;
|
||||
uint32_t is_physical;
|
||||
} MemoryHeapInit;
|
||||
typedef struct {
|
||||
static const uint32_t event_type = ALLOY_RUNTIME_MEMORY_HEAP_DEINIT;
|
||||
uint32_t heap_id;
|
||||
} MemoryHeapDeinit;
|
||||
typedef struct {
|
||||
static const uint32_t event_type = ALLOY_RUNTIME_MEMORY_HEAP_ALLOC;
|
||||
uint32_t heap_id;
|
||||
uint32_t flags;
|
||||
uint64_t address;
|
||||
size_t size;
|
||||
} MemoryHeapAlloc;
|
||||
typedef struct {
|
||||
static const uint32_t event_type = ALLOY_RUNTIME_MEMORY_HEAP_FREE;
|
||||
uint32_t heap_id;
|
||||
uint64_t address;
|
||||
} MemoryHeapFree;
|
||||
};
|
||||
|
||||
|
||||
} // namespace runtime
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_RUNTIME_TRACING_H_
|
|
@ -0,0 +1,46 @@
|
|||
# Copyright 2013 Ben Vanik. All Rights Reserved.
|
||||
{
|
||||
'sources': [
|
||||
'alloy-private.h',
|
||||
'alloy.h',
|
||||
'arena.cc',
|
||||
'arena.h',
|
||||
'core.h',
|
||||
'memory.cc',
|
||||
'memory.h',
|
||||
'mutex.h',
|
||||
'string_buffer.cc',
|
||||
'string_buffer.h',
|
||||
'type_pool.h',
|
||||
],
|
||||
|
||||
'conditions': [
|
||||
['OS == "mac" or OS == "linux"', {
|
||||
'sources': [
|
||||
'mutex_posix.cc',
|
||||
],
|
||||
}],
|
||||
['OS == "linux"', {
|
||||
'sources': [
|
||||
],
|
||||
}],
|
||||
['OS == "mac"', {
|
||||
'sources': [
|
||||
],
|
||||
}],
|
||||
['OS == "win"', {
|
||||
'sources': [
|
||||
'mutex_win.cc',
|
||||
],
|
||||
}],
|
||||
],
|
||||
|
||||
'includes': [
|
||||
'backend/sources.gypi',
|
||||
'compiler/sources.gypi',
|
||||
'frontend/sources.gypi',
|
||||
'hir/sources.gypi',
|
||||
'runtime/sources.gypi',
|
||||
'tracing/sources.gypi',
|
||||
],
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue