4 from openpower
.decoder
.selectable_int
import (SelectableInt
, onebit
,
6 from nmutil
.divmod import trunc_divs
, trunc_rems
7 from operator
import floordiv
, mod
8 from openpower
.decoder
.selectable_int
import selectltu
as ltu
9 from openpower
.decoder
.selectable_int
import selectgtu
as gtu
10 from openpower
.decoder
.selectable_int
import check_extsign
12 from openpower
.util
import log
22 * https://bugs.libre-soc.org/show_bug.cgi?id=324 - add trunc_div and trunc_rem
23 * https://bugs.libre-soc.org/show_bug.cgi?id=671#c38 - RANGE (and bugfixes)
27 def RANGE(start
, end
):
30 # auto-subtract-one (sigh) due to python range
31 return range(start
, end
-1, -1)
32 # auto-add-one (sigh) due to python range
33 return range(start
, end
+1)
36 def exts(value
, bits
):
37 sign
= 1 << (bits
- 1)
38 return (value
& (sign
- 1)) - (value
& sign
)
42 """ extends sign bit out from current MSB to all 256 bits
44 log("EXTS", value
, type(value
))
45 assert isinstance(value
, SelectableInt
)
46 return SelectableInt(exts(value
.value
, value
.bits
) & ((1 << 256)-1), 256)
50 """ extends sign bit out from current MSB to 64 bits
52 assert isinstance(value
, SelectableInt
)
53 return SelectableInt(exts(value
.value
, value
.bits
) & ((1 << 64)-1), 64)
57 """ extends sign bit out from current MSB to 128 bits
59 assert isinstance(value
, SelectableInt
)
60 return SelectableInt(exts(value
.value
, value
.bits
) & ((1 << 128)-1), 128)
63 # signed version of MUL
65 if isinstance(b
, int):
66 b
= SelectableInt(b
, self
.bits
)
67 b
= check_extsign(a
, b
)
68 a_s
= a
.value
& (1 << (a
.bits
-1)) != 0
69 b_s
= b
.value
& (1 << (b
.bits
-1)) != 0
70 result
= abs(a
) * abs(b
)
71 log("MULS", result
, a_s
, b_s
)
77 # XXX should this explicitly extend from 32 to 64?
79 if isinstance(value
, SelectableInt
):
81 return SelectableInt(value
& ((1 << 32)-1), 64)
84 def rotl(value
, bits
, wordlen
):
85 if isinstance(bits
, SelectableInt
):
87 mask
= (1 << wordlen
) - 1
88 bits
= bits
& (wordlen
- 1)
89 return ((value
<< bits
) |
(value
>> (wordlen
-bits
))) & mask
92 def SHL64(value
, bits
, wordlen
=64):
93 if isinstance(bits
, SelectableInt
):
95 mask
= (1 << wordlen
) - 1
96 bits
= bits
& (wordlen
- 1)
97 return SelectableInt((value
<< bits
) & mask
, 64)
100 def ROTL64(value
, bits
):
101 return rotl(value
, bits
, 64)
104 def ROTL32(value
, bits
):
105 if isinstance(bits
, SelectableInt
):
107 if isinstance(value
, SelectableInt
):
108 value
= SelectableInt(value
.value
, 64)
109 return rotl(value |
(value
<< 32), bits
, 64)
113 if isinstance(x
, SelectableInt
):
115 if isinstance(y
, SelectableInt
):
117 return MASK(x
+32, y
+32)
121 if isinstance(x
, SelectableInt
):
123 if isinstance(y
, SelectableInt
):
128 mask_a
= ((1 << x
) - 1) & ((1 << 64) - 1)
129 mask_b
= ((1 << y
) - 1) & ((1 << 64) - 1)
135 mask_a
= ((1 << x
) - 1) & ((1 << 64) - 1)
136 mask_b
= (~
((1 << y
) - 1)) & ((1 << 64) - 1)
137 return mask_a ^ mask_b
141 return onebit(a
!= b
)
145 return onebit(a
== b
)
153 return onebit(a
>= b
)
161 return onebit(a
<= b
)
169 """ function that, for Power spec purposes, returns undefined bits of
170 the same shape as the input bits. however, for purposes of matching
171 POWER9's behavior returns the input bits unchanged. this effectively
172 "marks" (tags) locations in the v3.0B spec that need to be submitted
179 """convert incoming FRS into 32-bit word. v3.0B p144 section 4.6.3
181 # result - WORD - start off all zeros
182 WORD
= SelectableInt(0, 32)
189 log("s e m", s
.value
, e
.value
, m
.value
)
191 # No Denormalization Required (includes Zero / Infinity / NaN)
192 if e
.value
> 896 or FRS
[1:64].value
== 0:
193 log("nodenorm", FRS
[0:2].value
, hex(FRS
[5:35].value
))
195 WORD
[2:32] = FRS
[5:35]
197 # Denormalization Required
198 if e
.value
>= 874 and e
.value
<= 896:
201 frac
= selectconcat(SelectableInt(1, 1), FRS
[12:64])
202 log("exp, fract", exp
, hex(frac
.value
))
203 # denormalize operand
205 frac
[0:53] = selectconcat(SelectableInt(0, 1), frac
[0:52])
208 WORD
[1:9] = SelectableInt(0, 8)
209 WORD
[9:32] = frac
[1:24]
210 # else WORD = undefined # return zeros
216 # XXX NOTE: these are very quick hacked functions for utterly basic
220 def signinv(res
, sign
):
229 def fp64toselectable(frt
):
230 """convert FP number to 64 bit SelectableInt
232 b
= struct
.pack(">d", frt
)
233 val
= int.from_bytes(b
, byteorder
='big', signed
=False)
234 return SelectableInt(val
, 64)
239 def FPSIN32(self
, FRB
):
240 #FRB = DOUBLE(SINGLE(FRB))
241 result
= math
.sin(float(FRB
))
242 cvt
= fp64toselectable(result
)
243 cvt
= self
.DOUBLE2SINGLE(cvt
)
244 log("FPSIN32", FRB
, float(FRB
), "=", result
, cvt
)
247 def FPCOS32(self
, FRB
):
248 #FRB = DOUBLE(SINGLE(FRB))
249 result
= math
.cos(float(FRB
))
250 cvt
= fp64toselectable(result
)
251 cvt
= self
.DOUBLE2SINGLE(cvt
)
252 log("FPCOS32", FRB
, float(FRB
), "=", result
, cvt
)
255 def FPADD32(self
, FRA
, FRB
):
256 # return FPADD64(FRA, FRB)
257 #FRA = DOUBLE(SINGLE(FRA))
258 #FRB = DOUBLE(SINGLE(FRB))
259 result
= float(FRA
) + float(FRB
)
260 cvt
= fp64toselectable(result
)
261 cvt
= self
.DOUBLE2SINGLE(cvt
)
262 log("FPADD32", FRA
, FRB
, float(FRA
), "+", float(FRB
), "=", result
, cvt
)
265 def FPSUB32(self
, FRA
, FRB
):
266 # return FPSUB64(FRA, FRB)
267 #FRA = DOUBLE(SINGLE(FRA))
268 #FRB = DOUBLE(SINGLE(FRB))
269 result
= float(FRA
) - float(FRB
)
270 cvt
= fp64toselectable(result
)
271 cvt
= self
.DOUBLE2SINGLE(cvt
)
272 log("FPSUB32", FRA
, FRB
, float(FRA
), "-", float(FRB
), "=", result
, cvt
)
275 def FPMUL32(self
, FRA
, FRB
, sign
=1):
276 # return FPMUL64(FRA, FRB)
277 FRA
= self
.DOUBLE(SINGLE(FRA
))
278 FRB
= self
.DOUBLE(SINGLE(FRB
))
279 result
= signinv(float(FRA
) * float(FRB
), sign
)
280 log("FPMUL32", FRA
, FRB
, float(FRA
), float(FRB
), result
, sign
)
281 cvt
= fp64toselectable(result
)
282 cvt
= self
.DOUBLE2SINGLE(cvt
)
286 def FPMULADD32(self
, FRA
, FRC
, FRB
, mulsign
, addsign
):
287 # return FPMUL64(FRA, FRB)
288 #FRA = DOUBLE(SINGLE(FRA))
289 #FRB = DOUBLE(SINGLE(FRB))
292 result
= float(FRA
) * float(FRC
) + float(FRB
) # fmadds
294 result
= -(float(FRA
) * float(FRC
) - float(FRB
)) # fnmsubs
297 result
= float(FRA
) * float(FRC
) - float(FRB
) # fmsubs
299 result
= -(float(FRA
) * float(FRC
) + float(FRB
)) # fnmadds
302 log("FPMULADD32 FRA FRC FRB", FRA
, FRC
, FRB
)
303 log(" FRA", float(FRA
))
304 log(" FRC", float(FRC
))
305 log(" FRB", float(FRB
))
306 log(" (FRA*FRC)+FRB=", mulsign
, addsign
, result
)
307 cvt
= fp64toselectable(result
)
308 cvt
= self
.DOUBLE2SINGLE(cvt
)
312 def FPDIV32(self
, FRA
, FRB
, sign
=1):
313 # return FPDIV64(FRA, FRB)
314 #FRA = DOUBLE(SINGLE(FRA))
315 #FRB = DOUBLE(SINGLE(FRB))
316 result
= signinv(float(FRA
) / float(FRB
), sign
)
317 cvt
= fp64toselectable(result
)
318 cvt
= self
.DOUBLE2SINGLE(cvt
)
319 log("FPDIV32", FRA
, FRB
, result
, cvt
)
323 def FPADD64(FRA
, FRB
):
324 result
= float(FRA
) + float(FRB
)
325 cvt
= fp64toselectable(result
)
326 log("FPADD64", FRA
, FRB
, result
, cvt
)
330 def FPSUB64(FRA
, FRB
):
331 result
= float(FRA
) - float(FRB
)
332 cvt
= fp64toselectable(result
)
333 log("FPSUB64", FRA
, FRB
, result
, cvt
)
337 def FPMUL64(FRA
, FRB
, sign
=1):
338 result
= signinv(float(FRA
) * float(FRB
), sign
)
339 cvt
= fp64toselectable(result
)
340 log("FPMUL64", FRA
, FRB
, result
, cvt
, sign
)
344 def FPDIV64(FRA
, FRB
, sign
=1):
345 result
= signinv(float(FRA
) / float(FRB
), sign
)
346 cvt
= fp64toselectable(result
)
347 log("FPDIV64", FRA
, FRB
, result
, cvt
, sign
)
352 """Returns the integer whose value is the reverse of the lowest
353 'width' bits of the integer 'val'
356 width
= VL
.bit_length()-1
357 for _
in range(width
):
358 result
= (result
<< 1) |
(val
& 1)
364 """return the base-2 logarithm of `val`. Only works for powers of 2."""
365 if isinstance(val
, SelectableInt
):
367 retval
= val
.bit_length() - 1
368 assert val
== 2 ** retval
, "value is not a power of 2"
372 # For these tests I tried to find power instructions that would let me
373 # isolate each of these helper operations. So for instance, when I was
374 # testing the MASK() function, I chose rlwinm and rldicl because if I
375 # set the shift equal to 0 and passed in a value of all ones, the
376 # result I got would be exactly the same as the output of MASK()
379 class HelperTests(unittest
.TestCase
):
381 # Verified using rlwinm, rldicl, rldicr in qemu
383 # rlwinm reg, 1, 0, 5, 15
384 self
.assertHex(MASK(5+32, 15+32), 0x7ff0000)
385 # rlwinm reg, 1, 0, 15, 5
386 self
.assertHex(MASK(15+32, 5+32), 0xfffffffffc01ffff)
387 self
.assertHex(MASK(30+32, 2+32), 0xffffffffe0000003)
388 # rldicl reg, 1, 0, 37
389 self
.assertHex(MASK(37, 63), 0x7ffffff)
390 self
.assertHex(MASK(10, 63), 0x3fffffffffffff)
391 self
.assertHex(MASK(58, 63), 0x3f)
392 # rldicr reg, 1, 0, 37
393 self
.assertHex(MASK(0, 37), 0xfffffffffc000000)
394 self
.assertHex(MASK(0, 10), 0xffe0000000000000)
395 self
.assertHex(MASK(0, 58), 0xffffffffffffffe0)
399 self
.assertHex(MASK(32, 63-5), 0xffffffe0)
401 self
.assertHex(MASK(32, 33), 0xc0000000)
402 self
.assertHex(MASK(32, 32), 0x80000000)
403 self
.assertHex(MASK(33, 33), 0x40000000)
405 def test_ROTL64(self
):
406 # r1 = 0xdeadbeef12345678
407 value
= 0xdeadbeef12345678
409 # rldicl reg, 1, 10, 0
410 self
.assertHex(ROTL64(value
, 10), 0xb6fbbc48d159e37a)
411 # rldicl reg, 1, 35, 0
412 self
.assertHex(ROTL64(value
, 35), 0x91a2b3c6f56df778)
413 self
.assertHex(ROTL64(value
, 58), 0xe37ab6fbbc48d159)
414 self
.assertHex(ROTL64(value
, 22), 0xbbc48d159e37ab6f)
416 def test_ROTL32(self
):
420 # rlwinm reg, 1, 10, 0, 31
421 self
.assertHex(ROTL32(value
, 10), 0xb6fbbf7a)
422 # rlwinm reg, 1, 17, 0, 31
423 self
.assertHex(ROTL32(value
, 17), 0x7ddfbd5b)
424 self
.assertHex(ROTL32(value
, 25), 0xdfbd5b7d)
425 self
.assertHex(ROTL32(value
, 30), 0xf7ab6fbb)
427 def test_EXTS64(self
):
428 value_a
= SelectableInt(0xdeadbeef, 32) # r1
429 value_b
= SelectableInt(0x73123456, 32) # r2
430 value_c
= SelectableInt(0x80000000, 32) # r3
433 self
.assertHex(EXTS64(value_a
), 0xffffffffdeadbeef)
435 self
.assertHex(EXTS64(value_b
), SelectableInt(value_b
.value
, 64))
437 self
.assertHex(EXTS64(value_c
), 0xffffffff80000000)
439 def test_FPADD32(self
):
440 value_a
= SelectableInt(0x4014000000000000, 64) # 5.0
441 value_b
= SelectableInt(0x403B4CCCCCCCCCCD, 64) # 27.3
442 result
= FPADD32(value_a
, value_b
)
443 self
.assertHex(0x4040266666666666, result
)
445 def assertHex(self
, a
, b
):
447 if isinstance(a
, SelectableInt
):
450 if isinstance(b
, SelectableInt
):
452 msg
= "{:x} != {:x}".format(a_val
, b_val
)
453 return self
.assertEqual(a
, b
, msg
)
456 class ISACallerHelper
:
457 def __init__(self
, XLEN
):
464 def XLCASTS(self
, value
):
465 return SelectableInt(exts(value
.value
, self
.XLEN
), self
.XLEN
)
467 def XLCASTU(self
, value
):
468 # SelectableInt already takes care of masking out the bits
469 return SelectableInt(value
.value
, self
.XLEN
)
471 def EXTSXL(self
, value
, bits
):
472 return SelectableInt(exts(value
.value
, bits
), self
.XLEN
)
474 def DOUBLE2SINGLE(self
, FRS
):
475 """ DOUBLE2SINGLE has been renamed to FRSP since it is the
476 implementation of the frsp instruction.
477 use SINGLE() or FRSP() instead, or just use struct.pack/unpack
480 'UE': SelectableInt(0, 1),
481 'OE': SelectableInt(0, 1),
482 'RN': SelectableInt(0, 2), # round to nearest, ties to even
483 'XX': SelectableInt(0, 1),
485 FRT
, FPSCR
= self
.FRSP(FRS
, FPSCR
)
488 def __getattr__(self
, attr
):
490 return globals()[attr
]
492 raise AttributeError(attr
)
495 if __name__
== '__main__':
496 log(SelectableInt
.__bases
__)