[[insns-vaeskf1, Vector AES-128 Forward KeySchedule]]
= vaeskf1.vi

Synopsis::
Vector AES-128 Forward KeySchedule generation

Mnemonic::
vaeskf1.vi vd, vs2, uimm

Encoding::
[wavedrom, , svg]
....
{reg:[
{bits: 7, name: 'OP-P'},
{bits: 5, name: 'vd'},
{bits: 3, name: 'OPMVV'},
{bits: 5, name: 'uimm'},
{bits: 5, name: 'vs2'},
{bits: 1, name: '1'},
{bits: 6, name: '100010'},
]}
....
Reserved Encodings::
* `SEW` is any value other than 32

Arguments::

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

| uimm | input  | -    | - | -  | Round Number (rnd)
| Vs2  | input  | 128  | 4 | 32 | Current round key
| Vd   | output | 128  | 4 | 32 | Next round key
|===

Description:: 
A single round of the forward AES-128 KeySchedule is performed.

// Within each element group, 
The next round key is generated word by word from the
current round key element group in `vs2` and the immediately previous word of the
round key. The least significant word is generated using the most significant 
word of the current round key as well as a round constant which is selected by
the round number. 

The round number, which ranges from 1 to 10, comes from `uimm[3:0]`;
`uimm[4]` is ignored.
The out-of-range `uimm[3:0]` values of 0 and 11-15 are mapped to in-range
values by inverting `uimm[3]`. Thus, 0 maps to 8, and 11-15 maps to 3-7.
The round number is used to specify a round constant which is used in generating
the first round key word.

This instruction must always be implemented such that its execution latency does not depend
on the data being operated upon.

[NOTE]
====
We chose to map out-of-range round numbers to in-range values as this allows the instruction's
behavior to be fully defined for all values of `uimm[4:0]` with minimal extra logic. 
====

// Each `EGW=128` element group next-round-key output is produced and is written to each `EGW=128`
// element group of `vd`.


//
// 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 (VAESKF1(rnd, vd, vs2)) = {
  if(LMUL*VLEN < EGW)  then {
    handle_illegal();  // illegal instruction exception
    RETIRE_FAIL
  } else {

 // project out-of-range immediates onto in-range values
 if( (unsigned(rnd[3:0]) > 10) | (rnd[3:0] = 0)) then rnd[3] = ~rnd[3]
 
  eg_len = (vl/EGS)
  eg_start = (vstart/EGS)

  let r : bits(4) = rnd-1;

  foreach (i from eg_start to eg_len-1) {
      let CurrentRoundKey[3:0]  : bits(32)  = get_velem(vs2, EGW=128, i);
      let w[0] : bits(32) = aes_subword_fwd(aes_rotword(CurrentRoundKey[3])) XOR
        aes_decode_rcon(r) XOR CurrentRoundKey[0]
      let w[1] : bits(32) = w[0] XOR CurrentRoundKey[1]
      let w[2] : bits(32) = w[1] XOR CurrentRoundKey[2]
      let w[3] : bits(32) = w[2] XOR CurrentRoundKey[3]
      set_velem(vd, EGW=128, i, w[3:0]);
    }
    RETIRE_SUCCESS
  }
}

--

Included in::
<<zvkn>>, <<zvknc>>, <<zvkned>>, <<zvkng>>
