power_insn: remove the whitespaces properly
[openpower-isa.git] / src / openpower / decoder / selectable_int.py
index 675243a2ba727b66b03db753f251f8749cb673c7..55f5e6c824a8cb8ce52d56403897972e3c34f3b8 100644 (file)
@@ -2,9 +2,9 @@ import unittest
 import struct
 from copy import copy
 import functools
-from openpower.decoder.power_fields import BitRange
+from collections import OrderedDict
 from operator import (add, sub, mul, floordiv, truediv, mod, or_, and_, xor,
-                      neg, inv, lshift, rshift)
+                      neg, inv, lshift, rshift, lt, eq)
 from openpower.util import log
 
 
@@ -18,18 +18,44 @@ def check_extsign(a, b):
     return SelectableInt(b.value, a.bits)
 
 
+class BitRange(OrderedDict):
+    """BitRange: remaps from straight indices (0,1,2..) to bit numbers
+    """
+
+    def __getitem__(self, subscript):
+        if isinstance(subscript, slice):
+            return list(self.values())[subscript]
+        else:
+            return OrderedDict.__getitem__(self, subscript)
+
+
+@functools.total_ordering
 class FieldSelectableInt:
     """FieldSelectableInt: allows bit-range selection onto another target
     """
 
     def __init__(self, si, br):
-        self.si = si  # target selectable int
+        if not isinstance(si, (FieldSelectableInt, SelectableInt)):
+            raise ValueError(si)
+
         if isinstance(br, (list, tuple, range)):
             _br = BitRange()
             for i, v in enumerate(br):
                 _br[i] = v
             br = _br
-        self.br = br  # map of indices.
+
+        if isinstance(si, FieldSelectableInt):
+            fsi = si
+            if len(br) > len(fsi.br):
+                raise OverflowError(br)
+            _br = BitRange()
+            for (i, v) in br.items():
+                _br[i] = fsi.br[v]
+            br = _br
+            si = fsi.si
+
+        self.si = si  # target selectable int
+        self.br = br  # map of indices
 
     def eq(self, b):
         if isinstance(b, int):
@@ -55,16 +81,24 @@ class FieldSelectableInt:
         vi = op(vi)
         return self.merge(vi)
 
+    def __len__(self):
+        return len(self.br)
+
     def __getitem__(self, key):
         log("getitem", key, self.br)
         if isinstance(key, SelectableInt):
             key = key.value
+
         if isinstance(key, int):
             key = self.br[key]  # don't do POWER 1.3.4 bit-inversion
             return self.si[key]
-        if isinstance(key, slice):
+        elif isinstance(key, slice):
             key = self.br[key]
             return selectconcat(*[self.si[x] for x in key])
+        elif isinstance(key, (tuple, list, range)):
+            return FieldSelectableInt(si=self, br=key)
+        else:
+            raise ValueError(key)
 
     def __setitem__(self, key, value):
         if isinstance(key, SelectableInt):
@@ -79,7 +113,7 @@ class FieldSelectableInt:
                 self.si[k] = value[i]
 
     def __negate__(self):
-        return self._op1(negate)
+        return self._op1(neg)
 
     def __invert__(self):
         return self._op1(inv)
@@ -108,6 +142,14 @@ class FieldSelectableInt:
     def __xor__(self, b):
         return self._op(xor, b)
 
+    def __lt__(self, b):
+        vi = self.get_range()
+        return onebit(lt(vi, b))
+
+    def __eq__(self, b):
+        vi = self.get_range()
+        return onebit(eq(vi, b))
+
     def get_range(self):
         vi = SelectableInt(0, len(self.br))
         for k, v in self.br.items():
@@ -123,10 +165,21 @@ class FieldSelectableInt:
     def __repr__(self):
         return f"{self.__class__.__name__}(si={self.si}, br={self.br})"
 
+    def __bool__(self):
+        for key in self.br.values():
+            bit = self.si[key].value
+            if bit:
+                return True
+        return False
+
+    def __int__(self):
+        return self.asint(msb0=True)
+
     def asint(self, msb0=False):
         res = 0
         brlen = len(self.br)
         for i, key in self.br.items():
+            log("asint", i, key, self.si[key])
             bit = self.si[key].value
             #log("asint", i, key, bit)
             res |= bit << ((brlen-i-1) if msb0 else i)
@@ -186,8 +239,22 @@ class SelectableInt:
 
     def __init__(self, value, bits=None):
         if isinstance(value, SelectableInt):
+            if bits is not None:
+                # check if the bitlength is different. TODO, allow override?
+                if bits != value.bits:
+                    raise ValueError(value)
             bits = value.bits
             value = value.value
+        elif isinstance(value, FieldSelectableInt):
+            if bits is not None:
+                raise ValueError(value)
+            bits = len(value.br)
+            value = value.si.value
+        else:
+            if not isinstance(value, int):
+                raise ValueError(value)
+            if bits is None:
+                raise ValueError(bits)
         mask = (1 << bits) - 1
         self.value = value & mask
         self.bits = bits
@@ -289,6 +356,7 @@ class SelectableInt:
         return SelectableInt(self.value >> b.value, self.bits)
 
     def __getitem__(self, key):
+        log ("SelectableInt.__getitem__", self, key, type(key))
         if isinstance(key, SelectableInt):
             key = key.value
         if isinstance(key, int):
@@ -311,11 +379,19 @@ class SelectableInt:
             start = self.bits - key.stop
 
             bits = stop - start
-            #log ("__getitem__ slice num bits", start, stop, bits)
+            log ("__getitem__ slice num bits", start, stop, bits)
             mask = (1 << bits) - 1
             value = (self.value >> start) & mask
             log("getitem", stop, start, self.bits, hex(self.value), value)
             return SelectableInt(value, bits)
+        else:
+            bits = []
+            key = tuple(key)
+            for bit in key:
+                if not isinstance(bit, (int, SelectableInt)):
+                    raise ValueError(key)
+                bits.append(self[bit])
+            return selectconcat(*bits)
 
     def __setitem__(self, key, value):
         if isinstance(key, SelectableInt):
@@ -357,6 +433,8 @@ class SelectableInt:
             mask = ((1 << bits) - 1) << start
             value = value << start
             self.value = (self.value & ~mask) | (value & mask)
+        else:
+            raise ValueError(key)
 
     def __ge__(self, other):
         if isinstance(other, FieldSelectableInt):
@@ -427,7 +505,7 @@ class SelectableInt:
         return self.value != 0
 
     def __repr__(self):
-        value = f"value=0x{self.value:x}, bits={self.bits}"
+        value = f"value={hex(self.value)}, bits={self.bits}"
         return f"{self.__class__.__name__}({value})"
 
     def __len__(self):
@@ -436,6 +514,9 @@ class SelectableInt:
     def asint(self):
         return self.value
 
+    def __int__(self):
+        return self.asint()
+
     def __float__(self):
         """convert to double-precision float.  TODO, properly convert
         rather than a hack-job: must actually support Power IEEE754 FP
@@ -445,56 +526,6 @@ class SelectableInt:
         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)