add mv etc.
[libreriscv.git] / simple_v_extension.mdwn
index 5dffcf00d1a49f4f6cce2207a9ab192105ea009f..92b616e5c9d1d05ce01300b5d742c0b72d884c77 100644 (file)
@@ -534,17 +534,27 @@ and 31 for RV32 or RV64).
 
 Note that RVV on top of Simple-V may choose to over-ride this decision.
 
-## Register CSR key-value table
-
-Element bitwidths may be specified with a per-register CSR, and indicate
-how a register (integer or floating-point) is to be subdivided.
-
-| RegNo | (2..0) |
-| ----- | ------ |
-| r0    | vew0   |
-| r1    | vew1   |
-| ..    | vew..  |
-| r31   | vew31  |
+## Register CSR key-value (CAM) table
+
+The purpose of the Register CSR 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-6-bit lookup table
+  (where the 6th bit - bank - is always set to 0 for now).
+* 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.
+* To indicate if the register is to be interpreted as "packed" (SIMD)
+  i.e. containing multiple contiguous elements of size equal to "bitwidth".
+
+| RgCSR | 15     | 14     | 13       | (12..11) | 10  | (9..5)  | (4..0)  |
+| ----- | -      | -      | -        | -        | -   | ------- | ------- |
+| 0     | simd0  | bank0  | isvec0   | vew0     | i/f | regidx  | predidx |
+| 1     | simd1  | bank1  | isvec1   | vew1     | i/f | regidx  | predidx |
+| ..    | simd.. | bank.. | isvec..  | vew..    | i/f | regidx  | predidx |
+| 15    | simd15 | bank15 | isvec15  | vew15    | i/f | regidx  | predidx |
 
 vew may be one of the following (giving a table "bytestable", used below):
 
@@ -558,14 +568,30 @@ vew may be one of the following (giving a table "bytestable", used below):
 Extending this table (with extra bits) is covered in the section
 "Implementing RVV on top of Simple-V".
 
-Note that when using the "vsetl rs1, rs2" instruction, taking bitwidth
-into account, it becomes:
+As the above table is a CAM (key-value store) it may be appropriate
+to expand it as follows:
+
+    struct vectorised fp_vec[32], int_vec[32]; // 64 in future
+
+    for (i = 0; i < 16; i++) // 16 CSRs?
+       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
+       tb[idx].bank     = CSRvec[i].bank    // 0 (1=rsvd)
 
+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] # 1 2 4 8 16
+        bytesperreg = bytestable[vew] # 8 or 16
     simdmult = (XLEN/8) / bytesperreg # or FLEN as appropriate
     vlen = CSRvectorlen[rs1] * simdmult
     CSRvlength = MIN(MIN(vlen, MAXVECTORDEPTH), rs2)
@@ -579,12 +605,21 @@ is given in the section "Bitwidth Virtual Register Reordering".
 
 # Instructions
 
-By being a topological remap of RVV concepts, the following RVV instructions
-remain exactly the same: VMPOP, VMFIRST, VEXTRACT, VINSERT, VMERGE, VSELECT,
-VSLIDE, VCLASS and VPOPC.  Two instructions, VCLIP and VCLIPI, do not
-have RV Standard equivalents, so are left out of Simple-V.
-All other instructions from RVV are topologically re-mapped and retain
-their complete functionality, intact.
+Despite being a 98% complete and accurate topological remap of RVV
+concepts and functionality, the only instructions needed are VSETVL
+and VGETVL.  *All* RVV instructions can be re-mapped, however xBitManip
+becomes a critical dependency for efficient manipulation of predication
+masks (as a bit-field).  Despite the removal of all but VSETVL and VGETVL,
+*all instructions from RVV are topologically re-mapped and retain their
+complete functionality, intact*.
+
+Three instructions, VSELECT, VCLIP and VCLIPI, do not have RV Standard
+equivalents, so are left out of Simple-V.  VSELECT could be included if
+there existed a MV.X instruction in RV (MV.X is a hypothetical
+non-immediate variant of MV that would allow another register to
+specify which register was to be copied).  Note that if any of these three
+instructions are added to any given RV extension, their functionality
+will be inherently parallelised.
 
 ## Instruction Format
 
@@ -592,9 +627,11 @@ The instruction format for Simple-V does not actually have *any* explicit
 compare operations, *any* arithmetic, floating point or *any*
 memory instructions.
 Instead it *overloads* pre-existing branch operations into predicated
-variants, and implicitly overloads arithmetic operations and LOAD/STORE
-depending on CSR configurations for vector length, bitwidth and
-predication.  *This includes Compressed instructions* as well as any
+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.
 
 * For analysis of RVV see [[v_comparative_analysis]] which begins to
@@ -625,58 +662,46 @@ the entire bank of registers using a single instruction (see Appendix,
 down to the fact that predication bits fit into a single register of length
 XLEN bits.
 
-The second minor change is that when VSETVL is requested to be stored
-into x0, it is *ignored* silently.
+The second change is that when VSETVL is requested to be stored
+into x0, it is *ignored* silently (VSETVL x0, x5, #4)
 
-Unlike RVV, implementors *must* provide pseudo-parallelism (using sequential
-loops in hardware) if actual 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 third change is that there is an additional immediate added to VSETVL,
+to which VL is set after first going through MIN-filtering.
+So When using the "vsetl rs1, rs2, #vlen" instruction, it becomes:
 
-### Under review / discussion: remove CSR vector length, use VSETVL <a name="vsetvl"></a>
+    VL = MIN(MIN(vlen, MAXVECTORDEPTH), rs2)
 
-So the issue is as follows:
+where RegfileLen <= MAXVECTORDEPTH < XLEN
 
-* CSRs are used to set the "span" of a vector (how many of the standard
-  register file to contiguously use)
-* VSETVL in RVV works as follows: it sets the vector length (copy of which
-  is placed in a dest register), and if the "required" length is longer
-  than the *available* length, the dest reg is set to the MIN of those
-  two.
-* **HOWEVER**... in SV, *EVERY* vector register has its own separate
-  length and thus there is no way (at the time that VSETVL is called) to
-  know what to set the vector length *to*.
-* At first glance it seems that it would be perfectly fine to just limit
-  the vector operation to the length specified in the destination
-  register's CSR, at the time that each instruction is issued...
-  except that that cannot possibly be guaranteed to match
-  with the value *already loaded into the target register from VSETVL*.
-
-Therefore a different approach is needed.
-
-Possible options include:
+This has implication for the microarchitecture, as VL is required to be
+set (limits from MAXVECTORDEPTH notwithstanding) to the actual value
+requested in the #immediate parameter.  RVV has the option to set VL
+to an arbitrary value that suits the conditions and the micro-architecture:
+SV does *not* permit that.
 
-* Removing the CSR "Vector Length" and always using the value from
-  VSETVL.  "VSETVL destreg, counterreg, #lenimmed" will set VL *and*
-  destreg equal to MIN(counterreg, lenimmed), with register-based
-  variant "VSETVL destreg, counterreg, lenreg" doing the same.
-* Keeping the CSR "Vector Length" and having the lenreg version have
-  a "twist": "if lengreg is vectorised, read the length from the CSR"
-* Other (TBD)
+The reason is so that if SV is to be used for a context-switch or as a
+substitute for LOAD/STORE-Multiple, the operation can be done with only
+2-3 instructions (setup of the CSRs, VSETVL x0, x0, #{regfilelen-1},
+single LD/ST operation).  If VL does *not* get set to the register file
+length when VSETVL is called, then a software-loop would be needed.
+To avoid this need, VL *must* be set to exactly what is requested
+(limits notwithstanding).
 
-The first option (of the ones brainstormed so far) is a lot simpler.
-It does however mean that the length set in VSETVL will apply across-the-board
-to all src1, src2 and dest vectorised registers until it is otherwise changed
-(by another VSETVL call).  This is probably desirable behaviour.
+Therefore, in turn, unlike RVV, implementors *must* provide
+pseudo-parallelism (using sequential loops in hardware) if actual
+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.
 
 ## Branch Instruction:
 
-Branch operations use standard RV opcodes that are reinterpreted to be
-"predicate variants" in the instance where either of the two src registers
-have their corresponding CSRvectorlen[src] entry as non-zero.  When this
-reinterpretation is enabled the predicate target register rs3 is to be
-treated as a bitfield (up to a maximum of XLEN bits corresponding to a
-maximum of XLEN elements).
+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 (isvector=1).  When this reinterpretation
+is enabled the "immediate" field of the branch operation is taken to be a
+predication target register, rs3.  The predicate target register rs3 is
+to be treated as a bitfield (up to a maximum of XLEN bits corresponding
+to a maximum of XLEN elements).
 
 If either of src1 or src2 are scalars (CSRvectorlen[src] == 0) the comparison
 goes ahead as vector-scalar or scalar-vector.  Implementors should note that
@@ -727,16 +752,15 @@ It is however 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 as an explicit (scalar) instruction is needed
-to invert the predicate bitmask.  An additional encoding funct3=011 is
-therefore proposed to cater for this.
+becomes more of an impact.  To deal with this, SV's predication has
+had "invert" added to it.
 
 [[!table  data="""
 31 .. 27| 26 .. 25 |24 ... 20 | 19 15 | 14  12 | 11 .. 7  | 6 ... 0 |
 funct5  | fmt      | rs2      | rs1   | funct3 | rd       | opcode  |
 5       | 2        | 5        | 5     | 3      | 4        | 7       |
 10100   | 00/01/11 | src2     | src1  | 010    | pred rs3 | FEQ     |
-10100   | 00/01/11 | src2     | src1  | **011**| pred rs3 | FNE     |
+10100   | 00/01/11 | src2     | src1  | **011**| pred rs3 | rsvd    |
 10100   | 00/01/11 | src2     | src1  | 001    | pred rs3 | FLT     |
 10100   | 00/01/11 | src2     | src1  | 000    | pred rs3 | FLE     |
 """]]
@@ -760,19 +784,19 @@ and temporarily ignoring bitwidth (which makes the comparisons more
 complex), this becomes:
 
     if I/F == INT: # integer type cmp
-        pred_enabled = int_pred_enabled # TODO: exception if not set!
         preg = int_pred_reg[rd]
         reg = int_regfile
     else:
-        pred_enabled = fp_pred_enabled # TODO: exception if not set!
         preg = fp_pred_reg[rd]
         reg = fp_regfile
 
-    s1 = CSRvectorlen[src1] > 1;
-    s2 = CSRvectorlen[src2] > 1;
-    for (int i=0; i<vl; ++i)
-       preg[rs3][i] = cmp(s1 ? reg[src1+i] : reg[src1],
-                          s2 ? reg[src2+i] : reg[src2]);
+    s1 = reg_is_vectorised(src1);
+    s2 = reg_is_vectorised(src2);
+    if (!s2 && !s1) goto branch;
+    for (int i = 0; i < VL; ++i)
+      if (cmp(s1 ? reg[src1+i]:reg[src1],
+              s2 ? reg[src2+i]:reg[src2])
+             preg[rs3] |= 1<<i;  # bitfield not vector
 
 Notes:
 
@@ -784,13 +808,17 @@ Notes:
   Counter, so all of bits 25 through 30 in every case are not needed.
 * There are plenty of reserved opcodes for which bits 25 through 30 could
   be put to good use if there is a suitable use-case.
-* FEQ and FNE (and BEQ and BNE) are included in order to save one
-  instruction having to invert the resultant predicate bitfield.
   FLT and FLE may be inverted to FGT and FGE if needed by swapping
   src1 and src2 (likewise the integer counterparts).
 
 ## Compressed Branch Instruction:
 
+Compressed Branch instructions are likewise re-interpreted as predicated
+2-register operations, with the result going into rs3.  All the bits of
+the immediate are re-interpreted for different purposes, to extend the
+number of comparator operations to beyond the original specification,
+but also to cater for floating-point comparisons as well as integer ones.
+
 [[!table  data="""
 15..13 | 12...10  | 9..7 | 6..5  | 4..2 | 1..0 | name |
 funct3 | imm      | rs10 | imm   |      | op   |      |
@@ -850,15 +878,14 @@ Pseudo-code (excludes CSR SIMD bitwidth for simplicity):
     if (unit-strided) stride = elsize;
     else stride = areg[as2]; // constant-strided
 
-    pred_enabled = int_pred_enabled
     preg = int_pred_reg[rd]
 
     for (int i=0; i<vl; ++i)
-      if (preg_enabled[rd] && [!]preg[i])
+      if ([!]preg[rd] & 1<<i)
         for (int j=0; j<seglen+1; j++)
         {
           if CSRvectorised[rs2])
-             offs = vreg[rs2][i]
+             offs = vreg[rs2+i]
           else
              offs = i*(seglen+1)*stride;
           vreg[rd+j][i] = mem[sreg[base] + offs + j*stride];
@@ -918,6 +945,115 @@ of detecting early page / segmentation faults and adjusting the TLB
 in advance, accordingly: other strategies are explored in the Appendix
 Section "Virtual Memory Page Faults".
 
+## Vectorised Copy/Move (and conversion) instructions
+
+There is a series of 2-operand instructions involving copying (and
+alteration): C.MV, FMV, FNEG, FABS, FCVT, FSGNJ.  These operations all
+follow the same pattern, as it is *both* the source *and* destination
+predication masks that are taken into account.  This is different from
+the three-operand arithmetic instructions, where the predication mask
+is taken from the *destination* register, and applied uniformly to the
+elements of the source register(s), element-for-element.
+
+### C.MV Instruction <a name="c_mv"></a>
+
+There is no MV instruction in RV however there is a C.MV instruction.
+It is used for copying integer-to-integer registers (vectorised FMV
+is used for copying floating-point).
+
+If either the source or the destination register are marked as vectors
+C.MV is reinterpreted to be a vectorised (multi-register) predicated
+move operation.  The actual instruction's format does not change:
+
+[[!table  data="""
+15  12 | 11   7 | 6  2 | 1  0 |
+funct4 | rd     | rs   | op   |
+4      | 5      | 5    | 2    |
+C.MV   | dest   | src  | C0   |
+"""]]
+
+A simplified version of the pseudocode for this operation is as follows:
+
+    function op_mv(rd, rs) # MV not VMV!
+      rd = int_vec[rd].isvector ? int_vec[rd].regidx : rd;
+      rs = int_vec[rs].isvector ? int_vec[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_vec[rs].isvec) while (!(ps & 1<<i)) i++;
+        if (int_vec[rd].isvec) while (!(pd & 1<<j)) j++;
+        ireg[rd+j] <= ireg[rs+i];
+        if (int_vec[rs].isvec) i++;
+        if (int_vec[rd].isvec) j++;
+
+Note that:
+
+* elwidth (SIMD) is not covered above
+* ending the loop early in scalar cases (VINSERT, VEXTRACT) is also
+  not covered
+
+There are several different instructions from RVV that are covered by
+this one opcode:
+
+[[!table  data="""
+src    | dest    | predication   | op             |
+scalar | vector  | none          | VSPLAT         |
+scalar | vector  | destination   | sparse VSPLAT  |
+scalar | vector  | 1-bit dest    | VINSERT        |
+vector | scalar  | 1-bit? src    | VEXTRACT       |
+vector | vector  | none          | VCOPY          |
+vector | vector  | src           | Vector Gather  |
+vector | vector  | dest          | Vector Scatter |
+vector | vector  | src & dest    | Gather/Scatter |
+vector | vector  | src == dest   | sparse VCOPY   |
+"""]]
+
+Also, VMERGE may be implemented as back-to-back (macro-op fused) C.MV
+operations with inversion on the src and dest predication for one of the
+two C.MV operations.
+
+Note that in the instance where the Compressed Extension is not implemented,
+MV may be used, but that is a pseudo-operation mapping to addi rd, x0, rs.
+Note that the behaviour is **different** from C.MV because with addi the
+predication mask to use is taken **only** from rd and is applied against
+all elements: rs[i] = rd[i].
+
+### FMV, FNEG and FABS Instructions
+
+These are identical in form to C.MV, except covering floating-point
+register copying.  The same double-predication rules also apply.
+However when elwidth is not set to default the instruction is implicitly
+and automatic converted to a (vectorised) floating-point type conversion
+operation of the appropriate size covering the source and destination
+register bitwidths.
+
+(Note that FMV, FNEG and FABS are all actually pseudo-instructions)
+
+### FVCT Instructions
+
+These are again identical in form to C.MV, except that they cover
+floating-point to integer and integer to floating-point.  When element
+width in each vector is set to default, the instructions behave exactly
+as they are defined for standard RV (scalar) operations, except vectorised
+in exactly the same fashion as outlined in C.MV.
+
+However when the source or destination element width is not set to default,
+the opcode's explicit element widths are *over-ridden* to new definitions,
+and the opcode's element width is taken as indicative of the SIMD width
+(if applicable i.e. if packed SIMD is requested) instead.
+
+For example FCVT.S.L would normally be used to convert a 64-bit
+integer in register rs1 to a 64-bit floating-point number in rd.
+If however the source rs1 is set to be a vector, where elwidth is set to
+default/2 and "packed SIMD" is enabled, then the first 32 bits of
+rs1 are converted to a floating-point number to be stored in rd's
+first element and the higher 32-bits *also* converted to floating-point
+and stored in the second.  The 32 bit size comes from the fact that
+FCVT.S.L's integer width is 64 bit, and with elwidth on rs1 set to
+divide that by two it means that rs1 element width is to be taken as 32.
+
+Similar rules apply to the destination register.
+
 # Exceptions
 
 > What does an ADD of two different-sized vectors do in simple-V?
@@ -1925,6 +2061,45 @@ summary: don't restrict / remove.  it's fine.
 
 <https://groups.google.com/a/groups.riscv.org/forum/#!topic/isa-dev/g3feFnAoKIM>
 
+## Under review / discussion: remove CSR vector length, use VSETVL <a name="vsetvl"></a>
+
+**DECISION: 11jun2018 - CSR vector length removed, VSETVL determines
+length on all regs**.  This section kept for historical reasons.
+
+So the issue is as follows:
+
+* CSRs are used to set the "span" of a vector (how many of the standard
+  register file to contiguously use)
+* VSETVL in RVV works as follows: it sets the vector length (copy of which
+  is placed in a dest register), and if the "required" length is longer
+  than the *available* length, the dest reg is set to the MIN of those
+  two.
+* **HOWEVER**... in SV, *EVERY* vector register has its own separate
+  length and thus there is no way (at the time that VSETVL is called) to
+  know what to set the vector length *to*.
+* At first glance it seems that it would be perfectly fine to just limit
+  the vector operation to the length specified in the destination
+  register's CSR, at the time that each instruction is issued...
+  except that that cannot possibly be guaranteed to match
+  with the value *already loaded into the target register from VSETVL*.
+
+Therefore a different approach is needed.
+
+Possible options include:
+
+* Removing the CSR "Vector Length" and always using the value from
+  VSETVL.  "VSETVL destreg, counterreg, #lenimmed" will set VL *and*
+  destreg equal to MIN(counterreg, lenimmed), with register-based
+  variant "VSETVL destreg, counterreg, lenreg" doing the same.
+* Keeping the CSR "Vector Length" and having the lenreg version have
+  a "twist": "if lengreg is vectorised, read the length from the CSR"
+* Other (TBD)
+
+The first option (of the ones brainstormed so far) is a lot simpler.
+It does however mean that the length set in VSETVL will apply across-the-board
+to all src1, src2 and dest vectorised registers until it is otherwise changed
+(by another VSETVL call).  This is probably desirable behaviour.
+
 ## Implementation Paradigms <a name="implementation_paradigms"></a>
 
 TODO: assess various implementation paradigms.  These are listed roughly