power_insn: fix Rc operand accessor
[openpower-isa.git] / src / openpower / decoder / power_insn.py
index e9a51625c72378cf36c123ce4873da08359b9314..1f216388bb574a20ed5e1828ca9d1c0b61bc1b04 100644 (file)
@@ -3,7 +3,9 @@ import csv as _csv
 import dataclasses as _dataclasses
 import enum as _enum
 import functools as _functools
+import itertools as _itertools
 import os as _os
+import operator as _operator
 import pathlib as _pathlib
 import re as _re
 
@@ -20,6 +22,7 @@ from openpower.decoder.power_enums import (
     In3Sel as _In3Sel,
     OutSel as _OutSel,
     CRInSel as _CRInSel,
+    CRIn2Sel as _CRIn2Sel,
     CROutSel as _CROutSel,
     LDSTLen as _LDSTLen,
     LDSTMode as _LDSTMode,
@@ -27,6 +30,7 @@ from openpower.decoder.power_enums import (
     CryIn as _CryIn,
     Form as _Form,
     SVEtype as _SVEtype,
+    SVmask_src as _SVmask_src,
     SVMode as _SVMode,
     SVPtype as _SVPtype,
     SVExtra as _SVExtra,
@@ -40,13 +44,24 @@ from openpower.decoder.selectable_int import (
 )
 from openpower.decoder.power_fields import (
     Field as _Field,
-    Array as _Array,
     Mapping as _Mapping,
     DecodeFields as _DecodeFields,
 )
 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 = {}
@@ -74,22 +89,37 @@ def dataclass(cls, record, keymap=None, typemap=None):
 @_functools.total_ordering
 @_dataclasses.dataclass(eq=True, frozen=True)
 class Opcode:
-    class Value(int):
-        def __repr__(self):
-            if self.bit_length() <= 32:
-                return f"0x{self:08x}"
-            else:
-                return f"0x{self:016x}"
+    class Integer(int):
+        def __new__(cls, value):
+            if isinstance(value, str):
+                value = int(value, 0)
+            if not isinstance(value, int):
+                raise ValueError(value)
+
+            if value.bit_length() > 64:
+                raise ValueError(value)
+
+            return super().__new__(cls, value)
+
+        def __str__(self):
+            return super().__repr__()
 
-    class Mask(int):
         def __repr__(self):
-            if self.bit_length() <= 32:
-                return f"0x{self:08x}"
-            else:
-                return f"0x{self:016x}"
+            return f"{self:0{self.bit_length()}b}"
+
+        def bit_length(self):
+            if super().bit_length() > 32:
+                return 64
+            return 32
+
+    class Value(Integer):
+        pass
+
+    class Mask(Integer):
+        pass
 
     value: Value
-    mask: Mask = None
+    mask: Mask
 
     def __lt__(self, other):
         if not isinstance(other, Opcode):
@@ -97,39 +127,41 @@ class Opcode:
         return ((self.value, self.mask) < (other.value, other.mask))
 
     def __post_init__(self):
-        (value, mask) = (self.value, self.mask)
-
-        if isinstance(value, Opcode):
-            if mask is not None:
-                raise ValueError(mask)
-            (value, mask) = (value.value, value.mask)
-        elif isinstance(value, str):
-            if mask is not None:
-                raise ValueError(mask)
-            value = int(value, 0)
-
-        if not isinstance(value, int):
-            raise ValueError(value)
-        if mask is None:
-            mask = value
-        if not isinstance(mask, int):
-            raise ValueError(mask)
+        if self.value.bit_length() != self.mask.bit_length():
+            raise ValueError("bit length mismatch")
+
+    def __repr__(self):
+        def pattern(value, mask, bit_length):
+            for bit in range(bit_length):
+                if ((mask & (1 << (bit_length - bit - 1))) == 0):
+                    yield "-"
+                elif (value & (1 << (bit_length - bit - 1))):
+                    yield "1"
+                else:
+                    yield "0"
 
-        object.__setattr__(self, "value", self.__class__.Value(value))
-        object.__setattr__(self, "mask", self.__class__.Mask(mask))
+        return "".join(pattern(self.value, self.mask, self.value.bit_length()))
 
 
 class IntegerOpcode(Opcode):
     def __init__(self, value):
-        if isinstance(value, str):
-            value = int(value, 0)
-        return super().__init__(value=value, mask=None)
+        if value.startswith("0b"):
+           mask = int(("1" * len(value[2:])), 2)
+        else:
+            mask = 0b111111
+
+        value = Opcode.Value(value)
+        mask = Opcode.Mask(mask)
+
+        return super().__init__(value=value, mask=mask)
 
 
 class PatternOpcode(Opcode):
-    def __init__(self, value):
-        (pattern, value, mask) = (value, 0, 0)
+    def __init__(self, pattern):
+        if not isinstance(pattern, str):
+            raise ValueError(pattern)
 
+        (value, mask) = (0, 0)
         for symbol in pattern:
             if symbol not in {"0", "1", "-"}:
                 raise ValueError(pattern)
@@ -140,22 +172,8 @@ class PatternOpcode(Opcode):
         value >>= 1
         mask >>= 1
 
-        return super().__init__(value=value, mask=mask)
-
-
-class FieldsOpcode(Opcode):
-    def __init__(self, fields):
-        def field(opcode, field):
-            (value, mask) = opcode
-            (field, bits) = field
-            shifts = map(lambda bit: (31 - bit), reversed(tuple(bits)))
-            for (index, shift) in enumerate(shifts):
-                bit = ((field & (1 << index)) != 0)
-                value |= (bit << shift)
-                mask |= (1 << shift)
-            return (value, mask)
-
-        (value, mask) = _functools.reduce(field, fields, (0, 0))
+        value = Opcode.Value(value)
+        mask = Opcode.Mask(mask)
 
         return super().__init__(value=value, mask=mask)
 
@@ -196,6 +214,7 @@ class PPCRecord:
     in3: _In3Sel = _In3Sel.NONE
     out: _OutSel = _OutSel.NONE
     cr_in: _CRInSel = _CRInSel.NONE
+    cr_in2: _CRIn2Sel = _CRIn2Sel.NONE
     cr_out: _CROutSel = _CROutSel.NONE
     cry_in: _CryIn = _CryIn.ZERO
     ldst_len: _LDSTLen = _LDSTLen.NONE
@@ -217,10 +236,15 @@ class PPCRecord:
     }
 
     @classmethod
-    def CSV(cls, record, opcode_cls=Opcode):
+    def CSV(cls, record, opcode_cls):
         typemap = {field.name:field.type for field in _dataclasses.fields(cls)}
         typemap["opcode"] = opcode_cls
 
+        if record["CR in"] == "BA_BB":
+            record["cr_in"] = "BA"
+            record["cr_in2"] = "BB"
+            del record["CR in"]
+
         flags = set()
         for flag in frozenset(PPCRecord.Flags):
             if bool(record.pop(flag, "")):
@@ -236,38 +260,11 @@ class PPCRecord:
         return frozenset(self.comment.split("=")[-1].split("/"))
 
 
-class PPCMultiRecord(frozenset):
-    @cached_property
-    def unified(self):
-        def merge(lhs, rhs):
-            value = 0
-            mask = 0
-            lvalue = lhs.opcode.value
-            rvalue = rhs.opcode.value
-            lmask = lhs.opcode.mask
-            rmask = rhs.opcode.mask
-            bits = max(lmask.bit_length(), rmask.bit_length())
-            for bit in range(bits):
-                lvstate = ((lvalue & (1 << bit)) != 0)
-                rvstate = ((rvalue & (1 << bit)) != 0)
-                lmstate = ((lmask & (1 << bit)) != 0)
-                rmstate = ((rmask & (1 << bit)) != 0)
-                vstate = lvstate
-                mstate = True
-                if (not lmstate or not rmstate) or (lvstate != rvstate):
-                    vstate = 0
-                    mstate = 0
-                value |= (vstate << bit)
-                mask |= (mstate << bit)
-
-            opcode = opcode=Opcode(value=value, mask=mask)
-
-            return _dataclasses.replace(lhs, opcode=opcode)
-
-        return _functools.reduce(merge, self)
-
+class PPCMultiRecord(tuple):
     def __getattr__(self, attr):
-        return getattr(self.unified, attr)
+        if attr == "opcode":
+            raise AttributeError(attr)
+        return getattr(self[0], attr)
 
 
 @_dataclasses.dataclass(eq=True, frozen=True)
@@ -312,12 +309,14 @@ class SVP64Record:
     name: str
     ptype: _SVPtype = _SVPtype.NONE
     etype: _SVEtype = _SVEtype.NONE
+    msrc: _SVmask_src = _SVmask_src.NO # MASK_SRC is active
     in1: _In1Sel = _In1Sel.NONE
     in2: _In2Sel = _In2Sel.NONE
     in3: _In3Sel = _In3Sel.NONE
     out: _OutSel = _OutSel.NONE
     out2: _OutSel = _OutSel.NONE
     cr_in: _CRInSel = _CRInSel.NONE
+    cr_in2: _CRIn2Sel = _CRIn2Sel.NONE
     cr_out: _CROutSel = _CROutSel.NONE
     extra: ExtraMap = ExtraMap()
     conditions: str = ""
@@ -328,17 +327,26 @@ class SVP64Record:
         "CONDITIONS": "conditions",
         "Ptype": "ptype",
         "Etype": "etype",
+        "SM": "msrc",
         "CR in": "cr_in",
         "CR out": "cr_out",
     }
 
     @classmethod
     def CSV(cls, record):
-        for key in ("in1", "in2", "in3", "out", "out2", "CR in", "CR out"):
+        for key in frozenset({
+                    "in1", "in2", "in3", "CR in",
+                    "out", "out2", "CR out",
+                }):
             value = record[key]
             if value == "0":
                 record[key] = "NONE"
 
+        if record["CR in"] == "BA_BB":
+            record["cr_in"] = "BA"
+            record["cr_in2"] = "BB"
+            del record["CR in"]
+
         extra = []
         for idx in range(0, 4):
             extra.append(record.pop(f"{idx}"))
@@ -357,7 +365,7 @@ class SVP64Record:
         )
 
         if key not in frozenset({
-                    "in1", "in2", "in3", "cr_in",
+                    "in1", "in2", "in3", "cr_in", "cr_in2",
                     "out", "out2", "cr_out",
                 }):
             raise KeyError(key)
@@ -425,6 +433,9 @@ class BitSel:
     def __iter__(self):
         yield from range(self.start, (self.end + 1))
 
+    def __reversed__(self):
+        return tuple(reversed(tuple(self)))
+
     @property
     def start(self):
         return self.__start
@@ -465,14 +476,18 @@ class Section:
             return (bin(self) if self else "None")
 
     path: _pathlib.Path
-    opcode: Opcode
     bitsel: BitSel
     suffix: Suffix
     mode: Mode
+    opcode: IntegerOpcode = None
 
     @classmethod
     def CSV(cls, record):
-        return dataclass(cls, record)
+        typemap = {field.name:field.type for field in _dataclasses.fields(cls)}
+        if record["opcode"] == "NONE":
+            typemap["opcode"] = lambda _: None
+
+        return dataclass(cls, record, typemap=typemap)
 
 
 class Fields:
@@ -482,7 +497,7 @@ class Fields:
 
         def transform(item):
             (name, bitrange) = item
-            return (name, list(bitrange.values()))
+            return (name, tuple(bitrange.values()))
 
         self.__mapping = dict(map(transform, items))
 
@@ -505,142 +520,330 @@ class Fields:
 class Operand:
     name: str
 
-    def disassemble(self, value, record, verbose=False):
+    def span(self, record):
+        return record.fields[self.name]
+
+    def disassemble(self, insn, record,
+            verbosity=Verbosity.NORMAL, indent=""):
         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)
+    def disassemble(self, insn, record,
+            verbosity=Verbosity.NORMAL, indent=""):
+        span = self.span(record=record)
+        if isinstance(insn, SVP64Instruction):
+            span = tuple(map(lambda bit: (bit + 32), span))
+        value = insn[span]
+
+        if verbosity >= Verbosity.VERBOSE:
+            span = map(str, span)
+            yield f"{indent}{self.name}"
+            yield f"{indent}{indent}{int(value):0{value.bits}b}"
+            yield f"{indent}{indent}{', '.join(span)}"
         else:
             yield str(int(value))
 
 
+class SignedOperand(DynamicOperand):
+    def disassemble(self, insn, record,
+            verbosity=Verbosity.NORMAL, indent=""):
+        span = self.span(record=record)
+        if isinstance(insn, SVP64Instruction):
+            span = tuple(map(lambda bit: (bit + 32), span))
+        value = insn[span]
+
+        if verbosity >= Verbosity.VERBOSE:
+            span = map(str, span)
+            yield f"{indent}{self.name}"
+            yield f"{indent}{indent}{int(value):0{value.bits}b}"
+            yield f"{indent}{indent}{', '.join(span)}"
+        else:
+            yield str(value.to_signed_int())
+
+
 @_dataclasses.dataclass(eq=True, frozen=True)
-class DynamicOperandReg(DynamicOperand):
+class StaticOperand(Operand):
+    value: int
+
+    def disassemble(self, insn, record,
+            verbosity=Verbosity.NORMAL, indent=""):
+        span = self.span(record=record)
+        if isinstance(insn, SVP64Instruction):
+            span = tuple(map(lambda bit: (bit + 32), span))
+        value = insn[span]
+
+        if verbosity >= Verbosity.VERBOSE:
+            span = map(str, span)
+            yield f"{indent}{self.name}"
+            yield f"{indent}{indent}{int(value):0{value.bits}b}"
+            yield f"{indent}{indent}{', '.join(span)}"
+        else:
+            yield str(int(value))
+
+
+class ImmediateOperand(DynamicOperand):
+    pass
+
+
+class NonZeroOperand(DynamicOperand):
+    def disassemble(self, insn, record,
+            verbosity=Verbosity.NORMAL, indent=""):
+        span = self.span(record=record)
+        if isinstance(insn, SVP64Instruction):
+            span = tuple(map(lambda bit: (bit + 32), span))
+        value = insn[span]
+
+        if verbosity >= Verbosity.VERBOSE:
+            span = map(str, span)
+            yield f"{indent}{self.name}"
+            yield f"{indent}{indent}{int(value):0{value.bits}b}"
+            yield f"{indent}{indent}{', '.join(span)}"
+        else:
+            yield str(int(value) + 1)
+
+
+class RegisterOperand(DynamicOperand):
+    def sv_spec_enter(self, value, span):
+        return (value, span)
+
+    def sv_spec_leave(self, value, span, origin_value, origin_span):
+        return (value, span)
+
+    def spec(self, insn, record):
+        vector = False
+        span = self.span(record=record)
+        if isinstance(insn, SVP64Instruction):
+            span = tuple(map(lambda bit: (bit + 32), span))
+        value = insn[span]
+        span = tuple(map(str, span))
+
+        if isinstance(insn, SVP64Instruction):
+            (origin_value, origin_span) = (value, span)
+            (value, span) = self.sv_spec_enter(value=value, span=span)
+
+            extra_idx = self.extra_idx(record=record)
+            if extra_idx is _SVExtra.NONE:
+                return (vector, value, span)
+
+            if record.etype is _SVEtype.EXTRA3:
+                spec = insn.prefix.rm.extra3[extra_idx]
+            elif record.etype is _SVEtype.EXTRA2:
+                spec = insn.prefix.rm.extra2[extra_idx]
+            else:
+                raise ValueError(record.etype)
+
+            if spec != 0:
+                vector = bool(spec[0])
+                spec_span = spec.__class__
+                if record.etype is _SVEtype.EXTRA3:
+                    spec_span = tuple(map(str, spec_span[1, 2]))
+                    spec = spec[1, 2]
+                elif record.etype is _SVEtype.EXTRA2:
+                    spec_span = tuple(map(str, spec_span[1,]))
+                    spec = _SelectableInt(value=spec[1].value, bits=2)
+                    if vector:
+                        spec <<= 1
+                        spec_span = (spec_span + ("{0}",))
+                    else:
+                        spec_span = (("{0}",) + spec_span)
+                else:
+                    raise ValueError(record.etype)
+
+                vector_shift = (2 + (5 - value.bits))
+                scalar_shift = value.bits
+                spec_shift = (5 - value.bits)
+
+                bits = (len(span) + len(spec_span))
+                value = _SelectableInt(value=value.value, bits=bits)
+                spec = _SelectableInt(value=spec.value, bits=bits)
+                if vector:
+                    value = ((value << vector_shift) | (spec << spec_shift))
+                    span = (span + spec_span + ((spec_shift * ('{0}',))))
+                else:
+                    value = ((spec << scalar_shift) | value)
+                    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)
+
+        return (vector, value, span)
+
     @property
     def extra_reg(self):
         return _SVExtraReg(self.name)
 
     def extra_idx(self, record):
         for key in frozenset({
-                    "in1", "in2", "in3", "cr_in",
+                    "in1", "in2", "in3", "cr_in", "cr_in2",
                     "out", "out2", "cr_out",
                 }):
-            if self.extra_reg == record.svp64.extra_reg(key):
-                return record.extra_idx(key)
+            extra_reg = record.svp64.extra_reg(key=key)
+            if extra_reg is self.extra_reg:
+                return record.extra_idx(key=key)
 
         return _SVExtra.NONE
 
-
-@_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)
+    def disassemble(self, insn, record,
+            verbosity=Verbosity.NORMAL, prefix="", indent=""):
+        (vector, value, span) = self.spec(insn=insn, record=record)
+
+        if verbosity >= Verbosity.VERBOSE:
+            mode = "vector" if vector else "scalar"
+            yield f"{indent}{self.name} ({mode})"
+            yield f"{indent}{indent}{int(value):0{value.bits}b}"
+            yield f"{indent}{indent}{', '.join(span)}"
+            if isinstance(insn, SVP64Instruction):
+                extra_idx = self.extra_idx(record)
+                if record.etype is _SVEtype.NONE:
+                    yield f"{indent}{indent}extra[none]"
+                else:
+                    etype = repr(record.etype).lower()
+                    yield f"{indent}{indent}{etype}{extra_idx!r}"
         else:
-            yield str(int(value))
+            vector = "*" if vector else ""
+            yield f"{vector}{prefix}{int(value)}"
 
 
-@_dataclasses.dataclass(eq=True, frozen=True)
-class DynamicOperandTargetAddrLI(DynamicOperandReg):
-    @property
-    def name(self):
-        return "LI"
+class GPROperand(RegisterOperand):
+    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)
 
-    @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 FPROperand(RegisterOperand):
+    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 DynamicOperandTargetAddrBD(DynamicOperand):
-    @property
-    def name(self):
-        return "BD"
+class CR3Operand(RegisterOperand):
+    pass
 
-    @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))))
+class CR5Operand(RegisterOperand):
+    def sv_spec_enter(self, value, span):
+        value = _SelectableInt(value=(value.value >> 2), bits=3)
+        return (value, span)
 
+    def sv_spec_leave(self, value, span, origin_value, origin_span):
+        value = _selectconcat(value, origin_value[3:5])
+        span += origin_span
+        return (value, span)
 
-@_dataclasses.dataclass(eq=True, frozen=True)
-class DynamicOperandGPR(DynamicOperandReg):
-    def disassemble(self, value, record, verbose=False):
-        svp64 = isinstance(value, SVP64Instruction)
-        span = record.fields[self.name]
-        value = value[span]
-        if verbose:
-            yield f"{int(value):0{value.bits}b}"
-            yield repr(span)
-            if svp64:
-                yield repr(self.extra_idx(record))
-        else:
-            yield f"r{str(int(value))}"
 
+class TargetAddrOperand(RegisterOperand):
+    def disassemble(self, insn, record, field,
+            verbosity=Verbosity.NORMAL, indent=""):
+        span = self.span(record=record)
+        if isinstance(insn, SVP64Instruction):
+            span = tuple(map(lambda bit: (bit + 32), span))
+        value = insn[span]
 
-@_dataclasses.dataclass(eq=True, frozen=True)
-class DynamicOperandFPR(DynamicOperandReg):
-    def disassemble(self, value, record, verbose=False):
-        svp64 = isinstance(value, SVP64Instruction)
-        span = record.fields[self.name]
-        value = value[span]
-        if verbose:
-            yield f"{int(value):0{value.bits}b}"
-            yield repr(span)
-            if svp64:
-                yield repr(self.extra_idx(record))
+        if verbosity >= Verbosity.VERBOSE:
+            span = tuple(map(str, span))
+            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}'))}"
+        else:
+            yield hex(_selectconcat(value,
+                _SelectableInt(value=0b00, bits=2)).to_signed_int())
+
+
+class TargetAddrOperandLI(TargetAddrOperand):
+    def span(self, record):
+        return record.fields["LI"]
+
+    def disassemble(self, insn, record,
+            verbosity=Verbosity.NORMAL, indent=""):
+        return super().disassemble(field="LI",
+            insn=insn, record=record,
+            verbosity=verbosity, indent=indent)
+
+
+class TargetAddrOperandBD(TargetAddrOperand):
+    def span(self, record):
+        return record.fields["BD"]
+
+    def disassemble(self, insn, record,
+            verbosity=Verbosity.NORMAL, indent=""):
+        return super().disassemble(field="BD",
+            insn=insn, record=record,
+            verbosity=verbosity, indent=indent)
+
+
+class DOperandDX(SignedOperand):
+    def span(self, record):
+        operands = map(DynamicOperand, ("d0", "d1", "d2"))
+        spans = map(lambda operand: operand.span(record=record), operands)
+        return sum(spans, tuple())
+
+    def disassemble(self, insn, record,
+            verbosity=Verbosity.NORMAL, indent=""):
+        span = self.span(record=record)
+        if isinstance(insn, SVP64Instruction):
+            span = tuple(map(lambda bit: (bit + 32), span))
+        value = insn[span]
+
+        if verbosity >= Verbosity.VERBOSE:
+            yield f"{indent}D"
+            mapping = {
+                "d0": "[0:9]",
+                "d1": "[10:15]",
+                "d2": "[16]",
+            }
+            for (subname, subspan) in mapping.items():
+                operand = DynamicOperand(name=subname)
+                span = operand.span(record=record)
+                if isinstance(insn, SVP64Instruction):
+                    span = tuple(map(lambda bit: (bit + 32), span))
+                value = insn[span]
+                span = map(str, span)
+                yield f"{indent}{indent}{operand.name} = D{subspan}"
+                yield f"{indent}{indent}{indent}{int(value):0{value.bits}b}"
+                yield f"{indent}{indent}{indent}{', '.join(span)}"
         else:
-            yield f"f{str(int(value))}"
+            yield str(value.to_signed_int())
 
 
 class Operands(tuple):
     def __new__(cls, insn, iterable):
-        branches = {
-            "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},
+        custom_insns = {
+            "b": {"target_addr": TargetAddrOperandLI},
+            "ba": {"target_addr": TargetAddrOperandLI},
+            "bl": {"target_addr": TargetAddrOperandLI},
+            "bla": {"target_addr": TargetAddrOperandLI},
+            "bc": {"target_addr": TargetAddrOperandBD},
+            "bca": {"target_addr": TargetAddrOperandBD},
+            "bcl": {"target_addr": TargetAddrOperandBD},
+            "bcla": {"target_addr": TargetAddrOperandBD},
+            "addpcis": {"D": DOperandDX},
+            "fishmv": {"D": DOperandDX},
+            "fmvis": {"D": DOperandDX},
+        }
+        custom_fields = {
+            "SVi": NonZeroOperand,
+            "SVd": NonZeroOperand,
+            "SVxd": NonZeroOperand,
+            "SVyd": NonZeroOperand,
+            "SVzd": NonZeroOperand,
+            "BD": SignedOperand,
+            "D": SignedOperand,
+            "DQ": SignedOperand,
+            "DS": SignedOperand,
+            "SI": SignedOperand,
+            "IB": SignedOperand,
+            "LI": SignedOperand,
+            "SIM": SignedOperand,
+            "SVD": SignedOperand,
+            "SVDS": SignedOperand,
         }
 
         operands = []
@@ -662,15 +865,21 @@ class Operands(tuple):
                 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 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]
                     if regtype is _RegType.GPR:
-                        dynamic_cls = DynamicOperandGPR
+                        dynamic_cls = GPROperand
                     elif regtype is _RegType.FPR:
-                        dynamic_cls = DynamicOperandFPR
+                        dynamic_cls = FPROperand
+                    if regtype is _RegType.CR_BIT: # 5-bit
+                        dynamic_cls = CR5Operand
+                    if regtype is _RegType.CR_REG: # actually CR Field, 3-bit
+                        dynamic_cls = CR3Operand
 
                 operand = dynamic_cls(name=operand)
                 operands.append(operand)
@@ -700,6 +909,24 @@ class Operands(tuple):
                 yield operand
 
 
+class PCode:
+    def __init__(self, iterable):
+        self.__pcode = tuple(iterable)
+        return super().__init__()
+
+    def __iter__(self):
+        yield from self.__pcode
+
+    def __repr__(self):
+        return self.__pcode.__repr__()
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class MarkdownRecord:
+    pcode: PCode
+    operands: Operands
+
+
 @_functools.total_ordering
 @_dataclasses.dataclass(eq=True, frozen=True)
 class Record:
@@ -707,27 +934,49 @@ class Record:
     section: Section
     ppc: PPCRecord
     fields: Fields
-    operands: Operands
+    mdwn: MarkdownRecord
     svp64: SVP64Record = None
 
     def __lt__(self, other):
         if not isinstance(other, Record):
             return NotImplemented
-        return (self.opcode < other.opcode)
+        return (min(self.opcodes) < min(other.opcodes))
 
-    @cached_property
-    def opcode(self):
-        fields = []
-        if self.section.opcode:
-            fields += [(self.section.opcode.value, BitSel((0, 5)))]
-            fields += [(self.ppc.opcode.value, self.section.bitsel)]
-        else:
-            fields += [(self.ppc.opcode.value, self.section.bitsel)]
+    @property
+    def opcodes(self):
+        def opcode(ppc):
+            value = ([0] * 32)
+            mask = ([0] * 32)
+
+            PO = self.section.opcode
+            if PO is not None:
+                for (src, dst) in enumerate(reversed(BitSel((0, 5)))):
+                    value[dst] = int((PO.value & (1 << src)) != 0)
+                    mask[dst] = int((PO.mask & (1 << src)) != 0)
+
+            XO = ppc.opcode
+            for (src, dst) in enumerate(reversed(self.section.bitsel)):
+                value[dst] = int((XO.value & (1 << src)) != 0)
+                mask[dst] = int((XO.mask & (1 << src)) != 0)
+
+            for operand in self.mdwn.operands.static:
+                for (src, dst) in enumerate(reversed(operand.span(record=self))):
+                    value[dst] = int((operand.value & (1 << src)) != 0)
+                    mask[dst] = 1
+
+            value = Opcode.Value(int(("".join(map(str, value))), 2))
+            mask = Opcode.Mask(int(("".join(map(str, mask))), 2))
+
+            return Opcode(value=value, mask=mask)
 
-        for operand in self.operands.static:
-            fields += [(operand.value, self.fields[operand.name])]
+        return tuple(sorted(map(opcode, self.ppc)))
 
-        return FieldsOpcode(fields)
+    def match(self, key):
+        for opcode in self.opcodes:
+            if ((opcode.value & opcode.mask) ==
+                    (key & opcode.mask)):
+                return True
+        return False
 
     @property
     def function(self):
@@ -759,22 +1008,27 @@ class Record:
     def cr_in(self):
         return self.ppc.cr_in
 
+    @property
+    def cr_in2(self):
+        return self.ppc.cr_in2
+
     @property
     def cr_out(self):
         return self.ppc.cr_out
 
+    ptype = property(lambda self: self.svp64.ptype)
+    etype = property(lambda self: self.svp64.etype)
+
     def extra_idx(self, key):
         return self.svp64.extra_idx(key)
 
-    ptype = property(lambda self: self.svp64.ptype)
-    etype = property(lambda self: self.svp64.etype)
-    extra_in1 = property(lambda self: self.svp64.extra_in1)
-    extra_in2 = property(lambda self: self.svp64.extra_in2)
-    extra_in3 = property(lambda self: self.svp64.extra_in3)
-    extra_out = property(lambda self: self.svp64.extra_out)
-    extra_out2 = property(lambda self: self.svp64.extra_out2)
-    extra_cr_in = property(lambda self: self.svp64.extra_cr_in)
-    extra_cr_out = property(lambda self: self.svp64.extra_cr_out)
+    extra_idx_in1 = property(lambda self: self.svp64.extra_idx_in1)
+    extra_idx_in2 = property(lambda self: self.svp64.extra_idx_in2)
+    extra_idx_in3 = property(lambda self: self.svp64.extra_idx_in3)
+    extra_idx_out = property(lambda self: self.svp64.extra_idx_out)
+    extra_idx_out2 = property(lambda self: self.svp64.extra_idx_out2)
+    extra_idx_cr_in = property(lambda self: self.svp64.extra_idx_cr_in)
+    extra_idx_cr_out = property(lambda self: self.svp64.extra_idx_cr_out)
 
 
 class Instruction(_Mapping):
@@ -807,13 +1061,70 @@ 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:
             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.mdwn.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.mdwn.operands.static:
+            yield (operand.name, operand.value)
+
+    def disassemble(self, db,
+            byteorder="little",
+            verbosity=Verbosity.NORMAL):
         raise NotImplementedError
 
 
@@ -833,88 +1144,49 @@ 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}"
-
-    def mask(self, db):
-        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)
+        record = db[self]
         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(value=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)
-            opcode = self.opcode(db=db)
-            mask = self.mask(db=db)
+            spec = self.spec(db=db, prefix="")
             yield f"{indent}spec"
             yield f"{indent}{indent}{spec}"
+            yield f"{indent}pcode"
+            for stmt in record.mdwn.pcode:
+                yield f"{indent}{indent}{stmt}"
             yield f"{indent}binary"
             yield f"{indent}{indent}[0:8]   {binary[0:8]}"
             yield f"{indent}{indent}[8:16]  {binary[8:16]}"
             yield f"{indent}{indent}[16:24] {binary[16:24]}"
             yield f"{indent}{indent}[24:32] {binary[24:32]}"
-            yield f"{indent}opcode"
-            yield f"{indent}{indent}{opcode}"
-            yield f"{indent}mask"
-            yield f"{indent}{indent}{mask}"
-            for operand in record.operands:
-                name = operand.name
-                yield f"{indent}{name}"
-                parts = operand.disassemble(value=self,
-                    record=record, verbose=True)
-                for part in parts:
-                    yield f"{indent}{indent}{part}"
+            yield f"{indent}opcodes"
+            for opcode in record.opcodes:
+                yield f"{indent}{indent}{opcode!r}"
+            for operand in record.mdwn.operands:
+                yield from operand.disassemble(insn=self, record=record,
+                    verbosity=verbosity, indent=indent)
             yield ""
 
 
@@ -943,213 +1215,668 @@ 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):
     _: _Field = range(0, 5)
-    sel: _Field = range(0, 2)
 
 
-class NormalMode(Mode):
-    class simple(Mode):
-        """simple mode"""
-        dz: Mode[3]
-        sz: Mode[4]
+class Extra(_Mapping):
+    _: _Field = range(0, 9)
 
-    class smr(Mode):
-        """scalar reduce mode (mapreduce), SUBVL=1"""
-        RG: Mode[4]
 
-    class pmr(Mode):
-        """parallel reduce mode (mapreduce), SUBVL=1"""
-        pass
+class Extra2(Extra):
+    idx0: _Field = range(0, 2)
+    idx1: _Field = range(2, 4)
+    idx2: _Field = range(4, 6)
+    idx3: _Field = range(6, 8)
 
-    class svmr(Mode):
-        """subvector reduce mode, SUBVL>1"""
-        SVM: Mode[3]
-
-    class pu(Mode):
-        """Pack/Unpack mode, SUBVL>1"""
-        SVM: Mode[3]
-
-    class ffrc1(Mode):
-        """Rc=1: ffirst CR sel"""
-        inv: Mode[2]
-        CRbit: Mode[3, 4]
-
-    class ffrc0(Mode):
-        """Rc=0: ffirst z/nonz"""
-        inv: Mode[2]
-        VLi: Mode[3]
-        RC1: Mode[4]
-
-    class sat(Mode):
-        """sat mode: N=0/1 u/s, SUBVL=1"""
-        N: Mode[2]
-        dz: Mode[3]
-        sz: Mode[4]
-
-    class satx(Mode):
-        """sat mode: N=0/1 u/s, SUBVL>1"""
-        N: Mode[2]
-        zz: Mode[3]
-        dz: Mode[3]
-        sz: Mode[3]
-
-    class satpu(Mode):
-        """Pack/Unpack sat mode: N=0/1 u/s, SUBVL>1"""
-        N: Mode[2]
-        zz: Mode[3]
-        dz: Mode[3]
-        sz: Mode[3]
-
-    class prrc1(Mode):
-        """Rc=1: pred-result CR sel"""
-        inv: Mode[2]
-        CRbit: Mode[3, 4]
-
-    class prrc0(Mode):
-        """Rc=0: pred-result z/nonz"""
-        inv: Mode[2]
-        zz: Mode[3]
-        RC1: Mode[4]
-        dz: Mode[3]
-        sz: Mode[3]
-
-    simple: simple
-    smr: smr
-    pmr: pmr
-    svmr: svmr
-    pu: pu
-    ffrc1: ffrc1
-    ffrc0: ffrc0
-    sat: sat
-    satx: satx
-    satpu: satpu
-    prrc1: prrc1
-    prrc0: prrc0
-
-
-class LDSTImmMode(Mode):
-    class simple(Mode):
-        """simple mode"""
-        zz: Mode[3]
-        els: Mode[4]
-        dz: Mode[3]
-        sz: Mode[3]
-
-    class spu(Mode):
-        """Structured Pack/Unpack"""
-        zz: Mode[3]
-        els: Mode[4]
-        dz: Mode[3]
-        sz: Mode[3]
-
-    class ffrc1(Mode):
-        """Rc=1: ffirst CR sel"""
-        inv: Mode[2]
-        CRbit: Mode[3, 4]
-
-    class ffrc0(Mode):
-        """Rc=0: ffirst z/nonz"""
-        inv: Mode[2]
-        els: Mode[3]
-        RC1: Mode[4]
-
-    class sat(Mode):
-        """sat mode: N=0/1 u/s"""
-        N: Mode[2]
-        zz: Mode[3]
-        els: Mode[4]
-        dz: Mode[3]
-        sz: Mode[3]
-
-    class prrc1(Mode):
-        """Rc=1: pred-result CR sel"""
-        inv: Mode[2]
-        CRbit: Mode[3, 4]
-
-    class prrc0(Mode):
-        """Rc=0: pred-result z/nonz"""
-        inv: Mode[2]
-        els: Mode[3]
-        RC1: Mode[4]
-
-    simple: simple
-    spu: spu
-    ffrc1: ffrc1
-    ffrc0: ffrc0
-    sat: sat
-    prrc1: prrc1
-    prrc0: prrc0
-
-
-class LDSTIdxMode(Mode):
-    class simple(Mode):
-        """simple mode"""
-        SEA: Mode[2]
-        sz: Mode[3]
-        dz: Mode[3]
-
-    class stride(Mode):
-        """strided (scalar only source)"""
-        SEA: Mode[2]
-        dz: Mode[3]
-        sz: Mode[4]
-
-    class sat(Mode):
-        """sat mode: N=0/1 u/s"""
-        N: Mode[2]
-        dz: Mode[3]
-        sz: Mode[4]
-
-    class prrc1(Mode):
-        """Rc=1: pred-result CR sel"""
-        inv: Mode[2]
-        CRbit: Mode[3, 4]
-
-    class prrc0(Mode):
-        """Rc=0: pred-result z/nonz"""
-        inv: Mode[2]
-        zz: Mode[3]
-        RC1: Mode[4]
-        dz: Mode[3]
-        sz: Mode[3]
-
-    simple: simple
-    stride: stride
-    sat: sat
-    prrc1: prrc1
-    prrc0: prrc0
-
-
-class RM(_Mapping):
-    class Mode(Mode):
-        normal: NormalMode
-        ldst_imm: LDSTImmMode
-        ldst_idx: LDSTIdxMode
+    def __getitem__(self, key):
+        return {
+            0: self.idx0,
+            1: self.idx1,
+            2: self.idx2,
+            3: self.idx3,
+            _SVExtra.Idx0: self.idx0,
+            _SVExtra.Idx1: self.idx1,
+            _SVExtra.Idx2: self.idx2,
+            _SVExtra.Idx3: self.idx3,
+        }[key]
+
+    def __setitem__(self, key, value):
+        self[key].assign(value)
+
+
+class Extra3(Extra):
+    idx0: _Field = range(0, 3)
+    idx1: _Field = range(3, 6)
+    idx2: _Field = range(6, 9)
+
+    def __getitem__(self, key):
+        return {
+            0: self.idx0,
+            1: self.idx1,
+            2: self.idx2,
+            _SVExtra.Idx0: self.idx0,
+            _SVExtra.Idx1: self.idx1,
+            _SVExtra.Idx2: self.idx2,
+        }[key]
 
+    def __setitem__(self, key, value):
+        self[key].assign(value)
+
+
+class BaseRM(_Mapping):
     _: _Field = range(24)
     mmode: _Field = (0,)
     mask: _Field = range(1, 4)
     elwidth: _Field = range(4, 6)
     ewsrc: _Field = range(6, 8)
     subvl: _Field = range(8, 10)
-    extra: _Field = range(10, 19)
     mode: Mode.remap(range(19, 24))
-    extra2: _Array[4] = (
-        range(10, 12),
-        range(12, 14),
-        range(14, 16),
-        range(16, 18),
-    )
     smask: _Field = range(16, 19)
-    extra3: _Array[3] = (
-        range(10, 13),
-        range(13, 16),
-        range(16, 19),
-    )
+    extra: Extra.remap(range(10, 19))
+    extra2: Extra2.remap(range(10, 19))
+    extra3: Extra3.remap(range(10, 19))
+
+    def specifiers(self, record):
+        subvl = int(self.subvl)
+        if subvl > 0:
+            yield {
+                1: "vec2",
+                2: "vec3",
+                3: "vec4",
+            }[subvl]
+
+    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 NormalLDSTBaseRM(BaseRM):
+    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={widths[dw]}"
+        else:
+            if dw != 0b00:
+                yield f"dw={widths[dw]}"
+            if sw != 0b00:
+                yield f"sw={widths[sw]}"
+
+        yield from super().specifiers(record=record)
+
+
+class NormalBaseRM(NormalLDSTBaseRM):
+    pass
+
+
+class NormalSimpleRM(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 NormalScalarReduceRM(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 NormalFailFirstRc1RM(NormalBaseRM):
+    """normal: Rc=1: ffirst CR sel"""
+    inv: BaseRM.mode[2]
+    CR: BaseRM.mode[3, 4]
+
+
+class NormalFailFirstRc0RM(NormalBaseRM):
+    """normal: Rc=0: ffirst z/nonz"""
+    inv: BaseRM.mode[2]
+    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"""
+    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"
+        if self.N:
+            yield "sats"
+        else:
+            yield "satu"
+
+        yield from super().specifiers(record=record)
+
+
+class NormalPredResultRc1RM(NormalBaseRM):
+    """normal: Rc=1: pred-result CR sel"""
+    inv: BaseRM.mode[2]
+    CR: BaseRM.mode[3, 4]
+
+
+class NormalPredResultRc0RM(NormalBaseRM):
+    """normal: Rc=0: pred-result z/nonz"""
+    inv: BaseRM.mode[2]
+    zz: BaseRM.mode[3]
+    RC1: BaseRM.mode[4]
+    dz: BaseRM.mode[3]
+    sz: BaseRM.mode[3]
+
+    def specifiers(self, record):
+        if self.zz:
+            yield f"zz"
+        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
+    reserved: NormalReservedRM
+    ffrc1: NormalFailFirstRc1RM
+    ffrc0: NormalFailFirstRc0RM
+    sat: NormalSaturationRM
+    prrc1: NormalPredResultRc1RM
+    prrc0: NormalPredResultRc0RM
+
+
+class LDSTImmBaseRM(NormalLDSTBaseRM):
+    pass
+
+
+class LDSTImmSimpleRM(LDSTImmBaseRM):
+    """ld/st immediate: simple mode"""
+    zz: BaseRM.mode[3]
+    els: BaseRM.mode[4]
+    dz: BaseRM.mode[3]
+    sz: BaseRM.mode[3]
+
+    def specifiers(self, record):
+        if self.zz:
+            yield f"zz"
+
+        yield from super().specifiers(record=record)
+
+
+class LDSTImmReservedRM(LDSTImmBaseRM):
+    """ld/st immediate: reserved"""
+    pass
+
+
+class LDSTImmFailFirstRc1RM(LDSTImmBaseRM):
+    """ld/st immediate: Rc=1: ffirst CR sel"""
+    inv: BaseRM.mode[2]
+    CR: BaseRM.mode[3, 4]
+
+
+class LDSTImmFailFirstRc0RM(LDSTImmBaseRM):
+    """ld/st immediate: Rc=0: ffirst z/nonz"""
+    inv: BaseRM.mode[2]
+    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"""
+    N: BaseRM.mode[2]
+    zz: BaseRM.mode[3]
+    els: BaseRM.mode[4]
+    dz: BaseRM.mode[3]
+    sz: BaseRM.mode[3]
+
+    def specifiers(self, record):
+        if self.zz:
+            yield f"zz"
+        if self.N:
+            yield "sats"
+        else:
+            yield "satu"
+
+        yield from super().specifiers(record=record)
+
+
+class LDSTImmPredResultRc1RM(LDSTImmBaseRM):
+    """ld/st immediate: Rc=1: pred-result CR sel"""
+    inv: BaseRM.mode[2]
+    CR: BaseRM.mode[3, 4]
+
+
+class LDSTImmPredResultRc0RM(LDSTImmBaseRM):
+    """ld/st immediate: Rc=0: pred-result z/nonz"""
+    inv: BaseRM.mode[2]
+    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
+    reserved: LDSTImmReservedRM
+    ffrc1: LDSTImmFailFirstRc1RM
+    ffrc0: LDSTImmFailFirstRc0RM
+    sat: LDSTImmSaturationRM
+    prrc1: LDSTImmPredResultRc1RM
+    prrc0: LDSTImmPredResultRc0RM
+
+
+class LDSTIdxBaseRM(NormalLDSTBaseRM):
+    pass
+
+
+class LDSTIdxSimpleRM(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)
+
+
+class LDSTIdxStrideRM(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 LDSTIdxSaturationRM(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"
+        if self.N:
+            yield "sats"
+        else:
+            yield "satu"
+
+        yield from super().specifiers(record=record)
+
+
+class LDSTIdxPredResultRc1RM(LDSTIdxBaseRM):
+    """ld/st index: Rc=1: pred-result CR sel"""
+    inv: BaseRM.mode[2]
+    CR: BaseRM.mode[3, 4]
+
+
+class LDSTIdxPredResultRc0RM(LDSTIdxBaseRM):
+    """ld/st index: Rc=0: pred-result z/nonz"""
+    inv: BaseRM.mode[2]
+    zz: BaseRM.mode[3]
+    RC1: BaseRM.mode[4]
+    dz: BaseRM.mode[3]
+    sz: BaseRM.mode[3]
+
+    def specifiers(self, record):
+        if self.zz:
+            yield f"zz"
+        if self.RC1:
+            inv = "~" if self.inv else ""
+            yield f"pr={inv}RC1"
+
+        yield from super().specifiers(record=record)
+
+
+class LDSTIdxRM(LDSTIdxBaseRM):
+    simple: LDSTIdxSimpleRM
+    stride: LDSTIdxStrideRM
+    sat: LDSTIdxSaturationRM
+    prrc1: LDSTIdxPredResultRc1RM
+    prrc0: LDSTIdxPredResultRc0RM
+
+
+class CROpBaseRM(BaseRM):
+    pass
+
+
+class CROpSimpleRM(CROpBaseRM):
+    """cr_op: simple mode"""
+    sz: BaseRM[6]
+    SNZ: BaseRM[7]
+    RG: BaseRM[20]
+    dz: BaseRM[22]
+
+    def specifiers(self, record):
+        if self.dz:
+            yield f"dz"
+        if self.sz:
+            yield f"sz"
+        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]
+
+    def specifiers(self, record):
+        if self.sz:
+            yield f"sz"
+        if self.RG:
+            yield "mrr"
+
+        yield from super().specifiers(record=record)
+
+
+class CROpReservedRM(CROpBaseRM):
+    """cr_op: reserved"""
+    zz: BaseRM[6]
+    SNZ: BaseRM[7]
+    RG: BaseRM[20]
+    dz: BaseRM[6]
+    sz: BaseRM[6]
+
+    def specifiers(self, record):
+        if self.zz:
+            yield f"zz"
+        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]
+
+    def specifiers(self, record):
+        if self.zz:
+            yield f"zz"
+        yield from super().specifiers(record=record)
+
+
+class CROpFailFirst5RM(CROpBaseRM):
+    """cr_op: ffirst 5-bit mode"""
+    sz: BaseRM[6]
+    SNZ: BaseRM[7]
+    VLI: BaseRM[20]
+    inv: BaseRM[21]
+    dz: BaseRM[22]
+
+    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: CROpScalarReduceRM
+    reserved: CROpReservedRM
+    ff3: CROpFailFirst3RM
+    ff5: CROpFailFirst5RM
+
+
+class BranchBaseRM(BaseRM):
+    ALL: BaseRM[4]
+    SNZ: BaseRM[5]
+    SL: BaseRM[17]
+    SLu: BaseRM[18]
+    LRu: BaseRM[22]
+    sz: BaseRM[23]
+
+
+class BranchSimpleRM(BranchBaseRM):
+    """branch: simple mode"""
+    pass
+
+
+class BranchVLSRM(BranchBaseRM):
+    """branch: VLSET mode"""
+    VSb: BaseRM[7]
+    VLI: BaseRM[21]
+
+
+class BranchCTRRM(BranchBaseRM):
+    """branch: CTR-test mode"""
+    CTi: BaseRM[6]
+
+
+class BranchCTRVLSRM(BranchVLSRM, BranchCTRRM):
+    """branch: CTR-test+VLSET mode"""
+    pass
+
+
+class BranchRM(BranchBaseRM):
+    simple: BranchSimpleRM
+    vls: BranchVLSRM
+    ctr: BranchCTRRM
+    ctrvls: BranchCTRVLSRM
+
+
+class RM(BaseRM):
+    normal: NormalRM
+    ldst_imm: LDSTImmRM
+    ldst_idx: LDSTIdxRM
+    cr_op: CROpRM
+
+    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
+            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
+            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
+            search = ((int(rm.mode) << 1) | Rc)
+
+        elif record.svp64.mode is _SVMode.CROP:
+            # 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:
+                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:
+            # 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)
+
+        return rm
 
 
 class SVP64Instruction(PrefixedInstruction):
@@ -1160,6 +1887,12 @@ class SVP64Instruction(PrefixedInstruction):
 
     prefix: Prefix
 
+    def record(self, db):
+        record = db[self.suffix]
+        if record is None:
+            raise KeyError(self)
+        return record
+
     @property
     def binary(self):
         bits = []
@@ -1168,154 +1901,60 @@ 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)
-
-    def mask(self, db):
-        return self.suffix.mask(db=db)
-
-    def mode(self, db):
-        record = self.record(db=db)
-
-        Rc = False
-        if record.operands["Rc"] is not None:
-            Rc = bool(self[record.fields["Rc"]])
-
-        record = self.record(db=db)
-        subvl = self.prefix.rm.subvl
-        mode = self.prefix.rm.mode
-        sel = mode.sel
-
-        if record.svp64.mode is _SVMode.NORMAL:
-            mode = mode.normal
-            if sel == 0b00:
-                if mode[2] == 0b0:
-                    mode = mode.simple
-                else:
-                    if subvl == 0b00:
-                        if mode[3] == 0b0:
-                            mode = mode.smr
-                        else:
-                            mode = mode.pmr
-                    else:
-                        if mode[4] == 0b0:
-                            mode = mode.svmr
-                        else:
-                            mode = mode.pu
-            elif sel == 0b01:
-                if Rc:
-                    mode = mode.ffrc1
-                else:
-                    mode = mode.ffrc0
-            elif sel == 0b10:
-                if subvl == 0b00:
-                    mode = mode.sat
-                else:
-                    if mode[4]:
-                        mode = mode.satx
-                    else:
-                        mode = mode.satpu
-            elif sel == 0b11:
-                if Rc:
-                    mode = mode.prrc1
-                else:
-                    mode = mode.prrc0
-        elif record.svp64.mode is _SVMode.LDST_IMM:
-            mode = mode.ldst_imm
-            if sel == 0b00:
-                if mode[2] == 0b0:
-                    mode = mode.simple
-                else:
-                    mode = mode.spu
-            elif sel == 0b01:
-                if Rc:
-                    mode = mode.ffrc1
-                else:
-                    mode = mode.ffrc0
-            elif sel == 0b10:
-                mode = mode.sat
-            elif sel == 0b11:
-                if Rc:
-                    mode = mode.prrc1
-                else:
-                    mode = mode.prrc0
-        elif record.svp64.mode is _SVMode.LDST_IMM:
-            mode = mode.ldst_idx
-            if mode.sel == 0b00:
-                mode = mode.simple
-            elif mode.sel == 0b01:
-                mode = mode.stride
-            elif mode.sel == 0b10:
-                mode = mode.sat
-            elif mode.sel == 0b11:
-                if Rc:
-                    mode = mode.prrc1
-                else:
-                    mode = mode.prrc0
-
-        modes = {
-            NormalMode.simple: "normal: simple",
-            NormalMode.smr: "normal: smr",
-            NormalMode.pmr: "normal: pmr",
-            NormalMode.svmr: "normal: svmr",
-            NormalMode.pu: "normal: pu",
-            NormalMode.ffrc1: "normal: ffrc1",
-            NormalMode.ffrc0: "normal: ffrc0",
-            NormalMode.sat: "normal: sat",
-            NormalMode.satx: "normal: satx",
-            NormalMode.satpu: "normal: satpu",
-            NormalMode.prrc1: "normal: prrc1",
-            NormalMode.prrc0: "normal: prrc0",
-            LDSTImmMode.simple: "ld/st imm: simple",
-            LDSTImmMode.spu: "ld/st imm: spu",
-            LDSTImmMode.ffrc1: "ld/st imm: ffrc1",
-            LDSTImmMode.ffrc0: "ld/st imm: ffrc0",
-            LDSTImmMode.sat: "ld/st imm: sat",
-            LDSTImmMode.prrc1: "ld/st imm: prrc1",
-            LDSTImmMode.prrc0: "ld/st imm: prrc0",
-            LDSTIdxMode.simple: "ld/st idx simple",
-            LDSTIdxMode.stride: "ld/st idx stride",
-            LDSTIdxMode.sat: "ld/st idx sat",
-            LDSTIdxMode.prrc1: "ld/st idx prrc1",
-            LDSTIdxMode.prrc0: "ld/st idx prrc0",
-        }
-        for (cls, desc) in modes.items():
-            if isinstance(mode, cls):
-                return (mode, desc)
-
-        raise NotImplementedError
-
-    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}    "
 
         record = self.record(db=db)
+        blob_prefix = blob(int(self.prefix))
+        blob_suffix = blob(int(self.suffix))
         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
 
-        yield f"{blob_prefix}    sv.{record.name}"
-        yield f"{blob_suffix}"
+        name = f"sv.{record.name}"
 
-        (mode, mode_desc) = self.mode(db=db)
+        Rc = False
+        if record.mdwn.operands["Rc"] is not None:
+            Rc = bool(record.mdwn.operands["Rc"].value)
+        rm = self.prefix.rm.select(record=record, Rc=Rc)
+
+        specifiers = tuple(rm.specifiers(record=record))
+        if specifiers:
+            specifiers = "/".join(specifiers)
+            specifiers = f"/{specifiers}"
+        else:
+            specifiers = ""
 
-        if verbose:
+        operands = tuple(map(_operator.itemgetter(1),
+            self.dynamic_operands(db=db, verbosity=verbosity)))
+        if operands:
+            operands = f" {','.join(operands)}"
+        else:
+            operands = ""
+
+        yield f"{blob_prefix}{name}{specifiers}{operands}"
+        if blob_suffix:
+            yield f"{blob_suffix}"
+
+        if verbosity >= Verbosity.VERBOSE:
             indent = (" " * 4)
             binary = self.binary
-            spec = self.spec(db=db)
-            opcode = self.opcode(db=db)
-            mask = self.mask(db=db)
+            spec = self.spec(db=db, prefix="sv.")
+
             yield f"{indent}spec"
             yield f"{indent}{indent}{spec}"
+            yield f"{indent}pcode"
+            for stmt in record.mdwn.pcode:
+                yield f"{indent}{indent}{stmt}"
             yield f"{indent}binary"
             yield f"{indent}{indent}[0:8]   {binary[0:8]}"
             yield f"{indent}{indent}[8:16]  {binary[8:16]}"
@@ -1325,20 +1964,16 @@ class SVP64Instruction(PrefixedInstruction):
             yield f"{indent}{indent}[40:48] {binary[40:48]}"
             yield f"{indent}{indent}[48:56] {binary[48:56]}"
             yield f"{indent}{indent}[56:64] {binary[56:64]}"
-            yield f"{indent}opcode"
-            yield f"{indent}{indent}{opcode}"
-            yield f"{indent}mask"
-            yield f"{indent}{indent}{mask}"
-            for operand in record.operands:
-                name = operand.name
-                yield f"{indent}{name}"
-                parts = operand.disassemble(value=self,
-                    record=record, verbose=True)
-                for part in parts:
-                    yield f"{indent}{indent}{part}"
-
-            yield f"{indent}mode"
-            yield f"{indent}{indent}{mode_desc}"
+            yield f"{indent}opcodes"
+            for opcode in record.opcodes:
+                yield f"{indent}{indent}{opcode!r}"
+            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.__doc__}"
+            for line in rm.disassemble(verbosity=verbosity):
+                yield f"{indent}{indent}{line}"
             yield ""
 
 
@@ -1361,13 +1996,20 @@ class MarkdownDatabase:
                 (dynamic, *static) = desc.regs
                 operands.extend(dynamic)
                 operands.extend(static)
-            db[name] = Operands(insn=name, iterable=operands)
+            pcode = PCode(iterable=desc.pcode)
+            operands = Operands(insn=name, iterable=operands)
+            db[name] = MarkdownRecord(pcode=pcode, operands=operands)
+
         self.__db = db
+
         return super().__init__()
 
     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)
 
@@ -1413,67 +2055,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):
-            for name in record.names:
-                if name == key:
-                    return True
-
-            return False
-
-        def Rc_match(key, record):
-            if not key.endswith("."):
-                return False
-
-            if not record.Rc is _RCOE.RC:
-                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]["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:
@@ -1508,14 +2147,16 @@ class SVP64Database:
 class Database:
     def __init__(self, root):
         root = _pathlib.Path(root)
-
         mdwndb = MarkdownDatabase()
         fieldsdb = FieldsDatabase()
         ppcdb = PPCDatabase(root=root, mdwndb=mdwndb)
         svp64db = SVP64Database(root=root, ppcdb=ppcdb)
 
         db = set()
-        for (name, operands) in mdwndb:
+        names = {}
+        opcodes = _collections.defaultdict(set)
+
+        for (name, mdwn) in mdwndb:
             (section, ppc) = ppcdb[name]
             if ppc is None:
                 continue
@@ -1523,10 +2164,17 @@ class Database:
             fields = fieldsdb[ppc.form]
             record = Record(name=name,
                 section=section, ppc=ppc, svp64=svp64,
-                operands=operands, fields=fields)
+                mdwn=mdwn, fields=fields)
             db.add(record)
+            names[record.name] = record
+            PO = section.opcode
+            if PO is None:
+                PO = ppc[0].opcode
+            opcodes[PO.value].add(record)
 
-        self.__db = tuple(sorted(db))
+        self.__db = db
+        self.__names = names
+        self.__opcodes = opcodes
 
         return super().__init__()
 
@@ -1544,18 +2192,12 @@ class Database:
     def __getitem__(self, key):
         if isinstance(key, (int, Instruction)):
             key = int(key)
-            for record in self:
-                opcode = record.opcode
-                if ((opcode.value & opcode.mask) ==
-                        (key & opcode.mask)):
-                    return record
-            return None
-        elif isinstance(key, Opcode):
-            for record in self:
-                if record.opcode == key:
-                    return record
+            XO = int(_SelectableInt(value=int(key), bits=32)[0:6])
+            for record in self.__opcodes[XO]:
+                if record.match(key=key):
+                   return record
+
         elif isinstance(key, str):
-            for record in self:
-                if record.name == key:
-                    return record
+            return self.__names[key]
+
         return None