selectable_int: remove debug prints
[openpower-isa.git] / src / openpower / decoder / selectable_int.py
1 import unittest
2 import struct
3 from copy import copy
4 import functools
5 from openpower.decoder.power_fields import BitRange
6 from operator import (add, sub, mul, floordiv, truediv, mod, or_, and_, xor,
7 neg, inv, lshift, rshift)
8 from openpower.util import log
9
10
11 def check_extsign(a, b):
12 if isinstance(b, FieldSelectableInt):
13 b = b.get_range()
14 if isinstance(b, int):
15 return SelectableInt(b, a.bits)
16 if b.bits != 256:
17 return b
18 return SelectableInt(b.value, a.bits)
19
20
21 class FieldSelectableInt:
22 """FieldSelectableInt: allows bit-range selection onto another target
23 """
24
25 def __init__(self, si, br):
26 self.si = si # target selectable int
27 if isinstance(br, (list, tuple, range)):
28 _br = BitRange()
29 for i, v in enumerate(br):
30 _br[i] = v
31 br = _br
32 self.br = br # map of indices.
33
34 def eq(self, b):
35 if isinstance(b, int):
36 # convert integer to same SelectableInt of same bitlength as range
37 blen = len(self.br)
38 b = SelectableInt(b, blen)
39 for i in range(b.bits):
40 self[i] = b[i]
41 elif isinstance(b, SelectableInt):
42 for i in range(b.bits):
43 self[i] = b[i]
44 else:
45 self.si = copy(b.si)
46 self.br = copy(b.br)
47
48 def _op(self, op, b):
49 vi = self.get_range()
50 vi = op(vi, b)
51 return self.merge(vi)
52
53 def _op1(self, op):
54 vi = self.get_range()
55 vi = op(vi)
56 return self.merge(vi)
57
58 def __getitem__(self, key):
59 log("getitem", key, self.br)
60 if isinstance(key, SelectableInt):
61 key = key.value
62 if isinstance(key, int):
63 key = self.br[key] # don't do POWER 1.3.4 bit-inversion
64 return self.si[key]
65 if isinstance(key, slice):
66 key = self.br[key]
67 return selectconcat(*[self.si[x] for x in key])
68
69 def __setitem__(self, key, value):
70 if isinstance(key, SelectableInt):
71 key = key.value
72 key = self.br[key] # don't do POWER 1.3.4 bit-inversion
73 if isinstance(key, int):
74 return self.si.__setitem__(key, value)
75 else:
76 if not isinstance(value, SelectableInt):
77 value = SelectableInt(value, bits=len(key))
78 for i, k in enumerate(key):
79 self.si[k] = value[i]
80
81 def __negate__(self):
82 return self._op1(negate)
83
84 def __invert__(self):
85 return self._op1(inv)
86
87 def __add__(self, b):
88 return self._op(add, b)
89
90 def __sub__(self, b):
91 return self._op(sub, b)
92
93 def __mul__(self, b):
94 return self._op(mul, b)
95
96 def __div__(self, b):
97 return self._op(truediv, b)
98
99 def __mod__(self, b):
100 return self._op(mod, b)
101
102 def __and__(self, b):
103 return self._op(and_, b)
104
105 def __or__(self, b):
106 return self._op(or_, b)
107
108 def __xor__(self, b):
109 return self._op(xor, b)
110
111 def get_range(self):
112 vi = SelectableInt(0, len(self.br))
113 for k, v in self.br.items():
114 vi[k] = self.si[v]
115 return vi
116
117 def merge(self, vi):
118 fi = copy(self)
119 for i, v in fi.br.items():
120 fi.si[v] = vi[i]
121 return fi
122
123 def __repr__(self):
124 return f"{self.__class__.__name__}(si={self.si}, br={self.br})"
125
126 def asint(self, msb0=False):
127 res = 0
128 brlen = len(self.br)
129 for i, key in self.br.items():
130 bit = self.si[key].value
131 #log("asint", i, key, bit)
132 res |= bit << ((brlen-i-1) if msb0 else i)
133 return res
134
135
136 class FieldSelectableIntTestCase(unittest.TestCase):
137 def test_arith(self):
138 a = SelectableInt(0b10101, 5)
139 b = SelectableInt(0b011, 3)
140 br = BitRange()
141 br[0] = 0
142 br[1] = 2
143 br[2] = 3
144 fs = FieldSelectableInt(a, br)
145 c = fs + b
146 log(c)
147 #self.assertEqual(c.value, a.value + b.value)
148
149 def test_select(self):
150 a = SelectableInt(0b00001111, 8)
151 br = BitRange()
152 br[0] = 0
153 br[1] = 1
154 br[2] = 4
155 br[3] = 5
156 fs = FieldSelectableInt(a, br)
157
158 self.assertEqual(fs.get_range(), 0b0011)
159
160 def test_select_range(self):
161 a = SelectableInt(0b00001111, 8)
162 br = BitRange()
163 br[0] = 0
164 br[1] = 1
165 br[2] = 4
166 br[3] = 5
167 fs = FieldSelectableInt(a, br)
168
169 self.assertEqual(fs[2:4], 0b11)
170
171 fs[0:2] = 0b10
172 self.assertEqual(fs.get_range(), 0b1011)
173
174
175 class SelectableInt:
176 """SelectableInt - a class that behaves exactly like python int
177
178 this class is designed to mirror precisely the behaviour of python int.
179 the only difference is that it must contain the context of the bitwidth
180 (number of bits) associated with that integer.
181
182 FieldSelectableInt can then operate on partial bits, and because there
183 is a bit width associated with SelectableInt, slices operate correctly
184 including negative start/end points.
185 """
186
187 def __init__(self, value, bits=None):
188 if isinstance(value, SelectableInt):
189 bits = value.bits
190 value = value.value
191 mask = (1 << bits) - 1
192 self.value = value & mask
193 self.bits = bits
194 self.overflow = (value & ~mask) != 0
195
196 def eq(self, b):
197 self.value = b.value
198 self.bits = b.bits
199
200 def to_signed_int(self):
201 log ("to signed?", self.value & (1<<(self.bits-1)), self.value)
202 if self.value & (1<<(self.bits-1)) != 0: # negative
203 res = self.value - (1<<self.bits)
204 log (" val -ve:", self.bits, res)
205 else:
206 res = self.value
207 log (" val +ve:", res)
208 return res
209
210 def _op(self, op, b):
211 if isinstance(b, int):
212 b = SelectableInt(b, self.bits)
213 b = check_extsign(self, b)
214 assert b.bits == self.bits
215 return SelectableInt(op(self.value, b.value), self.bits)
216
217 def __add__(self, b):
218 return self._op(add, b)
219
220 def __sub__(self, b):
221 return self._op(sub, b)
222
223 def __mul__(self, b):
224 # different case: mul result needs to fit the total bitsize
225 if isinstance(b, int):
226 b = SelectableInt(b, self.bits)
227 log("SelectableInt mul", hex(self.value), hex(b.value),
228 self.bits, b.bits)
229 return SelectableInt(self.value * b.value, self.bits + b.bits)
230
231 def __floordiv__(self, b):
232 return self._op(floordiv, b)
233
234 def __truediv__(self, b):
235 return self._op(truediv, b)
236
237 def __mod__(self, b):
238 return self._op(mod, b)
239
240 def __and__(self, b):
241 return self._op(and_, b)
242
243 def __or__(self, b):
244 return self._op(or_, b)
245
246 def __xor__(self, b):
247 return self._op(xor, b)
248
249 def __abs__(self):
250 log("abs", self.value & (1 << (self.bits-1)))
251 if self.value & (1 << (self.bits-1)) != 0:
252 return -self
253 return self
254
255 def __rsub__(self, b):
256 if isinstance(b, int):
257 b = SelectableInt(b, self.bits)
258 b = check_extsign(self, b)
259 assert b.bits == self.bits
260 return SelectableInt(b.value - self.value, self.bits)
261
262 def __radd__(self, b):
263 if isinstance(b, int):
264 b = SelectableInt(b, self.bits)
265 b = check_extsign(self, b)
266 assert b.bits == self.bits
267 return SelectableInt(b.value + self.value, self.bits)
268
269 def __rxor__(self, b):
270 b = check_extsign(self, b)
271 assert b.bits == self.bits
272 return SelectableInt(self.value ^ b.value, self.bits)
273
274 def __invert__(self):
275 return SelectableInt(~self.value, self.bits)
276
277 def __neg__(self):
278 res = SelectableInt((~self.value) + 1, self.bits)
279 log ("neg", hex(self.value), hex(res.value))
280 return res
281
282 def __lshift__(self, b):
283 b = check_extsign(self, b)
284 return SelectableInt(self.value << b.value, self.bits)
285
286 def __rshift__(self, b):
287 b = check_extsign(self, b)
288 return SelectableInt(self.value >> b.value, self.bits)
289
290 def __getitem__(self, key):
291 if isinstance(key, SelectableInt):
292 key = key.value
293 if isinstance(key, int):
294 assert key < self.bits, "key %d accessing %d" % (key, self.bits)
295 assert key >= 0
296 # NOTE: POWER 3.0B annotation order! see p4 1.3.2
297 # MSB is indexed **LOWEST** (sigh)
298 key = self.bits - (key + 1)
299
300 value = (self.value >> key) & 1
301 log("getitem", key, self.bits, hex(self.value), value)
302 return SelectableInt(value, 1)
303 elif isinstance(key, slice):
304 assert key.step is None or key.step == 1
305 assert key.start < key.stop
306 assert key.start >= 0
307 assert key.stop <= self.bits
308
309 stop = self.bits - key.start
310 start = self.bits - key.stop
311
312 bits = stop - start
313 #log ("__getitem__ slice num bits", start, stop, bits)
314 mask = (1 << bits) - 1
315 value = (self.value >> start) & mask
316 log("getitem", stop, start, self.bits, hex(self.value), value)
317 return SelectableInt(value, bits)
318
319 def __setitem__(self, key, value):
320 if isinstance(key, SelectableInt):
321 key = key.value
322 if isinstance(key, int):
323 if isinstance(value, SelectableInt):
324 assert value.bits == 1
325 value = value.value
326 log("setitem", key, self.bits, hex(self.value), hex(value))
327
328 assert key < self.bits
329 assert key >= 0
330 key = self.bits - (key + 1)
331
332 value = value << key
333 mask = 1 << key
334 self.value = (self.value & ~mask) | (value & mask)
335 elif isinstance(key, slice):
336 assert key.step is None or key.step == 1
337 assert key.start < key.stop
338 assert key.start >= 0
339 assert key.stop <= self.bits, \
340 "key stop %d bits %d" % (key.stop, self.bits)
341
342 stop = self.bits - key.start
343 start = self.bits - key.stop
344
345 bits = stop - start
346 #log ("__setitem__ slice num bits", bits)
347 if isinstance(value, SelectableInt):
348 assert value.bits == bits, "%d into %d" % (value.bits, bits)
349 value = value.value
350 log("setitem", key, self.bits, hex(self.value), hex(value))
351 mask = ((1 << bits) - 1) << start
352 value = value << start
353 self.value = (self.value & ~mask) | (value & mask)
354
355 def __ge__(self, other):
356 if isinstance(other, FieldSelectableInt):
357 other = other.get_range()
358 if isinstance(other, SelectableInt):
359 other = check_extsign(self, other)
360 assert other.bits == self.bits
361 other = other.to_signed_int()
362 if isinstance(other, int):
363 return onebit(self.to_signed_int() >= other)
364 assert False
365
366 def __le__(self, other):
367 if isinstance(other, FieldSelectableInt):
368 other = other.get_range()
369 if isinstance(other, SelectableInt):
370 other = check_extsign(self, other)
371 assert other.bits == self.bits
372 other = other.to_signed_int()
373 if isinstance(other, int):
374 return onebit(self.to_signed_int() <= other)
375 assert False
376
377 def __gt__(self, other):
378 if isinstance(other, FieldSelectableInt):
379 other = other.get_range()
380 if isinstance(other, SelectableInt):
381 other = check_extsign(self, other)
382 assert other.bits == self.bits
383 other = other.to_signed_int()
384 if isinstance(other, int):
385 return onebit(self.to_signed_int() > other)
386 assert False
387
388 def __lt__(self, other):
389 log ("SelectableInt lt", self, other)
390 if isinstance(other, FieldSelectableInt):
391 other = other.get_range()
392 if isinstance(other, SelectableInt):
393 other = check_extsign(self, other)
394 assert other.bits == self.bits
395 other = other.to_signed_int()
396 if isinstance(other, int):
397 a = self.to_signed_int()
398 res = onebit(a < other)
399 log (" a < b", a, other, res)
400 return res
401 assert False
402
403 def __eq__(self, other):
404 log("__eq__", self, other)
405 if isinstance(other, FieldSelectableInt):
406 other = other.get_range()
407 if isinstance(other, SelectableInt):
408 other = check_extsign(self, other)
409 assert other.bits == self.bits
410 other = other.value
411 log (" eq", other, self.value, other == self.value)
412 if isinstance(other, int):
413 return onebit(other == self.value)
414 assert False
415
416 def narrow(self, bits):
417 assert bits <= self.bits
418 return SelectableInt(self.value, bits)
419
420 def __bool__(self):
421 return self.value != 0
422
423 def __repr__(self):
424 value = f"value=0x{self.value:x}, bits={self.bits}"
425 return f"{self.__class__.__name__}({value})"
426
427 def __len__(self):
428 return self.bits
429
430 def asint(self):
431 return self.value
432
433 def __float__(self):
434 """convert to double-precision float. TODO, properly convert
435 rather than a hack-job: must actually support Power IEEE754 FP
436 """
437 assert self.bits == 64 # must be 64-bit
438 data = self.value.to_bytes(8, byteorder='little')
439 return struct.unpack('<d', data)[0]
440
441
442 class SelectableIntMappingMeta(type):
443 def __new__(metacls, name, bases, attrs, bits=0, fields=None):
444 if fields is None:
445 fields = {}
446
447 def field(item):
448 (key, value) = item
449 if isinstance(value, dict):
450 value = dict(map(field, value.items()))
451 else:
452 value = tuple(value)
453 return (key, value)
454
455 cls = super().__new__(metacls, name, bases, attrs)
456 cls.__bits = bits
457 cls.__fields = dict(map(field, fields.items()))
458
459 return cls
460
461 def __iter__(cls):
462 for (key, value) in cls.__fields.items():
463 yield (key, value)
464
465 def __getattr__(cls, attr):
466 try:
467 return cls.__fields[attr]
468 except KeyError as error:
469 raise AttributeError from error
470
471 @property
472 def bits(cls):
473 return cls.__bits
474
475
476 class SelectableIntMapping(SelectableInt, metaclass=SelectableIntMappingMeta):
477 def __init__(self, value=0):
478 return super().__init__(value, self.__class__.bits)
479
480 def __getattr__(self, attr):
481 def field(value):
482 if isinstance(value, dict):
483 return {key:field(value) for (key, value) in tuple(value.items())}
484 return FieldSelectableInt(si=self, br=value)
485
486 try:
487 return field(getattr(self.__class__, attr))
488 except KeyError as error:
489 raise AttributeError from error
490
491
492 def onebit(bit):
493 return SelectableInt(1 if bit else 0, 1)
494
495
496 def selectltu(lhs, rhs):
497 """ less-than (unsigned)
498 """
499 if isinstance(rhs, SelectableInt):
500 rhs = rhs.value
501 return onebit(lhs.value < rhs)
502
503
504 def selectgtu(lhs, rhs):
505 """ greater-than (unsigned)
506 """
507 if isinstance(rhs, SelectableInt):
508 rhs = rhs.value
509 return onebit(lhs.value > rhs)
510
511
512 # XXX this probably isn't needed...
513 def selectassign(lhs, idx, rhs):
514 if isinstance(idx, tuple):
515 if len(idx) == 2:
516 lower, upper = idx
517 step = None
518 else:
519 lower, upper, step = idx
520 toidx = range(lower, upper, step)
521 fromidx = range(0, upper-lower, step) # XXX eurgh...
522 else:
523 toidx = [idx]
524 fromidx = [0]
525 for t, f in zip(toidx, fromidx):
526 lhs[t] = rhs[f]
527
528
529 def selectconcat(*args, repeat=1):
530 if repeat != 1 and len(args) == 1 and isinstance(args[0], int):
531 args = [SelectableInt(args[0], 1)]
532 if repeat != 1: # multiplies the incoming arguments
533 tmp = []
534 for i in range(repeat):
535 tmp += args
536 args = tmp
537 res = copy(args[0])
538 for i in args[1:]:
539 if isinstance(i, FieldSelectableInt):
540 i = i.si
541 assert isinstance(i, SelectableInt), "can only concat SIs, sorry"
542 res.bits += i.bits
543 res.value = (res.value << i.bits) | i.value
544 log("concat", repeat, res)
545 return res
546
547
548 class SelectableIntTestCase(unittest.TestCase):
549 def test_arith(self):
550 a = SelectableInt(5, 8)
551 b = SelectableInt(9, 8)
552 c = a + b
553 d = a - b
554 e = a * b
555 f = -a
556 g = abs(f)
557 h = abs(a)
558 self.assertEqual(c.value, a.value + b.value)
559 self.assertEqual(d.value, (a.value - b.value) & 0xFF)
560 self.assertEqual(e.value, (a.value * b.value) & 0xFF)
561 self.assertEqual(f.value, (-a.value) & 0xFF)
562 self.assertEqual(c.bits, a.bits)
563 self.assertEqual(d.bits, a.bits)
564 self.assertEqual(e.bits, a.bits)
565 self.assertEqual(a.bits, f.bits)
566 self.assertEqual(a.bits, h.bits)
567
568 def test_logic(self):
569 a = SelectableInt(0x0F, 8)
570 b = SelectableInt(0xA5, 8)
571 c = a & b
572 d = a | b
573 e = a ^ b
574 f = ~a
575 self.assertEqual(c.value, a.value & b.value)
576 self.assertEqual(d.value, a.value | b.value)
577 self.assertEqual(e.value, a.value ^ b.value)
578 self.assertEqual(f.value, 0xF0)
579
580 def test_get(self):
581 a = SelectableInt(0xa2, 8)
582 # These should be big endian
583 self.assertEqual(a[7], 0)
584 self.assertEqual(a[0:4], 10)
585 self.assertEqual(a[4:8], 2)
586
587 def test_set(self):
588 a = SelectableInt(0x5, 8)
589 a[7] = SelectableInt(0, 1)
590 self.assertEqual(a, 4)
591 a[4:8] = 9
592 self.assertEqual(a, 9)
593 a[0:4] = 3
594 self.assertEqual(a, 0x39)
595 a[0:4] = a[4:8]
596 self.assertEqual(a, 0x99)
597
598 def test_concat(self):
599 a = SelectableInt(0x1, 1)
600 c = selectconcat(a, repeat=8)
601 self.assertEqual(c, 0xff)
602 self.assertEqual(c.bits, 8)
603 a = SelectableInt(0x0, 1)
604 c = selectconcat(a, repeat=8)
605 self.assertEqual(c, 0x00)
606 self.assertEqual(c.bits, 8)
607
608 def test_repr(self):
609 for i in range(65536):
610 a = SelectableInt(i, 16)
611 b = eval(repr(a))
612 self.assertEqual(a, b)
613
614 def test_cmp(self):
615 a = SelectableInt(10, bits=8)
616 b = SelectableInt(5, bits=8)
617 self.assertTrue(a > b)
618 self.assertFalse(a < b)
619 self.assertTrue(a != b)
620 self.assertFalse(a == b)
621
622 def test_unsigned(self):
623 a = SelectableInt(0x80, bits=8)
624 b = SelectableInt(0x7f, bits=8)
625 self.assertTrue(a > b)
626 self.assertFalse(a < b)
627 self.assertTrue(a != b)
628 self.assertFalse(a == b)
629
630 def test_maxint(self):
631 a = SelectableInt(0xffffffffffffffff, bits=64)
632 b = SelectableInt(0, bits=64)
633 result = a + b
634 self.assertTrue(result.value == 0xffffffffffffffff)
635
636 def test_double_1(self):
637 """use http://weitz.de/ieee/,
638 """
639 for asint, asfloat in [(0x4000000000000000, 2.0),
640 (0x4056C00000000000, 91.0),
641 (0xff80000000000000, -1.4044477616111843e+306),
642 ]:
643 a = SelectableInt(asint, bits=64)
644 convert = float(a)
645 log ("test_double_1", asint, asfloat, convert)
646 self.assertTrue(asfloat == convert)
647
648
649 if __name__ == "__main__":
650 unittest.main()