V-Ext: Tests for vle8 and vse8

* Verification of a simple load then store.
* Adds tests for multiple VL and LMUL values.

Tests were verified to pass in Qemu.

Change-Id: Icf0cb445534b0de60aadfc9aff0aeadb29329dc3
diff --git a/CMakeLists.txt b/CMakeLists.txt
index cd80428..e7acefb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -36,4 +36,7 @@
 
 add_subdirectory(pw_unit_test_demo)
 
+add_subdirectory(test_v_helpers)
+
 add_subdirectory(test_vsetvl)
+add_subdirectory(test_vle_vse)
diff --git a/cmake/vec_cc_test.cmake b/cmake/vec_cc_test.cmake
index ff355ba..332a085 100644
--- a/cmake/vec_cc_test.cmake
+++ b/cmake/vec_cc_test.cmake
@@ -20,6 +20,7 @@
       pw_unit_test
       pw_unit_test.main
       pw_assert_basic
+      test_v_helpers
       ${_RULE_DEPS}
   LINKOPTS
     ${_RULE_LINKOPTS}
diff --git a/test_v_helpers/CMakeLists.txt b/test_v_helpers/CMakeLists.txt
new file mode 100644
index 0000000..5a3b3ce
--- /dev/null
+++ b/test_v_helpers/CMakeLists.txt
@@ -0,0 +1,9 @@
+
+add_library(test_v_helpers
+	test_v_helpers.cpp)
+
+target_include_directories(test_v_helpers PUBLIC include)
+
+target_compile_options(test_v_helpers PUBLIC
+      ${VEC_DEFAULT_COPTS}
+)
diff --git a/test_v_helpers/include/test_v_helpers.h b/test_v_helpers/include/test_v_helpers.h
new file mode 100644
index 0000000..25d8975
--- /dev/null
+++ b/test_v_helpers/include/test_v_helpers.h
@@ -0,0 +1,35 @@
+#ifndef TEST_V_HELPERS_H
+#define TEST_V_HELPERS_H
+
+namespace test_v_helpers {
+
+enum VSEW {
+  SEW_E8 = 0,
+  SEW_E16 = 1,
+  SEW_E32 = 2,
+/* // SEW limited to E32
+  SEW_E64 = 3,
+  SEW_E128 = 4,
+  SEW_E256 = 5,
+  SEW_E512 = 6,
+  SEW_E1024 = 7,
+*/
+};
+
+enum VLMUL {
+
+/* // Fractional LMUL not supported by our compiler
+  LMUL_MF8 = 5,
+  LMUL_MF4 = 6,
+  LMUL_MF2 = 7,
+*/
+  LMUL_M1 = 0,
+  LMUL_M2 = 1,
+  LMUL_M4 = 2,
+  LMUL_M8 = 3,
+};
+
+int set_vsetvl_intrinsic(VSEW sew, VLMUL lmul, uint32_t avl);
+
+}
+#endif
\ No newline at end of file
diff --git a/test_v_helpers/test_v_helpers.cpp b/test_v_helpers/test_v_helpers.cpp
new file mode 100644
index 0000000..6d91c16
--- /dev/null
+++ b/test_v_helpers/test_v_helpers.cpp
@@ -0,0 +1,78 @@
+#include <riscv_vector.h>
+#include "test_v_helpers.h"
+
+
+namespace test_v_helpers {
+
+int set_vsetvl_intrinsic(VSEW sew, VLMUL lmul, uint32_t avl) {
+  switch(lmul) {
+    case VLMUL::LMUL_M1:
+      switch(sew) {
+        case VSEW::SEW_E8:
+          return vsetvl_e8m1(avl);
+          break;
+        case VSEW::SEW_E16:
+          return vsetvl_e16m1(avl);
+          break;
+        case VSEW::SEW_E32:
+          return vsetvl_e32m1(avl);
+          break;
+        default:
+          return -1;
+          break;
+      }
+      break;
+    case VLMUL::LMUL_M2:
+      switch(sew) {
+        case VSEW::SEW_E8:
+          return vsetvl_e8m2(avl);
+          break;
+        case VSEW::SEW_E16:
+          return vsetvl_e16m2(avl);
+          break;
+        case VSEW::SEW_E32:
+          return vsetvl_e32m2(avl);
+          break;
+        default:
+          return -1;
+          break;
+      }
+    case VLMUL::LMUL_M4:
+      switch(sew) {
+        case VSEW::SEW_E8:
+          return vsetvl_e8m4(avl);
+          break;
+        case VSEW::SEW_E16:
+          return vsetvl_e16m4(avl);
+          break;
+        case VSEW::SEW_E32:
+          return vsetvl_e32m4(avl);
+          break;
+        default:
+          return -1;
+          break;
+      }
+      break;
+    case VLMUL::LMUL_M8:
+      switch(sew) {
+        case VSEW::SEW_E8:
+          return vsetvl_e8m8(avl);
+          break;
+        case VSEW::SEW_E16:
+          return vsetvl_e16m8(avl);
+          break;
+        case VSEW::SEW_E32:
+          return vsetvl_e32m8(avl);
+          break;
+        default:
+          return -1;
+          break;
+      }
+      break;
+    default:
+      break;
+  }
+  return -1;
+}
+
+}
\ No newline at end of file
diff --git a/test_vle_vse/CMakeLists.txt b/test_vle_vse/CMakeLists.txt
new file mode 100644
index 0000000..8a98026
--- /dev/null
+++ b/test_vle_vse/CMakeLists.txt
@@ -0,0 +1,12 @@
+
+vec_cc_test(
+  NAME
+    test_vle_vse
+  SRCS
+    test_vle_vse.cpp
+  DEPS
+    springbok
+  LINKOPTS
+   -T${LINKER_SCRIPT}
+   -Xlinker --defsym=__itcm_length__=256K
+)
diff --git a/test_vle_vse/test_vle_vse.cpp b/test_vle_vse/test_vle_vse.cpp
new file mode 100644
index 0000000..e2a9152
--- /dev/null
+++ b/test_vle_vse/test_vle_vse.cpp
@@ -0,0 +1,143 @@
+#include <riscv_vector.h>
+#include <stddef.h>
+#include <springbok_intrinsics.h>
+
+#include "test_v_helpers.h"
+#include "pw_unit_test/framework.h"
+
+namespace vle_vse_test {
+namespace {
+
+using namespace test_v_helpers;
+
+const int VLEN = 512u;
+const int ELEN = 32u;
+const int LMUL_MAX = 8u;
+const int MAXVL_BYTES = VLEN / sizeof(uint8_t) * LMUL_MAX;
+const int AVL_STEP = 4;
+
+uint8_t test_vector_1[MAXVL_BYTES];
+uint8_t test_vector_2[MAXVL_BYTES];
+
+static int get_vsetvlmax(VSEW sew, VLMUL lmul) {
+  switch(lmul) {
+    case VLMUL::LMUL_M1:
+      switch(sew) {
+        case VSEW::SEW_E8:
+          return vsetvlmax_e8m1();
+          break;
+        case VSEW::SEW_E16:
+          return vsetvlmax_e16m1();
+          break;
+        case VSEW::SEW_E32:
+          return vsetvlmax_e32m1();
+          break;
+        default:
+          return -1;
+          break;
+      }
+      break;
+    case VLMUL::LMUL_M2:
+      switch(sew) {
+        case VSEW::SEW_E8:
+          return vsetvlmax_e8m2();
+          break;
+        case VSEW::SEW_E16:
+          return vsetvlmax_e16m2();
+          break;
+        case VSEW::SEW_E32:
+          return vsetvlmax_e32m2();
+          break;
+        default:
+          return -1;
+          break;
+      }
+    case VLMUL::LMUL_M4:
+      switch(sew) {
+        case VSEW::SEW_E8:
+          return vsetvlmax_e8m4();
+          break;
+        case VSEW::SEW_E16:
+          return vsetvlmax_e16m4();
+          break;
+        case VSEW::SEW_E32:
+          return vsetvlmax_e32m4();
+          break;
+        default:
+          return -1;
+          break;
+      }
+      break;
+    case VLMUL::LMUL_M8:
+      switch(sew) {
+        case VSEW::SEW_E8:
+          return vsetvlmax_e8m8();
+          break;
+        case VSEW::SEW_E16:
+          return vsetvlmax_e16m8();
+          break;
+        case VSEW::SEW_E32:
+          return vsetvlmax_e32m8();
+          break;
+        default:
+          return -1;
+          break;
+      }
+      break;
+    default:
+      break;
+  }
+  return -1;
+}
+
+
+static void vle8vse8_test(VSEW sew, VLMUL lmul, bool use_intrinsic) {
+  int vlmax = get_vsetvlmax(sew, lmul);
+
+  for (int avl = 0; avl <= vlmax; avl+=AVL_STEP) {
+    // clear arrays
+    memset(test_vector_1, 0, MAXVL_BYTES);
+    memset(test_vector_2, 0, MAXVL_BYTES);
+    int vl = set_vsetvl_intrinsic(sew, lmul, avl);
+    EXPECT_EQ(avl, vl);
+    uint8_t *dest = (uint8_t *)test_vector_1;
+    for (int idx = 0; idx < vl; idx++) {
+      dest[idx] = idx;
+    }
+
+    // load c-array values into vector
+    // TODO(gkielian): utilize intrinsics for vle
+    if (use_intrinsic) {
+
+    } else {
+      __asm__ volatile("vle8.v v0, (%0)" : : "r" (test_vector_1));
+
+      // 2) store the vector back into memory (into result c-array)
+      __asm__ volatile("vse8.v v0, (%0)" : : "r" (test_vector_2));
+      }
+    for(int idx = 0; idx < MAXVL_BYTES; idx++)
+    {
+      EXPECT_EQ(test_vector_1[idx], test_vector_2[idx]);
+    }
+  }
+}
+
+TEST(VleVseTest, vle8vse8_e8m1) {
+  vle8vse8_test(VSEW::SEW_E8, VLMUL::LMUL_M1, false);
+}
+
+TEST(VleVseTest, vle8vse8_e8m2) {
+  vle8vse8_test(VSEW::SEW_E8, VLMUL::LMUL_M2, false);
+}
+
+TEST(VleVseTest, vle8vse8_e8m4) {
+  vle8vse8_test(VSEW::SEW_E8, VLMUL::LMUL_M4, false);
+}
+
+TEST(VleVseTest, vle8vse8_e8m8) {
+  vle8vse8_test(VSEW::SEW_E8, VLMUL::LMUL_M8, false);
+}
+
+}  // namespace
+}  // namespace test_vle_vse
+