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/string_util.h
|
||||
frontend/arm/FPSCR.h
|
||||
frontend/arm/PSR.h
|
||||
frontend/arm_types.h
|
||||
frontend/decoder/arm.h
|
||||
frontend/decoder/decoder_detail.h
|
||||
|
|
|
@ -46,10 +46,8 @@ struct Jit::Impl {
|
|||
|
||||
size_t Execute(size_t cycle_count) {
|
||||
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;
|
||||
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/common_types.h"
|
||||
#include "frontend/arm/FPSCR.h"
|
||||
#include "frontend/arm/PSR.h"
|
||||
|
||||
namespace Dynarmic {
|
||||
namespace Arm {
|
||||
|
@ -72,18 +73,22 @@ enum class SignExtendRotation {
|
|||
* 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, bool tflag, bool eflag, FPSCR fpscr)
|
||||
: arm_pc(arm_pc), tflag(tflag), eflag(eflag), fpscr(fpscr.Value() & FPSCR_MODE_MASK) {}
|
||||
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 tflag; }
|
||||
bool EFlag() const { return eflag; }
|
||||
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, 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 {
|
||||
|
@ -91,23 +96,29 @@ struct LocationDescriptor {
|
|||
}
|
||||
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
return LocationDescriptor(arm_pc, tflag, eflag, new_fpscr & FPSCR_MODE_MASK);
|
||||
return LocationDescriptor(arm_pc, cpsr, new_fpscr & FPSCR_MODE_MASK);
|
||||
}
|
||||
|
||||
u64 UniqueHash() const {
|
||||
|
@ -115,16 +126,15 @@ struct LocationDescriptor {
|
|||
// 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 = tflag ? (1ull << 35) : 0;
|
||||
u64 e_u64 = eflag ? (1ull << 39) : 0;
|
||||
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;
|
||||
bool tflag; ///< Thumb / ARM
|
||||
bool eflag; ///< Big / Little Endian
|
||||
Arm::FPSCR fpscr; ///< Floating point status control register
|
||||
u32 arm_pc; ///< Current program counter value.
|
||||
Arm::PSR cpsr; ///< Current program status register.
|
||||
Arm::FPSCR fpscr; ///< Floating point status control register.
|
||||
};
|
||||
|
||||
struct LocationDescriptorHash {
|
||||
|
|
|
@ -291,7 +291,7 @@ void FuzzJitArm(const size_t instruction_count, const size_t instructions_to_exe
|
|||
|
||||
size_t num_insts = 0;
|
||||
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::Optimization::GetSetElimination(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);
|
||||
}
|
||||
|
||||
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::DeadCodeElimination(ir_block);
|
||||
Dynarmic::Optimization::VerificationPass(ir_block);
|
||||
|
|
Loading…
Reference in a new issue