xref: /qemu/tests/tcg/hexagon/load_unpack.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 unpack instructions
20  *
21  * Example
22  *     r0 = memubh(r1+#0)
23  * loads a half word from memory and zero-extends the 2 bytes to form a word
24  *
25  * For each addressing mode, there are 4 tests
26  *     bzw2          unsigned     2 elements
27  *     bsw2          signed       2 elements
28  *     bzw4          unsigned     4 elements
29  *     bsw4          signed       4 elements
30  * There are 8 addressing modes, for a total of 32 instructions to test
31  */
32 
33 #include <stdio.h>
34 #include <stdint.h>
35 #include <string.h>
36 
37 int err;
38 
39 #include "hex_test.h"
40 
41 int8_t buf[16] __attribute__((aligned(1 << 16)));
42 
43 void init_buf(void)
44 {
45     for (int i = 0; i < 16; i++) {
46         int sign = i % 2 == 0 ? 0x80 : 0;
47         buf[i] = sign | (i + 1);
48     }
49 }
50 
51 /*
52  ****************************************************************************
53  * _io addressing mode (addr + offset)
54  */
55 #define BxW_LOAD_io(SZ, RES, ADDR, OFF) \
56     __asm__( \
57         "%0 = mem" #SZ "(%1+#" #OFF ")\n\t" \
58         : "=r"(RES) \
59         : "r"(ADDR))
60 #define BxW_LOAD_io_Z(RES, ADDR, OFF) \
61     BxW_LOAD_io(ubh, RES, ADDR, OFF)
62 #define BxW_LOAD_io_S(RES, ADDR, OFF) \
63     BxW_LOAD_io(bh, RES, ADDR, OFF)
64 
65 #define TEST_io(NAME, TYPE, SIGN, SIZE, EXT, EXP1, EXP2, EXP3, EXP4) \
66 void test_##NAME(void) \
67 { \
68     TYPE result; \
69     init_buf(); \
70     BxW_LOAD_io_##SIGN(result, buf, 0 * (SIZE)); \
71     check64(result, (EXP1) | (EXT)); \
72     BxW_LOAD_io_##SIGN(result, buf, 1 * (SIZE)); \
73     check64(result, (EXP2) | (EXT)); \
74     BxW_LOAD_io_##SIGN(result, buf, 2 * (SIZE)); \
75     check64(result, (EXP3) | (EXT)); \
76     BxW_LOAD_io_##SIGN(result, buf, 3 * (SIZE)); \
77     check64(result, (EXP4) | (EXT)); \
78 }
79 
80 
81 TEST_io(loadbzw2_io, int32_t, Z, 2, 0x00000000,
82         0x00020081, 0x00040083, 0x00060085, 0x00080087)
83 TEST_io(loadbsw2_io, int32_t, S, 2, 0x0000ff00,
84         0x00020081, 0x00040083, 0x00060085, 0x00080087)
85 TEST_io(loadbzw4_io, int64_t, Z,  4, 0x0000000000000000LL,
86         0x0004008300020081LL, 0x0008008700060085LL,
87         0x000c008b000a0089LL, 0x0010008f000e008dLL)
88 TEST_io(loadbsw4_io, int64_t, S,  4, 0x0000ff000000ff00LL,
89         0x0004008300020081LL, 0x0008008700060085LL,
90         0x000c008b000a0089LL, 0x0010008f000e008dLL)
91 
92 /*
93  ****************************************************************************
94  * _ur addressing mode (index << offset + base)
95  */
96 #define BxW_LOAD_ur(SZ, RES, SHIFT, IDX) \
97     __asm__( \
98         "%0 = mem" #SZ "(%1<<#" #SHIFT " + ##buf)\n\t" \
99         : "=r"(RES) \
100         : "r"(IDX))
101 #define BxW_LOAD_ur_Z(RES, SHIFT, IDX) \
102     BxW_LOAD_ur(ubh, RES, SHIFT, IDX)
103 #define BxW_LOAD_ur_S(RES, SHIFT, IDX) \
104     BxW_LOAD_ur(bh, RES, SHIFT, IDX)
105 
106 #define TEST_ur(NAME, TYPE, SIGN, SHIFT, EXT, RES1, RES2, RES3, RES4) \
107 void test_##NAME(void) \
108 { \
109     TYPE result; \
110     init_buf(); \
111     BxW_LOAD_ur_##SIGN(result, (SHIFT), 0); \
112     check64(result, (RES1) | (EXT)); \
113     BxW_LOAD_ur_##SIGN(result, (SHIFT), 1); \
114     check64(result, (RES2) | (EXT)); \
115     BxW_LOAD_ur_##SIGN(result, (SHIFT), 2); \
116     check64(result, (RES3) | (EXT)); \
117     BxW_LOAD_ur_##SIGN(result, (SHIFT), 3); \
118     check64(result, (RES4) | (EXT)); \
119 } \
120 
121 TEST_ur(loadbzw2_ur, int32_t, Z, 1, 0x00000000,
122         0x00020081, 0x00040083, 0x00060085, 0x00080087)
123 TEST_ur(loadbsw2_ur, int32_t, S, 1, 0x0000ff00,
124         0x00020081, 0x00040083, 0x00060085, 0x00080087)
125 TEST_ur(loadbzw4_ur, int64_t, Z, 2, 0x0000000000000000LL,
126         0x0004008300020081LL, 0x0008008700060085LL,
127         0x000c008b000a0089LL, 0x0010008f000e008dLL)
128 TEST_ur(loadbsw4_ur, int64_t, S, 2, 0x0000ff000000ff00LL,
129         0x0004008300020081LL, 0x0008008700060085LL,
130         0x000c008b000a0089LL, 0x0010008f000e008dLL)
131 
132 /*
133  ****************************************************************************
134  * _ap addressing mode (addr = base)
135  */
136 #define BxW_LOAD_ap(SZ, RES, PTR, ADDR) \
137     __asm__( \
138         "%0 = mem" #SZ "(%1 = ##" #ADDR ")\n\t" \
139         : "=r"(RES), "=r"(PTR))
140 #define BxW_LOAD_ap_Z(RES, PTR, ADDR) \
141     BxW_LOAD_ap(ubh, RES, PTR, ADDR)
142 #define BxW_LOAD_ap_S(RES, PTR, ADDR) \
143     BxW_LOAD_ap(bh, RES, PTR, ADDR)
144 
145 #define TEST_ap(NAME, TYPE, SIGN, SIZE, EXT, RES1, RES2, RES3, RES4) \
146 void test_##NAME(void) \
147 { \
148     TYPE result; \
149     void *ptr; \
150     init_buf(); \
151     BxW_LOAD_ap_##SIGN(result, ptr, (buf + 0 * (SIZE))); \
152     check64(result, (RES1) | (EXT)); \
153     checkp(ptr, &buf[0 * (SIZE)]); \
154     BxW_LOAD_ap_##SIGN(result, ptr, (buf + 1 * (SIZE))); \
155     check64(result, (RES2) | (EXT)); \
156     checkp(ptr, &buf[1 * (SIZE)]); \
157     BxW_LOAD_ap_##SIGN(result, ptr, (buf + 2 * (SIZE))); \
158     check64(result, (RES3) | (EXT)); \
159     checkp(ptr, &buf[2 * (SIZE)]); \
160     BxW_LOAD_ap_##SIGN(result, ptr, (buf + 3 * (SIZE))); \
161     check64(result, (RES4) | (EXT)); \
162     checkp(ptr, &buf[3 * (SIZE)]); \
163 }
164 
165 TEST_ap(loadbzw2_ap, int32_t, Z, 2, 0x00000000,
166         0x00020081, 0x00040083, 0x00060085, 0x00080087)
167 TEST_ap(loadbsw2_ap, int32_t, S, 2, 0x0000ff00,
168         0x00020081, 0x00040083, 0x00060085, 0x00080087)
169 TEST_ap(loadbzw4_ap, int64_t, Z, 4, 0x0000000000000000LL,
170         0x0004008300020081LL, 0x0008008700060085LL,
171         0x000c008b000a0089LL, 0x0010008f000e008dLL)
172 TEST_ap(loadbsw4_ap, int64_t, S, 4, 0x0000ff000000ff00LL,
173         0x0004008300020081LL, 0x0008008700060085LL,
174         0x000c008b000a0089LL, 0x0010008f000e008dLL)
175 
176 /*
177  ****************************************************************************
178  * _rp addressing mode (addr ++ modifer-reg)
179  */
180 #define BxW_LOAD_pr(SZ, RES, PTR, INC) \
181     __asm__( \
182         "m0 = %2\n\t" \
183         "%0 = mem" #SZ "(%1++m0)\n\t" \
184         : "=r"(RES), "+r"(PTR) \
185         : "r"(INC) \
186         : "m0")
187 #define BxW_LOAD_pr_Z(RES, PTR, INC) \
188     BxW_LOAD_pr(ubh, RES, PTR, INC)
189 #define BxW_LOAD_pr_S(RES, PTR, INC) \
190     BxW_LOAD_pr(bh, RES, PTR, INC)
191 
192 #define TEST_pr(NAME, TYPE, SIGN, SIZE, EXT, RES1, RES2, RES3, RES4) \
193 void test_##NAME(void) \
194 { \
195     TYPE result; \
196     void *ptr = buf; \
197     init_buf(); \
198     BxW_LOAD_pr_##SIGN(result, ptr, (SIZE)); \
199     check64(result, (RES1) | (EXT)); \
200     checkp(ptr, &buf[1 * (SIZE)]); \
201     BxW_LOAD_pr_##SIGN(result, ptr, (SIZE)); \
202     check64(result, (RES2) | (EXT)); \
203     checkp(ptr, &buf[2 * (SIZE)]); \
204     BxW_LOAD_pr_##SIGN(result, ptr, (SIZE)); \
205     check64(result, (RES3) | (EXT)); \
206     checkp(ptr, &buf[3 * (SIZE)]); \
207     BxW_LOAD_pr_##SIGN(result, ptr, (SIZE)); \
208     check64(result, (RES4) | (EXT)); \
209     checkp(ptr, &buf[4 * (SIZE)]); \
210 }
211 
212 TEST_pr(loadbzw2_pr, int32_t, Z, 2, 0x00000000,
213     0x00020081, 0x0040083, 0x00060085, 0x00080087)
214 TEST_pr(loadbsw2_pr, int32_t, S, 2, 0x0000ff00,
215     0x00020081, 0x0040083, 0x00060085, 0x00080087)
216 TEST_pr(loadbzw4_pr, int64_t, Z, 4, 0x0000000000000000LL,
217     0x0004008300020081LL, 0x0008008700060085LL,
218     0x000c008b000a0089LL, 0x0010008f000e008dLL)
219 TEST_pr(loadbsw4_pr, int64_t, S, 4, 0x0000ff000000ff00LL,
220     0x0004008300020081LL, 0x0008008700060085LL,
221     0x000c008b000a0089LL, 0x0010008f000e008dLL)
222 
223 /*
224  ****************************************************************************
225  * _pbr addressing mode (addr ++ modifer-reg:brev)
226  */
227 #define BxW_LOAD_pbr(SZ, RES, PTR) \
228     __asm__( \
229         "r4 = #(1 << (16 - 4))\n\t" \
230         "m0 = r4\n\t" \
231         "%0 = mem" #SZ "(%1++m0:brev)\n\t" \
232         : "=r"(RES), "+r"(PTR) \
233         : \
234         : "r4", "m0")
235 #define BxW_LOAD_pbr_Z(RES, PTR) \
236     BxW_LOAD_pbr(ubh, RES, PTR)
237 #define BxW_LOAD_pbr_S(RES, PTR) \
238     BxW_LOAD_pbr(bh, RES, PTR)
239 
240 #define TEST_pbr(NAME, TYPE, SIGN, EXT, RES1, RES2, RES3, RES4) \
241 void test_##NAME(void) \
242 { \
243     TYPE result; \
244     void *ptr = buf; \
245     init_buf(); \
246     BxW_LOAD_pbr_##SIGN(result, ptr); \
247     check64(result, (RES1) | (EXT)); \
248     BxW_LOAD_pbr_##SIGN(result, ptr); \
249     check64(result, (RES2) | (EXT)); \
250     BxW_LOAD_pbr_##SIGN(result, ptr); \
251     check64(result, (RES3) | (EXT)); \
252     BxW_LOAD_pbr_##SIGN(result, ptr); \
253     check64(result, (RES4) | (EXT)); \
254 }
255 
256 TEST_pbr(loadbzw2_pbr, int32_t, Z, 0x00000000,
257     0x00020081, 0x000a0089, 0x00060085, 0x000e008d)
258 TEST_pbr(loadbsw2_pbr, int32_t, S, 0x0000ff00,
259     0x00020081, 0x000aff89, 0x0006ff85, 0x000eff8d)
260 TEST_pbr(loadbzw4_pbr, int64_t, Z, 0x0000000000000000LL,
261     0x0004008300020081LL, 0x000c008b000a0089LL,
262     0x0008008700060085LL, 0x0010008f000e008dLL)
263 TEST_pbr(loadbsw4_pbr, int64_t, S, 0x0000ff000000ff00LL,
264     0x0004008300020081LL, 0x000cff8b000aff89LL,
265     0x0008ff870006ff85LL, 0x0010ff8f000eff8dLL)
266 
267 /*
268  ****************************************************************************
269  * _pi addressing mode (addr ++ inc)
270  */
271 #define BxW_LOAD_pi(SZ, RES, PTR, INC) \
272     __asm__( \
273         "%0 = mem" #SZ "(%1++#" #INC ")\n\t" \
274         : "=r"(RES), "+r"(PTR))
275 #define BxW_LOAD_pi_Z(RES, PTR, INC) \
276     BxW_LOAD_pi(ubh, RES, PTR, INC)
277 #define BxW_LOAD_pi_S(RES, PTR, INC) \
278     BxW_LOAD_pi(bh, RES, PTR, INC)
279 
280 #define TEST_pi(NAME, TYPE, SIGN, INC, EXT, RES1, RES2, RES3, RES4) \
281 void test_##NAME(void) \
282 { \
283     TYPE result; \
284     void *ptr = buf; \
285     init_buf(); \
286     BxW_LOAD_pi_##SIGN(result, ptr, (INC)); \
287     check64(result, (RES1) | (EXT)); \
288     checkp(ptr, &buf[1 * (INC)]); \
289     BxW_LOAD_pi_##SIGN(result, ptr, (INC)); \
290     check64(result, (RES2) | (EXT)); \
291     checkp(ptr, &buf[2 * (INC)]); \
292     BxW_LOAD_pi_##SIGN(result, ptr, (INC)); \
293     check64(result, (RES3) | (EXT)); \
294     checkp(ptr, &buf[3 * (INC)]); \
295     BxW_LOAD_pi_##SIGN(result, ptr, (INC)); \
296     check64(result, (RES4) | (EXT)); \
297     checkp(ptr, &buf[4 * (INC)]); \
298 }
299 
300 TEST_pi(loadbzw2_pi, int32_t, Z, 2, 0x00000000,
301     0x00020081, 0x00040083, 0x00060085, 0x00080087)
302 TEST_pi(loadbsw2_pi, int32_t, S, 2, 0x0000ff00,
303     0x00020081, 0x00040083, 0x00060085, 0x00080087)
304 TEST_pi(loadbzw4_pi, int64_t, Z, 4, 0x0000000000000000LL,
305     0x0004008300020081LL, 0x0008008700060085LL,
306     0x000c008b000a0089LL, 0x0010008f000e008dLL)
307 TEST_pi(loadbsw4_pi, int64_t, S, 4, 0x0000ff000000ff00LL,
308     0x0004008300020081LL, 0x0008008700060085LL,
309     0x000c008b000a0089LL, 0x0010008f000e008dLL)
310 
311 /*
312  ****************************************************************************
313  * _pci addressing mode (addr ++ inc:circ)
314  */
315 #define BxW_LOAD_pci(SZ, RES, PTR, START, LEN, INC) \
316     __asm__( \
317         "r4 = %3\n\t" \
318         "m0 = r4\n\t" \
319         "cs0 = %2\n\t" \
320         "%0 = mem" #SZ "(%1++#" #INC ":circ(m0))\n\t" \
321         : "=r"(RES), "+r"(PTR) \
322         : "r"(START), "r"(LEN) \
323         : "r4", "m0", "cs0")
324 #define BxW_LOAD_pci_Z(RES, PTR, START, LEN, INC) \
325     BxW_LOAD_pci(ubh, RES, PTR, START, LEN, INC)
326 #define BxW_LOAD_pci_S(RES, PTR, START, LEN, INC) \
327     BxW_LOAD_pci(bh, RES, PTR, START, LEN, INC)
328 
329 #define TEST_pci(NAME, TYPE, SIGN, LEN, INC, EXT, RES1, RES2, RES3, RES4) \
330 void test_##NAME(void) \
331 { \
332     TYPE result; \
333     void *ptr = buf; \
334     init_buf(); \
335     BxW_LOAD_pci_##SIGN(result, ptr, buf, (LEN), (INC)); \
336     check64(result, (RES1) | (EXT)); \
337     checkp(ptr, &buf[(1 * (INC)) % (LEN)]); \
338     BxW_LOAD_pci_##SIGN(result, ptr, buf, (LEN), (INC)); \
339     check64(result, (RES2) | (EXT)); \
340     checkp(ptr, &buf[(2 * (INC)) % (LEN)]); \
341     BxW_LOAD_pci_##SIGN(result, ptr, buf, (LEN), (INC)); \
342     check64(result, (RES3) | (EXT)); \
343     checkp(ptr, &buf[(3 * (INC)) % (LEN)]); \
344     BxW_LOAD_pci_##SIGN(result, ptr, buf, (LEN), (INC)); \
345     check64(result, (RES4) | (EXT)); \
346     checkp(ptr, &buf[(4 * (INC)) % (LEN)]); \
347 }
348 
349 TEST_pci(loadbzw2_pci, int32_t, Z, 6, 2, 0x00000000,
350     0x00020081, 0x00040083, 0x00060085, 0x00020081)
351 TEST_pci(loadbsw2_pci, int32_t, S, 6, 2, 0x0000ff00,
352     0x00020081, 0x00040083, 0x00060085, 0x00020081)
353 TEST_pci(loadbzw4_pci, int64_t, Z, 8, 4, 0x0000000000000000LL,
354     0x0004008300020081LL, 0x0008008700060085LL,
355     0x0004008300020081LL, 0x0008008700060085LL)
356 TEST_pci(loadbsw4_pci, int64_t, S, 8, 4, 0x0000ff000000ff00LL,
357     0x0004008300020081LL, 0x0008008700060085LL,
358     0x0004008300020081LL, 0x0008008700060085LL)
359 
360 /*
361  ****************************************************************************
362  * _pcr addressing mode (addr ++ I:circ(modifier-reg))
363  */
364 #define BxW_LOAD_pcr(SZ, RES, PTR, START, LEN, INC) \
365     __asm__( \
366         "r4 = %2\n\t" \
367         "m1 = r4\n\t" \
368         "cs1 = %3\n\t" \
369         "%0 = mem" #SZ "(%1++I:circ(m1))\n\t" \
370         : "=r"(RES), "+r"(PTR) \
371         : "r"((((INC) & 0x7f) << 17) | ((LEN) & 0x1ffff)), \
372           "r"(START) \
373         : "r4", "m1", "cs1")
374 #define BxW_LOAD_pcr_Z(RES, PTR, START, LEN, INC) \
375     BxW_LOAD_pcr(ubh, RES, PTR, START, LEN, INC)
376 #define BxW_LOAD_pcr_S(RES, PTR, START, LEN, INC) \
377     BxW_LOAD_pcr(bh, RES, PTR, START, LEN, INC)
378 
379 #define TEST_pcr(NAME, TYPE, SIGN, SIZE, LEN, INC, \
380                  EXT, RES1, RES2, RES3, RES4) \
381 void test_##NAME(void) \
382 { \
383     TYPE result; \
384     void *ptr = buf; \
385     init_buf(); \
386     BxW_LOAD_pcr_##SIGN(result, ptr, buf, (LEN), (INC)); \
387     check64(result, (RES1) | (EXT)); \
388     checkp(ptr, &buf[(1 * (INC) * (SIZE)) % (LEN)]); \
389     BxW_LOAD_pcr_##SIGN(result, ptr, buf, (LEN), (INC)); \
390     check64(result, (RES2) | (EXT)); \
391     checkp(ptr, &buf[(2 * (INC) * (SIZE)) % (LEN)]); \
392     BxW_LOAD_pcr_##SIGN(result, ptr, buf, (LEN), (INC)); \
393     check64(result, (RES3) | (EXT)); \
394     checkp(ptr, &buf[(3 * (INC) * (SIZE)) % (LEN)]); \
395     BxW_LOAD_pcr_##SIGN(result, ptr, buf, (LEN), (INC)); \
396     check64(result, (RES4) | (EXT)); \
397     checkp(ptr, &buf[(4 * (INC) * (SIZE)) % (LEN)]); \
398 }
399 
400 TEST_pcr(loadbzw2_pcr, int32_t, Z, 2, 8, 2, 0x00000000,
401     0x00020081, 0x00060085, 0x00020081, 0x00060085)
402 TEST_pcr(loadbsw2_pcr, int32_t, S, 2, 8, 2, 0x0000ff00,
403     0x00020081, 0x00060085, 0x00020081, 0x00060085)
404 TEST_pcr(loadbzw4_pcr, int64_t, Z, 4, 8, 1, 0x0000000000000000LL,
405     0x0004008300020081LL, 0x0008008700060085LL,
406     0x0004008300020081LL, 0x0008008700060085LL)
407 TEST_pcr(loadbsw4_pcr, int64_t, S, 4, 8, 1, 0x0000ff000000ff00LL,
408     0x0004008300020081LL, 0x0008008700060085LL,
409     0x0004008300020081LL, 0x0008008700060085LL)
410 
411 int main()
412 {
413     test_loadbzw2_io();
414     test_loadbsw2_io();
415     test_loadbzw4_io();
416     test_loadbsw4_io();
417 
418     test_loadbzw2_ur();
419     test_loadbsw2_ur();
420     test_loadbzw4_ur();
421     test_loadbsw4_ur();
422 
423     test_loadbzw2_ap();
424     test_loadbsw2_ap();
425     test_loadbzw4_ap();
426     test_loadbsw4_ap();
427 
428     test_loadbzw2_pr();
429     test_loadbsw2_pr();
430     test_loadbzw4_pr();
431     test_loadbsw4_pr();
432 
433     test_loadbzw2_pbr();
434     test_loadbsw2_pbr();
435     test_loadbzw4_pbr();
436     test_loadbsw4_pbr();
437 
438     test_loadbzw2_pi();
439     test_loadbsw2_pi();
440     test_loadbzw4_pi();
441     test_loadbsw4_pi();
442 
443     test_loadbzw2_pci();
444     test_loadbsw2_pci();
445     test_loadbzw4_pci();
446     test_loadbsw4_pci();
447 
448     test_loadbzw2_pcr();
449     test_loadbsw2_pcr();
450     test_loadbzw4_pcr();
451     test_loadbsw4_pcr();
452 
453     puts(err ? "FAIL" : "PASS");
454     return err ? 1 : 0;
455 }
456