arm: Add PSR helper type (#3)
This commit is contained in:
parent
00d0f4d5ff
commit
6ec651498d
6 changed files with 258 additions and 21 deletions
|
@ -54,6 +54,7 @@ set(HEADERS
|
||||||
common/scope_exit.h
|
common/scope_exit.h
|
||||||
common/string_util.h
|
common/string_util.h
|
||||||
frontend/arm/FPSCR.h
|
frontend/arm/FPSCR.h
|
||||||
|
frontend/arm/PSR.h
|
||||||
frontend/arm_types.h
|
frontend/arm_types.h
|
||||||
frontend/decoder/arm.h
|
frontend/decoder/arm.h
|
||||||
frontend/decoder/decoder_detail.h
|
frontend/decoder/decoder_detail.h
|
||||||
|
|
|
@ -46,10 +46,8 @@ struct Jit::Impl {
|
||||||
|
|
||||||
size_t Execute(size_t cycle_count) {
|
size_t Execute(size_t cycle_count) {
|
||||||
u32 pc = jit_state.Reg[15];
|
u32 pc = jit_state.Reg[15];
|
||||||
bool TFlag = Common::Bit<5>(jit_state.Cpsr);
|
|
||||||
bool EFlag = Common::Bit<9>(jit_state.Cpsr);
|
|
||||||
|
|
||||||
Arm::LocationDescriptor descriptor{pc, TFlag, EFlag, jit_state.guest_FPSCR_mode};
|
Arm::LocationDescriptor descriptor{pc, Arm::PSR{jit_state.Cpsr}, jit_state.guest_FPSCR_mode};
|
||||||
|
|
||||||
CodePtr code_ptr = GetBasicBlock(descriptor).code_ptr;
|
CodePtr code_ptr = GetBasicBlock(descriptor).code_ptr;
|
||||||
return block_of_code.RunCode(&jit_state, code_ptr, cycle_count);
|
return block_of_code.RunCode(&jit_state, code_ptr, cycle_count);
|
||||||
|
|
225
src/frontend/arm/PSR.h
Normal file
225
src/frontend/arm/PSR.h
Normal file
|
@ -0,0 +1,225 @@
|
||||||
|
/* 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 "common/bit_util.h"
|
||||||
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
namespace Dynarmic {
|
||||||
|
namespace Arm {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Program Status Register
|
||||||
|
*
|
||||||
|
* | Bit(s) | Description |
|
||||||
|
* |:-------:|:----------------------------------------------|
|
||||||
|
* | N | Negative |
|
||||||
|
* | Z | Zero |
|
||||||
|
* | C | Carry |
|
||||||
|
* | V | Overflow |
|
||||||
|
* | Q | Sticky overflow for DSP-oriented instructions |
|
||||||
|
* | IT[1:0] | Lower two bits of the If-Then execution state |
|
||||||
|
* | J | Jazelle bit |
|
||||||
|
* | GE | Greater-than or Equal |
|
||||||
|
* | IT[7:2] | Upper six bits of the If-Then execution state |
|
||||||
|
* | E | Endian (0 is little endian, 1 is big endian) |
|
||||||
|
* | A | Imprecise data abort (disables them when set) |
|
||||||
|
* | I | IRQ interrupts (disabled when set) |
|
||||||
|
* | F | FIQ interrupts (disabled when set) |
|
||||||
|
* | T | Thumb bit |
|
||||||
|
* | M | Current processor mode |
|
||||||
|
*/
|
||||||
|
class PSR final {
|
||||||
|
public:
|
||||||
|
/// Valid processor modes that may be indicated.
|
||||||
|
enum class Mode : u32
|
||||||
|
{
|
||||||
|
User = 0b10000,
|
||||||
|
FIQ = 0b10001,
|
||||||
|
IRQ = 0b10010,
|
||||||
|
Supervisor = 0b10011,
|
||||||
|
Monitor = 0b10110,
|
||||||
|
Abort = 0b10111,
|
||||||
|
Hypervisor = 0b11010,
|
||||||
|
Undefined = 0b11011,
|
||||||
|
System = 0b11111
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Instruction sets that may be signified through a PSR.
|
||||||
|
enum class InstructionSet
|
||||||
|
{
|
||||||
|
ARM,
|
||||||
|
Jazelle,
|
||||||
|
Thumb,
|
||||||
|
ThumbEE
|
||||||
|
};
|
||||||
|
|
||||||
|
PSR() = default;
|
||||||
|
explicit PSR(u32 data) : value{data & mask} {}
|
||||||
|
|
||||||
|
PSR& operator=(u32 data) {
|
||||||
|
value = data & mask;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool N() const {
|
||||||
|
return Common::Bit<31>(value);
|
||||||
|
}
|
||||||
|
void N(bool set) {
|
||||||
|
value = (value & ~0x80000000) | static_cast<u32>(set) << 31;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Z() const {
|
||||||
|
return Common::Bit<30>(value);
|
||||||
|
}
|
||||||
|
void Z(bool set) {
|
||||||
|
value = (value & ~0x40000000) | static_cast<u32>(set) << 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool C() const {
|
||||||
|
return Common::Bit<29>(value);
|
||||||
|
}
|
||||||
|
void C(bool set) {
|
||||||
|
value = (value & ~0x20000000) | static_cast<u32>(set) << 29;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool V() const {
|
||||||
|
return Common::Bit<28>(value);
|
||||||
|
}
|
||||||
|
void V(bool set) {
|
||||||
|
value = (value & ~0x10000000) | static_cast<u32>(set) << 28;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Q() const {
|
||||||
|
return Common::Bit<27>(value);
|
||||||
|
}
|
||||||
|
void Q(bool set) {
|
||||||
|
value = (value & ~0x8000000) | static_cast<u32>(set) << 27;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool J() const {
|
||||||
|
return Common::Bit<24>(value);
|
||||||
|
}
|
||||||
|
void J(bool set) {
|
||||||
|
value = (value & ~0x1000000) | static_cast<u32>(set) << 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 GE() const {
|
||||||
|
return Common::Bits<16, 19>(value);
|
||||||
|
}
|
||||||
|
void GE(u32 data) {
|
||||||
|
value = (value & ~0xF0000) | (data & 0xF) << 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 IT() const {
|
||||||
|
return (value & 0x6000000) >> 25 | (value & 0xFC00) >> 8;
|
||||||
|
}
|
||||||
|
void IT(u32 data) {
|
||||||
|
value = (value & ~0x000FC00) | (data & 0b11111100) << 8;
|
||||||
|
value = (value & ~0x6000000) | (data & 0b00000011) << 25;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool E() const {
|
||||||
|
return Common::Bit<9>(value);
|
||||||
|
}
|
||||||
|
void E(bool set) {
|
||||||
|
value = (value & ~0x200) | static_cast<u32>(set) << 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool A() const {
|
||||||
|
return Common::Bit<8>(value);
|
||||||
|
}
|
||||||
|
void A(bool set) {
|
||||||
|
value = (value & ~0x100) | static_cast<u32>(set) << 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool I() const {
|
||||||
|
return Common::Bit<7>(value);
|
||||||
|
}
|
||||||
|
void I(bool set) {
|
||||||
|
value = (value & ~0x80) | static_cast<u32>(set) << 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool F() const {
|
||||||
|
return Common::Bit<6>(value);
|
||||||
|
}
|
||||||
|
void F(bool set) {
|
||||||
|
value = (value & ~0x40) | static_cast<u32>(set) << 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool T() const {
|
||||||
|
return Common::Bit<5>(value);
|
||||||
|
}
|
||||||
|
void T(bool set) {
|
||||||
|
value = (value & ~0x20) | static_cast<u32>(set) << 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mode M() const {
|
||||||
|
return static_cast<Mode>(Common::Bits<0, 4>(value));
|
||||||
|
}
|
||||||
|
void M(Mode mode) {
|
||||||
|
value = (value & ~0x1F) | (static_cast<u32>(mode) & 0x1F);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 Value() const {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
InstructionSet CurrentInstructionSet() const {
|
||||||
|
const bool j_bit = J();
|
||||||
|
const bool t_bit = T();
|
||||||
|
|
||||||
|
if (j_bit && t_bit)
|
||||||
|
return InstructionSet::ThumbEE;
|
||||||
|
|
||||||
|
if (t_bit)
|
||||||
|
return InstructionSet::Thumb;
|
||||||
|
|
||||||
|
if (j_bit)
|
||||||
|
return InstructionSet::Jazelle;
|
||||||
|
|
||||||
|
return InstructionSet::ARM;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CurrentInstructionSet(InstructionSet instruction_set) {
|
||||||
|
switch (instruction_set) {
|
||||||
|
case InstructionSet::ARM:
|
||||||
|
T(false);
|
||||||
|
J(false);
|
||||||
|
break;
|
||||||
|
case InstructionSet::Jazelle:
|
||||||
|
T(false);
|
||||||
|
J(true);
|
||||||
|
break;
|
||||||
|
case InstructionSet::Thumb:
|
||||||
|
T(true);
|
||||||
|
J(false);
|
||||||
|
break;
|
||||||
|
case InstructionSet::ThumbEE:
|
||||||
|
T(true);
|
||||||
|
J(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Bits 20-23 are reserved and should be zero.
|
||||||
|
static constexpr u32 mask = 0xFF0FFFFF;
|
||||||
|
|
||||||
|
u32 value = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline bool operator==(PSR lhs, PSR rhs) {
|
||||||
|
return lhs.Value() == rhs.Value();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator!=(PSR lhs, PSR rhs) {
|
||||||
|
return !operator==(lhs, rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Arm
|
||||||
|
} // namespace Dynarmic
|
|
@ -14,6 +14,7 @@
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "frontend/arm/FPSCR.h"
|
#include "frontend/arm/FPSCR.h"
|
||||||
|
#include "frontend/arm/PSR.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace Arm {
|
||||||
|
@ -72,18 +73,22 @@ enum class SignExtendRotation {
|
||||||
* tells us if the processor is in Thumb or Arm mode.
|
* tells us if the processor is in Thumb or Arm mode.
|
||||||
*/
|
*/
|
||||||
struct LocationDescriptor {
|
struct LocationDescriptor {
|
||||||
|
// Indicates bits that should be preserved within descriptors.
|
||||||
|
static constexpr u32 CPSR_MODE_MASK = 0x00000220;
|
||||||
static constexpr u32 FPSCR_MODE_MASK = 0x03F79F00;
|
static constexpr u32 FPSCR_MODE_MASK = 0x03F79F00;
|
||||||
|
|
||||||
LocationDescriptor(u32 arm_pc, bool tflag, bool eflag, FPSCR fpscr)
|
LocationDescriptor(u32 arm_pc, PSR cpsr, FPSCR fpscr)
|
||||||
: arm_pc(arm_pc), tflag(tflag), eflag(eflag), fpscr(fpscr.Value() & FPSCR_MODE_MASK) {}
|
: arm_pc(arm_pc), cpsr(cpsr.Value() & CPSR_MODE_MASK), fpscr(fpscr.Value() & FPSCR_MODE_MASK) {}
|
||||||
|
|
||||||
u32 PC() const { return arm_pc; }
|
u32 PC() const { return arm_pc; }
|
||||||
bool TFlag() const { return tflag; }
|
bool TFlag() const { return cpsr.T(); }
|
||||||
bool EFlag() const { return eflag; }
|
bool EFlag() const { return cpsr.E(); }
|
||||||
|
|
||||||
|
Arm::PSR CPSR() const { return cpsr; }
|
||||||
Arm::FPSCR FPSCR() const { return fpscr; }
|
Arm::FPSCR FPSCR() const { return fpscr; }
|
||||||
|
|
||||||
bool operator == (const LocationDescriptor& o) const {
|
bool operator == (const LocationDescriptor& o) const {
|
||||||
return std::tie(arm_pc, tflag, eflag, fpscr) == std::tie(o.arm_pc, o.tflag, o.eflag, o.fpscr);
|
return std::tie(arm_pc, cpsr, fpscr) == std::tie(o.arm_pc, o.cpsr, o.fpscr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator != (const LocationDescriptor& o) const {
|
bool operator != (const LocationDescriptor& o) const {
|
||||||
|
@ -91,23 +96,29 @@ struct LocationDescriptor {
|
||||||
}
|
}
|
||||||
|
|
||||||
LocationDescriptor SetPC(u32 new_arm_pc) const {
|
LocationDescriptor SetPC(u32 new_arm_pc) const {
|
||||||
return LocationDescriptor(new_arm_pc, tflag, eflag, fpscr);
|
return LocationDescriptor(new_arm_pc, cpsr, fpscr);
|
||||||
}
|
}
|
||||||
|
|
||||||
LocationDescriptor AdvancePC(int amount) const {
|
LocationDescriptor AdvancePC(int amount) const {
|
||||||
return LocationDescriptor(static_cast<u32>(arm_pc + amount), tflag, eflag, fpscr);
|
return LocationDescriptor(static_cast<u32>(arm_pc + amount), cpsr, fpscr);
|
||||||
}
|
}
|
||||||
|
|
||||||
LocationDescriptor SetTFlag(bool new_tflag) const {
|
LocationDescriptor SetTFlag(bool new_tflag) const {
|
||||||
return LocationDescriptor(arm_pc, new_tflag, eflag, fpscr);
|
PSR new_cpsr = cpsr;
|
||||||
|
new_cpsr.T(new_tflag);
|
||||||
|
|
||||||
|
return LocationDescriptor(arm_pc, new_cpsr, fpscr);
|
||||||
}
|
}
|
||||||
|
|
||||||
LocationDescriptor SetEFlag(bool new_eflag) const {
|
LocationDescriptor SetEFlag(bool new_eflag) const {
|
||||||
return LocationDescriptor(arm_pc, tflag, new_eflag, fpscr);
|
PSR new_cpsr = cpsr;
|
||||||
|
new_cpsr.E(new_eflag);
|
||||||
|
|
||||||
|
return LocationDescriptor(arm_pc, new_cpsr, fpscr);
|
||||||
}
|
}
|
||||||
|
|
||||||
LocationDescriptor SetFPSCR(u32 new_fpscr) const {
|
LocationDescriptor SetFPSCR(u32 new_fpscr) const {
|
||||||
return LocationDescriptor(arm_pc, tflag, eflag, new_fpscr & FPSCR_MODE_MASK);
|
return LocationDescriptor(arm_pc, cpsr, new_fpscr & FPSCR_MODE_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 UniqueHash() const {
|
u64 UniqueHash() const {
|
||||||
|
@ -115,16 +126,15 @@ struct LocationDescriptor {
|
||||||
// This calculation has to match up with EmitX64::EmitTerminalPopRSBHint
|
// This calculation has to match up with EmitX64::EmitTerminalPopRSBHint
|
||||||
u64 pc_u64 = u64(arm_pc);
|
u64 pc_u64 = u64(arm_pc);
|
||||||
u64 fpscr_u64 = u64(fpscr.Value()) << 32;
|
u64 fpscr_u64 = u64(fpscr.Value()) << 32;
|
||||||
u64 t_u64 = tflag ? (1ull << 35) : 0;
|
u64 t_u64 = cpsr.T() ? (1ull << 35) : 0;
|
||||||
u64 e_u64 = eflag ? (1ull << 39) : 0;
|
u64 e_u64 = cpsr.E() ? (1ull << 39) : 0;
|
||||||
return pc_u64 | fpscr_u64 | t_u64 | e_u64;
|
return pc_u64 | fpscr_u64 | t_u64 | e_u64;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
u32 arm_pc;
|
u32 arm_pc; ///< Current program counter value.
|
||||||
bool tflag; ///< Thumb / ARM
|
Arm::PSR cpsr; ///< Current program status register.
|
||||||
bool eflag; ///< Big / Little Endian
|
Arm::FPSCR fpscr; ///< Floating point status control register.
|
||||||
Arm::FPSCR fpscr; ///< Floating point status control register
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LocationDescriptorHash {
|
struct LocationDescriptorHash {
|
||||||
|
|
|
@ -291,7 +291,7 @@ void FuzzJitArm(const size_t instruction_count, const size_t instructions_to_exe
|
||||||
|
|
||||||
size_t num_insts = 0;
|
size_t num_insts = 0;
|
||||||
while (num_insts < instructions_to_execute_count) {
|
while (num_insts < instructions_to_execute_count) {
|
||||||
Dynarmic::Arm::LocationDescriptor descriptor = {u32(num_insts * 4), false, false, 0};
|
Dynarmic::Arm::LocationDescriptor descriptor = {u32(num_insts * 4), Dynarmic::Arm::PSR{}, 0};
|
||||||
Dynarmic::IR::Block ir_block = Dynarmic::Arm::Translate(descriptor, &MemoryRead32);
|
Dynarmic::IR::Block ir_block = Dynarmic::Arm::Translate(descriptor, &MemoryRead32);
|
||||||
Dynarmic::Optimization::GetSetElimination(ir_block);
|
Dynarmic::Optimization::GetSetElimination(ir_block);
|
||||||
Dynarmic::Optimization::DeadCodeElimination(ir_block);
|
Dynarmic::Optimization::DeadCodeElimination(ir_block);
|
||||||
|
|
|
@ -244,7 +244,10 @@ void FuzzJitThumb(const size_t instruction_count, const size_t instructions_to_e
|
||||||
printf("%zu [%x] = %" PRIu64 "\n", record.size, record.address, record.data);
|
printf("%zu [%x] = %" PRIu64 "\n", record.size, record.address, record.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
Dynarmic::IR::Block ir_block = Dynarmic::Arm::Translate({0, true, false, 0}, MemoryRead32);
|
Dynarmic::Arm::PSR cpsr;
|
||||||
|
cpsr.T(true);
|
||||||
|
|
||||||
|
Dynarmic::IR::Block ir_block = Dynarmic::Arm::Translate({0, cpsr, 0}, MemoryRead32);
|
||||||
Dynarmic::Optimization::GetSetElimination(ir_block);
|
Dynarmic::Optimization::GetSetElimination(ir_block);
|
||||||
Dynarmic::Optimization::DeadCodeElimination(ir_block);
|
Dynarmic::Optimization::DeadCodeElimination(ir_block);
|
||||||
Dynarmic::Optimization::VerificationPass(ir_block);
|
Dynarmic::Optimization::VerificationPass(ir_block);
|
||||||
|
|
Loading…
Reference in a new issue