dynarmic/src/frontend/A32/PSR.h
2020-04-22 20:44:38 +01:00

223 lines
5.6 KiB
C++

/* 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::A32 {
/**
* 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 Dynarmic::A32