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