redo formatting
[libreriscv.git] / simple_v_extension / specification.mdwn
index aaf546f7d85e59cd4f06048d4597626d88a20ff8..2eb60764fa4f6abcbd32e52a77d56c6ebb405d2e 100644 (file)
@@ -1,15 +1,19 @@
 # Simple-V (Parallelism Extension Proposal) Specification
 
-* Status: DRAFTv0.2
-* Last edited: 17 oct 2018
-* Ancillary resource: [[opcodes]]
+* Copyright (C) 2017, 2018, 3029 Luke Kenneth Casson Leighton
+* Status: DRAFTv0.6
+* Last edited: 21 jun 2019
+* Ancillary resource: [[opcodes]] [[sv_prefix_proposal]]
 
 With thanks to:
 
 * Allen Baum
+* Bruce Hoult
+* comp.arch
 * Jacob Bachmeyer
 * Guy Lemurieux
 * Jacob Lifshay
+* Terje Mathisen
 * The RISC-V Founders, without whom this all would not be possible.
 
 [[!toc ]]
@@ -20,8 +24,10 @@ Simple-V is a uniform parallelism API for RISC-V hardware that has several
 unplanned side-effects including code-size reduction, expansion of
 HINT space and more.  The reason for
 creating it is to provide a manageable way to turn a pre-existing design
-into a parallel one, in a step-by-step incremental fashion, allowing
+into a parallel one, in a step-by-step incremental fashion, without adding any new opcodes, thus allowing
 the implementor to focus on adding hardware where it is needed and necessary.
+The primary target is for mobile-class 3D GPUs and VPUs, with secondary
+goals being to reduce executable size and reduce context-switch latency.
 
 Critically: **No new instructions are added**.  The parallelism (if any
 is implemented) is implicitly added by tagging *standard* scalar registers
@@ -69,102 +75,95 @@ when and whether to parallelise operations **entirely to the implementor**.
 
 The principle of SV is as follows:
 
-* CSRs indicating which registers are "tagged" as parallel are set up
+* Standard RV instructions are "prefixed" (extended) through a 48/64
+  bit format (single instruction option) or a variable
+ length VLIW-like prefix (multi or "grouped" option).
+* The prefix(es) indicate which registers are "tagged" as
+  "vectorised". Predicates can also be added.
 * A "Vector Length" CSR is set, indicating the span of any future
   "parallel" operations.
-* A **scalar** operation, just after the decode phase and before the
-  execution phase, checks the CSR register tables to see if any of
-  its registers have been marked as "vectorised"
-* If so, a hardware "macro-unrolling loop" is activated, of length
-  VL, that effectively issues **multiple** identical instructions (whether
-  they be sequential or parallel is entirely up to the implementor),
-  using contiguous sequentially-incrementing registers.
+* If any operation (a **scalar** standard RV opcode) uses a register
+  that has been so "marked" ("tagged"), a hardware "macro-unrolling loop"
+  is activated, of length VL, that effectively issues **multiple**
+  identical instructions using contiguous sequentially-incrementing
+  register numbers, based on the "tags".
+* **Whether they be executed sequentially or in parallel or a
+  mixture of both or punted to software-emulation in a trap handler
+  is entirely up to the implementor**.
 
 In this way an entire scalar algorithm may be vectorised with
 the minimum of modification to the hardware and to compiler toolchains.
-There are **no** new opcodes.
 
-# CSRs <a name="csrs"></a>
+To reiterate: **There are *no* new opcodes**. The scheme works *entirely*
+on hidden context that augments *scalar* RISCV instructions.
 
-For U-Mode there are two CSR key-value stores needed to create lookup
-tables which are used at the register decode phase.
+# CSRs <a name="csrs"></a>
 
-* A register CSR key-value table (typically 8 32-bit CSRs of 2 16-bits each)
-* A predication CSR key-value table (again, 8 32-bit CSRs of 2 16-bits each)
-* Small U-Mode and S-Mode register and predication CSR key-value tables
-  (2 32-bit CSRs of 2x 16-bit entries each).
 * An optional "reshaping" CSR key-value table which remaps from a 1D
   linear shape to 2D or 3D, including full transposition.
 
-There are also four additional CSRs for User-Mode:
+There are also five additional User mode CSRs :
 
-* CFG subsets the CSR tables
-* MVL (the Maximum Vector Length)
-* VL (which has different characteristics from standard CSRs)
-* STATE (useful for saving and restoring during context switch,
+* uMVL (the Maximum Vector Length)
+* uVL (which has different characteristics from standard CSRs)
+* uSUBVL (effectively a kind of SIMD)
+* uEPCVLIW (a copy of the sub-execution Program Counter, that is relative
+  to the start of the current VLIW Group, set on a trap).
+* uSTATE (useful for saving and restoring during context switch,
   and for providing fast transitions)
 
-There are also three additional CSRs for Supervisor-Mode:
+There are also five additional CSRs for Supervisor-Mode:
 
 * SMVL
 * SVL
+* SSUBVL
+* SEPCVLIW
 * SSTATE
 
 And likewise for M-Mode:
 
 * MMVL
 * MVL
+* MSUBVL
+* MEPCVLIW
 * MSTATE
 
-Both Supervisor and M-Mode have their own (small) CSR register and
-predication tables of only 4 entries each.
-
-## CFG
-
-This CSR may be used to switch between subsets of the CSR Register and
-Predication Tables: it is kept to 5 bits so that a single CSRRWI instruction
-can be used.  A setting of all ones is reserved to indicate that SimpleV
-is disabled.
+Both Supervisor and M-Mode have their own CSR registers, independent
+of the other privilege levels, in order to make it easier to use
+Vectorisation in each level without affecting other privilege levels.
 
-| (4..3) | (2...0) |
-| ------ | ------- |
-| size   | bank    |
+The access pattern for these groups of CSRs in each mode follows the
+same pattern for other CSRs that have M-Mode and S-Mode "mirrors":
 
-Bank is 3 bits in size, and indicates the starting index of the CSR
-Register and Predication Table entries that are "enabled".  Given that
-each CSR table row is 16 bits and contains 2 CAM entries each, there
-are only 8 CSRs to cover in each table, so 8 bits is sufficient.
+* In M-Mode, the S-Mode and U-Mode CSRs are separate and distinct.
+* In S-Mode, accessing and changing of the M-Mode CSRs is transparently
+  identical
+  to changing the S-Mode CSRs.  Accessing and changing the U-Mode
+  CSRs is permitted.
+* In U-Mode, accessing and changing of the S-Mode and U-Mode CSRs
+  is prohibited.
 
-Size is 2 bits.  With the exception of when bank == 7 and size == 3,
-the number of elements enabled is taken by right-shifting 2 by size:
+In M-Mode, only the M-Mode CSRs are in effect, i.e. it is only the
+M-Mode MVL, the M-Mode STATE and so on that influences the processor
+behaviour.  Likewise for S-Mode, and likewise for U-Mode.
 
-| size   | elements |
-| ------ | -------- |
-| 0      | 2        |
-| 1      | 4        |
-| 2      | 8        |
-| 3      | 16       |
+This has the interesting benefit of allowing M-Mode (or S-Mode) to be set
+up, for context-switching to take place, and, on return back to the higher
+privileged mode, the CSRs of that mode will be exactly as they were.
+Thus, it becomes possible for example to set up CSRs suited best to aiding
+and assisting low-latency fast context-switching *once and only once*
+(for example at boot time), without the need for re-initialising the
+CSRs needed to do so.
 
-Given that there are 2 16-bit CAM entries per CSR table row, this
-may also be viewed as the number of CSR rows to enable, by raising size to
-the power of 2.
+Another interesting side effect of separate S Mode CSRs is that Vectorised
+saving of the entire register file to the stack is a single instruction
+(accidental provision of LOAD-MULTI semantics). It can even be predicated,
+which opens up some very interesting possibilities.
 
-Examples:
+The xEPCVLIW CSRs must be treated exactly like their corresponding xepc
+equivalents. See VLIW section for details.
 
-* When bank = 0 and size = 3, SVREGCFG0 through to SVREGCFG7 are
-  enabled, and SVPREDCFG0 through to SVPREGCFG7 are enabled.
-* When bank = 1 and size = 3, SVREGCFG1 through to SVREGCFG7 are
-  enabled, and SVPREDCFG1 through to SVPREGCFG7 are enabled.
-* When bank = 3 and size = 0, SVREGCFG3 and SVPREDCFG3 are enabled.
-* When bank = 3 and size = 0, SVREGCFG3 and SVPREDCFG3 are enabled.
-* When bank = 7 and size = 1, SVREGCFG7 and SVPREDCFG7 are enabled.
-* When bank = 7 and size = 3, SimpleV is entirely disabled.
-
-In this way it is possible to enable and disable SimpleV with a
-single instruction, and, furthermore, on context-switching the quantity
-of CSRs to be saved and restored is greatly reduced.
-
-## MAXVECTORLENGTH (MVL)
+## MAXVECTORLENGTH (MVL) <a name="mvl" />
 
 MAXVECTORLENGTH is the same concept as MVL in RVV, except that it
 is variable length and may be dynamically set.  MVL is
@@ -175,16 +174,15 @@ The reason for setting this limit is so that predication registers, when
 marked as such, may fit into a single register as opposed to fanning out
 over several registers.  This keeps the implementation a little simpler.
 
-The other important factor to note is that the actual MVL is **offset
-by one**, so that it can fit into only 6 bits (for RV64) and still cover
-a range up to XLEN bits.  So, when setting the MVL CSR to 0, this actually
-means that MVL==1.  When setting the MVL CSR to 3, this actually means
-that MVL==4, and so on.  This is expressed more clearly in the "pseudocode"
+The other important factor to note is that the actual MVL is internally
+stored **offset by one**, so that it can fit into only 6 bits (for RV64)
+and still cover a range up to XLEN bits.  Attempts to set MVL to zero will
+return an exception.  This is expressed more clearly in the "pseudocode"
 section, where there are subtle differences between CSRRW and CSRRWI.
 
-## Vector Length (VL)
+## Vector Length (VL) <a name="vl" />
 
-VSETVL is slightly different from RVV.  Like RVV, VL is set to be within
+VSETVL is slightly different from RVV.  Similar to RVV, VL is set to be within
 the range 1 <= VL <= MVL (where MVL in turn is limited to 1 <= MVL <= XLEN)
 
     VL = rd = MIN(vlen, MVL)
@@ -236,44 +234,73 @@ exactly as standard CSRs, and contains more than just VL.
 
 One interesting side-effect of using CSRRWI to set VL is that this
 may be done with a single instruction, useful particularly for a
-context-load/save.  There are however limitations: CSRWWI's immediate
-is limited to 0-31.
+context-load/save.  There are however limitations: CSRWI's immediate
+is limited to 0-31 (representing VL=1-32).
+
+Note that when VL is set to 1, all parallel operations cease: the
+hardware loop is reduced to a single element: scalar operations.
+
+## SUBVL - Sub Vector Length
+
+This is a "group by quantity" that effectively divides VL into groups
+of elements of length SUBVL. VL itself must therefore be set in advance
+to a multiple of SUBVL.
+
+Legal values are 1, 2, 3 and 4, and the STATE CSR must hold the 2 bit values 0b00 thru 0b11.
+
+Setting this CSR to 0 must raise an exception.  Setting it to a value
+greater than 4 likewise.
+
+The main effect of SUBVL is that predication bits are applied per **group**, 
+rather than by individual element.
+
+This saves a not insignificant number of instructions when handling 3D
+vectors, as otherwise a much longer predicate mask would have to be set
+up with regularly-repeated bit patterns.
 
 ## STATE
 
 This is a standard CSR that contains sufficient information for a
-full context save/restore.  It contains (and permits setting of)
-MVL, VL, CFG, the destination element offset of the current parallel
-instruction being executed, and, for twin-predication, the source
-element offset as well.  Interestingly it may hypothetically
-also be used to make the immediately-following instruction to skip a
-certain number of elements, however the recommended method to do
-this is predication.
+full context save/restore.  It contains (and permits setting of):
+
+* MVL
+* VL
+* SUBVL
+* the destination element offset of the current parallel instruction
+  being executed
+* and, for twin-predication, the source element offset as well.
+
+Interestingly STATE may hypothetically also be used to make the
+immediately-following instruction to skip a certain number of elements,
+by playing with destoffs and srcoffs.
 
 Setting destoffs and srcoffs is realistically intended for saving state
 so that exceptions (page faults in particular) may be serviced and the
 hardware-loop that was being executed at the time of the trap, from
-user-mode (or Supervisor-mode), may be returned to and continued from
+user-mode (or Supervisor-mode), may be returned to and continued from exactly
 where it left off.  The reason why this works is because setting
 User-Mode STATE will not change (not be used) in M-Mode or S-Mode
 (and is entirely why M-Mode and S-Mode have their own STATE CSRs).
 
 The format of the STATE CSR is as follows:
 
-| (28..26) | (25..24) | (23..18) | (17..12) | (11..6) | (5...0) |
+| (28..27) | (26..24) | (23..18) | (17..12) | (11..6) | (5...0) |
 | -------- | -------- | -------- | -------- | ------- | ------- |
-| size     | bank     | destoffs | srcoffs  | vl      | maxvl   |
+| rsvd     | subvl    | destoffs | srcoffs  | vl      | maxvl   |
 
 When setting this CSR, the following characteristics will be enforced:
 
 * **MAXVL** will be truncated (after offset) to be within the range 1 to XLEN
 * **VL** will be truncated (after offset) to be within the range 1 to MAXVL
+* **SUBVL** which sets a SIMD-like quantity, has only 4 values however
+  if VL is not a multiple of SUBVL an exception will be raised.
 * **srcoffs** will be truncated to be within the range 0 to VL-1
 * **destoffs** will be truncated to be within the range 0 to VL-1
 
-## MVL, VL and CSR Pseudocode
+## MVL and VL  Pseudocode
 
-The pseudo-code for get and set of VL and MVL are as follows:
+The pseudo-code for get and set of VL and MVL use the following internal
+functions as follows:
 
     set_mvl_csr(value, rd):
         regs[rd] = MVL
@@ -285,13 +312,15 @@ The pseudo-code for get and set of VL and MVL are as follows:
     set_vl_csr(value, rd):
         VL = MIN(value, MVL)
         regs[rd] = VL # yes returning the new value NOT the old CSR
+        return VL
 
     get_vl_csr(rd):
         regs[rd] = VL
+        return VL
 
-Note that where setting MVL behaves as a normal CSR, unlike standard CSR
-behaviour, setting VL will return the **new** value of VL **not** the old
-one.
+Note that where setting MVL behaves as a normal CSR (returns the old
+value), unlike standard CSR behaviour, setting VL will return the **new**
+value of VL **not** the old one.
 
 For CSRRWI, the range of the immediate is restricted to 5 bits.  In order to
 maximise the effectiveness, an immediate of 0 is used to set VL=1,
@@ -303,20 +332,20 @@ an immediate of 1 is used to set VL=2 and so on:
     CSRRWI_Set_VL(value):
         set_vl_csr(value+1, x0)
 
-However for CSRRW the following pseudocide is used for MVL and VL,
+However for CSRRW the following pseudocode is used for MVL and VL,
 where setting the value to zero will cause an exception to be raised.
 The reason is that if VL or MVL are set to zero, the STATE CSR is
 not capable of returning that value.
 
     CSRRW_Set_MVL(rs1, rd):
         value = regs[rs1]
-        if value == 0:
+        if value == 0 or value > XLEN:
             raise Exception
         set_mvl_csr(value, rd)
 
     CSRRW_Set_VL(rs1, rd):
         value = regs[rs1]
-        if value == 0:
+        if value == 0 or value > XLEN:
             raise Exception
         set_vl_csr(value, rd)
 
@@ -350,13 +379,12 @@ VL==1, "00001" represents VL==2 and so on (likewise for MVL):
         get_state_csr(rd)
         MVL = set_mvl_csr(value[11:6]+1)
         VL = set_vl_csr(value[5:0]+1)
-        CFG = value[28:24]>>24
         destoffs = value[23:18]>>18
         srcoffs = value[23:18]>>12
 
     get_state_csr(rd):
         regs[rd] = (MVL-1) | (VL-1)<<6 | (srcoffs)<<12 |
-                   (destoffs)<<18 | (CFG)<<24
+                   (destoffs)<<18
         return regs[rd]
 
 In both cases, whilst CSR read of VL and MVL return the exact values
@@ -364,38 +392,63 @@ of VL and MVL respectively, reading and writing the STATE CSR returns
 those values **minus one**.  This is absolutely critical to implement
 if the STATE CSR is to be used for fast context-switching.
 
-## Register CSR key-value (CAM) table
+## Register key-value (CAM) table <a name="regcsrtable" />
 
-The purpose of the Register CSR table is four-fold:
+*NOTE: in prior versions of SV, this table used to be writable and
+accessible via CSRs. It is now stored in the VLIW instruction format,
+and entries may be overridden by the SVPrefix format*
+
+The purpose of the Register table is four-fold:
 
 * To mark integer and floating-point registers as requiring "redirection"
   if it is ever used as a source or destination in any given operation.
   This involves a level of indirection through a 5-to-7-bit lookup table,
   such that **unmodified** operands with 5 bit (3 for Compressed) may
-  access up to **64** registers.
+  access up to **128** registers.
 * To indicate whether, after redirection through the lookup table, the
   register is a vector (or remains a scalar).
 * To over-ride the implicit or explicit bitwidth that the operation would
   normally give the register.
 
-| RgCSR | | 15       | (14..8)  | 7   | (6..5) | (4..0)  |
-| ----- | | -        | -        | -   | ------ | ------- |
-| 0     | | isvec0   | regidx0  | i/f | vew0   | regkey  |
-| 1     | | isvec1   | regidx1  | i/f | vew1   | regkey  |
-| ..    | | isvec..  | regidx.. | i/f | vew..  | regkey  |
-| 15    | | isvec15  | regidx15 | i/f | vew15  | regkey  |
+16 bit format:
+
+| RegCAM | | 15       | (14..8)  | 7   | (6..5) | (4..0)  |
+| ------ | | -        | -        | -   | ------ | ------- |
+| 0      | | isvec0   | regidx0  | i/f | vew0   | regkey  |
+| 1      | | isvec1   | regidx1  | i/f | vew1   | regkey  |
+| ..     | | isvec..  | regidx.. | i/f | vew..  | regkey  |
+| 15     | | isvec15  | regidx15 | i/f | vew15  | regkey  |
+
+8 bit format:
+
+| RegCAM | | 7   | (6..5) | (4..0)  |
+| ------ | | -   | ------ | ------- |
+| 0      | | i/f | vew0   | regnum  |
 
 i/f is set to "1" to indicate that the redirection/tag entry is to be applied
 to integer registers; 0 indicates that it is relevant to floating-point
-registers.  vew has the following meanings, indicating that the instruction's
+registers.
+
+The 8 bit format is used for a much more compact expression. "isvec"
+is implicit and, similar to [[sv-prefix-proposal]], the target vector
+is "regnum<<2", implicitly. Contrast this with the 16-bit format where
+the target vector is *explicitly* named in bits 8 to 14, and bit 15 may
+optionally set "scalar" mode.
+
+Note that whilst SVPrefis adds one extra bit to each of rd, rs1 etc.,
+and thus the "vector" mode need only shift the (6 bit) regnum by 1 to
+get the actual (7 bit) register number to use, there is not enough space
+in the 8 bit format so "regnum<<2" is required.
+
+vew has the following meanings, indicating that the instruction's
 operand size is "over-ridden" in a polymorphic fashion:
 
-| vew | bitwidth   |
-| --- | ---------- |
-| 00  | default    |
-| 01  | default/2  |
-| 10  | default\*2 |
-| 11  | 8          |
+| vew | bitwidth            |
+| --- | ------------------- |
+| 00  | default (XLEN/FLEN) |
+| 01  | 8 bit               |
+| 10  | 16 bit              |
+| 11  | 32 bit              |
 
 As the above table is a CAM (key-value store) it may be appropriate
 (faster, implementation-wise) to expand it as follows:
@@ -410,79 +463,33 @@ As the above table is a CAM (key-value store) it may be appropriate
        tb[idx].isvector = CSRvec[i].isvector // 0=scalar
        tb[idx].packed   = CSRvec[i].packed  // SIMD or not
 
-The actual size of the CSR Register table depends on the platform
-and on whether other Extensions are present (RV64G, RV32E, etc.).
-For details see "Subsets" section.
-
-16-bit CSR Register CAM entries are mapped directly into 32-bit
-on any RV32-based system, however RV64 (XLEN=64) and RV128 (XLEN=128)
-are slightly different: the 16-bit entries appear (and can be set)
-multiple times, in an overlapping fashion.  Here is the table for RV64:
-
-| CSR#  | 63..48  | 47..32  | 31..16  | 15..0   |
-| 0x4c0 | RgCSR3  | RgCSR2  | RgCSR1  | RgCSR0  |
-| 0x4c1 | RgCSR5  | RgCSR4  | RgCSR3  | RgCSR2  |
-| 0x4c2 | ...     | ...     | ...     | ...     |
-| 0x4c1 | RgCSR15 | RgCSR14 | RgCSR13 | RgCSR12 |
-| 0x4c8 | n/a     | n/a     | RgCSR15 | RgCSR4  |
-
-The rules for writing to these CSRs are that any entries above the ones
-being set will be automatically wiped (to zero), so to fill several entries
-they must be written in a sequentially increasing manner.  This functionality
-was in an early draft of RVV and it means that, firstly, compilers do not have
-to spend time zero-ing out CSRs unnecessarily, and secondly, that on
-context-switching (and function calls) the number of CSRs that may need
-saving is implicitly known.
-
-The reason for the overlapping entries is that in the worst-case on an
-RV64 system, only 4 64-bit CSR reads/writes are required for a full
-context-switch (and an RV128 system, only 2 128-bit CSR reads/writes).
-
---
-
-TODO: move elsewhere
-
-    # TODO: use elsewhere (retire for now)
-    vew = CSRbitwidth[rs1]
-    if (vew == 0)
-        bytesperreg = (XLEN/8) # or FLEN as appropriate
-    elif (vew == 1)
-        bytesperreg = (XLEN/4) # or FLEN/2 as appropriate
-    else:
-        bytesperreg = bytestable[vew] # 8 or 16
-    simdmult = (XLEN/8) / bytesperreg # or FLEN as appropriate
-    vlen = CSRvectorlen[rs1] * simdmult
-    CSRvlength = MIN(MIN(vlen, MAXVECTORLENGTH), rs2)
 
-The reason for multiplying the vector length by the number of SIMD elements
-(in each individual register) is so that each SIMD element may optionally be
-predicated.
 
-An example of how to subdivide the register file when bitwidth != default
-is given in the section "Bitwidth Virtual Register Reordering".
+## Predication Table <a name="predication_csr_table"></a>
 
-## Predication CSR <a name="predication_csr_table"></a>
+*NOTE: in prior versions of SV, this table used to be writable and
+accessible via CSRs. It is now stored in the VLIW instruction format,
+and entries may be overridden by the SVPrefix format*
 
-TODO: update CSR tables, now 7-bit for regidx
+The Predication Table is a key-value store indicating whether, if a
+given destination register (integer or floating-point) is referred to
+in an instruction, it is to be predicated. Like the Register table, it
+is an indirect lookup that allows the RV opcodes to not need modification.
 
-The Predication CSR is a key-value store indicating whether, if a given
-destination register (integer or floating-point) is referred to in an
-instruction, it is to be predicated.  Tt is particularly important to note
+It is particularly important to note
 that the *actual* register used can be *different* from the one that is
 in the instruction, due to the redirection through the lookup table.
 
-* regidx is the actual register that in combination with the
-  i/f flag, if that integer or floating-point register is referred to,
+* regidx is the register that in combination with the
+  i/f flag, if that integer or floating-point register is referred to
+ in a (standard RV) instruction
   results in the lookup table being referenced to find the predication
-  mask to use on the operation in which that (regidx) register has
-  been used
-* predidx (in combination with the bank bit in the future) is the
-  *actual* register to be used for the predication mask.  Note:
-  in effect predidx is actually a 6-bit register address, as the bank
-  bit is the MSB (and is nominally set to zero for now).
+  mask to use for this operation.
+* predidx is the
+  *actual* (full, 7 bit) register to be used for the predication mask. 
 * inv indicates that the predication mask bits are to be inverted
   prior to use *without* actually modifying the contents of the
-  register itself.
+  registerfrom which those bits originated.
 * zeroing is either 1 or 0, and if set to 1, the operation must
   place zeros in any element position where the predication mask is
   set to zero.  If zeroing is set to 0, unpredicated elements *must*
@@ -492,21 +499,30 @@ in the instruction, due to the redirection through the lookup table.
   interpret unpredicated elements as an internal "copy element"
   operation (which would be necessary in SIMD microarchitectures
   that perform register-renaming)
-* "packed" indicates if the register is to be interpreted as SIMD
-  i.e. containing multiple contiguous elements of size equal to "bitwidth".
-  (Note: in earlier drafts this was in the Register CSR table.
-  However after extending to 7 bits there was not enough space.
-  To use "unpredicated" packed SIMD, set the predicate to x0 and
-  set "invert".  This has the effect of setting a predicate of all 1s)
-
-| PrCSR | 13     | 12     | 11    | 10  | (9..5)  | (4..0)  |
-| ----- | -      | -      | -     | -   | ------- | ------- |
-| 0     | bank0  | zero0  | inv0  | i/f | regidx  | predkey |
-| 1     | bank1  | zero1  | inv1  | i/f | regidx  | predkey |
-| ..    | bank.. | zero.. | inv.. | i/f | regidx  | predkey |
-| 15    | bank15 | zero15 | inv15 | i/f | regidx  | predkey |
-
-The Predication CSR Table is a key-value store, so implementation-wise
+
+16 bit format:
+
+| PrCSR | (15..11) | 10     | 9     | 8   | (7..1)  | 0       |
+| ----- | -        | -      | -     | -   | ------- | ------- |
+| 0     | predkey  | zero0  | inv0  | i/f | regidx  | rsrvd |
+| 1     | predkey  | zero1  | inv1  | i/f | regidx  | rsvd |
+| ...   | predkey  | .....  | ....  | i/f | ....... | ....... |
+| 15    | predkey  | zero15 | inv15 | i/f | regidx  | rsvd |
+
+
+8 bit format:
+
+| PrCSR | 7     | 6     | 5   | (4..0)  |
+| ----- | -     | -     | -   | ------- |
+| 0     | zero0 | inv0  | i/f | regnum  |
+
+The 8 bit format is a compact and less expressive variant of the full
+16 bit format.  Using the 8 bit formatis very different: the predicate
+register to use is implicit, and numbering begins inplicitly from x9. The
+regnum is still used to "activate" predication, in the same fashion as
+described above.
+
+The 16 bit Predication CSR Table is a key-value store, so implementation-wise
 it will be faster to turn the table around (maintain topologically
 equivalent state):
 
@@ -540,7 +556,7 @@ reference to the predication register to be used:
                 s2 ? vreg[rs2][i] : sreg[rs2]); // for insts with 2 inputs
 
 This instead becomes an *indirect* reference using the *internal* state
-table generated from the Predication CSR key-value store, which iwws used
+table generated from the Predication CSR key-value store, which is used
 as follows.
 
     if type(iop) == INT:
@@ -563,7 +579,7 @@ Note:
   source1 and source2 are vector or scalar
 * key-value CSR-redirection of rd, rs1 and rs2 have NOT been included
   above, for clarity.  rd, rs1 and rs2 all also must ALSO go through
-  register-level redirection (from the Register CSR table) if they are
+  register-level redirection (from the Register table) if they are
   vectors.
 
 If written as a function, obtaining the predication mask (and whether
@@ -583,24 +599,26 @@ zeroing takes place) may be done as follows:
        return predicate, tb[reg].zero
 
 Note here, critically, that **only** if the register is marked
-in its CSR **register** table entry as being "active" does the testing
-proceed further to check if the CSR **predicate** table entry is
+in its **register** table entry as being "active" does the testing
+proceed further to check if the **predicate** table entry is
 also active.
 
 Note also that this is in direct contrast to branch operations
 for the storage of comparisions: in these specific circumstances
-the requirement for there to be an active CSR *register* entry
+the requirement for there to be an active *register* entry
 is removed.
 
-## REMAP CSR
+## REMAP CSR <a name="remap" />
 
 (Note: both the REMAP and SHAPE sections are best read after the
  rest of the document has been read)
 
 There is one 32-bit CSR which may be used to indicate which registers,
 if used in any operation, must be "reshaped" (re-mapped) from a linear
-form to a 2D or 3D transposed form.  The 32-bit REMAP CSR may reshape
-up to 3 registers:
+form to a 2D or 3D transposed form, or "offset" to permit arbitrary
+access to elements within a register.
+
+The 32-bit REMAP CSR may reshape up to 3 registers:
 
 | 29..28 | 27..26 | 25..24 | 23 | 22..16  | 15 | 14..8   | 7  | 6..0    |
 | ------ | ------ | ------ | -- | ------- | -- | ------- | -- | ------- |
@@ -608,9 +626,16 @@ up to 3 registers:
 
 regidx0-2 refer not to the Register CSR CAM entry but to the underlying
 *real* register (see regidx, the value) and consequently is 7-bits wide.
+When set to zero (referring to x0), clearly reshaping x0 is pointless,
+so is used to indicate "disabled".
 shape0-2 refers to one of three SHAPE CSRs.  A value of 0x3 is reserved.
 Bits 7, 15, 23, 30 and 31 are also reserved, and must be set to zero.
 
+It is anticipated that these specialist CSRs not be very often used.
+Unlike the CSR Register and Predication tables, the REMAP CSRs use
+the full 7-bit regidx so that they can be set once and left alone,
+whilst the CSR Register entries pointing to them are disabled, instead.
+
 ## SHAPE 1D/2D/3D vector-matrix remapping CSRs
 
 (Note: both the REMAP and SHAPE sections are best read after the
@@ -620,9 +645,12 @@ There are three "shape" CSRs, SHAPE0, SHAPE1, SHAPE2, 32-bits in each,
 which have the same format.  When each SHAPE CSR is set entirely to zeros,
 remapping is disabled: the register's elements are a linear (1D) vector.
 
-| 26..24  | 23 | 22..16  | 15 | 14..8   | 7  | 6..0    |
-| ------- | -- | ------- | -- | ------- | -- | ------- |
-| permute | 0  | zdimsz  | 0  | ydimsz  | 0  | xdimsz  |
+| 26..24  | 23      | 22..16  | 15      | 14..8   | 7       | 6..0    |
+| ------- | --      | ------- | --      | ------- | --      | ------- |
+| permute | offs[2] | zdimsz  | offs[1] | ydimsz  | offs[0] | xdimsz  |
+
+offs is a 3-bit field, spread out across bits 7, 15 and 23, which
+is added to the element index during the loop calculation.
 
 xdimsz, ydimsz and zdimsz are offset by 1, such that a value of 0 indicates
 that the array dimensionality for that dimension is 1.  A value of xdimsz=2
@@ -657,9 +685,10 @@ shows this more clearly, and may be executed as a python program:
     lims = [xdim, ydim, zdim]
     idxs = [0,0,0] # starting indices
     order = [1,0,2] # experiment with different permutations, here
+    offs = 0        # experiment with different offsets, here
 
     for idx in range(xdim * ydim * zdim):
-        new_idx = idxs[0] + idxs[1] * xdim + idxs[2] * xdim * ydim
+        new_idx = offs + idxs[0] + idxs[1] * xdim + idxs[2] * xdim * ydim
         print new_idx,
         for i in range(3):
             idxs[order[i]] = idxs[order[i]] + 1
@@ -699,6 +728,11 @@ changed to target different registers.
 
 Note that:
 
+* Over-running the register file clearly has to be detected and
+  an illegal instruction exception thrown
+* When non-default elwidths are set, the exact same algorithm still
+  applies (i.e. it offsets elements *within* registers rather than
+  entire registers).
 * If permute option 000 is utilised, the actual order of the
   reindexing does not change!
 * If two or more dimensions are set to zero, the actual order does not change!
@@ -712,6 +746,11 @@ Note that:
   operands be remapped.  *This even includes C.LDSP* and other operations
   in that category, where in that case it will be the **offset** that is
   remapped (see Compressed Stack LOAD/STORE section).
+* Offset is especially useful, on its own, for accessing elements
+  within the middle of a register.  Without offsets, it is necessary
+  to either use a predicated MV, skipping the first elements, or
+  performing a LOAD/STORE cycle to memory.
+  With offsets, the data does not have to be moved.
 * Setting the total elements (xdim+1) times (ydim+1) times (zdim+1) to
   less than MVL is **perfectly legal**, albeit very obscure.  It permits
   entries to be regularly presented to operands **more than once**, thus
@@ -750,7 +789,7 @@ It is **purely** about compacting what would otherwise be contiguous
 instructions that use sequentially-increasing register numbers down
 to the **one** instruction.
 
-# Instructions
+# Instructions <a name="instructions" />
 
 Despite being a 98% complete and accurate topological remap of RVV
 concepts and functionality, no new instructions are needed.
@@ -775,16 +814,18 @@ With some exceptions, where it does not make sense or is simply too
 challenging, all RV-Base instructions are parallelised:
 
 * CSR instructions, whilst a case could be made for fast-polling of
-  a CSR into multiple registers, would require guarantees of strict
-  sequential ordering that SV does not provide.  Therefore, CSRs are
-  not really suitable and are left out.
+  a CSR into multiple registers, or for being able to copy multiple
+  contiguously addressed CSRs into contiguous registers, and so on,
+  are the fundamental core basis of SV.  If parallelised, extreme
+  care would need to be taken.  Additionally, CSR reads are done
+  using x0, and it is *really* inadviseable to tag x0.
 * LUI, C.J, C.JR, WFI, AUIPC are not suitable for parallelising so are
   left as scalar.
 * LR/SC could hypothetically be parallelised however their purpose is
   single (complex) atomic memory operations where the LR must be followed
   up by a matching SC.  A sequence of parallel LR instructions followed
   by a sequence of parallel SC instructions therefore is guaranteed to
-  not be useful. Not least: the guarantees of LR/SC
+  not be useful. Not least: the guarantees of a Multi-LR/SC
   would be impossible to provide if emulated in a trap.
 * EBREAK, NOP, FENCE and others do not use registers so are not inherently
   paralleliseable anyway.
@@ -810,16 +851,30 @@ Floating-point uses fp csrs.
         if (int_vec[rs1].isvector)  { irs1 += 1; }
         if (int_vec[rs2].isvector)  { irs2 += 1; }
 
+Note that for simplicity there is quite a lot missing from the above
+pseudo-code: element widths, zeroing on predication, dimensional
+reshaping and offsets and so on.  However it demonstrates the basic
+principle.  Augmentations that produce the full pseudo-code are covered in
+other sections.
+
 ## Instruction Format
 
-There are **no operations added to SV, at all**.
-Instead SV  *overloads* pre-existing branch operations into predicated
-variants, and implicitly overloads arithmetic operations, MV,
-FCVT, and LOAD/STORE
-depending on CSR configurations for bitwidth and
-predication.  **Everything** becomes parallelised.  *This includes
-Compressed instructions* as well as any
-future instructions and Custom Extensions.
+It is critical to appreciate that there are
+**no operations added to SV, at all**.
+
+Instead, by using CSRs to tag registers as an indication of "changed
+behaviour", SV *overloads* pre-existing branch operations into predicated
+variants, and implicitly overloads arithmetic operations, MV, FCVT, and
+LOAD/STORE depending on CSR configurations for bitwidth and predication.
+**Everything** becomes parallelised.  *This includes Compressed
+instructions* as well as any future instructions and Custom Extensions.
+
+Note: CSR tags to change behaviour of instructions is nothing new, including
+in RISC-V.  UXL, SXL and MXL change the behaviour so that XLEN=32/64/128.
+FRM changes the behaviour of the floating-point unit, to alter the rounding
+mode.  Other architectures change the LOAD/STORE byte-order from big-endian
+to little-endian on a per-instruction basis.  SV is just a little more...
+comprehensive in its effect on instructions.
 
 ## Branch Instructions
 
@@ -829,8 +884,10 @@ Branch operations use standard RV opcodes that are reinterpreted to
 be "predicate variants" in the instance where either of the two src
 registers are marked as vectors (active=1, vector=1).
 
-Note that he predication register to use (if one is enabled) is taken from
-the *first* src register.  The target (destination) predication register
+Note that the predication register to use (if one is enabled) is taken from
+the *first* src register, and that this is used, just as with predicated
+arithmetic operations, to mask whether the comparison operations take
+place or not.  The target (destination) predication register
 to use (if one is enabled) is taken from the *second* src register.
 
 If either of src1 or src2 are scalars (whether by there being no
@@ -844,6 +901,17 @@ Where vectorisation is present on either or both src registers, the
 branch may stil go ahead if any only if *all* tests succeed (i.e. excluding
 those tests that are predicated out).
 
+Note that when zero-predication is enabled (from source rs1),
+a cleared bit in the predicate indicates that the result
+of the compare is set to "false", i.e. that the corresponding
+destination bit (or result)) be set to zero.  Contrast this with
+when zeroing is not set: bits in the destination predicate are
+only *set*; they are **not** cleared.  This is important to appreciate,
+as there may be an expectation that, going into the hardware-loop,
+the destination predicate is always expected to be set to zero:
+this is **not** the case.  The destination predicate is only set
+to zero if **zeroing** is enabled.
+
 Note that just as with the standard (scalar, non-predicated) branch
 operations, BLE, BGT, BLEU and BTGU may be synthesised by inverting
 src1 and src2.
@@ -874,34 +942,46 @@ complex), this becomes:
     ps = get_pred_val(I/F==INT, rs1);
     rd = get_pred_val(I/F==INT, rs2); # this may not exist
 
-    if not exists(rd)
-        temporary_result = 0
+    if not exists(rd) or zeroing:
+        result = 0
     else
-        preg[rd] = 0; # initialise to zero
+        result = preg[rd]
 
     for (int i = 0; i < VL; ++i)
-      if (ps & (1<<i)) && (cmp(s1 ? reg[src1+i]:reg[src1],
+      if (zeroing)
+        if not (ps & (1<<i))
+           result &= ~(1<<i);
+      else if (ps & (1<<i))
+          if (cmp(s1 ? reg[src1+i]:reg[src1],
                                s2 ? reg[src2+i]:reg[src2])
-          if not exists(rd)
-              temporary_result |= 1<<i;
+              result |= 1<<i;
           else
-              preg[rd] |= 1<<i;  # bitfield not vector
+              result &= ~(1<<i);
 
      if not exists(rd)
-        if temporary_result == ps
+        if result == ps
             goto branch
      else
+        preg[rd] = result # store in destination
         if preg[rd] == ps
             goto branch
 
 Notes:
 
-* zeroing has been temporarily left out of the above pseudo-code,
-  for clarity
 * Predicated SIMD comparisons would break src1 and src2 further down
   into bitwidth-sized chunks (see Appendix "Bitwidth Virtual Register
   Reordering") setting Vector-Length times (number of SIMD elements) bits
   in Predicate Register rd, as opposed to just Vector-Length bits.
+* The execution of "parallelised" instructions **must** be implemented
+  as "re-entrant" (to use a term from software).  If an exception (trap)
+  occurs during the middle of a vectorised
+  Branch (now a SV predicated compare) operation, the partial results
+  of any comparisons must be written out to the destination
+  register before the trap is permitted to begin.  If however there
+  is no predicate, the **entire** set of comparisons must be **restarted**,
+  with the offset loop indices set back to zero.  This is because
+  there is no place to store the temporary result during the handling
+  of traps.
 
 TODO: predication now taken from src2.  also branch goes ahead
 if all compares are successful.
@@ -913,21 +993,43 @@ for branches this is **not** the case.  src2 does **not** have
 to have its CSR register entry marked as active in order for
 predication on src2 to be active.
 
+Also note: SV Branch operations are **not** twin-predicated
+(see Twin Predication section).  This would require three
+element offsets: one to track src1, one to track src2 and a third
+to track where to store the accumulation of the results.  Given
+that the element offsets need to be exposed via CSRs so that
+the parallel hardware looping may be made re-entrant on traps
+and exceptions, the decision was made not to make SV Branches
+twin-predicated.
+
 ### Floating-point Comparisons
 
 There does not exist floating-point branch operations, only compare.
 Interestingly no change is needed to the instruction format because
 FP Compare already stores a 1 or a zero in its "rd" integer register
 target, i.e. it's not actually a Branch at all: it's a compare.
-Thus, no change is made to the floating-point comparison, so
 
-It is however noted that an entry "FNE" (the opposite of FEQ) is missing,
+In RV (scalar) Base, a branch on a floating-point compare is
+done via the sequence "FEQ x1, f0, f5; BEQ x1, x0, #jumploc".
+This does extend to SV, as long as x1 (in the example sequence given)
+is vectorised.  When that is the case, x1..x(1+VL-1) will also be
+set to 0 or 1 depending on whether f0==f5, f1==f6, f2==f7 and so on.
+The BEQ that follows will *also* compare x1==x0, x2==x0, x3==x0 and
+so on.  Consequently, unlike integer-branch, FP Compare needs no
+modification in its behaviour.
+
+In addition, it is noted that an entry "FNE" (the opposite of FEQ) is missing,
 and whilst in ordinary branch code this is fine because the standard
 RVF compare can always be followed up with an integer BEQ or a BNE (or
 a compressed comparison to zero or non-zero), in predication terms that
 becomes more of an impact.  To deal with this, SV's predication has
 had "invert" added to it.
 
+Also: note that FP Compare may be predicated, using the destination
+integer register (rd) to determine the predicate.  FP Compare is **not**
+a twin-predication operation, as, again, just as with SV Branches,
+there are three registers involved: FP src1, FP src2 and INT rd.
+
 ### Compressed Branch Instruction
 
 Compressed Branch instructions are, just like standard Branch instructions,
@@ -1088,7 +1190,8 @@ Similar rules apply to the destination register.
 
 ## LOAD / STORE Instructions and LOAD-FP/STORE-FP <a name="load_store"></a>
 
-An earlier draft of SV modified the behaviour of LOAD/STORE.  This
+An earlier draft of SV modified the behaviour of LOAD/STORE (modified
+the interpretation of the instruction fields).  This
 actually undermined the fundamental principle of SV, namely that there
 be no modifications to the scalar behaviour (except where absolutely
 necessary), in order to simplify an implementor's task if considering
@@ -1096,74 +1199,88 @@ converting a pre-existing scalar design to support parallelism.
 
 So the original RISC-V scalar LOAD/STORE and LOAD-FP/STORE-FP functionality
 do not change in SV, however just as with C.MV it is important to note
-that dual-predication is possible.  Using the template outlined in
-the section "Vectorised dual-op instructions", the pseudo-code covering
-scalar-scalar, scalar-vector, vector-scalar and vector-vector applies,
-where SCALAR\_OPERATION is as follows, exactly as for a standard
-scalar RV LOAD operation:
-
-        srcbase = ireg[rs+i];
-        return mem[srcbase + imm];
-
-Whilst LOAD and STORE remain as-is when compared to their scalar
-counterparts, the incrementing on the source register (for LOAD)
-means that pointers-to-structures can be easily implemented, and
-if contiguous offsets are required, those pointers (the contents
-of the contiguous source registers) may simply be set up to point
-to contiguous locations.
+that dual-predication is possible.
+
+In vectorised architectures there are usually at least two different modes
+for LOAD/STORE:
+
+* Read (or write for STORE) from sequential locations, where one
+  register specifies the address, and the one address is incremented
+  by a fixed amount.  This is usually known as "Unit Stride" mode.
+* Read (or write) from multiple indirected addresses, where the
+  vector elements each specify separate and distinct addresses.
+
+To support these different addressing modes, the CSR Register "isvector"
+bit is used.  So, for a LOAD, when the src register is set to
+scalar, the LOADs are sequentially incremented by the src register
+element width, and when the src register is set to "vector", the
+elements are treated as indirection addresses.  Simplified
+pseudo-code would look like this:
+
+    function op_ld(rd, rs) # LD not VLD!
+      rdv = int_csr[rd].active ? int_csr[rd].regidx : rd;
+      rsv = int_csr[rs].active ? int_csr[rs].regidx : rs;
+      ps = get_pred_val(FALSE, rs); # predication on src
+      pd = get_pred_val(FALSE, rd); # ... AND on dest
+      for (int i = 0, int j = 0; i < VL && j < VL;):
+        if (int_csr[rs].isvec) while (!(ps & 1<<i)) i++;
+        if (int_csr[rd].isvec) while (!(pd & 1<<j)) j++;
+        if (int_csr[rd].isvec)
+          # indirect mode (multi mode)
+          srcbase = ireg[rsv+i];
+        else
+          # unit stride mode
+          srcbase = ireg[rsv] + i * XLEN/8; # offset in bytes
+        ireg[rdv+j] <= mem[srcbase + imm_offs];
+        if (!int_csr[rs].isvec &&
+            !int_csr[rd].isvec) break # scalar-scalar LD
+        if (int_csr[rs].isvec) i++;
+        if (int_csr[rd].isvec) j++;
+
+Notes:
+
+* For simplicity, zeroing and elwidth is not included in the above:
+  the key focus here is the decision-making for srcbase; vectorised
+  rs means use sequentially-numbered registers as the indirection
+  address, and scalar rs is "offset" mode.
+* The test towards the end for whether both source and destination are
+  scalar is what makes the above pseudo-code provide the "standard" RV
+  Base behaviour for LD operations.
+* The offset in bytes (XLEN/8) changes depending on whether the
+  operation is a LB (1 byte), LH (2 byes), LW (4 bytes) or LD
+  (8 bytes), and also whether the element width is over-ridden
+  (see special element width section).
 
 ## Compressed Stack LOAD / STORE Instructions <a name="c_ld_st"></a>
 
 C.LWSP / C.SWSP and floating-point etc. are also source-dest twin-predicated,
-where it is implicit in C.LWSP/FLWSP that x2 is the source register.
+where it is implicit in C.LWSP/FLWSP etc. that x2 is the source register.
 It is therefore possible to use predicated C.LWSP to efficiently
 pop registers off the stack (by predicating x2 as the source), cherry-picking
 which registers to store to (by predicating the destination).  Likewise
 for C.SWSP.  In this way, LOAD/STORE-Multiple is efficiently achieved.
 
-However, to do so, the behaviour of C.LWSP/C.SWSP needs to be slightly
-different: where x2 is marked as vectorised, instead of incrementing
-the register on each loop (x2, x3, x4...), instead it is the *immediate*
-that must be incremented.  Pseudo-code follows:
-
-    function lwsp(rd, rs):
-      rd = int_csr[rd].active ? int_csr[rd].regidx : rd;
-      rs = x2 # effectively no redirection on x2.
-      ps = get_pred_val(FALSE, rs); # predication on src
-      pd = get_pred_val(FALSE, rd); # ... AND on dest
-      for (int i = 0, int j = 0; i < VL && j < VL;):
-        if (int_csr[rs].isvec) while (!(ps & 1<<i)) i++;
-        if (int_csr[rd].isvec) while (!(pd & 1<<j)) j++;
-        reg[rd+j] = mem[x2 + ((offset+i) * 4)]
-        if (int_csr[rs].isvec) i++;
-        if (int_csr[rd].isvec) j++; else break;
-
-For C.LDSP, the offset (and loop) multiplier would be 8, and for
-C.LQSP it would be 16.  Effectively this makes C.LWSP etc. a Vector
-"Unit Stride" Load instruction.
+The two modes ("unit stride" and multi-indirection) are still supported,
+as with standard LD/ST.  Essentially, the only difference is that the
+use of x2 is hard-coded into the instruction.
 
 **Note**: it is still possible to redirect x2 to an alternative target
 register.  With care, this allows C.LWSP / C.SWSP (and C.FLWSP) to be used as
-general-purpose Vector "Unit Stride" LOAD/STORE operations.
+general-purpose LOAD/STORE operations.
 
 ## Compressed LOAD / STORE Instructions
 
 Compressed LOAD and STORE are again exactly the same as scalar LOAD/STORE,
 where the same rules apply and the same pseudo-code apply as for
-non-compressed LOAD/STORE.  This is **different** from Compressed Stack
-LOAD/STORE (C.LWSP / C.SWSP), which have been augmented to become
-Vector "Unit Stride" capable.
-
-Just as with uncompressed LOAD/STORE C.LD / C.ST increment the *register*
-during the hardware loop, **not** the offset.
+non-compressed LOAD/STORE.  Again: setting scalar or vector mode
+on the src for LOAD and dest for STORE switches mode from "Unit Stride"
+to "Multi-indirection", respectively.
 
 # Element bitwidth polymorphism <a name="elwidth"></a>
 
 Element bitwidth is best covered as its own special section, as it
 is quite involved and applies uniformly across-the-board.  SV restricts
-bitwidth polymorphism to default, default/2, default\*2 and 8-bit
-(whilst this seems limiting, the justification is covered in a later
-sub-section).
+bitwidth polymorphism to default, 8-bit, 16-bit and 32-bit.
 
 The effect of setting an element bitwidth is to re-cast each entry
 in the register table, and for all memory operations involving
@@ -1415,13 +1532,53 @@ to ensure a correct answer.  Example:
 * the maximum bitwidth is thus determined to be 16-bit - max(8,16)
 * RS2 is **truncated to a range of values from 0 to 15**: RS2 & (16-1)
 
-Pseudocode for this example would therefore be:
+Pseudocode (in spike) for this example would therefore be:
 
     WRITE_RD(sext_xlen(zext_16bit(RS1) << (RS2 & (16-1))));
 
 This example illustrates that considerable care therefore needs to be
 taken to ensure that left and right shift operations are implemented
-correctly.
+correctly.  The key is that
+
+* The operation bitwidth is determined by the maximum bitwidth
+  of the *source registers*, **not** the destination register bitwidth
+* The result is then sign-extend (or truncated) as appropriate.
+
+## Polymorphic MULH/MULHU/MULHSU
+
+MULH is designed to take the top half MSBs of a multiply that
+does not fit within the range of the source operands, such that
+smaller width operations may produce a full double-width multiply
+in two cycles.  The issue is: SV allows the source operands to
+have variable bitwidth.
+
+Here again special attention has to be paid to the rules regarding
+bitwidth, which, again, are that the operation is performed at
+the maximum bitwidth of the **source** registers.  Therefore:
+
+* An 8-bit x 8-bit multiply will create a 16-bit result that must
+  be shifted down by 8 bits
+* A 16-bit x 8-bit multiply will create a 24-bit result that must
+  be shifted down by 16 bits (top 8 bits being zero)
+* A 16-bit x 16-bit multiply will create a 32-bit result that must
+  be shifted down by 16 bits
+* A 32-bit x 16-bit multiply will create a 48-bit result that must
+  be shifted down by 32 bits
+* A 32-bit x 8-bit multiply will create a 40-bit result that must
+  be shifted down by 32 bits
+
+So again, just as with shift-left and shift-right, the result
+is shifted down by the maximum of the two source register bitwidths.
+And, exactly again, truncation or sign-extension is performed on the
+result.  If sign-extension is to be carried out, it is performed
+from the same maximum of the two source register bitwidths out
+to the result element's bitwidth.
+
+If truncation occurs, i.e. the top MSBs of the result are lost,
+this is "Officially Not Our Problem", i.e. it is assumed that the
+programmer actually desires the result to be truncated.  i.e. if the
+programmer wanted all of the bits, they would have set the destination
+elwidth to accommodate them.
 
 ## Polymorphic elwidth on LOAD/STORE <a name="elwidth_loadstore"></a>
 
@@ -1487,7 +1644,7 @@ As LOAD/STORE may be twin-predicated, it is important to note that
 the rules on twin predication still apply, except where in previous
 pseudo-code (elwidth=default for both source and target) it was
 the *registers* that the predication was applied to, it is now the
-**elements** that the predication are applied to.
+**elements** that the predication is applied to.
 
 Thus the full pseudocode for all LD operations may be written out
 as follows:
@@ -1547,33 +1704,91 @@ Note:
   is also marked as scalar, this is how the compatibility with
   standard RV LOAD/STORE is preserved by this algorithm.
 
-### Example Tables showing LOAD:
+### Example Tables showing LOAD elements
+
+This section contains examples of vectorised LOAD operations, showing
+how the two stage process works (three if zero/sign-extension is included).
 
-LH - 16-bit load, to elwidth 32-bit
 
-^ byte 0 ^ byte 1 ^ byte 2 ^ byte 3 ^ byte 4 ^ byte 5 ^ byte 6 ^ byte 7 ^
-| ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ |
-| elem 0         || elem 1         || elem 2         || elem 3         ||
-| elem 4         || elem 5         || elem 6         || elem 7         ||
+#### Example: LD x8, x5(0), x8 CSR-elwidth=32, x5 CSR-elwidth=16, VL=7
 
+This is:
+
+* a 64-bit load, with an offset of zero
+* with a source-address elwidth of 16-bit
+* into a destination-register with an elwidth of 32-bit
+* where VL=7
+* from register x5 (actually x5-x6) to x8 (actually x8 to half of x11)
+* RV64, where XLEN=64 is assumed.
+
+First, the memory table, which, due to the
+element width being 16 and the operation being LD (64), the 64-bits
+loaded from memory are subdivided into groups of **four** elements.
+And, with VL being 7 (deliberately to illustrate that this is reasonable
+and possible), the first four are sourced from the offset addresses pointed
+to by x5, and the next three from the ofset addresses pointed to by
+the next contiguous register, x6:
+
+[[!table  data="""
+addr | byte 0 | byte 1 | byte 2 | byte 3 | byte 4 | byte 5 | byte 6 | byte 7 |
+@x5  | elem 0         || elem 1         || elem 2         || elem 3         ||
+@x6  | elem 4         || elem 5         || elem 6         || not loaded     ||
+"""]]
+
+Next, the elements are zero-extended from 16-bit to 32-bit, as whilst
+the elwidth CSR entry for x5 is 16-bit, the destination elwidth on x8 is 32.
+
+[[!table  data="""
+byte 3 | byte 2 | byte 1 | byte 0 |
+0x0    | 0x0    | elem0          ||
+0x0    | 0x0    | elem1          ||
+0x0    | 0x0    | elem2          ||
+0x0    | 0x0    | elem3          ||
+0x0    | 0x0    | elem4          ||
+0x0    | 0x0    | elem5          ||
+0x0    | 0x0    | elem6          ||
+0x0    | 0x0    | elem7          ||
+"""]]
+
+Lastly, the elements are stored in contiguous blocks, as if x8 was also
+byte-addressable "memory".  That "memory" happens to cover registers
+x8, x9, x10 and x11, with the last 32 "bits" of x11 being **UNMODIFIED**:
+
+[[!table  data="""
+reg# | byte 7 | byte 6 | byte 5 | byte 4 | byte 3 | byte 2 | byte 1 | byte 0 |
+x8   | 0x0    | 0x0    | elem 1         || 0x0    | 0x0    | elem 0         ||
+x9   | 0x0    | 0x0    | elem 3         || 0x0    | 0x0    | elem 2         ||
+x10  | 0x0    | 0x0    | elem 5         || 0x0    | 0x0    | elem 4         ||
+x11  | **UNMODIFIED**                 |||| 0x0    | 0x0    | elem 6         ||
+"""]]
+
+Thus we have data that is loaded from the **addresses** pointed to by
+x5 and x6, zero-extended from 16-bit to 32-bit, stored in the **registers**
+x8 through to half of x11.
+The end result is that elements 0 and 1 end up in x8, with element 8 being
+shifted up 32 bits, and so on, until finally element 6 is in the
+LSBs of x11.
+
+Note that whilst the memory addressing table is shown left-to-right byte order,
+the registers are shown in right-to-left (MSB) order.  This does **not**
+imply that bit or byte-reversal is carried out: it's just easier to visualise
+memory as being contiguous bytes, and emphasises that registers are not
+really actually "memory" as such.
 
 ## Why SV bitwidth specification is restricted to 4 entries
 
 The four entries for SV element bitwidths only allows three over-rides:
 
-* default bitwidth for a given operation *divided* by two
-* default bitwidth for a given operation *multiplied* by two
-* 8-bit
+* 8 bit
+* 16 hit
+* 32 bit
 
-At first glance this seems completely inadequate: for example, RV64
-cannot possibly operate on 16-bit operations, because 64 divided by
-2 is 32.  However, the reader may have forgotten that it is possible,
-at run-time, to switch a 64-bit application into 32-bit mode, by
-setting UXL.  Once switched, opcodes that formerly had 64-bit
-meanings now have 32-bit meanings, and in this way, "default/2"
-now reaches **16-bit** where previously it meant "32-bit".
+This would seem inadequate, surely it would be better to have 3 bits or
+more and allow 64, 128 and some other options besides.  The answer here
+is, it gets too complex, no RV128 implementation yet exists, and so RV64's
+default is 64 bit, so the 4 major element widths are covered anyway.
 
-There is however an absolutely crucial aspect oF SV here that explicitly
+There is an absolutely crucial aspect oF SV here that explicitly
 needs spelling out, and it's whether the "vectorised" bit is set in
 the Register's CSR entry.
 
@@ -1588,10 +1803,26 @@ When vectorised is *set*, this indicates that the operation now treats
 the length, any parts of a given actual register that are not involved
 in the operation are **NOT** modified, but are **PRESERVED**.
 
+For example:
+
+* when the vector bit is clear and elwidth set to 16 on the destination
+  register, operations are truncated to 16 bit and then sign or zero
+  extended to the *FULL* XLEN register width.
+* when the vector bit is set, elwidth is 16 and VL=1 (or other value where
+  groups of elwidth sized elements do not fill an entire XLEN register),
+  the "top" bits of the destination register do *NOT* get modified, zero'd
+  or otherwise overwritten.
+
 SIMD micro-architectures may implement this by using predication on
 any elements in a given actual register that are beyond the end of
 multi-element operation.
 
+Other microarchitectures may choose to provide byte-level write-enable
+lines on the register file, such that each 64 bit register in an RV64
+system requires 8 WE lines.  Scalar RV64 operations would require
+activation of all 8 lines, where SV elwidth based operations would
+activate the required subset of those byte-level write lines.
+
 Example:
 
 * rs1, rs2 and rd are all set to 8-bit
@@ -1618,6 +1849,78 @@ Example SIMD micro-architectural implementation:
 This requires a read on rd, however this is required anyway in order
 to support non-zeroing mode.
 
+## Polymorphic floating-point
+
+Standard scalar RV integer operations base the register width on XLEN,
+which may be changed (UXL in USTATUS, and the corresponding MXL and
+SXL in MSTATUS and SSTATUS respectively).  Integer LOAD, STORE and
+arithmetic operations are therefore restricted to an active XLEN bits,
+with sign or zero extension to pad out the upper bits when XLEN has
+been dynamically set to less than the actual register size.
+
+For scalar floating-point, the active (used / changed) bits are
+specified exclusively by the operation: ADD.S specifies an active
+32-bits, with the upper bits of the source registers needing to
+be all 1s ("NaN-boxed"), and the destination upper bits being
+*set* to all 1s (including on LOAD/STOREs).
+
+Where elwidth is set to default (on any source or the destination)
+it is obvious that this NaN-boxing behaviour can and should be
+preserved.  When elwidth is non-default things are less obvious,
+so need to be thought through.  Here is a normal (scalar) sequence,
+assuming an RV64 which supports Quad (128-bit) FLEN:
+
+* FLD loads 64-bit wide from memory.  Top 64 MSBs are set to all 1s
+* ADD.D performs a 64-bit-wide add.  Top 64 MSBs of destination set to 1s.
+* FSD stores lowest 64-bits from the 128-bit-wide register to memory:
+  top 64 MSBs ignored.
+
+Therefore it makes sense to mirror this behaviour when, for example,
+elwidth is set to 32.  Assume elwidth set to 32 on all source and
+destination registers:
+
+* FLD loads 64-bit wide from memory as **two** 32-bit single-precision
+  floating-point numbers.
+* ADD.D performs **two** 32-bit-wide adds, storing one of the adds
+  in bits 0-31 and the second in bits 32-63.
+* FSD stores lowest 64-bits from the 128-bit-wide register to memory
+
+Here's the thing: it does not make sense to overwrite the top 64 MSBs
+of the registers either during the FLD **or** the ADD.D.  The reason
+is that, effectively, the top 64 MSBs actually represent a completely
+independent 64-bit register, so overwriting it is not only gratuitous
+but may actually be harmful for a future extension to SV which may
+have a way to directly access those top 64 bits.
+
+The decision is therefore **not** to touch the upper parts of floating-point
+registers whereever elwidth is set to non-default values, including
+when "isvec" is false in a given register's CSR entry.  Only when the
+elwidth is set to default **and** isvec is false will the standard
+RV behaviour be followed, namely that the upper bits be modified.
+
+Ultimately if elwidth is default and isvec false on *all* source
+and destination registers, a SimpleV instruction defaults completely
+to standard RV scalar behaviour (this holds true for **all** operations,
+right across the board).
+
+The nice thing here is that ADD.S, ADD.D and ADD.Q when elwidth are
+non-default values are effectively all the same: they all still perform
+multiple ADD operations, just at different widths.  A future extension
+to SimpleV may actually allow ADD.S to access the upper bits of the
+register, effectively breaking down a 128-bit register into a bank
+of 4 independently-accesible 32-bit registers.
+
+In the meantime, although when e.g. setting VL to 8 it would technically
+make no difference to the ALU whether ADD.S, ADD.D or ADD.Q is used,
+using ADD.Q may be an easy way to signal to the microarchitecture that
+it is to receive a higher VL value.  On a superscalar OoO architecture
+there may be absolutely no difference, however on simpler SIMD-style
+microarchitectures they may not necessarily have the infrastructure in
+place to know the difference, such that when VL=8 and an ADD.D instruction
+is issued, it completes in 2 cycles (or more) rather than one, where
+if an ADD.Q had been issued instead on such simpler microarchitectures
+it would complete in one.
+
 ## Specific instruction walk-throughs
 
 This section covers walk-throughs of the above-outlined procedure
@@ -1693,6 +1996,128 @@ Polymorphic variant:
 * add @ max(rs1, 12) bits
 * RD @ rd bits. sign-extend to rd if rd > max(rs1, 12) otherwise truncate
 
+# Predication Element Zeroing
+
+The introduction of zeroing on traditional vector predication is usually
+intended as an optimisation for lane-based microarchitectures with register
+renaming to be able to save power by avoiding a register read on elements
+that are passed through en-masse through the ALU.  Simpler microarchitectures
+do not have this issue: they simply do not pass the element through to
+the ALU at all, and therefore do not store it back in the destination.
+More complex non-lane-based micro-architectures can, when zeroing is
+not set, use the predication bits to simply avoid sending element-based
+operations to the ALUs, entirely: thus, over the long term, potentially
+keeping all ALUs 100% occupied even when elements are predicated out.
+
+SimpleV's design principle is not based on or influenced by
+microarchitectural design factors: it is a hardware-level API.
+Therefore, looking purely at whether zeroing is *useful* or not,
+(whether less instructions are needed for certain scenarios),
+given that a case can be made for zeroing *and* non-zeroing, the
+decision was taken to add support for both.
+
+## Single-predication (based on destination register)
+
+Zeroing on predication for arithmetic operations is taken from
+the destination register's predicate.  i.e. the predication *and*
+zeroing settings to be applied to the whole operation come from the
+CSR Predication table entry for the destination register.
+Thus when zeroing is set on predication of a destination element,
+if the predication bit is clear, then the destination element is *set*
+to zero (twin-predication is slightly different, and will be covered
+next).
+
+Thus the pseudo-code loop for a predicated arithmetic operation
+is modified to as follows:
+
+      for (i = 0; i < VL; i++)
+        if not zeroing: # an optimisation
+           while (!(predval & 1<<i) && i < VL)
+             if (int_vec[rd ].isvector)  { id += 1; }
+             if (int_vec[rs1].isvector)  { irs1 += 1; }
+             if (int_vec[rs2].isvector)  { irs2 += 1; }
+           if i == VL:
+             break
+        if (predval & 1<<i)
+           src1 = ....
+           src2 = ...
+           else:
+               result = src1 + src2 # actual add (or other op) here
+           set_polymorphed_reg(rd, destwid, ird, result)
+           if (!int_vec[rd].isvector) break
+        else if zeroing:
+           result = 0
+           set_polymorphed_reg(rd, destwid, ird, result)
+        if (int_vec[rd ].isvector)  { id += 1; }
+        else if (predval & 1<<i) break;
+        if (int_vec[rs1].isvector)  { irs1 += 1; }
+        if (int_vec[rs2].isvector)  { irs2 += 1; }
+
+The optimisation to skip elements entirely is only possible for certain
+micro-architectures when zeroing is not set.  However for lane-based
+micro-architectures this optimisation may not be practical, as it
+implies that elements end up in different "lanes".  Under these
+circumstances it is perfectly fine to simply have the lanes
+"inactive" for predicated elements, even though it results in
+less than 100% ALU utilisation.
+
+## Twin-predication (based on source and destination register)
+
+Twin-predication is not that much different, except that that
+the source is independently zero-predicated from the destination.
+This means that the source may be zero-predicated *or* the
+destination zero-predicated *or both*, or neither.
+
+When with twin-predication, zeroing is set on the source and not
+the destination, if a predicate bit is set it indicates that a zero
+data element is passed through the operation (the exception being:
+if the source data element is to be treated as an address - a LOAD -
+then the data returned *from* the LOAD is zero, rather than looking up an
+*address* of zero.
+
+When zeroing is set on the destination and not the source, then just
+as with single-predicated operations, a zero is stored into the destination
+element (or target memory address for a STORE).
+
+Zeroing on both source and destination effectively result in a bitwise
+NOR operation of the source and destination predicate: the result is that
+where either source predicate OR destination predicate is set to 0,
+a zero element will ultimately end up in the destination register.
+
+However: this may not necessarily be the case for all operations;
+implementors, particularly of custom instructions, clearly need to
+think through the implications in each and every case.
+
+Here is pseudo-code for a twin zero-predicated operation:
+
+    function op_mv(rd, rs) # MV not VMV!
+      rd = int_csr[rd].active ? int_csr[rd].regidx : rd;
+      rs = int_csr[rs].active ? int_csr[rs].regidx : rs;
+      ps, zerosrc = get_pred_val(FALSE, rs); # predication on src
+      pd, zerodst = get_pred_val(FALSE, rd); # ... AND on dest
+      for (int i = 0, int j = 0; i < VL && j < VL):
+        if (int_csr[rs].isvec && !zerosrc) while (!(ps & 1<<i)) i++;
+        if (int_csr[rd].isvec && !zerodst) while (!(pd & 1<<j)) j++;
+        if ((pd & 1<<j))
+            if ((pd & 1<<j))
+                sourcedata = ireg[rs+i];
+            else
+                sourcedata = 0
+            ireg[rd+j] <= sourcedata
+        else if (zerodst)
+            ireg[rd+j] <= 0
+        if (int_csr[rs].isvec)
+            i++;
+        if (int_csr[rd].isvec)
+            j++;
+        else
+            if ((pd & 1<<j))
+                break;
+
+Note that in the instance where the destination is a scalar, the hardware
+loop is ended the moment a value *or a zero* is placed into the destination
+register/element.  Also note that, for clarity, variable element widths
+have been left out of the above.
 
 # Exceptions
 
@@ -1728,6 +2153,169 @@ in as a *parameter* to the HINT operation.
 
 No specific hints are yet defined in Simple-V
 
+# VLIW Format <a name="vliw-format"></a>
+
+One issue with SV is the setup and teardown time of the CSRs.  The cost
+of the use of a full CSRRW (requiring LI) is quite high.  A VLIW format
+therefore makes sense.
+
+A suitable prefix, which fits the Expanded Instruction-Length encoding
+for "(80 + 16 times instruction_length)", as defined in Section 1.5
+of the RISC-V ISA, is as follows:
+
+| 15    | 14:12 | 11:10 | 9:8   | 7    | 6:0     |
+| -     | ----- | ----- | ----- | ---  | ------- |
+| vlset | 16xil | pplen | rplen | mode | 1111111 |
+
+An optional VL Block, optional predicate entries, optional register
+entries and finally some 16/32/48 bit standard RV or SVPrefix opcodes
+follow.
+
+The variable-length format from Section 1.5 of the RISC-V ISA:
+
+| base+4 ... base+2          | base             | number of bits             |
+| ------ -----------------   | ---------------- | -------------------------- |
+| ..xxxx  xxxxxxxxxxxxxxxx   | xnnnxxxxx1111111 | (80+16\*nnn)-bit, nnn!=111 |
+| {ops}{Pred}{Reg}{VL Block} | SV Prefix        |                            |
+
+VL/MAXVL/SubVL Block:
+
+| 31-30 | 29:28 | 27:22  | 21:17  - 16  |
+| -     | ----- | ------ | ------ - -   |
+| 0     | SubVL | VLdest | VLEN     vlt |
+| 1     | SubVL | VLdest | VLEN         |
+
+Note: this format is very similar to that used in [[sv_prefix_proposal]]
+
+If vlt is 0, VLEN is a 5 bit immediate value, offset by one (i.e
+a bit sequence of 0b00000 represents VL=1 and so on). If vlt is 1,
+it specifies the scalar register from which VL is set by this VLIW
+instruction group. VL, whether set from the register or the immediate,
+is then modified (truncated) to be MIN(VL, MAXVL), and the result stored
+in the scalar register specified in VLdest. If VLdest is zero, no store
+in the regfile occurs (however VL is still set).
+
+This option will typically be used to start vectorised loops, where
+the VLIW instruction effectively embeds an optional "SETSUBVL, SETVL"
+sequence (in compact form).
+
+When bit 15 is set to 1, MAXVL and VL are both set to the immediate,
+VLEN (again, offset by one), which is 6 bits in length, and the same
+value stored in scalar register VLdest (if that register is nonzero).
+A value of 0b000000 will set MAXVL=VL=1, a value of 0b000001 will
+set MAXVL=VL= 2 and so on.
+
+This option will typically not be used so much for loops as it will be
+for one-off instructions such as saving the entire register file to the
+stack with a single one-off Vectorised and predicated LD/ST, or as a way
+to save or restore registers in a function call with a single instruction.
+
+CSRs needed:
+
+* mepcvliw
+* sepcvliw
+* uepcvliw
+* hepcvliw
+
+Notes:
+
+* Bit 7 specifies if the prefix block format is the full 16 bit format
+  (1) or the compact less expressive format (0). In the 8 bit format,
+  pplen is multiplied by 2.
+* 8 bit format predicate numbering is implicit and begins from x9. Thus
+  it is critical to put blocks in the correct order as required.
+* Bit 7 also specifies if the register block format is 16 bit (1) or 8 bit
+  (0). In the 8 bit format, rplen is multiplied by 2. If only an odd number
+  of entries are needed the last may be set to 0x00, indicating "unused".
+* Bit 15 specifies if the VL Block is present. If set to 1, the VL Block
+  immediately follows the VLIW instruction Prefix
+* Bits 8 and 9 define how many RegCam entries (0 to 3 if bit 15 is 1,
+  otherwise 0 to 6) follow the (optional) VL Block.
+* Bits 10 and 11 define how many PredCam entries (0 to 3 if bit 7 is 1,
+  otherwise 0 to 6) follow the (optional) RegCam entries
+* Bits 14 to 12 (IL) define the actual length of the instruction: total
+  number of bits is 80 + 16 times IL.  Standard RV32, RVC and also
+  SVPrefix (P48/64-\*-Type) instructions fit into this space, after the
+  (optional) VL / RegCam / PredCam entries
+* Anything - any registers - within the VLIW-prefixed format *MUST* have the
+  RegCam and PredCam entries applied to it.
+* At the end of the VLIW Group, the RegCam and PredCam entries
+  *no longer apply*.  VL, MAXVL and SUBVL on the other hand remain at
+  the values set by the last instruction (whether a CSRRW or the VL
+  Block header).
+* Although an inefficient use of resources, it is fine to set the MAXVL,
+  VL and SUBVL CSRs with standard CSRRW instructions, within a VLIW block.
+
+All this would greatly reduce the amount of space utilised by Vectorised
+instructions, given that 64-bit CSRRW requires 3, even 4 32-bit opcodes: the
+CSR itself, a LI, and the setting up of the value into the RS register
+of the CSR, which, again, requires a LI / LUI to get the 32 bit
+data into the CSR.  To get 64-bit data into the register in order to put
+it into the CSR(s), LOAD operations from memory are needed!
+
+Given that each 64-bit CSR can hold only 4x PredCAM entries (or 4 RegCAM
+entries), that's potentially 6 to eight 32-bit instructions, just to
+establish the Vector State!
+
+Not only that: even CSRRW on VL and MAXVL requires 64-bits (even more bits if
+VL needs to be set to greater than 32).  Bear in mind that in SV, both MAXVL
+and VL need to be set.
+
+By contrast, the VLIW prefix is only 16 bits, the VL/MAX/SubVL block is
+only 16 bits, and as long as not too many predicates and register vector
+qualifiers are specified, several 32-bit and 16-bit opcodes can fit into
+the format. If the full flexibility of the 16 bit block formats are not
+needed, more space is saved by using the 8 bit formats.
+
+In this light, embedding the VL/MAXVL, PredCam and RegCam CSR entries into
+a VLIW format makes a lot of sense.
+
+Open Questions:
+
+* Is it necessary to stick to the RISC-V 1.5 format?  Why not go with
+  using the 15th bit to allow 80 + 16\*0bnnnn bits?  Perhaps to be sane,
+  limit to 256 bits (16 times 0-11).
+* Could a "hint" be used to set which operations are parallel and which
+  are sequential?
+* Could a new sub-instruction opcode format be used, one that does not
+  conform precisely to RISC-V rules, but *unpacks* to RISC-V opcodes?
+  no need for byte or bit-alignment
+* Could a hardware compression algorithm be deployed?  Quite likely,
+  because of the sub-execution context (sub-VLIW PC)
+
+## Limitations on instructions.
+
+To greatly simplify implementations, it is required to treat the VLIW
+group as a separate sub-program with its own separate PC. The sub-pc
+advances separately whilst the main PC remains pointing at the beginning
+of the VLIW instruction (not to be confused with how VL works, which
+is exactly the same principle, except it is VStart in the STATE CSR
+that increments).
+
+This has implications, namely that a new set of CSRs identical to xepc
+(mepc, srpc, hepc and uepc) must be created and managed and respected
+as being a sub extension of the xepc set of CSRs.  Thus, xepcvliw CSRs
+must be context switched and saved / restored in traps.
+
+The VStart indices in the STATE CSR may be similarly regarded as another
+sub-execution context, giving in effect two sets of nested sub-levels
+of the RISCV Program Counter.
+
+In addition, as xepcvliw CSRs are relative to the beginning of the VLIW
+block, branches MUST be restricted to within the block, i.e. addressing
+is now restricted to the start (and very short) length of the block.
+
+Also: calling subroutines is inadviseable, unless they can be entirely
+accomplished within a block.
+
+A normal jump and a normal function call may only be taken by letting
+the VLIW end, returning to "normal" standard RV mode, using RVC, 32 bit
+or P48/64-\*-type opcodes.
+
+## Links
+
+* <https://groups.google.com/d/msg/comp.arch/yIFmee-Cx-c/jRcf0evSAAAJ>
+
 # Subsets of RV functionality
 
 This section describes the differences when SV is implemented on top of
@@ -1749,16 +2337,13 @@ actually specifically an "option" it is worth noting.
 ## RV32G
 
 Normally in standard RV32 it does not make much sense to have
-RV32G, however it is automatically implied to exist in RV32+SV due to
-the option for the element width to be doubled.  This may be sufficient
-for implementors, such that actually needing RV32G itself (which makes
-no sense given that the RV32 integer register file is 32-bit) may be
-redundant.
+RV32G, The critical instructions that are missing in standard RV32
+are those for moving data to and from the double-width floating-point
+registers into the integer ones, as well as the FCVT routines.
 
-It is a strange combination that may make sense on closer inspection,
-particularly given that under the standard RV32 system many of the opcodes
-to convert and sign-extend 64-bit integers to 64-bit floating-point will
-be missing, as they are assumed to only be present in an RV64 context.
+In an earlier draft of SV, it was possible to specify an elwidth
+of double the standard register size: this had to be dropped,
+and may be reintroduced in future revisions.
 
 ## RV32 (not RV32F / RV32G) and RV64 (not RV64F / RV64G)
 
@@ -1828,11 +2413,10 @@ answer: they're not vectorised, so not a problem
 
 ---
 
-TODO: update elwidth to be default / 8 / 16 / 32
-
----
-
 TODO: document different lengths for INT / FP regfiles, and provide
 as part of info register. 00=32, 01=64, 10=128, 11=reserved.
 
+---
 
+TODO, update to remove RegCam and PredCam CSRs, just use SVprefix and
+VLIW format