Extend test coverage for kelvin_encoder

PiperOrigin-RevId: 558820949
diff --git a/sim/kelvin_encoding.cc b/sim/kelvin_encoding.cc
index 9e3eee4..6f4d1dc 100644
--- a/sim/kelvin_encoding.cc
+++ b/sim/kelvin_encoding.cc
@@ -397,7 +397,7 @@
   auto sz = encoding::kelvin_v2_args_type::ExtractSz(inst_word_);
   auto func2_ignore_unsigned = func2 & (~(1u << 0));
 
-  // Func1 0b100 VAcc[u] needs 2x src1 registers.
+  // Func1 0b100 VAcc.[h,w].[u] needs 2x src1 registers.
   if ((func1 == 0b100) && (func2_ignore_unsigned == 0b1010)) {
     return 2;
   }
diff --git a/sim/test/BUILD b/sim/test/BUILD
index 6e1ac0a..76ad1e3 100644
--- a/sim/test/BUILD
+++ b/sim/test/BUILD
@@ -21,6 +21,7 @@
         "//sim:kelvin_state",
         "@com_google_googletest//:gtest_main",
         "@com_google_mpact-riscv//riscv:riscv_state",
+        "@com_google_mpact-sim//mpact/sim/generic:arch_state",
     ],
 )
 
diff --git a/sim/test/kelvin_encoding_test.cc b/sim/test/kelvin_encoding_test.cc
index 66ec918..d962321 100644
--- a/sim/test/kelvin_encoding_test.cc
+++ b/sim/test/kelvin_encoding_test.cc
@@ -1,11 +1,14 @@
 #include "sim/kelvin_encoding.h"
 
+#include <any>
 #include <cstdint>
+#include <type_traits>
 
 #include "sim/kelvin_enums.h"
 #include "sim/kelvin_state.h"
 #include "googletest/include/gtest/gtest.h"
 #include "riscv/riscv_register.h"
+#include "mpact/sim/generic/register.h"
 
 namespace {
 
@@ -15,6 +18,11 @@
 using OpcodeEnum = kelvin::sim::isa32::OpcodeEnum;
 using SourceOpEnum = kelvin::sim::isa32::SourceOpEnum;
 using RV32VectorSourceOperand = mpact::sim::riscv::RV32VectorSourceOperand;
+using RV32SourceOperand = mpact::sim::generic::RegisterSourceOperand<uint64_t>;
+using DestOpEnum = kelvin::sim::isa32::DestOpEnum;
+using RV32VectorDestOperand = mpact::sim::riscv::RV32VectorDestinationOperand;
+using RV32DestOperand =
+    mpact::sim::generic::RegisterDestinationOperand<uint64_t>;
 
 // RV32I
 constexpr uint32_t kLui = 0b0000000000000000000000000'0110111;
@@ -100,13 +108,20 @@
     delete state_;
   }
 
-  RV32VectorSourceOperand *VectorSourceEncodeHelper(
-      uint32_t inst_word, OpcodeEnum opcode, SourceOpEnum source_op) const {
+  template <typename T>
+  T *EncodeOpHelper(uint32_t inst_word, OpcodeEnum opcode, std::any op) const {
     enc_->ParseInstruction(inst_word);
     EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), opcode);
-    auto source = enc_->GetSource(SlotEnum::kKelvin, 0, opcode, source_op, 0);
-    return reinterpret_cast<mpact::sim::riscv::RV32VectorSourceOperand *>(
-        source);
+    if (std::is_same<T, RV32SourceOperand>::value ||
+        std::is_same<T, RV32VectorSourceOperand>::value) {
+      auto *source = enc_->GetSource(SlotEnum::kKelvin, 0, opcode,
+                                     std::any_cast<SourceOpEnum>(op), 0);
+      return reinterpret_cast<T *>(source);
+    }
+    auto *dest = enc_->GetDestination(SlotEnum::kKelvin, 0, opcode,
+                                      std::any_cast<DestOpEnum>(op), 0,
+                                      /*latency=*/0);
+    return reinterpret_cast<T *>(dest);
   }
 
   KelvinState *state_;
@@ -137,6 +152,10 @@
   return (iword | ((succ & 0xf) << 20));
 }
 
+static inline uint32_t SetSz(uint32_t iword, uint32_t sz) {
+  return (iword | ((sz & 0x3) << 12));
+}
+
 TEST_F(KelvinEncodingTest, RV32IOpcodes) {
   enc_->ParseInstruction(SetRd(kLui, kRdValue));
   EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kLui);
@@ -252,16 +271,6 @@
   EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kKlog);
 }
 
-TEST_F(KelvinEncodingTest, KelvinVldOpcodes) {
-  enc_->ParseInstruction(SetRs1(kVld, kRdValue));
-  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kVldBX);
-  enc_->ParseInstruction(SetRs1(kVld, kRdValue) | (0b01 << 12 /* sz */));
-  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kVldHX);
-  enc_->ParseInstruction(SetRs1(kVld, kRdValue) | (0b10 << 12 /* sz */) |
-                         (0b10 << 20 /* xs2 */) | (0b1 << 26 /* length */));
-  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kVldWLXx);
-}
-
 TEST_F(KelvinEncodingTest, ZifenceiOpcodes) {
   // RV32 Zifencei
   enc_->ParseInstruction(kFencei);
@@ -316,40 +325,160 @@
   EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kRemu);
 }
 
-TEST_F(KelvinEncodingTest, VsraxsWideningVs1) {
+TEST_F(KelvinEncodingTest, KelvinVldEncodeXs1Xs2) {
+  enc_->ParseInstruction(SetRs1(kVld, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kVldBX);
+  enc_->ParseInstruction(SetSz(SetRs1(kVld, kRdValue), 0b1));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kVldHX);
+  // Test vld.w.l.xx
+  auto *src = EncodeOpHelper<RV32SourceOperand>(
+      SetSz(SetRs1(kVld, kRdValue), 0b10) | (0b10 << 20 /* xs2 */) |
+          (0b1 << 26 /* length */),
+      OpcodeEnum::kVldWLXx, SourceOpEnum::kVs1);
+  EXPECT_EQ(src->AsString(), "ra");
+  delete src;
+  src = EncodeOpHelper<RV32SourceOperand>(
+      SetSz(SetRs1(kVld, kRdValue), 0b10) | (0b10 << 20 /* xs2 */) |
+          (0b1 << 26 /* length */),
+      OpcodeEnum::kVldWLXx, SourceOpEnum::kVs2);
+  EXPECT_EQ(src->AsString(), "sp");
+  delete src;
+}
+
+TEST_F(KelvinEncodingTest, KelvinVstEncodeXs1Xs2Vd) {
+  constexpr uint32_t kVstBase = 0b001000'000000'000000'00'000000'0'111'11;
+  // Test vd in vst.b.x as source
+  auto *v_src = EncodeOpHelper<RV32VectorSourceOperand>(
+      SetRs1(kVstBase, kRdValue), OpcodeEnum::kVstBX, SourceOpEnum::kVd);
+  EXPECT_EQ(v_src->AsString(), "v0");
+  delete v_src;
+
+  // Test xs1 in vst.w.l.xx as destination
+  auto *dest = EncodeOpHelper<RV32DestOperand>(
+      SetSz(SetRs1(kVstBase, kRdValue), 0b10) | (0b10 << 20 /* xs2 */) |
+          (1 << 26 /* length */),
+      OpcodeEnum::kVstWLXx, DestOpEnum::kVs1);
+  EXPECT_EQ(dest->AsString(), "ra");
+  delete dest;
+
+  // Test xs2 in vstq.b.s.xx as source
+  auto *src = EncodeOpHelper<RV32SourceOperand>(
+      SetRs1(kVstBase, kRdValue) | (1 << 30 /* vstq */) |
+          (0b10 << 20 /* xs2 */) | (1 << 27 /* stride */),
+      OpcodeEnum::kVstqBSXx, SourceOpEnum::kVs2);
+  EXPECT_EQ(src->AsString(), "sp");
+  delete src;
+}
+
+TEST_F(KelvinEncodingTest, KelvinWideningVs1) {
   constexpr uint32_t kVSransBase = 0b010000'000001'000000'00'001000'0'010'00;
-  auto v_src = VectorSourceEncodeHelper(kVSransBase, OpcodeEnum::kVsransBVv,
-                                        SourceOpEnum::kVs1);
+  auto *v_src = EncodeOpHelper<RV32VectorSourceOperand>(
+      kVSransBase, OpcodeEnum::kVsransBVv, SourceOpEnum::kVs1);
   EXPECT_EQ(v_src->size(), 2);
   delete v_src;
 
   // Test vsrans.b.r.vv
-  v_src = VectorSourceEncodeHelper(kVSransBase | (1 << 27),
-                                   OpcodeEnum::kVsransBRVv, SourceOpEnum::kVs1);
+  v_src = EncodeOpHelper<RV32VectorSourceOperand>(
+      kVSransBase | (1 << 27 /* vsrans.r */), OpcodeEnum::kVsransBRVv,
+      SourceOpEnum::kVs1);
   EXPECT_EQ(v_src->size(), 2);
   delete v_src;
 
   // Test vsrans.h.vv
-  v_src = VectorSourceEncodeHelper(kVSransBase | (1 << 12),
-                                   OpcodeEnum::kVsransHVv, SourceOpEnum::kVs1);
+  v_src = EncodeOpHelper<RV32VectorSourceOperand>(
+      SetSz(kVSransBase, 0b1), OpcodeEnum::kVsransHVv, SourceOpEnum::kVs1);
   EXPECT_EQ(v_src->size(), 2);
   delete v_src;
 
   // Test vsraqs.b.vv
-  v_src = VectorSourceEncodeHelper(kVSransBase | (1 << 29),
-                                   OpcodeEnum::kVsraqsBVv, SourceOpEnum::kVs1);
+  v_src = EncodeOpHelper<RV32VectorSourceOperand>(
+      kVSransBase | (1 << 29 /* vsraqs */), OpcodeEnum::kVsraqsBVv,
+      SourceOpEnum::kVs1);
   EXPECT_EQ(v_src->size(), 4);
   delete v_src;
 
   // Test vsraqs.b.r.vv
-  v_src = VectorSourceEncodeHelper(kVSransBase | (1 << 29) | (1 << 27),
-                                   OpcodeEnum::kVsraqsBRVv, SourceOpEnum::kVs1);
+  v_src = EncodeOpHelper<RV32VectorSourceOperand>(
+      kVSransBase | (1 << 29) | (1 << 27), OpcodeEnum::kVsraqsBRVv,
+      SourceOpEnum::kVs1);
   EXPECT_EQ(v_src->size(), 4);
   delete v_src;
 
   // Test illegal vsrans (vsrans.w.vv)
-  enc_->ParseInstruction(kVSransBase | (2 << 12));
+  enc_->ParseInstruction(SetSz(kVSransBase, 0b10));
   EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kNone);
+
+  // Test vacc.h.vv
+  constexpr uint32_t kVAccsBase = 0b001010'000001'000000'00'001000'0'100'00;
+  v_src = EncodeOpHelper<RV32VectorSourceOperand>(
+      SetSz(kVAccsBase, 0b1), OpcodeEnum::kVaccHVv, SourceOpEnum::kVs1);
+  EXPECT_EQ(v_src->size(), 2);
+  delete v_src;
+
+  // Test vacc.w.u.vv
+  v_src = EncodeOpHelper<RV32VectorSourceOperand>(
+      SetSz(kVAccsBase, 0b10) | (1 << 26), OpcodeEnum::kVaccWUVv,
+      SourceOpEnum::kVs1);
+  EXPECT_EQ(v_src->size(), 2);
+  delete v_src;
+}
+
+TEST_F(KelvinEncodingTest, KelvinWideningVd) {
+  // No widening for vld
+  auto *v_dest = EncodeOpHelper<RV32VectorDestOperand>(
+      SetRs1(kVld, kRdValue), OpcodeEnum::kVldBX, DestOpEnum::kVd);
+  EXPECT_EQ(v_dest->size(), 1);
+  delete v_dest;
+
+  // Test vaddw.h.vv
+  constexpr uint32_t kVAddwBase = 0b000100'000001'000000'00'001000'0'100'00;
+  v_dest = EncodeOpHelper<RV32VectorDestOperand>(
+      SetSz(kVAddwBase, 0b1), OpcodeEnum::kVaddwHVv, DestOpEnum::kVd);
+  EXPECT_EQ(v_dest->size(), 2);
+  delete v_dest;
+
+  // Test vsubw.w.u.vv
+  v_dest = EncodeOpHelper<RV32VectorDestOperand>(
+      SetSz(kVAddwBase, 0b10) | (0b11 << 26 /* vsubw.u */),
+      OpcodeEnum::kVsubwWUVv, DestOpEnum::kVd);
+  EXPECT_EQ(v_dest->size(), 2);
+  delete v_dest;
+
+  // Test vmvp.vv
+  constexpr uint32_t kVMvpBase = 0b001101'000001'000000'00'001000'0'001'00;
+  v_dest = EncodeOpHelper<RV32VectorDestOperand>(kVMvpBase, OpcodeEnum::kVmvpVv,
+                                                 DestOpEnum::kVd);
+  EXPECT_EQ(v_dest->size(), 2);
+  delete v_dest;
+
+  // Test vmulw.h.vv
+  constexpr uint32_t kVMulwBase = 0b000100'000001'000000'00'001000'0'011'00;
+  v_dest = EncodeOpHelper<RV32VectorDestOperand>(
+      SetSz(kVMulwBase, 0b1), OpcodeEnum::kVmulwHVv, DestOpEnum::kVd);
+  EXPECT_EQ(v_dest->size(), 2);
+  delete v_dest;
+
+  // Test vmulw.w.u.vv
+  v_dest = EncodeOpHelper<RV32VectorDestOperand>(
+      SetSz(kVMulwBase, 0b10) | (1 << 26 /* vmulw.u */), OpcodeEnum::kVmulwWUVv,
+      DestOpEnum::kVd);
+  EXPECT_EQ(v_dest->size(), 2);
+  delete v_dest;
+
+  // Test vevnodd.b.vv
+  constexpr uint32_t kVEvnoddBase = 0b011000'000001'000000'00'001000'0'110'00;
+  v_dest = EncodeOpHelper<RV32VectorDestOperand>(
+      kVEvnoddBase | (0b10 << 26 /* vevenodd */), OpcodeEnum::kVevnoddBVv,
+      DestOpEnum::kVd);
+  EXPECT_EQ(v_dest->size(), 2);
+  delete v_dest;
+
+  // Test vzip.h.vv
+  v_dest = EncodeOpHelper<RV32VectorDestOperand>(
+      SetSz(kVEvnoddBase, 0b1) | (0b100 << 26 /* vzip */), OpcodeEnum::kVzipHVv,
+      DestOpEnum::kVd);
+  EXPECT_EQ(v_dest->size(), 2);
+  delete v_dest;
 }
 
 }  // namespace