| /* |
| * Copyright (c) 2022 Synopsys |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| /* |
| * @file |
| * @brief complex number multiplication portion of DSP sharing test |
| * |
| * @ingroup kernel_dspsharing_tests |
| * |
| * This module is used for the DSP sharing test, and supplements the basic |
| * load/store test by incorporating two additional threads that utilize the |
| * DSP unit. |
| * |
| * Testing utilizes a pair of tasks that independently compute complex vector |
| * dot product. The lower priority task is regularly preempted by the higher |
| * priority task, thereby testing whether DSP context information is properly |
| * preserved. |
| * |
| * A reference value of computed result is computed once at the start of the |
| * test. All subsequent computations must produce the same value, otherwise |
| * an error has occurred. |
| */ |
| |
| #include <zephyr/ztest.h> |
| #include "fxarc.h" |
| #include "dsp_context.h" |
| #include "test_common.h" |
| |
| /* stored in XY memory, need ARC_AGU_SHARING */ |
| #define DATA_ATTR __xy __attribute__((section(".Xdata"))) |
| static DATA_ATTR const cq15_t cq15_a[3] = {{0x20, 10}, {0x10, 20}, {4, 30}}; |
| static DATA_ATTR const cq15_t cq15_b[3] = {{0x20, 11}, {0x10, 21}, {5, 31}}; |
| |
| static volatile short reference_result; |
| |
| static volatile unsigned int calc_low_count; |
| static volatile unsigned int calc_high_count; |
| |
| /* Indicates that the load/store test exited */ |
| static volatile bool test_exited; |
| |
| /* Semaphore for signaling end of test */ |
| static K_SEM_DEFINE(test_exit_sem, 0, 1); |
| |
| /** |
| * @brief Entry point for the low priority compute task |
| * |
| * @ingroup kernel_dspsharing_tests |
| */ |
| static void calculate_low(void) |
| { |
| volatile short res[2]; |
| /* Loop until the test finishes, or an error is detected. */ |
| for (calc_low_count = 0; !test_exited; calc_low_count++) { |
| |
| v2accum32_t acc = {0, 0}; |
| |
| for (int i = 0; i < 3; i++) { |
| acc = fx_v2a32_cmac_cq15(acc, cq15_a[i], cq15_b[i]); |
| } |
| /* cast reult from v2accum32_ to short type */ |
| res[0] = fx_q15_cast_asl_rnd_a32(fx_get_v2a32(acc, 0), 15); |
| res[1] = fx_q15_cast_asl_rnd_a32(fx_get_v2a32(acc, 1), 15); |
| |
| if (reference_result == 0) { |
| reference_result = res[0]; |
| } else if (reference_result != res[0]) { |
| printf("Computed result %d, reference result %d\n", |
| res[0], reference_result); |
| } |
| |
| zassert_equal(reference_result, res[0], "complex product computation error"); |
| } |
| } |
| |
| /** |
| * @brief Entry point for the high priority compute task |
| * |
| * @ingroup kernel_dspsharing_tests |
| */ |
| static void calculate_high(void) |
| { |
| volatile short res[2]; |
| /* Run the test until the specified maximum test count is reached */ |
| for (calc_high_count = 0; calc_high_count <= MAX_TESTS; calc_high_count++) { |
| |
| v2accum32_t acc = {0, 0}; |
| |
| for (int i = 0; i < 3; i++) { |
| acc = fx_v2a32_cmac_cq15(acc, cq15_a[i], cq15_b[i]); |
| } |
| |
| /* |
| * Relinquish the processor for the remainder of the current |
| * system clock tick, so that lower priority threads get a |
| * chance to run. |
| * |
| * This exercises the ability of the kernel to restore the |
| * DSP state of a low priority thread _and_ the ability of the |
| * kernel to provide a "clean" DSP state to this thread |
| * once the sleep ends. |
| */ |
| k_sleep(K_MSEC(10)); |
| |
| res[0] = fx_q15_cast_asl_rnd_a32(fx_get_v2a32(acc, 0), 15); |
| res[1] = fx_q15_cast_asl_rnd_a32(fx_get_v2a32(acc, 1), 15); |
| |
| if (reference_result == 0) { |
| reference_result = res[0]; |
| } else if (reference_result != res[0]) { |
| printf("Computed result %d, reference result %d\n", |
| res[0], reference_result); |
| } |
| |
| zassert_equal(reference_result, res[0], "complex product computation error"); |
| |
| /* Periodically issue progress report */ |
| if ((calc_high_count % 100) == 50) { |
| printf("complex product calculation OK after %u (high) " |
| "+" |
| " %u (low) tests (computed %d)\n", |
| calc_high_count, calc_low_count, res[0]); |
| } |
| } |
| |
| /* Signal end of test */ |
| test_exited = true; |
| k_sem_give(&test_exit_sem); |
| } |
| |
| K_THREAD_DEFINE(cal_low, THREAD_STACK_SIZE, calculate_low, NULL, NULL, NULL, |
| THREAD_LOW_PRIORITY, THREAD_DSP_FLAGS, K_TICKS_FOREVER); |
| |
| K_THREAD_DEFINE(cal_high, THREAD_STACK_SIZE, calculate_high, NULL, NULL, NULL, |
| THREAD_HIGH_PRIORITY, THREAD_DSP_FLAGS, K_TICKS_FOREVER); |
| |
| ZTEST(dsp_sharing, test_calculation) |
| { |
| /* Initialise test states */ |
| test_exited = false; |
| k_sem_reset(&test_exit_sem); |
| |
| /* Start test threads */ |
| k_thread_start(cal_low); |
| k_thread_start(cal_high); |
| |
| /* Wait for test threads to exit */ |
| k_sem_take(&test_exit_sem, K_FOREVER); |
| } |