A32: Introduce PreCodeTranslationHook
This commit is contained in:
parent
714216fd0e
commit
51b155df92
8 changed files with 59 additions and 21 deletions
|
@ -161,7 +161,7 @@ private:
|
|||
PerformCacheInvalidation();
|
||||
}
|
||||
|
||||
IR::Block ir_block = A32::Translate(A32::LocationDescriptor{descriptor}, [this](u32 vaddr) { return conf.callbacks->MemoryReadCode(vaddr); }, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions});
|
||||
IR::Block ir_block = A32::Translate(A32::LocationDescriptor{descriptor}, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions});
|
||||
if (conf.HasOptimization(OptimizationFlag::GetSetElimination)) {
|
||||
Optimization::A32GetSetElimination(ir_block);
|
||||
Optimization::DeadCodeElimination(ir_block);
|
||||
|
|
|
@ -3,17 +3,18 @@
|
|||
* SPDX-License-Identifier: 0BSD
|
||||
*/
|
||||
|
||||
#include "dynarmic/frontend/A32/location_descriptor.h"
|
||||
#include "dynarmic/frontend/A32/translate/translate.h"
|
||||
|
||||
#include "dynarmic/frontend/A32/location_descriptor.h"
|
||||
#include "dynarmic/ir/basic_block.h"
|
||||
|
||||
namespace Dynarmic::A32 {
|
||||
|
||||
IR::Block TranslateArm(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, const TranslationOptions& options);
|
||||
IR::Block TranslateThumb(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, const TranslationOptions& options);
|
||||
IR::Block TranslateArm(LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options);
|
||||
IR::Block TranslateThumb(LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options);
|
||||
|
||||
IR::Block Translate(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, const TranslationOptions& options) {
|
||||
return (descriptor.TFlag() ? TranslateThumb : TranslateArm)(descriptor, memory_read_code, options);
|
||||
IR::Block Translate(LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options) {
|
||||
return (descriptor.TFlag() ? TranslateThumb : TranslateArm)(descriptor, tcb, options);
|
||||
}
|
||||
|
||||
bool TranslateSingleArmInstruction(IR::Block& block, LocationDescriptor descriptor, u32 instruction);
|
||||
|
|
|
@ -14,6 +14,7 @@ class Block;
|
|||
namespace Dynarmic::A32 {
|
||||
|
||||
class LocationDescriptor;
|
||||
struct TranslateCallbacks;
|
||||
|
||||
using MemoryReadCodeFuncType = std::function<u32(u32 vaddr)>;
|
||||
|
||||
|
@ -34,11 +35,11 @@ struct TranslationOptions {
|
|||
/**
|
||||
* This function translates instructions in memory into our intermediate representation.
|
||||
* @param descriptor The starting location of the basic block. Includes information like PC, Thumb state, &c.
|
||||
* @param memory_read_code The function we should use to read emulated memory.
|
||||
* @param tcb The callbacks we should use to read emulated memory.
|
||||
* @param options Configures how certain instructions are translated.
|
||||
* @return A translated basic block in the intermediate representation.
|
||||
*/
|
||||
IR::Block Translate(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, const TranslationOptions& options);
|
||||
IR::Block Translate(LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options);
|
||||
|
||||
/**
|
||||
* This function translates a single provided instruction into our intermediate representation.
|
||||
|
|
|
@ -11,13 +11,14 @@
|
|||
#include "dynarmic/frontend/A32/translate/conditional_state.h"
|
||||
#include "dynarmic/frontend/A32/translate/impl/translate.h"
|
||||
#include "dynarmic/frontend/A32/translate/translate.h"
|
||||
#include "dynarmic/frontend/A32/translate/translate_callbacks.h"
|
||||
#include "dynarmic/frontend/A32/types.h"
|
||||
#include "dynarmic/interface/A32/config.h"
|
||||
#include "dynarmic/ir/basic_block.h"
|
||||
|
||||
namespace Dynarmic::A32 {
|
||||
|
||||
IR::Block TranslateArm(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, const TranslationOptions& options) {
|
||||
IR::Block TranslateArm(LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options) {
|
||||
const bool single_step = descriptor.SingleStepping();
|
||||
|
||||
IR::Block block{descriptor};
|
||||
|
@ -26,9 +27,11 @@ IR::Block TranslateArm(LocationDescriptor descriptor, MemoryReadCodeFuncType mem
|
|||
bool should_continue = true;
|
||||
do {
|
||||
const u32 arm_pc = visitor.ir.current_location.PC();
|
||||
const u32 arm_instruction = memory_read_code(arm_pc);
|
||||
const u32 arm_instruction = tcb->MemoryReadCode(arm_pc);
|
||||
visitor.current_instruction_size = 4;
|
||||
|
||||
tcb->PreCodeTranslationHook(false, arm_pc, visitor.ir);
|
||||
|
||||
if (const auto vfp_decoder = DecodeVFP<TranslatorVisitor>(arm_instruction)) {
|
||||
should_continue = vfp_decoder->get().call(visitor, arm_instruction);
|
||||
} else if (const auto asimd_decoder = DecodeASIMD<TranslatorVisitor>(arm_instruction)) {
|
||||
|
|
25
src/dynarmic/frontend/A32/translate/translate_callbacks.h
Normal file
25
src/dynarmic/frontend/A32/translate/translate_callbacks.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2021 MerryMage
|
||||
* SPDX-License-Identifier: 0BSD
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "dynarmic/common/common_types.h"
|
||||
|
||||
namespace Dynarmic::A32 {
|
||||
|
||||
using VAddr = u32;
|
||||
|
||||
class IREmitter;
|
||||
|
||||
struct TranslateCallbacks {
|
||||
// All reads through this callback are 4-byte aligned.
|
||||
// Memory must be interpreted as little endian.
|
||||
virtual std::uint32_t MemoryReadCode(VAddr vaddr) = 0;
|
||||
|
||||
// Thus function is called before the instruction at pc is interpreted.
|
||||
// IR code can be emitted by the callee prior to translation of the instruction.
|
||||
virtual void PreCodeTranslationHook(bool is_thumb, VAddr pc, A32::IREmitter& ir) = 0;
|
||||
};
|
||||
|
||||
} // namespace Dynarmic::A32
|
|
@ -16,6 +16,7 @@
|
|||
#include "dynarmic/frontend/A32/translate/conditional_state.h"
|
||||
#include "dynarmic/frontend/A32/translate/impl/translate.h"
|
||||
#include "dynarmic/frontend/A32/translate/translate.h"
|
||||
#include "dynarmic/frontend/A32/translate/translate_callbacks.h"
|
||||
#include "dynarmic/frontend/imm.h"
|
||||
#include "dynarmic/interface/A32/config.h"
|
||||
|
||||
|
@ -40,8 +41,8 @@ bool IsUnconditionalInstruction(bool is_thumb_16, u32 instruction) {
|
|||
return false;
|
||||
}
|
||||
|
||||
std::tuple<u32, ThumbInstSize> ReadThumbInstruction(u32 arm_pc, MemoryReadCodeFuncType memory_read_code) {
|
||||
u32 first_part = memory_read_code(arm_pc & 0xFFFFFFFC);
|
||||
std::tuple<u32, ThumbInstSize> ReadThumbInstruction(u32 arm_pc, TranslateCallbacks* tcb) {
|
||||
u32 first_part = tcb->MemoryReadCode(arm_pc & 0xFFFFFFFC);
|
||||
if ((arm_pc & 0x2) != 0) {
|
||||
first_part >>= 16;
|
||||
}
|
||||
|
@ -55,7 +56,7 @@ std::tuple<u32, ThumbInstSize> ReadThumbInstruction(u32 arm_pc, MemoryReadCodeFu
|
|||
// 32-bit thumb instruction
|
||||
// These always start with 0b11101, 0b11110 or 0b11111.
|
||||
|
||||
u32 second_part = memory_read_code((arm_pc + 2) & 0xFFFFFFFC);
|
||||
u32 second_part = tcb->MemoryReadCode((arm_pc + 2) & 0xFFFFFFFC);
|
||||
if (((arm_pc + 2) & 0x2) != 0) {
|
||||
second_part >>= 16;
|
||||
}
|
||||
|
@ -84,7 +85,7 @@ bool MaybeVFPOrASIMDInstruction(u32 thumb_instruction) {
|
|||
|
||||
} // local namespace
|
||||
|
||||
IR::Block TranslateThumb(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, const TranslationOptions& options) {
|
||||
IR::Block TranslateThumb(LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options) {
|
||||
const bool single_step = descriptor.SingleStepping();
|
||||
|
||||
IR::Block block{descriptor};
|
||||
|
@ -93,10 +94,12 @@ IR::Block TranslateThumb(LocationDescriptor descriptor, MemoryReadCodeFuncType m
|
|||
bool should_continue = true;
|
||||
do {
|
||||
const u32 arm_pc = visitor.ir.current_location.PC();
|
||||
const auto [thumb_instruction, inst_size] = ReadThumbInstruction(arm_pc, memory_read_code);
|
||||
const auto [thumb_instruction, inst_size] = ReadThumbInstruction(arm_pc, tcb);
|
||||
const bool is_thumb_16 = inst_size == ThumbInstSize::Thumb16;
|
||||
visitor.current_instruction_size = is_thumb_16 ? 2 : 4;
|
||||
|
||||
tcb->PreCodeTranslationHook(false, arm_pc, visitor.ir);
|
||||
|
||||
if (IsUnconditionalInstruction(is_thumb_16, thumb_instruction) || visitor.ThumbConditionPassed()) {
|
||||
if (is_thumb_16) {
|
||||
if (const auto decoder = DecodeThumb16<TranslatorVisitor>(static_cast<u16>(thumb_instruction))) {
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
#include "dynarmic/frontend/A32/translate/translate_callbacks.h"
|
||||
#include "dynarmic/interface/A32/arch_version.h"
|
||||
#include "dynarmic/interface/optimization_flags.h"
|
||||
|
||||
|
@ -53,12 +54,16 @@ enum class Exception {
|
|||
};
|
||||
|
||||
/// These function pointers may be inserted into compiled code.
|
||||
struct UserCallbacks {
|
||||
struct UserCallbacks : public TranslateCallbacks {
|
||||
virtual ~UserCallbacks() = default;
|
||||
|
||||
// All reads through this callback are 4-byte aligned.
|
||||
// Memory must be interpreted as little endian.
|
||||
virtual std::uint32_t MemoryReadCode(VAddr vaddr) { return MemoryRead32(vaddr); }
|
||||
std::uint32_t MemoryReadCode(VAddr vaddr) override { return MemoryRead32(vaddr); }
|
||||
|
||||
// Thus function is called before the instruction at pc is interpreted.
|
||||
// IR code can be emitted by the callee prior to translation of the instruction.
|
||||
void PreCodeTranslationHook(bool /*is_thumb*/, VAddr /*pc*/, A32::IREmitter& /*ir*/) override {}
|
||||
|
||||
// Reads through these callbacks may not be aligned.
|
||||
// Memory must be interpreted as if ENDIANSTATE == 0, endianness will be corrected by the JIT.
|
||||
|
@ -83,7 +88,7 @@ struct UserCallbacks {
|
|||
// return the same value at any point in time for this vaddr. The JIT may use this information
|
||||
// in optimizations.
|
||||
// A conservative implementation that always returns false is safe.
|
||||
virtual bool IsReadOnlyMemory(VAddr /* vaddr */) { return false; }
|
||||
virtual bool IsReadOnlyMemory(VAddr /*vaddr*/) { return false; }
|
||||
|
||||
/// The interpreter must execute exactly num_instructions starting from PC.
|
||||
virtual void InterpreterFallback(VAddr pc, size_t num_instructions) = 0;
|
||||
|
|
|
@ -19,10 +19,10 @@
|
|||
#include "./testenv.h"
|
||||
#include "dynarmic/common/bit_util.h"
|
||||
#include "dynarmic/common/common_types.h"
|
||||
#include "dynarmic/frontend/A32/disassembler/disassembler.h"
|
||||
#include "dynarmic/frontend/A32/FPSCR.h"
|
||||
#include "dynarmic/frontend/A32/location_descriptor.h"
|
||||
#include "dynarmic/frontend/A32/PSR.h"
|
||||
#include "dynarmic/frontend/A32/disassembler/disassembler.h"
|
||||
#include "dynarmic/frontend/A32/location_descriptor.h"
|
||||
#include "dynarmic/frontend/A32/translate/translate.h"
|
||||
#include "dynarmic/interface/A32/a32.h"
|
||||
#include "dynarmic/ir/basic_block.h"
|
||||
|
@ -177,7 +177,7 @@ static void RunInstance(size_t run_number, ThumbTestEnv& test_env, A32Unicorn<Th
|
|||
size_t num_insts = 0;
|
||||
while (num_insts < instructions_to_execute_count) {
|
||||
A32::LocationDescriptor descriptor = {u32(num_insts * 4), cpsr, A32::FPSCR{}};
|
||||
IR::Block ir_block = A32::Translate(descriptor, [&test_env](u32 vaddr) { return test_env.MemoryReadCode(vaddr); }, {});
|
||||
IR::Block ir_block = A32::Translate(descriptor, &test_env, {});
|
||||
Optimization::A32GetSetElimination(ir_block);
|
||||
Optimization::DeadCodeElimination(ir_block);
|
||||
Optimization::A32ConstantMemoryReads(ir_block, &test_env);
|
||||
|
|
Loading…
Reference in a new issue