Merge "Add MACC tests."
diff --git a/scripts/test_runner.py b/scripts/test_runner.py
index 5941830..f9e3c72 100755
--- a/scripts/test_runner.py
+++ b/scripts/test_runner.py
@@ -2,6 +2,7 @@
"""Runs test within Qemu and Renode simulators."""
import argparse
import os
+import re
import sys
import tempfile
@@ -120,10 +121,20 @@
simulator_class = Simulators[args.simulator]
simulator = simulator_class(simulator_path, args.elf)
output = simulator.run(timeout=args.timeout)
+ # mono API generates escape characters at the termination. Need to clean up.
+ # TODO(hcindyl): Remove this when Renode fix the mono call.
+ ansi_escape = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])")
+ output = ansi_escape.sub("", output)
print(output)
failure_strings = ["FAILED", "Exception occurred"]
if any(x in output for x in failure_strings):
sys.exit(1)
+ # Grab the return code from the output string with regex
+ # Syntax: "main returned: ", <code> (<hex_code>)
+ return_string = re.compile(
+ r"\"main returned:\s\",(?P<ret_code>\s[0-9]+\s*)")
+ code = return_string.search(output)
+ sys.exit(int(code.group(1)))
if __name__ == "__main__":
diff --git a/springbok/crt0.S b/springbok/crt0.S
index d4ce006..68351ce 100644
--- a/springbok/crt0.S
+++ b/springbok/crt0.S
@@ -117,8 +117,25 @@
# Check the stack, and fix it if it's broken
jal ra, _check_stack
- # Save check_stack's return value
- mv s1, a0
+ # Was the stack corrupted?
+ beq a0, zero, 1f
+
+ # The stack was corrupted!
+ # These strings are stored in instruction memory like
+ # this so they can't ever be corrupted.
+ li t0, 0x63617473 # "stac"
+ li t1, 0x6f63206b # "k co"
+ li t2, 0x70757272 # "rrup"
+ li t3, 0x00646574 # "ted\0"
+ addi sp, sp, -16
+ sw t0, 0(sp)
+ sw t1, 4(sp)
+ sw t2, 8(sp)
+ sw t3, 12(sp)
+ li t4, 0 # ERROR logging level
+ .word 0x00A10EFB # simprint t4, sp, a0 (encoded as custom3<func3=0>)
+ addi sp, sp, 16
+1:
# Restore the application's return value
mv a0, s0
@@ -139,25 +156,6 @@
.word 0x00A10EFB # simprint t4, sp, a0 (encoded as custom3<func3=0>)
addi sp, sp, 16
- # Was the stack corrupted?
- beq s1, zero, _finish
-
- # The stack was corrupted!
- li t0, 0x63617473 # "stac"
- li t1, 0x6f63206b # "k co"
- li t2, 0x70757272 # "rrup"
- li t3, 0x00646574 # "ted\0"
- addi sp, sp, -16
- sw t0, 0(sp)
- sw t1, 4(sp)
- sw t2, 8(sp)
- sw t3, 12(sp)
- mv a0, s1
- li t4, 0 # ERROR logging level
- .word 0x00A10EFB # simprint t4, sp, a0 (encoded as custom3<func3=0>)
- addi sp, sp, 16
- mv a0, s0
-
_finish:
# Store the application's return value onto the stack
addi sp, sp, -8
@@ -247,6 +245,8 @@
.weak exception_handler
exception_handler:
# Exception occurred
+ # These strings are stored in instruction memory like
+ # this so they can't ever be corrupted.
li t0, 0x65637845 # "Exce"
li t1, 0x6f697470 # "ptio"
li t2, 0x636f206e # "n oc"
diff --git a/springbok/springbok.cpp b/springbok/springbok.cpp
index 95c3941..514eda0 100644
--- a/springbok/springbok.cpp
+++ b/springbok/springbok.cpp
@@ -109,7 +109,8 @@
extern "C" int float_to_str(const int len, char *buffer, const float value) {
if (buffer == NULL && len != 0) {
// Bad inputs
- springbok_simprint(SPRINGBOK_SIMPRINT_ERROR, "float_to_str handed null buffer with non-zero length! len:", len);
+ LOG_ERROR("float_to_str handed null buffer with non-zero length! len:%d",
+ len);
return 0;
}
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index e51930f..dbe8669 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -517,3 +517,12 @@
LINKOPTS
-Xlinker --defsym=__itcm_length__=128K
)
+
+vec_cc_test(
+ NAME
+ vmerge_test
+ SRCS
+ vmerge_test.cpp
+ LINKOPTS
+ -Xlinker --defsym=__itcm_length__=128K
+)
diff --git a/tests/vmerge_test.cpp b/tests/vmerge_test.cpp
new file mode 100644
index 0000000..a8f741f
--- /dev/null
+++ b/tests/vmerge_test.cpp
@@ -0,0 +1,106 @@
+#include <stdlib.h>
+
+#include "pw_unit_test/framework.h"
+#include "test_v_helpers.h"
+
+// Test for vmerge.vim and vmerge.vvm instructions.
+namespace vmerge_test {
+namespace {
+
+using namespace test_v_helpers;
+
+uint8_t src_vector_1[MAXVL_BYTES];
+uint8_t src_vector_2[MAXVL_BYTES];
+uint8_t src_mask_vector[MAXVL_BYTES];
+uint8_t dest_vector[MAXVL_BYTES];
+
+class VmergeTest : public ::testing::Test {
+ protected:
+ void SetUp() override { zero_vector_registers(); }
+ void TearDown() override { zero_vector_registers(); }
+};
+
+TEST_F(VmergeTest, vmerge_vim) {
+ for (int i = 0; i < AVL_COUNT; i++) {
+ int32_t avl = AVLS[i];
+ int vlmax;
+ int vl;
+ /* For non narrowing instructions all vectors have same type*/
+ std::tie(vlmax, vl) = vector_test_setup<uint8_t>(
+ VLMUL::LMUL_M1, avl, {dest_vector, src_vector_2, src_mask_vector});
+ if (avl > vlmax) {
+ continue;
+ }
+
+ fill_random_vector<uint8_t>(src_vector_2, vl);
+ fill_random_vector<uint8_t>(src_mask_vector, vl);
+ const int8_t test_val = 12;
+
+ // Load vector registers
+ __asm__ volatile("vle8.v v16, (%0)" : : "r"(src_vector_2));
+ __asm__ volatile("vle8.v v0, (%0)" : : "r"(src_mask_vector));
+
+ // Run target instruction
+ __asm__ volatile("vmerge.vim v24, v16, %[IMM], v0" ::[IMM] "n"(test_val));
+
+ // Store result vector register
+ __asm__ volatile("vse8.v v24, (%0)" : : "r"(dest_vector));
+
+ // Check vector elements
+ constexpr uint32_t kShift = 3; // shift for uint8_t
+ for (int idx = 0; idx < vl; idx++) {
+ uint32_t mask_idx = idx >> kShift;
+ uint32_t mask_pos = idx & ~(mask_idx << kShift);
+ if (src_mask_vector[mask_idx] & (1 << mask_pos)) {
+ ASSERT_EQ(dest_vector[idx], test_val);
+ } else {
+ ASSERT_EQ(dest_vector[idx], src_vector_2[idx]);
+ }
+ }
+ }
+}
+
+TEST_F(VmergeTest, vmerge_vvm) {
+ for (int i = 0; i < AVL_COUNT; i++) {
+ int32_t avl = AVLS[i];
+ int vlmax;
+ int vl;
+ /* For non narrowing instructions all vectors have same type*/
+ std::tie(vlmax, vl) = vector_test_setup<uint8_t>(
+ VLMUL::LMUL_M1, avl,
+ {dest_vector, src_vector_1, src_vector_2, src_mask_vector});
+ if (avl > vlmax) {
+ continue;
+ }
+
+ fill_random_vector<uint8_t>(src_vector_1, vl);
+ fill_random_vector<uint8_t>(src_vector_2, vl);
+ fill_random_vector<uint8_t>(src_mask_vector, vl);
+
+ // Load vector registers
+ __asm__ volatile("vle8.v v8, (%0)" : : "r"(src_vector_1));
+ __asm__ volatile("vle8.v v16, (%0)" : : "r"(src_vector_2));
+ __asm__ volatile("vle8.v v0, (%0)" : : "r"(src_mask_vector));
+
+ // Run target instruction
+ __asm__ volatile("vmerge.vvm v24, v16, v8, v0");
+
+ // Store result vector register
+ __asm__ volatile("vse8.v v24, (%0)" : : "r"(dest_vector));
+
+ // Check vector elements
+ constexpr uint32_t kShift = 3; // shift for uint8_t
+ for (int idx = 0; idx < vl; idx++) {
+ uint32_t mask_idx = idx >> kShift;
+ uint32_t mask_pos = idx & ~(mask_idx << kShift);
+ if (src_mask_vector[mask_idx] & (1 << mask_pos)) {
+ ASSERT_EQ(dest_vector[idx], src_vector_1[idx]);
+ } else {
+ ASSERT_EQ(dest_vector[idx], src_vector_2[idx]);
+ }
+ }
+ }
+}
+
+} // namespace
+} // namespace vmerge_test