format code
[openpower-isa.git] / src / openpower / decoder / helpers.py
1 import unittest
2 import struct
3 import sys
4 from openpower.decoder.selectable_int import (SelectableInt, onebit,
5 selectconcat)
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
11
12 from openpower.util import log
13 import math
14
15 trunc_div = floordiv
16 trunc_rem = mod
17 DIVS = trunc_divs
18 MODS = trunc_rems
19
20 """
21 Links:
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)
24 """
25
26
27 def RANGE(start, end):
28 if start > end:
29 # reverse direction
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)
34
35
36 def exts(value, bits):
37 sign = 1 << (bits - 1)
38 return (value & (sign - 1)) - (value & sign)
39
40
41 def EXTS(value):
42 """ extends sign bit out from current MSB to all 256 bits
43 """
44 log("EXTS", value, type(value))
45 assert isinstance(value, SelectableInt)
46 return SelectableInt(exts(value.value, value.bits) & ((1 << 256)-1), 256)
47
48
49 def EXTS64(value):
50 """ extends sign bit out from current MSB to 64 bits
51 """
52 assert isinstance(value, SelectableInt)
53 return SelectableInt(exts(value.value, value.bits) & ((1 << 64)-1), 64)
54
55
56 def EXTS128(value):
57 """ extends sign bit out from current MSB to 128 bits
58 """
59 assert isinstance(value, SelectableInt)
60 return SelectableInt(exts(value.value, value.bits) & ((1 << 128)-1), 128)
61
62
63 # signed version of MUL
64 def MULS(a, b):
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)
72 if a_s == b_s:
73 return result
74 return -result
75
76
77 # XXX should this explicitly extend from 32 to 64?
78 def EXTZ64(value):
79 if isinstance(value, SelectableInt):
80 value = value.value
81 return SelectableInt(value & ((1 << 32)-1), 64)
82
83
84 def rotl(value, bits, wordlen):
85 if isinstance(bits, SelectableInt):
86 bits = bits.value
87 mask = (1 << wordlen) - 1
88 bits = bits & (wordlen - 1)
89 return ((value << bits) | (value >> (wordlen-bits))) & mask
90
91
92 def SHL64(value, bits, wordlen=64):
93 if isinstance(bits, SelectableInt):
94 bits = bits.value
95 mask = (1 << wordlen) - 1
96 bits = bits & (wordlen - 1)
97 return SelectableInt((value << bits) & mask, 64)
98
99
100 def ROTL64(value, bits):
101 return rotl(value, bits, 64)
102
103
104 def ROTL32(value, bits):
105 if isinstance(bits, SelectableInt):
106 bits = bits.value
107 if isinstance(value, SelectableInt):
108 value = SelectableInt(value.value, 64)
109 return rotl(value | (value << 32), bits, 64)
110
111
112 def MASK32(x, y):
113 if isinstance(x, SelectableInt):
114 x = x.value
115 if isinstance(y, SelectableInt):
116 y = y.value
117 return MASK(x+32, y+32)
118
119
120 def MASK(x, y):
121 if isinstance(x, SelectableInt):
122 x = x.value
123 if isinstance(y, SelectableInt):
124 y = y.value
125 if x < y:
126 x = 64-x
127 y = 63-y
128 mask_a = ((1 << x) - 1) & ((1 << 64) - 1)
129 mask_b = ((1 << y) - 1) & ((1 << 64) - 1)
130 elif x == y:
131 return 1 << (63-x)
132 else:
133 x = 64-x
134 y = 63-y
135 mask_a = ((1 << x) - 1) & ((1 << 64) - 1)
136 mask_b = (~((1 << y) - 1)) & ((1 << 64) - 1)
137 return mask_a ^ mask_b
138
139
140 def ne(a, b):
141 return onebit(a != b)
142
143
144 def eq(a, b):
145 return onebit(a == b)
146
147
148 def gt(a, b):
149 return onebit(a > b)
150
151
152 def ge(a, b):
153 return onebit(a >= b)
154
155
156 def lt(a, b):
157 return onebit(a < b)
158
159
160 def le(a, b):
161 return onebit(a <= b)
162
163
164 def length(a):
165 return len(a)
166
167
168 def undefined(v):
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
173 for clarification.
174 """
175 return v
176
177
178 def SINGLE(FRS):
179 """convert incoming FRS into 32-bit word. v3.0B p144 section 4.6.3
180 """
181 # result - WORD - start off all zeros
182 WORD = SelectableInt(0, 32)
183
184 e = FRS[1:12]
185 m = FRS[12:64]
186 s = FRS[0]
187
188 log("SINGLE", FRS)
189 log("s e m", s.value, e.value, m.value)
190
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))
194 WORD[0:2] = FRS[0:2]
195 WORD[2:32] = FRS[5:35]
196
197 # Denormalization Required
198 if e.value >= 874 and e.value <= 896:
199 sign = FRS[0]
200 exp = e.value - 1023
201 frac = selectconcat(SelectableInt(1, 1), FRS[12:64])
202 log("exp, fract", exp, hex(frac.value))
203 # denormalize operand
204 while exp < -126:
205 frac[0:53] = selectconcat(SelectableInt(0, 1), frac[0:52])
206 exp = exp + 1
207 WORD[0] = sign
208 WORD[1:9] = SelectableInt(0, 8)
209 WORD[9:32] = frac[1:24]
210 # else WORD = undefined # return zeros
211
212 log("WORD", WORD)
213
214 return WORD
215
216 # XXX NOTE: these are very quick hacked functions for utterly basic
217 # FP support
218
219
220 def signinv(res, sign):
221 if sign == 1:
222 return res
223 if sign == 0:
224 return 0.0
225 if sign == -1:
226 return -res
227
228
229 def fp64toselectable(frt):
230 """convert FP number to 64 bit SelectableInt
231 """
232 b = struct.pack(">d", frt)
233 val = int.from_bytes(b, byteorder='big', signed=False)
234 return SelectableInt(val, 64)
235
236
237 class ISAFPHelpers:
238
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)
245 return cvt
246
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)
253 return cvt
254
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)
263 return cvt
264
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)
273 return cvt
274
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)
283 log(" cvt", cvt)
284 return cvt
285
286 def FPMULADD32(self, FRA, FRC, FRB, mulsign, addsign):
287 # return FPMUL64(FRA, FRB)
288 #FRA = DOUBLE(SINGLE(FRA))
289 #FRB = DOUBLE(SINGLE(FRB))
290 if addsign == 1:
291 if mulsign == 1:
292 result = float(FRA) * float(FRC) + float(FRB) # fmadds
293 elif mulsign == -1:
294 result = -(float(FRA) * float(FRC) - float(FRB)) # fnmsubs
295 elif addsign == -1:
296 if mulsign == 1:
297 result = float(FRA) * float(FRC) - float(FRB) # fmsubs
298 elif mulsign == -1:
299 result = -(float(FRA) * float(FRC) + float(FRB)) # fnmadds
300 elif addsign == 0:
301 result = 0.0
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)
309 log(" cvt", cvt)
310 return cvt
311
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)
320 return cvt
321
322
323 def FPADD64(FRA, FRB):
324 result = float(FRA) + float(FRB)
325 cvt = fp64toselectable(result)
326 log("FPADD64", FRA, FRB, result, cvt)
327 return cvt
328
329
330 def FPSUB64(FRA, FRB):
331 result = float(FRA) - float(FRB)
332 cvt = fp64toselectable(result)
333 log("FPSUB64", FRA, FRB, result, cvt)
334 return cvt
335
336
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)
341 return cvt
342
343
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)
348 return cvt
349
350
351 def bitrev(val, VL):
352 """Returns the integer whose value is the reverse of the lowest
353 'width' bits of the integer 'val'
354 """
355 result = 0
356 width = VL.bit_length()-1
357 for _ in range(width):
358 result = (result << 1) | (val & 1)
359 val >>= 1
360 return result
361
362
363 # For these tests I tried to find power instructions that would let me
364 # isolate each of these helper operations. So for instance, when I was
365 # testing the MASK() function, I chose rlwinm and rldicl because if I
366 # set the shift equal to 0 and passed in a value of all ones, the
367 # result I got would be exactly the same as the output of MASK()
368
369
370 class HelperTests(unittest.TestCase):
371 def test_MASK(self):
372 # Verified using rlwinm, rldicl, rldicr in qemu
373 # li 1, -1
374 # rlwinm reg, 1, 0, 5, 15
375 self.assertHex(MASK(5+32, 15+32), 0x7ff0000)
376 # rlwinm reg, 1, 0, 15, 5
377 self.assertHex(MASK(15+32, 5+32), 0xfffffffffc01ffff)
378 self.assertHex(MASK(30+32, 2+32), 0xffffffffe0000003)
379 # rldicl reg, 1, 0, 37
380 self.assertHex(MASK(37, 63), 0x7ffffff)
381 self.assertHex(MASK(10, 63), 0x3fffffffffffff)
382 self.assertHex(MASK(58, 63), 0x3f)
383 # rldicr reg, 1, 0, 37
384 self.assertHex(MASK(0, 37), 0xfffffffffc000000)
385 self.assertHex(MASK(0, 10), 0xffe0000000000000)
386 self.assertHex(MASK(0, 58), 0xffffffffffffffe0)
387
388 # li 2, 5
389 # slw 1, 1, 2
390 self.assertHex(MASK(32, 63-5), 0xffffffe0)
391
392 self.assertHex(MASK(32, 33), 0xc0000000)
393 self.assertHex(MASK(32, 32), 0x80000000)
394 self.assertHex(MASK(33, 33), 0x40000000)
395
396 def test_ROTL64(self):
397 # r1 = 0xdeadbeef12345678
398 value = 0xdeadbeef12345678
399
400 # rldicl reg, 1, 10, 0
401 self.assertHex(ROTL64(value, 10), 0xb6fbbc48d159e37a)
402 # rldicl reg, 1, 35, 0
403 self.assertHex(ROTL64(value, 35), 0x91a2b3c6f56df778)
404 self.assertHex(ROTL64(value, 58), 0xe37ab6fbbc48d159)
405 self.assertHex(ROTL64(value, 22), 0xbbc48d159e37ab6f)
406
407 def test_ROTL32(self):
408 # r1 = 0xdeadbeef
409 value = 0xdeadbeef
410
411 # rlwinm reg, 1, 10, 0, 31
412 self.assertHex(ROTL32(value, 10), 0xb6fbbf7a)
413 # rlwinm reg, 1, 17, 0, 31
414 self.assertHex(ROTL32(value, 17), 0x7ddfbd5b)
415 self.assertHex(ROTL32(value, 25), 0xdfbd5b7d)
416 self.assertHex(ROTL32(value, 30), 0xf7ab6fbb)
417
418 def test_EXTS64(self):
419 value_a = SelectableInt(0xdeadbeef, 32) # r1
420 value_b = SelectableInt(0x73123456, 32) # r2
421 value_c = SelectableInt(0x80000000, 32) # r3
422
423 # extswsli reg, 1, 0
424 self.assertHex(EXTS64(value_a), 0xffffffffdeadbeef)
425 # extswsli reg, 2, 0
426 self.assertHex(EXTS64(value_b), SelectableInt(value_b.value, 64))
427 # extswsli reg, 3, 0
428 self.assertHex(EXTS64(value_c), 0xffffffff80000000)
429
430 def test_FPADD32(self):
431 value_a = SelectableInt(0x4014000000000000, 64) # 5.0
432 value_b = SelectableInt(0x403B4CCCCCCCCCCD, 64) # 27.3
433 result = FPADD32(value_a, value_b)
434 self.assertHex(0x4040266666666666, result)
435
436 def assertHex(self, a, b):
437 a_val = a
438 if isinstance(a, SelectableInt):
439 a_val = a.value
440 b_val = b
441 if isinstance(b, SelectableInt):
442 b_val = b.value
443 msg = "{:x} != {:x}".format(a_val, b_val)
444 return self.assertEqual(a, b, msg)
445
446
447 class ISACallerHelper:
448 def __init__(self, XLEN):
449 self.__XLEN = XLEN
450
451 @property
452 def XLEN(self):
453 return self.__XLEN
454
455 def XLCASTS(self, value):
456 return SelectableInt(exts(value.value, self.XLEN), self.XLEN)
457
458 def XLCASTU(self, value):
459 # SelectableInt already takes care of masking out the bits
460 return SelectableInt(value.value, self.XLEN)
461
462 def EXTSXL(self, value, bits):
463 return SelectableInt(exts(value.value, bits), self.XLEN)
464
465 def __getattr__(self, attr):
466 try:
467 return globals()[attr]
468 except KeyError:
469 raise AttributeError(attr)
470
471
472 if __name__ == '__main__':
473 log(SelectableInt.__bases__)
474 unittest.main()