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 <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

View file

@ -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

View file

@ -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);

View file

@ -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
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
if (ArchVersion() >= 5) {
BXWritePC(value);
} else {
BranchWritePC(value);
}
}
void IREmitter::CallSupervisor(const IR::U32& value) {

View file

@ -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

View file

@ -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");
}

View file

@ -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");
}

View file

@ -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.