]>
Commit | Line | Data |
---|---|---|
4d1135e4 FB |
1 | #include <stdlib.h> |
2 | #include <stdio.h> | |
6dbad63e | 3 | #include <inttypes.h> |
4d1135e4 FB |
4 | #include <math.h> |
5 | ||
5dd9488c FB |
6 | #define TEST_CMOV 0 |
7 | ||
4d1135e4 FB |
8 | #define xglue(x, y) x ## y |
9 | #define glue(x, y) xglue(x, y) | |
10 | #define stringify(s) tostring(s) | |
11 | #define tostring(s) #s | |
12 | ||
13 | #define CC_C 0x0001 | |
14 | #define CC_P 0x0004 | |
15 | #define CC_A 0x0010 | |
16 | #define CC_Z 0x0040 | |
17 | #define CC_S 0x0080 | |
18 | #define CC_O 0x0800 | |
19 | ||
4d1135e4 FB |
20 | #define __init_call __attribute__ ((unused,__section__ (".initcall.init"))) |
21 | ||
22 | static void *call_start __init_call = NULL; | |
23 | ||
4b74fe1f FB |
24 | #define CC_MASK (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A) |
25 | ||
4d1135e4 FB |
26 | #define OP add |
27 | #include "test-i386.h" | |
28 | ||
29 | #define OP sub | |
30 | #include "test-i386.h" | |
31 | ||
32 | #define OP xor | |
33 | #include "test-i386.h" | |
34 | ||
35 | #define OP and | |
36 | #include "test-i386.h" | |
37 | ||
38 | #define OP or | |
39 | #include "test-i386.h" | |
40 | ||
41 | #define OP cmp | |
42 | #include "test-i386.h" | |
43 | ||
44 | #define OP adc | |
45 | #define OP_CC | |
46 | #include "test-i386.h" | |
47 | ||
48 | #define OP sbb | |
49 | #define OP_CC | |
50 | #include "test-i386.h" | |
51 | ||
52 | #define OP inc | |
53 | #define OP_CC | |
54 | #define OP1 | |
55 | #include "test-i386.h" | |
56 | ||
57 | #define OP dec | |
58 | #define OP_CC | |
59 | #define OP1 | |
60 | #include "test-i386.h" | |
61 | ||
62 | #define OP neg | |
63 | #define OP_CC | |
64 | #define OP1 | |
65 | #include "test-i386.h" | |
66 | ||
67 | #define OP not | |
68 | #define OP_CC | |
69 | #define OP1 | |
70 | #include "test-i386.h" | |
71 | ||
4b74fe1f FB |
72 | #undef CC_MASK |
73 | #define CC_MASK (CC_C | CC_P | CC_Z | CC_S | CC_O) | |
74 | ||
379ca80d FB |
75 | #define OP shl |
76 | #include "test-i386-shift.h" | |
77 | ||
78 | #define OP shr | |
79 | #include "test-i386-shift.h" | |
80 | ||
81 | #define OP sar | |
82 | #include "test-i386-shift.h" | |
83 | ||
84 | #define OP rol | |
85 | #include "test-i386-shift.h" | |
86 | ||
87 | #define OP ror | |
88 | #include "test-i386-shift.h" | |
89 | ||
90 | #define OP rcr | |
91 | #define OP_CC | |
92 | #include "test-i386-shift.h" | |
93 | ||
94 | #define OP rcl | |
95 | #define OP_CC | |
96 | #include "test-i386-shift.h" | |
97 | ||
d57c4e01 FB |
98 | #define OP shld |
99 | #define OP_SHIFTD | |
100 | #define OP_NOBYTE | |
101 | #include "test-i386-shift.h" | |
102 | ||
103 | #define OP shrd | |
104 | #define OP_SHIFTD | |
105 | #define OP_NOBYTE | |
106 | #include "test-i386-shift.h" | |
107 | ||
108 | /* XXX: should be more precise ? */ | |
109 | #undef CC_MASK | |
110 | #define CC_MASK (CC_C) | |
111 | ||
112 | #define OP bt | |
113 | #define OP_NOBYTE | |
114 | #include "test-i386-shift.h" | |
115 | ||
116 | #define OP bts | |
117 | #define OP_NOBYTE | |
118 | #include "test-i386-shift.h" | |
119 | ||
120 | #define OP btr | |
121 | #define OP_NOBYTE | |
122 | #include "test-i386-shift.h" | |
123 | ||
124 | #define OP btc | |
125 | #define OP_NOBYTE | |
126 | #include "test-i386-shift.h" | |
379ca80d | 127 | |
4d1135e4 FB |
128 | /* lea test (modrm support) */ |
129 | #define TEST_LEA(STR)\ | |
130 | {\ | |
131 | asm("leal " STR ", %0"\ | |
132 | : "=r" (res)\ | |
133 | : "a" (eax), "b" (ebx), "c" (ecx), "d" (edx), "S" (esi), "D" (edi));\ | |
134 | printf("lea %s = %08x\n", STR, res);\ | |
135 | } | |
136 | ||
137 | #define TEST_LEA16(STR)\ | |
138 | {\ | |
139 | asm(".code16 ; .byte 0x67 ; leal " STR ", %0 ; .code32"\ | |
140 | : "=wq" (res)\ | |
141 | : "a" (eax), "b" (ebx), "c" (ecx), "d" (edx), "S" (esi), "D" (edi));\ | |
142 | printf("lea %s = %08x\n", STR, res);\ | |
143 | } | |
144 | ||
145 | ||
146 | void test_lea(void) | |
147 | { | |
148 | int eax, ebx, ecx, edx, esi, edi, res; | |
149 | eax = 0x0001; | |
150 | ebx = 0x0002; | |
151 | ecx = 0x0004; | |
152 | edx = 0x0008; | |
153 | esi = 0x0010; | |
154 | edi = 0x0020; | |
155 | ||
156 | TEST_LEA("0x4000"); | |
157 | ||
158 | TEST_LEA("(%%eax)"); | |
159 | TEST_LEA("(%%ebx)"); | |
160 | TEST_LEA("(%%ecx)"); | |
161 | TEST_LEA("(%%edx)"); | |
162 | TEST_LEA("(%%esi)"); | |
163 | TEST_LEA("(%%edi)"); | |
164 | ||
165 | TEST_LEA("0x40(%%eax)"); | |
166 | TEST_LEA("0x40(%%ebx)"); | |
167 | TEST_LEA("0x40(%%ecx)"); | |
168 | TEST_LEA("0x40(%%edx)"); | |
169 | TEST_LEA("0x40(%%esi)"); | |
170 | TEST_LEA("0x40(%%edi)"); | |
171 | ||
172 | TEST_LEA("0x4000(%%eax)"); | |
173 | TEST_LEA("0x4000(%%ebx)"); | |
174 | TEST_LEA("0x4000(%%ecx)"); | |
175 | TEST_LEA("0x4000(%%edx)"); | |
176 | TEST_LEA("0x4000(%%esi)"); | |
177 | TEST_LEA("0x4000(%%edi)"); | |
178 | ||
179 | TEST_LEA("(%%eax, %%ecx)"); | |
180 | TEST_LEA("(%%ebx, %%edx)"); | |
181 | TEST_LEA("(%%ecx, %%ecx)"); | |
182 | TEST_LEA("(%%edx, %%ecx)"); | |
183 | TEST_LEA("(%%esi, %%ecx)"); | |
184 | TEST_LEA("(%%edi, %%ecx)"); | |
185 | ||
186 | TEST_LEA("0x40(%%eax, %%ecx)"); | |
187 | TEST_LEA("0x4000(%%ebx, %%edx)"); | |
188 | ||
189 | TEST_LEA("(%%ecx, %%ecx, 2)"); | |
190 | TEST_LEA("(%%edx, %%ecx, 4)"); | |
191 | TEST_LEA("(%%esi, %%ecx, 8)"); | |
192 | ||
193 | TEST_LEA("(,%%eax, 2)"); | |
194 | TEST_LEA("(,%%ebx, 4)"); | |
195 | TEST_LEA("(,%%ecx, 8)"); | |
196 | ||
197 | TEST_LEA("0x40(,%%eax, 2)"); | |
198 | TEST_LEA("0x40(,%%ebx, 4)"); | |
199 | TEST_LEA("0x40(,%%ecx, 8)"); | |
200 | ||
201 | ||
202 | TEST_LEA("-10(%%ecx, %%ecx, 2)"); | |
203 | TEST_LEA("-10(%%edx, %%ecx, 4)"); | |
204 | TEST_LEA("-10(%%esi, %%ecx, 8)"); | |
205 | ||
206 | TEST_LEA("0x4000(%%ecx, %%ecx, 2)"); | |
207 | TEST_LEA("0x4000(%%edx, %%ecx, 4)"); | |
208 | TEST_LEA("0x4000(%%esi, %%ecx, 8)"); | |
209 | ||
210 | /* limited 16 bit addressing test */ | |
211 | TEST_LEA16("0x4000"); | |
212 | TEST_LEA16("(%%bx)"); | |
213 | TEST_LEA16("(%%si)"); | |
214 | TEST_LEA16("(%%di)"); | |
215 | TEST_LEA16("0x40(%%bx)"); | |
216 | TEST_LEA16("0x40(%%si)"); | |
217 | TEST_LEA16("0x40(%%di)"); | |
218 | TEST_LEA16("0x4000(%%bx)"); | |
219 | TEST_LEA16("0x4000(%%si)"); | |
220 | TEST_LEA16("(%%bx,%%si)"); | |
221 | TEST_LEA16("(%%bx,%%di)"); | |
222 | TEST_LEA16("0x40(%%bx,%%si)"); | |
223 | TEST_LEA16("0x40(%%bx,%%di)"); | |
224 | TEST_LEA16("0x4000(%%bx,%%si)"); | |
225 | TEST_LEA16("0x4000(%%bx,%%di)"); | |
226 | } | |
227 | ||
228 | #define TEST_JCC(JCC, v1, v2)\ | |
229 | {\ | |
5dd9488c | 230 | int res;\ |
4d1135e4 FB |
231 | asm("movl $1, %0\n\t"\ |
232 | "cmpl %2, %1\n\t"\ | |
5dd9488c | 233 | "j" JCC " 1f\n\t"\ |
4d1135e4 FB |
234 | "movl $0, %0\n\t"\ |
235 | "1:\n\t"\ | |
236 | : "=r" (res)\ | |
237 | : "r" (v1), "r" (v2));\ | |
5dd9488c FB |
238 | printf("%-10s %d\n", "j" JCC, res);\ |
239 | \ | |
240 | asm("movl $0, %0\n\t"\ | |
241 | "cmpl %2, %1\n\t"\ | |
242 | "set" JCC " %b0\n\t"\ | |
243 | : "=r" (res)\ | |
244 | : "r" (v1), "r" (v2));\ | |
245 | printf("%-10s %d\n", "set" JCC, res);\ | |
246 | if (TEST_CMOV) {\ | |
247 | asm("movl $0x12345678, %0\n\t"\ | |
248 | "cmpl %2, %1\n\t"\ | |
249 | "cmov" JCC "l %3, %0\n\t"\ | |
250 | : "=r" (res)\ | |
251 | : "r" (v1), "r" (v2), "m" (1));\ | |
252 | printf("%-10s R=0x%08x\n", "cmov" JCC "l", res);\ | |
253 | asm("movl $0x12345678, %0\n\t"\ | |
254 | "cmpl %2, %1\n\t"\ | |
255 | "cmov" JCC "w %w3, %w0\n\t"\ | |
256 | : "=r" (res)\ | |
257 | : "r" (v1), "r" (v2), "r" (1));\ | |
258 | printf("%-10s R=0x%08x\n", "cmov" JCC "w", res);\ | |
259 | } \ | |
4d1135e4 FB |
260 | } |
261 | ||
262 | /* various jump tests */ | |
263 | void test_jcc(void) | |
264 | { | |
5dd9488c FB |
265 | TEST_JCC("ne", 1, 1); |
266 | TEST_JCC("ne", 1, 0); | |
4d1135e4 | 267 | |
5dd9488c FB |
268 | TEST_JCC("e", 1, 1); |
269 | TEST_JCC("e", 1, 0); | |
4d1135e4 | 270 | |
5dd9488c FB |
271 | TEST_JCC("l", 1, 1); |
272 | TEST_JCC("l", 1, 0); | |
273 | TEST_JCC("l", 1, -1); | |
4d1135e4 | 274 | |
5dd9488c FB |
275 | TEST_JCC("le", 1, 1); |
276 | TEST_JCC("le", 1, 0); | |
277 | TEST_JCC("le", 1, -1); | |
4d1135e4 | 278 | |
5dd9488c FB |
279 | TEST_JCC("ge", 1, 1); |
280 | TEST_JCC("ge", 1, 0); | |
281 | TEST_JCC("ge", -1, 1); | |
4d1135e4 | 282 | |
5dd9488c FB |
283 | TEST_JCC("g", 1, 1); |
284 | TEST_JCC("g", 1, 0); | |
285 | TEST_JCC("g", 1, -1); | |
4d1135e4 | 286 | |
5dd9488c FB |
287 | TEST_JCC("b", 1, 1); |
288 | TEST_JCC("b", 1, 0); | |
289 | TEST_JCC("b", 1, -1); | |
4d1135e4 | 290 | |
5dd9488c FB |
291 | TEST_JCC("be", 1, 1); |
292 | TEST_JCC("be", 1, 0); | |
293 | TEST_JCC("be", 1, -1); | |
4d1135e4 | 294 | |
5dd9488c FB |
295 | TEST_JCC("ae", 1, 1); |
296 | TEST_JCC("ae", 1, 0); | |
297 | TEST_JCC("ae", 1, -1); | |
4d1135e4 | 298 | |
5dd9488c FB |
299 | TEST_JCC("a", 1, 1); |
300 | TEST_JCC("a", 1, 0); | |
301 | TEST_JCC("a", 1, -1); | |
4d1135e4 FB |
302 | |
303 | ||
5dd9488c FB |
304 | TEST_JCC("p", 1, 1); |
305 | TEST_JCC("p", 1, 0); | |
4d1135e4 | 306 | |
5dd9488c FB |
307 | TEST_JCC("np", 1, 1); |
308 | TEST_JCC("np", 1, 0); | |
4d1135e4 | 309 | |
5dd9488c FB |
310 | TEST_JCC("o", 0x7fffffff, 0); |
311 | TEST_JCC("o", 0x7fffffff, -1); | |
4d1135e4 | 312 | |
5dd9488c FB |
313 | TEST_JCC("no", 0x7fffffff, 0); |
314 | TEST_JCC("no", 0x7fffffff, -1); | |
4d1135e4 | 315 | |
5dd9488c FB |
316 | TEST_JCC("s", 0, 1); |
317 | TEST_JCC("s", 0, -1); | |
318 | TEST_JCC("s", 0, 0); | |
4d1135e4 | 319 | |
5dd9488c FB |
320 | TEST_JCC("ns", 0, 1); |
321 | TEST_JCC("ns", 0, -1); | |
322 | TEST_JCC("ns", 0, 0); | |
4d1135e4 FB |
323 | } |
324 | ||
4b74fe1f FB |
325 | #undef CC_MASK |
326 | #define CC_MASK (CC_O | CC_C) | |
327 | ||
328 | #define OP mul | |
329 | #include "test-i386-muldiv.h" | |
330 | ||
331 | #define OP imul | |
332 | #include "test-i386-muldiv.h" | |
333 | ||
334 | #undef CC_MASK | |
335 | #define CC_MASK (0) | |
336 | ||
337 | #define OP div | |
338 | #include "test-i386-muldiv.h" | |
339 | ||
340 | #define OP idiv | |
341 | #include "test-i386-muldiv.h" | |
342 | ||
343 | void test_imulw2(int op0, int op1) | |
344 | { | |
345 | int res, s1, s0, flags; | |
346 | s0 = op0; | |
347 | s1 = op1; | |
348 | res = s0; | |
349 | flags = 0; | |
350 | asm ("push %4\n\t" | |
351 | "popf\n\t" | |
352 | "imulw %w2, %w0\n\t" | |
353 | "pushf\n\t" | |
354 | "popl %1\n\t" | |
355 | : "=q" (res), "=g" (flags) | |
356 | : "q" (s1), "0" (res), "1" (flags)); | |
357 | printf("%-10s A=%08x B=%08x R=%08x CC=%04x\n", | |
358 | "imulw", s0, s1, res, flags & CC_MASK); | |
359 | } | |
360 | ||
361 | void test_imull2(int op0, int op1) | |
362 | { | |
363 | int res, s1, s0, flags; | |
364 | s0 = op0; | |
365 | s1 = op1; | |
366 | res = s0; | |
367 | flags = 0; | |
368 | asm ("push %4\n\t" | |
369 | "popf\n\t" | |
370 | "imull %2, %0\n\t" | |
371 | "pushf\n\t" | |
372 | "popl %1\n\t" | |
373 | : "=q" (res), "=g" (flags) | |
374 | : "q" (s1), "0" (res), "1" (flags)); | |
375 | printf("%-10s A=%08x B=%08x R=%08x CC=%04x\n", | |
376 | "imull", s0, s1, res, flags & CC_MASK); | |
377 | } | |
378 | ||
379 | void test_mul(void) | |
380 | { | |
381 | test_imulb(0x1234561d, 4); | |
382 | test_imulb(3, -4); | |
383 | test_imulb(0x80, 0x80); | |
384 | test_imulb(0x10, 0x10); | |
385 | ||
386 | test_imulw(0, 0x1234001d, 45); | |
387 | test_imulw(0, 23, -45); | |
388 | test_imulw(0, 0x8000, 0x8000); | |
389 | test_imulw(0, 0x100, 0x100); | |
390 | ||
391 | test_imull(0, 0x1234001d, 45); | |
392 | test_imull(0, 23, -45); | |
393 | test_imull(0, 0x80000000, 0x80000000); | |
394 | test_imull(0, 0x10000, 0x10000); | |
395 | ||
396 | test_mulb(0x1234561d, 4); | |
397 | test_mulb(3, -4); | |
398 | test_mulb(0x80, 0x80); | |
399 | test_mulb(0x10, 0x10); | |
400 | ||
401 | test_mulw(0, 0x1234001d, 45); | |
402 | test_mulw(0, 23, -45); | |
403 | test_mulw(0, 0x8000, 0x8000); | |
404 | test_mulw(0, 0x100, 0x100); | |
405 | ||
406 | test_mull(0, 0x1234001d, 45); | |
407 | test_mull(0, 23, -45); | |
408 | test_mull(0, 0x80000000, 0x80000000); | |
409 | test_mull(0, 0x10000, 0x10000); | |
410 | ||
411 | test_imulw2(0x1234001d, 45); | |
412 | test_imulw2(23, -45); | |
413 | test_imulw2(0x8000, 0x8000); | |
414 | test_imulw2(0x100, 0x100); | |
415 | ||
416 | test_imull2(0x1234001d, 45); | |
417 | test_imull2(23, -45); | |
418 | test_imull2(0x80000000, 0x80000000); | |
419 | test_imull2(0x10000, 0x10000); | |
420 | ||
421 | test_idivb(0x12341678, 0x127e); | |
422 | test_idivb(0x43210123, -5); | |
423 | test_idivb(0x12340004, -1); | |
424 | ||
425 | test_idivw(0, 0x12345678, 12347); | |
426 | test_idivw(0, -23223, -45); | |
427 | test_idivw(0, 0x12348000, -1); | |
428 | test_idivw(0x12343, 0x12345678, 0x81238567); | |
429 | ||
430 | test_idivl(0, 0x12345678, 12347); | |
431 | test_idivl(0, -233223, -45); | |
432 | test_idivl(0, 0x80000000, -1); | |
433 | test_idivl(0x12343, 0x12345678, 0x81234567); | |
434 | ||
435 | test_divb(0x12341678, 0x127e); | |
436 | test_divb(0x43210123, -5); | |
437 | test_divb(0x12340004, -1); | |
438 | ||
439 | test_divw(0, 0x12345678, 12347); | |
440 | test_divw(0, -23223, -45); | |
441 | test_divw(0, 0x12348000, -1); | |
442 | test_divw(0x12343, 0x12345678, 0x81238567); | |
443 | ||
444 | test_divl(0, 0x12345678, 12347); | |
445 | test_divl(0, -233223, -45); | |
446 | test_divl(0, 0x80000000, -1); | |
447 | test_divl(0x12343, 0x12345678, 0x81234567); | |
448 | } | |
449 | ||
9d8e9c09 FB |
450 | #define TEST_BSX(op, size, op0)\ |
451 | {\ | |
452 | int res, val, resz;\ | |
453 | val = op0;\ | |
454 | asm("xorl %1, %1 ; " #op " %" size "2, %" size "0 ; setz %b1" \ | |
455 | : "=r" (res), "=q" (resz)\ | |
456 | : "g" (val));\ | |
457 | printf("%-10s A=%08x R=%08x %d\n", #op, val, resz ? 0 : res, resz);\ | |
458 | } | |
459 | ||
460 | void test_bsx(void) | |
461 | { | |
462 | TEST_BSX(bsrw, "w", 0); | |
463 | TEST_BSX(bsrw, "w", 0x12340128); | |
464 | TEST_BSX(bsrl, "", 0); | |
465 | TEST_BSX(bsrl, "", 0x00340128); | |
466 | TEST_BSX(bsfw, "w", 0); | |
467 | TEST_BSX(bsfw, "w", 0x12340128); | |
468 | TEST_BSX(bsfl, "", 0); | |
469 | TEST_BSX(bsfl, "", 0x00340128); | |
470 | } | |
471 | ||
55480af8 FB |
472 | /**********************************************/ |
473 | ||
9d8e9c09 FB |
474 | void test_fops(double a, double b) |
475 | { | |
476 | printf("a=%f b=%f a+b=%f\n", a, b, a + b); | |
477 | printf("a=%f b=%f a-b=%f\n", a, b, a - b); | |
478 | printf("a=%f b=%f a*b=%f\n", a, b, a * b); | |
479 | printf("a=%f b=%f a/b=%f\n", a, b, a / b); | |
480 | printf("a=%f b=%f fmod(a, b)=%f\n", a, b, fmod(a, b)); | |
481 | printf("a=%f sqrt(a)=%f\n", a, sqrt(a)); | |
482 | printf("a=%f sin(a)=%f\n", a, sin(a)); | |
483 | printf("a=%f cos(a)=%f\n", a, cos(a)); | |
484 | printf("a=%f tan(a)=%f\n", a, tan(a)); | |
485 | printf("a=%f log(a)=%f\n", a, log(a)); | |
486 | printf("a=%f exp(a)=%f\n", a, exp(a)); | |
487 | printf("a=%f b=%f atan2(a, b)=%f\n", a, b, atan2(a, b)); | |
488 | /* just to test some op combining */ | |
489 | printf("a=%f asin(sin(a))=%f\n", a, asin(sin(a))); | |
490 | printf("a=%f acos(cos(a))=%f\n", a, acos(cos(a))); | |
491 | printf("a=%f atan(tan(a))=%f\n", a, atan(tan(a))); | |
492 | ||
493 | } | |
494 | ||
495 | void test_fcmp(double a, double b) | |
496 | { | |
497 | printf("(%f<%f)=%d\n", | |
498 | a, b, a < b); | |
499 | printf("(%f<=%f)=%d\n", | |
500 | a, b, a <= b); | |
501 | printf("(%f==%f)=%d\n", | |
502 | a, b, a == b); | |
503 | printf("(%f>%f)=%d\n", | |
504 | a, b, a > b); | |
505 | printf("(%f<=%f)=%d\n", | |
506 | a, b, a >= b); | |
507 | } | |
508 | ||
509 | void test_fcvt(double a) | |
510 | { | |
511 | float fa; | |
512 | long double la; | |
513 | ||
514 | fa = a; | |
515 | la = a; | |
516 | printf("(float)%f = %f\n", a, fa); | |
517 | printf("(long double)%f = %Lf\n", a, la); | |
c5e9815d FB |
518 | printf("a=%016Lx\n", *(long long *)&a); |
519 | printf("la=%016Lx %04x\n", *(long long *)&la, | |
520 | *(unsigned short *)((char *)(&la) + 8)); | |
9d8e9c09 FB |
521 | printf("a=%f floor(a)=%f\n", a, floor(a)); |
522 | printf("a=%f ceil(a)=%f\n", a, ceil(a)); | |
523 | printf("a=%f rint(a)=%f\n", a, rint(a)); | |
524 | } | |
525 | ||
526 | #define TEST(N) \ | |
527 | asm("fld" #N : "=t" (a)); \ | |
528 | printf("fld" #N "= %f\n", a); | |
529 | ||
530 | void test_fconst(void) | |
531 | { | |
532 | double a; | |
533 | TEST(1); | |
534 | TEST(l2t); | |
535 | TEST(l2e); | |
536 | TEST(pi); | |
537 | TEST(lg2); | |
538 | TEST(ln2); | |
539 | TEST(z); | |
540 | } | |
541 | ||
c5e9815d FB |
542 | void test_fbcd(double a) |
543 | { | |
544 | unsigned short bcd[5]; | |
545 | double b; | |
546 | ||
547 | asm("fbstp %0" : "=m" (bcd[0]) : "t" (a) : "st"); | |
548 | asm("fbld %1" : "=t" (b) : "m" (bcd[0])); | |
549 | printf("a=%f bcd=%04x%04x%04x%04x%04x b=%f\n", | |
550 | a, bcd[4], bcd[3], bcd[2], bcd[1], bcd[0], b); | |
551 | } | |
552 | ||
9d8e9c09 FB |
553 | void test_floats(void) |
554 | { | |
555 | test_fops(2, 3); | |
556 | test_fops(1.4, -5); | |
557 | test_fcmp(2, -1); | |
558 | test_fcmp(2, 2); | |
559 | test_fcmp(2, 3); | |
560 | test_fcvt(1.0/7.0); | |
561 | test_fcvt(-1.0/9.0); | |
562 | test_fcvt(1e30); | |
563 | test_fconst(); | |
c5e9815d FB |
564 | test_fbcd(1234567890123456); |
565 | test_fbcd(-123451234567890); | |
9d8e9c09 | 566 | } |
4b74fe1f | 567 | |
55480af8 FB |
568 | /**********************************************/ |
569 | ||
570 | #define TEST_BCD(op, op0, cc_in, cc_mask)\ | |
571 | {\ | |
572 | int res, flags;\ | |
573 | res = op0;\ | |
574 | flags = cc_in;\ | |
575 | asm ("push %3\n\t"\ | |
576 | "popf\n\t"\ | |
577 | #op "\n\t"\ | |
578 | "pushf\n\t"\ | |
579 | "popl %1\n\t"\ | |
580 | : "=a" (res), "=g" (flags)\ | |
581 | : "0" (res), "1" (flags));\ | |
582 | printf("%-10s A=%08x R=%08x CCIN=%04x CC=%04x\n",\ | |
583 | #op, op0, res, cc_in, flags & cc_mask);\ | |
584 | } | |
585 | ||
586 | void test_bcd(void) | |
587 | { | |
588 | TEST_BCD(daa, 0x12340503, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); | |
589 | TEST_BCD(daa, 0x12340506, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); | |
590 | TEST_BCD(daa, 0x12340507, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); | |
591 | TEST_BCD(daa, 0x12340559, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); | |
592 | TEST_BCD(daa, 0x12340560, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); | |
593 | TEST_BCD(daa, 0x1234059f, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); | |
594 | TEST_BCD(daa, 0x123405a0, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); | |
595 | TEST_BCD(daa, 0x12340503, 0, (CC_C | CC_P | CC_Z | CC_S | CC_A)); | |
596 | TEST_BCD(daa, 0x12340506, 0, (CC_C | CC_P | CC_Z | CC_S | CC_A)); | |
597 | TEST_BCD(daa, 0x12340503, CC_C, (CC_C | CC_P | CC_Z | CC_S | CC_A)); | |
598 | TEST_BCD(daa, 0x12340506, CC_C, (CC_C | CC_P | CC_Z | CC_S | CC_A)); | |
599 | TEST_BCD(daa, 0x12340503, CC_C | CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); | |
600 | TEST_BCD(daa, 0x12340506, CC_C | CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); | |
601 | ||
602 | TEST_BCD(das, 0x12340503, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); | |
603 | TEST_BCD(das, 0x12340506, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); | |
604 | TEST_BCD(das, 0x12340507, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); | |
605 | TEST_BCD(das, 0x12340559, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); | |
606 | TEST_BCD(das, 0x12340560, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); | |
607 | TEST_BCD(das, 0x1234059f, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); | |
608 | TEST_BCD(das, 0x123405a0, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); | |
609 | TEST_BCD(das, 0x12340503, 0, (CC_C | CC_P | CC_Z | CC_S | CC_A)); | |
610 | TEST_BCD(das, 0x12340506, 0, (CC_C | CC_P | CC_Z | CC_S | CC_A)); | |
611 | TEST_BCD(das, 0x12340503, CC_C, (CC_C | CC_P | CC_Z | CC_S | CC_A)); | |
612 | TEST_BCD(das, 0x12340506, CC_C, (CC_C | CC_P | CC_Z | CC_S | CC_A)); | |
613 | TEST_BCD(das, 0x12340503, CC_C | CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); | |
614 | TEST_BCD(das, 0x12340506, CC_C | CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); | |
615 | ||
616 | TEST_BCD(aaa, 0x12340205, CC_A, (CC_C | CC_A)); | |
617 | TEST_BCD(aaa, 0x12340306, CC_A, (CC_C | CC_A)); | |
618 | TEST_BCD(aaa, 0x1234040a, CC_A, (CC_C | CC_A)); | |
619 | TEST_BCD(aaa, 0x123405fa, CC_A, (CC_C | CC_A)); | |
620 | TEST_BCD(aaa, 0x12340205, 0, (CC_C | CC_A)); | |
621 | TEST_BCD(aaa, 0x12340306, 0, (CC_C | CC_A)); | |
622 | TEST_BCD(aaa, 0x1234040a, 0, (CC_C | CC_A)); | |
623 | TEST_BCD(aaa, 0x123405fa, 0, (CC_C | CC_A)); | |
624 | ||
625 | TEST_BCD(aas, 0x12340205, CC_A, (CC_C | CC_A)); | |
626 | TEST_BCD(aas, 0x12340306, CC_A, (CC_C | CC_A)); | |
627 | TEST_BCD(aas, 0x1234040a, CC_A, (CC_C | CC_A)); | |
628 | TEST_BCD(aas, 0x123405fa, CC_A, (CC_C | CC_A)); | |
629 | TEST_BCD(aas, 0x12340205, 0, (CC_C | CC_A)); | |
630 | TEST_BCD(aas, 0x12340306, 0, (CC_C | CC_A)); | |
631 | TEST_BCD(aas, 0x1234040a, 0, (CC_C | CC_A)); | |
632 | TEST_BCD(aas, 0x123405fa, 0, (CC_C | CC_A)); | |
633 | ||
634 | TEST_BCD(aam, 0x12340547, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A)); | |
635 | TEST_BCD(aad, 0x12340407, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A)); | |
636 | } | |
637 | ||
e5918247 FB |
638 | #define TEST_XCHG(op, size, opconst)\ |
639 | {\ | |
640 | int op0, op1;\ | |
641 | op0 = 0x12345678;\ | |
642 | op1 = 0xfbca7654;\ | |
643 | asm(#op " %" size "0, %" size "1" \ | |
644 | : "=q" (op0), opconst (op1) \ | |
645 | : "0" (op0), "1" (op1));\ | |
646 | printf("%-10s A=%08x B=%08x\n",\ | |
647 | #op, op0, op1);\ | |
648 | } | |
649 | ||
650 | #define TEST_CMPXCHG(op, size, opconst, eax)\ | |
651 | {\ | |
652 | int op0, op1;\ | |
653 | op0 = 0x12345678;\ | |
654 | op1 = 0xfbca7654;\ | |
655 | asm(#op " %" size "0, %" size "1" \ | |
656 | : "=q" (op0), opconst (op1) \ | |
657 | : "0" (op0), "1" (op1), "a" (eax));\ | |
658 | printf("%-10s EAX=%08x A=%08x C=%08x\n",\ | |
659 | #op, eax, op0, op1);\ | |
660 | } | |
661 | ||
662 | void test_xchg(void) | |
663 | { | |
664 | TEST_XCHG(xchgl, "", "=q"); | |
665 | TEST_XCHG(xchgw, "w", "=q"); | |
666 | TEST_XCHG(xchgb, "b", "=q"); | |
667 | ||
668 | TEST_XCHG(xchgl, "", "=m"); | |
669 | TEST_XCHG(xchgw, "w", "=m"); | |
670 | TEST_XCHG(xchgb, "b", "=m"); | |
671 | ||
672 | TEST_XCHG(xaddl, "", "=q"); | |
673 | TEST_XCHG(xaddw, "w", "=q"); | |
674 | TEST_XCHG(xaddb, "b", "=q"); | |
675 | ||
676 | TEST_XCHG(xaddl, "", "=m"); | |
677 | TEST_XCHG(xaddw, "w", "=m"); | |
678 | TEST_XCHG(xaddb, "b", "=m"); | |
679 | ||
680 | TEST_CMPXCHG(cmpxchgl, "", "=q", 0xfbca7654); | |
681 | TEST_CMPXCHG(cmpxchgw, "w", "=q", 0xfbca7654); | |
682 | TEST_CMPXCHG(cmpxchgb, "b", "=q", 0xfbca7654); | |
683 | ||
684 | TEST_CMPXCHG(cmpxchgl, "", "=q", 0xfffefdfc); | |
685 | TEST_CMPXCHG(cmpxchgw, "w", "=q", 0xfffefdfc); | |
686 | TEST_CMPXCHG(cmpxchgb, "b", "=q", 0xfffefdfc); | |
687 | ||
688 | TEST_CMPXCHG(cmpxchgl, "", "=m", 0xfbca7654); | |
689 | TEST_CMPXCHG(cmpxchgw, "w", "=m", 0xfbca7654); | |
690 | TEST_CMPXCHG(cmpxchgb, "b", "=m", 0xfbca7654); | |
691 | ||
692 | TEST_CMPXCHG(cmpxchgl, "", "=m", 0xfffefdfc); | |
693 | TEST_CMPXCHG(cmpxchgw, "w", "=m", 0xfffefdfc); | |
694 | TEST_CMPXCHG(cmpxchgb, "b", "=m", 0xfffefdfc); | |
695 | } | |
696 | ||
6dbad63e FB |
697 | /**********************************************/ |
698 | /* segmentation tests */ | |
699 | ||
700 | #include <asm/ldt.h> | |
701 | #include <linux/unistd.h> | |
702 | ||
703 | _syscall3(int, modify_ldt, int, func, void *, ptr, unsigned long, bytecount) | |
704 | ||
705 | uint8_t seg_data1[4096]; | |
706 | uint8_t seg_data2[4096]; | |
707 | ||
e5918247 | 708 | #define MK_SEL(n) (((n) << 3) | 7) |
6dbad63e FB |
709 | |
710 | /* NOTE: we use Linux modify_ldt syscall */ | |
711 | void test_segs(void) | |
712 | { | |
713 | struct modify_ldt_ldt_s ldt; | |
714 | long long ldt_table[3]; | |
04369ff2 | 715 | int res, res2; |
6dbad63e | 716 | char tmp; |
e1d4294a FB |
717 | struct { |
718 | uint32_t offset; | |
719 | uint16_t seg; | |
720 | } __attribute__((packed)) segoff; | |
6dbad63e FB |
721 | |
722 | ldt.entry_number = 1; | |
723 | ldt.base_addr = (unsigned long)&seg_data1; | |
724 | ldt.limit = (sizeof(seg_data1) + 0xfff) >> 12; | |
725 | ldt.seg_32bit = 1; | |
726 | ldt.contents = MODIFY_LDT_CONTENTS_DATA; | |
727 | ldt.read_exec_only = 0; | |
728 | ldt.limit_in_pages = 1; | |
729 | ldt.seg_not_present = 0; | |
730 | ldt.useable = 1; | |
731 | modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */ | |
732 | ||
733 | ldt.entry_number = 2; | |
734 | ldt.base_addr = (unsigned long)&seg_data2; | |
735 | ldt.limit = (sizeof(seg_data2) + 0xfff) >> 12; | |
736 | ldt.seg_32bit = 1; | |
737 | ldt.contents = MODIFY_LDT_CONTENTS_DATA; | |
738 | ldt.read_exec_only = 0; | |
739 | ldt.limit_in_pages = 1; | |
740 | ldt.seg_not_present = 0; | |
741 | ldt.useable = 1; | |
742 | modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */ | |
743 | ||
744 | modify_ldt(0, &ldt_table, sizeof(ldt_table)); /* read ldt entries */ | |
04369ff2 FB |
745 | #if 0 |
746 | { | |
747 | int i; | |
748 | for(i=0;i<3;i++) | |
749 | printf("%d: %016Lx\n", i, ldt_table[i]); | |
750 | } | |
751 | #endif | |
6dbad63e FB |
752 | /* do some tests with fs or gs */ |
753 | asm volatile ("movl %0, %%fs" : : "r" (MK_SEL(1))); | |
754 | asm volatile ("movl %0, %%gs" : : "r" (MK_SEL(2))); | |
755 | ||
756 | seg_data1[1] = 0xaa; | |
757 | seg_data2[1] = 0x55; | |
758 | ||
759 | asm volatile ("fs movzbl 0x1, %0" : "=r" (res)); | |
760 | printf("FS[1] = %02x\n", res); | |
761 | ||
762 | asm volatile ("gs movzbl 0x1, %0" : "=r" (res)); | |
763 | printf("GS[1] = %02x\n", res); | |
764 | ||
765 | /* tests with ds/ss (implicit segment case) */ | |
766 | tmp = 0xa5; | |
767 | asm volatile ("pushl %%ebp\n\t" | |
768 | "pushl %%ds\n\t" | |
769 | "movl %2, %%ds\n\t" | |
770 | "movl %3, %%ebp\n\t" | |
771 | "movzbl 0x1, %0\n\t" | |
772 | "movzbl (%%ebp), %1\n\t" | |
773 | "popl %%ds\n\t" | |
774 | "popl %%ebp\n\t" | |
775 | : "=r" (res), "=r" (res2) | |
776 | : "r" (MK_SEL(1)), "r" (&tmp)); | |
777 | printf("DS[1] = %02x\n", res); | |
778 | printf("SS[tmp] = %02x\n", res2); | |
e1d4294a FB |
779 | |
780 | segoff.seg = MK_SEL(2); | |
781 | segoff.offset = 0xabcdef12; | |
782 | asm volatile("lfs %2, %0\n\t" | |
783 | "movl %%fs, %1\n\t" | |
784 | : "=r" (res), "=g" (res2) | |
785 | : "m" (segoff)); | |
786 | printf("FS:reg = %04x:%08x\n", res2, res); | |
6dbad63e | 787 | } |
55480af8 | 788 | |
e5918247 FB |
789 | /* 16 bit code test */ |
790 | extern char code16_start, code16_end; | |
791 | extern char code16_func1; | |
792 | extern char code16_func2; | |
793 | extern char code16_func3; | |
a300e691 | 794 | |
e5918247 | 795 | void test_code16(void) |
1a9353d2 | 796 | { |
e5918247 FB |
797 | struct modify_ldt_ldt_s ldt; |
798 | int res, res2; | |
a300e691 | 799 | |
e5918247 FB |
800 | /* build a code segment */ |
801 | ldt.entry_number = 1; | |
802 | ldt.base_addr = (unsigned long)&code16_start; | |
803 | ldt.limit = &code16_end - &code16_start; | |
804 | ldt.seg_32bit = 0; | |
805 | ldt.contents = MODIFY_LDT_CONTENTS_CODE; | |
806 | ldt.read_exec_only = 0; | |
807 | ldt.limit_in_pages = 0; | |
808 | ldt.seg_not_present = 0; | |
809 | ldt.useable = 1; | |
810 | modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */ | |
a300e691 | 811 | |
e5918247 FB |
812 | /* call the first function */ |
813 | asm volatile ("lcall %1, %2" | |
814 | : "=a" (res) | |
815 | : "i" (MK_SEL(1)), "i" (&code16_func1): "memory", "cc"); | |
816 | printf("func1() = 0x%08x\n", res); | |
817 | asm volatile ("lcall %2, %3" | |
818 | : "=a" (res), "=c" (res2) | |
819 | : "i" (MK_SEL(1)), "i" (&code16_func2): "memory", "cc"); | |
820 | printf("func2() = 0x%08x spdec=%d\n", res, res2); | |
821 | asm volatile ("lcall %1, %2" | |
822 | : "=a" (res) | |
823 | : "i" (MK_SEL(1)), "i" (&code16_func3): "memory", "cc"); | |
824 | printf("func3() = 0x%08x\n", res); | |
1a9353d2 FB |
825 | } |
826 | ||
e1d4294a FB |
827 | void test_misc(void) |
828 | { | |
829 | char table[256]; | |
830 | int res, i; | |
831 | ||
832 | for(i=0;i<256;i++) table[i] = 256 - i; | |
833 | res = 0x12345678; | |
834 | asm ("xlat" : "=a" (res) : "b" (table), "0" (res)); | |
835 | printf("xlat: EAX=%08x\n", res); | |
836 | } | |
837 | ||
838 | uint8_t str_buffer[4096]; | |
839 | ||
840 | #define TEST_STRING1(OP, size, DF, REP)\ | |
841 | {\ | |
842 | int esi, edi, eax, ecx, eflags;\ | |
843 | \ | |
844 | esi = (long)(str_buffer + sizeof(str_buffer) / 2);\ | |
845 | edi = (long)(str_buffer + sizeof(str_buffer) / 2) + 16;\ | |
846 | eax = 0x12345678;\ | |
847 | ecx = 17;\ | |
848 | \ | |
849 | asm volatile ("pushl $0\n\t"\ | |
850 | "popf\n\t"\ | |
851 | DF "\n\t"\ | |
852 | REP #OP size "\n\t"\ | |
853 | "cld\n\t"\ | |
854 | "pushf\n\t"\ | |
855 | "popl %4\n\t"\ | |
856 | : "=S" (esi), "=D" (edi), "=a" (eax), "=c" (ecx), "=g" (eflags)\ | |
857 | : "0" (esi), "1" (edi), "2" (eax), "3" (ecx));\ | |
858 | printf("%-10s ESI=%08x EDI=%08x EAX=%08x ECX=%08x EFL=%04x\n",\ | |
859 | REP #OP size, esi, edi, eax, ecx,\ | |
860 | eflags & (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A));\ | |
861 | } | |
862 | ||
863 | #define TEST_STRING(OP, REP)\ | |
864 | TEST_STRING1(OP, "b", "", REP);\ | |
865 | TEST_STRING1(OP, "w", "", REP);\ | |
866 | TEST_STRING1(OP, "l", "", REP);\ | |
867 | TEST_STRING1(OP, "b", "std", REP);\ | |
868 | TEST_STRING1(OP, "w", "std", REP);\ | |
869 | TEST_STRING1(OP, "l", "std", REP) | |
870 | ||
871 | void test_string(void) | |
872 | { | |
873 | int i; | |
874 | for(i = 0;i < sizeof(str_buffer); i++) | |
875 | str_buffer[i] = i + 0x56; | |
876 | TEST_STRING(stos, ""); | |
877 | TEST_STRING(stos, "rep "); | |
878 | TEST_STRING(lods, ""); /* to verify stos */ | |
879 | TEST_STRING(lods, "rep "); | |
880 | TEST_STRING(movs, ""); | |
881 | TEST_STRING(movs, "rep "); | |
882 | TEST_STRING(lods, ""); /* to verify stos */ | |
883 | ||
884 | /* XXX: better tests */ | |
885 | TEST_STRING(scas, ""); | |
886 | TEST_STRING(scas, "repz "); | |
887 | TEST_STRING(scas, "repnz "); | |
888 | TEST_STRING(cmps, ""); | |
889 | TEST_STRING(cmps, "repz "); | |
890 | TEST_STRING(cmps, "repnz "); | |
891 | } | |
e5918247 | 892 | |
4d1135e4 FB |
893 | static void *call_end __init_call = NULL; |
894 | ||
895 | int main(int argc, char **argv) | |
896 | { | |
897 | void **ptr; | |
898 | void (*func)(void); | |
4b74fe1f | 899 | |
4d1135e4 FB |
900 | ptr = &call_start + 1; |
901 | while (*ptr != NULL) { | |
902 | func = *ptr++; | |
903 | func(); | |
904 | } | |
9d8e9c09 | 905 | test_bsx(); |
d57c4e01 | 906 | test_mul(); |
4d1135e4 | 907 | test_jcc(); |
9d8e9c09 | 908 | test_floats(); |
55480af8 | 909 | test_bcd(); |
1a9353d2 | 910 | test_xchg(); |
e1d4294a FB |
911 | test_string(); |
912 | test_misc(); | |
6dbad63e FB |
913 | test_lea(); |
914 | test_segs(); | |
e5918247 | 915 | test_code16(); |
4d1135e4 FB |
916 | return 0; |
917 | } |