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