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