comments
[openpower-isa.git] / src / openpower / decoder / helpers.py
1 import unittest
2 import struct
3 from openpower.decoder.selectable_int import (SelectableInt, onebit,
4 selectconcat)
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
10
11 from openpower.util import log
12 import math
13
14 trunc_div = floordiv
15 trunc_rem = mod
16 DIVS = trunc_divs
17 MODS = trunc_rems
18
19 """
20 Links:
21 * https://bugs.libre-soc.org/show_bug.cgi?id=324 - add trunc_div and trunc_rem
22 """
23
24
25 def exts(value, bits):
26 sign = 1 << (bits - 1)
27 return (value & (sign - 1)) - (value & sign)
28
29
30 def EXTS(value):
31 """ extends sign bit out from current MSB to all 256 bits
32 """
33 log ("EXTS", value, type(value))
34 assert isinstance(value, SelectableInt)
35 return SelectableInt(exts(value.value, value.bits) & ((1 << 256)-1), 256)
36
37
38 def EXTS64(value):
39 """ extends sign bit out from current MSB to 64 bits
40 """
41 assert isinstance(value, SelectableInt)
42 return SelectableInt(exts(value.value, value.bits) & ((1 << 64)-1), 64)
43
44
45 def EXTS128(value):
46 """ extends sign bit out from current MSB to 128 bits
47 """
48 assert isinstance(value, SelectableInt)
49 return SelectableInt(exts(value.value, value.bits) & ((1 << 128)-1), 128)
50
51
52 # signed version of MUL
53 def MULS(a, b):
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)
61 if a_s == b_s:
62 return result
63 return -result
64
65
66 # XXX should this explicitly extend from 32 to 64?
67 def EXTZ64(value):
68 if isinstance(value, SelectableInt):
69 value = value.value
70 return SelectableInt(value & ((1 << 32)-1), 64)
71
72
73 def rotl(value, bits, wordlen):
74 if isinstance(bits, SelectableInt):
75 bits = bits.value
76 mask = (1 << wordlen) - 1
77 bits = bits & (wordlen - 1)
78 return ((value << bits) | (value >> (wordlen-bits))) & mask
79
80
81 def SHL64(value, bits, wordlen=64):
82 if isinstance(bits, SelectableInt):
83 bits = bits.value
84 mask = (1 << wordlen) - 1
85 bits = bits & (wordlen - 1)
86 return SelectableInt((value << bits) & mask, 64)
87
88
89 def ROTL64(value, bits):
90 return rotl(value, bits, 64)
91
92
93 def ROTL32(value, bits):
94 if isinstance(bits, SelectableInt):
95 bits = bits.value
96 if isinstance(value, SelectableInt):
97 value = SelectableInt(value.value, 64)
98 return rotl(value | (value << 32), bits, 64)
99
100 def MASK32(x, y):
101 if isinstance(x, SelectableInt):
102 x = x.value
103 if isinstance(y, SelectableInt):
104 y = y.value
105 return MASK(x+32, y+32)
106
107 def MASK(x, y):
108 if isinstance(x, SelectableInt):
109 x = x.value
110 if isinstance(y, SelectableInt):
111 y = y.value
112 if x < y:
113 x = 64-x
114 y = 63-y
115 mask_a = ((1 << x) - 1) & ((1 << 64) - 1)
116 mask_b = ((1 << y) - 1) & ((1 << 64) - 1)
117 elif x == y:
118 return 1 << (63-x)
119 else:
120 x = 64-x
121 y = 63-y
122 mask_a = ((1 << x) - 1) & ((1 << 64) - 1)
123 mask_b = (~((1 << y) - 1)) & ((1 << 64) - 1)
124 return mask_a ^ mask_b
125
126
127 def ne(a, b):
128 return onebit(a != b)
129
130
131 def eq(a, b):
132 return onebit(a == b)
133
134
135 def gt(a, b):
136 return onebit(a > b)
137
138
139 def ge(a, b):
140 return onebit(a >= b)
141
142
143 def lt(a, b):
144 return onebit(a < b)
145
146
147 def le(a, b):
148 return onebit(a <= b)
149
150
151 def length(a):
152 return len(a)
153
154
155 def undefined(v):
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
160 for clarification.
161 """
162 return v
163
164 def DOUBLE(WORD):
165 """convert incoming WORD to double. v3.0B p140 section 4.6.2
166 """
167 # result, FRT, start off all zeros
168 log ("WORD", WORD)
169 FRT = SelectableInt(0, 64)
170 z1 = SelectableInt(0, 1)
171 z29 = SelectableInt(0, 29)
172 e = WORD[1:9]
173 m = WORD[9:32]
174 s = WORD[0]
175 log ("word s e m", s, e, m)
176
177 # Normalized Operand
178 if e.value > 0 and e.value < 255:
179 log ("normalised")
180 FRT[0:2] = WORD[0:2]
181 FRT[2] = ~WORD[1]
182 FRT[3] = ~WORD[1]
183 FRT[4] = ~WORD[1]
184 FRT[5:64] = selectconcat(WORD[2:32], z29)
185
186 # Denormalized Operand
187 if e.value == 0 and m.value != 0:
188 log ("denormalised")
189 sign = WORD[0]
190 exp = -126
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)
195 exp = exp - 1
196 FRT[0] = sign
197 FRT[1:12] = exp + 1023
198 FRT[12:64] = frac[1:53]
199
200 # Zero / Infinity / NaN
201 if e.value == 255 or WORD[1:32].value == 0:
202 log ("z/inf/nan")
203 FRT[0:2] = WORD[0:2]
204 FRT[2] = WORD[1]
205 FRT[3] = WORD[1]
206 FRT[4] = WORD[1]
207 FRT[5:64] = selectconcat(WORD[2:32], z29)
208
209 log ("Double s e m", FRT[0].value, FRT[1:12].value-1023,
210 FRT[12:64].value)
211
212 return FRT
213
214
215 def SINGLE(FRS):
216 """convert incoming FRS into 32-bit word. v3.0B p144 section 4.6.3
217 """
218 # result - WORD - start off all zeros
219 WORD = SelectableInt(0, 32)
220
221 e = FRS[1:12]
222 m = FRS[12:64]
223 s = FRS[0]
224
225 log ("SINGLE", FRS)
226 log ("s e m", s.value, e.value, m.value)
227
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))
231 WORD[0:2] = FRS[0:2]
232 WORD[2:32] = FRS[5:35]
233
234 #Denormalization Required
235 if e.value >= 874 and e.value <= 896:
236 sign = FRS[0]
237 exp = e.value - 1023
238 frac = selectconcat(SelectableInt(1, 1), FRS[12:64])
239 log("exp, fract", exp, hex(frac.value))
240 # denormalize operand
241 while exp < -126:
242 frac[0:53] = selectconcat(SelectableInt(0, 1), frac[0:52])
243 exp = exp + 1
244 WORD[0] = sign
245 WORD[1:9] = SelectableInt(0, 8)
246 WORD[9:32] = frac[1:24]
247 #else WORD = undefined # return zeros
248
249 log ("WORD", WORD)
250
251 return WORD
252
253 # XXX NOTE: these are very quick hacked functions for utterly basic
254 # FP support
255
256 def fp64toselectable(frt):
257 """convert FP number to 64 bit SelectableInt
258 """
259 b = struct.pack(">d", frt)
260 val = int.from_bytes(b, byteorder='big', signed=False)
261 return SelectableInt(val, 64)
262
263
264 def FPSIN32(FRB):
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)
271 return cvt
272
273
274 def FPCOS32(FRB):
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)
281 return cvt
282
283
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)
293 return cvt
294
295
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)
305 return cvt
306
307
308 def signinv(res, sign):
309 if sign == 1:
310 return res
311 if sign == 0:
312 return 0.0
313 if sign == -1:
314 return -res
315
316
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)
326 log (" cvt", cvt)
327 return cvt
328
329
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))
335 if addsign == 1:
336 if mulsign == 1:
337 result = float(FRA) * float(FRC) + float(FRB) # fmadds
338 elif mulsign == -1:
339 result = -(float(FRA) * float(FRC) - float(FRB)) # fnmsubs
340 elif addsign == -1:
341 if mulsign == 1:
342 result = float(FRA) * float(FRC) - float(FRB) # fmsubs
343 elif mulsign == -1:
344 result = -(float(FRA) * float(FRC) + float(FRB)) # fnmadds
345 elif addsign == 0:
346 result = 0.0
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)
354 log (" cvt", cvt)
355 return cvt
356
357
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)
367 return cvt
368
369
370 def FPADD64(FRA, FRB):
371 result = float(FRA) + float(FRB)
372 cvt = fp64toselectable(result)
373 log ("FPADD64", FRA, FRB, result, cvt)
374 return cvt
375
376
377 def FPSUB64(FRA, FRB):
378 result = float(FRA) - float(FRB)
379 cvt = fp64toselectable(result)
380 log ("FPSUB64", FRA, FRB, result, cvt)
381 return cvt
382
383
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)
388 return cvt
389
390
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)
395 return cvt
396
397
398
399 def bitrev(val, VL):
400 """Returns the integer whose value is the reverse of the lowest
401 'width' bits of the integer 'val'
402 """
403 result = 0
404 width = VL.bit_length()-1
405 for _ in range(width):
406 result = (result << 1) | (val & 1)
407 val >>= 1
408 return result
409
410
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()
416
417
418 class HelperTests(unittest.TestCase):
419 def test_MASK(self):
420 # Verified using rlwinm, rldicl, rldicr in qemu
421 # li 1, -1
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)
435
436 # li 2, 5
437 # slw 1, 1, 2
438 self.assertHex(MASK(32, 63-5), 0xffffffe0)
439
440 self.assertHex(MASK(32, 33), 0xc0000000)
441 self.assertHex(MASK(32, 32), 0x80000000)
442 self.assertHex(MASK(33, 33), 0x40000000)
443
444 def test_ROTL64(self):
445 # r1 = 0xdeadbeef12345678
446 value = 0xdeadbeef12345678
447
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)
454
455 def test_ROTL32(self):
456 # r1 = 0xdeadbeef
457 value = 0xdeadbeef
458
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)
465
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
470
471 # extswsli reg, 1, 0
472 self.assertHex(EXTS64(value_a), 0xffffffffdeadbeef)
473 # extswsli reg, 2, 0
474 self.assertHex(EXTS64(value_b), SelectableInt(value_b.value, 64))
475 # extswsli reg, 3, 0
476 self.assertHex(EXTS64(value_c), 0xffffffff80000000)
477
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)
483
484 def assertHex(self, a, b):
485 a_val = a
486 if isinstance(a, SelectableInt):
487 a_val = a.value
488 b_val = b
489 if isinstance(b, SelectableInt):
490 b_val = b.value
491 msg = "{:x} != {:x}".format(a_val, b_val)
492 return self.assertEqual(a, b, msg)
493
494
495 if __name__ == '__main__':
496 log(SelectableInt.__bases__)
497 unittest.main()