xref: /openbmc/qemu/tests/tcg/hexagon/load_align.c (revision ac12b601)
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 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 <string.h>
33 
34 int err;
35 
36 char buf[16] __attribute__((aligned(1 << 16)));
37 
38 void init_buf(void)
39 {
40     int i;
41     for (i = 0; i < 16; i++) {
42         buf[i] = i + 1;
43     }
44 }
45 
46 void __check(int line, long long result, long long expect)
47 {
48     if (result != expect) {
49         printf("ERROR at line %d: 0x%016llx != 0x%016llx\n",
50                line, result, expect);
51         err++;
52     }
53 }
54 
55 #define check(RES, EXP) __check(__LINE__, RES, EXP)
56 
57 void __checkp(int line, void *p, void *expect)
58 {
59     if (p != expect) {
60         printf("ERROR at line %d: 0x%p != 0x%p\n", line, p, expect);
61         err++;
62     }
63 }
64 
65 #define checkp(RES, EXP) __checkp(__LINE__, RES, EXP)
66 
67 /*
68  ****************************************************************************
69  * _io addressing mode (addr + offset)
70  */
71 #define LOAD_io(SZ, RES, ADDR, OFF) \
72     __asm__( \
73         "%0 = mem" #SZ "_fifo(%1+#" #OFF ")\n\t" \
74         : "+r"(RES) \
75         : "r"(ADDR))
76 #define LOAD_io_b(RES, ADDR, OFF) \
77     LOAD_io(b, RES, ADDR, OFF)
78 #define LOAD_io_h(RES, ADDR, OFF) \
79     LOAD_io(h, RES, ADDR, OFF)
80 
81 #define TEST_io(NAME, SZ, SIZE, EXP1, EXP2, EXP3, EXP4) \
82 void test_##NAME(void) \
83 { \
84     long long result = ~0LL; \
85     LOAD_io_##SZ(result, buf, 0 * (SIZE)); \
86     check(result, (EXP1)); \
87     LOAD_io_##SZ(result, buf, 1 * (SIZE)); \
88     check(result, (EXP2)); \
89     LOAD_io_##SZ(result, buf, 2 * (SIZE)); \
90     check(result, (EXP3)); \
91     LOAD_io_##SZ(result, buf, 3 * (SIZE)); \
92     check(result, (EXP4)); \
93 }
94 
95 TEST_io(loadalignb_io, b, 1,
96         0x01ffffffffffffffLL, 0x0201ffffffffffffLL,
97         0x030201ffffffffffLL, 0x04030201ffffffffLL)
98 TEST_io(loadalignh_io, h, 2,
99         0x0201ffffffffffffLL, 0x04030201ffffffffLL,
100         0x060504030201ffffLL, 0x0807060504030201LL)
101 
102 /*
103  ****************************************************************************
104  * _ur addressing mode (index << offset + base)
105  */
106 #define LOAD_ur(SZ, RES, SHIFT, IDX) \
107     __asm__( \
108         "%0 = mem" #SZ "_fifo(%1<<#" #SHIFT " + ##buf)\n\t" \
109         : "+r"(RES) \
110         : "r"(IDX))
111 #define LOAD_ur_b(RES, SHIFT, IDX) \
112     LOAD_ur(b, RES, SHIFT, IDX)
113 #define LOAD_ur_h(RES, SHIFT, IDX) \
114     LOAD_ur(h, RES, SHIFT, IDX)
115 
116 #define TEST_ur(NAME, SZ, SHIFT, RES1, RES2, RES3, RES4) \
117 void test_##NAME(void) \
118 { \
119     long long result = ~0LL; \
120     LOAD_ur_##SZ(result, (SHIFT), 0); \
121     check(result, (RES1)); \
122     LOAD_ur_##SZ(result, (SHIFT), 1); \
123     check(result, (RES2)); \
124     LOAD_ur_##SZ(result, (SHIFT), 2); \
125     check(result, (RES3)); \
126     LOAD_ur_##SZ(result, (SHIFT), 3); \
127     check(result, (RES4)); \
128 }
129 
130 TEST_ur(loadalignb_ur, b, 1,
131         0x01ffffffffffffffLL, 0x0301ffffffffffffLL,
132         0x050301ffffffffffLL, 0x07050301ffffffffLL)
133 TEST_ur(loadalignh_ur, h, 1,
134         0x0201ffffffffffffLL, 0x04030201ffffffffLL,
135         0x060504030201ffffLL, 0x0807060504030201LL)
136 
137 /*
138  ****************************************************************************
139  * _ap addressing mode (addr = base)
140  */
141 #define LOAD_ap(SZ, RES, PTR, ADDR) \
142     __asm__(  \
143         "%0 = mem" #SZ "_fifo(%1 = ##" #ADDR ")\n\t" \
144         : "+r"(RES), "=r"(PTR))
145 #define LOAD_ap_b(RES, PTR, ADDR) \
146     LOAD_ap(b, RES, PTR, ADDR)
147 #define LOAD_ap_h(RES, PTR, ADDR) \
148     LOAD_ap(h, RES, PTR, ADDR)
149 
150 #define TEST_ap(NAME, SZ, SIZE, RES1, RES2, RES3, RES4) \
151 void test_##NAME(void) \
152 { \
153     long long result = ~0LL; \
154     void *ptr; \
155     LOAD_ap_##SZ(result, ptr, (buf + 0 * (SIZE))); \
156     check(result, (RES1)); \
157     checkp(ptr, &buf[0 * (SIZE)]); \
158     LOAD_ap_##SZ(result, ptr, (buf + 1 * (SIZE))); \
159     check(result, (RES2)); \
160     checkp(ptr, &buf[1 * (SIZE)]); \
161     LOAD_ap_##SZ(result, ptr, (buf + 2 * (SIZE))); \
162     check(result, (RES3)); \
163     checkp(ptr, &buf[2 * (SIZE)]); \
164     LOAD_ap_##SZ(result, ptr, (buf + 3 * (SIZE))); \
165     check(result, (RES4)); \
166     checkp(ptr, &buf[3 * (SIZE)]); \
167 }
168 
169 TEST_ap(loadalignb_ap, b, 1,
170         0x01ffffffffffffffLL, 0x0201ffffffffffffLL,
171         0x030201ffffffffffLL, 0x04030201ffffffffLL)
172 TEST_ap(loadalignh_ap, h, 2,
173         0x0201ffffffffffffLL, 0x04030201ffffffffLL,
174         0x060504030201ffffLL, 0x0807060504030201LL)
175 
176 /*
177  ****************************************************************************
178  * _rp addressing mode (addr ++ modifer-reg)
179  */
180 #define LOAD_pr(SZ, RES, PTR, INC) \
181     __asm__( \
182         "m0 = %2\n\t" \
183         "%0 = mem" #SZ "_fifo(%1++m0)\n\t" \
184         : "+r"(RES), "+r"(PTR) \
185         : "r"(INC) \
186         : "m0")
187 #define LOAD_pr_b(RES, PTR, INC) \
188     LOAD_pr(b, RES, PTR, INC)
189 #define LOAD_pr_h(RES, PTR, INC) \
190     LOAD_pr(h, RES, PTR, INC)
191 
192 #define TEST_pr(NAME, SZ, SIZE, RES1, RES2, RES3, RES4) \
193 void test_##NAME(void) \
194 { \
195     long long result = ~0LL; \
196     void *ptr = buf; \
197     LOAD_pr_##SZ(result, ptr, (SIZE)); \
198     check(result, (RES1)); \
199     checkp(ptr, &buf[1 * (SIZE)]); \
200     LOAD_pr_##SZ(result, ptr, (SIZE)); \
201     check(result, (RES2)); \
202     checkp(ptr, &buf[2 * (SIZE)]); \
203     LOAD_pr_##SZ(result, ptr, (SIZE)); \
204     check(result, (RES3)); \
205     checkp(ptr, &buf[3 * (SIZE)]); \
206     LOAD_pr_##SZ(result, ptr, (SIZE)); \
207     check(result, (RES4)); \
208     checkp(ptr, &buf[4 * (SIZE)]); \
209 }
210 
211 TEST_pr(loadalignb_pr, b, 1,
212         0x01ffffffffffffffLL, 0x0201ffffffffffffLL,
213         0x030201ffffffffffLL, 0x04030201ffffffffLL)
214 TEST_pr(loadalignh_pr, h, 2,
215         0x0201ffffffffffffLL, 0x04030201ffffffffLL,
216         0x060504030201ffffLL, 0x0807060504030201LL)
217 
218 /*
219  ****************************************************************************
220  * _pbr addressing mode (addr ++ modifer-reg:brev)
221  */
222 #define LOAD_pbr(SZ, RES, PTR) \
223     __asm__( \
224         "r4 = #(1 << (16 - 3))\n\t" \
225         "m0 = r4\n\t" \
226         "%0 = mem" #SZ "_fifo(%1++m0:brev)\n\t" \
227         : "+r"(RES), "+r"(PTR) \
228         : \
229         : "r4", "m0")
230 #define LOAD_pbr_b(RES, PTR) \
231     LOAD_pbr(b, RES, PTR)
232 #define LOAD_pbr_h(RES, PTR) \
233     LOAD_pbr(h, RES, PTR)
234 
235 #define TEST_pbr(NAME, SZ, RES1, RES2, RES3, RES4) \
236 void test_##NAME(void) \
237 { \
238     long long result = ~0LL; \
239     void *ptr = buf; \
240     LOAD_pbr_##SZ(result, ptr); \
241     check(result, (RES1)); \
242     LOAD_pbr_##SZ(result, ptr); \
243     check(result, (RES2)); \
244     LOAD_pbr_##SZ(result, ptr); \
245     check(result, (RES3)); \
246     LOAD_pbr_##SZ(result, ptr); \
247     check(result, (RES4)); \
248 }
249 
250 TEST_pbr(loadalignb_pbr, b,
251     0x01ffffffffffffffLL, 0x0501ffffffffffffLL,
252     0x030501ffffffffffLL, 0x07030501ffffffffLL)
253 TEST_pbr(loadalignh_pbr, h,
254     0x0201ffffffffffffLL, 0x06050201ffffffffLL,
255     0x040306050201ffffLL, 0x0807040306050201LL)
256 
257 /*
258  ****************************************************************************
259  * _pi addressing mode (addr ++ inc)
260  */
261 #define LOAD_pi(SZ, RES, PTR, INC) \
262     __asm__( \
263         "%0 = mem" #SZ "_fifo(%1++#" #INC ")\n\t" \
264         : "+r"(RES), "+r"(PTR))
265 #define LOAD_pi_b(RES, PTR, INC) \
266     LOAD_pi(b, RES, PTR, INC)
267 #define LOAD_pi_h(RES, PTR, INC) \
268     LOAD_pi(h, RES, PTR, INC)
269 
270 #define TEST_pi(NAME, SZ, INC, RES1, RES2, RES3, RES4) \
271 void test_##NAME(void) \
272 { \
273     long long result = ~0LL; \
274     void *ptr = buf; \
275     LOAD_pi_##SZ(result, ptr, (INC)); \
276     check(result, (RES1)); \
277     checkp(ptr, &buf[1 * (INC)]); \
278     LOAD_pi_##SZ(result, ptr, (INC)); \
279     check(result, (RES2)); \
280     checkp(ptr, &buf[2 * (INC)]); \
281     LOAD_pi_##SZ(result, ptr, (INC)); \
282     check(result, (RES3)); \
283     checkp(ptr, &buf[3 * (INC)]); \
284     LOAD_pi_##SZ(result, ptr, (INC)); \
285     check(result, (RES4)); \
286     checkp(ptr, &buf[4 * (INC)]); \
287 }
288 
289 TEST_pi(loadalignb_pi, b, 1,
290         0x01ffffffffffffffLL, 0x0201ffffffffffffLL,
291         0x030201ffffffffffLL, 0x04030201ffffffffLL)
292 TEST_pi(loadalignh_pi, h, 2,
293         0x0201ffffffffffffLL, 0x04030201ffffffffLL,
294         0x060504030201ffffLL, 0x0807060504030201LL)
295 
296 /*
297  ****************************************************************************
298  * _pci addressing mode (addr ++ inc:circ)
299  */
300 #define LOAD_pci(SZ, RES, PTR, START, LEN, INC) \
301     __asm__( \
302         "r4 = %3\n\t" \
303         "m0 = r4\n\t" \
304         "cs0 = %2\n\t" \
305         "%0 = mem" #SZ "_fifo(%1++#" #INC ":circ(m0))\n\t" \
306         : "+r"(RES), "+r"(PTR) \
307         : "r"(START), "r"(LEN) \
308         : "r4", "m0", "cs0")
309 #define LOAD_pci_b(RES, PTR, START, LEN, INC) \
310     LOAD_pci(b, RES, PTR, START, LEN, INC)
311 #define LOAD_pci_h(RES, PTR, START, LEN, INC) \
312     LOAD_pci(h, RES, PTR, START, LEN, INC)
313 
314 #define TEST_pci(NAME, SZ, LEN, INC, RES1, RES2, RES3, RES4) \
315 void test_##NAME(void) \
316 { \
317     long long result = ~0LL; \
318     void *ptr = buf; \
319     LOAD_pci_##SZ(result, ptr, buf, (LEN), (INC)); \
320     check(result, (RES1)); \
321     checkp(ptr, &buf[(1 * (INC)) % (LEN)]); \
322     LOAD_pci_##SZ(result, ptr, buf, (LEN), (INC)); \
323     check(result, (RES2)); \
324     checkp(ptr, &buf[(2 * (INC)) % (LEN)]); \
325     LOAD_pci_##SZ(result, ptr, buf, (LEN), (INC)); \
326     check(result, (RES3)); \
327     checkp(ptr, &buf[(3 * (INC)) % (LEN)]); \
328     LOAD_pci_##SZ(result, ptr, buf, (LEN), (INC)); \
329     check(result, (RES4)); \
330     checkp(ptr, &buf[(4 * (INC)) % (LEN)]); \
331 }
332 
333 TEST_pci(loadalignb_pci, b, 2, 1,
334     0x01ffffffffffffffLL, 0x0201ffffffffffffLL,
335     0x010201ffffffffffLL, 0x02010201ffffffffLL)
336 TEST_pci(loadalignh_pci, h, 4, 2,
337     0x0201ffffffffffffLL, 0x04030201ffffffffLL,
338     0x020104030201ffffLL, 0x0403020104030201LL)
339 
340 /*
341  ****************************************************************************
342  * _pcr addressing mode (addr ++ I:circ(modifier-reg))
343  */
344 #define LOAD_pcr(SZ, RES, PTR, START, LEN, INC) \
345     __asm__( \
346         "r4 = %2\n\t" \
347         "m1 = r4\n\t" \
348         "cs1 = %3\n\t" \
349         "%0 = mem" #SZ "_fifo(%1++I:circ(m1))\n\t" \
350         : "+r"(RES), "+r"(PTR) \
351         : "r"((((INC) & 0x7f) << 17) | ((LEN) & 0x1ffff)), \
352           "r"(START) \
353         : "r4", "m1", "cs1")
354 #define LOAD_pcr_b(RES, PTR, START, LEN, INC) \
355     LOAD_pcr(b, RES, PTR, START, LEN, INC)
356 #define LOAD_pcr_h(RES, PTR, START, LEN, INC) \
357     LOAD_pcr(h, RES, PTR, START, LEN, INC)
358 
359 #define TEST_pcr(NAME, SZ, SIZE, LEN, INC, RES1, RES2, RES3, RES4) \
360 void test_##NAME(void) \
361 { \
362     long long result = ~0LL; \
363     void *ptr = buf; \
364     LOAD_pcr_##SZ(result, ptr, buf, (LEN), (INC)); \
365     check(result, (RES1)); \
366     checkp(ptr, &buf[(1 * (INC) * (SIZE)) % (LEN)]); \
367     LOAD_pcr_##SZ(result, ptr, buf, (LEN), (INC)); \
368     check(result, (RES2)); \
369     checkp(ptr, &buf[(2 * (INC) * (SIZE)) % (LEN)]); \
370     LOAD_pcr_##SZ(result, ptr, buf, (LEN), (INC)); \
371     check(result, (RES3)); \
372     checkp(ptr, &buf[(3 * (INC) * (SIZE)) % (LEN)]); \
373     LOAD_pcr_##SZ(result, ptr, buf, (LEN), (INC)); \
374     check(result, (RES4)); \
375     checkp(ptr, &buf[(4 * (INC) * (SIZE)) % (LEN)]); \
376 }
377 
378 TEST_pcr(loadalignb_pcr, b, 1, 2, 1,
379     0x01ffffffffffffffLL, 0x0201ffffffffffffLL,
380     0x010201ffffffffffLL, 0x02010201ffffffffLL)
381 TEST_pcr(loadalignh_pcr, h, 2, 4, 1,
382     0x0201ffffffffffffLL, 0x04030201ffffffffLL,
383     0x020104030201ffffLL, 0x0403020104030201LL)
384 
385 int main()
386 {
387     init_buf();
388 
389     test_loadalignb_io();
390     test_loadalignh_io();
391 
392     test_loadalignb_ur();
393     test_loadalignh_ur();
394 
395     test_loadalignb_ap();
396     test_loadalignh_ap();
397 
398     test_loadalignb_pr();
399     test_loadalignh_pr();
400 
401     test_loadalignb_pbr();
402     test_loadalignh_pbr();
403 
404     test_loadalignb_pi();
405     test_loadalignh_pi();
406 
407     test_loadalignb_pci();
408     test_loadalignh_pci();
409 
410     test_loadalignb_pcr();
411     test_loadalignh_pcr();
412 
413     puts(err ? "FAIL" : "PASS");
414     return err ? 1 : 0;
415 }
416