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