deepcopy is really slow and unnecessary here
[openpower-isa.git] / src / openpower / fpscr.py
1 # SPDX-License-Identifier: LGPLv3+
2 # Funded by NLnet https://nlnet.nl/
3
4 # XXX TODO: get this into openpower/consts.py instead.
5 # create the layout from an auto-created Enum FPSCRb
6 """ Record for FPSCR as defined in
7 Power ISA v3.1B Book I section 4.2.2 page 136(162)
8
9 FPSCR fields in MSB0:
10
11 |Bits |Mnemonic | Description |
12 |-----|---------|-------------------------------------------------------------|
13 |0:28 |   | Reserved |
14 |29:31| DRN | Decimal Rounding Mode |
15 |32 | FX | FP Exception Summary |
16 |33 | FEX | FP Enabled Exception Summary |
17 |34 | VX | FP Invalid Operation Exception Summary |
18 |35 | OX | FP Overflow Exception |
19 |36 | UX | FP Underflow Exception |
20 |37 | ZX | FP Zero Divide Exception |
21 |38 | XX | FP Inexact Exception |
22 |39 | VXSNAN | FP Invalid Operation Exception (SNaN) |
23 |40 | VXISI | FP Invalid Operation Exception (∞ - ∞) |
24 |41 | VXIDI | FP Invalid Operation Exception (∞ ÷ ∞) |
25 |42 | VXZDZ | FP Invalid Operation Exception (0 ÷ 0) |
26 |43 | VXIMZ | FP Invalid Operation Exception (∞ × 0) |
27 |44 | VXVC | FP Invalid Operation Exception (Invalid Compare) |
28 |45 | FR | FP Fraction Rounded |
29 |46 | FI | FP Fraction Inexact |
30 |47:51| FPRF | FP Result Flags |
31 |47 | C | FP Result Class Descriptor |
32 |48:51| FPCC | FP Condition Code |
33 |48 | FL | FP Less Than or Negative |
34 |49 | FG | FP Greater Than or Positive |
35 |50 | FE | FP Equal or Zero |
36 |51 | FU | FP Unordered or NaN |
37 |52 |   | Reserved |
38 |53 | VXSOFT | FP Invalid Operation Exception (Software-Defined Condition) |
39 |54 | VXSQRT | FP Invalid Operation Exception (Invalid Square Root) |
40 |55 | VXCVI | FP Invalid Operation Exception (Invalid Integer Convert) |
41 |56 | VE | FP Invalid Operation Exception Enable |
42 |57 | OE | FP Overflow Exception Enable |
43 |58 | UE | FP Underflow Exception Enable |
44 |59 | ZE | FP Zero Divide Exception Enable |
45 |60 | XE | FP Inexact Exception Enable |
46 |61 | NI | FP Non-IEEE Mode |
47 |62:63| RN | FP Rounding Control |
48 """
49
50 from nmigen import Record
51 from copy import deepcopy
52 from openpower.util import log
53 from openpower.decoder.selectable_int import (
54 FieldSelectableInt, SelectableInt)
55
56
57 class FPSCRRecord(Record):
58 layout = [("RN", 2),
59 ("NI", 1),
60 ("XE", 1),
61 ("ZE", 1),
62 ("UE", 1),
63 ("OE", 1),
64 ("VE", 1),
65 ("VXCVI", 1),
66 ("VXSQRT", 1),
67 ("VXSOFT", 1),
68 ("rsvd1", 1),
69 ("FPRF", [
70 ("FPCC", [
71 ("FU", 1),
72 ("FE", 1),
73 ("FG", 1),
74 ("FL", 1),
75 ]),
76 ("C", 1),
77 ]),
78 ("FI", 1),
79 ("FR", 1),
80 ("VXVC", 1),
81 ("VXIMZ", 1),
82 ("VXZDZ", 1),
83 ("VXIDI", 1),
84 ("VXISI", 1),
85 ("VXSNAN", 1),
86 ("XX", 1),
87 ("ZX", 1),
88 ("UX", 1),
89 ("OX", 1),
90 ("VX", 1),
91 ("FEX", 1),
92 ("FX", 1),
93 ("DRN", 3),
94 ("rsvd2", 29),
95 ]
96
97 def __init__(self, name=None):
98 super().__init__(name=name, layout=FPSCRRecord.layout)
99
100
101 class FPSCR_FPRF(FieldSelectableInt):
102 """ special FieldSelectableInt instance to handle assigning strings to
103 FPSCR.FPRF
104
105 Translation Table from:
106 PowerISA v3.1B Book I Section 4.2.2 Page 139(165)
107 Figure 47 Floating-Point Result Flags
108 """
109 TRANSLATION_TABLE = (
110 ("Quiet NaN", 0b10001),
111 ("QNaN", 0b10001),
112 ("- Infinity", 0b01001),
113 ("- Normalized Number", 0b01000),
114 ("- Normal Number", 0b01000),
115 ("- Denormalized Number", 0b11000),
116 ("- Zero", 0b10010),
117 ("+ Zero", 0b00010),
118 ("+ Denormalized Number", 0b10100),
119 ("+ Normalized Number", 0b00100),
120 ("+ Normal Number", 0b00100),
121 ("+ Infinity", 0b00101),
122 )
123 TRANSLATION_TABLE_DICT = {k.casefold(): v for k, v in TRANSLATION_TABLE}
124
125 def eq(self, b):
126 if isinstance(b, str):
127 b = FPSCR_FPRF.TRANSLATION_TABLE_DICT[b.casefold()]
128 super().eq(b)
129
130
131 class FPSCRState(SelectableInt):
132 def __init__(self, value=0, *, auto_update_summary_bits=True):
133 self.__do_update_summary_bits = False
134 SelectableInt.__init__(self, value, 64)
135 self.fsi = {}
136 offs = 0
137 # set up sub-fields from Record layout
138 self.fsi = {}
139 for field, width in reversed(FPSCRRecord.layout):
140 if field == "FPRF":
141 v = FPSCR_FPRF(self, tuple(range(47, 52)))
142 end = 52
143 else:
144 end = offs + width
145 fs = tuple(range(offs, end))
146 v = FieldSelectableInt(self, fs)
147 self.fsi[field] = v
148 offs = end
149 # extra fields, temporarily explicitly added. TODO nested layout above
150 extras = [
151 (47, "C"),
152 (range(48, 52), "FPCC"),
153 (48, "FL"),
154 (49, "FG"),
155 (50, "FE"),
156 (51, "FU"),
157 ]
158 for offs, field in extras:
159 if isinstance(offs, int):
160 fs = (offs,)
161 else:
162 fs = tuple(offs)
163 v = FieldSelectableInt(self, fs)
164 self.fsi[field] = v
165 if auto_update_summary_bits:
166 self.__update_summary_bits()
167
168 @property
169 def value(self):
170 return self.__value
171
172 @value.setter
173 def value(self, value):
174 self.__value = value
175 if self.__do_update_summary_bits:
176 self.__update_summary_bits()
177
178 def __update_summary_bits(self):
179 self.__do_update_summary_bits = False
180 try:
181 # update summary bits -- FX is manually handled by pseudo-code,
182 # so we don't update it here
183 self.VX = (self.VXSNAN |
184 self.VXISI |
185 self.VXIDI |
186 self.VXZDZ |
187 self.VXIMZ |
188 self.VXVC |
189 self.VXSOFT |
190 self.VXSQRT |
191 self.VXCVI)
192 self.FEX = ((self.VX & self.VE) |
193 (self.OX & self.OE) |
194 (self.UX & self.UE) |
195 (self.ZX & self.ZE) |
196 (self.XX & self.XE))
197 finally:
198 self.__do_update_summary_bits = True
199
200 @property
201 def DRN(self):
202 return self.fsi['DRN'].asint(msb0=True)
203
204 @DRN.setter
205 def DRN(self, value):
206 self.fsi['DRN'].eq(value)
207
208 @property
209 def FX(self):
210 return self.fsi['FX'].asint(msb0=True)
211
212 @FX.setter
213 def FX(self, value):
214 self.fsi['FX'].eq(value)
215
216 @property
217 def FEX(self):
218 return self.fsi['FEX'].asint(msb0=True)
219
220 @FEX.setter
221 def FEX(self, value):
222 self.fsi['FEX'].eq(value)
223
224 @property
225 def VX(self):
226 return self.fsi['VX'].asint(msb0=True)
227
228 @VX.setter
229 def VX(self, value):
230 self.fsi['VX'].eq(value)
231
232 @property
233 def OX(self):
234 return self.fsi['OX'].asint(msb0=True)
235
236 @OX.setter
237 def OX(self, value):
238 self.fsi['OX'].eq(value)
239
240 @property
241 def UX(self):
242 return self.fsi['UX'].asint(msb0=True)
243
244 @UX.setter
245 def UX(self, value):
246 self.fsi['UX'].eq(value)
247
248 @property
249 def ZX(self):
250 return self.fsi['ZX'].asint(msb0=True)
251
252 @ZX.setter
253 def ZX(self, value):
254 self.fsi['ZX'].eq(value)
255
256 @property
257 def XX(self):
258 return self.fsi['XX'].asint(msb0=True)
259
260 @XX.setter
261 def XX(self, value):
262 self.fsi['XX'].eq(value)
263
264 @property
265 def VXSNAN(self):
266 return self.fsi['VXSNAN'].asint(msb0=True)
267
268 @VXSNAN.setter
269 def VXSNAN(self, value):
270 self.fsi['VXSNAN'].eq(value)
271
272 @property
273 def VXISI(self):
274 return self.fsi['VXISI'].asint(msb0=True)
275
276 @VXISI.setter
277 def VXISI(self, value):
278 self.fsi['VXISI'].eq(value)
279
280 @property
281 def VXIDI(self):
282 return self.fsi['VXIDI'].asint(msb0=True)
283
284 @VXIDI.setter
285 def VXIDI(self, value):
286 self.fsi['VXIDI'].eq(value)
287
288 @property
289 def VXZDZ(self):
290 return self.fsi['VXZDZ'].asint(msb0=True)
291
292 @VXZDZ.setter
293 def VXZDZ(self, value):
294 self.fsi['VXZDZ'].eq(value)
295
296 @property
297 def VXIMZ(self):
298 return self.fsi['VXIMZ'].asint(msb0=True)
299
300 @VXIMZ.setter
301 def VXIMZ(self, value):
302 self.fsi['VXIMZ'].eq(value)
303
304 @property
305 def VXVC(self):
306 return self.fsi['VXVC'].asint(msb0=True)
307
308 @VXVC.setter
309 def VXVC(self, value):
310 self.fsi['VXVC'].eq(value)
311
312 @property
313 def FR(self):
314 return self.fsi['FR'].asint(msb0=True)
315
316 @FR.setter
317 def FR(self, value):
318 self.fsi['FR'].eq(value)
319
320 @property
321 def FI(self):
322 return self.fsi['FI'].asint(msb0=True)
323
324 @FI.setter
325 def FI(self, value):
326 self.fsi['FI'].eq(value)
327
328 @property
329 def FPRF(self):
330 return self.fsi['FPRF'].asint(msb0=True)
331
332 @FPRF.setter
333 def FPRF(self, value):
334 self.fsi['FPRF'].eq(value)
335
336 @property
337 def C(self):
338 return self.fsi['C'].asint(msb0=True)
339
340 @C.setter
341 def C(self, value):
342 self.fsi['C'].eq(value)
343
344 @property
345 def FPCC(self):
346 return self.fsi['FPCC'].asint(msb0=True)
347
348 @FPCC.setter
349 def FPCC(self, value):
350 self.fsi['FPCC'].eq(value)
351
352 @property
353 def FL(self):
354 return self.fsi['FL'].asint(msb0=True)
355
356 @FL.setter
357 def FL(self, value):
358 self.fsi['FL'].eq(value)
359
360 @property
361 def FG(self):
362 return self.fsi['FG'].asint(msb0=True)
363
364 @FG.setter
365 def FG(self, value):
366 self.fsi['FG'].eq(value)
367
368 @property
369 def FE(self):
370 return self.fsi['FE'].asint(msb0=True)
371
372 @FE.setter
373 def FE(self, value):
374 self.fsi['FE'].eq(value)
375
376 @property
377 def FU(self):
378 return self.fsi['FU'].asint(msb0=True)
379
380 @FU.setter
381 def FU(self, value):
382 self.fsi['FU'].eq(value)
383
384 @property
385 def VXSOFT(self):
386 return self.fsi['VXSOFT'].asint(msb0=True)
387
388 @VXSOFT.setter
389 def VXSOFT(self, value):
390 self.fsi['VXSOFT'].eq(value)
391
392 @property
393 def VXSQRT(self):
394 return self.fsi['VXSQRT'].asint(msb0=True)
395
396 @VXSQRT.setter
397 def VXSQRT(self, value):
398 self.fsi['VXSQRT'].eq(value)
399
400 @property
401 def VXCVI(self):
402 return self.fsi['VXCVI'].asint(msb0=True)
403
404 @VXCVI.setter
405 def VXCVI(self, value):
406 self.fsi['VXCVI'].eq(value)
407
408 @property
409 def VE(self):
410 return self.fsi['VE'].asint(msb0=True)
411
412 @VE.setter
413 def VE(self, value):
414 self.fsi['VE'].eq(value)
415
416 @property
417 def OE(self):
418 return self.fsi['OE'].asint(msb0=True)
419
420 @OE.setter
421 def OE(self, value):
422 self.fsi['OE'].eq(value)
423
424 @property
425 def UE(self):
426 return self.fsi['UE'].asint(msb0=True)
427
428 @UE.setter
429 def UE(self, value):
430 self.fsi['UE'].eq(value)
431
432 @property
433 def ZE(self):
434 return self.fsi['ZE'].asint(msb0=True)
435
436 @ZE.setter
437 def ZE(self, value):
438 self.fsi['ZE'].eq(value)
439
440 @property
441 def XE(self):
442 return self.fsi['XE'].asint(msb0=True)
443
444 @XE.setter
445 def XE(self, value):
446 self.fsi['XE'].eq(value)
447
448 @property
449 def NI(self):
450 return self.fsi['NI'].asint(msb0=True)
451
452 @NI.setter
453 def NI(self, value):
454 self.fsi['NI'].eq(value)
455
456 @property
457 def RN(self):
458 return self.fsi['RN'].asint(msb0=True)
459
460 @RN.setter
461 def RN(self, value):
462 self.fsi['RN'].eq(value)
463
464
465 if __name__ == "__main__":
466 from pprint import pprint
467 print("FPSCRRecord.layout:")
468 pprint(FPSCRRecord.layout)
469 print("FPSCRState.fsi:")
470 pprint(FPSCRState().fsi)
471
472 # quick test of setter/getters
473 fpscr = FPSCRState()
474 fpscr.FPCC = 0b0001
475 print(fpscr.FPCC, fpscr.FL, fpscr.FG, fpscr.FE, fpscr.FU)
476 fpscr.FG = 0b1
477 print(fpscr.FPCC, fpscr.FL, fpscr.FG, fpscr.FE, fpscr.FU)
478 fpscr.FPRF = 0b00011
479 print(fpscr.FPRF, fpscr.C)
480 fpscr[63] = 1
481 print(fpscr.RN)