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