A32: Add arch_version option

This commit is contained in:
MerryMage 2021-02-07 11:44:01 +00:00
parent 51fa6a725a
commit 7e5ae6076a
9 changed files with 76 additions and 8 deletions

View 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

View file

@ -10,6 +10,7 @@
#include <cstdint> #include <cstdint>
#include <memory> #include <memory>
#include <dynarmic/A32/arch_version.h>
#include <dynarmic/optimization_flags.h> #include <dynarmic/optimization_flags.h>
namespace Dynarmic { namespace Dynarmic {
@ -105,6 +106,10 @@ struct UserConfig {
size_t processor_id = 0; size_t processor_id = 0;
ExclusiveMonitor* global_monitor = nullptr; 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 /// This selects other optimizations than can't otherwise be disabled by setting other
/// configuration options. This includes: /// configuration options. This includes:
/// - IR optimizations /// - IR optimizations

View file

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

View file

@ -175,7 +175,7 @@ private:
PerformCacheInvalidation(); 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)) { if (conf.HasOptimization(OptimizationFlag::GetSetElimination)) {
Optimization::A32GetSetElimination(ir_block); Optimization::A32GetSetElimination(ir_block);
Optimization::DeadCodeElimination(ir_block); Optimization::DeadCodeElimination(ir_block);

View file

@ -8,10 +8,32 @@
#include "frontend/A32/types.h" #include "frontend/A32/types.h"
#include "frontend/ir/opcodes.h" #include "frontend/ir/opcodes.h"
#include <dynarmic/A32/arch_version.h>
namespace Dynarmic::A32 { namespace Dynarmic::A32 {
using Opcode = IR::Opcode; 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 { u32 IREmitter::PC() const {
const u32 offset = current_location.TFlag() ? 4 : 8; const u32 offset = current_location.TFlag() ? 4 : 8;
return current_location.PC() + offset; 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) { void IREmitter::ALUWritePC(const IR::U32& value) {
// This behaviour is ARM version-dependent. // This behaviour is ARM version-dependent.
// The below implementation is for ARMv6k if (ArchVersion() >= 7 && !current_location.TFlag()) {
BranchWritePC(value); BXWritePC(value);
} else {
BranchWritePC(value);
}
} }
void IREmitter::BranchWritePC(const IR::U32& value) { void IREmitter::BranchWritePC(const IR::U32& value) {
if (!current_location.TFlag()) { 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)); const auto new_pc = And(value, Imm32(0xFFFFFFFC));
Inst(Opcode::A32SetRegister, IR::Value(A32::Reg::PC), new_pc); Inst(Opcode::A32SetRegister, IR::Value(A32::Reg::PC), new_pc);
} else { } else {
@ -88,8 +114,11 @@ void IREmitter::BXWritePC(const IR::U32& value) {
void IREmitter::LoadWritePC(const IR::U32& value) { void IREmitter::LoadWritePC(const IR::U32& value) {
// This behaviour is ARM version-dependent. // This behaviour is ARM version-dependent.
// The below implementation is for ARMv6k if (ArchVersion() >= 5) {
BXWritePC(value); BXWritePC(value);
} else {
BranchWritePC(value);
}
} }
void IREmitter::CallSupervisor(const IR::U32& value) { void IREmitter::CallSupervisor(const IR::U32& value) {

View file

@ -14,6 +14,7 @@
namespace Dynarmic::A32 { namespace Dynarmic::A32 {
enum class ArchVersion;
enum class CoprocReg; enum class CoprocReg;
enum class Exception; enum class Exception;
enum class ExtReg; enum class ExtReg;
@ -26,10 +27,12 @@ enum class Reg;
*/ */
class IREmitter : public IR::IREmitter { class IREmitter : public IR::IREmitter {
public: 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; LocationDescriptor current_location;
size_t ArchVersion() const;
u32 PC() const; u32 PC() const;
u32 AlignPC(size_t alignment) 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); 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 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); 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 } // namespace Dynarmic::A32

View file

@ -31,7 +31,7 @@ enum class ConditionalState {
struct ArmTranslatorVisitor final { struct ArmTranslatorVisitor final {
using instruction_return_type = bool; 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"); ASSERT_MSG(!descriptor.TFlag(), "The processor must be in Arm mode");
} }

View file

@ -19,7 +19,7 @@ enum class Exception;
struct ThumbTranslatorVisitor final { struct ThumbTranslatorVisitor final {
using instruction_return_type = bool; 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"); ASSERT_MSG(descriptor.TFlag(), "The processor must be in Thumb mode");
} }

View file

@ -6,6 +6,8 @@
#include "common/common_types.h" #include "common/common_types.h"
#include <dynarmic/A32/arch_version.h>
namespace Dynarmic::IR { namespace Dynarmic::IR {
class Block; class Block;
} // namespace Dynarmic::IR } // namespace Dynarmic::IR
@ -17,6 +19,8 @@ class LocationDescriptor;
using MemoryReadCodeFuncType = std::function<u32(u32 vaddr)>; using MemoryReadCodeFuncType = std::function<u32(u32 vaddr)>;
struct TranslationOptions { struct TranslationOptions {
ArchVersion arch_version;
/// This changes what IR we emit when we translate an unpredictable instruction. /// 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 false, the ExceptionRaised IR instruction is emitted.
/// If this is true, we define some behaviour for some instructions. /// If this is true, we define some behaviour for some instructions.