Set vill based on sew and lmul.

Change-Id: I7a4bec14380c910ca147bc372f942648da9d47c9
diff --git a/hdl/chisel/src/kelvin/rvv/RvvCore.scala b/hdl/chisel/src/kelvin/rvv/RvvCore.scala
index c80defe..cde9738 100644
--- a/hdl/chisel/src/kelvin/rvv/RvvCore.scala
+++ b/hdl/chisel/src/kelvin/rvv/RvvCore.scala
@@ -113,6 +113,7 @@
         |    output [1:0] configXrm,
         |    output [2:0] configSew,
         |    output [2:0] configLmul,
+        |    output configVill,
         |    output logic rvv_idle,
         |    output logic [3:0] queue_capacity,
         |""".stripMargin.replaceAll("VSTART_LEN", (log2Ceil(vlen) - 1).toString)
@@ -133,6 +134,7 @@
             |    output rd_rob2rt_o_GENI_vector_csr_xrm,
             |    output rd_rob2rt_o_GENI_vector_csr_sew,
             |    output rd_rob2rt_o_GENI_vector_csr_lmul,
+            |    output rd_rob2rt_o_GENI_vector_csr_vill,
             |    output [15:0] rd_rob2rt_o_GENI_vxsaturate,""".stripMargin.replaceAll("GENI", i.toString)
     }
 
@@ -308,6 +310,7 @@
       |  assign rd_rob2rt_o_GENI_vector_csr_xrm = rd_rob2rt_o[GENI].vector_csr.xrm;
       |  assign rd_rob2rt_o_GENI_vector_csr_sew = rd_rob2rt_o[GENI].vector_csr.sew;
       |  assign rd_rob2rt_o_GENI_vector_csr_lmul = rd_rob2rt_o[GENI].vector_csr.lmul;
+      |  assign rd_rob2rt_o_GENI_vector_csr_vill = rd_rob2rt_o[GENI].vector_csr.vill;
       |  assign rd_rob2rt_o_GENI_vxsaturate = rd_rob2rt_o[GENI].vxsaturate;
       |""".stripMargin.replaceAll("GENI", i.toString)
     }
@@ -331,6 +334,7 @@
     coreInstantiation += "  assign configXrm = config_state.xrm;\n"
     coreInstantiation += "  assign configSew = config_state.sew;\n"
     coreInstantiation += "  assign configLmul = config_state.lmul;\n"
+    coreInstantiation += "  assign configVill = config_state.vill;\n"
 
     moduleInterface + coreInstantiation + "endmodule\n"
   }
@@ -378,6 +382,7 @@
     val configXrm = Output(UInt(2.W))
     val configSew = Output(UInt(3.W))
     val configLmul = Output(UInt(3.W))
+    val configVill = Output(Bool())
     val rvv_idle = Output(Bool())
     val queue_capacity = Output(UInt(4.W))
   })
@@ -488,6 +493,7 @@
   io.configState.bits.xrm    := rvvCoreWrapper.io.configXrm
   io.configState.bits.sew    := rvvCoreWrapper.io.configSew
   io.configState.bits.lmul   := rvvCoreWrapper.io.configLmul
+  io.configState.bits.vill   := rvvCoreWrapper.io.configVill
   io.rvv_idle                := rvvCoreWrapper.io.rvv_idle
   io.queue_capacity          := rvvCoreWrapper.io.queue_capacity
 
diff --git a/hdl/chisel/src/kelvin/rvv/RvvInterface.scala b/hdl/chisel/src/kelvin/rvv/RvvInterface.scala
index 86ebc2c..d606cd6 100644
--- a/hdl/chisel/src/kelvin/rvv/RvvInterface.scala
+++ b/hdl/chisel/src/kelvin/rvv/RvvInterface.scala
@@ -26,13 +26,14 @@
   val xrm = Output(UInt(2.W))
   val sew = Output(UInt(3.W))
   val lmul = Output(UInt(3.W))
+  val vill = Output(Bool())
 
   /**
    * Construct the vtype CSR value.
    * See section 3.4 of the RISC-V Vector Specification v1.0.
    */
   def vtype: UInt = {
-    Cat(0.U(24.W), ma, ta, sew, lmul)
+    Cat(vill, 0.U(23.W), ma, ta, sew, lmul)
   }
 }
 
diff --git a/hdl/verilog/rvv/design/RvvFrontEnd.sv b/hdl/verilog/rvv/design/RvvFrontEnd.sv
index 3946b56..facb7d3 100644
--- a/hdl/verilog/rvv/design/RvvFrontEnd.sv
+++ b/hdl/verilog/rvv/design/RvvFrontEnd.sv
@@ -139,7 +139,6 @@
           (inst_q[i].opcode == RVV) &&
           (inst_q[i].bits[7:5] == 3'b111)) begin
         if (inst_q[i].bits[24] == 0) begin  // vsetvli
-          inst_config_state[i+1].vill = 0;
           inst_config_state[i+1].vl = reg_read_data_i[2*i];
           inst_config_state[i+1].lmul = RVVLMUL'(inst_q[i].bits[15:13]);
           inst_config_state[i+1].sew = RVVSEW'(inst_q[i].bits[18:16]);
@@ -147,7 +146,6 @@
           inst_config_state[i+1].ma = inst_q[i].bits[20];
           is_setvl[i] = 1;
         end else if (inst_q[i].bits[24:23] == 2'b11) begin  // vsetivli
-          inst_config_state[i+1].vill = 0;
           inst_config_state[i+1].vl =
               {{(`VL_WIDTH - 5){1'b0}}, inst_q[i].bits[12:8]};
           inst_config_state[i+1].lmul = RVVLMUL'(inst_q[i].bits[15:13]);
@@ -156,7 +154,6 @@
           inst_config_state[i+1].ma = inst_q[i].bits[20];
           is_setvl[i] = 1;
         end else if (inst_q[i].bits[24:23] == 2'b10) begin  // vsetvl
-          inst_config_state[i+1].vill = 0;
           inst_config_state[i+1].vl = reg_read_data_i[2*i];
           inst_config_state[i+1].lmul =
               RVVLMUL'(reg_read_data_i[(2*i) + 1][2:0]);
@@ -167,6 +164,35 @@
           is_setvl[i] = 1;
         end
       end
+
+      // Compute legality of vtype.
+      if (is_setvl[i]) begin
+        unique case (inst_config_state[i+1].sew)
+          SEW8:
+            unique case(inst_config_state[i+1].lmul)
+              LMULRESERVED: inst_config_state[i+1].vill = 1;
+              LMUL1_8: inst_config_state[i+1].vill = 1;
+              default: inst_config_state[i+1].vill = 0;
+            endcase
+          SEW16:
+            unique case(inst_config_state[i+1].lmul)
+              LMULRESERVED: inst_config_state[i+1].vill = 1;
+              LMUL1_8: inst_config_state[i+1].vill = 1;
+              LMUL1_4: inst_config_state[i+1].vill = 1;
+              default: inst_config_state[i+1].vill = 0;
+            endcase
+          SEW32:
+            unique case(inst_config_state[i+1].lmul)
+              LMULRESERVED: inst_config_state[i+1].vill = 1;
+              LMUL1_8: inst_config_state[i+1].vill = 1;
+              LMUL1_4: inst_config_state[i+1].vill = 1;
+              LMUL1_2: inst_config_state[i+1].vill = 1;
+              default: inst_config_state[i+1].vill = 0;
+            endcase
+          default: inst_config_state[i+1].vill = 1;
+        endcase
+      end
+
     end
   end
 
diff --git a/tests/cocotb/rvv_assembly_cocotb_test.py b/tests/cocotb/rvv_assembly_cocotb_test.py
index 8af90c7..c2e1aa8 100644
--- a/tests/cocotb/rvv_assembly_cocotb_test.py
+++ b/tests/cocotb/rvv_assembly_cocotb_test.py
@@ -1,5 +1,7 @@
 import cocotb
+import itertools
 import numpy as np
+import tqdm
 from kelvin_test_utils.core_mini_axi_interface import CoreMiniAxiInterface
 from kelvin_test_utils.sim_test_fixture import Fixture
 from bazel_tools.tools.python.runfiles import runfiles
@@ -10,7 +12,9 @@
     0b010,  # SEW32
 ]
 
+# See 3.4.2. Vector Register Grouping of RVV Spec
 LMULS = [
+    0b100,  # Reserved
     0b101,  # LMUL1/8
     0b110,  # LMUL1/4
     0b111,  # LMUL1/2
@@ -20,6 +24,26 @@
     0b011,  # LMUL8
 ]
 
+def _illegal_vtype(sew, lmul):
+    # SEW must be SEW8,16,32. Others are illegal
+    if not ((sew == 0b000) or (sew == 0b001) or (sew == 0b010)):
+      return True
+
+    # Reserved or LMUL=1/8 always illegal
+    if (lmul == 0b100) or (lmul == 0b101):
+      return True
+
+    # LMUL=1/4 is illegal for SEW16 and SEW32
+    if (sew != 0b000) and (lmul == 0b110):
+      return True
+
+    # LMUL=1/2 is illegal for SEW32
+    if (sew == 0b010) and (lmul == 0b111):
+      return True
+
+    return False
+
+
 @cocotb.test()
 async def core_mini_rvv_load(dut):
     """Testbench to test RVV load intrinsics.
@@ -184,10 +208,12 @@
         vl_addr = core_mini_axi.lookup_symbol(f, "vl")
         vtype_addr = core_mini_axi.lookup_symbol(f, "vtype")
 
-    for ma in range(2):
-      for ta in range(2):
-        for sew in SEWS:
-          for lmul in LMULS:
+    combined_loops = itertools.product(range(2), range(2), SEWS, LMULS)
+    total_loops = 2 * 2 * len(SEWS) * len(LMULS)
+    with tqdm.tqdm(combined_loops, total=total_loops) as t:
+        for ma, ta, sew, lmul in t:
+            t.set_postfix(
+                {'ma': ma, 'ta': ta, 'sew': bin(sew), 'lmul': bin(lmul) })
             await core_mini_axi.write_word(vma_addr, ma)
             await core_mini_axi.write_word(vta_addr, ta)
             await core_mini_axi.write_word(sew_addr, sew)
@@ -200,15 +226,24 @@
 
             vtype_result = (
                 await core_mini_axi.read_word(vtype_addr)).view(np.uint32)[0]
-            ma_result = (vtype_result & (1 << 7)) >> 7
-            ta_result = (vtype_result & (1 << 6)) >> 6
-            sew_result = (vtype_result & (0b111 << 3)) >> 3
-            lmul_result = (vtype_result & 0b111)
 
-            assert (ma == ma_result)
-            assert (ta == ta_result)
-            assert (sew == sew_result)
-            assert (lmul == lmul_result)
+            # Check if vtype is legal
+            expected_illegal = _illegal_vtype(sew, lmul)
+            result_illegal = (vtype_result & (1 << 31)) >> 31
+            assert (expected_illegal == result_illegal)
+
+            if expected_illegal:
+                ma_result = (vtype_result & (1 << 7)) >> 7
+                ta_result = (vtype_result & (1 << 6)) >> 6
+                sew_result = (vtype_result & (0b111 << 3)) >> 3
+                lmul_result = (vtype_result & 0b111)
+
+                assert (ma == ma_result)
+                assert (ta == ta_result)
+                assert (sew == sew_result)
+                assert (lmul == lmul_result)
+
+
 
 
 async def test_vstart_not_zero_failure(dut, binary):