nope - need it to be zero if not identified as svp64
[soc.git] / src / soc / decoder / power_decoder2.py
index 20c40075617bae978113b3fd8259552c3800afc0..2f6c0bdec572db0ab605e83087ec7b72758e704c 100644 (file)
@@ -8,28 +8,32 @@ over-riding the internal opcode when an exception is needed.
 
 from nmigen import Module, Elaboratable, Signal, Mux, Const, Cat, Repl, Record
 from nmigen.cli import rtlil
 
 from nmigen import Module, Elaboratable, Signal, Mux, Const, Cat, Repl, Record
 from nmigen.cli import rtlil
+from soc.regfile.regfiles import XERRegs
 
 
+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_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 (InternalOp, CryIn, Function,
+from soc.decoder.power_enums import (MicrOp, CryIn, Function,
                                      CRInSel, CROutSel,
                                      LdstLen, In1Sel, In2Sel, In3Sel,
                                      CRInSel, CROutSel,
                                      LdstLen, In1Sel, In2Sel, In3Sel,
-                                     OutSel, SPR, RC)
-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.regfile.regfiles import FastRegs
+from soc.consts import TT
+from soc.config.state import CoreState
+from soc.regfile.util import spr_to_fast
 
 
-# see traptype (and trap main_stage.py)
-
-TT_FP = 1<<0
-TT_PRIV = 1<<1
-TT_TRAP = 1<<2
-TT_ADDR = 1<<3
-TT_ILLEG = 1<<4
 
 def decode_spr_num(spr):
     return Cat(spr[5:10], spr[0:5])
 
 def decode_spr_num(spr):
     return Cat(spr[5:10], spr[0:5])
@@ -39,41 +43,180 @@ def instr_is_priv(m, op, insn):
     """determines if the instruction is privileged or not
     """
     comb = m.d.comb
     """determines if the instruction is privileged or not
     """
     comb = m.d.comb
-    Signal = is_priv_insn(reset_less=True)
+    is_priv_insn = Signal(reset_less=True)
     with m.Switch(op):
     with m.Switch(op):
-        with m.Case(InternalOp.OP_ATTN)  : comb += is_priv_insn.eq(1)
-        with m.Case(InternalOp.OP_MFMSR) : comb += is_priv_insn.eq(1)
-        with m.Case(InternalOp.OP_MTMSRD): comb += is_priv_insn.eq(1)
-        with m.Case(InternalOp.OP_MTMSR): comb += is_priv_insn.eq(1)
-        with m.Case(InternalOp.OP_RFID)  : comb += is_priv_insn.eq(1)
-        with m.Case(InternalOp.OP_TLBIE) : comb += is_priv_insn.eq(1)
-    with m.If(op == OP_MFSPR | op == OP_MTSPR):
-        with m.If(insn[20]): # field XFX.spr[-1] i think
+        with m.Case(MicrOp.OP_ATTN, MicrOp.OP_MFMSR, MicrOp.OP_MTMSRD,
+                    MicrOp.OP_MTMSR, MicrOp.OP_RFID):
             comb += is_priv_insn.eq(1)
             comb += is_priv_insn.eq(1)
+        # XXX TODO
+        #with m.Case(MicrOp.OP_TLBIE) : comb += is_priv_insn.eq(1)
+        with m.Case(MicrOp.OP_MFSPR, MicrOp.OP_MTSPR):
+            with m.If(insn[20]):  # field XFX.spr[-1] i think
+                comb += is_priv_insn.eq(1)
     return is_priv_insn
 
 
 class SPRMap(Elaboratable):
     return is_priv_insn
 
 
 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):
     """
 
     def __init__(self, dec):
@@ -81,13 +224,14 @@ class DecodeA(Elaboratable):
         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.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.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
+        reg = self.reg_out
         m.submodules.sprmap = sprmap = SPRMap()
 
         # select Register A field
         m.submodules.sprmap = sprmap = SPRMap()
 
         # select Register A field
@@ -96,63 +240,66 @@ 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 += 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)
+            comb += reg.data.eq(ra)
+            comb += reg.ok.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 += self.reg_out.ok.eq(1)
+            comb += reg.data.eq(rs)
+            comb += reg.ok.eq(1)
 
         # decode Fast-SPR based on instruction type
 
         # decode Fast-SPR based on instruction type
-        op = self.dec.op
-        # BC or BCREG: potential implicit register (CTR) NOTE: same in DecodeOut
-        with m.If(op.internal_op == InternalOp.OP_BC):
-            with m.If(~self.dec.BO[2]): # 3.0B p38 BO2=0, use CTR reg
-                comb += self.fast_out.data.eq(FastRegs.CTR) # constant: CTR
-                comb += self.fast_out.ok.eq(1)
-        with m.Elif(op.internal_op == InternalOp.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 & ~xo5):
-                comb += self.fast_out.data.eq(FastRegs.CTR) # constant: CTR
-                comb += self.fast_out.ok.eq(1)
+        with m.Switch(op.internal_op):
 
 
-        # MFSPR move from SPRs
-        with m.If(op.internal_op == InternalOp.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):
+            # BC or BCREG: implicit register (CTR) NOTE: same in DecodeOut
+            with m.Case(MicrOp.OP_BC):
+                with m.If(~self.dec.BO[2]):  # 3.0B p38 BO2=0, use CTR reg
+                    # constant: CTR
                     comb += self.fast_out.data.eq(FastRegs.CTR)
                     comb += self.fast_out.ok.eq(1)
                     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)
+            with m.Case(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 & ~xo5):
+                    # constant: CTR
+                    comb += self.fast_out.data.eq(FastRegs.CTR)
                     comb += self.fast_out.ok.eq(1)
                     comb += self.fast_out.ok.eq(1)
-                with m.Case(SPR.XER.value):
-                    pass # do nothing
-                # XXX TODO: 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)
 
 
+            # MFSPR move from SPRs
+            with m.Case(MicrOp.OP_MFSPR):
+                spr = Signal(10, reset_less=True)
+                comb += spr.eq(decode_spr_num(self.dec.SPR))  # from XFX
+                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
 
@@ -170,70 +317,99 @@ class DecodeB(Elaboratable):
         self.dec = dec
         self.sel_in = Signal(In2Sel, reset_less=True)
         self.insn_in = Signal(32, reset_less=True)
         self.dec = dec
         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
+        reg = self.reg_out
 
         # 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 += self.reg_out.ok.eq(1)
+                comb += reg.data.eq(self.dec.RB)
+                comb += reg.ok.eq(1)
             with m.Case(In2Sel.RS):
             with m.Case(In2Sel.RS):
-                comb += self.reg_out.data.eq(self.dec.RS) # for M-Form shiftrot
-                comb += self.reg_out.ok.eq(1)
-            with m.Case(In2Sel.CONST_UI):
+                # for M-Form shiftrot
+                comb += reg.data.eq(self.dec.RS)
+                comb += reg.ok.eq(1)
+
+        # 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)
                 comb += self.imm_out.data.eq(self.dec.UI)
                 comb += self.imm_out.ok.eq(1)
-            with m.Case(In2Sel.CONST_SI): # TODO: sign-extend here?
-                comb += self.imm_out.data.eq(
-                    exts(self.dec.SI, 16, 64))
+            with m.Case(In2Sel.CONST_SI):  # sign-extended 16-bit
+                si = Signal(16, reset_less=True)
+                comb += si.eq(self.dec.SI)
+                comb += self.imm_out.data.eq(exts(si, 16, 64))
                 comb += self.imm_out.ok.eq(1)
                 comb += self.imm_out.ok.eq(1)
-            with m.Case(In2Sel.CONST_UI_HI):
-                comb += self.imm_out.data.eq(self.dec.UI<<16)
+            with m.Case(In2Sel.CONST_SI_HI):  # sign-extended 16+16=32 bit
+                si_hi = Signal(32, reset_less=True)
+                comb += si_hi.eq(self.dec.SI << 16)
+                comb += self.imm_out.data.eq(exts(si_hi, 32, 64))
                 comb += self.imm_out.ok.eq(1)
                 comb += self.imm_out.ok.eq(1)
-            with m.Case(In2Sel.CONST_SI_HI): # TODO: sign-extend here?
-                comb += self.imm_out.data.eq(self.dec.SI<<16)
-                comb += self.imm_out.data.eq(
-                    exts(self.dec.SI << 16, 32, 64))
+            with m.Case(In2Sel.CONST_UI_HI): # unsigned
+                ui = Signal(16, reset_less=True)
+                comb += ui.eq(self.dec.UI)
+                comb += self.imm_out.data.eq(ui << 16)
                 comb += self.imm_out.ok.eq(1)
                 comb += self.imm_out.ok.eq(1)
-            with m.Case(In2Sel.CONST_LI):
-                comb += self.imm_out.data.eq(self.dec.LI<<2)
+            with m.Case(In2Sel.CONST_LI): # sign-extend 24+2=26 bit
+                li = Signal(26, reset_less=True)
+                comb += li.eq(self.dec.LI << 2)
+                comb += self.imm_out.data.eq(exts(li, 26, 64))
                 comb += self.imm_out.ok.eq(1)
                 comb += self.imm_out.ok.eq(1)
-            with m.Case(In2Sel.CONST_BD):
-                comb += self.imm_out.data.eq(self.dec.BD<<2)
+            with m.Case(In2Sel.CONST_BD): # sign-extend (14+2)=16 bit
+                bd = Signal(16, reset_less=True)
+                comb += bd.eq(self.dec.BD << 2)
+                comb += self.imm_out.data.eq(exts(bd, 16, 64))
                 comb += self.imm_out.ok.eq(1)
                 comb += self.imm_out.ok.eq(1)
-            with m.Case(In2Sel.CONST_DS):
-                comb += self.imm_out.data.eq(self.dec.DS<<2)
+            with m.Case(In2Sel.CONST_DS): # sign-extended (14+2=16) bit
+                ds = Signal(16, reset_less=True)
+                comb += ds.eq(self.dec.DS << 2)
+                comb += self.imm_out.data.eq(exts(ds, 16, 64))
                 comb += self.imm_out.ok.eq(1)
                 comb += self.imm_out.ok.eq(1)
-            with m.Case(In2Sel.CONST_M1):
-                comb += self.imm_out.data.eq(~Const(0, 64)) # all 1s
+            with m.Case(In2Sel.CONST_M1): # signed (-1)
+                comb += self.imm_out.data.eq(~Const(0, 64))  # all 1s
                 comb += self.imm_out.ok.eq(1)
                 comb += self.imm_out.ok.eq(1)
-            with m.Case(In2Sel.CONST_SH):
+            with m.Case(In2Sel.CONST_SH): # unsigned - for shift
                 comb += self.imm_out.data.eq(self.dec.sh)
                 comb += self.imm_out.ok.eq(1)
                 comb += self.imm_out.data.eq(self.dec.sh)
                 comb += self.imm_out.ok.eq(1)
-            with m.Case(In2Sel.CONST_SH32):
+            with m.Case(In2Sel.CONST_SH32): # unsigned - for shift
                 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 == InternalOp.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
 
 
@@ -252,15 +428,18 @@ class DecodeC(Elaboratable):
     def elaborate(self, platform):
         m = Module()
         comb = m.d.comb
     def elaborate(self, platform):
         m = Module()
         comb = m.d.comb
+        op = self.dec.op
+        reg = self.reg_out
 
         # select Register C field
         with m.Switch(self.sel_in):
             with m.Case(In3Sel.RB):
 
         # select Register C field
         with m.Switch(self.sel_in):
             with m.Case(In3Sel.RB):
-                comb += self.reg_out.data.eq(self.dec.RB) # for M-Form shiftrot
-                comb += self.reg_out.ok.eq(1)
+                # for M-Form shiftrot
+                comb += reg.data.eq(self.dec.RB)
+                comb += reg.ok.eq(1)
             with m.Case(In3Sel.RS):
             with m.Case(In3Sel.RS):
-                comb += self.reg_out.data.eq(self.dec.RS)
-                comb += self.reg_out.ok.eq(1)
+                comb += reg.data.eq(self.dec.RS)
+                comb += reg.ok.eq(1)
 
         return m
 
 
         return m
 
@@ -284,58 +463,39 @@ 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
+        reg = self.reg_out
 
         # 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 += self.reg_out.ok.eq(1)
+                comb += reg.data.eq(self.dec.RT)
+                comb += reg.ok.eq(1)
             with m.Case(OutSel.RA):
             with m.Case(OutSel.RA):
-                comb += self.reg_out.data.eq(self.dec.RA)
-                comb += self.reg_out.ok.eq(1)
+                comb += reg.data.eq(self.dec.RA)
+                comb += reg.ok.eq(1)
             with m.Case(OutSel.SPR):
                 spr = Signal(10, reset_less=True)
             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)
-                with m.If(op.internal_op == InternalOp.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):
-                            pass # do nothing
-                        # XXX TODO: 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)
-
-        # BC or BCREG: potential implicit register (CTR) NOTE: same in DecodeA
-        op = self.dec.op
-        with m.If((op.internal_op == InternalOp.OP_BC) |
-                  (op.internal_op == InternalOp.OP_BCREG)):
-            with m.If(~self.dec.BO[2]): # 3.0B p38 BO2=0, use CTR reg
-                comb += self.fast_out.data.eq(FastRegs.CTR) # constant: CTR
-                comb += self.fast_out.ok.eq(1)
+                comb += spr.eq(decode_spr_num(self.dec.SPR))  # from XFX
+                # MFSPR move to SPRs - needs mapping
+                with m.If(op.internal_op == MicrOp.OP_MTSPR):
+                    comb += sprmap.spr_i.eq(spr)
+                    comb += self.spr_out.eq(sprmap.spr_o)
+                    comb += self.fast_out.eq(sprmap.fast_o)
+
+        # determine Fast Reg
+        with m.Switch(op.internal_op):
+
+            # BC or BCREG: implicit register (CTR) NOTE: same in DecodeA
+            with m.Case(MicrOp.OP_BC, MicrOp.OP_BCREG):
+                with m.If(~self.dec.BO[2]):  # 3.0B p38 BO2=0, use CTR reg
+                    # constant: CTR
+                    comb += self.fast_out.data.eq(FastRegs.CTR)
+                    comb += self.fast_out.ok.eq(1)
 
 
-        # RFID 1st spr (fast)
-        with m.If(op.internal_op == InternalOp.OP_RFID):
-            comb += self.fast_out.data.eq(FastRegs.SRR0) # constant: SRR0
-            comb += self.fast_out.ok.eq(1)
+            # RFID 1st spr (fast)
+            with m.Case(MicrOp.OP_RFID):
+                comb += self.fast_out.data.eq(FastRegs.SRR0)  # constant: SRR0
+                comb += self.fast_out.ok.eq(1)
 
         return m
 
 
         return m
 
@@ -343,7 +503,15 @@ 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):
     """
 
     def __init__(self, dec):
@@ -351,29 +519,37 @@ class DecodeOut2(Elaboratable):
         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(5, "reg_o2")
+        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):
-            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)
 
 
-        # BC or BCREG: potential implicit register (LR) output
-        op = self.dec.op
-        with m.If((op.internal_op == InternalOp.OP_BC) |
-                  (op.internal_op == InternalOp.OP_BCREG)):
-            with m.If(self.lk): # "link" mode
-                comb += self.fast_out.data.eq(FastRegs.LR) # constant: LR
-                comb += self.fast_out.ok.eq(1)
+        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)
 
 
-        # RFID 2nd spr (fast)
-        with m.If(op.internal_op == InternalOp.OP_RFID):
-                comb += self.fast_out.data.eq(FastRegs.SRR1) # constant: SRR1
+        # B, BC or BCREG: potential implicit register (LR) output
+        # these give bl, bcl, bclrl, etc.
+        with m.Switch(op.internal_op):
+
+            # BC* implicit register (LR)
+            with m.Case(MicrOp.OP_BC, MicrOp.OP_B, MicrOp.OP_BCREG):
+                with m.If(self.lk):  # "link" mode
+                    comb += self.fast_out.data.eq(FastRegs.LR)  # constant: LR
+                    comb += self.fast_out.ok.eq(1)
+
+            # RFID 2nd spr (fast)
+            with m.Case(MicrOp.OP_RFID):
+                comb += self.fast_out.data.eq(FastRegs.SRR1)  # constant: SRR1
                 comb += self.fast_out.ok.eq(1)
 
         return m
                 comb += self.fast_out.ok.eq(1)
 
         return m
@@ -384,6 +560,7 @@ class DecodeRC(Elaboratable):
 
     decodes Record bit Rc
     """
 
     decodes Record bit Rc
     """
+
     def __init__(self, dec):
         self.dec = dec
         self.sel_in = Signal(RC, reset_less=True)
     def __init__(self, dec):
         self.dec = dec
         self.sel_in = Signal(RC, reset_less=True)
@@ -420,6 +597,7 @@ class DecodeOE(Elaboratable):
     -- actual POWER9 does if we set it on those instructions, for now we
     -- test that further down when assigning to the multiplier oe input.
     """
     -- actual POWER9 does if we set it on those instructions, for now we
     -- test that further down when assigning to the multiplier oe input.
     """
+
     def __init__(self, dec):
         self.dec = dec
         self.sel_in = Signal(RC, reset_less=True)
     def __init__(self, dec):
         self.dec = dec
         self.sel_in = Signal(RC, reset_less=True)
@@ -429,15 +607,33 @@ class DecodeOE(Elaboratable):
     def elaborate(self, platform):
         m = Module()
         comb = m.d.comb
     def elaborate(self, platform):
         m = Module()
         comb = m.d.comb
+        op = self.dec.op
 
 
-        # select OE bit out field
-        with m.Switch(self.sel_in):
-            with m.Case(RC.RC):
-                comb += self.oe_out.data.eq(self.dec.OE)
-                comb += self.oe_out.ok.eq(1)
+        with m.Switch(op.internal_op):
+
+            # mulhw, mulhwu, mulhd, mulhdu - these *ignore* OE
+            # also rotate
+            # XXX ARGH! ignoring OE causes incompatibility with microwatt
+            # http://lists.libre-soc.org/pipermail/libre-soc-dev/2020-August/000302.html
+            with m.Case(MicrOp.OP_MUL_H64, MicrOp.OP_MUL_H32,
+                        MicrOp.OP_EXTS, MicrOp.OP_CNTZ,
+                        MicrOp.OP_SHL, MicrOp.OP_SHR, MicrOp.OP_RLC,
+                        MicrOp.OP_LOAD, MicrOp.OP_STORE,
+                        MicrOp.OP_RLCL, MicrOp.OP_RLCR,
+                        MicrOp.OP_EXTSWSLI):
+                pass
+
+            # all other ops decode OE field
+            with m.Default():
+                # select OE bit out field
+                with m.Switch(self.sel_in):
+                    with m.Case(RC.RC):
+                        comb += self.oe_out.data.eq(self.dec.OE)
+                        comb += self.oe_out.ok.eq(1)
 
         return m
 
 
         return m
 
+
 class DecodeCRIn(Elaboratable):
     """Decodes input CR from instruction
 
 class DecodeCRIn(Elaboratable):
     """Decodes input CR from instruction
 
@@ -452,20 +648,27 @@ class DecodeCRIn(Elaboratable):
         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_bitfield = Data(3, "cr_bitfield")
         self.cr_bitfield_b = Data(3, "cr_bitfield_b")
         self.cr_bitfield_o = Data(3, "cr_bitfield_o")
-        self.whole_reg = Signal(reset_less=True)
+        self.whole_reg = Data(8,  "cr_fxm")
 
     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.ppick = ppick = PriorityPicker(8, reverse_i=True,
+                                                       reverse_o=True)
 
 
+        # 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.whole_reg.eq(0)
+        comb += self.cr_bitfield_o.ok.eq(0)
+        comb += self.whole_reg.ok.eq(0)
+
+        # select the relevant CR bitfields
         with m.Switch(self.sel_in):
             with m.Case(CRInSel.NONE):
         with m.Switch(self.sel_in):
             with m.Case(CRInSel.NONE):
-                pass # No bitfield activated
+                pass  # No bitfield activated
             with m.Case(CRInSel.CR0):
             with m.Case(CRInSel.CR0):
-                comb += self.cr_bitfield.data.eq(0)
+                comb += self.cr_bitfield.data.eq(0) # CR0 (MSB0 numbering)
                 comb += self.cr_bitfield.ok.eq(1)
             with m.Case(CRInSel.BI):
                 comb += self.cr_bitfield.data.eq(self.dec.BI[2:5])
                 comb += self.cr_bitfield.ok.eq(1)
             with m.Case(CRInSel.BI):
                 comb += self.cr_bitfield.data.eq(self.dec.BI[2:5])
@@ -484,7 +687,16 @@ class DecodeCRIn(Elaboratable):
                 comb += self.cr_bitfield.data.eq(self.dec.BC[2:5])
                 comb += self.cr_bitfield.ok.eq(1)
             with m.Case(CRInSel.WHOLE_REG):
                 comb += self.cr_bitfield.data.eq(self.dec.BC[2:5])
                 comb += self.cr_bitfield.ok.eq(1)
             with m.Case(CRInSel.WHOLE_REG):
-                comb += self.whole_reg.eq(1)
+                comb += self.whole_reg.ok.eq(1)
+                move_one = Signal(reset_less=True)
+                comb += move_one.eq(self.insn_in[20]) # MSB0 bit 11
+                with m.If((op.internal_op == MicrOp.OP_MFCR) & 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.Else():
+                    # otherwise use all of it
+                    comb += self.whole_reg.data.eq(0xff)
 
         return m
 
 
         return m
 
@@ -502,20 +714,24 @@ class DecodeCROut(Elaboratable):
         self.sel_in = Signal(CROutSel, reset_less=True)
         self.insn_in = Signal(32, reset_less=True)
         self.cr_bitfield = Data(3, "cr_bitfield")
         self.sel_in = Signal(CROutSel, reset_less=True)
         self.insn_in = Signal(32, reset_less=True)
         self.cr_bitfield = Data(3, "cr_bitfield")
-        self.whole_reg = Signal(reset_less=True)
+        self.whole_reg = Data(8,  "cr_fxm")
 
     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.ppick = ppick = PriorityPicker(8, reverse_i=True,
+                                                       reverse_o=True)
 
         comb += self.cr_bitfield.ok.eq(0)
 
         comb += self.cr_bitfield.ok.eq(0)
-        comb += self.whole_reg.eq(0)
+        comb += self.whole_reg.ok.eq(0)
+
         with m.Switch(self.sel_in):
             with m.Case(CROutSel.NONE):
         with m.Switch(self.sel_in):
             with m.Case(CROutSel.NONE):
-                pass # No bitfield activated
+                pass  # No bitfield activated
             with m.Case(CROutSel.CR0):
             with m.Case(CROutSel.CR0):
-                comb += self.cr_bitfield.data.eq(0)
-                comb += self.cr_bitfield.ok.eq(self.rc_in) # only when RC=1
+                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(1)
             with m.Case(CROutSel.BF):
                 comb += self.cr_bitfield.data.eq(self.dec.FormX.BF)
                 comb += self.cr_bitfield.ok.eq(1)
@@ -523,85 +739,386 @@ class DecodeCROut(Elaboratable):
                 comb += self.cr_bitfield.data.eq(self.dec.FormXL.BT[2:5])
                 comb += self.cr_bitfield.ok.eq(1)
             with m.Case(CROutSel.WHOLE_REG):
                 comb += self.cr_bitfield.data.eq(self.dec.FormXL.BT[2:5])
                 comb += self.cr_bitfield.ok.eq(1)
             with m.Case(CROutSel.WHOLE_REG):
-                comb += self.whole_reg.eq(1)
+                comb += self.whole_reg.ok.eq(1)
+                move_one = Signal(reset_less=True)
+                comb += move_one.eq(self.insn_in[20])
+                with m.If((op.internal_op == MicrOp.OP_MTCRF)):
+                    with m.If(move_one):
+                        # must one-hot the FXM field
+                        comb += ppick.i.eq(self.dec.FXM)
+                        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():
+                    # otherwise use all of it
+                    comb += self.whole_reg.data.eq(0xff)
 
         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
 
 
-class XerBits:
-    def __init__(self):
-        self.ca = Signal(2, reset_less=True)
-        self.ov = Signal(2, reset_less=True)
-        self.so = Signal(reset_less=True)
+        # state information needed by the Decoder
+        if state is None:
+            state = CoreState("dec2")
+        self.state = state
+
+    def get_col_subset(self, do):
+        subset = { '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):
 
     def ports(self):
-        return [self.ca, self.ov, self.so]
+        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)
 
 
-class PowerDecode2(Elaboratable):
+        # 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)
 
 
-    def __init__(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)
 
 
-        self.dec = dec
-        self.e = Decode2ToExecute1Type()
-        self.valid = Signal() # sync signal
+        # ...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_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
 
 
-    def ports(self):
-        return self.dec.ports() + self.e.ports()
+
+class PowerDecode2(PowerDecodeSubset):
+    """PowerDecode2: the main instruction decoder.
+
+    whilst PowerDecode is responsible for decoding the actual opcode, this
+    module encapsulates further specialist, sparse information and
+    expansion of fields that is inconvenient to have in the CSV files.
+    for example: the encoding of the immediates, which are detected
+    and expanded out to their full value from an annotated (enum)
+    representation.
+
+    implicit register usage is also set up, here.  for example: OP_BC
+    requires implicitly reading CTR, OP_RFID requires implicitly writing
+    to SRR1 and so on.
+
+    in addition, PowerDecoder2 is responsible for detecting whether
+    instructions are illegal (or privileged) or not, and instead of
+    just leaving at that, *replacing* the instruction to execute with
+    a suitable alternative (trap).
+
+    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.
+
+    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 __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")
+
+        self.cr_out_isvec = Signal(1, name="cr_out_isvec")
+        self.cr_in_isvec = Signal(1, name="cr_in_isvec")
+        self.cr_in_b_isvec = Signal(1, name="cr_in_b_isvec")
+        self.cr_in_o_isvec = Signal(1, name="cr_in_o_isvec")
+        self.in1_isvec = Signal(1, name="reg_a_isvec")
+        self.in2_isvec = Signal(1, name="reg_b_isvec")
+        self.in3_isvec = Signal(1, name="reg_c_isvec")
+        self.o_isvec = Signal(1, name="reg_o_isvec")
+        self.o2_isvec = Signal(1, name="reg_o2_isvec")
+
+    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
-        e, op, do = self.e, self.dec.op, self.e.do
+        state = self.state
+        e_out, op, do_out = self.e, self.dec.op, self.e.do
+        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
 
         # 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)
+
+        # and SVP64 Extra decoders
+        m.submodules.crout_svdec = crout_svdec = SVP64CRExtra()
+        m.submodules.crin_svdec = crin_svdec = SVP64CRExtra()
+        m.submodules.crin_svdec_b = crin_svdec_b = SVP64CRExtra()
+        m.submodules.crin_svdec_o = crin_svdec_o = SVP64CRExtra()
+        m.submodules.in1_svdec = in1_svdec = SVP64RegExtra()
+        m.submodules.in2_svdec = in2_svdec = SVP64RegExtra()
+        m.submodules.in3_svdec = in3_svdec = SVP64RegExtra()
+        m.submodules.o_svdec = o_svdec = SVP64RegExtra()
+        m.submodules.o2_svdec = o2_svdec = SVP64RegExtra()
+
+        # get the 5-bit reg data before svp64-munging it into 7-bit plus isvec
+        reg = Signal(5, reset_less=True)
 
         # 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)
 
+        # 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
+
+        #######
+        # CR out
+        comb += crout_svdec.idx.eq(op.sv_cr_out)  # SVP64 CR out
+        comb += self.cr_out_isvec.eq(crout_svdec.isvec)
+
+        #######
+        # CR in - index selection slightly different due to shared CR field sigh
+        cr_a_idx = Signal(SVEXTRA)
+        cr_b_idx = Signal(SVEXTRA)
+
+        # these change slightly, 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)
+
+        comb += self.cr_in_isvec.eq(crin_svdec.isvec)
+        comb += self.cr_in_b_isvec.eq(crin_svdec_b.isvec)
+        comb += self.cr_in_o_isvec.eq(crin_svdec_o.isvec)
+
+        # indices are slightly different, BA/BB mess sorted above
+        comb += crin_svdec.idx.eq(cr_a_idx)       # SVP64 CR in A
+        comb += crin_svdec_b.idx.eq(cr_b_idx)     # SVP64 CR in B
+        comb += crin_svdec_o.idx.eq(op.sv_cr_out) # SVP64 CR out
+
         # ...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)
-
-        # set up instruction, pick fn unit
-        comb += e.nia.eq(0)    # XXX TODO (or remove? not sure yet)
-        comb += do.insn_type.eq(op.internal_op) # no op: defaults to OP_ILLEGAL
-        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, svdec in (
+            (e.read_reg1, dec_a.reg_out, in1_svdec),
+            (e.read_reg2, dec_b.reg_out, in2_svdec),
+            (e.read_reg3, dec_c.reg_out, in3_svdec),
+            (e.write_reg, dec_o.reg_out, o_svdec),
+            (e.write_ea, dec_o2.reg_out, o2_svdec)):
+            comb += svdec.extra.eq(extra)        # EXTRA field of SVP64 RM
+            comb += svdec.etype.eq(op.SV_Etype)  # EXTRA2/3 for this insn
+            comb += svdec.reg_in.eq(fromreg.data) # 3-bit (CR0/BC/BFA)
+            comb += to_reg.data.eq(svdec.reg_out) # 7-bit output
+            comb += to_reg.ok.eq(fromreg.ok)
+
+        comb += in1_svdec.idx.eq(op.sv_in1)  # SVP64 reg #1 (matches in1_sel)
+        comb += in2_svdec.idx.eq(op.sv_in2)  # SVP64 reg #2 (matches in2_sel)
+        comb += in3_svdec.idx.eq(op.sv_in3)  # SVP64 reg #3 (matches in3_sel)
+        comb += o_svdec.idx.eq(op.sv_out)    # SVP64 output (matches out_sel)
+        # XXX TODO - work out where this should come from.  the problem is
+        # that LD-with-update is implied (computed from "is instruction in
+        # "update mode" rather than specified cleanly as its own CSV column
+        #comb += o2_svdec.idx.eq(op.sv_out)    # SVP64 output (implicit)
+
+        comb += self.in1_isvec.eq(in1_svdec.isvec)
+        comb += self.in2_isvec.eq(in2_svdec.isvec)
+        comb += self.in3_isvec.eq(in3_svdec.isvec)
+        comb += self.o_isvec.eq(o_svdec.isvec)
+        comb += self.o2_isvec.eq(o2_svdec.isvec)
 
         # SPRs out
         comb += e.read_spr1.eq(dec_a.spr_out)
 
         # SPRs out
         comb += e.read_spr1.eq(dec_a.spr_out)
@@ -614,123 +1131,208 @@ 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_a.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.update.eq(op.upd) # LD/ST "update" mode.
-
-        # 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, svdec in (
+            (e.read_cr1, self.dec_cr_in.cr_bitfield, crin_svdec),
+            (e.read_cr2, self.dec_cr_in.cr_bitfield_b, crin_svdec_b),
+            (e.read_cr3, self.dec_cr_in.cr_bitfield_o, crin_svdec_o),
+            (e.write_cr, self.dec_cr_out.cr_bitfield, crout_svdec)):
+            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(fromreg.data) # 3-bit (CR0/BC/BFA)
+            comb += to_reg.data.eq(svdec.cr_out) # 7-bit output
+            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
         # access to the XER bits.  however setting e.oe is not appropriate
 
         # sigh this is exactly the sort of thing for which the
         # decoder is designed to not need.  MTSPR, MFSPR and others need
         # access to the XER bits.  however setting e.oe is not appropriate
-        with m.If(op.internal_op == InternalOp.OP_MFSPR):
-            comb += e.xer_in.eq(1)
-        with m.If(op.internal_op == InternalOp.OP_MTSPR):
+        with m.If(op.internal_op == MicrOp.OP_MFSPR):
+            comb += e.xer_in.eq(0b111) # SO, CA, OV
+        with m.If(op.internal_op == MicrOp.OP_CMP):
+            comb += e.xer_in.eq(1<<XERRegs.SO) # SO
+        with m.If(op.internal_op == MicrOp.OP_MTSPR):
             comb += e.xer_out.eq(1)
 
         # set the trapaddr to 0x700 for a td/tw/tdi/twi operation
             comb += e.xer_out.eq(1)
 
         # set the trapaddr to 0x700 for a td/tw/tdi/twi operation
-        with m.If(op.internal_op == InternalOp.OP_TRAP):
-            comb += do.trapaddr.eq(0x70)    # addr=0x700 (strip first nibble)
+        with m.If(op.internal_op == MicrOp.OP_TRAP):
+            # *DO NOT* call self.trap here.  that would reset absolutely
+            # 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
+
+        # 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)
 
         # 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.If(op.internal_op == InternalOp.OP_ILLEGAL):
+        with m.Elif(illeg_ok):
             # illegal instruction trap
             # illegal instruction trap
-            self.trap(m, TT_ILLEG, 0x700)
+            self.trap(m, TT.ILLEG, 0x700)
+
+        # no exception, just copy things to the output
+        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
 
         # 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.insn_type == InternalOp.OP_TRAP) |
-                  (do.insn_type == InternalOp.OP_SC)):
+        with m.If((do_out.insn_type == MicrOp.OP_TRAP) |
+                  (do_out.insn_type == MicrOp.OP_SC)):
             # TRAP write fast1 = SRR0
             # TRAP write fast1 = SRR0
-            comb += e.write_fast1.data.eq(FastRegs.SRR0) # constant: SRR0
-            comb += e.write_fast1.ok.eq(1)
+            comb += e_out.write_fast1.data.eq(FastRegs.SRR0)  # constant: SRR0
+            comb += e_out.write_fast1.ok.eq(1)
             # TRAP write fast2 = SRR1
             # TRAP write fast2 = SRR1
-            comb += e.write_fast2.data.eq(FastRegs.SRR1) # constant: SRR1
-            comb += e.write_fast2.ok.eq(1)
+            comb += e_out.write_fast2.data.eq(FastRegs.SRR1)  # constant: SRR1
+            comb += e_out.write_fast2.ok.eq(1)
 
         # RFID: needs to read SRR0/1
 
         # RFID: needs to read SRR0/1
-        with m.If(do.insn_type == InternalOp.OP_RFID):
+        with m.If(do_out.insn_type == MicrOp.OP_RFID):
             # TRAP read fast1 = SRR0
             # TRAP read fast1 = SRR0
-            comb += e.read_fast1.data.eq(FastRegs.SRR0) # constant: SRR0
-            comb += e.read_fast1.ok.eq(1)
+            comb += e_out.read_fast1.data.eq(FastRegs.SRR0)  # constant: SRR0
+            comb += e_out.read_fast1.ok.eq(1)
             # TRAP read fast2 = SRR1
             # TRAP read fast2 = SRR1
-            comb += e.read_fast2.data.eq(FastRegs.SRR1) # constant: SRR1
-            comb += e.read_fast2.ok.eq(1)
+            comb += e_out.read_fast2.data.eq(FastRegs.SRR1)  # constant: SRR1
+            comb += e_out.read_fast2.ok.eq(1)
 
 
-        return m
+        # annoying simulator bug
+        if hasattr(e_out, "asmcode") and hasattr(self.dec.op, "asmcode"):
+            comb += e_out.asmcode.eq(self.dec.op.asmcode)
 
 
-        # TODO: get msr, then can do privileged instruction
-        with m.If(instr_is_priv(m, op.internal_op, e.insn) & msr[MSR_PR]):
-            # privileged instruction trap
-            self.trap(m, TT_PRIV, 0x700)
         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
-        e, op, do = self.e, self.dec.op, self.e.do
-        comb += e.eq(0) # reset eeeeeverything
+        op, e = self.dec.op, self.e
+        comb += e.eq(0)  # reset eeeeeverything
+
         # start again
         # start again
-        comb += do.insn.eq(self.dec.opcode_in)
-        comb += do.insn_type.eq(InternalOp.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
-
-    def regspecmap_read(self, regfile, regname):
-        """regspecmap_read: provides PowerDecode2 with an encoding relationship
-        to Function Unit port regfiles (read-enable, read regnum, write regnum)
-        regfile and regname arguments are fields 1 and 2 from a given regspec.
-        """
-        return regspec_decode_read(self.e, regfile, regname)
+        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 regspecmap_write(self, regfile, regname):
-        """regspecmap_write: provides PowerDecode2 with an encoding relationship
-        to Function Unit port regfiles (write port, write regnum)
-        regfile and regname arguments are fields 1 and 2 from a given regspec.
-        """
-        return regspec_decode_write(self.e, regfile, regname)
 
 
-    def rdflags(self, cu):
-        rdl = []
-        for idx in range(cu.n_src):
-            regfile, regname, _ = cu.get_in_spec(idx)
-            rdflag, read = self.regspecmap_read(regfile, regname)
-            rdl.append(rdflag)
-        print ("rdflags", rdl)
-        return Cat(*rdl)
+# SVP64 Prefix fields: see https://libre-soc.org/openpower/sv/svp64/
+# identifies if an instruction is a SVP64-encoded prefix, and extracts
+# the 24-bit SVP64 context (RM) if it is
+class SVP64PowerDecoder(Elaboratable):
+
+    def __init__(self):
+        self.opcode_in = Signal(32, reset_less=True)
+        self.raw_opcode_in = Signal.like(self.opcode_in, reset_less=True)
+        self.is_svp64_mode = Signal(1, reset_less=True)
+        self.svp64_rm = Signal(24, reset_less=True)
+        self.bigendian = Signal(reset_less=True)
+
+    def elaborate(self, platform):
+        m = Module()
+        comb = m.d.comb
+        # sigh copied this from TopPowerDecoder
+        # raw opcode in assumed to be in LE order: byte-reverse it to get BE
+        raw_le = self.raw_opcode_in
+        l = []
+        for i in range(0, 32, 8):
+            l.append(raw_le[i:i+8])
+        l.reverse()
+        raw_be = Cat(*l)
+        comb += self.opcode_in.eq(Mux(self.bigendian, raw_be, raw_le))
+
+        # start identifying if the incoming opcode is SVP64 prefix)
+        major = Signal(6, reset_less=True)
+
+        comb += major.eq(self.opcode_in[26:32])
+        comb += self.is_svp64_mode.eq((major == Const(1, 6)) & # EXT01
+                                      self.opcode_in[31-7] & # identifier
+                                      self.opcode_in[31-9])  # bits
+
+        # now grab the 24-bit ReMap context bits,
+        rmfields = [6, 8] + list(range(10,32)) # SVP64 24-bit RM
+        l = []
+        for idx in rmfields:
+            l.append(self.opcode_in[32-idx])
+        with m.If(self.is_svp64_mode):
+            comb += self.svp64_rm.eq(Cat(*l))
+
+        return m
+
+    def ports(self):
+        return [self.opcode_in, self.raw_opcode_in, self.is_svp64_mode,
+                self.svp64_rm, self.bigendian]
+
+def get_rdflags(e, cu):
+    rdl = []
+    for idx in range(cu.n_src):
+        regfile, regname, _ = cu.get_in_spec(idx)
+        rdflag, read = regspec_decode_read(e, regfile, regname)
+        rdl.append(rdflag)
+    print("rdflags", rdl)
+    return Cat(*rdl)
 
 
 if __name__ == '__main__':
 
 
 if __name__ == '__main__':
+    svp64 = SVP64PowerDecoder()
+    vl = rtlil.convert(svp64, ports=svp64.ports())
+    with open("svp64_dec.il", "w") as f:
+        f.write(vl)
     pdecode = create_pdecode()
     dec2 = PowerDecode2(pdecode)
     vl = rtlil.convert(dec2, ports=dec2.ports() + pdecode.ports())
     with open("dec2.il", "w") as f:
         f.write(vl)
     pdecode = create_pdecode()
     dec2 = PowerDecode2(pdecode)
     vl = rtlil.convert(dec2, ports=dec2.ports() + pdecode.ports())
     with open("dec2.il", "w") as f:
         f.write(vl)
-