Merge "Move generator script to top-level directory."
diff --git a/softrvv/include/softrvv.h b/softrvv/include/softrvv.h
index df7f591..0edbf3c 100644
--- a/softrvv/include/softrvv.h
+++ b/softrvv/include/softrvv.h
@@ -5,6 +5,7 @@
 
 #include "encoding.h"
 #include "softrvv_vadd.h"
+#include "softrvv_vmin.h"
 #include "softrvv_vsub.h"
 #include "softrvv_vwadd.h"
 #include "softrvv_vwsub.h"
diff --git a/softrvv/include/softrvv_vmin.h b/softrvv/include/softrvv_vmin.h
new file mode 100644
index 0000000..d853455
--- /dev/null
+++ b/softrvv/include/softrvv_vmin.h
@@ -0,0 +1,25 @@
+#ifndef SOFTRVV_VMIN_H
+#define SOFTRVV_VMIN_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+namespace softrvv {
+
+template <typename T>
+void vmin_vx(T *dest, T *src1, const T *src2, int32_t avl) {
+  for (int32_t idx = 0; idx < avl; idx++) {
+    dest[idx] = (src1[idx] < *src2) ? src1[idx] : *src2;
+  }
+}
+
+template <typename T>
+void vmin_vv(T *dest, T *src1, T *src2, int32_t avl) {
+  for (int32_t idx = 0; idx < avl; idx++) {
+    dest[idx] = (src1[idx] < src2[idx]) ? src1[idx] : src2[idx];
+  }
+}
+
+}  // namespace softrvv
+
+#endif  // SOFTRVV_VMIN_H
diff --git a/softrvv/tests/CMakeLists.txt b/softrvv/tests/CMakeLists.txt
index 9156040..edb6575 100644
--- a/softrvv/tests/CMakeLists.txt
+++ b/softrvv/tests/CMakeLists.txt
@@ -97,3 +97,14 @@
   LINKOPTS
    -Xlinker --defsym=__itcm_length__=128K
 )
+
+vec_cc_test(
+  NAME
+    softrvv_vmin
+  SRCS
+    softrvv_vmin_test.cpp
+  DEPS
+    softrvv
+  LINKOPTS
+   -Xlinker --defsym=__itcm_length__=128K
+)
diff --git a/softrvv/tests/softrvv_vmin_test.cpp b/softrvv/tests/softrvv_vmin_test.cpp
new file mode 100644
index 0000000..c3852f7
--- /dev/null
+++ b/softrvv/tests/softrvv_vmin_test.cpp
@@ -0,0 +1,48 @@
+#include <riscv_vector.h>
+#include <springbok.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "pw_unit_test/framework.h"
+#include "softrvv.h"
+
+namespace softrvv_vmin_test {
+namespace {
+
+// common to all tests
+int32_t src1[] = {-1, 2, 3, 4, 5};
+
+// vector test
+int32_t src2[] = {5, 4, 3, 2, 1};
+
+// scalar register tests
+int32_t rs1[] = {1, 3, 5};
+
+};  // namespace
+const int32_t kAVL = sizeof(src1) / sizeof(src1[0]);
+int32_t dest[kAVL];
+
+int32_t ref_vv[] = {-1, 2, 3, 2, 1};
+
+int32_t ref_vx[3][kAVL] = {{-1, 1, 1, 1, 1}, {-1, 2, 3, 3, 3}, {-1, 2, 3, 4, 5}};
+
+class SoftRvvVminTest : public ::testing::Test {
+ protected:
+  void SetUp() override { memset(dest, 0, sizeof(dest)); }
+};
+
+TEST_F(SoftRvvVminTest, VV) {
+  softrvv::vmin_vv<int32_t>(dest, src1, src2, kAVL);
+  ASSERT_EQ(memcmp(dest, ref_vv, sizeof(dest)), 0);
+}
+
+TEST_F(SoftRvvVminTest, VX) {
+  const int32_t num_vx_tests = sizeof(ref_vx) / sizeof(ref_vx[0]);
+  for (int32_t i = 0; i < num_vx_tests; i++) {
+    softrvv::vmin_vx<int32_t>(dest, src1, &rs1[i], kAVL);
+    ASSERT_EQ(memcmp(dest, &ref_vx[i], sizeof(dest)), 0);
+  }
+}
+
+}  // namespace softrvv_vmin_test
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index b2d178e..1ec4a36 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -44,6 +44,26 @@
 
 vec_cc_generated_test(
   NAME
+    vmin
+  OPFMT
+    OPIVV
+    OPIVX
+  LINKOPTS
+   -Xlinker --defsym=__itcm_length__=128K
+)
+
+vec_cc_generated_test(
+  NAME
+    vminu
+  OPFMT
+    OPIVV
+    OPIVX
+  LINKOPTS
+   -Xlinker --defsym=__itcm_length__=128K
+)
+
+vec_cc_generated_test(
+  NAME
     vwadd
   OPFMT
     OPIVV
diff --git a/tests/vsetvl_test.cpp b/tests/vsetvl_test.cpp
index 6ea9b73..0aedb0a 100644
--- a/tests/vsetvl_test.cpp
+++ b/tests/vsetvl_test.cpp
@@ -90,6 +90,31 @@
   test_vsetvl(VSEW::SEW_E32, VLMUL::LMUL_M8, 32, 8.0);
 }
 
+TEST(VsetvlTest, vsetvl_e8mf2) {
+  test_vsetvl(VSEW::SEW_E8, VLMUL::LMUL_MF2, 8, 0.5);
+}
+
+TEST(VsetvlTest, vsetvl_e8mf4) {
+  test_vsetvl(VSEW::SEW_E8, VLMUL::LMUL_MF4, 8, 0.25);
+}
+
+TEST(VsetvlTest, vsetvl_e16mf2) {
+  test_vsetvl(VSEW::SEW_E16, VLMUL::LMUL_MF2, 16, 0.5);
+}
+
+// The tests pass on Renode but fail on Qemu.
+TEST(VsetvlTest, DISABLED_vsetvl_e8mf8) {
+  test_vsetvl(VSEW::SEW_E8, VLMUL::LMUL_MF8, 8, 0.125);
+}
+
+TEST(VsetvlTest, DISABLED_vsetvl_e16m4) {
+  test_vsetvl(VSEW::SEW_E16, VLMUL::LMUL_MF4, 16, 0.25);
+}
+
+TEST(VsetvlTest, DISABLED_vsetvl_e32mf2) {
+  test_vsetvl(VSEW::SEW_E32, VLMUL::LMUL_MF2, 32, 0.5);
+}
+
 TEST(VsetvlTest, vsetvlmax_e8m1) {
   test_vsetvlmax(VSEW::SEW_E8, VLMUL::LMUL_M1, 8, 1.0);
 }
@@ -138,5 +163,30 @@
   test_vsetvlmax(VSEW::SEW_E32, VLMUL::LMUL_M8, 32, 8.0);
 }
 
+TEST(VsetvlTest, vsetvlmax_e8mf2) {
+  test_vsetvlmax(VSEW::SEW_E8, VLMUL::LMUL_MF2, 8, 0.5);
+}
+
+TEST(VsetvlTest, vsetvlmax_e8mf4) {
+  test_vsetvlmax(VSEW::SEW_E8, VLMUL::LMUL_MF4, 8, 0.25);
+}
+
+TEST(VsetvlTest, vsetvlmax_e16mf2) {
+  test_vsetvlmax(VSEW::SEW_E16, VLMUL::LMUL_MF2, 16, 0.5);
+}
+
+// The tests pass on Renode but fail on Qemu.
+TEST(VsetvlTest, DISABLED_vsetvlmax_e8mf8) {
+  test_vsetvlmax(VSEW::SEW_E8, VLMUL::LMUL_MF8, 8, 0.125);
+}
+
+TEST(VsetvlTest, DISABLED_vsetvlmax_e16m4) {
+  test_vsetvlmax(VSEW::SEW_E16, VLMUL::LMUL_MF4, 16, 0.25);
+}
+
+TEST(VsetvlTest, DISABLED_vsetvlmax_e32mf2) {
+  test_vsetvlmax(VSEW::SEW_E32, VLMUL::LMUL_MF2, 32, 0.5);
+}
+
 }  // namespace
 }  // namespace vsetvl_test