move ffadds to not conflict with fptrans -- makes space for min/max/fmod/remainder ops
[openpower-isa.git] / src / openpower / decoder / power_insn.py
index b3d90517ef1aae0fa0392badac15be5f2b5b81a9..2c28fc9e466df07d88201c29097a28bc20d5b754 100644 (file)
@@ -4,6 +4,7 @@ import dataclasses as _dataclasses
 import enum as _enum
 import functools as _functools
 import os as _os
+import operator as _operator
 import pathlib as _pathlib
 import re as _re
 
@@ -46,6 +47,18 @@ from openpower.decoder.power_fields import (
 from openpower.decoder.pseudo.pagereader import ISA as _ISA
 
 
+@_functools.total_ordering
+class Verbosity(_enum.Enum):
+    SHORT = _enum.auto()
+    NORMAL = _enum.auto()
+    VERBOSE = _enum.auto()
+
+    def __lt__(self, other):
+        if not isinstance(other, self.__class__):
+            return NotImplemented
+        return (self.value < other.value)
+
+
 def dataclass(cls, record, keymap=None, typemap=None):
     if keymap is None:
         keymap = {}
@@ -504,19 +517,21 @@ class Fields:
 class Operand:
     name: str
 
-    def disassemble(self, insn, record, verbose=False, indent=""):
+    def disassemble(self, insn, record,
+            verbosity=Verbosity.NORMAL, indent=""):
         raise NotImplementedError
 
 
 @_dataclasses.dataclass(eq=True, frozen=True)
 class DynamicOperand(Operand):
-    def disassemble(self, insn, record, verbose=False, indent=""):
+    def disassemble(self, insn, record,
+            verbosity=Verbosity.NORMAL, indent=""):
         span = record.fields[self.name]
         if isinstance(insn, SVP64Instruction):
             span = tuple(map(lambda bit: (bit + 32), span))
         value = insn[span]
 
-        if verbose:
+        if verbosity >= Verbosity.VERBOSE:
             span = map(str, span)
             yield f"{indent}{self.name}"
             yield f"{indent}{indent}{int(value):0{value.bits}b}"
@@ -596,10 +611,11 @@ class DynamicOperandReg(DynamicOperand):
 
         return _SVExtra.NONE
 
-    def disassemble(self, insn, record, verbose=False, prefix="", indent=""):
+    def disassemble(self, insn, record,
+            verbosity=Verbosity.NORMAL, prefix="", indent=""):
         (vector, value, span) = self.spec(insn=insn, record=record)
 
-        if verbose:
+        if verbosity >= Verbosity.VERBOSE:
             yield f"{indent}{self.name}"
             yield f"{indent}{indent}{int(value):0{value.bits}b}"
             yield f"{indent}{indent}{', '.join(span)}"
@@ -610,6 +626,8 @@ class DynamicOperandReg(DynamicOperand):
                 else:
                     etype = repr(record.etype).lower()
                     yield f"{indent}{indent}{etype}{extra_idx!r}"
+                yield f"{indent}type"
+                yield f"{indent}{indent}{'vector' if vector else 'scalar'}"
         else:
             vector = "*" if vector else ""
             yield f"{vector}{prefix}{int(value)}"
@@ -624,13 +642,14 @@ class ImmediateOperand(DynamicOperand):
 class StaticOperand(Operand):
     value: int
 
-    def disassemble(self, insn, record, verbose=False, indent=""):
+    def disassemble(self, insn, record,
+            verbosity=Verbosity.NORMAL, indent=""):
         span = record.fields[self.name]
         if isinstance(insn, SVP64Instruction):
             span = tuple(map(lambda bit: (bit + 32), span))
         value = insn[span]
 
-        if verbose:
+        if verbosity >= Verbosity.VERBOSE:
             span = map(str, span)
             yield f"{indent}{self.name}"
             yield f"{indent}{indent}{int(value):0{value.bits}b}"
@@ -641,13 +660,14 @@ class StaticOperand(Operand):
 
 @_dataclasses.dataclass(eq=True, frozen=True)
 class DynamicOperandTargetAddr(DynamicOperandReg):
-    def disassemble(self, insn, record, field, verbose=False, indent=""):
+    def disassemble(self, insn, record, field,
+            verbosity=Verbosity.NORMAL, indent=""):
         span = record.fields[field]
         if isinstance(insn, SVP64Instruction):
             span = tuple(map(lambda bit: (bit + 32), span))
         value = insn[span]
 
-        if verbose:
+        if verbosity >= Verbosity.VERBOSE:
             span = tuple(map(str, span))
             yield f"{indent}{self.name}"
             yield f"{indent}{indent}{int(value):0{value.bits}b}00"
@@ -660,29 +680,39 @@ class DynamicOperandTargetAddr(DynamicOperandReg):
 
 @_dataclasses.dataclass(eq=True, frozen=True)
 class DynamicOperandTargetAddrLI(DynamicOperandTargetAddr):
-    def disassemble(self, insn, record, verbose=False, indent=""):
+    def disassemble(self, insn, record,
+            verbosity=Verbosity.NORMAL, indent=""):
         return super().disassemble(field="LI",
-            insn=insn, record=record, verbose=verbose, indent=indent)
+            insn=insn, record=record,
+            verbosity=verbosity, indent=indent)
 
 
 class DynamicOperandTargetAddrBD(DynamicOperandTargetAddr):
-    def disassemble(self, insn, record, verbose=False, indent=""):
+    def disassemble(self, insn, record,
+            verbosity=Verbosity.NORMAL, indent=""):
         return super().disassemble(field="BD",
-            insn=insn, record=record, verbose=verbose, indent=indent)
+            insn=insn, record=record,
+            verbosity=verbosity, indent=indent)
 
 
 @_dataclasses.dataclass(eq=True, frozen=True)
 class DynamicOperandGPR(DynamicOperandReg):
-    def disassemble(self, insn, record, verbose=False, indent=""):
-        yield from super().disassemble(prefix="r",
-            insn=insn, record=record, verbose=verbose, indent=indent)
+    def disassemble(self, insn, record,
+            verbosity=Verbosity.NORMAL, indent=""):
+        prefix = "" if (verbosity <= Verbosity.SHORT) else "r"
+        yield from super().disassemble(prefix=prefix,
+            insn=insn, record=record,
+            verbosity=verbosity, indent=indent)
 
 
 @_dataclasses.dataclass(eq=True, frozen=True)
 class DynamicOperandFPR(DynamicOperandReg):
-    def disassemble(self, insn, record, verbose=False, indent=""):
-        yield from super().disassemble(prefix="f",
-            insn=insn, record=record, verbose=verbose, indent=indent)
+    def disassemble(self, insn, record,
+            verbosity=Verbosity.NORMAL, indent=""):
+        prefix = "" if (verbosity <= Verbosity.SHORT) else "f"
+        yield from super().disassemble(prefix=prefix,
+            insn=insn, record=record,
+            verbosity=verbosity, indent=indent)
 
 
 class Operands(tuple):
@@ -869,7 +899,54 @@ class Instruction(_Mapping):
             raise KeyError(self)
         return record
 
-    def disassemble(self, db, byteorder="little", verbose=False):
+    def spec(self, db, prefix):
+        record = self.record(db=db)
+
+        dynamic_operands = tuple(map(_operator.itemgetter(0),
+            self.dynamic_operands(db=db)))
+
+        static_operands = []
+        for (name, value) in self.static_operands(db=db):
+            static_operands.append(f"{name}={value}")
+
+        operands = ""
+        if dynamic_operands:
+            operands += f" {','.join(dynamic_operands)}"
+        if static_operands:
+            operands += f" ({' '.join(static_operands)})"
+
+        return f"{prefix}{record.name}{operands}"
+
+    def dynamic_operands(self, db, verbosity=Verbosity.NORMAL):
+        record = self.record(db=db)
+
+        imm = False
+        imm_name = ""
+        imm_value = ""
+        for operand in record.operands.dynamic:
+            name = operand.name
+            dis = operand.disassemble(insn=self, record=record,
+                verbosity=min(verbosity, Verbosity.NORMAL))
+            value = " ".join(dis)
+            if imm:
+                name = f"{imm_name}({name})"
+                value = f"{imm_value}({value})"
+                imm = False
+            if isinstance(operand, ImmediateOperand):
+                imm_name = name
+                imm_value = value
+                imm = True
+            if not imm:
+                yield (name, value)
+
+    def static_operands(self, db):
+        record = self.record(db=db)
+        for operand in record.operands.static:
+            yield (operand.name, operand.value)
+
+    def disassemble(self, db,
+            byteorder="little",
+            verbosity=Verbosity.NORMAL):
         raise NotImplementedError
 
 
@@ -889,33 +966,6 @@ class WordInstruction(Instruction):
             bits.append(bit)
         return "".join(map(str, bits))
 
-    def spec(self, db):
-        record = self.record(db=db)
-
-        immediate = ""
-        dynamic_operands = []
-        for operand in record.operands.dynamic:
-            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, db):
         record = self.record(db=db)
         return f"0x{record.opcode.value:08x}"
@@ -924,33 +974,33 @@ class WordInstruction(Instruction):
         record = self.record(db=db)
         return f"0x{record.opcode.mask:08x}"
 
-    def disassemble(self, db, byteorder="little", verbose=False):
+    def disassemble(self, db,
+            byteorder="little",
+            verbosity=Verbosity.NORMAL):
         integer = int(self)
-        blob = integer.to_bytes(length=4, byteorder=byteorder)
-        blob = " ".join(map(lambda byte: f"{byte:02x}", blob))
+        if verbosity <= Verbosity.SHORT:
+            blob = ""
+        else:
+            blob = integer.to_bytes(length=4, byteorder=byteorder)
+            blob = " ".join(map(lambda byte: f"{byte:02x}", blob))
+            blob += "    "
 
         record = self.record(db=db)
         if record is None:
-            yield f"{blob}    .long 0x{integer:08x}"
+            yield f"{blob}.long 0x{integer:08x}"
             return
 
-        operands = []
-        for operand in record.operands.dynamic:
-            operand = " ".join(operand.disassemble(insn=self,
-                record=record, verbose=False))
-            operands.append(operand)
+        operands = tuple(map(_operator.itemgetter(1),
+            self.dynamic_operands(db=db, verbosity=verbosity)))
         if operands:
-            operands = ",".join(operands)
-            operands = f" {operands}"
+            yield f"{blob}{record.name} {','.join(operands)}"
         else:
-            operands = ""
-
-        yield f"{blob}    {record.name}{operands}"
+            yield f"{blob}{record.name}"
 
-        if verbose:
+        if verbosity >= Verbosity.VERBOSE:
             indent = (" " * 4)
             binary = self.binary
-            spec = self.spec(db=db)
+            spec = self.spec(db=db, prefix="")
             opcode = self.opcode(db=db)
             mask = self.mask(db=db)
             yield f"{indent}spec"
@@ -965,8 +1015,8 @@ class WordInstruction(Instruction):
             yield f"{indent}mask"
             yield f"{indent}{indent}{mask}"
             for operand in record.operands:
-                yield from operand.disassemble(insn=self,
-                        record=record, verbose=True, indent=indent)
+                yield from operand.disassemble(insn=self, record=record,
+                    verbosity=verbosity, indent=indent)
             yield ""
 
 
@@ -1257,9 +1307,6 @@ class SVP64Instruction(PrefixedInstruction):
             bits.append(bit)
         return "".join(map(str, bits))
 
-    def spec(self, db):
-        return f"sv.{self.suffix.spec(db=db)}"
-
     def opcode(self, db):
         return self.suffix.opcode(db=db)
 
@@ -1380,41 +1427,39 @@ class SVP64Instruction(PrefixedInstruction):
 
         raise ValueError(self)
 
-    def disassemble(self, db, byteorder="little", verbose=False):
-        integer_prefix = int(self.prefix)
-        blob_prefix = integer_prefix.to_bytes(length=4, byteorder=byteorder)
-        blob_prefix = " ".join(map(lambda byte: f"{byte:02x}", blob_prefix))
-
-        integer_suffix = int(self.suffix)
-        blob_suffix = integer_suffix.to_bytes(length=4, byteorder=byteorder)
-        blob_suffix = " ".join(map(lambda byte: f"{byte:02x}", blob_suffix))
+    def disassemble(self, db,
+            byteorder="little",
+            verbosity=Verbosity.NORMAL):
+        def blob(integer):
+            if verbosity <= Verbosity.SHORT:
+                return ""
+            else:
+                blob = integer.to_bytes(length=4, byteorder=byteorder)
+                blob = " ".join(map(lambda byte: f"{byte:02x}", blob))
+                return f"{blob}    "
 
+        blob_prefix = blob(int(self.prefix))
+        blob_suffix = blob(int(self.suffix))
         record = self.record(db=db)
         if record is None or record.svp64 is None:
-            yield f"{blob_prefix}    .long 0x{int(self.prefix):08x}"
-            yield f"{blob_suffix}    .long 0x{int(self.suffix):08x}"
+            yield f"{blob_prefix}.long 0x{int(self.prefix):08x}"
+            yield f"{blob_suffix}.long 0x{int(self.suffix):08x}"
             return
 
-        operands = []
-        for operand in record.operands.dynamic:
-            operand = " ".join(operand.disassemble(insn=self,
-                record=record, verbose=False))
-            operands.append(operand)
+        operands = tuple(map(_operator.itemgetter(1),
+            self.dynamic_operands(db=db, verbosity=verbosity)))
         if operands:
-            operands = ",".join(operands)
-            operands = f" {operands}"
+            yield f"{blob_prefix}sv.{record.name} {','.join(operands)}"
         else:
-            operands = ""
-
-        yield f"{blob_prefix}    sv.{record.name}{operands}"
+            yield f"{blob_prefix}{record.name}"
         yield f"{blob_suffix}"
 
         (mode, mode_desc) = self.mode(db=db)
 
-        if verbose:
+        if verbosity >= Verbosity.VERBOSE:
             indent = (" " * 4)
             binary = self.binary
-            spec = self.spec(db=db)
+            spec = self.spec(db=db, prefix="sv.")
             opcode = self.opcode(db=db)
             mask = self.mask(db=db)
             yield f"{indent}spec"
@@ -1433,8 +1478,8 @@ class SVP64Instruction(PrefixedInstruction):
             yield f"{indent}mask"
             yield f"{indent}{indent}{mask}"
             for operand in record.operands:
-                yield from operand.disassemble(insn=self,
-                        record=record, verbose=True, indent=indent)
+                yield from operand.disassemble(insn=self, record=record,
+                    verbosity=verbosity, indent=indent)
 
             yield f"{indent}mode"
             yield f"{indent}{indent}{mode_desc}"