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