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