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