[[insns-vsm3me, SM3 Message Expansion]]
= vsm3me.vv

Synopsis::
Vector SM3 Message Expansion

Mnemonic::
vsm3me.vv vd, vs2, vs1

Encoding::
[wavedrom, , svg]
....
{reg:[
{bits: 7, name: 'OP-P'},
{bits: 5, name: 'vd'},
{bits: 3, name: 'OPMVV'},
{bits: 5, name: 'vs1'},
{bits: 5, name: 'vs2'},
{bits: 1, name: '1'},
{bits: 6, name: '100000'},
]}
....
Reserved Encodings::
* `SEW` is any value other than 32
* The `vd` register group overlaps with the `vs2` register group.

Arguments::

[%autowidth]
[%header,cols="4,2,2,2,2,2"]
|===
|Register
|Direction
|EGW
|EGS
|EEW
|Definition

| Vs1 | input  | 256  | 8 | 32 | Message words W[7:0]
| Vs2 | input  | 256  | 8 | 32 | Message words W[15:8]
| Vd  | output | 256  | 8 | 32 | Message words W[23:16]
|===

Description::
Eight rounds of SM3 message expansion are performed.


The sixteen most recent 32-bit message words are read in as two
eight-element groups from `vs1` and `vs2`. Each of these words is
swapped from big endian to little endian.
The next eight 32-bit message words are generated,
swapped from little endian to big endian, and are returned in
an eight-element group.

[NOTE]
====
The endian byte swapping of the input and output words enables us to align with the SM3
specification without requiring that software perform these swaps.
====

// NOTE
// ====
// For the best performance, it is recommended that implementations have VLEN≥256.
// When VLEN<EGW, an appropriate LMUL needs to be used by software so that elements from the 
// specified register groups can be combined to form the full element group.
// ====

// The number of element groups to be processed is `vl`/`EGS`.
// `vl` must be set to the number of `SEW=32` elements to be processed and
// therefore must be a multiple of `EGS=8`. +
// Likewise, `vstart` must be a multiple of `EGS=8`.

[NOTE]
====
Preventing overlap between `vd` and `vs2` simplifies implementations with `VLEN < EGW`.
This restriction should not have any coding impact since the algorithm requires these
values to be preserved for generating the next 8 words.
====

Operation::
[source,sail]
--
function clause execute (VSM3ME(vs2, vs1)) = {
  if(LMUL*VLEN < EGW)  then {
    handle_illegal();  // illegal instruction exception
    RETIRE_FAIL
  } else {

  eg_len = (vl/EGS)
  eg_start = (vstart/EGS)
  
  foreach (i from eg_start to eg_len-1) {
    let w[7:0]  : bits(256) = get_velem(vs1, 256, i);
    let w[15:8] : bits(256) = get_velem(vs2, 256, i);
    
    // Byte Swap inputs from big-endian to little-endian
    let w15 = rev8(w[15]);
    let w14 = rev8(w[14]);
    let w13 = rev8(w[13]);
    let w12 = rev8(w[12]);
    let w11 = rev8(w[11]);
    let w10 = rev8(w[10]);
    let w9  = rev8(w[9]);
    let w8  = rev8(w[8]);
    let w7  = rev8(w[7]);
    let w6  = rev8(w[6]);
    let w5  = rev8(w[5]);
    let w4  = rev8(w[4]);
    let w3  = rev8(w[3]);
    let w2  = rev8(w[2]);
    let w1  = rev8(w[1]);
    let w0  = rev8(w[0]);

    // Note that some of the newly computed words are used in later invocations.
    let w[16] = ZVKSH_W(w0 @  w7 @  w13 @   w3 @  w10);
    let w[17] = ZVKSH_W(w1 @  w8 @  w14 @   w4 @  w11);
    let w[18] = ZVKSH_W(w2 @  w9 @  w15 @   w5 @  w12);
    let w[19] = ZVKSH_W(w3 @ w10 @  w16 @   w6 @  w13);
    let w[20] = ZVKSH_W(w4 @ w11 @  w17 @   w7 @  w14);
    let w[21] = ZVKSH_W(w5 @ w12 @  w18 @   w8 @  w15);
    let w[22] = ZVKSH_W(w6 @ w13 @  w19 @   w9 @  w16);
    let w[23] = ZVKSH_W(w7 @ w14 @  w20 @  w10 @  w17);

  // Byte swap outputs from little-endian back to big-endian
    let w16 : Bits(32) = rev8(W[16]);
    let w17 : Bits(32) = rev8(W[17]);
    let w18 : Bits(32) = rev8(W[18]);
    let w19 : Bits(32) = rev8(W[19]);
    let w20 : Bits(32) = rev8(W[20]);
    let w21 : Bits(32) = rev8(W[21]);
    let w22 : Bits(32) = rev8(W[22]);
    let w23 : Bits(32) = rev8(W[23]);


    // Update the destination register.
    set_velem(vd, 256, i, {w23 @ w22 @ w21 @ w20 @ w19 @ w18 @ w17 @ w16});
  }
  RETIRE_SUCCESS
  }
}

  function P_1(X) ((X) ^ ROL32((X), 15) ^ ROL32((X), 23))

  function ZVKSH_W(M16, M9, M3, M13, M6) = \
  (P1( (M16) ^  (M9) ^ ROL32((M3), 15) ) ^ ROL32((M13), 7) ^ (M6))
--

Included in::
<<zvks>>, <<zvksc>>, <<zvksg>>, <<zvksh>>
