1 /* This file is part of the dynarmic project.
2  * Copyright (c) 2016 MerryMage
3  * SPDX-License-Identifier: 0BSD
4  */
5 
6 #pragma once
7 
8 #include <optional>
9 
10 #include "common/bit_util.h"
11 #include "common/common_types.h"
12 #include "common/fp/rounding_mode.h"
13 
14 namespace Dynarmic::A32 {
15 
16 /**
17  * Representation of the Floating-Point Status and Control Register.
18  */
19 class FPSCR final
20 {
21 public:
22     FPSCR() = default;
23     FPSCR(const FPSCR&) = default;
24     FPSCR(FPSCR&&) = default;
FPSCR(u32 data)25     explicit FPSCR(u32 data) : value{data & mask} {}
26 
27     FPSCR& operator=(const FPSCR&) = default;
28     FPSCR& operator=(FPSCR&&) = default;
29     FPSCR& operator=(u32 data) {
30         value = data & mask;
31         return *this;
32     }
33 
34     /// Negative condition flag.
N()35     bool N() const {
36         return Common::Bit<31>(value);
37     }
38 
39     /// Zero condition flag.
Z()40     bool Z() const {
41         return Common::Bit<30>(value);
42     }
43 
44     /// Carry condition flag.
C()45     bool C() const {
46         return Common::Bit<29>(value);
47     }
48 
49     /// Overflow condition flag.
V()50     bool V() const {
51         return Common::Bit<28>(value);
52     }
53 
54     /// Cumulative saturation flag.
QC()55     bool QC() const {
56         return Common::Bit<27>(value);
57     }
58 
59     /// Alternate half-precision control flag.
AHP()60     bool AHP() const {
61         return Common::Bit<26>(value);
62     }
63 
64     /// Default NaN mode control bit.
DN()65     bool DN() const {
66         return Common::Bit<25>(value);
67     }
68 
69     /// Flush-to-zero mode control bit.
FTZ()70     bool FTZ() const {
71         return Common::Bit<24>(value);
72     }
73 
74     /// Rounding mode control field.
RMode()75     FP::RoundingMode RMode() const {
76         return static_cast<FP::RoundingMode>(Common::Bits<22, 23>(value));
77     }
78 
79     /// Indicates the stride of a vector.
Stride()80     std::optional<size_t> Stride() const {
81         switch (Common::Bits<20, 21>(value)) {
82         case 0b00:
83             return 1;
84         case 0b11:
85             return 2;
86         default:
87             return std::nullopt;
88         }
89     }
90 
91     /// Indicates the length of a vector.
Len()92     size_t Len() const {
93         return Common::Bits<16, 18>(value) + 1;
94     }
95 
96     /// Input denormal exception trap enable flag.
IDE()97     bool IDE() const {
98         return Common::Bit<15>(value);
99     }
100 
101     /// Inexact exception trap enable flag.
IXE()102     bool IXE() const {
103         return Common::Bit<12>(value);
104     }
105 
106     /// Underflow exception trap enable flag.
UFE()107     bool UFE() const {
108         return Common::Bit<11>(value);
109     }
110 
111     /// Overflow exception trap enable flag.
OFE()112     bool OFE() const {
113         return Common::Bit<10>(value);
114     }
115 
116     /// Division by zero exception trap enable flag.
DZE()117     bool DZE() const {
118         return Common::Bit<9>(value);
119     }
120 
121     /// Invalid operation exception trap enable flag.
IOE()122     bool IOE() const {
123         return Common::Bit<8>(value);
124     }
125 
126     /// Input denormal cumulative exception bit.
IDC()127     bool IDC() const {
128         return Common::Bit<7>(value);
129     }
130 
131     /// Inexact cumulative exception bit.
IXC()132     bool IXC() const {
133         return Common::Bit<4>(value);
134     }
135 
136     /// Underflow cumulative exception bit.
UFC()137     bool UFC() const {
138         return Common::Bit<3>(value);
139     }
140 
141     /// Overflow cumulative exception bit.
OFC()142     bool OFC() const {
143         return Common::Bit<2>(value);
144     }
145 
146     /// Division by zero cumulative exception bit.
DZC()147     bool DZC() const {
148         return Common::Bit<1>(value);
149     }
150 
151     /// Invalid operation cumulative exception bit.
IOC()152     bool IOC() const {
153         return Common::Bit<0>(value);
154     }
155 
156     /**
157      * Whether or not the FPSCR indicates RunFast mode.
158      *
159      * RunFast mode is enabled when:
160      *   - Flush-to-zero is enabled
161      *   - Default NaNs are enabled.
162      *   - All exception enable bits are cleared.
163      */
InRunFastMode()164     bool InRunFastMode() const {
165         constexpr u32 runfast_mask = 0x03001F00;
166         constexpr u32 expected     = 0x03000000;
167 
168         return (value & runfast_mask) == expected;
169     }
170 
171     /// Gets the underlying raw value within the FPSCR.
Value()172     u32 Value() const {
173         return value;
174     }
175 
176 private:
177     // Bits 5-6, 13-14, and 19 are reserved.
178     static constexpr u32 mask = 0xFFF79F9F;
179     u32 value = 0;
180 };
181 
182 inline bool operator==(FPSCR lhs, FPSCR rhs) {
183     return lhs.Value() == rhs.Value();
184 }
185 
186 inline bool operator!=(FPSCR lhs, FPSCR rhs) {
187     return !operator==(lhs, rhs);
188 }
189 
190 } // namespace Dynarmic::A32
191