power_insn: refactor and fix RM mappings
[openpower-isa.git] / src / openpower / decoder / power_insn.py
index 5a85ecdee1e5b9c1cee11a8d9eadf5a895fec443..bfaf2fa751216c70b5f4ad9942d14365e8d0cfe1 100644 (file)
@@ -776,7 +776,7 @@ class TargetAddrOperandBD(TargetAddrOperand):
             verbosity=verbosity, indent=indent)
 
 
-class DOperandDX(DynamicOperand):
+class DOperandDX(SignedOperand):
     def span(self, record):
         operands = map(DynamicOperand, ("d0", "d1", "d2"))
         spans = map(lambda operand: operand.span(record=record), operands)
@@ -862,10 +862,10 @@ class Operands(tuple):
                 if immediate is not None:
                     operands.append(ImmediateOperand(name=immediate))
 
-                if insn in custom_insns and operand in custom_insns[insn]:
-                    dynamic_cls = custom_insns[insn][operand]
                 if operand in custom_fields:
                     dynamic_cls = custom_fields[operand]
+                if insn in custom_insns and operand in custom_insns[insn]:
+                    dynamic_cls = custom_insns[insn][operand]
 
                 if operand in _RegType.__members__:
                     regtype = _RegType[operand]
@@ -1058,6 +1058,16 @@ class Instruction(_Mapping):
     def __hash__(self):
         return hash(int(self))
 
+    def __getitem__(self, key):
+        return self.storage.__getitem__(key)
+
+    def __setitem__(self, key, value):
+        return self.storage.__setitem__(key, value)
+
+    def bytes(self, byteorder="little"):
+        nr_bytes = (self.storage.bits // 8)
+        return int(self).to_bytes(nr_bytes, byteorder=byteorder)
+
     def record(self, db):
         record = db[self]
         if record is None:
@@ -1202,7 +1212,7 @@ class PrefixedInstruction(Instruction):
         (prefix, suffix) = map(transform, (prefix, suffix))
         value = _selectconcat(prefix, suffix)
 
-        return super().integer(value=value)
+        return super().integer(bits=64, value=value)
 
 
 class Mode(_Mapping):
@@ -1268,67 +1278,75 @@ class BaseRM(_Mapping):
     extra2: Extra2.remap(range(10, 19))
     extra3: Extra3.remap(range(10, 19))
 
+    def disassemble(self, verbosity=Verbosity.NORMAL):
+        if verbosity >= Verbosity.VERBOSE:
+            indent = (" " * 4)
+            for (name, value, members) in self.traverse(path="RM"):
+                yield f"{name}"
+                yield f"{indent}{int(value):0{value.bits}b}"
+                yield f"{indent}{', '.join(map(str, members))}"
+
 
 class NormalRM(BaseRM):
     class simple(BaseRM):
-        """simple mode"""
+        """normal: simple mode"""
         dz: BaseRM.mode[3]
         sz: BaseRM.mode[4]
 
-    class smr(Mode):
-        """scalar reduce mode (mapreduce), SUBVL=1"""
+    class smr(BaseRM):
+        """normal: scalar reduce mode (mapreduce), SUBVL=1"""
         RG: BaseRM.mode[4]
 
-    class pmr(Mode):
-        """parallel reduce mode (mapreduce), SUBVL=1"""
+    class pmr(BaseRM):
+        """normal: parallel reduce mode (mapreduce), SUBVL=1"""
         pass
 
-    class svmr(Mode):
-        """subvector reduce mode, SUBVL>1"""
+    class svmr(BaseRM):
+        """normal: subvector reduce mode, SUBVL>1"""
         SVM: BaseRM.mode[3]
 
-    class pu(Mode):
-        """Pack/Unpack mode, SUBVL>1"""
+    class pu(BaseRM):
+        """normal: Pack/Unpack mode, SUBVL>1"""
         SVM: BaseRM.mode[3]
 
-    class ffrc1(Mode):
-        """Rc=1: ffirst CR sel"""
+    class ffrc1(BaseRM):
+        """normal: Rc=1: ffirst CR sel"""
         inv: BaseRM.mode[2]
         CR: BaseRM.mode[3, 4]
 
-    class ffrc0(Mode):
-        """Rc=0: ffirst z/nonz"""
+    class ffrc0(BaseRM):
+        """normal: Rc=0: ffirst z/nonz"""
         inv: BaseRM.mode[2]
         VLi: BaseRM.mode[3]
         RC1: BaseRM.mode[4]
 
-    class sat(Mode):
-        """sat mode: N=0/1 u/s, SUBVL=1"""
+    class sat(BaseRM):
+        """normal: sat mode: N=0/1 u/s, SUBVL=1"""
         N: BaseRM.mode[2]
         dz: BaseRM.mode[3]
         sz: BaseRM.mode[4]
 
-    class satx(Mode):
-        """sat mode: N=0/1 u/s, SUBVL>1"""
+    class satx(BaseRM):
+        """normal: sat mode: N=0/1 u/s, SUBVL>1"""
         N: BaseRM.mode[2]
         zz: BaseRM.mode[3]
         dz: BaseRM.mode[3]
         sz: BaseRM.mode[3]
 
-    class satpu(Mode):
-        """Pack/Unpack sat mode: N=0/1 u/s, SUBVL>1"""
+    class satpu(BaseRM):
+        """normal: Pack/Unpack sat mode: N=0/1 u/s, SUBVL>1"""
         N: BaseRM.mode[2]
         zz: BaseRM.mode[3]
         dz: BaseRM.mode[3]
         sz: BaseRM.mode[3]
 
-    class prrc1(Mode):
-        """Rc=1: pred-result CR sel"""
+    class prrc1(BaseRM):
+        """normal: Rc=1: pred-result CR sel"""
         inv: BaseRM.mode[2]
         CR: BaseRM.mode[3, 4]
 
-    class prrc0(Mode):
-        """Rc=0: pred-result z/nonz"""
+    class prrc0(BaseRM):
+        """normal: Rc=0: pred-result z/nonz"""
         inv: BaseRM.mode[2]
         zz: BaseRM.mode[3]
         RC1: BaseRM.mode[4]
@@ -1350,46 +1368,46 @@ class NormalRM(BaseRM):
 
 
 class LDSTImmRM(BaseRM):
-    class simple(Mode):
-        """simple mode"""
+    class simple(BaseRM):
+        """ld/st immediate: simple mode"""
         zz: BaseRM.mode[3]
         els: BaseRM.mode[4]
         dz: BaseRM.mode[3]
         sz: BaseRM.mode[3]
 
-    class spu(Mode):
-        """Structured Pack/Unpack"""
+    class spu(BaseRM):
+        """ld/st immediate: Structured Pack/Unpack"""
         zz: BaseRM.mode[3]
         els: BaseRM.mode[4]
         dz: BaseRM.mode[3]
         sz: BaseRM.mode[3]
 
-    class ffrc1(Mode):
-        """Rc=1: ffirst CR sel"""
+    class ffrc1(BaseRM):
+        """ld/st immediate: Rc=1: ffirst CR sel"""
         inv: BaseRM.mode[2]
         CR: BaseRM.mode[3, 4]
 
-    class ffrc0(Mode):
-        """Rc=0: ffirst z/nonz"""
+    class ffrc0(BaseRM):
+        """ld/st immediate: Rc=0: ffirst z/nonz"""
         inv: BaseRM.mode[2]
         els: BaseRM.mode[3]
         RC1: BaseRM.mode[4]
 
-    class sat(Mode):
-        """sat mode: N=0/1 u/s"""
+    class sat(BaseRM):
+        """ld/st immediate: sat mode: N=0/1 u/s"""
         N: BaseRM.mode[2]
         zz: BaseRM.mode[3]
         els: BaseRM.mode[4]
         dz: BaseRM.mode[3]
         sz: BaseRM.mode[3]
 
-    class prrc1(Mode):
-        """Rc=1: pred-result CR sel"""
+    class prrc1(BaseRM):
+        """ld/st immediate: Rc=1: pred-result CR sel"""
         inv: BaseRM.mode[2]
         CR: BaseRM.mode[3, 4]
 
-    class prrc0(Mode):
-        """Rc=0: pred-result z/nonz"""
+    class prrc0(BaseRM):
+        """ld/st immediate: Rc=0: pred-result z/nonz"""
         inv: BaseRM.mode[2]
         els: BaseRM.mode[3]
         RC1: BaseRM.mode[4]
@@ -1404,31 +1422,31 @@ class LDSTImmRM(BaseRM):
 
 
 class LDSTIdxRM(BaseRM):
-    class simple(Mode):
-        """simple mode"""
+    class simple(BaseRM):
+        """ld/st index: simple mode"""
         SEA: BaseRM.mode[2]
         sz: BaseRM.mode[3]
         dz: BaseRM.mode[3]
 
-    class stride(Mode):
-        """strided (scalar only source)"""
+    class stride(BaseRM):
+        """ld/st index: strided (scalar only source)"""
         SEA: BaseRM.mode[2]
         dz: BaseRM.mode[3]
         sz: BaseRM.mode[4]
 
-    class sat(Mode):
-        """sat mode: N=0/1 u/s"""
+    class sat(BaseRM):
+        """ld/st index: sat mode: N=0/1 u/s"""
         N: BaseRM.mode[2]
         dz: BaseRM.mode[3]
         sz: BaseRM.mode[4]
 
-    class prrc1(Mode):
-        """Rc=1: pred-result CR sel"""
+    class prrc1(BaseRM):
+        """ld/st index: Rc=1: pred-result CR sel"""
         inv: BaseRM.mode[2]
         CR: BaseRM.mode[3, 4]
 
-    class prrc0(Mode):
-        """Rc=0: pred-result z/nonz"""
+    class prrc0(BaseRM):
+        """ld/st index: Rc=0: pred-result z/nonz"""
         inv: BaseRM.mode[2]
         zz: BaseRM.mode[3]
         RC1: BaseRM.mode[4]
@@ -1444,20 +1462,20 @@ class LDSTIdxRM(BaseRM):
 
 class CROpRM(BaseRM):
     class simple(BaseRM):
-        """simple mode"""
+        """cr_op: simple mode"""
         sz: BaseRM[6]
         SNZ: BaseRM[7]
         RG: BaseRM[20]
         dz: BaseRM[22]
 
     class smr(BaseRM):
-        """scalar reduce mode (mapreduce), SUBVL=1"""
+        """cr_op: scalar reduce mode (mapreduce), SUBVL=1"""
         sz: BaseRM[6]
         SNZ: BaseRM[7]
         RG: BaseRM[20]
 
     class svmr(BaseRM):
-        """subvector reduce mode, SUBVL>1"""
+        """cr_op: subvector reduce mode, SUBVL>1"""
         zz: BaseRM[6]
         SNZ: BaseRM[7]
         RG: BaseRM[20]
@@ -1466,7 +1484,7 @@ class CROpRM(BaseRM):
         sz: BaseRM[6]
 
     class reserved(BaseRM):
-        """reserved"""
+        """cr_op: reserved"""
         zz: BaseRM[6]
         SNZ: BaseRM[7]
         RG: BaseRM[20]
@@ -1474,7 +1492,7 @@ class CROpRM(BaseRM):
         sz: BaseRM[6]
 
     class ff3(BaseRM):
-        """ffirst 3-bit mode"""
+        """cr_op: ffirst 3-bit mode"""
         zz: BaseRM[6]
         SNZ: BaseRM[7]
         VLI: BaseRM[20]
@@ -1484,7 +1502,7 @@ class CROpRM(BaseRM):
         sz: BaseRM[6]
 
     class ff5(BaseRM):
-        """ffirst 5-bit mode"""
+        """cr_op: ffirst 5-bit mode"""
         zz: BaseRM[6]
         SNZ: BaseRM[7]
         VLI: BaseRM[20]
@@ -1512,20 +1530,20 @@ class BranchBaseRM(BaseRM):
 
 class BranchRM(BranchBaseRM):
     class simple(BranchBaseRM):
-        """simple mode"""
+        """branch: simple mode"""
         pass
 
     class vls(BranchBaseRM):
-        """VLSET mode"""
+        """branch: VLSET mode"""
         VSb: BaseRM[7]
         VLI: BaseRM[21]
 
     class ctr(BranchBaseRM):
-        """CTR-test mode"""
+        """branch: CTR-test mode"""
         CTi: BaseRM[6]
 
     class ctrvls(vls, ctr):
-        """CTR-test+VLSET mode"""
+        """branch: CTR-test+VLSET mode"""
         pass
 
 
@@ -1535,39 +1553,8 @@ class RM(BaseRM):
     ldst_idx: LDSTIdxRM
     cr_op: CROpRM
 
-
-class SVP64Instruction(PrefixedInstruction):
-    """SVP64 instruction: https://libre-soc.org/openpower/sv/svp64/"""
-    class Prefix(PrefixedInstruction.Prefix):
-        id: _Field = (7, 9)
-        rm: RM.remap((6, 8) + tuple(range(10, 32)))
-
-    prefix: Prefix
-
-    def record(self, db):
-        record = db[self.suffix]
-        if record is None:
-            raise KeyError(self)
-        return record
-
-    @property
-    def binary(self):
-        bits = []
-        for idx in range(64):
-            bit = int(self[idx])
-            bits.append(bit)
-        return "".join(map(str, bits))
-
-    def rm(self, db):
-        record = self.record(db=db)
-
-        Rc = False
-        if record.mdwn.operands["Rc"] is not None:
-            Rc = bool(self[record.fields["Rc"]])
-
-        record = self.record(db=db)
-        subvl = self.prefix.rm.subvl
-        rm = self.prefix.rm
+    def select(self, record, Rc):
+        rm = self
 
         if record.svp64.mode is _SVMode.NORMAL:
             rm = rm.normal
@@ -1575,7 +1562,7 @@ class SVP64Instruction(PrefixedInstruction):
                 if rm.mode[2] == 0b0:
                     rm = rm.simple
                 else:
-                    if subvl == 0b00:
+                    if self.subvl == 0b00:
                         if rm.mode[3] == 0b0:
                             rm = rm.smr
                         else:
@@ -1591,7 +1578,7 @@ class SVP64Instruction(PrefixedInstruction):
                 else:
                     rm = rm.ffrc0
             elif rm.mode[0:2] == 0b10:
-                if subvl == 0b00:
+                if self.subvl == 0b00:
                     rm = rm.sat
                 else:
                     if rm.mode[4]:
@@ -1644,7 +1631,7 @@ class SVP64Instruction(PrefixedInstruction):
                 if rm[21] == 0b0:
                     rm = rm.simple
                 else:
-                    if subvl == 0:
+                    if self.subvl == 0:
                         rm = rm.smr
                     else:
                         if rm[23] == 0b0:
@@ -1678,50 +1665,33 @@ class SVP64Instruction(PrefixedInstruction):
                 else:
                     rm = rm.ctrvls
 
-        else:
+        if rm.__class__ is self.__class__:
             raise ValueError(self)
 
-        table = {
-            NormalRM.simple: "normal: simple",
-            NormalRM.smr: "normal: smr",
-            NormalRM.pmr: "normal: pmr",
-            NormalRM.svmr: "normal: svmr",
-            NormalRM.pu: "normal: pu",
-            NormalRM.ffrc1: "normal: ffrc1",
-            NormalRM.ffrc0: "normal: ffrc0",
-            NormalRM.sat: "normal: sat",
-            NormalRM.satx: "normal: satx",
-            NormalRM.satpu: "normal: satpu",
-            NormalRM.prrc1: "normal: prrc1",
-            NormalRM.prrc0: "normal: prrc0",
-            LDSTImmRM.simple: "ld/st imm: simple",
-            LDSTImmRM.spu: "ld/st imm: spu",
-            LDSTImmRM.ffrc1: "ld/st imm: ffrc1",
-            LDSTImmRM.ffrc0: "ld/st imm: ffrc0",
-            LDSTImmRM.sat: "ld/st imm: sat",
-            LDSTImmRM.prrc1: "ld/st imm: prrc1",
-            LDSTImmRM.prrc0: "ld/st imm: prrc0",
-            LDSTIdxRM.simple: "ld/st idx: simple",
-            LDSTIdxRM.stride: "ld/st idx: stride",
-            LDSTIdxRM.sat: "ld/st idx: sat",
-            LDSTIdxRM.prrc1: "ld/st idx: prrc1",
-            LDSTIdxRM.prrc0: "ld/st idx: prrc0",
-            CROpRM.simple: "simple mode",
-            CROpRM.smr: "scalar reduce mode (mapreduce), SUBVL=1",
-            CROpRM.svmr: "subvector reduce mode, SUBVL>1",
-            CROpRM.reserved: "reserved",
-            CROpRM.ff3: "ffirst 3-bit mode",
-            CROpRM.ff5: "ffirst 5-bit mode",
-            BranchRM.simple: "simple mode",
-            BranchRM.vls: "VLSET mode",
-            BranchRM.ctr: "CTR-test mode",
-            BranchRM.ctrvls: "CTR-test+VLSET mode",
-        }
-        for (cls, desc) in table.items():
-            if isinstance(rm, cls):
-                return (rm, desc)
+        return rm
 
-        raise ValueError(self)
+
+class SVP64Instruction(PrefixedInstruction):
+    """SVP64 instruction: https://libre-soc.org/openpower/sv/svp64/"""
+    class Prefix(PrefixedInstruction.Prefix):
+        id: _Field = (7, 9)
+        rm: RM.remap((6, 8) + tuple(range(10, 32)))
+
+    prefix: Prefix
+
+    def record(self, db):
+        record = db[self.suffix]
+        if record is None:
+            raise KeyError(self)
+        return record
+
+    @property
+    def binary(self):
+        bits = []
+        for idx in range(64):
+            bit = int(self[idx])
+            bits.append(bit)
+        return "".join(map(str, bits))
 
     def disassemble(self, db,
             byteorder="little",
@@ -1734,9 +1704,9 @@ class SVP64Instruction(PrefixedInstruction):
                 blob = " ".join(map(lambda byte: f"{byte:02x}", blob))
                 return f"{blob}    "
 
+        record = self.record(db=db)
         blob_prefix = blob(int(self.prefix))
         blob_suffix = blob(int(self.suffix))
-        record = db[self]
         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}"
@@ -1751,12 +1721,16 @@ class SVP64Instruction(PrefixedInstruction):
         if blob_suffix:
             yield f"{blob_suffix}"
 
-        (rm, rm_desc) = self.rm(db=db)
+        Rc = False
+        if record.mdwn.operands["Rc"] is not None:
+            Rc = bool(self.suffix[record.fields["Rc"]])
 
+        rm = self.prefix.rm.select(record=record, Rc=Rc)
         if verbosity >= Verbosity.VERBOSE:
             indent = (" " * 4)
             binary = self.binary
             spec = self.spec(db=db, prefix="sv.")
+
             yield f"{indent}spec"
             yield f"{indent}{indent}{spec}"
             yield f"{indent}pcode"
@@ -1777,9 +1751,10 @@ class SVP64Instruction(PrefixedInstruction):
             for operand in record.mdwn.operands:
                 yield from operand.disassemble(insn=self, record=record,
                     verbosity=verbosity, indent=indent)
-
             yield f"{indent}RM"
-            yield f"{indent}{indent}{rm_desc}"
+            yield f"{indent}{indent}{rm.__doc__}"
+            for line in rm.disassemble(verbosity=verbosity):
+                yield f"{indent}{indent}{line}"
             yield ""
 
 
@@ -1813,6 +1788,9 @@ class MarkdownDatabase:
     def __iter__(self):
         yield from self.__db.items()
 
+    def __contains__(self, key):
+        return self.__db.__contains__(key)
+
     def __getitem__(self, key):
         return self.__db.__getitem__(key)
 
@@ -1858,63 +1836,64 @@ class PPCDatabase:
                     for insn in parse(stream, factory):
                         records[section][insn.comment].add(insn)
 
-        db = dd(set)
+        sections = dd(set)
         for (section, group) in records.items():
             for records in group.values():
-                db[section].add(PPCMultiRecord(records))
+                sections[section].add(PPCMultiRecord(records))
+
+        db = {}
+        for (section, records) in sections.items():
+            for record in records:
+                def exact_match(names):
+                    for name in names:
+                        if name in mdwndb:
+                            yield name
+
+                def Rc_match(names):
+                    for name in names:
+                        if f"{name}." in mdwndb:
+                            yield f"{name}."
+                        yield name
+
+                def LK_match(names):
+                    if "lk" not in record.flags:
+                        yield from names
+                        return
+
+                    for name in names:
+                        if f"{name}l" in mdwndb:
+                            yield f"{name}l"
+                        yield name
+
+                def AA_match(names):
+                    if record.intop not in {_MicrOp.OP_B, _MicrOp.OP_BC}:
+                        yield from names
+                        return
+
+                    for name in names:
+                        operands = mdwndb[name].operands["AA"]
+                        if ((operands is not None) and
+                                (f"{name}a" in mdwndb)):
+                            yield f"{name}a"
+                        yield name
+
+                def reductor(names, match):
+                    return match(names)
+
+                matches = (exact_match, Rc_match, LK_match, AA_match)
+
+                names = _functools.reduce(reductor, matches, record.names)
+                for name in names:
+                    db[name] = (section, record)
 
         self.__db = db
         self.__mdwndb = mdwndb
 
         return super().__init__()
 
+    @_functools.lru_cache(maxsize=512, typed=False)
     def __getitem__(self, key):
-        def exact_match(key, record):
-            return (key in record.names)
-
-        def Rc_match(key, record):
-            if not key.endswith("."):
-                return False
-
-            if record.Rc is _RCOE.NONE:
-                return False
-
-            return exact_match(key[:-1], record)
-
-        def LK_match(key, record):
-            if not key.endswith("l"):
-                return False
-
-            if "lk" not in record.flags:
-                return False
-
-            return exact_match(key[:-1], record)
-
-        def AA_match(key, record):
-            if not key.endswith("a"):
-                return False
-
-            if record.intop not in {_MicrOp.OP_B, _MicrOp.OP_BC}:
-                return False
-
-            if self.__mdwndb[key].operands["AA"] is None:
-                return False
-
-            return (exact_match(key[:-1], record) or
-                LK_match(key[:-1], record))
-
-        for (section, records) in self.__db.items():
-            for record in records:
-                if exact_match(key, record):
-                    return (section, record)
-
-            for record in records:
-                if (Rc_match(key, record) or
-                        LK_match(key, record) or
-                        AA_match(key, record)):
-                    return (section, record)
-
-        return (None, None)
+        return self.__db.get(key, (None, None))
 
 
 class SVP64Database: