add SVP64 CR out extending to 7-bit in PowerDecoder2
[soc.git] / src / soc / decoder / power_decoder2.py
index 612a44d83cbd44ec0b8d4f4f1c851ea91d52cc05..4dcf078da16d7f13243dd84a07ca59428cfa6cdf 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,56 +43,201 @@ 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):
         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)
@@ -96,63 +245,80 @@ 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
-        # 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
 
@@ -168,72 +334,117 @@ 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):
                 comb += self.reg_out.ok.eq(1)
             with m.Case(In2Sel.RS):
-                comb += self.reg_out.data.eq(self.dec.RS) # for M-Form shiftrot
+                # for M-Form shiftrot
+                comb += reg.eq(self.dec.RS)
                 comb += self.reg_out.ok.eq(1)
                 comb += self.reg_out.ok.eq(1)
-            with m.Case(In2Sel.CONST_UI):
+
+        # 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)
                 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
 
 
@@ -245,23 +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):
 
         # 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
+                # for M-Form shiftrot
+                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
 
 
@@ -273,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")
 
@@ -284,58 +517,54 @@ 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 += 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)
-                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)
+
+        # 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)
 
 
-        # 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)
+        # 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.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.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,37 +572,55 @@ 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):
-            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)
+
+        # B, BC or BCREG: potential implicit register (LR) output
+        # these give bl, bcl, bclrl, etc.
+        with m.Switch(op.internal_op):
 
 
-        # RFID 2nd spr (fast)
-        with m.If(op.internal_op == InternalOp.OP_RFID):
-                comb += self.fast_out.data.eq(FastRegs.SRR1) # constant: SRR1
+            # 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 +631,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 +668,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 +678,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
 
@@ -447,44 +714,112 @@ 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.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.whole_reg = Signal(reset_less=True)
+        self.cr_bitfield = Data(7, "cr_bitfield")
+        self.cr_bitfield_b = Data(7, "cr_bitfield_b")
+        self.cr_bitfield_o = Data(7, "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()
         comb = m.d.comb
 
     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)
+
+        # 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.whole_reg.eq(0)
+        comb += self.cr_bitfield_o.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):
         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 += 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.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)
+
+        # 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 (CR0/BC/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
 
@@ -498,115 +833,366 @@ 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)
-        self.cr_bitfield = Data(3, "cr_bitfield")
-        self.whole_reg = Signal(reset_less=True)
+        self.cr_bitfield = Data(7, "cr_bitfield")
+        self.cr_isvec = Signal(1, name="cr_isvec")
+        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.svdec = svdec = SVP64CRExtra()
+        m.submodules.ppick = ppick = PriorityPicker(8, reverse_i=True,
+                                                       reverse_o=True)
+
+        # get the 3-bit reg data before svp64-munging it into 7-bit plus isvec
+        cr_bf = Signal(3, reset_less=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 += cr_bf.eq(0) # CR0 (MSB0 numbering)
+                comb += self.cr_bitfield.ok.eq(self.rc_in)  # only when RC=1
             with m.Case(CROutSel.BF):
             with m.Case(CROutSel.BF):
-                comb += self.cr_bitfield.data.eq(self.dec.FormX.BF)
+                comb += cr_bf.eq(self.dec.FormX.BF)
                 comb += self.cr_bitfield.ok.eq(1)
             with m.Case(CROutSel.BT):
                 comb += self.cr_bitfield.ok.eq(1)
             with m.Case(CROutSel.BT):
-                comb += self.cr_bitfield.data.eq(self.dec.FormXL.BT[2:5])
+                comb += cr_bf.eq(self.dec.FormXL.BT[2:5])
                 comb += self.cr_bitfield.ok.eq(1)
             with m.Case(CROutSel.WHOLE_REG):
                 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)
+
+        # 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 (CR0/BC/BFA)
+        comb += svdec.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)
 
         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 = {'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):
 
     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()
+        # ...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
 
 
-    def ports(self):
-        return self.dec.ports() + self.e.ports()
+        # 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(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")
+
+    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)
 
         # 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)
-
-        # set up instruction, pick fn unit
-        comb += e.nia.eq(0)    # XXX TODO (or remove? not sure yet)
-        fu = op.function_unit
-        with m.If((fu == Function.NONE) &
-                   (op.internal_op != InternalOp.OP_ATTN)):
-            comb += do.insn_type.eq(InternalOp.OP_ILLEGAL)
-        with m.Else():
-            comb += do.insn_type.eq(op.internal_op)
-        comb += do.fn_unit.eq(fu)
+        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)
@@ -619,117 +1205,149 @@ 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 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
         # 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
-        # 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)
+        op, e = self.dec.op, self.e
+        comb += e.eq(0)  # reset eeeeeverything
 
 
-    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)
+        # start again
+        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):
+    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__':
@@ -738,4 +1356,3 @@ if __name__ == '__main__':
     vl = rtlil.convert(dec2, ports=dec2.ports() + pdecode.ports())
     with open("dec2.il", "w") as f:
         f.write(vl)
     vl = rtlil.convert(dec2, ports=dec2.ports() + pdecode.ports())
     with open("dec2.il", "w") as f:
         f.write(vl)
-