1ae31ce398417015763d6a1675b02f48f170ca70
[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):
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 l = deepcopy(FPSCRRecord.layout)
140 l.reverse()
141 for field, width in l:
142 if field == "FPRF":
143 v = FPSCR_FPRF(self, tuple(range(47, 52)))
144 end = 52
145 else:
146 end = offs + width
147 fs = tuple(range(offs, end))
148 v = FieldSelectableInt(self, fs)
149 self.fsi[field] = v
150 offs = end
151 # extra fields, temporarily explicitly added. TODO nested layout above
152 extras = [
153 (47, "C"),
154 (range(48, 52), "FPCC"),
155 (48, "FL"),
156 (49, "FG"),
157 (50, "FE"),
158 (51, "FU"),
159 ]
160 for offs, field in extras:
161 if isinstance(offs, int):
162 fs = (offs,)
163 else:
164 fs = tuple(offs)
165 v = FieldSelectableInt(self, fs)
166 self.fsi[field] = v
167 self.__update_summary_bits()
168
169 @property
170 def value(self):
171 return self.__value
172
173 @value.setter
174 def value(self, value):
175 self.__value = value
176 if self.__do_update_summary_bits:
177 self.__update_summary_bits()
178
179 def __update_summary_bits(self):
180 self.__do_update_summary_bits = False
181 try:
182 # update summary bits -- FX is manually handled by pseudo-code,
183 # so we don't update it here
184 self.VX = (self.VXSNAN |
185 self.VXISI |
186 self.VXIDI |
187 self.VXZDZ |
188 self.VXIMZ |
189 self.VXVC |
190 self.VXSOFT |
191 self.VXSQRT |
192 self.VXCVI)
193 self.FEX = ((self.VX & self.VE) |
194 (self.OX & self.OE) |
195 (self.UX & self.UE) |
196 (self.ZX & self.ZE) |
197 (self.XX & self.XE))
198 finally:
199 self.__do_update_summary_bits = True
200
201 @property
202 def DRN(self):
203 return self.fsi['DRN'].asint(msb0=True)
204
205 @DRN.setter
206 def DRN(self, value):
207 self.fsi['DRN'].eq(value)
208
209 @property
210 def FX(self):
211 return self.fsi['FX'].asint(msb0=True)
212
213 @FX.setter
214 def FX(self, value):
215 self.fsi['FX'].eq(value)
216
217 @property
218 def FEX(self):
219 return self.fsi['FEX'].asint(msb0=True)
220
221 @FEX.setter
222 def FEX(self, value):
223 self.fsi['FEX'].eq(value)
224
225 @property
226 def VX(self):
227 return self.fsi['VX'].asint(msb0=True)
228
229 @VX.setter
230 def VX(self, value):
231 self.fsi['VX'].eq(value)
232
233 @property
234 def OX(self):
235 return self.fsi['OX'].asint(msb0=True)
236
237 @OX.setter
238 def OX(self, value):
239 self.fsi['OX'].eq(value)
240
241 @property
242 def UX(self):
243 return self.fsi['UX'].asint(msb0=True)
244
245 @UX.setter
246 def UX(self, value):
247 self.fsi['UX'].eq(value)
248
249 @property
250 def ZX(self):
251 return self.fsi['ZX'].asint(msb0=True)
252
253 @ZX.setter
254 def ZX(self, value):
255 self.fsi['ZX'].eq(value)
256
257 @property
258 def XX(self):
259 return self.fsi['XX'].asint(msb0=True)
260
261 @XX.setter
262 def XX(self, value):
263 self.fsi['XX'].eq(value)
264
265 @property
266 def VXSNAN(self):
267 return self.fsi['VXSNAN'].asint(msb0=True)
268
269 @VXSNAN.setter
270 def VXSNAN(self, value):
271 self.fsi['VXSNAN'].eq(value)
272
273 @property
274 def VXISI(self):
275 return self.fsi['VXISI'].asint(msb0=True)
276
277 @VXISI.setter
278 def VXISI(self, value):
279 self.fsi['VXISI'].eq(value)
280
281 @property
282 def VXIDI(self):
283 return self.fsi['VXIDI'].asint(msb0=True)
284
285 @VXIDI.setter
286 def VXIDI(self, value):
287 self.fsi['VXIDI'].eq(value)
288
289 @property
290 def VXZDZ(self):
291 return self.fsi['VXZDZ'].asint(msb0=True)
292
293 @VXZDZ.setter
294 def VXZDZ(self, value):
295 self.fsi['VXZDZ'].eq(value)
296
297 @property
298 def VXIMZ(self):
299 return self.fsi['VXIMZ'].asint(msb0=True)
300
301 @VXIMZ.setter
302 def VXIMZ(self, value):
303 self.fsi['VXIMZ'].eq(value)
304
305 @property
306 def VXVC(self):
307 return self.fsi['VXVC'].asint(msb0=True)
308
309 @VXVC.setter
310 def VXVC(self, value):
311 self.fsi['VXVC'].eq(value)
312
313 @property
314 def FR(self):
315 return self.fsi['FR'].asint(msb0=True)
316
317 @FR.setter
318 def FR(self, value):
319 self.fsi['FR'].eq(value)
320
321 @property
322 def FI(self):
323 return self.fsi['FI'].asint(msb0=True)
324
325 @FI.setter
326 def FI(self, value):
327 self.fsi['FI'].eq(value)
328
329 @property
330 def FPRF(self):
331 return self.fsi['FPRF'].asint(msb0=True)
332
333 @FPRF.setter
334 def FPRF(self, value):
335 self.fsi['FPRF'].eq(value)
336
337 @property
338 def C(self):
339 return self.fsi['C'].asint(msb0=True)
340
341 @C.setter
342 def C(self, value):
343 self.fsi['C'].eq(value)
344
345 @property
346 def FPCC(self):
347 return self.fsi['FPCC'].asint(msb0=True)
348
349 @FPCC.setter
350 def FPCC(self, value):
351 self.fsi['FPCC'].eq(value)
352
353 @property
354 def FL(self):
355 return self.fsi['FL'].asint(msb0=True)
356
357 @FL.setter
358 def FL(self, value):
359 self.fsi['FL'].eq(value)
360
361 @property
362 def FG(self):
363 return self.fsi['FG'].asint(msb0=True)
364
365 @FG.setter
366 def FG(self, value):
367 self.fsi['FG'].eq(value)
368
369 @property
370 def FE(self):
371 return self.fsi['FE'].asint(msb0=True)
372
373 @FE.setter
374 def FE(self, value):
375 self.fsi['FE'].eq(value)
376
377 @property
378 def FU(self):
379 return self.fsi['FU'].asint(msb0=True)
380
381 @FU.setter
382 def FU(self, value):
383 self.fsi['FU'].eq(value)
384
385 @property
386 def VXSOFT(self):
387 return self.fsi['VXSOFT'].asint(msb0=True)
388
389 @VXSOFT.setter
390 def VXSOFT(self, value):
391 self.fsi['VXSOFT'].eq(value)
392
393 @property
394 def VXSQRT(self):
395 return self.fsi['VXSQRT'].asint(msb0=True)
396
397 @VXSQRT.setter
398 def VXSQRT(self, value):
399 self.fsi['VXSQRT'].eq(value)
400
401 @property
402 def VXCVI(self):
403 return self.fsi['VXCVI'].asint(msb0=True)
404
405 @VXCVI.setter
406 def VXCVI(self, value):
407 self.fsi['VXCVI'].eq(value)
408
409 @property
410 def VE(self):
411 return self.fsi['VE'].asint(msb0=True)
412
413 @VE.setter
414 def VE(self, value):
415 self.fsi['VE'].eq(value)
416
417 @property
418 def OE(self):
419 return self.fsi['OE'].asint(msb0=True)
420
421 @OE.setter
422 def OE(self, value):
423 self.fsi['OE'].eq(value)
424
425 @property
426 def UE(self):
427 return self.fsi['UE'].asint(msb0=True)
428
429 @UE.setter
430 def UE(self, value):
431 self.fsi['UE'].eq(value)
432
433 @property
434 def ZE(self):
435 return self.fsi['ZE'].asint(msb0=True)
436
437 @ZE.setter
438 def ZE(self, value):
439 self.fsi['ZE'].eq(value)
440
441 @property
442 def XE(self):
443 return self.fsi['XE'].asint(msb0=True)
444
445 @XE.setter
446 def XE(self, value):
447 self.fsi['XE'].eq(value)
448
449 @property
450 def NI(self):
451 return self.fsi['NI'].asint(msb0=True)
452
453 @NI.setter
454 def NI(self, value):
455 self.fsi['NI'].eq(value)
456
457 @property
458 def RN(self):
459 return self.fsi['RN'].asint(msb0=True)
460
461 @RN.setter
462 def RN(self, value):
463 self.fsi['RN'].eq(value)
464
465
466 if __name__ == "__main__":
467 from pprint import pprint
468 print("FPSCRRecord.layout:")
469 pprint(FPSCRRecord.layout)
470 print("FPSCRState.fsi:")
471 pprint(FPSCRState().fsi)
472
473 # quick test of setter/getters
474 fpscr = FPSCRState()
475 fpscr.FPCC = 0b0001
476 print(fpscr.FPCC, fpscr.FL, fpscr.FG, fpscr.FE, fpscr.FU)
477 fpscr.FG = 0b1
478 print(fpscr.FPCC, fpscr.FL, fpscr.FG, fpscr.FE, fpscr.FU)
479 fpscr.FPRF = 0b00011
480 print(fpscr.FPRF, fpscr.C)
481 fpscr[63] = 1
482 print(fpscr.RN)