Internal change

PiperOrigin-RevId: 550427286
diff --git a/sim/kelvin_encoding.cc b/sim/kelvin_encoding.cc
index 9bd3987..a92b6c3 100644
--- a/sim/kelvin_encoding.cc
+++ b/sim/kelvin_encoding.cc
@@ -202,6 +202,9 @@
             return new mpact::sim::generic::IntLiteralOperand<0>(
                 {1}, xreg_alias_[0]);
           }
+          // `vs1` is stored in bit[19:14], but scalar xs1 is in bit[19:15]
+          // (same as the regular riscv32 encoding)
+          reg_num >>= 1;
           return GetRegisterSourceOp<mpact::sim::riscv::RV32Register>(
               state_,
               absl::StrCat(mpact::sim::riscv::RiscVState::kXregPrefix, reg_num),
@@ -222,6 +225,9 @@
             return new mpact::sim::generic::IntLiteralOperand<0>(
                 {1}, xreg_alias_[0]);
           }
+          // `vs2` is stored in bit[26:20], but scalar xs2 is in bit[25:20]
+          // (same as in the regular riscv32 encoding)
+          reg_num = reg_num & 0x1F;
           return GetRegisterSourceOp<mpact::sim::riscv::RV32Register>(
               state_,
               absl::StrCat(mpact::sim::riscv::RiscVState::kXregPrefix, reg_num),
@@ -230,6 +236,17 @@
         return GetVectorRegisterSourceOp<mpact::sim::riscv::RVVectorRegister>(
             state_, reg_num, strip_mine, 1 /* widen_factor */);
       });
+  source_op_getters_.emplace(
+      // vst and vstq use `vd` field as the source for the vector store.
+      static_cast<int>(SourceOpEnum::kVd),
+      [this]() -> SourceOperandInterface * {
+        auto reg_num = encoding::kelvin_v2_args_type::ExtractVd(inst_word_);
+        bool strip_mine = encoding::kelvin_v2_args_type::ExtractM(inst_word_);
+        if (opcode_ < OpcodeEnum::kVstBLXx || opcode_ > OpcodeEnum::kVstqWSpXxM)
+          return nullptr;
+        return GetVectorRegisterSourceOp<mpact::sim::riscv::RVVectorRegister>(
+            state_, reg_num, strip_mine, 1 /* widen_factor */);
+      });
   source_op_getters_.insert(std::make_pair(
       static_cast<int>(SourceOpEnum::kNone), []() { return nullptr; }));
 }
diff --git a/sim/test/BUILD b/sim/test/BUILD
index f0c8147..7cf1e1d 100644
--- a/sim/test/BUILD
+++ b/sim/test/BUILD
@@ -2,6 +2,7 @@
 
 exports_files([
     "testfiles/hello_world_rv32imf.elf",
+    "testfiles/kelvin_vldvst.elf",
     "testfiles/rv32i.elf",
     "testfiles/rv32m.elf",
     "testfiles/rv32soft_fp.elf",
@@ -52,6 +53,7 @@
     data = [
         "testfiles/hello_world_mpause.elf",
         "testfiles/hello_world_rv32imf.elf",
+        "testfiles/kelvin_vldvst.elf",
         "testfiles/rv32i.elf",
         "testfiles/rv32m.elf",
         "testfiles/rv32soft_fp.elf",
diff --git a/sim/test/kelvin_top_test.cc b/sim/test/kelvin_top_test.cc
index 6b218c9..28e4b8b 100644
--- a/sim/test/kelvin_top_test.cc
+++ b/sim/test/kelvin_top_test.cc
@@ -29,6 +29,7 @@
 constexpr char kRV32mElfFileName[] = "rv32m.elf";
 constexpr char kRV32SoftFloatElfFileName[] = "rv32soft_fp.elf";
 constexpr char kRV32fElfFileName[] = "rv32uf_fadd.elf";
+constexpr char kKelvinVldVstFileName[] = "kelvin_vldvst.elf";
 
 // The depot path to the test directory.
 constexpr char kDepotPath[] = "sim/test/";
@@ -329,4 +330,18 @@
   }
 }
 
+TEST_F(KelvinTopTest, RunKelvinVectorProgram) {
+  LoadFile(kKelvinVldVstFileName);
+  testing::internal::CaptureStdout();
+  EXPECT_OK(kelvin_top_->WriteRegister("pc", entry_point_));
+  EXPECT_OK(kelvin_top_->Run());
+  EXPECT_OK(kelvin_top_->Wait());
+  auto halt_result = kelvin_top_->GetLastHaltReason();
+  CHECK_OK(halt_result);
+  EXPECT_EQ(static_cast<int>(halt_result.value()),
+            static_cast<int>(HaltReason::kUserRequest));
+  const std::string stdout_str = testing::internal::GetCapturedStdout();
+  EXPECT_THAT(stdout_str, testing::HasSubstr("vld_vst test passed!"));
+}
+
 }  // namespace
diff --git a/sim/test/testfiles/kelvin_vldvst.elf b/sim/test/testfiles/kelvin_vldvst.elf
new file mode 100755
index 0000000..34916db
--- /dev/null
+++ b/sim/test/testfiles/kelvin_vldvst.elf
Binary files differ