C++17ification.
C++17ification! - Filesystem interaction now uses std::filesystem::path. - Usage of const char*, std::string have been changed to std::string_view where appropriate. - Usage of printf-style functions changed to use fmt.
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
@@ -23,7 +23,7 @@ class CodeCache {
|
||||
CodeCache() = default;
|
||||
virtual ~CodeCache() = default;
|
||||
|
||||
virtual std::wstring file_name() const = 0;
|
||||
virtual const std::filesystem::path& file_name() const = 0;
|
||||
virtual uint32_t base_address() const = 0;
|
||||
virtual uint32_t total_size() const = 0;
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ project("xenia-cpu-backend-x64")
|
||||
language("C++")
|
||||
links({
|
||||
"capstone",
|
||||
"fmt",
|
||||
"xenia-base",
|
||||
"xenia-cpu",
|
||||
})
|
||||
|
||||
@@ -86,7 +86,7 @@ bool X64Assembler::Assemble(GuestFunction* function, HIRBuilder* builder,
|
||||
if (debug_info_flags & DebugInfoFlags::kDebugInfoDisasmMachineCode) {
|
||||
DumpMachineCode(machine_code, code_size, function->source_map(),
|
||||
&string_buffer_);
|
||||
debug_info->set_machine_code_disasm(string_buffer_.ToString());
|
||||
debug_info->set_machine_code_disasm(strdup(string_buffer_.buffer()));
|
||||
string_buffer_.Reset();
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ void X64Assembler::DumpMachineCode(
|
||||
if (code_offset >= next_code_offset &&
|
||||
source_map_index < source_map.size()) {
|
||||
auto& source_map_entry = source_map[source_map_index];
|
||||
str->AppendFormat("%.8X ", source_map_entry.guest_address);
|
||||
str->AppendFormat("{:08X} ", source_map_entry.guest_address);
|
||||
++source_map_index;
|
||||
next_code_offset = source_map_index < source_map.size()
|
||||
? source_map[source_map_index].code_offset
|
||||
@@ -135,7 +135,7 @@ void X64Assembler::DumpMachineCode(
|
||||
str->Append(" ");
|
||||
}
|
||||
|
||||
str->AppendFormat("%.8X %-6s %s\n", uint32_t(insn.address),
|
||||
str->AppendFormat("{:08X} {:<6} {}\n", uint32_t(insn.address),
|
||||
insn.mnemonic, insn.op_str);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2019 Ben Vanik. All rights reserved. *
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
@@ -17,6 +17,7 @@
|
||||
#pragma comment(lib, "../third_party/vtune/lib64/jitprofiling.lib")
|
||||
#endif
|
||||
|
||||
#include "third_party/fmt/include/fmt/format.h"
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/clock.h"
|
||||
#include "xenia/base/logging.h"
|
||||
@@ -61,8 +62,8 @@ bool X64CodeCache::Initialize() {
|
||||
}
|
||||
|
||||
// Create mmap file. This allows us to share the code cache with the debugger.
|
||||
file_name_ = std::wstring(L"Local\\xenia_code_cache_") +
|
||||
std::to_wstring(Clock::QueryHostTickCount());
|
||||
file_name_ =
|
||||
fmt::format("Local\\xenia_code_cache_{}", Clock::QueryHostTickCount());
|
||||
mapping_ = xe::memory::CreateFileMappingHandle(
|
||||
file_name_, kGeneratedCodeSize, xe::memory::PageAccess::kExecuteReadWrite,
|
||||
false);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2019 Ben Vanik. All rights reserved. *
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
@@ -45,7 +45,7 @@ class X64CodeCache : public CodeCache {
|
||||
|
||||
virtual bool Initialize();
|
||||
|
||||
std::wstring file_name() const override { return file_name_; }
|
||||
const std::filesystem::path& file_name() const override { return file_name_; }
|
||||
uint32_t base_address() const override { return kGeneratedCodeBase; }
|
||||
uint32_t total_size() const override { return kGeneratedCodeSize; }
|
||||
|
||||
@@ -99,7 +99,7 @@ class X64CodeCache : public CodeCache {
|
||||
const EmitFunctionInfo& func_info, void* code_address,
|
||||
UnwindReservation unwind_reservation) {}
|
||||
|
||||
std::wstring file_name_;
|
||||
std::filesystem::path file_name_;
|
||||
xe::memory::FileMappingHandle mapping_ = nullptr;
|
||||
|
||||
// NOTE: the global critical region must be held when manipulating the offsets
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2019 Ben Vanik. All rights reserved. *
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
@@ -10,9 +10,11 @@
|
||||
#include "xenia/cpu/backend/x64/x64_emitter.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <climits>
|
||||
#include <cstring>
|
||||
|
||||
#include "third_party/fmt/include/fmt/format.h"
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/atomic.h"
|
||||
#include "xenia/base/debugging.h"
|
||||
@@ -476,8 +478,8 @@ void X64Emitter::CallIndirect(const hir::Instr* instr,
|
||||
uint64_t UndefinedCallExtern(void* raw_context, uint64_t function_ptr) {
|
||||
auto function = reinterpret_cast<Function*>(function_ptr);
|
||||
if (!cvars::ignore_undefined_externs) {
|
||||
xe::FatalError("undefined extern call to %.8X %s", function->address(),
|
||||
function->name().c_str());
|
||||
xe::FatalError(fmt::format("undefined extern call to {:08X} {}",
|
||||
function->address(), function->name().c_str()));
|
||||
} else {
|
||||
XELOGE("undefined extern call to %.8X %s", function->address(),
|
||||
function->name().c_str());
|
||||
|
||||
@@ -2,13 +2,14 @@
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2014 Ben Vanik. All rights reserved. *
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/cpu/compiler/passes/finalization_pass.h"
|
||||
|
||||
#include "third_party/fmt/include/fmt/format.h"
|
||||
#include "xenia/base/profiling.h"
|
||||
#include "xenia/cpu/backend/backend.h"
|
||||
#include "xenia/cpu/compiler/compiler.h"
|
||||
@@ -43,9 +44,11 @@ bool FinalizationPass::Run(HIRBuilder* builder) {
|
||||
auto label = block->label_head;
|
||||
while (label) {
|
||||
if (!label->name) {
|
||||
const size_t label_len = 6 + 4 + 1;
|
||||
char* name = reinterpret_cast<char*>(arena->Alloc(label_len));
|
||||
snprintf(name, label_len, "_label%d", label->id);
|
||||
const size_t label_len = 6 + 4;
|
||||
char* name = reinterpret_cast<char*>(arena->Alloc(label_len + 1));
|
||||
assert_true(label->id <= 9999);
|
||||
auto end = fmt::format_to_n(name, label_len, "_label{}", label->id);
|
||||
name[end.size] = '\0';
|
||||
label->name = name;
|
||||
}
|
||||
label = label->next;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
@@ -58,7 +58,7 @@ bool ElfModule::is_executable() const {
|
||||
return hdr->e_entry != 0;
|
||||
}
|
||||
|
||||
bool ElfModule::Load(const std::string& name, const std::string& path,
|
||||
bool ElfModule::Load(const std::string_view name, const std::string_view path,
|
||||
const void* elf_addr, size_t elf_length) {
|
||||
name_ = name;
|
||||
path_ = path;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
@@ -34,7 +34,7 @@ class ElfModule : public xe::cpu::Module {
|
||||
bool is_executable() const override;
|
||||
const std::string& path() const { return path_; }
|
||||
|
||||
bool Load(const std::string& name, const std::string& path,
|
||||
bool Load(const std::string_view name, const std::string_view path,
|
||||
const void* elf_addr, size_t elf_length);
|
||||
bool Unload();
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
@@ -11,20 +11,15 @@
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/math.h"
|
||||
#include "xenia/base/string.h"
|
||||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
|
||||
ExportResolver::Table::Table(const char* module_name,
|
||||
ExportResolver::Table::Table(const std::string_view module_name,
|
||||
const std::vector<Export*>* exports_by_ordinal)
|
||||
: exports_by_ordinal_(exports_by_ordinal) {
|
||||
auto dot_pos = std::strrchr(module_name, '.');
|
||||
if (dot_pos != nullptr) {
|
||||
std::strncpy(module_name_, module_name,
|
||||
static_cast<size_t>(dot_pos - module_name));
|
||||
} else {
|
||||
std::strncpy(module_name_, module_name, xe::countof(module_name_) - 1);
|
||||
}
|
||||
module_name_ = utf8::find_base_name_from_guest_path(module_name);
|
||||
|
||||
exports_by_name_.reserve(exports_by_ordinal_->size());
|
||||
for (size_t i = 0; i < exports_by_ordinal_->size(); ++i) {
|
||||
@@ -43,7 +38,8 @@ ExportResolver::ExportResolver() = default;
|
||||
ExportResolver::~ExportResolver() = default;
|
||||
|
||||
void ExportResolver::RegisterTable(
|
||||
const char* module_name, const std::vector<xe::cpu::Export*>* exports) {
|
||||
const std::string_view module_name,
|
||||
const std::vector<xe::cpu::Export*>* exports) {
|
||||
tables_.emplace_back(module_name, exports);
|
||||
|
||||
all_exports_by_name_.reserve(all_exports_by_name_.size() + exports->size());
|
||||
@@ -58,11 +54,10 @@ void ExportResolver::RegisterTable(
|
||||
[](Export* a, Export* b) { return std::strcmp(a->name, b->name) <= 0; });
|
||||
}
|
||||
|
||||
Export* ExportResolver::GetExportByOrdinal(const char* module_name,
|
||||
Export* ExportResolver::GetExportByOrdinal(const std::string_view module_name,
|
||||
uint16_t ordinal) {
|
||||
for (const auto& table : tables_) {
|
||||
if (std::strncmp(module_name, table.module_name(),
|
||||
std::strlen(table.module_name())) == 0) {
|
||||
if (xe::utf8::starts_with_case(module_name, table.module_name())) {
|
||||
if (ordinal > table.exports_by_ordinal().size()) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -72,7 +67,7 @@ Export* ExportResolver::GetExportByOrdinal(const char* module_name,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ExportResolver::SetVariableMapping(const char* module_name,
|
||||
void ExportResolver::SetVariableMapping(const std::string_view module_name,
|
||||
uint16_t ordinal, uint32_t value) {
|
||||
auto export_entry = GetExportByOrdinal(module_name, ordinal);
|
||||
assert_not_null(export_entry);
|
||||
@@ -80,7 +75,7 @@ void ExportResolver::SetVariableMapping(const char* module_name,
|
||||
export_entry->variable_ptr = value;
|
||||
}
|
||||
|
||||
void ExportResolver::SetFunctionMapping(const char* module_name,
|
||||
void ExportResolver::SetFunctionMapping(const std::string_view module_name,
|
||||
uint16_t ordinal,
|
||||
xe_kernel_export_shim_fn shim) {
|
||||
auto export_entry = GetExportByOrdinal(module_name, ordinal);
|
||||
@@ -89,7 +84,7 @@ void ExportResolver::SetFunctionMapping(const char* module_name,
|
||||
export_entry->function_data.shim = shim;
|
||||
}
|
||||
|
||||
void ExportResolver::SetFunctionMapping(const char* module_name,
|
||||
void ExportResolver::SetFunctionMapping(const std::string_view module_name,
|
||||
uint16_t ordinal,
|
||||
ExportTrampoline trampoline) {
|
||||
auto export_entry = GetExportByOrdinal(module_name, ordinal);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2019 Ben Vanik. All rights reserved. *
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
@@ -117,9 +117,10 @@ class ExportResolver {
|
||||
public:
|
||||
class Table {
|
||||
public:
|
||||
Table(const char* module_name, const std::vector<Export*>* exports);
|
||||
Table(const std::string_view module_name,
|
||||
const std::vector<Export*>* exports);
|
||||
|
||||
const char* module_name() const { return module_name_; }
|
||||
const std::string& module_name() const { return module_name_; }
|
||||
const std::vector<Export*>& exports_by_ordinal() const {
|
||||
return *exports_by_ordinal_;
|
||||
}
|
||||
@@ -128,7 +129,7 @@ class ExportResolver {
|
||||
}
|
||||
|
||||
private:
|
||||
char module_name_[32] = {0};
|
||||
std::string module_name_;
|
||||
const std::vector<Export*>* exports_by_ordinal_ = nullptr;
|
||||
std::vector<Export*> exports_by_name_;
|
||||
};
|
||||
@@ -136,20 +137,21 @@ class ExportResolver {
|
||||
ExportResolver();
|
||||
~ExportResolver();
|
||||
|
||||
void RegisterTable(const char* module_name,
|
||||
void RegisterTable(const std::string_view module_name,
|
||||
const std::vector<Export*>* exports);
|
||||
const std::vector<Table>& tables() const { return tables_; }
|
||||
const std::vector<Export*>& all_exports_by_name() const {
|
||||
return all_exports_by_name_;
|
||||
}
|
||||
|
||||
Export* GetExportByOrdinal(const char* module_name, uint16_t ordinal);
|
||||
Export* GetExportByOrdinal(const std::string_view module_name,
|
||||
uint16_t ordinal);
|
||||
|
||||
void SetVariableMapping(const char* module_name, uint16_t ordinal,
|
||||
void SetVariableMapping(const std::string_view module_name, uint16_t ordinal,
|
||||
uint32_t value);
|
||||
void SetFunctionMapping(const char* module_name, uint16_t ordinal,
|
||||
void SetFunctionMapping(const std::string_view module_name, uint16_t ordinal,
|
||||
xe_kernel_export_shim_fn shim);
|
||||
void SetFunctionMapping(const char* module_name, uint16_t ordinal,
|
||||
void SetFunctionMapping(const std::string_view module_name, uint16_t ordinal,
|
||||
ExportTrampoline trampoline);
|
||||
|
||||
private:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
@@ -110,25 +110,25 @@ void HIRBuilder::DumpValue(StringBuffer* str, Value* value) {
|
||||
if (value->IsConstant()) {
|
||||
switch (value->type) {
|
||||
case INT8_TYPE:
|
||||
str->AppendFormat("%X", value->constant.i8);
|
||||
str->AppendFormat("{:X}", value->constant.i8);
|
||||
break;
|
||||
case INT16_TYPE:
|
||||
str->AppendFormat("%X", value->constant.i16);
|
||||
str->AppendFormat("{:X}", value->constant.i16);
|
||||
break;
|
||||
case INT32_TYPE:
|
||||
str->AppendFormat("%X", value->constant.i32);
|
||||
str->AppendFormat("{:X}", value->constant.i32);
|
||||
break;
|
||||
case INT64_TYPE:
|
||||
str->AppendFormat("%" PRIX64, value->constant.i64);
|
||||
str->AppendFormat("{:X}", value->constant.i64);
|
||||
break;
|
||||
case FLOAT32_TYPE:
|
||||
str->AppendFormat("%F", value->constant.f32);
|
||||
str->AppendFormat("{:F}", value->constant.f32);
|
||||
break;
|
||||
case FLOAT64_TYPE:
|
||||
str->AppendFormat("%F", value->constant.f64);
|
||||
str->AppendFormat("{:F}", value->constant.f64);
|
||||
break;
|
||||
case VEC128_TYPE:
|
||||
str->AppendFormat("(%F,%F,%F,%F)", value->constant.v128.x,
|
||||
str->AppendFormat("({:F},{:F},{:F},{:F})", value->constant.v128.x,
|
||||
value->constant.v128.y, value->constant.v128.z,
|
||||
value->constant.v128.w);
|
||||
break;
|
||||
@@ -140,10 +140,10 @@ void HIRBuilder::DumpValue(StringBuffer* str, Value* value) {
|
||||
static const char* type_names[] = {
|
||||
"i8", "i16", "i32", "i64", "f32", "f64", "v128",
|
||||
};
|
||||
str->AppendFormat("v%d.%s", value->ordinal, type_names[value->type]);
|
||||
str->AppendFormat("v{}.{}", value->ordinal, type_names[value->type]);
|
||||
}
|
||||
if (value->reg.index != -1) {
|
||||
str->AppendFormat("<%s%d>", value->reg.set->name, value->reg.index);
|
||||
str->AppendFormat("<{}{}>", value->reg.set->name, value->reg.index);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,11 +156,11 @@ void HIRBuilder::DumpOp(StringBuffer* str, OpcodeSignatureType sig_type,
|
||||
if (op->label->name) {
|
||||
str->Append(op->label->name);
|
||||
} else {
|
||||
str->AppendFormat("label%d", op->label->id);
|
||||
str->AppendFormat("label{}", op->label->id);
|
||||
}
|
||||
break;
|
||||
case OPCODE_SIG_TYPE_O:
|
||||
str->AppendFormat("+%lld", op->offset);
|
||||
str->AppendFormat("+{}", op->offset);
|
||||
break;
|
||||
case OPCODE_SIG_TYPE_S:
|
||||
if (true) {
|
||||
@@ -176,7 +176,7 @@ void HIRBuilder::DumpOp(StringBuffer* str, OpcodeSignatureType sig_type,
|
||||
|
||||
void HIRBuilder::Dump(StringBuffer* str) {
|
||||
if (attributes_) {
|
||||
str->AppendFormat("; attributes = %.8X\n", attributes_);
|
||||
str->AppendFormat("; attributes = {:08X}\n", attributes_);
|
||||
}
|
||||
|
||||
for (auto it = locals_.begin(); it != locals_.end(); ++it) {
|
||||
@@ -192,16 +192,16 @@ void HIRBuilder::Dump(StringBuffer* str) {
|
||||
if (block == block_head_) {
|
||||
str->Append("<entry>:\n");
|
||||
} else if (!block->label_head) {
|
||||
str->AppendFormat("<block%d>:\n", block_ordinal);
|
||||
str->AppendFormat("<block{}>:\n", block_ordinal);
|
||||
}
|
||||
block_ordinal++;
|
||||
|
||||
Label* label = block->label_head;
|
||||
while (label) {
|
||||
if (label->name) {
|
||||
str->AppendFormat("%s:\n", label->name);
|
||||
str->AppendFormat("{}:\n", label->name);
|
||||
} else {
|
||||
str->AppendFormat("label%d:\n", label->id);
|
||||
str->AppendFormat("label{}:\n", label->id);
|
||||
}
|
||||
label = label->next;
|
||||
}
|
||||
@@ -210,13 +210,13 @@ void HIRBuilder::Dump(StringBuffer* str) {
|
||||
while (incoming_edge) {
|
||||
auto src_label = incoming_edge->src->label_head;
|
||||
if (src_label && src_label->name) {
|
||||
str->AppendFormat(" ; in: %s", src_label->name);
|
||||
str->AppendFormat(" ; in: {}", src_label->name);
|
||||
} else if (src_label) {
|
||||
str->AppendFormat(" ; in: label%d", src_label->id);
|
||||
str->AppendFormat(" ; in: label{}", src_label->id);
|
||||
} else {
|
||||
str->AppendFormat(" ; in: <block%d>", incoming_edge->src->ordinal);
|
||||
str->AppendFormat(" ; in: <block{}>", incoming_edge->src->ordinal);
|
||||
}
|
||||
str->AppendFormat(", dom:%d, uncond:%d\n",
|
||||
str->AppendFormat(", dom:{}, uncond:{}\n",
|
||||
(incoming_edge->flags & Edge::DOMINATES) ? 1 : 0,
|
||||
(incoming_edge->flags & Edge::UNCONDITIONAL) ? 1 : 0);
|
||||
incoming_edge = incoming_edge->incoming_next;
|
||||
@@ -225,13 +225,13 @@ void HIRBuilder::Dump(StringBuffer* str) {
|
||||
while (outgoing_edge) {
|
||||
auto dest_label = outgoing_edge->dest->label_head;
|
||||
if (dest_label && dest_label->name) {
|
||||
str->AppendFormat(" ; out: %s", dest_label->name);
|
||||
str->AppendFormat(" ; out: {}", dest_label->name);
|
||||
} else if (dest_label) {
|
||||
str->AppendFormat(" ; out: label%d", dest_label->id);
|
||||
str->AppendFormat(" ; out: label{}", dest_label->id);
|
||||
} else {
|
||||
str->AppendFormat(" ; out: <block%d>", outgoing_edge->dest->ordinal);
|
||||
str->AppendFormat(" ; out: <block{}>", outgoing_edge->dest->ordinal);
|
||||
}
|
||||
str->AppendFormat(", dom:%d, uncond:%d\n",
|
||||
str->AppendFormat(", dom:{}, uncond:{}\n",
|
||||
(outgoing_edge->flags & Edge::DOMINATES) ? 1 : 0,
|
||||
(outgoing_edge->flags & Edge::UNCONDITIONAL) ? 1 : 0);
|
||||
outgoing_edge = outgoing_edge->outgoing_next;
|
||||
@@ -244,7 +244,7 @@ void HIRBuilder::Dump(StringBuffer* str) {
|
||||
continue;
|
||||
}
|
||||
if (i->opcode == &OPCODE_COMMENT_info) {
|
||||
str->AppendFormat(" ; %s\n", reinterpret_cast<char*>(i->src1.offset));
|
||||
str->AppendFormat(" ; {}\n", reinterpret_cast<char*>(i->src1.offset));
|
||||
i = i->next;
|
||||
continue;
|
||||
}
|
||||
@@ -260,7 +260,7 @@ void HIRBuilder::Dump(StringBuffer* str) {
|
||||
str->Append(" = ");
|
||||
}
|
||||
if (i->flags) {
|
||||
str->AppendFormat("%s.%d", info->name, i->flags);
|
||||
str->AppendFormat("{}.{}", info->name, i->flags);
|
||||
} else {
|
||||
str->Append(info->name);
|
||||
}
|
||||
@@ -734,13 +734,14 @@ Value* HIRBuilder::CloneValue(Value* source) {
|
||||
return value;
|
||||
}
|
||||
|
||||
void HIRBuilder::Comment(const char* value) {
|
||||
size_t length = std::strlen(value);
|
||||
if (!length) {
|
||||
void HIRBuilder::Comment(std::string_view value) {
|
||||
if (value.empty()) {
|
||||
return;
|
||||
}
|
||||
void* p = arena_->Alloc(length + 1);
|
||||
std::memcpy(p, value, length + 1);
|
||||
auto size = value.size();
|
||||
auto p = reinterpret_cast<char*>(arena_->Alloc(size + 1));
|
||||
std::memcpy(p, value.data(), size);
|
||||
p[size] = '\0';
|
||||
Instr* i = AppendInstr(OPCODE_COMMENT_info, 0);
|
||||
i->src1.offset = (uint64_t)p;
|
||||
i->src2.value = i->src3.value = NULL;
|
||||
@@ -750,22 +751,16 @@ void HIRBuilder::Comment(const StringBuffer& value) {
|
||||
if (!value.length()) {
|
||||
return;
|
||||
}
|
||||
void* p = arena_->Alloc(value.length() + 1);
|
||||
std::memcpy(p, value.GetString(), value.length() + 1);
|
||||
auto size = value.length();
|
||||
auto p = reinterpret_cast<char*>(arena_->Alloc(size + 1));
|
||||
std::memcpy(p, value.buffer(), size);
|
||||
p[size] = '\0';
|
||||
Instr* i = AppendInstr(OPCODE_COMMENT_info, 0);
|
||||
i->src1.offset = (uint64_t)p;
|
||||
i->src2.value = i->src3.value = NULL;
|
||||
}
|
||||
|
||||
void HIRBuilder::CommentFormat(const char* format, ...) {
|
||||
static const uint32_t kMaxCommentSize = 1024;
|
||||
char* p = reinterpret_cast<char*>(arena_->Alloc(kMaxCommentSize));
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
size_t chars_written = vsnprintf(p, kMaxCommentSize - 1, format, args);
|
||||
va_end(args);
|
||||
size_t rewind = kMaxCommentSize - chars_written - 1;
|
||||
arena_->Rewind(rewind);
|
||||
void HIRBuilder::CommentBuffer(const char* p) {
|
||||
Instr* i = AppendInstr(OPCODE_COMMENT_info, 0);
|
||||
i->src1.offset = (uint64_t)p;
|
||||
i->src2.value = i->src3.value = NULL;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "third_party/fmt/include/fmt/format.h"
|
||||
#include "xenia/base/arena.h"
|
||||
#include "xenia/base/string_buffer.h"
|
||||
#include "xenia/cpu/hir/block.h"
|
||||
@@ -68,9 +69,19 @@ class HIRBuilder {
|
||||
// static allocations:
|
||||
// Value* AllocStatic(size_t length);
|
||||
|
||||
void Comment(const char* value);
|
||||
void Comment(const std::string_view value);
|
||||
void Comment(const StringBuffer& value);
|
||||
void CommentFormat(const char* format, ...);
|
||||
|
||||
template <typename... Args>
|
||||
void CommentFormat(const std::string_view format, const Args&... args) {
|
||||
static const uint32_t kMaxCommentSize = 1024;
|
||||
char* p = reinterpret_cast<char*>(arena_->Alloc(kMaxCommentSize));
|
||||
auto result = fmt::format_to_n(p, kMaxCommentSize - 1, format, args...);
|
||||
p[result.size] = '\0';
|
||||
size_t rewind = kMaxCommentSize - 1 - result.size;
|
||||
arena_->Rewind(rewind);
|
||||
CommentBuffer(p);
|
||||
}
|
||||
|
||||
void Nop();
|
||||
|
||||
@@ -261,6 +272,7 @@ class HIRBuilder {
|
||||
void EndBlock();
|
||||
bool IsUnconditionalJump(Instr* instr);
|
||||
Instr* AppendInstr(const OpcodeInfo& opcode, uint16_t flags, Value* dest = 0);
|
||||
void CommentBuffer(const char* p);
|
||||
Value* CompareXX(const OpcodeInfo& opcode, Value* value1, Value* value2);
|
||||
Value* VectorCompareXX(const OpcodeInfo& opcode, Value* value1, Value* value2,
|
||||
TypeName part_type);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
@@ -143,13 +143,12 @@ void PPCContext::SetRegFromString(const char* name, const char* value) {
|
||||
}
|
||||
|
||||
bool PPCContext::CompareRegWithString(const char* name, const char* value,
|
||||
char* out_value,
|
||||
size_t out_value_size) const {
|
||||
std::string& result) const {
|
||||
int n;
|
||||
if (sscanf(name, "r%d", &n) == 1) {
|
||||
uint64_t expected = string_util::from_string<uint64_t>(value);
|
||||
if (this->r[n] != expected) {
|
||||
std::snprintf(out_value, out_value_size, "%016" PRIX64, this->r[n]);
|
||||
result = fmt::format("{:016X}", this->r[n]);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -157,23 +156,17 @@ bool PPCContext::CompareRegWithString(const char* name, const char* value,
|
||||
if (std::strstr(value, "0x")) {
|
||||
// Special case: Treat float as integer.
|
||||
uint64_t expected = string_util::from_string<uint64_t>(value, true);
|
||||
|
||||
union {
|
||||
double f;
|
||||
uint64_t u;
|
||||
} f2u;
|
||||
f2u.f = this->f[n];
|
||||
|
||||
if (f2u.u != expected) {
|
||||
std::snprintf(out_value, out_value_size, "%016" PRIX64, f2u.u);
|
||||
uint64_t pun;
|
||||
std::memcpy(&pun, &this->f[n], sizeof(pun));
|
||||
if (pun != expected) {
|
||||
result = fmt::format("{:016X}", pun);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
double expected = string_util::from_string<double>(value);
|
||||
|
||||
// TODO(benvanik): epsilon
|
||||
if (this->f[n] != expected) {
|
||||
std::snprintf(out_value, out_value_size, "%f", this->f[n]);
|
||||
result = fmt::format("{:.17f}", this->f[n]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -181,9 +174,9 @@ bool PPCContext::CompareRegWithString(const char* name, const char* value,
|
||||
} else if (sscanf(name, "v%d", &n) == 1) {
|
||||
vec128_t expected = string_util::from_string<vec128_t>(value);
|
||||
if (this->v[n] != expected) {
|
||||
std::snprintf(out_value, out_value_size, "[%.8X, %.8X, %.8X, %.8X]",
|
||||
this->v[n].i32[0], this->v[n].i32[1], this->v[n].i32[2],
|
||||
this->v[n].i32[3]);
|
||||
result =
|
||||
fmt::format("[{:08X}, {:08X}, {:08X}, {:08X}]", this->v[n].i32[0],
|
||||
this->v[n].i32[1], this->v[n].i32[2], this->v[n].i32[3]);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -191,7 +184,7 @@ bool PPCContext::CompareRegWithString(const char* name, const char* value,
|
||||
uint64_t actual = this->cr();
|
||||
uint64_t expected = string_util::from_string<uint64_t>(value);
|
||||
if (actual != expected) {
|
||||
std::snprintf(out_value, out_value_size, "%016" PRIX64, actual);
|
||||
result = fmt::format("{:016X}", actual);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
@@ -432,7 +432,7 @@ typedef struct PPCContext_s {
|
||||
|
||||
void SetRegFromString(const char* name, const char* value);
|
||||
bool CompareRegWithString(const char* name, const char* value,
|
||||
char* out_value, size_t out_value_size) const;
|
||||
std::string& result) const;
|
||||
} PPCContext;
|
||||
#pragma pack(pop)
|
||||
static_assert(sizeof(PPCContext) % 64 == 0, "64b padded");
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
@@ -12,6 +12,8 @@
|
||||
#include <stddef.h>
|
||||
#include <cstring>
|
||||
|
||||
#include "third_party/fmt/include/fmt/format.h"
|
||||
|
||||
#include "xenia/base/byte_order.h"
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/base/memory.h"
|
||||
@@ -48,10 +50,10 @@ void DumpAllOpcodeCounts() {
|
||||
auto& disasm_info = GetOpcodeDisasmInfo(opcode);
|
||||
auto translation_count = opcode_translation_counts[i];
|
||||
if (translation_count) {
|
||||
sb.AppendFormat("%8d : %s\n", translation_count, disasm_info.name);
|
||||
sb.AppendFormat("{:8d} : {}\n", translation_count, disasm_info.name);
|
||||
}
|
||||
}
|
||||
fprintf(stdout, "%s", sb.GetString());
|
||||
fprintf(stdout, "%s", sb.to_string().c_str());
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
@@ -83,7 +85,7 @@ bool PPCHIRBuilder::Emit(GuestFunction* function, uint32_t flags) {
|
||||
|
||||
with_debug_info_ = (flags & EMIT_DEBUG_COMMENTS) == EMIT_DEBUG_COMMENTS;
|
||||
if (with_debug_info_) {
|
||||
CommentFormat("%s fn %.8X-%.8X %s", function_->module()->name().c_str(),
|
||||
CommentFormat("{} fn {:08X}-{:08X} {}", function_->module()->name().c_str(),
|
||||
function_->address(), function_->end_address(),
|
||||
function_->name().c_str());
|
||||
}
|
||||
@@ -127,7 +129,7 @@ bool PPCHIRBuilder::Emit(GuestFunction* function, uint32_t flags) {
|
||||
AnnotateLabel(address, label);
|
||||
}
|
||||
comment_buffer_.Reset();
|
||||
comment_buffer_.AppendFormat("%.8X %.8X ", address, code);
|
||||
comment_buffer_.AppendFormat("{:08X} {:08X} ", address, code);
|
||||
DisasmPPC(address, code, &comment_buffer_);
|
||||
Comment(comment_buffer_);
|
||||
first_instr = last_instr();
|
||||
@@ -229,7 +231,8 @@ void PPCHIRBuilder::MaybeBreakOnInstruction(uint32_t address) {
|
||||
|
||||
void PPCHIRBuilder::AnnotateLabel(uint32_t address, Label* label) {
|
||||
char name_buffer[13];
|
||||
snprintf(name_buffer, xe::countof(name_buffer), "loc_%.8X", address);
|
||||
auto format_result = fmt::format_to_n(name_buffer, 12, "loc_{:08X}", address);
|
||||
name_buffer[format_result.size] = '\0';
|
||||
label->name = (char*)arena_->Alloc(sizeof(name_buffer));
|
||||
memcpy(label->name, name_buffer, sizeof(name_buffer));
|
||||
}
|
||||
|
||||
@@ -148,9 +148,9 @@ void PrintDisasm_bcx(const PPCDecodeData& d, StringBuffer* str) {
|
||||
if (d.B.LK()) str->Append('l');
|
||||
if (d.B.AA()) str->Append('a');
|
||||
PadStringBuffer(str, str_start, kNamePad);
|
||||
str->AppendFormat("%d", bo);
|
||||
str->AppendFormat("{}", bo);
|
||||
str->Append(", ");
|
||||
str->AppendFormat("%d", bi);
|
||||
str->AppendFormat("{}", bi);
|
||||
} else {
|
||||
if (d.B.LK()) str->Append('l');
|
||||
if (d.B.AA()) str->Append('a');
|
||||
@@ -162,11 +162,11 @@ void PrintDisasm_bcx(const PPCDecodeData& d, StringBuffer* str) {
|
||||
}
|
||||
|
||||
PadStringBuffer(str, str_start, kNamePad);
|
||||
str->AppendFormat("crf%d", bi / 4);
|
||||
str->AppendFormat("crf{}", bi / 4);
|
||||
}
|
||||
|
||||
str->Append(", ");
|
||||
str->AppendFormat("0x%X", addr);
|
||||
str->AppendFormat("0x{:X}", addr);
|
||||
}
|
||||
|
||||
} // namespace ppc
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -28,7 +28,7 @@ bool DisasmPPC(uint32_t address, uint32_t code, StringBuffer* str) {
|
||||
d.code = code;
|
||||
disasm_info.disasm(d, str);
|
||||
} else {
|
||||
str->AppendFormat("%-8s", disasm_info.name);
|
||||
str->AppendFormat("{:<8}", disasm_info.name);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -155,7 +155,7 @@ bool PPCTranslator::Translate(GuestFunction* function,
|
||||
// Stash source.
|
||||
if (debug_info_flags & DebugInfoFlags::kDebugInfoDisasmSource) {
|
||||
DumpSource(function, &string_buffer_);
|
||||
debug_info->set_source_disasm(string_buffer_.ToString());
|
||||
debug_info->set_source_disasm(strdup(string_buffer_.buffer()));
|
||||
string_buffer_.Reset();
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ bool PPCTranslator::Translate(GuestFunction* function,
|
||||
// Stash raw HIR.
|
||||
if (debug_info_flags & DebugInfoFlags::kDebugInfoDisasmRawHir) {
|
||||
builder_->Dump(&string_buffer_);
|
||||
debug_info->set_raw_hir_disasm(string_buffer_.ToString());
|
||||
debug_info->set_raw_hir_disasm(strdup(string_buffer_.buffer()));
|
||||
string_buffer_.Reset();
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ bool PPCTranslator::Translate(GuestFunction* function,
|
||||
// Stash optimized HIR.
|
||||
if (debug_info_flags & DebugInfoFlags::kDebugInfoDisasmHir) {
|
||||
builder_->Dump(&string_buffer_);
|
||||
debug_info->set_hir_disasm(string_buffer_.ToString());
|
||||
debug_info->set_hir_disasm(strdup(string_buffer_.buffer()));
|
||||
string_buffer_.Reset();
|
||||
}
|
||||
|
||||
@@ -201,7 +201,7 @@ void PPCTranslator::DumpSource(GuestFunction* function,
|
||||
Memory* memory = frontend_->memory();
|
||||
|
||||
string_buffer->AppendFormat(
|
||||
"%s fn %.8X-%.8X %s\n", function->module()->name().c_str(),
|
||||
"{} fn {:08X}-{:08X} {}\n", function->module()->name().c_str(),
|
||||
function->address(), function->end_address(), function->name().c_str());
|
||||
|
||||
auto blocks = scanner_->FindBlocks(function);
|
||||
@@ -216,12 +216,12 @@ void PPCTranslator::DumpSource(GuestFunction* function,
|
||||
|
||||
// Check labels.
|
||||
if (block_it != blocks.end() && block_it->start_address == address) {
|
||||
string_buffer->AppendFormat("%.8X loc_%.8X:\n", address,
|
||||
string_buffer->AppendFormat("{:08X} loc_{:08X}:\n", address,
|
||||
address);
|
||||
++block_it;
|
||||
}
|
||||
|
||||
string_buffer->AppendFormat("%.8X %.8X ", address, code);
|
||||
string_buffer->AppendFormat("{:08X} {:08X} ", address, code);
|
||||
DisasmPPC(address, code, string_buffer);
|
||||
string_buffer->Append('\n');
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2019 Ben Vanik. All rights reserved. *
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
@@ -23,10 +23,10 @@
|
||||
#include "xenia/base/platform_win.h"
|
||||
#endif // XE_COMPILER_MSVC
|
||||
|
||||
DEFINE_string(test_path, "src/xenia/cpu/ppc/testing/",
|
||||
"Directory scanned for test files.", "Other");
|
||||
DEFINE_string(test_bin_path, "src/xenia/cpu/ppc/testing/bin/",
|
||||
"Directory with binary outputs of the test files.", "Other");
|
||||
DEFINE_path(test_path, "src/xenia/cpu/ppc/testing/",
|
||||
"Directory scanned for test files.", "Other");
|
||||
DEFINE_path(test_bin_path, "src/xenia/cpu/ppc/testing/bin/",
|
||||
"Directory with binary outputs of the test files.", "Other");
|
||||
DEFINE_transient_string(test_name, "", "Specifies test name.", "General");
|
||||
|
||||
namespace xe {
|
||||
@@ -49,43 +49,45 @@ struct TestCase {
|
||||
|
||||
class TestSuite {
|
||||
public:
|
||||
TestSuite(const std::wstring& src_file_path) : src_file_path(src_file_path) {
|
||||
name = src_file_path.substr(src_file_path.find_last_of(xe::kPathSeparator) +
|
||||
1);
|
||||
name = ReplaceExtension(name, L"");
|
||||
map_file_path = xe::to_wstring(cvars::test_bin_path) + name + L".map";
|
||||
bin_file_path = xe::to_wstring(cvars::test_bin_path) + name + L".bin";
|
||||
TestSuite(const std::filesystem::path& src_file_path)
|
||||
: src_file_path_(src_file_path) {
|
||||
auto name = src_file_path.filename();
|
||||
name = name.replace_extension();
|
||||
|
||||
name_ = xe::path_to_utf8(name);
|
||||
map_file_path_ = cvars::test_bin_path / name.replace_extension(".map");
|
||||
bin_file_path_ = cvars::test_bin_path / name.replace_extension(".bin");
|
||||
}
|
||||
|
||||
bool Load() {
|
||||
if (!ReadMap(map_file_path)) {
|
||||
XELOGE("Unable to read map for test %ls", src_file_path.c_str());
|
||||
if (!ReadMap()) {
|
||||
XELOGE("Unable to read map for test %s",
|
||||
xe::path_to_utf8(src_file_path_).c_str());
|
||||
return false;
|
||||
}
|
||||
if (!ReadAnnotations(src_file_path)) {
|
||||
XELOGE("Unable to read annotations for test %ls", src_file_path.c_str());
|
||||
if (!ReadAnnotations()) {
|
||||
XELOGE("Unable to read annotations for test %s",
|
||||
xe::path_to_utf8(src_file_path_).c_str());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::wstring name;
|
||||
std::wstring src_file_path;
|
||||
std::wstring map_file_path;
|
||||
std::wstring bin_file_path;
|
||||
std::vector<TestCase> test_cases;
|
||||
const std::string& name() const { return name_; }
|
||||
const std::filesystem::path& src_file_path() const { return src_file_path_; }
|
||||
const std::filesystem::path& map_file_path() const { return map_file_path_; }
|
||||
const std::filesystem::path& bin_file_path() const { return bin_file_path_; }
|
||||
std::vector<TestCase>& test_cases() { return test_cases_; }
|
||||
|
||||
private:
|
||||
std::wstring ReplaceExtension(const std::wstring& path,
|
||||
const std::wstring& new_extension) {
|
||||
std::wstring result = path;
|
||||
auto last_dot = result.find_last_of('.');
|
||||
result.replace(result.begin() + last_dot, result.end(), new_extension);
|
||||
return result;
|
||||
}
|
||||
std::string name_;
|
||||
std::filesystem::path src_file_path_;
|
||||
std::filesystem::path map_file_path_;
|
||||
std::filesystem::path bin_file_path_;
|
||||
std::vector<TestCase> test_cases_;
|
||||
|
||||
TestCase* FindTestCase(const std::string& name) {
|
||||
for (auto& test_case : test_cases) {
|
||||
TestCase* FindTestCase(const std::string_view name) {
|
||||
for (auto& test_case : test_cases_) {
|
||||
if (test_case.name == name) {
|
||||
return &test_case;
|
||||
}
|
||||
@@ -93,8 +95,8 @@ class TestSuite {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool ReadMap(const std::wstring& map_file_path) {
|
||||
FILE* f = fopen(xe::to_string(map_file_path).c_str(), "r");
|
||||
bool ReadMap() {
|
||||
FILE* f = filesystem::OpenFile(map_file_path_, "r");
|
||||
if (!f) {
|
||||
return false;
|
||||
}
|
||||
@@ -114,15 +116,16 @@ class TestSuite {
|
||||
}
|
||||
std::string address(line_buffer, t_test_ - line_buffer);
|
||||
std::string name(t_test_ + strlen(" t test_"));
|
||||
test_cases.emplace_back(START_ADDRESS + std::stoul(address, 0, 16), name);
|
||||
test_cases_.emplace_back(START_ADDRESS + std::stoul(address, 0, 16),
|
||||
name);
|
||||
}
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReadAnnotations(const std::wstring& src_file_path) {
|
||||
bool ReadAnnotations() {
|
||||
TestCase* current_test_case = nullptr;
|
||||
FILE* f = fopen(xe::to_string(src_file_path).c_str(), "r");
|
||||
FILE* f = filesystem::OpenFile(src_file_path_, "r");
|
||||
if (!f) {
|
||||
return false;
|
||||
}
|
||||
@@ -141,8 +144,8 @@ class TestSuite {
|
||||
std::string label(start + strlen("test_"), strchr(start, ':'));
|
||||
current_test_case = FindTestCase(label);
|
||||
if (!current_test_case) {
|
||||
XELOGE("Test case %s not found in corresponding map for %ls",
|
||||
label.c_str(), src_file_path.c_str());
|
||||
XELOGE("Test case %s not found in corresponding map for %s",
|
||||
label.c_str(), xe::path_to_utf8(src_file_path_).c_str());
|
||||
return false;
|
||||
}
|
||||
} else if (strlen(start) > 3 && start[0] == '#' && start[1] == '_') {
|
||||
@@ -157,8 +160,8 @@ class TestSuite {
|
||||
value.erase(value.end() - 1);
|
||||
}
|
||||
if (!current_test_case) {
|
||||
XELOGE("Annotation outside of test case in %ls",
|
||||
src_file_path.c_str());
|
||||
XELOGE("Annotation outside of test case in %s",
|
||||
xe::path_to_utf8(src_file_path_).c_str());
|
||||
return false;
|
||||
}
|
||||
current_test_case->annotations.emplace_back(key, value);
|
||||
@@ -172,21 +175,20 @@ class TestSuite {
|
||||
|
||||
class TestRunner {
|
||||
public:
|
||||
TestRunner() {
|
||||
memory_size = 64 * 1024 * 1024;
|
||||
memory.reset(new Memory());
|
||||
memory->Initialize();
|
||||
TestRunner() : memory_size_(64 * 1024 * 1024) {
|
||||
memory_.reset(new Memory());
|
||||
memory_->Initialize();
|
||||
}
|
||||
|
||||
~TestRunner() {
|
||||
thread_state.reset();
|
||||
processor.reset();
|
||||
memory.reset();
|
||||
thread_state_.reset();
|
||||
processor_.reset();
|
||||
memory_.reset();
|
||||
}
|
||||
|
||||
bool Setup(TestSuite& suite) {
|
||||
// Reset memory.
|
||||
memory->Reset();
|
||||
memory_->Reset();
|
||||
|
||||
std::unique_ptr<xe::cpu::backend::Backend> backend;
|
||||
if (!backend) {
|
||||
@@ -205,23 +207,24 @@ class TestRunner {
|
||||
}
|
||||
|
||||
// Setup a fresh processor.
|
||||
processor.reset(new Processor(memory.get(), nullptr));
|
||||
processor->Setup(std::move(backend));
|
||||
processor->set_debug_info_flags(DebugInfoFlags::kDebugInfoAll);
|
||||
processor_.reset(new Processor(memory_.get(), nullptr));
|
||||
processor_->Setup(std::move(backend));
|
||||
processor_->set_debug_info_flags(DebugInfoFlags::kDebugInfoAll);
|
||||
|
||||
// Load the binary module.
|
||||
auto module = std::make_unique<xe::cpu::RawModule>(processor.get());
|
||||
if (!module->LoadFile(START_ADDRESS, suite.bin_file_path)) {
|
||||
XELOGE("Unable to load test binary %ls", suite.bin_file_path.c_str());
|
||||
auto module = std::make_unique<xe::cpu::RawModule>(processor_.get());
|
||||
if (!module->LoadFile(START_ADDRESS, suite.bin_file_path())) {
|
||||
XELOGE("Unable to load test binary %s",
|
||||
xe::path_to_utf8(suite.bin_file_path).c_str());
|
||||
return false;
|
||||
}
|
||||
processor->AddModule(std::move(module));
|
||||
processor_->AddModule(std::move(module));
|
||||
|
||||
processor->backend()->CommitExecutableRange(START_ADDRESS,
|
||||
START_ADDRESS + 1024 * 1024);
|
||||
processor_->backend()->CommitExecutableRange(START_ADDRESS,
|
||||
START_ADDRESS + 1024 * 1024);
|
||||
|
||||
// Add dummy space for memory.
|
||||
processor->memory()->LookupHeap(0)->AllocFixed(
|
||||
processor_->memory()->LookupHeap(0)->AllocFixed(
|
||||
0x10001000, 0xEFFF, 0,
|
||||
kMemoryAllocationReserve | kMemoryAllocationCommit,
|
||||
kMemoryProtectRead | kMemoryProtectWrite);
|
||||
@@ -230,8 +233,8 @@ class TestRunner {
|
||||
uint32_t stack_size = 64 * 1024;
|
||||
uint32_t stack_address = START_ADDRESS - stack_size;
|
||||
uint32_t pcr_address = stack_address - 0x1000;
|
||||
thread_state.reset(
|
||||
new ThreadState(processor.get(), 0x100, stack_address, pcr_address));
|
||||
thread_state_.reset(
|
||||
new ThreadState(processor_.get(), 0x100, stack_address, pcr_address));
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -244,15 +247,15 @@ class TestRunner {
|
||||
}
|
||||
|
||||
// Execute test.
|
||||
auto fn = processor->ResolveFunction(test_case.address);
|
||||
auto fn = processor_->ResolveFunction(test_case.address);
|
||||
if (!fn) {
|
||||
XELOGE("Entry function not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto ctx = thread_state->context();
|
||||
auto ctx = thread_state_->context();
|
||||
ctx->lr = 0xBCBCBCBC;
|
||||
fn->Call(thread_state.get(), uint32_t(ctx->lr));
|
||||
fn->Call(thread_state_.get(), uint32_t(ctx->lr));
|
||||
|
||||
// Assert test state expectations.
|
||||
bool result = CheckTestResults(test_case);
|
||||
@@ -267,7 +270,7 @@ class TestRunner {
|
||||
}
|
||||
|
||||
bool SetupTestState(TestCase& test_case) {
|
||||
auto ppc_context = thread_state->context();
|
||||
auto ppc_context = thread_state_->context();
|
||||
for (auto& it : test_case.annotations) {
|
||||
if (it.first == "REGISTER_IN") {
|
||||
size_t space_pos = it.second.find(" ");
|
||||
@@ -279,7 +282,7 @@ class TestRunner {
|
||||
auto address_str = it.second.substr(0, space_pos);
|
||||
auto bytes_str = it.second.substr(space_pos + 1);
|
||||
uint32_t address = std::strtoul(address_str.c_str(), nullptr, 16);
|
||||
auto p = memory->TranslateVirtual(address);
|
||||
auto p = memory_->TranslateVirtual(address);
|
||||
const char* c = bytes_str.c_str();
|
||||
while (*c) {
|
||||
while (*c == ' ') ++c;
|
||||
@@ -298,9 +301,7 @@ class TestRunner {
|
||||
}
|
||||
|
||||
bool CheckTestResults(TestCase& test_case) {
|
||||
auto ppc_context = thread_state->context();
|
||||
|
||||
char actual_value[2048];
|
||||
auto ppc_context = thread_state_->context();
|
||||
|
||||
bool any_failed = false;
|
||||
for (auto& it : test_case.annotations) {
|
||||
@@ -308,9 +309,9 @@ class TestRunner {
|
||||
size_t space_pos = it.second.find(" ");
|
||||
auto reg_name = it.second.substr(0, space_pos);
|
||||
auto reg_value = it.second.substr(space_pos + 1);
|
||||
if (!ppc_context->CompareRegWithString(reg_name.c_str(),
|
||||
reg_value.c_str(), actual_value,
|
||||
xe::countof(actual_value))) {
|
||||
std::string actual_value;
|
||||
if (!ppc_context->CompareRegWithString(
|
||||
reg_name.c_str(), reg_value.c_str(), actual_value)) {
|
||||
any_failed = true;
|
||||
XELOGE("Register %s assert failed:\n", reg_name.c_str());
|
||||
XELOGE(" Expected: %s == %s\n", reg_name.c_str(), reg_value.c_str());
|
||||
@@ -321,7 +322,7 @@ class TestRunner {
|
||||
auto address_str = it.second.substr(0, space_pos);
|
||||
auto bytes_str = it.second.substr(space_pos + 1);
|
||||
uint32_t address = std::strtoul(address_str.c_str(), nullptr, 16);
|
||||
auto base_address = memory->TranslateVirtual(address);
|
||||
auto base_address = memory_->TranslateVirtual(address);
|
||||
auto p = base_address;
|
||||
const char* c = bytes_str.c_str();
|
||||
while (*c) {
|
||||
@@ -348,19 +349,18 @@ class TestRunner {
|
||||
return !any_failed;
|
||||
}
|
||||
|
||||
size_t memory_size;
|
||||
std::unique_ptr<Memory> memory;
|
||||
std::unique_ptr<Processor> processor;
|
||||
std::unique_ptr<ThreadState> thread_state;
|
||||
size_t memory_size_;
|
||||
std::unique_ptr<Memory> memory_;
|
||||
std::unique_ptr<Processor> processor_;
|
||||
std::unique_ptr<ThreadState> thread_state_;
|
||||
};
|
||||
|
||||
bool DiscoverTests(std::wstring& test_path,
|
||||
std::vector<std::wstring>& test_files) {
|
||||
bool DiscoverTests(const std::filesystem::path& test_path,
|
||||
std::vector<std::filesystem::path>& test_files) {
|
||||
auto file_infos = xe::filesystem::ListFiles(test_path);
|
||||
for (auto& file_info : file_infos) {
|
||||
if (file_info.name != L"." && file_info.name != L".." &&
|
||||
file_info.name.rfind(L".s") == file_info.name.size() - 2) {
|
||||
test_files.push_back(xe::join_paths(test_path, file_info.name));
|
||||
if (file_info.name.extension() == ".s") {
|
||||
test_files.push_back(test_path / file_info.name);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -401,14 +401,16 @@ void ProtectedRunTest(TestSuite& test_suite, TestRunner& runner,
|
||||
#endif // XE_COMPILER_MSVC
|
||||
}
|
||||
|
||||
bool RunTests(const std::wstring& test_name) {
|
||||
bool RunTests(const std::string_view test_name) {
|
||||
int result_code = 1;
|
||||
int failed_count = 0;
|
||||
int passed_count = 0;
|
||||
|
||||
auto test_path_root =
|
||||
xe::fix_path_separators(xe::to_wstring(cvars::test_path));
|
||||
std::vector<std::wstring> test_files;
|
||||
XELOGI("Haswell instruction usage {}.",
|
||||
cvars::use_haswell_instructions ? "enabled" : "disabled");
|
||||
|
||||
auto test_path_root = cvars::test_path;
|
||||
std::vector<std::filesystem::path> test_files;
|
||||
if (!DiscoverTests(test_path_root, test_files)) {
|
||||
return false;
|
||||
}
|
||||
@@ -423,11 +425,12 @@ bool RunTests(const std::wstring& test_name) {
|
||||
bool load_failed = false;
|
||||
for (auto& test_path : test_files) {
|
||||
TestSuite test_suite(test_path);
|
||||
if (!test_name.empty() && test_suite.name != test_name) {
|
||||
if (!test_name.empty() && test_suite.name() != test_name) {
|
||||
continue;
|
||||
}
|
||||
if (!test_suite.Load()) {
|
||||
XELOGE("TEST SUITE %ls FAILED TO LOAD", test_path.c_str());
|
||||
XELOGE("TEST SUITE %s FAILED TO LOAD",
|
||||
xe::path_to_utf8(test_path).c_str());
|
||||
load_failed = true;
|
||||
continue;
|
||||
}
|
||||
@@ -440,9 +443,9 @@ bool RunTests(const std::wstring& test_name) {
|
||||
XELOGI("%d tests loaded.", (int)test_suites.size());
|
||||
TestRunner runner;
|
||||
for (auto& test_suite : test_suites) {
|
||||
XELOGI("%ls.s:", test_suite.name.c_str());
|
||||
XELOGI("%s.s:", xe::path_to_utf8(test_suite.name()).c_str());
|
||||
|
||||
for (auto& test_case : test_suite.test_cases) {
|
||||
for (auto& test_case : test_suite.test_cases()) {
|
||||
XELOGI(" - %s", test_case.name.c_str());
|
||||
ProtectedRunTest(test_suite, runner, test_case, failed_count,
|
||||
passed_count);
|
||||
@@ -459,9 +462,9 @@ bool RunTests(const std::wstring& test_name) {
|
||||
return failed_count ? false : true;
|
||||
}
|
||||
|
||||
int main(const std::vector<std::wstring>& args) {
|
||||
int main(const std::vector<std::string>& args) {
|
||||
// Grab test name, if present.
|
||||
std::wstring test_name;
|
||||
std::string test_name;
|
||||
if (args.size() >= 2) {
|
||||
test_name = args[1];
|
||||
}
|
||||
@@ -473,5 +476,5 @@ int main(const std::vector<std::wstring>& args) {
|
||||
} // namespace cpu
|
||||
} // namespace xe
|
||||
|
||||
DEFINE_ENTRY_POINT(L"xenia-cpu-ppc-test", xe::cpu::test::main, "[test name]",
|
||||
DEFINE_ENTRY_POINT("xenia-cpu-ppc-test", xe::cpu::test::main, "[test name]",
|
||||
"test_name");
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2017 Ben Vanik. All rights reserved. *
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
@@ -87,7 +87,7 @@ class TestSuite {
|
||||
return result;
|
||||
}
|
||||
|
||||
TestCase* FindTestCase(const std::string& name) {
|
||||
TestCase* FindTestCase(const std::string_view name) {
|
||||
for (auto& test_case : test_cases) {
|
||||
if (test_case.name == name) {
|
||||
return &test_case;
|
||||
|
||||
@@ -7,12 +7,13 @@ project("xenia-cpu-ppc-tests")
|
||||
kind("ConsoleApp")
|
||||
language("C++")
|
||||
links({
|
||||
"capstone", -- cpu-backend-x64
|
||||
"fmt",
|
||||
"mspack",
|
||||
"xenia-core",
|
||||
"xenia-cpu-backend-x64",
|
||||
"xenia-cpu",
|
||||
"xenia-base",
|
||||
"capstone", -- cpu-backend-x64
|
||||
"mspack",
|
||||
})
|
||||
files({
|
||||
"ppc_testing_main.cc",
|
||||
@@ -40,6 +41,7 @@ project("xenia-cpu-ppc-nativetests")
|
||||
kind("ConsoleApp")
|
||||
language("C++")
|
||||
links({
|
||||
"fmt",
|
||||
"xenia-base",
|
||||
})
|
||||
files({
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
@@ -42,8 +42,8 @@
|
||||
|
||||
DEFINE_bool(debug, DEFAULT_DEBUG_FLAG,
|
||||
"Allow debugging and retain debug information.", "General");
|
||||
DEFINE_string(trace_function_data_path, "", "File to write trace data to.",
|
||||
"CPU");
|
||||
DEFINE_path(trace_function_data_path, "", "File to write trace data to.",
|
||||
"CPU");
|
||||
DEFINE_bool(break_on_start, false, "Break into the debugger on startup.",
|
||||
"CPU");
|
||||
|
||||
@@ -140,7 +140,7 @@ bool Processor::Setup(std::unique_ptr<backend::Backend> backend) {
|
||||
}
|
||||
|
||||
// Open the trace data path, if requested.
|
||||
functions_trace_path_ = xe::to_wstring(cvars::trace_function_data_path);
|
||||
functions_trace_path_ = cvars::trace_function_data_path;
|
||||
if (!functions_trace_path_.empty()) {
|
||||
functions_trace_file_ = ChunkedMappedMemoryWriter::Open(
|
||||
functions_trace_path_, 32 * 1024 * 1024, true);
|
||||
@@ -167,7 +167,7 @@ bool Processor::AddModule(std::unique_ptr<Module> module) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Module* Processor::GetModule(const char* name) {
|
||||
Module* Processor::GetModule(const std::string_view name) {
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
for (const auto& module : modules_) {
|
||||
if (module->name() == name) {
|
||||
@@ -186,7 +186,7 @@ std::vector<Module*> Processor::GetModules() {
|
||||
return clone;
|
||||
}
|
||||
|
||||
Function* Processor::DefineBuiltin(const std::string& name,
|
||||
Function* Processor::DefineBuiltin(const std::string_view name,
|
||||
BuiltinFunction::Handler handler, void* arg0,
|
||||
void* arg1) {
|
||||
uint32_t address = next_builtin_address_;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
@@ -99,12 +99,11 @@ class Processor {
|
||||
}
|
||||
|
||||
bool AddModule(std::unique_ptr<Module> module);
|
||||
Module* GetModule(const char* name);
|
||||
Module* GetModule(const std::string& name) { return GetModule(name.c_str()); }
|
||||
Module* GetModule(const std::string_view name);
|
||||
std::vector<Module*> GetModules();
|
||||
|
||||
Module* builtin_module() const { return builtin_module_; }
|
||||
Function* DefineBuiltin(const std::string& name,
|
||||
Function* DefineBuiltin(const std::string_view name,
|
||||
BuiltinFunction::Handler handler, void* arg0,
|
||||
void* arg1);
|
||||
|
||||
@@ -245,7 +244,7 @@ class Processor {
|
||||
// Which debug features are enabled in generated code.
|
||||
uint32_t debug_info_flags_ = 0;
|
||||
// If specified, the file trace data gets written to when running.
|
||||
std::wstring functions_trace_path_;
|
||||
std::filesystem::path functions_trace_path_;
|
||||
std::unique_ptr<ChunkedMappedMemoryWriter> functions_trace_file_;
|
||||
|
||||
std::unique_ptr<ppc::PPCFrontend> frontend_;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
@@ -23,9 +23,9 @@ RawModule::RawModule(Processor* processor)
|
||||
|
||||
RawModule::~RawModule() {}
|
||||
|
||||
bool RawModule::LoadFile(uint32_t base_address, const std::wstring& path) {
|
||||
auto fixed_path = xe::fix_path_separators(path);
|
||||
FILE* file = xe::filesystem::OpenFile(fixed_path, "rb");
|
||||
bool RawModule::LoadFile(uint32_t base_address,
|
||||
const std::filesystem::path& path) {
|
||||
FILE* file = xe::filesystem::OpenFile(path, "rb");
|
||||
fseek(file, 0, SEEK_END);
|
||||
uint32_t file_length = static_cast<uint32_t>(ftell(file));
|
||||
fseek(file, 0, SEEK_SET);
|
||||
@@ -48,12 +48,7 @@ bool RawModule::LoadFile(uint32_t base_address, const std::wstring& path) {
|
||||
fclose(file);
|
||||
|
||||
// Setup debug info.
|
||||
auto last_slash = fixed_path.find_last_of(xe::kPathSeparator);
|
||||
if (last_slash != std::string::npos) {
|
||||
name_ = xe::to_string(fixed_path.substr(last_slash + 1));
|
||||
} else {
|
||||
name_ = xe::to_string(fixed_path);
|
||||
}
|
||||
name_ = xe::path_to_utf8(path.filename());
|
||||
// TODO(benvanik): debug info
|
||||
|
||||
low_address_ = base_address;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
@@ -22,7 +22,7 @@ class RawModule : public Module {
|
||||
explicit RawModule(Processor* processor);
|
||||
~RawModule() override;
|
||||
|
||||
bool LoadFile(uint32_t base_address, const std::wstring& path);
|
||||
bool LoadFile(uint32_t base_address, const std::filesystem::path& path);
|
||||
|
||||
// Set address range if you've already allocated memory and placed code
|
||||
// in it.
|
||||
@@ -30,7 +30,7 @@ class RawModule : public Module {
|
||||
|
||||
const std::string& name() const override { return name_; }
|
||||
bool is_executable() const override { return is_executable_; }
|
||||
void set_name(const std::string& name) { name_ = name; }
|
||||
void set_name(const std::string_view name) { name_ = name; }
|
||||
void set_executable(bool is_executable) { is_executable_ = is_executable; }
|
||||
|
||||
bool ContainsAddress(uint32_t address) override;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
@@ -45,7 +45,7 @@ class Symbol {
|
||||
uint32_t address() const { return address_; }
|
||||
|
||||
const std::string& name() const { return name_; }
|
||||
void set_name(const std::string& value) { name_ = value; }
|
||||
void set_name(const std::string_view value) { name_ = value; }
|
||||
|
||||
protected:
|
||||
Type type_ = Type::kVariable;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2014 Ben Vanik. All rights reserved. *
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
@@ -24,7 +24,7 @@ using xe::cpu::compiler::Compiler;
|
||||
using xe::cpu::hir::HIRBuilder;
|
||||
namespace passes = xe::cpu::compiler::passes;
|
||||
|
||||
TestModule::TestModule(Processor* processor, const std::string& name,
|
||||
TestModule::TestModule(Processor* processor, const std::string_view name,
|
||||
std::function<bool(uint32_t)> contains_address,
|
||||
std::function<bool(hir::HIRBuilder&)> generate)
|
||||
: Module(processor),
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2014 Ben Vanik. All rights reserved. *
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
@@ -24,7 +24,7 @@ namespace cpu {
|
||||
|
||||
class TestModule : public Module {
|
||||
public:
|
||||
TestModule(Processor* processor, const std::string& name,
|
||||
TestModule(Processor* processor, const std::string_view name,
|
||||
std::function<bool(uint32_t)> contains_address,
|
||||
std::function<bool(hir::HIRBuilder&)> generate);
|
||||
~TestModule() override;
|
||||
|
||||
@@ -4,6 +4,7 @@ include(project_root.."/tools/build")
|
||||
test_suite("xenia-cpu-tests", project_root, ".", {
|
||||
links = {
|
||||
"capstone",
|
||||
"fmt",
|
||||
"xenia-base",
|
||||
"xenia-core",
|
||||
"xenia-cpu",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "third_party/fmt/include/fmt/format.h"
|
||||
|
||||
#include "xenia/base/byte_order.h"
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/base/math.h"
|
||||
@@ -156,7 +158,7 @@ uint32_t XexModule::GetProcAddress(uint16_t ordinal) const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t XexModule::GetProcAddress(const char* name) const {
|
||||
uint32_t XexModule::GetProcAddress(const std::string_view name) const {
|
||||
assert_not_zero(base_address_);
|
||||
|
||||
xex2_opt_data_directory* pe_export_directory = 0;
|
||||
@@ -185,7 +187,7 @@ uint32_t XexModule::GetProcAddress(const char* name) const {
|
||||
auto fn_name = reinterpret_cast<const char*>(uintptr_t(e) + name_table[i]);
|
||||
uint16_t ordinal = ordinal_table[i];
|
||||
uint32_t addr = base_address_ + function_table[ordinal];
|
||||
if (!std::strcmp(name, fn_name)) {
|
||||
if (name == std::string_view(fn_name)) {
|
||||
// We have a match!
|
||||
return addr;
|
||||
}
|
||||
@@ -865,7 +867,7 @@ int XexModule::ReadPEHeaders() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool XexModule::Load(const std::string& name, const std::string& path,
|
||||
bool XexModule::Load(const std::string_view name, const std::string_view path,
|
||||
const void* xex_addr, size_t xex_length) {
|
||||
auto src_header = reinterpret_cast<const xex2_header*>(xex_addr);
|
||||
|
||||
@@ -922,8 +924,8 @@ bool XexModule::Load(const std::string& name, const std::string& path,
|
||||
base_address_ = *base_addr_opt;
|
||||
|
||||
// Setup debug info.
|
||||
name_ = std::string(name);
|
||||
path_ = std::string(path);
|
||||
name_ = name;
|
||||
path_ = path;
|
||||
|
||||
uint8_t* data = memory()->TranslateVirtual(base_address_);
|
||||
|
||||
@@ -1027,7 +1029,8 @@ bool XexModule::LoadContinue() {
|
||||
assert_true(library_name_index <
|
||||
opt_import_libraries->string_table.count);
|
||||
assert_not_null(string_table[library_name_index]);
|
||||
SetupLibraryImports(string_table[library_name_index], library);
|
||||
auto library_name = std::string(string_table[library_name_index]);
|
||||
SetupLibraryImports(library_name, library);
|
||||
library_offset += library->size;
|
||||
}
|
||||
}
|
||||
@@ -1087,7 +1090,7 @@ bool XexModule::Unload() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool XexModule::SetupLibraryImports(const char* name,
|
||||
bool XexModule::SetupLibraryImports(const std::string_view name,
|
||||
const xex2_import_library* library) {
|
||||
ExportResolver* kernel_resolver = nullptr;
|
||||
if (kernel_state_->IsKernelModule(name)) {
|
||||
@@ -1096,14 +1099,10 @@ bool XexModule::SetupLibraryImports(const char* name,
|
||||
|
||||
auto user_module = kernel_state_->GetModule(name);
|
||||
|
||||
std::string libbasename = name;
|
||||
auto dot = libbasename.find_last_of('.');
|
||||
if (dot != libbasename.npos) {
|
||||
libbasename = libbasename.substr(0, dot);
|
||||
}
|
||||
auto base_name = utf8::find_base_name_from_guest_path(name);
|
||||
|
||||
ImportLibrary library_info;
|
||||
library_info.name = libbasename;
|
||||
library_info.name = base_name;
|
||||
library_info.id = library->id;
|
||||
library_info.version.value = library->version.value;
|
||||
library_info.min_version.value = library->version_min.value;
|
||||
@@ -1135,7 +1134,7 @@ bool XexModule::SetupLibraryImports(const char* name,
|
||||
XELOGW(
|
||||
"WARNING: an import variable was not resolved! (library: %s, import "
|
||||
"lib: %s, ordinal: %.3X)",
|
||||
name_.c_str(), name, ordinal);
|
||||
name_.c_str(), name.c_str(), ordinal);
|
||||
}
|
||||
|
||||
StringBuffer import_name;
|
||||
@@ -1147,11 +1146,11 @@ bool XexModule::SetupLibraryImports(const char* name,
|
||||
import_info.value_address = record_addr;
|
||||
library_info.imports.push_back(import_info);
|
||||
|
||||
import_name.AppendFormat("__imp__");
|
||||
import_name.Append("__imp__");
|
||||
if (kernel_export) {
|
||||
import_name.AppendFormat("%s", kernel_export->name);
|
||||
import_name.Append(kernel_export->name);
|
||||
} else {
|
||||
import_name.AppendFormat("%s_%.3X", libbasename.c_str(), ordinal);
|
||||
import_name.AppendFormat("{}_{:03X}", base_name, ordinal);
|
||||
}
|
||||
|
||||
if (kernel_export) {
|
||||
@@ -1180,7 +1179,7 @@ bool XexModule::SetupLibraryImports(const char* name,
|
||||
// Setup a variable and define it.
|
||||
Symbol* var_info;
|
||||
DeclareVariable(record_addr, &var_info);
|
||||
var_info->set_name(import_name.GetString());
|
||||
var_info->set_name(import_name.to_string_view());
|
||||
var_info->set_status(Symbol::Status::kDeclared);
|
||||
DefineVariable(var_info);
|
||||
var_info->set_status(Symbol::Status::kDefined);
|
||||
@@ -1194,15 +1193,15 @@ bool XexModule::SetupLibraryImports(const char* name,
|
||||
}
|
||||
|
||||
if (kernel_export) {
|
||||
import_name.AppendFormat("%s", kernel_export->name);
|
||||
import_name.Append(kernel_export->name);
|
||||
} else {
|
||||
import_name.AppendFormat("__%s_%.3X", libbasename.c_str(), ordinal);
|
||||
import_name.AppendFormat("__{}_{:03X}", base_name, ordinal);
|
||||
}
|
||||
|
||||
Function* function;
|
||||
DeclareFunction(record_addr, &function);
|
||||
function->set_end_address(record_addr + 16 - 4);
|
||||
function->set_name(import_name.GetString());
|
||||
function->set_name(import_name.to_string_view());
|
||||
|
||||
if (user_export_addr) {
|
||||
// Rewrite PPC code to set r11 to the target address
|
||||
@@ -1253,7 +1252,7 @@ bool XexModule::SetupLibraryImports(const char* name,
|
||||
}
|
||||
} else {
|
||||
XELOGW("WARNING: Imported kernel function %s is unimplemented!",
|
||||
import_name.GetString());
|
||||
import_name.buffer());
|
||||
}
|
||||
static_cast<GuestFunction*>(function)->SetupExtern(handler,
|
||||
kernel_export);
|
||||
@@ -1488,11 +1487,12 @@ bool XexModule::FindSaveRest() {
|
||||
if (gplr_start) {
|
||||
uint32_t address = gplr_start;
|
||||
for (int n = 14; n <= 31; n++) {
|
||||
snprintf(name, xe::countof(name), "__savegprlr_%d", n);
|
||||
auto format_result =
|
||||
fmt::format_to_n(name, xe::countof(name), "__savegprlr_{}", n);
|
||||
Function* function;
|
||||
DeclareFunction(address, &function);
|
||||
function->set_end_address(address + (31 - n) * 4 + 2 * 4);
|
||||
function->set_name(name);
|
||||
function->set_name(std::string_view(name, format_result.size));
|
||||
// TODO(benvanik): set type fn->type = FunctionSymbol::User;
|
||||
// TODO(benvanik): set flags fn->flags |= FunctionSymbol::kFlagSaveGprLr;
|
||||
function->set_behavior(Function::Behavior::kProlog);
|
||||
@@ -1501,11 +1501,12 @@ bool XexModule::FindSaveRest() {
|
||||
}
|
||||
address = gplr_start + 20 * 4;
|
||||
for (int n = 14; n <= 31; n++) {
|
||||
snprintf(name, xe::countof(name), "__restgprlr_%d", n);
|
||||
auto format_result =
|
||||
fmt::format_to_n(name, xe::countof(name), "__restgprlr_{}", n);
|
||||
Function* function;
|
||||
DeclareFunction(address, &function);
|
||||
function->set_end_address(address + (31 - n) * 4 + 3 * 4);
|
||||
function->set_name(name);
|
||||
function->set_name(std::string_view(name, format_result.size));
|
||||
// TODO(benvanik): set type fn->type = FunctionSymbol::User;
|
||||
// TODO(benvanik): set flags fn->flags |= FunctionSymbol::kFlagRestGprLr;
|
||||
function->set_behavior(Function::Behavior::kEpilogReturn);
|
||||
@@ -1516,11 +1517,12 @@ bool XexModule::FindSaveRest() {
|
||||
if (fpr_start) {
|
||||
uint32_t address = fpr_start;
|
||||
for (int n = 14; n <= 31; n++) {
|
||||
snprintf(name, xe::countof(name), "__savefpr_%d", n);
|
||||
auto format_result =
|
||||
fmt::format_to_n(name, xe::countof(name), "__savefpr_{}", n);
|
||||
Function* function;
|
||||
DeclareFunction(address, &function);
|
||||
function->set_end_address(address + (31 - n) * 4 + 1 * 4);
|
||||
function->set_name(name);
|
||||
function->set_name(std::string_view(name, format_result.size));
|
||||
// TODO(benvanik): set type fn->type = FunctionSymbol::User;
|
||||
// TODO(benvanik): set flags fn->flags |= FunctionSymbol::kFlagSaveFpr;
|
||||
function->set_behavior(Function::Behavior::kProlog);
|
||||
@@ -1529,11 +1531,12 @@ bool XexModule::FindSaveRest() {
|
||||
}
|
||||
address = fpr_start + (18 * 4) + (1 * 4);
|
||||
for (int n = 14; n <= 31; n++) {
|
||||
snprintf(name, xe::countof(name), "__restfpr_%d", n);
|
||||
auto format_result =
|
||||
fmt::format_to_n(name, xe::countof(name), "__restfpr_{}", n);
|
||||
Function* function;
|
||||
DeclareFunction(address, &function);
|
||||
function->set_end_address(address + (31 - n) * 4 + 1 * 4);
|
||||
function->set_name(name);
|
||||
function->set_name(std::string_view(name, format_result.size));
|
||||
// TODO(benvanik): set type fn->type = FunctionSymbol::User;
|
||||
// TODO(benvanik): set flags fn->flags |= FunctionSymbol::kFlagRestFpr;
|
||||
function->set_behavior(Function::Behavior::kEpilog);
|
||||
@@ -1549,10 +1552,11 @@ bool XexModule::FindSaveRest() {
|
||||
// 64-127 rest
|
||||
uint32_t address = vmx_start;
|
||||
for (int n = 14; n <= 31; n++) {
|
||||
snprintf(name, xe::countof(name), "__savevmx_%d", n);
|
||||
auto format_result =
|
||||
fmt::format_to_n(name, xe::countof(name), "__savevmx_{}", n);
|
||||
Function* function;
|
||||
DeclareFunction(address, &function);
|
||||
function->set_name(name);
|
||||
function->set_name(std::string_view(name, format_result.size));
|
||||
// TODO(benvanik): set type fn->type = FunctionSymbol::User;
|
||||
// TODO(benvanik): set flags fn->flags |= FunctionSymbol::kFlagSaveVmx;
|
||||
function->set_behavior(Function::Behavior::kProlog);
|
||||
@@ -1561,10 +1565,11 @@ bool XexModule::FindSaveRest() {
|
||||
}
|
||||
address += 4;
|
||||
for (int n = 64; n <= 127; n++) {
|
||||
snprintf(name, xe::countof(name), "__savevmx_%d", n);
|
||||
auto format_result =
|
||||
fmt::format_to_n(name, xe::countof(name), "__savevmx_{}", n);
|
||||
Function* function;
|
||||
DeclareFunction(address, &function);
|
||||
function->set_name(name);
|
||||
function->set_name(std::string_view(name, format_result.size));
|
||||
// TODO(benvanik): set type fn->type = FunctionSymbol::User;
|
||||
// TODO(benvanik): set flags fn->flags |= FunctionSymbol::kFlagSaveVmx;
|
||||
function->set_behavior(Function::Behavior::kProlog);
|
||||
@@ -1573,10 +1578,11 @@ bool XexModule::FindSaveRest() {
|
||||
}
|
||||
address = vmx_start + (18 * 2 * 4) + (1 * 4) + (64 * 2 * 4) + (1 * 4);
|
||||
for (int n = 14; n <= 31; n++) {
|
||||
snprintf(name, xe::countof(name), "__restvmx_%d", n);
|
||||
auto format_result =
|
||||
fmt::format_to_n(name, xe::countof(name), "__restvmx_{}", n);
|
||||
Function* function;
|
||||
DeclareFunction(address, &function);
|
||||
function->set_name(name);
|
||||
function->set_name(std::string_view(name, format_result.size));
|
||||
// TODO(benvanik): set type fn->type = FunctionSymbol::User;
|
||||
// TODO(benvanik): set flags fn->flags |= FunctionSymbol::kFlagRestVmx;
|
||||
function->set_behavior(Function::Behavior::kEpilog);
|
||||
@@ -1585,10 +1591,11 @@ bool XexModule::FindSaveRest() {
|
||||
}
|
||||
address += 4;
|
||||
for (int n = 64; n <= 127; n++) {
|
||||
snprintf(name, xe::countof(name), "__restvmx_%d", n);
|
||||
auto format_result =
|
||||
fmt::format_to_n(name, xe::countof(name), "__restvmx_{}", n);
|
||||
Function* function;
|
||||
DeclareFunction(address, &function);
|
||||
function->set_name(name);
|
||||
function->set_name(std::string_view(name, format_result.size));
|
||||
// TODO(benvanik): set type fn->type = FunctionSymbol::User;
|
||||
// TODO(benvanik): set flags fn->flags |= FunctionSymbol::kFlagRestVmx;
|
||||
function->set_behavior(Function::Behavior::kEpilog);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
@@ -132,10 +132,10 @@ class XexModule : public xe::cpu::Module {
|
||||
const PESection* GetPESection(const char* name);
|
||||
|
||||
uint32_t GetProcAddress(uint16_t ordinal) const;
|
||||
uint32_t GetProcAddress(const char* name) const;
|
||||
uint32_t GetProcAddress(const std::string_view name) const;
|
||||
|
||||
int ApplyPatch(XexModule* module);
|
||||
bool Load(const std::string& name, const std::string& path,
|
||||
bool Load(const std::string_view name, const std::string_view path,
|
||||
const void* xex_addr, size_t xex_length);
|
||||
bool LoadContinue();
|
||||
bool Unload();
|
||||
@@ -177,7 +177,7 @@ class XexModule : public xe::cpu::Module {
|
||||
|
||||
int ReadPEHeaders();
|
||||
|
||||
bool SetupLibraryImports(const char* name,
|
||||
bool SetupLibraryImports(const std::string_view name,
|
||||
const xex2_import_library* library);
|
||||
bool FindSaveRest();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user