power_fields: restore class-oriented traversal
[openpower-isa.git] / src / openpower / decoder / power_insn.py
index df544e30ec8590525e27a47d5101df58e9131275..c1fb4a2fcf6047f92b555ae08bdb15424e01bbbf 100644 (file)
@@ -421,7 +421,7 @@ class BitSel:
             (start, end) = value
         if start < 0 or end < 0 or start >= end:
             raise ValueError(value)
-        
+
         self.__start = start
         self.__end = end
 
@@ -659,10 +659,10 @@ class RegisterOperand(DynamicOperand):
                 spec = _SelectableInt(value=spec.value, bits=bits)
                 if vector:
                     value = ((value << vector_shift) | (spec << spec_shift))
-                    span = (span + spec_span + ((spec_shift * ('{0}',))))
+                    span = (span + spec_span + ((spec_shift * ("{0}",))))
                 else:
                     value = ((spec << scalar_shift) | value)
-                    span = ((spec_shift * ('{0}',)) + spec_span + span)
+                    span = ((spec_shift * ("{0}",)) + spec_span + span)
 
             (value, span) = self.sv_spec_leave(value=value, span=span,
                 origin_value=origin_value, origin_span=origin_span)
@@ -747,11 +747,11 @@ class TargetAddrOperand(RegisterOperand):
         value = insn[span]
 
         if verbosity >= Verbosity.VERBOSE:
-            span = tuple(map(str, span))
+            span = (tuple(map(str, span)) + ("{0}", "{0}"))
             yield f"{indent}{self.name} = EXTS({field} || 0b00))"
             yield f"{indent}{indent}{field}"
             yield f"{indent}{indent}{indent}{int(value):0{value.bits}b}00"
-            yield f"{indent}{indent}{indent}{', '.join(span + ('{0}', '{0}'))}"
+            yield f"{indent}{indent}{indent}{', '.join(span)}"
         else:
             yield hex(_selectconcat(value,
                 _SelectableInt(value=0b00, bits=2)).to_signed_int())
@@ -1089,9 +1089,11 @@ class Instruction(_Mapping):
 
         operands = ""
         if dynamic_operands:
-            operands += f" {','.join(dynamic_operands)}"
+            operands += " "
+            operands += ",".join(dynamic_operands)
         if static_operands:
-            operands += f" ({' '.join(static_operands)})"
+            operands += " "
+            operands += " ".join(static_operands)
 
         return f"{prefix}{record.name}{operands}"
 
@@ -1163,7 +1165,8 @@ class WordInstruction(Instruction):
         operands = tuple(map(_operator.itemgetter(1),
             self.dynamic_operands(db=db, verbosity=verbosity)))
         if operands:
-            yield f"{blob}{record.name} {','.join(operands)}"
+            operands = ",".join(operands)
+            yield f"{blob}{record.name} {operands}"
         else:
             yield f"{blob}{record.name}"
 
@@ -1292,10 +1295,22 @@ class BaseRM(_Mapping):
     def disassemble(self, verbosity=Verbosity.NORMAL):
         if verbosity >= Verbosity.VERBOSE:
             indent = (" " * 4)
-            for (name, value, members) in self.traverse(path="RM"):
+            for (name, span) in self.traverse(path="RM"):
+                value = self.storage[span]
                 yield f"{name}"
                 yield f"{indent}{int(value):0{value.bits}b}"
-                yield f"{indent}{', '.join(map(str, members))}"
+                yield f"{indent}{', '.join(map(str, span))}"
+
+
+class FFPRRc1BaseRM(BaseRM):
+    def specifiers(self, record, mode):
+        inv = _SelectableInt(value=int(self.inv), bits=1)
+        CR = _SelectableInt(value=int(self.CR), bits=2)
+        mask = int(_selectconcat(CR, inv))
+        predicate = PredicateBaseRM.predicate(True, mask)
+        yield f"{mode}={predicate}"
+
+        yield from super().specifiers(record=record)
 
 
 class FFPRRc0BaseRM(BaseRM):
@@ -1325,104 +1340,153 @@ class ZZBaseRM(BaseRM):
         yield from super().specifiers(record=record)
 
 
-class NormalLDSTBaseRM(BaseRM):
+class DZBaseRM(BaseRM):
+    def specifiers(self, record):
+        if self.dz:
+            yield "dz"
+
+        yield from super().specifiers(record=record)
+
+
+class SZBaseRM(BaseRM):
     def specifiers(self, record):
-        widths = {
+        if self.sz:
+            yield "sz"
+
+        yield from super().specifiers(record=record)
+
+
+class MRBaseRM(BaseRM):
+    def specifiers(self, record):
+        if self.RG:
+            yield "mrr"
+        else:
+            yield "mr"
+
+        yield from super().specifiers(record=record)
+
+
+class ElsBaseRM(BaseRM):
+    def specifiers(self, record):
+        if self.els:
+            yield "els"
+
+        yield from super().specifiers(record=record)
+
+
+class WidthBaseRM(BaseRM):
+    @staticmethod
+    def width(FP, width):
+        width = {
             0b11: "8",
             0b10: "16",
             0b01: "32",
-        }
-        predicates = {
+        }.get(width)
+        if width is None:
+            return None
+        if FP:
+            width = ("fp" + width)
+        return width
+
+    def specifiers(self, record):
+        # elwidths: use "w=" if same otherwise dw/sw
+        # FIXME this should consider FP instructions
+        FP = False
+        dw = WidthBaseRM.width(FP, int(self.elwidth))
+        sw = WidthBaseRM.width(FP, int(self.ewsrc))
+        if dw == sw and dw:
+            yield ("w=" + dw)
+        else:
+            if dw:
+                yield ("dw=" + dw)
+            if sw:
+                yield ("sw=" + sw)
+
+        yield from super().specifiers(record=record)
+
+
+class PredicateBaseRM(BaseRM):
+    @staticmethod
+    def predicate(CR, mask):
+        return {
             # integer
-            (0, 0b001): "1<<r3",
-            (0, 0b010): "r3",
-            (0, 0b011): "~r3",
-            (0, 0b100): "r10",
-            (0, 0b101): "~r10",
-            (0, 0b110): "r30",
-            (0, 0b111): "~r30",
+            (False, 0b001): "1<<r3",
+            (False, 0b010): "r3",
+            (False, 0b011): "~r3",
+            (False, 0b100): "r10",
+            (False, 0b101): "~r10",
+            (False, 0b110): "r30",
+            (False, 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",
-        }
+            (True, 0b000): "lt",
+            (True, 0b001): "ge",
+            (True, 0b010): "gt",
+            (True, 0b011): "le",
+            (True, 0b100): "eq",
+            (True, 0b101): "ne",
+            (True, 0b110): "so",
+            (True, 0b111): "ns",
+        }.get((CR, mask))
 
-        mmode = int(self.mmode)
+    def specifiers(self, record):
+        # predication - single and twin
+        # use "m=" if same otherwise sm/dm
+        CR = (int(self.mmode) == 1)
         mask = int(self.mask)
+        sm = dm = PredicateBaseRM.predicate(CR, 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={widths[dw]}"
+            smask = int(self.smask)
+            sm = PredicateBaseRM.predicate(CR, smask)
+        if sm == dm and dm:
+            yield ("m=" + dm)
         else:
-            if dw != 0b00:
-                yield f"dw={widths[dw]}"
-            if sw != 0b00:
-                yield f"sw={widths[sw]}"
+            if sm:
+                yield ("sm=" + sm)
+            if dm:
+                yield ("dm=" + dm)
 
         yield from super().specifiers(record=record)
 
 
-# ********************
-# Normal mode
-# https://libre-soc.org/openpower/sv/normal/
-class NormalBaseRM(NormalLDSTBaseRM):
+class PredicateWidthBaseRM(WidthBaseRM, PredicateBaseRM):
     pass
 
 
-class NormalSimpleRM(NormalBaseRM):
+class NormalBaseRM(PredicateWidthBaseRM):
+    """
+    Normal mode
+    https://libre-soc.org/openpower/sv/normal/
+    """
+    pass
+
+
+class NormalSimpleRM(DZBaseRM, SZBaseRM, NormalBaseRM):
     """normal: simple mode"""
     dz: BaseRM.mode[3]
     sz: BaseRM.mode[4]
 
     def specifiers(self, record):
-        if self.dz:
-            yield f"dz"
-        if self.sz:
-            yield f"sz"
-
         yield from super().specifiers(record=record)
 
 
-class NormalSMRRM(NormalBaseRM):
+class NormalSMRRM(MRBaseRM, NormalBaseRM):
     """normal: scalar reduce mode (mapreduce), SUBVL=1"""
     RG: BaseRM.mode[4]
 
-    def specifiers(self, record):
-        if self.RG:
-            yield "mrr"
-
-        yield from super().specifiers(record=record)
-
 
 class NormalReservedRM(NormalBaseRM):
     """normal: reserved"""
     pass
 
 
-class NormalFFRc1RM(NormalBaseRM):
+class NormalFFRc1RM(FFPRRc1BaseRM, NormalBaseRM):
     """normal: Rc=1: ffirst CR sel"""
     inv: BaseRM.mode[2]
     CR: BaseRM.mode[3, 4]
 
+    def specifiers(self, record):
+        yield from super().specifiers(record=record, mode="ff")
+
 
 class NormalFFRc0RM(FFPRRc0BaseRM, NormalBaseRM):
     """normal: Rc=0: ffirst z/nonz"""
@@ -1431,29 +1495,27 @@ class NormalFFRc0RM(FFPRRc0BaseRM, NormalBaseRM):
     RC1: BaseRM.mode[4]
 
     def specifiers(self, record):
+        if self.VLi:
+            yield "vli"
+
         yield from super().specifiers(record=record, mode="ff")
 
 
-class NormalSatRM(SatBaseRM, NormalBaseRM):
+class NormalSatRM(SatBaseRM, DZBaseRM, SZBaseRM, NormalBaseRM):
     """normal: sat mode: N=0/1 u/s, SUBVL=1"""
     N: BaseRM.mode[2]
     dz: BaseRM.mode[3]
     sz: BaseRM.mode[4]
 
-    def specifiers(self, record):
-        if self.dz:
-            yield f"dz"
-        if self.sz:
-            yield f"sz"
 
-        yield from super().specifiers(record=record)
-
-
-class NormalPRRc1RM(NormalBaseRM):
+class NormalPRRc1RM(FFPRRc1BaseRM, NormalBaseRM):
     """normal: Rc=1: pred-result CR sel"""
     inv: BaseRM.mode[2]
     CR: BaseRM.mode[3, 4]
 
+    def specifiers(self, record):
+        yield from super().specifiers(record=record, mode="pr")
+
 
 class NormalPRRc0RM(FFPRRc0BaseRM, ZZBaseRM, NormalBaseRM):
     """normal: Rc=0: pred-result z/nonz"""
@@ -1478,15 +1540,15 @@ class NormalRM(NormalBaseRM):
     prrc0: NormalPRRc0RM
 
 
-# ********************
-# LD/ST Immediate mode
-# https://libre-soc.org/openpower/sv/ldst/
-
-class LDSTImmBaseRM(NormalLDSTBaseRM):
+class LDSTImmBaseRM(PredicateWidthBaseRM):
+    """
+    LD/ST Immediate mode
+    https://libre-soc.org/openpower/sv/ldst/
+    """
     pass
 
 
-class LDSTImmSimpleRM(ZZBaseRM, LDSTImmBaseRM):
+class LDSTImmSimpleRM(ElsBaseRM, ZZBaseRM, LDSTImmBaseRM):
     """ld/st immediate: simple mode"""
     zz: BaseRM.mode[3]
     els: BaseRM.mode[4]
@@ -1499,13 +1561,16 @@ class LDSTImmReservedRM(LDSTImmBaseRM):
     pass
 
 
-class LDSTImmFFRc1RM(LDSTImmBaseRM):
+class LDSTImmFFRc1RM(FFPRRc1BaseRM, LDSTImmBaseRM):
     """ld/st immediate: Rc=1: ffirst CR sel"""
     inv: BaseRM.mode[2]
     CR: BaseRM.mode[3, 4]
 
+    def specifiers(self, record):
+        yield from super().specifiers(record=record, mode="ff")
+
 
-class LDSTImmFFRc0RM(FFPRRc0BaseRM, LDSTImmBaseRM):
+class LDSTImmFFRc0RM(FFPRRc0BaseRM, ElsBaseRM, LDSTImmBaseRM):
     """ld/st immediate: Rc=0: ffirst z/nonz"""
     inv: BaseRM.mode[2]
     els: BaseRM.mode[3]
@@ -1515,7 +1580,7 @@ class LDSTImmFFRc0RM(FFPRRc0BaseRM, LDSTImmBaseRM):
         yield from super().specifiers(record=record, mode="ff")
 
 
-class LDSTImmSatRM(SatBaseRM, ZZBaseRM, LDSTImmBaseRM):
+class LDSTImmSatRM(ElsBaseRM, SatBaseRM, ZZBaseRM, LDSTImmBaseRM):
     """ld/st immediate: sat mode: N=0/1 u/s"""
     N: BaseRM.mode[2]
     zz: BaseRM.mode[3]
@@ -1524,13 +1589,16 @@ class LDSTImmSatRM(SatBaseRM, ZZBaseRM, LDSTImmBaseRM):
     sz: BaseRM.mode[3]
 
 
-class LDSTImmPRRc1RM(LDSTImmBaseRM):
+class LDSTImmPRRc1RM(FFPRRc1BaseRM, LDSTImmBaseRM):
     """ld/st immediate: Rc=1: pred-result CR sel"""
     inv: BaseRM.mode[2]
     CR: BaseRM.mode[3, 4]
 
+    def specifiers(self, record):
+        yield from super().specifiers(record=record, mode="pr")
+
 
-class LDSTImmPRRc0RM(FFPRRc0BaseRM, LDSTImmBaseRM):
+class LDSTImmPRRc0RM(FFPRRc0BaseRM, ElsBaseRM, LDSTImmBaseRM):
     """ld/st immediate: Rc=0: pred-result z/nonz"""
     inv: BaseRM.mode[2]
     els: BaseRM.mode[3]
@@ -1550,64 +1618,43 @@ class LDSTImmRM(LDSTImmBaseRM):
     prrc0: LDSTImmPRRc0RM
 
 
-# ********************
-# LD/ST Indexed mode
-# https://libre-soc.org/openpower/sv/ldst/
-
-class LDSTIdxBaseRM(NormalLDSTBaseRM):
+class LDSTIdxBaseRM(PredicateWidthBaseRM):
+    """
+    LD/ST Indexed mode
+    https://libre-soc.org/openpower/sv/ldst/
+    """
     pass
 
 
-class LDSTIdxSimpleRM(LDSTIdxBaseRM):
+class LDSTIdxSimpleRM(DZBaseRM, SZBaseRM, LDSTIdxBaseRM):
     """ld/st index: simple mode"""
     SEA: BaseRM.mode[2]
-    sz: BaseRM.mode[3]
     dz: BaseRM.mode[3]
-
-    def specifiers(self, record):
-        if self.dz:
-            yield f"dz"
-        if self.sz:
-            yield f"sz"
-
-        yield from super().specifiers(record=record)
+    sz: BaseRM.mode[4]
 
 
-class LDSTIdxStrideRM(LDSTIdxBaseRM):
+class LDSTIdxStrideRM(DZBaseRM, SZBaseRM, LDSTIdxBaseRM):
     """ld/st index: strided (scalar only source)"""
     SEA: BaseRM.mode[2]
     dz: BaseRM.mode[3]
     sz: BaseRM.mode[4]
 
-    def specifiers(self, record):
-        if self.dz:
-            yield f"dz"
-        if self.sz:
-            yield f"sz"
 
-        yield from super().specifiers(record=record)
-
-
-class LDSTIdxSatRM(SatBaseRM, LDSTIdxBaseRM):
+class LDSTIdxSatRM(SatBaseRM, DZBaseRM, SZBaseRM, LDSTIdxBaseRM):
     """ld/st index: sat mode: N=0/1 u/s"""
     N: BaseRM.mode[2]
     dz: BaseRM.mode[3]
     sz: BaseRM.mode[4]
 
-    def specifiers(self, record):
-        if self.dz:
-            yield f"dz"
-        if self.sz:
-            yield f"sz"
-
-        yield from super().specifiers(record=record)
-
 
 class LDSTIdxPRRc1RM(LDSTIdxBaseRM):
     """ld/st index: Rc=1: pred-result CR sel"""
     inv: BaseRM.mode[2]
     CR: BaseRM.mode[3, 4]
 
+    def specifiers(self, record):
+        yield from super().specifiers(record=record, mode="pr")
+
 
 class LDSTIdxPRRc0RM(FFPRRc0BaseRM, ZZBaseRM, LDSTIdxBaseRM):
     """ld/st index: Rc=0: pred-result z/nonz"""
@@ -1630,102 +1677,67 @@ class LDSTIdxRM(LDSTIdxBaseRM):
 
 
 
-# ********************
-# CR ops mode
-# https://libre-soc.org/openpower/sv/cr_ops/
-
 class CROpBaseRM(BaseRM):
-    pass
+    """
+    CR ops mode
+    https://libre-soc.org/openpower/sv/cr_ops/
+    """
+    SNZ: BaseRM[7]
 
 
-class CROpSimpleRM(CROpBaseRM):
+class CROpSimpleRM(DZBaseRM, SZBaseRM, CROpBaseRM):
     """cr_op: simple mode"""
-    SNZ: BaseRM[7]
     RG: BaseRM[20]
-    sz: BaseRM[21]
     dz: BaseRM[22]
+    sz: BaseRM[23]
 
     def specifiers(self, record):
-        if self.dz:
-            yield f"dz"
-        if self.sz:
-            yield f"sz"
         if self.RG:
-            yield "mrr"
+            yield "rg" # simple CR Mode reports /rg
 
         yield from super().specifiers(record=record)
 
-
-class CROpSMRRM(CROpBaseRM):
+class CROpSMRRM(MRBaseRM, DZBaseRM, SZBaseRM, CROpBaseRM):
     """cr_op: scalar reduce mode (mapreduce), SUBVL=1"""
-    SNZ: BaseRM[7]
     RG: BaseRM[20]
-    sz: BaseRM[21]
     dz: BaseRM[22]
-
-    def specifiers(self, record):
-        if self.sz:
-            yield f"sz"
-        if self.RG:
-            yield "mrr"
-
-        yield from super().specifiers(record=record)
+    sz: BaseRM[23]
 
 
-class CROpReservedRM(ZZBaseRM, CROpBaseRM):
-    """cr_op: reserved"""
+class CROpFF3RM(ZZBaseRM, CROpBaseRM):
+    """cr_op: ffirst 3-bit mode"""
+    VLI: BaseRM[20]
+    inv: BaseRM[21]
+    CR: BaseRM[22, 23]
     zz: BaseRM[6]
-    SNZ: BaseRM[7]
-    RG: BaseRM[20]
     sz: BaseRM[6]
     dz: BaseRM[6]
 
     def specifiers(self, record):
-        if self.RG:
-            yield "mrr"
-
-        yield from super().specifiers(record=record)
-
-
-class CROpFailFirst3RM(ZZBaseRM, CROpBaseRM):
-    """cr_op: ffirst 3-bit mode"""
-    SNZ: BaseRM[7]
-    VLI: BaseRM[20]
-    inv: BaseRM[21]
-    CR: BaseRM[22, 23]
-    sz: BaseRM[21]
-    dz: BaseRM[22]
+        yield from super().specifiers(record=record, mode="ff")
 
 
-class CROpFailFirst5RM(CROpBaseRM):
+class CROpFF5RM(DZBaseRM, SZBaseRM, CROpBaseRM):
     """cr_op: ffirst 5-bit mode"""
-    sz: BaseRM[6]
-    SNZ: BaseRM[7]
     VLI: BaseRM[20]
     inv: BaseRM[21]
     dz: BaseRM[22]
+    sz: BaseRM[23]
 
     def specifiers(self, record):
-        if self.dz:
-            yield f"dz"
-        if self.sz:
-            yield f"sz"
         yield from super().specifiers(record=record)
 
 
 class CROpRM(CROpBaseRM):
     simple: CROpSimpleRM
     smr: CROpSMRRM
-    reserved: CROpReservedRM
-    ff3: CROpFailFirst3RM
-    ff5: CROpFailFirst5RM
+    ff3: CROpFF3RM
+    ff5: CROpFF5RM
 
 
 # ********************
 # Branches mode
 # https://libre-soc.org/openpower/sv/branches/
-
-
 class BranchBaseRM(BaseRM):
     ALL: BaseRM[4]
     SNZ: BaseRM[5]
@@ -1733,6 +1745,42 @@ class BranchBaseRM(BaseRM):
     SLu: BaseRM[18]
     LRu: BaseRM[22]
     sz: BaseRM[23]
+    CTR: BaseRM[19]
+    VLS: BaseRM[20]
+
+    def specifiers(self, record):
+        if self.ALL:
+            yield "all"
+
+        # /sz
+        #   branch.sz=1
+        #   branch.snz=0
+        # /snz
+        #   branch.sz=1
+        #   branch.snz=1
+        if self.SNZ:
+            if not self.sz:
+                raise ValueError(self.sz)
+            yield "snz"
+        elif self.sz:
+            yield "sz"
+
+        if self.SL:
+            yield "sl"
+        if self.SLu:
+            yield "slu"
+        if self.LRu:
+            yield "lru"
+
+        # Branch modes lack source mask.
+        # Therefore a custom code is needed.
+        CR = (int(self.mmode) == 1)
+        mask = int(self.mask)
+        m = PredicateBaseRM.predicate(CR, mask)
+        if m is not None:
+            yield ("m=" + m)
+
+        yield from super().specifiers(record=record)
 
 
 class BranchSimpleRM(BranchBaseRM):
@@ -1745,11 +1793,29 @@ class BranchVLSRM(BranchBaseRM):
     VSb: BaseRM[7]
     VLI: BaseRM[21]
 
+    def specifiers(self, record):
+        yield {
+            (0b0, 0b0): "vs",
+            (0b0, 0b1): "vsi",
+            (0b1, 0b0): "vsb",
+            (0b1, 0b1): "vsbi",
+        }[int(self.VSb), int(self.VLI)]
+
+        yield from super().specifiers(record=record)
+
 
 class BranchCTRRM(BranchBaseRM):
     """branch: CTR-test mode"""
     CTi: BaseRM[6]
 
+    def specifiers(self, record):
+        if self.CTi:
+            yield "cti"
+        else:
+            yield "ctr"
+
+        yield from super().specifiers(record=record)
+
 
 class BranchCTRVLSRM(BranchVLSRM, BranchCTRRM):
     """branch: CTR-test+VLSET mode"""
@@ -1768,6 +1834,7 @@ class RM(BaseRM):
     ldst_imm: LDSTImmRM
     ldst_idx: LDSTIdxRM
     cr_op: CROpRM
+    branch: BranchRM
 
     def select(self, record, Rc):
         rm = self
@@ -1852,15 +1919,17 @@ class RM(BaseRM):
             search = ((int(rm.mode) << 1) | (regtype or 0))
 
         elif record.svp64.mode is _SVMode.BRANCH:
-            # 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
-                    ]
+            # just mode 2-bit
+            #    mode  mask  member
+            table = (
+                (0b00, 0b11, "simple"), # simple
+                (0b01, 0b11, "vls"),    # VLset
+                (0b10, 0b11, "ctr"),    # CTR mode
+                (0b11, 0b11, "ctrvls"), # CTR+VLset mode
+            )
             # slightly weird: doesn't have a 5-bit "mode" field like others
-            search = int(rm[19:23])
+            rm = rm.branch
+            search = int(rm.mode[0, 1])
 
         # look up in table
         if table is not None:
@@ -1923,18 +1992,18 @@ class SVP64Instruction(PrefixedInstruction):
             Rc = bool(record.mdwn.operands["Rc"].value)
         rm = self.prefix.rm.select(record=record, Rc=Rc)
 
-        # convert specifiers to /x/y/z
-        specifiers = list(rm.specifiers(record=record))
+        # convert specifiers to /x/y/z (sorted lexicographically)
+        specifiers = sorted(rm.specifiers(record=record))
         if specifiers: # if any add one extra to get the extra "/"
-            specifiers = ['']+specifiers
+            specifiers = ([""] + specifiers)
         specifiers = "/".join(specifiers)
 
         # convert operands to " ,x,y,z"
         operands = tuple(map(_operator.itemgetter(1),
             self.dynamic_operands(db=db, verbosity=verbosity)))
-        operands = ','.join(operands)
+        operands = ",".join(operands)
         if len(operands) > 0: # if any separate with a space
-            operands = " " + operands
+            operands = (" " + operands)
 
         yield f"{blob_prefix}{name}{specifiers}{operands}"
         if blob_suffix: