arm: Add PSR helper type (#3)

This commit is contained in:
Mat M 2016-09-02 12:34:33 -04:00 committed by Merry
parent 00d0f4d5ff
commit 6ec651498d
6 changed files with 258 additions and 21 deletions

View file

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

View file

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

View file

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

View file

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

View file

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