power_insn: switch to new fields
authorDmitry Selyutin <ghostmansd@gmail.com>
Fri, 19 Aug 2022 10:48:20 +0000 (13:48 +0300)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Mon, 29 Aug 2022 19:38:52 +0000 (20:38 +0100)
src/openpower/decoder/power_insn.py
src/openpower/sv/trans/pysvp64dis.py

index 5e9e8b06131c477327f359df2274840d71121c1b..411ec02e6e13309b1c4be8825ac71003f223ad13 100644 (file)
@@ -1,5 +1,4 @@
 import collections as _collections
-import copy as _copy
 import csv as _csv
 import dataclasses as _dataclasses
 import enum as _enum
@@ -37,12 +36,13 @@ from openpower.decoder.power_enums import (
 )
 from openpower.decoder.selectable_int import (
     SelectableInt as _SelectableInt,
+    selectconcat as _selectconcat,
 )
 
 # TODO: these should be present in the decoder module.
-from openpower.decoder.isa.caller import (
-    SVP64PrefixFields as _SVP64PrefixFields,
-    SVP64RMFields as _SVP64RMFields,
+from openpower.decoder.power_fields import (
+    Field as _Field,
+    Mapping as _Mapping,
 )
 
 
@@ -533,130 +533,138 @@ class Record:
         return self.svp64.etype
 
 
-class Instruction(_SelectableInt):
-    def __init__(self, value, bits=None, byteorder="little", db=None):
-        if isinstance(value, _SelectableInt):
-            if bits is not None:
-                raise ValueError(bits)
-            bits = value.bits
-            value = value.value
-        else:
-            if bits is None:
-                bits = 32
-            if isinstance(value, bytes):
-                value = int.from_bytes(value, byteorder=str(byteorder))
-            if not isinstance(bits, int):
-                raise ValueError(bits)
+class Instruction(_Mapping):
+    @classmethod
+    def integer(cls, value=0, bits=None, byteorder="little"):
+        if isinstance(value, (int, bytes)) and not isinstance(bits, int):
+            raise ValueError(bits)
 
-        if not isinstance(value, int):
-            raise ValueError(value)
+        if isinstance(value, bytes):
+            if ((len(value) * 8) != bits):
+                raise ValueError(f"bit length mismatch")
+            value = int.from_bytes(value, byteorder=byteorder)
 
-        if db is not None and not isinstance(db, Database):
-            raise ValueError(db)
+        if isinstance(value, int):
+            value = _SelectableInt(value=value, bits=bits)
+        elif isinstance(value, Instruction):
+            value = value.storage
 
-        self.__db = db
+        if not isinstance(value, _SelectableInt):
+            raise ValueError(value)
+        if bits is None:
+            bits = len(cls)
+        if len(value) != bits:
+            raise ValueError(value)
 
-        return super().__init__(value=value, bits=bits)
+        value = _SelectableInt(value=value, bits=bits)
 
-    def __repr__(self):
-        return f"{self.__class__.__name__}({self.value:08x})"
+        return cls(storage=value)
 
-    def disassemble(self):
-        if self.dbrecord is None:
-            yield f".long 0x{self.value:08x}"
-        else:
-            yield f".long 0x{self.value:08x} # {self.dbrecord.name}"
+    def __hash__(self):
+        return hash(int(self))
 
-    @property
-    def major(self):
-        return self[0:6]
+    def disassemble(self, db):
+        raise NotImplementedError
 
-    @property
-    def dbrecord(self):
-        if self.__db is None:
-            return None
-        try:
-            return self.__db[int(self)]
-        except KeyError:
-            return None
 
+class WordInstruction(Instruction):
+    class PO(_Mapping):
+        _: _Field = range(0, 6)
 
-class PrefixedInstruction(Instruction):
-    def __init__(self, prefix, suffix, byteorder="little", db=None):
-        insn = _functools.partial(Instruction, byteorder=byteorder, db=db)
-        (prefix, suffix) = map(insn, (prefix, suffix))
-        value = ((prefix.value << 32) | suffix.value)
-
-        return super().__init__(value=value, bits=64,
-            byteorder=byteorder, db=db)
+    _: _Field = range(0, 32)
+    po: PO
 
-    def __repr__(self):
-        return f"{self.__class__.__name__}({self.value:016x})"
+    @classmethod
+    def integer(cls, value, byteorder="little"):
+        return super().integer(bits=32, value=value, byteorder=byteorder)
 
-    def disassemble(self):
-        if self.dbrecord is None:
-            yield f".llong 0x{self.value:08x}"
+    def disassemble(self, db):
+        record = db[self]
+        if record is None:
+            yield f".long 0x{int(self):08x}"
         else:
-            yield f".llong 0x{self.value:08x} # {self.dbrecord.name}"
+            yield f".long 0x{int(self):08x} # {record.name}"
 
-    @property
-    def prefix(self):
-        return Instruction(self[0:32])
 
-    @property
-    def suffix(self):
-        return Instruction(self[32:64])
+class PrefixedInstruction(Instruction):
+    class Prefix(WordInstruction.remap(range(0, 32))):
+        pass
 
-    @property
-    def major(self):
-        return self.suffix.major
+    class Suffix(WordInstruction.remap(range(32, 64))):
+        pass
 
-    @property
-    def dbrecord(self):
-        return self.suffix.dbrecord
+    _: _Field = range(64)
+    prefix: Prefix
+    suffix: Suffix
+    po: Suffix.PO = Suffix.po
 
+    @classmethod
+    def integer(cls, value, byteorder="little"):
+        return super().integer(bits=64, value=value, byteorder=byteorder)
 
-class SVP64Instruction(PrefixedInstruction):
-    class PrefixError(ValueError):
-        pass
+    @classmethod
+    def pair(cls, prefix=0, suffix=0, byteorder="little"):
+        def transform(value):
+            return WordInstruction.integer(value=value,
+                byteorder=byteorder)[0:32]
 
-    class Prefix(Instruction, _SVP64PrefixFields):
-        class RM(_SVP64RMFields):
-            @property
-            def sv_mode(self):
-                return (self.mode & 0b11)
+        (prefix, suffix) = map(transform, (prefix, suffix))
+        value = _selectconcat(prefix, suffix)
 
-        @property
-        def rm(self):
-            return self.__class__.RM(super().rm)
+        return super().integer(value=value)
 
-    class Suffix(Instruction):
-        pass
+    def disassemble(self, db):
+        record = db[self.suffix]
+        if record is None:
+            yield f".long 0x{int(self.prefix):08x}"
+            yield f".long 0x{int(self.suffix):08x}"
+        else:
+            yield f".llong 0x{int(self):08x} # {record.name}"
 
-    def __init__(self, prefix, suffix, byteorder="little", db=None):
-        insn = _functools.partial(Instruction, byteorder=byteorder, db=db)
-        (prefix, suffix) = map(insn, (prefix, suffix))
 
-        prefix = SVP64Instruction.Prefix(value=prefix)
-        if prefix.pid != 0b11:
-            raise SVP64Instruction.PrefixError(prefix)
+class SVP64Instruction(PrefixedInstruction):
+    class Prefix(PrefixedInstruction.Prefix):
+        """SVP64 Prefix: https://libre-soc.org/openpower/sv/svp64/"""
+        class RM(_Mapping):
+            """SVP64 RM: https://libre-soc.org/openpower/sv/svp64/"""
+            _: _Field = range(24)
+            mmode: _Field = (0,)
+            mask: _Field = range(1, 4)
+            elwidth: _Field = range(4, 6)
+            ewsrc: _Field = range(6, 8)
+            subvl: _Field = range(8, 10)
+            extra: _Field = range(10, 19)
+            mode: _Field = range(19, 24)
+            extra2: _Field[4] = (
+                range(10, 12),
+                range(12, 14),
+                range(14, 16),
+                range(16, 18),
+            )
+            smask: _Field = range(16, 19)
+            extra3: _Field[3] = (
+                range(10, 13),
+                range(13, 16),
+                range(16, 19),
+            )
 
-        return super().__init__(prefix=prefix, suffix=suffix,
-            byteorder=byteorder, db=db)
+            # Backward compatibility
+            spr: _Field = _
 
-    def disassemble(self):
-        if self.dbrecord is None:
-            yield f".llong 0x{self.value:08x}"
-        else:
-            yield f".llong 0x{self.value:08x} # sv.{self.dbrecord.name}"
+        id: _Field = (7, 9)
+        rm: RM = ((6, 8) + tuple(range(10, 32)))
 
-    @property
-    def prefix(self):
-        return self.__class__.Prefix(super().prefix)
+        # Backward compatibility
+        insn: PrefixedInstruction.Prefix
 
-    @property
-    def suffix(self):
-        return self.__class__.Suffix(super().suffix)
+    prefix: Prefix
+
+    def disassemble(self, db):
+        record = db[self.suffix]
+        if record is None:
+            yield f".llong 0x{int(self):08x}"
+        else:
+            yield f".llong 0x{int(self):08x} # sv.{record.name}"
 
 
 class Database:
@@ -772,10 +780,11 @@ class Database:
     def __getitem__(self, key):
         if isinstance(key, Opcode):
             return self.__opcodes.__getitem__(key)
-        elif isinstance(key, int):
+        elif isinstance(key, (int, Instruction)):
+            ikey = int(key)
             for (opcode, insn) in self.__opcodes.items():
                 if ((opcode.value & opcode.mask) ==
-                        (key & opcode.mask)):
+                        (ikey & opcode.mask)):
                     return insn
             raise KeyError(key)
         elif isinstance(key, str):
index 67833b358e3dcc2f74f54538e8e72dba86807270..cf62722067de3fb4cfc912620e09132f3219c540 100644 (file)
@@ -9,9 +9,14 @@ from openpower.decoder.power_enums import (
 from openpower.decoder.power_insn import (
     Database as _Database,
     Instruction as _Instruction,
+    WordInstruction as _WordInstruction,
     PrefixedInstruction as _PrefixedInstruction,
     SVP64Instruction as _SVP64Instruction,
 )
+from openpower.decoder.selectable_int import (
+    SelectableInt as _SelectableInt,
+    FieldSelectableInt as _FieldSelectableInt
+)
 
 
 class ByteOrder(_enum.Enum):
@@ -23,42 +28,39 @@ class ByteOrder(_enum.Enum):
 
 
 def load(ifile, byteorder, **_):
-    db = _Database(_find_wiki_dir())
+    byteorder = str(byteorder)
 
-    def load(ifile):
+    while True:
         prefix = ifile.read(4)
         length = len(prefix)
         if length == 0:
-            return None
+            return
         elif length < 4:
             raise IOError(prefix)
-        prefix = _Instruction(value=prefix, byteorder=byteorder, db=db)
-        if prefix.major != 0x1:
-            return prefix
+        prefix = _WordInstruction.integer(value=prefix, byteorder=byteorder)
 
         suffix = ifile.read(4)
         length = len(suffix)
         if length == 0:
-            return prefix
+            yield prefix
         elif length < 4:
             raise IOError(suffix)
-        try:
-            return _SVP64Instruction(prefix=prefix, suffix=suffix,
-                byteorder=byteorder, db=db)
-        except _SVP64Instruction.PrefixError:
-            return _PrefixedInstruction(prefix=prefix, suffix=suffix,
-                byteorder=byteorder, db=db)
+        suffix = _WordInstruction.integer(value=suffix, byteorder=byteorder)
 
-    while True:
-        insn = load(ifile)
-        if insn is None:
-            break
-        yield insn
+        if prefix.po == 0x1:
+            insn = _SVP64Instruction.pair(prefix=prefix, suffix=suffix)
+            if insn.prefix.id != 0b11:
+                insn = _PrefixedInstruction.pair(prefix=prefix, suffix=suffix)
+            yield insn
+        else:
+            yield prefix
+            yield suffix
 
 
 def dump(insns, **_):
+    db = _Database(_find_wiki_dir())
     for insn in insns:
-        yield from insn.disassemble()
+        yield from insn.disassemble(db=db)
 
 
 def main():