add a Discrete FFT butterfly unit test as an intermediary (incremental)
[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
13 trunc_div = floordiv
14 trunc_rem = mod
15 DIVS = trunc_divs
16 MODS = trunc_rems
17
18 """
19 Links:
20 * https://bugs.libre-soc.org/show_bug.cgi?id=324 - add trunc_div and trunc_rem
21 """
22
23
24 def exts(value, bits):
25 sign = 1 << (bits - 1)
26 return (value & (sign - 1)) - (value & sign)
27
28
29 def EXTS(value):
30 """ extends sign bit out from current MSB to all 256 bits
31 """
32 log ("EXTS", value, type(value))
33 assert isinstance(value, SelectableInt)
34 return SelectableInt(exts(value.value, value.bits) & ((1 << 256)-1), 256)
35
36
37 def EXTS64(value):
38 """ extends sign bit out from current MSB to 64 bits
39 """
40 assert isinstance(value, SelectableInt)
41 return SelectableInt(exts(value.value, value.bits) & ((1 << 64)-1), 64)
42
43
44 def EXTS128(value):
45 """ extends sign bit out from current MSB to 128 bits
46 """
47 assert isinstance(value, SelectableInt)
48 return SelectableInt(exts(value.value, value.bits) & ((1 << 128)-1), 128)
49
50
51 # signed version of MUL
52 def MULS(a, b):
53 if isinstance(b, int):
54 b = SelectableInt(b, self.bits)
55 b = check_extsign(a, b)
56 a_s = a.value & (1 << (a.bits-1)) != 0
57 b_s = b.value & (1 << (b.bits-1)) != 0
58 result = abs(a) * abs(b)
59 log("MULS", result, a_s, b_s)
60 if a_s == b_s:
61 return result
62 return -result
63
64
65 # XXX should this explicitly extend from 32 to 64?
66 def EXTZ64(value):
67 if isinstance(value, SelectableInt):
68 value = value.value
69 return SelectableInt(value & ((1 << 32)-1), 64)
70
71
72 def rotl(value, bits, wordlen):
73 if isinstance(bits, SelectableInt):
74 bits = bits.value
75 mask = (1 << wordlen) - 1
76 bits = bits & (wordlen - 1)
77 return ((value << bits) | (value >> (wordlen-bits))) & mask
78
79
80 def SHL64(value, bits, wordlen=64):
81 if isinstance(bits, SelectableInt):
82 bits = bits.value
83 mask = (1 << wordlen) - 1
84 bits = bits & (wordlen - 1)
85 return SelectableInt((value << bits) & mask, 64)
86
87
88 def ROTL64(value, bits):
89 return rotl(value, bits, 64)
90
91
92 def ROTL32(value, bits):
93 if isinstance(bits, SelectableInt):
94 bits = bits.value
95 if isinstance(value, SelectableInt):
96 value = SelectableInt(value.value, 64)
97 return rotl(value | (value << 32), bits, 64)
98
99 def MASK32(x, y):
100 if isinstance(x, SelectableInt):
101 x = x.value
102 if isinstance(y, SelectableInt):
103 y = y.value
104 return MASK(x+32, y+32)
105
106 def MASK(x, y):
107 if isinstance(x, SelectableInt):
108 x = x.value
109 if isinstance(y, SelectableInt):
110 y = y.value
111 if x < y:
112 x = 64-x
113 y = 63-y
114 mask_a = ((1 << x) - 1) & ((1 << 64) - 1)
115 mask_b = ((1 << y) - 1) & ((1 << 64) - 1)
116 elif x == y:
117 return 1 << (63-x)
118 else:
119 x = 64-x
120 y = 63-y
121 mask_a = ((1 << x) - 1) & ((1 << 64) - 1)
122 mask_b = (~((1 << y) - 1)) & ((1 << 64) - 1)
123 return mask_a ^ mask_b
124
125
126 def ne(a, b):
127 return onebit(a != b)
128
129
130 def eq(a, b):
131 return onebit(a == b)
132
133
134 def gt(a, b):
135 return onebit(a > b)
136
137
138 def ge(a, b):
139 return onebit(a >= b)
140
141
142 def lt(a, b):
143 return onebit(a < b)
144
145
146 def le(a, b):
147 return onebit(a <= b)
148
149
150 def length(a):
151 return len(a)
152
153
154 def undefined(v):
155 """ function that, for Power spec purposes, returns undefined bits of
156 the same shape as the input bits. however, for purposes of matching
157 POWER9's behavior returns the input bits unchanged. this effectively
158 "marks" (tags) locations in the v3.0B spec that need to be submitted
159 for clarification.
160 """
161 return v
162
163 def DOUBLE(WORD):
164 """convert incoming WORD to double. v3.0B p140 section 4.6.2
165 """
166 # result, FRT, start off all zeros
167 log ("WORD", WORD)
168 FRT = SelectableInt(0, 64)
169 z1 = SelectableInt(0, 1)
170 z29 = SelectableInt(0, 29)
171 e = WORD[1:9]
172 m = WORD[9:32]
173 s = WORD[0]
174 log ("word s e m", s, e, m)
175
176 # Normalized Operand
177 if e.value > 0 and e.value < 255:
178 log ("normalised")
179 FRT[0:2] = WORD[0:2]
180 FRT[2] = ~WORD[1]
181 FRT[3] = ~WORD[1]
182 FRT[4] = ~WORD[1]
183 FRT[5:64] = selectconcat(WORD[2:32], z29)
184
185 # Denormalized Operand
186 if e.value == 0 and m.value != 0:
187 log ("denormalised")
188 sign = WORD[0]
189 exp = -126
190 frac = selectconcat(z1, WORD[9:32], z29)
191 # normalize the operand
192 while frac[0].value == 0:
193 frac[0:53] = selectconcat(frac[1:53], z1)
194 exp = exp - 1
195 FRT[0] = sign
196 FRT[1:12] = exp + 1023
197 FRT[12:64] = frac[1:53]
198
199 # Zero / Infinity / NaN
200 if e.value == 255 or WORD[1:32].value == 0:
201 log ("z/inf/nan")
202 FRT[0:2] = WORD[0:2]
203 FRT[2] = WORD[1]
204 FRT[3] = WORD[1]
205 FRT[4] = WORD[1]
206 FRT[5:64] = selectconcat(WORD[2:32], z29)
207
208 log ("Double s e m", FRT[0].value, FRT[1:12].value-1023,
209 FRT[12:64].value)
210
211 return FRT
212
213
214 def SINGLE(FRS):
215 """convert incoming FRS into 32-bit word. v3.0B p144 section 4.6.3
216 """
217 # result - WORD - start off all zeros
218 WORD = SelectableInt(0, 32)
219
220 e = FRS[1:12]
221 m = FRS[12:64]
222 s = FRS[0]
223
224 log ("SINGLE", FRS)
225 log ("s e m", s.value, e.value, m.value)
226
227 #No Denormalization Required (includes Zero / Infinity / NaN)
228 if e.value > 896 or FRS[1:64].value == 0:
229 log("nodenorm", FRS[0:2].value, hex(FRS[5:35].value))
230 WORD[0:2] = FRS[0:2]
231 WORD[2:32] = FRS[5:35]
232
233 #Denormalization Required
234 if e.value >= 874 and e.value <= 896:
235 sign = FRS[0]
236 exp = e.value - 1023
237 frac = selectconcat(SelectableInt(1, 1), FRS[12:64])
238 log("exp, fract", exp, hex(frac.value))
239 # denormalize operand
240 while exp < -126:
241 frac[0:53] = selectconcat(SelectableInt(0, 1), frac[0:52])
242 exp = exp + 1
243 WORD[0] = sign
244 WORD[1:9] = SelectableInt(0, 8)
245 WORD[9:32] = frac[1:24]
246 #else WORD = undefined # return zeros
247
248 log ("WORD", WORD)
249
250 return WORD
251
252 # XXX NOTE: these are very quick hacked functions for utterly basic
253 # FP support
254
255 def fp64toselectable(frt):
256 """convert FP number to 64 bit SelectableInt
257 """
258 b = struct.pack(">d", frt)
259 val = int.from_bytes(b, byteorder='big', signed=False)
260 return SelectableInt(val, 64)
261
262
263 def FPADD32(FRA, FRB):
264 from openpower.decoder.isafunctions.double2single import DOUBLE2SINGLE
265 #return FPADD64(FRA, FRB)
266 #FRA = DOUBLE(SINGLE(FRA))
267 #FRB = DOUBLE(SINGLE(FRB))
268 result = float(FRA) + float(FRB)
269 cvt = fp64toselectable(result)
270 cvt = DOUBLE2SINGLE(cvt)
271 log ("FPADD32", FRA, FRB, float(FRA), "+", float(FRB), "=", result, cvt)
272 return cvt
273
274
275 def FPSUB32(FRA, FRB):
276 from openpower.decoder.isafunctions.double2single import DOUBLE2SINGLE
277 #return FPSUB64(FRA, FRB)
278 #FRA = DOUBLE(SINGLE(FRA))
279 #FRB = DOUBLE(SINGLE(FRB))
280 result = float(FRA) - float(FRB)
281 cvt = fp64toselectable(result)
282 cvt = DOUBLE2SINGLE(cvt)
283 log ("FPSUB32", FRA, FRB, float(FRA), "-", float(FRB), "=", result, cvt)
284 return cvt
285
286
287 def signinv(res, sign):
288 if sign == 1:
289 return res
290 if sign == 0:
291 return 0.0
292 if sign == -1:
293 return -res
294
295
296 def FPMUL32(FRA, FRB, sign=1):
297 from openpower.decoder.isafunctions.double2single import DOUBLE2SINGLE
298 #return FPMUL64(FRA, FRB)
299 FRA = DOUBLE(SINGLE(FRA))
300 FRB = DOUBLE(SINGLE(FRB))
301 result = signinv(float(FRA) * float(FRB), sign)
302 log ("FPMUL32", FRA, FRB, float(FRA), float(FRB), result, sign)
303 cvt = fp64toselectable(result)
304 cvt = DOUBLE2SINGLE(cvt)
305 log (" cvt", cvt)
306 return cvt
307
308
309 def FPMULADD32(FRA, FRC, FRB, mulsign, addsign):
310 from openpower.decoder.isafunctions.double2single import DOUBLE2SINGLE
311 #return FPMUL64(FRA, FRB)
312 #FRA = DOUBLE(SINGLE(FRA))
313 #FRB = DOUBLE(SINGLE(FRB))
314 if addsign == 1:
315 if mulsign == 1:
316 result = float(FRA) * float(FRC) + float(FRB) # fmadds
317 elif mulsign == -1:
318 result = -(float(FRA) * float(FRC) - float(FRB)) # fnmsubs
319 elif addsign == -1:
320 if mulsign == 1:
321 result = float(FRA) * float(FRC) - float(FRB) # fmsubs
322 elif mulsign == -1:
323 result = -(float(FRA) * float(FRC) + float(FRB)) # fnmadds
324 elif addsign == 0:
325 result = 0.0
326 log ("FPMULADD32 FRA FRC FRB", FRA, FRC, FRB)
327 log (" FRA", float(FRA))
328 log (" FRC", float(FRC))
329 log (" FRB", float(FRB))
330 log (" (FRA*FRC)+FRB=", mulsign, addsign, result)
331 cvt = fp64toselectable(result)
332 cvt = DOUBLE2SINGLE(cvt)
333 log (" cvt", cvt)
334 return cvt
335
336
337 def FPDIV32(FRA, FRB, sign=1):
338 from openpower.decoder.isafunctions.double2single import DOUBLE2SINGLE
339 #return FPDIV64(FRA, FRB)
340 #FRA = DOUBLE(SINGLE(FRA))
341 #FRB = DOUBLE(SINGLE(FRB))
342 result = signinv(float(FRA) / float(FRB), sign)
343 cvt = fp64toselectable(result)
344 cvt = DOUBLE2SINGLE(cvt)
345 log ("FPDIV32", FRA, FRB, result, cvt)
346 return cvt
347
348
349 def FPADD64(FRA, FRB):
350 result = float(FRA) + float(FRB)
351 cvt = fp64toselectable(result)
352 log ("FPADD64", FRA, FRB, result, cvt)
353 return cvt
354
355
356 def FPSUB64(FRA, FRB):
357 result = float(FRA) - float(FRB)
358 cvt = fp64toselectable(result)
359 log ("FPSUB64", FRA, FRB, result, cvt)
360 return cvt
361
362
363 def FPMUL64(FRA, FRB, sign=1):
364 result = signinv(float(FRA) * float(FRB), sign)
365 cvt = fp64toselectable(result)
366 log ("FPMUL64", FRA, FRB, result, cvt, sign)
367 return cvt
368
369
370 def FPDIV64(FRA, FRB, sign=1):
371 result = signinv(float(FRA) / float(FRB), sign)
372 cvt = fp64toselectable(result)
373 log ("FPDIV64", FRA, FRB, result, cvt, sign)
374 return cvt
375
376
377
378 def bitrev(val, VL):
379 """Returns the integer whose value is the reverse of the lowest
380 'width' bits of the integer 'val'
381 """
382 result = 0
383 width = VL.bit_length()-1
384 for _ in range(width):
385 result = (result << 1) | (val & 1)
386 val >>= 1
387 return result
388
389
390 # For these tests I tried to find power instructions that would let me
391 # isolate each of these helper operations. So for instance, when I was
392 # testing the MASK() function, I chose rlwinm and rldicl because if I
393 # set the shift equal to 0 and passed in a value of all ones, the
394 # result I got would be exactly the same as the output of MASK()
395
396
397 class HelperTests(unittest.TestCase):
398 def test_MASK(self):
399 # Verified using rlwinm, rldicl, rldicr in qemu
400 # li 1, -1
401 # rlwinm reg, 1, 0, 5, 15
402 self.assertHex(MASK(5+32, 15+32), 0x7ff0000)
403 # rlwinm reg, 1, 0, 15, 5
404 self.assertHex(MASK(15+32, 5+32), 0xfffffffffc01ffff)
405 self.assertHex(MASK(30+32, 2+32), 0xffffffffe0000003)
406 # rldicl reg, 1, 0, 37
407 self.assertHex(MASK(37, 63), 0x7ffffff)
408 self.assertHex(MASK(10, 63), 0x3fffffffffffff)
409 self.assertHex(MASK(58, 63), 0x3f)
410 # rldicr reg, 1, 0, 37
411 self.assertHex(MASK(0, 37), 0xfffffffffc000000)
412 self.assertHex(MASK(0, 10), 0xffe0000000000000)
413 self.assertHex(MASK(0, 58), 0xffffffffffffffe0)
414
415 # li 2, 5
416 # slw 1, 1, 2
417 self.assertHex(MASK(32, 63-5), 0xffffffe0)
418
419 self.assertHex(MASK(32, 33), 0xc0000000)
420 self.assertHex(MASK(32, 32), 0x80000000)
421 self.assertHex(MASK(33, 33), 0x40000000)
422
423 def test_ROTL64(self):
424 # r1 = 0xdeadbeef12345678
425 value = 0xdeadbeef12345678
426
427 # rldicl reg, 1, 10, 0
428 self.assertHex(ROTL64(value, 10), 0xb6fbbc48d159e37a)
429 # rldicl reg, 1, 35, 0
430 self.assertHex(ROTL64(value, 35), 0x91a2b3c6f56df778)
431 self.assertHex(ROTL64(value, 58), 0xe37ab6fbbc48d159)
432 self.assertHex(ROTL64(value, 22), 0xbbc48d159e37ab6f)
433
434 def test_ROTL32(self):
435 # r1 = 0xdeadbeef
436 value = 0xdeadbeef
437
438 # rlwinm reg, 1, 10, 0, 31
439 self.assertHex(ROTL32(value, 10), 0xb6fbbf7a)
440 # rlwinm reg, 1, 17, 0, 31
441 self.assertHex(ROTL32(value, 17), 0x7ddfbd5b)
442 self.assertHex(ROTL32(value, 25), 0xdfbd5b7d)
443 self.assertHex(ROTL32(value, 30), 0xf7ab6fbb)
444
445 def test_EXTS64(self):
446 value_a = SelectableInt(0xdeadbeef, 32) # r1
447 value_b = SelectableInt(0x73123456, 32) # r2
448 value_c = SelectableInt(0x80000000, 32) # r3
449
450 # extswsli reg, 1, 0
451 self.assertHex(EXTS64(value_a), 0xffffffffdeadbeef)
452 # extswsli reg, 2, 0
453 self.assertHex(EXTS64(value_b), SelectableInt(value_b.value, 64))
454 # extswsli reg, 3, 0
455 self.assertHex(EXTS64(value_c), 0xffffffff80000000)
456
457 def test_FPADD32(self):
458 value_a = SelectableInt(0x4014000000000000, 64) # 5.0
459 value_b = SelectableInt(0x403B4CCCCCCCCCCD, 64) # 27.3
460 result = FPADD32(value_a, value_b)
461 self.assertHex(0x4040266666666666, result)
462
463 def assertHex(self, a, b):
464 a_val = a
465 if isinstance(a, SelectableInt):
466 a_val = a.value
467 b_val = b
468 if isinstance(b, SelectableInt):
469 b_val = b.value
470 msg = "{:x} != {:x}".format(a_val, b_val)
471 return self.assertEqual(a, b, msg)
472
473
474 if __name__ == '__main__':
475 log(SelectableInt.__bases__)
476 unittest.main()