A32: Add arch_version option
This commit is contained in:
parent
51fa6a725a
commit
7e5ae6076a
9 changed files with 76 additions and 8 deletions
23
include/dynarmic/A32/arch_version.h
Normal file
23
include/dynarmic/A32/arch_version.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2020 MerryMage
|
||||
* SPDX-License-Identifier: 0BSD
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Dynarmic {
|
||||
namespace A32 {
|
||||
|
||||
enum class ArchVersion {
|
||||
v3,
|
||||
v4,
|
||||
v4T,
|
||||
v5TE,
|
||||
v6K,
|
||||
v6T2,
|
||||
v7,
|
||||
v8,
|
||||
};
|
||||
|
||||
} // namespace A32
|
||||
} // namespace Dynarmic
|
|
@ -10,6 +10,7 @@
|
|||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
#include <dynarmic/A32/arch_version.h>
|
||||
#include <dynarmic/optimization_flags.h>
|
||||
|
||||
namespace Dynarmic {
|
||||
|
@ -105,6 +106,10 @@ struct UserConfig {
|
|||
size_t processor_id = 0;
|
||||
ExclusiveMonitor* global_monitor = nullptr;
|
||||
|
||||
/// Select the architecture version to use.
|
||||
/// There are minor behavioural differences between versions.
|
||||
ArchVersion arch_version = ArchVersion::v8;
|
||||
|
||||
/// This selects other optimizations than can't otherwise be disabled by setting other
|
||||
/// configuration options. This includes:
|
||||
/// - IR optimizations
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
add_library(dynarmic
|
||||
../include/dynarmic/A32/a32.h
|
||||
../include/dynarmic/A32/arch_version.h
|
||||
../include/dynarmic/A32/config.h
|
||||
../include/dynarmic/A32/coprocessor.h
|
||||
../include/dynarmic/A32/coprocessor_util.h
|
||||
|
|
|
@ -175,7 +175,7 @@ private:
|
|||
PerformCacheInvalidation();
|
||||
}
|
||||
|
||||
IR::Block ir_block = A32::Translate(A32::LocationDescriptor{descriptor}, [this](u32 vaddr) { return conf.callbacks->MemoryReadCode(vaddr); }, {conf.define_unpredictable_behaviour, conf.hook_hint_instructions});
|
||||
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});
|
||||
if (conf.HasOptimization(OptimizationFlag::GetSetElimination)) {
|
||||
Optimization::A32GetSetElimination(ir_block);
|
||||
Optimization::DeadCodeElimination(ir_block);
|
||||
|
|
|
@ -8,10 +8,32 @@
|
|||
#include "frontend/A32/types.h"
|
||||
#include "frontend/ir/opcodes.h"
|
||||
|
||||
#include <dynarmic/A32/arch_version.h>
|
||||
|
||||
namespace Dynarmic::A32 {
|
||||
|
||||
using Opcode = IR::Opcode;
|
||||
|
||||
size_t IREmitter::ArchVersion() const {
|
||||
switch (arch_version) {
|
||||
case ArchVersion::v3:
|
||||
return 3;
|
||||
case ArchVersion::v4:
|
||||
case ArchVersion::v4T:
|
||||
return 4;
|
||||
case ArchVersion::v5TE:
|
||||
return 5;
|
||||
case ArchVersion::v6K:
|
||||
case ArchVersion::v6T2:
|
||||
return 6;
|
||||
case ArchVersion::v7:
|
||||
return 7;
|
||||
case ArchVersion::v8:
|
||||
return 8;
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
u32 IREmitter::PC() const {
|
||||
const u32 offset = current_location.TFlag() ? 4 : 8;
|
||||
return current_location.PC() + offset;
|
||||
|
@ -68,12 +90,16 @@ void IREmitter::SetVector(ExtReg reg, const IR::U128& value) {
|
|||
|
||||
void IREmitter::ALUWritePC(const IR::U32& value) {
|
||||
// This behaviour is ARM version-dependent.
|
||||
// The below implementation is for ARMv6k
|
||||
BranchWritePC(value);
|
||||
if (ArchVersion() >= 7 && !current_location.TFlag()) {
|
||||
BXWritePC(value);
|
||||
} else {
|
||||
BranchWritePC(value);
|
||||
}
|
||||
}
|
||||
|
||||
void IREmitter::BranchWritePC(const IR::U32& value) {
|
||||
if (!current_location.TFlag()) {
|
||||
// Note that for ArchVersion() < 6, this is UNPREDICTABLE when value<1:0> != 0b00
|
||||
const auto new_pc = And(value, Imm32(0xFFFFFFFC));
|
||||
Inst(Opcode::A32SetRegister, IR::Value(A32::Reg::PC), new_pc);
|
||||
} else {
|
||||
|
@ -88,8 +114,11 @@ void IREmitter::BXWritePC(const IR::U32& value) {
|
|||
|
||||
void IREmitter::LoadWritePC(const IR::U32& value) {
|
||||
// This behaviour is ARM version-dependent.
|
||||
// The below implementation is for ARMv6k
|
||||
BXWritePC(value);
|
||||
if (ArchVersion() >= 5) {
|
||||
BXWritePC(value);
|
||||
} else {
|
||||
BranchWritePC(value);
|
||||
}
|
||||
}
|
||||
|
||||
void IREmitter::CallSupervisor(const IR::U32& value) {
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
namespace Dynarmic::A32 {
|
||||
|
||||
enum class ArchVersion;
|
||||
enum class CoprocReg;
|
||||
enum class Exception;
|
||||
enum class ExtReg;
|
||||
|
@ -26,10 +27,12 @@ enum class Reg;
|
|||
*/
|
||||
class IREmitter : public IR::IREmitter {
|
||||
public:
|
||||
explicit IREmitter(IR::Block& block, LocationDescriptor descriptor) : IR::IREmitter(block), current_location(descriptor) {}
|
||||
IREmitter(IR::Block& block, LocationDescriptor descriptor, ArchVersion arch_version) : IR::IREmitter(block), current_location(descriptor), arch_version(arch_version) {}
|
||||
|
||||
LocationDescriptor current_location;
|
||||
|
||||
size_t ArchVersion() const;
|
||||
|
||||
u32 PC() const;
|
||||
u32 AlignPC(size_t alignment) const;
|
||||
|
||||
|
@ -99,6 +102,9 @@ public:
|
|||
IR::U64 CoprocGetTwoWords(size_t coproc_no, bool two, size_t opc, CoprocReg CRm);
|
||||
void CoprocLoadWords(size_t coproc_no, bool two, bool long_transfer, CoprocReg CRd, const IR::U32& address, bool has_option, u8 option);
|
||||
void CoprocStoreWords(size_t coproc_no, bool two, bool long_transfer, CoprocReg CRd, const IR::U32& address, bool has_option, u8 option);
|
||||
|
||||
private:
|
||||
enum ArchVersion arch_version;
|
||||
};
|
||||
|
||||
} // namespace Dynarmic::A32
|
||||
|
|
|
@ -31,7 +31,7 @@ enum class ConditionalState {
|
|||
struct ArmTranslatorVisitor final {
|
||||
using instruction_return_type = bool;
|
||||
|
||||
explicit ArmTranslatorVisitor(IR::Block& block, LocationDescriptor descriptor, const TranslationOptions& options) : ir(block, descriptor), options(options) {
|
||||
explicit ArmTranslatorVisitor(IR::Block& block, LocationDescriptor descriptor, const TranslationOptions& options) : ir(block, descriptor, options.arch_version), options(options) {
|
||||
ASSERT_MSG(!descriptor.TFlag(), "The processor must be in Arm mode");
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ enum class Exception;
|
|||
struct ThumbTranslatorVisitor final {
|
||||
using instruction_return_type = bool;
|
||||
|
||||
explicit ThumbTranslatorVisitor(IR::Block& block, LocationDescriptor descriptor, const TranslationOptions& options) : ir(block, descriptor), options(options) {
|
||||
explicit ThumbTranslatorVisitor(IR::Block& block, LocationDescriptor descriptor, const TranslationOptions& options) : ir(block, descriptor, options.arch_version), options(options) {
|
||||
ASSERT_MSG(descriptor.TFlag(), "The processor must be in Thumb mode");
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
#include "common/common_types.h"
|
||||
|
||||
#include <dynarmic/A32/arch_version.h>
|
||||
|
||||
namespace Dynarmic::IR {
|
||||
class Block;
|
||||
} // namespace Dynarmic::IR
|
||||
|
@ -17,6 +19,8 @@ class LocationDescriptor;
|
|||
using MemoryReadCodeFuncType = std::function<u32(u32 vaddr)>;
|
||||
|
||||
struct TranslationOptions {
|
||||
ArchVersion arch_version;
|
||||
|
||||
/// This changes what IR we emit when we translate an unpredictable instruction.
|
||||
/// If this is false, the ExceptionRaised IR instruction is emitted.
|
||||
/// If this is true, we define some behaviour for some instructions.
|
||||
|
|
Loading…
Reference in a new issue