sw:vec:tests: Add multi-register load/store tests

Add v{l,s}{1,2,4,8}re{8,16,32} tests

Change-Id: Ifec16a55e43a898553ed97ef3a9699af283083f9
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 646c272..02a410c 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -249,3 +249,12 @@
   TIMEOUT
     40
 )
+
+vec_cc_test(
+  NAME
+    vlnr_vsnr_test
+  SRCS
+    vlnr_vsnr_test.cpp
+  LINKOPTS
+    -Xlinker --defsym=__itcm_length__=128K
+)
diff --git a/tests/vlnr_vsnr_test.cpp b/tests/vlnr_vsnr_test.cpp
new file mode 100644
index 0000000..a552600
--- /dev/null
+++ b/tests/vlnr_vsnr_test.cpp
@@ -0,0 +1,146 @@
+#include <stdlib.h>
+
+#include "pw_unit_test/framework.h"
+#include "test_v_helpers.h"
+
+// Test for vl{1,2,8}re{8,16,32}.v and vs{1,2,8}r{8,16,32}.v instructions.
+namespace vlnr_vsnr_test {
+namespace {
+
+using namespace test_v_helpers;
+
+uint8_t test_vector_1[MAXVL_BYTES];
+uint8_t reference_vector_1[MAXVL_BYTES];
+
+enum VNF { NF1 = 0, NF2 = 1, NF4 = 2, NF8 = 3 };
+
+class VlnrVsnrTest : public ::testing::Test {
+ public:
+  void vsr_test(VSEW sew, VNF nf);
+
+ protected:
+  void SetUp() override { zero_vector_registers(); }
+  void TearDown() override { zero_vector_registers(); }
+};
+
+void VlnrVsnrTest::vsr_test(VSEW sew, VNF nf) {
+  int avl = get_vsetvlmax_intrinsic(SEW_E8, LMUL_M1);
+  int vlmax;
+  int vl;
+  int nf_val = 1 << nf;
+
+  std::tie(vlmax, vl) = vector_test_setup<uint8_t>(
+      LMUL_M1, avl, {test_vector_1, reference_vector_1});
+  fill_random_vector<uint8_t>(reinterpret_cast<uint8_t *>(reference_vector_1),
+                              avl * nf_val);
+  switch (nf) {
+    case NF1: {
+      switch (sew) {
+        case SEW_E8:
+          __asm__ volatile(
+              "vl1r.v v25, (%[REG])" ::[REG] "r"(reference_vector_1));
+          break;
+        case SEW_E16:
+          __asm__ volatile(
+              "vl1re16.v v25, (%[REG])" ::[REG] "r"(reference_vector_1));
+          break;
+        case SEW_E32:
+          __asm__ volatile(
+              "vl1re32.v v25, (%[REG])" ::[REG] "r"(reference_vector_1));
+          break;
+        default:
+          break;
+      }
+      __asm__ volatile("vs1r.v v25, (%[REG])" ::[REG] "r"(test_vector_1));
+      break;
+    }
+    case NF2: {
+      switch (sew) {
+        case SEW_E8:
+          __asm__ volatile(
+              "vl2r.v v26, (%[REG])" ::[REG] "r"(reference_vector_1));
+          break;
+        case SEW_E16:
+          __asm__ volatile(
+              "vl2re16.v v26, (%[REG])" ::[REG] "r"(reference_vector_1));
+          break;
+        case SEW_E32:
+          __asm__ volatile(
+              "vl2re32.v v26, (%[REG])" ::[REG] "r"(reference_vector_1));
+          break;
+        default:
+          break;
+      }
+      __asm__ volatile("vs2r.v v26, (%[REG])" ::[REG] "r"(test_vector_1));
+      break;
+    }
+    case NF4: {
+      switch (sew) {
+        case SEW_E8:
+          __asm__ volatile(
+              "vl4r.v v28, (%[REG])" ::[REG] "r"(reference_vector_1));
+          break;
+        case SEW_E16:
+          __asm__ volatile(
+              "vl4re16.v v28, (%[REG])" ::[REG] "r"(reference_vector_1));
+          break;
+        case SEW_E32:
+          __asm__ volatile(
+              "vl4re32.v v28, (%[REG])" ::[REG] "r"(reference_vector_1));
+          break;
+        default:
+          break;
+      }
+      __asm__ volatile("vs4r.v v28, (%[REG])" ::[REG] "r"(test_vector_1));
+      break;
+    }
+    case NF8: {
+      switch (sew) {
+        case SEW_E8:
+          __asm__ volatile(
+              "vl8r.v v0, (%[REG])" ::[REG] "r"(reference_vector_1));
+          break;
+        case SEW_E16:
+          __asm__ volatile(
+              "vl8re16.v v0, (%[REG])" ::[REG] "r"(reference_vector_1));
+          break;
+        case SEW_E32:
+          __asm__ volatile(
+              "vl8re32.v v0, (%[REG])" ::[REG] "r"(reference_vector_1));
+          break;
+        default:
+          break;
+      }
+      __asm__ volatile("vs8r.v v0, (%[REG])" ::[REG] "r"(test_vector_1));
+      break;
+    }
+  }
+  assert_vec_elem_eq<uint8_t>(avl * nf_val, test_vector_1, reference_vector_1);
+}
+
+TEST_F(VlnrVsnrTest, vl1re8_vs1r) { vsr_test(SEW_E8, NF1); }
+
+TEST_F(VlnrVsnrTest, vl2re8_vs2r) { vsr_test(SEW_E8, NF2); }
+
+TEST_F(VlnrVsnrTest, vl4re8_vs4r) { vsr_test(SEW_E8, NF4); }
+
+TEST_F(VlnrVsnrTest, vl8re8_vs8r) { vsr_test(SEW_E8, NF8); }
+
+TEST_F(VlnrVsnrTest, vl1re16_vs1r) { vsr_test(SEW_E16, NF1); }
+
+TEST_F(VlnrVsnrTest, vl2re16_vs2r) { vsr_test(SEW_E16, NF2); }
+
+TEST_F(VlnrVsnrTest, vl4re16_vs4r) { vsr_test(SEW_E16, NF4); }
+
+TEST_F(VlnrVsnrTest, vl8re16_vs8r) { vsr_test(SEW_E16, NF8); }
+
+TEST_F(VlnrVsnrTest, vl1re32_vs1r) { vsr_test(SEW_E32, NF1); }
+
+TEST_F(VlnrVsnrTest, vl2re32_vs2r) { vsr_test(SEW_E32, NF2); }
+
+TEST_F(VlnrVsnrTest, vl4re32_vs4r) { vsr_test(SEW_E32, NF4); }
+
+TEST_F(VlnrVsnrTest, vl8re32_vs8r) { vsr_test(SEW_E32, NF8); }
+
+}  // namespace
+}  // namespace vlnr_vsnr_test