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