rename invert_a to invert_in because logical inverts RB
[soc.git] / src / soc / decoder / power_decoder2.py
index 535ce65a3f8740d9fbd56181c86cd91731897597..51c3511f9dc93cde787029b4903e1358f57594da 100644 (file)
@@ -2,21 +2,68 @@
 
 based on Anton Blanchard microwatt decode2.vhdl
 
 
 based on Anton Blanchard microwatt decode2.vhdl
 
+Note: OP_TRAP is used for exceptions and interrupts (micro-code style) by
+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 nmutil.iocontrol import RecordObject
 from nmutil.extend import exts
 
 from nmigen import Module, Elaboratable, Signal, Mux, Const, Cat, Repl, Record
 from nmigen.cli import rtlil
 
 from nmutil.iocontrol import RecordObject
 from nmutil.extend import exts
 
-from soc.decoder.power_regspec_map import regspec_decode
+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_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)
+                                     OutSel, SPR, RC, LDSTMode)
+from soc.decoder.decode2execute1 import Decode2ToExecute1Type, Data
+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
+
+
+def decode_spr_num(spr):
+    return Cat(spr[5:10], spr[0:5])
+
+
+def instr_is_priv(m, op, insn):
+    """determines if the instruction is privileged or not
+    """
+    comb = m.d.comb
+    is_priv_insn = Signal(reset_less=True)
+    with m.Switch(op):
+        with m.Case(MicrOp.OP_ATTN, MicrOp.OP_MFMSR, MicrOp.OP_MTMSRD,
+                    MicrOp.OP_MTMSR, MicrOp.OP_RFID):
+            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):
+    """SPRMap: maps POWER9 SPR numbers to internal enum values
+    """
+
+    def __init__(self):
+        self.spr_i = Signal(10, reset_less=True)
+        self.spr_o = Signal(SPR, reset_less=True)
+
+    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)
+        return m
+
 
 class DecodeA(Elaboratable):
     """DecodeA from instruction
 
 class DecodeA(Elaboratable):
     """DecodeA from instruction
@@ -31,12 +78,13 @@ class DecodeA(Elaboratable):
         self.insn_in = Signal(32, reset_less=True)
         self.reg_out = Data(5, name="reg_a")
         self.immz_out = Signal(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(10, "spr_a")
+        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.fast_out = Data(3, "fast_a")
 
     def elaborate(self, platform):
         m = Module()
         comb = m.d.comb
+        m.submodules.sprmap = sprmap = SPRMap()
 
         # select Register A field
         ra = Signal(5, reset_less=True)
 
         # select Register A field
         ra = Signal(5, reset_less=True)
@@ -59,42 +107,55 @@ class DecodeA(Elaboratable):
 
         # decode Fast-SPR based on instruction type
         op = self.dec.op
 
         # 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)
-
-        # MFSPR move from SPRs
-        with m.If(op.internal_op == InternalOp.OP_MFSPR):
-            # XXX TODO: fast/slow SPR decoding and mapping
-            comb += self.spr_out.data.eq(self.dec.SPR) # SPR field, XFX
-            comb += self.spr_out.ok.eq(1)
+        with m.Switch(op.internal_op):
+
+            # 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)
+            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)
+
+            # 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
+                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
+                    # : 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)
 
         return m
 
 
 
         return m
 
 
-class Data(Record):
-
-    def __init__(self, width, name):
-        name_ok = "%s_ok" % name
-        layout = ((name, width), (name_ok, 1))
-        Record.__init__(self, layout)
-        self.data = getattr(self, name) # convenience
-        self.ok = getattr(self, name_ok) # convenience
-        self.data.reset_less = True # grrr
-        self.reset_less = True # grrr
-
-    def ports(self):
-        return [self.data, self.ok]
-
-
 class DecodeB(Elaboratable):
     """DecodeB from instruction
 
 class DecodeB(Elaboratable):
     """DecodeB from instruction
 
@@ -122,39 +183,49 @@ class DecodeB(Elaboratable):
                 comb += self.reg_out.data.eq(self.dec.RB)
                 comb += self.reg_out.ok.eq(1)
             with m.Case(In2Sel.RS):
                 comb += self.reg_out.data.eq(self.dec.RB)
                 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 += self.reg_out.data.eq(self.dec.RS)
                 comb += self.reg_out.ok.eq(1)
                 comb += self.reg_out.ok.eq(1)
-            with m.Case(In2Sel.CONST_UI):
+            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)
 
@@ -162,9 +233,9 @@ class DecodeB(Elaboratable):
         op = self.dec.op
         # BCREG implicitly uses LR or TAR for 2nd reg
         # CTR however is already in fast_spr1 *not* 2.
         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(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.If(~xo9):
                 comb += self.fast_out.data.eq(FastRegs.LR)
                 comb += self.fast_out.ok.eq(1)
@@ -194,7 +265,8 @@ class DecodeC(Elaboratable):
         # 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 += self.reg_out.data.eq(self.dec.RB)
                 comb += self.reg_out.ok.eq(1)
             with m.Case(In3Sel.RS):
                 comb += self.reg_out.data.eq(self.dec.RS)
                 comb += self.reg_out.ok.eq(1)
             with m.Case(In3Sel.RS):
                 comb += self.reg_out.data.eq(self.dec.RS)
@@ -214,12 +286,13 @@ class DecodeOut(Elaboratable):
         self.sel_in = Signal(OutSel, reset_less=True)
         self.insn_in = Signal(32, reset_less=True)
         self.reg_out = Data(5, "reg_o")
         self.sel_in = Signal(OutSel, reset_less=True)
         self.insn_in = Signal(32, reset_less=True)
         self.reg_out = Data(5, "reg_o")
-        self.spr_out = Data(10, "spr_o")
+        self.spr_out = Data(SPR, "spr_o")
         self.fast_out = Data(3, "fast_o")
 
     def elaborate(self, platform):
         m = Module()
         comb = m.d.comb
         self.fast_out = Data(3, "fast_o")
 
     def elaborate(self, platform):
         m = Module()
         comb = m.d.comb
+        m.submodules.sprmap = sprmap = SPRMap()
         op = self.dec.op
 
         # select Register out field
         op = self.dec.op
 
         # select Register out field
@@ -231,40 +304,50 @@ class DecodeOut(Elaboratable):
                 comb += self.reg_out.data.eq(self.dec.RA)
                 comb += self.reg_out.ok.eq(1)
             with m.Case(OutSel.SPR):
                 comb += self.reg_out.data.eq(self.dec.RA)
                 comb += self.reg_out.ok.eq(1)
             with m.Case(OutSel.SPR):
-                comb += self.spr_out.data.eq(self.dec.SPR) # from XFX
-                comb += self.spr_out.ok.eq(1)
+                spr = Signal(10, reset_less=True)
+                comb += spr.eq(decode_spr_num(self.dec.SPR))  # from XFX
                 # TODO MTSPR 1st spr (fast)
                 # TODO MTSPR 1st spr (fast)
-                with m.If(op.internal_op == InternalOp.OP_MTSPR):
-                    pass
-                    """
-                    sprn := decode_spr_num(f_in.insn);
-                    v.ispr1 := fast_spr_num(sprn);
-                    -- Make slow SPRs single issue
-                    if is_fast_spr(v.ispr1) = '0' then
-                        v.decode.sgl_pipe := '1';
-                        -- send MMU-related SPRs to loadstore1
-                        case sprn is
-                        when SPR_DAR | SPR_DSISR | SPR_PID | SPR_PRTBL =>
-                            v.decode.unit := LDST;
-                        when others =>
-                        end case;
-                    end if;
-                    """
-
-
-        # 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
+                with m.If(op.internal_op == MicrOp.OP_MTSPR):
+                    with m.Switch(spr):
+                        # fast SPRs
+                        with m.Case(SPR.CTR.value):
+                            comb += self.fast_out.data.eq(FastRegs.CTR)
+                            comb += self.fast_out.ok.eq(1)
+                        with m.Case(SPR.LR.value):
+                            comb += self.fast_out.data.eq(FastRegs.LR)
+                            comb += self.fast_out.ok.eq(1)
+                        with m.Case(SPR.TAR.value):
+                            comb += self.fast_out.data.eq(FastRegs.TAR)
+                            comb += self.fast_out.ok.eq(1)
+                        with m.Case(SPR.SRR0.value):
+                            comb += self.fast_out.data.eq(FastRegs.SRR0)
+                            comb += self.fast_out.ok.eq(1)
+                        with m.Case(SPR.SRR1.value):
+                            comb += self.fast_out.data.eq(FastRegs.SRR1)
+                            comb += self.fast_out.ok.eq(1)
+                        with m.Case(SPR.XER.value):
+                            pass  # do nothing
+                        # : map to internal SPR numbers
+                        # XXX TODO: dec and tb not to go through mapping.
+                        with m.Default():
+                            comb += sprmap.spr_i.eq(spr)
+                            comb += self.spr_out.data.eq(sprmap.spr_o)
+                            comb += self.spr_out.ok.eq(1)
+
+        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)
 
                 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)
-
         return m
 
 
         return m
 
 
@@ -287,21 +370,24 @@ class DecodeOut2(Elaboratable):
         comb = m.d.comb
 
         # update mode LD/ST uses read-reg A also as an output
         comb = m.d.comb
 
         # update mode LD/ST uses read-reg A also as an output
-        with m.If(self.dec.op.upd):
+        with m.If(self.dec.op.upd == LDSTMode.update):
             comb += self.reg_out.eq(self.dec.RA)
             comb += self.reg_out.ok.eq(1)
 
             comb += self.reg_out.eq(self.dec.RA)
             comb += self.reg_out.ok.eq(1)
 
-        # BC or BCREG: potential implicit register (LR) output
+        # B, BC or BCREG: potential implicit register (LR) output
+        # these give bl, bcl, bclrl, etc.
         op = self.dec.op
         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)
+        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
@@ -312,6 +398,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)
@@ -348,6 +435,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)
@@ -357,15 +445,25 @@ 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
+            with m.Case(MicrOp.OP_MUL_H64, MicrOp.OP_MUL_H32):
+                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
 
@@ -391,7 +489,7 @@ class DecodeCRIn(Elaboratable):
         comb += self.whole_reg.eq(0)
         with m.Switch(self.sel_in):
             with m.Case(CRInSel.NONE):
         comb += self.whole_reg.eq(0)
         with m.Switch(self.sel_in):
             with m.Case(CRInSel.NONE):
-                pass # No bitfield activated
+                pass  # No bitfield activated
             with m.Case(CRInSel.CR0):
                 comb += self.cr_bitfield.data.eq(0)
                 comb += self.cr_bitfield.ok.eq(1)
             with m.Case(CRInSel.CR0):
                 comb += self.cr_bitfield.data.eq(0)
                 comb += self.cr_bitfield.ok.eq(1)
@@ -440,10 +538,10 @@ class DecodeCROut(Elaboratable):
         comb += self.whole_reg.eq(0)
         with m.Switch(self.sel_in):
             with m.Case(CROutSel.NONE):
         comb += self.whole_reg.eq(0)
         with m.Switch(self.sel_in):
             with m.Case(CROutSel.NONE):
-                pass # No bitfield activated
+                pass  # No bitfield activated
             with m.Case(CROutSel.CR0):
                 comb += self.cr_bitfield.data.eq(0)
             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.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)
@@ -456,80 +554,47 @@ class DecodeCROut(Elaboratable):
         return m
 
 
         return m
 
 
-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)
-
-    def ports(self):
-        return [self.ca, self.ov, self.so]
-
-
-class Decode2ToExecute1Type(RecordObject):
-
-    def __init__(self, name=None):
-
-        RecordObject.__init__(self, name=name)
-
-        self.valid = Signal(reset_less=True)
-        self.insn_type = Signal(InternalOp, reset_less=True)
-        self.fn_unit = Signal(Function, reset_less=True)
-        self.nia = Signal(64, reset_less=True)
-        self.write_reg = Data(5, name="rego")
-        self.write_ea = Data(5, name="ea") # for LD/ST in update mode
-        self.read_reg1 = Data(5, name="reg1")
-        self.read_reg2 = Data(5, name="reg2")
-        self.read_reg3 = Data(5, name="reg3")
-        self.imm_data = Data(64, name="imm")
-        self.write_spr = Data(10, name="spro")
-        self.read_spr1 = Data(10, name="spr1")
-        self.read_spr2 = Data(10, name="spr2")
-
-        self.read_fast1 = Data(3, name="fast1")
-        self.read_fast2 = Data(3, name="fast2")
-        self.write_fast1 = Data(3, name="fasto1")
-        self.write_fast2 = Data(3, name="fasto2")
-
-        self.read_cr1 = Data(3, name="cr_in1")
-        self.read_cr2 = Data(3, name="cr_in2")
-        self.read_cr3 = Data(3, name="cr_in2")
-        self.read_cr_whole = Signal(reset_less=True)
-        self.write_cr = Data(3, name="cr_out")
-        self.write_cr_whole = Signal(reset_less=True)
-        self.lk = Signal(reset_less=True)
-        self.rc = Data(1, "rc")
-        self.oe = Data(1, "oe")
-        self.invert_a = Signal(reset_less=True)
-        self.zero_a = Signal(reset_less=True)
-        self.invert_out = Signal(reset_less=True)
-        self.input_carry = Signal(CryIn, reset_less=True)
-        self.output_carry = Signal(reset_less=True)
-        self.input_cr = Signal(reset_less=True)  # instr. has a CR as input
-        self.output_cr = Signal(reset_less=True) # instr. has a CR as output
-        self.is_32bit = Signal(reset_less=True)
-        self.is_signed = Signal(reset_less=True)
-        self.insn = Signal(32, reset_less=True)
-        self.data_len = Signal(4, reset_less=True) # bytes
-        self.byte_reverse  = Signal(reset_less=True)
-        self.sign_extend  = Signal(reset_less=True)# do we need this?
-        self.update  = Signal(reset_less=True) # LD/ST is "update" variant
-
-
 class PowerDecode2(Elaboratable):
 class PowerDecode2(Elaboratable):
+    """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).
+    """
 
     def __init__(self, dec):
 
         self.dec = dec
         self.e = Decode2ToExecute1Type()
 
 
     def __init__(self, dec):
 
         self.dec = dec
         self.e = Decode2ToExecute1Type()
 
+        # state information needed by the Decoder (TODO: this as a Record)
+        self.state = CoreState("dec2")
+
     def ports(self):
         return self.dec.ports() + self.e.ports()
 
     def elaborate(self, platform):
         m = Module()
         comb = m.d.comb
     def ports(self):
         return self.dec.ports() + self.e.ports()
 
     def elaborate(self, platform):
         m = Module()
         comb = m.d.comb
-        e, op = self.e, self.dec.op
+        e_out, op, do_out = self.e, self.dec.op, self.e.do
+        msr, cia = self.state.msr, self.state.pc
+
+        # fill in for a normal instruction (not an exception)
+        # copy over if non-exception, non-privileged etc. is detected
+        e = Decode2ToExecute1Type()
+        do = e.do
 
         # set up submodule decoders
         m.submodules.dec = self.dec
 
         # set up submodule decoders
         m.submodules.dec = self.dec
@@ -544,7 +609,7 @@ class PowerDecode2(Elaboratable):
         m.submodules.dec_cr_out = dec_cr_out = DecodeCROut(self.dec)
 
         # copy instruction through...
         m.submodules.dec_cr_out = dec_cr_out = DecodeCROut(self.dec)
 
         # copy instruction through...
-        for i in [e.insn, dec_a.insn_in, dec_b.insn_in,
+        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]:
             comb += i.eq(self.dec.opcode_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]:
             comb += i.eq(self.dec.opcode_in)
@@ -555,29 +620,21 @@ class PowerDecode2(Elaboratable):
         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_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(e.lk)
+        comb += dec_o2.lk.eq(do.lk)
         comb += dec_rc.sel_in.eq(op.rc_sel)
         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_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)
 
         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)
 
-        # decode LD/ST length
-        with m.Switch(op.ldst_len):
-            with m.Case(LdstLen.is1B):
-                comb += e.data_len.eq(1)
-            with m.Case(LdstLen.is2B):
-                comb += e.data_len.eq(2)
-            with m.Case(LdstLen.is4B):
-                comb += e.data_len.eq(4)
-            with m.Case(LdstLen.is8B):
-                comb += e.data_len.eq(8)
-
-        comb += e.nia.eq(0)    # XXX TODO (or remove? not sure yet)
-        fu = op.function_unit
-        itype = Mux(fu == Function.NONE, InternalOp.OP_ILLEGAL, op.internal_op)
-        comb += e.insn_type.eq(itype)
-        comb += e.fn_unit.eq(fu)
+        # copy "state" over
+        comb += do.msr.eq(msr)
+        comb += do.cia.eq(cia)
+
+        # set up instruction, pick fn unit
+        # no op: defaults to OP_ILLEGAL
+        comb += do.insn_type.eq(op.internal_op)
+        comb += do.fn_unit.eq(op.function_unit)
 
         # registers a, b, c and out and out2 (LD/ST EA)
         comb += e.read_reg1.eq(dec_a.reg_out)
 
         # registers a, b, c and out and out2 (LD/ST EA)
         comb += e.read_reg1.eq(dec_a.reg_out)
@@ -585,12 +642,12 @@ class PowerDecode2(Elaboratable):
         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 += 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 += e.imm_data.eq(dec_b.imm_out) # immediate in RB (usually)
-        comb += e.zero_a.eq(dec_a.immz_out)  # RA==0 detected
+        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
 
         # rc and oe out
-        comb += e.rc.eq(dec_rc.rc_out)
-        comb += e.oe.eq(dec_oe.oe_out)
+        comb += do.rc.eq(dec_rc.rc_out)
+        comb += do.oe.eq(dec_oe.oe_out)
 
         # SPRs out
         comb += e.read_spr1.eq(dec_a.spr_out)
 
         # SPRs out
         comb += e.read_spr1.eq(dec_a.spr_out)
@@ -602,51 +659,113 @@ class PowerDecode2(Elaboratable):
         comb += e.write_fast1.eq(dec_o.fast_out)
         comb += e.write_fast2.eq(dec_o2.fast_out)
 
         comb += e.write_fast1.eq(dec_o.fast_out)
         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.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.read_cr_whole.eq(dec_cr_in.whole_reg)
-
         comb += e.write_cr.eq(dec_cr_out.cr_bitfield)
         comb += e.write_cr.eq(dec_cr_out.cr_bitfield)
-        comb += e.write_cr_whole.eq(dec_cr_out.whole_reg)
+
+        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
 
         # decoded/selected instruction flags
-        comb += e.invert_a.eq(op.inv_a)
-        comb += e.invert_out.eq(op.inv_out)
-        comb += e.input_carry.eq(op.cry_in)   # carry comes in
-        comb += e.output_carry.eq(op.cry_out) # carry goes out
-        comb += e.is_32bit.eq(op.is_32b)
-        comb += e.is_signed.eq(op.sgn)
+        comb += do.data_len.eq(op.ldst_len)
+        comb += do.invert_in.eq(op.inv_a)
+        comb += do.invert_out.eq(op.inv_out)
+        comb += do.input_carry.eq(op.cry_in)   # carry comes in
+        comb += do.output_carry.eq(op.cry_out)  # carry goes out
+        comb += do.is_32bit.eq(op.is_32b)
+        comb += do.is_signed.eq(op.sgn)
         with m.If(op.lk):
         with m.If(op.lk):
-            comb += e.lk.eq(self.dec.LK) # XXX TODO: accessor
-
-        comb += e.byte_reverse.eq(op.br)
-        comb += e.sign_extend.eq(op.sgn_ext)
-        comb += e.update.eq(op.upd) # LD/ST "update" mode.
+            comb += do.lk.eq(self.dec.LK)  # XXX TODO: accessor
 
 
+        comb += do.byte_reverse.eq(op.br)
+        comb += do.sign_extend.eq(op.sgn_ext)
+        comb += do.ldst_mode.eq(op.upd)  # LD/ST mode (update, cache-inhibit)
 
         # These should be removed eventually
 
         # These should be removed eventually
-        comb += e.input_cr.eq(op.cr_in)   # condition reg comes in
-        comb += e.output_cr.eq(op.cr_out) # condition reg goes in
-
+        comb += do.input_cr.eq(op.cr_in)   # condition reg comes in
+        comb += do.output_cr.eq(op.cr_out)  # condition reg goes in
+
+        # 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 == MicrOp.OP_MFSPR):
+            comb += e.xer_in.eq(1)
+        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
+        with m.If(op.internal_op == MicrOp.OP_TRAP):
+            # *DO NOT* call self.trap here.  that would reset absolutely
+            # rverything including destroying read of RA and RB.
+            comb += do.trapaddr.eq(0x70)    # addr=0x700 (strip first nibble)
+
+        # TODO: get msr, then can do privileged instruction
+        with m.If(instr_is_priv(m, op.internal_op, e.do.insn) & msr[MSR.PR]):
+            # privileged instruction trap
+            self.trap(m, TT.PRIV, 0x700)
+
+        # illegal instruction must redirect to trap. this is done by
+        # *overwriting* the decoded instruction and starting again.
+        # (note: the same goes for interrupts and for privileged operations,
+        # just with different trapaddr and traptype)
+        with m.Elif(op.internal_op == MicrOp.OP_ILLEGAL):
+            # illegal instruction trap
+            self.trap(m, TT.ILLEG, 0x700)
+
+        # no exception, just copy things to the output
+        with m.Else():
+            comb += e_out.eq(e)
+
+        # trap: (note e.insn_type so this includes OP_ILLEGAL) set up fast regs
+        # Note: OP_SC could actually be modified to just be a trap
+        with m.If((do_out.insn_type == MicrOp.OP_TRAP) |
+                  (do_out.insn_type == MicrOp.OP_SC)):
+            # TRAP write fast1 = SRR0
+            comb += e_out.write_fast1.data.eq(FastRegs.SRR0)  # constant: SRR0
+            comb += e_out.write_fast1.ok.eq(1)
+            # TRAP write fast2 = SRR1
+            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
+        with m.If(do_out.insn_type == MicrOp.OP_RFID):
+            # TRAP read fast1 = SRR0
+            comb += e_out.read_fast1.data.eq(FastRegs.SRR0)  # constant: SRR0
+            comb += e_out.read_fast1.ok.eq(1)
+            # TRAP read fast2 = SRR1
+            comb += e_out.read_fast2.data.eq(FastRegs.SRR1)  # constant: SRR1
+            comb += e_out.read_fast2.ok.eq(1)
 
         return m
 
 
         return m
 
-    def regspecmap(self, regfile, regname):
-        """regspecmap: 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.
+    def trap(self, m, traptype, trapaddr):
+        """trap: this basically "rewrites" the decoded instruction as a trap
         """
         """
-        return regspec_decode(self.e, regfile, regname)
+        comb = m.d.comb
+        op, do, e = self.dec.op, self.e.do, self.e
+        comb += e.eq(0)  # reset eeeeeverything
 
 
-    def rdflags(self, cu):
-        rdl = []
-        for idx in range(cu.n_src):
-            regfile, regname, _ = cu.get_in_spec(idx)
-            rdflag, read, write = self.regspecmap(regfile, regname)
-            rdl.append(rdflag)
-        print ("rdflags", rdl)
-        return Cat(*rdl)
+        # start again
+        comb += do.insn.eq(self.dec.opcode_in)
+        comb += do.insn_type.eq(MicrOp.OP_TRAP)
+        comb += do.fn_unit.eq(Function.TRAP)
+        comb += do.trapaddr.eq(trapaddr >> 4)  # cut bottom 4 bits
+        comb += do.traptype.eq(traptype)  # request type
+        comb += do.msr.eq(self.state.msr)  # copy of MSR "state"
+        comb += do.cia.eq(self.state.pc)  # copy of PC "state"
+
+
+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__':
@@ -655,4 +774,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)
-