1 # SPDX-License-Identifier: LGPLv3+
2 # Funded by NLnet https://nlnet.nl/
3 """ Record for FPSCR as defined in
4 Power ISA v3.1B Book I section 4.2.2 page 136(162)
8 | Bits | Mnemonic | Description |
9 |-------|----------|-------------------------------------------------------------------------|
10 | 0:28 | | Reserved |
11 | 29:31 | DRN | Decimal Rounding Mode |
12 | 32 | FX | Floating-Point Exception Summary |
13 | 33 | FEX | Floating-Point Enabled Exception Summary |
14 | 34 | VX | Floating-Point Invalid Operation Exception Summary |
15 | 35 | OX | Floating-Point Overflow Exception |
16 | 36 | UX | Floating-Point Underflow Exception |
17 | 37 | ZX | Floating-Point Zero Divide Exception |
18 | 38 | XX | Floating-Point Inexact Exception |
19 | 39 | VXSNAN | Floating-Point Invalid Operation Exception (SNaN) |
20 | 40 | VXISI | Floating-Point Invalid Operation Exception (∞ - ∞) |
21 | 41 | VXIDI | Floating-Point Invalid Operation Exception (∞ ÷ ∞) |
22 | 42 | VXZDZ | Floating-Point Invalid Operation Exception (0 ÷ 0) |
23 | 43 | VXIMZ | Floating-Point Invalid Operation Exception (∞ × 0) |
24 | 44 | VXVC | Floating-Point Invalid Operation Exception (Invalid Compare) |
25 | 45 | FR | Floating-Point Fraction Rounded |
26 | 46 | FI | Floating-Point Fraction Inexact |
27 | 47:51 | FPRF | Floating-Point Result Flags |
28 | 47 | C | Floating-Point Result Class Descriptor |
29 | 48:51 | FPCC | Floating-Point Condition Code |
30 | 48 | FL | Floating-Point Less Than or Negative |
31 | 49 | FG | Floating-Point Greater Than or Positive |
32 | 50 | FE | Floating-Point Equal or Zero |
33 | 51 | FU | Floating-Point Unordered or NaN |
34 | 52 | | Reserved |
35 | 53 | VXSOFT | Floating-Point Invalid Operation Exception (Software-Defined Condition) |
36 | 54 | VXSQRT | Floating-Point Invalid Operation Exception (Invalid Square Root) |
37 | 55 | VXCVI | Floating-Point Invalid Operation Exception (Invalid Integer Convert) |
38 | 56 | VE | Floating-Point Invalid Operation Exception Enable |
39 | 57 | OE | Floating-Point Overflow Exception Enable |
40 | 58 | UE | Floating-Point Underflow Exception Enable |
41 | 59 | ZE | Floating-Point Zero Divide Exception Enable |
42 | 60 | XE | Floating-Point Inexact Exception Enable |
43 | 61 | NI | Floating-Point Non-IEEE Mode |
44 | 62:63 | RN | Floating-Point Rounding Control |
47 from nmigen
import Record
48 from typing
import NoReturn
49 from nmutil
.plain_data
import plain_data
51 from openpower
.decoder
.selectable_int
import (
52 FieldSelectableInt
, SelectableInt
)
55 def _parse_line_fields(line
):
56 # type: (str) -> None | list[str]
58 if not sline
.startswith("|"):
60 if not sline
.endswith("|"):
64 return [v
.strip() for v
in sline
[1:-2].split("|")]
68 _MNEMONIC_FIELD
= "Mnemonic"
74 __slots__
= "name", "bits_msb0", "lineno", "include_in_record"
76 def __init__(self
, name
, bits_msb0
, lineno
, include_in_record
=True):
77 # type: (str, int | range, int, bool) -> None
79 self
.bits_msb0
= bits_msb0
81 self
.include_in_record
= include_in_record
83 def bits_msb0_iter(self
):
84 # type: () -> range | tuple[int]
85 if isinstance(self
.bits_msb0
, int):
86 return self
.bits_msb0
,
90 # type () -> FPSCRField
91 return FPSCRField(name
=self
.name
, bits_msb0
=self
.bits_msb0
,
92 include_in_record
=self
.include_in_record
)
95 @plain_data(frozen
=True, unsafe_hash
=True)
97 __slots__
= "name", "bits_msb0", "include_in_record"
99 def __init__(self
, name
, bits_msb0
, include_in_record
):
100 # type: (str, int | range, bool) -> None
102 self
.bits_msb0
= bits_msb0
103 self
.include_in_record
= include_in_record
104 """True if this field should be
105 included in `FPSCRRecord`, since there are some overlapping fields and
106 `Record` doesn't support that.
109 def bits_msb0_iter(self
):
110 # type: () -> range | tuple[int]
111 if isinstance(self
.bits_msb0
, int):
112 return self
.bits_msb0
,
113 return self
.bits_msb0
117 # type: () -> tuple[FPSCRField, ...]
118 lines
= __doc__
.splitlines()
119 in_header_sep
= False
120 in_table_body
= False
121 header_fields
= [] # type: list[str]
123 fields
= {} # type: dict[str, _MutableField]
124 bit_fields
= [None] * FPSCR_WIDTH
# type: list[_MutableField | None]
127 def raise_(msg
, col
=1, err_lineno
=None):
128 # type: (str, int, int | None) -> NoReturn
130 if err_lineno
is None:
132 for i
in range(10000): # 10000 is random limit if we can't read
133 if linecache
.getline(__file__
, i
).strip().startswith('"'):
135 err_lineno
+= 1 # lines before doc comment start
136 raise SyntaxError(msg
, (
137 __file__
, err_lineno
+ 3, col
, lines
[err_lineno
]))
139 for lineno
, line
in enumerate(lines
):
140 line_fields
= _parse_line_fields(line
)
142 if line_fields
is None:
144 raise_("missing table body")
146 if len(line_fields
) != len(header_fields
):
147 raise_("wrong number of fields")
148 fields_dict
= {k
: v
for k
, v
in zip(header_fields
, line_fields
)}
149 name
= fields_dict
[_MNEMONIC_FIELD
]
150 if name
== "" or name
== " ":
152 if not name
.isidentifier():
153 raise_(f
"invalid field name {name!r}")
155 raise_(f
"duplicate field name {name}")
156 bits_str
= fields_dict
[_BITS_FIELD
]
157 bits_fields_str
= bits_str
.split(":")
158 if len(bits_fields_str
) not in (1, 2) or not all(
159 v
.isascii() and v
.isdigit() for v
in bits_fields_str
):
160 raise_(f
"`{_BITS_FIELD}` field must be "
161 f
"of the form `23` or `23:56`")
162 bits_fields
= [int(v
, base
=10) for v
in bits_fields_str
]
163 if not all(0 <= v
< FPSCR_WIDTH
for v
in bits_fields
):
164 raise_(f
"`{_BITS_FIELD}` field value is beyond the "
165 f
"limits of FPSCR: must be `0 <= v < {FPSCR_WIDTH}`")
166 if len(bits_fields
) == 2:
167 first
, last
= bits_fields
169 raise_(f
"`{_BITS_FIELD}` field value is an improper "
170 f
"range: {first} > {last}")
171 bits
= range(first
, last
+ 1)
173 bits
= bits_fields
[0]
174 field
= _MutableField(name
=name
, bits_msb0
=bits
, lineno
=lineno
)
176 for bit
in field
.bits_msb0_iter():
177 old_field
= bit_fields
[bit
]
178 if old_field
is not None:
179 # field is overwritten -- don't include in Record
180 old_field
.include_in_record
= False
181 bit_fields
[bit
] = field
183 if line_fields
is None:
184 raise_("missing header separator line")
185 for v
in line_fields
:
186 if v
!= "-" * len(v
):
187 raise_("header separator field isn't just hyphens")
188 if len(line_fields
) != len(header_fields
):
189 raise_("wrong number of fields")
190 in_header_sep
= False
193 if line_fields
is None:
195 if _BITS_FIELD
not in line_fields
:
196 raise_(f
"missing `{_BITS_FIELD}` field")
197 if _MNEMONIC_FIELD
not in line_fields
:
198 raise_(f
"missing `{_MNEMONIC_FIELD}` field")
199 if len(set(line_fields
)) != len(line_fields
):
200 raise_("duplicate header field")
201 header_fields
= line_fields
203 header_lineno
= lineno
205 raise_("missing table")
206 # insert reserved fields and check for partially overwritten fields
207 for bit
in range(FPSCR_WIDTH
):
208 field
= bit_fields
[bit
]
212 while bit
< FPSCR_WIDTH
and bit_fields
[bit
] is None:
214 field
= _MutableField(name
=f
"RESERVED_{start}_{bit - 1}",
215 bits_msb0
=range(start
, bit
),
216 lineno
=header_lineno
)
217 if len(field
.bits_msb0
) == 1:
218 field
.bits_msb0
= start
219 field
.name
= f
"RESERVED_{start}"
220 for bit
in field
.bits_msb0_iter():
221 bit_fields
[bit
] = field
222 if field
.name
in fields
:
223 raise_(f
"field {field.name}'s name conflicts with a "
224 f
"generated reserved field",
225 err_lineno
=fields
[field
.name
].lineno
)
226 fields
[field
.name
] = field
227 elif not field
.include_in_record
:
228 raise_(f
"field {field.name} is partially overwritten -- "
229 f
"this is an error because FPSCRRecord will have "
230 f
"incorrect fields", err_lineno
=field
.lineno
)
233 return tuple(f
.to_field() for f
in fields
.values())
236 FPSCR_FIELDS_MSB0
= _parse_fields() # type: tuple[FPSCRField, ...]
237 """ All fields in FPSCR. """
240 def _calc_record_layout_lsb0():
241 # type: () -> list[tuple[str, int]]
242 fields_lsb0
= [] # type: list[tuple[int, int, str]]
243 for field
in FPSCR_FIELDS_MSB0
:
244 if not field
.include_in_record
:
246 start_msb0
= field
.bits_msb0_iter()[0]
247 field_len
= len(field
.bits_msb0_iter())
248 start_lsb0
= FPSCR_WIDTH
- 1 - start_msb0
249 fields_lsb0
.append((start_lsb0
, field_len
, field
.name
))
251 # _parse_fields already checks for partially overlapping fields and
252 # inserts reserved fields ensuring the returned fields cover every bit
253 # exactly one, therefore this is correct
254 return [(name
, f_len
) for _
, f_len
, name
in fields_lsb0
]
257 class FPSCRRecord(Record
):
258 layout
= _calc_record_layout_lsb0()
260 def __init__(self
, name
=None):
261 super().__init
__(name
=name
, layout
=FPSCRRecord
.layout
)
264 class FPSCRState(SelectableInt
):
265 def __init__(self
, value
=0):
266 SelectableInt
.__init
__(self
, value
, FPSCR_WIDTH
)
268 for field
in FPSCR_FIELDS_MSB0
:
269 bits_msb0
= tuple(field
.bits_msb0_iter())
270 self
.fsi
[field
.name
] = FieldSelectableInt(self
, bits_msb0
)
274 return self
.fsi
['DRN'].asint(msb0
=True)
277 def DRN(self
, value
):
278 self
.fsi
['DRN'].eq(value
)
282 return self
.fsi
['FX'].asint(msb0
=True)
286 self
.fsi
['FX'].eq(value
)
290 return self
.fsi
['FEX'].asint(msb0
=True)
293 def FEX(self
, value
):
294 self
.fsi
['FEX'].eq(value
)
298 return self
.fsi
['VX'].asint(msb0
=True)
302 self
.fsi
['VX'].eq(value
)
306 return self
.fsi
['OX'].asint(msb0
=True)
310 self
.fsi
['OX'].eq(value
)
314 return self
.fsi
['UX'].asint(msb0
=True)
318 self
.fsi
['UX'].eq(value
)
322 return self
.fsi
['ZX'].asint(msb0
=True)
326 self
.fsi
['ZX'].eq(value
)
330 return self
.fsi
['XX'].asint(msb0
=True)
334 self
.fsi
['XX'].eq(value
)
338 return self
.fsi
['VXSNAN'].asint(msb0
=True)
341 def VXSNAN(self
, value
):
342 self
.fsi
['VXSNAN'].eq(value
)
346 return self
.fsi
['VXISI'].asint(msb0
=True)
349 def VXISI(self
, value
):
350 self
.fsi
['VXISI'].eq(value
)
354 return self
.fsi
['VXIDI'].asint(msb0
=True)
357 def VXIDI(self
, value
):
358 self
.fsi
['VXIDI'].eq(value
)
362 return self
.fsi
['VXZDZ'].asint(msb0
=True)
365 def VXZDZ(self
, value
):
366 self
.fsi
['VXZDZ'].eq(value
)
370 return self
.fsi
['VXIMZ'].asint(msb0
=True)
373 def VXIMZ(self
, value
):
374 self
.fsi
['VXIMZ'].eq(value
)
378 return self
.fsi
['VXVC'].asint(msb0
=True)
381 def VXVC(self
, value
):
382 self
.fsi
['VXVC'].eq(value
)
386 return self
.fsi
['FR'].asint(msb0
=True)
390 self
.fsi
['FR'].eq(value
)
394 return self
.fsi
['FI'].asint(msb0
=True)
398 self
.fsi
['FI'].eq(value
)
402 return self
.fsi
['FPRF'].asint(msb0
=True)
405 def FPRF(self
, value
):
406 self
.fsi
['FPRF'].eq(value
)
410 return self
.fsi
['C'].asint(msb0
=True)
414 self
.fsi
['C'].eq(value
)
418 return self
.fsi
['FPCC'].asint(msb0
=True)
421 def FPCC(self
, value
):
422 self
.fsi
['FPCC'].eq(value
)
426 return self
.fsi
['FL'].asint(msb0
=True)
430 self
.fsi
['FL'].eq(value
)
434 return self
.fsi
['FG'].asint(msb0
=True)
438 self
.fsi
['FG'].eq(value
)
442 return self
.fsi
['FE'].asint(msb0
=True)
446 self
.fsi
['FE'].eq(value
)
450 return self
.fsi
['FU'].asint(msb0
=True)
454 self
.fsi
['FU'].eq(value
)
458 return self
.fsi
['VXSOFT'].asint(msb0
=True)
461 def VXSOFT(self
, value
):
462 self
.fsi
['VXSOFT'].eq(value
)
466 return self
.fsi
['VXSQRT'].asint(msb0
=True)
469 def VXSQRT(self
, value
):
470 self
.fsi
['VXSQRT'].eq(value
)
474 return self
.fsi
['VXCVI'].asint(msb0
=True)
477 def VXCVI(self
, value
):
478 self
.fsi
['VXCVI'].eq(value
)
482 return self
.fsi
['VE'].asint(msb0
=True)
486 self
.fsi
['VE'].eq(value
)
490 return self
.fsi
['OE'].asint(msb0
=True)
494 self
.fsi
['OE'].eq(value
)
498 return self
.fsi
['UE'].asint(msb0
=True)
502 self
.fsi
['UE'].eq(value
)
506 return self
.fsi
['ZE'].asint(msb0
=True)
510 self
.fsi
['ZE'].eq(value
)
514 return self
.fsi
['XE'].asint(msb0
=True)
518 self
.fsi
['XE'].eq(value
)
522 return self
.fsi
['NI'].asint(msb0
=True)
526 self
.fsi
['NI'].eq(value
)
530 return self
.fsi
['RN'].asint(msb0
=True)
534 self
.fsi
['RN'].eq(value
)
537 if __name__
== "__main__":
538 from pprint
import pprint
539 print("FPSCR_FIELDS_MSB0:")
540 pprint(FPSCR_FIELDS_MSB0
)
541 print("FPSCRRecord.layout:")
542 pprint(FPSCRRecord
.layout
)
543 print("FPSCRState.fsi:")
544 pprint(FPSCRState().fsi
)