Fix `vsrans.h` support

Add encoding unit test coverage

PiperOrigin-RevId: 558201551
diff --git a/sim/kelvin_encoding.cc b/sim/kelvin_encoding.cc
index 53047f0..9e3eee4 100644
--- a/sim/kelvin_encoding.cc
+++ b/sim/kelvin_encoding.cc
@@ -402,14 +402,14 @@
     return 2;
   }
 
-  // Func1 0b010 VSrans[u][.r] also needs 2x src1 registers.
-  if ((func1 == 0b010) && (sz == 0) &&
+  // Func1 0b010 VSrans.[b,h].[u][.r] also needs 2x src1 registers.
+  if ((func1 == 0b010) && ((sz == 0) || (sz == 1)) &&
       (func2_ignore_unsigned == 0b010000 ||
        func2_ignore_unsigned == 0b010010)) {
     return 2;
   }
 
-  // Func1 0b010 VSraqs[u][.r] needs 4x src1 registers.
+  // Func1 0b010 VSraqs.b.[u][.r] needs 4x src1 registers.
   if ((func1 == 0b010) && (sz == 0) &&
       (func2_ignore_unsigned == 0b011000 ||
        func2_ignore_unsigned == 0b011010)) {
diff --git a/sim/test/BUILD b/sim/test/BUILD
index 73a0b56..6e1ac0a 100644
--- a/sim/test/BUILD
+++ b/sim/test/BUILD
@@ -17,8 +17,10 @@
     ],
     deps = [
         "//sim:kelvin_decoder",
+        "//sim:kelvin_isa",
         "//sim:kelvin_state",
         "@com_google_googletest//:gtest_main",
+        "@com_google_mpact-riscv//riscv:riscv_state",
     ],
 )
 
diff --git a/sim/test/kelvin_encoding_test.cc b/sim/test/kelvin_encoding_test.cc
index 0037c7b..66ec918 100644
--- a/sim/test/kelvin_encoding_test.cc
+++ b/sim/test/kelvin_encoding_test.cc
@@ -1,7 +1,11 @@
 #include "sim/kelvin_encoding.h"
 
+#include <cstdint>
+
+#include "sim/kelvin_enums.h"
 #include "sim/kelvin_state.h"
 #include "googletest/include/gtest/gtest.h"
+#include "riscv/riscv_register.h"
 
 namespace {
 
@@ -9,6 +13,8 @@
 using kelvin::sim::isa32::KelvinEncoding;
 using SlotEnum = kelvin::sim::isa32::SlotEnum;
 using OpcodeEnum = kelvin::sim::isa32::OpcodeEnum;
+using SourceOpEnum = kelvin::sim::isa32::SourceOpEnum;
+using RV32VectorSourceOperand = mpact::sim::riscv::RV32VectorSourceOperand;
 
 // RV32I
 constexpr uint32_t kLui = 0b0000000000000000000000000'0110111;
@@ -94,6 +100,15 @@
     delete state_;
   }
 
+  RV32VectorSourceOperand *VectorSourceEncodeHelper(
+      uint32_t inst_word, OpcodeEnum opcode, SourceOpEnum source_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);
+  }
+
   KelvinState *state_;
   KelvinEncoding *enc_;
 };
@@ -300,4 +315,41 @@
   enc_->ParseInstruction(kRemu);
   EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kRemu);
 }
+
+TEST_F(KelvinEncodingTest, VsraxsWideningVs1) {
+  constexpr uint32_t kVSransBase = 0b010000'000001'000000'00'001000'0'010'00;
+  auto v_src = VectorSourceEncodeHelper(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);
+  EXPECT_EQ(v_src->size(), 2);
+  delete v_src;
+
+  // Test vsrans.h.vv
+  v_src = VectorSourceEncodeHelper(kVSransBase | (1 << 12),
+                                   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);
+  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);
+  EXPECT_EQ(v_src->size(), 4);
+  delete v_src;
+
+  // Test illegal vsrans (vsrans.w.vv)
+  enc_->ParseInstruction(kVSransBase | (2 << 12));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kNone);
+}
+
 }  // namespace