(no commit message)
[libreriscv.git] / simple_v_extension / specification.mdwn
index d519e8a8574a6f445c4d2cf20d0f79b8d83bd49a..0d164f72cad2eeea934c1e067810ebc6925fc203 100644 (file)
@@ -1,9 +1,9 @@
 # Simple-V (Parallelism Extension Proposal) Specification
 
-* Copyright (C) 2017, 2018 Luke Kenneth Casson Leighton
-* Status: DRAFTv0.4
-* Last edited: 14 nov 2018
-* Ancillary resource: [[opcodes]]
+* Copyright (C) 2017, 2018, 2019 Luke Kenneth Casson Leighton
+* Status: DRAFTv0.6
+* Last edited: 21 jun 2019
+* Ancillary resource: [[opcodes]] [[sv_prefix_proposal]]
 
 With thanks to:
 
@@ -24,10 +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.
+goals being to reduce executable size (by extending the effectiveness of RV opcodes, RVC in particular) 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
@@ -75,65 +75,82 @@ when and whether to parallelise operations **entirely to the implementor**.
 
 The principle of SV is as follows:
 
-* CSRs indicating which registers are "tagged" as "vectorised"
-  (potentially parallel, depending on the microarchitecture)
-  must be 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, and element widths
+  overridden on any src or dest register.
 * 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
-  using contiguous sequentially-incrementing registers.
-  **Whether they be executed sequentially or in parallel or a
+* 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 five additional CSRs, available in any privilege level:
 
-* 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,
+* SUBVL (effectively a kind of SIMD)
+* STATE (containing copies of MVL, VL and SUBVL as well as context information)
+* PCVLIW (the current operation being executed within a VLIW Group)
+
+For User Mode there are the following CSRs:
+
+* uePCVLIW (a copy of the sub-execution Program Counter, that is relative
+  to the start of the current VLIW Group, set on a trap).
+* ueSTATE (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 two additional CSRs for Supervisor-Mode:
 
-* SMVL
-* SVL
-* SSTATE
+* sePCVLIW
+* seSTATE
 
 And likewise for M-Mode:
 
-* MMVL
-* MVL
-* MSTATE
+* mePCVLIW
+* meSTATE
+
+The u/m/s CSRs are treated and handled exactly like their (x)epc
+equivalents. On entry to a privilege level, the contents of its (x)eSTATE
+and (x)ePCVLIW CSRs are copied into STATE and PCVLIW respectively, and
+on exit from a priv level the STATE and PCVLIW CSRs are copied to the
+exited priv level's corresponding CSRs.
+
+Thus for example, a User Mode trap will end up swapping STATE and ueSTATE
+(on both entry and exit), allowing User Mode traps to have their own
+Vectorisation Context set up, separated from and unaffected by normal
+user applications.
 
-Both Supervisor and M-Mode have their own (small) CSR register and
-predication tables of only 4 entries each.
+Likewise, Supervisor Mode may perform context-switches, safe in the
+knowledge that its Vectorisation State is unaffected by User Mode.
+
+For this to work, the (x)eSTATE CSR must be saved onto the stack by the
+trap, just like (x)epc, before modifying the trap atomicity flag (x)ie.
 
 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":
 
 * 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 identical
+* 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
@@ -143,60 +160,24 @@ 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.
 
-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*, without the need for
-re-initialising the CSRs needed to do so.
-
-## 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.
-
-| (4..3) | (2...0) |
-| ------ | ------- |
-| size   | bank    |
-
-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.
-
-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:
-
-| size   | elements |
-| ------ | -------- |
-| 0      | 2        |
-| 1      | 4        |
-| 2      | 8        |
-| 3      | 16       |
-
-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.
-
-Examples:
-
-* 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 = 1, SVREGCFG3-4 and SVPREDCFG3-4 are enabled.
-* When bank = 7 and size = 1, SVREGCFG7 and SVPREDCFG7 are enabled
-  (because there are only 8 32-bit CSRs there does not exist a
-  SVREGCFG8 or SVPREDCFG8 to enable).
-* 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.
+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.
+
+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).  If the
+SVPrefix P64-LD-type format is used, LOAD-MULTI may even be done with a
+single standalone 64 bit opcode (P64 may set up both VL and MVL from an
+immediate field). It can even be predicated, which opens up some very
+interesting possibilities.
+
+The (x)EPCVLIW CSRs must be treated exactly like their corresponding (x)epc
+equivalents. See VLIW section for details.
 
 ## MAXVECTORLENGTH (MVL) <a name="mvl" />
 
@@ -206,19 +187,19 @@ however limited to the regfile bitwidth XLEN (1-32 for RV32,
 1-64 for RV64 and so on).
 
 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"
+marked as such, may fit into a single register as opposed to fanning
+out over several registers.  This keeps the hardware implementation a
+little simpler.
+
+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) <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)
@@ -234,10 +215,7 @@ Appendix, "Context Switch Example").  The reason for limiting VL to XLEN
 is down to the fact that predication bits fit into a single register of
 length XLEN bits.
 
-The second change is that when VSETVL is requested to be stored
-into x0, it is *ignored* silently (VSETVL x0, x5)
-
-The third and most important change is that, within the limits set by
+The second and most important change is that, within the limits set by
 MVL, the value passed in **must** be set in VL (and in the
 destination register).
 
@@ -260,72 +238,160 @@ hardware-parallelism in the ALUs is not deployed.  A hybrid is also
 permitted (as used in Broadcom's VideoCore-IV) however this must be
 *entirely* transparent to the ISA.
 
-The fourth change is that VSETVL is implemented as a CSR, where the
+The third change is that VSETVL is implemented as a CSR, where the
 behaviour of CSRRW (and CSRRWI) must be changed to specifically store
 the *new* value in the destination register, **not** the old value.
 Where context-load/save is to be implemented in the usual fashion
 by using a single CSRRW instruction to obtain the old value, the
-*secondary* CSR must be used (SVSTATE).  This CSR behaves
+*secondary* CSR must be used (STATE).  This CSR by contrast behaves
 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, vector operations cease (but not subvector
+operations: that requires setting SUBVL=1) the hardware loop is reduced
+to a single element: scalar operations.  This is in effect the default,
+normal operating mode. However it is important to appreciate that this
+does **not** result in the Register table or SUBVL being disabled. Only
+when the Register table is empty (P48/64 prefix fields notwithstanding)
+would SV have no effect.
+
+## SUBVL - Sub Vector Length
+
+This is a "group by quantity" that effectivrly asks each iteration
+of the hardware loop to load SUBVL elements of width elwidth at a
+time. Effectively, SUBVL is like a SIMD multiplier: instead of just 1
+operation issued, SUBVL operations are issued.
+
+Another way to view SUBVL is that each element in the VL length vector is
+now SUBVL times elwidth bits in length and now comprises SUBVL discrete
+sub operations.  An inner SUBVL for-loop within a VL for-loop in effect,
+with the sub-element increased every time in the innermost loop. This
+is best illustrated in the (simplified) pseudocode example, later.
+
+The primary use case for SUBVL is for 3D FP Vectors. A Vector of 3D
+coordinates X,Y,Z for example may be loaded and multiplied the stored, per
+VL element iteration, rather than having to set VL to three times larger.
+
+Legal values are 1, 2, 3 and 4 (and the STATE CSR must hold the 2 bit
+values 0b00 thru 0b11 to represent them).
+
+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.
+
+See SUBVL Pseudocode illustration for details.
 
 ## 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 or using the offset mode of the REMAP CSRs.
+full context save/restore.  It contains (and permits setting of):
+
+* MVL
+* VL
+* destoffs - the destination element offset of the current parallel
+  instruction being executed
+* srcoffs - for twin-predication, the source element offset as well.
+* SUBVL
+* svdestoffs - the subvector destination element offset of the current
+  parallel instruction being executed
+* svsrcoffs - for twin-predication, the subvector source element offset
+  as well.
+
+Interestingly STATE may hypothetically also be modified to make the
+immediately-following instruction to skip a certain number of elements,
+by playing with destoffs and srcoffs (and the subvector offsets as well)
 
 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
-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).
+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, meSTATE
+and seSTATE).
 
 The format of the STATE CSR is as follows:
 
-| (28..27) | (26..24) | (23..18) | (17..12) | (11..6) | (5...0) |
-| -------- | -------- | -------- | -------- | ------- | ------- |
-| size     | bank     | destoffs | srcoffs  | vl      | maxvl   |
+| (29..28 | (27..26) | (25..24) | (23..18) | (17..12) | (11..6) | (5...0) |
+| ------- | -------- | -------- | -------- | -------- | ------- | ------- |
+| dsvoffs | ssvoffs  | 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 there
+  are no changes needed
 * **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
+* **ssvoffs** will be truncated to be within the range 0 to SUBVL-1
+* **dsvoffs** will be truncated to be within the range 0 to SUBVL-1
 
-## MVL, VL and CSR Pseudocode
+NOTE: if the following instruction is not a twin predicated instruction,
+and destoffs or dsvoffs has been set to non-zero, subsequent execution
+behaviour is undefined. **USE WITH CARE**.
 
-The pseudo-code for get and set of VL and MVL are as follows:
+### Hardware rules for when to increment STATE offsets
+
+The offsets inside STATE are like the indices in a loop, except
+in hardware. They are also partially (conceptually) similar to a
+"sub-execution Program Counter". As such, and to allow proper context
+switching and to define correct exception behaviour, the following rules
+must be observed:
+
+* When the VL CSR is set, srcoffs and destoffs are reset to zero.
+* Each instruction that contains a "tagged" register shall start
+  execution at the *current* value of srcoffs (and destoffs in the case
+  of twin predication)
+* Unpredicated bits (in nonzeroing mode) shall cause the element operation
+  to skip, incrementing the srcoffs (or destoffs)
+* On execution of an element operation, Exceptions shall **NOT** cause
+  srcoffs or destoffs to increment.
+* On completion of the full Vector Loop (srcoffs = VL-1 or destoffs =
+  VL-1 after the last element is executed), both srcoffs and destoffs
+  shall be reset to zero.
+
+This latter is why srcoffs and destoffs may be stored as values from
+0 to XLEN-1 in the STATE CSR, because as loop indices they refer to
+elements. srcoffs and destoffs never need to be set to VL: their maximum
+operating values are limited to 0 to VL-1.
+
+The same corresponding rules apply to SUBVL, svsrcoffs and svdestoffs.
+
+## MVL and VL Pseudocode
+
+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
-        MVL = MIN(value, MVL)
+        regs[rd] = STATE.MVL
+        STATE.MVL = MIN(value, STATE.MVL)
 
     get_mvl_csr(rd):
-        regs[rd] = VL
+        regs[rd] = STATE.VL
 
     set_vl_csr(value, rd):
-        VL = MIN(value, MVL)
-        regs[rd] = VL # yes returning the new value NOT the old CSR
+        STATE.VL = MIN(value, STATE.MVL)
+        regs[rd] = STATE.VL # yes returning the new value NOT the old CSR
+        return STATE.VL
 
     get_vl_csr(rd):
-        regs[rd] = VL
+        regs[rd] = STATE.VL
+        return STATE.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,
@@ -337,20 +403,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.
+not capable of storing 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)
 
@@ -382,15 +448,14 @@ VL==1, "00001" represents VL==2 and so on (likewise for MVL):
     CSRRW_Set_SV_STATE(rs1, rd):
         value = regs[rs1]
         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
+        STATE.MVL = set_mvl_csr(value[11:6]+1)
+        STATE.VL = set_vl_csr(value[5:0]+1)
+        STATE.destoffs = value[23:18]>>18
+        STATE.srcoffs = value[23:18]>>12
 
     get_state_csr(rd):
-        regs[rd] = (MVL-1) | (VL-1)<<6 | (srcoffs)<<12 |
-                   (destoffs)<<18 | (CFG)<<24
+        regs[rd] = (STATE.MVL-1) | (STATE.VL-1)<<6 | (STATE.srcoffs)<<12 |
+                   (STATE.destoffs)<<18
         return regs[rd]
 
 In both cases, whilst CSR read of VL and MVL return the exact values
@@ -398,32 +463,85 @@ 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 <a name="regcsrtable" />
+## VL, MVL and SUBVL instruction aliases
+
+This table contains pseudo-assembly instruction aliases. Note the
+subtraction of 1 from the CSRRWI pseudo variants, to compensate for the
+reduced range of the 5 bit immediate.
 
-The purpose of the Register CSR table is four-fold:
+| alias           | CSR                  |
+| -               | -                    |
+| SETVL rd, rs    | CSRRW  VL, rd, rs    |
+| SETVLi rd, #n   | CSRRWI VL, rd, #n-1  |
+| GETVL rd        | CSRRW  VL, rd, x0    |
+| SETMVL rd, rs   | CSRRW  MVL, rd, rs   |
+| SETMVLi rd, #n  | CSRRWI MVL,rd, #n-1  |
+| GETMVL rd       | CSRRW  MVL, rd, x0   |
+
+Note: CSRRC and other bitsetting may still be used, they are however not particularly useful (very obscure).
+
+## Register key-value (CAM) table <a name="regcsrtable" />
+
+*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. Note
+that this table does *not* get applied to the SVPrefix P48/64 format,
+only to scalar opcodes*
+
+The purpose of the Register table is three-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
+  such that **unmodified** operands with 5 bits (3 for some RVC ops) may
   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.
 
-TODO: update
+Note: clearly, if an RVC operation uses a 3 bit spec'd register (x8-x15)
+and the Register table contains entried that only refer to registerd
+x1-x14 or x16-x31, such operations will *never* activate the VL hardware
+loop!
+
+If however the (16 bit) Register table does contain such an entry (x8-x15
+or x2 in the case of LWSP), that src or dest reg may be redirected
+anywhere to the *full* 128 register range. Thus, RVC becomes far more
+powerful and has many more opportunities to reduce code size that in
+Standard RV32/RV64 executables.
+
+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  |
-
-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
+| ------ | | -        | -        | -   | ------ | ------- |
+| 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.
+
+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 SVPrefix 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 (only 5 bits for regnum) 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            |
@@ -438,131 +556,37 @@ As the above table is a CAM (key-value store) it may be appropriate
 
     struct vectorised fp_vec[32], int_vec[32];
 
-    for (i = 0; i < 16; i++) // 16 CSRs?
+    for (i = 0; i < len; i++) // from VLIW Format
        tb = int_vec if CSRvec[i].type == 0 else fp_vec
        idx = CSRvec[i].regkey // INT/FP src/dst reg in opcode
        tb[idx].elwidth  = CSRvec[i].elwidth
        tb[idx].regidx   = CSRvec[i].regidx  // indirection
        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.
-
-There are two CSRs (per privilege level) for adding to and removing
-entries from the table, which, conceptually may be viewed as either
-a register window (similar to SPARC) or as the "top of a stack".
-
-* SVREGTOP will push or pop entries onto the top of the "stack"
-  (highest non-zero indexed entry in the table)
-* SVREGBOT will push or pop entries from the bottom (always
-  element indexed as zero.
-
-In addition, note that CSRRWI behaviour is completely different
-from CSRRW when writing to these two CSR registers.  The CSRRW
-behaviour: the src register is subdivided into 16-bit chunks,
-and each non-zero chunk is pushed/popped separately.  The
-CSRRWI behaviour: the immediate indicates the number of
-entries in the table to be popped.
-
-CSRRWI:
-
-* The src register indicates how many entries to pop from the
-  CAM table.
-* "CSRRWI SVREGTOP, 3" indicates that the top 3
-  entries are to be zero'd and returned as the CSR return
-  result.  The top entry is returned in bits 0-15, the
-  next entry down in bits 16-31, and when XLEN==64, an
-  extra 2 entries are also returned.
-* "CSRRWI SVREGBOT, 3" indicates that the bottom 3 entries are
-  to be returned, and the entries with indices above 3 are
-  to be shuffled down.  The first entry to be popped off the
-  bottom is returned in bits 0-15, the second entry as bits
-  16-31 and so on.
-* If XLEN==32, only a maximum of 2 entries may be returned
-  (and shuffled).  If XLEN==64, only a maximum of 4 entries
-  may be returned
-* If however the destination register is x0 (zero), then
-  the exact number of entries requested will be removed
-  (shuffled down).
-
-CSRRW when src == 0:
-
-* When the src register is all zeros, this is a request to
-  pop one and only one 16-bit element from the table.
-* "CSRRW SVREGTOP, 0" will return (and clear) the highest
-  non-zero 16-bit entry in the table
-* "CSRRW SVREGBOT, 0" will return (and clear) the zero'th
-  16-bit entry in the table, and will shuffle down all
-  other entries (if any) by one index.
-
-CSRRW when src != 0:
-
-All other CSRRW behaviours are a "loop", taking 16-bits
-at a time from the src register.  Obviously, for XLEN=32
-that can only be up to 2 16-bit entries, however for XLEN=64
-it can be up to 4.
-
-* When the src 16-bit chunk is non-zero and there already exists
-  an entry with the exact same "regkey" (bits 0-4), the
-  entry is **updated**.  No other modifications are made.
-* When the 16-bit chunk is non-zero and there does not exist
-  an entry, the new value will be placed at the end
-  (in the highest non-zero slot), or at the beginning
-  (shuffling up all other entries to make room).
-* If there is not enough room, the entry at the opposite
-  end will become part of the CSR return result.
-* The process is repeated for the next 16-bit chunk (starting
-  with bits 0-15 and moving next to 16-31 and so on), until
-  the limit of XLEN is reached or a chunk is all-zeros, at
-  which point the looping stops.
-* Any 16-bit entries that are pushed out of the stack
-  (from either end) are concatenated in order (first entry
-  pushed out is bits 0-15 of the return result).
-
-What this behaviour basically does is allow the CAM table to
-effectively be like the top entries of a stack.  Entries that
-get returned from CSRRW SVREGTOP can be *actually* stored on the stack,
-such that after a function call exits, CSRRWI SVREGTOP may be used
-to delete the callee's CAM entries, and the caller's entries may then
-be pushed *back*, using CSRRW SVREGBOT.
-
-Context-switching may be carried out in a loop, where CSRRWI may
-be called to "pop" values that are tested for being non-zero, and
-transferred onto the stack with C.SWSP using only around 4-5 instructions.
-CSRRW may then be used in combination with C.LWSP to get the CAM entries
-off the stack and back into the CAM table, again with a loop using
-only around 4-5 instructions.
-
-Contrast this with needing around 6-7 instructions (8-9 without SV on
-RV64, and 16-17 on RV32) to do a context-switch of fixed-address CSRs:
-a sequence of fixed-address C.LWSP with fixed offsets plus fixed-address
-CSRRWs, and that is without testing if any of the entries are zero
-or not.
-
-## Predication CSR <a name="predication_csr_table"></a>
-
-TODO: update CSR tables, now 7-bit for regidx
-
-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
+
+## Predication Table <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. 
+The table does **not** apply to SVPrefix opcodes*
+
+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.
+
+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,
-  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).
+* 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 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*
@@ -572,39 +596,65 @@ 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
-it will be faster to turn the table around (maintain topologically
-equivalent state):
+* ffirst is a special mode that stops sequential element processing when
+  a data-dependent condition occurs, whether a trap or a conditional test.
+  The handling of each (trap or conditional test) is slightly different:
+  see Instruction sections for further details
+
+16 bit format:
+
+| PrCSR | (15..11) | 10     | 9     | 8   | (7..1)  | 0       |
+| ----- | -        | -      | -     | -   | ------- | ------- |
+| 0     | predidx  | zero0  | inv0  | i/f | regidx  | ffirst0 |
+| 1     | predidx  | zero1  | inv1  | i/f | regidx  | ffirst1 |
+| 2     | predidx  | zero2  | inv2  | i/f | regidx  | ffirst2 |
+| 3     | predidx  | zero3  | inv3  | i/f | regidx  | ffirst3 |
+
+Note: predidx=x0, zero=1, inv=1 is a RESERVED encoding.  Its use must
+generate an illegal instruction trap.
+
+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.
+
+Thus if we map from 8 to 16 bit format, the table becomes:
+
+| PrCSR | (15..11) | 10     | 9     | 8   | (7..1)  | 0       |
+| ----- | -        | -      | -     | -   | ------- | ------- |
+| 0     | x9       | zero0  | inv0  | i/f | regnum  | ff=0    |
+| 1     | x10      | zero1  | inv1  | i/f | regnum  | ff=0    |
+| 2     | x11      | zero2  | inv2  | i/f | regnum  | ff=0    |
+| 3     | x12      | zero3  | inv3  | i/f | regnum  | ff=0    |
+
+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):
 
     struct pred {
-        bool zero;
-        bool inv;
-        bool enabled;
-        int predidx; // redirection: actual int register to use
+        bool zero;    // zeroing
+        bool inv;     // register at predidx is inverted
+        bool ffirst;  // fail-on-first
+        bool enabled; // use this to tell if the table-entry is active
+        int predidx;  // redirection: actual int register to use
     }
 
     struct pred fp_pred_reg[32];   // 64 in future (bank=1)
     struct pred int_pred_reg[32];  // 64 in future (bank=1)
 
-    for (i = 0; i < 16; i++)
-      tb = int_pred_reg if CSRpred[i].type == 0 else fp_pred_reg;
-      idx = CSRpred[i].regidx
-      tb[idx].zero = CSRpred[i].zero
-      tb[idx].inv  = CSRpred[i].inv
+    for (i = 0; i < len; i++) // number of Predication entries in VBLOCK
+      tb = int_pred_reg if PredicateTable[i].type == 0 else fp_pred_reg;
+      idx = PredicateTable[i].regidx
+      tb[idx].zero     = CSRpred[i].zero
+      tb[idx].inv      = CSRpred[i].inv
+      tb[idx].ffirst   = CSRpred[i].ffirst
       tb[idx].predidx  = CSRpred[i].predidx
       tb[idx].enabled  = true
 
@@ -620,7 +670,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:
@@ -631,9 +681,12 @@ as follows.
     for (int i=0; i<vl; ++i)
         predicate, zeroing = get_pred_val(type(iop) == INT, rd):
         if (predicate && (1<<i))
-           (d ? regfile[rd+i] : regfile[rd]) =
-            iop(s1 ? regfile[rs1+i] : regfile[rs1],
-                s2 ? regfile[rs2+i] : regfile[rs2]); // for insts with 2 inputs
+           result = iop(s1 ? regfile[rs1+i] : regfile[rs1],
+                        s2 ? regfile[rs2+i] : regfile[rs2]);
+           (d ? regfile[rd+i] : regfile[rd]) = result
+           if preg.ffirst and result == 0:
+              VL = i # result was zero, end loop early, return VL
+              return
         else if (zeroing)
            (d ? regfile[rd+i] : regfile[rd]) = 0
 
@@ -643,8 +696,11 @@ 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.
+* fail-on-first mode stops execution early whenever an operation
+  returns a zero value.  floating-point results count both
+  positive-zero as well as negative-zero as "fail".
 
 If written as a function, obtaining the predication mask (and whether
 zeroing takes place) may be done as follows:
@@ -663,15 +719,81 @@ 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.
 
+## Fail-on-First Mode <a name="ffirst-mode"></a>
+
+ffirst is a special data-dependent predicate mode.  There are two
+variants: one is for faults: typically for LOAD/STORE operations,
+which may encounter end of page faults during a series of operations.
+The other variant is comparisons such as FEQ (or the augmented behaviour
+of Branch), and any operation that returns a result of zero (whether
+integer or floating-point).  In the FP case, this includes negative-zero.
+
+Note that the execution order must "appear" to be sequential for ffirst
+mode to work correctly.  An in-order architecture must execute the element
+operations in sequence, whilst an out-of-order architecture must *commit*
+the element operations in sequence (giving the appearance of in-order
+execution).
+
+Note also, that if ffirst mode is needed without predication, a special
+"always-on" Predicate Table Entry may be constructed by setting
+inverse-on and using x0 as the predicate register.  This
+will have the effect of creating a mask of all ones, allowing ffirst
+to be set.
+
+### Fail-on-first traps
+
+Except for the first element, ffault stops sequential element processing
+when a trap occurs.  The first element is treated normally (as if ffirst
+is clear).  Should any subsequent element instruction require a trap,
+instead it and subsequent indexed elements are ignored (or cancelled in
+out-of-order designs), and VL is set to the *last* instruction that did
+not take the trap.
+
+Note that predicated-out elements (where the predicate mask bit is zero)
+are clearly excluded (i.e. the trap will not occur).  However, note that
+the loop still had to test the predicate bit: thus on return,
+VL is set to include elements that did not take the trap *and* includes
+the elements that were predicated (masked) out (not tested up to the
+point where the trap occurred).
+
+If SUBVL is being used (SUBVL!=1), the first *sub-group* of elements
+will cause a trap as normal (as if ffirst is not set); subsequently,
+the trap must not occur in the *sub-group* of elements.  SUBVL will **NOT**
+be modified.
+
+Given that predication bits apply to SUBVL groups, the same rules apply
+to predicated-out (masked-out) sub-groups in calculating the value that VL
+is set to.
+
+### Fail-on-first conditional tests
+
+ffault stops sequential element conditional testing on the first element result
+being zero.  VL is set to the number of elements that were processed before
+the fail-condition was encountered.
+
+Note that just as with traps, if SUBVL!=1, the first of any of the *sub-group*
+will cause the processing to end, and, even if there were elements within
+the *sub-group* that passed the test, that sub-group is still (entirely)
+excluded from the count (from setting VL).  i.e. VL is set to the total
+number of *sub-groups* that had no fail-condition up until execution was
+stopped.
+
+Note again that, just as with traps, predicated-out (masked-out) elements
+are included in the count leading up to the fail-condition, even though they
+were not tested.
+
+The pseudo-code for Predication makes this clearer and simpler than it is
+in words (the loop ends, VL is set to the current element index, "i").
+
 ## REMAP CSR <a name="remap" />
 
 (Note: both the REMAP and SHAPE sections are best read after the
@@ -774,6 +896,7 @@ remapped:
       ...
       ...
       for (i = 0; i < VL; i++)
+        xSTATE.srcoffs = i # save context
         if (predval & 1<<i) # predication uses intregs
            ireg[rd+remap(id)] <= ireg[rs1+remap(irs1)] +
                                  ireg[rs2+remap(irs2)];
@@ -898,8 +1021,8 @@ All other operations using registers are automatically parallelised.
 This includes AMOMAX, AMOSWAP and so on, where particular care and
 attention must be paid.
 
-Example pseudo-code for an integer ADD operation (including scalar operations).
-Floating-point uses fp csrs.
+Example pseudo-code for an integer ADD operation (including scalar
+operations).  Floating-point uses the FP Register Table.
 
     function op_add(rd, rs1, rs2) # add not VADD!
       int i, id=0, irs1=0, irs2=0;
@@ -908,6 +1031,7 @@ Floating-point uses fp csrs.
       rs1 = int_vec[rs1].isvector ? int_vec[rs1].regidx : rs1;
       rs2 = int_vec[rs2].isvector ? int_vec[rs2].regidx : rs2;
       for (i = 0; i < VL; i++)
+        xSTATE.srcoffs = i # save context
         if (predval & 1<<i) # predication uses intregs
            ireg[rd+id] <= ireg[rs1+irs1] + ireg[rs2+irs2];
            if (!int_vec[rd ].isvector) break;
@@ -921,18 +1045,54 @@ reshaping and offsets and so on.  However it demonstrates the basic
 principle.  Augmentations that produce the full pseudo-code are covered in
 other sections.
 
+## SUBVL Pseudocode <a name="subvl-pseudocode"></a>
+
+Adding in support for SUBVL is a matter of adding in an extra inner
+for-loop, where register src and dest are still incremented inside the
+inner part. Not that the predication is still taken from the VL index.
+
+So whilst elements are indexed by "(i * SUBVL + s)", predicate bits are
+indexed by "(i)"
+
+    function op_add(rd, rs1, rs2) # add not VADD!
+      int i, id=0, irs1=0, irs2=0;
+      predval = get_pred_val(FALSE, rd);
+      rd  = int_vec[rd ].isvector ? int_vec[rd ].regidx : rd;
+      rs1 = int_vec[rs1].isvector ? int_vec[rs1].regidx : rs1;
+      rs2 = int_vec[rs2].isvector ? int_vec[rs2].regidx : rs2;
+      for (i = 0; i < VL; i++)
+       xSTATE.srcoffs = i # save context
+       for (s = 0; s < SUBVL; s++)
+        xSTATE.ssvoffs = s # save context
+        if (predval & 1<<i) # predication uses intregs
+           # actual add is here (at last)
+           ireg[rd+id] <= ireg[rs1+irs1] + ireg[rs2+irs2];
+           if (!int_vec[rd ].isvector) break;
+        if (int_vec[rd ].isvector)  { id += 1; }
+        if (int_vec[rs1].isvector)  { irs1 += 1; }
+        if (int_vec[rs2].isvector)  { irs2 += 1; }
+        if (id == VL or irs1 == VL or irs2 == VL) {
+          # end VL hardware loop
+          xSTATE.srcoffs = 0; # reset
+          xSTATE.ssvoffs = 0; # reset
+          return;
+        }
+
+
+NOTE: pseudocode simplified greatly: zeroing, proper predicate handling,
+elwidth handling etc. all left out.
+
 ## Instruction Format
 
 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.
+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.
@@ -943,6 +1103,12 @@ comprehensive in its effect on instructions.
 
 ## Branch Instructions
 
+Branch operations are augmented slightly to be a little more like FP
+Compares (FEQ, FNE etc.), by permitting the cumulation (and storage)
+of multiple comparisons into a register (taken indirectly from the predicate
+table).  As such, "ffirst" - fail-on-first - condition mode can be enabled.
+See ffirst mode in the Predication Table section.
+
 ### Standard Branch <a name="standard_branch"></a>
 
 Branch operations use standard RV opcodes that are reinterpreted to
@@ -950,7 +1116,9 @@ be "predicate variants" in the instance where either of the two src
 registers are marked as vectors (active=1, vector=1).
 
 Note that the predication register to use (if one is enabled) is taken from
-the *first* src register.  The target (destination) predication register
+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
@@ -1035,7 +1203,9 @@ Notes:
   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.
-* If an exception (trap) occurs during the middle of a vectorised
+* 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
@@ -1091,6 +1261,8 @@ 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.
 
+Also: note that ffirst (fail first mode) applies directly to this operation.
+
 ### Compressed Branch Instruction
 
 Compressed Branch instructions are, just like standard Branch instructions,
@@ -1138,6 +1310,8 @@ follows:
       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++;
+        xSTATE.srcoffs = i # save context
+        xSTATE.destoffs = j # save context
         reg[rd+j] = SCALAR_OPERATION_ON(reg[rs+i])
         if (int_csr[rs].isvec) i++;
         if (int_csr[rd].isvec) j++; else break
@@ -1183,6 +1357,8 @@ A simplified version of the pseudocode for this operation is as follows:
       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++;
+        xSTATE.srcoffs = i # save context
+        xSTATE.destoffs = j # save context
         ireg[rd+j] <= ireg[rs+i];
         if (int_csr[rs].isvec) i++;
         if (int_csr[rd].isvec) j++; else break
@@ -1341,9 +1517,7 @@ to "Multi-indirection", respectively.
 
 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
@@ -1639,7 +1813,9 @@ 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.
+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>
 
@@ -1705,7 +1881,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:
@@ -1840,19 +2016,16 @@ really actually "memory" as such.
 
 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.
 
@@ -1867,10 +2040,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
@@ -2085,21 +2274,25 @@ is modified to as follows:
              if (int_vec[rs1].isvector)  { irs1 += 1; }
              if (int_vec[rs2].isvector)  { irs2 += 1; }
            if i == VL:
-             break
+             return
         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
+           if int_vec[rd].ffirst and result == 0:
+              VL = i # result was zero, end loop early, return VL
+              return
+           if (!int_vec[rd].isvector) return
         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;
+        else if (predval & 1<<i) return
         if (int_vec[rs1].isvector)  { irs1 += 1; }
         if (int_vec[rs2].isvector)  { irs2 += 1; }
+        if (rd == VL or rs1 == VL or rs2 == VL): return
 
 The optimisation to skip elements entirely is only possible for certain
 micro-architectures when zeroing is not set.  However for lane-based
@@ -2201,6 +2394,189 @@ in as a *parameter* to the HINT operation.
 
 No specific hints are yet defined in Simple-V
 
+# Vector Block Format <a name="vliw-format"></a>
+
+One issue with a former revision of SV was the setup and teardown
+time of the CSRs.  The cost of the use of a full CSRRW (requiring LI)
+to set up registers and predicates was quite high.  A VLIW-like format
+therefore makes sense, and is conceptually reminiscent of the ARM Thumb2
+"IT" instruction.
+
+The format is:
+
+* the standard RISC-V 80 to 192 bit encoding sequence, with bits
+  defining the options to follow within the block
+* An optional VL Block (16-bit)
+* Optional predicate entries (8/16-bit blocks: see Predicate Table, above)
+* Optional register entries (8/16-bit blocks: see Register Table, above)
+* finally some 16/32/48 bit standard RV or SVPrefix opcodes follow.
+
+Thus, the variable-length format from Section 1.5 of the RISC-V ISA is used
+as follows:
+
+| base+4 ... base+2          | base             | number of bits             |
+| ------ -----------------   | ---------------- | -------------------------- |
+| ..xxxx  xxxxxxxxxxxxxxxx   | xnnnxxxxx1111111 | (80+16\*nnn)-bit, nnn!=111 |
+| {ops}{Pred}{Reg}{VL Block} | SV Prefix        |                            |
+
+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 |
+
+The VL/MAXVL/SubVL Block format:
+
+| 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
+* In any RVC or 32 Bit opcode, any registers within the VLIW-prefixed
+  format *MUST* have the RegCam and PredCam entries applied to the
+  operation (and the Vectorisation loop activated)
+* P48 and P64 opcodes do **not** take their Register or predication
+  context from the VLIW Block tables: they do however have VL or SUBVL
+  applied (unless VLtyp or svlen are set).
+* 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.
+
+Bear in mind the warning in an earlier section that use of VLtyp or svlen
+in a P48 or P64 opcode within a VLIW Group will result in corruption
+(use) of the STATE CSR, as the STATE CSR is shared with SVPrefix. To
+avoid this situation, the STATE CSR may be copied into a temp register
+and restored afterwards.
+
+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 srcoffs and destoffs 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 (actually, three including
+SUBVL and ssvoffs).
+
+In addition, as xepcvliw CSRs are relative to the beginning of the VLIW
+block, branches MUST be restricted to within (relative to) 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, normal branch and a normal function call may only be taken
+by letting the VLIW group end, returning to "normal" standard RV mode,
+and then using standard 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
@@ -2208,6 +2584,16 @@ different subsets of RV.
 
 ## Common options
 
+It is permitted to only implement SVprefix and not the VLIW instruction
+format option, and vice-versa.  UNIX Platforms **MUST** raise illegal
+instruction on seeing an unsupported VLIW or SVprefix opcode, so that
+traps may emulate the format.
+
+It is permitted in SVprefix to either not implement VL or not implement
+SUBVL (see [[sv_prefix_proposal]] for full details. Again, UNIX Platforms
+*MUST* raise illegal instruction on implementations that do not support
+VL or SUBVL.
+
 It is permitted to limit the size of either (or both) the register files
 down to the original size of the standard RV architecture.  However, below
 the mandatory limits set in the RV standard will result in non-compliance
@@ -2298,18 +2684,104 @@ 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: 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
 
 ---
 
-push/pop of vector config state:
-<https://groups.google.com/d/msg/comp.arch/bGBeaNjAKvc/z2d_cST7AgAJ>
+Could the 8 bit Register VLIW format use regnum<<1 instead, only accessing regs 0 to 64?
+
+--
+
+Expand the range of SUBVL and its associated svsrcoffs and svdestoffs by
+adding a 2nd STATE CSR (or extending STATE to 64 bits).  Future version?
+
+--
+
+TODO evaluate strncpy and strlen
+<https://groups.google.com/forum/m/#!msg/comp.arch/bGBeaNjAKvc/_vbqyxTUAQAJ>
+
+RVV version: <a name="strncpy"></>
+
+    strncpy: 
+        mv a3, a0               # Copy dst 
+    loop: 
+        setvli x0, a2, vint8    # Vectors of bytes. 
+        vlbff.v v1, (a1)        # Get src bytes 
+        vseq.vi v0, v1, 0       # Flag zero bytes 
+        vmfirst a4, v0          # Zero found? 
+        vmsif.v v0, v0          # Set mask up to and including zero byte. Ppplio
+        vsb.v v1, (a3), v0.t    # Write out bytes 
+        bgez a4, exit           # Done 
+        csrr t1, vl             # Get number of bytes fetched 
+        add a1, a1, t1          # Bump src pointer 
+        sub a2, a2, t1          # Decrement count. 
+        add a3, a3, t1          # Bump dst pointer 
+        bnez a2, loop           # Anymore? 
+
+    exit: 
+        ret 
+
+SV version (WIP):
+
+    strncpy:
+        mv a3, a0
+        SETMVLI 8 # set max vector to 8
+        RegCSR[a3] = 8bit, a3, vector
+        RegCSR[a1] = 8bit, a3, vector
+        PredTb[t0] = ffirst, x0, inv
+        add t2, x0, x0 #t2 = 0
+    loop:
+        SETVLI a2, t4 # t4 and VL now 1..8
+        ldb t0, (a1) # t0 fail first mode
+        bne t0, x0, allnonzero # still ff
+        # VL points to last nonzero
+        GETVL t4       # from bne tests
+        addi t4, t4, 1 # include zero
+        SETVL t4       # set exactly to t4
+        stb t0, (a3)   # store incl zero
+        ret            # end subroutine
+    allnonzero:
+        stb t0, (a3)    # VL legal range
+        GETVL t4        # from bne tests
+        add a1, a1, t4  # Bump src pointer 
+        sub a2, a2, t4  # Decrement count. 
+        add a3, a3, t4  # Bump dst pointer 
+        bnez a2, loop   # Anymore? 
+    exit:
+        ret
+
+Notes:
 
-when Bank in CFG is altered, shift the "addressing" of Reg and
-Pred CSRs to match.  i.e. treat the Reg and Pred CSRs as a
-"mini stack".
+* ldb and bne are both using t0, both in ffirst mode
+* ldb will end on illegal mem, reduce VL, but copied all sorts of stuff into t0
+* bne behaviour modified to do multiple tests (more like FNE).
+* bne t0 x0 tests up to the NEW VL for nonzero, vector t0 against scalar  x0
+* however as t0 is in ffirst mode, the first fail wil ALSO stop the compares, and reduce VL as well
+* the branch only goes to allnonzero if all tests succeed
+* if it did not, we can safely increment VL by 1 (using a4) to include the zero.
+* SETVL sets *exactly* the requested amount into VL.
+* the SETVL just after allnonzero label is needed in case the ldb ffirst activates but the bne allzeros does not.
+* this would cause the stb to copy up to the end of the legal memory
+* of course, on the next loop the ldb would throw a trap, as a1 points to the first illegal mem location.
+
+RVV version:
+
+        mv a3, a0             # Save start 
+    loop: 
+        setvli a1, x0, vint8  # byte vec, x0 (Zero reg) => use max hardware len
+        vldbff.v v1, (a3)     # Get bytes
+        csrr a1, vl           # Get bytes actually read e.g. if fault
+        vseq.vi v0, v1, 0     # Set v0[i] where v1[i] = 0 
+        add a3, a3, a1        # Bump pointer
+        vmfirst a2, v0        # Find first set bit in mask, returns -1 if none
+        bltz a2, loop         # Not found?
+        add a0, a0, a1        # Sum start + bump
+        add a3, a3, a2        # Add index of zero byte
+        sub a0, a3, a0        # Subtract start address+bump
+        ret