]> Git Repo - qemu.git/blame - target-i386/fpu_helper.c
Merge remote-tracking branch 'remotes/kraxel/tags/pull-ui-20160108-1' into staging
[qemu.git] / target-i386 / fpu_helper.c
CommitLineData
f299f437
BS
1/*
2 * x86 FPU, MMX/3DNow!/SSE/SSE2/SSE3/SSSE3/SSE4/PNI helpers
3 *
4 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <math.h>
21#include "cpu.h"
2ef6175a 22#include "exec/helper-proto.h"
c334a388 23#include "qemu/host-utils.h"
f08b6170 24#include "exec/cpu_ldst.h"
92fc4b58 25
f299f437
BS
26#define FPU_RC_MASK 0xc00
27#define FPU_RC_NEAR 0x000
28#define FPU_RC_DOWN 0x400
29#define FPU_RC_UP 0x800
30#define FPU_RC_CHOP 0xc00
31
32#define MAXTAN 9223372036854775808.0
33
34/* the following deal with x86 long double-precision numbers */
35#define MAXEXPD 0x7fff
36#define EXPBIAS 16383
37#define EXPD(fp) (fp.l.upper & 0x7fff)
38#define SIGND(fp) ((fp.l.upper) & 0x8000)
39#define MANTD(fp) (fp.l.lower)
40#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7fff)) | EXPBIAS
41
42#define FPUS_IE (1 << 0)
43#define FPUS_DE (1 << 1)
44#define FPUS_ZE (1 << 2)
45#define FPUS_OE (1 << 3)
46#define FPUS_UE (1 << 4)
47#define FPUS_PE (1 << 5)
48#define FPUS_SF (1 << 6)
49#define FPUS_SE (1 << 7)
50#define FPUS_B (1 << 15)
51
52#define FPUC_EM 0x3f
53
54#define floatx80_lg2 make_floatx80(0x3ffd, 0x9a209a84fbcff799LL)
55#define floatx80_l2e make_floatx80(0x3fff, 0xb8aa3b295c17f0bcLL)
56#define floatx80_l2t make_floatx80(0x4000, 0xd49a784bcd1b8afeLL)
57
d3eb5eae 58static inline void fpush(CPUX86State *env)
f299f437
BS
59{
60 env->fpstt = (env->fpstt - 1) & 7;
61 env->fptags[env->fpstt] = 0; /* validate stack entry */
62}
63
d3eb5eae 64static inline void fpop(CPUX86State *env)
f299f437
BS
65{
66 env->fptags[env->fpstt] = 1; /* invalidate stack entry */
67 env->fpstt = (env->fpstt + 1) & 7;
68}
69
6cad09d2
PD
70static inline floatx80 helper_fldt(CPUX86State *env, target_ulong ptr,
71 uintptr_t retaddr)
f299f437
BS
72{
73 CPU_LDoubleU temp;
74
6cad09d2
PD
75 temp.l.lower = cpu_ldq_data_ra(env, ptr, retaddr);
76 temp.l.upper = cpu_lduw_data_ra(env, ptr + 8, retaddr);
f299f437
BS
77 return temp.d;
78}
79
6cad09d2
PD
80static inline void helper_fstt(CPUX86State *env, floatx80 f, target_ulong ptr,
81 uintptr_t retaddr)
f299f437
BS
82{
83 CPU_LDoubleU temp;
84
85 temp.d = f;
6cad09d2
PD
86 cpu_stq_data_ra(env, ptr, temp.l.lower, retaddr);
87 cpu_stw_data_ra(env, ptr + 8, temp.l.upper, retaddr);
f299f437
BS
88}
89
90/* x87 FPU helpers */
91
d3eb5eae 92static inline double floatx80_to_double(CPUX86State *env, floatx80 a)
f299f437
BS
93{
94 union {
95 float64 f64;
96 double d;
97 } u;
98
99 u.f64 = floatx80_to_float64(a, &env->fp_status);
100 return u.d;
101}
102
d3eb5eae 103static inline floatx80 double_to_floatx80(CPUX86State *env, double a)
f299f437
BS
104{
105 union {
106 float64 f64;
107 double d;
108 } u;
109
110 u.d = a;
111 return float64_to_floatx80(u.f64, &env->fp_status);
112}
113
d3eb5eae 114static void fpu_set_exception(CPUX86State *env, int mask)
f299f437
BS
115{
116 env->fpus |= mask;
117 if (env->fpus & (~env->fpuc & FPUC_EM)) {
118 env->fpus |= FPUS_SE | FPUS_B;
119 }
120}
121
d3eb5eae 122static inline floatx80 helper_fdiv(CPUX86State *env, floatx80 a, floatx80 b)
f299f437
BS
123{
124 if (floatx80_is_zero(b)) {
d3eb5eae 125 fpu_set_exception(env, FPUS_ZE);
f299f437
BS
126 }
127 return floatx80_div(a, b, &env->fp_status);
128}
129
6cad09d2 130static void fpu_raise_exception(CPUX86State *env, uintptr_t retaddr)
f299f437
BS
131{
132 if (env->cr[0] & CR0_NE_MASK) {
6cad09d2 133 raise_exception_ra(env, EXCP10_COPR, retaddr);
f299f437
BS
134 }
135#if !defined(CONFIG_USER_ONLY)
136 else {
137 cpu_set_ferr(env);
138 }
139#endif
140}
141
d3eb5eae 142void helper_flds_FT0(CPUX86State *env, uint32_t val)
f299f437
BS
143{
144 union {
145 float32 f;
146 uint32_t i;
147 } u;
148
149 u.i = val;
150 FT0 = float32_to_floatx80(u.f, &env->fp_status);
151}
152
d3eb5eae 153void helper_fldl_FT0(CPUX86State *env, uint64_t val)
f299f437
BS
154{
155 union {
156 float64 f;
157 uint64_t i;
158 } u;
159
160 u.i = val;
161 FT0 = float64_to_floatx80(u.f, &env->fp_status);
162}
163
d3eb5eae 164void helper_fildl_FT0(CPUX86State *env, int32_t val)
f299f437
BS
165{
166 FT0 = int32_to_floatx80(val, &env->fp_status);
167}
168
d3eb5eae 169void helper_flds_ST0(CPUX86State *env, uint32_t val)
f299f437
BS
170{
171 int new_fpstt;
172 union {
173 float32 f;
174 uint32_t i;
175 } u;
176
177 new_fpstt = (env->fpstt - 1) & 7;
178 u.i = val;
179 env->fpregs[new_fpstt].d = float32_to_floatx80(u.f, &env->fp_status);
180 env->fpstt = new_fpstt;
181 env->fptags[new_fpstt] = 0; /* validate stack entry */
182}
183
d3eb5eae 184void helper_fldl_ST0(CPUX86State *env, uint64_t val)
f299f437
BS
185{
186 int new_fpstt;
187 union {
188 float64 f;
189 uint64_t i;
190 } u;
191
192 new_fpstt = (env->fpstt - 1) & 7;
193 u.i = val;
194 env->fpregs[new_fpstt].d = float64_to_floatx80(u.f, &env->fp_status);
195 env->fpstt = new_fpstt;
196 env->fptags[new_fpstt] = 0; /* validate stack entry */
197}
198
d3eb5eae 199void helper_fildl_ST0(CPUX86State *env, int32_t val)
f299f437
BS
200{
201 int new_fpstt;
202
203 new_fpstt = (env->fpstt - 1) & 7;
204 env->fpregs[new_fpstt].d = int32_to_floatx80(val, &env->fp_status);
205 env->fpstt = new_fpstt;
206 env->fptags[new_fpstt] = 0; /* validate stack entry */
207}
208
d3eb5eae 209void helper_fildll_ST0(CPUX86State *env, int64_t val)
f299f437
BS
210{
211 int new_fpstt;
212
213 new_fpstt = (env->fpstt - 1) & 7;
214 env->fpregs[new_fpstt].d = int64_to_floatx80(val, &env->fp_status);
215 env->fpstt = new_fpstt;
216 env->fptags[new_fpstt] = 0; /* validate stack entry */
217}
218
d3eb5eae 219uint32_t helper_fsts_ST0(CPUX86State *env)
f299f437
BS
220{
221 union {
222 float32 f;
223 uint32_t i;
224 } u;
225
226 u.f = floatx80_to_float32(ST0, &env->fp_status);
227 return u.i;
228}
229
d3eb5eae 230uint64_t helper_fstl_ST0(CPUX86State *env)
f299f437
BS
231{
232 union {
233 float64 f;
234 uint64_t i;
235 } u;
236
237 u.f = floatx80_to_float64(ST0, &env->fp_status);
238 return u.i;
239}
240
d3eb5eae 241int32_t helper_fist_ST0(CPUX86State *env)
f299f437
BS
242{
243 int32_t val;
244
245 val = floatx80_to_int32(ST0, &env->fp_status);
246 if (val != (int16_t)val) {
247 val = -32768;
248 }
249 return val;
250}
251
d3eb5eae 252int32_t helper_fistl_ST0(CPUX86State *env)
f299f437
BS
253{
254 int32_t val;
ea32aaf1
DP
255 signed char old_exp_flags;
256
257 old_exp_flags = get_float_exception_flags(&env->fp_status);
258 set_float_exception_flags(0, &env->fp_status);
f299f437
BS
259
260 val = floatx80_to_int32(ST0, &env->fp_status);
ea32aaf1
DP
261 if (get_float_exception_flags(&env->fp_status) & float_flag_invalid) {
262 val = 0x80000000;
263 }
264 set_float_exception_flags(get_float_exception_flags(&env->fp_status)
265 | old_exp_flags, &env->fp_status);
f299f437
BS
266 return val;
267}
268
d3eb5eae 269int64_t helper_fistll_ST0(CPUX86State *env)
f299f437
BS
270{
271 int64_t val;
ea32aaf1
DP
272 signed char old_exp_flags;
273
274 old_exp_flags = get_float_exception_flags(&env->fp_status);
275 set_float_exception_flags(0, &env->fp_status);
f299f437 276
178846bd 277 val = floatx80_to_int64(ST0, &env->fp_status);
ea32aaf1
DP
278 if (get_float_exception_flags(&env->fp_status) & float_flag_invalid) {
279 val = 0x8000000000000000ULL;
280 }
281 set_float_exception_flags(get_float_exception_flags(&env->fp_status)
282 | old_exp_flags, &env->fp_status);
f299f437
BS
283 return val;
284}
285
d3eb5eae 286int32_t helper_fistt_ST0(CPUX86State *env)
f299f437
BS
287{
288 int32_t val;
289
290 val = floatx80_to_int32_round_to_zero(ST0, &env->fp_status);
291 if (val != (int16_t)val) {
292 val = -32768;
293 }
294 return val;
295}
296
d3eb5eae 297int32_t helper_fisttl_ST0(CPUX86State *env)
f299f437
BS
298{
299 int32_t val;
300
301 val = floatx80_to_int32_round_to_zero(ST0, &env->fp_status);
302 return val;
303}
304
d3eb5eae 305int64_t helper_fisttll_ST0(CPUX86State *env)
f299f437
BS
306{
307 int64_t val;
308
309 val = floatx80_to_int64_round_to_zero(ST0, &env->fp_status);
310 return val;
311}
312
d3eb5eae 313void helper_fldt_ST0(CPUX86State *env, target_ulong ptr)
f299f437
BS
314{
315 int new_fpstt;
316
317 new_fpstt = (env->fpstt - 1) & 7;
6cad09d2 318 env->fpregs[new_fpstt].d = helper_fldt(env, ptr, GETPC());
f299f437
BS
319 env->fpstt = new_fpstt;
320 env->fptags[new_fpstt] = 0; /* validate stack entry */
321}
322
d3eb5eae 323void helper_fstt_ST0(CPUX86State *env, target_ulong ptr)
f299f437 324{
6cad09d2 325 helper_fstt(env, ST0, ptr, GETPC());
f299f437
BS
326}
327
d3eb5eae 328void helper_fpush(CPUX86State *env)
f299f437 329{
d3eb5eae 330 fpush(env);
f299f437
BS
331}
332
d3eb5eae 333void helper_fpop(CPUX86State *env)
f299f437 334{
d3eb5eae 335 fpop(env);
f299f437
BS
336}
337
d3eb5eae 338void helper_fdecstp(CPUX86State *env)
f299f437
BS
339{
340 env->fpstt = (env->fpstt - 1) & 7;
341 env->fpus &= ~0x4700;
342}
343
d3eb5eae 344void helper_fincstp(CPUX86State *env)
f299f437
BS
345{
346 env->fpstt = (env->fpstt + 1) & 7;
347 env->fpus &= ~0x4700;
348}
349
350/* FPU move */
351
d3eb5eae 352void helper_ffree_STN(CPUX86State *env, int st_index)
f299f437
BS
353{
354 env->fptags[(env->fpstt + st_index) & 7] = 1;
355}
356
d3eb5eae 357void helper_fmov_ST0_FT0(CPUX86State *env)
f299f437
BS
358{
359 ST0 = FT0;
360}
361
d3eb5eae 362void helper_fmov_FT0_STN(CPUX86State *env, int st_index)
f299f437
BS
363{
364 FT0 = ST(st_index);
365}
366
d3eb5eae 367void helper_fmov_ST0_STN(CPUX86State *env, int st_index)
f299f437
BS
368{
369 ST0 = ST(st_index);
370}
371
d3eb5eae 372void helper_fmov_STN_ST0(CPUX86State *env, int st_index)
f299f437
BS
373{
374 ST(st_index) = ST0;
375}
376
d3eb5eae 377void helper_fxchg_ST0_STN(CPUX86State *env, int st_index)
f299f437
BS
378{
379 floatx80 tmp;
380
381 tmp = ST(st_index);
382 ST(st_index) = ST0;
383 ST0 = tmp;
384}
385
386/* FPU operations */
387
388static const int fcom_ccval[4] = {0x0100, 0x4000, 0x0000, 0x4500};
389
d3eb5eae 390void helper_fcom_ST0_FT0(CPUX86State *env)
f299f437
BS
391{
392 int ret;
393
394 ret = floatx80_compare(ST0, FT0, &env->fp_status);
395 env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret + 1];
396}
397
d3eb5eae 398void helper_fucom_ST0_FT0(CPUX86State *env)
f299f437
BS
399{
400 int ret;
401
402 ret = floatx80_compare_quiet(ST0, FT0, &env->fp_status);
403 env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret + 1];
404}
405
406static const int fcomi_ccval[4] = {CC_C, CC_Z, 0, CC_Z | CC_P | CC_C};
407
d3eb5eae 408void helper_fcomi_ST0_FT0(CPUX86State *env)
f299f437
BS
409{
410 int eflags;
411 int ret;
412
413 ret = floatx80_compare(ST0, FT0, &env->fp_status);
d3eb5eae 414 eflags = cpu_cc_compute_all(env, CC_OP);
f299f437
BS
415 eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1];
416 CC_SRC = eflags;
417}
418
d3eb5eae 419void helper_fucomi_ST0_FT0(CPUX86State *env)
f299f437
BS
420{
421 int eflags;
422 int ret;
423
424 ret = floatx80_compare_quiet(ST0, FT0, &env->fp_status);
d3eb5eae 425 eflags = cpu_cc_compute_all(env, CC_OP);
f299f437
BS
426 eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1];
427 CC_SRC = eflags;
428}
429
d3eb5eae 430void helper_fadd_ST0_FT0(CPUX86State *env)
f299f437
BS
431{
432 ST0 = floatx80_add(ST0, FT0, &env->fp_status);
433}
434
d3eb5eae 435void helper_fmul_ST0_FT0(CPUX86State *env)
f299f437
BS
436{
437 ST0 = floatx80_mul(ST0, FT0, &env->fp_status);
438}
439
d3eb5eae 440void helper_fsub_ST0_FT0(CPUX86State *env)
f299f437
BS
441{
442 ST0 = floatx80_sub(ST0, FT0, &env->fp_status);
443}
444
d3eb5eae 445void helper_fsubr_ST0_FT0(CPUX86State *env)
f299f437
BS
446{
447 ST0 = floatx80_sub(FT0, ST0, &env->fp_status);
448}
449
d3eb5eae 450void helper_fdiv_ST0_FT0(CPUX86State *env)
f299f437 451{
d3eb5eae 452 ST0 = helper_fdiv(env, ST0, FT0);
f299f437
BS
453}
454
d3eb5eae 455void helper_fdivr_ST0_FT0(CPUX86State *env)
f299f437 456{
d3eb5eae 457 ST0 = helper_fdiv(env, FT0, ST0);
f299f437
BS
458}
459
460/* fp operations between STN and ST0 */
461
d3eb5eae 462void helper_fadd_STN_ST0(CPUX86State *env, int st_index)
f299f437
BS
463{
464 ST(st_index) = floatx80_add(ST(st_index), ST0, &env->fp_status);
465}
466
d3eb5eae 467void helper_fmul_STN_ST0(CPUX86State *env, int st_index)
f299f437
BS
468{
469 ST(st_index) = floatx80_mul(ST(st_index), ST0, &env->fp_status);
470}
471
d3eb5eae 472void helper_fsub_STN_ST0(CPUX86State *env, int st_index)
f299f437
BS
473{
474 ST(st_index) = floatx80_sub(ST(st_index), ST0, &env->fp_status);
475}
476
d3eb5eae 477void helper_fsubr_STN_ST0(CPUX86State *env, int st_index)
f299f437
BS
478{
479 ST(st_index) = floatx80_sub(ST0, ST(st_index), &env->fp_status);
480}
481
d3eb5eae 482void helper_fdiv_STN_ST0(CPUX86State *env, int st_index)
f299f437
BS
483{
484 floatx80 *p;
485
486 p = &ST(st_index);
d3eb5eae 487 *p = helper_fdiv(env, *p, ST0);
f299f437
BS
488}
489
d3eb5eae 490void helper_fdivr_STN_ST0(CPUX86State *env, int st_index)
f299f437
BS
491{
492 floatx80 *p;
493
494 p = &ST(st_index);
d3eb5eae 495 *p = helper_fdiv(env, ST0, *p);
f299f437
BS
496}
497
498/* misc FPU operations */
d3eb5eae 499void helper_fchs_ST0(CPUX86State *env)
f299f437
BS
500{
501 ST0 = floatx80_chs(ST0);
502}
503
d3eb5eae 504void helper_fabs_ST0(CPUX86State *env)
f299f437
BS
505{
506 ST0 = floatx80_abs(ST0);
507}
508
d3eb5eae 509void helper_fld1_ST0(CPUX86State *env)
f299f437
BS
510{
511 ST0 = floatx80_one;
512}
513
d3eb5eae 514void helper_fldl2t_ST0(CPUX86State *env)
f299f437
BS
515{
516 ST0 = floatx80_l2t;
517}
518
d3eb5eae 519void helper_fldl2e_ST0(CPUX86State *env)
f299f437
BS
520{
521 ST0 = floatx80_l2e;
522}
523
d3eb5eae 524void helper_fldpi_ST0(CPUX86State *env)
f299f437
BS
525{
526 ST0 = floatx80_pi;
527}
528
d3eb5eae 529void helper_fldlg2_ST0(CPUX86State *env)
f299f437
BS
530{
531 ST0 = floatx80_lg2;
532}
533
d3eb5eae 534void helper_fldln2_ST0(CPUX86State *env)
f299f437
BS
535{
536 ST0 = floatx80_ln2;
537}
538
d3eb5eae 539void helper_fldz_ST0(CPUX86State *env)
f299f437
BS
540{
541 ST0 = floatx80_zero;
542}
543
d3eb5eae 544void helper_fldz_FT0(CPUX86State *env)
f299f437
BS
545{
546 FT0 = floatx80_zero;
547}
548
d3eb5eae 549uint32_t helper_fnstsw(CPUX86State *env)
f299f437
BS
550{
551 return (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
552}
553
d3eb5eae 554uint32_t helper_fnstcw(CPUX86State *env)
f299f437
BS
555{
556 return env->fpuc;
557}
558
5bde1407 559void update_fp_status(CPUX86State *env)
f299f437
BS
560{
561 int rnd_type;
562
563 /* set rounding mode */
564 switch (env->fpuc & FPU_RC_MASK) {
565 default:
566 case FPU_RC_NEAR:
567 rnd_type = float_round_nearest_even;
568 break;
569 case FPU_RC_DOWN:
570 rnd_type = float_round_down;
571 break;
572 case FPU_RC_UP:
573 rnd_type = float_round_up;
574 break;
575 case FPU_RC_CHOP:
576 rnd_type = float_round_to_zero;
577 break;
578 }
579 set_float_rounding_mode(rnd_type, &env->fp_status);
580 switch ((env->fpuc >> 8) & 3) {
581 case 0:
582 rnd_type = 32;
583 break;
584 case 2:
585 rnd_type = 64;
586 break;
587 case 3:
588 default:
589 rnd_type = 80;
590 break;
591 }
592 set_floatx80_rounding_precision(rnd_type, &env->fp_status);
593}
594
d3eb5eae 595void helper_fldcw(CPUX86State *env, uint32_t val)
f299f437 596{
5bde1407 597 cpu_set_fpuc(env, val);
f299f437
BS
598}
599
d3eb5eae 600void helper_fclex(CPUX86State *env)
f299f437
BS
601{
602 env->fpus &= 0x7f00;
603}
604
d3eb5eae 605void helper_fwait(CPUX86State *env)
f299f437
BS
606{
607 if (env->fpus & FPUS_SE) {
6cad09d2 608 fpu_raise_exception(env, GETPC());
f299f437
BS
609 }
610}
611
d3eb5eae 612void helper_fninit(CPUX86State *env)
f299f437
BS
613{
614 env->fpus = 0;
615 env->fpstt = 0;
5bde1407 616 cpu_set_fpuc(env, 0x37f);
f299f437
BS
617 env->fptags[0] = 1;
618 env->fptags[1] = 1;
619 env->fptags[2] = 1;
620 env->fptags[3] = 1;
621 env->fptags[4] = 1;
622 env->fptags[5] = 1;
623 env->fptags[6] = 1;
624 env->fptags[7] = 1;
625}
626
627/* BCD ops */
628
d3eb5eae 629void helper_fbld_ST0(CPUX86State *env, target_ulong ptr)
f299f437
BS
630{
631 floatx80 tmp;
632 uint64_t val;
633 unsigned int v;
634 int i;
635
636 val = 0;
637 for (i = 8; i >= 0; i--) {
6cad09d2 638 v = cpu_ldub_data_ra(env, ptr + i, GETPC());
f299f437
BS
639 val = (val * 100) + ((v >> 4) * 10) + (v & 0xf);
640 }
641 tmp = int64_to_floatx80(val, &env->fp_status);
6cad09d2 642 if (cpu_ldub_data_ra(env, ptr + 9, GETPC()) & 0x80) {
18b41f95 643 tmp = floatx80_chs(tmp);
f299f437 644 }
d3eb5eae 645 fpush(env);
f299f437
BS
646 ST0 = tmp;
647}
648
d3eb5eae 649void helper_fbst_ST0(CPUX86State *env, target_ulong ptr)
f299f437
BS
650{
651 int v;
652 target_ulong mem_ref, mem_end;
653 int64_t val;
654
655 val = floatx80_to_int64(ST0, &env->fp_status);
656 mem_ref = ptr;
657 mem_end = mem_ref + 9;
658 if (val < 0) {
6cad09d2 659 cpu_stb_data_ra(env, mem_end, 0x80, GETPC());
f299f437
BS
660 val = -val;
661 } else {
6cad09d2 662 cpu_stb_data_ra(env, mem_end, 0x00, GETPC());
f299f437
BS
663 }
664 while (mem_ref < mem_end) {
665 if (val == 0) {
666 break;
667 }
668 v = val % 100;
669 val = val / 100;
670 v = ((v / 10) << 4) | (v % 10);
6cad09d2 671 cpu_stb_data_ra(env, mem_ref++, v, GETPC());
f299f437
BS
672 }
673 while (mem_ref < mem_end) {
6cad09d2 674 cpu_stb_data_ra(env, mem_ref++, 0, GETPC());
f299f437
BS
675 }
676}
677
d3eb5eae 678void helper_f2xm1(CPUX86State *env)
f299f437 679{
d3eb5eae 680 double val = floatx80_to_double(env, ST0);
f299f437
BS
681
682 val = pow(2.0, val) - 1.0;
d3eb5eae 683 ST0 = double_to_floatx80(env, val);
f299f437
BS
684}
685
d3eb5eae 686void helper_fyl2x(CPUX86State *env)
f299f437 687{
d3eb5eae 688 double fptemp = floatx80_to_double(env, ST0);
f299f437
BS
689
690 if (fptemp > 0.0) {
691 fptemp = log(fptemp) / log(2.0); /* log2(ST) */
d3eb5eae
BS
692 fptemp *= floatx80_to_double(env, ST1);
693 ST1 = double_to_floatx80(env, fptemp);
694 fpop(env);
f299f437
BS
695 } else {
696 env->fpus &= ~0x4700;
697 env->fpus |= 0x400;
698 }
699}
700
d3eb5eae 701void helper_fptan(CPUX86State *env)
f299f437 702{
d3eb5eae 703 double fptemp = floatx80_to_double(env, ST0);
f299f437
BS
704
705 if ((fptemp > MAXTAN) || (fptemp < -MAXTAN)) {
706 env->fpus |= 0x400;
707 } else {
708 fptemp = tan(fptemp);
d3eb5eae
BS
709 ST0 = double_to_floatx80(env, fptemp);
710 fpush(env);
f299f437
BS
711 ST0 = floatx80_one;
712 env->fpus &= ~0x400; /* C2 <-- 0 */
713 /* the above code is for |arg| < 2**52 only */
714 }
715}
716
d3eb5eae 717void helper_fpatan(CPUX86State *env)
f299f437
BS
718{
719 double fptemp, fpsrcop;
720
d3eb5eae
BS
721 fpsrcop = floatx80_to_double(env, ST1);
722 fptemp = floatx80_to_double(env, ST0);
723 ST1 = double_to_floatx80(env, atan2(fpsrcop, fptemp));
724 fpop(env);
f299f437
BS
725}
726
d3eb5eae 727void helper_fxtract(CPUX86State *env)
f299f437
BS
728{
729 CPU_LDoubleU temp;
730
731 temp.d = ST0;
732
733 if (floatx80_is_zero(ST0)) {
734 /* Easy way to generate -inf and raising division by 0 exception */
735 ST0 = floatx80_div(floatx80_chs(floatx80_one), floatx80_zero,
736 &env->fp_status);
d3eb5eae 737 fpush(env);
f299f437
BS
738 ST0 = temp.d;
739 } else {
740 int expdif;
741
742 expdif = EXPD(temp) - EXPBIAS;
743 /* DP exponent bias */
744 ST0 = int32_to_floatx80(expdif, &env->fp_status);
d3eb5eae 745 fpush(env);
f299f437
BS
746 BIASEXPONENT(temp);
747 ST0 = temp.d;
748 }
749}
750
d3eb5eae 751void helper_fprem1(CPUX86State *env)
f299f437
BS
752{
753 double st0, st1, dblq, fpsrcop, fptemp;
754 CPU_LDoubleU fpsrcop1, fptemp1;
755 int expdif;
756 signed long long int q;
757
d3eb5eae
BS
758 st0 = floatx80_to_double(env, ST0);
759 st1 = floatx80_to_double(env, ST1);
f299f437
BS
760
761 if (isinf(st0) || isnan(st0) || isnan(st1) || (st1 == 0.0)) {
d3eb5eae 762 ST0 = double_to_floatx80(env, 0.0 / 0.0); /* NaN */
f299f437
BS
763 env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */
764 return;
765 }
766
767 fpsrcop = st0;
768 fptemp = st1;
769 fpsrcop1.d = ST0;
770 fptemp1.d = ST1;
771 expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
772
773 if (expdif < 0) {
774 /* optimisation? taken from the AMD docs */
775 env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */
776 /* ST0 is unchanged */
777 return;
778 }
779
780 if (expdif < 53) {
781 dblq = fpsrcop / fptemp;
782 /* round dblq towards nearest integer */
783 dblq = rint(dblq);
784 st0 = fpsrcop - fptemp * dblq;
785
786 /* convert dblq to q by truncating towards zero */
787 if (dblq < 0.0) {
788 q = (signed long long int)(-dblq);
789 } else {
790 q = (signed long long int)dblq;
791 }
792
793 env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */
794 /* (C0,C3,C1) <-- (q2,q1,q0) */
795 env->fpus |= (q & 0x4) << (8 - 2); /* (C0) <-- q2 */
796 env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */
797 env->fpus |= (q & 0x1) << (9 - 0); /* (C1) <-- q0 */
798 } else {
799 env->fpus |= 0x400; /* C2 <-- 1 */
800 fptemp = pow(2.0, expdif - 50);
801 fpsrcop = (st0 / st1) / fptemp;
802 /* fpsrcop = integer obtained by chopping */
803 fpsrcop = (fpsrcop < 0.0) ?
804 -(floor(fabs(fpsrcop))) : floor(fpsrcop);
805 st0 -= (st1 * fpsrcop * fptemp);
806 }
d3eb5eae 807 ST0 = double_to_floatx80(env, st0);
f299f437
BS
808}
809
d3eb5eae 810void helper_fprem(CPUX86State *env)
f299f437
BS
811{
812 double st0, st1, dblq, fpsrcop, fptemp;
813 CPU_LDoubleU fpsrcop1, fptemp1;
814 int expdif;
815 signed long long int q;
816
d3eb5eae
BS
817 st0 = floatx80_to_double(env, ST0);
818 st1 = floatx80_to_double(env, ST1);
f299f437
BS
819
820 if (isinf(st0) || isnan(st0) || isnan(st1) || (st1 == 0.0)) {
d3eb5eae 821 ST0 = double_to_floatx80(env, 0.0 / 0.0); /* NaN */
f299f437
BS
822 env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */
823 return;
824 }
825
826 fpsrcop = st0;
827 fptemp = st1;
828 fpsrcop1.d = ST0;
829 fptemp1.d = ST1;
830 expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
831
832 if (expdif < 0) {
833 /* optimisation? taken from the AMD docs */
834 env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */
835 /* ST0 is unchanged */
836 return;
837 }
838
839 if (expdif < 53) {
840 dblq = fpsrcop / fptemp; /* ST0 / ST1 */
841 /* round dblq towards zero */
842 dblq = (dblq < 0.0) ? ceil(dblq) : floor(dblq);
843 st0 = fpsrcop - fptemp * dblq; /* fpsrcop is ST0 */
844
845 /* convert dblq to q by truncating towards zero */
846 if (dblq < 0.0) {
847 q = (signed long long int)(-dblq);
848 } else {
849 q = (signed long long int)dblq;
850 }
851
852 env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */
853 /* (C0,C3,C1) <-- (q2,q1,q0) */
854 env->fpus |= (q & 0x4) << (8 - 2); /* (C0) <-- q2 */
855 env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */
856 env->fpus |= (q & 0x1) << (9 - 0); /* (C1) <-- q0 */
857 } else {
858 int N = 32 + (expdif % 32); /* as per AMD docs */
859
860 env->fpus |= 0x400; /* C2 <-- 1 */
861 fptemp = pow(2.0, (double)(expdif - N));
862 fpsrcop = (st0 / st1) / fptemp;
863 /* fpsrcop = integer obtained by chopping */
864 fpsrcop = (fpsrcop < 0.0) ?
865 -(floor(fabs(fpsrcop))) : floor(fpsrcop);
866 st0 -= (st1 * fpsrcop * fptemp);
867 }
d3eb5eae 868 ST0 = double_to_floatx80(env, st0);
f299f437
BS
869}
870
d3eb5eae 871void helper_fyl2xp1(CPUX86State *env)
f299f437 872{
d3eb5eae 873 double fptemp = floatx80_to_double(env, ST0);
f299f437
BS
874
875 if ((fptemp + 1.0) > 0.0) {
876 fptemp = log(fptemp + 1.0) / log(2.0); /* log2(ST + 1.0) */
d3eb5eae
BS
877 fptemp *= floatx80_to_double(env, ST1);
878 ST1 = double_to_floatx80(env, fptemp);
879 fpop(env);
f299f437
BS
880 } else {
881 env->fpus &= ~0x4700;
882 env->fpus |= 0x400;
883 }
884}
885
d3eb5eae 886void helper_fsqrt(CPUX86State *env)
f299f437
BS
887{
888 if (floatx80_is_neg(ST0)) {
889 env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */
890 env->fpus |= 0x400;
891 }
892 ST0 = floatx80_sqrt(ST0, &env->fp_status);
893}
894
d3eb5eae 895void helper_fsincos(CPUX86State *env)
f299f437 896{
d3eb5eae 897 double fptemp = floatx80_to_double(env, ST0);
f299f437
BS
898
899 if ((fptemp > MAXTAN) || (fptemp < -MAXTAN)) {
900 env->fpus |= 0x400;
901 } else {
d3eb5eae
BS
902 ST0 = double_to_floatx80(env, sin(fptemp));
903 fpush(env);
904 ST0 = double_to_floatx80(env, cos(fptemp));
f299f437
BS
905 env->fpus &= ~0x400; /* C2 <-- 0 */
906 /* the above code is for |arg| < 2**63 only */
907 }
908}
909
d3eb5eae 910void helper_frndint(CPUX86State *env)
f299f437
BS
911{
912 ST0 = floatx80_round_to_int(ST0, &env->fp_status);
913}
914
d3eb5eae 915void helper_fscale(CPUX86State *env)
f299f437
BS
916{
917 if (floatx80_is_any_nan(ST1)) {
918 ST0 = ST1;
919 } else {
920 int n = floatx80_to_int32_round_to_zero(ST1, &env->fp_status);
921 ST0 = floatx80_scalbn(ST0, n, &env->fp_status);
922 }
923}
924
d3eb5eae 925void helper_fsin(CPUX86State *env)
f299f437 926{
d3eb5eae 927 double fptemp = floatx80_to_double(env, ST0);
f299f437
BS
928
929 if ((fptemp > MAXTAN) || (fptemp < -MAXTAN)) {
930 env->fpus |= 0x400;
931 } else {
d3eb5eae 932 ST0 = double_to_floatx80(env, sin(fptemp));
f299f437
BS
933 env->fpus &= ~0x400; /* C2 <-- 0 */
934 /* the above code is for |arg| < 2**53 only */
935 }
936}
937
d3eb5eae 938void helper_fcos(CPUX86State *env)
f299f437 939{
d3eb5eae 940 double fptemp = floatx80_to_double(env, ST0);
f299f437
BS
941
942 if ((fptemp > MAXTAN) || (fptemp < -MAXTAN)) {
943 env->fpus |= 0x400;
944 } else {
d3eb5eae 945 ST0 = double_to_floatx80(env, cos(fptemp));
f299f437
BS
946 env->fpus &= ~0x400; /* C2 <-- 0 */
947 /* the above code is for |arg| < 2**63 only */
948 }
949}
950
d3eb5eae 951void helper_fxam_ST0(CPUX86State *env)
f299f437
BS
952{
953 CPU_LDoubleU temp;
954 int expdif;
955
956 temp.d = ST0;
957
958 env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */
959 if (SIGND(temp)) {
960 env->fpus |= 0x200; /* C1 <-- 1 */
961 }
962
963 /* XXX: test fptags too */
964 expdif = EXPD(temp);
965 if (expdif == MAXEXPD) {
966 if (MANTD(temp) == 0x8000000000000000ULL) {
967 env->fpus |= 0x500; /* Infinity */
968 } else {
969 env->fpus |= 0x100; /* NaN */
970 }
971 } else if (expdif == 0) {
972 if (MANTD(temp) == 0) {
973 env->fpus |= 0x4000; /* Zero */
974 } else {
975 env->fpus |= 0x4400; /* Denormal */
976 }
977 } else {
978 env->fpus |= 0x400;
979 }
980}
981
6cad09d2
PD
982static void do_fstenv(CPUX86State *env, target_ulong ptr, int data32,
983 uintptr_t retaddr)
f299f437
BS
984{
985 int fpus, fptag, exp, i;
986 uint64_t mant;
987 CPU_LDoubleU tmp;
988
989 fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
990 fptag = 0;
991 for (i = 7; i >= 0; i--) {
992 fptag <<= 2;
993 if (env->fptags[i]) {
994 fptag |= 3;
995 } else {
996 tmp.d = env->fpregs[i].d;
997 exp = EXPD(tmp);
998 mant = MANTD(tmp);
999 if (exp == 0 && mant == 0) {
1000 /* zero */
1001 fptag |= 1;
1002 } else if (exp == 0 || exp == MAXEXPD
1003 || (mant & (1LL << 63)) == 0) {
1004 /* NaNs, infinity, denormal */
1005 fptag |= 2;
1006 }
1007 }
1008 }
1009 if (data32) {
1010 /* 32 bit */
6cad09d2
PD
1011 cpu_stl_data_ra(env, ptr, env->fpuc, retaddr);
1012 cpu_stl_data_ra(env, ptr + 4, fpus, retaddr);
1013 cpu_stl_data_ra(env, ptr + 8, fptag, retaddr);
1014 cpu_stl_data_ra(env, ptr + 12, 0, retaddr); /* fpip */
1015 cpu_stl_data_ra(env, ptr + 16, 0, retaddr); /* fpcs */
1016 cpu_stl_data_ra(env, ptr + 20, 0, retaddr); /* fpoo */
1017 cpu_stl_data_ra(env, ptr + 24, 0, retaddr); /* fpos */
f299f437
BS
1018 } else {
1019 /* 16 bit */
6cad09d2
PD
1020 cpu_stw_data_ra(env, ptr, env->fpuc, retaddr);
1021 cpu_stw_data_ra(env, ptr + 2, fpus, retaddr);
1022 cpu_stw_data_ra(env, ptr + 4, fptag, retaddr);
1023 cpu_stw_data_ra(env, ptr + 6, 0, retaddr);
1024 cpu_stw_data_ra(env, ptr + 8, 0, retaddr);
1025 cpu_stw_data_ra(env, ptr + 10, 0, retaddr);
1026 cpu_stw_data_ra(env, ptr + 12, 0, retaddr);
f299f437
BS
1027 }
1028}
1029
6cad09d2
PD
1030void helper_fstenv(CPUX86State *env, target_ulong ptr, int data32)
1031{
1032 do_fstenv(env, ptr, data32, GETPC());
1033}
1034
1035static void do_fldenv(CPUX86State *env, target_ulong ptr, int data32,
1036 uintptr_t retaddr)
f299f437
BS
1037{
1038 int i, fpus, fptag;
1039
1040 if (data32) {
6cad09d2
PD
1041 cpu_set_fpuc(env, cpu_lduw_data_ra(env, ptr, retaddr));
1042 fpus = cpu_lduw_data_ra(env, ptr + 4, retaddr);
1043 fptag = cpu_lduw_data_ra(env, ptr + 8, retaddr);
f299f437 1044 } else {
6cad09d2
PD
1045 cpu_set_fpuc(env, cpu_lduw_data_ra(env, ptr, retaddr));
1046 fpus = cpu_lduw_data_ra(env, ptr + 2, retaddr);
1047 fptag = cpu_lduw_data_ra(env, ptr + 4, retaddr);
f299f437
BS
1048 }
1049 env->fpstt = (fpus >> 11) & 7;
1050 env->fpus = fpus & ~0x3800;
1051 for (i = 0; i < 8; i++) {
1052 env->fptags[i] = ((fptag & 3) == 3);
1053 fptag >>= 2;
1054 }
1055}
1056
6cad09d2
PD
1057void helper_fldenv(CPUX86State *env, target_ulong ptr, int data32)
1058{
1059 do_fldenv(env, ptr, data32, GETPC());
1060}
1061
d3eb5eae 1062void helper_fsave(CPUX86State *env, target_ulong ptr, int data32)
f299f437
BS
1063{
1064 floatx80 tmp;
1065 int i;
1066
6cad09d2 1067 do_fstenv(env, ptr, data32, GETPC());
f299f437
BS
1068
1069 ptr += (14 << data32);
1070 for (i = 0; i < 8; i++) {
1071 tmp = ST(i);
6cad09d2 1072 helper_fstt(env, tmp, ptr, GETPC());
f299f437
BS
1073 ptr += 10;
1074 }
1075
1076 /* fninit */
1077 env->fpus = 0;
1078 env->fpstt = 0;
5bde1407 1079 cpu_set_fpuc(env, 0x37f);
f299f437
BS
1080 env->fptags[0] = 1;
1081 env->fptags[1] = 1;
1082 env->fptags[2] = 1;
1083 env->fptags[3] = 1;
1084 env->fptags[4] = 1;
1085 env->fptags[5] = 1;
1086 env->fptags[6] = 1;
1087 env->fptags[7] = 1;
1088}
1089
d3eb5eae 1090void helper_frstor(CPUX86State *env, target_ulong ptr, int data32)
f299f437
BS
1091{
1092 floatx80 tmp;
1093 int i;
1094
6cad09d2 1095 do_fldenv(env, ptr, data32, GETPC());
f299f437
BS
1096 ptr += (14 << data32);
1097
1098 for (i = 0; i < 8; i++) {
6cad09d2 1099 tmp = helper_fldt(env, ptr, GETPC());
f299f437
BS
1100 ST(i) = tmp;
1101 ptr += 10;
1102 }
1103}
1104
1105#if defined(CONFIG_USER_ONLY)
d3eb5eae 1106void cpu_x86_fsave(CPUX86State *env, target_ulong ptr, int data32)
f299f437 1107{
d3eb5eae 1108 helper_fsave(env, ptr, data32);
f299f437
BS
1109}
1110
d3eb5eae 1111void cpu_x86_frstor(CPUX86State *env, target_ulong ptr, int data32)
f299f437 1112{
d3eb5eae 1113 helper_frstor(env, ptr, data32);
f299f437
BS
1114}
1115#endif
1116
6cad09d2
PD
1117static void do_fxsave(CPUX86State *env, target_ulong ptr, int data64,
1118 uintptr_t retaddr)
f299f437
BS
1119{
1120 int fpus, fptag, i, nb_xmm_regs;
1121 floatx80 tmp;
1122 target_ulong addr;
1123
1124 /* The operand must be 16 byte aligned */
1125 if (ptr & 0xf) {
6cad09d2 1126 raise_exception_ra(env, EXCP0D_GPF, retaddr);
f299f437
BS
1127 }
1128
1129 fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
1130 fptag = 0;
1131 for (i = 0; i < 8; i++) {
1132 fptag |= (env->fptags[i] << i);
1133 }
6cad09d2
PD
1134 cpu_stw_data_ra(env, ptr, env->fpuc, retaddr);
1135 cpu_stw_data_ra(env, ptr + 2, fpus, retaddr);
1136 cpu_stw_data_ra(env, ptr + 4, fptag ^ 0xff, retaddr);
f299f437
BS
1137#ifdef TARGET_X86_64
1138 if (data64) {
6cad09d2
PD
1139 cpu_stq_data_ra(env, ptr + 0x08, 0, retaddr); /* rip */
1140 cpu_stq_data_ra(env, ptr + 0x10, 0, retaddr); /* rdp */
f299f437
BS
1141 } else
1142#endif
1143 {
6cad09d2
PD
1144 cpu_stl_data_ra(env, ptr + 0x08, 0, retaddr); /* eip */
1145 cpu_stl_data_ra(env, ptr + 0x0c, 0, retaddr); /* sel */
1146 cpu_stl_data_ra(env, ptr + 0x10, 0, retaddr); /* dp */
1147 cpu_stl_data_ra(env, ptr + 0x14, 0, retaddr); /* sel */
f299f437
BS
1148 }
1149
1150 addr = ptr + 0x20;
1151 for (i = 0; i < 8; i++) {
1152 tmp = ST(i);
6cad09d2 1153 helper_fstt(env, tmp, addr, retaddr);
f299f437
BS
1154 addr += 16;
1155 }
1156
1157 if (env->cr[4] & CR4_OSFXSR_MASK) {
1158 /* XXX: finish it */
6cad09d2
PD
1159 cpu_stl_data_ra(env, ptr + 0x18, env->mxcsr, retaddr); /* mxcsr */
1160 cpu_stl_data_ra(env, ptr + 0x1c, 0x0000ffff, retaddr); /* mxcsr_mask */
f299f437
BS
1161 if (env->hflags & HF_CS64_MASK) {
1162 nb_xmm_regs = 16;
1163 } else {
1164 nb_xmm_regs = 8;
1165 }
1166 addr = ptr + 0xa0;
1167 /* Fast FXSAVE leaves out the XMM registers */
1168 if (!(env->efer & MSR_EFER_FFXSR)
1169 || (env->hflags & HF_CPL_MASK)
1170 || !(env->hflags & HF_LMA_MASK)) {
1171 for (i = 0; i < nb_xmm_regs; i++) {
6cad09d2
PD
1172 cpu_stq_data_ra(env, addr, env->xmm_regs[i].XMM_Q(0), retaddr);
1173 cpu_stq_data_ra(env, addr + 8, env->xmm_regs[i].XMM_Q(1), retaddr);
f299f437
BS
1174 addr += 16;
1175 }
1176 }
1177 }
1178}
1179
6cad09d2
PD
1180void helper_fxsave(CPUX86State *env, target_ulong ptr, int data64)
1181{
1182 do_fxsave(env, ptr, data64, GETPC());
1183}
1184
1185static void do_fxrstor(CPUX86State *env, target_ulong ptr, int data64,
1186 uintptr_t retaddr)
f299f437
BS
1187{
1188 int i, fpus, fptag, nb_xmm_regs;
1189 floatx80 tmp;
1190 target_ulong addr;
1191
1192 /* The operand must be 16 byte aligned */
1193 if (ptr & 0xf) {
6cad09d2 1194 raise_exception_ra(env, EXCP0D_GPF, retaddr);
f299f437
BS
1195 }
1196
6cad09d2
PD
1197 cpu_set_fpuc(env, cpu_lduw_data_ra(env, ptr, retaddr));
1198 fpus = cpu_lduw_data_ra(env, ptr + 2, retaddr);
1199 fptag = cpu_lduw_data_ra(env, ptr + 4, retaddr);
f299f437
BS
1200 env->fpstt = (fpus >> 11) & 7;
1201 env->fpus = fpus & ~0x3800;
1202 fptag ^= 0xff;
1203 for (i = 0; i < 8; i++) {
1204 env->fptags[i] = ((fptag >> i) & 1);
1205 }
1206
1207 addr = ptr + 0x20;
1208 for (i = 0; i < 8; i++) {
6cad09d2 1209 tmp = helper_fldt(env, addr, retaddr);
f299f437
BS
1210 ST(i) = tmp;
1211 addr += 16;
1212 }
1213
1214 if (env->cr[4] & CR4_OSFXSR_MASK) {
1215 /* XXX: finish it */
6cad09d2
PD
1216 cpu_set_mxcsr(env, cpu_ldl_data_ra(env, ptr + 0x18, retaddr));
1217 /* cpu_ldl_data_ra(env, ptr + 0x1c, retaddr); */
f299f437
BS
1218 if (env->hflags & HF_CS64_MASK) {
1219 nb_xmm_regs = 16;
1220 } else {
1221 nb_xmm_regs = 8;
1222 }
1223 addr = ptr + 0xa0;
1224 /* Fast FXRESTORE leaves out the XMM registers */
1225 if (!(env->efer & MSR_EFER_FFXSR)
1226 || (env->hflags & HF_CPL_MASK)
1227 || !(env->hflags & HF_LMA_MASK)) {
1228 for (i = 0; i < nb_xmm_regs; i++) {
6cad09d2
PD
1229 env->xmm_regs[i].XMM_Q(0) = cpu_ldq_data_ra(env, addr, retaddr);
1230 env->xmm_regs[i].XMM_Q(1) = cpu_ldq_data_ra(env, addr + 8, retaddr);
f299f437
BS
1231 addr += 16;
1232 }
1233 }
1234 }
1235}
1236
6cad09d2
PD
1237void helper_fxrstor(CPUX86State *env, target_ulong ptr, int data64)
1238{
1239 do_fxrstor(env, ptr, data64, GETPC());
1240}
1241
f299f437
BS
1242void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, floatx80 f)
1243{
1244 CPU_LDoubleU temp;
1245
1246 temp.d = f;
1247 *pmant = temp.l.lower;
1248 *pexp = temp.l.upper;
1249}
1250
1251floatx80 cpu_set_fp80(uint64_t mant, uint16_t upper)
1252{
1253 CPU_LDoubleU temp;
1254
1255 temp.l.upper = upper;
1256 temp.l.lower = mant;
1257 return temp.d;
1258}
1259
1260/* MMX/SSE */
1261/* XXX: optimize by storing fptt and fptags in the static cpu state */
1262
1263#define SSE_DAZ 0x0040
1264#define SSE_RC_MASK 0x6000
1265#define SSE_RC_NEAR 0x0000
1266#define SSE_RC_DOWN 0x2000
1267#define SSE_RC_UP 0x4000
1268#define SSE_RC_CHOP 0x6000
1269#define SSE_FZ 0x8000
1270
4e47e39a 1271void cpu_set_mxcsr(CPUX86State *env, uint32_t mxcsr)
f299f437
BS
1272{
1273 int rnd_type;
1274
4e47e39a
RH
1275 env->mxcsr = mxcsr;
1276
f299f437 1277 /* set rounding mode */
4e47e39a 1278 switch (mxcsr & SSE_RC_MASK) {
f299f437
BS
1279 default:
1280 case SSE_RC_NEAR:
1281 rnd_type = float_round_nearest_even;
1282 break;
1283 case SSE_RC_DOWN:
1284 rnd_type = float_round_down;
1285 break;
1286 case SSE_RC_UP:
1287 rnd_type = float_round_up;
1288 break;
1289 case SSE_RC_CHOP:
1290 rnd_type = float_round_to_zero;
1291 break;
1292 }
1293 set_float_rounding_mode(rnd_type, &env->sse_status);
1294
1295 /* set denormals are zero */
4e47e39a 1296 set_flush_inputs_to_zero((mxcsr & SSE_DAZ) ? 1 : 0, &env->sse_status);
f299f437
BS
1297
1298 /* set flush to zero */
4e47e39a 1299 set_flush_to_zero((mxcsr & SSE_FZ) ? 1 : 0, &env->fp_status);
f299f437
BS
1300}
1301
5bde1407
PD
1302void cpu_set_fpuc(CPUX86State *env, uint16_t val)
1303{
1304 env->fpuc = val;
1305 update_fp_status(env);
1306}
1307
d3eb5eae 1308void helper_ldmxcsr(CPUX86State *env, uint32_t val)
f299f437 1309{
4e47e39a 1310 cpu_set_mxcsr(env, val);
f299f437
BS
1311}
1312
d3eb5eae 1313void helper_enter_mmx(CPUX86State *env)
f299f437
BS
1314{
1315 env->fpstt = 0;
1316 *(uint32_t *)(env->fptags) = 0;
1317 *(uint32_t *)(env->fptags + 4) = 0;
1318}
1319
d3eb5eae 1320void helper_emms(CPUX86State *env)
f299f437
BS
1321{
1322 /* set to empty state */
1323 *(uint32_t *)(env->fptags) = 0x01010101;
1324 *(uint32_t *)(env->fptags + 4) = 0x01010101;
1325}
1326
1327/* XXX: suppress */
d3eb5eae 1328void helper_movq(CPUX86State *env, void *d, void *s)
f299f437
BS
1329{
1330 *(uint64_t *)d = *(uint64_t *)s;
1331}
1332
1333#define SHIFT 0
1334#include "ops_sse.h"
1335
1336#define SHIFT 1
1337#include "ops_sse.h"
This page took 0.441169 seconds and 4 git commands to generate.