add mm=1 svindex test, setting single targetted SVSHAPE
[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 log("rsub", b, self.value)
257 if isinstance(b, int):
258 b = SelectableInt(b, 256) # max extent
259 #b = check_extsign(self, b)
260 #assert b.bits == self.bits
261 return SelectableInt(b.value - self.value, b.bits)
262
263 def __radd__(self, b):
264 if isinstance(b, int):
265 b = SelectableInt(b, self.bits)
266 b = check_extsign(self, b)
267 assert b.bits == self.bits
268 return SelectableInt(b.value + self.value, self.bits)
269
270 def __rxor__(self, b):
271 b = check_extsign(self, b)
272 assert b.bits == self.bits
273 return SelectableInt(self.value ^ b.value, self.bits)
274
275 def __invert__(self):
276 return SelectableInt(~self.value, self.bits)
277
278 def __neg__(self):
279 res = SelectableInt((~self.value) + 1, self.bits)
280 log ("neg", hex(self.value), hex(res.value))
281 return res
282
283 def __lshift__(self, b):
284 b = check_extsign(self, b)
285 return SelectableInt(self.value << b.value, self.bits)
286
287 def __rshift__(self, b):
288 b = check_extsign(self, b)
289 return SelectableInt(self.value >> b.value, self.bits)
290
291 def __getitem__(self, key):
292 if isinstance(key, SelectableInt):
293 key = key.value
294 if isinstance(key, int):
295 assert key < self.bits, "key %d accessing %d" % (key, self.bits)
296 assert key >= 0
297 # NOTE: POWER 3.0B annotation order! see p4 1.3.2
298 # MSB is indexed **LOWEST** (sigh)
299 key = self.bits - (key + 1)
300
301 value = (self.value >> key) & 1
302 log("getitem", key, self.bits, hex(self.value), value)
303 return SelectableInt(value, 1)
304 elif isinstance(key, slice):
305 assert key.step is None or key.step == 1
306 assert key.start < key.stop
307 assert key.start >= 0
308 assert key.stop <= self.bits
309
310 stop = self.bits - key.start
311 start = self.bits - key.stop
312
313 bits = stop - start
314 #log ("__getitem__ slice num bits", start, stop, bits)
315 mask = (1 << bits) - 1
316 value = (self.value >> start) & mask
317 log("getitem", stop, start, self.bits, hex(self.value), value)
318 return SelectableInt(value, bits)
319
320 def __setitem__(self, key, value):
321 if isinstance(key, SelectableInt):
322 key = key.value
323 if isinstance(key, int):
324 if isinstance(value, SelectableInt):
325 assert value.bits == 1
326 value = value.value
327 log("setitem", key, self.bits, hex(self.value), hex(value))
328
329 assert key < self.bits
330 assert key >= 0
331 key = self.bits - (key + 1)
332
333 value = value << key
334 mask = 1 << key
335 self.value = (self.value & ~mask) | (value & mask)
336 elif isinstance(key, slice):
337 kstart, kstop, kstep = key.start, key.stop, key.step
338 if isinstance(kstart, SelectableInt): kstart = kstart.asint()
339 if isinstance(kstop, SelectableInt): kstop = kstop.asint()
340 if isinstance(kstep, SelectableInt): kstep = kstep.asint()
341 log ("__setitem__ slice ", kstart, kstop, kstep)
342 assert kstep is None or kstep == 1
343 assert kstart < kstop
344 assert kstart >= 0
345 assert kstop <= self.bits, \
346 "key stop %d bits %d" % (kstop, self.bits)
347
348 stop = self.bits - kstart
349 start = self.bits - kstop
350
351 bits = stop - start
352 #log ("__setitem__ slice num bits", bits)
353 if isinstance(value, SelectableInt):
354 assert value.bits == bits, "%d into %d" % (value.bits, bits)
355 value = value.value
356 log("setitem", key, self.bits, hex(self.value), hex(value))
357 mask = ((1 << bits) - 1) << start
358 value = value << start
359 self.value = (self.value & ~mask) | (value & mask)
360
361 def __ge__(self, other):
362 if isinstance(other, FieldSelectableInt):
363 other = other.get_range()
364 if isinstance(other, SelectableInt):
365 other = check_extsign(self, other)
366 assert other.bits == self.bits
367 other = other.to_signed_int()
368 if isinstance(other, int):
369 return onebit(self.to_signed_int() >= other)
370 assert False
371
372 def __le__(self, other):
373 if isinstance(other, FieldSelectableInt):
374 other = other.get_range()
375 if isinstance(other, SelectableInt):
376 other = check_extsign(self, other)
377 assert other.bits == self.bits
378 other = other.to_signed_int()
379 if isinstance(other, int):
380 return onebit(self.to_signed_int() <= other)
381 assert False
382
383 def __gt__(self, other):
384 if isinstance(other, FieldSelectableInt):
385 other = other.get_range()
386 if isinstance(other, SelectableInt):
387 other = check_extsign(self, other)
388 assert other.bits == self.bits
389 other = other.to_signed_int()
390 if isinstance(other, int):
391 return onebit(self.to_signed_int() > other)
392 assert False
393
394 def __lt__(self, other):
395 log ("SelectableInt lt", self, other)
396 if isinstance(other, FieldSelectableInt):
397 other = other.get_range()
398 if isinstance(other, SelectableInt):
399 other = check_extsign(self, other)
400 assert other.bits == self.bits
401 other = other.to_signed_int()
402 if isinstance(other, int):
403 a = self.to_signed_int()
404 res = onebit(a < other)
405 log (" a < b", a, other, res)
406 return res
407 assert False
408
409 def __eq__(self, other):
410 log("__eq__", self, other)
411 if isinstance(other, FieldSelectableInt):
412 other = other.get_range()
413 if isinstance(other, SelectableInt):
414 other = check_extsign(self, other)
415 assert other.bits == self.bits
416 other = other.value
417 log (" eq", other, self.value, other == self.value)
418 if isinstance(other, int):
419 return onebit(other == self.value)
420 assert False
421
422 def narrow(self, bits):
423 assert bits <= self.bits
424 return SelectableInt(self.value, bits)
425
426 def __bool__(self):
427 return self.value != 0
428
429 def __repr__(self):
430 value = f"value=0x{self.value:x}, bits={self.bits}"
431 return f"{self.__class__.__name__}({value})"
432
433 def __len__(self):
434 return self.bits
435
436 def asint(self):
437 return self.value
438
439 def __float__(self):
440 """convert to double-precision float. TODO, properly convert
441 rather than a hack-job: must actually support Power IEEE754 FP
442 """
443 assert self.bits == 64 # must be 64-bit
444 data = self.value.to_bytes(8, byteorder='little')
445 return struct.unpack('<d', data)[0]
446
447
448 class SelectableIntMappingMeta(type):
449 def __new__(metacls, name, bases, attrs, bits=0, fields=None):
450 if fields is None:
451 fields = {}
452
453 def field(item):
454 (key, value) = item
455 if isinstance(value, dict):
456 value = dict(map(field, value.items()))
457 else:
458 value = tuple(value)
459 return (key, value)
460
461 cls = super().__new__(metacls, name, bases, attrs)
462 cls.__bits = bits
463 cls.__fields = dict(map(field, fields.items()))
464
465 return cls
466
467 def __iter__(cls):
468 for (key, value) in cls.__fields.items():
469 yield (key, value)
470
471 def __getattr__(cls, attr):
472 try:
473 return cls.__fields[attr]
474 except KeyError as error:
475 raise AttributeError from error
476
477 @property
478 def bits(cls):
479 return cls.__bits
480
481
482 class SelectableIntMapping(SelectableInt, metaclass=SelectableIntMappingMeta):
483 def __init__(self, value=0):
484 return super().__init__(value, self.__class__.bits)
485
486 def __getattr__(self, attr):
487 def field(value):
488 if isinstance(value, dict):
489 return {key:field(value) for (key, value) in tuple(value.items())}
490 return FieldSelectableInt(si=self, br=value)
491
492 try:
493 return field(getattr(self.__class__, attr))
494 except KeyError as error:
495 raise AttributeError from error
496
497
498 def onebit(bit):
499 return SelectableInt(1 if bit else 0, 1)
500
501
502 def selectltu(lhs, rhs):
503 """ less-than (unsigned)
504 """
505 if isinstance(rhs, SelectableInt):
506 rhs = rhs.value
507 return onebit(lhs.value < rhs)
508
509
510 def selectgtu(lhs, rhs):
511 """ greater-than (unsigned)
512 """
513 if isinstance(rhs, SelectableInt):
514 rhs = rhs.value
515 return onebit(lhs.value > rhs)
516
517
518 # XXX this probably isn't needed...
519 def selectassign(lhs, idx, rhs):
520 if isinstance(idx, tuple):
521 if len(idx) == 2:
522 lower, upper = idx
523 step = None
524 else:
525 lower, upper, step = idx
526 toidx = range(lower, upper, step)
527 fromidx = range(0, upper-lower, step) # XXX eurgh...
528 else:
529 toidx = [idx]
530 fromidx = [0]
531 for t, f in zip(toidx, fromidx):
532 lhs[t] = rhs[f]
533
534
535 def selectconcat(*args, repeat=1):
536 if repeat != 1 and len(args) == 1 and isinstance(args[0], int):
537 args = [SelectableInt(args[0], 1)]
538 if repeat != 1: # multiplies the incoming arguments
539 tmp = []
540 for i in range(repeat):
541 tmp += args
542 args = tmp
543 res = copy(args[0])
544 for i in args[1:]:
545 if isinstance(i, FieldSelectableInt):
546 i = i.si
547 assert isinstance(i, SelectableInt), "can only concat SIs, sorry"
548 res.bits += i.bits
549 res.value = (res.value << i.bits) | i.value
550 log("concat", repeat, res)
551 return res
552
553
554 class SelectableIntTestCase(unittest.TestCase):
555 def test_arith(self):
556 a = SelectableInt(5, 8)
557 b = SelectableInt(9, 8)
558 c = a + b
559 d = a - b
560 e = a * b
561 f = -a
562 g = abs(f)
563 h = abs(a)
564 self.assertEqual(c.value, a.value + b.value)
565 self.assertEqual(d.value, (a.value - b.value) & 0xFF)
566 self.assertEqual(e.value, (a.value * b.value) & 0xFF)
567 self.assertEqual(f.value, (-a.value) & 0xFF)
568 self.assertEqual(c.bits, a.bits)
569 self.assertEqual(d.bits, a.bits)
570 self.assertEqual(e.bits, a.bits)
571 self.assertEqual(a.bits, f.bits)
572 self.assertEqual(a.bits, h.bits)
573
574 def test_logic(self):
575 a = SelectableInt(0x0F, 8)
576 b = SelectableInt(0xA5, 8)
577 c = a & b
578 d = a | b
579 e = a ^ b
580 f = ~a
581 self.assertEqual(c.value, a.value & b.value)
582 self.assertEqual(d.value, a.value | b.value)
583 self.assertEqual(e.value, a.value ^ b.value)
584 self.assertEqual(f.value, 0xF0)
585
586 def test_get(self):
587 a = SelectableInt(0xa2, 8)
588 # These should be big endian
589 self.assertEqual(a[7], 0)
590 self.assertEqual(a[0:4], 10)
591 self.assertEqual(a[4:8], 2)
592
593 def test_set(self):
594 a = SelectableInt(0x5, 8)
595 a[7] = SelectableInt(0, 1)
596 self.assertEqual(a, 4)
597 a[4:8] = 9
598 self.assertEqual(a, 9)
599 a[0:4] = 3
600 self.assertEqual(a, 0x39)
601 a[0:4] = a[4:8]
602 self.assertEqual(a, 0x99)
603
604 def test_concat(self):
605 a = SelectableInt(0x1, 1)
606 c = selectconcat(a, repeat=8)
607 self.assertEqual(c, 0xff)
608 self.assertEqual(c.bits, 8)
609 a = SelectableInt(0x0, 1)
610 c = selectconcat(a, repeat=8)
611 self.assertEqual(c, 0x00)
612 self.assertEqual(c.bits, 8)
613
614 def test_repr(self):
615 for i in range(65536):
616 a = SelectableInt(i, 16)
617 b = eval(repr(a))
618 self.assertEqual(a, b)
619
620 def test_cmp(self):
621 a = SelectableInt(10, bits=8)
622 b = SelectableInt(5, bits=8)
623 self.assertTrue(a > b)
624 self.assertFalse(a < b)
625 self.assertTrue(a != b)
626 self.assertFalse(a == b)
627
628 def test_unsigned(self):
629 a = SelectableInt(0x80, bits=8)
630 b = SelectableInt(0x7f, bits=8)
631 self.assertTrue(a > b)
632 self.assertFalse(a < b)
633 self.assertTrue(a != b)
634 self.assertFalse(a == b)
635
636 def test_maxint(self):
637 a = SelectableInt(0xffffffffffffffff, bits=64)
638 b = SelectableInt(0, bits=64)
639 result = a + b
640 self.assertTrue(result.value == 0xffffffffffffffff)
641
642 def test_double_1(self):
643 """use http://weitz.de/ieee/,
644 """
645 for asint, asfloat in [(0x4000000000000000, 2.0),
646 (0x4056C00000000000, 91.0),
647 (0xff80000000000000, -1.4044477616111843e+306),
648 ]:
649 a = SelectableInt(asint, bits=64)
650 convert = float(a)
651 log ("test_double_1", asint, asfloat, convert)
652 self.assertTrue(asfloat == convert)
653
654
655 if __name__ == "__main__":
656 unittest.main()