A32: Change UserCallbacks to be similar to A64's interface

This commit is contained in:
MerryMage 2018-01-27 22:36:55 +00:00
parent b9ce660113
commit 98ec9c5f90
21 changed files with 472 additions and 622 deletions

View file

@ -1,6 +1,6 @@
add_library(dynarmic
../include/dynarmic/A32/a32.h
../include/dynarmic/A32/callbacks.h
../include/dynarmic/A32/config.h
../include/dynarmic/A32/coprocessor.h
../include/dynarmic/A32/coprocessor_util.h
../include/dynarmic/A32/disassembler.h

View file

@ -13,6 +13,7 @@
#include "backend_x64/a32_jitstate.h"
#include "backend_x64/abi.h"
#include "backend_x64/block_of_code.h"
#include "backend_x64/devirtualize.h"
#include "backend_x64/emit_x64.h"
#include "common/address_range.h"
#include "common/assert.h"
@ -67,8 +68,8 @@ bool A32EmitContext::FPSCR_DN() const {
return Location().FPSCR().DN();
}
A32EmitX64::A32EmitX64(BlockOfCode* code, A32::UserCallbacks cb, A32::Jit* jit_interface)
: EmitX64(code), cb(cb), jit_interface(jit_interface)
A32EmitX64::A32EmitX64(BlockOfCode* code, A32::UserConfig config, A32::Jit* jit_interface)
: EmitX64(code), config(config), jit_interface(jit_interface)
{
GenMemoryAccessors();
code->PreludeComplete();
@ -146,56 +147,56 @@ void A32EmitX64::GenMemoryAccessors() {
code->align();
read_memory_8 = code->getCurr<const void*>();
ABI_PushCallerSaveRegistersAndAdjustStack(code);
code->CallFunction(cb.memory.Read8);
DEVIRT(config.callbacks, &A32::UserCallbacks::MemoryRead8).EmitCall(code);
ABI_PopCallerSaveRegistersAndAdjustStack(code);
code->ret();
code->align();
read_memory_16 = code->getCurr<const void*>();
ABI_PushCallerSaveRegistersAndAdjustStack(code);
code->CallFunction(cb.memory.Read16);
DEVIRT(config.callbacks, &A32::UserCallbacks::MemoryRead16).EmitCall(code);
ABI_PopCallerSaveRegistersAndAdjustStack(code);
code->ret();
code->align();
read_memory_32 = code->getCurr<const void*>();
ABI_PushCallerSaveRegistersAndAdjustStack(code);
code->CallFunction(cb.memory.Read32);
DEVIRT(config.callbacks, &A32::UserCallbacks::MemoryRead32).EmitCall(code);
ABI_PopCallerSaveRegistersAndAdjustStack(code);
code->ret();
code->align();
read_memory_64 = code->getCurr<const void*>();
ABI_PushCallerSaveRegistersAndAdjustStack(code);
code->CallFunction(cb.memory.Read64);
DEVIRT(config.callbacks, &A32::UserCallbacks::MemoryRead64).EmitCall(code);
ABI_PopCallerSaveRegistersAndAdjustStack(code);
code->ret();
code->align();
write_memory_8 = code->getCurr<const void*>();
ABI_PushCallerSaveRegistersAndAdjustStack(code);
code->CallFunction(cb.memory.Write8);
DEVIRT(config.callbacks, &A32::UserCallbacks::MemoryWrite8).EmitCall(code);
ABI_PopCallerSaveRegistersAndAdjustStack(code);
code->ret();
code->align();
write_memory_16 = code->getCurr<const void*>();
ABI_PushCallerSaveRegistersAndAdjustStack(code);
code->CallFunction(cb.memory.Write16);
DEVIRT(config.callbacks, &A32::UserCallbacks::MemoryWrite16).EmitCall(code);
ABI_PopCallerSaveRegistersAndAdjustStack(code);
code->ret();
code->align();
write_memory_32 = code->getCurr<const void*>();
ABI_PushCallerSaveRegistersAndAdjustStack(code);
code->CallFunction(cb.memory.Write32);
DEVIRT(config.callbacks, &A32::UserCallbacks::MemoryWrite32).EmitCall(code);
ABI_PopCallerSaveRegistersAndAdjustStack(code);
code->ret();
code->align();
write_memory_64 = code->getCurr<const void*>();
ABI_PushCallerSaveRegistersAndAdjustStack(code);
code->CallFunction(cb.memory.Write64);
DEVIRT(config.callbacks, &A32::UserCallbacks::MemoryWrite64).EmitCall(code);
ABI_PopCallerSaveRegistersAndAdjustStack(code);
code->ret();
}
@ -568,14 +569,14 @@ void A32EmitX64::EmitA32CallSupervisor(A32EmitContext& ctx, IR::Inst* inst) {
ctx.reg_alloc.HostCall(nullptr);
code->SwitchMxcsrOnExit();
code->mov(code->ABI_PARAM1, qword[r15 + offsetof(A32JitState, cycles_to_run)]);
code->sub(code->ABI_PARAM1, qword[r15 + offsetof(A32JitState, cycles_remaining)]);
code->CallFunction(cb.AddTicks);
code->mov(code->ABI_PARAM2, qword[r15 + offsetof(A32JitState, cycles_to_run)]);
code->sub(code->ABI_PARAM2, qword[r15 + offsetof(A32JitState, cycles_remaining)]);
DEVIRT(config.callbacks, &A32::UserCallbacks::AddTicks).EmitCall(code);
ctx.reg_alloc.EndOfAllocScope();
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.HostCall(nullptr, args[0]);
code->CallFunction(cb.CallSVC);
code->CallFunction(cb.GetTicksRemaining);
ctx.reg_alloc.HostCall(nullptr, {}, args[0]);
DEVIRT(config.callbacks, &A32::UserCallbacks::CallSVC).EmitCall(code);
DEVIRT(config.callbacks, &A32::UserCallbacks::GetTicksRemaining).EmitCall(code);
code->mov(qword[r15 + offsetof(A32JitState, cycles_to_run)], code->ABI_RETURN);
code->mov(qword[r15 + offsetof(A32JitState, cycles_remaining)], code->ABI_RETURN);
code->SwitchMxcsrOnEntry();
@ -632,26 +633,27 @@ void A32EmitX64::EmitA32SetExclusive(A32EmitContext& ctx, IR::Inst* inst) {
code->mov(dword[r15 + offsetof(A32JitState, exclusive_address)], address);
}
template <typename RawFn>
static void ReadMemory(BlockOfCode* code, RegAlloc& reg_alloc, IR::Inst* inst, const A32::UserCallbacks& cb, size_t bit_size, RawFn raw_fn, const CodePtr wrapped_fn) {
template <typename T, T (A32::UserCallbacks::*raw_fn)(A32::VAddr)>
static void ReadMemory(BlockOfCode* code, RegAlloc& reg_alloc, IR::Inst* inst, const A32::UserConfig& config, const CodePtr wrapped_fn) {
constexpr size_t bit_size = Common::BitSize<T>();
auto args = reg_alloc.GetArgumentInfo(inst);
if (!cb.page_table) {
reg_alloc.HostCall(inst, args[0]);
code->CallFunction(raw_fn);
if (!config.page_table) {
reg_alloc.HostCall(inst, {}, args[0]);
DEVIRT(config.callbacks, raw_fn).EmitCall(code);
return;
}
reg_alloc.UseScratch(args[0], ABI_PARAM1);
reg_alloc.UseScratch(args[0], ABI_PARAM2);
Xbyak::Reg64 result = reg_alloc.ScratchGpr({ABI_RETURN});
Xbyak::Reg32 vaddr = code->ABI_PARAM1.cvt32();
Xbyak::Reg32 vaddr = code->ABI_PARAM2.cvt32();
Xbyak::Reg64 page_index = reg_alloc.ScratchGpr();
Xbyak::Reg64 page_offset = reg_alloc.ScratchGpr();
Xbyak::Label abort, end;
code->mov(result, reinterpret_cast<u64>(cb.page_table));
code->mov(result, reinterpret_cast<u64>(config.page_table));
code->mov(page_index.cvt32(), vaddr);
code->shr(page_index.cvt32(), 12);
code->mov(result, qword[result + page_index * 8]);
@ -684,28 +686,29 @@ static void ReadMemory(BlockOfCode* code, RegAlloc& reg_alloc, IR::Inst* inst, c
reg_alloc.DefineValue(inst, result);
}
template <typename RawFn>
static void WriteMemory(BlockOfCode* code, RegAlloc& reg_alloc, IR::Inst* inst, const A32::UserCallbacks& cb, size_t bit_size, RawFn raw_fn, const CodePtr wrapped_fn) {
template <typename T, void (A32::UserCallbacks::*raw_fn)(A32::VAddr, T)>
static void WriteMemory(BlockOfCode* code, RegAlloc& reg_alloc, IR::Inst* inst, const A32::UserConfig& config, const CodePtr wrapped_fn) {
constexpr size_t bit_size = Common::BitSize<T>();
auto args = reg_alloc.GetArgumentInfo(inst);
if (!cb.page_table) {
reg_alloc.HostCall(nullptr, args[0], args[1]);
code->CallFunction(raw_fn);
if (!config.page_table) {
reg_alloc.HostCall(nullptr, {}, args[0], args[1]);
DEVIRT(config.callbacks, raw_fn).EmitCall(code);
return;
}
reg_alloc.ScratchGpr({ABI_RETURN});
reg_alloc.UseScratch(args[0], ABI_PARAM1);
reg_alloc.UseScratch(args[1], ABI_PARAM2);
reg_alloc.UseScratch(args[0], ABI_PARAM2);
reg_alloc.UseScratch(args[1], ABI_PARAM3);
Xbyak::Reg32 vaddr = code->ABI_PARAM1.cvt32();
Xbyak::Reg64 value = code->ABI_PARAM2;
Xbyak::Reg32 vaddr = code->ABI_PARAM2.cvt32();
Xbyak::Reg64 value = code->ABI_PARAM3;
Xbyak::Reg64 page_index = reg_alloc.ScratchGpr();
Xbyak::Reg64 page_offset = reg_alloc.ScratchGpr();
Xbyak::Label abort, end;
code->mov(rax, reinterpret_cast<u64>(cb.page_table));
code->mov(rax, reinterpret_cast<u64>(config.page_table));
code->mov(page_index.cvt32(), vaddr);
code->shr(page_index.cvt32(), 12);
code->mov(rax, qword[rax + page_index * 8]);
@ -737,44 +740,44 @@ static void WriteMemory(BlockOfCode* code, RegAlloc& reg_alloc, IR::Inst* inst,
}
void A32EmitX64::EmitA32ReadMemory8(A32EmitContext& ctx, IR::Inst* inst) {
ReadMemory(code, ctx.reg_alloc, inst, cb, 8, cb.memory.Read8, read_memory_8);
ReadMemory<u8, &A32::UserCallbacks::MemoryRead8>(code, ctx.reg_alloc, inst, config, read_memory_8);
}
void A32EmitX64::EmitA32ReadMemory16(A32EmitContext& ctx, IR::Inst* inst) {
ReadMemory(code, ctx.reg_alloc, inst, cb, 16, cb.memory.Read16, read_memory_16);
ReadMemory<u16, &A32::UserCallbacks::MemoryRead16>(code, ctx.reg_alloc, inst, config, read_memory_16);
}
void A32EmitX64::EmitA32ReadMemory32(A32EmitContext& ctx, IR::Inst* inst) {
ReadMemory(code, ctx.reg_alloc, inst, cb, 32, cb.memory.Read32, read_memory_32);
ReadMemory<u32, &A32::UserCallbacks::MemoryRead32>(code, ctx.reg_alloc, inst, config, read_memory_32);
}
void A32EmitX64::EmitA32ReadMemory64(A32EmitContext& ctx, IR::Inst* inst) {
ReadMemory(code, ctx.reg_alloc, inst, cb, 64, cb.memory.Read64, read_memory_64);
ReadMemory<u64, &A32::UserCallbacks::MemoryRead64>(code, ctx.reg_alloc, inst, config, read_memory_64);
}
void A32EmitX64::EmitA32WriteMemory8(A32EmitContext& ctx, IR::Inst* inst) {
WriteMemory(code, ctx.reg_alloc, inst, cb, 8, cb.memory.Write8, write_memory_8);
WriteMemory<u8, &A32::UserCallbacks::MemoryWrite8>(code, ctx.reg_alloc, inst, config, write_memory_8);
}
void A32EmitX64::EmitA32WriteMemory16(A32EmitContext& ctx, IR::Inst* inst) {
WriteMemory(code, ctx.reg_alloc, inst, cb, 16, cb.memory.Write16, write_memory_16);
WriteMemory<u16, &A32::UserCallbacks::MemoryWrite16>(code, ctx.reg_alloc, inst, config, write_memory_16);
}
void A32EmitX64::EmitA32WriteMemory32(A32EmitContext& ctx, IR::Inst* inst) {
WriteMemory(code, ctx.reg_alloc, inst, cb, 32, cb.memory.Write32, write_memory_32);
WriteMemory<u32, &A32::UserCallbacks::MemoryWrite32>(code, ctx.reg_alloc, inst, config, write_memory_32);
}
void A32EmitX64::EmitA32WriteMemory64(A32EmitContext& ctx, IR::Inst* inst) {
WriteMemory(code, ctx.reg_alloc, inst, cb, 64, cb.memory.Write64, write_memory_64);
WriteMemory<u64, &A32::UserCallbacks::MemoryWrite64>(code, ctx.reg_alloc, inst, config, write_memory_64);
}
template <typename FunctionPointer>
static void ExclusiveWrite(BlockOfCode* code, RegAlloc& reg_alloc, IR::Inst* inst, FunctionPointer fn, bool prepend_high_word) {
template <typename T, void (A32::UserCallbacks::*fn)(A32::VAddr, T)>
static void ExclusiveWrite(BlockOfCode* code, RegAlloc& reg_alloc, IR::Inst* inst, const A32::UserConfig& config, bool prepend_high_word) {
auto args = reg_alloc.GetArgumentInfo(inst);
if (prepend_high_word) {
reg_alloc.HostCall(nullptr, args[0], args[1], args[2]);
reg_alloc.HostCall(nullptr, {}, args[0], args[1], args[2]);
} else {
reg_alloc.HostCall(nullptr, args[0], args[1]);
reg_alloc.HostCall(nullptr, {}, args[0], args[1]);
}
Xbyak::Reg32 passed = reg_alloc.ScratchGpr().cvt32();
Xbyak::Reg32 tmp = code->ABI_RETURN.cvt32(); // Use one of the unusued HostCall registers.
@ -784,17 +787,17 @@ static void ExclusiveWrite(BlockOfCode* code, RegAlloc& reg_alloc, IR::Inst* ins
code->mov(passed, u32(1));
code->cmp(code->byte[r15 + offsetof(A32JitState, exclusive_state)], u8(0));
code->je(end);
code->mov(tmp, code->ABI_PARAM1);
code->mov(tmp, code->ABI_PARAM2);
code->xor_(tmp, dword[r15 + offsetof(A32JitState, exclusive_address)]);
code->test(tmp, A32JitState::RESERVATION_GRANULE_MASK);
code->jne(end);
code->mov(code->byte[r15 + offsetof(A32JitState, exclusive_state)], u8(0));
if (prepend_high_word) {
code->mov(code->ABI_PARAM2.cvt32(), code->ABI_PARAM2.cvt32()); // zero extend to 64-bits
code->shl(code->ABI_PARAM3, 32);
code->or_(code->ABI_PARAM2, code->ABI_PARAM3);
code->mov(code->ABI_PARAM3.cvt32(), code->ABI_PARAM3.cvt32()); // zero extend to 64-bits
code->shl(code->ABI_PARAM4, 32);
code->or_(code->ABI_PARAM3, code->ABI_PARAM4);
}
code->CallFunction(fn);
DEVIRT(config.callbacks, fn).EmitCall(code);
code->xor_(passed, passed);
code->L(end);
@ -802,19 +805,19 @@ static void ExclusiveWrite(BlockOfCode* code, RegAlloc& reg_alloc, IR::Inst* ins
}
void A32EmitX64::EmitA32ExclusiveWriteMemory8(A32EmitContext& ctx, IR::Inst* inst) {
ExclusiveWrite(code, ctx.reg_alloc, inst, cb.memory.Write8, false);
ExclusiveWrite<u8, &A32::UserCallbacks::MemoryWrite8>(code, ctx.reg_alloc, inst, config, false);
}
void A32EmitX64::EmitA32ExclusiveWriteMemory16(A32EmitContext& ctx, IR::Inst* inst) {
ExclusiveWrite(code, ctx.reg_alloc, inst, cb.memory.Write16, false);
ExclusiveWrite<u16, &A32::UserCallbacks::MemoryWrite16>(code, ctx.reg_alloc, inst, config, false);
}
void A32EmitX64::EmitA32ExclusiveWriteMemory32(A32EmitContext& ctx, IR::Inst* inst) {
ExclusiveWrite(code, ctx.reg_alloc, inst, cb.memory.Write32, false);
ExclusiveWrite<u32, &A32::UserCallbacks::MemoryWrite32>(code, ctx.reg_alloc, inst, config, false);
}
void A32EmitX64::EmitA32ExclusiveWriteMemory64(A32EmitContext& ctx, IR::Inst* inst) {
ExclusiveWrite(code, ctx.reg_alloc, inst, cb.memory.Write64, true);
ExclusiveWrite<u64, &A32::UserCallbacks::MemoryWrite64>(code, ctx.reg_alloc, inst, config, true);
}
static void EmitCoprocessorException() {
@ -843,7 +846,7 @@ void A32EmitX64::EmitA32CoprocInternalOperation(A32EmitContext& ctx, IR::Inst* i
A32::CoprocReg CRm = static_cast<A32::CoprocReg>(coproc_info[5]);
unsigned opc2 = static_cast<unsigned>(coproc_info[6]);
std::shared_ptr<A32::Coprocessor> coproc = cb.coprocessors[coproc_num];
std::shared_ptr<A32::Coprocessor> coproc = config.coprocessors[coproc_num];
if (!coproc) {
EmitCoprocessorException();
return;
@ -869,7 +872,7 @@ void A32EmitX64::EmitA32CoprocSendOneWord(A32EmitContext& ctx, IR::Inst* inst) {
A32::CoprocReg CRm = static_cast<A32::CoprocReg>(coproc_info[4]);
unsigned opc2 = static_cast<unsigned>(coproc_info[5]);
std::shared_ptr<A32::Coprocessor> coproc = cb.coprocessors[coproc_num];
std::shared_ptr<A32::Coprocessor> coproc = config.coprocessors[coproc_num];
if (!coproc) {
EmitCoprocessorException();
return;
@ -908,7 +911,7 @@ void A32EmitX64::EmitA32CoprocSendTwoWords(A32EmitContext& ctx, IR::Inst* inst)
unsigned opc = static_cast<unsigned>(coproc_info[2]);
A32::CoprocReg CRm = static_cast<A32::CoprocReg>(coproc_info[3]);
std::shared_ptr<A32::Coprocessor> coproc = cb.coprocessors[coproc_num];
std::shared_ptr<A32::Coprocessor> coproc = config.coprocessors[coproc_num];
if (!coproc) {
EmitCoprocessorException();
return;
@ -951,7 +954,7 @@ void A32EmitX64::EmitA32CoprocGetOneWord(A32EmitContext& ctx, IR::Inst* inst) {
A32::CoprocReg CRm = static_cast<A32::CoprocReg>(coproc_info[4]);
unsigned opc2 = static_cast<unsigned>(coproc_info[5]);
std::shared_ptr<A32::Coprocessor> coproc = cb.coprocessors[coproc_num];
std::shared_ptr<A32::Coprocessor> coproc = config.coprocessors[coproc_num];
if (!coproc) {
EmitCoprocessorException();
return;
@ -991,7 +994,7 @@ void A32EmitX64::EmitA32CoprocGetTwoWords(A32EmitContext& ctx, IR::Inst* inst) {
unsigned opc = coproc_info[2];
A32::CoprocReg CRm = static_cast<A32::CoprocReg>(coproc_info[3]);
std::shared_ptr<A32::Coprocessor> coproc = cb.coprocessors[coproc_num];
std::shared_ptr<A32::Coprocessor> coproc = config.coprocessors[coproc_num];
if (!coproc) {
EmitCoprocessorException();
return;
@ -1039,7 +1042,7 @@ void A32EmitX64::EmitA32CoprocLoadWords(A32EmitContext& ctx, IR::Inst* inst) {
bool has_option = coproc_info[4] != 0;
boost::optional<u8> option{has_option, coproc_info[5]};
std::shared_ptr<A32::Coprocessor> coproc = cb.coprocessors[coproc_num];
std::shared_ptr<A32::Coprocessor> coproc = config.coprocessors[coproc_num];
if (!coproc) {
EmitCoprocessorException();
return;
@ -1065,7 +1068,7 @@ void A32EmitX64::EmitA32CoprocStoreWords(A32EmitContext& ctx, IR::Inst* inst) {
bool has_option = coproc_info[4] != 0;
boost::optional<u8> option{has_option, coproc_info[5]};
std::shared_ptr<A32::Coprocessor> coproc = cb.coprocessors[coproc_num];
std::shared_ptr<A32::Coprocessor> coproc = config.coprocessors[coproc_num];
if (!coproc) {
EmitCoprocessorException();
return;
@ -1085,12 +1088,11 @@ void A32EmitX64::EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDesc
ASSERT_MSG(A32::LocationDescriptor{terminal.next}.EFlag() == A32::LocationDescriptor{initial_location}.EFlag(), "Unimplemented");
ASSERT_MSG(terminal.num_instructions == 1, "Unimplemented");
code->mov(code->ABI_PARAM1.cvt32(), A32::LocationDescriptor{terminal.next}.PC());
code->mov(code->ABI_PARAM2, reinterpret_cast<u64>(jit_interface));
code->mov(code->ABI_PARAM3, reinterpret_cast<u64>(cb.user_arg));
code->mov(MJitStateReg(A32::Reg::PC), code->ABI_PARAM1.cvt32());
code->mov(code->ABI_PARAM2.cvt32(), A32::LocationDescriptor{terminal.next}.PC());
code->mov(code->ABI_PARAM3.cvt32(), 1);
code->mov(MJitStateReg(A32::Reg::PC), code->ABI_PARAM2.cvt32());
code->SwitchMxcsrOnExit();
code->CallFunction(cb.InterpreterFallback);
DEVIRT(config.callbacks, &A32::UserCallbacks::InterpreterFallback).EmitCall(code);
code->ReturnFromRunCode(true); // TODO: Check cycles
}

View file

@ -12,7 +12,7 @@
#include "backend_x64/block_range_information.h"
#include "backend_x64/emit_x64.h"
#include "dynarmic/A32/a32.h"
#include "dynarmic/A32/callbacks.h"
#include "dynarmic/A32/config.h"
#include "frontend/A32/location_descriptor.h"
#include "frontend/ir/terminal.h"
@ -30,7 +30,7 @@ struct A32EmitContext final : public EmitContext {
class A32EmitX64 final : public EmitX64 {
public:
A32EmitX64(BlockOfCode* code, A32::UserCallbacks cb, A32::Jit* jit_interface);
A32EmitX64(BlockOfCode* code, A32::UserConfig config, A32::Jit* jit_interface);
~A32EmitX64() override;
/**
@ -44,7 +44,7 @@ public:
void InvalidateCacheRanges(const boost::icl::interval_set<u32>& ranges);
protected:
const A32::UserCallbacks cb;
const A32::UserConfig config;
A32::Jit* jit_interface;
BlockRangeInformation<u32> block_ranges;

View file

@ -18,6 +18,7 @@
#include "backend_x64/a32_jitstate.h"
#include "backend_x64/block_of_code.h"
#include "backend_x64/callback.h"
#include "backend_x64/devirtualize.h"
#include "backend_x64/jitstate_info.h"
#include "common/assert.h"
#include "common/common_types.h"
@ -33,26 +34,26 @@ namespace Dynarmic::A32 {
using namespace BackendX64;
static RunCodeCallbacks GenRunCodeCallbacks(A32::UserCallbacks cb, CodePtr (*LookupBlock)(void* lookup_block_arg), void* arg) {
static RunCodeCallbacks GenRunCodeCallbacks(A32::UserCallbacks* cb, CodePtr (*LookupBlock)(void* lookup_block_arg), void* arg) {
return RunCodeCallbacks{
std::make_unique<ArgCallback>(LookupBlock, reinterpret_cast<u64>(arg)),
std::make_unique<SimpleCallback>(cb.AddTicks),
std::make_unique<SimpleCallback>(cb.GetTicksRemaining),
std::make_unique<ArgCallback>(DEVIRT(cb, &A32::UserCallbacks::AddTicks)),
std::make_unique<ArgCallback>(DEVIRT(cb, &A32::UserCallbacks::GetTicksRemaining)),
};
}
struct Jit::Impl {
Impl(Jit* jit, A32::UserCallbacks callbacks)
: block_of_code(GenRunCodeCallbacks(callbacks, &GetCurrentBlock, this), JitStateInfo{jit_state})
, emitter(&block_of_code, callbacks, jit)
, callbacks(callbacks)
Impl(Jit* jit, A32::UserConfig config)
: block_of_code(GenRunCodeCallbacks(config.callbacks, &GetCurrentBlock, this), JitStateInfo{jit_state})
, emitter(&block_of_code, config, jit)
, config(config)
, jit_interface(jit)
{}
A32JitState jit_state;
BlockOfCode block_of_code;
A32EmitX64 emitter;
const A32::UserCallbacks callbacks;
const A32::UserConfig config;
// Requests made during execution to invalidate the cache are queued up here.
size_t invalid_cache_generation = 0;
@ -164,10 +165,10 @@ private:
PerformCacheInvalidation();
}
IR::Block ir_block = A32::Translate(A32::LocationDescriptor{descriptor}, callbacks.memory.ReadCode);
IR::Block ir_block = A32::Translate(A32::LocationDescriptor{descriptor}, [this](u32 vaddr) { return config.callbacks->MemoryReadCode(vaddr); });
Optimization::A32GetSetElimination(ir_block);
Optimization::DeadCodeElimination(ir_block);
Optimization::A32ConstantMemoryReads(ir_block, callbacks.memory);
Optimization::A32ConstantMemoryReads(ir_block, config.callbacks);
Optimization::ConstantPropagation(ir_block);
Optimization::DeadCodeElimination(ir_block);
Optimization::VerificationPass(ir_block);
@ -175,7 +176,7 @@ private:
}
};
Jit::Jit(UserCallbacks callbacks) : impl(std::make_unique<Impl>(this, callbacks)) {}
Jit::Jit(UserConfig config) : impl(std::make_unique<Impl>(this, config)) {}
Jit::~Jit() {}

View file

@ -6,6 +6,7 @@
#pragma once
#include <array>
#include <memory>
#include <type_traits>
@ -16,7 +17,6 @@
#include "backend_x64/constant_pool.h"
#include "backend_x64/jitstate_info.h"
#include "common/common_types.h"
#include "dynarmic/A32/callbacks.h"
namespace Dynarmic::BackendX64 {

View file

@ -30,7 +30,7 @@ struct ThunkBuilder<R(C::*)(Args...), mfp> {
} // namespace impl
template <typename FunctionType, FunctionType mfp>
ArgCallback Devirtualize(mp::class_type_t<decltype(mfp)>* this_) {
ArgCallback Devirtualize(mp::class_type_t<FunctionType>* this_) {
return ArgCallback{&impl::ThunkBuilder<FunctionType, mfp>::Thunk, reinterpret_cast<u64>(this_)};
}

View file

@ -15,7 +15,7 @@ namespace Dynarmic::A32 {
class LocationDescriptor;
using MemoryReadCodeFuncType = u32 (*)(u32 vaddr);
using MemoryReadCodeFuncType = std::function<u32(u32 vaddr)>;
/**
* This function translates instructions in memory into our intermediate representation.

View file

@ -4,7 +4,7 @@
* General Public License version 2 or any later version.
*/
#include <dynarmic/A32/callbacks.h>
#include <dynarmic/A32/config.h>
#include "frontend/ir/basic_block.h"
#include "frontend/ir/opcodes.h"
@ -12,7 +12,7 @@
namespace Dynarmic::Optimization {
void A32ConstantMemoryReads(IR::Block& block, const A32::UserCallbacks::Memory& memory_callbacks) {
void A32ConstantMemoryReads(IR::Block& block, A32::UserCallbacks* cb) {
for (auto& inst : block) {
switch (inst.GetOpcode()) {
case IR::Opcode::A32SetCFlag: {
@ -27,8 +27,8 @@ void A32ConstantMemoryReads(IR::Block& block, const A32::UserCallbacks::Memory&
break;
u32 vaddr = inst.GetArg(0).GetU32();
if (memory_callbacks.IsReadOnlyMemory(vaddr)) {
u8 value_from_memory = memory_callbacks.Read8(vaddr);
if (cb->IsReadOnlyMemory(vaddr)) {
u8 value_from_memory = cb->MemoryRead8(vaddr);
inst.ReplaceUsesWith(IR::Value{value_from_memory});
}
break;
@ -38,8 +38,8 @@ void A32ConstantMemoryReads(IR::Block& block, const A32::UserCallbacks::Memory&
break;
u32 vaddr = inst.GetArg(0).GetU32();
if (memory_callbacks.IsReadOnlyMemory(vaddr)) {
u16 value_from_memory = memory_callbacks.Read16(vaddr);
if (cb->IsReadOnlyMemory(vaddr)) {
u16 value_from_memory = cb->MemoryRead16(vaddr);
inst.ReplaceUsesWith(IR::Value{value_from_memory});
}
break;
@ -49,8 +49,8 @@ void A32ConstantMemoryReads(IR::Block& block, const A32::UserCallbacks::Memory&
break;
u32 vaddr = inst.GetArg(0).GetU32();
if (memory_callbacks.IsReadOnlyMemory(vaddr)) {
u32 value_from_memory = memory_callbacks.Read32(vaddr);
if (cb->IsReadOnlyMemory(vaddr)) {
u32 value_from_memory = cb->MemoryRead32(vaddr);
inst.ReplaceUsesWith(IR::Value{value_from_memory});
}
break;
@ -60,8 +60,8 @@ void A32ConstantMemoryReads(IR::Block& block, const A32::UserCallbacks::Memory&
break;
u32 vaddr = inst.GetArg(0).GetU32();
if (memory_callbacks.IsReadOnlyMemory(vaddr)) {
u64 value_from_memory = memory_callbacks.Read64(vaddr);
if (cb->IsReadOnlyMemory(vaddr)) {
u64 value_from_memory = cb->MemoryRead64(vaddr);
inst.ReplaceUsesWith(IR::Value{value_from_memory});
}
break;

View file

@ -4,7 +4,7 @@
* General Public License version 2 or any later version.
*/
#include <dynarmic/A32/callbacks.h>
#include <dynarmic/A32/config.h>
#include "frontend/ir/basic_block.h"
#include "frontend/ir/opcodes.h"

View file

@ -6,7 +6,7 @@
#pragma once
#include <dynarmic/A32/callbacks.h>
#include <dynarmic/A32/config.h>
#include <dynarmic/A64/config.h>
namespace Dynarmic::IR {
@ -16,7 +16,7 @@ class Block;
namespace Dynarmic::Optimization {
void A32GetSetElimination(IR::Block& block);
void A32ConstantMemoryReads(IR::Block& block, const A32::UserCallbacks::Memory& memory_callbacks);
void A32ConstantMemoryReads(IR::Block& block, A32::UserCallbacks* cb);
void A64GetSetElimination(IR::Block& block);
void A64MergeInterpretBlocksPass(IR::Block& block, A64::UserCallbacks* cb);
void ConstantPropagation(IR::Block& block);