add SVP64 CR EXTRA field-extension, from 3-bit to 7-bit (plus isvec)
[soc.git] / src / soc / decoder / power_decoder2.py
index 4405cf2c2631a33a934f70d57964859b71941f93..cd9bae1bd0e40f15adebbccb870ea7cf94d59e9c 100644 (file)
@@ -14,19 +14,25 @@ from nmutil.picker import PriorityPicker
 from nmutil.iocontrol import RecordObject
 from nmutil.extend import exts
 
 from nmutil.iocontrol import RecordObject
 from nmutil.extend import exts
 
+from soc.experiment.mem_types import LDSTException
+
 from soc.decoder.power_regspec_map import regspec_decode_read
 from soc.decoder.power_regspec_map import regspec_decode_write
 from soc.decoder.power_decoder import create_pdecode
 from soc.decoder.power_enums import (MicrOp, CryIn, Function,
                                      CRInSel, CROutSel,
                                      LdstLen, In1Sel, In2Sel, In3Sel,
 from soc.decoder.power_regspec_map import regspec_decode_read
 from soc.decoder.power_regspec_map import regspec_decode_write
 from soc.decoder.power_decoder import create_pdecode
 from soc.decoder.power_enums import (MicrOp, CryIn, Function,
                                      CRInSel, CROutSel,
                                      LdstLen, In1Sel, In2Sel, In3Sel,
-                                     OutSel, SPR, RC, LDSTMode)
-from soc.decoder.decode2execute1 import Decode2ToExecute1Type, Data
+                                     OutSel, SPR, RC, LDSTMode,
+                                     SVEXTRA, SVEtype)
+from soc.decoder.decode2execute1 import (Decode2ToExecute1Type, Data,
+                                         Decode2ToOperand)
+from soc.sv.svp64 import SVP64Rec
 from soc.consts import MSR
 
 from soc.regfile.regfiles import FastRegs
 from soc.consts import TT
 from soc.config.state import CoreState
 from soc.consts import MSR
 
 from soc.regfile.regfiles import FastRegs
 from soc.consts import TT
 from soc.config.state import CoreState
+from soc.regfile.util import spr_to_fast
 
 
 def decode_spr_num(spr):
 
 
 def decode_spr_num(spr):
@@ -51,42 +57,187 @@ def instr_is_priv(m, op, insn):
 
 
 class SPRMap(Elaboratable):
 
 
 class SPRMap(Elaboratable):
-    """SPRMap: maps POWER9 SPR numbers to internal enum values
+    """SPRMap: maps POWER9 SPR numbers to internal enum values, fast and slow
     """
 
     def __init__(self):
         self.spr_i = Signal(10, reset_less=True)
     """
 
     def __init__(self):
         self.spr_i = Signal(10, reset_less=True)
-        self.spr_o = Signal(SPR, reset_less=True)
+        self.spr_o = Data(SPR, name="spr_o")
+        self.fast_o = Data(3, name="fast_o")
 
     def elaborate(self, platform):
         m = Module()
         with m.Switch(self.spr_i):
             for i, x in enumerate(SPR):
                 with m.Case(x.value):
 
     def elaborate(self, platform):
         m = Module()
         with m.Switch(self.spr_i):
             for i, x in enumerate(SPR):
                 with m.Case(x.value):
-                    m.d.comb += self.spr_o.eq(i)
+                    m.d.comb += self.spr_o.data.eq(i)
+                    m.d.comb += self.spr_o.ok.eq(1)
+            for x, v in spr_to_fast.items():
+                with m.Case(x.value):
+                    m.d.comb += self.fast_o.data.eq(v)
+                    m.d.comb += self.fast_o.ok.eq(1)
+        return m
+
+
+class SVP64ExtraSpec(Elaboratable):
+    """SVP64ExtraSpec - decodes SVP64 Extra specification.
+
+    selects the required EXTRA2/3 field.
+
+    see https://libre-soc.org/openpower/sv/svp64/
+    """
+    def __init__(self):
+        self.extra   = Signal(10, reset_less=True)
+        self.etype   = Signal(SVEtype, reset_less=True) # 2 or 3 bits
+        self.idx     = Signal(SVEXTRA, reset_less=True) # which part of extra
+        self.spec  = Signal(3) # EXTRA spec for the register
+
+    def elaborate(self, platform):
+        m = Module()
+        comb = m.d.comb
+        spec = self.spec
+
+        # back in the LDSTRM-* and RM-* files generated by sv_analysis.py
+        # we marked every op with an Etype: EXTRA2 or EXTRA3, and also said
+        # which of the 4 (or 3 for EXTRA3) sub-fields of bits 10:18 contain
+        # the register-extension information.  extract those now
+        with m.Switch(self.etype):
+            # 2-bit index selection mode
+            with m.Case(SVEtype.EXTRA2):
+                with m.Switch(self.idx):
+                    with m.Case(SVEXTRA.Idx0): # 1st 2 bits
+                        comb += spec[1:3].eq(self.extra[0:2])
+                    with m.Case(SVEXTRA.Idx1): # 2nd 2 bits
+                        comb += spec[1:3].eq(self.extra[2:4])
+                    with m.Case(SVEXTRA.Idx2): # 3rd 2 bits
+                        comb += spec[1:3].eq(self.extra[4:6])
+                    with m.Case(SVEXTRA.Idx3): # 4th 2 bits
+                        comb += spec[1:3].eq(self.extra[6:8])
+            # 3-bit index selection mode
+            with m.Case(SVEtype.EXTRA3):
+                with m.Switch(self.idx):
+                    with m.Case(SVEXTRA.Idx0): # 1st 3 bits
+                        comb += spec.eq(self.extra[0:3])
+                    with m.Case(SVEXTRA.Idx1): # 2nd 3 bits
+                        comb += spec.eq(self.extra[3:6])
+                    with m.Case(SVEXTRA.Idx2): # 3rd 3 bits
+                        comb += spec.eq(self.extra[6:9])
+                    # cannot fit more than 9 bits so there is no 4th thing
+
+        return m
+
+
+class SVP64RegExtra(SVP64ExtraSpec):
+    """SVP64RegExtra - decodes SVP64 Extra fields to determine reg extension
+
+    incoming 5-bit GPR/FP is turned into a 7-bit and marked as scalar/vector
+    depending on info in one of the positions in the EXTRA field.
+
+    designed so that "no change" to the 5-bit register number occurs if
+    SV either does not apply or the relevant EXTRA2/3 field bits are zero.
+
+    see https://libre-soc.org/openpower/sv/svp64/
+    """
+    def __init__(self):
+        SVP64ExtraSpec.__init__(self)
+        self.reg_in  = Signal(5) # incoming reg number (5 bits, RA, RB)
+        self.reg_out = Signal(7) # extra-augmented output (7 bits)
+        self.isvec   = Signal(1) # reg is marked as vector if true
+
+    def elaborate(self, platform):
+        m = super().elaborate(platform) # select required EXTRA2/3
+        comb = m.d.comb
+
+        # first get the spec.  if not changed it's "scalar identity behaviour"
+        # which is zero which is ok.
+        spec = self.spec
+
+        # now decode it. bit 2 is "scalar/vector".  note that spec could be zero
+        #  from above, which (by design) has the effect of "no change", below.
+
+        # simple: isvec is top bit of spec
+        comb += self.isvec.eq(spec[2])
+
+        # decode vector differently from scalar
+        with m.If(self.isvec):
+            # Vector: shifted up, extra in LSBs (RA << 2) | spec[0:1]
+            comb += self.reg_out.eq(Cat(spec[:2], self.reg_in))
+        with m.Else():
+            # Scalar: not shifted up, extra in MSBs RA | (spec[0:1] << 5)
+            comb += self.reg_out.eq(Cat(self.reg_in, spec[:2]))
+
+        return m
+
+
+class SVP64CRExtra(SVP64ExtraSpec):
+    """SVP64CRExtra - decodes SVP64 Extra fields to determine CR extension
+
+    incoming 3-bit CR is turned into a 7-bit and marked as scalar/vector
+    depending on info in one of the positions in the EXTRA field.
+
+    yes, really, 128 CRs.  INT is 128, FP is 128, therefore CRs are 128.
+
+    designed so that "no change" to the 3-bit CR register number occurs if
+    SV either does not apply or the relevant EXTRA2/3 field bits are zero.
+
+    see https://libre-soc.org/openpower/sv/svp64/appendix
+    """
+    def __init__(self):
+        SVP64ExtraSpec.__init__(self)
+        self.cr_in  = Signal(3) # incoming CR number (3 bits, BA[2:5], BFA)
+        self.cr_out = Signal(7) # extra-augmented CR output (7 bits)
+        self.isvec  = Signal(1) # reg is marked as vector if true
+
+    def elaborate(self, platform):
+        m = super().elaborate(platform) # select required EXTRA2/3
+        comb = m.d.comb
+
+        # first get the spec.  if not changed it's "scalar identity behaviour"
+        # which is zero which is ok.
+        spec = self.spec
+
+        # now decode it. bit 2 is "scalar/vector".  note that spec could be zero
+        #  from above, which (by design) has the effect of "no change", below.
+
+        # simple: isvec is top bit of spec
+        comb += self.isvec.eq(spec[2])
+
+        # decode vector differently from scalar, insert bits 0 and 1 accordingly
+        with m.If(self.isvec):
+            # Vector: shifted up, extra in LSBs (CR << 4) | (spec[0:1] << 2)
+            comb += self.cr_out.eq(Cat(Const(0, 2), spec[:2], self.cr_in))
+        with m.Else():
+            # Scalar: not shifted up, extra in MSBs CR | (spec[0:1] << 3)
+            comb += self.cr_out.eq(Cat(self.cr_in, spec[:2]))
+
         return m
 
 
 class DecodeA(Elaboratable):
     """DecodeA from instruction
 
         return m
 
 
 class DecodeA(Elaboratable):
     """DecodeA from instruction
 
-    decodes register RA, whether immediate-zero, implicit and
-    explicit CSRs
+    decodes register RA, implicit and explicit CSRs
     """
 
     def __init__(self, dec):
         self.dec = dec
     """
 
     def __init__(self, dec):
         self.dec = dec
+        self.sv_rm = SVP64Rec() # SVP64 RM field
         self.sel_in = Signal(In1Sel, reset_less=True)
         self.insn_in = Signal(32, reset_less=True)
         self.sel_in = Signal(In1Sel, reset_less=True)
         self.insn_in = Signal(32, reset_less=True)
-        self.reg_out = Data(5, name="reg_a")
-        self.immz_out = Signal(reset_less=True)
+        self.reg_out = Data(7, name="reg_a")
+        self.reg_isvec = Signal(1, name="reg_a_isvec") # TODO: in reg_out
         self.spr_out = Data(SPR, "spr_a")
         self.fast_out = Data(3, "fast_a")
 
     def elaborate(self, platform):
         m = Module()
         comb = m.d.comb
         self.spr_out = Data(SPR, "spr_a")
         self.fast_out = Data(3, "fast_a")
 
     def elaborate(self, platform):
         m = Module()
         comb = m.d.comb
+        op = self.dec.op
         m.submodules.sprmap = sprmap = SPRMap()
         m.submodules.sprmap = sprmap = SPRMap()
+        m.submodules.svdec = svdec = SVP64RegExtra()
+
+        # get the 5-bit reg data before svp64-munging it into 7-bit plus isvec
+        reg = Signal(5, reset_less=True)
 
         # select Register A field
         ra = Signal(5, reset_less=True)
 
         # select Register A field
         ra = Signal(5, reset_less=True)
@@ -94,21 +245,32 @@ class DecodeA(Elaboratable):
         with m.If((self.sel_in == In1Sel.RA) |
                   ((self.sel_in == In1Sel.RA_OR_ZERO) &
                    (ra != Const(0, 5)))):
         with m.If((self.sel_in == In1Sel.RA) |
                   ((self.sel_in == In1Sel.RA_OR_ZERO) &
                    (ra != Const(0, 5)))):
-            comb += self.reg_out.data.eq(ra)
+            comb += reg.eq(ra)
             comb += self.reg_out.ok.eq(1)
 
             comb += self.reg_out.ok.eq(1)
 
-        # zero immediate requested
-        with m.If((self.sel_in == In1Sel.RA_OR_ZERO) &
-                  (self.reg_out.data == Const(0, 5))):
-            comb += self.immz_out.eq(1)
-
         # some Logic/ALU ops have RS as the 3rd arg, but no "RA".
         # some Logic/ALU ops have RS as the 3rd arg, but no "RA".
+        # moved it to 1st position (in1_sel)... because
+        rs = Signal(5, reset_less=True)
+        comb += rs.eq(self.dec.RS)
         with m.If(self.sel_in == In1Sel.RS):
         with m.If(self.sel_in == In1Sel.RS):
-            comb += self.reg_out.data.eq(self.dec.RS)
+            comb += reg.eq(rs)
             comb += self.reg_out.ok.eq(1)
 
             comb += self.reg_out.ok.eq(1)
 
+        # now do the SVP64 munging.  op.SV_Etype and op.sv_in1 comes from
+        # PowerDecoder which in turn comes from LDST-RM*.csv and RM-*.csv
+        # which in turn were auto-generated by sv_analysis.py
+
+        extra = self.sv_rm.extra            # SVP64 extra bits 10:18
+        comb += svdec.extra.eq(extra)       # EXTRA field of SVP64 RM
+        comb += svdec.etype.eq(op.SV_Etype) # EXTRA2/3 for this insn
+        comb += svdec.idx.eq(op.sv_in1)     # SVP64 reg #1 (matches in1_sel)
+        comb += svdec.reg_in.eq(reg)        # 5-bit (RA, RS)
+
+        # outputs: 7-bit reg number and whether it's vectorised
+        comb += self.reg_out.data.eq(svdec.reg_out)
+        comb += self.reg_isvec.eq(svdec.isvec)
+
         # decode Fast-SPR based on instruction type
         # decode Fast-SPR based on instruction type
-        op = self.dec.op
         with m.Switch(op.internal_op):
 
             # BC or BCREG: implicit register (CTR) NOTE: same in DecodeOut
         with m.Switch(op.internal_op):
 
             # BC or BCREG: implicit register (CTR) NOTE: same in DecodeOut
@@ -129,33 +291,34 @@ class DecodeA(Elaboratable):
             with m.Case(MicrOp.OP_MFSPR):
                 spr = Signal(10, reset_less=True)
                 comb += spr.eq(decode_spr_num(self.dec.SPR))  # from XFX
             with m.Case(MicrOp.OP_MFSPR):
                 spr = Signal(10, reset_less=True)
                 comb += spr.eq(decode_spr_num(self.dec.SPR))  # from XFX
-                with m.Switch(spr):
-                    # fast SPRs
-                    with m.Case(SPR.CTR.value):
-                        comb += self.fast_out.data.eq(FastRegs.CTR)
-                        comb += self.fast_out.ok.eq(1)
-                    with m.Case(SPR.LR.value):
-                        comb += self.fast_out.data.eq(FastRegs.LR)
-                        comb += self.fast_out.ok.eq(1)
-                    with m.Case(SPR.TAR.value):
-                        comb += self.fast_out.data.eq(FastRegs.TAR)
-                        comb += self.fast_out.ok.eq(1)
-                    with m.Case(SPR.SRR0.value):
-                        comb += self.fast_out.data.eq(FastRegs.SRR0)
-                        comb += self.fast_out.ok.eq(1)
-                    with m.Case(SPR.SRR1.value):
-                        comb += self.fast_out.data.eq(FastRegs.SRR1)
-                        comb += self.fast_out.ok.eq(1)
-                    with m.Case(SPR.XER.value):
-                        comb += self.fast_out.data.eq(FastRegs.XER)
-                        comb += self.fast_out.ok.eq(1)
-                        pass  # do nothing
-                    # : map to internal SPR numbers
-                    # XXX TODO: dec and tb not to go through mapping.
-                    with m.Default():
-                        comb += sprmap.spr_i.eq(spr)
-                        comb += self.spr_out.data.eq(sprmap.spr_o)
-                        comb += self.spr_out.ok.eq(1)
+                comb += sprmap.spr_i.eq(spr)
+                comb += self.spr_out.eq(sprmap.spr_o)
+                comb += self.fast_out.eq(sprmap.fast_o)
+
+        return m
+
+
+class DecodeAImm(Elaboratable):
+    """DecodeA immediate from instruction
+
+    decodes register RA, whether immediate-zero, implicit and
+    explicit CSRs
+    """
+
+    def __init__(self, dec):
+        self.dec = dec
+        self.sel_in = Signal(In1Sel, reset_less=True)
+        self.immz_out = Signal(reset_less=True)
+
+    def elaborate(self, platform):
+        m = Module()
+        comb = m.d.comb
+
+        # zero immediate requested
+        ra = Signal(5, reset_less=True)
+        comb += ra.eq(self.dec.RA)
+        with m.If((self.sel_in == In1Sel.RA_OR_ZERO) & (ra == Const(0, 5))):
+            comb += self.immz_out.eq(1)
 
         return m
 
 
         return m
 
@@ -171,25 +334,74 @@ class DecodeB(Elaboratable):
 
     def __init__(self, dec):
         self.dec = dec
 
     def __init__(self, dec):
         self.dec = dec
+        self.sv_rm = SVP64Rec() # SVP64 RM field
         self.sel_in = Signal(In2Sel, reset_less=True)
         self.insn_in = Signal(32, reset_less=True)
         self.sel_in = Signal(In2Sel, reset_less=True)
         self.insn_in = Signal(32, reset_less=True)
-        self.reg_out = Data(5, "reg_b")
-        self.imm_out = Data(64, "imm_b")
+        self.reg_out = Data(7, "reg_b")
+        self.reg_isvec = Signal(1, name="reg_b_isvec") # TODO: in reg_out
         self.fast_out = Data(3, "fast_b")
 
     def elaborate(self, platform):
         m = Module()
         comb = m.d.comb
         self.fast_out = Data(3, "fast_b")
 
     def elaborate(self, platform):
         m = Module()
         comb = m.d.comb
+        op = self.dec.op
+        m.submodules.svdec = svdec = SVP64RegExtra()
+
+        # get the 5-bit reg data before svp64-munging it into 7-bit plus isvec
+        reg = Signal(5, reset_less=True)
 
         # select Register B field
         with m.Switch(self.sel_in):
             with m.Case(In2Sel.RB):
 
         # select Register B field
         with m.Switch(self.sel_in):
             with m.Case(In2Sel.RB):
-                comb += self.reg_out.data.eq(self.dec.RB)
+                comb += reg.eq(self.dec.RB)
                 comb += self.reg_out.ok.eq(1)
             with m.Case(In2Sel.RS):
                 # for M-Form shiftrot
                 comb += self.reg_out.ok.eq(1)
             with m.Case(In2Sel.RS):
                 # for M-Form shiftrot
-                comb += self.reg_out.data.eq(self.dec.RS)
+                comb += reg.eq(self.dec.RS)
                 comb += self.reg_out.ok.eq(1)
                 comb += self.reg_out.ok.eq(1)
+
+        # now do the SVP64 munging.  different from DecodeA only by sv_in2
+
+        extra = self.sv_rm.extra            # SVP64 extra bits 10:18
+        comb += svdec.extra.eq(extra)       # EXTRA field of SVP64 RM
+        comb += svdec.etype.eq(op.SV_Etype) # EXTRA2/3 for this insn
+        comb += svdec.idx.eq(op.sv_in2)     # SVP64 reg #2 (matches in2_sel)
+        comb += svdec.reg_in.eq(reg)        # 5-bit (RA, RS)
+
+        # outputs: 7-bit reg number and whether it's vectorised
+        comb += self.reg_out.data.eq(svdec.reg_out)
+        comb += self.reg_isvec.eq(svdec.isvec)
+
+        # decode SPR2 based on instruction type
+        # BCREG implicitly uses LR or TAR for 2nd reg
+        # CTR however is already in fast_spr1 *not* 2.
+        with m.If(op.internal_op == MicrOp.OP_BCREG):
+            xo9 = self.dec.FormXL.XO[9]  # 3.0B p38 top bit of XO
+            xo5 = self.dec.FormXL.XO[5]  # 3.0B p38
+            with m.If(~xo9):
+                comb += self.fast_out.data.eq(FastRegs.LR)
+                comb += self.fast_out.ok.eq(1)
+            with m.Elif(xo5):
+                comb += self.fast_out.data.eq(FastRegs.TAR)
+                comb += self.fast_out.ok.eq(1)
+
+        return m
+
+
+class DecodeBImm(Elaboratable):
+    """DecodeB immediate from instruction
+    """
+    def __init__(self, dec):
+        self.dec = dec
+        self.sel_in = Signal(In2Sel, reset_less=True)
+        self.imm_out = Data(64, "imm_b")
+
+    def elaborate(self, platform):
+        m = Module()
+        comb = m.d.comb
+
+        # select Register B Immediate
+        with m.Switch(self.sel_in):
             with m.Case(In2Sel.CONST_UI): # unsigned
                 comb += self.imm_out.data.eq(self.dec.UI)
                 comb += self.imm_out.ok.eq(1)
             with m.Case(In2Sel.CONST_UI): # unsigned
                 comb += self.imm_out.data.eq(self.dec.UI)
                 comb += self.imm_out.ok.eq(1)
@@ -233,20 +445,6 @@ class DecodeB(Elaboratable):
                 comb += self.imm_out.data.eq(self.dec.SH32)
                 comb += self.imm_out.ok.eq(1)
 
                 comb += self.imm_out.data.eq(self.dec.SH32)
                 comb += self.imm_out.ok.eq(1)
 
-        # decode SPR2 based on instruction type
-        op = self.dec.op
-        # BCREG implicitly uses LR or TAR for 2nd reg
-        # CTR however is already in fast_spr1 *not* 2.
-        with m.If(op.internal_op == MicrOp.OP_BCREG):
-            xo9 = self.dec.FormXL.XO[9]  # 3.0B p38 top bit of XO
-            xo5 = self.dec.FormXL.XO[5]  # 3.0B p38
-            with m.If(~xo9):
-                comb += self.fast_out.data.eq(FastRegs.LR)
-                comb += self.fast_out.ok.eq(1)
-            with m.Elif(xo5):
-                comb += self.fast_out.data.eq(FastRegs.TAR)
-                comb += self.fast_out.ok.eq(1)
-
         return m
 
 
         return m
 
 
@@ -258,24 +456,43 @@ class DecodeC(Elaboratable):
 
     def __init__(self, dec):
         self.dec = dec
 
     def __init__(self, dec):
         self.dec = dec
+        self.sv_rm = SVP64Rec() # SVP64 RM field
         self.sel_in = Signal(In3Sel, reset_less=True)
         self.insn_in = Signal(32, reset_less=True)
         self.sel_in = Signal(In3Sel, reset_less=True)
         self.insn_in = Signal(32, reset_less=True)
-        self.reg_out = Data(5, "reg_c")
+        self.reg_out = Data(7, "reg_c")
+        self.reg_isvec = Signal(1, name="reg_c_isvec") # TODO: in reg_out
 
     def elaborate(self, platform):
         m = Module()
         comb = m.d.comb
 
     def elaborate(self, platform):
         m = Module()
         comb = m.d.comb
+        op = self.dec.op
+        m.submodules.svdec = svdec = SVP64RegExtra()
+
+        # get the 5-bit reg data before svp64-munging it into 7-bit plus isvec
+        reg = Signal(5, reset_less=True)
 
         # select Register C field
         with m.Switch(self.sel_in):
             with m.Case(In3Sel.RB):
                 # for M-Form shiftrot
 
         # select Register C field
         with m.Switch(self.sel_in):
             with m.Case(In3Sel.RB):
                 # for M-Form shiftrot
-                comb += self.reg_out.data.eq(self.dec.RB)
+                comb += reg.eq(self.dec.RB)
                 comb += self.reg_out.ok.eq(1)
             with m.Case(In3Sel.RS):
                 comb += self.reg_out.ok.eq(1)
             with m.Case(In3Sel.RS):
-                comb += self.reg_out.data.eq(self.dec.RS)
+                comb += reg.eq(self.dec.RS)
                 comb += self.reg_out.ok.eq(1)
 
                 comb += self.reg_out.ok.eq(1)
 
+        # now do the SVP64 munging.  different from DecodeA only by sv_in3
+
+        extra = self.sv_rm.extra            # SVP64 extra bits 10:18
+        comb += svdec.extra.eq(extra)       # EXTRA field of SVP64 RM
+        comb += svdec.etype.eq(op.SV_Etype) # EXTRA2/3 for this insn
+        comb += svdec.idx.eq(op.sv_in3)     # SVP64 reg #3 (matches in3_sel)
+        comb += svdec.reg_in.eq(reg)        # 5-bit (RA, RS)
+
+        # outputs: 7-bit reg number and whether it's vectorised
+        comb += self.reg_out.data.eq(svdec.reg_out)
+        comb += self.reg_isvec.eq(svdec.isvec)
+
         return m
 
 
         return m
 
 
@@ -287,9 +504,11 @@ class DecodeOut(Elaboratable):
 
     def __init__(self, dec):
         self.dec = dec
 
     def __init__(self, dec):
         self.dec = dec
+        self.sv_rm = SVP64Rec() # SVP64 RM field
         self.sel_in = Signal(OutSel, reset_less=True)
         self.insn_in = Signal(32, reset_less=True)
         self.sel_in = Signal(OutSel, reset_less=True)
         self.insn_in = Signal(32, reset_less=True)
-        self.reg_out = Data(5, "reg_o")
+        self.reg_out = Data(7, "reg_o")
+        self.reg_isvec = Signal(1, name="reg_o_isvec") # TODO: in reg_out
         self.spr_out = Data(SPR, "spr_o")
         self.fast_out = Data(3, "fast_o")
 
         self.spr_out = Data(SPR, "spr_o")
         self.fast_out = Data(3, "fast_o")
 
@@ -298,48 +517,41 @@ class DecodeOut(Elaboratable):
         comb = m.d.comb
         m.submodules.sprmap = sprmap = SPRMap()
         op = self.dec.op
         comb = m.d.comb
         m.submodules.sprmap = sprmap = SPRMap()
         op = self.dec.op
+        m.submodules.svdec = svdec = SVP64RegExtra()
+
+        # get the 5-bit reg data before svp64-munging it into 7-bit plus isvec
+        reg = Signal(5, reset_less=True)
 
         # select Register out field
         with m.Switch(self.sel_in):
             with m.Case(OutSel.RT):
 
         # select Register out field
         with m.Switch(self.sel_in):
             with m.Case(OutSel.RT):
-                comb += self.reg_out.data.eq(self.dec.RT)
+                comb += reg.eq(self.dec.RT)
                 comb += self.reg_out.ok.eq(1)
             with m.Case(OutSel.RA):
                 comb += self.reg_out.ok.eq(1)
             with m.Case(OutSel.RA):
-                comb += self.reg_out.data.eq(self.dec.RA)
+                comb += reg.eq(self.dec.RA)
                 comb += self.reg_out.ok.eq(1)
             with m.Case(OutSel.SPR):
                 spr = Signal(10, reset_less=True)
                 comb += spr.eq(decode_spr_num(self.dec.SPR))  # from XFX
                 comb += self.reg_out.ok.eq(1)
             with m.Case(OutSel.SPR):
                 spr = Signal(10, reset_less=True)
                 comb += spr.eq(decode_spr_num(self.dec.SPR))  # from XFX
-                # TODO MTSPR 1st spr (fast)
+                # MFSPR move to SPRs - needs mapping
                 with m.If(op.internal_op == MicrOp.OP_MTSPR):
                 with m.If(op.internal_op == MicrOp.OP_MTSPR):
-                    with m.Switch(spr):
-                        # fast SPRs
-                        with m.Case(SPR.CTR.value):
-                            comb += self.fast_out.data.eq(FastRegs.CTR)
-                            comb += self.fast_out.ok.eq(1)
-                        with m.Case(SPR.LR.value):
-                            comb += self.fast_out.data.eq(FastRegs.LR)
-                            comb += self.fast_out.ok.eq(1)
-                        with m.Case(SPR.TAR.value):
-                            comb += self.fast_out.data.eq(FastRegs.TAR)
-                            comb += self.fast_out.ok.eq(1)
-                        with m.Case(SPR.SRR0.value):
-                            comb += self.fast_out.data.eq(FastRegs.SRR0)
-                            comb += self.fast_out.ok.eq(1)
-                        with m.Case(SPR.SRR1.value):
-                            comb += self.fast_out.data.eq(FastRegs.SRR1)
-                            comb += self.fast_out.ok.eq(1)
-                        with m.Case(SPR.XER.value):
-                            comb += self.fast_out.data.eq(FastRegs.XER)
-                            comb += self.fast_out.ok.eq(1)
-                            pass  # do nothing
-                        # : map to internal SPR numbers
-                        # XXX TODO: dec and tb not to go through mapping.
-                        with m.Default():
-                            comb += sprmap.spr_i.eq(spr)
-                            comb += self.spr_out.data.eq(sprmap.spr_o)
-                            comb += self.spr_out.ok.eq(1)
+                    comb += sprmap.spr_i.eq(spr)
+                    comb += self.spr_out.eq(sprmap.spr_o)
+                    comb += self.fast_out.eq(sprmap.fast_o)
+
+        # now do the SVP64 munging.  different from DecodeA only by sv_out
 
 
+        extra = self.sv_rm.extra            # SVP64 extra bits 10:18
+        comb += svdec.extra.eq(extra)       # EXTRA field of SVP64 RM
+        comb += svdec.etype.eq(op.SV_Etype) # EXTRA2/3 for this insn
+        comb += svdec.idx.eq(op.sv_out)     # SVP64 reg out1 (matches out_sel)
+        comb += svdec.reg_in.eq(reg)        # 5-bit (RA, RS)
+
+        # outputs: 7-bit reg number and whether it's vectorised
+        comb += self.reg_out.data.eq(svdec.reg_out)
+        comb += self.reg_isvec.eq(svdec.isvec)
+
+        # determine Fast Reg
         with m.Switch(op.internal_op):
 
             # BC or BCREG: implicit register (CTR) NOTE: same in DecodeA
         with m.Switch(op.internal_op):
 
             # BC or BCREG: implicit register (CTR) NOTE: same in DecodeA
@@ -360,29 +572,44 @@ class DecodeOut(Elaboratable):
 class DecodeOut2(Elaboratable):
     """DecodeOut2 from instruction
 
 class DecodeOut2(Elaboratable):
     """DecodeOut2 from instruction
 
-    decodes output registers
+    decodes output registers (2nd one).  note that RA is *implicit* below,
+    which now causes problems with SVP64
+
+    TODO: SVP64 is a little more complex, here.  svp64 allows extending
+    by one more destination by having one more EXTRA field.  RA-as-src
+    is not the same as RA-as-dest.  limited in that it's the same first
+    5 bits (from the v3.0B opcode), but still kinda cool.  mostly used
+    for operations that have src-as-dest: mostly this is LD/ST-with-update
+    but there are others.
     """
 
     def __init__(self, dec):
         self.dec = dec
     """
 
     def __init__(self, dec):
         self.dec = dec
+        self.sv_rm = SVP64Rec() # SVP64 RM field
         self.sel_in = Signal(OutSel, reset_less=True)
         self.lk = Signal(reset_less=True)
         self.insn_in = Signal(32, reset_less=True)
         self.sel_in = Signal(OutSel, reset_less=True)
         self.lk = Signal(reset_less=True)
         self.insn_in = Signal(32, reset_less=True)
-        self.reg_out = Data(5, "reg_o")
-        self.fast_out = Data(3, "fast_o")
+        self.reg_out = Data(7, "reg_o2")
+        #self.reg_isvec = Signal(1, name="reg_o2_isvec") # TODO: in reg_out
+        self.fast_out = Data(3, "fast_o2")
 
     def elaborate(self, platform):
         m = Module()
         comb = m.d.comb
 
     def elaborate(self, platform):
         m = Module()
         comb = m.d.comb
+        op = self.dec.op
+        #m.submodules.svdec = svdec = SVP64RegExtra()
 
 
-        # update mode LD/ST uses read-reg A also as an output
-        with m.If(self.dec.op.upd == LDSTMode.update):
-            comb += self.reg_out.eq(self.dec.RA)
-            comb += self.reg_out.ok.eq(1)
+        # get the 5-bit reg data before svp64-munging it into 7-bit plus isvec
+        #reg = Signal(5, reset_less=True)
+
+        if hasattr(self.dec.op, "upd"):
+            # update mode LD/ST uses read-reg A also as an output
+            with m.If(self.dec.op.upd == LDSTMode.update):
+                comb += self.reg_out.data.eq(self.dec.RA)
+                comb += self.reg_out.ok.eq(1)
 
         # B, BC or BCREG: potential implicit register (LR) output
         # these give bl, bcl, bclrl, etc.
 
         # B, BC or BCREG: potential implicit register (LR) output
         # these give bl, bcl, bclrl, etc.
-        op = self.dec.op
         with m.Switch(op.internal_op):
 
             # BC* implicit register (LR)
         with m.Switch(op.internal_op):
 
             # BC* implicit register (LR)
@@ -487,45 +714,73 @@ class DecodeCRIn(Elaboratable):
 
     def __init__(self, dec):
         self.dec = dec
 
     def __init__(self, dec):
         self.dec = dec
+        self.sv_rm = SVP64Rec() # SVP64 RM field
         self.sel_in = Signal(CRInSel, reset_less=True)
         self.insn_in = Signal(32, reset_less=True)
         self.cr_bitfield = Data(3, "cr_bitfield")
         self.cr_bitfield_b = Data(3, "cr_bitfield_b")
         self.cr_bitfield_o = Data(3, "cr_bitfield_o")
         self.sel_in = Signal(CRInSel, reset_less=True)
         self.insn_in = Signal(32, reset_less=True)
         self.cr_bitfield = Data(3, "cr_bitfield")
         self.cr_bitfield_b = Data(3, "cr_bitfield_b")
         self.cr_bitfield_o = Data(3, "cr_bitfield_o")
+        self.cr_isvec = Signal(1, name="cr_isvec")
+        self.cr_b_isvec = Signal(1, name="cr_b_isvec")
+        self.cr_o_isvec = Signal(1, name="cr_o_isvec")
         self.whole_reg = Data(8,  "cr_fxm")
 
     def elaborate(self, platform):
         m = Module()
         self.whole_reg = Data(8,  "cr_fxm")
 
     def elaborate(self, platform):
         m = Module()
+        comb = m.d.comb
+        op = self.dec.op
+        m.submodules.svdec = svdec = SVP64CRExtra()
+        m.submodules.svdec_b = svdec_b = SVP64CRExtra()
+        m.submodules.svdec_o = svdec_o = SVP64CRExtra()
         m.submodules.ppick = ppick = PriorityPicker(8, reverse_i=True,
                                                        reverse_o=True)
 
         m.submodules.ppick = ppick = PriorityPicker(8, reverse_i=True,
                                                        reverse_o=True)
 
-        comb = m.d.comb
-        op = self.dec.op
 
 
+        # get the 3-bit reg data before svp64-munging it into 7-bit plus isvec
+        cr_bf = Signal(3, reset_less=True)
+        cr_bf_b = Signal(3, reset_less=True)
+        cr_bf_o = Signal(3, reset_less=True)
+
+        # index selection slightly different due to shared CR field sigh
+        cr_a_idx = Signal(SVEXTRA)
+        cr_b_idx = Signal(SVEXTRA)
+
+        # zero-initialisation
         comb += self.cr_bitfield.ok.eq(0)
         comb += self.cr_bitfield_b.ok.eq(0)
         comb += self.cr_bitfield.ok.eq(0)
         comb += self.cr_bitfield_b.ok.eq(0)
+        comb += self.cr_bitfield_o.ok.eq(0)
         comb += self.whole_reg.ok.eq(0)
         comb += self.whole_reg.ok.eq(0)
+
+        # these change slighly, when decoding BA/BB.  really should have
+        # their own separate CSV column: sv_cr_in1 and sv_cr_in2, but hey
+        comb += cr_a_idx.eq(op.sv_cr_in)
+        comb += cr_b_idx.eq(SVEXTRA.NONE)
+        with m.If(op.sv_cr_in == SVEXTRA.Idx_1_2.value):
+            comb += cr_a_idx.eq(SVEXTRA.Idx1)
+            comb += cr_b_idx.eq(SVEXTRA.Idx2)
+
+        # select the relevant CR bitfields
         with m.Switch(self.sel_in):
             with m.Case(CRInSel.NONE):
                 pass  # No bitfield activated
             with m.Case(CRInSel.CR0):
         with m.Switch(self.sel_in):
             with m.Case(CRInSel.NONE):
                 pass  # No bitfield activated
             with m.Case(CRInSel.CR0):
-                comb += self.cr_bitfield.data.eq(0)
+                comb += cr_bf.eq(0) # CR0 (MSB0 numbering)
                 comb += self.cr_bitfield.ok.eq(1)
             with m.Case(CRInSel.BI):
                 comb += self.cr_bitfield.ok.eq(1)
             with m.Case(CRInSel.BI):
-                comb += self.cr_bitfield.data.eq(self.dec.BI[2:5])
+                comb += cr_bf.eq(self.dec.BI[2:5])
                 comb += self.cr_bitfield.ok.eq(1)
             with m.Case(CRInSel.BFA):
                 comb += self.cr_bitfield.ok.eq(1)
             with m.Case(CRInSel.BFA):
-                comb += self.cr_bitfield.data.eq(self.dec.FormX.BFA)
+                comb += cr_bf.eq(self.dec.FormX.BFA)
                 comb += self.cr_bitfield.ok.eq(1)
             with m.Case(CRInSel.BA_BB):
                 comb += self.cr_bitfield.ok.eq(1)
             with m.Case(CRInSel.BA_BB):
-                comb += self.cr_bitfield.data.eq(self.dec.BA[2:5])
+                comb += cr_bf.eq(self.dec.BA[2:5])
                 comb += self.cr_bitfield.ok.eq(1)
                 comb += self.cr_bitfield.ok.eq(1)
-                comb += self.cr_bitfield_b.data.eq(self.dec.BB[2:5])
+                comb += cr_bf_b.eq(self.dec.BB[2:5])
                 comb += self.cr_bitfield_b.ok.eq(1)
                 comb += self.cr_bitfield_b.ok.eq(1)
-                comb += self.cr_bitfield_o.data.eq(self.dec.BT[2:5])
+                comb += cr_bf_o.eq(self.dec.BT[2:5])
                 comb += self.cr_bitfield_o.ok.eq(1)
             with m.Case(CRInSel.BC):
                 comb += self.cr_bitfield_o.ok.eq(1)
             with m.Case(CRInSel.BC):
-                comb += self.cr_bitfield.data.eq(self.dec.BC[2:5])
+                comb += cr_bf.eq(self.dec.BC[2:5])
                 comb += self.cr_bitfield.ok.eq(1)
             with m.Case(CRInSel.WHOLE_REG):
                 comb += self.whole_reg.ok.eq(1)
                 comb += self.cr_bitfield.ok.eq(1)
             with m.Case(CRInSel.WHOLE_REG):
                 comb += self.whole_reg.ok.eq(1)
@@ -539,6 +794,34 @@ class DecodeCRIn(Elaboratable):
                     # otherwise use all of it
                     comb += self.whole_reg.data.eq(0xff)
 
                     # otherwise use all of it
                     comb += self.whole_reg.data.eq(0xff)
 
+        # now do the SVP64 munging.
+        extra = self.sv_rm.extra            # SVP64 extra bits 10:18
+
+        comb += svdec.extra.eq(extra)       # EXTRA field of SVP64 RM
+        comb += svdec.etype.eq(op.SV_Etype) # EXTRA2/3 for this insn
+        comb += svdec.cr_in.eq(cr_bf)        # 3-bit (BFA)
+
+        comb += svdec_b.extra.eq(extra)       # EXTRA field of SVP64 RM
+        comb += svdec_b.etype.eq(op.SV_Etype) # EXTRA2/3 for this insn
+        comb += svdec_b.cr_in.eq(cr_bf_b)    # 3-bit (BB[2:5])
+
+        comb += svdec_o.extra.eq(extra)       # EXTRA field of SVP64 RM
+        comb += svdec_o.etype.eq(op.SV_Etype) # EXTRA2/3 for this insn
+        comb += svdec_o.cr_in.eq(cr_bf_o)    # 3-bit (BT[2:5])
+
+        # indices are slightly different, BA/BB mess sorted above
+        comb += svdec.idx.eq(cr_a_idx)       # SVP64 CR in A
+        comb += svdec_b.idx.eq(cr_b_idx)     # SVP64 CR in B
+        comb += svdec_o.idx.eq(op.sv_cr_out) # SVP64 CR out
+
+        # outputs: 7-bit reg number and whether it's vectorised
+        comb += self.cr_bitfield.data.eq(svdec.cr_out)
+        comb += self.cr_isvec.eq(svdec.isvec)
+        comb += self.cr_bitfield_b.data.eq(svdec_b.cr_out)
+        comb += self.cr_b_isvec.eq(svdec_b.isvec)
+        comb += self.cr_bitfield_o.data.eq(svdec_o.cr_out)
+        comb += self.cr_o_isvec.eq(svdec_o.isvec)
+
         return m
 
 
         return m
 
 
@@ -551,6 +834,7 @@ class DecodeCROut(Elaboratable):
 
     def __init__(self, dec):
         self.dec = dec
 
     def __init__(self, dec):
         self.dec = dec
+        self.sv_rm = SVP64Rec() # SVP64 RM field
         self.rc_in = Signal(reset_less=True)
         self.sel_in = Signal(CROutSel, reset_less=True)
         self.insn_in = Signal(32, reset_less=True)
         self.rc_in = Signal(reset_less=True)
         self.sel_in = Signal(CROutSel, reset_less=True)
         self.insn_in = Signal(32, reset_less=True)
@@ -570,7 +854,7 @@ class DecodeCROut(Elaboratable):
             with m.Case(CROutSel.NONE):
                 pass  # No bitfield activated
             with m.Case(CROutSel.CR0):
             with m.Case(CROutSel.NONE):
                 pass  # No bitfield activated
             with m.Case(CROutSel.CR0):
-                comb += self.cr_bitfield.data.eq(0)
+                comb += self.cr_bitfield.data.eq(0) # CR0 (MSB0 numbering)
                 comb += self.cr_bitfield.ok.eq(self.rc_in)  # only when RC=1
             with m.Case(CROutSel.BF):
                 comb += self.cr_bitfield.data.eq(self.dec.FormX.BF)
                 comb += self.cr_bitfield.ok.eq(self.rc_in)  # only when RC=1
             with m.Case(CROutSel.BF):
                 comb += self.cr_bitfield.data.eq(self.dec.FormX.BF)
@@ -586,7 +870,10 @@ class DecodeCROut(Elaboratable):
                     with m.If(move_one):
                         # must one-hot the FXM field
                         comb += ppick.i.eq(self.dec.FXM)
                     with m.If(move_one):
                         # must one-hot the FXM field
                         comb += ppick.i.eq(self.dec.FXM)
-                        comb += self.whole_reg.data.eq(ppick.o)
+                        with m.If(ppick.en_o):
+                            comb += self.whole_reg.data.eq(ppick.o)
+                        with m.Else():
+                            comb += self.whole_reg.data.eq(0b00000001) # CR7
                     with m.Else():
                         comb += self.whole_reg.data.eq(self.dec.FXM)
                 with m.Else():
                     with m.Else():
                         comb += self.whole_reg.data.eq(self.dec.FXM)
                 with m.Else():
@@ -595,8 +882,200 @@ class DecodeCROut(Elaboratable):
 
         return m
 
 
         return m
 
+# dictionary of Input Record field names that, if they exist,
+# will need a corresponding CSV Decoder file column (actually, PowerOp)
+# to be decoded (this includes the single bit names)
+record_names = {'insn_type': 'internal_op',
+                'fn_unit': 'function_unit',
+                'rc': 'rc_sel',
+                'oe': 'rc_sel',
+                'zero_a': 'in1_sel',
+                'imm_data': 'in2_sel',
+                'invert_in': 'inv_a',
+                'invert_out': 'inv_out',
+                'rc': 'cr_out',
+                'oe': 'cr_in',
+                'output_carry': 'cry_out',
+                'input_carry': 'cry_in',
+                'is_32bit': 'is_32b',
+                'is_signed': 'sgn',
+                'lk': 'lk',
+                'data_len': 'ldst_len',
+                'byte_reverse': 'br',
+                'sign_extend': 'sgn_ext',
+                'ldst_mode': 'upd',
+                }
+
+
+class PowerDecodeSubset(Elaboratable):
+    """PowerDecodeSubset: dynamic subset decoder
+
+    only fields actually requested are copied over. hence, "subset" (duh).
+    """
+    def __init__(self, dec, opkls=None, fn_name=None, final=False, state=None):
+
+        self.sv_rm = SVP64Rec(name="dec_svp64") # SVP64 RM field
+        self.final = final
+        self.opkls = opkls
+        self.fn_name = fn_name
+        if opkls is None:
+            opkls = Decode2ToOperand
+        self.do = opkls(fn_name)
+        col_subset = self.get_col_subset(self.do)
+
+        # only needed for "main" PowerDecode2
+        if not self.final:
+            self.e = Decode2ToExecute1Type(name=self.fn_name, do=self.do)
+
+        # create decoder if one not already given
+        if dec is None:
+            dec = create_pdecode(name=fn_name, col_subset=col_subset,
+                                      row_subset=self.rowsubsetfn)
+        self.dec = dec
+
+        # state information needed by the Decoder
+        if state is None:
+            state = CoreState("dec2")
+        self.state = state
+
+    def get_col_subset(self, do):
+        subset = {'sv_cr_in', 'sv_cr_out', 'SV_Etype',
+                  'cr_in', 'cr_out', 'rc_sel'} # needed, non-optional
+        for k, v in record_names.items():
+            if hasattr(do, k):
+                subset.add(v)
+        print ("get_col_subset", self.fn_name, do.fields, subset)
+        return subset
+
+    def rowsubsetfn(self, opcode, row):
+        return row['unit'] == self.fn_name
+
+    def ports(self):
+        return self.dec.ports() + self.e.ports() + self.sv_rm.ports()
+
+    def needs_field(self, field, op_field):
+        if self.final:
+            do = self.do
+        else:
+            do = self.e_tmp.do
+        return hasattr(do, field) and self.op_get(op_field) is not None
+
+    def do_copy(self, field, val, final=False):
+        if final or self.final:
+            do = self.do
+        else:
+            do = self.e_tmp.do
+        if hasattr(do, field) and val is not None:
+            return getattr(do, field).eq(val)
+        return []
+
+    def op_get(self, op_field):
+        return getattr(self.dec.op, op_field, None)
+
+    def elaborate(self, platform):
+        m = Module()
+        comb = m.d.comb
+        state = self.state
+        op, do = self.dec.op, self.do
+        msr, cia = state.msr, state.pc
+
+        # fill in for a normal instruction (not an exception)
+        # copy over if non-exception, non-privileged etc. is detected
+        if not self.final:
+            if self.fn_name is None:
+                name = "tmp"
+            else:
+                name = self.fn_name + "tmp"
+            self.e_tmp = Decode2ToExecute1Type(name=name, opkls=self.opkls)
+
+        # set up submodule decoders
+        m.submodules.dec = self.dec
+        m.submodules.dec_rc = dec_rc = DecodeRC(self.dec)
+        m.submodules.dec_oe = dec_oe = DecodeOE(self.dec)
+        m.submodules.dec_cr_in = self.dec_cr_in = DecodeCRIn(self.dec)
+        m.submodules.dec_cr_out = self.dec_cr_out = DecodeCROut(self.dec)
+
+        # copy instruction through...
+        for i in [do.insn,
+                  dec_rc.insn_in, dec_oe.insn_in,
+                  self.dec_cr_in.insn_in, self.dec_cr_out.insn_in]:
+            comb += i.eq(self.dec.opcode_in)
+
+        # ...and subdecoders' input fields
+        comb += dec_rc.sel_in.eq(op.rc_sel)
+        comb += dec_oe.sel_in.eq(op.rc_sel)  # XXX should be OE sel
+        comb += self.dec_cr_in.sel_in.eq(op.cr_in)
+        comb += self.dec_cr_in.sv_rm.eq(self.sv_rm)
+        comb += self.dec_cr_out.sv_rm.eq(self.sv_rm)
+        comb += self.dec_cr_out.sel_in.eq(op.cr_out)
+        comb += self.dec_cr_out.rc_in.eq(dec_rc.rc_out.data)
+
+        # copy "state" over
+        comb += self.do_copy("msr", msr)
+        comb += self.do_copy("cia", cia)
+
+        # set up instruction type
+        # no op: defaults to OP_ILLEGAL
+        comb += self.do_copy("insn_type", self.op_get("internal_op"))
+
+        # function unit for decoded instruction: requires minor redirect
+        # for SPR set/get
+        fn = self.op_get("function_unit")
+        spr = Signal(10, reset_less=True)
+        comb += spr.eq(decode_spr_num(self.dec.SPR)) # from XFX
+
+        # for first test only forward SPRs 18 and 19 to MMU, when
+        # operation is MTSPR or MFSPR.  TODO: add other MMU SPRs
+        with m.If(((self.dec.op.internal_op == MicrOp.OP_MTSPR) |
+                   (self.dec.op.internal_op == MicrOp.OP_MFSPR)) &
+                  ((spr == SPR.DSISR) | (spr == SPR.DAR))):
+            comb += self.do_copy("fn_unit", Function.MMU)
+        with m.Else():
+            comb += self.do_copy("fn_unit",fn)
+
+        # immediates
+        if self.needs_field("zero_a", "in1_sel"):
+            m.submodules.dec_ai = dec_ai = DecodeAImm(self.dec)
+            comb += dec_ai.sel_in.eq(op.in1_sel)
+            comb += self.do_copy("zero_a", dec_ai.immz_out)  # RA==0 detected
+        if self.needs_field("imm_data", "in2_sel"):
+            m.submodules.dec_bi = dec_bi = DecodeBImm(self.dec)
+            comb += dec_bi.sel_in.eq(op.in2_sel)
+            comb += self.do_copy("imm_data", dec_bi.imm_out) # imm in RB
+
+        # rc and oe out
+        comb += self.do_copy("rc", dec_rc.rc_out)
+        comb += self.do_copy("oe", dec_oe.oe_out)
+
+        # CR in/out
+        comb += self.do_copy("read_cr_whole", self.dec_cr_in.whole_reg)
+        comb += self.do_copy("write_cr_whole", self.dec_cr_out.whole_reg)
+        comb += self.do_copy("write_cr0", self.dec_cr_out.cr_bitfield.ok)
+
+        comb += self.do_copy("input_cr", self.op_get("cr_in"))   # CR in
+        comb += self.do_copy("output_cr", self.op_get("cr_out"))  # CR out
+
+        # decoded/selected instruction flags
+        comb += self.do_copy("data_len", self.op_get("ldst_len"))
+        comb += self.do_copy("invert_in", self.op_get("inv_a"))
+        comb += self.do_copy("invert_out", self.op_get("inv_out"))
+        comb += self.do_copy("input_carry", self.op_get("cry_in"))
+        comb += self.do_copy("output_carry", self.op_get("cry_out"))
+        comb += self.do_copy("is_32bit", self.op_get("is_32b"))
+        comb += self.do_copy("is_signed", self.op_get("sgn"))
+        lk = self.op_get("lk")
+        if lk is not None:
+            with m.If(lk):
+                comb += self.do_copy("lk", self.dec.LK)  # XXX TODO: accessor
+
+        comb += self.do_copy("byte_reverse", self.op_get("br"))
+        comb += self.do_copy("sign_extend", self.op_get("sgn_ext"))
+        comb += self.do_copy("ldst_mode", self.op_get("upd"))  # LD/ST mode
+
+        return m
+
 
 
-class PowerDecode2(Elaboratable):
+class PowerDecode2(PowerDecodeSubset):
     """PowerDecode2: the main instruction decoder.
 
     whilst PowerDecode is responsible for decoding the actual opcode, this
     """PowerDecode2: the main instruction decoder.
 
     whilst PowerDecode is responsible for decoding the actual opcode, this
@@ -614,82 +1093,90 @@ class PowerDecode2(Elaboratable):
     instructions are illegal (or privileged) or not, and instead of
     just leaving at that, *replacing* the instruction to execute with
     a suitable alternative (trap).
     instructions are illegal (or privileged) or not, and instead of
     just leaving at that, *replacing* the instruction to execute with
     a suitable alternative (trap).
-    """
 
 
-    def __init__(self, dec):
-
-        self.dec = dec
-        self.e = Decode2ToExecute1Type()
+    LDSTExceptions are done the cycle _after_ they're detected (after
+    they come out of LDSTCompUnit).  basically despite the instruction
+    being decoded, the results of the decode are completely ignored
+    and "exception.happened" used to set the "actual" instruction to
+    "OP_TRAP".  the LDSTException data structure gets filled in,
+    in the CompTrapOpSubset and that's what it fills in SRR.
 
 
-        # state information needed by the Decoder (TODO: this as a Record)
-        self.state = CoreState("dec2")
+    to make this work, TestIssuer must notice "exception.happened"
+    after the (failed) LD/ST and copies the LDSTException info from
+    the output, into here (PowerDecoder2).  without incrementing PC.
+    """
 
 
-    def ports(self):
-        return self.dec.ports() + self.e.ports()
+    def __init__(self, dec, opkls=None, fn_name=None, final=False, state=None):
+        super().__init__(dec, opkls, fn_name, final, state)
+        self.exc = LDSTException("dec2_exc")
+
+    def get_col_subset(self, opkls):
+        subset = super().get_col_subset(opkls)
+        subset.add("asmcode")
+        subset.add("in1_sel")
+        subset.add("in2_sel")
+        subset.add("in3_sel")
+        subset.add("out_sel")
+        subset.add("sv_in1")
+        subset.add("sv_in2")
+        subset.add("sv_in3")
+        subset.add("sv_out")
+        subset.add("sv_cr_in")
+        subset.add("sv_cr_out")
+        subset.add("SV_Etype")
+        subset.add("SV_Ptype")
+        subset.add("lk")
+        subset.add("internal_op")
+        subset.add("form")
+        return subset
 
     def elaborate(self, platform):
 
     def elaborate(self, platform):
-        m = Module()
+        m = super().elaborate(platform)
         comb = m.d.comb
         comb = m.d.comb
+        state = self.state
         e_out, op, do_out = self.e, self.dec.op, self.e.do
         e_out, op, do_out = self.e, self.dec.op, self.e.do
-        msr, cia = self.state.msr, self.state.pc
+        dec_spr, msr, cia, ext_irq = state.dec, state.msr, state.pc, state.eint
+        e = self.e_tmp
+        do = e.do
 
         # fill in for a normal instruction (not an exception)
         # copy over if non-exception, non-privileged etc. is detected
 
         # fill in for a normal instruction (not an exception)
         # copy over if non-exception, non-privileged etc. is detected
-        e = Decode2ToExecute1Type()
-        do = e.do
 
         # set up submodule decoders
 
         # set up submodule decoders
-        m.submodules.dec = self.dec
         m.submodules.dec_a = dec_a = DecodeA(self.dec)
         m.submodules.dec_b = dec_b = DecodeB(self.dec)
         m.submodules.dec_c = dec_c = DecodeC(self.dec)
         m.submodules.dec_o = dec_o = DecodeOut(self.dec)
         m.submodules.dec_o2 = dec_o2 = DecodeOut2(self.dec)
         m.submodules.dec_a = dec_a = DecodeA(self.dec)
         m.submodules.dec_b = dec_b = DecodeB(self.dec)
         m.submodules.dec_c = dec_c = DecodeC(self.dec)
         m.submodules.dec_o = dec_o = DecodeOut(self.dec)
         m.submodules.dec_o2 = dec_o2 = DecodeOut2(self.dec)
-        m.submodules.dec_rc = dec_rc = DecodeRC(self.dec)
-        m.submodules.dec_oe = dec_oe = DecodeOE(self.dec)
-        m.submodules.dec_cr_in = dec_cr_in = DecodeCRIn(self.dec)
-        m.submodules.dec_cr_out = dec_cr_out = DecodeCROut(self.dec)
 
         # copy instruction through...
         for i in [do.insn, dec_a.insn_in, dec_b.insn_in,
 
         # copy instruction through...
         for i in [do.insn, dec_a.insn_in, dec_b.insn_in,
-                  dec_c.insn_in, dec_o.insn_in, dec_o2.insn_in, dec_rc.insn_in,
-                  dec_oe.insn_in, dec_cr_in.insn_in, dec_cr_out.insn_in]:
+                  dec_c.insn_in, dec_o.insn_in, dec_o2.insn_in]:
             comb += i.eq(self.dec.opcode_in)
 
             comb += i.eq(self.dec.opcode_in)
 
+        # ... and svp64 rm
+        for i in [dec_a.insn_in, dec_b.insn_in,
+                  dec_c.insn_in, dec_o.insn_in, dec_o2.insn_in]:
+            comb += i.eq(self.sv_rm)
+
         # ...and subdecoders' input fields
         comb += dec_a.sel_in.eq(op.in1_sel)
         comb += dec_b.sel_in.eq(op.in2_sel)
         comb += dec_c.sel_in.eq(op.in3_sel)
         comb += dec_o.sel_in.eq(op.out_sel)
         comb += dec_o2.sel_in.eq(op.out_sel)
         # ...and subdecoders' input fields
         comb += dec_a.sel_in.eq(op.in1_sel)
         comb += dec_b.sel_in.eq(op.in2_sel)
         comb += dec_c.sel_in.eq(op.in3_sel)
         comb += dec_o.sel_in.eq(op.out_sel)
         comb += dec_o2.sel_in.eq(op.out_sel)
-        comb += dec_o2.lk.eq(do.lk)
-        comb += dec_rc.sel_in.eq(op.rc_sel)
-        comb += dec_oe.sel_in.eq(op.rc_sel)  # XXX should be OE sel
-        comb += dec_cr_in.sel_in.eq(op.cr_in)
-        comb += dec_cr_out.sel_in.eq(op.cr_out)
-        comb += dec_cr_out.rc_in.eq(dec_rc.rc_out.data)
-
-        # copy "state" over
-        comb += do.msr.eq(msr)
-        comb += do.cia.eq(cia)
-
-        # set up instruction, pick fn unit
-        # no op: defaults to OP_ILLEGAL
-        comb += do.insn_type.eq(op.internal_op)
-        comb += do.fn_unit.eq(op.function_unit)
+        if hasattr(do, "lk"):
+            comb += dec_o2.lk.eq(do.lk)
 
         # registers a, b, c and out and out2 (LD/ST EA)
 
         # registers a, b, c and out and out2 (LD/ST EA)
-        comb += e.read_reg1.eq(dec_a.reg_out)
-        comb += e.read_reg2.eq(dec_b.reg_out)
-        comb += e.read_reg3.eq(dec_c.reg_out)
-        comb += e.write_reg.eq(dec_o.reg_out)
-        comb += e.write_ea.eq(dec_o2.reg_out)
-        comb += do.imm_data.eq(dec_b.imm_out)  # immediate in RB (usually)
-        comb += do.zero_a.eq(dec_a.immz_out)  # RA==0 detected
-
-        # rc and oe out
-        comb += do.rc.eq(dec_rc.rc_out)
-        comb += do.oe.eq(dec_oe.oe_out)
+        for to_reg, fromreg in (
+            (e.read_reg1, dec_a.reg_out),
+            (e.read_reg2, dec_b.reg_out),
+            (e.read_reg3, dec_c.reg_out),
+            (e.write_reg, dec_o.reg_out),
+            (e.write_ea, dec_o2.reg_out)):
+            comb += to_reg.data.eq(fromreg.data)
+            comb += to_reg.ok.eq(fromreg.ok)
 
         # SPRs out
         comb += e.read_spr1.eq(dec_a.spr_out)
 
         # SPRs out
         comb += e.read_spr1.eq(dec_a.spr_out)
@@ -702,33 +1189,13 @@ class PowerDecode2(Elaboratable):
         comb += e.write_fast2.eq(dec_o2.fast_out)
 
         # condition registers (CR)
         comb += e.write_fast2.eq(dec_o2.fast_out)
 
         # condition registers (CR)
-        comb += e.read_cr1.eq(dec_cr_in.cr_bitfield)
-        comb += e.read_cr2.eq(dec_cr_in.cr_bitfield_b)
-        comb += e.read_cr3.eq(dec_cr_in.cr_bitfield_o)
-        comb += e.write_cr.eq(dec_cr_out.cr_bitfield)
-
-        comb += do.read_cr_whole.eq(dec_cr_in.whole_reg)
-        comb += do.write_cr_whole.eq(dec_cr_out.whole_reg)
-        comb += do.write_cr0.eq(dec_cr_out.cr_bitfield.ok)
-
-        # decoded/selected instruction flags
-        comb += do.data_len.eq(op.ldst_len)
-        comb += do.invert_in.eq(op.inv_a)
-        comb += do.invert_out.eq(op.inv_out)
-        comb += do.input_carry.eq(op.cry_in)   # carry comes in
-        comb += do.output_carry.eq(op.cry_out)  # carry goes out
-        comb += do.is_32bit.eq(op.is_32b)
-        comb += do.is_signed.eq(op.sgn)
-        with m.If(op.lk):
-            comb += do.lk.eq(self.dec.LK)  # XXX TODO: accessor
-
-        comb += do.byte_reverse.eq(op.br)
-        comb += do.sign_extend.eq(op.sgn_ext)
-        comb += do.ldst_mode.eq(op.upd)  # LD/ST mode (update, cache-inhibit)
-
-        # These should be removed eventually
-        comb += do.input_cr.eq(op.cr_in)   # condition reg comes in
-        comb += do.output_cr.eq(op.cr_out)  # condition reg goes in
+        for to_reg, fromreg in (
+            (e.read_cr1, self.dec_cr_in.cr_bitfield),
+            (e.read_cr2, self.dec_cr_in.cr_bitfield_b),
+            (e.read_cr3, self.dec_cr_in.cr_bitfield_o),
+            (e.write_cr, self.dec_cr_out.cr_bitfield)):
+            comb += to_reg.data.eq(fromreg.data)
+            comb += to_reg.ok.eq(fromreg.ok)
 
         # sigh this is exactly the sort of thing for which the
         # decoder is designed to not need.  MTSPR, MFSPR and others need
 
         # sigh this is exactly the sort of thing for which the
         # decoder is designed to not need.  MTSPR, MFSPR and others need
@@ -743,19 +1210,66 @@ class PowerDecode2(Elaboratable):
         # set the trapaddr to 0x700 for a td/tw/tdi/twi operation
         with m.If(op.internal_op == MicrOp.OP_TRAP):
             # *DO NOT* call self.trap here.  that would reset absolutely
         # set the trapaddr to 0x700 for a td/tw/tdi/twi operation
         with m.If(op.internal_op == MicrOp.OP_TRAP):
             # *DO NOT* call self.trap here.  that would reset absolutely
-            # rverything including destroying read of RA and RB.
-            comb += do.trapaddr.eq(0x70)    # addr=0x700 (strip first nibble)
+            # everything including destroying read of RA and RB.
+            comb += self.do_copy("trapaddr", 0x70) # strip first nibble
+
+        ####################
+        # ok so the instruction's been decoded, blah blah, however
+        # now we need to determine if it's actually going to go ahead...
+        # *or* if in fact it's a privileged operation, whether there's
+        # an external interrupt, etc. etc.  this is a simple priority
+        # if-elif-elif sequence.  decrement takes highest priority,
+        # EINT next highest, privileged operation third.
+
+        # check if instruction is privileged
+        is_priv_insn = instr_is_priv(m, op.internal_op, e.do.insn)
+
+        # different IRQ conditions
+        ext_irq_ok = Signal()
+        dec_irq_ok = Signal()
+        priv_ok = Signal()
+        illeg_ok = Signal()
+        exc = self.exc
+
+        comb += ext_irq_ok.eq(ext_irq & msr[MSR.EE]) # v3.0B p944 (MSR.EE)
+        comb += dec_irq_ok.eq(dec_spr[63] & msr[MSR.EE]) # 6.5.11 p1076
+        comb += priv_ok.eq(is_priv_insn & msr[MSR.PR])
+        comb += illeg_ok.eq(op.internal_op == MicrOp.OP_ILLEGAL)
+
+        # LD/ST exceptions.  TestIssuer copies the exception info at us
+        # after a failed LD/ST.
+        with m.If(exc.happened):
+            with m.If(exc.alignment):
+                self.trap(m, TT.PRIV, 0x600)
+            with m.Elif(exc.instr_fault):
+                with m.If(exc.segment_fault):
+                    self.trap(m, TT.PRIV, 0x480)
+                with m.Else():
+                    # pass exception info to trap to create SRR1
+                    self.trap(m, TT.MEMEXC, 0x400, exc)
+            with m.Else():
+                with m.If(exc.segment_fault):
+                    self.trap(m, TT.PRIV, 0x380)
+                with m.Else():
+                    self.trap(m, TT.PRIV, 0x300)
+
+        # decrement counter (v3.0B p1099): TODO 32-bit version (MSR.LPCR)
+        with m.Elif(dec_irq_ok):
+            self.trap(m, TT.DEC, 0x900)   # v3.0B 6.5 p1065
 
 
-        # TODO: get msr, then can do privileged instruction
-        with m.If(instr_is_priv(m, op.internal_op, e.do.insn) & msr[MSR.PR]):
-            # privileged instruction trap
+        # external interrupt? only if MSR.EE set
+        with m.Elif(ext_irq_ok):
+            self.trap(m, TT.EINT, 0x500)
+
+        # privileged instruction trap
+        with m.Elif(priv_ok):
             self.trap(m, TT.PRIV, 0x700)
 
         # illegal instruction must redirect to trap. this is done by
         # *overwriting* the decoded instruction and starting again.
         # (note: the same goes for interrupts and for privileged operations,
         # just with different trapaddr and traptype)
             self.trap(m, TT.PRIV, 0x700)
 
         # illegal instruction must redirect to trap. this is done by
         # *overwriting* the decoded instruction and starting again.
         # (note: the same goes for interrupts and for privileged operations,
         # just with different trapaddr and traptype)
-        with m.Elif(op.internal_op == MicrOp.OP_ILLEGAL):
+        with m.Elif(illeg_ok):
             # illegal instruction trap
             self.trap(m, TT.ILLEG, 0x700)
 
             # illegal instruction trap
             self.trap(m, TT.ILLEG, 0x700)
 
@@ -763,6 +1277,9 @@ class PowerDecode2(Elaboratable):
         with m.Else():
             comb += e_out.eq(e)
 
         with m.Else():
             comb += e_out.eq(e)
 
+        ####################
+        # follow-up after trap/irq to set up SRR0/1
+
         # trap: (note e.insn_type so this includes OP_ILLEGAL) set up fast regs
         # Note: OP_SC could actually be modified to just be a trap
         with m.If((do_out.insn_type == MicrOp.OP_TRAP) |
         # trap: (note e.insn_type so this includes OP_ILLEGAL) set up fast regs
         # Note: OP_SC could actually be modified to just be a trap
         with m.If((do_out.insn_type == MicrOp.OP_TRAP) |
@@ -783,23 +1300,28 @@ class PowerDecode2(Elaboratable):
             comb += e_out.read_fast2.data.eq(FastRegs.SRR1)  # constant: SRR1
             comb += e_out.read_fast2.ok.eq(1)
 
             comb += e_out.read_fast2.data.eq(FastRegs.SRR1)  # constant: SRR1
             comb += e_out.read_fast2.ok.eq(1)
 
+        # annoying simulator bug
+        if hasattr(e_out, "asmcode") and hasattr(self.dec.op, "asmcode"):
+            comb += e_out.asmcode.eq(self.dec.op.asmcode)
+
         return m
 
         return m
 
-    def trap(self, m, traptype, trapaddr):
+    def trap(self, m, traptype, trapaddr, exc=None):
         """trap: this basically "rewrites" the decoded instruction as a trap
         """
         comb = m.d.comb
         """trap: this basically "rewrites" the decoded instruction as a trap
         """
         comb = m.d.comb
-        op, do, e = self.dec.op, self.e.do, self.e
+        op, e = self.dec.op, self.e
         comb += e.eq(0)  # reset eeeeeverything
 
         # start again
         comb += e.eq(0)  # reset eeeeeverything
 
         # start again
-        comb += do.insn.eq(self.dec.opcode_in)
-        comb += do.insn_type.eq(MicrOp.OP_TRAP)
-        comb += do.fn_unit.eq(Function.TRAP)
-        comb += do.trapaddr.eq(trapaddr >> 4)  # cut bottom 4 bits
-        comb += do.traptype.eq(traptype)  # request type
-        comb += do.msr.eq(self.state.msr)  # copy of MSR "state"
-        comb += do.cia.eq(self.state.pc)  # copy of PC "state"
+        comb += self.do_copy("insn", self.dec.opcode_in, True)
+        comb += self.do_copy("insn_type", MicrOp.OP_TRAP, True)
+        comb += self.do_copy("fn_unit", Function.TRAP, True)
+        comb += self.do_copy("trapaddr", trapaddr >> 4, True) # bottom 4 bits
+        comb += self.do_copy("traptype", traptype, True)  # request type
+        comb += self.do_copy("ldst_exc", exc, True)  # request type
+        comb += self.do_copy("msr", self.state.msr, True) # copy of MSR "state"
+        comb += self.do_copy("cia", self.state.pc, True)  # copy of PC "state"
 
 
 def get_rdflags(e, cu):
 
 
 def get_rdflags(e, cu):