(no commit message)
[libreriscv.git] / openpower / sv / remap.mdwn
index e6a2029be7119bdb6bd66d4e704b1d2225570e7d..c1c9661338ef8f570c6f7fabf69d9917fc5eb192 100644 (file)
@@ -7,6 +7,7 @@
 * <https://bugs.libre-soc.org/show_bug.cgi?id=911> offset svshape option
 * <https://bugs.libre-soc.org/show_bug.cgi?id=864> parallel reduction
 * <https://bugs.libre-soc.org/show_bug.cgi?id=930> DCT/FFT "strides"
+* <https://bugs.libre-soc.org/show_bug.cgi?id=1155> bigmul (normal and carry-save)
 * see [[sv/remap/appendix]] for examples and usage
 * see [[sv/propagation]] for a future way to apply REMAP
 * [[remap/discussion]]
 REMAP is an advanced form of Vector "Structure Packing" that provides
 hardware-level support for commonly-used *nested* loop patterns that would
 otherwise require full inline loop unrolling.  For more general reordering
-an Indexed REMAP mode is available (an abstracted analog to `xxperm`).
+an Indexed REMAP mode is available (a RISC-paradigm
+abstracted analog to `xxperm`).
 
 REMAP allows the usual sequential vector loop `0..VL-1` to be "reshaped"
 (re-mapped) from a linear form to a 2D or 3D transposed form, or "offset"
-to permit arbitrary access to elements (when elwidth overrides are
-used), independently on each Vector src or dest register. Aside from
+to permit arbitrary access to elements, independently on each
+Vector src or dest register. Up to four separate independent REMAPs may be applied
+to the registers of any instruction.
+
+A normal Vector Add (no Element-width Overrides):
+
+```
+   for i in range(VL):
+     GPR[RT+i] <= GPR[RA+i] + GPR[RB+i];
+```
+
+A Hardware-assisted REMAP Vector Add:
+
+```
+   for i in range(VL):
+     GPR[RT+remap1(i)] <= GPR[RA+remap2(i)] + GPR[RB+remap3(i)];
+```
+
+Aside from
 Indexed REMAP this is entirely Hardware-accelerated reordering and
-consequently not costly in terms of register access. It will however
+consequently not costly in terms of register access for the Indices. It will however
 place a burden on Multi-Issue systems but no more than if the equivalent
 Scalar instructions were explicitly loop-unrolled without SVP64, and
 some advanced implementations may even find the Deterministic nature of
 the Scheduling to be easier on resources.
 
-The initial primary motivation of REMAP was for Matrix Multiplication,
-reordering of sequential data in-place: in-place DCT and FFT were
-easily justified given the exceptionally high usage in Computer Science.
-Four SPRs are provided which may be applied to any GPR, FPR or CR Field so
-that for example a single FMAC may be used in a single hardware-controlled
-100% Deterministic loop to perform 5x3 times 3x4 Matrix multiplication,
-generating 60 FMACs *without needing explicit assembler unrolling*.
-Additional uses include regular "Structure Packing" such as RGB pixel
-data extraction and reforming (although less costly vec2/3/4 reshaping
-is achievable with `PACK/UNPACK`).
-
-REMAP, like all of SV, is abstracted out, meaning that unlike traditional
-Vector ISAs which would typically only have a limited set of instructions
-that can be structure-packed (LD/ST and Move operations
-being the most common), REMAP may be applied to
-literally any instruction: CRs, Arithmetic, Logical, LD/ST, even
-Vectorised Branch-Conditional.
-
-When SUBVL is greater than 1 a given group of Subvector
-elements are kept together: effectively the group becomes the
-element, and with REMAP applying to elements
-(not sub-elements) each group is REMAPed together.
-Swizzle *can* however be applied to the same
-instruction as REMAP, providing re-sequencing of
-Subvector elements which REMAP cannot. Also as explained in [[sv/mv.swizzle]], [[sv/mv.vec]] and the [[svp64/appendix]], Pack and Unpack Mode bits
-can extend down into Sub-vector elements to influence vec2/vec3/vec4
-sequential reordering, but even here, REMAP reordering is not *individually*
-extended down to the actual sub-vector elements themselves.
-This keeps the relevant Predicate Mask bit applicable to the Subvector
-group, just as it does when REMAP is not active.
-
-In its general form, REMAP is quite expensive to set up, and on some
+*Hardware note: in its general form, REMAP is quite expensive to set up, and on some
 implementations may introduce latency, so should realistically be used
 only where it is worthwhile.  Given that even with latency the fact
 that up to 127 operations can be Deterministically issued (from a single
 instruction) it should be clear that REMAP should not be dismissed
 for *possible* latency alone.  Commonly-used patterns such as Matrix
 Multiply, DCT and FFT have helper instruction options which make REMAP
-easier to use.
+easier to use.*
 
-There are four types of REMAP:
+There are five types of REMAP:
 
 * **Matrix**, also known as 2D and 3D reshaping, can perform in-place
   Matrix transpose and rotate. The Shapes are set up for an "Outer Product"
-  Matrix Multiply.
+  Matrix Multiply (a future variant may introduce Inner Product).
 * **FFT/DCT**, with full triple-loop in-place support: limited to
   Power-2 RADIX
 * **Indexing**, for any general-purpose reordering, also includes
@@ -80,6 +68,9 @@ There are four types of REMAP:
 * **Parallel Reduction**, for scheduling a sequence of operations
   in a Deterministic fashion, in a way that may be parallelised,
   to reduce a Vector down to a single value.
+* **Parallel Prefix Sum**, implemented as a work-efficient Schedule,
+  has several key Computer Science uses. Again Prefix Sum is 100%
+  Deterministic.
 
 Best implemented on top of a Multi-Issue Out-of-Order Micro-architecture,
 REMAP Schedules are 100% Deterministic **including Indexing** and are
@@ -95,322 +86,16 @@ Architectural State is permitted to assume that the Indices
 are cacheable from the point at which the `svindex` instruction
 is executed.
 
-Parallel Reduction is unusual in that it requires a full vector array
-of results (not a scalar) and uses the rest of the result Vector for
-the purposes of storing intermediary calculations.  As these intermediary
-results are Deterministically computed they may be useful.
-Additionally, because the intermediate results are always written out
-it is possible to service Precise Interrupts without affecting latency
-(a common limitation of Vector ISAs implementing explicit
-Parallel Reduction instructions).
-
-## Basic principle
-
-* normal vector element read/write of operands would be sequential
-  (0 1 2 3 ....)
-* this is not appropriate for (e.g.) Matrix multiply which requires
-  accessing elements in alternative sequences (0 3 6 1 4 7 ...)
-* normal Vector ISAs use either Indexed-MV or Indexed-LD/ST to "cope"
-  with this.  both are expensive (copy large vectors, spill through memory)
-  and very few Packed SIMD ISAs cope with non-Power-2.
-* REMAP **redefines** the order of access according to set
-  (Deterministic) "Schedules".
-* Matrix Schedules are not at all restricted to power-of-two boundaries
-  making it unnecessary to have for example specialised 3x4 transpose
-  instructions of other Vector ISAs.
-
-Only the most commonly-used algorithms in computer science have REMAP
-support, due to the high cost in both the ISA and in hardware.  For
-arbitrary remapping the `Indexed` REMAP may be used.
-
-## Example Usage
-
-* `svshape` to set the type of reordering to be applied to an
-  otherwise usual `0..VL-1` hardware for-loop
-* `svremap` to set which registers a given reordering is to apply to
-  (RA, RT etc)
-* `sv.{instruction}` where any Vectorised register marked by `svremap`
-  will have its ordering REMAPPED according to the schedule set
-  by `svshape`.
-
-The following illustrative example multiplies a 3x4 and a 5x3
-matrix to create
-a 5x4 result:
-
-```
-    svshape 5, 4, 3, 0, 0            # Outer Product
-    svremap 15, 1, 2, 3, 0, 0, 0, 0
-    sv.fmadds *0, *32, *64, *0
-```
-
-* svshape sets up the four SVSHAPE SPRS for a Matrix Schedule
-* svremap activates four out of five registers RA RB RC RT RS (15)
-* svremap requests:
-  - RA to use SVSHAPE1
-  - RB to use SVSHAPE2
-  - RC to use SVSHAPE3
-  - RT to use SVSHAPE0
-  - RS Remapping to not be activated
-* sv.fmadds has RT=0.v, RA=8.v, RB=16.v, RC=0.v
-* With REMAP being active each register's element index is
-  *independently* transformed using the specified SHAPEs.
-
-Thus the Vector Loop is arranged such that the use of
-the multiply-and-accumulate instruction executes precisely the required
-Schedule to perform an in-place in-registers Outer Product
-Matrix Multiply with no
-need to perform additional Transpose or register copy instructions.
-The example above may be executed as a unit test and demo,
-[here](https://git.libre-soc.org/?p=openpower-isa.git;a=blob;f=src/openpower/decoder/isa/test_caller_svp64_matrix.py;h=c15479db9a36055166b6b023c7495f9ca3637333;hb=a17a252e474d5d5bf34026c25a19682e3f2015c3#l94)
-
-## REMAP types
-
-This section summarises the motivation for each REMAP Schedule
-and briefly goes over their characteristics and limitations.
 Further details on the Deterministic Precise-Interruptible algorithms
 used in these Schedules is found in the [[sv/remap/appendix]].
 
-### Matrix (1D/2D/3D shaping)
-
-Matrix Multiplication is a huge part of High-Performance Compute,
-and 3D.
-In many PackedSIMD as well as Scalable Vector ISAs, non-power-of-two
-Matrix sizes are a serious challenge. PackedSIMD ISAs, in order to
-cope with for example 3x4 Matrices, recommend rolling data-repetition and loop-unrolling.
-Aside from the cost of the load on the L1 I-Cache, the trick only
-works if one of the dimensions X or Y are power-two. Prime Numbers
-(5x7, 3x5) become deeply problematic to unroll.
-
-Even traditional Scalable Vector ISAs have issues with Matrices, often
-having to perform data Transpose by pushing out through Memory and back,
-or computing Transposition Indices (costly) then copying to another
-Vector (costly).
-
-Matrix REMAP was thus designed to solve these issues by providing Hardware
-Assisted
-"Schedules" that can view what would otherwise be limited to a strictly
-linear Vector as instead being 2D (even 3D) *in-place* reordered.
-With both Transposition and non-power-two being supported the issues
-faced by other ISAs are mitigated.
-
-Limitations of Matrix REMAP are that the Vector Length (VL) is currently
-restricted to 127: up to 127 FMAs (or other operation)
-may be performed in total.
-Also given that it is in-registers only at present some care has to be
-taken on regfile resource utilisation. However it is perfectly possible
-to utilise Matrix REMAP to perform the three inner-most "kernel"
-("Tiling") loops of
-the usual 6-level large Matrix Multiply, without the usual difficulties
-associated with SIMD.
-
-Also the `svshape` instruction only provides access to part of the
-Matrix REMAP capability. Rotation and mirroring need to be done by
-programming the SVSHAPE SPRs directly, which can take a lot more
-instructions. Future versions of SVP64 will include EXT1xx prefixed
-variants (`psvshape`) which provide more comprehensive capacity and
-mitigate the need to write direct to the SVSHAPE SPRs.
-
-### FFT/DCT Triple Loop
-
-DCT and FFT are some of the most astonishingly used algorithms in
-Computer Science.  Radar, Audio, Video, R.F. Baseband and dozens more.  At least
-two DSPs, TMS320 and Hexagon, have VLIW instructions specially tailored
-to FFT.
-
-An in-depth analysis showed that it is possible to do in-place in-register
-DCT and FFT as long as twin-result "butterfly" instructions are provided.
-These can be found in the [[openpower/isa/svfparith]] page if performing
-IEEE754 FP transforms. *(For fixed-point transforms, equivalent 3-in 2-out
-integer operations would be required)*. These "butterfly" instructions
-avoid the need for a temporary register because the two array positions
-being overwritten will be "in-flight" in any In-Order or Out-of-Order
-micro-architecture.
+*Future specification note: future versions of the REMAP Management instructions
+will extend to EXT1xx Prefixed variants. This will overcome some of the limitations
+present in the 32-bit variants of the REMAP Management instructions that at
+present require direct writing to SVSHAPE0-3 SPRs.  Additional
+REMAP Modes may also be introduced at that time.*
 
-DCT and FFT Schedules are currently limited to RADIX2 sizes and do not
-accept predicate masks.  Given that it is common to perform recursive
-convolutions combining smaller Power-2 DCT/FFT to create larger DCT/FFTs
-in practice the RADIX2 limit is not a problem.  A Bluestein convolution
-to compute arbitrary length is demonstrated by
-[Project Nayuki](https://www.nayuki.io/res/free-small-fft-in-multiple-languages/fft.py)
-
-### Indexed
-
-The purpose of Indexing is to provide a generalised version of
-Vector ISA "Permute" instructions, such as VSX `vperm`.  The
-Indexing is abstracted out and may be applied to much more
-than an element move/copy, and is not limited for example
-to the number of bytes that can fit into a VSX register.
-Indexing may be applied to LD/ST (even on Indexed LD/ST
-instructions such as `sv.lbzx`), arithmetic operations,
-extsw: there is no artificial limit.
-
-The only major caveat is that the registers to be used as
-Indices must not be modified by any instruction after Indexed Mode
-is established, and neither must MAXVL be altered. Additionally,
-no register used as an Index may exceed MAXVL-1.
-
-Failure to observe
-these conditions results in `UNDEFINED` behaviour.
-These conditions allow a Read-After-Write (RAW) Hazard to be created on
-the entire range of Indices to be subsequently used, but a corresponding
-Write-After-Read Hazard by any instruction that modifies the Indices
-**does not have to be created**. Given the large number of registers
-involved in Indexing this is a huge resource saving and reduction
-in micro-architectural complexity. MAXVL is likewise
-included in the RAW Hazards because it is involved in calculating
-how many registers are to be considered Indices.
-
-With these Hazard Mitigations in place, high-performance implementations
-may read-cache the Indices at the point where a given `svindex` instruction
-is called (or SVSHAPE SPRs - and MAXVL - directly altered) by issuing
-background GPR register file reads whilst other instructions are being
-issued and executed.
-
-The original motivation for Indexed REMAP was to mitigate the need to add
-an expensive `mv.x` to the Scalar ISA, which was likely to be rejected as
-a stand-alone instruction.  Usually a Vector ISA would add a non-conflicting
-variant (as in VSX `vperm`) but it is common to need to permute by source,
-with the risk of conflict, that has to be resolved, for example, in AVX-512
-with `conflictd`.
-
-Indexed REMAP on the other hand **does not prevent conflicts** (overlapping
-destinations), which on a superficial analysis may be perceived to be a
-problem, until it is recalled that, firstly, Simple-V is designed specifically
-to require Program Order to be respected, and that Matrix, DCT and FFT
-all *already* critically depend on overlapping Reads/Writes: Matrix
-uses overlapping registers as accumulators.  Thus the Register Hazard
-Management needed by Indexed REMAP *has* to be in place anyway.
-
-The cost compared to Matrix and other REMAPs (and Pack/Unpack) is
-clearly that of the additional reading of the GPRs to be used as Indices,
-plus the setup cost associated with creating those same Indices.
-If any Deterministic REMAP can cover the required task, clearly it
-is adviseable to use it instead.
-
-*Programmer's note: some algorithms may require skipping of Indices exceeding
-VL-1, not MAXVL-1. This may be achieved programmatically by performing
-an `sv.cmp *BF,*RA,RB` where RA is the same GPRs used in the Indexed REMAP,
-and RB contains the value of VL returned from `setvl`. The resultant
-CR Fields may then be used as Predicate Masks to exclude those operations
-with an Index exceeding VL-1.*
-
-### Parallel Reduction
-
-Vector Reduce Mode issues a deterministic tree-reduction schedule to the underlying micro-architecture.  Like Scalar reduction, the "Scalar Base"
-(Power ISA v3.0B) operation is leveraged, unmodified, to give the
-*appearance* and *effect* of Reduction.
-
-In Horizontal-First Mode, Vector-result reduction **requires**
-the destination to be a Vector, which will be used to store
-intermediary results.
-
-Given that the tree-reduction schedule is deterministic,
-Interrupts and exceptions
-can therefore also be precise.  The final result will be in the first
-non-predicate-masked-out destination element, but due again to
-the deterministic schedule programmers may find uses for the intermediate
-results.
-
-When Rc=1 a corresponding Vector of co-resultant CRs is also
-created.  No special action is taken: the result *and its CR Field*
-are stored "as usual" exactly as all other SVP64 Rc=1 operations.
-
-Note that the Schedule only makes sense on top of certain instructions:
-X-Form with a Register Profile of `RT,RA,RB` is fine because two sources
-and the destination are all the same type.  Like Scalar
-Reduction, nothing is prohibited:
-the results of execution on an unsuitable instruction may simply
-not make sense. With care, even 3-input instructions (madd, fmadd, ternlogi) 
-may be used, and whilst it is down to the Programmer to walk through the
-process the Programmer can be confident that the Parallel-Reduction is
-guaranteed 100% Deterministic.
-
-Critical to note regarding use of Parallel-Reduction REMAP is that,
-exactly as with all REMAP Modes, the `svshape` instruction *requests*
-a certain Vector Length (number of elements to reduce) and then
-sets VL and MAXVL at the number of **operations** needed to be
-carried out.  Thus, equally as importantly, like Matrix REMAP
-the total number of operations
-is restricted to 127.  Any Parallel-Reduction requiring more operations
-will need to be done manually in batches (hierarchical
-recursive Reduction).
-
-Also important to note is that the Deterministic Schedule is arranged
-so that some implementations *may* parallelise it (as long as doing so
-respects Program Order and Register Hazards).  Performance (speed)
-of any given
-implementation is neither strictly defined or guaranteed.  As with
-the Vulkan(tm) Specification, strict compliance is paramount whilst
-performance is at the discretion of Implementors.
-
-**Parallel-Reduction with Predication**
-
-To avoid breaking the strict RISC-paradigm, keeping the Issue-Schedule
-completely separate from the actual element-level (scalar) operations,
-Move operations are **not** included in the Schedule.  This means that
-the Schedule leaves the final (scalar) result in the first-non-masked 
-element of the Vector used.  With the predicate mask being dynamic
-(but deterministic) this result could be anywhere.
-
-If that result is needed to be moved to a (single) scalar register
-then a follow-up `sv.mv/sm=predicate rt, *ra` instruction will be
-needed to get it, where the predicate is the exact same predicate used
-in the prior Parallel-Reduction instruction.
-
-* If there was only a single
-  bit in the predicate then the result will not have moved or been altered
-  from the source vector prior to the Reduction
-* If there was more than one bit the result will be in the
-  first element with a predicate bit set.
-
-In either case the result is in the element with the first bit set in
-the predicate mask. Thus, no move/copy *within the Reduction itself* was needed.
-
-Programmer's Note: For *some* hardware implementations
-the vector-to-scalar copy may be a slow operation, as may the Predicated
-Parallel Reduction itself.
-It may be better to perform a pre-copy
-of the values, compressing them (VREDUCE-style) into a contiguous block,
-which will guarantee that the result goes into the very first element
-of the destination vector, in which case clearly no follow-up
-predicated vector-to-scalar MV operation is needed.
-
-**Usage conditions**
-
-The simplest usage is to perform an overwrite, specifying all three
-register operands the same.
-
-```
-    svshape parallelreduce, 6
-    sv.add *8, *8, *8
-```
-
-The Reduction Schedule will issue the Parallel Tree Reduction spanning
-registers 8 through 13, by adjusting the offsets to RT, RA and RB as
-necessary (see "Parallel Reduction algorithm" in a later section).
-
-A non-overwrite is possible as well but just as with the overwrite
-version, only those destination elements necessary for storing
-intermediary computations will be written to: the remaining elements
-will **not** be overwritten and will **not** be zero'd.
-
-```
-    svshape parallelreduce, 6
-    sv.add *0, *8, *8
-```
-
-However it is critical to note that if the source and destination are
-not the same then the trick of using a follow-up vector-scalar MV will
-not work.
-
-### Sub-Vector Horizontal Reduction
-
-To achieve Sub-Vector Horizontal Reduction, Pack/Unpack should be enabled,
-which will turn the Schedule around such that issuing of the Scalar
-Defined Words is done with SUBVL looping as the inner loop not the
-outer loop. Rc=1 with Sub-Vectors (SUBVL=2,3,4) is `UNDEFINED` behaviour.
-
-## Determining Register Hazards
+## Determining Register Hazards (hphint)
 
 For high-performance (Multi-Issue, Out-of-Order) systems it is critical
 to be able to statically determine the extent of Vectors in order to
@@ -448,31 +133,55 @@ the Write-Hazards for result registers the corresponding Write-Hazards for the
 corresponding associated co-result CR Field must not be forgotten, *including* when
 Predication is used.
 
-## REMAP area of SVSTATE SPR
+**Horizontal-Parallelism Hint**
+
+To help further in reducing Hazards,
+`SVSTATE.hphint` is an indicator to hardware of how many elements are 100%
+fully independent.  Hardware is permitted to assume that groups of elements
+up to `hphint` in size need not have Register (or Memory) Hazards created
+between them, including when `hphint > VL`, which greatly aids simplification of
+Multi-Issue implementations.
+
+If care is not taken in setting `hphint` correctly it may wreak havoc.
+For example Matrix Outer Product relies on the innermost loop computations
+being independent.  If `hphint` is set to greater than the Outer Product
+depth then data corruption is guaranteed to occur.
+
+Likewise on FFTs it is assumed that each layer of the RADIX2 triple-loop
+is independent, but that there is strict *inter-layer* Register Hazards.
+Therefore if `hphint` is set to greater than the RADIX2 width of the FFT,
+data corruption is guaranteed.
+
+Thus the key message is that setting `hphint` requires in-depth knowledge
+of the REMAP Algorithm Schedules, given in the Appendix.
+
+## REMAP area of SVSTATE SPR <a name="svstate_remap_area"> </>
 
 The following bits of the SVSTATE SPR are used for REMAP:
 
-|32.33|34.35|36.37|38.39|40.41| 42.46 | 62 |
-| --  | --  | --  | --  | --  | ----- | ------ |
-|mi0  |mi1  |mi2  |mo0  |mo1  | SVme  | RMpst    |
+```
+    |32:33|34:35|36:37|38:39|40:41| 42:46 | 62     |
+    | --  | --  | --  | --  | --  | ----- | ------ |
+    |mi0  |mi1  |mi2  |mo0  |mo1  | SVme  | RMpst  |
+```
 
 mi0-2 and mo0-1 each select SVSHAPE0-3 to apply to a given register.
 mi0-2 apply to RA, RB, RC respectively, as input registers, and
 likewise mo0-1 apply to output registers (RT/FRT, RS/FRS) respectively.
 SVme is 5 bits (one for each of mi0-2/mo0-1) and indicates whether the
-SVSHAPE is actively applied or not.
+SVSHAPE is actively applied or not, and if so, to which registers.
 
-* bit 0 of SVme indicates if mi0 is applied to RA / FRA / BA / BFA
-* bit 1 of SVme indicates if mi1 is applied to RB / FRB / BB
-* bit 2 of SVme indicates if mi2 is applied to RC / FRC / BC
-* bit 3 of SVme indicates if mo0 is applied to RT / FRT / BT / BF
-* bit 4 of SVme indicates if mo1 is applied to Effective Address / FRS / RS
+* bit 4 of SVme indicates if mi0 is applied to source RA / FRA / BA / BFA / RT / FRT
+* bit 3 of SVme indicates if mi1 is applied to source RB / FRB / BB
+* bit 2 of SVme indicates if mi2 is applied to source RC / FRC / BC
+* bit 1 of SVme indicates if mo0 is applied to result RT / FRT / BT / BF
+* bit 0 of SVme indicates if mo1 is applied to result Effective Address / FRS / RS
   (LD/ST-with-update has an implicit 2nd write register, RA)
 
 The "persistence" bit if set will result in all Active REMAPs being applied
 indefinitely.
 
-----------------
+-----------
 
 \newpage{}
 
@@ -480,14 +189,10 @@ indefinitely.
 
 SVRM-Form:
 
-    svremap SVme,mi0,mi1,mi2,mo0,mo2,pst
-
 |0     |6     |11  |13   |15   |17   |19   |21    | 22:25 |26:31  |
 | --   | --   | -- | --  | --  | --  | --  | --   | ----  | ----- |
 | PO   | SVme |mi0 | mi1 | mi2 | mo0 | mo1 | pst  | rsvd  | XO    |
 
-SVRM-Form
-
 * svremap SVme,mi0,mi1,mi2,mo0,mo1,pst
 
 Pseudo-code:
@@ -511,7 +216,7 @@ Special Registers Altered:
     SVSTATE
 ```
 
-`svremap` determines the relationship between registers and SVSHAPE SPRs.
+`svremap` establishes the connection between registers and SVSHAPE SPRs.
 The bitmask `SVme` determines which registers have a REMAP applied, and mi0-mo1
 determine which shape is applied to an activated register.  the `pst` bit if
 cleared indicated that the REMAP operation shall only apply to the immediately-following
@@ -527,7 +232,8 @@ the bits 32 to 46 will at least have been set in SVSTATE. This may prove useful
 when using `svindex` or `svshape2`.
 
 Hardware Architectural Note: when persistence is not set it is critically important
-to treat the `svremap` and the following SVP64 instruction as an indivisible fused operation.
+to treat the `svremap` and the immediately-following SVP64 instruction as an
+indivisible fused operation.
 *No state* is stored in the SVSTATE SPR in order to allow continuation should an
 Interrupt occur between the two instructions. Thus, Interrupts must be prohibited
 from occurring or other workaround deployed.  When persistence is set this issue
@@ -544,32 +250,40 @@ to activate REMAP on any given (following) instruction.  If persistence is set h
 # SHAPE Remapping SPRs
 
 There are four "shape" SPRs, SHAPE0-3, 32-bits in each,
-which have the same format.  
+which have the same format.  It is possible to write directly to these
+SPRs but it is recommended to use the Management instructions
+`svshape`, `svshape2` or `svindex`.
 
-Shape is 32-bits.  When SHAPE is set entirely to zeros, remapping is
+When SHAPE is set entirely to zeros, remapping is
 disabled: the register's elements are a linear (1D) vector.
 
-|31.30|29..28 |27..24| 23..21 | 20..18  | 17..12  |11..6 |5..0  | Mode  |
-|---- |------ |------| ------ | ------- | ------- |----- |----- | ----- |
-|mode |skip   |offset| invxyz | permute | zdimsz  |ydimsz|xdimsz|Matrix |
-|0b00 |elwidth|offset|sk1/invxy|0b110/0b111|SVGPR|ydimsz|xdimsz|Indexed|
-|0b01 |submode|offset| invxyz | submode2| zdimsz  |mode  |xdimsz|DCT/FFT|
-|0b10 |submode|offset| invxyz | rsvd    | rsvd    |rsvd  |xdimsz|Preduce|
-|0b11 |       |      |        |         |         |      |      |rsvd   |
+|0:5   |6:11  | 12:17   | 18:20   | 21:23   |24:27 |28:29  |30:31| Mode  |
+|----- |----- | ------- | ------- | ------  |------|------ |---- | ----- |
+|xdimsz|ydimsz| zdimsz  | permute | invxyz  |offset|skip   |mode |Matrix |
+|xdimsz|ydimsz|SVGPR    | 11/     |sk1/invxy|offset|elwidth|0b00 |Indexed|
+|xdimsz|mode  | zdimsz  | submode2| invxyz  |offset|submode|0b01 |DCT/FFT|
+| rsvd |rsvd  |xdimsz   | rsvd    | invxyz  |offset|submode|0b10 |Red/Sum|
+|      |      |         |         |         |      |       |0b11 |rsvd   |
 
-mode sets different behaviours (straight matrix multiply, FFT, DCT).
+`mode` sets different behaviours (straight matrix multiply, FFT, DCT).
 
 * **mode=0b00** sets straight Matrix Mode
 * **mode=0b00** with permute=0b110 or 0b111 sets Indexed Mode
 * **mode=0b01** sets "FFT/DCT" mode and activates submodes
-* **mode=0b10** sets "Parallel Reduction" Schedules.
+* **mode=0b10** sets "Parallel Reduction or Prefix-Sum" Schedules.
+
+*Architectural Resource Allocation note: the four SVSHAPE SPRs are best
+allocated sequentially and contiguously in order that `sv.mtspr` may
+be used. This is safe to do as long as `SVSTATE.SVme=0`*
 
-## Parallel Reduction Mode
+## Parallel Reduction / Prefix-Sum Mode
 
-Creates the Schedules for Parallel Tree Reduction.
+Creates the Schedules for Parallel Tree Reduction and Prefix-Sum
 
-* **submode=0b00** selects the left operand index
-* **submode=0b01** selects the right operand index
+* **submode=0b00** selects the left operand index for Reduction
+* **submode=0b01** selects the right operand index for Reduction
+* **submode=0b10** selects the left operand index for Prefix-Sum
+* **submode=0b11** selects the right operand index for Prefix-Sum
 
 * When bit 0 of `invxyz` is set, the order of the indices
   in the inner for-loop are reversed. This has the side-effect
@@ -586,6 +300,149 @@ Creates the Schedules for Parallel Tree Reduction.
   When clear the step will begin at 2 and double on each
   inner loop.
 
+**Parallel Prefix Sum**
+
+This is a work-efficient Parallel Schedule that for example produces Trangular
+or Factorial number sequences. Half of the Prefix Sum Schedule is near-identical
+to Parallel Reduction.  Whilst the Arithmetic mapreduce Mode (`/mr`) may achieve the same
+end-result, implementations may only implement Mapreduce in serial form (or give
+the appearance to Programmers of the same). The Parallel Prefix Schedule is
+*required* to be implemented in such a way that its Deterministic Schedule may be
+parallelised. Like the Reduction Schedule it is 100% Deterministic and consequently
+may be used with non-commutative operations.
+The Schedule Algorithm may be found in the [[sv/remap/appendix]]
+
+**Parallel Reduction**
+
+Vector Reduce Mode issues a deterministic tree-reduction schedule to the underlying micro-architecture.  Like Scalar reduction, the "Scalar Base"
+(Power ISA v3.0B) operation is leveraged, unmodified, to give the
+*appearance* and *effect* of Reduction. Parallel Reduction is not limited
+to Power-of-two but is limited as usual by the total number of
+element operations (127) as well as available register file size.
+
+In Horizontal-First Mode, Vector-result reduction **requires**
+the destination to be a Vector, which will be used to store
+intermediary results, in order to achieve a correct final
+result.
+
+Given that the tree-reduction schedule is deterministic,
+Interrupts and exceptions
+can therefore also be precise.  The final result will be in the first
+non-predicate-masked-out destination element, but due again to
+the deterministic schedule programmers may find uses for the intermediate
+results, even for non-commutative Defined Word-instruction operations.
+Additionally, because the intermediate results are always written out
+it is possible to service Precise Interrupts without affecting latency
+(a common limitation of Vector ISAs implementing explicit
+Parallel Reduction instructions, because their Architectural State cannot
+hold the partial results).
+
+When Rc=1 a corresponding Vector of co-resultant CRs is also
+created.  No special action is taken: the result *and its CR Field*
+are stored "as usual" exactly as all other SVP64 Rc=1 operations.
+
+Note that the Schedule only makes sense on top of certain instructions:
+X-Form with a Register Profile of `RT,RA,RB` is fine because two sources
+and the destination are all the same type.  Like Scalar
+Reduction, nothing is prohibited:
+the results of execution on an unsuitable instruction may simply
+not make sense. With care, even 3-input instructions (madd, fmadd, ternlogi) 
+may be used, and whilst it is down to the Programmer to walk through the
+process the Programmer can be confident that the Parallel-Reduction is
+guaranteed 100% Deterministic.
+
+Critical to note regarding use of Parallel-Reduction REMAP is that,
+exactly as with all REMAP Modes, the `svshape` instruction *requests*
+a certain Vector Length (number of elements to reduce) and then
+sets VL and MAXVL at the number of **operations** needed to be
+carried out.  Thus, equally as importantly, like Matrix REMAP
+the total number of operations
+is restricted to 127.  Any Parallel-Reduction requiring more operations
+will need to be done manually in batches (hierarchical
+recursive Reduction).
+
+Also important to note is that the Deterministic Schedule is arranged
+so that some implementations *may* parallelise it (as long as doing so
+respects Program Order and Register Hazards).  Performance (speed)
+of any given
+implementation is neither strictly defined or guaranteed.  As with
+the Vulkan(tm) Specification, strict compliance is paramount whilst
+performance is at the discretion of Implementors.
+
+**Parallel-Reduction with Predication**
+
+To avoid breaking the strict RISC-paradigm, keeping the Issue-Schedule
+completely separate from the actual element-level (scalar) operations,
+Move operations are **not** included in the Schedule.  This means that
+the Schedule leaves the final (scalar) result in the first-non-masked 
+element of the Vector used.  With the predicate mask being dynamic
+(but deterministic) at a superficial glance it seems this result
+could be anywhere.
+
+If that result is needed to be moved to a (single) scalar register
+then a follow-up `sv.mv/sm=predicate rt, *ra` instruction will be
+needed to get it, where the predicate is the exact same predicate used
+in the prior Parallel-Reduction instruction.
+
+* If there was only a single
+  bit in the predicate then the result will not have moved or been altered
+  from the source vector prior to the Reduction
+* If there was more than one bit the result will be in the
+  first element with a predicate bit set.
+
+In either case the result is in the element with the first bit set in
+the predicate mask. Thus, no move/copy *within the Reduction itself* was needed.
+
+Programmer's Note: For *some* hardware implementations
+the vector-to-scalar copy may be a slow operation, as may the Predicated
+Parallel Reduction itself.
+It may be better to perform a pre-copy
+of the values, compressing them (VREDUCE-style) into a contiguous block,
+which will guarantee that the result goes into the very first element
+of the destination vector, in which case clearly no follow-up
+predicated vector-to-scalar MV operation is needed. A VREDUCE effect
+is achieved by setting just a source predicate mask on Twin-Predicated
+operations.
+
+**Usage conditions**
+
+The simplest usage is to perform an overwrite, specifying all three
+register operands the same.
+
+```
+    svshape parallelreduce, 6
+    sv.add *8, *8, *8
+```
+
+The Reduction Schedule will issue the Parallel Tree Reduction spanning
+registers 8 through 13, by adjusting the offsets to RT, RA and RB as
+necessary (see "Parallel Reduction algorithm" in a later section).
+
+A non-overwrite is possible as well but just as with the overwrite
+version, only those destination elements necessary for storing
+intermediary computations will be written to: the remaining elements
+will **not** be overwritten and will **not** be zero'd.
+
+```
+    svshape parallelreduce, 6
+    sv.add *0, *8, *8
+```
+
+However it is critical to note that if the source and destination are
+not the same then the trick of using a follow-up vector-scalar MV will
+not work.
+
+**Sub-Vector Horizontal Reduction**
+
+To achieve Sub-Vector Horizontal Reduction, Pack/Unpack should be enabled,
+which will turn the Schedule around such that issuing of the Scalar
+Defined Word-instructions is done with SUBVL looping as the inner loop not the
+outer loop. Rc=1 with Sub-Vectors (SUBVL=2,3,4) is `UNDEFINED` behaviour.
+
+*Programmer's Note: Overwrite Parallel Reduction with Sub-Vectors
+will clearly result in data corruption.  It may be best to perform
+a Pack/Unpack Transposing copy of the data first*
+
 ## FFT/DCT mode
 
 submode2=0 is for FFT. For FFT submode the following schedules may be 
@@ -623,7 +480,7 @@ column-based in-place DCT/FFT.
 ## Matrix Mode
 
 In Matrix Mode, skip allows dimensions to be skipped from being included
-in the resultant output index.  this allows sequences to be repeated:
+in the resultant output index.  This allows sequences to be repeated:
 ```0 0 0 1 1 1 2 2 2 ...``` or in the case of skip=0b11 this results in
 modulo ```0 1 2 0 1 2 ...```
 
@@ -643,7 +500,7 @@ offset will have the effect of offsetting the result by ```offset``` elements:
         GPR(RT + remap(i) + SVSHAPE.offset) = ....
 ```
 
-this appears redundant because the register RT could simply be changed by a compiler, until element width overrides are introduced.  also
+This appears redundant because the register RT could simply be changed by a compiler, until element width overrides are introduced.  Also
 bear in mind that unlike a static compiler SVSHAPE.offset may
 be set dynamically at runtime.
 
@@ -687,6 +544,40 @@ With all these options it is possible to support in-place transpose,
 in-place rotate, Matrix Multiply and Convolutions, without being
 limited to Power-of-Two dimension sizes.
 
+**Limitations and caveats**
+
+Limitations of Matrix REMAP are that the Vector Length (VL) is currently
+restricted to 127: up to 127 FMAs (or other operation)
+may be performed in total.
+Also given that it is in-registers only at present some care has to be
+taken on regfile resource utilisation. However it is perfectly possible
+to utilise Matrix REMAP to perform the three inner-most "kernel" loops of
+the usual 6-level "Tiled" large Matrix Multiply, without the usual 
+difficulties associated with SIMD.
+
+Also the `svshape` instruction only provides access to *part* of the
+Matrix REMAP capability. Rotation and mirroring need to be done by
+programming the SVSHAPE SPRs directly, which can take a lot more
+instructions. Future versions of SVP64 will 
+provide more comprehensive capacity and
+mitigate the need to write direct to the SVSHAPE SPRs.
+
+Additionally there is not yet a way to set Matrix sizes from registers
+with `svshape`: this was an intentional decision to simplify Hardware, that
+may be corrected in a future version of SVP64. The limitation may presently
+be overcome by direct programming of the SVSHAPE SPRs.
+
+*Hardware Architectural note: with the Scheduling applying as a Phase between
+Decode and Issue in a Deterministic fashion the Register Hazards may be
+easily computed and a standard Out-of-Order Micro-Architecture exploited to good
+effect.  Even an In-Order system may observe that for large Outer Product
+Schedules there will be no stalls, but if the Matrices are particularly
+small size an In-Order system would have to stall, just as it would if
+the operations were loop-unrolled without Simple-V. Thus: regardless
+of the Micro-Architecture the Hardware Engineer should first consider
+how best to process the exact same equivalent loop-unrolled instruction
+stream. Once solved Matrix REMAP will fit naturally.*
+
 ## Indexed Mode
 
 Indexed Mode activates reading of the element indices from the GPR
@@ -749,7 +640,68 @@ The most important observation above is that the Matrix-style
 remapping occurs first and the Index lookup second.  Thus it
 becomes possible to perform in-place Transpose of Indices which
 may have been costly to set up or costly to duplicate
-(waste register file space).
+(waste register file space). In other words: it is fine for two or more
+SVSHAPEs to simultaneously use the same
+Indices (use the same GPRs), even if one SVSHAPE has different
+2D dimensions and ordering from the others.
+
+**Caveats and Limitations**
+
+The purpose of Indexing is to provide a generalised version of
+Vector ISA "Permute" instructions, such as VSX `vperm`.  The
+Indexing is abstracted out and may be applied to much more
+than an element move/copy, and is not limited for example
+to the number of bytes that can fit into a VSX register.
+Indexing may be applied to LD/ST (even on Indexed LD/ST
+instructions such as `sv.lbzx`), arithmetic operations,
+extsw: there is no artificial limit.
+
+The only major caveat is that the registers to be used as
+Indices must not be modified by any instruction after Indexed Mode
+is established, and neither must MAXVL be altered. Additionally,
+no register used as an Index may exceed MAXVL-1.
+
+Failure to observe
+these conditions results in `UNDEFINED` behaviour.
+These conditions allow a Read-After-Write (RAW) Hazard to be created on
+the entire range of Indices to be subsequently used, but a corresponding
+Write-After-Read Hazard by any instruction that modifies the Indices
+**does not have to be created**. Given the large number of registers
+involved in Indexing this is a huge resource saving and reduction
+in micro-architectural complexity. MAXVL is likewise
+included in the RAW Hazards because it is involved in calculating
+how many registers are to be considered Indices.
+
+With these Hazard Mitigations in place, high-performance implementations
+may read-cache the Indices at the point where a given `svindex` instruction
+is called (or SVSHAPE SPRs - and MAXVL - directly altered) by issuing
+background GPR register file reads whilst other instructions are being
+issued and executed.
+
+Indexed REMAP **does not prevent conflicts** (overlapping
+destinations), which on a superficial analysis may be perceived to be a
+problem, until it is recalled that, firstly, Simple-V is designed specifically
+to require Program Order to be respected, and that Matrix, DCT and FFT
+all *already* critically depend on overlapping Reads/Writes: Matrix
+uses overlapping registers as accumulators.  Thus the Register Hazard
+Management needed by Indexed REMAP *has* to be in place anyway.
+
+*Programmer's Note: `hphint` may be used to help hardware identify
+parallelism opportunities but it is critical to remember that the
+groupings are by `FLOOR(step/MAXVL)` not `FLOOR(REMAP(step)/MAXVL)`.*
+
+The cost compared to Matrix and other REMAPs (and Pack/Unpack) is
+clearly that of the additional reading of the GPRs to be used as Indices,
+plus the setup cost associated with creating those same Indices.
+If any Deterministic REMAP can cover the required task, clearly it
+is adviseable to use it instead.
+
+*Programmer's note: some algorithms may require skipping of Indices exceeding
+VL-1, not MAXVL-1. This may be achieved programmatically by performing
+an `sv.cmp *BF,*RA,RB` where RA is the same GPRs used in the Indexed REMAP,
+and RB contains the value of VL returned from `setvl`. The resultant
+CR Fields may then be used as Predicate Masks to exclude those operations
+with an Index exceeding VL-1.*
 
 -------------
 
@@ -765,228 +717,7 @@ SVM-Form
 | -- | --   | ---   | ----- | ------ | -- | ------| -------- |
 |PO  | SVxd | SVyd  | SVzd  | SVRM   | vf | XO    | svshape  |
 
-```
-    # for convenience, VL to be calculated and stored in SVSTATE
-    vlen <- [0] * 7
-    mscale[0:5] <- 0b000001 # for scaling MAXVL
-    itercount[0:6] <- [0] * 7
-    SVSTATE[0:31] <- [0] * 32
-    # only overwrite REMAP if "persistence" is zero
-    if (SVSTATE[62] = 0b0) then
-        SVSTATE[32:33] <- 0b00
-        SVSTATE[34:35] <- 0b00
-        SVSTATE[36:37] <- 0b00
-        SVSTATE[38:39] <- 0b00
-        SVSTATE[40:41] <- 0b00
-        SVSTATE[42:46] <- 0b00000
-        SVSTATE[62] <- 0b0
-        SVSTATE[63] <- 0b0
-    # clear out all SVSHAPEs
-    SVSHAPE0[0:31] <- [0] * 32
-    SVSHAPE1[0:31] <- [0] * 32
-    SVSHAPE2[0:31] <- [0] * 32
-    SVSHAPE3[0:31] <- [0] * 32
-
-    # set schedule up for multiply
-    if (SVrm = 0b0000) then
-        # VL in Matrix Multiply is xd*yd*zd
-        xd <- (0b00 || SVxd) + 1
-        yd <- (0b00 || SVyd) + 1
-        zd <- (0b00 || SVzd) + 1
-        n <- xd * yd * zd
-        vlen[0:6] <- n[14:20]
-        # set up template in SVSHAPE0, then copy to 1-3
-        SVSHAPE0[0:5] <- (0b0 || SVxd)   # xdim
-        SVSHAPE0[6:11] <- (0b0 || SVyd)   # ydim
-        SVSHAPE0[12:17] <- (0b0 || SVzd)   # zdim
-        SVSHAPE0[28:29] <- 0b11           # skip z
-        # copy
-        SVSHAPE1[0:31] <- SVSHAPE0[0:31]
-        SVSHAPE2[0:31] <- SVSHAPE0[0:31]
-        SVSHAPE3[0:31] <- SVSHAPE0[0:31]
-        # set up FRA
-        SVSHAPE1[18:20] <- 0b001          # permute x,z,y
-        SVSHAPE1[28:29] <- 0b01           # skip z
-        # FRC
-        SVSHAPE2[18:20] <- 0b001          # permute x,z,y
-        SVSHAPE2[28:29] <- 0b11           # skip y
-
-    # set schedule up for FFT butterfly
-    if (SVrm = 0b0001) then
-        # calculate O(N log2 N)
-        n <- [0] * 3
-        do while n < 5
-           if SVxd[4-n] = 0 then
-               leave
-           n <- n + 1
-        n <- ((0b0 || SVxd) + 1) * n
-        vlen[0:6] <- n[1:7]
-        # set up template in SVSHAPE0, then copy to 1-3
-        # for FRA and FRT
-        SVSHAPE0[0:5] <- (0b0 || SVxd)   # xdim
-        SVSHAPE0[12:17] <- (0b0 || SVzd)   # zdim - "striding" (2D FFT)
-        mscale <- (0b0 || SVzd) + 1
-        SVSHAPE0[30:31] <- 0b01          # Butterfly mode
-        # copy
-        SVSHAPE1[0:31] <- SVSHAPE0[0:31]
-        SVSHAPE2[0:31] <- SVSHAPE0[0:31]
-        # set up FRB and FRS
-        SVSHAPE1[28:29] <- 0b01           # j+halfstep schedule
-        # FRC (coefficients)
-        SVSHAPE2[28:29] <- 0b10           # k schedule
-
-    # set schedule up for (i)DCT Inner butterfly
-    # SVrm Mode 4 (Mode 12 for iDCT) is for on-the-fly (Vertical-First Mode)
-    if ((SVrm = 0b0100) |
-        (SVrm = 0b1100)) then
-        # calculate O(N log2 N)
-        n <- [0] * 3
-        do while n < 5
-           if SVxd[4-n] = 0 then
-               leave
-           n <- n + 1
-        n <- ((0b0 || SVxd) + 1) * n
-        vlen[0:6] <- n[1:7]
-        # set up template in SVSHAPE0, then copy to 1-3
-        # set up FRB and FRS
-        SVSHAPE0[0:5] <- (0b0 || SVxd)   # xdim
-        SVSHAPE0[12:17] <- (0b0 || SVzd)   # zdim - "striding" (2D DCT)
-        mscale <- (0b0 || SVzd) + 1
-        if (SVrm = 0b1100) then
-            SVSHAPE0[30:31] <- 0b11          # iDCT mode
-            SVSHAPE0[18:20] <- 0b011         # iDCT Inner Butterfly sub-mode
-        else
-            SVSHAPE0[30:31] <- 0b01          # DCT mode
-            SVSHAPE0[18:20] <- 0b001         # DCT Inner Butterfly sub-mode
-            SVSHAPE0[21:23] <- 0b001         # "inverse" on outer loop
-        SVSHAPE0[6:11] <- 0b000011       # (i)DCT Inner Butterfly mode 4
-        # copy
-        SVSHAPE1[0:31] <- SVSHAPE0[0:31]
-        SVSHAPE2[0:31] <- SVSHAPE0[0:31]
-        if (SVrm != 0b0100) & (SVrm != 0b1100) then
-            SVSHAPE3[0:31] <- SVSHAPE0[0:31]
-        # for FRA and FRT
-        SVSHAPE0[28:29] <- 0b01           # j+halfstep schedule
-        # for cos coefficient
-        SVSHAPE2[28:29] <- 0b10           # ci (k for mode 4) schedule
-        SVSHAPE2[12:17] <- 0b000000       # reset costable "striding" to 1
-        if (SVrm != 0b0100) & (SVrm != 0b1100) then
-            SVSHAPE3[28:29] <- 0b11           # size schedule
-
-    # set schedule up for (i)DCT Outer butterfly
-    if (SVrm = 0b0011) | (SVrm = 0b1011) then
-        # calculate O(N log2 N) number of outer butterfly overlapping adds
-        vlen[0:6] <- [0] * 7
-        n <- 0b000
-        size <- 0b0000001
-        itercount[0:6] <- (0b00 || SVxd) + 0b0000001
-        itercount[0:6] <- (0b0 || itercount[0:5])
-        do while n < 5
-           if SVxd[4-n] = 0 then
-               leave
-           n <- n + 1
-           count <- (itercount - 0b0000001) * size
-           vlen[0:6] <- vlen + count[7:13]
-           size[0:6] <- (size[1:6] || 0b0)
-           itercount[0:6] <- (0b0 || itercount[0:5])
-        # set up template in SVSHAPE0, then copy to 1-3
-        # set up FRB and FRS
-        SVSHAPE0[0:5] <- (0b0 || SVxd)   # xdim
-        SVSHAPE0[12:17] <- (0b0 || SVzd)   # zdim - "striding" (2D DCT)
-        mscale <- (0b0 || SVzd) + 1
-        if (SVrm = 0b1011) then
-            SVSHAPE0[30:31] <- 0b11      # iDCT mode
-            SVSHAPE0[18:20] <- 0b011     # iDCT Outer Butterfly sub-mode
-            SVSHAPE0[21:23] <- 0b101     # "inverse" on outer and inner loop
-        else
-            SVSHAPE0[30:31] <- 0b01      # DCT mode
-            SVSHAPE0[18:20] <- 0b100     # DCT Outer Butterfly sub-mode
-        SVSHAPE0[6:11] <- 0b000010       # DCT Butterfly mode
-        # copy
-        SVSHAPE1[0:31] <- SVSHAPE0[0:31] # j+halfstep schedule
-        SVSHAPE2[0:31] <- SVSHAPE0[0:31] # costable coefficients
-        # for FRA and FRT
-        SVSHAPE1[28:29] <- 0b01           # j+halfstep schedule
-        # reset costable "striding" to 1
-        SVSHAPE2[12:17] <- 0b000000
-
-    # set schedule up for DCT COS table generation
-    if (SVrm = 0b0101) | (SVrm = 0b1101) then
-        # calculate O(N log2 N)
-        vlen[0:6] <- [0] * 7
-        itercount[0:6] <- (0b00 || SVxd) + 0b0000001
-        itercount[0:6] <- (0b0 || itercount[0:5])
-        n <- [0] * 3
-        do while n < 5
-           if SVxd[4-n] = 0 then
-               leave
-           n <- n + 1
-           vlen[0:6] <- vlen + itercount
-           itercount[0:6] <- (0b0 || itercount[0:5])
-        # set up template in SVSHAPE0, then copy to 1-3
-        # set up FRB and FRS
-        SVSHAPE0[0:5] <- (0b0 || SVxd)   # xdim
-        SVSHAPE0[12:17] <- (0b0 || SVzd)   # zdim - "striding" (2D DCT)
-        mscale <- (0b0 || SVzd) + 1
-        SVSHAPE0[30:31] <- 0b01          # DCT/FFT mode
-        SVSHAPE0[6:11] <- 0b000100       # DCT Inner Butterfly COS-gen mode
-        if (SVrm = 0b0101) then
-            SVSHAPE0[21:23] <- 0b001     # "inverse" on outer loop for DCT
-        # copy
-        SVSHAPE1[0:31] <- SVSHAPE0[0:31]
-        SVSHAPE2[0:31] <- SVSHAPE0[0:31]
-        # for cos coefficient
-        SVSHAPE1[28:29] <- 0b10           # ci schedule
-        SVSHAPE2[28:29] <- 0b11           # size schedule
-
-    # set schedule up for iDCT / DCT inverse of half-swapped ordering
-    if (SVrm = 0b0110) | (SVrm = 0b1110) | (SVrm = 0b1111) then
-        vlen[0:6] <- (0b00 || SVxd) + 0b0000001
-        # set up template in SVSHAPE0
-        SVSHAPE0[0:5] <- (0b0 || SVxd)   # xdim
-        SVSHAPE0[12:17] <- (0b0 || SVzd)   # zdim - "striding" (2D DCT)
-        mscale <- (0b0 || SVzd) + 1
-        if (SVrm = 0b1110) then
-            SVSHAPE0[18:20] <- 0b001     # DCT opposite half-swap
-        if (SVrm = 0b1111) then
-            SVSHAPE0[30:31] <- 0b01          # FFT mode
-        else
-            SVSHAPE0[30:31] <- 0b11          # DCT mode
-        SVSHAPE0[6:11] <- 0b000101       # DCT "half-swap" mode
-
-    # set schedule up for parallel reduction
-    if (SVrm = 0b0111) then
-        # calculate the total number of operations (brute-force)
-        vlen[0:6] <- [0] * 7
-        itercount[0:6] <- (0b00 || SVxd) + 0b0000001
-        step[0:6] <- 0b0000001
-        i[0:6] <- 0b0000000
-        do while step <u itercount
-            newstep <- step[1:6] || 0b0
-            j[0:6] <- 0b0000000
-            do while (j+step <u itercount)
-                j <- j + newstep
-                i <- i + 1
-            step <- newstep
-        # VL in Parallel-Reduce is the number of operations
-        vlen[0:6] <- i
-        # set up template in SVSHAPE0, then copy to 1. only 2 needed
-        SVSHAPE0[0:5] <- (0b0 || SVxd)   # xdim
-        SVSHAPE0[12:17] <- (0b0 || SVzd)   # zdim - "striding" (2D DCT)
-        mscale <- (0b0 || SVzd) + 1
-        SVSHAPE0[30:31] <- 0b10          # parallel reduce submode
-        # copy
-        SVSHAPE1[0:31] <- SVSHAPE0[0:31]
-        # set up right operand (left operand 28:29 is zero)
-        SVSHAPE1[28:29] <- 0b01           # right operand
-
-    # set VL, MVL and Vertical-First
-    m[0:12] <- vlen * mscale
-    maxvl[0:6] <- m[6:12]
-    SVSTATE[0:6] <- maxvl  # MAVXL
-    SVSTATE[7:13] <- vlen  # VL
-    SVSTATE[63] <- vf
-```
+See [[sv/remap/appendix]] for `svshape` pseudocode
 
 Special Registers Altered:
 
@@ -1002,9 +733,9 @@ require `setvl`.
 
 Fields:
 
-* **SVxd** - SV REMAP "xdim"
-* **SVyd** - SV REMAP "ydim"
-* **SVzd** - SV REMAP "zdim"
+* **SVxd** - SV REMAP "xdim" (X-dimension)
+* **SVyd** - SV REMAP "ydim" (Y-dimension, sometimes used for sub-mode selection)
+* **SVzd** - SV REMAP "zdim" (Z-dimension)
 * **SVRM** - SV REMAP Mode (0b00000 for Matrix, 0b00001 for FFT etc.)
 * **vf** - sets "Vertical-First" mode
 * **XO** - standard 6-bit XO field
@@ -1024,7 +755,7 @@ are RESERVED)
 | 0b0100 | DCT Inner butterfly, on-the-fly (Vertical-First Mode) |
 | 0b0101 | DCT COS table index generation |
 | 0b0110 | DCT half-swap   |
-| 0b0111 | Parallel Reduction |
+| 0b0111 | Parallel Reduction and Prefix Sum |
 | 0b1000 | reserved for svshape2 |
 | 0b1001 | reserved for svshape2 |
 | 0b1010 | reserved |
@@ -1046,8 +777,20 @@ will be zero (`SVxd || 0b00`).
 `svshape` has *limited applicability* due to being a 32-bit instruction.
 The full capability of SVSHAPE SPRs may be accessed by directly writing
 to SVSHAPE0-3 with `mtspr`. Circumstances include Matrices with dimensions
-larger than 32, and in-place Transpose.  Potentially a future v3.1 Prefixed
-instruction, `psvshape`, may extend the capability here.
+larger than 32, and in-place Transpose.  Potentially a future
+instruction may extend the capability here.
+
+Programmer's Note: Parallel Reduction Mode is selected by setting `SVRM=7,SVyd=1`.
+Prefix Sum Mode is selected by setting `SVRM=7,SVyd=3`:
+
+```
+    # Vector length of 8.
+    svshape 8, 3, 1, 0x7, 0
+    # activate SVSHAPE0 (prefix-sum lhs) for RA
+    # activate SVSHAPE1 (prefix-sum rhs) for RT and RB
+    svremap 7, 0, 1, 0, 1, 0, 0
+    sv.add *10, *10, *10
+```
 
 *Architectural Resource Allocation note: the SVRM field is carefully
 crafted to allocate two Modes, corresponding to bits 21-23 within the
@@ -1072,66 +815,7 @@ SVI-Form
 
 * svindex SVG,rmm,SVd,ew,SVyx,mm,sk
 
-Pseudo-code:
-
-```
-    # based on nearest MAXVL compute other dimension
-    MVL <- SVSTATE[0:6]
-    d <- [0] * 6
-    dim <- SVd+1
-    do while d*dim <u ([0]*4 || MVL)
-       d <- d + 1
-
-    # set up template, then copy once location identified
-    shape <- [0]*32
-    shape[30:31] <- 0b00            # mode
-    if SVyx = 0 then
-        shape[18:20] <- 0b110       # indexed xd/yd
-        shape[0:5] <- (0b0 || SVd)  # xdim
-        if sk = 0 then shape[6:11] <- 0 # ydim
-        else           shape[6:11] <- 0b111111 # ydim max
-    else
-        shape[18:20] <- 0b111       # indexed yd/xd
-        if sk = 1 then shape[6:11] <- 0 # ydim
-        else           shape[6:11] <- d-1 # ydim max
-        shape[0:5] <- (0b0 || SVd) # ydim
-    shape[12:17] <- (0b0 || SVG)        # SVGPR
-    shape[28:29] <- ew                  # element-width override
-    shape[21] <- sk                     # skip 1st dimension
-
-    # select the mode for updating SVSHAPEs
-    SVSTATE[62] <- mm # set or clear persistence
-    if mm = 0 then
-        # clear out all SVSHAPEs first
-        SVSHAPE0[0:31] <- [0] * 32
-        SVSHAPE1[0:31] <- [0] * 32
-        SVSHAPE2[0:31] <- [0] * 32
-        SVSHAPE3[0:31] <- [0] * 32
-        SVSTATE[32:41] <- [0] * 10 # clear REMAP.mi/o
-        SVSTATE[42:46] <- rmm # rmm exactly REMAP.SVme
-        idx <- 0
-        for bit = 0 to 4
-            if rmm[4-bit] then
-                # activate requested shape
-                if idx = 0 then SVSHAPE0 <- shape
-                if idx = 1 then SVSHAPE1 <- shape
-                if idx = 2 then SVSHAPE2 <- shape
-                if idx = 3 then SVSHAPE3 <- shape
-                SVSTATE[bit*2+32:bit*2+33] <- idx
-                # increment shape index, modulo 4
-                if idx = 3 then idx <- 0
-                else            idx <- idx + 1
-    else
-        # refined SVSHAPE/REMAP update mode
-        bit <- rmm[0:2]
-        idx <- rmm[3:4]
-        if idx = 0 then SVSHAPE0 <- shape
-        if idx = 1 then SVSHAPE1 <- shape
-        if idx = 2 then SVSHAPE2 <- shape
-        if idx = 3 then SVSHAPE3 <- shape
-        SVSTATE[bit*2+32:bit*2+33] <- idx
-        SVSTATE[46-bit] <- 1
-```
+See [[sv/remap/appendix]] for `svindex` pseudocode
 
 Special Registers Altered:
 
@@ -1262,64 +946,7 @@ SVM2-Form
 
 * svshape2 offs,yx,rmm,SVd,sk,mm
 
-Pseudo-code:
-
-```
-    # based on nearest MAXVL compute other dimension
-    MVL <- SVSTATE[0:6]
-    d <- [0] * 6
-    dim <- SVd+1
-    do while d*dim <u ([0]*4 || MVL)
-       d <- d + 1
-    # set up template, then copy once location identified
-    shape <- [0]*32
-    shape[30:31] <- 0b00            # mode
-    shape[0:5] <- (0b0 || SVd)      # x/ydim
-    if SVyx = 0 then
-        shape[18:20] <- 0b000       # ordering xd/yd(/zd)
-        if sk = 0 then shape[6:11] <- 0 # ydim
-        else           shape[6:11] <- 0b111111 # ydim max
-    else
-        shape[18:20] <- 0b010       # ordering yd/xd(/zd)
-        if sk = 1 then shape[6:11] <- 0 # ydim
-        else           shape[6:11] <- d-1 # ydim max
-    # offset (the prime purpose of this instruction)
-    shape[24:27] <- SVo         # offset
-    if sk = 1 then shape[28:29] <- 0b01 # skip 1st dimension
-    else           shape[28:29] <- 0b00 # no skipping
-    # select the mode for updating SVSHAPEs
-    SVSTATE[62] <- mm # set or clear persistence
-    if mm = 0 then
-        # clear out all SVSHAPEs first
-        SVSHAPE0[0:31] <- [0] * 32
-        SVSHAPE1[0:31] <- [0] * 32
-        SVSHAPE2[0:31] <- [0] * 32
-        SVSHAPE3[0:31] <- [0] * 32
-        SVSTATE[32:41] <- [0] * 10 # clear REMAP.mi/o
-        SVSTATE[42:46] <- rmm # rmm exactly REMAP.SVme
-        idx <- 0
-        for bit = 0 to 4
-            if rmm[4-bit] then
-                # activate requested shape
-                if idx = 0 then SVSHAPE0 <- shape
-                if idx = 1 then SVSHAPE1 <- shape
-                if idx = 2 then SVSHAPE2 <- shape
-                if idx = 3 then SVSHAPE3 <- shape
-                SVSTATE[bit*2+32:bit*2+33] <- idx
-                # increment shape index, modulo 4
-                if idx = 3 then idx <- 0
-                else            idx <- idx + 1
-    else
-        # refined SVSHAPE/REMAP update mode
-        bit <- rmm[0:2]
-        idx <- rmm[3:4]
-        if idx = 0 then SVSHAPE0 <- shape
-        if idx = 1 then SVSHAPE1 <- shape
-        if idx = 2 then SVSHAPE2 <- shape
-        if idx = 3 then SVSHAPE3 <- shape
-        SVSTATE[bit*2+32:bit*2+33] <- idx
-        SVSTATE[46-bit] <- 1
-```
+See [[sv/remap/appendix]] for `svshape2` pseudocode
 
 Special Registers Altered:
 
@@ -1329,18 +956,18 @@ Special Registers Altered:
 
 `svshape2` is an additional convenience instruction that prioritises
 setting `SVSHAPE.offset`. Its primary purpose is for use when
-element-width overrides are used. It has identical capabilities to `svindex` and
+element-width overrides are used. It has identical capabilities to `svindex`
 in terms of both options (skip, etc.) and ability to activate REMAP
-(rmm, mask mode) but unlike `svindex` it does not set GPR REMAP,
+(rmm, mask mode) but unlike `svindex` it does not set GPR REMAP:
 only a 1D or 2D `svshape`, and
-unlike `svshape` it can set an arbirrary `SVSHAPE.offset` immediate.
+unlike `svshape` it can set an arbitrary `SVSHAPE.offset` immediate.
 
 One of the limitations of Simple-V is that Vector elements start on the boundary
 of the Scalar regfile, which is fine when element-width overrides are not
 needed. If the starting point of a Vector with smaller elwidths must begin
 in the middle of a register, normally there would be no way to do so except
-through LD/ST.  `SVSHAPE.offset` caters for this scenario and `svshape2`is
-makes it easier.
+through costly LD/ST.  `SVSHAPE.offset` caters for this scenario and `svshape2`
+makes it easier to access.
 
 **Operand Fields**: