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 <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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in a new issue