power_insn: support PPC multi-records
[openpower-isa.git] / src / openpower / decoder / power_fields.py
index a500059f3af9c80304325d8c390cb396ffaef2a0..48cd23d45dd2f8f02fd265462a76ac1f31ff8278 100644 (file)
@@ -46,13 +46,12 @@ class Reference:
         _ = (args, kwargs)
 
     def __binary_operator(self, op, other):
-        span = self.__class__.span
+        span = dict.fromkeys(self.__class__.span).keys()
         lhs = _selectconcat(*(self.storage[bit] for bit in span))
 
-        if isinstance(other, Field):
-            bits = len(other.__class__)
-            value = int(other)
-            rhs = _SelectableInt(value=value, bits=bits)
+        if isinstance(other, Reference):
+            span = dict.fromkeys(other.__class__.span).keys()
+            rhs = _selectconcat(*(other.storage[bit] for bit in span))
         elif isinstance(other, int):
             bits = len(self.__class__)
             if other.bit_length() > bits:
@@ -117,11 +116,6 @@ class FieldMeta(type):
 
         return super().__new__(metacls, clsname, bases, ns)
 
-    def __getitem__(cls, size):
-        clsname = f"{cls.__name__}[{size}]"
-        items = ((Field,) * size)
-        return ArrayMeta(clsname, (Array,), {}, items=items)
-
     def __repr__(cls):
         if not cls.__members__:
             return cls.__name__
@@ -133,9 +127,18 @@ class FieldMeta(type):
     def __len__(cls):
         return len(cls.__members__)
 
-    @property
-    def span(cls):
-        return cls.__members__
+    def __getitem__(cls, selector):
+        if isinstance(selector, int):
+            selector = (selector,)
+
+        items = []
+        for idx in selector:
+            if not isinstance(idx, int):
+                raise ValueError(selector)
+            item = cls.__members__[idx]
+            items.append(item)
+
+        return cls.__class__(cls.__name__, (Field,), {}, items=items)
 
     def remap(cls, scheme):
         if isinstance(scheme, type) and issubclass(scheme, Mapping):
@@ -153,6 +156,13 @@ class FieldMeta(type):
 
         return cls.__class__(cls.__name__, (cls,), {}, items=items)
 
+    @property
+    def span(cls):
+        return cls.__members__
+
+    def traverse(cls, path):
+        yield (path, cls.__members__)
+
 
 class Field(Reference, metaclass=FieldMeta):
     def __len__(self):
@@ -194,6 +204,11 @@ class ArrayMeta(type):
             length += len(field)
         return length
 
+    def __getitem__(cls, size):
+        clsname = f"{cls.__name__}[{size}]"
+        items = ((Field,) * size)
+        return ArrayMeta(clsname, (Array,), {}, items=items)
+
     def remap(cls, scheme):
         scheme_md = []
         scheme_sd = []
@@ -244,6 +259,10 @@ class ArrayMeta(type):
         for field in cls.__members__:
             yield from field.span
 
+    def traverse(cls, path=""):
+        for (idx, field) in cls:
+            yield from field.traverse(path=f"{path}[{idx}]")
+
 
 class Array(Reference, metaclass=ArrayMeta):
     def __init__(self, storage):
@@ -311,6 +330,19 @@ class MappingMeta(type):
             length = max(length, len(field))
         return length
 
+    def __getitem__(cls, selector):
+        best_min = 0
+        best_max = 0
+        for field in cls.__members__.values():
+            length = len(field)
+            best_min = min(best_min, length)
+            best_max = max(best_max, length)
+
+        items = tuple(range(best_min, best_max))
+        field = FieldMeta(cls.__name__, (Field,), {}, items=items)
+
+        return field[selector]
+
     def remap(cls, scheme):
         ns = {}
         annotations = {}
@@ -326,6 +358,15 @@ class MappingMeta(type):
         for field in cls.__members__.values():
             yield from field.span
 
+    def traverse(cls, path=""):
+        for (name, field) in cls:
+            if name == "_":
+                yield from field.traverse(path=path)
+            elif path == "":
+                yield from field.traverse(path=name)
+            else:
+                yield from field.traverse(path=f"{path}.{name}")
+
 
 class Mapping(Reference, metaclass=MappingMeta):
     def __init__(self, storage, **kwargs):