reenable tests
[openpower-isa.git] / src / openpower / decoder / power_decoder2.py
index 2fa6feac74a14f9ccf2bc573395a90eb3240a7e7..b73fbe761e311e75402de7e8e981a3dff04e8aa4 100644 (file)
@@ -31,8 +31,8 @@ from openpower.decoder.power_enums import (MicrOp, CryIn, Function,
                                            CRInSel, CROutSel,
                                            LdstLen, In1Sel, In2Sel, In3Sel,
                                            OutSel, SPRfull, SPRreduced,
-                                           RC, SVP64LDSTmode, LDSTMode,
-                                           SVEXTRA, SVEtype, SVPtype)
+                                           RCOE, SVP64LDSTmode, LDSTMode,
+                                           SVEXTRA, SVEType, SVPType)
 from openpower.decoder.decode2execute1 import (Decode2ToExecute1Type, Data,
                                                Decode2ToOperand)
 
@@ -41,7 +41,7 @@ from openpower.consts import (MSR, SPEC, EXTRA2, EXTRA3, SVP64P, field,
                               FastRegsEnum, XERRegsEnum, TT)
 
 from openpower.state import CoreState
-from openpower.util import (spr_to_fast, log)
+from openpower.util import (spr_to_fast, spr_to_state, log)
 
 
 def decode_spr_num(spr):
@@ -78,7 +78,8 @@ class SPRMap(Elaboratable):
 
         self.spr_i = Signal(10, reset_less=True)
         self.spr_o = Data(SPR, name="spr_o")
-        self.fast_o = Data(3, name="fast_o")
+        self.fast_o = Data(4, name="fast_o")
+        self.state_o = Data(3, name="state_o")
 
     def elaborate(self, platform):
         m = Module()
@@ -95,6 +96,10 @@ class SPRMap(Elaboratable):
                 with m.Case(x.value):
                     m.d.comb += self.fast_o.data.eq(v)
                     m.d.comb += self.fast_o.ok.eq(1)
+            for x, v in spr_to_state.items():
+                with m.Case(x.value):
+                    m.d.comb += self.state_o.data.eq(v)
+                    m.d.comb += self.state_o.ok.eq(1)
         return m
 
 
@@ -116,7 +121,8 @@ class DecodeA(Elaboratable):
         self.insn_in = Signal(32, reset_less=True)
         self.reg_out = Data(5, name="reg_a")
         self.spr_out = Data(SPR, "spr_a")
-        self.fast_out = Data(3, "fast_a")
+        self.fast_out = Data(4, "fast_a")
+        self.state_out = Data(3, "state_a")
         self.sv_nz = Signal(1)
 
     def elaborate(self, platform):
@@ -157,6 +163,13 @@ class DecodeA(Elaboratable):
             comb += reg.data.eq(frs)
             comb += reg.ok.eq(1)
 
+        # select Register FRT field,
+        frt = Signal(5, reset_less=True)
+        comb += frt.eq(self.dec.FRT)
+        with m.If(self.sel_in == In1Sel.FRT):
+            comb += reg.data.eq(frt)
+            comb += reg.ok.eq(1)
+
         # decode Fast-SPR based on instruction type
         with m.Switch(op.internal_op):
 
@@ -181,6 +194,7 @@ class DecodeA(Elaboratable):
                 comb += sprmap.spr_i.eq(spr)
                 comb += self.spr_out.eq(sprmap.spr_o)
                 comb += self.fast_out.eq(sprmap.fast_o)
+                comb += self.state_out.eq(sprmap.state_o)
 
         return m
 
@@ -229,7 +243,7 @@ class DecodeB(Elaboratable):
         self.insn_in = Signal(32, reset_less=True)
         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")
+        self.fast_out = Data(4, "fast_b")
 
     def elaborate(self, platform):
         m = Module()
@@ -355,6 +369,9 @@ class DecodeC(Elaboratable):
             with m.Case(In3Sel.FRS):
                 comb += reg.data.eq(self.dec.FRS)
                 comb += reg.ok.eq(1)
+            with m.Case(In3Sel.FRA):
+                comb += reg.data.eq(self.dec.FRA)
+                comb += reg.ok.eq(1)
             with m.Case(In3Sel.FRC):
                 comb += reg.data.eq(self.dec.FRC)
                 comb += reg.ok.eq(1)
@@ -365,7 +382,7 @@ class DecodeC(Elaboratable):
                 comb += reg.data.eq(self.dec.RC)
                 comb += reg.ok.eq(1)
             with m.Case(In3Sel.RT):
-                # for TI-form ternary
+                # for TLI-form ternlogi
                 comb += reg.data.eq(self.dec.RT)
                 comb += reg.ok.eq(1)
 
@@ -375,7 +392,7 @@ class DecodeC(Elaboratable):
 class DecodeOut(Elaboratable):
     """DecodeOut from instruction
 
-    decodes output register RA, RT or SPR
+    decodes output register RA, RT, FRS, FRT, or SPR
     """
 
     def __init__(self, dec, op, regreduce_en):
@@ -390,7 +407,8 @@ class DecodeOut(Elaboratable):
         self.insn_in = Signal(32, reset_less=True)
         self.reg_out = Data(5, "reg_o")
         self.spr_out = Data(SPR, "spr_o")
-        self.fast_out = Data(3, "fast_o")
+        self.fast_out = Data(4, "fast_o")
+        self.state_out = Data(3, "state_o")
 
     def elaborate(self, platform):
         m = Module()
@@ -401,6 +419,12 @@ class DecodeOut(Elaboratable):
 
         # select Register out field
         with m.Switch(self.sel_in):
+            with m.Case(OutSel.FRS):
+                comb += reg.data.eq(self.dec.FRS)
+                comb += reg.ok.eq(1)
+            with m.Case(OutSel.FRA):
+                comb += reg.data.eq(self.dec.FRA)
+                comb += reg.ok.eq(1)
             with m.Case(OutSel.FRT):
                 comb += reg.data.eq(self.dec.FRT)
                 comb += reg.ok.eq(1)
@@ -418,6 +442,7 @@ class DecodeOut(Elaboratable):
                     comb += sprmap.spr_i.eq(spr)
                     comb += self.spr_out.eq(sprmap.spr_o)
                     comb += self.fast_out.eq(sprmap.fast_o)
+                    comb += self.state_out.eq(sprmap.state_o)
 
         # determine Fast Reg
         with m.Switch(op.internal_op):
@@ -455,13 +480,14 @@ class DecodeOut2(Elaboratable):
         self.dec = dec
         self.op = op
         self.sel_in = Signal(OutSel, reset_less=True)
-        self.svp64_fft_mode = Signal(reset_less=True)  # SVP64 FFT mode
+        self.implicit_rs = Signal(reset_less=True)  # SVP64 implicit RS/FRS
+        self.implicit_from_rc = Signal(reset_less=True)# implicit RS from RC
         self.lk = Signal(reset_less=True)
         self.insn_in = Signal(32, reset_less=True)
         self.reg_out = Data(5, "reg_o2")
-        self.fp_madd_en = Signal(reset_less=True)  # FFT instruction detected
-        self.fast_out = Data(3, "fast_o2")
-        self.fast_out3 = Data(3, "fast_o3")
+        self.rs_en = Signal(reset_less=True)  # FFT instruction detected
+        self.fast_out = Data(4, "fast_o2")
+        self.fast_out3 = Data(4, "fast_o3")
 
     def elaborate(self, platform):
         m = Module()
@@ -498,10 +524,13 @@ class DecodeOut2(Elaboratable):
         # SVP64 FFT mode, FP mul-add: 2nd output reg (FRS) same as FRT
         # will be offset by VL in hardware
         # with m.Case(MicrOp.OP_FP_MADD):
-        with m.If(self.svp64_fft_mode):
-            comb += self.reg_out.data.eq(self.dec.FRT)
+        with m.If(self.implicit_rs):
+            with m.If(self.implicit_from_rc):
+                comb += self.reg_out.data.eq(self.dec.FRC) # same as RC
+            with m.Else():
+                comb += self.reg_out.data.eq(self.dec.FRT) # same as RT
             comb += self.reg_out.ok.eq(1)
-            comb += self.fp_madd_en.eq(1)
+            comb += self.rs_en.eq(1)
 
         return m
 
@@ -514,7 +543,7 @@ class DecodeRC(Elaboratable):
 
     def __init__(self, dec):
         self.dec = dec
-        self.sel_in = Signal(RC, reset_less=True)
+        self.sel_in = Signal(RCOE, reset_less=True)
         self.insn_in = Signal(32, reset_less=True)
         self.rc_out = Data(1, "rc")
 
@@ -524,13 +553,13 @@ class DecodeRC(Elaboratable):
 
         # select Record bit out field
         with m.Switch(self.sel_in):
-            with m.Case(RC.RC):
+            with m.Case(RCOE.RC, RCOE.RC_ONLY):
                 comb += self.rc_out.data.eq(self.dec.Rc)
                 comb += self.rc_out.ok.eq(1)
-            with m.Case(RC.ONE):
+            with m.Case(RCOE.ONE):
                 comb += self.rc_out.data.eq(1)
                 comb += self.rc_out.ok.eq(1)
-            with m.Case(RC.NONE):
+            with m.Case(RCOE.NONE):
                 comb += self.rc_out.data.eq(0)
                 comb += self.rc_out.ok.eq(1)
 
@@ -540,48 +569,30 @@ class DecodeRC(Elaboratable):
 class DecodeOE(Elaboratable):
     """DecodeOE from instruction
 
-    decodes OE field: uses RC decode detection which might not be good
-
-    -- For now, use "rc" in the decode table to decide whether oe exists.
-    -- This is not entirely correct architecturally: For mulhd and
-    -- mulhdu, the OE field is reserved. It remains to be seen what an
-    -- actual POWER9 does if we set it on those instructions, for now we
-    -- test that further down when assigning to the multiplier oe input.
+    decodes OE field: uses RC decode detection which has now been
+    updated to separate out RC_ONLY.  all cases RC_ONLY are *NOT*
+    listening to the OE field, here.
     """
 
     def __init__(self, dec, op):
         self.dec = dec
         self.op = op
-        self.sel_in = Signal(RC, reset_less=True)
+        self.sel_in = Signal(RCOE, reset_less=True)
         self.insn_in = Signal(32, reset_less=True)
         self.oe_out = Data(1, "oe")
 
     def elaborate(self, platform):
         m = Module()
         comb = m.d.comb
-        op = self.op
-
-        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.Switch(self.sel_in):
+            with m.Case(RCOE.RC):
+                comb += self.oe_out.data.eq(self.dec.OE)
+                comb += self.oe_out.ok.eq(1)
             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)
+                # default: clear OE.
+                comb += self.oe_out.data.eq(0)
+                comb += self.oe_out.ok.eq(0)
 
         return m
 
@@ -677,6 +688,8 @@ class DecodeCROut(Elaboratable):
         self.cr_bitfield = Data(3, "cr_bitfield")
         self.whole_reg = Data(8,  "cr_fxm")
         self.sv_override = Signal(2, reset_less=True)  # do not do EXTRA spec
+        self.cr_5bit = Signal(reset_less=True)  # set True for 5-bit
+        self.cr_2bit = Signal(2, reset_less=True)  # get lowest 2 bits
 
     def elaborate(self, platform):
         m = Module()
@@ -688,6 +701,7 @@ class DecodeCROut(Elaboratable):
         comb += self.cr_bitfield.ok.eq(0)
         comb += self.whole_reg.ok.eq(0)
         comb += self.sv_override.eq(0)
+        comb += self.cr_5bit.eq(0)
 
         # please note these MUST match (setting of cr_bitfield.ok) exactly
         # with write_cr0 below in PowerDecoder2.  the reason it's separated
@@ -712,6 +726,8 @@ class DecodeCROut(Elaboratable):
             with m.Case(CROutSel.BT):
                 comb += self.cr_bitfield.data.eq(self.dec.FormXL.BT[2:5])
                 comb += self.cr_bitfield.ok.eq(1)
+                comb += self.cr_5bit.eq(1)
+                comb += self.cr_2bit.eq(self.dec.FormXL.BT[0:2])
             with m.Case(CROutSel.WHOLE_REG):
                 comb += self.whole_reg.ok.eq(1)
                 move_one = Signal(reset_less=True)
@@ -739,6 +755,7 @@ class DecodeCROut(Elaboratable):
 record_names = {'insn_type': 'internal_op',
                 'fn_unit': 'function_unit',
                 'SV_Ptype': 'SV_Ptype',
+                'SV_mode': 'SV_mode',
                 'rc': 'rc_sel',
                 'oe': 'rc_sel',
                 'zero_a': 'in1_sel',
@@ -753,6 +770,7 @@ record_names = {'insn_type': 'internal_op',
                 'is_signed': 'sgn',
                 'lk': 'lk',
                 'data_len': 'ldst_len',
+                'reserve': 'rsrv',
                 'byte_reverse': 'br',
                 'sign_extend': 'sgn_ext',
                 'ldst_mode': 'upd',
@@ -766,14 +784,16 @@ class PowerDecodeSubset(Elaboratable):
     """
 
     def __init__(self, dec, opkls=None, fn_name=None, final=False, state=None,
-                 svp64_en=True, regreduce_en=False):
+                 svp64_en=True, regreduce_en=False, fp_en=False):
 
         self.svp64_en = svp64_en
         self.regreduce_en = regreduce_en
+        self.fp_en = fp_en
         if svp64_en:
             self.is_svp64_mode = Signal()  # mark decoding as SVP64 Mode
-            self.use_svp64_ldst_dec = Signal()  # must use LDST decoder
-            self.use_svp64_fft = Signal()      # FFT Mode
+            self.implicit_rs = Signal()    # implicit RS/FRS
+            self.extend_rb_maxvl = Signal() # jumps RB by an additional MAXVL
+            self.extend_rc_maxvl = Signal() # jumps RS by MAXVL from RC
             self.sv_rm = SVP64Rec(name="dec_svp64")  # SVP64 RM field
             self.rm_dec = SVP64RMModeDecode("svp64_rm_dec")
             # set these to the predicate mask bits needed for the ALU
@@ -797,8 +817,8 @@ class PowerDecodeSubset(Elaboratable):
         # alternatives.  useful for PCR (Program Compatibility Register)
         # amongst other things
         if svp64_en:
-            conditions = {'SVP64BREV': self.use_svp64_ldst_dec,
-                          'SVP64FFT': self.use_svp64_fft,
+            conditions = {
+                          # XXX NO 'SVP64FFT': self.use_svp64_fft,
                           }
         else:
             conditions = None
@@ -812,7 +832,7 @@ class PowerDecodeSubset(Elaboratable):
         if dec is None:
             dec = create_pdecode(name=fn_name, col_subset=col_subset,
                                  row_subset=row_subset,
-                                 conditions=conditions)
+                                 conditions=conditions, include_fp=fp_en)
         self.dec = dec
 
         # set up a copy of the PowerOp
@@ -847,6 +867,11 @@ class PowerDecodeSubset(Elaboratable):
                 # to support multiple tasks (unit column multiple entries)
                 # see https://bugs.libre-soc.org/show_bug.cgi?id=310
                 (self.fn_name == 'MMU' and row['unit'] == 'SPR' and
+                 row['internal op'] in ['OP_MTSPR', 'OP_MFSPR']) or
+                # urrr... and the KAIVB SPR, which must also be redirected
+                # (to the TRAP pipeline)
+                # see https://bugs.libre-soc.org/show_bug.cgi?id=859
+                (self.fn_name == 'TRAP' and row['unit'] == 'SPR' and
                  row['internal op'] in ['OP_MTSPR', 'OP_MFSPR'])
                 )
 
@@ -855,8 +880,7 @@ class PowerDecodeSubset(Elaboratable):
         if self.svp64_en:
             ports += self.sv_rm.ports()
             ports.append(self.is_svp64_mode)
-            ports.append(self.use_svp64_ldst_dec)
-            ports.append(self.use_svp64_fft)
+            ports.append(self.implicit_rs)
         return ports
 
     def needs_field(self, field, op_field):
@@ -940,20 +964,30 @@ class PowerDecodeSubset(Elaboratable):
 
         # Microwatt doesn't implement the partition table
         # instead has PRTBL register (SPR) to point to process table
+        # Kestrel has a KAIVB SPR to "rebase" exceptions. rebasing is normally
+        # done with Hypervisor Mode which is not implemented (yet)
         is_spr_mv = Signal()
         is_mmu_spr = Signal()
+        is_trap_spr = Signal()
         comb += is_spr_mv.eq((internal_op == MicrOp.OP_MTSPR) |
                              (internal_op == MicrOp.OP_MFSPR))
         comb += is_mmu_spr.eq((spr == SPR.DSISR.value) |
                               (spr == SPR.DAR.value) |
                               (spr == SPR.PRTBL.value) |
                               (spr == SPR.PIDR.value))
+        comb += is_trap_spr.eq((spr == SPR.KAIVB.value)
+                              )
         # MMU must receive MMU SPRs
         with m.If(is_spr_mv & (fn == Function.SPR) & is_mmu_spr):
             comb += self.do_copy("fn_unit", Function.MMU)
             comb += self.do_copy("insn_type", internal_op)
-        # SPR pipe must *not* receive MMU SPRs
-        with m.Elif(is_spr_mv & (fn == Function.MMU) & ~is_mmu_spr):
+        # TRAP must receive TRAP SPR KAIVB
+        with m.If(is_spr_mv & (fn == Function.SPR) & is_trap_spr):
+            comb += self.do_copy("fn_unit", Function.TRAP)
+            comb += self.do_copy("insn_type", internal_op)
+        # SPR pipe must *not* receive MMU or TRAP SPRs
+        with m.Elif(is_spr_mv & ((fn == Function.MMU) & ~is_mmu_spr) &
+                                ((fn == Function.TRAP) & ~is_trap_spr)):
             comb += self.do_copy("fn_unit", Function.NONE)
             comb += self.do_copy("insn_type", MicrOp.OP_ILLEGAL)
         # all others ok
@@ -971,15 +1005,6 @@ class PowerDecodeSubset(Elaboratable):
             comb += dec_bi.sel_in.eq(self.op_get("in2_sel"))
             comb += self.do_copy("imm_data", dec_bi.imm_out)  # imm in RB
 
-        # rc and oe out
-        comb += self.do_copy("rc", dec_rc.rc_out)
-        if self.svp64_en:
-            # OE only enabled when SVP64 not active
-            with m.If(~self.is_svp64_mode):
-                comb += self.do_copy("oe", dec_oe.oe_out)
-        else:
-            comb += self.do_copy("oe", dec_oe.oe_out)
-
         # CR in/out - note: these MUST match with what happens in
         # DecodeCROut!
         rc_out = self.dec_rc.rc_out.data
@@ -999,28 +1024,10 @@ class PowerDecodeSubset(Elaboratable):
             # quickly determined, and the Decoder result MUXed over to
             # the alternative decoder, svdecldst. what a mess... *sigh*
             sv_ptype = self.op_get("SV_Ptype")
+            sv_mode = self.op_get("SV_mode")
             fn = self.op_get("function_unit")
-            # detect major opcode for LDs: include 58 here. from CSV files.
-            # BLECH! TODO: these should be done using "mini decoders",
-            # using row and column subsets
-            is_major_ld = Signal()
-            # bits... errr... MSB0 0..5 which is 26:32 python
-            major = Signal(6)
-            comb += major.eq(self.dec.opcode_in[26:32])
-            comb += is_major_ld.eq((major == 34) | (major == 35) |
-                                   (major == 50) | (major == 51) |
-                                   (major == 48) | (major == 49) |
-                                   (major == 42) | (major == 43) |
-                                   (major == 40) | (major == 41) |
-                                   (major == 32) | (major == 33) |
-                                   (major == 58))
-            with m.If(self.is_svp64_mode & is_major_ld):
-                # straight-up: "it's a LD".  this gives enough info
-                # for SVP64 RM Mode decoding to detect LD/ST, and
-                # consequently detect the SHIFT mode. sigh
-                comb += rm_dec.fn_in.eq(Function.LDST)
-            with m.Else():
-                comb += rm_dec.fn_in.eq(fn)  # decode needs to know Fn type
+            comb += rm_dec.sv_mode.eq(sv_mode)  # BRANCH/CROP/LDST_IMM etc.
+            comb += rm_dec.fn_in.eq(fn)  # decode needs to know Fn type
             comb += rm_dec.ptype_in.eq(sv_ptype)  # Single/Twin predicated
             comb += rm_dec.rc_in.eq(rc_out)  # Rc=1
             comb += rm_dec.rm_in.eq(self.sv_rm)  # SVP64 RM mode
@@ -1029,20 +1036,73 @@ class PowerDecodeSubset(Elaboratable):
                 comb += rm_dec.ldst_imz_in.eq(bzero)  # B immediate is zero
 
             # main PowerDecoder2 determines if different SVP64 modes enabled
-            if not self.final:
-                # if shift mode requested
-                shiftmode = rm_dec.ldstmode == SVP64LDSTmode.SHIFT
-                comb += self.use_svp64_ldst_dec.eq(shiftmode)
             # detect if SVP64 FFT mode enabled (really bad hack),
             # exclude fcfids and others
             # XXX this is a REALLY bad hack, REALLY has to be done better.
             # likely with a sub-decoder.
-            xo5 = Signal(1)  # 1 bit from Minor 59 XO field == 0b0XXXX
-            comb += xo5.eq(self.dec.opcode_in[5])
-            xo = Signal(5)  # 5 bits from Minor 59 fcfids == 0b01110
-            comb += xo.eq(self.dec.opcode_in[1:6])
-            comb += self.use_svp64_fft.eq((major == 59) & (xo5 == 0b0) &
-                                          (xo != 0b01110))
+            # what this ultimately does is enable the 2nd implicit register
+            # (FRS) for SVP64-decoding.  all of these instructions are
+            # 3-in 2-out but there is not enough room either in the
+            # opcode *or* EXTRA2/3 to specify a 5th operand.
+            major = Signal(6)
+            comb += major.eq(self.dec.opcode_in[26:32])
+            xo = Signal(10)
+            comb += xo.eq(self.dec.opcode_in[1:11])
+            comb += self.implicit_rs.eq(0)
+            comb += self.extend_rb_maxvl.eq(0)
+            comb += self.extend_rc_maxvl.eq(0)
+            # implicit RS for major 59
+            with m.If((major == 59) & xo.matches(
+                    '-----00100',  # ffmsubs
+                    '-----00101',  # ffmadds
+                    '-----00110',  # ffnmsubs
+                    '-----00111',  # ffnmadds
+                    '1111100000',  # ffadds
+                    '-----11011',  # fdmadds
+                )):
+                comb += self.implicit_rs.eq(1)
+                comb += self.extend_rb_maxvl.eq(1) # extend RB
+            xo6 = Signal(6)
+            comb += xo6.eq(self.dec.opcode_in[0:6])
+            # implicit RS for major 4
+            with m.If((major == 4) & xo6.matches(
+                    '111000',  # pcdec
+                    '110010',  # maddedu
+                    '111001',  # maddedus
+                    '111010',  # divmod2du
+                    '11010-',  # dsld
+                    '11011-',  # dsrd
+                )):
+                comb += self.implicit_rs.eq(1)
+                comb += self.extend_rc_maxvl.eq(1) # RS=RT+MAXVL or RS=RC
+            # implicit RS for major 22, integer maddsubrs
+            with m.If((major == 22) & xo6.matches(
+                    '-01000',  # maddsubrs
+                    '-01001',  # maddrs
+                    '-01011',  # msubrs
+                )):
+                comb += self.implicit_rs.eq(1)
+                comb += self.extend_rb_maxvl.eq(1) # extend RB
+
+        # rc and oe out
+        comb += self.do_copy("rc", dec_rc.rc_out)
+        if self.svp64_en:
+            # OE only enabled when SVP64 not active
+            with m.If(~self.is_svp64_mode):
+                comb += self.do_copy("oe", dec_oe.oe_out)
+            # RC1 overrides Rc if rc type is NONE or ONE or Rc=0, in svp64_mode
+            # for instructions with a forced-Rc=1 (stbcx., pcdec.)
+            # the RC1 RM bit *becomes* Rc=0/1, but for instructions
+            # that have Rc=0/1 then when Rc=0 RC1 *becomes* (replaces) Rc.
+            with m.Elif((dec_rc.sel_in.matches(RCOE.RC, RCOE.RC_ONLY) &
+                         dec_rc.rc_out.data == 0) |
+                         (dec_rc.sel_in == RCOE.ONE)):
+                RC1 = Data(1, "RC1")
+                comb += RC1.ok.eq(rm_dec.RC1)
+                comb += RC1.RC1.eq(rm_dec.RC1)
+                comb += self.do_copy("rc", RC1)
+        else:
+            comb += self.do_copy("oe", dec_oe.oe_out)
 
         # decoded/selected instruction flags
         comb += self.do_copy("data_len", self.op_get("ldst_len"))
@@ -1060,6 +1120,7 @@ class PowerDecodeSubset(Elaboratable):
         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
+        comb += self.do_copy("reserve", self.op_get("rsrv"))  # atomic
 
         # copy over SVP64 input record fields (if they exist)
         if self.svp64_en:
@@ -1108,13 +1169,18 @@ class PowerDecode2(PowerDecodeSubset):
     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.
+
+    also instr_fault works the same way: the instruction is "rewritten"
+    so that the "fake" op that gets created is OP_FETCH_FAILED
     """
 
     def __init__(self, dec, opkls=None, fn_name=None, final=False,
-                 state=None, svp64_en=True, regreduce_en=False):
+                 state=None, svp64_en=True, regreduce_en=False, fp_en=False):
         super().__init__(dec, opkls, fn_name, final, state, svp64_en,
-                         regreduce_en=False)
-        self.ldst_exc = LDSTException("dec2_exc")
+                         regreduce_en=False, fp_en=fp_en)
+        self.ldst_exc = LDSTException("dec2_exc")  # rewrites as OP_TRAP
+        self.instr_fault = Signal()  # rewrites instruction as OP_FETCH_FAILED
+        self.crout_5bit = Signal()  # CR out is 5-bit
 
         if self.svp64_en:
             self.cr_out_isvec = Signal(1, name="cr_out_isvec")
@@ -1157,6 +1223,7 @@ class PowerDecode2(PowerDecodeSubset):
             subset.add("sv_cr_out")
             subset.add("SV_Etype")
             subset.add("SV_Ptype")
+            subset.add("SV_mode")
             # from SVP64RMModeDecode
             for (field, _) in sv_input_record_layout:
                 subset.add(field)
@@ -1187,6 +1254,7 @@ class PowerDecode2(PowerDecodeSubset):
         m.submodules.dec_cr_in = self.dec_cr_in = DecodeCRIn(self.dec, op)
         m.submodules.dec_cr_out = self.dec_cr_out = DecodeCROut(self.dec, op)
         comb += dec_a.sv_nz.eq(self.sv_a_nz)
+        comb += self.crout_5bit.eq(self.dec_cr_out.cr_5bit)
 
         if self.svp64_en:
             # and SVP64 Extra decoders
@@ -1229,7 +1297,8 @@ class PowerDecode2(PowerDecodeSubset):
         comb += dec_o.sel_in.eq(self.op_get("out_sel"))
         comb += dec_o2.sel_in.eq(self.op_get("out_sel"))
         if self.svp64_en:
-            comb += dec_o2.svp64_fft_mode.eq(self.use_svp64_fft)
+            comb += dec_o2.implicit_rs.eq(self.implicit_rs)
+            comb += dec_o2.implicit_from_rc.eq(self.extend_rc_maxvl)
         if hasattr(do, "lk"):
             comb += dec_o2.lk.eq(do.lk)
 
@@ -1270,16 +1339,29 @@ class PowerDecode2(PowerDecodeSubset):
 
             # get SVSTATE srcstep (TODO: elwidth etc.) needed below
             vl = Signal.like(self.state.svstate.vl)
+            maxvl = Signal.like(self.state.svstate.maxvl)
+            subvl = Signal.like(self.rm_dec.rm_in.subvl)
             srcstep = Signal.like(self.state.svstate.srcstep)
             dststep = Signal.like(self.state.svstate.dststep)
+            ssubstep = Signal.like(self.state.svstate.ssubstep)
+            dsubstep = Signal.like(self.state.svstate.ssubstep)
             comb += vl.eq(self.state.svstate.vl)
+            comb += maxvl.eq(self.state.svstate.maxvl)
+            comb += subvl.eq(self.rm_dec.rm_in.subvl)
             comb += srcstep.eq(self.state.svstate.srcstep)
             comb += dststep.eq(self.state.svstate.dststep)
+            comb += ssubstep.eq(self.state.svstate.ssubstep)
+            comb += dsubstep.eq(self.state.svstate.dsubstep)
 
             in1_step, in2_step = self.in1_step, self.in2_step
             in3_step = self.in3_step
             o_step, o2_step = self.o_step, self.o2_step
 
+            # multiply vl by subvl - note that this is only 7 bit!
+            # when elwidth overrides get involved this will have to go up
+            vmax = Signal(7)
+            comb += vmax.eq(vl*(subvl+1))
+
             # registers a, b, c and out and out2 (LD/ST EA)
             sv_etype = self.op_get("SV_Etype")
             for i, stuff in enumerate((
@@ -1287,7 +1369,7 @@ class PowerDecode2(PowerDecodeSubset):
                 ("RB", e.read_reg2, dec_b.reg_out, in2_svdec, in2_step, False),
                 ("RC", e.read_reg3, dec_c.reg_out, in3_svdec, in3_step, False),
                 ("RT", e.write_reg, dec_o.reg_out, o_svdec, o_step, True),
-                    ("EA", e.write_ea, dec_o2.reg_out, o2_svdec, o2_step, True))):
+                ("EA", e.write_ea, dec_o2.reg_out, o2_svdec, o2_step, True))):
                 rname, to_reg, fromreg, svdec, remapstep, out = stuff
                 comb += svdec.extra.eq(extra)     # EXTRA field of SVP64 RM
                 comb += svdec.etype.eq(sv_etype)  # EXTRA2/3 for this insn
@@ -1302,26 +1384,30 @@ class PowerDecode2(PowerDecodeSubset):
                     # automagically add on an extra offset to RB.
                     # however when REMAP is active, the FFT REMAP
                     # schedule takes care of this offset.
-                    with m.If(dec_o2.reg_out.ok & dec_o2.fp_madd_en):
+                    with m.If(dec_o2.reg_out.ok & dec_o2.rs_en &
+                              self.extend_rb_maxvl):
                         with m.If(~self.remap_active[i]):
                             with m.If(svdec.isvec):
-                                comb += offs.eq(vl)  # VL for Vectors
+                                comb += offs.eq(maxvl)  # MAXVL for Vectors
                 # detect if Vectorised: add srcstep/dststep if yes.
                 # to_reg is 7-bits, outs get dststep added, ins get srcstep
                 with m.If(svdec.isvec):
                     selectstep = dststep if out else srcstep
+                    subselect = dsubstep if out else ssubstep
                     step = Signal(7, name="step_%s" % rname.lower())
                     with m.If(self.remap_active[i]):
-                        comb += step.eq(remapstep)
+                        comb += step.eq((remapstep*(subvl+1))+subselect)
                     with m.Else():
-                        comb += step.eq(selectstep)
+                        comb += step.eq((selectstep*(subvl+1))+subselect)
                     # reverse gear goes the opposite way
                     with m.If(self.rm_dec.reverse_gear):
-                        comb += to_reg.data.eq(offs+svdec.reg_out+(vl-1-step))
+                        comb += to_reg.offs.eq(offs+(vmax-1-step))
                     with m.Else():
-                        comb += to_reg.data.eq(offs+step+svdec.reg_out)
+                        comb += to_reg.offs.eq(offs+step)
                 with m.Else():
-                    comb += to_reg.data.eq(offs+svdec.reg_out)
+                    comb += to_reg.offs.eq(offs)
+                comb += to_reg.base.eq(svdec.reg_out)
+                comb += to_reg.data.eq(to_reg.base + to_reg.offs)
 
             # SVP64 in/out fields
             comb += in1_svdec.idx.eq(self.op_get("sv_in1"))  # reg #1 (in1_sel)
@@ -1342,38 +1428,53 @@ class PowerDecode2(PowerDecodeSubset):
             comb += self.o2_isvec.eq(o2_svdec.isvec)
 
             # urrr... don't ask... the implicit register FRS in FFT mode
-            # "tracks" FRT exactly except it's offset by VL.  rather than
+            # "tracks" FRT exactly except it's offset by MAXVL.  rather than
             # mess up the above with if-statements, override it here.
-            # same trick is applied to FRA, above, but it's a lot cleaner, there
-            with m.If(dec_o2.reg_out.ok & dec_o2.fp_madd_en):
+            # same trick is applied to FRB, above, but it's a lot cleaner there
+            with m.If(dec_o2.reg_out.ok & dec_o2.rs_en):
+                imp_reg_out = Signal(7)
+                imp_isvec   = Signal(1)
+                with m.If(self.extend_rc_maxvl): # maddedu etc. from RC
+                    comb += imp_isvec.eq(in3_svdec.isvec)
+                    comb += imp_reg_out.eq(in3_svdec.reg_out)
+                with m.Else():
+                    comb += imp_isvec.eq(o_svdec.isvec)
+                    comb += imp_reg_out.eq(o_svdec.reg_out)
                 comb += offs.eq(0)
                 with m.If(~self.remap_active[4]):
-                    with m.If(o2_svdec.isvec):
-                        comb += offs.eq(vl)  # VL for Vectors
+                    with m.If(imp_isvec):
+                        comb += offs.eq(maxvl)  # MAXVL for Vectors
+                    with m.Elif(self.extend_rc_maxvl): # maddedu etc. from RC
+                        comb += offs.eq(0)  # keep as RC
                     with m.Else():
                         comb += offs.eq(1)  # add 1 if scalar
-                svdec = o_svdec  # yes take source as o_svdec...
-                with m.If(svdec.isvec):
+                with m.If(imp_isvec):
                     step = Signal(7, name="step_%s" % rname.lower())
                     with m.If(self.remap_active[4]):
-                        comb += step.eq(o2_step)
+                        with m.If(self.extend_rc_maxvl): # maddedu etc. from RC
+                            comb += step.eq(in3_step)
+                        with m.Else():
+                            comb += step.eq(o2_step)
                     with m.Else():
                         comb += step.eq(dststep)
                     # reverse gear goes the opposite way
                     with m.If(self.rm_dec.reverse_gear):
                         roffs = offs+(vl-1-step)
-                        comb += to_reg.data.eq(roffs+svdec.reg_out)
+                        comb += e.write_ea.data.eq(roffs)
                     with m.Else():
-                        comb += to_reg.data.eq(offs+step+svdec.reg_out)
+                        comb += e.write_ea.data.eq(offs+step)
                 with m.Else():
-                    comb += to_reg.data.eq(offs+svdec.reg_out)
+                    comb += e.write_ea.offs.eq(offs)
+                comb += e.write_ea.base.eq(imp_reg_out)
+                comb += e.write_ea.data.eq(e.write_ea.base + e.write_ea.offs)
                 # ... but write to *second* output
-                comb += self.o2_isvec.eq(svdec.isvec)
+                comb += self.o2_isvec.eq(imp_isvec)
                 comb += o2_svdec.idx.eq(self.op_get("sv_out"))
 
             # TODO add SPRs here.  must be True when *all* are scalar
             l = map(lambda svdec: svdec.isvec, [in1_svdec, in2_svdec, in3_svdec,
-                                                crin_svdec, crin_svdec_b, crin_svdec_o])
+                                                crin_svdec, crin_svdec_b,
+                                                crin_svdec_o])
             comb += self.no_in_vec.eq(~Cat(*l).bool())  # all input scalar
             l = map(lambda svdec: svdec.isvec, [
                     o2_svdec, o_svdec, crout_svdec])
@@ -1387,11 +1488,11 @@ class PowerDecode2(PowerDecodeSubset):
             # should continue.  this doesn't include predication bit-tests
             loop = self.loop_continue
             with m.Switch(self.op_get("SV_Ptype")):
-                with m.Case(SVPtype.P2.value):
+                with m.Case(SVPType.P2.value):
                     # twin-predication
                     # TODO: *and cache-inhibited LD/ST!*
                     comb += loop.eq(~(self.no_in_vec | self.no_out_vec))
-                with m.Case(SVPtype.P1.value):
+                with m.Case(SVPType.P1.value):
                     # single-predication, test relies on dest only
                     comb += loop.eq(~self.no_out_vec)
                 with m.Default():
@@ -1403,7 +1504,7 @@ class PowerDecode2(PowerDecodeSubset):
                 (e.read_cr1, self.dec_cr_in, "cr_bitfield", crin_svdec, 0),
                 (e.read_cr2, self.dec_cr_in, "cr_bitfield_b", crin_svdec_b, 0),
                 (e.read_cr3, self.dec_cr_in, "cr_bitfield_o", crin_svdec_o, 0),
-                    (e.write_cr, self.dec_cr_out, "cr_bitfield", crout_svdec, 1)):
+                (e.write_cr, self.dec_cr_out, "cr_bitfield", crout_svdec, 1)):
                 fromreg = getattr(cr, name)
                 comb += svdec.extra.eq(extra)     # EXTRA field of SVP64 RM
                 comb += svdec.etype.eq(sv_etype)  # EXTRA2/3 for this insn
@@ -1449,6 +1550,10 @@ class PowerDecode2(PowerDecodeSubset):
 
         if self.svp64_en:
             comb += self.rm_dec.ldst_ra_vec.eq(self.in1_isvec)  # RA is vector
+            comb += self.rm_dec.cr_5bit_in.eq(self.crout_5bit)  # CR is 5-bit
+            # take bottom 2 bits of CR out (CR field selector)
+            with m.If(self.crout_5bit):
+                comb += self.rm_dec.cr_2bit_in.eq(self.dec_cr_out.cr_2bit)
 
         # SPRs out
         comb += e.read_spr1.eq(dec_a.spr_out)
@@ -1460,6 +1565,9 @@ class PowerDecode2(PowerDecodeSubset):
         comb += e.write_fast1.eq(dec_o.fast_out)   # SRR0 (OP_RFID)
         comb += e.write_fast2.eq(dec_o2.fast_out)  # SRR1 (ditto)
         comb += e.write_fast3.eq(dec_o2.fast_out3)  # SVSRR0 (ditto)
+        # and State regs (DEC, TB)
+        comb += e.read_state1.eq(dec_a.state_out)    # DEC/TB
+        comb += e.write_state1.eq(dec_o.state_out)   # DEC/TB
 
         # sigh this is exactly the sort of thing for which the
         # decoder is designed to not need.  MTSPR, MFSPR and others need
@@ -1501,22 +1609,33 @@ class PowerDecode2(PowerDecodeSubset):
         comb += priv_ok.eq(is_priv_insn & msr[MSR.PR])
         comb += illeg_ok.eq(op.internal_op == MicrOp.OP_ILLEGAL)
 
+        # absolute top priority: check for an instruction failed
+        with m.If(self.instr_fault):
+            comb += self.e.eq(0)  # reset eeeeeverything
+            comb += self.do_copy("insn", self.dec.opcode_in, True)
+            comb += self.do_copy("insn_type", MicrOp.OP_FETCH_FAILED, True)
+            comb += self.do_copy("fn_unit", Function.MMU, True)
+            comb += self.do_copy("cia", self.state.pc, True)  # PC
+            comb += self.do_copy("msr", self.state.msr, True)  # MSR
+            # special override on internal_op, due to being a "fake" op
+            comb += self.dec.op.internal_op.eq(MicrOp.OP_FETCH_FAILED)
+
         # LD/ST exceptions.  TestIssuer copies the exception info at us
         # after a failed LD/ST.
-        with m.If(ldst_exc.happened):
+        with m.Elif(ldst_exc.happened):
             with m.If(ldst_exc.alignment):
-                self.trap(m, TT.PRIV, 0x600)
+                self.trap(m, TT.MEMEXC, 0x600)
             with m.Elif(ldst_exc.instr_fault):
                 with m.If(ldst_exc.segment_fault):
-                    self.trap(m, TT.PRIV, 0x480)
+                    self.trap(m, TT.MEMEXC, 0x480)
                 with m.Else():
                     # pass exception info to trap to create SRR1
                     self.trap(m, TT.MEMEXC, 0x400, ldst_exc)
             with m.Else():
                 with m.If(ldst_exc.segment_fault):
-                    self.trap(m, TT.PRIV, 0x380)
+                    self.trap(m, TT.MEMEXC, 0x380)
                 with m.Else():
-                    self.trap(m, TT.PRIV, 0x300)
+                    self.trap(m, TT.MEMEXC, 0x300)
 
         # decrement counter (v3.0B p1099): TODO 32-bit version (MSR.LPCR)
         with m.Elif(dec_irq_ok):
@@ -1599,12 +1718,15 @@ class PowerDecode2(PowerDecodeSubset):
         comb += self.do_copy("svstate", self.state.svstate, True)  # SVSTATE
 
 
-def get_rdflags(e, cu):
+def get_rdflags(m, e, cu):
+    """returns a sequential list of the read "ok" flags for a given FU.
+    this list is in order of the CompUnit input specs
+    """
     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)
+        decinfo = regspec_decode_read(m, e, regfile, regname)
+        rdl.append(decinfo.okflag)
     log("rdflags", rdl)
     return Cat(*rdl)