xref: /qemu/tests/tcg/hexagon/load_align.c (revision 78f314cf)
1 /*
2  *  Copyright(c) 2019-2023 Qualcomm Innovation Center, Inc. All Rights Reserved.
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 /*
19  * Test load align instructions
20  *
21  * Example
22  *     r1:0 = memh_fifo(r1+#0)
23  * loads a half word from memory, shifts the destination register
24  * right by one half word and inserts the loaded value into the high
25  * half word of the destination.
26  *
27  * There are 8 addressing modes and byte and half word variants, for a
28  * total of 16 instructions to test
29  */
30 
31 #include <stdio.h>
32 #include <stdint.h>
33 #include <string.h>
34 
35 int err;
36 
37 #include "hex_test.h"
38 
39 int8_t buf[16] __attribute__((aligned(1 << 16)));
40 
41 void init_buf(void)
42 {
43     for (int i = 0; i < 16; i++) {
44         buf[i] = i + 1;
45     }
46 }
47 
48 /*
49  ****************************************************************************
50  * _io addressing mode (addr + offset)
51  */
52 #define LOAD_io(SZ, RES, ADDR, OFF) \
53     __asm__( \
54         "%0 = mem" #SZ "_fifo(%1+#" #OFF ")\n\t" \
55         : "+r"(RES) \
56         : "r"(ADDR))
57 #define LOAD_io_b(RES, ADDR, OFF) \
58     LOAD_io(b, RES, ADDR, OFF)
59 #define LOAD_io_h(RES, ADDR, OFF) \
60     LOAD_io(h, RES, ADDR, OFF)
61 
62 #define TEST_io(NAME, SZ, SIZE, EXP1, EXP2, EXP3, EXP4) \
63 void test_##NAME(void) \
64 { \
65     int64_t result = ~0LL; \
66     LOAD_io_##SZ(result, buf, 0 * (SIZE)); \
67     check64(result, (EXP1)); \
68     LOAD_io_##SZ(result, buf, 1 * (SIZE)); \
69     check64(result, (EXP2)); \
70     LOAD_io_##SZ(result, buf, 2 * (SIZE)); \
71     check64(result, (EXP3)); \
72     LOAD_io_##SZ(result, buf, 3 * (SIZE)); \
73     check64(result, (EXP4)); \
74 }
75 
76 TEST_io(loadalignb_io, b, 1,
77         0x01ffffffffffffffLL, 0x0201ffffffffffffLL,
78         0x030201ffffffffffLL, 0x04030201ffffffffLL)
79 TEST_io(loadalignh_io, h, 2,
80         0x0201ffffffffffffLL, 0x04030201ffffffffLL,
81         0x060504030201ffffLL, 0x0807060504030201LL)
82 
83 /*
84  ****************************************************************************
85  * _ur addressing mode (index << offset + base)
86  */
87 #define LOAD_ur(SZ, RES, SHIFT, IDX) \
88     __asm__( \
89         "%0 = mem" #SZ "_fifo(%1<<#" #SHIFT " + ##buf)\n\t" \
90         : "+r"(RES) \
91         : "r"(IDX))
92 #define LOAD_ur_b(RES, SHIFT, IDX) \
93     LOAD_ur(b, RES, SHIFT, IDX)
94 #define LOAD_ur_h(RES, SHIFT, IDX) \
95     LOAD_ur(h, RES, SHIFT, IDX)
96 
97 #define TEST_ur(NAME, SZ, SHIFT, RES1, RES2, RES3, RES4) \
98 void test_##NAME(void) \
99 { \
100     uint64_t result = ~0LL; \
101     LOAD_ur_##SZ(result, (SHIFT), 0); \
102     check64(result, (RES1)); \
103     LOAD_ur_##SZ(result, (SHIFT), 1); \
104     check64(result, (RES2)); \
105     LOAD_ur_##SZ(result, (SHIFT), 2); \
106     check64(result, (RES3)); \
107     LOAD_ur_##SZ(result, (SHIFT), 3); \
108     check64(result, (RES4)); \
109 }
110 
111 TEST_ur(loadalignb_ur, b, 1,
112         0x01ffffffffffffffLL, 0x0301ffffffffffffLL,
113         0x050301ffffffffffLL, 0x07050301ffffffffLL)
114 TEST_ur(loadalignh_ur, h, 1,
115         0x0201ffffffffffffLL, 0x04030201ffffffffLL,
116         0x060504030201ffffLL, 0x0807060504030201LL)
117 
118 /*
119  ****************************************************************************
120  * _ap addressing mode (addr = base)
121  */
122 #define LOAD_ap(SZ, RES, PTR, ADDR) \
123     __asm__(  \
124         "%0 = mem" #SZ "_fifo(%1 = ##" #ADDR ")\n\t" \
125         : "+r"(RES), "=r"(PTR))
126 #define LOAD_ap_b(RES, PTR, ADDR) \
127     LOAD_ap(b, RES, PTR, ADDR)
128 #define LOAD_ap_h(RES, PTR, ADDR) \
129     LOAD_ap(h, RES, PTR, ADDR)
130 
131 #define TEST_ap(NAME, SZ, SIZE, RES1, RES2, RES3, RES4) \
132 void test_##NAME(void) \
133 { \
134     int64_t result = ~0LL; \
135     void *ptr; \
136     LOAD_ap_##SZ(result, ptr, (buf + 0 * (SIZE))); \
137     check64(result, (RES1)); \
138     checkp(ptr, &buf[0 * (SIZE)]); \
139     LOAD_ap_##SZ(result, ptr, (buf + 1 * (SIZE))); \
140     check64(result, (RES2)); \
141     checkp(ptr, &buf[1 * (SIZE)]); \
142     LOAD_ap_##SZ(result, ptr, (buf + 2 * (SIZE))); \
143     check64(result, (RES3)); \
144     checkp(ptr, &buf[2 * (SIZE)]); \
145     LOAD_ap_##SZ(result, ptr, (buf + 3 * (SIZE))); \
146     check64(result, (RES4)); \
147     checkp(ptr, &buf[3 * (SIZE)]); \
148 }
149 
150 TEST_ap(loadalignb_ap, b, 1,
151         0x01ffffffffffffffLL, 0x0201ffffffffffffLL,
152         0x030201ffffffffffLL, 0x04030201ffffffffLL)
153 TEST_ap(loadalignh_ap, h, 2,
154         0x0201ffffffffffffLL, 0x04030201ffffffffLL,
155         0x060504030201ffffLL, 0x0807060504030201LL)
156 
157 /*
158  ****************************************************************************
159  * _rp addressing mode (addr ++ modifer-reg)
160  */
161 #define LOAD_pr(SZ, RES, PTR, INC) \
162     __asm__( \
163         "m0 = %2\n\t" \
164         "%0 = mem" #SZ "_fifo(%1++m0)\n\t" \
165         : "+r"(RES), "+r"(PTR) \
166         : "r"(INC) \
167         : "m0")
168 #define LOAD_pr_b(RES, PTR, INC) \
169     LOAD_pr(b, RES, PTR, INC)
170 #define LOAD_pr_h(RES, PTR, INC) \
171     LOAD_pr(h, RES, PTR, INC)
172 
173 #define TEST_pr(NAME, SZ, SIZE, RES1, RES2, RES3, RES4) \
174 void test_##NAME(void) \
175 { \
176     int64_t result = ~0LL; \
177     void *ptr = buf; \
178     LOAD_pr_##SZ(result, ptr, (SIZE)); \
179     check64(result, (RES1)); \
180     checkp(ptr, &buf[1 * (SIZE)]); \
181     LOAD_pr_##SZ(result, ptr, (SIZE)); \
182     check64(result, (RES2)); \
183     checkp(ptr, &buf[2 * (SIZE)]); \
184     LOAD_pr_##SZ(result, ptr, (SIZE)); \
185     check64(result, (RES3)); \
186     checkp(ptr, &buf[3 * (SIZE)]); \
187     LOAD_pr_##SZ(result, ptr, (SIZE)); \
188     check64(result, (RES4)); \
189     checkp(ptr, &buf[4 * (SIZE)]); \
190 }
191 
192 TEST_pr(loadalignb_pr, b, 1,
193         0x01ffffffffffffffLL, 0x0201ffffffffffffLL,
194         0x030201ffffffffffLL, 0x04030201ffffffffLL)
195 TEST_pr(loadalignh_pr, h, 2,
196         0x0201ffffffffffffLL, 0x04030201ffffffffLL,
197         0x060504030201ffffLL, 0x0807060504030201LL)
198 
199 /*
200  ****************************************************************************
201  * _pbr addressing mode (addr ++ modifer-reg:brev)
202  */
203 #define LOAD_pbr(SZ, RES, PTR) \
204     __asm__( \
205         "r4 = #(1 << (16 - 3))\n\t" \
206         "m0 = r4\n\t" \
207         "%0 = mem" #SZ "_fifo(%1++m0:brev)\n\t" \
208         : "+r"(RES), "+r"(PTR) \
209         : \
210         : "r4", "m0")
211 #define LOAD_pbr_b(RES, PTR) \
212     LOAD_pbr(b, RES, PTR)
213 #define LOAD_pbr_h(RES, PTR) \
214     LOAD_pbr(h, RES, PTR)
215 
216 #define TEST_pbr(NAME, SZ, RES1, RES2, RES3, RES4) \
217 void test_##NAME(void) \
218 { \
219     int64_t result = ~0LL; \
220     void *ptr = buf; \
221     LOAD_pbr_##SZ(result, ptr); \
222     check64(result, (RES1)); \
223     LOAD_pbr_##SZ(result, ptr); \
224     check64(result, (RES2)); \
225     LOAD_pbr_##SZ(result, ptr); \
226     check64(result, (RES3)); \
227     LOAD_pbr_##SZ(result, ptr); \
228     check64(result, (RES4)); \
229 }
230 
231 TEST_pbr(loadalignb_pbr, b,
232     0x01ffffffffffffffLL, 0x0501ffffffffffffLL,
233     0x030501ffffffffffLL, 0x07030501ffffffffLL)
234 TEST_pbr(loadalignh_pbr, h,
235     0x0201ffffffffffffLL, 0x06050201ffffffffLL,
236     0x040306050201ffffLL, 0x0807040306050201LL)
237 
238 /*
239  ****************************************************************************
240  * _pi addressing mode (addr ++ inc)
241  */
242 #define LOAD_pi(SZ, RES, PTR, INC) \
243     __asm__( \
244         "%0 = mem" #SZ "_fifo(%1++#" #INC ")\n\t" \
245         : "+r"(RES), "+r"(PTR))
246 #define LOAD_pi_b(RES, PTR, INC) \
247     LOAD_pi(b, RES, PTR, INC)
248 #define LOAD_pi_h(RES, PTR, INC) \
249     LOAD_pi(h, RES, PTR, INC)
250 
251 #define TEST_pi(NAME, SZ, INC, RES1, RES2, RES3, RES4) \
252 void test_##NAME(void) \
253 { \
254     int64_t result = ~0LL; \
255     void *ptr = buf; \
256     LOAD_pi_##SZ(result, ptr, (INC)); \
257     check64(result, (RES1)); \
258     checkp(ptr, &buf[1 * (INC)]); \
259     LOAD_pi_##SZ(result, ptr, (INC)); \
260     check64(result, (RES2)); \
261     checkp(ptr, &buf[2 * (INC)]); \
262     LOAD_pi_##SZ(result, ptr, (INC)); \
263     check64(result, (RES3)); \
264     checkp(ptr, &buf[3 * (INC)]); \
265     LOAD_pi_##SZ(result, ptr, (INC)); \
266     check64(result, (RES4)); \
267     checkp(ptr, &buf[4 * (INC)]); \
268 }
269 
270 TEST_pi(loadalignb_pi, b, 1,
271         0x01ffffffffffffffLL, 0x0201ffffffffffffLL,
272         0x030201ffffffffffLL, 0x04030201ffffffffLL)
273 TEST_pi(loadalignh_pi, h, 2,
274         0x0201ffffffffffffLL, 0x04030201ffffffffLL,
275         0x060504030201ffffLL, 0x0807060504030201LL)
276 
277 /*
278  ****************************************************************************
279  * _pci addressing mode (addr ++ inc:circ)
280  */
281 #define LOAD_pci(SZ, RES, PTR, START, LEN, INC) \
282     __asm__( \
283         "r4 = %3\n\t" \
284         "m0 = r4\n\t" \
285         "cs0 = %2\n\t" \
286         "%0 = mem" #SZ "_fifo(%1++#" #INC ":circ(m0))\n\t" \
287         : "+r"(RES), "+r"(PTR) \
288         : "r"(START), "r"(LEN) \
289         : "r4", "m0", "cs0")
290 #define LOAD_pci_b(RES, PTR, START, LEN, INC) \
291     LOAD_pci(b, RES, PTR, START, LEN, INC)
292 #define LOAD_pci_h(RES, PTR, START, LEN, INC) \
293     LOAD_pci(h, RES, PTR, START, LEN, INC)
294 
295 #define TEST_pci(NAME, SZ, LEN, INC, RES1, RES2, RES3, RES4) \
296 void test_##NAME(void) \
297 { \
298     int64_t result = ~0LL; \
299     void *ptr = buf; \
300     LOAD_pci_##SZ(result, ptr, buf, (LEN), (INC)); \
301     check64(result, (RES1)); \
302     checkp(ptr, &buf[(1 * (INC)) % (LEN)]); \
303     LOAD_pci_##SZ(result, ptr, buf, (LEN), (INC)); \
304     check64(result, (RES2)); \
305     checkp(ptr, &buf[(2 * (INC)) % (LEN)]); \
306     LOAD_pci_##SZ(result, ptr, buf, (LEN), (INC)); \
307     check64(result, (RES3)); \
308     checkp(ptr, &buf[(3 * (INC)) % (LEN)]); \
309     LOAD_pci_##SZ(result, ptr, buf, (LEN), (INC)); \
310     check64(result, (RES4)); \
311     checkp(ptr, &buf[(4 * (INC)) % (LEN)]); \
312 }
313 
314 TEST_pci(loadalignb_pci, b, 2, 1,
315     0x01ffffffffffffffLL, 0x0201ffffffffffffLL,
316     0x010201ffffffffffLL, 0x02010201ffffffffLL)
317 TEST_pci(loadalignh_pci, h, 4, 2,
318     0x0201ffffffffffffLL, 0x04030201ffffffffLL,
319     0x020104030201ffffLL, 0x0403020104030201LL)
320 
321 /*
322  ****************************************************************************
323  * _pcr addressing mode (addr ++ I:circ(modifier-reg))
324  */
325 #define LOAD_pcr(SZ, RES, PTR, START, LEN, INC) \
326     __asm__( \
327         "r4 = %2\n\t" \
328         "m1 = r4\n\t" \
329         "cs1 = %3\n\t" \
330         "%0 = mem" #SZ "_fifo(%1++I:circ(m1))\n\t" \
331         : "+r"(RES), "+r"(PTR) \
332         : "r"((((INC) & 0x7f) << 17) | ((LEN) & 0x1ffff)), \
333           "r"(START) \
334         : "r4", "m1", "cs1")
335 #define LOAD_pcr_b(RES, PTR, START, LEN, INC) \
336     LOAD_pcr(b, RES, PTR, START, LEN, INC)
337 #define LOAD_pcr_h(RES, PTR, START, LEN, INC) \
338     LOAD_pcr(h, RES, PTR, START, LEN, INC)
339 
340 #define TEST_pcr(NAME, SZ, SIZE, LEN, INC, RES1, RES2, RES3, RES4) \
341 void test_##NAME(void) \
342 { \
343     int64_t result = ~0LL; \
344     void *ptr = buf; \
345     LOAD_pcr_##SZ(result, ptr, buf, (LEN), (INC)); \
346     check64(result, (RES1)); \
347     checkp(ptr, &buf[(1 * (INC) * (SIZE)) % (LEN)]); \
348     LOAD_pcr_##SZ(result, ptr, buf, (LEN), (INC)); \
349     check64(result, (RES2)); \
350     checkp(ptr, &buf[(2 * (INC) * (SIZE)) % (LEN)]); \
351     LOAD_pcr_##SZ(result, ptr, buf, (LEN), (INC)); \
352     check64(result, (RES3)); \
353     checkp(ptr, &buf[(3 * (INC) * (SIZE)) % (LEN)]); \
354     LOAD_pcr_##SZ(result, ptr, buf, (LEN), (INC)); \
355     check64(result, (RES4)); \
356     checkp(ptr, &buf[(4 * (INC) * (SIZE)) % (LEN)]); \
357 }
358 
359 TEST_pcr(loadalignb_pcr, b, 1, 2, 1,
360     0x01ffffffffffffffLL, 0x0201ffffffffffffLL,
361     0x010201ffffffffffLL, 0x02010201ffffffffLL)
362 TEST_pcr(loadalignh_pcr, h, 2, 4, 1,
363     0x0201ffffffffffffLL, 0x04030201ffffffffLL,
364     0x020104030201ffffLL, 0x0403020104030201LL)
365 
366 int main()
367 {
368     init_buf();
369 
370     test_loadalignb_io();
371     test_loadalignh_io();
372 
373     test_loadalignb_ur();
374     test_loadalignh_ur();
375 
376     test_loadalignb_ap();
377     test_loadalignh_ap();
378 
379     test_loadalignb_pr();
380     test_loadalignh_pr();
381 
382     test_loadalignb_pbr();
383     test_loadalignh_pbr();
384 
385     test_loadalignb_pi();
386     test_loadalignh_pi();
387 
388     test_loadalignb_pci();
389     test_loadalignh_pci();
390 
391     test_loadalignb_pcr();
392     test_loadalignh_pcr();
393 
394     puts(err ? "FAIL" : "PASS");
395     return err ? 1 : 0;
396 }
397