1 /*
2 * Copyright (c) 2022 Synopsys
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /*
8 * @file
9 * @brief complex number multiplication portion of DSP sharing test
10 *
11 * @ingroup kernel_dspsharing_tests
12 *
13 * This module is used for the DSP sharing test, and supplements the basic
14 * load/store test by incorporating two additional threads that utilize the
15 * DSP unit.
16 *
17 * Testing utilizes a pair of tasks that independently compute complex vector
18 * dot product. The lower priority task is regularly preempted by the higher
19 * priority task, thereby testing whether DSP context information is properly
20 * preserved.
21 *
22 * A reference value of computed result is computed once at the start of the
23 * test. All subsequent computations must produce the same value, otherwise
24 * an error has occurred.
25 */
26
27 #include <zephyr/ztest.h>
28 #include "fxarc.h"
29 #include "dsp_context.h"
30 #include "test_common.h"
31
32 /* stored in XY memory, need ARC_AGU_SHARING */
33 #define DATA_ATTR __xy __attribute__((section(".Xdata")))
34 static DATA_ATTR const cq15_t cq15_a[3] = {{0x20, 10}, {0x10, 20}, {4, 30}};
35 static DATA_ATTR const cq15_t cq15_b[3] = {{0x20, 11}, {0x10, 21}, {5, 31}};
36
37 static volatile short reference_result;
38
39 static volatile unsigned int calc_low_count;
40 static volatile unsigned int calc_high_count;
41
42 /* Indicates that the load/store test exited */
43 static volatile bool test_exited;
44
45 /* Semaphore for signaling end of test */
46 static K_SEM_DEFINE(test_exit_sem, 0, 1);
47
48 /**
49 * @brief Entry point for the low priority compute task
50 *
51 * @ingroup kernel_dspsharing_tests
52 */
calculate_low(void)53 static void calculate_low(void)
54 {
55 volatile short res[2];
56 /* Loop until the test finishes, or an error is detected. */
57 for (calc_low_count = 0; !test_exited; calc_low_count++) {
58
59 v2accum32_t acc = {0, 0};
60
61 for (int i = 0; i < 3; i++) {
62 acc = fx_v2a32_cmac_cq15(acc, cq15_a[i], cq15_b[i]);
63 }
64 /* cast reult from v2accum32_ to short type */
65 res[0] = fx_q15_cast_asl_rnd_a32(fx_get_v2a32(acc, 0), 15);
66 res[1] = fx_q15_cast_asl_rnd_a32(fx_get_v2a32(acc, 1), 15);
67
68 if (reference_result == 0) {
69 reference_result = res[0];
70 } else if (reference_result != res[0]) {
71 printf("Computed result %d, reference result %d\n",
72 res[0], reference_result);
73 }
74
75 zassert_equal(reference_result, res[0], "complex product computation error");
76 }
77 }
78
79 /**
80 * @brief Entry point for the high priority compute task
81 *
82 * @ingroup kernel_dspsharing_tests
83 */
calculate_high(void)84 static void calculate_high(void)
85 {
86 volatile short res[2];
87 /* Run the test until the specified maximum test count is reached */
88 for (calc_high_count = 0; calc_high_count <= MAX_TESTS; calc_high_count++) {
89
90 v2accum32_t acc = {0, 0};
91
92 for (int i = 0; i < 3; i++) {
93 acc = fx_v2a32_cmac_cq15(acc, cq15_a[i], cq15_b[i]);
94 }
95
96 /*
97 * Relinquish the processor for the remainder of the current
98 * system clock tick, so that lower priority threads get a
99 * chance to run.
100 *
101 * This exercises the ability of the kernel to restore the
102 * DSP state of a low priority thread _and_ the ability of the
103 * kernel to provide a "clean" DSP state to this thread
104 * once the sleep ends.
105 */
106 k_sleep(K_MSEC(10));
107
108 res[0] = fx_q15_cast_asl_rnd_a32(fx_get_v2a32(acc, 0), 15);
109 res[1] = fx_q15_cast_asl_rnd_a32(fx_get_v2a32(acc, 1), 15);
110
111 if (reference_result == 0) {
112 reference_result = res[0];
113 } else if (reference_result != res[0]) {
114 printf("Computed result %d, reference result %d\n",
115 res[0], reference_result);
116 }
117
118 zassert_equal(reference_result, res[0], "complex product computation error");
119
120 /* Periodically issue progress report */
121 if ((calc_high_count % 100) == 50) {
122 printf("complex product calculation OK after %u (high) "
123 "+"
124 " %u (low) tests (computed %d)\n",
125 calc_high_count, calc_low_count, res[0]);
126 }
127 }
128
129 /* Signal end of test */
130 test_exited = true;
131 k_sem_give(&test_exit_sem);
132 }
133
134 K_THREAD_DEFINE(cal_low, THREAD_STACK_SIZE, calculate_low, NULL, NULL, NULL,
135 THREAD_LOW_PRIORITY, THREAD_DSP_FLAGS, K_TICKS_FOREVER);
136
137 K_THREAD_DEFINE(cal_high, THREAD_STACK_SIZE, calculate_high, NULL, NULL, NULL,
138 THREAD_HIGH_PRIORITY, THREAD_DSP_FLAGS, K_TICKS_FOREVER);
139
ZTEST(dsp_sharing,test_calculation)140 ZTEST(dsp_sharing, test_calculation)
141 {
142 /* Initialise test states */
143 test_exited = false;
144 k_sem_reset(&test_exit_sem);
145
146 /* Start test threads */
147 k_thread_start(cal_low);
148 k_thread_start(cal_high);
149
150 /* Wait for test threads to exit */
151 k_sem_take(&test_exit_sem, K_FOREVER);
152 }
153