swap complicated bits, simplify ISACaller, reduce indent level
[openpower-isa.git] / src / openpower / decoder / isa / caller.py
index 275136e9c3642c4fe2d6405d3f8e69c247110ade..e51d24f62a731e006e0cab22f7ce1615c80964d4 100644 (file)
@@ -13,18 +13,24 @@ related bugs:
 * https://bugs.libre-soc.org/show_bug.cgi?id=424
 """
 
 * https://bugs.libre-soc.org/show_bug.cgi?id=424
 """
 
+import re
 from nmigen.back.pysim import Settle
 from functools import wraps
 from copy import copy, deepcopy
 from openpower.decoder.orderedset import OrderedSet
 from nmigen.back.pysim import Settle
 from functools import wraps
 from copy import copy, deepcopy
 from openpower.decoder.orderedset import OrderedSet
-from openpower.decoder.selectable_int import (FieldSelectableInt, SelectableInt,
-                                        selectconcat)
+from openpower.decoder.selectable_int import (
+    SelectableIntMapping,
+    FieldSelectableInt,
+    SelectableInt,
+    selectconcat,
+)
 from openpower.decoder.power_enums import (spr_dict, spr_byname, XER_bits,
 from openpower.decoder.power_enums import (spr_dict, spr_byname, XER_bits,
-                                     insns, MicrOp, In1Sel, In2Sel, In3Sel,
-                                     OutSel, CRInSel, CROutSel, LDSTMode,
-                                     SVP64RMMode, SVP64PredMode,
-                                     SVP64PredInt, SVP64PredCR,
-                                     SVP64LDSTmode)
+                                           insns, MicrOp,
+                                           In1Sel, In2Sel, In3Sel,
+                                           OutSel, CRInSel, CROutSel, LDSTMode,
+                                           SVP64RMMode, SVP64PredMode,
+                                           SVP64PredInt, SVP64PredCR,
+                                           SVP64LDSTmode)
 
 from openpower.decoder.power_enums import SVPtype
 
 
 from openpower.decoder.power_enums import SVPtype
 
@@ -33,7 +39,7 @@ from openpower.decoder.helpers import (exts, gtu, ltu, undefined,
 from openpower.consts import PIb, MSRb  # big-endian (PowerISA versions)
 from openpower.consts import (SVP64MODE,
                               SVP64CROffs,
 from openpower.consts import PIb, MSRb  # big-endian (PowerISA versions)
 from openpower.consts import (SVP64MODE,
                               SVP64CROffs,
-                             )
+                              )
 from openpower.decoder.power_svp64 import SVP64RM, decode_extra
 
 from openpower.decoder.isa.radixmmu import RADIX
 from openpower.decoder.power_svp64 import SVP64RM, decode_extra
 
 from openpower.decoder.isa.radixmmu import RADIX
@@ -88,7 +94,7 @@ REG_SORT_ORDER = {
     "CA": 0,
     "CA32": 0,
 
     "CA": 0,
     "CA32": 0,
 
-    "overflow": 7, # should definitely be last
+    "overflow": 7,  # should definitely be last
 }
 
 fregs = ['FRA', 'FRB', 'FRC', 'FRS', 'FRT']
 }
 
 fregs = ['FRA', 'FRB', 'FRC', 'FRS', 'FRT']
@@ -102,7 +108,6 @@ def create_args(reglist, extra=None):
     return retval
 
 
     return retval
 
 
-
 class GPR(dict):
     def __init__(self, decoder, isacaller, svstate, regfile):
         dict.__init__(self)
 class GPR(dict):
     def __init__(self, decoder, isacaller, svstate, regfile):
         dict.__init__(self)
@@ -221,7 +226,7 @@ class SPR(dict):
     def dump(self, printout=True):
         res = []
         keys = list(self.keys())
     def dump(self, printout=True):
         res = []
         keys = list(self.keys())
-        #keys.sort()
+        # keys.sort()
         for k in keys:
             sprname = spr_dict.get(k, None)
             if sprname is None:
         for k in keys:
             sprname = spr_dict.get(k, None)
             if sprname is None:
@@ -238,7 +243,7 @@ class SPR(dict):
 class PC:
     def __init__(self, pc_init=0):
         self.CIA = SelectableInt(pc_init, 64)
 class PC:
     def __init__(self, pc_init=0):
         self.CIA = SelectableInt(pc_init, 64)
-        self.NIA = self.CIA + SelectableInt(4, 64) # only true for v3.0B!
+        self.NIA = self.CIA + SelectableInt(4, 64)  # only true for v3.0B!
 
     def update_nia(self, is_svp64):
         increment = 8 if is_svp64 else 4
 
     def update_nia(self, is_svp64):
         increment = 8 if is_svp64 else 4
@@ -254,56 +259,66 @@ class PC:
 
 
 # SVP64 ReMap field
 
 
 # SVP64 ReMap field
-class SVP64RMFields:
-    def __init__(self, init=0):
-        self.spr = SelectableInt(init, 24)
-        # SVP64 RM fields: see https://libre-soc.org/openpower/sv/svp64/
-        self.mmode = FieldSelectableInt(self.spr, [0])
-        self.mask = FieldSelectableInt(self.spr, tuple(range(1,4)))
-        self.elwidth = FieldSelectableInt(self.spr, tuple(range(4,6)))
-        self.ewsrc = FieldSelectableInt(self.spr, tuple(range(6,8)))
-        self.subvl = FieldSelectableInt(self.spr, tuple(range(8,10)))
-        self.extra = FieldSelectableInt(self.spr, tuple(range(10,19)))
-        self.mode = FieldSelectableInt(self.spr, tuple(range(19,24)))
-        # these cover the same extra field, split into parts as EXTRA2
-        self.extra2 = list(range(4))
-        self.extra2[0] = FieldSelectableInt(self.spr, tuple(range(10,12)))
-        self.extra2[1] = FieldSelectableInt(self.spr, tuple(range(12,14)))
-        self.extra2[2] = FieldSelectableInt(self.spr, tuple(range(14,16)))
-        self.extra2[3] = FieldSelectableInt(self.spr, tuple(range(16,18)))
-        self.smask = FieldSelectableInt(self.spr, tuple(range(16,19)))
-        # and here as well, but EXTRA3
-        self.extra3 = list(range(3))
-        self.extra3[0] = FieldSelectableInt(self.spr, tuple(range(10,13)))
-        self.extra3[1] = FieldSelectableInt(self.spr, tuple(range(13,16)))
-        self.extra3[2] = FieldSelectableInt(self.spr, tuple(range(16,19)))
-
-
-SVP64RM_MMODE_SIZE = len(SVP64RMFields().mmode.br)
-SVP64RM_MASK_SIZE = len(SVP64RMFields().mask.br)
-SVP64RM_ELWIDTH_SIZE = len(SVP64RMFields().elwidth.br)
-SVP64RM_EWSRC_SIZE = len(SVP64RMFields().ewsrc.br)
-SVP64RM_SUBVL_SIZE = len(SVP64RMFields().subvl.br)
-SVP64RM_EXTRA2_SPEC_SIZE = len(SVP64RMFields().extra2[0].br)
-SVP64RM_EXTRA3_SPEC_SIZE = len(SVP64RMFields().extra3[0].br)
-SVP64RM_SMASK_SIZE = len(SVP64RMFields().smask.br)
-SVP64RM_MODE_SIZE = len(SVP64RMFields().mode.br)
+class SVP64RMFields(SelectableIntMapping, bits=24, fields={
+    "spr": range(24),
+    # SVP64 RM fields: see https://libre-soc.org/openpower/sv/svp64/
+    "mmode": (0,),
+    "mask": range(1, 4),
+    "elwidth": range(4, 6),
+    "ewsrc": range(6, 8),
+    "subvl": range(8, 10),
+    "extra": range(10, 19),
+    "mode": range(19, 24),
+    # these cover the same extra field, split into parts as EXTRA2
+    "extra2": dict(enumerate([
+        range(10, 12),
+        range(12, 14),
+        range(14, 16),
+        range(16, 18),
+    ])),
+    "smask": range(16, 19),
+    # and here as well, but EXTRA3
+    "extra3": dict(enumerate([
+        range(10, 13),
+        range(13, 16),
+        range(16, 19),
+    ])),
+}):
+
+    def __init__(self, value=0):
+        super().__init__(value=value)
+        self.spr = self
+
+
+SVP64RM_MMODE_SIZE = len(SVP64RMFields.mmode)
+SVP64RM_MASK_SIZE = len(SVP64RMFields.mask)
+SVP64RM_ELWIDTH_SIZE = len(SVP64RMFields.elwidth)
+SVP64RM_EWSRC_SIZE = len(SVP64RMFields.ewsrc)
+SVP64RM_SUBVL_SIZE = len(SVP64RMFields.subvl)
+SVP64RM_EXTRA2_SPEC_SIZE = len(SVP64RMFields.extra2[0])
+SVP64RM_EXTRA3_SPEC_SIZE = len(SVP64RMFields.extra3[0])
+SVP64RM_SMASK_SIZE = len(SVP64RMFields.smask)
+SVP64RM_MODE_SIZE = len(SVP64RMFields.mode)
 
 
 # SVP64 Prefix fields: see https://libre-soc.org/openpower/sv/svp64/
 
 
 # SVP64 Prefix fields: see https://libre-soc.org/openpower/sv/svp64/
-class SVP64PrefixFields:
-    def __init__(self):
-        self.insn = SelectableInt(0, 32)
-        # 6 bit major opcode EXT001, 2 bits "identifying" (7, 9), 24 SV ReMap
-        self.major = FieldSelectableInt(self.insn, tuple(range(0,6)))
-        self.pid = FieldSelectableInt(self.insn, (7, 9)) # must be 0b11
-        rmfields = [6, 8] + list(range(10,32)) # SVP64 24-bit RM (ReMap)
-        self.rm = FieldSelectableInt(self.insn, rmfields)
+class SVP64PrefixFields(SelectableIntMapping, bits=32, fields={
+    "insn": range(32),
+    # 6 bit major opcode EXT001, 2 bits "identifying" (7, 9), 24 SV ReMap
+    "major": range(0, 6),
+    "pid": (7, 9),
+    # SVP64 24-bit RM (ReMap)
+    "rm": ((6, 8) + tuple(range(10, 32))),
+}):
 
 
+    def __init__(self, value=0):
+        super().__init__(value=value)
+        self.insn = self
 
 
-SV64P_MAJOR_SIZE = len(SVP64PrefixFields().major.br)
-SV64P_PID_SIZE = len(SVP64PrefixFields().pid.br)
-SV64P_RM_SIZE = len(SVP64PrefixFields().rm.br)
+
+SV64P_MAJOR_SIZE = len(SVP64PrefixFields.major)
+SV64P_PID_SIZE = len(SVP64PrefixFields.pid)
+SV64P_RM_SIZE = len(SVP64PrefixFields.rm)
 
 
 # CR register fields
 
 
 # CR register fields
@@ -327,12 +342,14 @@ class CRFields:
             self.crl.append(_cr)
 
 # decode SVP64 predicate integer to reg number and invert
             self.crl.append(_cr)
 
 # decode SVP64 predicate integer to reg number and invert
+
+
 def get_predint(gpr, mask):
     r10 = gpr(10)
     r30 = gpr(30)
 def get_predint(gpr, mask):
     r10 = gpr(10)
     r30 = gpr(30)
-    log ("get_predint", mask, SVP64PredInt.ALWAYS.value)
+    log("get_predint", mask, SVP64PredInt.ALWAYS.value)
     if mask == SVP64PredInt.ALWAYS.value:
     if mask == SVP64PredInt.ALWAYS.value:
-        return 0xffff_ffff_ffff_ffff
+        return 0xffff_ffff_ffff_ffff  # 64 bits of 1
     if mask == SVP64PredInt.R3_UNARY.value:
         return 1 << (gpr(3).value & 0b111111)
     if mask == SVP64PredInt.R3.value:
     if mask == SVP64PredInt.R3_UNARY.value:
         return 1 << (gpr(3).value & 0b111111)
     if mask == SVP64PredInt.R3.value:
@@ -349,6 +366,8 @@ def get_predint(gpr, mask):
         return ~gpr(30).value
 
 # decode SVP64 predicate CR to reg number and invert status
         return ~gpr(30).value
 
 # decode SVP64 predicate CR to reg number and invert status
+
+
 def _get_predcr(mask):
     if mask == SVP64PredCR.LT.value:
         return 0, 1
 def _get_predcr(mask):
     if mask == SVP64PredCR.LT.value:
         return 0, 1
@@ -369,13 +388,15 @@ def _get_predcr(mask):
 
 # read individual CR fields (0..VL-1), extract the required bit
 # and construct the mask
 
 # read individual CR fields (0..VL-1), extract the required bit
 # and construct the mask
+
+
 def get_predcr(crl, mask, vl):
     idx, noninv = _get_predcr(mask)
     mask = 0
     for i in range(vl):
         cr = crl[i+SVP64CROffs.CRPred]
         if cr[idx].value == noninv:
 def get_predcr(crl, mask, vl):
     idx, noninv = _get_predcr(mask)
     mask = 0
     for i in range(vl):
         cr = crl[i+SVP64CROffs.CRPred]
         if cr[idx].value == noninv:
-            mask |= (1<<i)
+            mask |= (1 << i)
     return mask
 
 
     return mask
 
 
@@ -392,22 +413,22 @@ def get_pdecode_idx_in(dec2, name):
     in1_isvec = yield dec2.in1_isvec
     in2_isvec = yield dec2.in2_isvec
     in3_isvec = yield dec2.in3_isvec
     in1_isvec = yield dec2.in1_isvec
     in2_isvec = yield dec2.in2_isvec
     in3_isvec = yield dec2.in3_isvec
-    log ("get_pdecode_idx_in in1", name, in1_sel, In1Sel.RA.value,
-                                     in1, in1_isvec)
-    log ("get_pdecode_idx_in in2", name, in2_sel, In2Sel.RB.value,
-                                     in2, in2_isvec)
-    log ("get_pdecode_idx_in in3", name, in3_sel, In3Sel.RS.value,
-                                     in3, in3_isvec)
-    log ("get_pdecode_idx_in FRS in3", name, in3_sel, In3Sel.FRS.value,
-                                     in3, in3_isvec)
-    log ("get_pdecode_idx_in FRB in2", name, in2_sel, In2Sel.FRB.value,
-                                     in2, in2_isvec)
-    log ("get_pdecode_idx_in FRC in3", name, in3_sel, In3Sel.FRC.value,
-                                     in3, in3_isvec)
+    log("get_pdecode_idx_in in1", name, in1_sel, In1Sel.RA.value,
+        in1, in1_isvec)
+    log("get_pdecode_idx_in in2", name, in2_sel, In2Sel.RB.value,
+        in2, in2_isvec)
+    log("get_pdecode_idx_in in3", name, in3_sel, In3Sel.RS.value,
+        in3, in3_isvec)
+    log("get_pdecode_idx_in FRS in3", name, in3_sel, In3Sel.FRS.value,
+        in3, in3_isvec)
+    log("get_pdecode_idx_in FRB in2", name, in2_sel, In2Sel.FRB.value,
+        in2, in2_isvec)
+    log("get_pdecode_idx_in FRC in3", name, in3_sel, In3Sel.FRC.value,
+        in3, in3_isvec)
     # identify which regnames map to in1/2/3
     if name == 'RA':
         if (in1_sel == In1Sel.RA.value or
     # identify which regnames map to in1/2/3
     if name == 'RA':
         if (in1_sel == In1Sel.RA.value or
-            (in1_sel == In1Sel.RA_OR_ZERO.value and in1 != 0)):
+                (in1_sel == In1Sel.RA_OR_ZERO.value and in1 != 0)):
             return in1, in1_isvec
         if in1_sel == In1Sel.RA_OR_ZERO.value:
             return in1, in1_isvec
             return in1, in1_isvec
         if in1_sel == In1Sel.RA_OR_ZERO.value:
             return in1, in1_isvec
@@ -454,16 +475,16 @@ def get_pdecode_cr_in(dec2, name):
     # get the IN1/2/3 from the decoder (includes SVP64 remap and isvec)
     in1 = yield dec2.e.read_cr1.data
     cr_isvec = yield dec2.cr_in_isvec
     # get the IN1/2/3 from the decoder (includes SVP64 remap and isvec)
     in1 = yield dec2.e.read_cr1.data
     cr_isvec = yield dec2.cr_in_isvec
-    log ("get_pdecode_cr_in", in_sel, CROutSel.CR0.value, in1, cr_isvec)
-    log ("    sv_cr_in", sv_cr_in)
-    log ("    cr_bf", in_bitfield)
-    log ("    spec", spec)
-    log ("    override", sv_override)
+    log("get_pdecode_cr_in", in_sel, CROutSel.CR0.value, in1, cr_isvec)
+    log("    sv_cr_in", sv_cr_in)
+    log("    cr_bf", in_bitfield)
+    log("    spec", spec)
+    log("    override", sv_override)
     # identify which regnames map to in / o2
     if name == 'BI':
         if in_sel == CRInSel.BI.value:
             return in1, cr_isvec
     # identify which regnames map to in / o2
     if name == 'BI':
         if in_sel == CRInSel.BI.value:
             return in1, cr_isvec
-    log ("get_pdecode_cr_in not found", name)
+    log("get_pdecode_cr_in not found", name)
     return None, False
 
 
     return None, False
 
 
@@ -478,16 +499,16 @@ def get_pdecode_cr_out(dec2, name):
     # get the IN1/2/3 from the decoder (includes SVP64 remap and isvec)
     out = yield dec2.e.write_cr.data
     o_isvec = yield dec2.o_isvec
     # get the IN1/2/3 from the decoder (includes SVP64 remap and isvec)
     out = yield dec2.e.write_cr.data
     o_isvec = yield dec2.o_isvec
-    log ("get_pdecode_cr_out", out_sel, CROutSel.CR0.value, out, o_isvec)
-    log ("    sv_cr_out", sv_cr_out)
-    log ("    cr_bf", out_bitfield)
-    log ("    spec", spec)
-    log ("    override", sv_override)
+    log("get_pdecode_cr_out", out_sel, CROutSel.CR0.value, out, o_isvec)
+    log("    sv_cr_out", sv_cr_out)
+    log("    cr_bf", out_bitfield)
+    log("    spec", spec)
+    log("    override", sv_override)
     # identify which regnames map to out / o2
     if name == 'CR0':
         if out_sel == CROutSel.CR0.value:
             return out, o_isvec
     # identify which regnames map to out / o2
     if name == 'CR0':
         if out_sel == CROutSel.CR0.value:
             return out, o_isvec
-    log ("get_pdecode_cr_out not found", name)
+    log("get_pdecode_cr_out not found", name)
     return None, False
 
 
     return None, False
 
 
@@ -500,31 +521,31 @@ def get_pdecode_idx_out(dec2, name):
     o_isvec = yield dec2.o_isvec
     # identify which regnames map to out / o2
     if name == 'RA':
     o_isvec = yield dec2.o_isvec
     # identify which regnames map to out / o2
     if name == 'RA':
-        log ("get_pdecode_idx_out", out_sel, OutSel.RA.value, out, o_isvec)
+        log("get_pdecode_idx_out", out_sel, OutSel.RA.value, out, o_isvec)
         if out_sel == OutSel.RA.value:
             return out, o_isvec
     elif name == 'RT':
         if out_sel == OutSel.RA.value:
             return out, o_isvec
     elif name == 'RT':
-        log ("get_pdecode_idx_out", out_sel, OutSel.RT.value,
-                                      OutSel.RT_OR_ZERO.value, out, o_isvec,
-                                      dec2.dec.RT)
+        log("get_pdecode_idx_out", out_sel, OutSel.RT.value,
+            OutSel.RT_OR_ZERO.value, out, o_isvec,
+            dec2.dec.RT)
         if out_sel == OutSel.RT.value:
             return out, o_isvec
     elif name == 'RT_OR_ZERO':
         if out_sel == OutSel.RT.value:
             return out, o_isvec
     elif name == 'RT_OR_ZERO':
-        log ("get_pdecode_idx_out", out_sel, OutSel.RT.value,
-                                      OutSel.RT_OR_ZERO.value, out, o_isvec,
-                                      dec2.dec.RT)
+        log("get_pdecode_idx_out", out_sel, OutSel.RT.value,
+            OutSel.RT_OR_ZERO.value, out, o_isvec,
+            dec2.dec.RT)
         if out_sel == OutSel.RT_OR_ZERO.value:
             return out, o_isvec
     elif name == 'FRA':
         if out_sel == OutSel.RT_OR_ZERO.value:
             return out, o_isvec
     elif name == 'FRA':
-        log ("get_pdecode_idx_out", out_sel, OutSel.FRA.value, out, o_isvec)
+        log("get_pdecode_idx_out", out_sel, OutSel.FRA.value, out, o_isvec)
         if out_sel == OutSel.FRA.value:
             return out, o_isvec
     elif name == 'FRT':
         if out_sel == OutSel.FRA.value:
             return out, o_isvec
     elif name == 'FRT':
-        log ("get_pdecode_idx_out", out_sel, OutSel.FRT.value,
-                                      OutSel.FRT.value, out, o_isvec)
+        log("get_pdecode_idx_out", out_sel, OutSel.FRT.value,
+            OutSel.FRT.value, out, o_isvec)
         if out_sel == OutSel.FRT.value:
             return out, o_isvec
         if out_sel == OutSel.FRT.value:
             return out, o_isvec
-    log ("get_pdecode_idx_out not found", name, out_sel, out, o_isvec)
+    log("get_pdecode_idx_out not found", name, out_sel, out, o_isvec)
     return None, False
 
 
     return None, False
 
 
@@ -536,7 +557,7 @@ def get_pdecode_idx_out2(dec2, name):
     out = yield dec2.e.write_ea.data
     o_isvec = yield dec2.o2_isvec
     out_ok = yield dec2.e.write_ea.ok
     out = yield dec2.e.write_ea.data
     o_isvec = yield dec2.o2_isvec
     out_ok = yield dec2.e.write_ea.ok
-    log ("get_pdecode_idx_out2", name, out_sel, out, out_ok, o_isvec)
+    log("get_pdecode_idx_out2", name, out_sel, out, out_ok, o_isvec)
     if not out_ok:
         return None, False
 
     if not out_ok:
         return None, False
 
@@ -544,18 +565,18 @@ def get_pdecode_idx_out2(dec2, name):
         if hasattr(op, "upd"):
             # update mode LD/ST uses read-reg A also as an output
             upd = yield op.upd
         if hasattr(op, "upd"):
             # update mode LD/ST uses read-reg A also as an output
             upd = yield op.upd
-            log ("get_pdecode_idx_out2", upd, LDSTMode.update.value,
-                                           out_sel, OutSel.RA.value,
-                                           out, o_isvec)
+            log("get_pdecode_idx_out2", upd, LDSTMode.update.value,
+                out_sel, OutSel.RA.value,
+                out, o_isvec)
             if upd == LDSTMode.update.value:
                 return out, o_isvec
     if name == 'FRS':
         int_op = yield dec2.dec.op.internal_op
         fft_en = yield dec2.use_svp64_fft
             if upd == LDSTMode.update.value:
                 return out, o_isvec
     if name == 'FRS':
         int_op = yield dec2.dec.op.internal_op
         fft_en = yield dec2.use_svp64_fft
-        #if int_op == MicrOp.OP_FP_MADD.value and fft_en:
+        # if int_op == MicrOp.OP_FP_MADD.value and fft_en:
         if fft_en:
         if fft_en:
-            log ("get_pdecode_idx_out2", out_sel, OutSel.FRS.value,
-                                           out, o_isvec)
+            log("get_pdecode_idx_out2", out_sel, OutSel.FRS.value,
+                out, o_isvec)
             return out, o_isvec
     return None, False
 
             return out, o_isvec
     return None, False
 
@@ -621,20 +642,20 @@ class ISACaller(ISACallerHelper, ISAFPHelpers):
         self.msr = SelectableInt(initial_msr, 64)  # underlying reg
         self.pc = PC()
         # GPR FPR SPR registers
         self.msr = SelectableInt(initial_msr, 64)  # underlying reg
         self.pc = PC()
         # GPR FPR SPR registers
-        initial_sprs = deepcopy(initial_sprs) # so as not to get modified
+        initial_sprs = deepcopy(initial_sprs)  # so as not to get modified
         self.gpr = GPR(decoder2, self, self.svstate, regfile)
         self.fpr = GPR(decoder2, self, self.svstate, fpregfile)
         self.gpr = GPR(decoder2, self, self.svstate, regfile)
         self.fpr = GPR(decoder2, self, self.svstate, fpregfile)
-        self.spr = SPR(decoder2, initial_sprs) # initialise SPRs before MMU
+        self.spr = SPR(decoder2, initial_sprs)  # initialise SPRs before MMU
 
         # set up 4 dummy SVSHAPEs if they aren't already set up
         for i in range(4):
             sname = 'SVSHAPE%d' % i
             if sname not in self.spr:
 
         # set up 4 dummy SVSHAPEs if they aren't already set up
         for i in range(4):
             sname = 'SVSHAPE%d' % i
             if sname not in self.spr:
-                self.spr[sname] = SVSHAPE(0)
+                val = 0
             else:
             else:
-                # make sure it's an SVSHAPE
                 val = self.spr[sname].value
                 val = self.spr[sname].value
-                self.spr[sname] = SVSHAPE(val)
+            # make sure it's an SVSHAPE
+            self.spr[sname] = SVSHAPE(val, self.gpr)
         self.last_op_svshape = False
 
         # "raw" memory
         self.last_op_svshape = False
 
         # "raw" memory
@@ -664,7 +685,7 @@ class ISACaller(ISACallerHelper, ISAFPHelpers):
         self.cr = self.cr_fields.cr
 
         # "undefined", just set to variable-bit-width int (use exts "max")
         self.cr = self.cr_fields.cr
 
         # "undefined", just set to variable-bit-width int (use exts "max")
-        #self.undefined = SelectableInt(0, 256)  # TODO, not hard-code 256!
+        # self.undefined = SelectableInt(0, 256)  # TODO, not hard-code 256!
 
         self.namespace = {}
         self.namespace.update(self.spr)
 
         self.namespace = {}
         self.namespace.update(self.spr)
@@ -720,15 +741,18 @@ class ISACaller(ISACallerHelper, ISAFPHelpers):
         hence the default arguments.  when calling from inside ISACaller
         it is best to use call_trap()
         """
         hence the default arguments.  when calling from inside ISACaller
         it is best to use call_trap()
         """
-        log("TRAP:", hex(trap_addr), hex(self.namespace['MSR'].value))
+        # https://bugs.libre-soc.org/show_bug.cgi?id=859
+        kaivb = self.spr['KAIVB'].value
+        msr = self.namespace['MSR'].value
+        log("TRAP:", hex(trap_addr), hex(msr), "kaivb", hex(kaivb))
         # store CIA(+4?) in SRR0, set NIA to 0x700
         # store MSR in SRR1, set MSR to um errr something, have to check spec
         # store SVSTATE (if enabled) in SVSRR0
         self.spr['SRR0'].value = self.pc.CIA.value
         # store CIA(+4?) in SRR0, set NIA to 0x700
         # store MSR in SRR1, set MSR to um errr something, have to check spec
         # store SVSTATE (if enabled) in SVSRR0
         self.spr['SRR0'].value = self.pc.CIA.value
-        self.spr['SRR1'].value = self.namespace['MSR'].value
+        self.spr['SRR1'].value = msr
         if self.is_svp64_mode:
             self.spr['SVSRR0'] = self.namespace['SVSTATE'].value
         if self.is_svp64_mode:
             self.spr['SVSRR0'] = self.namespace['SVSTATE'].value
-        self.trap_nia = SelectableInt(trap_addr, 64)
+        self.trap_nia = SelectableInt(trap_addr | (kaivb&~0x1fff), 64)
         self.spr['SRR1'][trap_bit] = 1  # change *copy* of MSR in SRR1
 
         # set exception bits.  TODO: this should, based on the address
         self.spr['SRR1'][trap_bit] = 1  # change *copy* of MSR in SRR1
 
         # set exception bits.  TODO: this should, based on the address
@@ -766,15 +790,15 @@ class ISACaller(ISACallerHelper, ISAFPHelpers):
         log("prep_namespace", formname, op_fields)
         for name in op_fields:
             # CR immediates. deal with separately.  needs modifying
         log("prep_namespace", formname, op_fields)
         for name in op_fields:
             # CR immediates. deal with separately.  needs modifying
-            # pseudocode 
-            if self.is_svp64_mode and name in ['BI']: # TODO, more CRs
+            # pseudocode
+            if self.is_svp64_mode and name in ['BI']:  # TODO, more CRs
                 # BI is a 5-bit, must reconstruct the value
                 regnum, is_vec = yield from get_pdecode_cr_in(self.dec2, name)
                 sig = getattr(fields, name)
                 val = yield sig
                 # low 2 LSBs (CR field selector) remain same, CR num extended
                 assert regnum <= 7, "sigh, TODO, 128 CR fields"
                 # BI is a 5-bit, must reconstruct the value
                 regnum, is_vec = yield from get_pdecode_cr_in(self.dec2, name)
                 sig = getattr(fields, name)
                 val = yield sig
                 # low 2 LSBs (CR field selector) remain same, CR num extended
                 assert regnum <= 7, "sigh, TODO, 128 CR fields"
-                val = (val & 0b11) | (regnum<<2)
+                val = (val & 0b11) | (regnum << 2)
             else:
                 if name == 'spr':
                     sig = getattr(fields, name.upper())
             else:
                 if name == 'spr':
                     sig = getattr(fields, name.upper())
@@ -972,29 +996,30 @@ class ISACaller(ISACallerHelper, ISAFPHelpers):
         # SVP64.  first, check if the opcode is EXT001, and SVP64 id bits set
         yield Settle()
         opcode = yield self.dec2.dec.opcode_in
         # SVP64.  first, check if the opcode is EXT001, and SVP64 id bits set
         yield Settle()
         opcode = yield self.dec2.dec.opcode_in
-        pfx = SVP64PrefixFields() # TODO should probably use SVP64PrefixDecoder
+        pfx = SVP64PrefixFields()  # TODO should probably use SVP64PrefixDecoder
         pfx.insn.value = opcode
         pfx.insn.value = opcode
-        major = pfx.major.asint(msb0=True) # MSB0 inversion
-        log ("prefix test: opcode:", major, bin(major),
-                pfx.insn[7] == 0b1, pfx.insn[9] == 0b1)
+        major = pfx.major.asint(msb0=True)  # MSB0 inversion
+        log("prefix test: opcode:", major, bin(major),
+            pfx.insn[7] == 0b1, pfx.insn[9] == 0b1)
         self.is_svp64_mode = ((major == 0b000001) and
                               pfx.insn[7].value == 0b1 and
                               pfx.insn[9].value == 0b1)
         self.pc.update_nia(self.is_svp64_mode)
         self.is_svp64_mode = ((major == 0b000001) and
                               pfx.insn[7].value == 0b1 and
                               pfx.insn[9].value == 0b1)
         self.pc.update_nia(self.is_svp64_mode)
-        yield self.dec2.is_svp64_mode.eq(self.is_svp64_mode) # set SVP64 decode
+        # set SVP64 decode
+        yield self.dec2.is_svp64_mode.eq(self.is_svp64_mode)
         self.namespace['NIA'] = self.pc.NIA
         self.namespace['SVSTATE'] = self.svstate
         if not self.is_svp64_mode:
             return
 
         # in SVP64 mode.  decode/print out svp64 prefix, get v3.0B instruction
         self.namespace['NIA'] = self.pc.NIA
         self.namespace['SVSTATE'] = self.svstate
         if not self.is_svp64_mode:
             return
 
         # in SVP64 mode.  decode/print out svp64 prefix, get v3.0B instruction
-        log ("svp64.rm", bin(pfx.rm.asint(msb0=True)))
-        log ("    svstate.vl", self.svstate.vl)
-        log ("    svstate.mvl", self.svstate.maxvl)
+        log("svp64.rm", bin(pfx.rm.asint(msb0=True)))
+        log("    svstate.vl", self.svstate.vl)
+        log("    svstate.mvl", self.svstate.maxvl)
         sv_rm = pfx.rm.asint(msb0=True)
         ins = self.imem.ld(pc+4, 4, False, True, instr_fetch=True)
         log("     svsetup: 0x%x 0x%x %s" % (pc+4, ins & 0xffffffff, bin(ins)))
         sv_rm = pfx.rm.asint(msb0=True)
         ins = self.imem.ld(pc+4, 4, False, True, instr_fetch=True)
         log("     svsetup: 0x%x 0x%x %s" % (pc+4, ins & 0xffffffff, bin(ins)))
-        yield self.dec2.dec.raw_opcode_in.eq(ins & 0xffffffff) # v3.0B suffix
+        yield self.dec2.dec.raw_opcode_in.eq(ins & 0xffffffff)  # v3.0B suffix
         yield self.dec2.sv_rm.eq(sv_rm)                        # svp64 prefix
         yield Settle()
 
         yield self.dec2.sv_rm.eq(sv_rm)                        # svp64 prefix
         yield Settle()
 
@@ -1018,20 +1043,39 @@ class ISACaller(ISACallerHelper, ISAFPHelpers):
         try:
             yield from self.call(opname)         # execute the instruction
         except MemException as e:                # check for memory errors
         try:
             yield from self.call(opname)         # execute the instruction
         except MemException as e:                # check for memory errors
-            if e.args[0] != 'unaligned':         # only doing aligned at the mo
-                raise e                          # ... re-raise
-            # run a Trap but set DAR first
-            print ("memory unaligned exception, DAR", e.dar)
-            self.spr['DAR'] = SelectableInt(e.dar, 64)
-            self.call_trap(0x600, PIb.PRIV)                # 0x600, privileged
-            return
+            if e.args[0] == 'unaligned':         # alignment error
+               # run a Trap but set DAR first
+                print("memory unaligned exception, DAR", e.dar)
+                self.spr['DAR'] = SelectableInt(e.dar, 64)
+                self.call_trap(0x600, PIb.PRIV)    # 0x600, privileged
+                return
+            elif e.args[0] == 'invalid':         # invalid
+               # run a Trap but set DAR first
+                log("RADIX MMU memory invalid error, mode %s" % e.mode)
+                if e.mode == 'EXECUTE':
+                    # XXX TODO: must set a few bits in SRR1,
+                    # see microwatt loadstore1.vhdl
+                    # if m_in.segerr = '0' then
+                    #     v.srr1(47 - 33) := m_in.invalid;
+                    #     v.srr1(47 - 35) := m_in.perm_error; -- noexec fault
+                    #     v.srr1(47 - 44) := m_in.badtree;
+                    #     v.srr1(47 - 45) := m_in.rc_error;
+                    #     v.intr_vec := 16#400#;
+                    # else
+                    #     v.intr_vec := 16#480#;
+                    self.call_trap(0x400, PIb.PRIV)    # 0x400, privileged
+                else:
+                    self.call_trap(0x300, PIb.PRIV)    # 0x300, privileged
+                return
+            # not supported yet:
+            raise e                          # ... re-raise
 
         # don't use this except in special circumstances
         if not self.respect_pc:
             self.fake_pc += 4
 
         log("execute one, CIA NIA", hex(self.pc.CIA.value),
 
         # don't use this except in special circumstances
         if not self.respect_pc:
             self.fake_pc += 4
 
         log("execute one, CIA NIA", hex(self.pc.CIA.value),
-                                    hex(self.pc.NIA.value))
+            hex(self.pc.NIA.value))
 
     def get_assembly_name(self):
         # TODO, asmregs is from the spec, e.g. add RT,RA,RB
 
     def get_assembly_name(self):
         # TODO, asmregs is from the spec, e.g. add RT,RA,RB
@@ -1041,7 +1085,7 @@ class ISACaller(ISACallerHelper, ISAFPHelpers):
         asmcode = yield self.dec2.dec.op.asmcode
         int_op = yield self.dec2.dec.op.internal_op
         log("get assembly name asmcode", asmcode, int_op,
         asmcode = yield self.dec2.dec.op.asmcode
         int_op = yield self.dec2.dec.op.internal_op
         log("get assembly name asmcode", asmcode, int_op,
-                            hex(dec_insn), bin(insn_1_11))
+            hex(dec_insn), bin(insn_1_11))
         asmop = insns.get(asmcode, None)
 
         # sigh reconstruct the assembly instruction name
         asmop = insns.get(asmcode, None)
 
         # sigh reconstruct the assembly instruction name
@@ -1059,7 +1103,7 @@ class ISACaller(ISACallerHelper, ISAFPHelpers):
             rc_ok = False
         # grrrr have to special-case MUL op (see DecodeOE)
         log("ov %d en %d rc %d en %d op %d" %
             rc_ok = False
         # grrrr have to special-case MUL op (see DecodeOE)
         log("ov %d en %d rc %d en %d op %d" %
-              (ov_ok, ov_en, rc_ok, rc_en, int_op))
+            (ov_ok, ov_en, rc_ok, rc_en, int_op))
         if int_op in [MicrOp.OP_MUL_H64.value, MicrOp.OP_MUL_H32.value]:
             log("mul op")
             if rc_en & rc_ok:
         if int_op in [MicrOp.OP_MUL_H64.value, MicrOp.OP_MUL_H32.value]:
             log("mul op")
             if rc_en & rc_ok:
@@ -1098,7 +1142,7 @@ class ISACaller(ISACallerHelper, ISAFPHelpers):
         in the class for later use.  this to avoid problems with yield
         """
         # go through all iterators in lock-step, advance to next remap_idx
         in the class for later use.  this to avoid problems with yield
         """
         # go through all iterators in lock-step, advance to next remap_idx
-        srcstep, dststep = self.get_src_dststeps()
+        srcstep, dststep, ssubstep, dsubstep = self.get_src_dststeps()
         # get four SVSHAPEs. here we are hard-coding
         SVSHAPE0 = self.spr['SVSHAPE0']
         SVSHAPE1 = self.spr['SVSHAPE1']
         # get four SVSHAPEs. here we are hard-coding
         SVSHAPE0 = self.spr['SVSHAPE0']
         SVSHAPE1 = self.spr['SVSHAPE1']
@@ -1109,7 +1153,7 @@ class ISACaller(ISACallerHelper, ISAFPHelpers):
                   (SVSHAPE1, SVSHAPE1.get_iterator()),
                   (SVSHAPE2, SVSHAPE2.get_iterator()),
                   (SVSHAPE3, SVSHAPE3.get_iterator()),
                   (SVSHAPE1, SVSHAPE1.get_iterator()),
                   (SVSHAPE2, SVSHAPE2.get_iterator()),
                   (SVSHAPE3, SVSHAPE3.get_iterator()),
-                 ]
+                  ]
 
         self.remap_loopends = [0] * 4
         self.remap_idxs = [0, 1, 2, 3]
 
         self.remap_loopends = [0] * 4
         self.remap_idxs = [0, 1, 2, 3]
@@ -1128,7 +1172,7 @@ class ISACaller(ISACallerHelper, ISAFPHelpers):
             self.remap_loopends[i] = loopends
             dbg.append((i, step, remap_idx, loopends))
         for (i, step, remap_idx, loopends) in dbg:
             self.remap_loopends[i] = loopends
             dbg.append((i, step, remap_idx, loopends))
         for (i, step, remap_idx, loopends) in dbg:
-            log ("SVSHAPE %d idx, end" % i, step, remap_idx, bin(loopends))
+            log("SVSHAPE %d idx, end" % i, step, remap_idx, bin(loopends))
         return remaps
 
     def get_spr_msb(self):
         return remaps
 
     def get_spr_msb(self):
@@ -1138,8 +1182,8 @@ class ISACaller(ISACallerHelper, ISAFPHelpers):
     def call(self, name):
         """call(opcode) - the primary execution point for instructions
         """
     def call(self, name):
         """call(opcode) - the primary execution point for instructions
         """
-        self.last_st_addr = None # reset the last known store address
-        self.last_ld_addr = None # etc.
+        self.last_st_addr = None  # reset the last known store address
+        self.last_ld_addr = None  # etc.
 
         ins_name = name.strip()  # remove spaces if not already done so
         if self.halted:
 
         ins_name = name.strip()  # remove spaces if not already done so
         if self.halted:
@@ -1168,7 +1212,7 @@ class ISACaller(ISACallerHelper, ISAFPHelpers):
             instr_is_privileged = True
 
         log("is priv", instr_is_privileged, hex(self.msr.value),
             instr_is_privileged = True
 
         log("is priv", instr_is_privileged, hex(self.msr.value),
-              self.msr[MSRb.PR])
+            self.msr[MSRb.PR])
         # check MSR priv bit and whether op is privileged: if so, throw trap
         if instr_is_privileged and self.msr[MSRb.PR] == 1:
             self.call_trap(0x700, PIb.PRIV)
         # check MSR priv bit and whether op is privileged: if so, throw trap
         if instr_is_privileged and self.msr[MSRb.PR] == 1:
             self.call_trap(0x700, PIb.PRIV)
@@ -1184,54 +1228,24 @@ class ISACaller(ISACallerHelper, ISAFPHelpers):
         if ins_name not in ['mtcrf', 'mtocrf']:
             illegal = ins_name != asmop
 
         if ins_name not in ['mtcrf', 'mtocrf']:
             illegal = ins_name != asmop
 
-        # sigh deal with setvl not being supported by binutils (.long)
-        if asmop.startswith('setvl'):
-            illegal = False
-            ins_name = 'setvl'
-
-        # and svstep not being supported by binutils (.long)
-        if asmop.startswith('svstep'):
-            illegal = False
-            ins_name = 'svstep'
-
-        # and svremap not being supported by binutils (.long)
-        if asmop.startswith('svremap'):
-            illegal = False
-            ins_name = 'svremap'
-
-        # and svshape not being supported by binutils (.long)
-        if asmop.startswith('svshape'):
-            illegal = False
-            ins_name = 'svshape'
-
-        # and fsin and fcos
-        if asmop == 'fsins':
-            illegal = False
-            ins_name = 'fsins'
-        if asmop == 'fcoss':
-            illegal = False
-            ins_name = 'fcoss'
-
-        # sigh also deal with ffmadds not being supported by binutils (.long)
-        if asmop == 'ffmadds':
-            illegal = False
-            ins_name = 'ffmadds'
-
-        # and fdmadds not being supported by binutils (.long)
-        if asmop == 'fdmadds':
-            illegal = False
-            ins_name = 'fdmadds'
-
-        # and ffadds not being supported by binutils (.long)
-        if asmop == 'ffadds':
+        # list of instructions not being supported by binutils (.long)
+        dotstrp = asmop[:-1] if asmop[-1] == '.' else asmop
+        if dotstrp in [ 'fsins', 'fcoss',
+                    'ffmadds', 'fdmadds', 'ffadds',
+                     'mins', 'maxs', 'minu', 'maxu',
+                    'setvl', 'svindex', 'svremap', 'svstep', 'svshape',
+                    'grev', 'ternlogi', 'bmask', 'cprop',
+                    'absdu', 'absds', 'absdacs', 'absdacu', 'avgadd',
+                    'fmvis', 'fishmv',
+                    ]:
             illegal = False
             illegal = False
-            ins_name = 'ffadds'
+            ins_name = dotstrp
 
         # branch-conditional redirects to sv.bc
         if asmop.startswith('bc') and self.is_svp64_mode:
             ins_name = 'sv.%s' % ins_name
 
 
         # branch-conditional redirects to sv.bc
         if asmop.startswith('bc') and self.is_svp64_mode:
             ins_name = 'sv.%s' % ins_name
 
-        log("   post-processed name", ins_name, asmop)
+        log("   post-processed name", dotstrp, ins_name, asmop)
 
         # illegal instructions call TRAP at 0x700
         if illegal:
 
         # illegal instructions call TRAP at 0x700
         if illegal:
@@ -1268,11 +1282,11 @@ class ISACaller(ISACallerHelper, ISAFPHelpers):
             dest_cr, src_cr, src_byname, dest_byname = decode_extra(sv_rm)
         else:
             dest_cr, src_cr, src_byname, dest_byname = False, False, {}, {}
             dest_cr, src_cr, src_byname, dest_byname = decode_extra(sv_rm)
         else:
             dest_cr, src_cr, src_byname, dest_byname = False, False, {}, {}
-        log ("sv rm", sv_rm, dest_cr, src_cr, src_byname, dest_byname)
+        log("sv rm", sv_rm, dest_cr, src_cr, src_byname, dest_byname)
 
         # see if srcstep/dststep need skipping over masked-out predicate bits
         if (self.is_svp64_mode or ins_name == 'setvl' or
 
         # see if srcstep/dststep need skipping over masked-out predicate bits
         if (self.is_svp64_mode or ins_name == 'setvl' or
-           ins_name in ['svremap', 'svstate']):
+                ins_name in ['svremap', 'svstate']):
             yield from self.svstate_pre_inc()
         if self.is_svp64_mode:
             pre = yield from self.update_new_svstate_steps()
             yield from self.svstate_pre_inc()
         if self.is_svp64_mode:
             pre = yield from self.update_new_svstate_steps()
@@ -1281,16 +1295,17 @@ class ISACaller(ISACallerHelper, ISAFPHelpers):
                 self.update_nia()
                 self.update_pc_next()
                 return
                 self.update_nia()
                 self.update_pc_next()
                 return
-            srcstep, dststep = self.get_src_dststeps()
+            srcstep, dststep, ssubstep, dsubstep = self.get_src_dststeps()
             pred_dst_zero = self.pred_dst_zero
             pred_src_zero = self.pred_src_zero
             vl = self.svstate.vl
             pred_dst_zero = self.pred_dst_zero
             pred_src_zero = self.pred_src_zero
             vl = self.svstate.vl
+            subvl = yield self.dec2.rm_dec.rm_in.subvl
 
         # VL=0 in SVP64 mode means "do nothing: skip instruction"
         if self.is_svp64_mode and vl == 0:
             self.pc.update(self.namespace, self.is_svp64_mode)
             log("SVP64: VL=0, end of call", self.namespace['CIA'],
 
         # VL=0 in SVP64 mode means "do nothing: skip instruction"
         if self.is_svp64_mode and vl == 0:
             self.pc.update(self.namespace, self.is_svp64_mode)
             log("SVP64: VL=0, end of call", self.namespace['CIA'],
-                                       self.namespace['NIA'])
+                self.namespace['NIA'])
             return
 
         # for when SVREMAP is active, using pre-arranged schedule.
             return
 
         # for when SVREMAP is active, using pre-arranged schedule.
@@ -1298,83 +1313,30 @@ class ISACaller(ISACallerHelper, ISAFPHelpers):
         remap_en = self.svstate.SVme
         persist = self.svstate.RMpst
         active = (persist or self.last_op_svshape) and remap_en != 0
         remap_en = self.svstate.SVme
         persist = self.svstate.RMpst
         active = (persist or self.last_op_svshape) and remap_en != 0
-        yield self.dec2.remap_active.eq(remap_en if active else 0)
+        if self.is_svp64_mode:
+            yield self.dec2.remap_active.eq(remap_en if active else 0)
         yield Settle()
         if persist or self.last_op_svshape:
             remaps = self.get_remap_indices()
         if self.is_svp64_mode and (persist or self.last_op_svshape):
         yield Settle()
         if persist or self.last_op_svshape:
             remaps = self.get_remap_indices()
         if self.is_svp64_mode and (persist or self.last_op_svshape):
-            # just some convenient debug info
-            for i in range(4):
-                sname = 'SVSHAPE%d' % i
-                shape = self.spr[sname]
-                log (sname, bin(shape.value))
-                log ("    lims", shape.lims)
-                log ("    mode", shape.mode)
-                log ("    skip", shape.skip)
-
-            # set up the list of steps to remap
-            mi0 = self.svstate.mi0
-            mi1 = self.svstate.mi1
-            mi2 = self.svstate.mi2
-            mo0 = self.svstate.mo0
-            mo1 = self.svstate.mo1
-            steps = [(self.dec2.in1_step, mi0), # RA
-                     (self.dec2.in2_step, mi1), # RB
-                     (self.dec2.in3_step, mi2), # RC
-                     (self.dec2.o_step, mo0),   # RT
-                     (self.dec2.o2_step, mo1),   # EA
-                    ]
-            remap_idxs = self.remap_idxs
-            rremaps = []
-            # now cross-index the required SHAPE for each of 3-in 2-out regs
-            rnames = ['RA', 'RB', 'RC', 'RT', 'EA']
-            for i, (dstep, shape_idx) in enumerate(steps):
-                (shape, remap) = remaps[shape_idx]
-                remap_idx = remap_idxs[shape_idx]
-                # zero is "disabled"
-                if shape.value == 0x0:
-                    continue
-                # now set the actual requested step to the current index
-                yield dstep.eq(remap_idx)
-
-                # debug printout info
-                rremaps.append((shape.mode, i, rnames[i], shape_idx,
-                                remap_idx))
-            for x in rremaps:
-                log ("shape remap", x)
+            yield from self.remap_debug(remaps)
         # after that, settle down (combinatorial) to let Vector reg numbers
         # work themselves out
         yield Settle()
         # after that, settle down (combinatorial) to let Vector reg numbers
         # work themselves out
         yield Settle()
-        remap_active = yield self.dec2.remap_active
-        log ("remap active", bin(remap_active))
+        if self.is_svp64_mode:
+            remap_active = yield self.dec2.remap_active
+        else:
+            remap_active = False
+        log("remap active", bin(remap_active))
 
         # main input registers (RT, RA ...)
         inputs = []
         for name in input_names:
 
         # main input registers (RT, RA ...)
         inputs = []
         for name in input_names:
-            # using PowerDecoder2, first, find the decoder index.
-            # (mapping name RA RB RC RS to in1, in2, in3)
-            regnum, is_vec = yield from get_pdecode_idx_in(self.dec2, name)
-            if regnum is None:
-                # doing this is not part of svp64, it's because output
-                # registers, to be modified, need to be in the namespace.
-                regnum, is_vec = yield from get_pdecode_idx_out(self.dec2, name)
-            if regnum is None:
-                regnum, is_vec = yield from get_pdecode_idx_out2(self.dec2,
-                                                                 name)
-
-            # in case getting the register number is needed, _RA, _RB
-            regname = "_" + name
-            self.namespace[regname] = regnum
-            if not self.is_svp64_mode or not pred_src_zero:
-                log('reading reg %s %s' % (name, str(regnum)), is_vec)
-                if name in fregs:
-                    reg_val = SelectableInt(self.fpr(regnum))
-                elif name is not None:
-                    reg_val = SelectableInt(self.gpr(regnum))
-            else:
-                log('zero input reg %s %s' % (name, str(regnum)), is_vec)
-                reg_val = 0
-            inputs.append(reg_val)
+            print("name", name)
+            regval = (yield from self.get_input(name))
+            print("regval", regval)
+            inputs.append(regval)
+
         # arrrrgh, awful hack, to get _RT into namespace
         if ins_name in ['setvl', 'svstep']:
             regname = "_RT"
         # arrrrgh, awful hack, to get _RT into namespace
         if ins_name in ['setvl', 'svstep']:
             regname = "_RT"
@@ -1388,71 +1350,8 @@ class ISACaller(ISACallerHelper, ISAFPHelpers):
         # in SVP64 mode for LD/ST work out immediate
         # XXX TODO: replace_ds for DS-Form rather than D-Form.
         # use info.form to detect
         # in SVP64 mode for LD/ST work out immediate
         # XXX TODO: replace_ds for DS-Form rather than D-Form.
         # use info.form to detect
-        replace_d = False # update / replace constant in pseudocode
         if self.is_svp64_mode:
         if self.is_svp64_mode:
-            ldstmode = yield self.dec2.rm_dec.ldstmode
-            # shift mode reads SVD (or SVDS - TODO)
-            # *BUT*... because this is "overloading" of LD operations,
-            # it gets *STORED* into D (or DS, TODO)
-            if ldstmode == SVP64LDSTmode.SHIFT.value:
-                imm = yield self.dec2.dec.fields.FormSVD.SVD[0:11]
-                imm = exts(imm, 11) # sign-extend to integer
-                log ("shift SVD", imm)
-                replace_d = True
-            else:
-                if info.form == 'DS':
-                    # DS-Form, multiply by 4 then knock 2 bits off after
-                    imm = yield self.dec2.dec.fields.FormDS.DS[0:14] * 4
-                else:
-                    imm = yield self.dec2.dec.fields.FormD.D[0:16]
-                imm = exts(imm, 16) # sign-extend to integer
-            # get the right step. LD is from srcstep, ST is dststep
-            op = yield self.dec2.e.do.insn_type
-            offsmul = 0
-            if op == MicrOp.OP_LOAD.value:
-                if remap_active:
-                    offsmul = yield self.dec2.in1_step
-                    log("D-field REMAP src", imm, offsmul)
-                else:
-                    offsmul = srcstep
-                    log("D-field src", imm, offsmul)
-            elif op == MicrOp.OP_STORE.value:
-                # XXX NOTE! no bit-reversed STORE! this should not ever be used
-                offsmul = dststep
-                log("D-field dst", imm, offsmul)
-            # bit-reverse mode, rev already done through get_src_dst_steps()
-            if ldstmode == SVP64LDSTmode.SHIFT.value:
-                # manually look up RC, sigh
-                RC = yield self.dec2.dec.RC[0:5]
-                RC = self.gpr(RC)
-                log ("LD-SHIFT:", "VL", vl,
-                      "RC", RC.value, "imm", imm,
-                     "offs", bin(offsmul),
-                     )
-                imm = SelectableInt((imm * offsmul) << RC.value, 32)
-            # Unit-Strided LD/ST adds offset*width to immediate
-            elif ldstmode == SVP64LDSTmode.UNITSTRIDE.value:
-                ldst_len = yield self.dec2.e.do.data_len
-                imm = SelectableInt(imm + offsmul * ldst_len, 32)
-                replace_d = True
-            # Element-strided multiplies the immediate by element step
-            elif ldstmode == SVP64LDSTmode.ELSTRIDE.value:
-                imm = SelectableInt(imm * offsmul, 32)
-                replace_d = True
-            if replace_d:
-                ldst_ra_vec = yield self.dec2.rm_dec.ldst_ra_vec
-                ldst_imz_in = yield self.dec2.rm_dec.ldst_imz_in
-                log("LDSTmode", SVP64LDSTmode(ldstmode),
-                                offsmul, imm, ldst_ra_vec, ldst_imz_in)
-        # new replacement D... errr.. DS
-        if replace_d:
-            if info.form == 'DS':
-                # TODO: assert 2 LSBs are zero?
-                log("DS-Form, TODO, assert 2 LSBs zero?", bin(imm.value))
-                imm.value = imm.value >> 2
-                self.namespace['DS'] = imm
-            else:
-                self.namespace['D'] = imm
+            yield from self.check_replace_d(info, remap_active)
 
         # "special" registers
         for special in info.special_regs:
 
         # "special" registers
         for special in info.special_regs:
@@ -1468,7 +1367,7 @@ class ISACaller(ISACallerHelper, ISAFPHelpers):
         # this is the last check to be made as a loop.  combined with
         # the ALL/ANY mode we can early-exit
         if self.is_svp64_mode and ins_name.startswith("sv.bc"):
         # this is the last check to be made as a loop.  combined with
         # the ALL/ANY mode we can early-exit
         if self.is_svp64_mode and ins_name.startswith("sv.bc"):
-            no_in_vec = yield self.dec2.no_in_vec # BI is scalar
+            no_in_vec = yield self.dec2.no_in_vec  # BI is scalar
             end_loop = no_in_vec or srcstep == vl-1 or dststep == vl-1
             self.namespace['end_loop'] = SelectableInt(end_loop, 1)
 
             end_loop = no_in_vec or srcstep == vl-1 or dststep == vl-1
             self.namespace['end_loop'] = SelectableInt(end_loop, 1)
 
@@ -1487,13 +1386,13 @@ class ISACaller(ISACallerHelper, ISAFPHelpers):
         # check if op was a LD/ST so that debugging can check the
         # address
         if int_op in [MicrOp.OP_STORE.value,
         # check if op was a LD/ST so that debugging can check the
         # address
         if int_op in [MicrOp.OP_STORE.value,
-                     ]:
+                      ]:
             self.last_st_addr = self.mem.last_st_addr
         if int_op in [MicrOp.OP_LOAD.value,
             self.last_st_addr = self.mem.last_st_addr
         if int_op in [MicrOp.OP_LOAD.value,
-                     ]:
+                      ]:
             self.last_ld_addr = self.mem.last_ld_addr
             self.last_ld_addr = self.mem.last_ld_addr
-        log ("op", int_op, MicrOp.OP_STORE.value, MicrOp.OP_LOAD.value,
-                   self.last_st_addr, self.last_ld_addr)
+        log("op", int_op, MicrOp.OP_STORE.value, MicrOp.OP_LOAD.value,
+            self.last_st_addr, self.last_ld_addr)
 
         # detect if CA/CA32 already in outputs (sra*, basically)
         already_done = 0
 
         # detect if CA/CA32 already in outputs (sra*, basically)
         already_done = 0
@@ -1513,7 +1412,7 @@ class ISACaller(ISACallerHelper, ISAFPHelpers):
         if carry_en:
             yield from self.handle_carry_(inputs, results, already_done)
 
         if carry_en:
             yield from self.handle_carry_(inputs, results, already_done)
 
-        if not self.is_svp64_mode: # yeah just no. not in parallel processing
+        if not self.is_svp64_mode:  # yeah just no. not in parallel processing
             # detect if overflow was in return result
             overflow = None
             if info.write_regs:
             # detect if overflow was in return result
             overflow = None
             if info.write_regs:
@@ -1543,52 +1442,176 @@ class ISACaller(ISACallerHelper, ISAFPHelpers):
         # any modified return results?
         if info.write_regs:
             for name, output in zip(output_names, results):
         # any modified return results?
         if info.write_regs:
             for name, output in zip(output_names, results):
-                if name == 'overflow':  # ignore, done already (above)
-                    continue
-                if isinstance(output, int):
-                    output = SelectableInt(output, 256)
-                if name in ['CA', 'CA32']:
-                    if carry_en:
-                        log("writing %s to XER" % name, output)
-                        self.spr['XER'][XER_bits[name]] = output.value
-                    else:
-                        log("NOT writing %s to XER" % name, output)
-                elif name in info.special_regs:
-                    log('writing special %s' % name, output, special_sprs)
-                    if name in special_sprs:
-                        self.spr[name] = output
-                    else:
-                        self.namespace[name].eq(output)
-                    if name == 'MSR':
-                        log('msr written', hex(self.msr.value))
+                yield from self.check_write(info, name, output, carry_en)
+
+        nia_update = (yield from self.check_step_increment(results, rc_en,
+                                                           asmop, ins_name))
+        if nia_update:
+            self.update_pc_next()
+
+    def check_replace_d(self, info, remap_active):
+        replace_d = False  # update / replace constant in pseudocode
+        ldstmode = yield self.dec2.rm_dec.ldstmode
+        vl = self.svstate.vl
+        subvl = yield self.dec2.rm_dec.rm_in.subvl
+        srcstep, dststep = self.new_srcstep, self.new_dststep
+        ssubstep, dsubstep = self.new_ssubstep, self.new_dsubstep
+        if info.form == 'DS':
+            # DS-Form, multiply by 4 then knock 2 bits off after
+            imm = yield self.dec2.dec.fields.FormDS.DS[0:14] * 4
+        else:
+            imm = yield self.dec2.dec.fields.FormD.D[0:16]
+        imm = exts(imm, 16)  # sign-extend to integer
+        # get the right step. LD is from srcstep, ST is dststep
+        op = yield self.dec2.e.do.insn_type
+        offsmul = 0
+        if op == MicrOp.OP_LOAD.value:
+            if remap_active:
+                offsmul = yield self.dec2.in1_step
+                log("D-field REMAP src", imm, offsmul)
+            else:
+                offsmul = (srcstep * (subvl+1)) + ssubstep
+                log("D-field src", imm, offsmul)
+        elif op == MicrOp.OP_STORE.value:
+            # XXX NOTE! no bit-reversed STORE! this should not ever be used
+            offsmul = (dststep * (subvl+1)) + dsubstep
+            log("D-field dst", imm, offsmul)
+        # Unit-Strided LD/ST adds offset*width to immediate
+        if ldstmode == SVP64LDSTmode.UNITSTRIDE.value:
+            ldst_len = yield self.dec2.e.do.data_len
+            imm = SelectableInt(imm + offsmul * ldst_len, 32)
+            replace_d = True
+        # Element-strided multiplies the immediate by element step
+        elif ldstmode == SVP64LDSTmode.ELSTRIDE.value:
+            imm = SelectableInt(imm * offsmul, 32)
+            replace_d = True
+        if replace_d:
+            ldst_ra_vec = yield self.dec2.rm_dec.ldst_ra_vec
+            ldst_imz_in = yield self.dec2.rm_dec.ldst_imz_in
+            log("LDSTmode", SVP64LDSTmode(ldstmode),
+                offsmul, imm, ldst_ra_vec, ldst_imz_in)
+        # new replacement D... errr.. DS
+        if replace_d:
+            if info.form == 'DS':
+                # TODO: assert 2 LSBs are zero?
+                log("DS-Form, TODO, assert 2 LSBs zero?", bin(imm.value))
+                imm.value = imm.value >> 2
+                self.namespace['DS'] = imm
+            else:
+                self.namespace['D'] = imm
+
+    def get_input(self, name):
+        # using PowerDecoder2, first, find the decoder index.
+        # (mapping name RA RB RC RS to in1, in2, in3)
+        regnum, is_vec = yield from get_pdecode_idx_in(self.dec2, name)
+        if regnum is None:
+            # doing this is not part of svp64, it's because output
+            # registers, to be modified, need to be in the namespace.
+            regnum, is_vec = yield from get_pdecode_idx_out(self.dec2, name)
+        if regnum is None:
+            regnum, is_vec = yield from get_pdecode_idx_out2(self.dec2, name)
+
+        # in case getting the register number is needed, _RA, _RB
+        regname = "_" + name
+        self.namespace[regname] = regnum
+        if not self.is_svp64_mode or not self.pred_src_zero:
+            log('reading reg %s %s' % (name, str(regnum)), is_vec)
+            if name in fregs:
+                reg_val = SelectableInt(self.fpr(regnum))
+            elif name is not None:
+                reg_val = SelectableInt(self.gpr(regnum))
+        else:
+            log('zero input reg %s %s' % (name, str(regnum)), is_vec)
+            reg_val = 0
+        return reg_val
+
+    def remap_debug(self, remaps):
+        # just some convenient debug info
+        for i in range(4):
+            sname = 'SVSHAPE%d' % i
+            shape = self.spr[sname]
+            log(sname, bin(shape.value))
+            log("    lims", shape.lims)
+            log("    mode", shape.mode)
+            log("    skip", shape.skip)
+
+        # set up the list of steps to remap
+        mi0 = self.svstate.mi0
+        mi1 = self.svstate.mi1
+        mi2 = self.svstate.mi2
+        mo0 = self.svstate.mo0
+        mo1 = self.svstate.mo1
+        steps = [(self.dec2.in1_step, mi0),  # RA
+                 (self.dec2.in2_step, mi1),  # RB
+                 (self.dec2.in3_step, mi2),  # RC
+                 (self.dec2.o_step, mo0),   # RT
+                 (self.dec2.o2_step, mo1),   # EA
+                 ]
+        remap_idxs = self.remap_idxs
+        rremaps = []
+        # now cross-index the required SHAPE for each of 3-in 2-out regs
+        rnames = ['RA', 'RB', 'RC', 'RT', 'EA']
+        for i, (dstep, shape_idx) in enumerate(steps):
+            (shape, remap) = remaps[shape_idx]
+            remap_idx = remap_idxs[shape_idx]
+            # zero is "disabled"
+            if shape.value == 0x0:
+                continue
+            # now set the actual requested step to the current index
+            yield dstep.eq(remap_idx)
+
+            # debug printout info
+            rremaps.append((shape.mode, i, rnames[i], shape_idx, remap_idx))
+        for x in rremaps:
+            log("shape remap", x)
+
+    def check_write(self, info, name, output, carry_en):
+        if name == 'overflow':  # ignore, done already (above)
+            return
+        if isinstance(output, int):
+            output = SelectableInt(output, 256)
+        if name in ['CA', 'CA32']:
+            if carry_en:
+                log("writing %s to XER" % name, output)
+                self.spr['XER'][XER_bits[name]] = output.value
+            else:
+                log("NOT writing %s to XER" % name, output)
+        elif name in info.special_regs:
+            log('writing special %s' % name, output, special_sprs)
+            if name in special_sprs:
+                self.spr[name] = output
+            else:
+                self.namespace[name].eq(output)
+            if name == 'MSR':
+                log('msr written', hex(self.msr.value))
+        else:
+            regnum, is_vec = yield from get_pdecode_idx_out(self.dec2, name)
+            if regnum is None:
+                regnum, is_vec = yield from get_pdecode_idx_out2(
+                    self.dec2, name)
+            if regnum is None:
+                # temporary hack for not having 2nd output
+                regnum = yield getattr(self.decoder, name)
+                is_vec = False
+            if self.is_svp64_mode and self.pred_dst_zero:
+                log('zeroing reg %d %s' % (regnum, str(output)),
+                    is_vec)
+                output = SelectableInt(0, 256)
+            else:
+                if name in fregs:
+                    ftype = 'fpr'
                 else:
                 else:
-                    regnum, is_vec = yield from get_pdecode_idx_out(self.dec2,
-                                                name)
-                    if regnum is None:
-                        regnum, is_vec = yield from get_pdecode_idx_out2(
-                                                    self.dec2, name)
-                    if regnum is None:
-                        # temporary hack for not having 2nd output
-                        regnum = yield getattr(self.decoder, name)
-                        is_vec = False
-                    if self.is_svp64_mode and pred_dst_zero:
-                        log('zeroing reg %d %s' % (regnum, str(output)),
-                                                     is_vec)
-                        output = SelectableInt(0, 256)
-                    else:
-                        if name in fregs:
-                            ftype = 'fpr'
-                        else:
-                            ftype = 'gpr'
-                        log('writing %s %s %s' % (ftype, regnum, str(output)),
-                                                     is_vec)
-                    if output.bits > 64:
-                        output = SelectableInt(output.value, 64)
-                    if name in fregs:
-                        self.fpr[regnum] = output
-                    else:
-                        self.gpr[regnum] = output
+                    ftype = 'gpr'
+                log('writing %s %s %s' % (ftype, regnum, str(output)),
+                    is_vec)
+            if output.bits > 64:
+                output = SelectableInt(output.value, 64)
+            if name in fregs:
+                self.fpr[regnum] = output
+            else:
+                self.gpr[regnum] = output
 
 
+    def check_step_increment(self, results, rc_en, asmop, ins_name):
         # check if it is the SVSTATE.src/dest step that needs incrementing
         # this is our Sub-Program-Counter loop from 0 to VL-1
         pre = False
         # check if it is the SVSTATE.src/dest step that needs incrementing
         # this is our Sub-Program-Counter loop from 0 to VL-1
         pre = False
@@ -1596,72 +1619,71 @@ class ISACaller(ISACallerHelper, ISAFPHelpers):
         nia_update = True
         if self.allow_next_step_inc:
             log("SVSTATE_NEXT: inc requested, mode",
         nia_update = True
         if self.allow_next_step_inc:
             log("SVSTATE_NEXT: inc requested, mode",
-                    self.svstate_next_mode, self.allow_next_step_inc)
+                self.svstate_next_mode, self.allow_next_step_inc)
             yield from self.svstate_pre_inc()
             pre = yield from self.update_new_svstate_steps()
             if pre:
                 # reset at end of loop including exit Vertical Mode
             yield from self.svstate_pre_inc()
             pre = yield from self.update_new_svstate_steps()
             if pre:
                 # reset at end of loop including exit Vertical Mode
-                log ("SVSTATE_NEXT: end of loop, reset")
+                log("SVSTATE_NEXT: end of loop, reset")
                 self.svp64_reset_loop()
                 self.svstate.vfirst = 0
                 self.update_nia()
                 self.svp64_reset_loop()
                 self.svstate.vfirst = 0
                 self.update_nia()
-                if rc_en:
-                    results = [SelectableInt(0, 64)]
-                    self.handle_comparison(results) # CR0
+                if not rc_en:
+                    return True
+                results = [SelectableInt(0, 64)]
+                self.handle_comparison(results)  # CR0
+                return True
+            if self.allow_next_step_inc == 2:
+                log("SVSTATE_NEXT: read")
+                nia_update = (yield from self.svstate_post_inc(ins_name))
             else:
             else:
-                if self.allow_next_step_inc == 2:
-                    log ("SVSTATE_NEXT: read")
-                    nia_update = (yield from self.svstate_post_inc(ins_name))
-                else:
-                    log ("SVSTATE_NEXT: post-inc")
-                # use actual src/dst-step here to check end, do NOT
-                # use bit-reversed version
-                srcstep, dststep = self.new_srcstep, self.new_dststep
-                remaps = self.get_remap_indices()
-                remap_idxs = self.remap_idxs
-                vl = self.svstate.vl
-                end_src = srcstep == vl-1
-                end_dst = dststep == vl-1
-                if self.allow_next_step_inc != 2:
-                    if not end_src:
-                        self.svstate.srcstep += SelectableInt(1, 7)
-                    if not end_dst:
-                        self.svstate.dststep += SelectableInt(1, 7)
-                self.namespace['SVSTATE'] = self.svstate.spr
-                # set CR0 (if Rc=1) based on end
-                if rc_en:
-                    srcstep = self.svstate.srcstep
-                    dststep = self.svstate.srcstep
-                    endtest = 1 if (end_src or end_dst) else 0
-                    #results = [SelectableInt(endtest, 64)]
-                    #self.handle_comparison(results) # CR0
-
-                    # see if svstep was requested, if so, which SVSTATE
-                    endings = 0b111
-                    if self.svstate_next_mode > 0:
-                        shape_idx = self.svstate_next_mode.value-1
-                        endings = self.remap_loopends[shape_idx]
-                    cr_field = SelectableInt((~endings)<<1 | endtest, 4)
-                    print ("svstep Rc=1, CR0", cr_field)
-                    self.crl[0].eq(cr_field) # CR0
-                if end_src or end_dst:
-                    # reset at end of loop including exit Vertical Mode
-                    log ("SVSTATE_NEXT: after increments, reset")
-                    self.svp64_reset_loop()
-                    self.svstate.vfirst = 0
-
-        elif self.is_svp64_mode:
-            nia_update = (yield from self.svstate_post_inc(ins_name))
-        else:
-            # XXX only in non-SVP64 mode!
-            # record state of whether the current operation was an svshape,
-            # to be able to know if it should apply in the next instruction.
-            # also (if going to use this instruction) should disable ability
-            # to interrupt in between. sigh.
-            self.last_op_svshape = asmop == 'svremap'
+                log("SVSTATE_NEXT: post-inc")
+            # use actual src/dst-step here to check end, do NOT
+            # use bit-reversed version
+            srcstep, dststep = self.new_srcstep, self.new_dststep
+            ssubstep, dsubstep = self.new_ssubstep, self.new_dsubstep
+            remaps = self.get_remap_indices()
+            remap_idxs = self.remap_idxs
+            vl = self.svstate.vl
+            subvl = yield self.dec2.rm_dec.rm_in.subvl
+            end_src = srcstep == vl-1
+            end_dst = dststep == vl-1
+            if self.allow_next_step_inc != 2:
+                yield from self.advance_svstate_steps(end_src, end_dst)
+            self.namespace['SVSTATE'] = self.svstate.spr
+            # set CR0 (if Rc=1) based on end
+            if rc_en:
+                endtest = 1 if (end_src or end_dst) else 0
+                #results = [SelectableInt(endtest, 64)]
+                # self.handle_comparison(results) # CR0
+
+                # see if svstep was requested, if so, which SVSTATE
+                endings = 0b111
+                if self.svstate_next_mode > 0:
+                    shape_idx = self.svstate_next_mode.value-1
+                    endings = self.remap_loopends[shape_idx]
+                cr_field = SelectableInt((~endings) << 1 | endtest, 4)
+                print("svstep Rc=1, CR0", cr_field)
+                self.crl[0].eq(cr_field)  # CR0
+            if end_src or end_dst:
+                # reset at end of loop including exit Vertical Mode
+                log("SVSTATE_NEXT: after increments, reset")
+                self.svp64_reset_loop()
+                self.svstate.vfirst = 0
+            return nia_update
 
 
-        if nia_update:
-            self.update_pc_next()
+        if self.is_svp64_mode:
+            return (yield from self.svstate_post_inc(ins_name))
+
+        # XXX only in non-SVP64 mode!
+        # record state of whether the current operation was an svshape,
+        # OR svindex!
+        # to be able to know if it should apply in the next instruction.
+        # also (if going to use this instruction) should disable ability
+        # to interrupt in between. sigh.
+        self.last_op_svshape = asmop in ['svremap', 'svindex']
+
+        return True
 
     def SVSTATE_NEXT(self, mode, submode):
         """explicitly moves srcstep/dststep on to next element, for
 
     def SVSTATE_NEXT(self, mode, submode):
         """explicitly moves srcstep/dststep on to next element, for
@@ -1675,29 +1697,44 @@ class ISACaller(ISACallerHelper, ISAFPHelpers):
         self.allow_next_step_inc = submode.value + 1
         log("SVSTATE_NEXT mode", mode, submode, self.allow_next_step_inc)
         self.svstate_next_mode = mode
         self.allow_next_step_inc = submode.value + 1
         log("SVSTATE_NEXT mode", mode, submode, self.allow_next_step_inc)
         self.svstate_next_mode = mode
-        if self.svstate_next_mode > 0:
+        if self.svstate_next_mode > 0 and self.svstate_next_mode < 5:
             shape_idx = self.svstate_next_mode.value-1
             return SelectableInt(self.remap_idxs[shape_idx], 7)
             shape_idx = self.svstate_next_mode.value-1
             return SelectableInt(self.remap_idxs[shape_idx], 7)
+        if self.svstate_next_mode == 5:
+            self.svstate_next_mode = 0
+            return SelectableInt(self.svstate.srcstep, 7)
+        if self.svstate_next_mode == 6:
+            self.svstate_next_mode = 0
+            return SelectableInt(self.svstate.dststep, 7)
         return SelectableInt(0, 7)
 
     def svstate_pre_inc(self):
         """check if srcstep/dststep need to skip over masked-out predicate bits
         return SelectableInt(0, 7)
 
     def svstate_pre_inc(self):
         """check if srcstep/dststep need to skip over masked-out predicate bits
+        note that this is not supposed to do anything to substep,
+        it is purely for skipping masked-out bits
         """
         # get SVSTATE VL (oh and print out some debug stuff)
         vl = self.svstate.vl
         """
         # get SVSTATE VL (oh and print out some debug stuff)
         vl = self.svstate.vl
+        subvl = yield self.dec2.rm_dec.rm_in.subvl
         srcstep = self.svstate.srcstep
         dststep = self.svstate.dststep
         srcstep = self.svstate.srcstep
         dststep = self.svstate.dststep
+        ssubstep = self.svstate.ssubstep
+        dsubstep = self.svstate.dsubstep
         sv_a_nz = yield self.dec2.sv_a_nz
         fft_mode = yield self.dec2.use_svp64_fft
         in1 = yield self.dec2.e.read_reg1.data
         sv_a_nz = yield self.dec2.sv_a_nz
         fft_mode = yield self.dec2.use_svp64_fft
         in1 = yield self.dec2.e.read_reg1.data
-        log ("SVP64: VL, srcstep, dststep, sv_a_nz, in1 fft, svp64",
-                vl, srcstep, dststep, sv_a_nz, in1, fft_mode,
-                self.is_svp64_mode)
+        log("SVP64: VL, subvl, srcstep, dststep, ssubstep, dsybstep, sv_a_nz, "
+            "in1 fft, svp64",
+            vl, subvl, srcstep, dststep, ssubstep, dsubstep,
+            sv_a_nz, in1, fft_mode,
+            self.is_svp64_mode)
 
 
-        # get predicate mask
+        # get predicate mask (all 64 bits)
         srcmask = dstmask = 0xffff_ffff_ffff_ffff
 
         pmode = yield self.dec2.rm_dec.predmode
         srcmask = dstmask = 0xffff_ffff_ffff_ffff
 
         pmode = yield self.dec2.rm_dec.predmode
+        pack = yield self.dec2.rm_dec.pack
+        unpack = yield self.dec2.rm_dec.unpack
         reverse_gear = yield self.dec2.rm_dec.reverse_gear
         sv_ptype = yield self.dec2.dec.op.SV_Ptype
         srcpred = yield self.dec2.rm_dec.srcpred
         reverse_gear = yield self.dec2.rm_dec.reverse_gear
         sv_ptype = yield self.dec2.dec.op.SV_Ptype
         srcpred = yield self.dec2.rm_dec.srcpred
@@ -1712,62 +1749,85 @@ class ISACaller(ISACallerHelper, ISAFPHelpers):
             srcmask = dstmask = get_predcr(self.crl, dstpred, vl)
             if sv_ptype == SVPtype.P2.value:
                 srcmask = get_predcr(self.crl, srcpred, vl)
             srcmask = dstmask = get_predcr(self.crl, dstpred, vl)
             if sv_ptype == SVPtype.P2.value:
                 srcmask = get_predcr(self.crl, srcpred, vl)
-        log ("    pmode", pmode)
-        log ("    reverse", reverse_gear)
-        log ("    ptype", sv_ptype)
-        log ("    srcpred", bin(srcpred))
-        log ("    dstpred", bin(dstpred))
-        log ("    srcmask", bin(srcmask))
-        log ("    dstmask", bin(dstmask))
-        log ("    pred_sz", bin(pred_src_zero))
-        log ("    pred_dz", bin(pred_dst_zero))
+        # work out if the ssubsteps are completed
+        ssubstart = ssubstep == 0
+        dsubstart = dsubstep == 0
+        log("    pmode", pmode)
+        log("    pack/unpack", pack, unpack)
+        log("    reverse", reverse_gear)
+        log("    ptype", sv_ptype)
+        log("    srcpred", bin(srcpred))
+        log("    dstpred", bin(dstpred))
+        log("    srcmask", bin(srcmask))
+        log("    dstmask", bin(dstmask))
+        log("    pred_sz", bin(pred_src_zero))
+        log("    pred_dz", bin(pred_dst_zero))
+        log("    ssubstart", ssubstart)
+        log("    dsubstart", dsubstart)
 
         # okaaay, so here we simply advance srcstep (TODO dststep)
 
         # okaaay, so here we simply advance srcstep (TODO dststep)
-        # until the predicate mask has a "1" bit... or we run out of VL
-        # let srcstep==VL be the indicator to move to next instruction
-        if not pred_src_zero:
-            while (((1<<srcstep) & srcmask) == 0) and (srcstep != vl):
-                log ("      skip", bin(1<<srcstep))
-                srcstep += 1
-        # same for dststep
-        if not pred_dst_zero:
-            while (((1<<dststep) & dstmask) == 0) and (dststep != vl):
-                log ("      skip", bin(1<<dststep))
-                dststep += 1
+        # this can ONLY be done at the beginning of the "for" loop
+        # (this is all actually a FSM so it's hell to keep track sigh)
+        if ssubstart:
+            # until the predicate mask has a "1" bit... or we run out of VL
+            # let srcstep==VL be the indicator to move to next instruction
+            if not pred_src_zero:
+                while (((1 << srcstep) & srcmask) == 0) and (srcstep != vl):
+                    log("      sskip", bin(1 << srcstep))
+                    srcstep += 1
+        if dsubstart:
+            # same for dststep
+            if not pred_dst_zero:
+                while (((1 << dststep) & dstmask) == 0) and (dststep != vl):
+                    log("      dskip", bin(1 << dststep))
+                    dststep += 1
 
         # now work out if the relevant mask bits require zeroing
         if pred_dst_zero:
 
         # now work out if the relevant mask bits require zeroing
         if pred_dst_zero:
-            pred_dst_zero = ((1<<dststep) & dstmask) == 0
+            pred_dst_zero = ((1 << dststep) & dstmask) == 0
         if pred_src_zero:
         if pred_src_zero:
-            pred_src_zero = ((1<<srcstep) & srcmask) == 0
+            pred_src_zero = ((1 << srcstep) & srcmask) == 0
 
         # store new srcstep / dststep
 
         # store new srcstep / dststep
-        self.new_srcstep, self.new_dststep = srcstep, dststep
-        self.pred_dst_zero, self.pred_src_zero = pred_dst_zero, pred_src_zero
-        log ("    new srcstep", srcstep)
-        log ("    new dststep", dststep)
+        self.new_srcstep, self.new_dststep = (srcstep, dststep)
+        self.new_ssubstep, self.new_dsubstep = (ssubstep, dsubstep)
+        self.pred_dst_zero, self.pred_src_zero = (pred_dst_zero, pred_src_zero)
+        log("    new srcstep", srcstep)
+        log("    new dststep", dststep)
+        log("    new ssubstep", ssubstep)
+        log("    new dsubstep", dsubstep)
 
     def get_src_dststeps(self):
 
     def get_src_dststeps(self):
-        """gets srcstep and dststep 
+        """gets srcstep, dststep, and ssubstep, dsubstep
         """
         """
-        return self.new_srcstep, self.new_dststep
+        return (self.new_srcstep, self.new_dststep,
+                self.new_ssubstep, self.new_dsubstep)
 
     def update_new_svstate_steps(self):
         # note, do not get the bit-reversed srcstep here!
         srcstep, dststep = self.new_srcstep, self.new_dststep
 
     def update_new_svstate_steps(self):
         # note, do not get the bit-reversed srcstep here!
         srcstep, dststep = self.new_srcstep, self.new_dststep
+        ssubstep, dsubstep = self.new_ssubstep, self.new_dsubstep
 
         # update SVSTATE with new srcstep
         self.svstate.srcstep = srcstep
         self.svstate.dststep = dststep
 
         # update SVSTATE with new srcstep
         self.svstate.srcstep = srcstep
         self.svstate.dststep = dststep
+        self.svstate.ssubstep = ssubstep
+        self.svstate.dsubstep = dsubstep
         self.namespace['SVSTATE'] = self.svstate
         yield self.dec2.state.svstate.eq(self.svstate.value)
         self.namespace['SVSTATE'] = self.svstate
         yield self.dec2.state.svstate.eq(self.svstate.value)
-        yield Settle() # let decoder update
+        yield Settle()  # let decoder update
         srcstep = self.svstate.srcstep
         dststep = self.svstate.dststep
         srcstep = self.svstate.srcstep
         dststep = self.svstate.dststep
+        ssubstep = self.svstate.ssubstep
+        dsubstep = self.svstate.dsubstep
         vl = self.svstate.vl
         vl = self.svstate.vl
-        log ("    srcstep", srcstep)
-        log ("    dststep", dststep)
-        log ("         vl", vl)
+        subvl = yield self.dec2.rm_dec.rm_in.subvl
+        log("    srcstep", srcstep)
+        log("    dststep", dststep)
+        log("    ssubstep", ssubstep)
+        log("    dsubstep", dsubstep)
+        log("         vl", vl)
+        log("      subvl", subvl)
 
         # check if end reached (we let srcstep overrun, above)
         # nothing needs doing (TODO zeroing): just do next instruction
 
         # check if end reached (we let srcstep overrun, above)
         # nothing needs doing (TODO zeroing): just do next instruction
@@ -1776,7 +1836,7 @@ class ISACaller(ISACallerHelper, ISAFPHelpers):
     def svstate_post_inc(self, insn_name, vf=0):
         # check if SV "Vertical First" mode is enabled
         vfirst = self.svstate.vfirst
     def svstate_post_inc(self, insn_name, vf=0):
         # check if SV "Vertical First" mode is enabled
         vfirst = self.svstate.vfirst
-        log ("    SV Vertical First", vf, vfirst)
+        log("    SV Vertical First", vf, vfirst)
         if not vf and vfirst == 1:
             self.update_nia()
             return True
         if not vf and vfirst == 1:
             self.update_nia()
             return True
@@ -1785,23 +1845,29 @@ class ISACaller(ISACallerHelper, ISAFPHelpers):
         # this is our Sub-Program-Counter loop from 0 to VL-1
         # XXX twin predication TODO
         vl = self.svstate.vl
         # this is our Sub-Program-Counter loop from 0 to VL-1
         # XXX twin predication TODO
         vl = self.svstate.vl
+        subvl = yield self.dec2.rm_dec.rm_in.subvl
         mvl = self.svstate.maxvl
         srcstep = self.svstate.srcstep
         dststep = self.svstate.dststep
         mvl = self.svstate.maxvl
         srcstep = self.svstate.srcstep
         dststep = self.svstate.dststep
+        ssubstep = self.svstate.ssubstep
+        dsubstep = self.svstate.dsubstep
         rm_mode = yield self.dec2.rm_dec.mode
         reverse_gear = yield self.dec2.rm_dec.reverse_gear
         sv_ptype = yield self.dec2.dec.op.SV_Ptype
         out_vec = not (yield self.dec2.no_out_vec)
         in_vec = not (yield self.dec2.no_in_vec)
         rm_mode = yield self.dec2.rm_dec.mode
         reverse_gear = yield self.dec2.rm_dec.reverse_gear
         sv_ptype = yield self.dec2.dec.op.SV_Ptype
         out_vec = not (yield self.dec2.no_out_vec)
         in_vec = not (yield self.dec2.no_in_vec)
-        log ("    svstate.vl", vl)
-        log ("    svstate.mvl", mvl)
-        log ("    svstate.srcstep", srcstep)
-        log ("    svstate.dststep", dststep)
-        log ("    mode", rm_mode)
-        log ("    reverse", reverse_gear)
-        log ("    out_vec", out_vec)
-        log ("    in_vec", in_vec)
-        log ("    sv_ptype", sv_ptype, sv_ptype == SVPtype.P2.value)
+        log("    svstate.vl", vl)
+        log("    svstate.mvl", mvl)
+        log("         rm.subvl", subvl)
+        log("    svstate.srcstep", srcstep)
+        log("    svstate.dststep", dststep)
+        log("    svstate.ssubstep", ssubstep)
+        log("    svstate.dsubstep", dsubstep)
+        log("    mode", rm_mode)
+        log("    reverse", reverse_gear)
+        log("    out_vec", out_vec)
+        log("    in_vec", in_vec)
+        log("    sv_ptype", sv_ptype, sv_ptype == SVPtype.P2.value)
         # check if srcstep needs incrementing by one, stop PC advancing
         # svp64 loop can end early if the dest is scalar for single-pred
         # but for 2-pred both src/dest have to be checked.
         # check if srcstep needs incrementing by one, stop PC advancing
         # svp64 loop can end early if the dest is scalar for single-pred
         # but for 2-pred both src/dest have to be checked.
@@ -1818,37 +1884,65 @@ class ISACaller(ISACallerHelper, ISAFPHelpers):
                 self.svp64_reset_loop()
                 self.update_pc_next()
                 return False
                 self.svp64_reset_loop()
                 self.update_pc_next()
                 return False
-        if svp64_is_vector and srcstep != vl-1 and dststep != vl-1:
-            self.svstate.srcstep += SelectableInt(1, 7)
-            self.svstate.dststep += SelectableInt(1, 7)
-            self.namespace['SVSTATE'] = self.svstate
-            # not an SVP64 branch, so fix PC (NIA==CIA) for next loop
-            # (by default, NIA is CIA+4 if v3.0B or CIA+8 if SVP64)
-            # this way we keep repeating the same instruction (with new steps)
-            self.pc.NIA.value = self.pc.CIA.value
-            self.namespace['NIA'] = self.pc.NIA
-            log("end of sub-pc call", self.namespace['CIA'],
-                                 self.namespace['NIA'])
-            return False # DO NOT allow PC update whilst Sub-PC loop running
-
-        # reset loop to zero and update NIA
-        self.svp64_reset_loop()
-        self.update_nia()
+        # loops end at the first "hit" (source or dest)
+        loopend = ((srcstep == vl-1 and ssubstep == subvl) or
+                   (dststep == vl-1 and dsubstep == subvl))
+        if not svp64_is_vector or loopend:
+            # reset loop to zero and update NIA
+            self.svp64_reset_loop()
+            self.update_nia()
 
 
-        return True
+            return True
+
+        # still looping, advance and update NIA
+        yield from self.advance_svstate_steps()
+        self.namespace['SVSTATE'] = self.svstate
+        # not an SVP64 branch, so fix PC (NIA==CIA) for next loop
+        # (by default, NIA is CIA+4 if v3.0B or CIA+8 if SVP64)
+        # this way we keep repeating the same instruction (with new steps)
+        self.pc.NIA.value = self.pc.CIA.value
+        self.namespace['NIA'] = self.pc.NIA
+        log("end of sub-pc call", self.namespace['CIA'], self.namespace['NIA'])
+        return False  # DO NOT allow PC update whilst Sub-PC loop running
+
+    def advance_svstate_steps(self, end_src=False, end_dst=False):
+        """ advance sub/steps. note that Pack/Unpack *INVERTS* the order.
+        TODO when Pack/Unpack is set, substep becomes the *outer* loop
+        """
+        subvl = yield self.dec2.rm_dec.rm_in.subvl
+        # first source step
+        ssubstep = self.svstate.ssubstep
+        end_sub = ssubstep == subvl
+        if end_sub:
+            if not end_src:
+                self.svstate.srcstep += SelectableInt(1, 7)
+            self.svstate.ssubstep = SelectableInt(0, 2)  # reset
+        else:
+            self.svstate.ssubstep += SelectableInt(1, 2) # advance ssubstep
+        # now dest step
+        dsubstep = self.svstate.dsubstep
+        end_sub = dsubstep == subvl
+        if end_sub:
+            if not end_dst:
+                self.svstate.dststep += SelectableInt(1, 7)
+            self.svstate.dsubstep = SelectableInt(0, 2)  # reset
+        else:
+            self.svstate.dsubstep += SelectableInt(1, 2) # advance ssubstep
 
     def update_pc_next(self):
         # UPDATE program counter
         self.pc.update(self.namespace, self.is_svp64_mode)
         self.svstate.spr = self.namespace['SVSTATE']
         log("end of call", self.namespace['CIA'],
 
     def update_pc_next(self):
         # UPDATE program counter
         self.pc.update(self.namespace, self.is_svp64_mode)
         self.svstate.spr = self.namespace['SVSTATE']
         log("end of call", self.namespace['CIA'],
-                             self.namespace['NIA'],
-                             self.namespace['SVSTATE'])
+            self.namespace['NIA'],
+            self.namespace['SVSTATE'])
 
     def svp64_reset_loop(self):
         self.svstate.srcstep = 0
         self.svstate.dststep = 0
 
     def svp64_reset_loop(self):
         self.svstate.srcstep = 0
         self.svstate.dststep = 0
-        log ("    svstate.srcstep loop end (PC to update)")
+        self.svstate.ssubstep = 0
+        self.svstate.dsubstep = 0
+        log("    svstate.srcstep loop end (PC to update)")
         self.namespace['SVSTATE'] = self.svstate
 
     def update_nia(self):
         self.namespace['SVSTATE'] = self.svstate
 
     def update_nia(self):
@@ -1883,8 +1977,8 @@ def inject():
             result = func(*args, **kwargs)
             log("globals after", func_globals['CIA'], func_globals['NIA'])
             log("args[0]", args[0].namespace['CIA'],
             result = func(*args, **kwargs)
             log("globals after", func_globals['CIA'], func_globals['NIA'])
             log("args[0]", args[0].namespace['CIA'],
-                  args[0].namespace['NIA'],
-                  args[0].namespace['SVSTATE'])
+                args[0].namespace['NIA'],
+                args[0].namespace['SVSTATE'])
             if 'end_loop' in func_globals:
                 log("args[0] end_loop", func_globals['end_loop'])
             args[0].namespace = func_globals
             if 'end_loop' in func_globals:
                 log("args[0] end_loop", func_globals['end_loop'])
             args[0].namespace = func_globals
@@ -1898,5 +1992,3 @@ def inject():
         return decorator
 
     return variable_injector
         return decorator
 
     return variable_injector
-
-