power_insn: remove the whitespaces properly
[openpower-isa.git] / src / openpower / decoder / power_insn.py
index 085414c1302b4f74eebdb212e4b21c5680eec206..34ae88957279e3fc05bece07173c71fc8daaf9d2 100644 (file)
@@ -227,7 +227,9 @@ class PPCRecord:
                 flags.add(flag)
         record["flags"] = PPCRecord.Flags(flags)
 
-        return dataclass(cls, record, keymap=PPCRecord.__KEYMAP, typemap=typemap)
+        return dataclass(cls, record,
+            keymap=PPCRecord.__KEYMAP,
+            typemap=typemap)
 
     @cached_property
     def names(self):
@@ -258,7 +260,9 @@ class PPCMultiRecord(tuple):
                 value |= (vstate << bit)
                 mask |= (mstate << bit)
 
-            return _dataclasses.replace(lhs, opcode=Opcode(value=value, mask=mask))
+            opcode = opcode=Opcode(value=value, mask=mask)
+
+            return _dataclasses.replace(lhs, opcode=opcode)
 
         return _functools.reduce(merge, self)
 
@@ -335,7 +339,11 @@ class SVP64Record:
             if value == "0":
                 record[key] = "NONE"
 
-        record["extra"] = cls.ExtraMap(record.pop(f"{index}") for index in range(0, 4))
+        extra = []
+        for idx in range(0, 4):
+            extra.append(record.pop(f"{idx}"))
+
+        record["extra"] = cls.ExtraMap(extra)
 
         return dataclass(cls, record, keymap=cls.__KEYMAP)
 
@@ -436,151 +444,164 @@ class Fields:
         return self.__mapping.get(key, None)
 
 
-class Operands:
-    @_dataclasses.dataclass(eq=True, frozen=True)
-    class Operand:
-        name: str
+@_dataclasses.dataclass(eq=True, frozen=True)
+class Operand:
+    name: str
 
-        def disassemble(self, value, record, verbose=False):
-            raise NotImplementedError
+    def disassemble(self, value, record, verbose=False):
+        raise NotImplementedError
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class DynamicOperand(Operand):
+    def disassemble(self, value, record, verbose=False):
+        span = record.fields[self.name]
+        value = value[span]
+        if verbose:
+            yield f"{int(value):0{value.bits}b}"
+            yield repr(span)
+        else:
+            yield str(int(value))
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class ImmediateOperand(DynamicOperand):
+    pass
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class StaticOperand(Operand):
+    value: int
+
+    def disassemble(self, value, record, verbose=False):
+        span = record.fields[self.name]
+        value = value[span]
+        if verbose:
+            yield f"{int(value):0{value.bits}b}"
+            yield repr(span)
+        else:
+            yield str(int(value))
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class DynamicOperandTargetAddrLI(DynamicOperand):
+    @property
+    def name(self):
+        return "LI"
+
+    @name.setter
+    def name(self, _):
+        pass
+
+    def disassemble(self, value, record, verbose=False):
+        span = record.fields["LI"]
+        value = value[span]
+        if verbose:
+            yield f"{int(value):0{value.bits}b}"
+            yield repr(span)
+            yield "target_addr = EXTS(LI || 0b00))"
+        else:
+            yield hex(int(_selectconcat(value,
+                _SelectableInt(value=0b00, bits=2))))
 
-    @_dataclasses.dataclass(eq=True, frozen=True)
-    class DynamicOperand(Operand):
-        def disassemble(self, value, record, verbose=False):
-            span = record.fields[self.name]
-            value = value[span]
-            if verbose:
-                yield f"{int(value):0{value.bits}b}"
-                yield repr(span)
-            else:
-                yield str(int(value))
-
-    @_dataclasses.dataclass(eq=True, frozen=True)
-    class StaticOperand(Operand):
-        value: int
-
-        def disassemble(self, value, record, verbose=False):
-            span = record.fields[self.name]
-            value = value[span]
-            if verbose:
-                yield f"{int(value):0{value.bits}b}"
-                yield repr(span)
-            else:
-                yield str(int(value))
-
-    @_dataclasses.dataclass(eq=True, frozen=True)
-    class DynamicOperandIFormLI(DynamicOperand):
-        @property
-        def name(self):
-            return "LI"
-
-        @name.setter
-        def name(self, _):
-            pass
-
-        def disassemble(self, value, record, verbose=False):
-            span = record.fields["LI"]
-            value = value[span]
-            if verbose:
-                yield f"{int(value):0{value.bits}b}"
-                yield repr(span)
-                yield "target_addr = EXTS(LI || 0b00))"
-            else:
-                yield hex(int(_selectconcat(value,
-                    _SelectableInt(value=0b00, bits=2))))
-
-    class DynamicOperandBFormBD(DynamicOperand):
-        @property
-        def name(self):
-            return "BD"
-
-        @name.setter
-        def name(self, _):
-            pass
-
-        def disassemble(self, value, record, verbose=False):
-            span = record.fields["BD"]
-            value = value[span]
-            if verbose:
-                yield f"{int(value):0{value.bits}b}"
-                yield repr(span)
-                yield "target_addr = EXTS(BD || 0b00))"
-            else:
-                yield hex(int(_selectconcat(value,
-                    _SelectableInt(value=0b00, bits=2))))
-
-    @_dataclasses.dataclass(eq=True, frozen=True)
-    class DynamicOperandGPR(DynamicOperand):
-        def disassemble(self, value, record, verbose=False):
-            span = record.fields[self.name]
-            value = value[span]
-            if verbose:
-                yield f"{int(value):0{value.bits}b}"
-                yield repr(span)
-            else:
-                yield f"r{str(int(value))}"
-
-    @_dataclasses.dataclass(eq=True, frozen=True)
-    class DynamicOperandFPR(DynamicOperand):
-        def disassemble(self, value, record, verbose=False):
-            span = record.fields[self.name]
-            value = value[span]
-            if verbose:
-                yield f"{int(value):0{value.bits}b}"
-                yield repr(span)
-            else:
-                yield f"f{str(int(value))}"
 
-    def __init__(self, insn, iterable):
+class DynamicOperandTargetAddrBD(DynamicOperand):
+    @property
+    def name(self):
+        return "BD"
+
+    @name.setter
+    def name(self, _):
+        pass
+
+    def disassemble(self, value, record, verbose=False):
+        span = record.fields["BD"]
+        value = value[span]
+        if verbose:
+            yield f"{int(value):0{value.bits}b}"
+            yield repr(span)
+            yield "target_addr = EXTS(BD || 0b00))"
+        else:
+            yield hex(int(_selectconcat(value,
+                _SelectableInt(value=0b00, bits=2))))
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class DynamicOperandGPR(DynamicOperand):
+    def disassemble(self, value, record, verbose=False):
+        span = record.fields[self.name]
+        value = value[span]
+        if verbose:
+            yield f"{int(value):0{value.bits}b}"
+            yield repr(span)
+        else:
+            yield f"r{str(int(value))}"
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class DynamicOperandFPR(DynamicOperand):
+    def disassemble(self, value, record, verbose=False):
+        span = record.fields[self.name]
+        value = value[span]
+        if verbose:
+            yield f"{int(value):0{value.bits}b}"
+            yield repr(span)
+        else:
+            yield f"f{str(int(value))}"
+
+
+class Operands(tuple):
+    def __new__(cls, insn, iterable):
         branches = {
-            "b": {"LI": self.__class__.DynamicOperandIFormLI},
-            "ba": {"LI": self.__class__.DynamicOperandIFormLI},
-            "bl": {"LI": self.__class__.DynamicOperandIFormLI},
-            "bla": {"LI": self.__class__.DynamicOperandIFormLI},
-            "bc": {"BD": self.__class__.DynamicOperandBFormBD},
-            "bca": {"BD": self.__class__.DynamicOperandBFormBD},
-            "bcl": {"BD": self.__class__.DynamicOperandBFormBD},
-            "bcla": {"BD": self.__class__.DynamicOperandBFormBD},
+            "b": {"target_addr": DynamicOperandTargetAddrLI},
+            "ba": {"target_addr": DynamicOperandTargetAddrLI},
+            "bl": {"target_addr": DynamicOperandTargetAddrLI},
+            "bla": {"target_addr": DynamicOperandTargetAddrLI},
+            "bc": {"target_addr": DynamicOperandTargetAddrBD},
+            "bca": {"target_addr": DynamicOperandTargetAddrBD},
+            "bcl": {"target_addr": DynamicOperandTargetAddrBD},
+            "bcla": {"target_addr": DynamicOperandTargetAddrBD},
         }
 
         operands = []
         for operand in iterable:
-            dynamic_cls = self.__class__.DynamicOperand
-            static_cls = self.__class__.StaticOperand
+            dynamic_cls = DynamicOperand
+            static_cls = StaticOperand
 
             if "=" in operand:
                 (name, value) = operand.split("=")
                 operand = static_cls(name=name, value=int(value))
+                operands.append(operand)
             else:
+                if operand.endswith(")"):
+                    operand = operand.replace("(", " ").replace(")", "")
+                    (immediate, _, operand) = operand.partition(" ")
+                else:
+                    immediate = None
+
+                if immediate is not None:
+                    operands.append(ImmediateOperand(name=immediate))
+
                 if insn in branches and operand in branches[insn]:
                     dynamic_cls = branches[insn][operand]
 
                 if operand in _RegType.__members__:
                     regtype = _RegType[operand]
                     if regtype is _RegType.GPR:
-                        dynamic_cls = self.__class__.DynamicOperandGPR
+                        dynamic_cls = DynamicOperandGPR
                     elif regtype is _RegType.FPR:
-                        dynamic_cls = self.__class__.DynamicOperandFPR
+                        dynamic_cls = DynamicOperandFPR
 
                 operand = dynamic_cls(name=operand)
+                operands.append(operand)
 
-            operands.append(operand)
-
-        self.__operands = operands
-
-        return super().__init__()
-
-    def __repr__(self):
-        return self.__operands.__repr__()
-
-    def __iter__(self):
-        yield from self.__operands
+        return super().__new__(cls, operands)
 
     def __contains__(self, key):
         return self.__getitem__(key) is not None
 
     def __getitem__(self, key):
-        for operand in self.__operands:
+        for operand in self:
             if operand.name == key:
                 return operand
 
@@ -589,13 +610,13 @@ class Operands:
     @property
     def dynamic(self):
         for operand in self:
-            if isinstance(operand, self.__class__.DynamicOperand):
+            if isinstance(operand, DynamicOperand):
                 yield operand
 
     @property
     def static(self):
         for operand in self:
-            if isinstance(operand, self.__class__.StaticOperand):
+            if isinstance(operand, StaticOperand):
                 yield operand
 
 
@@ -770,17 +791,28 @@ class WordInstruction(Instruction):
         return "".join(map(str, bits))
 
     def spec(self, record):
+        immediate = ""
         dynamic_operands = []
         for operand in record.operands.dynamic:
-            dynamic_operands.append(operand.name)
+            name = operand.name
+            if immediate:
+                name = f"{immediate}({name})"
+                immediate = ""
+            if isinstance(operand, ImmediateOperand):
+                immediate = operand.name
+            if not immediate:
+                dynamic_operands.append(name)
+
         static_operands = []
         for operand in record.operands.static:
             static_operands.append(f"{operand.name}={operand.value}")
+
         operands = ""
         if dynamic_operands:
             operands += f" {','.join(dynamic_operands)}"
         if static_operands:
             operands += f" ({' '.join(static_operands)})"
+
         return f"{record.name}{operands}"
 
     def opcode(self, record):
@@ -1226,9 +1258,12 @@ class SVP64Instruction(PrefixedInstruction):
 
 
 def parse(stream, factory):
+    def match(entry):
+        return ("TODO" not in frozenset(entry.values()))
+
     lines = filter(lambda line: not line.strip().startswith("#"), stream)
     entries = _csv.DictReader(lines)
-    entries = filter(lambda entry: "TODO" not in frozenset(entry.values()), entries)
+    entries = filter(match, entries)
     return tuple(map(factory, entries))
 
 
@@ -1287,7 +1322,8 @@ class PPCDatabase:
                     section.Mode.INTEGER: IntegerOpcode,
                     section.Mode.PATTERN: PatternOpcode,
                 }[section.mode]
-                factory = _functools.partial(PPCRecord.CSV, opcode_cls=opcode_cls)
+                factory = _functools.partial(
+                    PPCRecord.CSV, opcode_cls=opcode_cls)
                 with open(path, "r", encoding="UTF-8") as stream:
                     for insn in parse(stream, factory):
                         records[section][insn.comment].add(insn)