1 
2 /* Derived from: */
3 
4 /*
5  *  x86 CPU test
6  *
7  *  Copyright (c) 2003 Fabrice Bellard
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 2 of the License, or
12  *  (at your option) any later version.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, write to the Free Software
21  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  */
23 
24 
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <inttypes.h>
29 #include <math.h>
30 
31 /**********************************************/
32 
test_fops(double a,double b)33 void test_fops(double a, double b)
34 {
35     printf("a=%f b=%f a+b=%f\n", a, b, a + b);
36     printf("a=%f b=%f a-b=%f\n", a, b, a - b);
37     printf("a=%f b=%f a*b=%f\n", a, b, a * b);
38     printf("a=%f b=%f a/b=%f\n", a, b, a / b);
39     printf("a=%f b=%f fmod(a, b)=%f\n", a, b, fmod(a, b));
40     printf("a=%f sqrt(a)=%f\n", a, sqrt(a));
41     printf("a=%f sin(a)=%f\n", a, sin(a));
42     printf("a=%f cos(a)=%f\n", a, cos(a));
43     printf("a=%f tan(a)=%f\n", a, tan(a));
44     printf("a=%f log(a)=%f\n", a, log(a));
45     printf("a=%f exp(a)=%f\n", a, exp(a));
46     printf("a=%f b=%f atan2(a, b)=%f\n", a, b, atan2(a, b));
47     /* just to test some op combining */
48     printf("a=%f asin(sin(a))=%f\n", a, asin(sin(a)));
49     printf("a=%f acos(cos(a))=%f\n", a, acos(cos(a)));
50     printf("a=%f atan(tan(a))=%f\n", a, atan(tan(a)));
51 }
52 #define CC_C    0x0001
53 #define CC_P    0x0004
54 #define CC_A    0x0010
55 #define CC_Z    0x0040
56 #define CC_S    0x0080
57 #define CC_O    0x0800
58 
59 
test_fcmp(double a,double b)60 void test_fcmp(double a, double b)
61 {
62     printf("(%f<%f)=%d\n",
63            a, b, a < b);
64     printf("(%f<=%f)=%d\n",
65            a, b, a <= b);
66     printf("(%f==%f)=%d\n",
67            a, b, a == b);
68     printf("(%f>%f)=%d\n",
69            a, b, a > b);
70     printf("(%f<=%f)=%d\n",
71            a, b, a >= b);
72     {
73         unsigned int eflags;
74         /* test f(u)comi instruction */
75         asm("fcomi %2, %1\n"
76             "pushf\n"
77             "pop %0\n"
78             : "=r" (eflags)
79             : "t" (a), "u" (b));
80         printf("fcomi(%f %f)=%08x\n", a, b, eflags & (CC_Z | CC_P | CC_C));
81     }
82 }
83 
test_fcvt(double a)84 void test_fcvt(double a)
85 {
86     float fa;
87     long double la;
88     int16_t fpuc;
89     int i;
90     int64_t lla;
91     int ia;
92     int16_t wa;
93     double ra;
94 
95     fa = a;
96     la = a;
97     printf("(float)%f = %f\n", a, fa);
98     printf("(long double)%f = %Lf\n", a, la);
99     printf("a=%016llx\n", *(long long *)&a);
100     printf("la=%016llx %04x\n", *(long long *)&la,
101            *(unsigned short *)((char *)(&la) + 8));
102 
103     /* test all roundings */
104     asm volatile ("fstcw %0" : "=m" (fpuc));
105     for(i=0;i<4;i++) {
106       int16_t tmp = (fpuc & ~0x0c00) | (i << 10);
107         asm volatile ("fldcw %0" : : "m" (tmp));
108         asm volatile ("fists %0" : "=m" (wa) : "t" (a));
109         asm volatile ("fistl %0" : "=m" (ia) : "t" (a));
110         asm volatile ("fistpll %0" : "=m" (lla) : "t" (a) : "st");
111         asm volatile ("frndint ; fstl %0" : "=m" (ra) : "t" (a));
112         asm volatile ("fldcw %0" : : "m" (fpuc));
113         printf("(short)a = %d\n", wa);
114         printf("(int)a = %d\n", ia);
115         printf("(int64_t)a = %lld\n", lla);
116         printf("rint(a) = %f\n", ra);
117     }
118 }
119 
120 #define TEST(N) \
121     asm("fld" #N : "=t" (a)); \
122     printf("fld" #N "= %f\n", a);
123 
test_fconst(void)124 void test_fconst(void)
125 {
126     double a;
127     TEST(1);
128     TEST(l2t);
129     TEST(l2e);
130     TEST(pi);
131     TEST(lg2);
132     TEST(ln2);
133     TEST(z);
134 }
135 
test_fbcd(double a)136 void test_fbcd(double a)
137 {
138     unsigned short bcd[5];
139     double b;
140 
141     asm("fbstp %0" : "=m" (bcd[0]) : "t" (a) : "st");
142     asm("fbld %1" : "=t" (b) : "m" (bcd[0]));
143     printf("a=%f bcd=%04x%04x%04x%04x%04x b=%f\n",
144            a, bcd[4], bcd[3], bcd[2], bcd[1], bcd[0], b);
145 }
146 
147 #define TEST_ENV(env, save, restore)\
148 {\
149     memset((env), 0xaa, sizeof(*(env)));\
150     for(i=0;i<5;i++)\
151         asm volatile ("fldl %0" : : "m" (dtab[i]));\
152     asm(save " %0\n" : : "m" (*(env)));\
153     asm(restore " %0\n": : "m" (*(env)));\
154     for(i=0;i<5;i++)\
155         asm volatile ("fstpl %0" : "=m" (rtab[i]));\
156     for(i=0;i<5;i++)\
157         printf("res[%d]=%f\n", i, rtab[i]);\
158     printf("fpuc=%04x fpus=%04x fptag=%04x\n",\
159            (env)->fpuc,\
160            (env)->fpus & 0xff00,\
161            (env)->fptag);\
162 }
163 
test_fenv(void)164 void test_fenv(void)
165 {
166     struct __attribute__((packed)) {
167         uint16_t fpuc;
168         uint16_t dummy1;
169         uint16_t fpus;
170         uint16_t dummy2;
171         uint16_t fptag;
172         uint16_t dummy3;
173         uint32_t ignored[4];
174         long double fpregs[8];
175     } float_env32;
176     struct __attribute__((packed)) {
177         uint16_t fpuc;
178         uint16_t fpus;
179         uint16_t fptag;
180         uint16_t ignored[4];
181         long double fpregs[8];
182     } float_env16;
183     double dtab[8];
184     double rtab[8];
185     int i;
186 
187     for(i=0;i<8;i++)
188         dtab[i] = i + 1;
189 
190     TEST_ENV(&float_env16, "data16/fnstenv", "data16/fldenv");
191     TEST_ENV(&float_env16, "data16/fnsave", "data16/frstor");
192     TEST_ENV(&float_env32, "fnstenv", "fldenv");
193     TEST_ENV(&float_env32, "fnsave", "frstor");
194 
195     /* test for ffree */
196     for(i=0;i<5;i++)
197         asm volatile ("fldl %0" : : "m" (dtab[i]));
198     asm volatile("ffree %st(2)");
199     asm volatile ("fnstenv %0\n" : : "m" (float_env32));
200     asm volatile ("fninit");
201     printf("fptag=%04x\n", float_env32.fptag);
202 }
203 
204 
205 #define TEST_FCMOV(a, b, eflags, CC)\
206 {\
207     double res;\
208     asm("push %3\n"\
209         "popf\n"\
210         "fcmov" CC " %2, %0\n"\
211         : "=t" (res)\
212         : "0" (a), "u" (b), "g" (eflags));\
213     printf("fcmov%s eflags=0x%04x-> %f\n", \
214            CC, eflags, res);\
215 }
216 
test_fcmov(void)217 void test_fcmov(void)
218 {
219     double a, b;
220     int eflags, i;
221 
222     a = 1.0;
223     b = 2.0;
224     for(i = 0; i < 4; i++) {
225         eflags = 0;
226         if (i & 1)
227             eflags |= CC_C;
228         if (i & 2)
229             eflags |= CC_Z;
230         TEST_FCMOV(a, b, eflags, "b");
231         TEST_FCMOV(a, b, eflags, "e");
232         TEST_FCMOV(a, b, eflags, "be");
233         TEST_FCMOV(a, b, eflags, "nb");
234         TEST_FCMOV(a, b, eflags, "ne");
235         TEST_FCMOV(a, b, eflags, "nbe");
236     }
237     TEST_FCMOV(a, b, 0, "u");
238     TEST_FCMOV(a, b, CC_P, "u");
239     TEST_FCMOV(a, b, 0, "nu");
240     TEST_FCMOV(a, b, CC_P, "nu");
241 }
242 
test_floats(void)243 void test_floats(void)
244 {
245     test_fops(2, 3);
246     test_fops(1.4, -5);
247     test_fcmp(2, -1);
248     test_fcmp(2, 2);
249     test_fcmp(2, 3);
250     test_fcvt(0.5);
251     test_fcvt(-0.5);
252     test_fcvt(1.0/7.0);
253     test_fcvt(-1.0/9.0);
254     test_fcvt(32768);
255     test_fcvt(-1e20);
256     test_fconst();
257 }
258 
main(void)259 int main ( void )
260 {
261   test_floats();
262   return 0;
263 }
264