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
33void 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
60void 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
84void 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
124void 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
136void 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
164void 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
217void 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
243void 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
259int main ( void )
260{
261  test_floats();
262  return 0;
263}
264