1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include "qemu/osdep.h"
21#include <math.h>
22#include "cpu.h"
23#include "exec/helper-proto.h"
24#include "qemu/host-utils.h"
25#include "exec/exec-all.h"
26#include "exec/cpu_ldst.h"
27#include "fpu/softfloat.h"
28
29#define FPU_RC_MASK 0xc00
30#define FPU_RC_NEAR 0x000
31#define FPU_RC_DOWN 0x400
32#define FPU_RC_UP 0x800
33#define FPU_RC_CHOP 0xc00
34
35#define MAXTAN 9223372036854775808.0
36
37
38#define MAXEXPD 0x7fff
39#define EXPBIAS 16383
40#define EXPD(fp) (fp.l.upper & 0x7fff)
41#define SIGND(fp) ((fp.l.upper) & 0x8000)
42#define MANTD(fp) (fp.l.lower)
43#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7fff)) | EXPBIAS
44
45#define FPUS_IE (1 << 0)
46#define FPUS_DE (1 << 1)
47#define FPUS_ZE (1 << 2)
48#define FPUS_OE (1 << 3)
49#define FPUS_UE (1 << 4)
50#define FPUS_PE (1 << 5)
51#define FPUS_SF (1 << 6)
52#define FPUS_SE (1 << 7)
53#define FPUS_B (1 << 15)
54
55#define FPUC_EM 0x3f
56
57#define floatx80_lg2 make_floatx80(0x3ffd, 0x9a209a84fbcff799LL)
58#define floatx80_l2e make_floatx80(0x3fff, 0xb8aa3b295c17f0bcLL)
59#define floatx80_l2t make_floatx80(0x4000, 0xd49a784bcd1b8afeLL)
60
61static inline void fpush(CPUX86State *env)
62{
63 env->fpstt = (env->fpstt - 1) & 7;
64 env->fptags[env->fpstt] = 0;
65}
66
67static inline void fpop(CPUX86State *env)
68{
69 env->fptags[env->fpstt] = 1;
70 env->fpstt = (env->fpstt + 1) & 7;
71}
72
73static inline floatx80 helper_fldt(CPUX86State *env, target_ulong ptr,
74 uintptr_t retaddr)
75{
76 CPU_LDoubleU temp;
77
78 temp.l.lower = cpu_ldq_data_ra(env, ptr, retaddr);
79 temp.l.upper = cpu_lduw_data_ra(env, ptr + 8, retaddr);
80 return temp.d;
81}
82
83static inline void helper_fstt(CPUX86State *env, floatx80 f, target_ulong ptr,
84 uintptr_t retaddr)
85{
86 CPU_LDoubleU temp;
87
88 temp.d = f;
89 cpu_stq_data_ra(env, ptr, temp.l.lower, retaddr);
90 cpu_stw_data_ra(env, ptr + 8, temp.l.upper, retaddr);
91}
92
93
94
95static inline double floatx80_to_double(CPUX86State *env, floatx80 a)
96{
97 union {
98 float64 f64;
99 double d;
100 } u;
101
102 u.f64 = floatx80_to_float64(a, &env->fp_status);
103 return u.d;
104}
105
106static inline floatx80 double_to_floatx80(CPUX86State *env, double a)
107{
108 union {
109 float64 f64;
110 double d;
111 } u;
112
113 u.d = a;
114 return float64_to_floatx80(u.f64, &env->fp_status);
115}
116
117static void fpu_set_exception(CPUX86State *env, int mask)
118{
119 env->fpus |= mask;
120 if (env->fpus & (~env->fpuc & FPUC_EM)) {
121 env->fpus |= FPUS_SE | FPUS_B;
122 }
123}
124
125static inline floatx80 helper_fdiv(CPUX86State *env, floatx80 a, floatx80 b)
126{
127 if (floatx80_is_zero(b)) {
128 fpu_set_exception(env, FPUS_ZE);
129 }
130 return floatx80_div(a, b, &env->fp_status);
131}
132
133static void fpu_raise_exception(CPUX86State *env, uintptr_t retaddr)
134{
135 if (env->cr[0] & CR0_NE_MASK) {
136 raise_exception_ra(env, EXCP10_COPR, retaddr);
137 }
138#if !defined(CONFIG_USER_ONLY)
139 else {
140 cpu_set_ferr(env);
141 }
142#endif
143}
144
145void helper_flds_FT0(CPUX86State *env, uint32_t val)
146{
147 union {
148 float32 f;
149 uint32_t i;
150 } u;
151
152 u.i = val;
153 FT0 = float32_to_floatx80(u.f, &env->fp_status);
154}
155
156void helper_fldl_FT0(CPUX86State *env, uint64_t val)
157{
158 union {
159 float64 f;
160 uint64_t i;
161 } u;
162
163 u.i = val;
164 FT0 = float64_to_floatx80(u.f, &env->fp_status);
165}
166
167void helper_fildl_FT0(CPUX86State *env, int32_t val)
168{
169 FT0 = int32_to_floatx80(val, &env->fp_status);
170}
171
172void helper_flds_ST0(CPUX86State *env, uint32_t val)
173{
174 int new_fpstt;
175 union {
176 float32 f;
177 uint32_t i;
178 } u;
179
180 new_fpstt = (env->fpstt - 1) & 7;
181 u.i = val;
182 env->fpregs[new_fpstt].d = float32_to_floatx80(u.f, &env->fp_status);
183 env->fpstt = new_fpstt;
184 env->fptags[new_fpstt] = 0;
185}
186
187void helper_fldl_ST0(CPUX86State *env, uint64_t val)
188{
189 int new_fpstt;
190 union {
191 float64 f;
192 uint64_t i;
193 } u;
194
195 new_fpstt = (env->fpstt - 1) & 7;
196 u.i = val;
197 env->fpregs[new_fpstt].d = float64_to_floatx80(u.f, &env->fp_status);
198 env->fpstt = new_fpstt;
199 env->fptags[new_fpstt] = 0;
200}
201
202void helper_fildl_ST0(CPUX86State *env, int32_t val)
203{
204 int new_fpstt;
205
206 new_fpstt = (env->fpstt - 1) & 7;
207 env->fpregs[new_fpstt].d = int32_to_floatx80(val, &env->fp_status);
208 env->fpstt = new_fpstt;
209 env->fptags[new_fpstt] = 0;
210}
211
212void helper_fildll_ST0(CPUX86State *env, int64_t val)
213{
214 int new_fpstt;
215
216 new_fpstt = (env->fpstt - 1) & 7;
217 env->fpregs[new_fpstt].d = int64_to_floatx80(val, &env->fp_status);
218 env->fpstt = new_fpstt;
219 env->fptags[new_fpstt] = 0;
220}
221
222uint32_t helper_fsts_ST0(CPUX86State *env)
223{
224 union {
225 float32 f;
226 uint32_t i;
227 } u;
228
229 u.f = floatx80_to_float32(ST0, &env->fp_status);
230 return u.i;
231}
232
233uint64_t helper_fstl_ST0(CPUX86State *env)
234{
235 union {
236 float64 f;
237 uint64_t i;
238 } u;
239
240 u.f = floatx80_to_float64(ST0, &env->fp_status);
241 return u.i;
242}
243
244int32_t helper_fist_ST0(CPUX86State *env)
245{
246 int32_t val;
247
248 val = floatx80_to_int32(ST0, &env->fp_status);
249 if (val != (int16_t)val) {
250 val = -32768;
251 }
252 return val;
253}
254
255int32_t helper_fistl_ST0(CPUX86State *env)
256{
257 int32_t val;
258 signed char old_exp_flags;
259
260 old_exp_flags = get_float_exception_flags(&env->fp_status);
261 set_float_exception_flags(0, &env->fp_status);
262
263 val = floatx80_to_int32(ST0, &env->fp_status);
264 if (get_float_exception_flags(&env->fp_status) & float_flag_invalid) {
265 val = 0x80000000;
266 }
267 set_float_exception_flags(get_float_exception_flags(&env->fp_status)
268 | old_exp_flags, &env->fp_status);
269 return val;
270}
271
272int64_t helper_fistll_ST0(CPUX86State *env)
273{
274 int64_t val;
275 signed char old_exp_flags;
276
277 old_exp_flags = get_float_exception_flags(&env->fp_status);
278 set_float_exception_flags(0, &env->fp_status);
279
280 val = floatx80_to_int64(ST0, &env->fp_status);
281 if (get_float_exception_flags(&env->fp_status) & float_flag_invalid) {
282 val = 0x8000000000000000ULL;
283 }
284 set_float_exception_flags(get_float_exception_flags(&env->fp_status)
285 | old_exp_flags, &env->fp_status);
286 return val;
287}
288
289int32_t helper_fistt_ST0(CPUX86State *env)
290{
291 int32_t val;
292
293 val = floatx80_to_int32_round_to_zero(ST0, &env->fp_status);
294 if (val != (int16_t)val) {
295 val = -32768;
296 }
297 return val;
298}
299
300int32_t helper_fisttl_ST0(CPUX86State *env)
301{
302 return floatx80_to_int32_round_to_zero(ST0, &env->fp_status);
303}
304
305int64_t helper_fisttll_ST0(CPUX86State *env)
306{
307 return floatx80_to_int64_round_to_zero(ST0, &env->fp_status);
308}
309
310void helper_fldt_ST0(CPUX86State *env, target_ulong ptr)
311{
312 int new_fpstt;
313
314 new_fpstt = (env->fpstt - 1) & 7;
315 env->fpregs[new_fpstt].d = helper_fldt(env, ptr, GETPC());
316 env->fpstt = new_fpstt;
317 env->fptags[new_fpstt] = 0;
318}
319
320void helper_fstt_ST0(CPUX86State *env, target_ulong ptr)
321{
322 helper_fstt(env, ST0, ptr, GETPC());
323}
324
325void helper_fpush(CPUX86State *env)
326{
327 fpush(env);
328}
329
330void helper_fpop(CPUX86State *env)
331{
332 fpop(env);
333}
334
335void helper_fdecstp(CPUX86State *env)
336{
337 env->fpstt = (env->fpstt - 1) & 7;
338 env->fpus &= ~0x4700;
339}
340
341void helper_fincstp(CPUX86State *env)
342{
343 env->fpstt = (env->fpstt + 1) & 7;
344 env->fpus &= ~0x4700;
345}
346
347
348
349void helper_ffree_STN(CPUX86State *env, int st_index)
350{
351 env->fptags[(env->fpstt + st_index) & 7] = 1;
352}
353
354void helper_fmov_ST0_FT0(CPUX86State *env)
355{
356 ST0 = FT0;
357}
358
359void helper_fmov_FT0_STN(CPUX86State *env, int st_index)
360{
361 FT0 = ST(st_index);
362}
363
364void helper_fmov_ST0_STN(CPUX86State *env, int st_index)
365{
366 ST0 = ST(st_index);
367}
368
369void helper_fmov_STN_ST0(CPUX86State *env, int st_index)
370{
371 ST(st_index) = ST0;
372}
373
374void helper_fxchg_ST0_STN(CPUX86State *env, int st_index)
375{
376 floatx80 tmp;
377
378 tmp = ST(st_index);
379 ST(st_index) = ST0;
380 ST0 = tmp;
381}
382
383
384
385static const int fcom_ccval[4] = {0x0100, 0x4000, 0x0000, 0x4500};
386
387void helper_fcom_ST0_FT0(CPUX86State *env)
388{
389 int ret;
390
391 ret = floatx80_compare(ST0, FT0, &env->fp_status);
392 env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret + 1];
393}
394
395void helper_fucom_ST0_FT0(CPUX86State *env)
396{
397 int ret;
398
399 ret = floatx80_compare_quiet(ST0, FT0, &env->fp_status);
400 env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret + 1];
401}
402
403static const int fcomi_ccval[4] = {CC_C, CC_Z, 0, CC_Z | CC_P | CC_C};
404
405void helper_fcomi_ST0_FT0(CPUX86State *env)
406{
407 int eflags;
408 int ret;
409
410 ret = floatx80_compare(ST0, FT0, &env->fp_status);
411 eflags = cpu_cc_compute_all(env, CC_OP);
412 eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1];
413 CC_SRC = eflags;
414}
415
416void helper_fucomi_ST0_FT0(CPUX86State *env)
417{
418 int eflags;
419 int ret;
420
421 ret = floatx80_compare_quiet(ST0, FT0, &env->fp_status);
422 eflags = cpu_cc_compute_all(env, CC_OP);
423 eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1];
424 CC_SRC = eflags;
425}
426
427void helper_fadd_ST0_FT0(CPUX86State *env)
428{
429 ST0 = floatx80_add(ST0, FT0, &env->fp_status);
430}
431
432void helper_fmul_ST0_FT0(CPUX86State *env)
433{
434 ST0 = floatx80_mul(ST0, FT0, &env->fp_status);
435}
436
437void helper_fsub_ST0_FT0(CPUX86State *env)
438{
439 ST0 = floatx80_sub(ST0, FT0, &env->fp_status);
440}
441
442void helper_fsubr_ST0_FT0(CPUX86State *env)
443{
444 ST0 = floatx80_sub(FT0, ST0, &env->fp_status);
445}
446
447void helper_fdiv_ST0_FT0(CPUX86State *env)
448{
449 ST0 = helper_fdiv(env, ST0, FT0);
450}
451
452void helper_fdivr_ST0_FT0(CPUX86State *env)
453{
454 ST0 = helper_fdiv(env, FT0, ST0);
455}
456
457
458
459void helper_fadd_STN_ST0(CPUX86State *env, int st_index)
460{
461 ST(st_index) = floatx80_add(ST(st_index), ST0, &env->fp_status);
462}
463
464void helper_fmul_STN_ST0(CPUX86State *env, int st_index)
465{
466 ST(st_index) = floatx80_mul(ST(st_index), ST0, &env->fp_status);
467}
468
469void helper_fsub_STN_ST0(CPUX86State *env, int st_index)
470{
471 ST(st_index) = floatx80_sub(ST(st_index), ST0, &env->fp_status);
472}
473
474void helper_fsubr_STN_ST0(CPUX86State *env, int st_index)
475{
476 ST(st_index) = floatx80_sub(ST0, ST(st_index), &env->fp_status);
477}
478
479void helper_fdiv_STN_ST0(CPUX86State *env, int st_index)
480{
481 floatx80 *p;
482
483 p = &ST(st_index);
484 *p = helper_fdiv(env, *p, ST0);
485}
486
487void helper_fdivr_STN_ST0(CPUX86State *env, int st_index)
488{
489 floatx80 *p;
490
491 p = &ST(st_index);
492 *p = helper_fdiv(env, ST0, *p);
493}
494
495
496void helper_fchs_ST0(CPUX86State *env)
497{
498 ST0 = floatx80_chs(ST0);
499}
500
501void helper_fabs_ST0(CPUX86State *env)
502{
503 ST0 = floatx80_abs(ST0);
504}
505
506void helper_fld1_ST0(CPUX86State *env)
507{
508 ST0 = floatx80_one;
509}
510
511void helper_fldl2t_ST0(CPUX86State *env)
512{
513 ST0 = floatx80_l2t;
514}
515
516void helper_fldl2e_ST0(CPUX86State *env)
517{
518 ST0 = floatx80_l2e;
519}
520
521void helper_fldpi_ST0(CPUX86State *env)
522{
523 ST0 = floatx80_pi;
524}
525
526void helper_fldlg2_ST0(CPUX86State *env)
527{
528 ST0 = floatx80_lg2;
529}
530
531void helper_fldln2_ST0(CPUX86State *env)
532{
533 ST0 = floatx80_ln2;
534}
535
536void helper_fldz_ST0(CPUX86State *env)
537{
538 ST0 = floatx80_zero;
539}
540
541void helper_fldz_FT0(CPUX86State *env)
542{
543 FT0 = floatx80_zero;
544}
545
546uint32_t helper_fnstsw(CPUX86State *env)
547{
548 return (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
549}
550
551uint32_t helper_fnstcw(CPUX86State *env)
552{
553 return env->fpuc;
554}
555
556void update_fp_status(CPUX86State *env)
557{
558 int rnd_type;
559
560
561 switch (env->fpuc & FPU_RC_MASK) {
562 default:
563 case FPU_RC_NEAR:
564 rnd_type = float_round_nearest_even;
565 break;
566 case FPU_RC_DOWN:
567 rnd_type = float_round_down;
568 break;
569 case FPU_RC_UP:
570 rnd_type = float_round_up;
571 break;
572 case FPU_RC_CHOP:
573 rnd_type = float_round_to_zero;
574 break;
575 }
576 set_float_rounding_mode(rnd_type, &env->fp_status);
577 switch ((env->fpuc >> 8) & 3) {
578 case 0:
579 rnd_type = 32;
580 break;
581 case 2:
582 rnd_type = 64;
583 break;
584 case 3:
585 default:
586 rnd_type = 80;
587 break;
588 }
589 set_floatx80_rounding_precision(rnd_type, &env->fp_status);
590}
591
592void helper_fldcw(CPUX86State *env, uint32_t val)
593{
594 cpu_set_fpuc(env, val);
595}
596
597void helper_fclex(CPUX86State *env)
598{
599 env->fpus &= 0x7f00;
600}
601
602void helper_fwait(CPUX86State *env)
603{
604 if (env->fpus & FPUS_SE) {
605 fpu_raise_exception(env, GETPC());
606 }
607}
608
609void helper_fninit(CPUX86State *env)
610{
611 env->fpus = 0;
612 env->fpstt = 0;
613 cpu_set_fpuc(env, 0x37f);
614 env->fptags[0] = 1;
615 env->fptags[1] = 1;
616 env->fptags[2] = 1;
617 env->fptags[3] = 1;
618 env->fptags[4] = 1;
619 env->fptags[5] = 1;
620 env->fptags[6] = 1;
621 env->fptags[7] = 1;
622}
623
624
625
626void helper_fbld_ST0(CPUX86State *env, target_ulong ptr)
627{
628 floatx80 tmp;
629 uint64_t val;
630 unsigned int v;
631 int i;
632
633 val = 0;
634 for (i = 8; i >= 0; i--) {
635 v = cpu_ldub_data_ra(env, ptr + i, GETPC());
636 val = (val * 100) + ((v >> 4) * 10) + (v & 0xf);
637 }
638 tmp = int64_to_floatx80(val, &env->fp_status);
639 if (cpu_ldub_data_ra(env, ptr + 9, GETPC()) & 0x80) {
640 tmp = floatx80_chs(tmp);
641 }
642 fpush(env);
643 ST0 = tmp;
644}
645
646void helper_fbst_ST0(CPUX86State *env, target_ulong ptr)
647{
648 int v;
649 target_ulong mem_ref, mem_end;
650 int64_t val;
651
652 val = floatx80_to_int64(ST0, &env->fp_status);
653 mem_ref = ptr;
654 mem_end = mem_ref + 9;
655 if (val < 0) {
656 cpu_stb_data_ra(env, mem_end, 0x80, GETPC());
657 val = -val;
658 } else {
659 cpu_stb_data_ra(env, mem_end, 0x00, GETPC());
660 }
661 while (mem_ref < mem_end) {
662 if (val == 0) {
663 break;
664 }
665 v = val % 100;
666 val = val / 100;
667 v = ((v / 10) << 4) | (v % 10);
668 cpu_stb_data_ra(env, mem_ref++, v, GETPC());
669 }
670 while (mem_ref < mem_end) {
671 cpu_stb_data_ra(env, mem_ref++, 0, GETPC());
672 }
673}
674
675void helper_f2xm1(CPUX86State *env)
676{
677 double val = floatx80_to_double(env, ST0);
678
679 val = pow(2.0, val) - 1.0;
680 ST0 = double_to_floatx80(env, val);
681}
682
683void helper_fyl2x(CPUX86State *env)
684{
685 double fptemp = floatx80_to_double(env, ST0);
686
687 if (fptemp > 0.0) {
688 fptemp = log(fptemp) / log(2.0);
689 fptemp *= floatx80_to_double(env, ST1);
690 ST1 = double_to_floatx80(env, fptemp);
691 fpop(env);
692 } else {
693 env->fpus &= ~0x4700;
694 env->fpus |= 0x400;
695 }
696}
697
698void helper_fptan(CPUX86State *env)
699{
700 double fptemp = floatx80_to_double(env, ST0);
701
702 if ((fptemp > MAXTAN) || (fptemp < -MAXTAN)) {
703 env->fpus |= 0x400;
704 } else {
705 fptemp = tan(fptemp);
706 ST0 = double_to_floatx80(env, fptemp);
707 fpush(env);
708 ST0 = floatx80_one;
709 env->fpus &= ~0x400;
710
711 }
712}
713
714void helper_fpatan(CPUX86State *env)
715{
716 double fptemp, fpsrcop;
717
718 fpsrcop = floatx80_to_double(env, ST1);
719 fptemp = floatx80_to_double(env, ST0);
720 ST1 = double_to_floatx80(env, atan2(fpsrcop, fptemp));
721 fpop(env);
722}
723
724void helper_fxtract(CPUX86State *env)
725{
726 CPU_LDoubleU temp;
727
728 temp.d = ST0;
729
730 if (floatx80_is_zero(ST0)) {
731
732 ST0 = floatx80_div(floatx80_chs(floatx80_one), floatx80_zero,
733 &env->fp_status);
734 fpush(env);
735 ST0 = temp.d;
736 } else {
737 int expdif;
738
739 expdif = EXPD(temp) - EXPBIAS;
740
741 ST0 = int32_to_floatx80(expdif, &env->fp_status);
742 fpush(env);
743 BIASEXPONENT(temp);
744 ST0 = temp.d;
745 }
746}
747
748void helper_fprem1(CPUX86State *env)
749{
750 double st0, st1, dblq, fpsrcop, fptemp;
751 CPU_LDoubleU fpsrcop1, fptemp1;
752 int expdif;
753 signed long long int q;
754
755 st0 = floatx80_to_double(env, ST0);
756 st1 = floatx80_to_double(env, ST1);
757
758 if (isinf(st0) || isnan(st0) || isnan(st1) || (st1 == 0.0)) {
759 ST0 = double_to_floatx80(env, 0.0 / 0.0);
760 env->fpus &= ~0x4700;
761 return;
762 }
763
764 fpsrcop = st0;
765 fptemp = st1;
766 fpsrcop1.d = ST0;
767 fptemp1.d = ST1;
768 expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
769
770 if (expdif < 0) {
771
772 env->fpus &= ~0x4700;
773
774 return;
775 }
776
777 if (expdif < 53) {
778 dblq = fpsrcop / fptemp;
779
780 dblq = rint(dblq);
781 st0 = fpsrcop - fptemp * dblq;
782
783
784 if (dblq < 0.0) {
785 q = (signed long long int)(-dblq);
786 } else {
787 q = (signed long long int)dblq;
788 }
789
790 env->fpus &= ~0x4700;
791
792 env->fpus |= (q & 0x4) << (8 - 2);
793 env->fpus |= (q & 0x2) << (14 - 1);
794 env->fpus |= (q & 0x1) << (9 - 0);
795 } else {
796 env->fpus |= 0x400;
797 fptemp = pow(2.0, expdif - 50);
798 fpsrcop = (st0 / st1) / fptemp;
799
800 fpsrcop = (fpsrcop < 0.0) ?
801 -(floor(fabs(fpsrcop))) : floor(fpsrcop);
802 st0 -= (st1 * fpsrcop * fptemp);
803 }
804 ST0 = double_to_floatx80(env, st0);
805}
806
807void helper_fprem(CPUX86State *env)
808{
809 double st0, st1, dblq, fpsrcop, fptemp;
810 CPU_LDoubleU fpsrcop1, fptemp1;
811 int expdif;
812 signed long long int q;
813
814 st0 = floatx80_to_double(env, ST0);
815 st1 = floatx80_to_double(env, ST1);
816
817 if (isinf(st0) || isnan(st0) || isnan(st1) || (st1 == 0.0)) {
818 ST0 = double_to_floatx80(env, 0.0 / 0.0);
819 env->fpus &= ~0x4700;
820 return;
821 }
822
823 fpsrcop = st0;
824 fptemp = st1;
825 fpsrcop1.d = ST0;
826 fptemp1.d = ST1;
827 expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
828
829 if (expdif < 0) {
830
831 env->fpus &= ~0x4700;
832
833 return;
834 }
835
836 if (expdif < 53) {
837 dblq = fpsrcop / fptemp;
838
839 dblq = (dblq < 0.0) ? ceil(dblq) : floor(dblq);
840 st0 = fpsrcop - fptemp * dblq;
841
842
843 if (dblq < 0.0) {
844 q = (signed long long int)(-dblq);
845 } else {
846 q = (signed long long int)dblq;
847 }
848
849 env->fpus &= ~0x4700;
850
851 env->fpus |= (q & 0x4) << (8 - 2);
852 env->fpus |= (q & 0x2) << (14 - 1);
853 env->fpus |= (q & 0x1) << (9 - 0);
854 } else {
855 int N = 32 + (expdif % 32);
856
857 env->fpus |= 0x400;
858 fptemp = pow(2.0, (double)(expdif - N));
859 fpsrcop = (st0 / st1) / fptemp;
860
861 fpsrcop = (fpsrcop < 0.0) ?
862 -(floor(fabs(fpsrcop))) : floor(fpsrcop);
863 st0 -= (st1 * fpsrcop * fptemp);
864 }
865 ST0 = double_to_floatx80(env, st0);
866}
867
868void helper_fyl2xp1(CPUX86State *env)
869{
870 double fptemp = floatx80_to_double(env, ST0);
871
872 if ((fptemp + 1.0) > 0.0) {
873 fptemp = log(fptemp + 1.0) / log(2.0);
874 fptemp *= floatx80_to_double(env, ST1);
875 ST1 = double_to_floatx80(env, fptemp);
876 fpop(env);
877 } else {
878 env->fpus &= ~0x4700;
879 env->fpus |= 0x400;
880 }
881}
882
883void helper_fsqrt(CPUX86State *env)
884{
885 if (floatx80_is_neg(ST0)) {
886 env->fpus &= ~0x4700;
887 env->fpus |= 0x400;
888 }
889 ST0 = floatx80_sqrt(ST0, &env->fp_status);
890}
891
892void helper_fsincos(CPUX86State *env)
893{
894 double fptemp = floatx80_to_double(env, ST0);
895
896 if ((fptemp > MAXTAN) || (fptemp < -MAXTAN)) {
897 env->fpus |= 0x400;
898 } else {
899 ST0 = double_to_floatx80(env, sin(fptemp));
900 fpush(env);
901 ST0 = double_to_floatx80(env, cos(fptemp));
902 env->fpus &= ~0x400;
903
904 }
905}
906
907void helper_frndint(CPUX86State *env)
908{
909 ST0 = floatx80_round_to_int(ST0, &env->fp_status);
910}
911
912void helper_fscale(CPUX86State *env)
913{
914 if (floatx80_is_any_nan(ST1)) {
915 ST0 = ST1;
916 } else {
917 int n = floatx80_to_int32_round_to_zero(ST1, &env->fp_status);
918 ST0 = floatx80_scalbn(ST0, n, &env->fp_status);
919 }
920}
921
922void helper_fsin(CPUX86State *env)
923{
924 double fptemp = floatx80_to_double(env, ST0);
925
926 if ((fptemp > MAXTAN) || (fptemp < -MAXTAN)) {
927 env->fpus |= 0x400;
928 } else {
929 ST0 = double_to_floatx80(env, sin(fptemp));
930 env->fpus &= ~0x400;
931
932 }
933}
934
935void helper_fcos(CPUX86State *env)
936{
937 double fptemp = floatx80_to_double(env, ST0);
938
939 if ((fptemp > MAXTAN) || (fptemp < -MAXTAN)) {
940 env->fpus |= 0x400;
941 } else {
942 ST0 = double_to_floatx80(env, cos(fptemp));
943 env->fpus &= ~0x400;
944
945 }
946}
947
948void helper_fxam_ST0(CPUX86State *env)
949{
950 CPU_LDoubleU temp;
951 int expdif;
952
953 temp.d = ST0;
954
955 env->fpus &= ~0x4700;
956 if (SIGND(temp)) {
957 env->fpus |= 0x200;
958 }
959
960
961 expdif = EXPD(temp);
962 if (expdif == MAXEXPD) {
963 if (MANTD(temp) == 0x8000000000000000ULL) {
964 env->fpus |= 0x500;
965 } else {
966 env->fpus |= 0x100;
967 }
968 } else if (expdif == 0) {
969 if (MANTD(temp) == 0) {
970 env->fpus |= 0x4000;
971 } else {
972 env->fpus |= 0x4400;
973 }
974 } else {
975 env->fpus |= 0x400;
976 }
977}
978
979static void do_fstenv(CPUX86State *env, target_ulong ptr, int data32,
980 uintptr_t retaddr)
981{
982 int fpus, fptag, exp, i;
983 uint64_t mant;
984 CPU_LDoubleU tmp;
985
986 fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
987 fptag = 0;
988 for (i = 7; i >= 0; i--) {
989 fptag <<= 2;
990 if (env->fptags[i]) {
991 fptag |= 3;
992 } else {
993 tmp.d = env->fpregs[i].d;
994 exp = EXPD(tmp);
995 mant = MANTD(tmp);
996 if (exp == 0 && mant == 0) {
997
998 fptag |= 1;
999 } else if (exp == 0 || exp == MAXEXPD
1000 || (mant & (1LL << 63)) == 0) {
1001
1002 fptag |= 2;
1003 }
1004 }
1005 }
1006 if (data32) {
1007
1008 cpu_stl_data_ra(env, ptr, env->fpuc, retaddr);
1009 cpu_stl_data_ra(env, ptr + 4, fpus, retaddr);
1010 cpu_stl_data_ra(env, ptr + 8, fptag, retaddr);
1011 cpu_stl_data_ra(env, ptr + 12, 0, retaddr);
1012 cpu_stl_data_ra(env, ptr + 16, 0, retaddr);
1013 cpu_stl_data_ra(env, ptr + 20, 0, retaddr);
1014 cpu_stl_data_ra(env, ptr + 24, 0, retaddr);
1015 } else {
1016
1017 cpu_stw_data_ra(env, ptr, env->fpuc, retaddr);
1018 cpu_stw_data_ra(env, ptr + 2, fpus, retaddr);
1019 cpu_stw_data_ra(env, ptr + 4, fptag, retaddr);
1020 cpu_stw_data_ra(env, ptr + 6, 0, retaddr);
1021 cpu_stw_data_ra(env, ptr + 8, 0, retaddr);
1022 cpu_stw_data_ra(env, ptr + 10, 0, retaddr);
1023 cpu_stw_data_ra(env, ptr + 12, 0, retaddr);
1024 }
1025}
1026
1027void helper_fstenv(CPUX86State *env, target_ulong ptr, int data32)
1028{
1029 do_fstenv(env, ptr, data32, GETPC());
1030}
1031
1032static void do_fldenv(CPUX86State *env, target_ulong ptr, int data32,
1033 uintptr_t retaddr)
1034{
1035 int i, fpus, fptag;
1036
1037 if (data32) {
1038 cpu_set_fpuc(env, cpu_lduw_data_ra(env, ptr, retaddr));
1039 fpus = cpu_lduw_data_ra(env, ptr + 4, retaddr);
1040 fptag = cpu_lduw_data_ra(env, ptr + 8, retaddr);
1041 } else {
1042 cpu_set_fpuc(env, cpu_lduw_data_ra(env, ptr, retaddr));
1043 fpus = cpu_lduw_data_ra(env, ptr + 2, retaddr);
1044 fptag = cpu_lduw_data_ra(env, ptr + 4, retaddr);
1045 }
1046 env->fpstt = (fpus >> 11) & 7;
1047 env->fpus = fpus & ~0x3800;
1048 for (i = 0; i < 8; i++) {
1049 env->fptags[i] = ((fptag & 3) == 3);
1050 fptag >>= 2;
1051 }
1052}
1053
1054void helper_fldenv(CPUX86State *env, target_ulong ptr, int data32)
1055{
1056 do_fldenv(env, ptr, data32, GETPC());
1057}
1058
1059void helper_fsave(CPUX86State *env, target_ulong ptr, int data32)
1060{
1061 floatx80 tmp;
1062 int i;
1063
1064 do_fstenv(env, ptr, data32, GETPC());
1065
1066 ptr += (14 << data32);
1067 for (i = 0; i < 8; i++) {
1068 tmp = ST(i);
1069 helper_fstt(env, tmp, ptr, GETPC());
1070 ptr += 10;
1071 }
1072
1073
1074 env->fpus = 0;
1075 env->fpstt = 0;
1076 cpu_set_fpuc(env, 0x37f);
1077 env->fptags[0] = 1;
1078 env->fptags[1] = 1;
1079 env->fptags[2] = 1;
1080 env->fptags[3] = 1;
1081 env->fptags[4] = 1;
1082 env->fptags[5] = 1;
1083 env->fptags[6] = 1;
1084 env->fptags[7] = 1;
1085}
1086
1087void helper_frstor(CPUX86State *env, target_ulong ptr, int data32)
1088{
1089 floatx80 tmp;
1090 int i;
1091
1092 do_fldenv(env, ptr, data32, GETPC());
1093 ptr += (14 << data32);
1094
1095 for (i = 0; i < 8; i++) {
1096 tmp = helper_fldt(env, ptr, GETPC());
1097 ST(i) = tmp;
1098 ptr += 10;
1099 }
1100}
1101
1102#if defined(CONFIG_USER_ONLY)
1103void cpu_x86_fsave(CPUX86State *env, target_ulong ptr, int data32)
1104{
1105 helper_fsave(env, ptr, data32);
1106}
1107
1108void cpu_x86_frstor(CPUX86State *env, target_ulong ptr, int data32)
1109{
1110 helper_frstor(env, ptr, data32);
1111}
1112#endif
1113
1114#define XO(X) offsetof(X86XSaveArea, X)
1115
1116static void do_xsave_fpu(CPUX86State *env, target_ulong ptr, uintptr_t ra)
1117{
1118 int fpus, fptag, i;
1119 target_ulong addr;
1120
1121 fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
1122 fptag = 0;
1123 for (i = 0; i < 8; i++) {
1124 fptag |= (env->fptags[i] << i);
1125 }
1126
1127 cpu_stw_data_ra(env, ptr + XO(legacy.fcw), env->fpuc, ra);
1128 cpu_stw_data_ra(env, ptr + XO(legacy.fsw), fpus, ra);
1129 cpu_stw_data_ra(env, ptr + XO(legacy.ftw), fptag ^ 0xff, ra);
1130
1131
1132
1133
1134 cpu_stq_data_ra(env, ptr + XO(legacy.fpip), 0, ra);
1135 cpu_stq_data_ra(env, ptr + XO(legacy.fpdp), 0, ra);
1136
1137 addr = ptr + XO(legacy.fpregs);
1138 for (i = 0; i < 8; i++) {
1139 floatx80 tmp = ST(i);
1140 helper_fstt(env, tmp, addr, ra);
1141 addr += 16;
1142 }
1143}
1144
1145static void do_xsave_mxcsr(CPUX86State *env, target_ulong ptr, uintptr_t ra)
1146{
1147 cpu_stl_data_ra(env, ptr + XO(legacy.mxcsr), env->mxcsr, ra);
1148 cpu_stl_data_ra(env, ptr + XO(legacy.mxcsr_mask), 0x0000ffff, ra);
1149}
1150
1151static void do_xsave_sse(CPUX86State *env, target_ulong ptr, uintptr_t ra)
1152{
1153 int i, nb_xmm_regs;
1154 target_ulong addr;
1155
1156 if (env->hflags & HF_CS64_MASK) {
1157 nb_xmm_regs = 16;
1158 } else {
1159 nb_xmm_regs = 8;
1160 }
1161
1162 addr = ptr + XO(legacy.xmm_regs);
1163 for (i = 0; i < nb_xmm_regs; i++) {
1164 cpu_stq_data_ra(env, addr, env->xmm_regs[i].ZMM_Q(0), ra);
1165 cpu_stq_data_ra(env, addr + 8, env->xmm_regs[i].ZMM_Q(1), ra);
1166 addr += 16;
1167 }
1168}
1169
1170static void do_xsave_bndregs(CPUX86State *env, target_ulong ptr, uintptr_t ra)
1171{
1172 target_ulong addr = ptr + offsetof(XSaveBNDREG, bnd_regs);
1173 int i;
1174
1175 for (i = 0; i < 4; i++, addr += 16) {
1176 cpu_stq_data_ra(env, addr, env->bnd_regs[i].lb, ra);
1177 cpu_stq_data_ra(env, addr + 8, env->bnd_regs[i].ub, ra);
1178 }
1179}
1180
1181static void do_xsave_bndcsr(CPUX86State *env, target_ulong ptr, uintptr_t ra)
1182{
1183 cpu_stq_data_ra(env, ptr + offsetof(XSaveBNDCSR, bndcsr.cfgu),
1184 env->bndcs_regs.cfgu, ra);
1185 cpu_stq_data_ra(env, ptr + offsetof(XSaveBNDCSR, bndcsr.sts),
1186 env->bndcs_regs.sts, ra);
1187}
1188
1189static void do_xsave_pkru(CPUX86State *env, target_ulong ptr, uintptr_t ra)
1190{
1191 cpu_stq_data_ra(env, ptr, env->pkru, ra);
1192}
1193
1194void helper_fxsave(CPUX86State *env, target_ulong ptr)
1195{
1196 uintptr_t ra = GETPC();
1197
1198
1199 if (ptr & 0xf) {
1200 raise_exception_ra(env, EXCP0D_GPF, ra);
1201 }
1202
1203 do_xsave_fpu(env, ptr, ra);
1204
1205 if (env->cr[4] & CR4_OSFXSR_MASK) {
1206 do_xsave_mxcsr(env, ptr, ra);
1207
1208 if (!(env->efer & MSR_EFER_FFXSR)
1209 || (env->hflags & HF_CPL_MASK)
1210 || !(env->hflags & HF_LMA_MASK)) {
1211 do_xsave_sse(env, ptr, ra);
1212 }
1213 }
1214}
1215
1216static uint64_t get_xinuse(CPUX86State *env)
1217{
1218 uint64_t inuse = -1;
1219
1220
1221
1222
1223
1224 if ((env->hflags & HF_MPX_IU_MASK) == 0) {
1225 inuse &= ~XSTATE_BNDREGS_MASK;
1226 }
1227 return inuse;
1228}
1229
1230static void do_xsave(CPUX86State *env, target_ulong ptr, uint64_t rfbm,
1231 uint64_t inuse, uint64_t opt, uintptr_t ra)
1232{
1233 uint64_t old_bv, new_bv;
1234
1235
1236 if (!(env->cr[4] & CR4_OSXSAVE_MASK)) {
1237 raise_exception_ra(env, EXCP06_ILLOP, ra);
1238 }
1239
1240
1241 if (ptr & 63) {
1242 raise_exception_ra(env, EXCP0D_GPF, ra);
1243 }
1244
1245
1246 rfbm &= env->xcr0;
1247 opt &= rfbm;
1248
1249 if (opt & XSTATE_FP_MASK) {
1250 do_xsave_fpu(env, ptr, ra);
1251 }
1252 if (rfbm & XSTATE_SSE_MASK) {
1253
1254 do_xsave_mxcsr(env, ptr, ra);
1255 }
1256 if (opt & XSTATE_SSE_MASK) {
1257 do_xsave_sse(env, ptr, ra);
1258 }
1259 if (opt & XSTATE_BNDREGS_MASK) {
1260 do_xsave_bndregs(env, ptr + XO(bndreg_state), ra);
1261 }
1262 if (opt & XSTATE_BNDCSR_MASK) {
1263 do_xsave_bndcsr(env, ptr + XO(bndcsr_state), ra);
1264 }
1265 if (opt & XSTATE_PKRU_MASK) {
1266 do_xsave_pkru(env, ptr + XO(pkru_state), ra);
1267 }
1268
1269
1270 old_bv = cpu_ldq_data_ra(env, ptr + XO(header.xstate_bv), ra);
1271 new_bv = (old_bv & ~rfbm) | (inuse & rfbm);
1272 cpu_stq_data_ra(env, ptr + XO(header.xstate_bv), new_bv, ra);
1273}
1274
1275void helper_xsave(CPUX86State *env, target_ulong ptr, uint64_t rfbm)
1276{
1277 do_xsave(env, ptr, rfbm, get_xinuse(env), -1, GETPC());
1278}
1279
1280void helper_xsaveopt(CPUX86State *env, target_ulong ptr, uint64_t rfbm)
1281{
1282 uint64_t inuse = get_xinuse(env);
1283 do_xsave(env, ptr, rfbm, inuse, inuse, GETPC());
1284}
1285
1286static void do_xrstor_fpu(CPUX86State *env, target_ulong ptr, uintptr_t ra)
1287{
1288 int i, fpuc, fpus, fptag;
1289 target_ulong addr;
1290
1291 fpuc = cpu_lduw_data_ra(env, ptr + XO(legacy.fcw), ra);
1292 fpus = cpu_lduw_data_ra(env, ptr + XO(legacy.fsw), ra);
1293 fptag = cpu_lduw_data_ra(env, ptr + XO(legacy.ftw), ra);
1294 cpu_set_fpuc(env, fpuc);
1295 env->fpstt = (fpus >> 11) & 7;
1296 env->fpus = fpus & ~0x3800;
1297 fptag ^= 0xff;
1298 for (i = 0; i < 8; i++) {
1299 env->fptags[i] = ((fptag >> i) & 1);
1300 }
1301
1302 addr = ptr + XO(legacy.fpregs);
1303 for (i = 0; i < 8; i++) {
1304 floatx80 tmp = helper_fldt(env, addr, ra);
1305 ST(i) = tmp;
1306 addr += 16;
1307 }
1308}
1309
1310static void do_xrstor_mxcsr(CPUX86State *env, target_ulong ptr, uintptr_t ra)
1311{
1312 cpu_set_mxcsr(env, cpu_ldl_data_ra(env, ptr + XO(legacy.mxcsr), ra));
1313}
1314
1315static void do_xrstor_sse(CPUX86State *env, target_ulong ptr, uintptr_t ra)
1316{
1317 int i, nb_xmm_regs;
1318 target_ulong addr;
1319
1320 if (env->hflags & HF_CS64_MASK) {
1321 nb_xmm_regs = 16;
1322 } else {
1323 nb_xmm_regs = 8;
1324 }
1325
1326 addr = ptr + XO(legacy.xmm_regs);
1327 for (i = 0; i < nb_xmm_regs; i++) {
1328 env->xmm_regs[i].ZMM_Q(0) = cpu_ldq_data_ra(env, addr, ra);
1329 env->xmm_regs[i].ZMM_Q(1) = cpu_ldq_data_ra(env, addr + 8, ra);
1330 addr += 16;
1331 }
1332}
1333
1334static void do_xrstor_bndregs(CPUX86State *env, target_ulong ptr, uintptr_t ra)
1335{
1336 target_ulong addr = ptr + offsetof(XSaveBNDREG, bnd_regs);
1337 int i;
1338
1339 for (i = 0; i < 4; i++, addr += 16) {
1340 env->bnd_regs[i].lb = cpu_ldq_data_ra(env, addr, ra);
1341 env->bnd_regs[i].ub = cpu_ldq_data_ra(env, addr + 8, ra);
1342 }
1343}
1344
1345static void do_xrstor_bndcsr(CPUX86State *env, target_ulong ptr, uintptr_t ra)
1346{
1347
1348 env->bndcs_regs.cfgu
1349 = cpu_ldq_data_ra(env, ptr + offsetof(XSaveBNDCSR, bndcsr.cfgu), ra);
1350 env->bndcs_regs.sts
1351 = cpu_ldq_data_ra(env, ptr + offsetof(XSaveBNDCSR, bndcsr.sts), ra);
1352}
1353
1354static void do_xrstor_pkru(CPUX86State *env, target_ulong ptr, uintptr_t ra)
1355{
1356 env->pkru = cpu_ldq_data_ra(env, ptr, ra);
1357}
1358
1359void helper_fxrstor(CPUX86State *env, target_ulong ptr)
1360{
1361 uintptr_t ra = GETPC();
1362
1363
1364 if (ptr & 0xf) {
1365 raise_exception_ra(env, EXCP0D_GPF, ra);
1366 }
1367
1368 do_xrstor_fpu(env, ptr, ra);
1369
1370 if (env->cr[4] & CR4_OSFXSR_MASK) {
1371 do_xrstor_mxcsr(env, ptr, ra);
1372
1373 if (!(env->efer & MSR_EFER_FFXSR)
1374 || (env->hflags & HF_CPL_MASK)
1375 || !(env->hflags & HF_LMA_MASK)) {
1376 do_xrstor_sse(env, ptr, ra);
1377 }
1378 }
1379}
1380
1381#if defined(CONFIG_USER_ONLY)
1382void cpu_x86_fxsave(CPUX86State *env, target_ulong ptr)
1383{
1384 helper_fxsave(env, ptr);
1385}
1386
1387void cpu_x86_fxrstor(CPUX86State *env, target_ulong ptr)
1388{
1389 helper_fxrstor(env, ptr);
1390}
1391#endif
1392
1393void helper_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm)
1394{
1395 uintptr_t ra = GETPC();
1396 uint64_t xstate_bv, xcomp_bv, reserve0;
1397
1398 rfbm &= env->xcr0;
1399
1400
1401 if (!(env->cr[4] & CR4_OSXSAVE_MASK)) {
1402 raise_exception_ra(env, EXCP06_ILLOP, ra);
1403 }
1404
1405
1406 if (ptr & 63) {
1407 raise_exception_ra(env, EXCP0D_GPF, ra);
1408 }
1409
1410 xstate_bv = cpu_ldq_data_ra(env, ptr + XO(header.xstate_bv), ra);
1411
1412 if ((int64_t)xstate_bv < 0) {
1413
1414 raise_exception_ra(env, EXCP0D_GPF, ra);
1415 }
1416
1417
1418
1419
1420 if (xstate_bv & ~env->xcr0) {
1421 raise_exception_ra(env, EXCP0D_GPF, ra);
1422 }
1423
1424
1425
1426
1427
1428
1429 xcomp_bv = cpu_ldq_data_ra(env, ptr + XO(header.xcomp_bv), ra);
1430 reserve0 = cpu_ldq_data_ra(env, ptr + XO(header.reserve0), ra);
1431 if (xcomp_bv || reserve0) {
1432 raise_exception_ra(env, EXCP0D_GPF, ra);
1433 }
1434
1435 if (rfbm & XSTATE_FP_MASK) {
1436 if (xstate_bv & XSTATE_FP_MASK) {
1437 do_xrstor_fpu(env, ptr, ra);
1438 } else {
1439 helper_fninit(env);
1440 memset(env->fpregs, 0, sizeof(env->fpregs));
1441 }
1442 }
1443 if (rfbm & XSTATE_SSE_MASK) {
1444
1445
1446 do_xrstor_mxcsr(env, ptr, ra);
1447 if (xstate_bv & XSTATE_SSE_MASK) {
1448 do_xrstor_sse(env, ptr, ra);
1449 } else {
1450
1451
1452 memset(env->xmm_regs, 0, sizeof(env->xmm_regs));
1453 }
1454 }
1455 if (rfbm & XSTATE_BNDREGS_MASK) {
1456 if (xstate_bv & XSTATE_BNDREGS_MASK) {
1457 do_xrstor_bndregs(env, ptr + XO(bndreg_state), ra);
1458 env->hflags |= HF_MPX_IU_MASK;
1459 } else {
1460 memset(env->bnd_regs, 0, sizeof(env->bnd_regs));
1461 env->hflags &= ~HF_MPX_IU_MASK;
1462 }
1463 }
1464 if (rfbm & XSTATE_BNDCSR_MASK) {
1465 if (xstate_bv & XSTATE_BNDCSR_MASK) {
1466 do_xrstor_bndcsr(env, ptr + XO(bndcsr_state), ra);
1467 } else {
1468 memset(&env->bndcs_regs, 0, sizeof(env->bndcs_regs));
1469 }
1470 cpu_sync_bndcs_hflags(env);
1471 }
1472 if (rfbm & XSTATE_PKRU_MASK) {
1473 uint64_t old_pkru = env->pkru;
1474 if (xstate_bv & XSTATE_PKRU_MASK) {
1475 do_xrstor_pkru(env, ptr + XO(pkru_state), ra);
1476 } else {
1477 env->pkru = 0;
1478 }
1479 if (env->pkru != old_pkru) {
1480 CPUState *cs = env_cpu(env);
1481 tlb_flush(cs);
1482 }
1483 }
1484}
1485
1486#undef XO
1487
1488uint64_t helper_xgetbv(CPUX86State *env, uint32_t ecx)
1489{
1490
1491 if (!(env->cr[4] & CR4_OSXSAVE_MASK)) {
1492 raise_exception_ra(env, EXCP06_ILLOP, GETPC());
1493 }
1494
1495 switch (ecx) {
1496 case 0:
1497 return env->xcr0;
1498 case 1:
1499 if (env->features[FEAT_XSAVE] & CPUID_XSAVE_XGETBV1) {
1500 return env->xcr0 & get_xinuse(env);
1501 }
1502 break;
1503 }
1504 raise_exception_ra(env, EXCP0D_GPF, GETPC());
1505}
1506
1507void helper_xsetbv(CPUX86State *env, uint32_t ecx, uint64_t mask)
1508{
1509 uint32_t dummy, ena_lo, ena_hi;
1510 uint64_t ena;
1511
1512
1513 if (!(env->cr[4] & CR4_OSXSAVE_MASK)) {
1514 raise_exception_ra(env, EXCP06_ILLOP, GETPC());
1515 }
1516
1517
1518 if (ecx != 0 || (mask & XSTATE_FP_MASK) == 0) {
1519 goto do_gpf;
1520 }
1521
1522
1523 cpu_x86_cpuid(env, 0x0d, 0, &ena_lo, &dummy, &dummy, &ena_hi);
1524 ena = ((uint64_t)ena_hi << 32) | ena_lo;
1525 if (mask & ~ena) {
1526 goto do_gpf;
1527 }
1528
1529
1530 if ((mask ^ (mask * (XSTATE_BNDCSR_MASK / XSTATE_BNDREGS_MASK)))
1531 & XSTATE_BNDCSR_MASK) {
1532 goto do_gpf;
1533 }
1534
1535 env->xcr0 = mask;
1536 cpu_sync_bndcs_hflags(env);
1537 return;
1538
1539 do_gpf:
1540 raise_exception_ra(env, EXCP0D_GPF, GETPC());
1541}
1542
1543
1544
1545
1546#define SSE_DAZ 0x0040
1547#define SSE_RC_MASK 0x6000
1548#define SSE_RC_NEAR 0x0000
1549#define SSE_RC_DOWN 0x2000
1550#define SSE_RC_UP 0x4000
1551#define SSE_RC_CHOP 0x6000
1552#define SSE_FZ 0x8000
1553
1554void update_mxcsr_status(CPUX86State *env)
1555{
1556 uint32_t mxcsr = env->mxcsr;
1557 int rnd_type;
1558
1559
1560 switch (mxcsr & SSE_RC_MASK) {
1561 default:
1562 case SSE_RC_NEAR:
1563 rnd_type = float_round_nearest_even;
1564 break;
1565 case SSE_RC_DOWN:
1566 rnd_type = float_round_down;
1567 break;
1568 case SSE_RC_UP:
1569 rnd_type = float_round_up;
1570 break;
1571 case SSE_RC_CHOP:
1572 rnd_type = float_round_to_zero;
1573 break;
1574 }
1575 set_float_rounding_mode(rnd_type, &env->sse_status);
1576
1577
1578 set_flush_inputs_to_zero((mxcsr & SSE_DAZ) ? 1 : 0, &env->sse_status);
1579
1580
1581 set_flush_to_zero((mxcsr & SSE_FZ) ? 1 : 0, &env->fp_status);
1582}
1583
1584void helper_ldmxcsr(CPUX86State *env, uint32_t val)
1585{
1586 cpu_set_mxcsr(env, val);
1587}
1588
1589void helper_enter_mmx(CPUX86State *env)
1590{
1591 env->fpstt = 0;
1592 *(uint32_t *)(env->fptags) = 0;
1593 *(uint32_t *)(env->fptags + 4) = 0;
1594}
1595
1596void helper_emms(CPUX86State *env)
1597{
1598
1599 *(uint32_t *)(env->fptags) = 0x01010101;
1600 *(uint32_t *)(env->fptags + 4) = 0x01010101;
1601}
1602
1603
1604void helper_movq(CPUX86State *env, void *d, void *s)
1605{
1606 *(uint64_t *)d = *(uint64_t *)s;
1607}
1608
1609#define SHIFT 0
1610#include "ops_sse.h"
1611
1612#define SHIFT 1
1613#include "ops_sse.h"
1614