mirror of
https://git.suyu.dev/suyu/dynarmic.git
synced 2026-01-03 13:14:42 +01:00
arm_types: Split out LocationDescriptor (#20)
This isn't really an ARM-specific type, since it's used to indicate a Block location.
This commit is contained in:
parent
84336cf29d
commit
6d53bb6d7e
19 changed files with 175 additions and 153 deletions
|
|
@ -6,15 +6,11 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/common_types.h"
|
||||
#include "frontend/arm/FPSCR.h"
|
||||
#include "frontend/arm/PSR.h"
|
||||
|
||||
namespace Dynarmic {
|
||||
namespace Arm {
|
||||
|
|
@ -66,77 +62,6 @@ enum class SignExtendRotation {
|
|||
ROR_24 ///< ROR #24
|
||||
};
|
||||
|
||||
/**
|
||||
* LocationDescriptor describes the location of a basic block.
|
||||
* The location is not solely based on the PC because other flags influence the way
|
||||
* instructions should be translated. The CPSR.T flag is most notable since it
|
||||
* tells us if the processor is in Thumb or Arm mode.
|
||||
*/
|
||||
struct LocationDescriptor {
|
||||
// Indicates bits that should be preserved within descriptors.
|
||||
static constexpr u32 CPSR_MODE_MASK = 0x00000220;
|
||||
static constexpr u32 FPSCR_MODE_MASK = 0x03F79F00;
|
||||
|
||||
LocationDescriptor(u32 arm_pc, PSR cpsr, FPSCR fpscr)
|
||||
: arm_pc(arm_pc), cpsr(cpsr.Value() & CPSR_MODE_MASK), fpscr(fpscr.Value() & FPSCR_MODE_MASK) {}
|
||||
|
||||
u32 PC() const { return arm_pc; }
|
||||
bool TFlag() const { return cpsr.T(); }
|
||||
bool EFlag() const { return cpsr.E(); }
|
||||
|
||||
Arm::PSR CPSR() const { return cpsr; }
|
||||
Arm::FPSCR FPSCR() const { return fpscr; }
|
||||
|
||||
bool operator == (const LocationDescriptor& o) const {
|
||||
return std::tie(arm_pc, cpsr, fpscr) == std::tie(o.arm_pc, o.cpsr, o.fpscr);
|
||||
}
|
||||
|
||||
bool operator != (const LocationDescriptor& o) const {
|
||||
return !operator==(o);
|
||||
}
|
||||
|
||||
LocationDescriptor SetPC(u32 new_arm_pc) const {
|
||||
return LocationDescriptor(new_arm_pc, cpsr, fpscr);
|
||||
}
|
||||
|
||||
LocationDescriptor AdvancePC(int amount) const {
|
||||
return LocationDescriptor(static_cast<u32>(arm_pc + amount), cpsr, fpscr);
|
||||
}
|
||||
|
||||
LocationDescriptor SetTFlag(bool new_tflag) const {
|
||||
PSR new_cpsr = cpsr;
|
||||
new_cpsr.T(new_tflag);
|
||||
|
||||
return LocationDescriptor(arm_pc, new_cpsr, fpscr);
|
||||
}
|
||||
|
||||
LocationDescriptor SetEFlag(bool new_eflag) const {
|
||||
PSR new_cpsr = cpsr;
|
||||
new_cpsr.E(new_eflag);
|
||||
|
||||
return LocationDescriptor(arm_pc, new_cpsr, fpscr);
|
||||
}
|
||||
|
||||
LocationDescriptor SetFPSCR(u32 new_fpscr) const {
|
||||
return LocationDescriptor(arm_pc, cpsr, Arm::FPSCR{new_fpscr & FPSCR_MODE_MASK});
|
||||
}
|
||||
|
||||
u64 UniqueHash() const {
|
||||
// This value MUST BE UNIQUE.
|
||||
// This calculation has to match up with EmitX64::EmitTerminalPopRSBHint
|
||||
u64 pc_u64 = u64(arm_pc);
|
||||
u64 fpscr_u64 = u64(fpscr.Value()) << 32;
|
||||
u64 t_u64 = cpsr.T() ? (1ull << 35) : 0;
|
||||
u64 e_u64 = cpsr.E() ? (1ull << 39) : 0;
|
||||
return pc_u64 | fpscr_u64 | t_u64 | e_u64;
|
||||
}
|
||||
|
||||
private:
|
||||
u32 arm_pc; ///< Current program counter value.
|
||||
Arm::PSR cpsr; ///< Current program status register.
|
||||
Arm::FPSCR fpscr; ///< Floating point status control register.
|
||||
};
|
||||
|
||||
const char* CondToString(Cond cond, bool explicit_al = false);
|
||||
const char* RegToString(Reg reg);
|
||||
const char* ExtRegToString(ExtReg reg);
|
||||
|
|
@ -177,12 +102,3 @@ inline ExtReg operator+(ExtReg reg, size_t number) {
|
|||
|
||||
} // namespace Arm
|
||||
} // namespace Dynarmic
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<Dynarmic::Arm::LocationDescriptor> {
|
||||
size_t operator()(const Dynarmic::Arm::LocationDescriptor& x) const {
|
||||
return std::hash<u64>()(x.UniqueHash());
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ void Block::AppendNewInst(Opcode opcode, std::initializer_list<IR::Value> args)
|
|||
instructions.push_back(inst);
|
||||
}
|
||||
|
||||
Arm::LocationDescriptor Block::Location() const {
|
||||
LocationDescriptor Block::Location() const {
|
||||
return location;
|
||||
}
|
||||
|
||||
|
|
@ -42,11 +42,11 @@ void Block::SetCondition(Arm::Cond condition) {
|
|||
cond = condition;
|
||||
}
|
||||
|
||||
Arm::LocationDescriptor Block::ConditionFailedLocation() const {
|
||||
LocationDescriptor Block::ConditionFailedLocation() const {
|
||||
return cond_failed.get();
|
||||
}
|
||||
|
||||
void Block::SetConditionFailedLocation(Arm::LocationDescriptor fail_location) {
|
||||
void Block::SetConditionFailedLocation(LocationDescriptor fail_location) {
|
||||
cond_failed = fail_location;
|
||||
}
|
||||
|
||||
|
|
@ -91,7 +91,7 @@ const size_t& Block::CycleCount() const {
|
|||
return cycle_count;
|
||||
}
|
||||
|
||||
static std::string LocDescToString(const Arm::LocationDescriptor& loc) {
|
||||
static std::string LocDescToString(const LocationDescriptor& loc) {
|
||||
return fmt::format("{{{},{},{},{}}}",
|
||||
loc.PC(),
|
||||
loc.TFlag() ? "T" : "!T",
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
#include "common/common_types.h"
|
||||
#include "common/intrusive_list.h"
|
||||
#include "common/memory_pool.h"
|
||||
#include "frontend/arm_types.h"
|
||||
#include "frontend/ir/location_descriptor.h"
|
||||
#include "frontend/ir/microinstruction.h"
|
||||
#include "frontend/ir/terminal.h"
|
||||
#include "frontend/ir/value.h"
|
||||
|
|
@ -40,7 +40,7 @@ public:
|
|||
using reverse_iterator = InstructionList::reverse_iterator;
|
||||
using const_reverse_iterator = InstructionList::const_reverse_iterator;
|
||||
|
||||
explicit Block(const Arm::LocationDescriptor& location) : location(location) {}
|
||||
explicit Block(const LocationDescriptor& location) : location(location) {}
|
||||
|
||||
bool empty() const { return instructions.empty(); }
|
||||
size_type size() const { return instructions.size(); }
|
||||
|
|
@ -77,7 +77,7 @@ public:
|
|||
void AppendNewInst(Opcode op, std::initializer_list<Value> args);
|
||||
|
||||
/// Gets the starting location for this basic block.
|
||||
Arm::LocationDescriptor Location() const;
|
||||
LocationDescriptor Location() const;
|
||||
|
||||
/// Gets the condition required to pass in order to execute this block.
|
||||
Arm::Cond GetCondition() const;
|
||||
|
|
@ -85,9 +85,9 @@ public:
|
|||
void SetCondition(Arm::Cond condition);
|
||||
|
||||
/// Gets the location of the block to execute if the predicated condition fails.
|
||||
Arm::LocationDescriptor ConditionFailedLocation() const;
|
||||
LocationDescriptor ConditionFailedLocation() const;
|
||||
/// Sets the location of the block to execute if the predicated condition fails.
|
||||
void SetConditionFailedLocation(Arm::LocationDescriptor fail_location);
|
||||
void SetConditionFailedLocation(LocationDescriptor fail_location);
|
||||
/// Determines whether or not a prediated condition failure block is present.
|
||||
bool HasConditionFailedLocation() const;
|
||||
|
||||
|
|
@ -115,11 +115,11 @@ public:
|
|||
|
||||
private:
|
||||
/// Description of the starting location of this block
|
||||
Arm::LocationDescriptor location;
|
||||
LocationDescriptor location;
|
||||
/// Conditional to pass in order to execute this block
|
||||
Arm::Cond cond = Arm::Cond::AL;
|
||||
/// Block to execute next if `cond` did not pass.
|
||||
boost::optional<Arm::LocationDescriptor> cond_failed = {};
|
||||
boost::optional<LocationDescriptor> cond_failed = {};
|
||||
/// Number of cycles this block takes to execute if the conditional fails.
|
||||
size_t cond_failed_cycle_count = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ void IREmitter::CallSupervisor(const Value& value) {
|
|||
Inst(Opcode::CallSupervisor, {value});
|
||||
}
|
||||
|
||||
void IREmitter::PushRSB(const Arm::LocationDescriptor& return_location) {
|
||||
void IREmitter::PushRSB(const LocationDescriptor& return_location) {
|
||||
Inst(Opcode::PushRSB, {Value(return_location.UniqueHash())});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@
|
|||
#include <initializer_list>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "frontend/arm_types.h"
|
||||
#include "frontend/ir/basic_block.h"
|
||||
#include "frontend/ir/location_descriptor.h"
|
||||
#include "frontend/ir/terminal.h"
|
||||
#include "frontend/ir/value.h"
|
||||
|
||||
|
|
@ -33,10 +33,10 @@ enum class Opcode;
|
|||
*/
|
||||
class IREmitter {
|
||||
public:
|
||||
explicit IREmitter(Arm::LocationDescriptor descriptor) : block(descriptor), current_location(descriptor) {}
|
||||
explicit IREmitter(LocationDescriptor descriptor) : block(descriptor), current_location(descriptor) {}
|
||||
|
||||
Block block;
|
||||
Arm::LocationDescriptor current_location;
|
||||
LocationDescriptor current_location;
|
||||
|
||||
struct ResultAndCarry {
|
||||
Value result;
|
||||
|
|
@ -67,7 +67,7 @@ public:
|
|||
void BXWritePC(const Value& value);
|
||||
void LoadWritePC(const Value& value);
|
||||
void CallSupervisor(const Value& value);
|
||||
void PushRSB(const Arm::LocationDescriptor& return_location);
|
||||
void PushRSB(const LocationDescriptor& return_location);
|
||||
|
||||
Value GetCpsr();
|
||||
void SetCpsr(const Value& value);
|
||||
|
|
|
|||
100
src/frontend/ir/location_descriptor.h
Normal file
100
src/frontend/ir/location_descriptor.h
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2016 MerryMage
|
||||
* This software may be used and distributed according to the terms of the GNU
|
||||
* General Public License version 2 or any later version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <tuple>
|
||||
#include "common/common_types.h"
|
||||
#include "frontend/arm/FPSCR.h"
|
||||
#include "frontend/arm/PSR.h"
|
||||
|
||||
namespace Dynarmic {
|
||||
namespace IR {
|
||||
|
||||
/**
|
||||
* LocationDescriptor describes the location of a basic block.
|
||||
* The location is not solely based on the PC because other flags influence the way
|
||||
* instructions should be translated. The CPSR.T flag is most notable since it
|
||||
* tells us if the processor is in Thumb or Arm mode.
|
||||
*/
|
||||
class LocationDescriptor {
|
||||
public:
|
||||
// Indicates bits that should be preserved within descriptors.
|
||||
static constexpr u32 CPSR_MODE_MASK = 0x00000220;
|
||||
static constexpr u32 FPSCR_MODE_MASK = 0x03F79F00;
|
||||
|
||||
LocationDescriptor(u32 arm_pc, Arm::PSR cpsr, Arm::FPSCR fpscr)
|
||||
: arm_pc(arm_pc), cpsr(cpsr.Value() & CPSR_MODE_MASK), fpscr(fpscr.Value() & FPSCR_MODE_MASK) {}
|
||||
|
||||
u32 PC() const { return arm_pc; }
|
||||
bool TFlag() const { return cpsr.T(); }
|
||||
bool EFlag() const { return cpsr.E(); }
|
||||
|
||||
Arm::PSR CPSR() const { return cpsr; }
|
||||
Arm::FPSCR FPSCR() const { return fpscr; }
|
||||
|
||||
bool operator == (const LocationDescriptor& o) const {
|
||||
return std::tie(arm_pc, cpsr, fpscr) == std::tie(o.arm_pc, o.cpsr, o.fpscr);
|
||||
}
|
||||
|
||||
bool operator != (const LocationDescriptor& o) const {
|
||||
return !operator==(o);
|
||||
}
|
||||
|
||||
LocationDescriptor SetPC(u32 new_arm_pc) const {
|
||||
return LocationDescriptor(new_arm_pc, cpsr, fpscr);
|
||||
}
|
||||
|
||||
LocationDescriptor AdvancePC(int amount) const {
|
||||
return LocationDescriptor(static_cast<u32>(arm_pc + amount), cpsr, fpscr);
|
||||
}
|
||||
|
||||
LocationDescriptor SetTFlag(bool new_tflag) const {
|
||||
Arm::PSR new_cpsr = cpsr;
|
||||
new_cpsr.T(new_tflag);
|
||||
|
||||
return LocationDescriptor(arm_pc, new_cpsr, fpscr);
|
||||
}
|
||||
|
||||
LocationDescriptor SetEFlag(bool new_eflag) const {
|
||||
Arm::PSR new_cpsr = cpsr;
|
||||
new_cpsr.E(new_eflag);
|
||||
|
||||
return LocationDescriptor(arm_pc, new_cpsr, fpscr);
|
||||
}
|
||||
|
||||
LocationDescriptor SetFPSCR(u32 new_fpscr) const {
|
||||
return LocationDescriptor(arm_pc, cpsr, Arm::FPSCR{new_fpscr & FPSCR_MODE_MASK});
|
||||
}
|
||||
|
||||
u64 UniqueHash() const {
|
||||
// This value MUST BE UNIQUE.
|
||||
// This calculation has to match up with EmitX64::EmitTerminalPopRSBHint
|
||||
u64 pc_u64 = u64(arm_pc);
|
||||
u64 fpscr_u64 = u64(fpscr.Value()) << 32;
|
||||
u64 t_u64 = cpsr.T() ? (1ull << 35) : 0;
|
||||
u64 e_u64 = cpsr.E() ? (1ull << 39) : 0;
|
||||
return pc_u64 | fpscr_u64 | t_u64 | e_u64;
|
||||
}
|
||||
|
||||
private:
|
||||
u32 arm_pc; ///< Current program counter value.
|
||||
Arm::PSR cpsr; ///< Current program status register.
|
||||
Arm::FPSCR fpscr; ///< Floating point status control register.
|
||||
};
|
||||
|
||||
} // namespace IR
|
||||
} // namespace Dynarmic
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<Dynarmic::IR::LocationDescriptor> {
|
||||
size_t operator()(const Dynarmic::IR::LocationDescriptor& x) const {
|
||||
return std::hash<u64>()(x.UniqueHash());
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
#include <boost/variant.hpp>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "frontend/arm_types.h"
|
||||
#include "frontend/ir/location_descriptor.h"
|
||||
|
||||
namespace Dynarmic {
|
||||
namespace IR {
|
||||
|
|
@ -22,8 +22,8 @@ struct Invalid {};
|
|||
* The interpreter must interpret exactly one instruction.
|
||||
*/
|
||||
struct Interpret {
|
||||
explicit Interpret(const Arm::LocationDescriptor& next_) : next(next_) {}
|
||||
Arm::LocationDescriptor next; ///< Location at which interpretation starts.
|
||||
explicit Interpret(const LocationDescriptor& next_) : next(next_) {}
|
||||
LocationDescriptor next; ///< Location at which interpretation starts.
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -38,8 +38,8 @@ struct ReturnToDispatch {};
|
|||
* dispatcher, which will return control to the host.
|
||||
*/
|
||||
struct LinkBlock {
|
||||
explicit LinkBlock(const Arm::LocationDescriptor& next_) : next(next_) {}
|
||||
Arm::LocationDescriptor next; ///< Location descriptor for next block.
|
||||
explicit LinkBlock(const LocationDescriptor& next_) : next(next_) {}
|
||||
LocationDescriptor next; ///< Location descriptor for next block.
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -51,8 +51,8 @@ struct LinkBlock {
|
|||
* as LinkBlock.
|
||||
*/
|
||||
struct LinkBlockFast {
|
||||
explicit LinkBlockFast(const Arm::LocationDescriptor& next_) : next(next_) {}
|
||||
Arm::LocationDescriptor next; ///< Location descriptor for next block.
|
||||
explicit LinkBlockFast(const LocationDescriptor& next_) : next(next_) {}
|
||||
LocationDescriptor next; ///< Location descriptor for next block.
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -4,17 +4,17 @@
|
|||
* General Public License version 2 or any later version.
|
||||
*/
|
||||
|
||||
#include "frontend/arm_types.h"
|
||||
#include "frontend/ir/basic_block.h"
|
||||
#include "frontend/ir/location_descriptor.h"
|
||||
#include "frontend/translate/translate.h"
|
||||
|
||||
namespace Dynarmic {
|
||||
namespace Arm {
|
||||
|
||||
IR::Block TranslateArm(LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32);
|
||||
IR::Block TranslateThumb(LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32);
|
||||
IR::Block TranslateArm(IR::LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32);
|
||||
IR::Block TranslateThumb(IR::LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32);
|
||||
|
||||
IR::Block Translate(LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32) {
|
||||
IR::Block Translate(IR::LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32) {
|
||||
return (descriptor.TFlag() ? TranslateThumb : TranslateArm)(descriptor, memory_read_32);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@
|
|||
namespace Dynarmic {
|
||||
|
||||
namespace IR {
|
||||
class Block;
|
||||
class Block;
|
||||
class LocationDescriptor;
|
||||
} // namespace IR
|
||||
|
||||
namespace Arm {
|
||||
|
|
@ -25,7 +26,7 @@ using MemoryRead32FuncType = u32 (*)(u32 vaddr);
|
|||
* @param memory_read_32 The function we should use to read emulated memory.
|
||||
* @return A translated basic block in the intermediate representation.
|
||||
*/
|
||||
IR::Block Translate(LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32);
|
||||
IR::Block Translate(IR::LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32);
|
||||
|
||||
} // namespace Arm
|
||||
} // namespace Dynarmic
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include "frontend/decoder/arm.h"
|
||||
#include "frontend/decoder/vfp2.h"
|
||||
#include "frontend/ir/basic_block.h"
|
||||
#include "frontend/ir/location_descriptor.h"
|
||||
#include "frontend/translate/translate.h"
|
||||
#include "frontend/translate/translate_arm/translate_arm.h"
|
||||
|
||||
|
|
@ -27,7 +28,7 @@ static bool CondCanContinue(ConditionalState cond_state, const IR::IREmitter& ir
|
|||
return std::all_of(ir.block.begin(), ir.block.end(), [](const IR::Inst& inst) { return !inst.WritesToCPSR(); });
|
||||
}
|
||||
|
||||
IR::Block TranslateArm(LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32) {
|
||||
IR::Block TranslateArm(IR::LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32) {
|
||||
ArmTranslatorVisitor visitor{descriptor};
|
||||
|
||||
bool should_continue = true;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "frontend/ir/ir_emitter.h"
|
||||
#include "frontend/ir/location_descriptor.h"
|
||||
|
||||
namespace Dynarmic {
|
||||
namespace Arm {
|
||||
|
|
@ -23,7 +24,7 @@ enum class ConditionalState {
|
|||
};
|
||||
|
||||
struct ArmTranslatorVisitor final {
|
||||
explicit ArmTranslatorVisitor(LocationDescriptor descriptor) : ir(descriptor) {
|
||||
explicit ArmTranslatorVisitor(IR::LocationDescriptor descriptor) : ir(descriptor) {
|
||||
ASSERT_MSG(!descriptor.TFlag(), "The processor must be in Arm mode");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include "frontend/decoder/thumb16.h"
|
||||
#include "frontend/decoder/thumb32.h"
|
||||
#include "frontend/ir/ir_emitter.h"
|
||||
#include "frontend/ir/location_descriptor.h"
|
||||
#include "frontend/translate/translate.h"
|
||||
|
||||
namespace Dynarmic {
|
||||
|
|
@ -20,7 +21,7 @@ namespace Arm {
|
|||
namespace {
|
||||
|
||||
struct ThumbTranslatorVisitor final {
|
||||
explicit ThumbTranslatorVisitor(LocationDescriptor descriptor) : ir(descriptor) {
|
||||
explicit ThumbTranslatorVisitor(IR::LocationDescriptor descriptor) : ir(descriptor) {
|
||||
ASSERT_MSG(descriptor.TFlag(), "The processor must be in Thumb mode");
|
||||
}
|
||||
|
||||
|
|
@ -857,7 +858,7 @@ std::tuple<u32, ThumbInstSize> ReadThumbInstruction(u32 arm_pc, MemoryRead32Func
|
|||
|
||||
} // local namespace
|
||||
|
||||
IR::Block TranslateThumb(LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32) {
|
||||
IR::Block TranslateThumb(IR::LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32) {
|
||||
ThumbTranslatorVisitor visitor{descriptor};
|
||||
|
||||
bool should_continue = true;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue