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();
|
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)) {
|
if (conf.HasOptimization(OptimizationFlag::GetSetElimination)) {
|
||||||
Optimization::A32GetSetElimination(ir_block);
|
Optimization::A32GetSetElimination(ir_block);
|
||||||
Optimization::DeadCodeElimination(ir_block);
|
Optimization::DeadCodeElimination(ir_block);
|
||||||
|
|
|
@ -3,17 +3,18 @@
|
||||||
* SPDX-License-Identifier: 0BSD
|
* SPDX-License-Identifier: 0BSD
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "dynarmic/frontend/A32/location_descriptor.h"
|
|
||||||
#include "dynarmic/frontend/A32/translate/translate.h"
|
#include "dynarmic/frontend/A32/translate/translate.h"
|
||||||
|
|
||||||
|
#include "dynarmic/frontend/A32/location_descriptor.h"
|
||||||
#include "dynarmic/ir/basic_block.h"
|
#include "dynarmic/ir/basic_block.h"
|
||||||
|
|
||||||
namespace Dynarmic::A32 {
|
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);
|
||||||
IR::Block TranslateThumb(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, 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) {
|
IR::Block Translate(LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options) {
|
||||||
return (descriptor.TFlag() ? TranslateThumb : TranslateArm)(descriptor, memory_read_code, options);
|
return (descriptor.TFlag() ? TranslateThumb : TranslateArm)(descriptor, tcb, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TranslateSingleArmInstruction(IR::Block& block, LocationDescriptor descriptor, u32 instruction);
|
bool TranslateSingleArmInstruction(IR::Block& block, LocationDescriptor descriptor, u32 instruction);
|
||||||
|
|
|
@ -14,6 +14,7 @@ class Block;
|
||||||
namespace Dynarmic::A32 {
|
namespace Dynarmic::A32 {
|
||||||
|
|
||||||
class LocationDescriptor;
|
class LocationDescriptor;
|
||||||
|
struct TranslateCallbacks;
|
||||||
|
|
||||||
using MemoryReadCodeFuncType = std::function<u32(u32 vaddr)>;
|
using MemoryReadCodeFuncType = std::function<u32(u32 vaddr)>;
|
||||||
|
|
||||||
|
@ -34,11 +35,11 @@ struct TranslationOptions {
|
||||||
/**
|
/**
|
||||||
* This function translates instructions in memory into our intermediate representation.
|
* 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 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.
|
* @param options Configures how certain instructions are translated.
|
||||||
* @return A translated basic block in the intermediate representation.
|
* @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.
|
* 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/conditional_state.h"
|
||||||
#include "dynarmic/frontend/A32/translate/impl/translate.h"
|
#include "dynarmic/frontend/A32/translate/impl/translate.h"
|
||||||
#include "dynarmic/frontend/A32/translate/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/frontend/A32/types.h"
|
||||||
#include "dynarmic/interface/A32/config.h"
|
#include "dynarmic/interface/A32/config.h"
|
||||||
#include "dynarmic/ir/basic_block.h"
|
#include "dynarmic/ir/basic_block.h"
|
||||||
|
|
||||||
namespace Dynarmic::A32 {
|
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();
|
const bool single_step = descriptor.SingleStepping();
|
||||||
|
|
||||||
IR::Block block{descriptor};
|
IR::Block block{descriptor};
|
||||||
|
@ -26,9 +27,11 @@ IR::Block TranslateArm(LocationDescriptor descriptor, MemoryReadCodeFuncType mem
|
||||||
bool should_continue = true;
|
bool should_continue = true;
|
||||||
do {
|
do {
|
||||||
const u32 arm_pc = visitor.ir.current_location.PC();
|
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;
|
visitor.current_instruction_size = 4;
|
||||||
|
|
||||||
|
tcb->PreCodeTranslationHook(false, arm_pc, visitor.ir);
|
||||||
|
|
||||||
if (const auto vfp_decoder = DecodeVFP<TranslatorVisitor>(arm_instruction)) {
|
if (const auto vfp_decoder = DecodeVFP<TranslatorVisitor>(arm_instruction)) {
|
||||||
should_continue = vfp_decoder->get().call(visitor, arm_instruction);
|
should_continue = vfp_decoder->get().call(visitor, arm_instruction);
|
||||||
} else if (const auto asimd_decoder = DecodeASIMD<TranslatorVisitor>(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/conditional_state.h"
|
||||||
#include "dynarmic/frontend/A32/translate/impl/translate.h"
|
#include "dynarmic/frontend/A32/translate/impl/translate.h"
|
||||||
#include "dynarmic/frontend/A32/translate/translate.h"
|
#include "dynarmic/frontend/A32/translate/translate.h"
|
||||||
|
#include "dynarmic/frontend/A32/translate/translate_callbacks.h"
|
||||||
#include "dynarmic/frontend/imm.h"
|
#include "dynarmic/frontend/imm.h"
|
||||||
#include "dynarmic/interface/A32/config.h"
|
#include "dynarmic/interface/A32/config.h"
|
||||||
|
|
||||||
|
@ -40,8 +41,8 @@ bool IsUnconditionalInstruction(bool is_thumb_16, u32 instruction) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<u32, ThumbInstSize> ReadThumbInstruction(u32 arm_pc, MemoryReadCodeFuncType memory_read_code) {
|
std::tuple<u32, ThumbInstSize> ReadThumbInstruction(u32 arm_pc, TranslateCallbacks* tcb) {
|
||||||
u32 first_part = memory_read_code(arm_pc & 0xFFFFFFFC);
|
u32 first_part = tcb->MemoryReadCode(arm_pc & 0xFFFFFFFC);
|
||||||
if ((arm_pc & 0x2) != 0) {
|
if ((arm_pc & 0x2) != 0) {
|
||||||
first_part >>= 16;
|
first_part >>= 16;
|
||||||
}
|
}
|
||||||
|
@ -55,7 +56,7 @@ std::tuple<u32, ThumbInstSize> ReadThumbInstruction(u32 arm_pc, MemoryReadCodeFu
|
||||||
// 32-bit thumb instruction
|
// 32-bit thumb instruction
|
||||||
// These always start with 0b11101, 0b11110 or 0b11111.
|
// 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) {
|
if (((arm_pc + 2) & 0x2) != 0) {
|
||||||
second_part >>= 16;
|
second_part >>= 16;
|
||||||
}
|
}
|
||||||
|
@ -84,7 +85,7 @@ bool MaybeVFPOrASIMDInstruction(u32 thumb_instruction) {
|
||||||
|
|
||||||
} // local namespace
|
} // 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();
|
const bool single_step = descriptor.SingleStepping();
|
||||||
|
|
||||||
IR::Block block{descriptor};
|
IR::Block block{descriptor};
|
||||||
|
@ -93,10 +94,12 @@ IR::Block TranslateThumb(LocationDescriptor descriptor, MemoryReadCodeFuncType m
|
||||||
bool should_continue = true;
|
bool should_continue = true;
|
||||||
do {
|
do {
|
||||||
const u32 arm_pc = visitor.ir.current_location.PC();
|
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;
|
const bool is_thumb_16 = inst_size == ThumbInstSize::Thumb16;
|
||||||
visitor.current_instruction_size = is_thumb_16 ? 2 : 4;
|
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 (IsUnconditionalInstruction(is_thumb_16, thumb_instruction) || visitor.ThumbConditionPassed()) {
|
||||||
if (is_thumb_16) {
|
if (is_thumb_16) {
|
||||||
if (const auto decoder = DecodeThumb16<TranslatorVisitor>(static_cast<u16>(thumb_instruction))) {
|
if (const auto decoder = DecodeThumb16<TranslatorVisitor>(static_cast<u16>(thumb_instruction))) {
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#include "dynarmic/frontend/A32/translate/translate_callbacks.h"
|
||||||
#include "dynarmic/interface/A32/arch_version.h"
|
#include "dynarmic/interface/A32/arch_version.h"
|
||||||
#include "dynarmic/interface/optimization_flags.h"
|
#include "dynarmic/interface/optimization_flags.h"
|
||||||
|
|
||||||
|
@ -53,12 +54,16 @@ enum class Exception {
|
||||||
};
|
};
|
||||||
|
|
||||||
/// These function pointers may be inserted into compiled code.
|
/// These function pointers may be inserted into compiled code.
|
||||||
struct UserCallbacks {
|
struct UserCallbacks : public TranslateCallbacks {
|
||||||
virtual ~UserCallbacks() = default;
|
virtual ~UserCallbacks() = default;
|
||||||
|
|
||||||
// All reads through this callback are 4-byte aligned.
|
// All reads through this callback are 4-byte aligned.
|
||||||
// Memory must be interpreted as little endian.
|
// 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.
|
// Reads through these callbacks may not be aligned.
|
||||||
// Memory must be interpreted as if ENDIANSTATE == 0, endianness will be corrected by the JIT.
|
// 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
|
// return the same value at any point in time for this vaddr. The JIT may use this information
|
||||||
// in optimizations.
|
// in optimizations.
|
||||||
// A conservative implementation that always returns false is safe.
|
// 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.
|
/// The interpreter must execute exactly num_instructions starting from PC.
|
||||||
virtual void InterpreterFallback(VAddr pc, size_t num_instructions) = 0;
|
virtual void InterpreterFallback(VAddr pc, size_t num_instructions) = 0;
|
||||||
|
|
|
@ -19,10 +19,10 @@
|
||||||
#include "./testenv.h"
|
#include "./testenv.h"
|
||||||
#include "dynarmic/common/bit_util.h"
|
#include "dynarmic/common/bit_util.h"
|
||||||
#include "dynarmic/common/common_types.h"
|
#include "dynarmic/common/common_types.h"
|
||||||
#include "dynarmic/frontend/A32/disassembler/disassembler.h"
|
|
||||||
#include "dynarmic/frontend/A32/FPSCR.h"
|
#include "dynarmic/frontend/A32/FPSCR.h"
|
||||||
#include "dynarmic/frontend/A32/location_descriptor.h"
|
|
||||||
#include "dynarmic/frontend/A32/PSR.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/frontend/A32/translate/translate.h"
|
||||||
#include "dynarmic/interface/A32/a32.h"
|
#include "dynarmic/interface/A32/a32.h"
|
||||||
#include "dynarmic/ir/basic_block.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;
|
size_t num_insts = 0;
|
||||||
while (num_insts < instructions_to_execute_count) {
|
while (num_insts < instructions_to_execute_count) {
|
||||||
A32::LocationDescriptor descriptor = {u32(num_insts * 4), cpsr, A32::FPSCR{}};
|
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::A32GetSetElimination(ir_block);
|
||||||
Optimization::DeadCodeElimination(ir_block);
|
Optimization::DeadCodeElimination(ir_block);
|
||||||
Optimization::A32ConstantMemoryReads(ir_block, &test_env);
|
Optimization::A32ConstantMemoryReads(ir_block, &test_env);
|
||||||
|
|
Loading…
Reference in a new issue