[[insns-vsha2ms, Vector SHA-2 Message Schedule]]
= vsha2ms.vv

Synopsis::
Vector SHA-2 message schedule.

Mnemonic::
vsha2ms.vv vd, vs2, vs1

Encoding (Vector-Vector)::
[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: '101101'},
]}
....
Reserved Encodings::
* `zvknha`: `SEW` is any value other than 32
* `zvknhb`: `SEW` is any value other than 32 or 64
* The `vd` register group overlaps with either `vs1` or `vs2`
Arguments::

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

| Vd  | input  | 4*SEW  | 4 | SEW | Message words {W[3],  W[2],  W[1],  W[0]}
| Vs2 | input  | 4*SEW  | 4 | SEW | Message words {W[11], W[10], W[9],  W[4]}
| Vs1 | input  | 4*SEW  | 4 | SEW | Message words {W[15], W[14], -, W[12]}
| Vd  | output | 4*SEW  | 4 | SEW | Message words {W[19], W[18], W[17], W[16]}
|===

Description::
- `SEW`=32: Four rounds of SHA-256 message schedule expansion are performed (`zvknha` and `zvknhb`)
- `SEW`=64: Four rounds of SHA-512 message schedule expansion are performed (`zvkhnb`)

Eleven of the last 16 `SEW`-sized message-schedule words from `vd` (oldest), `vs2`,
and `vs1` (most recent) are processed to produce the
next 4 message-schedule words.

[TIP]
.Note to software developers
====
The first 16 SEW-sized words of the message schedule come from the _message block_
in big-endian byte order. Since this instruction treats all words as little endian,
software is required to endian swap these words.

All of the subsequent message schedule words are produced by this instruction and
therefore do not require an endian swap.
====

[TIP]
.Note to software developers
====
Software is required to pack the words into element groups
as shown above in the arguments table. The indices indicate the relate age with
lower indices indicating older words.
====
// [NOTE]
// ====
// W~13~ is not used by the instruction.
// ====

// Four `SEW` message schedule words are packed into each element group of the
// source and destination registers. From a vector register point of view, 
// the message schedule words are packed into the
// element groups from the left to the right with the most significant word on the left
// and the least significant word on the right.

// `{W~3~, W~2~, W~1~, W~0~} +
// {W~7~, W~6~, W~5~, W~4~} +
// {W~11~, W~10~, W~9~, W~8~} +
// {W~15~, W~14~, W~13~, W~12~}`

// Since W~5~ through W~8~ are not needed in these calculations, we are able to compact these into
// three element groups
//
// `{W~3~, W~2~, W~1~, W~0~} +
// {W~11~, W~10~, W~9~, W~4~} +
// {W~15~, W~14~, W~13~, W~12~}`

[TIP]
.Note to software developers
====
The {W~11~, W~10~, W~9~, W~4~} element group can easily be formed by using a vector
vmerge instruction with the appropriate mask (for example with `vl=4` and `4b0001`
as the 4 mask bits)

`vmerge.vvm {W~11~, W~10~, W~9~, W~4~}, {W~11~, W~10~, W~9~, W~8~}, {W~7~, W~6~, W~5~, W~4~}, V0`
====

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

[NOTE]
====
Preventing overlap between `vd` and `vs1` or `vs2` simplifies implementation with `VLEN < EGW`.
This restriction does not have any coding impact since proper implementation of the algorithm requires
that `vd`, `vs1` and `vs2` each contain different portions of the message schedule.
====

// This instruction is not masked. If any element groups are not to be processed, the _vl_
// must be set accordingly. It is not possible to skip an intermediary element group.
// `VLMUL` must be at least 1. In typical usage it is expected to be 1.
// There are three source operands: `vd`, `vs1` and `vs2`. The result
// is written to `vd`.

// NB:: for implementations with `VLEN < EGW`, the minimal `VLMUL` is `EGW / VLEN`.

// In this code the input elements are numbered from 0 (16 words ago) to 15 (most recent message-schedule word).
// The outputs are numbered from 16 to 19.

// 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=4`. +
// Likewise, `vstart` must be a multiple of `EGS=4`.

Operation::
[source,sail]
--
function clause execute (VSHA2ms(vs2, vs1, vd)) = {
  // SEW32 = SHA-256
  // SEW64 =  SHA-512
  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) {
    {W[3] @  W[2] @  W[1] @  W[0]}  : bits(EGW) = get_velem(vd, EGW, i);
    {W[11] @ W[10] @ W[9] @  W[4]}  : bits(EGW) = get_velem(vs2, EGW, i);
    {W[15] @ W[14] @ W[13] @ W[12]} : bits(EGW) = get_velem(vs1, EGW, i);
  
    W[16] = sig1(W[14]) + W[9]  + sig0(W[1]) + W[0];
    W[17] = sig1(W[15]) + W[10] + sig0(W[2]) + W[1];
    W[18] = sig1(W[16]) + W[11] + sig0(W[3]) + W[2];
    W[19] = sig1(W[17]) + W[12] + sig0(W[4]) + W[3];

    set_velem(vd, EGW, i, {W[19] @ W[18] @ W[17] @ W[16]});
  }
  RETIRE_SUCCESS
  }
}

function sig0(x) = {
	match SEW {
		32 => (ROTR(x,7) XOR ROTR(x,18) XOR SHR(x,3)),
		64 => (ROTR(x,1) XOR ROTR(x,8) XOR SHR(x,7)));
	}
}

function sig1(x) = {
	match SEW {
		32 => (ROTR(x,17) XOR ROTR(x,19) XOR SHR(x,10),
		64 => ROTR(x,19) XOR ROTR(x,61) XOR SHR(x,6));
	}
}

function ROTR(x,n) = (x >> n) | (x << SEW - n)
function SHR (x,n) = x >> n

--

Included in::
 <<zvkn>>, <<zvknc>>, <<zvkng>>, <<zvknh, zvknh[ab]>>
