use log function for warnings about .mdwn files in pagereader.py
[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 def log2(val):
364 """return the base-2 logarithm of `val`. Only works for powers of 2."""
365 if isinstance(val, SelectableInt):
366 val = val.value
367 retval = val.bit_length() - 1
368 assert val == 2 ** retval, "value is not a power of 2"
369 return retval
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 class ISACallerHelper:
457 def __init__(self, XLEN):
458 self.__XLEN = XLEN
459
460 @property
461 def XLEN(self):
462 return self.__XLEN
463
464 def XLCASTS(self, value):
465 return SelectableInt(exts(value.value, self.XLEN), self.XLEN)
466
467 def XLCASTU(self, value):
468 # SelectableInt already takes care of masking out the bits
469 return SelectableInt(value.value, self.XLEN)
470
471 def EXTSXL(self, value, bits):
472 return SelectableInt(exts(value.value, bits), self.XLEN)
473
474 def DOUBLE2SINGLE(self, FRS):
475 """ DOUBLE2SINGLE has been renamed to FRSP since it is the
476 implementation of the frsp instruction.
477 use SINGLE() or FRSP() instead, or just use struct.pack/unpack
478 """
479 FPSCR = {
480 'UE': SelectableInt(0, 1),
481 'OE': SelectableInt(0, 1),
482 'RN': SelectableInt(0, 2), # round to nearest, ties to even
483 'XX': SelectableInt(0, 1),
484 }
485 FRT, FPSCR = self.FRSP(FRS, FPSCR)
486 return FRT
487
488 def __getattr__(self, attr):
489 try:
490 return globals()[attr]
491 except KeyError:
492 raise AttributeError(attr)
493
494
495 if __name__ == '__main__':
496 log(SelectableInt.__bases__)
497 unittest.main()