3 from openpower
.decoder
.selectable_int
import (SelectableInt
, onebit
,
5 from nmutil
.divmod import trunc_divs
, trunc_rems
6 from operator
import floordiv
, mod
7 from openpower
.decoder
.selectable_int
import selectltu
as ltu
8 from openpower
.decoder
.selectable_int
import selectgtu
as gtu
9 from openpower
.decoder
.selectable_int
import check_extsign
11 from openpower
.util
import log
21 * https://bugs.libre-soc.org/show_bug.cgi?id=324 - add trunc_div and trunc_rem
25 def exts(value
, bits
):
26 sign
= 1 << (bits
- 1)
27 return (value
& (sign
- 1)) - (value
& sign
)
31 """ extends sign bit out from current MSB to all 256 bits
33 log ("EXTS", value
, type(value
))
34 assert isinstance(value
, SelectableInt
)
35 return SelectableInt(exts(value
.value
, value
.bits
) & ((1 << 256)-1), 256)
39 """ extends sign bit out from current MSB to 64 bits
41 assert isinstance(value
, SelectableInt
)
42 return SelectableInt(exts(value
.value
, value
.bits
) & ((1 << 64)-1), 64)
46 """ extends sign bit out from current MSB to 128 bits
48 assert isinstance(value
, SelectableInt
)
49 return SelectableInt(exts(value
.value
, value
.bits
) & ((1 << 128)-1), 128)
52 # signed version of MUL
54 if isinstance(b
, int):
55 b
= SelectableInt(b
, self
.bits
)
56 b
= check_extsign(a
, b
)
57 a_s
= a
.value
& (1 << (a
.bits
-1)) != 0
58 b_s
= b
.value
& (1 << (b
.bits
-1)) != 0
59 result
= abs(a
) * abs(b
)
60 log("MULS", result
, a_s
, b_s
)
66 # XXX should this explicitly extend from 32 to 64?
68 if isinstance(value
, SelectableInt
):
70 return SelectableInt(value
& ((1 << 32)-1), 64)
73 def rotl(value
, bits
, wordlen
):
74 if isinstance(bits
, SelectableInt
):
76 mask
= (1 << wordlen
) - 1
77 bits
= bits
& (wordlen
- 1)
78 return ((value
<< bits
) |
(value
>> (wordlen
-bits
))) & mask
81 def SHL64(value
, bits
, wordlen
=64):
82 if isinstance(bits
, SelectableInt
):
84 mask
= (1 << wordlen
) - 1
85 bits
= bits
& (wordlen
- 1)
86 return SelectableInt((value
<< bits
) & mask
, 64)
89 def ROTL64(value
, bits
):
90 return rotl(value
, bits
, 64)
93 def ROTL32(value
, bits
):
94 if isinstance(bits
, SelectableInt
):
96 if isinstance(value
, SelectableInt
):
97 value
= SelectableInt(value
.value
, 64)
98 return rotl(value |
(value
<< 32), bits
, 64)
101 if isinstance(x
, SelectableInt
):
103 if isinstance(y
, SelectableInt
):
105 return MASK(x
+32, y
+32)
108 if isinstance(x
, SelectableInt
):
110 if isinstance(y
, SelectableInt
):
115 mask_a
= ((1 << x
) - 1) & ((1 << 64) - 1)
116 mask_b
= ((1 << y
) - 1) & ((1 << 64) - 1)
122 mask_a
= ((1 << x
) - 1) & ((1 << 64) - 1)
123 mask_b
= (~
((1 << y
) - 1)) & ((1 << 64) - 1)
124 return mask_a ^ mask_b
128 return onebit(a
!= b
)
132 return onebit(a
== b
)
140 return onebit(a
>= b
)
148 return onebit(a
<= b
)
156 """ function that, for Power spec purposes, returns undefined bits of
157 the same shape as the input bits. however, for purposes of matching
158 POWER9's behavior returns the input bits unchanged. this effectively
159 "marks" (tags) locations in the v3.0B spec that need to be submitted
165 """convert incoming WORD to double. v3.0B p140 section 4.6.2
167 # result, FRT, start off all zeros
169 FRT
= SelectableInt(0, 64)
170 z1
= SelectableInt(0, 1)
171 z29
= SelectableInt(0, 29)
175 log ("word s e m", s
, e
, m
)
178 if e
.value
> 0 and e
.value
< 255:
184 FRT
[5:64] = selectconcat(WORD
[2:32], z29
)
186 # Denormalized Operand
187 if e
.value
== 0 and m
.value
!= 0:
191 frac
= selectconcat(z1
, WORD
[9:32], z29
)
192 # normalize the operand
193 while frac
[0].value
== 0:
194 frac
[0:53] = selectconcat(frac
[1:53], z1
)
197 FRT
[1:12] = exp
+ 1023
198 FRT
[12:64] = frac
[1:53]
200 # Zero / Infinity / NaN
201 if e
.value
== 255 or WORD
[1:32].value
== 0:
207 FRT
[5:64] = selectconcat(WORD
[2:32], z29
)
209 log ("Double s e m", FRT
[0].value
, FRT
[1:12].value
-1023,
216 """convert incoming FRS into 32-bit word. v3.0B p144 section 4.6.3
218 # result - WORD - start off all zeros
219 WORD
= SelectableInt(0, 32)
226 log ("s e m", s
.value
, e
.value
, m
.value
)
228 #No Denormalization Required (includes Zero / Infinity / NaN)
229 if e
.value
> 896 or FRS
[1:64].value
== 0:
230 log("nodenorm", FRS
[0:2].value
, hex(FRS
[5:35].value
))
232 WORD
[2:32] = FRS
[5:35]
234 #Denormalization Required
235 if e
.value
>= 874 and e
.value
<= 896:
238 frac
= selectconcat(SelectableInt(1, 1), FRS
[12:64])
239 log("exp, fract", exp
, hex(frac
.value
))
240 # denormalize operand
242 frac
[0:53] = selectconcat(SelectableInt(0, 1), frac
[0:52])
245 WORD
[1:9] = SelectableInt(0, 8)
246 WORD
[9:32] = frac
[1:24]
247 #else WORD = undefined # return zeros
253 # XXX NOTE: these are very quick hacked functions for utterly basic
256 def fp64toselectable(frt
):
257 """convert FP number to 64 bit SelectableInt
259 b
= struct
.pack(">d", frt
)
260 val
= int.from_bytes(b
, byteorder
='big', signed
=False)
261 return SelectableInt(val
, 64)
265 from openpower
.decoder
.isafunctions
.double2single
import DOUBLE2SINGLE
266 #FRB = DOUBLE(SINGLE(FRB))
267 result
= math
.sin(float(FRB
))
268 cvt
= fp64toselectable(result
)
269 cvt
= DOUBLE2SINGLE(cvt
)
270 log ("FPSIN32", FRB
, float(FRB
), "=", result
, cvt
)
275 from openpower
.decoder
.isafunctions
.double2single
import DOUBLE2SINGLE
276 #FRB = DOUBLE(SINGLE(FRB))
277 result
= math
.cos(float(FRB
))
278 cvt
= fp64toselectable(result
)
279 cvt
= DOUBLE2SINGLE(cvt
)
280 log ("FPCOS32", FRB
, float(FRB
), "=", result
, cvt
)
284 def FPADD32(FRA
, FRB
):
285 from openpower
.decoder
.isafunctions
.double2single
import DOUBLE2SINGLE
286 #return FPADD64(FRA, FRB)
287 #FRA = DOUBLE(SINGLE(FRA))
288 #FRB = DOUBLE(SINGLE(FRB))
289 result
= float(FRA
) + float(FRB
)
290 cvt
= fp64toselectable(result
)
291 cvt
= DOUBLE2SINGLE(cvt
)
292 log ("FPADD32", FRA
, FRB
, float(FRA
), "+", float(FRB
), "=", result
, cvt
)
296 def FPSUB32(FRA
, FRB
):
297 from openpower
.decoder
.isafunctions
.double2single
import DOUBLE2SINGLE
298 #return FPSUB64(FRA, FRB)
299 #FRA = DOUBLE(SINGLE(FRA))
300 #FRB = DOUBLE(SINGLE(FRB))
301 result
= float(FRA
) - float(FRB
)
302 cvt
= fp64toselectable(result
)
303 cvt
= DOUBLE2SINGLE(cvt
)
304 log ("FPSUB32", FRA
, FRB
, float(FRA
), "-", float(FRB
), "=", result
, cvt
)
308 def signinv(res
, sign
):
317 def FPMUL32(FRA
, FRB
, sign
=1):
318 from openpower
.decoder
.isafunctions
.double2single
import DOUBLE2SINGLE
319 #return FPMUL64(FRA, FRB)
320 FRA
= DOUBLE(SINGLE(FRA
))
321 FRB
= DOUBLE(SINGLE(FRB
))
322 result
= signinv(float(FRA
) * float(FRB
), sign
)
323 log ("FPMUL32", FRA
, FRB
, float(FRA
), float(FRB
), result
, sign
)
324 cvt
= fp64toselectable(result
)
325 cvt
= DOUBLE2SINGLE(cvt
)
330 def FPMULADD32(FRA
, FRC
, FRB
, mulsign
, addsign
):
331 from openpower
.decoder
.isafunctions
.double2single
import DOUBLE2SINGLE
332 #return FPMUL64(FRA, FRB)
333 #FRA = DOUBLE(SINGLE(FRA))
334 #FRB = DOUBLE(SINGLE(FRB))
337 result
= float(FRA
) * float(FRC
) + float(FRB
) # fmadds
339 result
= -(float(FRA
) * float(FRC
) - float(FRB
)) # fnmsubs
342 result
= float(FRA
) * float(FRC
) - float(FRB
) # fmsubs
344 result
= -(float(FRA
) * float(FRC
) + float(FRB
)) # fnmadds
347 log ("FPMULADD32 FRA FRC FRB", FRA
, FRC
, FRB
)
348 log (" FRA", float(FRA
))
349 log (" FRC", float(FRC
))
350 log (" FRB", float(FRB
))
351 log (" (FRA*FRC)+FRB=", mulsign
, addsign
, result
)
352 cvt
= fp64toselectable(result
)
353 cvt
= DOUBLE2SINGLE(cvt
)
358 def FPDIV32(FRA
, FRB
, sign
=1):
359 from openpower
.decoder
.isafunctions
.double2single
import DOUBLE2SINGLE
360 #return FPDIV64(FRA, FRB)
361 #FRA = DOUBLE(SINGLE(FRA))
362 #FRB = DOUBLE(SINGLE(FRB))
363 result
= signinv(float(FRA
) / float(FRB
), sign
)
364 cvt
= fp64toselectable(result
)
365 cvt
= DOUBLE2SINGLE(cvt
)
366 log ("FPDIV32", FRA
, FRB
, result
, cvt
)
370 def FPADD64(FRA
, FRB
):
371 result
= float(FRA
) + float(FRB
)
372 cvt
= fp64toselectable(result
)
373 log ("FPADD64", FRA
, FRB
, result
, cvt
)
377 def FPSUB64(FRA
, FRB
):
378 result
= float(FRA
) - float(FRB
)
379 cvt
= fp64toselectable(result
)
380 log ("FPSUB64", FRA
, FRB
, result
, cvt
)
384 def FPMUL64(FRA
, FRB
, sign
=1):
385 result
= signinv(float(FRA
) * float(FRB
), sign
)
386 cvt
= fp64toselectable(result
)
387 log ("FPMUL64", FRA
, FRB
, result
, cvt
, sign
)
391 def FPDIV64(FRA
, FRB
, sign
=1):
392 result
= signinv(float(FRA
) / float(FRB
), sign
)
393 cvt
= fp64toselectable(result
)
394 log ("FPDIV64", FRA
, FRB
, result
, cvt
, sign
)
400 """Returns the integer whose value is the reverse of the lowest
401 'width' bits of the integer 'val'
404 width
= VL
.bit_length()-1
405 for _
in range(width
):
406 result
= (result
<< 1) |
(val
& 1)
411 # For these tests I tried to find power instructions that would let me
412 # isolate each of these helper operations. So for instance, when I was
413 # testing the MASK() function, I chose rlwinm and rldicl because if I
414 # set the shift equal to 0 and passed in a value of all ones, the
415 # result I got would be exactly the same as the output of MASK()
418 class HelperTests(unittest
.TestCase
):
420 # Verified using rlwinm, rldicl, rldicr in qemu
422 # rlwinm reg, 1, 0, 5, 15
423 self
.assertHex(MASK(5+32, 15+32), 0x7ff0000)
424 # rlwinm reg, 1, 0, 15, 5
425 self
.assertHex(MASK(15+32, 5+32), 0xfffffffffc01ffff)
426 self
.assertHex(MASK(30+32, 2+32), 0xffffffffe0000003)
427 # rldicl reg, 1, 0, 37
428 self
.assertHex(MASK(37, 63), 0x7ffffff)
429 self
.assertHex(MASK(10, 63), 0x3fffffffffffff)
430 self
.assertHex(MASK(58, 63), 0x3f)
431 # rldicr reg, 1, 0, 37
432 self
.assertHex(MASK(0, 37), 0xfffffffffc000000)
433 self
.assertHex(MASK(0, 10), 0xffe0000000000000)
434 self
.assertHex(MASK(0, 58), 0xffffffffffffffe0)
438 self
.assertHex(MASK(32, 63-5), 0xffffffe0)
440 self
.assertHex(MASK(32, 33), 0xc0000000)
441 self
.assertHex(MASK(32, 32), 0x80000000)
442 self
.assertHex(MASK(33, 33), 0x40000000)
444 def test_ROTL64(self
):
445 # r1 = 0xdeadbeef12345678
446 value
= 0xdeadbeef12345678
448 # rldicl reg, 1, 10, 0
449 self
.assertHex(ROTL64(value
, 10), 0xb6fbbc48d159e37a)
450 # rldicl reg, 1, 35, 0
451 self
.assertHex(ROTL64(value
, 35), 0x91a2b3c6f56df778)
452 self
.assertHex(ROTL64(value
, 58), 0xe37ab6fbbc48d159)
453 self
.assertHex(ROTL64(value
, 22), 0xbbc48d159e37ab6f)
455 def test_ROTL32(self
):
459 # rlwinm reg, 1, 10, 0, 31
460 self
.assertHex(ROTL32(value
, 10), 0xb6fbbf7a)
461 # rlwinm reg, 1, 17, 0, 31
462 self
.assertHex(ROTL32(value
, 17), 0x7ddfbd5b)
463 self
.assertHex(ROTL32(value
, 25), 0xdfbd5b7d)
464 self
.assertHex(ROTL32(value
, 30), 0xf7ab6fbb)
466 def test_EXTS64(self
):
467 value_a
= SelectableInt(0xdeadbeef, 32) # r1
468 value_b
= SelectableInt(0x73123456, 32) # r2
469 value_c
= SelectableInt(0x80000000, 32) # r3
472 self
.assertHex(EXTS64(value_a
), 0xffffffffdeadbeef)
474 self
.assertHex(EXTS64(value_b
), SelectableInt(value_b
.value
, 64))
476 self
.assertHex(EXTS64(value_c
), 0xffffffff80000000)
478 def test_FPADD32(self
):
479 value_a
= SelectableInt(0x4014000000000000, 64) # 5.0
480 value_b
= SelectableInt(0x403B4CCCCCCCCCCD, 64) # 27.3
481 result
= FPADD32(value_a
, value_b
)
482 self
.assertHex(0x4040266666666666, result
)
484 def assertHex(self
, a
, b
):
486 if isinstance(a
, SelectableInt
):
489 if isinstance(b
, SelectableInt
):
491 msg
= "{:x} != {:x}".format(a_val
, b_val
)
492 return self
.assertEqual(a
, b
, msg
)
495 if __name__
== '__main__':
496 log(SelectableInt
.__bases
__)