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