selectable_int: remove debug prints
[openpower-isa.git] / src / openpower / decoder / selectable_int.py
index 2afe50e67d5887e81ac8bde6307aa4a34d510c88..1e7458ee9f8e0de4c68ebbe7bd0580b80c92f3c9 100644 (file)
@@ -1,8 +1,11 @@
 import unittest
+import struct
 from copy import copy
+import functools
 from openpower.decoder.power_fields import BitRange
 from operator import (add, sub, mul, floordiv, truediv, mod, or_, and_, xor,
                       neg, inv, lshift, rshift)
+from openpower.util import log
 
 
 def check_extsign(a, b):
@@ -21,7 +24,7 @@ class FieldSelectableInt:
 
     def __init__(self, si, br):
         self.si = si  # target selectable int
-        if isinstance(br, list) or isinstance(br, tuple):
+        if isinstance(br, (list, tuple, range)):
             _br = BitRange()
             for i, v in enumerate(br):
                 _br[i] = v
@@ -29,7 +32,13 @@ class FieldSelectableInt:
         self.br = br  # map of indices.
 
     def eq(self, b):
-        if isinstance(b, SelectableInt):
+        if isinstance(b, int):
+            # convert integer to same SelectableInt of same bitlength as range
+            blen = len(self.br)
+            b = SelectableInt(b, blen)
+            for i in range(b.bits):
+                self[i] = b[i]
+        elif isinstance(b, SelectableInt):
             for i in range(b.bits):
                 self[i] = b[i]
         else:
@@ -47,7 +56,7 @@ class FieldSelectableInt:
         return self.merge(vi)
 
     def __getitem__(self, key):
-        print("getitem", key, self.br)
+        log("getitem", key, self.br)
         if isinstance(key, SelectableInt):
             key = key.value
         if isinstance(key, int):
@@ -112,14 +121,14 @@ class FieldSelectableInt:
         return fi
 
     def __repr__(self):
-        return "FieldSelectableInt(si=%s, br=%s)" % (self.si, self.br)
+        return f"{self.__class__.__name__}(si={self.si}, br={self.br})"
 
     def asint(self, msb0=False):
         res = 0
         brlen = len(self.br)
         for i, key in self.br.items():
             bit = self.si[key].value
-            #print("asint", i, key, bit)
+            #log("asint", i, key, bit)
             res |= bit << ((brlen-i-1) if msb0 else i)
         return res
 
@@ -134,7 +143,7 @@ class FieldSelectableIntTestCase(unittest.TestCase):
         br[2] = 3
         fs = FieldSelectableInt(a, br)
         c = fs + b
-        print(c)
+        log(c)
         #self.assertEqual(c.value, a.value + b.value)
 
     def test_select(self):
@@ -162,6 +171,7 @@ class FieldSelectableIntTestCase(unittest.TestCase):
         fs[0:2] = 0b10
         self.assertEqual(fs.get_range(), 0b1011)
 
+
 class SelectableInt:
     """SelectableInt - a class that behaves exactly like python int
 
@@ -174,8 +184,9 @@ class SelectableInt:
     including negative start/end points.
     """
 
-    def __init__(self, value, bits):
+    def __init__(self, value, bits=None):
         if isinstance(value, SelectableInt):
+            bits = value.bits
             value = value.value
         mask = (1 << bits) - 1
         self.value = value & mask
@@ -187,13 +198,13 @@ class SelectableInt:
         self.bits = b.bits
 
     def to_signed_int(self):
-        print ("to signed?", self.value & (1<<(self.bits-1)), self.value)
+        log ("to signed?", self.value & (1<<(self.bits-1)), self.value)
         if self.value & (1<<(self.bits-1)) != 0: # negative
             res = self.value - (1<<self.bits)
-            print ("    val -ve:", self.bits, res)
+            log ("    val -ve:", self.bits, res)
         else:
             res = self.value
-            print ("    val +ve:", res)
+            log ("    val +ve:", res)
         return res
 
     def _op(self, op, b):
@@ -213,7 +224,7 @@ class SelectableInt:
         # different case: mul result needs to fit the total bitsize
         if isinstance(b, int):
             b = SelectableInt(b, self.bits)
-        print("SelectableInt mul", hex(self.value), hex(b.value),
+        log("SelectableInt mul", hex(self.value), hex(b.value),
               self.bits, b.bits)
         return SelectableInt(self.value * b.value, self.bits + b.bits)
 
@@ -236,7 +247,7 @@ class SelectableInt:
         return self._op(xor, b)
 
     def __abs__(self):
-        print("abs", self.value & (1 << (self.bits-1)))
+        log("abs", self.value & (1 << (self.bits-1)))
         if self.value & (1 << (self.bits-1)) != 0:
             return -self
         return self
@@ -265,7 +276,7 @@ class SelectableInt:
 
     def __neg__(self):
         res = SelectableInt((~self.value) + 1, self.bits)
-        print ("neg", hex(self.value), hex(res.value))
+        log ("neg", hex(self.value), hex(res.value))
         return res
 
     def __lshift__(self, b):
@@ -287,7 +298,7 @@ class SelectableInt:
             key = self.bits - (key + 1)
 
             value = (self.value >> key) & 1
-            print("getitem", key, self.bits, hex(self.value), value)
+            log("getitem", key, self.bits, hex(self.value), value)
             return SelectableInt(value, 1)
         elif isinstance(key, slice):
             assert key.step is None or key.step == 1
@@ -299,23 +310,24 @@ class SelectableInt:
             start = self.bits - key.stop
 
             bits = stop - start
-            #print ("__getitem__ slice num bits", start, stop, bits)
+            #log ("__getitem__ slice num bits", start, stop, bits)
             mask = (1 << bits) - 1
             value = (self.value >> start) & mask
-            print("getitem", stop, start, self.bits, hex(self.value), value)
+            log("getitem", stop, start, self.bits, hex(self.value), value)
             return SelectableInt(value, bits)
 
     def __setitem__(self, key, value):
         if isinstance(key, SelectableInt):
             key = key.value
-        print("setitem", key, self.bits, hex(self.value))
         if isinstance(key, int):
-            assert key < self.bits
-            assert key >= 0
-            key = self.bits - (key + 1)
             if isinstance(value, SelectableInt):
                 assert value.bits == 1
                 value = value.value
+            log("setitem", key, self.bits, hex(self.value), hex(value))
+
+            assert key < self.bits
+            assert key >= 0
+            key = self.bits - (key + 1)
 
             value = value << key
             mask = 1 << key
@@ -324,16 +336,18 @@ class SelectableInt:
             assert key.step is None or key.step == 1
             assert key.start < key.stop
             assert key.start >= 0
-            assert key.stop <= self.bits
+            assert key.stop <= self.bits, \
+                   "key stop %d bits %d" % (key.stop, self.bits)
 
             stop = self.bits - key.start
             start = self.bits - key.stop
 
             bits = stop - start
-            #print ("__setitem__ slice num bits", bits)
+            #log ("__setitem__ slice num bits", bits)
             if isinstance(value, SelectableInt):
                 assert value.bits == bits, "%d into %d" % (value.bits, bits)
                 value = value.value
+            log("setitem", key, self.bits, hex(self.value), hex(value))
             mask = ((1 << bits) - 1) << start
             value = value << start
             self.value = (self.value & ~mask) | (value & mask)
@@ -372,7 +386,7 @@ class SelectableInt:
         assert False
 
     def __lt__(self, other):
-        print ("SelectableInt lt", self, other)
+        log ("SelectableInt lt", self, other)
         if isinstance(other, FieldSelectableInt):
             other = other.get_range()
         if isinstance(other, SelectableInt):
@@ -382,19 +396,19 @@ class SelectableInt:
         if isinstance(other, int):
             a = self.to_signed_int()
             res = onebit(a  < other)
-            print ("    a < b", a, other, res)
+            log ("    a < b", a, other, res)
             return res
         assert False
 
     def __eq__(self, other):
-        print("__eq__", self, other)
+        log("__eq__", self, other)
         if isinstance(other, FieldSelectableInt):
             other = other.get_range()
         if isinstance(other, SelectableInt):
             other = check_extsign(self, other)
             assert other.bits == self.bits
             other = other.value
-        print ("    eq", other, self.value, other == self.value)
+        log ("    eq", other, self.value, other == self.value)
         if isinstance(other, int):
             return onebit(other == self.value)
         assert False
@@ -407,8 +421,8 @@ class SelectableInt:
         return self.value != 0
 
     def __repr__(self):
-        return "SelectableInt(value=0x{:x}, bits={})".format(self.value,
-                                                             self.bits)
+        value = f"value=0x{self.value:x}, bits={self.bits}"
+        return f"{self.__class__.__name__}({value})"
 
     def __len__(self):
         return self.bits
@@ -416,6 +430,64 @@ class SelectableInt:
     def asint(self):
         return self.value
 
+    def __float__(self):
+        """convert to double-precision float.  TODO, properly convert
+        rather than a hack-job: must actually support Power IEEE754 FP
+        """
+        assert self.bits == 64 # must be 64-bit
+        data = self.value.to_bytes(8, byteorder='little')
+        return struct.unpack('<d', data)[0]
+
+
+class SelectableIntMappingMeta(type):
+    def __new__(metacls, name, bases, attrs, bits=0, fields=None):
+        if fields is None:
+            fields = {}
+
+        def field(item):
+            (key, value) = item
+            if isinstance(value, dict):
+                value = dict(map(field, value.items()))
+            else:
+                value = tuple(value)
+            return (key, value)
+
+        cls = super().__new__(metacls, name, bases, attrs)
+        cls.__bits = bits
+        cls.__fields = dict(map(field, fields.items()))
+
+        return cls
+
+    def __iter__(cls):
+        for (key, value) in cls.__fields.items():
+            yield (key, value)
+
+    def __getattr__(cls, attr):
+        try:
+            return cls.__fields[attr]
+        except KeyError as error:
+            raise AttributeError from error
+
+    @property
+    def bits(cls):
+        return cls.__bits
+
+
+class SelectableIntMapping(SelectableInt, metaclass=SelectableIntMappingMeta):
+    def __init__(self, value=0):
+        return super().__init__(value, self.__class__.bits)
+
+    def __getattr__(self, attr):
+        def field(value):
+            if isinstance(value, dict):
+                return {key:field(value) for (key, value) in tuple(value.items())}
+            return FieldSelectableInt(si=self, br=value)
+
+        try:
+            return field(getattr(self.__class__, attr))
+        except KeyError as error:
+            raise AttributeError from error
+
 
 def onebit(bit):
     return SelectableInt(1 if bit else 0, 1)
@@ -469,7 +541,7 @@ def selectconcat(*args, repeat=1):
         assert isinstance(i, SelectableInt), "can only concat SIs, sorry"
         res.bits += i.bits
         res.value = (res.value << i.bits) | i.value
-    print("concat", repeat, res)
+    log("concat", repeat, res)
     return res
 
 
@@ -555,6 +627,24 @@ class SelectableIntTestCase(unittest.TestCase):
         self.assertTrue(a != b)
         self.assertFalse(a == b)
 
+    def test_maxint(self):
+        a = SelectableInt(0xffffffffffffffff, bits=64)
+        b = SelectableInt(0, bits=64)
+        result = a + b
+        self.assertTrue(result.value == 0xffffffffffffffff)
+
+    def test_double_1(self):
+        """use http://weitz.de/ieee/,
+        """
+        for asint, asfloat in [(0x4000000000000000, 2.0),
+                               (0x4056C00000000000, 91.0),
+                               (0xff80000000000000, -1.4044477616111843e+306),
+                              ]:
+            a = SelectableInt(asint, bits=64)
+            convert = float(a)
+            log ("test_double_1", asint, asfloat, convert)
+            self.assertTrue(asfloat == convert)
+
 
 if __name__ == "__main__":
     unittest.main()