selectable_int: refactor fields mappings
authorDmitry Selyutin <ghostmansd@gmail.com>
Thu, 18 Aug 2022 11:44:38 +0000 (14:44 +0300)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Mon, 29 Aug 2022 19:38:51 +0000 (20:38 +0100)
src/openpower/decoder/isa/caller.py
src/openpower/decoder/power_insn.py
src/openpower/decoder/selectable_int.py
src/openpower/sv/trans/pysvp64dis.py
src/openpower/sv/trans/svp64.py

index 5ab5a06af9e1221c2b93ea79874554365c2f1267..d128d167bed3ef632eacc3721b831bf4df8973ab 100644 (file)
@@ -259,35 +259,29 @@ class PC:
 
 
 # SVP64 ReMap field
-class SVP64RMFields(SelectableIntMapping, bits=24, fields={
-    "spr": range(24),
-    # SVP64 RM fields: see https://libre-soc.org/openpower/sv/svp64/
-    "mmode": (0,),
-    "mask": range(1, 4),
-    "elwidth": range(4, 6),
-    "ewsrc": range(6, 8),
-    "subvl": range(8, 10),
-    "extra": range(10, 19),
-    "mode": range(19, 24),
-    # these cover the same extra field, split into parts as EXTRA2
-    "extra2": dict(enumerate([
+class SVP64RMFields(SelectableIntMapping):
+    """SVP64 RM: https://libre-soc.org/openpower/sv/svp64/"""
+    spr = range(24)
+    mmode = (0,)
+    mask = range(1, 4)
+    elwidth = range(4, 6)
+    ewsrc = range(6, 8)
+    subvl = range(8, 10)
+    extra = range(10, 19)
+    mode = range(19, 24)
+    extra2 = dict(enumerate([
         range(10, 12),
         range(12, 14),
         range(14, 16),
         range(16, 18),
-    ])),
-    "smask": range(16, 19),
-    # and here as well, but EXTRA3
-    "extra3": dict(enumerate([
+    ]))
+    smask = range(16, 19)
+    extra3 = dict(enumerate([
         range(10, 13),
         range(13, 16),
         range(16, 19),
-    ])),
-}):
+    ]))
 
-    def __init__(self, value=0):
-        super().__init__(value=value)
-        self.spr = self
 
 
 SVP64RM_MMODE_SIZE = len(SVP64RMFields.mmode)
@@ -301,20 +295,12 @@ SVP64RM_SMASK_SIZE = len(SVP64RMFields.smask)
 SVP64RM_MODE_SIZE = len(SVP64RMFields.mode)
 
 
-# SVP64 Prefix fields: see https://libre-soc.org/openpower/sv/svp64/
-class SVP64PrefixFields(SelectableIntMapping, bits=32, fields={
-    "insn": range(32),
-    # 6 bit major opcode EXT001, 2 bits "identifying" (7, 9), 24 SV ReMap
-    "major": range(0, 6),
-    "pid": (7, 9),
-    # SVP64 24-bit RM (ReMap)
-    "rm": ((6, 8) + tuple(range(10, 32))),
-}):
-
-    def __init__(self, value=0):
-        super().__init__(value=value)
-        self.insn = self
-
+class SVP64PrefixFields(SelectableIntMapping):
+    """SVP64 Prefix: https://libre-soc.org/openpower/sv/svp64/"""
+    insn = range(32)
+    major = range(0, 6)
+    pid = (7, 9)
+    rm = ((6, 8) + tuple(range(10, 32)))
 
 SV64P_MAJOR_SIZE = len(SVP64PrefixFields.major)
 SV64P_PID_SIZE = len(SVP64PrefixFields.pid)
@@ -1008,8 +994,7 @@ class ISACaller(ISACallerHelper, ISAFPHelpers):
         # SVP64.  first, check if the opcode is EXT001, and SVP64 id bits set
         yield Settle()
         opcode = yield self.dec2.dec.opcode_in
-        pfx = SVP64PrefixFields()  # TODO should probably use SVP64PrefixDecoder
-        pfx.insn.value = opcode
+        pfx = SVP64PrefixFields(opcode)
         major = pfx.major.asint(msb0=True)  # MSB0 inversion
         log("prefix test: opcode:", major, bin(major),
             pfx.insn[7] == 0b1, pfx.insn[9] == 0b1)
index 244eac522407eb8a56ca70d1b6e7a5b981be9df5..5e9e8b06131c477327f359df2274840d71121c1b 100644 (file)
@@ -545,7 +545,7 @@ class Instruction(_SelectableInt):
                 bits = 32
             if isinstance(value, bytes):
                 value = int.from_bytes(value, byteorder=str(byteorder))
-            if not isinstance(bits, int) or (bits not in {32, 64}):
+            if not isinstance(bits, int):
                 raise ValueError(bits)
 
         if not isinstance(value, int):
@@ -620,7 +620,7 @@ class SVP64Instruction(PrefixedInstruction):
     class PrefixError(ValueError):
         pass
 
-    class Prefix(_SVP64PrefixFields, Instruction):
+    class Prefix(Instruction, _SVP64PrefixFields):
         class RM(_SVP64RMFields):
             @property
             def sv_mode(self):
index a94bb43d41083432f1141e44a16ad11c1ab1c001..56ba07c3b78b1a9bf88dee0c37d755171732fcce 100644 (file)
@@ -127,10 +127,12 @@ class FieldSelectableInt:
         return self._op(xor, b)
 
     def __lt__(self, b):
-        return self._op(lt, b)
+        vi = self.get_range()
+        return onebit(lt(vi, b))
 
     def __eq__(self, b):
-        return self._op(eq, b)
+        vi = self.get_range()
+        return onebit(eq(vi, b))
 
     def get_range(self):
         vi = SelectableInt(0, len(self.br))
@@ -494,88 +496,103 @@ class SelectableInt:
 
 
 class SelectableIntMappingMeta(type):
-    @functools.total_ordering
-    class Field(FieldSelectableInt):
-        def __int__(self):
-            return self.asint(msb0=True)
-
-        def __lt__(self, b):
-            return int(self).__lt__(b)
-
-        def __eq__(self, b):
-            return int(self).__eq__(b)
-
-    class FieldProperty:
-        def __init__(self, field):
-            self.__field = field
-
-        def __repr__(self):
-            return self.__field.__repr__()
+    class Field(tuple):
+        def __call__(self, si):
+            return FieldSelectableInt(si=si, br=self)
+
+    class FieldMapping(dict):
+        def __init__(self, items):
+            if isinstance(items, dict):
+                items = items.items()
+
+            length = 0
+            mapping = {}
+            Field = SelectableIntMappingMeta.Field
+            for (key, value) in items:
+                field = Field(value)
+                mapping[key] = field
+                length = max(length, len(field))
+
+            self.__length = length
+
+            return super().__init__(mapping)
+
+        def __iter__(self):
+            yield from self.items()
+
+        def __len__(self):
+            return self.__length
+
+        def __call__(self, si):
+            return {key:value(si=si) for (key, value) in self}
+
+    def __new__(metacls, name, bases, attrs):
+        mapping = {}
+        valid = False
+        for base in reversed(bases):
+            if issubclass(base.__class__, metacls):
+                mapping.update(base)
+            if not valid and issubclass(base, SelectableInt):
+                valid = True
+        if not valid:
+            raise ValueError(bases)
+
+        for (key, value) in tuple(attrs.items()):
+            if key.startswith("_"):
+                continue
+            if isinstance(value, dict):
+                value = metacls.FieldMapping(value)
+            elif isinstance(value, (list, tuple, range)):
+                value = metacls.Field(value)
+            else:
+                continue
+            mapping[key] = value
+            attrs[key] = value
 
-        def __get__(self, instance, owner):
-            if instance is None:
-                return self.__field
+        length = 0
+        for (key, value) in mapping.items():
+            length = max(length, len(value))
 
-            cls = SelectableIntMappingMeta.Field
-            factory = lambda br: cls(si=instance, br=br)
-            if isinstance(self.__field, dict):
-                return {k:factory(br=v) for (k, v) in self.__field.items()}
-            else:
-                return factory(br=self.__field)
+        cls = super().__new__(metacls, name, bases, attrs)
+        cls.__length = length
+        cls.__mapping = mapping
 
-    class BitsProperty:
-        def __init__(self, bits):
-            self.__bits = bits
+        return cls
 
-        def __get__(self, instance, owner):
-            if instance is None:
-                return self.__bits
-            return instance.bits
+    def __len__(cls):
+        return cls.__length
 
-        def __repr__(self):
-            return self.__bits.__repr__()
+    def __contains__(cls, key):
+        return cls.__mapping.__contains__(key)
 
-    def __new__(metacls, name, bases, attrs, bits=None, fields=None):
-        if fields is None:
-            fields = {}
+    def __getitem__(cls, key):
+        return cls.__mapping.__getitem__(key)
 
-        def field(item):
-            (key, value) = item
-            if isinstance(value, dict):
-                value = dict(map(field, value.items()))
-            else:
-                value = tuple(value)
-            return (key, value)
+    def __iter__(cls):
+        yield from cls.__mapping.items()
+        if type(cls) is not SelectableIntMappingMeta:
+            yield from super().__iter__()
 
-        fields = dict(map(field, fields.items()))
-        for (key, value) in fields.items():
-            attrs.setdefault(key, metacls.FieldProperty(value))
 
+class SelectableIntMapping(SelectableInt, metaclass=SelectableIntMappingMeta):
+    def __init__(self, value=0, bits=None):
+        if isinstance(value, SelectableInt):
+            value = value.value
         if bits is None:
-            for base in bases:
-                bits = getattr(base, "bits", None)
-                if bits is not None:
-                    break
-
-        if not isinstance(bits, int):
+            bits = len(self.__class__)
+        if bits != len(self.__class__):
             raise ValueError(bits)
-        attrs.setdefault("bits", metacls.BitsProperty(bits))
 
-        cls = super().__new__(metacls, name, bases, attrs)
-        cls.__fields = fields
-        return cls
+        return super().__init__(value=value, bits=bits)
 
-    def __iter__(cls):
-        for (key, value) in cls.__fields.items():
-            yield (key, value)
+    def __iter__(self):
+        for (name, _) in self.__class__:
+            yield (name, getattr(self, name))
 
-
-class SelectableIntMapping(SelectableInt,
-            metaclass=SelectableIntMappingMeta, bits=0):
-    def __init__(self, value=0, bits=None):
-        if isinstance(value, int) and bits is None:
-            bits = self.__class__.bits
-        return super().__init__(value, bits)
+    def __getattribute__(self, attr):
+        if (attr != "__class__") and (attr in self.__class__):
+            return self.__class__[attr](si=self)
+        return super().__getattribute__(attr)
 
 
 def onebit(bit):
index b8c0183a20d8dcd2c3604dbc8acefbdbd949f444..67833b358e3dcc2f74f54538e8e72dba86807270 100644 (file)
@@ -56,7 +56,7 @@ def load(ifile, byteorder, **_):
         yield insn
 
 
-def dump(insns, ofile, **_):
+def dump(insns, **_):
     for insn in insns:
         yield from insn.disassemble()
 
@@ -76,7 +76,7 @@ def main():
     byteorder = args["byteorder"]
 
     insns = load(ifile, byteorder)
-    for line in dump(insns, byteorder):
+    for line in dump(insns):
         print(line, file=ofile)
 
 
index dc8fe9b521c9a1c7612974b078c8658fb4af6e86..15e47b67f28446a0feec48a5e78372267aa47d84 100644 (file)
@@ -1224,7 +1224,7 @@ class SVP64Asm:
 
         # nice debug printout. (and now for something completely different)
         # https://youtu.be/u0WOIwlXE9g?t=146
-        svp64_rm_value = svp64_rm.spr.value
+        svp64_rm_value = int(svp64_rm)
         log("svp64_rm", hex(svp64_rm_value), bin(svp64_rm_value))
         log("    mmode  0    :", bin(mmode))
         log("    pmask  1-3  :", bin(pmask))
@@ -1251,7 +1251,7 @@ class SVP64Asm:
         svp64_prefix = SVP64PrefixFields()
         svp64_prefix.major.eq(SelectableInt(0x1, SV64P_MAJOR_SIZE))
         svp64_prefix.pid.eq(SelectableInt(0b11, SV64P_PID_SIZE))
-        svp64_prefix.rm.eq(svp64_rm.spr)
+        svp64_prefix.rm.eq(svp64_rm)
 
         # fiinally yield the svp64 prefix and the thingy.  v3.0b opcode
         rc = '.' if rc_mode else ''