sigh, check length of string returned, if non-zero add space
[openpower-isa.git] / src / openpower / decoder / power_insn.py
index e258bb1f2406478b46eedef7238ea2b68160fca0..ec70efce65dae6ebe16af3c4478b1976734a3e9c 100644 (file)
@@ -1276,13 +1276,11 @@ class BaseRM(_Mapping):
     subvl: _Field = range(8, 10)
     mode: Mode.remap(range(19, 24))
     smask: _Field = range(16, 19)
-
     extra: Extra.remap(range(10, 19))
     extra2: Extra2.remap(range(10, 19))
     extra3: Extra3.remap(range(10, 19))
 
-    @property
-    def specifiers(self):
+    def specifiers(self, record):
         subvl = int(self.subvl)
         if subvl > 0:
             yield {
@@ -1300,26 +1298,64 @@ class BaseRM(_Mapping):
                 yield f"{indent}{', '.join(map(str, members))}"
 
 
+# ********************
+# Normal mode
+# https://libre-soc.org/openpower/sv/normal/
+
 class NormalLDSTBaseRM(BaseRM):
-    @property
-    def specifiers(self):
-        width = {
+    def specifiers(self, record):
+        widths = {
             0b11: "8",
             0b10: "16",
             0b01: "32",
         }
+        predicates = {
+            # integer
+            (0, 0b001): "1<<r3",
+            (0, 0b010): "r3",
+            (0, 0b011): "~r3",
+            (0, 0b100): "r10",
+            (0, 0b101): "~r10",
+            (0, 0b110): "r30",
+            (0, 0b111): "~r30",
+            # CRs
+            (1, 0b000): "lt",
+            (1, 0b001): "ge",
+            (1, 0b010): "gt",
+            (1, 0b011): "le",
+            (1, 0b100): "eq",
+            (1, 0b101): "ne",
+            (1, 0b110): "so",
+            (1, 0b111): "ns",
+        }
+
+        mmode = int(self.mmode)
+        mask = int(self.mask)
+        if record.svp64.ptype is _SVPtype.P2:
+            (smask, dmask) = (int(self.smask), mask)
+        else:
+            (smask, dmask) = (mask, mask)
+        if all((smask, dmask)) and (smask == dmask):
+            yield f"m={predicates[(mmode, smask)]}"
+        else:
+            sw = predicates.get((mmode, smask))
+            dw = predicates.get((mmode, dmask))
+            if sw:
+                yield f"sm={sw}"
+            if dw:
+                yield f"dm={dw}"
 
         dw = int(self.elwidth)
         sw = int(self.ewsrc)
-        if all((dw, sw)) and dw == sw:
-            yield f"w={width[dw]}"
+        if all((dw, sw)) and (dw == sw):
+            yield f"w={widths[dw]}"
         else:
             if dw != 0b00:
-                yield f"dw={width[dw]}"
+                yield f"dw={widths[dw]}"
             if sw != 0b00:
-                yield f"sw={width[sw]}"
+                yield f"sw={widths[sw]}"
 
-        yield from super().specifiers
+        yield from super().specifiers(record=record)
 
 
 class NormalBaseRM(NormalLDSTBaseRM):
@@ -1331,30 +1367,23 @@ class NormalSimpleRM(NormalBaseRM):
     dz: BaseRM.mode[3]
     sz: BaseRM.mode[4]
 
-    @property
-    def specifiers(self):
+    def specifiers(self, record):
         if self.dz:
             yield f"dz"
         if self.sz:
             yield f"sz"
-        yield from super().specifiers
+        yield from super().specifiers(record=record)
 
 
 class NormalScalarReduceRM(NormalBaseRM):
     """normal: scalar reduce mode (mapreduce), SUBVL=1"""
     RG: BaseRM.mode[4]
 
+    def specifiers(self, record):
+        if self.RG:
+            yield "mrr"
 
-class NormalSubvectorReduceRM(NormalBaseRM):
-    """normal: subvector reduce mode, SUBVL>1"""
-    SVM: BaseRM.mode[3]
-
-    @property
-    def specifiers(self):
-        if self.SVM:
-            yield "svm"
-
-        yield from super().specifiers
+        yield from super().specifiers(record=record)
 
 
 class NormalReservedRM(NormalBaseRM):
@@ -1374,6 +1403,13 @@ class NormalFailFirstRc0RM(NormalBaseRM):
     VLi: BaseRM.mode[3]
     RC1: BaseRM.mode[4]
 
+    def specifiers(self, record):
+        if self.RC1:
+            inv = "~" if self.inv else ""
+            yield f"ff={inv}RC1"
+
+        yield from super().specifiers(record=record)
+
 
 class NormalSaturationRM(NormalBaseRM):
     """normal: sat mode: N=0/1 u/s, SUBVL=1"""
@@ -1381,8 +1417,7 @@ class NormalSaturationRM(NormalBaseRM):
     dz: BaseRM.mode[3]
     sz: BaseRM.mode[4]
 
-    @property
-    def specifiers(self):
+    def specifiers(self, record):
         if self.dz:
             yield f"dz"
         if self.sz:
@@ -1391,25 +1426,8 @@ class NormalSaturationRM(NormalBaseRM):
             yield "sats"
         else:
             yield "satu"
-        yield from super().specifiers
 
-
-class NormalSaturationExtRM(NormalBaseRM):
-    """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]
-
-    @property
-    def specifiers(self):
-        if self.zz:
-            yield f"zz"
-        if self.N:
-            yield "sats"
-        else:
-            yield "satu"
-        yield from super().specifiers
+        yield from super().specifiers(record=record)
 
 
 class NormalPredResultRc1RM(NormalBaseRM):
@@ -1426,26 +1444,31 @@ class NormalPredResultRc0RM(NormalBaseRM):
     dz: BaseRM.mode[3]
     sz: BaseRM.mode[3]
 
-    @property
-    def specifiers(self):
+    def specifiers(self, record):
         if self.zz:
             yield f"zz"
-        yield from super().specifiers
+        if self.RC1:
+            inv = "~" if self.inv else ""
+            yield f"pr={inv}RC1"
+
+        yield from super().specifiers(record=record)
 
 
 class NormalRM(NormalBaseRM):
     simple: NormalSimpleRM
     smr: NormalScalarReduceRM
-    svmr: NormalSubvectorReduceRM
     reserved: NormalReservedRM
     ffrc1: NormalFailFirstRc1RM
     ffrc0: NormalFailFirstRc0RM
     sat: NormalSaturationRM
-    satx: NormalSaturationExtRM
     prrc1: NormalPredResultRc1RM
     prrc0: NormalPredResultRc0RM
 
 
+# ********************
+# LD/ST Immediate mode
+# https://libre-soc.org/openpower/sv/ldst/
+
 class LDSTImmBaseRM(NormalLDSTBaseRM):
     pass
 
@@ -1457,11 +1480,11 @@ class LDSTImmSimpleRM(LDSTImmBaseRM):
     dz: BaseRM.mode[3]
     sz: BaseRM.mode[3]
 
-    @property
-    def specifiers(self):
+    def specifiers(self, record):
         if self.zz:
             yield f"zz"
-        yield from super().specifiers
+
+        yield from super().specifiers(record=record)
 
 
 class LDSTImmReservedRM(LDSTImmBaseRM):
@@ -1481,6 +1504,12 @@ class LDSTImmFailFirstRc0RM(LDSTImmBaseRM):
     els: BaseRM.mode[3]
     RC1: BaseRM.mode[4]
 
+    def specifiers(self, record):
+        if self.RC1:
+            inv = "~" if self.inv else ""
+            yield f"ff={inv}RC1"
+
+        yield from super().specifiers(record=record)
 
 class LDSTImmSaturationRM(LDSTImmBaseRM):
     """ld/st immediate: sat mode: N=0/1 u/s"""
@@ -1490,15 +1519,15 @@ class LDSTImmSaturationRM(LDSTImmBaseRM):
     dz: BaseRM.mode[3]
     sz: BaseRM.mode[3]
 
-    @property
-    def specifiers(self):
+    def specifiers(self, record):
         if self.zz:
             yield f"zz"
         if self.N:
             yield "sats"
         else:
             yield "satu"
-        yield from super().specifiers
+
+        yield from super().specifiers(record=record)
 
 
 class LDSTImmPredResultRc1RM(LDSTImmBaseRM):
@@ -1513,6 +1542,12 @@ class LDSTImmPredResultRc0RM(LDSTImmBaseRM):
     els: BaseRM.mode[3]
     RC1: BaseRM.mode[4]
 
+    def specifiers(self, record):
+        if self.RC1:
+            inv = "~" if self.inv else ""
+            yield f"pr={inv}RC1"
+
+        yield from super().specifiers(record=record)
 
 class LDSTImmRM(LDSTImmBaseRM):
     simple: LDSTImmSimpleRM
@@ -1524,6 +1559,10 @@ class LDSTImmRM(LDSTImmBaseRM):
     prrc0: LDSTImmPredResultRc0RM
 
 
+# ********************
+# LD/ST Indexed mode
+# https://libre-soc.org/openpower/sv/ldst/
+
 class LDSTIdxBaseRM(NormalLDSTBaseRM):
     pass
 
@@ -1534,13 +1573,13 @@ class LDSTIdxSimpleRM(LDSTIdxBaseRM):
     sz: BaseRM.mode[3]
     dz: BaseRM.mode[3]
 
-    @property
-    def specifiers(self):
+    def specifiers(self, record):
         if self.dz:
             yield f"dz"
         if self.sz:
             yield f"sz"
-        yield from super().specifiers
+
+        yield from super().specifiers(record=record)
 
 
 class LDSTIdxStrideRM(LDSTIdxBaseRM):
@@ -1549,13 +1588,13 @@ class LDSTIdxStrideRM(LDSTIdxBaseRM):
     dz: BaseRM.mode[3]
     sz: BaseRM.mode[4]
 
-    @property
-    def specifiers(self):
+    def specifiers(self, record):
         if self.dz:
             yield f"dz"
         if self.sz:
             yield f"sz"
-        yield from super().specifiers
+
+        yield from super().specifiers(record=record)
 
 
 class LDSTIdxSaturationRM(LDSTIdxBaseRM):
@@ -1564,8 +1603,7 @@ class LDSTIdxSaturationRM(LDSTIdxBaseRM):
     dz: BaseRM.mode[3]
     sz: BaseRM.mode[4]
 
-    @property
-    def specifiers(self):
+    def specifiers(self, record):
         if self.dz:
             yield f"dz"
         if self.sz:
@@ -1574,7 +1612,8 @@ class LDSTIdxSaturationRM(LDSTIdxBaseRM):
             yield "sats"
         else:
             yield "satu"
-        yield from super().specifiers
+
+        yield from super().specifiers(record=record)
 
 
 class LDSTIdxPredResultRc1RM(LDSTIdxBaseRM):
@@ -1591,11 +1630,14 @@ class LDSTIdxPredResultRc0RM(LDSTIdxBaseRM):
     dz: BaseRM.mode[3]
     sz: BaseRM.mode[3]
 
-    @property
-    def specifiers(self):
+    def specifiers(self, record):
         if self.zz:
             yield f"zz"
-        yield from super().specifiers
+        if self.RC1:
+            inv = "~" if self.inv else ""
+            yield f"pr={inv}RC1"
+
+        yield from super().specifiers(record=record)
 
 
 class LDSTIdxRM(LDSTIdxBaseRM):
@@ -1606,56 +1648,47 @@ class LDSTIdxRM(LDSTIdxBaseRM):
     prrc0: LDSTIdxPredResultRc0RM
 
 
+
+# ********************
+# CR ops mode
+# https://libre-soc.org/openpower/sv/cr_ops/
+
 class CROpBaseRM(BaseRM):
     pass
 
 
 class CROpSimpleRM(CROpBaseRM):
     """cr_op: simple mode"""
-    sz: BaseRM[6]
     SNZ: BaseRM[7]
     RG: BaseRM[20]
+    sz: BaseRM[21]
     dz: BaseRM[22]
 
-    @property
-    def specifiers(self):
+    def specifiers(self, record):
         if self.dz:
             yield f"dz"
         if self.sz:
             yield f"sz"
-        yield from super().specifiers
+        if self.RG:
+            yield "mrr"
+
+        yield from super().specifiers(record=record)
 
 
 class CROpScalarReduceRM(CROpBaseRM):
     """cr_op: scalar reduce mode (mapreduce), SUBVL=1"""
-    sz: BaseRM[6]
     SNZ: BaseRM[7]
     RG: BaseRM[20]
+    sz: BaseRM[21]
+    dz: BaseRM[22]
 
-    @property
-    def specifiers(self):
+    def specifiers(self, record):
         if self.sz:
             yield f"sz"
-        yield from super().specifiers
-
-
-class CROpSubvectorReduceRM(CROpBaseRM):
-    """cr_op: subvector reduce mode, SUBVL>1"""
-    zz: BaseRM[6]
-    SNZ: BaseRM[7]
-    RG: BaseRM[20]
-    SVM: BaseRM[22]
-    dz: BaseRM[6]
-    sz: BaseRM[6]
-
-    @property
-    def specifiers(self):
-        if self.zz:
-            yield f"zz"
-        if self.SVM:
-            yield "svm"
+        if self.RG:
+            yield "mrr"
 
-        yield from super().specifiers
+        yield from super().specifiers(record=record)
 
 
 class CROpReservedRM(CROpBaseRM):
@@ -1663,31 +1696,31 @@ class CROpReservedRM(CROpBaseRM):
     zz: BaseRM[6]
     SNZ: BaseRM[7]
     RG: BaseRM[20]
-    dz: BaseRM[6]
     sz: BaseRM[6]
+    dz: BaseRM[6]
 
-    @property
-    def specifiers(self):
+    def specifiers(self, record):
         if self.zz:
             yield f"zz"
-        yield from super().specifiers
+        if self.RG:
+            yield "mrr"
+
+        yield from super().specifiers(record=record)
 
 
 class CROpFailFirst3RM(CROpBaseRM):
     """cr_op: ffirst 3-bit mode"""
-    zz: BaseRM[6]
     SNZ: BaseRM[7]
     VLI: BaseRM[20]
     inv: BaseRM[21]
     CR: BaseRM[22, 23]
-    dz: BaseRM[6]
-    sz: BaseRM[6]
+    sz: BaseRM[21]
+    dz: BaseRM[22]
 
-    @property
-    def specifiers(self):
+    def specifiers(self, record):
         if self.zz:
             yield f"zz"
-        yield from super().specifiers
+        yield from super().specifiers(record=record)
 
 
 class CROpFailFirst5RM(CROpBaseRM):
@@ -1698,24 +1731,27 @@ class CROpFailFirst5RM(CROpBaseRM):
     inv: BaseRM[21]
     dz: BaseRM[22]
 
-    @property
-    def specifiers(self):
+    def specifiers(self, record):
         if self.dz:
             yield f"dz"
         if self.sz:
             yield f"sz"
-        yield from super().specifiers
+        yield from super().specifiers(record=record)
 
 
 class CROpRM(CROpBaseRM):
     simple: CROpSimpleRM
     smr: CROpScalarReduceRM
-    svmr: CROpSubvectorReduceRM
     reserved: CROpReservedRM
     ff3: CROpFailFirst3RM
     ff5: CROpFailFirst5RM
 
 
+# ********************
+# Branches mode
+# https://libre-soc.org/openpower/sv/branches/
+
+
 class BranchBaseRM(BaseRM):
     ALL: BaseRM[4]
     SNZ: BaseRM[5]
@@ -1762,107 +1798,102 @@ class RM(BaseRM):
     def select(self, record, Rc):
         rm = self
 
+        # the idea behind these tables is that they are now literally
+        # in identical format to insndb.csv and minor_xx.csv and can
+        # be done precisely as that.  the only thing to watch out for
+        # is the insertion of Rc=1 as a "mask/value" bit and likewise
+        # regtype detection (3-bit BF/BFA, 5-bit BA/BB/BT) also inserted
+        # as the LSB.
+        table = None
         if record.svp64.mode is _SVMode.NORMAL:
+            # concatenate mode 5-bit with Rc (LSB) then do a mask/map search
+            #    mode  Rc  mask  Rc  member
+            table = (
+                (0b000000, 0b111000, "simple"), # simple     (no Rc)
+                (0b001000, 0b111000, "smr"),    # mapreduce  (no Rc)
+                (0b010000, 0b110001, "ffrc0"),  # ffirst,     Rc=0
+                (0b010001, 0b110001, "ffrc1"),  # ffirst,     Rc=1
+                (0b100000, 0b110000, "sat"),    # saturation (no Rc)
+                (0b110000, 0b110001, "prrc0"),  # predicate,  Rc=0
+                (0b110001, 0b110001, "prrc1"),  # predicate,  Rc=1
+            )
             rm = rm.normal
-            if rm.mode[0:2] == 0b00:
-                if rm.mode[2] == 0b0:
-                    rm = rm.simple
-                else:
-                    if self.subvl == 1:
-                        rm = rm.smr
-                    elif self.subvl > 1:
-                        rm = rm.svmr
-                    else:
-                        rm = rm.reserved
-            elif rm.mode[0:2] == 0b01:
-                if Rc:
-                    rm = rm.ffrc1
-                else:
-                    rm = rm.ffrc0
-            elif rm.mode[0:2] == 0b10:
-                if self.subvl == 0b00:
-                    rm = rm.sat
-                else:
-                    if rm.mode[4]:
-                        rm = rm.satx
-            elif rm.mode[0:2] == 0b11:
-                if Rc:
-                    rm = rm.prrc1
-                else:
-                    rm = rm.prrc0
+            search = ((int(rm.mode) << 1) | Rc)
 
         elif record.svp64.mode is _SVMode.LDST_IMM:
+            # concatenate mode 5-bit with Rc (LSB) then do a mask/map search
+            #    mode  Rc  mask  Rc  member
+            # ironically/coincidentally this table is identical to NORMAL
+            # mode except reserved in place of smr
+            table = (
+                (0b000000, 0b111000, "simple"),   # simple     (no Rc)
+                (0b001000, 0b111000, "reserved"), # rsvd       (no Rc)
+                (0b010000, 0b110001, "ffrc0"),    # ffirst,     Rc=0
+                (0b010001, 0b110001, "ffrc1"),    # ffirst,     Rc=1
+                (0b100000, 0b110000, "sat"),      # saturation (no Rc)
+                (0b110000, 0b110001, "prrc0"),    # predicate,  Rc=0
+                (0b110001, 0b110001, "prrc1"),    # predicate,  Rc=1
+            )
             rm = rm.ldst_imm
-            if rm.mode[0:2] == 0b00:
-                if rm.mode[2] == 0b0:
-                    rm = rm.simple
-                else:
-                    rm = rm.reserved
-            elif rm.mode[0:2] == 0b01:
-                if Rc:
-                    rm = rm.ffrc1
-                else:
-                    rm = rm.ffrc0
-            elif rm.mode[0:2] == 0b10:
-                rm = rm.sat
-            elif rm.mode[0:2] == 0b11:
-                if Rc:
-                    rm = rm.prrc1
-                else:
-                    rm = rm.prrc0
-
-        elif record.svp64.mode is _SVMode.LDST_IMM:
+            search = ((int(rm.mode) << 1) | Rc)
+
+        elif record.svp64.mode is _SVMode.LDST_IDX:
+            # concatenate mode 5-bit with Rc (LSB) then do a mask/map search
+            #    mode  Rc  mask  Rc  member
+            table = (
+                (0b000000, 0b111000, "simple"), # simple     (no Rc)
+                (0b010000, 0b110000, "stride"), # strided,   (no Rc)
+                (0b100000, 0b110000, "sat"),    # saturation (no Rc)
+                (0b110000, 0b110001, "prrc0"),  # predicate,  Rc=0
+                (0b110001, 0b110001, "prrc1"),  # predicate,  Rc=1
+            )
             rm = rm.ldst_idx
-            if rm.mode[0:2] == 0b00:
-                rm = rm.simple
-            elif rm.mode[0:2] == 0b01:
-                rm = rm.stride
-            elif rm.mode[0:2] == 0b10:
-                rm = rm.sat
-            elif rm.mode[0:2] == 0b11:
-                if Rc:
-                    rm = rm.prrc1
-                else:
-                    rm = rm.prrc0
+            search = ((int(rm.mode) << 1) | Rc)
 
         elif record.svp64.mode is _SVMode.CROP:
-            rm = rm.cr_op
-            if rm[19] == 0b0:
-                if rm[21] == 0b0:
-                    rm = rm.simple
-                else:
-                    if self.subvl == 1:
-                        rm = rm.smr
-                    elif self.subvl > 1:
-                        rm = rm.svmr
-                    else:
-                        rm = rm.reserved
+            # concatenate mode 5-bit with regtype (LSB) then do mask/map search
+            #    mode  3b  mask  3b  member
+            table = (
+                (0b000000, 0b111000, "simple"), # simple
+                (0b001000, 0b111000, "smr"),    # mapreduce
+                (0b100000, 0b100000, "ff5"),    # failfirst, 5-bit CR
+                (0b100001, 0b100001, "ff3"),    # failfirst, 3-bit CR
+            )
+            # determine CR type, 5-bit (BA/BB/BT) or 3-bit Field (BF/BFA)
+            regtype = None
+            for idx in range(0, 4):
+                for entry in record.svp64.extra[idx]:
+                    if entry.regtype is _SVExtraRegType.DST:
+                        if regtype is not None:
+                            raise ValueError(record.svp64)
+                        regtype = _RegType(entry.reg)
+            if regtype is _RegType.CR_REG:
+                regtype = 0 # 5-bit
+            elif regtype is _RegType.CR_BIT:
+                regtype = 1 # 3-bit
             else:
-                regtype = None
-                for idx in range(0, 4):
-                    for entry in record.svp64.extra[idx]:
-                        if entry.regtype is _SVExtraRegType.DST:
-                            if regtype is not None:
-                                raise ValueError(record.svp64)
-                            regtype = _RegType(entry.reg)
-                if regtype is _RegType.CR_REG:
-                    rm = rm.ff5
-                elif regtype is _RegType.CR_BIT:
-                    rm = rm.ff3
-                else:
-                    raise ValueError(record.svp64)
+                raise ValueError(record.svp64)
+            # finally provide info for search
+            rm = rm.cr_op
+            search = ((int(rm.mode) << 1) | (regtype or 0))
 
         elif record.svp64.mode is _SVMode.BRANCH:
-            if rm[19] == 0b0:
-                if rm[20] == 0b0:
-                    rm = rm.simple
-                else:
-                    rm = rm.vls
-            else:
-                if rm[20] == 0b0:
-                    rm = rm.ctr
-                else:
-                    rm = rm.ctrvls
+            # just mode 5-bit. could be reduced down to 2, oh well.
+            #         mode       mask   action(getattr)
+            table = [(0b00000, 0b11000, "simple"), # simple
+                     (0b01000, 0b11000, "vls"),    # VLset
+                     (0b10000, 0b11000, "ctr"),    # CTR mode
+                     (0b11000, 0b11000, "ctrvls"), # CTR+VLset mode
+                    ]
+            # slightly weird: doesn't have a 5-bit "mode" field like others
+            search = int(rm[19:23])
+
+        # look up in table
+        if table is not None:
+            for (value, mask, member) in table:
+                if ((value & search) == (mask & search)):
+                    rm = getattr(rm, member)
+                    break
 
         if rm.__class__ is self.__class__:
             raise ValueError(self)
@@ -1915,21 +1946,21 @@ class SVP64Instruction(PrefixedInstruction):
 
         Rc = False
         if record.mdwn.operands["Rc"] is not None:
-            Rc = bool(self.suffix[record.fields["Rc"]])
+            Rc = bool(record.mdwn.operands["Rc"].value)
         rm = self.prefix.rm.select(record=record, Rc=Rc)
 
-        specifiers = tuple(rm.specifiers)
-        if specifiers:
-            specifiers = f"/{'/'.join(specifiers)}"
-        else:
-            specifiers = ""
+        # convert specifiers to /x/y/z
+        specifiers = list(rm.specifiers(record=record))
+        if specifiers: # if any add one extra to get the extra "/"
+            specifiers = ['']+specifiers
+        specifiers = "/".join(specifiers)
 
+        # convert operands to " ,x,y,z"
         operands = tuple(map(_operator.itemgetter(1),
             self.dynamic_operands(db=db, verbosity=verbosity)))
-        if operands:
-            operands = f" {','.join(operands)}"
-        else:
-            operands = ""
+        operands = ','.join(operands)
+        if len(operands) > 0: # if any separate with a space
+            operands = " " + operands
 
         yield f"{blob_prefix}{name}{specifiers}{operands}"
         if blob_suffix: