selectable_int: derive SelectableIntMapping on per-class basis
[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 print("SelectableIntMappingMeta", attr)
467 try:
468 return cls.__fields[attr]
469 except KeyError as error:
470 raise AttributeError from error
471
472 @property
473 def bits(cls):
474 return cls.__bits
475
476
477 class SelectableIntMapping(SelectableInt, metaclass=SelectableIntMappingMeta):
478 def __init__(self, value=0):
479 return super().__init__(value, self.__class__.bits)
480
481 def __getattr__(self, attr):
482 def field(value):
483 if isinstance(value, dict):
484 return {key:field(value) for (key, value) in tuple(value.items())}
485 return FieldSelectableInt(si=self, br=value)
486
487 try:
488 return field(getattr(self.__class__, attr))
489 except KeyError as error:
490 raise AttributeError from error
491
492
493 def onebit(bit):
494 return SelectableInt(1 if bit else 0, 1)
495
496
497 def selectltu(lhs, rhs):
498 """ less-than (unsigned)
499 """
500 if isinstance(rhs, SelectableInt):
501 rhs = rhs.value
502 return onebit(lhs.value < rhs)
503
504
505 def selectgtu(lhs, rhs):
506 """ greater-than (unsigned)
507 """
508 if isinstance(rhs, SelectableInt):
509 rhs = rhs.value
510 return onebit(lhs.value > rhs)
511
512
513 # XXX this probably isn't needed...
514 def selectassign(lhs, idx, rhs):
515 if isinstance(idx, tuple):
516 if len(idx) == 2:
517 lower, upper = idx
518 step = None
519 else:
520 lower, upper, step = idx
521 toidx = range(lower, upper, step)
522 fromidx = range(0, upper-lower, step) # XXX eurgh...
523 else:
524 toidx = [idx]
525 fromidx = [0]
526 for t, f in zip(toidx, fromidx):
527 lhs[t] = rhs[f]
528
529
530 def selectconcat(*args, repeat=1):
531 if repeat != 1 and len(args) == 1 and isinstance(args[0], int):
532 args = [SelectableInt(args[0], 1)]
533 if repeat != 1: # multiplies the incoming arguments
534 tmp = []
535 for i in range(repeat):
536 tmp += args
537 args = tmp
538 res = copy(args[0])
539 for i in args[1:]:
540 if isinstance(i, FieldSelectableInt):
541 i = i.si
542 assert isinstance(i, SelectableInt), "can only concat SIs, sorry"
543 res.bits += i.bits
544 res.value = (res.value << i.bits) | i.value
545 log("concat", repeat, res)
546 return res
547
548
549 class SelectableIntTestCase(unittest.TestCase):
550 def test_arith(self):
551 a = SelectableInt(5, 8)
552 b = SelectableInt(9, 8)
553 c = a + b
554 d = a - b
555 e = a * b
556 f = -a
557 g = abs(f)
558 h = abs(a)
559 self.assertEqual(c.value, a.value + b.value)
560 self.assertEqual(d.value, (a.value - b.value) & 0xFF)
561 self.assertEqual(e.value, (a.value * b.value) & 0xFF)
562 self.assertEqual(f.value, (-a.value) & 0xFF)
563 self.assertEqual(c.bits, a.bits)
564 self.assertEqual(d.bits, a.bits)
565 self.assertEqual(e.bits, a.bits)
566 self.assertEqual(a.bits, f.bits)
567 self.assertEqual(a.bits, h.bits)
568
569 def test_logic(self):
570 a = SelectableInt(0x0F, 8)
571 b = SelectableInt(0xA5, 8)
572 c = a & b
573 d = a | b
574 e = a ^ b
575 f = ~a
576 self.assertEqual(c.value, a.value & b.value)
577 self.assertEqual(d.value, a.value | b.value)
578 self.assertEqual(e.value, a.value ^ b.value)
579 self.assertEqual(f.value, 0xF0)
580
581 def test_get(self):
582 a = SelectableInt(0xa2, 8)
583 # These should be big endian
584 self.assertEqual(a[7], 0)
585 self.assertEqual(a[0:4], 10)
586 self.assertEqual(a[4:8], 2)
587
588 def test_set(self):
589 a = SelectableInt(0x5, 8)
590 a[7] = SelectableInt(0, 1)
591 self.assertEqual(a, 4)
592 a[4:8] = 9
593 self.assertEqual(a, 9)
594 a[0:4] = 3
595 self.assertEqual(a, 0x39)
596 a[0:4] = a[4:8]
597 self.assertEqual(a, 0x99)
598
599 def test_concat(self):
600 a = SelectableInt(0x1, 1)
601 c = selectconcat(a, repeat=8)
602 self.assertEqual(c, 0xff)
603 self.assertEqual(c.bits, 8)
604 a = SelectableInt(0x0, 1)
605 c = selectconcat(a, repeat=8)
606 self.assertEqual(c, 0x00)
607 self.assertEqual(c.bits, 8)
608
609 def test_repr(self):
610 for i in range(65536):
611 a = SelectableInt(i, 16)
612 b = eval(repr(a))
613 self.assertEqual(a, b)
614
615 def test_cmp(self):
616 a = SelectableInt(10, bits=8)
617 b = SelectableInt(5, bits=8)
618 self.assertTrue(a > b)
619 self.assertFalse(a < b)
620 self.assertTrue(a != b)
621 self.assertFalse(a == b)
622
623 def test_unsigned(self):
624 a = SelectableInt(0x80, bits=8)
625 b = SelectableInt(0x7f, bits=8)
626 self.assertTrue(a > b)
627 self.assertFalse(a < b)
628 self.assertTrue(a != b)
629 self.assertFalse(a == b)
630
631 def test_maxint(self):
632 a = SelectableInt(0xffffffffffffffff, bits=64)
633 b = SelectableInt(0, bits=64)
634 result = a + b
635 self.assertTrue(result.value == 0xffffffffffffffff)
636
637 def test_double_1(self):
638 """use http://weitz.de/ieee/,
639 """
640 for asint, asfloat in [(0x4000000000000000, 2.0),
641 (0x4056C00000000000, 91.0),
642 (0xff80000000000000, -1.4044477616111843e+306),
643 ]:
644 a = SelectableInt(asint, bits=64)
645 convert = float(a)
646 log ("test_double_1", asint, asfloat, convert)
647 self.assertTrue(asfloat == convert)
648
649
650 if __name__ == "__main__":
651 unittest.main()