tests: Add verbose debugging output and test_reader
This commit is contained in:
parent
f865bbbad2
commit
ffc3dce9b1
14 changed files with 393 additions and 22 deletions
|
@ -24,10 +24,6 @@ add_library(dynarmic
|
|||
common/fp/op/FPMulAdd.cpp
|
||||
common/fp/op/FPMulAdd.h
|
||||
common/fp/op/FPNeg.h
|
||||
common/fp/op/FPRSqrtEstimate.cpp
|
||||
common/fp/op/FPRSqrtEstimate.h
|
||||
common/fp/op/FPRSqrtStepFused.cpp
|
||||
common/fp/op/FPRSqrtStepFused.h
|
||||
common/fp/op/FPRecipEstimate.cpp
|
||||
common/fp/op/FPRecipEstimate.h
|
||||
common/fp/op/FPRecipExponent.cpp
|
||||
|
@ -36,6 +32,10 @@ add_library(dynarmic
|
|||
common/fp/op/FPRecipStepFused.h
|
||||
common/fp/op/FPRoundInt.cpp
|
||||
common/fp/op/FPRoundInt.h
|
||||
common/fp/op/FPRSqrtEstimate.cpp
|
||||
common/fp/op/FPRSqrtEstimate.h
|
||||
common/fp/op/FPRSqrtStepFused.cpp
|
||||
common/fp/op/FPRSqrtStepFused.h
|
||||
common/fp/op/FPToFixed.cpp
|
||||
common/fp/op/FPToFixed.h
|
||||
common/fp/process_exception.cpp
|
||||
|
@ -98,6 +98,10 @@ add_library(dynarmic
|
|||
|
||||
if ("A32" IN_LIST DYNARMIC_FRONTENDS)
|
||||
target_sources(dynarmic PRIVATE
|
||||
frontend/A32/a32_ir_emitter.cpp
|
||||
frontend/A32/a32_ir_emitter.h
|
||||
frontend/A32/a32_location_descriptor.cpp
|
||||
frontend/A32/a32_location_descriptor.h
|
||||
frontend/A32/decoder/arm.h
|
||||
frontend/A32/decoder/arm.inc
|
||||
frontend/A32/decoder/asimd.h
|
||||
|
@ -112,21 +116,17 @@ if ("A32" IN_LIST DYNARMIC_FRONTENDS)
|
|||
frontend/A32/disassembler/disassembler_arm.cpp
|
||||
frontend/A32/disassembler/disassembler_thumb.cpp
|
||||
frontend/A32/FPSCR.h
|
||||
frontend/A32/a32_ir_emitter.cpp
|
||||
frontend/A32/a32_ir_emitter.h
|
||||
frontend/A32/a32_location_descriptor.cpp
|
||||
frontend/A32/a32_location_descriptor.h
|
||||
frontend/A32/ITState.h
|
||||
frontend/A32/PSR.h
|
||||
frontend/A32/translate/a32_translate.cpp
|
||||
frontend/A32/translate/a32_translate.h
|
||||
frontend/A32/translate/conditional_state.cpp
|
||||
frontend/A32/translate/conditional_state.h
|
||||
frontend/A32/translate/impl/a32_branch.cpp
|
||||
frontend/A32/translate/impl/a32_crc32.cpp
|
||||
frontend/A32/translate/impl/a32_exception_generating.cpp
|
||||
frontend/A32/translate/impl/a32_translate_impl.cpp
|
||||
frontend/A32/translate/impl/a32_translate_impl.h
|
||||
frontend/A32/translate/conditional_state.cpp
|
||||
frontend/A32/translate/conditional_state.h
|
||||
frontend/A32/translate/impl/asimd_load_store_structures.cpp
|
||||
frontend/A32/translate/impl/asimd_misc.cpp
|
||||
frontend/A32/translate/impl/asimd_one_reg_modified_immediate.cpp
|
||||
|
@ -284,12 +284,12 @@ if ("x86_64" IN_LIST ARCHITECTURE)
|
|||
backend/x64/emit_x64_crc32.cpp
|
||||
backend/x64/emit_x64_data_processing.cpp
|
||||
backend/x64/emit_x64_floating_point.cpp
|
||||
backend/x64/emit_x64_memory.h
|
||||
backend/x64/emit_x64_memory.cpp.inc
|
||||
backend/x64/emit_x64_memory.h
|
||||
backend/x64/emit_x64_packed.cpp
|
||||
backend/x64/emit_x64_saturation.cpp
|
||||
backend/x64/emit_x64_sm4.cpp
|
||||
backend/x64/emit_x64_sha.cpp
|
||||
backend/x64/emit_x64_sm4.cpp
|
||||
backend/x64/emit_x64_vector.cpp
|
||||
backend/x64/emit_x64_vector_floating_point.cpp
|
||||
backend/x64/emit_x64_vector_saturation.cpp
|
||||
|
@ -305,6 +305,8 @@ if ("x86_64" IN_LIST ARCHITECTURE)
|
|||
backend/x64/reg_alloc.cpp
|
||||
backend/x64/reg_alloc.h
|
||||
backend/x64/stack_layout.h
|
||||
backend/x64/verbose_debugging_output.cpp
|
||||
backend/x64/verbose_debugging_output.h
|
||||
common/spin_lock_x64.cpp
|
||||
common/spin_lock_x64.h
|
||||
common/x64_disassemble.cpp
|
||||
|
|
|
@ -94,6 +94,10 @@ A32EmitX64::A32EmitX64(BlockOfCode& code, A32::UserConfig conf, A32::Jit* jit_in
|
|||
A32EmitX64::~A32EmitX64() = default;
|
||||
|
||||
A32EmitX64::BlockDescriptor A32EmitX64::Emit(IR::Block& block) {
|
||||
if (conf.very_verbose_debugging_output) {
|
||||
std::puts(IR::DumpBlock(block).c_str());
|
||||
}
|
||||
|
||||
code.EnableWriting();
|
||||
SCOPE_EXIT { code.DisableWriting(); };
|
||||
|
||||
|
@ -142,6 +146,10 @@ A32EmitX64::BlockDescriptor A32EmitX64::Emit(IR::Block& block) {
|
|||
}
|
||||
|
||||
reg_alloc.EndOfAllocScope();
|
||||
|
||||
if (conf.very_verbose_debugging_output) {
|
||||
EmitVerboseDebuggingOutput(reg_alloc);
|
||||
}
|
||||
}
|
||||
|
||||
reg_alloc.AssertNoMoreUses();
|
||||
|
|
|
@ -65,6 +65,10 @@ A64EmitX64::A64EmitX64(BlockOfCode& code, A64::UserConfig conf, A64::Jit* jit_in
|
|||
A64EmitX64::~A64EmitX64() = default;
|
||||
|
||||
A64EmitX64::BlockDescriptor A64EmitX64::Emit(IR::Block& block) {
|
||||
if (conf.very_verbose_debugging_output) {
|
||||
std::puts(IR::DumpBlock(block).c_str());
|
||||
}
|
||||
|
||||
code.EnableWriting();
|
||||
SCOPE_EXIT { code.DisableWriting(); };
|
||||
|
||||
|
@ -113,6 +117,10 @@ A64EmitX64::BlockDescriptor A64EmitX64::Emit(IR::Block& block) {
|
|||
}
|
||||
|
||||
ctx.reg_alloc.EndOfAllocScope();
|
||||
|
||||
if (conf.very_verbose_debugging_output) {
|
||||
EmitVerboseDebuggingOutput(reg_alloc);
|
||||
}
|
||||
}
|
||||
|
||||
reg_alloc.AssertNoMoreUses();
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "dynarmic/backend/x64/nzcv_util.h"
|
||||
#include "dynarmic/backend/x64/perf_map.h"
|
||||
#include "dynarmic/backend/x64/stack_layout.h"
|
||||
#include "dynarmic/backend/x64/verbose_debugging_output.h"
|
||||
#include "dynarmic/common/variant_util.h"
|
||||
#include "dynarmic/ir/basic_block.h"
|
||||
#include "dynarmic/ir/microinstruction.h"
|
||||
|
@ -102,6 +103,34 @@ void EmitX64::PushRSBHelper(Xbyak::Reg64 loc_desc_reg, Xbyak::Reg64 index_reg, I
|
|||
code.mov(dword[r15 + code.GetJitStateInfo().offsetof_rsb_ptr], index_reg.cvt32());
|
||||
}
|
||||
|
||||
void EmitX64::EmitVerboseDebuggingOutput(RegAlloc& reg_alloc) {
|
||||
code.sub(rsp, sizeof(RegisterData));
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (rsp.getIdx() == i) {
|
||||
continue;
|
||||
}
|
||||
code.mov(qword[rsp + offsetof(RegisterData, gprs) + sizeof(u64) * i], Xbyak::Reg64{i});
|
||||
}
|
||||
for (int i = 0; i < 16; i++) {
|
||||
code.movaps(xword[rsp + offsetof(RegisterData, xmms) + 2 * sizeof(u64) * i], Xbyak::Xmm{i});
|
||||
}
|
||||
code.lea(rax, ptr[rsp + sizeof(RegisterData) + offsetof(StackLayout, spill)]);
|
||||
code.mov(xword[rsp + offsetof(RegisterData, spill)], rax);
|
||||
|
||||
reg_alloc.EmitVerboseDebuggingOutput();
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (rsp.getIdx() == i) {
|
||||
continue;
|
||||
}
|
||||
code.mov(Xbyak::Reg64{i}, qword[rsp + offsetof(RegisterData, gprs) + sizeof(u64) * i]);
|
||||
}
|
||||
for (int i = 0; i < 16; i++) {
|
||||
code.movaps(Xbyak::Xmm{i}, xword[rsp + offsetof(RegisterData, xmms) + 2 * sizeof(u64) * i]);
|
||||
}
|
||||
code.add(rsp, sizeof(RegisterData));
|
||||
}
|
||||
|
||||
void EmitX64::EmitPushRSB(EmitContext& ctx, IR::Inst* inst) {
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
ASSERT(args[0].IsImmediate());
|
||||
|
|
|
@ -108,6 +108,8 @@ protected:
|
|||
BlockDescriptor RegisterBlock(const IR::LocationDescriptor& location_descriptor, CodePtr entrypoint, size_t size);
|
||||
void PushRSBHelper(Xbyak::Reg64 loc_desc_reg, Xbyak::Reg64 index_reg, IR::LocationDescriptor target);
|
||||
|
||||
void EmitVerboseDebuggingOutput(RegAlloc& reg_alloc);
|
||||
|
||||
// Terminal instruction emitters
|
||||
void EmitTerminal(IR::Terminal terminal, IR::LocationDescriptor initial_location, bool is_single_step);
|
||||
virtual void EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDescriptor initial_location, bool is_single_step) = 0;
|
||||
|
|
|
@ -11,10 +11,12 @@
|
|||
|
||||
#include <fmt/ostream.h>
|
||||
#include <mcl/assert.hpp>
|
||||
#include <mcl/bit_cast.hpp>
|
||||
#include <xbyak/xbyak.h>
|
||||
|
||||
#include "dynarmic/backend/x64/abi.h"
|
||||
#include "dynarmic/backend/x64/stack_layout.h"
|
||||
#include "dynarmic/backend/x64/verbose_debugging_output.h"
|
||||
|
||||
namespace Dynarmic::Backend::X64 {
|
||||
|
||||
|
@ -85,6 +87,11 @@ bool HostLocInfo::IsLastUse() const {
|
|||
return is_being_used_count == 0 && current_references == 1 && accumulated_uses + 1 == total_uses;
|
||||
}
|
||||
|
||||
void HostLocInfo::SetLastUse() {
|
||||
ASSERT(IsLastUse());
|
||||
is_set_last_use = true;
|
||||
}
|
||||
|
||||
void HostLocInfo::ReadLock() {
|
||||
ASSERT(!is_scratch);
|
||||
is_being_used_count++;
|
||||
|
@ -119,7 +126,7 @@ void HostLocInfo::ReleaseAll() {
|
|||
accumulated_uses += current_references;
|
||||
current_references = 0;
|
||||
|
||||
ASSERT(total_uses == std::accumulate(values.begin(), values.end(), size_t(0), [](size_t sum, IR::Inst* inst) { return sum + inst->UseCount(); }));
|
||||
is_set_last_use = false;
|
||||
|
||||
if (total_uses == accumulated_uses) {
|
||||
values.clear();
|
||||
|
@ -141,11 +148,25 @@ size_t HostLocInfo::GetMaxBitWidth() const {
|
|||
}
|
||||
|
||||
void HostLocInfo::AddValue(IR::Inst* inst) {
|
||||
if (is_set_last_use) {
|
||||
is_set_last_use = false;
|
||||
values.clear();
|
||||
}
|
||||
values.push_back(inst);
|
||||
total_uses += inst->UseCount();
|
||||
max_bit_width = std::max(max_bit_width, GetBitWidth(inst->GetType()));
|
||||
}
|
||||
|
||||
void HostLocInfo::EmitVerboseDebuggingOutput(BlockOfCode& code, size_t host_loc_index) const {
|
||||
using namespace Xbyak::util;
|
||||
for (IR::Inst* value : values) {
|
||||
code.mov(code.ABI_PARAM1, rsp);
|
||||
code.mov(code.ABI_PARAM2, host_loc_index);
|
||||
code.mov(code.ABI_PARAM3, mcl::bit_cast<u64>(value));
|
||||
code.CallFunction(PrintVerboseDebuggingOutputLine);
|
||||
}
|
||||
}
|
||||
|
||||
IR::Type Argument::GetType() const {
|
||||
return value.GetType();
|
||||
}
|
||||
|
@ -369,6 +390,8 @@ HostLoc RegAlloc::UseScratchImpl(IR::Value use_value, const std::vector<HostLoc>
|
|||
if (can_use_current_location && !LocInfo(current_location).IsLocked()) {
|
||||
if (!LocInfo(current_location).IsLastUse()) {
|
||||
MoveOutOfTheWay(current_location);
|
||||
} else {
|
||||
LocInfo(current_location).SetLastUse();
|
||||
}
|
||||
LocInfo(current_location).WriteLock();
|
||||
return current_location;
|
||||
|
@ -471,6 +494,12 @@ void RegAlloc::AssertNoMoreUses() {
|
|||
ASSERT(std::all_of(hostloc_info.begin(), hostloc_info.end(), [](const auto& i) { return i.IsEmpty(); }));
|
||||
}
|
||||
|
||||
void RegAlloc::EmitVerboseDebuggingOutput() {
|
||||
for (size_t i = 0; i < hostloc_info.size(); i++) {
|
||||
hostloc_info[i].EmitVerboseDebuggingOutput(code, i);
|
||||
}
|
||||
}
|
||||
|
||||
HostLoc RegAlloc::SelectARegister(const std::vector<HostLoc>& desired_locations) const {
|
||||
std::vector<HostLoc> candidates = desired_locations;
|
||||
|
||||
|
|
|
@ -35,6 +35,8 @@ public:
|
|||
bool IsEmpty() const;
|
||||
bool IsLastUse() const;
|
||||
|
||||
void SetLastUse();
|
||||
|
||||
void ReadLock();
|
||||
void WriteLock();
|
||||
void AddArgReference();
|
||||
|
@ -46,10 +48,13 @@ public:
|
|||
|
||||
void AddValue(IR::Inst* inst);
|
||||
|
||||
void EmitVerboseDebuggingOutput(BlockOfCode& code, size_t host_loc_index) const;
|
||||
|
||||
private:
|
||||
// Current instruction state
|
||||
size_t is_being_used_count = 0;
|
||||
bool is_scratch = false;
|
||||
bool is_set_last_use = false;
|
||||
|
||||
// Block state
|
||||
size_t current_references = 0;
|
||||
|
@ -140,6 +145,8 @@ public:
|
|||
|
||||
void AssertNoMoreUses();
|
||||
|
||||
void EmitVerboseDebuggingOutput();
|
||||
|
||||
private:
|
||||
friend struct Argument;
|
||||
|
||||
|
|
29
src/dynarmic/backend/x64/verbose_debugging_output.cpp
Normal file
29
src/dynarmic/backend/x64/verbose_debugging_output.cpp
Normal file
|
@ -0,0 +1,29 @@
|
|||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2023 MerryMage
|
||||
* SPDX-License-Identifier: 0BSD
|
||||
*/
|
||||
|
||||
#include "dynarmic/backend/x64/verbose_debugging_output.h"
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "dynarmic/backend/x64/hostloc.h"
|
||||
|
||||
namespace Dynarmic::Backend::X64 {
|
||||
|
||||
void PrintVerboseDebuggingOutputLine(RegisterData& reg_data, HostLoc hostloc, u64 inst_addr) {
|
||||
if (HostLocIsGPR(hostloc)) {
|
||||
const u64 value = reg_data.gprs[HostLocToReg64(hostloc).getIdx()];
|
||||
fmt::print("dynarmic debug: {:016x} = {:016x}{:016x}\n", inst_addr, 0, value);
|
||||
} else if (HostLocIsXMM(hostloc)) {
|
||||
const Vector value = reg_data.xmms[HostLocToXmm(hostloc).getIdx()];
|
||||
fmt::print("dynarmic debug: {:016x} = {:016x}{:016x}\n", inst_addr, value[1], value[0]);
|
||||
} else if (HostLocIsSpill(hostloc)) {
|
||||
const Vector value = (*reg_data.spill)[static_cast<size_t>(hostloc) - static_cast<size_t>(HostLoc::FirstSpill)];
|
||||
fmt::print("dynarmic debug: {:016x} = {:016x}{:016x}\n", inst_addr, value[1], value[0]);
|
||||
} else {
|
||||
fmt::print("dynarmic debug: Invalid hostloc\n");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::Backend::X64
|
36
src/dynarmic/backend/x64/verbose_debugging_output.h
Normal file
36
src/dynarmic/backend/x64/verbose_debugging_output.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2023 MerryMage
|
||||
* SPDX-License-Identifier: 0BSD
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
#include <mcl/stdint.hpp>
|
||||
|
||||
#include "dynarmic/backend/x64/stack_layout.h"
|
||||
|
||||
namespace Dynarmic::Backend::X64 {
|
||||
|
||||
enum class HostLoc;
|
||||
using Vector = std::array<u64, 2>;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable : 4324) // Structure was padded due to alignment specifier
|
||||
#endif
|
||||
|
||||
struct alignas(16) RegisterData {
|
||||
std::array<u64, 16> gprs;
|
||||
std::array<Vector, 16> xmms;
|
||||
decltype(StackLayout::spill)* spill;
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
void PrintVerboseDebuggingOutputLine(RegisterData& reg_data, HostLoc hostloc, u64 inst_addr);
|
||||
|
||||
} // namespace Dynarmic::Backend::X64
|
|
@ -231,6 +231,9 @@ struct UserConfig {
|
|||
// Minimum size is about 8MiB. Maximum size is about 128MiB (arm64 host) or 2GiB (x64 host).
|
||||
// Maximum size is limited by the maximum length of a x86_64 / arm64 jump.
|
||||
size_t code_cache_size = 128 * 1024 * 1024; // bytes
|
||||
|
||||
/// Internal use only
|
||||
bool very_verbose_debugging_output = false;
|
||||
};
|
||||
|
||||
} // namespace A32
|
||||
|
|
|
@ -288,6 +288,9 @@ struct UserConfig {
|
|||
// Minimum size is about 8MiB. Maximum size is about 128MiB (arm64 host) or 2GiB (x64 host).
|
||||
// Maximum size is limited by the maximum length of a x86_64 / arm64 jump.
|
||||
size_t code_cache_size = 128 * 1024 * 1024; // bytes
|
||||
|
||||
/// Internal use only
|
||||
bool very_verbose_debugging_output = false;
|
||||
};
|
||||
|
||||
} // namespace A64
|
||||
|
|
|
@ -102,6 +102,19 @@ if (("A32" IN_LIST DYNARMIC_FRONTENDS) AND ("A64" IN_LIST DYNARMIC_FRONTENDS))
|
|||
target_compile_definitions(dynarmic_test_generator PRIVATE FMT_USE_USER_DEFINED_LITERALS=1)
|
||||
endif()
|
||||
|
||||
if (("A32" IN_LIST DYNARMIC_FRONTENDS) AND ("A64" IN_LIST DYNARMIC_FRONTENDS))
|
||||
add_executable(dynarmic_test_reader
|
||||
test_reader.cpp
|
||||
)
|
||||
|
||||
create_target_directory_groups(dynarmic_test_reader)
|
||||
|
||||
target_link_libraries(dynarmic_test_reader PRIVATE dynarmic Boost::boost fmt::fmt merry::mcl)
|
||||
target_include_directories(dynarmic_test_reader PRIVATE . ../src)
|
||||
target_compile_options(dynarmic_test_reader PRIVATE ${DYNARMIC_CXX_FLAGS})
|
||||
target_compile_definitions(dynarmic_test_reader PRIVATE FMT_USE_USER_DEFINED_LITERALS=1)
|
||||
endif()
|
||||
|
||||
create_target_directory_groups(dynarmic_tests)
|
||||
|
||||
target_link_libraries(dynarmic_tests PRIVATE dynarmic Boost::boost Catch2::Catch2WithMain fmt::fmt merry::mcl)
|
||||
|
|
|
@ -40,12 +40,6 @@
|
|||
#include <fmt/format.h>
|
||||
#include <fmt/ostream.h>
|
||||
|
||||
#if defined(__APPLE__) && defined(MCL_ARCHITECTURE_ARM64)
|
||||
# include <mach/mach_init.h>
|
||||
# include <mach/mach_port.h>
|
||||
# include <mach/task.h>
|
||||
#endif
|
||||
|
||||
constexpr bool mask_fpsr_cum_bits = true;
|
||||
|
||||
namespace {
|
||||
|
|
208
tests/test_reader.cpp
Normal file
208
tests/test_reader.cpp
Normal file
|
@ -0,0 +1,208 @@
|
|||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2023 MerryMage
|
||||
* SPDX-License-Identifier: 0BSD
|
||||
*/
|
||||
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <mcl/stdint.hpp>
|
||||
|
||||
#include "./A64/testenv.h"
|
||||
#include "dynarmic/common/fp/fpsr.h"
|
||||
#include "dynarmic/interface/A64/a64.h"
|
||||
|
||||
using namespace Dynarmic;
|
||||
|
||||
A64::UserConfig GetA64UserConfig(A64TestEnv& jit_env) {
|
||||
A64::UserConfig jit_user_config{&jit_env};
|
||||
jit_user_config.optimizations &= ~OptimizationFlag::FastDispatch;
|
||||
// The below corresponds to the settings for qemu's aarch64_max_initfn
|
||||
jit_user_config.dczid_el0 = 7;
|
||||
jit_user_config.ctr_el0 = 0x80038003;
|
||||
jit_user_config.very_verbose_debugging_output = true;
|
||||
return jit_user_config;
|
||||
}
|
||||
|
||||
template<size_t num_jit_reruns = 1>
|
||||
void RunTestInstance(A64::Jit& jit,
|
||||
A64TestEnv& jit_env,
|
||||
const std::array<u64, 31>& regs,
|
||||
const std::array<std::array<u64, 2>, 32>& vecs,
|
||||
const std::vector<u32>& instructions,
|
||||
const u32 pstate,
|
||||
const u32 fpcr,
|
||||
const u64 initial_sp,
|
||||
const u64 start_address,
|
||||
const size_t ticks_left) {
|
||||
jit.ClearCache();
|
||||
|
||||
for (size_t jit_rerun_count = 0; jit_rerun_count < num_jit_reruns; ++jit_rerun_count) {
|
||||
jit_env.code_mem = instructions;
|
||||
jit_env.code_mem.emplace_back(0x14000000); // B .
|
||||
jit_env.code_mem_start_address = start_address;
|
||||
jit_env.modified_memory.clear();
|
||||
jit_env.interrupts.clear();
|
||||
|
||||
jit.SetRegisters(regs);
|
||||
jit.SetVectors(vecs);
|
||||
jit.SetPC(start_address);
|
||||
jit.SetSP(initial_sp);
|
||||
jit.SetFpcr(fpcr);
|
||||
jit.SetFpsr(0);
|
||||
jit.SetPstate(pstate);
|
||||
jit.ClearCache();
|
||||
|
||||
jit_env.ticks_left = ticks_left;
|
||||
jit.Run();
|
||||
}
|
||||
|
||||
fmt::print("instructions:");
|
||||
for (u32 instruction : instructions) {
|
||||
fmt::print(" {:08x}", instruction);
|
||||
}
|
||||
fmt::print("\n");
|
||||
|
||||
fmt::print("initial_regs:");
|
||||
for (u64 i : regs) {
|
||||
fmt::print(" {:016x}", i);
|
||||
}
|
||||
fmt::print("\n");
|
||||
fmt::print("initial_vecs:");
|
||||
for (auto i : vecs) {
|
||||
fmt::print(" {:016x}:{:016x}", i[0], i[1]);
|
||||
}
|
||||
fmt::print("\n");
|
||||
fmt::print("initial_sp: {:016x}\n", initial_sp);
|
||||
fmt::print("initial_pstate: {:08x}\n", pstate);
|
||||
fmt::print("initial_fpcr: {:08x}\n", fpcr);
|
||||
|
||||
fmt::print("final_regs:");
|
||||
for (u64 i : jit.GetRegisters()) {
|
||||
fmt::print(" {:016x}", i);
|
||||
}
|
||||
fmt::print("\n");
|
||||
fmt::print("final_vecs:");
|
||||
for (auto i : jit.GetVectors()) {
|
||||
fmt::print(" {:016x}:{:016x}", i[0], i[1]);
|
||||
}
|
||||
fmt::print("\n");
|
||||
fmt::print("final_sp: {:016x}\n", jit.GetSP());
|
||||
fmt::print("final_pc: {:016x}\n", jit.GetPC());
|
||||
fmt::print("final_pstate: {:08x}\n", jit.GetPstate());
|
||||
fmt::print("final_fpcr: {:08x}\n", jit.GetFpcr());
|
||||
fmt::print("final_qc : {}\n", FP::FPSR{jit.GetFpsr()}.QC());
|
||||
|
||||
fmt::print("mod_mem:");
|
||||
for (auto [addr, value] : jit_env.modified_memory) {
|
||||
fmt::print(" {:08x}:{:02x}", addr, value);
|
||||
}
|
||||
fmt::print("\n");
|
||||
|
||||
fmt::print("interrupts:\n");
|
||||
for (const auto& i : jit_env.interrupts) {
|
||||
std::puts(i.c_str());
|
||||
}
|
||||
|
||||
fmt::print("===\n");
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::array<u64, 31> initial_regs{};
|
||||
std::array<std::array<u64, 2>, 32> initial_vecs{};
|
||||
std::vector<u32> instructions{};
|
||||
u32 initial_pstate = 0;
|
||||
u32 initial_fpcr = 0;
|
||||
u64 initial_sp = 0;
|
||||
u64 start_address = 100;
|
||||
|
||||
std::string line;
|
||||
while (std::getline(std::cin, line)) {
|
||||
std::string_view sv{line};
|
||||
|
||||
const auto skip_ws = [&] {
|
||||
auto nextpos{sv.find_first_not_of(' ')};
|
||||
if (nextpos != std::string::npos) {
|
||||
sv.remove_prefix(nextpos);
|
||||
}
|
||||
};
|
||||
const auto skip_header = [&] {
|
||||
sv.remove_prefix(sv.find_first_of(':') + 1);
|
||||
skip_ws();
|
||||
};
|
||||
const auto next_token = [&] {
|
||||
auto nextpos{sv.find_first_of(' ')};
|
||||
auto tok{sv.substr(0, nextpos)};
|
||||
sv.remove_prefix(nextpos == std::string::npos ? sv.size() : nextpos);
|
||||
skip_ws();
|
||||
return tok;
|
||||
};
|
||||
const auto parse_hex = [&](std::string_view hex) {
|
||||
u64 result = 0;
|
||||
while (!hex.empty()) {
|
||||
result <<= 4;
|
||||
if (hex.front() >= '0' && hex.front() <= '9') {
|
||||
result += hex.front() - '0';
|
||||
} else if (hex.front() >= 'a' && hex.front() <= 'f') {
|
||||
result += hex.front() - 'a' + 0xA;
|
||||
} else if (hex.front() >= 'A' && hex.front() <= 'F') {
|
||||
result += hex.front() - 'A' + 0xA;
|
||||
} else if (hex.front() == ':') {
|
||||
return result;
|
||||
} else {
|
||||
fmt::print("Character {} is not a valid hex character\n", hex.front());
|
||||
}
|
||||
hex.remove_prefix(1);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
if (sv.starts_with("instructions:")) {
|
||||
skip_header();
|
||||
while (!sv.empty()) {
|
||||
instructions.emplace_back((u32)parse_hex(next_token()));
|
||||
}
|
||||
} else if (sv.starts_with("initial_regs:")) {
|
||||
skip_header();
|
||||
for (size_t i = 0; i < initial_regs.size(); ++i) {
|
||||
initial_regs[i] = parse_hex(next_token());
|
||||
}
|
||||
} else if (sv.starts_with("initial_vecs:")) {
|
||||
skip_header();
|
||||
for (size_t i = 0; i < initial_vecs.size(); ++i) {
|
||||
auto tok{next_token()};
|
||||
initial_vecs[i][0] = parse_hex(tok);
|
||||
tok.remove_prefix(tok.find_first_of(':') + 1);
|
||||
initial_vecs[i][1] = parse_hex(tok);
|
||||
}
|
||||
} else if (sv.starts_with("initial_sp:")) {
|
||||
skip_header();
|
||||
initial_sp = parse_hex(next_token());
|
||||
} else if (sv.starts_with("initial_pstate:")) {
|
||||
skip_header();
|
||||
initial_pstate = (u32)parse_hex(next_token());
|
||||
} else if (sv.starts_with("initial_fpcr:")) {
|
||||
skip_header();
|
||||
initial_fpcr = (u32)parse_hex(next_token());
|
||||
}
|
||||
}
|
||||
|
||||
A64TestEnv jit_env{};
|
||||
A64::Jit jit{GetA64UserConfig(jit_env)};
|
||||
RunTestInstance(jit,
|
||||
jit_env,
|
||||
initial_regs,
|
||||
initial_vecs,
|
||||
instructions,
|
||||
initial_pstate,
|
||||
initial_fpcr,
|
||||
initial_sp,
|
||||
start_address,
|
||||
instructions.size());
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue