1 # SPDX-License-Identifier: LGPLv3+
2 # Funded by NLnet https://nlnet.nl/
4 """ Record for FPSCR as defined in
5 Power ISA v3.1B Book I section 4.2.2 page 136(162)
9 |Bits |Mnemonic | Description |
10 |-----|---------|-------------------------------------------------------------|
11 |0:28 | | Reserved |
12 |29:31| DRN | Decimal Rounding Mode |
13 |32 | FX | FP Exception Summary |
14 |33 | FEX | FP Enabled Exception Summary |
15 |34 | VX | FP Invalid Operation Exception Summary |
16 |35 | OX | FP Overflow Exception |
17 |36 | UX | FP Underflow Exception |
18 |37 | ZX | FP Zero Divide Exception |
19 |38 | XX | FP Inexact Exception |
20 |39 | VXSNAN | FP Invalid Operation Exception (SNaN) |
21 |40 | VXISI | FP Invalid Operation Exception (∞ - ∞) |
22 |41 | VXIDI | FP Invalid Operation Exception (∞ ÷ ∞) |
23 |42 | VXZDZ | FP Invalid Operation Exception (0 ÷ 0) |
24 |43 | VXIMZ | FP Invalid Operation Exception (∞ × 0) |
25 |44 | VXVC | FP Invalid Operation Exception (Invalid Compare) |
26 |45 | FR | FP Fraction Rounded |
27 |46 | FI | FP Fraction Inexact |
28 |47:51| FPRF | FP Result Flags |
29 |47 | C | FP Result Class Descriptor |
30 |48:51| FPCC | FP Condition Code |
31 |48 | FL | FP Less Than or Negative |
32 |49 | FG | FP Greater Than or Positive |
33 |50 | FE | FP Equal or Zero |
34 |51 | FU | FP Unordered or NaN |
35 |52 | | Reserved |
36 |53 | VXSOFT | FP Invalid Operation Exception (Software-Defined Condition) |
37 |54 | VXSQRT | FP Invalid Operation Exception (Invalid Square Root) |
38 |55 | VXCVI | FP Invalid Operation Exception (Invalid Integer Convert) |
39 |56 | VE | FP Invalid Operation Exception Enable |
40 |57 | OE | FP Overflow Exception Enable |
41 |58 | UE | FP Underflow Exception Enable |
42 |59 | ZE | FP Zero Divide Exception Enable |
43 |60 | XE | FP Inexact Exception Enable |
44 |61 | NI | FP Non-IEEE Mode |
45 |62:63| RN | FP Rounding Control |
48 https://bugs.libre-soc.org/show_bug.cgi?id=1135
49 to allow FP ops to compute in parallel despite each fp op semantically reading
50 the FPSCR output from the previous op, the FPSCR will be split into 3 parts
51 (I picked names that aren't necessarily standard names):
52 * volatile part: written nearly every insn but is rarely read
54 * sticky part: usually doesn't change but is read/written by nearly all insns:
55 all the sticky exception bits
56 * control part: generally doesn't change and is only read by nearly all insns:
59 The explanation of why FPSCR is split into 3 parts follows, we may not
60 implement it this way.
62 Additionally, as of Aug 2023 we're not planning on implementing it this way
65 the idea is that the cpu will have all three parts in separate registers and
66 will speculatively execute fp insns with the current value of the sticky part
67 register (not the one from the previous instruction, but the one from the
68 register, avoiding needing a dependency chain), and then will cancel and retry
69 all later insns if it turns out that the insn changed the sticky part (which
72 if desired the control part can be put in the same register and handled the
73 same way as the sticky part, but this makes code that temporarily changes the
74 rounding mode slower than necessary (common in x87 emulation and some math
78 from nmigen
import Record
, Shape
79 from enum
import Enum
, Flag
, unique
80 from functools
import lru_cache
83 class RoundingMode(Enum
):
85 # * PowerISA rounding modes (v3.1B 4.3.6 page 143(169))
86 # * PowerISA bfp_ROUND_<mode> functions (v3.1B 7.6.2.2 page 607(633))
87 # * SMTLIB abbreviated rounding modes
88 # https://smtlib.cs.uiowa.edu/theories-FloatingPoint.shtml
97 RoundTowardPosInfinity
= RTP
100 RoundTowardNegInfinity
= RTN
103 assert Shape
.cast(RoundingMode
) == Shape(width
=2, signed
=False)
106 class FPSCRBase(Record
):
109 Volatile
= "volatile"
110 "the part written nearly every insn but rarely read"
113 """usually doesn't change but is read/written by nearly all
114 instructions in order to or-in exception bits
118 "generally doesn't change and is only read by nearly all instructions"
120 Everything
= "everything"
123 @lru_cache(maxsize
=None)
127 ("RN", RoundingMode
, Part
.Control
),
128 ("NI", 1, Part
.Control
),
129 ("XE", 1, Part
.Control
),
130 ("ZE", 1, Part
.Control
),
131 ("UE", 1, Part
.Control
),
132 ("OE", 1, Part
.Control
),
133 ("VE", 1, Part
.Control
),
134 ("VXCVI", 1, Part
.Sticky
),
135 ("VXSQRT", 1, Part
.Sticky
),
137 # we may decide to set VXSOFT if something like `fcospi`
138 # causes an invalid exception, because it doesn't have an
139 # assigned exception bit and because doing it that way makes
140 # it match the math library better.
141 ("VXSOFT", 1, Part
.Sticky
),
142 ("rsvd1", 1, Part
.Control
),
152 ("FI", 1, Part
.Volatile
),
153 ("FR", 1, Part
.Volatile
),
154 ("VXVC", 1, Part
.Sticky
),
155 ("VXIMZ", 1, Part
.Sticky
),
156 ("VXZDZ", 1, Part
.Sticky
),
157 ("VXIDI", 1, Part
.Sticky
),
158 ("VXISI", 1, Part
.Sticky
),
159 ("VXSNAN", 1, Part
.Sticky
),
160 ("XX", 1, Part
.Sticky
),
161 ("ZX", 1, Part
.Sticky
),
162 ("UX", 1, Part
.Sticky
),
163 ("OX", 1, Part
.Sticky
),
164 ("VX", 1, Part
.Sticky
),
165 ("FEX", 1, Part
.Sticky
),
166 ("FX", 1, Part
.Sticky
),
167 ("DRN", 3, Part
.Control
),
168 ("rsvd2", 29, Part
.Control
),
170 everything
= self
is Part
.Everything
171 return tuple((n
, s
) for n
, s
, p
in l
if everything
or p
is self
)
173 PART
= Part
.Everything
176 def __init__(self
, *, name
=None, fields
=None, src_loc_at
=0):
177 super().__init
__(layout
=self
.PART
.layout
, name
=name
,
178 fields
=fields
, src_loc_at
=src_loc_at
+ 1)
181 class FPSCR(FPSCRBase
):
182 def calc_summary(self
):
183 """calculate and assign the summary bits in self"""
185 self
.fields
['VX'].eq(self
.VX
),
186 self
.fields
['FEX'].eq(self
.FEX
),
191 return (self
.VXSNAN |
203 return ((self
.VX
& self
.VE
) |
204 (self
.OX
& self
.OE
) |
205 (self
.UX
& self
.UE
) |
206 (self
.ZX
& self
.ZE
) |
210 def __make_record(fields
, cls
, name
, src_loc_at
):
211 return cls(name
=name
, fields
=fields
, src_loc_at
=1+src_loc_at
)
213 def volatile_part(self
, *, name
=None, src_loc_at
=0):
214 return FPSCR
.__make
_record
(self
.fields
, cls
=FPSCRVolatilePart
,
215 name
=name
, src_loc_at
=1+src_loc_at
)
217 def sticky_part(self
, *, name
=None, src_loc_at
=0):
218 return FPSCR
.__make
_record
(self
.fields
, cls
=FPSCRStickyPart
,
219 name
=name
, src_loc_at
=1+src_loc_at
)
221 def control_part(self
, *, name
=None, src_loc_at
=0):
222 return FPSCR
.__make
_record
(self
.fields
, cls
=FPSCRControlPart
,
223 name
=name
, src_loc_at
=1+src_loc_at
)
226 def from_parts(*, volatile_part
, sticky_part
, control_part
,
227 name
=None, src_loc_at
=0):
228 fields
= {**volatile_part
.fields
,
229 **sticky_part
.fields
,
230 **control_part
.fields
}
231 return FPSCR
.__make
_record
(fields
, cls
=FPSCR
,
232 name
=name
, src_loc_at
=1+src_loc_at
)
235 class FPSCRVolatilePart(FPSCRBase
):
236 """ the part of FPSCR that is written by nearly every FP instruction,
239 PART
= FPSCR
.Part
.Volatile
243 class FPSCRStickyPart(FPSCRBase
):
244 """ the part of FPSCR that usually doesn't change but is read/written by
245 nearly all FP instructions in order to or-in exception bits.
247 PART
= FPSCR
.Part
.Sticky
251 class FPSCRControlPart(FPSCRBase
):
252 """ the part of FPSCR that generally doesn't change and is read by
253 nearly all FP instructions.
256 PART
= FPSCR
.Part
.Control
260 if __name__
== "__main__":
261 from pprint
import pprint
262 for part
in FPSCR
.Part
:
263 print(f
"{part}.layout:")