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