blob: 29a8fb68f8930cf4879e3e1ea8b4802fed519005 [file] [log] [blame]
Blue Swirlf299f432012-04-28 20:21:41 +00001/*
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"
Blue Swirlf299f432012-04-28 20:21:41 +000022#include "helper.h"
Aurelien Jarnoc334a382013-03-26 19:56:02 +010023#include "qemu/host-utils.h"
Blue Swirlf299f432012-04-28 20:21:41 +000024
Blue Swirl92fc4b52012-04-29 20:35:48 +000025#if !defined(CONFIG_USER_ONLY)
Paolo Bonzini022c62c2012-12-17 18:19:49 +010026#include "exec/softmmu_exec.h"
Blue Swirl92fc4b52012-04-29 20:35:48 +000027#endif /* !defined(CONFIG_USER_ONLY) */
28
Blue Swirlf299f432012-04-28 20:21:41 +000029#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/* the following deal with x86 long double-precision numbers */
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
Blue Swirld3eb5ea2012-04-28 21:28:09 +000061static inline void fpush(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +000062{
63 env->fpstt = (env->fpstt - 1) & 7;
64 env->fptags[env->fpstt] = 0; /* validate stack entry */
65}
66
Blue Swirld3eb5ea2012-04-28 21:28:09 +000067static inline void fpop(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +000068{
69 env->fptags[env->fpstt] = 1; /* invalidate stack entry */
70 env->fpstt = (env->fpstt + 1) & 7;
71}
72
Blue Swirld3eb5ea2012-04-28 21:28:09 +000073static inline floatx80 helper_fldt(CPUX86State *env, target_ulong ptr)
Blue Swirlf299f432012-04-28 20:21:41 +000074{
75 CPU_LDoubleU temp;
76
Blue Swirld3eb5ea2012-04-28 21:28:09 +000077 temp.l.lower = cpu_ldq_data(env, ptr);
78 temp.l.upper = cpu_lduw_data(env, ptr + 8);
Blue Swirlf299f432012-04-28 20:21:41 +000079 return temp.d;
80}
81
Blue Swirld3eb5ea2012-04-28 21:28:09 +000082static inline void helper_fstt(CPUX86State *env, floatx80 f, target_ulong ptr)
Blue Swirlf299f432012-04-28 20:21:41 +000083{
84 CPU_LDoubleU temp;
85
86 temp.d = f;
Blue Swirld3eb5ea2012-04-28 21:28:09 +000087 cpu_stq_data(env, ptr, temp.l.lower);
88 cpu_stw_data(env, ptr + 8, temp.l.upper);
Blue Swirlf299f432012-04-28 20:21:41 +000089}
90
91/* x87 FPU helpers */
92
Blue Swirld3eb5ea2012-04-28 21:28:09 +000093static inline double floatx80_to_double(CPUX86State *env, floatx80 a)
Blue Swirlf299f432012-04-28 20:21:41 +000094{
95 union {
96 float64 f64;
97 double d;
98 } u;
99
100 u.f64 = floatx80_to_float64(a, &env->fp_status);
101 return u.d;
102}
103
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000104static inline floatx80 double_to_floatx80(CPUX86State *env, double a)
Blue Swirlf299f432012-04-28 20:21:41 +0000105{
106 union {
107 float64 f64;
108 double d;
109 } u;
110
111 u.d = a;
112 return float64_to_floatx80(u.f64, &env->fp_status);
113}
114
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000115static void fpu_set_exception(CPUX86State *env, int mask)
Blue Swirlf299f432012-04-28 20:21:41 +0000116{
117 env->fpus |= mask;
118 if (env->fpus & (~env->fpuc & FPUC_EM)) {
119 env->fpus |= FPUS_SE | FPUS_B;
120 }
121}
122
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000123static inline floatx80 helper_fdiv(CPUX86State *env, floatx80 a, floatx80 b)
Blue Swirlf299f432012-04-28 20:21:41 +0000124{
125 if (floatx80_is_zero(b)) {
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000126 fpu_set_exception(env, FPUS_ZE);
Blue Swirlf299f432012-04-28 20:21:41 +0000127 }
128 return floatx80_div(a, b, &env->fp_status);
129}
130
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000131static void fpu_raise_exception(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000132{
133 if (env->cr[0] & CR0_NE_MASK) {
134 raise_exception(env, EXCP10_COPR);
135 }
136#if !defined(CONFIG_USER_ONLY)
137 else {
138 cpu_set_ferr(env);
139 }
140#endif
141}
142
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000143void helper_flds_FT0(CPUX86State *env, uint32_t val)
Blue Swirlf299f432012-04-28 20:21:41 +0000144{
145 union {
146 float32 f;
147 uint32_t i;
148 } u;
149
150 u.i = val;
151 FT0 = float32_to_floatx80(u.f, &env->fp_status);
152}
153
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000154void helper_fldl_FT0(CPUX86State *env, uint64_t val)
Blue Swirlf299f432012-04-28 20:21:41 +0000155{
156 union {
157 float64 f;
158 uint64_t i;
159 } u;
160
161 u.i = val;
162 FT0 = float64_to_floatx80(u.f, &env->fp_status);
163}
164
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000165void helper_fildl_FT0(CPUX86State *env, int32_t val)
Blue Swirlf299f432012-04-28 20:21:41 +0000166{
167 FT0 = int32_to_floatx80(val, &env->fp_status);
168}
169
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000170void helper_flds_ST0(CPUX86State *env, uint32_t val)
Blue Swirlf299f432012-04-28 20:21:41 +0000171{
172 int new_fpstt;
173 union {
174 float32 f;
175 uint32_t i;
176 } u;
177
178 new_fpstt = (env->fpstt - 1) & 7;
179 u.i = val;
180 env->fpregs[new_fpstt].d = float32_to_floatx80(u.f, &env->fp_status);
181 env->fpstt = new_fpstt;
182 env->fptags[new_fpstt] = 0; /* validate stack entry */
183}
184
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000185void helper_fldl_ST0(CPUX86State *env, uint64_t val)
Blue Swirlf299f432012-04-28 20:21:41 +0000186{
187 int new_fpstt;
188 union {
189 float64 f;
190 uint64_t i;
191 } u;
192
193 new_fpstt = (env->fpstt - 1) & 7;
194 u.i = val;
195 env->fpregs[new_fpstt].d = float64_to_floatx80(u.f, &env->fp_status);
196 env->fpstt = new_fpstt;
197 env->fptags[new_fpstt] = 0; /* validate stack entry */
198}
199
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000200void helper_fildl_ST0(CPUX86State *env, int32_t val)
Blue Swirlf299f432012-04-28 20:21:41 +0000201{
202 int new_fpstt;
203
204 new_fpstt = (env->fpstt - 1) & 7;
205 env->fpregs[new_fpstt].d = int32_to_floatx80(val, &env->fp_status);
206 env->fpstt = new_fpstt;
207 env->fptags[new_fpstt] = 0; /* validate stack entry */
208}
209
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000210void helper_fildll_ST0(CPUX86State *env, int64_t val)
Blue Swirlf299f432012-04-28 20:21:41 +0000211{
212 int new_fpstt;
213
214 new_fpstt = (env->fpstt - 1) & 7;
215 env->fpregs[new_fpstt].d = int64_to_floatx80(val, &env->fp_status);
216 env->fpstt = new_fpstt;
217 env->fptags[new_fpstt] = 0; /* validate stack entry */
218}
219
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000220uint32_t helper_fsts_ST0(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000221{
222 union {
223 float32 f;
224 uint32_t i;
225 } u;
226
227 u.f = floatx80_to_float32(ST0, &env->fp_status);
228 return u.i;
229}
230
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000231uint64_t helper_fstl_ST0(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000232{
233 union {
234 float64 f;
235 uint64_t i;
236 } u;
237
238 u.f = floatx80_to_float64(ST0, &env->fp_status);
239 return u.i;
240}
241
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000242int32_t helper_fist_ST0(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000243{
244 int32_t val;
245
246 val = floatx80_to_int32(ST0, &env->fp_status);
247 if (val != (int16_t)val) {
248 val = -32768;
249 }
250 return val;
251}
252
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000253int32_t helper_fistl_ST0(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000254{
255 int32_t val;
256
257 val = floatx80_to_int32(ST0, &env->fp_status);
258 return val;
259}
260
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000261int64_t helper_fistll_ST0(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000262{
263 int64_t val;
264
265 val = floatx80_to_int64(ST0, &env->fp_status);
266 return val;
267}
268
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000269int32_t helper_fistt_ST0(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000270{
271 int32_t val;
272
273 val = floatx80_to_int32_round_to_zero(ST0, &env->fp_status);
274 if (val != (int16_t)val) {
275 val = -32768;
276 }
277 return val;
278}
279
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000280int32_t helper_fisttl_ST0(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000281{
282 int32_t val;
283
284 val = floatx80_to_int32_round_to_zero(ST0, &env->fp_status);
285 return val;
286}
287
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000288int64_t helper_fisttll_ST0(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000289{
290 int64_t val;
291
292 val = floatx80_to_int64_round_to_zero(ST0, &env->fp_status);
293 return val;
294}
295
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000296void helper_fldt_ST0(CPUX86State *env, target_ulong ptr)
Blue Swirlf299f432012-04-28 20:21:41 +0000297{
298 int new_fpstt;
299
300 new_fpstt = (env->fpstt - 1) & 7;
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000301 env->fpregs[new_fpstt].d = helper_fldt(env, ptr);
Blue Swirlf299f432012-04-28 20:21:41 +0000302 env->fpstt = new_fpstt;
303 env->fptags[new_fpstt] = 0; /* validate stack entry */
304}
305
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000306void helper_fstt_ST0(CPUX86State *env, target_ulong ptr)
Blue Swirlf299f432012-04-28 20:21:41 +0000307{
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000308 helper_fstt(env, ST0, ptr);
Blue Swirlf299f432012-04-28 20:21:41 +0000309}
310
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000311void helper_fpush(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000312{
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000313 fpush(env);
Blue Swirlf299f432012-04-28 20:21:41 +0000314}
315
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000316void helper_fpop(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000317{
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000318 fpop(env);
Blue Swirlf299f432012-04-28 20:21:41 +0000319}
320
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000321void helper_fdecstp(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000322{
323 env->fpstt = (env->fpstt - 1) & 7;
324 env->fpus &= ~0x4700;
325}
326
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000327void helper_fincstp(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000328{
329 env->fpstt = (env->fpstt + 1) & 7;
330 env->fpus &= ~0x4700;
331}
332
333/* FPU move */
334
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000335void helper_ffree_STN(CPUX86State *env, int st_index)
Blue Swirlf299f432012-04-28 20:21:41 +0000336{
337 env->fptags[(env->fpstt + st_index) & 7] = 1;
338}
339
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000340void helper_fmov_ST0_FT0(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000341{
342 ST0 = FT0;
343}
344
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000345void helper_fmov_FT0_STN(CPUX86State *env, int st_index)
Blue Swirlf299f432012-04-28 20:21:41 +0000346{
347 FT0 = ST(st_index);
348}
349
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000350void helper_fmov_ST0_STN(CPUX86State *env, int st_index)
Blue Swirlf299f432012-04-28 20:21:41 +0000351{
352 ST0 = ST(st_index);
353}
354
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000355void helper_fmov_STN_ST0(CPUX86State *env, int st_index)
Blue Swirlf299f432012-04-28 20:21:41 +0000356{
357 ST(st_index) = ST0;
358}
359
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000360void helper_fxchg_ST0_STN(CPUX86State *env, int st_index)
Blue Swirlf299f432012-04-28 20:21:41 +0000361{
362 floatx80 tmp;
363
364 tmp = ST(st_index);
365 ST(st_index) = ST0;
366 ST0 = tmp;
367}
368
369/* FPU operations */
370
371static const int fcom_ccval[4] = {0x0100, 0x4000, 0x0000, 0x4500};
372
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000373void helper_fcom_ST0_FT0(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000374{
375 int ret;
376
377 ret = floatx80_compare(ST0, FT0, &env->fp_status);
378 env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret + 1];
379}
380
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000381void helper_fucom_ST0_FT0(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000382{
383 int ret;
384
385 ret = floatx80_compare_quiet(ST0, FT0, &env->fp_status);
386 env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret + 1];
387}
388
389static const int fcomi_ccval[4] = {CC_C, CC_Z, 0, CC_Z | CC_P | CC_C};
390
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000391void helper_fcomi_ST0_FT0(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000392{
393 int eflags;
394 int ret;
395
396 ret = floatx80_compare(ST0, FT0, &env->fp_status);
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000397 eflags = cpu_cc_compute_all(env, CC_OP);
Blue Swirlf299f432012-04-28 20:21:41 +0000398 eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1];
399 CC_SRC = eflags;
400}
401
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000402void helper_fucomi_ST0_FT0(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000403{
404 int eflags;
405 int ret;
406
407 ret = floatx80_compare_quiet(ST0, FT0, &env->fp_status);
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000408 eflags = cpu_cc_compute_all(env, CC_OP);
Blue Swirlf299f432012-04-28 20:21:41 +0000409 eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1];
410 CC_SRC = eflags;
411}
412
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000413void helper_fadd_ST0_FT0(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000414{
415 ST0 = floatx80_add(ST0, FT0, &env->fp_status);
416}
417
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000418void helper_fmul_ST0_FT0(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000419{
420 ST0 = floatx80_mul(ST0, FT0, &env->fp_status);
421}
422
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000423void helper_fsub_ST0_FT0(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000424{
425 ST0 = floatx80_sub(ST0, FT0, &env->fp_status);
426}
427
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000428void helper_fsubr_ST0_FT0(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000429{
430 ST0 = floatx80_sub(FT0, ST0, &env->fp_status);
431}
432
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000433void helper_fdiv_ST0_FT0(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000434{
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000435 ST0 = helper_fdiv(env, ST0, FT0);
Blue Swirlf299f432012-04-28 20:21:41 +0000436}
437
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000438void helper_fdivr_ST0_FT0(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000439{
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000440 ST0 = helper_fdiv(env, FT0, ST0);
Blue Swirlf299f432012-04-28 20:21:41 +0000441}
442
443/* fp operations between STN and ST0 */
444
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000445void helper_fadd_STN_ST0(CPUX86State *env, int st_index)
Blue Swirlf299f432012-04-28 20:21:41 +0000446{
447 ST(st_index) = floatx80_add(ST(st_index), ST0, &env->fp_status);
448}
449
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000450void helper_fmul_STN_ST0(CPUX86State *env, int st_index)
Blue Swirlf299f432012-04-28 20:21:41 +0000451{
452 ST(st_index) = floatx80_mul(ST(st_index), ST0, &env->fp_status);
453}
454
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000455void helper_fsub_STN_ST0(CPUX86State *env, int st_index)
Blue Swirlf299f432012-04-28 20:21:41 +0000456{
457 ST(st_index) = floatx80_sub(ST(st_index), ST0, &env->fp_status);
458}
459
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000460void helper_fsubr_STN_ST0(CPUX86State *env, int st_index)
Blue Swirlf299f432012-04-28 20:21:41 +0000461{
462 ST(st_index) = floatx80_sub(ST0, ST(st_index), &env->fp_status);
463}
464
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000465void helper_fdiv_STN_ST0(CPUX86State *env, int st_index)
Blue Swirlf299f432012-04-28 20:21:41 +0000466{
467 floatx80 *p;
468
469 p = &ST(st_index);
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000470 *p = helper_fdiv(env, *p, ST0);
Blue Swirlf299f432012-04-28 20:21:41 +0000471}
472
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000473void helper_fdivr_STN_ST0(CPUX86State *env, int st_index)
Blue Swirlf299f432012-04-28 20:21:41 +0000474{
475 floatx80 *p;
476
477 p = &ST(st_index);
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000478 *p = helper_fdiv(env, ST0, *p);
Blue Swirlf299f432012-04-28 20:21:41 +0000479}
480
481/* misc FPU operations */
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000482void helper_fchs_ST0(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000483{
484 ST0 = floatx80_chs(ST0);
485}
486
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000487void helper_fabs_ST0(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000488{
489 ST0 = floatx80_abs(ST0);
490}
491
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000492void helper_fld1_ST0(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000493{
494 ST0 = floatx80_one;
495}
496
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000497void helper_fldl2t_ST0(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000498{
499 ST0 = floatx80_l2t;
500}
501
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000502void helper_fldl2e_ST0(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000503{
504 ST0 = floatx80_l2e;
505}
506
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000507void helper_fldpi_ST0(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000508{
509 ST0 = floatx80_pi;
510}
511
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000512void helper_fldlg2_ST0(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000513{
514 ST0 = floatx80_lg2;
515}
516
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000517void helper_fldln2_ST0(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000518{
519 ST0 = floatx80_ln2;
520}
521
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000522void helper_fldz_ST0(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000523{
524 ST0 = floatx80_zero;
525}
526
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000527void helper_fldz_FT0(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000528{
529 FT0 = floatx80_zero;
530}
531
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000532uint32_t helper_fnstsw(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000533{
534 return (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
535}
536
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000537uint32_t helper_fnstcw(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000538{
539 return env->fpuc;
540}
541
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000542static void update_fp_status(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000543{
544 int rnd_type;
545
546 /* set rounding mode */
547 switch (env->fpuc & FPU_RC_MASK) {
548 default:
549 case FPU_RC_NEAR:
550 rnd_type = float_round_nearest_even;
551 break;
552 case FPU_RC_DOWN:
553 rnd_type = float_round_down;
554 break;
555 case FPU_RC_UP:
556 rnd_type = float_round_up;
557 break;
558 case FPU_RC_CHOP:
559 rnd_type = float_round_to_zero;
560 break;
561 }
562 set_float_rounding_mode(rnd_type, &env->fp_status);
563 switch ((env->fpuc >> 8) & 3) {
564 case 0:
565 rnd_type = 32;
566 break;
567 case 2:
568 rnd_type = 64;
569 break;
570 case 3:
571 default:
572 rnd_type = 80;
573 break;
574 }
575 set_floatx80_rounding_precision(rnd_type, &env->fp_status);
576}
577
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000578void helper_fldcw(CPUX86State *env, uint32_t val)
Blue Swirlf299f432012-04-28 20:21:41 +0000579{
580 env->fpuc = val;
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000581 update_fp_status(env);
Blue Swirlf299f432012-04-28 20:21:41 +0000582}
583
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000584void helper_fclex(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000585{
586 env->fpus &= 0x7f00;
587}
588
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000589void helper_fwait(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000590{
591 if (env->fpus & FPUS_SE) {
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000592 fpu_raise_exception(env);
Blue Swirlf299f432012-04-28 20:21:41 +0000593 }
594}
595
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000596void helper_fninit(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000597{
598 env->fpus = 0;
599 env->fpstt = 0;
600 env->fpuc = 0x37f;
601 env->fptags[0] = 1;
602 env->fptags[1] = 1;
603 env->fptags[2] = 1;
604 env->fptags[3] = 1;
605 env->fptags[4] = 1;
606 env->fptags[5] = 1;
607 env->fptags[6] = 1;
608 env->fptags[7] = 1;
609}
610
611/* BCD ops */
612
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000613void helper_fbld_ST0(CPUX86State *env, target_ulong ptr)
Blue Swirlf299f432012-04-28 20:21:41 +0000614{
615 floatx80 tmp;
616 uint64_t val;
617 unsigned int v;
618 int i;
619
620 val = 0;
621 for (i = 8; i >= 0; i--) {
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000622 v = cpu_ldub_data(env, ptr + i);
Blue Swirlf299f432012-04-28 20:21:41 +0000623 val = (val * 100) + ((v >> 4) * 10) + (v & 0xf);
624 }
625 tmp = int64_to_floatx80(val, &env->fp_status);
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000626 if (cpu_ldub_data(env, ptr + 9) & 0x80) {
Blue Swirlf299f432012-04-28 20:21:41 +0000627 floatx80_chs(tmp);
628 }
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000629 fpush(env);
Blue Swirlf299f432012-04-28 20:21:41 +0000630 ST0 = tmp;
631}
632
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000633void helper_fbst_ST0(CPUX86State *env, target_ulong ptr)
Blue Swirlf299f432012-04-28 20:21:41 +0000634{
635 int v;
636 target_ulong mem_ref, mem_end;
637 int64_t val;
638
639 val = floatx80_to_int64(ST0, &env->fp_status);
640 mem_ref = ptr;
641 mem_end = mem_ref + 9;
642 if (val < 0) {
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000643 cpu_stb_data(env, mem_end, 0x80);
Blue Swirlf299f432012-04-28 20:21:41 +0000644 val = -val;
645 } else {
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000646 cpu_stb_data(env, mem_end, 0x00);
Blue Swirlf299f432012-04-28 20:21:41 +0000647 }
648 while (mem_ref < mem_end) {
649 if (val == 0) {
650 break;
651 }
652 v = val % 100;
653 val = val / 100;
654 v = ((v / 10) << 4) | (v % 10);
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000655 cpu_stb_data(env, mem_ref++, v);
Blue Swirlf299f432012-04-28 20:21:41 +0000656 }
657 while (mem_ref < mem_end) {
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000658 cpu_stb_data(env, mem_ref++, 0);
Blue Swirlf299f432012-04-28 20:21:41 +0000659 }
660}
661
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000662void helper_f2xm1(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000663{
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000664 double val = floatx80_to_double(env, ST0);
Blue Swirlf299f432012-04-28 20:21:41 +0000665
666 val = pow(2.0, val) - 1.0;
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000667 ST0 = double_to_floatx80(env, val);
Blue Swirlf299f432012-04-28 20:21:41 +0000668}
669
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000670void helper_fyl2x(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000671{
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000672 double fptemp = floatx80_to_double(env, ST0);
Blue Swirlf299f432012-04-28 20:21:41 +0000673
674 if (fptemp > 0.0) {
675 fptemp = log(fptemp) / log(2.0); /* log2(ST) */
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000676 fptemp *= floatx80_to_double(env, ST1);
677 ST1 = double_to_floatx80(env, fptemp);
678 fpop(env);
Blue Swirlf299f432012-04-28 20:21:41 +0000679 } else {
680 env->fpus &= ~0x4700;
681 env->fpus |= 0x400;
682 }
683}
684
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000685void helper_fptan(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000686{
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000687 double fptemp = floatx80_to_double(env, ST0);
Blue Swirlf299f432012-04-28 20:21:41 +0000688
689 if ((fptemp > MAXTAN) || (fptemp < -MAXTAN)) {
690 env->fpus |= 0x400;
691 } else {
692 fptemp = tan(fptemp);
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000693 ST0 = double_to_floatx80(env, fptemp);
694 fpush(env);
Blue Swirlf299f432012-04-28 20:21:41 +0000695 ST0 = floatx80_one;
696 env->fpus &= ~0x400; /* C2 <-- 0 */
697 /* the above code is for |arg| < 2**52 only */
698 }
699}
700
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000701void helper_fpatan(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000702{
703 double fptemp, fpsrcop;
704
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000705 fpsrcop = floatx80_to_double(env, ST1);
706 fptemp = floatx80_to_double(env, ST0);
707 ST1 = double_to_floatx80(env, atan2(fpsrcop, fptemp));
708 fpop(env);
Blue Swirlf299f432012-04-28 20:21:41 +0000709}
710
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000711void helper_fxtract(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000712{
713 CPU_LDoubleU temp;
714
715 temp.d = ST0;
716
717 if (floatx80_is_zero(ST0)) {
718 /* Easy way to generate -inf and raising division by 0 exception */
719 ST0 = floatx80_div(floatx80_chs(floatx80_one), floatx80_zero,
720 &env->fp_status);
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000721 fpush(env);
Blue Swirlf299f432012-04-28 20:21:41 +0000722 ST0 = temp.d;
723 } else {
724 int expdif;
725
726 expdif = EXPD(temp) - EXPBIAS;
727 /* DP exponent bias */
728 ST0 = int32_to_floatx80(expdif, &env->fp_status);
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000729 fpush(env);
Blue Swirlf299f432012-04-28 20:21:41 +0000730 BIASEXPONENT(temp);
731 ST0 = temp.d;
732 }
733}
734
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000735void helper_fprem1(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000736{
737 double st0, st1, dblq, fpsrcop, fptemp;
738 CPU_LDoubleU fpsrcop1, fptemp1;
739 int expdif;
740 signed long long int q;
741
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000742 st0 = floatx80_to_double(env, ST0);
743 st1 = floatx80_to_double(env, ST1);
Blue Swirlf299f432012-04-28 20:21:41 +0000744
745 if (isinf(st0) || isnan(st0) || isnan(st1) || (st1 == 0.0)) {
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000746 ST0 = double_to_floatx80(env, 0.0 / 0.0); /* NaN */
Blue Swirlf299f432012-04-28 20:21:41 +0000747 env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */
748 return;
749 }
750
751 fpsrcop = st0;
752 fptemp = st1;
753 fpsrcop1.d = ST0;
754 fptemp1.d = ST1;
755 expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
756
757 if (expdif < 0) {
758 /* optimisation? taken from the AMD docs */
759 env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */
760 /* ST0 is unchanged */
761 return;
762 }
763
764 if (expdif < 53) {
765 dblq = fpsrcop / fptemp;
766 /* round dblq towards nearest integer */
767 dblq = rint(dblq);
768 st0 = fpsrcop - fptemp * dblq;
769
770 /* convert dblq to q by truncating towards zero */
771 if (dblq < 0.0) {
772 q = (signed long long int)(-dblq);
773 } else {
774 q = (signed long long int)dblq;
775 }
776
777 env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */
778 /* (C0,C3,C1) <-- (q2,q1,q0) */
779 env->fpus |= (q & 0x4) << (8 - 2); /* (C0) <-- q2 */
780 env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */
781 env->fpus |= (q & 0x1) << (9 - 0); /* (C1) <-- q0 */
782 } else {
783 env->fpus |= 0x400; /* C2 <-- 1 */
784 fptemp = pow(2.0, expdif - 50);
785 fpsrcop = (st0 / st1) / fptemp;
786 /* fpsrcop = integer obtained by chopping */
787 fpsrcop = (fpsrcop < 0.0) ?
788 -(floor(fabs(fpsrcop))) : floor(fpsrcop);
789 st0 -= (st1 * fpsrcop * fptemp);
790 }
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000791 ST0 = double_to_floatx80(env, st0);
Blue Swirlf299f432012-04-28 20:21:41 +0000792}
793
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000794void helper_fprem(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000795{
796 double st0, st1, dblq, fpsrcop, fptemp;
797 CPU_LDoubleU fpsrcop1, fptemp1;
798 int expdif;
799 signed long long int q;
800
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000801 st0 = floatx80_to_double(env, ST0);
802 st1 = floatx80_to_double(env, ST1);
Blue Swirlf299f432012-04-28 20:21:41 +0000803
804 if (isinf(st0) || isnan(st0) || isnan(st1) || (st1 == 0.0)) {
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000805 ST0 = double_to_floatx80(env, 0.0 / 0.0); /* NaN */
Blue Swirlf299f432012-04-28 20:21:41 +0000806 env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */
807 return;
808 }
809
810 fpsrcop = st0;
811 fptemp = st1;
812 fpsrcop1.d = ST0;
813 fptemp1.d = ST1;
814 expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
815
816 if (expdif < 0) {
817 /* optimisation? taken from the AMD docs */
818 env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */
819 /* ST0 is unchanged */
820 return;
821 }
822
823 if (expdif < 53) {
824 dblq = fpsrcop / fptemp; /* ST0 / ST1 */
825 /* round dblq towards zero */
826 dblq = (dblq < 0.0) ? ceil(dblq) : floor(dblq);
827 st0 = fpsrcop - fptemp * dblq; /* fpsrcop is ST0 */
828
829 /* convert dblq to q by truncating towards zero */
830 if (dblq < 0.0) {
831 q = (signed long long int)(-dblq);
832 } else {
833 q = (signed long long int)dblq;
834 }
835
836 env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */
837 /* (C0,C3,C1) <-- (q2,q1,q0) */
838 env->fpus |= (q & 0x4) << (8 - 2); /* (C0) <-- q2 */
839 env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */
840 env->fpus |= (q & 0x1) << (9 - 0); /* (C1) <-- q0 */
841 } else {
842 int N = 32 + (expdif % 32); /* as per AMD docs */
843
844 env->fpus |= 0x400; /* C2 <-- 1 */
845 fptemp = pow(2.0, (double)(expdif - N));
846 fpsrcop = (st0 / st1) / fptemp;
847 /* fpsrcop = integer obtained by chopping */
848 fpsrcop = (fpsrcop < 0.0) ?
849 -(floor(fabs(fpsrcop))) : floor(fpsrcop);
850 st0 -= (st1 * fpsrcop * fptemp);
851 }
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000852 ST0 = double_to_floatx80(env, st0);
Blue Swirlf299f432012-04-28 20:21:41 +0000853}
854
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000855void helper_fyl2xp1(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000856{
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000857 double fptemp = floatx80_to_double(env, ST0);
Blue Swirlf299f432012-04-28 20:21:41 +0000858
859 if ((fptemp + 1.0) > 0.0) {
860 fptemp = log(fptemp + 1.0) / log(2.0); /* log2(ST + 1.0) */
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000861 fptemp *= floatx80_to_double(env, ST1);
862 ST1 = double_to_floatx80(env, fptemp);
863 fpop(env);
Blue Swirlf299f432012-04-28 20:21:41 +0000864 } else {
865 env->fpus &= ~0x4700;
866 env->fpus |= 0x400;
867 }
868}
869
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000870void helper_fsqrt(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000871{
872 if (floatx80_is_neg(ST0)) {
873 env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */
874 env->fpus |= 0x400;
875 }
876 ST0 = floatx80_sqrt(ST0, &env->fp_status);
877}
878
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000879void helper_fsincos(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000880{
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000881 double fptemp = floatx80_to_double(env, ST0);
Blue Swirlf299f432012-04-28 20:21:41 +0000882
883 if ((fptemp > MAXTAN) || (fptemp < -MAXTAN)) {
884 env->fpus |= 0x400;
885 } else {
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000886 ST0 = double_to_floatx80(env, sin(fptemp));
887 fpush(env);
888 ST0 = double_to_floatx80(env, cos(fptemp));
Blue Swirlf299f432012-04-28 20:21:41 +0000889 env->fpus &= ~0x400; /* C2 <-- 0 */
890 /* the above code is for |arg| < 2**63 only */
891 }
892}
893
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000894void helper_frndint(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000895{
896 ST0 = floatx80_round_to_int(ST0, &env->fp_status);
897}
898
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000899void helper_fscale(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000900{
901 if (floatx80_is_any_nan(ST1)) {
902 ST0 = ST1;
903 } else {
904 int n = floatx80_to_int32_round_to_zero(ST1, &env->fp_status);
905 ST0 = floatx80_scalbn(ST0, n, &env->fp_status);
906 }
907}
908
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000909void helper_fsin(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000910{
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000911 double fptemp = floatx80_to_double(env, ST0);
Blue Swirlf299f432012-04-28 20:21:41 +0000912
913 if ((fptemp > MAXTAN) || (fptemp < -MAXTAN)) {
914 env->fpus |= 0x400;
915 } else {
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000916 ST0 = double_to_floatx80(env, sin(fptemp));
Blue Swirlf299f432012-04-28 20:21:41 +0000917 env->fpus &= ~0x400; /* C2 <-- 0 */
918 /* the above code is for |arg| < 2**53 only */
919 }
920}
921
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000922void helper_fcos(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000923{
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000924 double fptemp = floatx80_to_double(env, ST0);
Blue Swirlf299f432012-04-28 20:21:41 +0000925
926 if ((fptemp > MAXTAN) || (fptemp < -MAXTAN)) {
927 env->fpus |= 0x400;
928 } else {
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000929 ST0 = double_to_floatx80(env, cos(fptemp));
Blue Swirlf299f432012-04-28 20:21:41 +0000930 env->fpus &= ~0x400; /* C2 <-- 0 */
931 /* the above code is for |arg| < 2**63 only */
932 }
933}
934
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000935void helper_fxam_ST0(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +0000936{
937 CPU_LDoubleU temp;
938 int expdif;
939
940 temp.d = ST0;
941
942 env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */
943 if (SIGND(temp)) {
944 env->fpus |= 0x200; /* C1 <-- 1 */
945 }
946
947 /* XXX: test fptags too */
948 expdif = EXPD(temp);
949 if (expdif == MAXEXPD) {
950 if (MANTD(temp) == 0x8000000000000000ULL) {
951 env->fpus |= 0x500; /* Infinity */
952 } else {
953 env->fpus |= 0x100; /* NaN */
954 }
955 } else if (expdif == 0) {
956 if (MANTD(temp) == 0) {
957 env->fpus |= 0x4000; /* Zero */
958 } else {
959 env->fpus |= 0x4400; /* Denormal */
960 }
961 } else {
962 env->fpus |= 0x400;
963 }
964}
965
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000966void helper_fstenv(CPUX86State *env, target_ulong ptr, int data32)
Blue Swirlf299f432012-04-28 20:21:41 +0000967{
968 int fpus, fptag, exp, i;
969 uint64_t mant;
970 CPU_LDoubleU tmp;
971
972 fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
973 fptag = 0;
974 for (i = 7; i >= 0; i--) {
975 fptag <<= 2;
976 if (env->fptags[i]) {
977 fptag |= 3;
978 } else {
979 tmp.d = env->fpregs[i].d;
980 exp = EXPD(tmp);
981 mant = MANTD(tmp);
982 if (exp == 0 && mant == 0) {
983 /* zero */
984 fptag |= 1;
985 } else if (exp == 0 || exp == MAXEXPD
986 || (mant & (1LL << 63)) == 0) {
987 /* NaNs, infinity, denormal */
988 fptag |= 2;
989 }
990 }
991 }
992 if (data32) {
993 /* 32 bit */
Blue Swirld3eb5ea2012-04-28 21:28:09 +0000994 cpu_stl_data(env, ptr, env->fpuc);
995 cpu_stl_data(env, ptr + 4, fpus);
996 cpu_stl_data(env, ptr + 8, fptag);
997 cpu_stl_data(env, ptr + 12, 0); /* fpip */
998 cpu_stl_data(env, ptr + 16, 0); /* fpcs */
999 cpu_stl_data(env, ptr + 20, 0); /* fpoo */
1000 cpu_stl_data(env, ptr + 24, 0); /* fpos */
Blue Swirlf299f432012-04-28 20:21:41 +00001001 } else {
1002 /* 16 bit */
Blue Swirld3eb5ea2012-04-28 21:28:09 +00001003 cpu_stw_data(env, ptr, env->fpuc);
1004 cpu_stw_data(env, ptr + 2, fpus);
1005 cpu_stw_data(env, ptr + 4, fptag);
1006 cpu_stw_data(env, ptr + 6, 0);
1007 cpu_stw_data(env, ptr + 8, 0);
1008 cpu_stw_data(env, ptr + 10, 0);
1009 cpu_stw_data(env, ptr + 12, 0);
Blue Swirlf299f432012-04-28 20:21:41 +00001010 }
1011}
1012
Blue Swirld3eb5ea2012-04-28 21:28:09 +00001013void helper_fldenv(CPUX86State *env, target_ulong ptr, int data32)
Blue Swirlf299f432012-04-28 20:21:41 +00001014{
1015 int i, fpus, fptag;
1016
1017 if (data32) {
Blue Swirld3eb5ea2012-04-28 21:28:09 +00001018 env->fpuc = cpu_lduw_data(env, ptr);
1019 fpus = cpu_lduw_data(env, ptr + 4);
1020 fptag = cpu_lduw_data(env, ptr + 8);
Blue Swirlf299f432012-04-28 20:21:41 +00001021 } else {
Blue Swirld3eb5ea2012-04-28 21:28:09 +00001022 env->fpuc = cpu_lduw_data(env, ptr);
1023 fpus = cpu_lduw_data(env, ptr + 2);
1024 fptag = cpu_lduw_data(env, ptr + 4);
Blue Swirlf299f432012-04-28 20:21:41 +00001025 }
1026 env->fpstt = (fpus >> 11) & 7;
1027 env->fpus = fpus & ~0x3800;
1028 for (i = 0; i < 8; i++) {
1029 env->fptags[i] = ((fptag & 3) == 3);
1030 fptag >>= 2;
1031 }
1032}
1033
Blue Swirld3eb5ea2012-04-28 21:28:09 +00001034void helper_fsave(CPUX86State *env, target_ulong ptr, int data32)
Blue Swirlf299f432012-04-28 20:21:41 +00001035{
1036 floatx80 tmp;
1037 int i;
1038
Blue Swirld3eb5ea2012-04-28 21:28:09 +00001039 helper_fstenv(env, ptr, data32);
Blue Swirlf299f432012-04-28 20:21:41 +00001040
1041 ptr += (14 << data32);
1042 for (i = 0; i < 8; i++) {
1043 tmp = ST(i);
Blue Swirld3eb5ea2012-04-28 21:28:09 +00001044 helper_fstt(env, tmp, ptr);
Blue Swirlf299f432012-04-28 20:21:41 +00001045 ptr += 10;
1046 }
1047
1048 /* fninit */
1049 env->fpus = 0;
1050 env->fpstt = 0;
1051 env->fpuc = 0x37f;
1052 env->fptags[0] = 1;
1053 env->fptags[1] = 1;
1054 env->fptags[2] = 1;
1055 env->fptags[3] = 1;
1056 env->fptags[4] = 1;
1057 env->fptags[5] = 1;
1058 env->fptags[6] = 1;
1059 env->fptags[7] = 1;
1060}
1061
Blue Swirld3eb5ea2012-04-28 21:28:09 +00001062void helper_frstor(CPUX86State *env, target_ulong ptr, int data32)
Blue Swirlf299f432012-04-28 20:21:41 +00001063{
1064 floatx80 tmp;
1065 int i;
1066
Blue Swirld3eb5ea2012-04-28 21:28:09 +00001067 helper_fldenv(env, ptr, data32);
Blue Swirlf299f432012-04-28 20:21:41 +00001068 ptr += (14 << data32);
1069
1070 for (i = 0; i < 8; i++) {
Blue Swirld3eb5ea2012-04-28 21:28:09 +00001071 tmp = helper_fldt(env, ptr);
Blue Swirlf299f432012-04-28 20:21:41 +00001072 ST(i) = tmp;
1073 ptr += 10;
1074 }
1075}
1076
1077#if defined(CONFIG_USER_ONLY)
Blue Swirld3eb5ea2012-04-28 21:28:09 +00001078void cpu_x86_fsave(CPUX86State *env, target_ulong ptr, int data32)
Blue Swirlf299f432012-04-28 20:21:41 +00001079{
Blue Swirld3eb5ea2012-04-28 21:28:09 +00001080 helper_fsave(env, ptr, data32);
Blue Swirlf299f432012-04-28 20:21:41 +00001081}
1082
Blue Swirld3eb5ea2012-04-28 21:28:09 +00001083void cpu_x86_frstor(CPUX86State *env, target_ulong ptr, int data32)
Blue Swirlf299f432012-04-28 20:21:41 +00001084{
Blue Swirld3eb5ea2012-04-28 21:28:09 +00001085 helper_frstor(env, ptr, data32);
Blue Swirlf299f432012-04-28 20:21:41 +00001086}
1087#endif
1088
Blue Swirld3eb5ea2012-04-28 21:28:09 +00001089void helper_fxsave(CPUX86State *env, target_ulong ptr, int data64)
Blue Swirlf299f432012-04-28 20:21:41 +00001090{
1091 int fpus, fptag, i, nb_xmm_regs;
1092 floatx80 tmp;
1093 target_ulong addr;
1094
1095 /* The operand must be 16 byte aligned */
1096 if (ptr & 0xf) {
1097 raise_exception(env, EXCP0D_GPF);
1098 }
1099
1100 fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
1101 fptag = 0;
1102 for (i = 0; i < 8; i++) {
1103 fptag |= (env->fptags[i] << i);
1104 }
Blue Swirld3eb5ea2012-04-28 21:28:09 +00001105 cpu_stw_data(env, ptr, env->fpuc);
1106 cpu_stw_data(env, ptr + 2, fpus);
1107 cpu_stw_data(env, ptr + 4, fptag ^ 0xff);
Blue Swirlf299f432012-04-28 20:21:41 +00001108#ifdef TARGET_X86_64
1109 if (data64) {
Blue Swirld3eb5ea2012-04-28 21:28:09 +00001110 cpu_stq_data(env, ptr + 0x08, 0); /* rip */
1111 cpu_stq_data(env, ptr + 0x10, 0); /* rdp */
Blue Swirlf299f432012-04-28 20:21:41 +00001112 } else
1113#endif
1114 {
Blue Swirld3eb5ea2012-04-28 21:28:09 +00001115 cpu_stl_data(env, ptr + 0x08, 0); /* eip */
1116 cpu_stl_data(env, ptr + 0x0c, 0); /* sel */
1117 cpu_stl_data(env, ptr + 0x10, 0); /* dp */
1118 cpu_stl_data(env, ptr + 0x14, 0); /* sel */
Blue Swirlf299f432012-04-28 20:21:41 +00001119 }
1120
1121 addr = ptr + 0x20;
1122 for (i = 0; i < 8; i++) {
1123 tmp = ST(i);
Blue Swirld3eb5ea2012-04-28 21:28:09 +00001124 helper_fstt(env, tmp, addr);
Blue Swirlf299f432012-04-28 20:21:41 +00001125 addr += 16;
1126 }
1127
1128 if (env->cr[4] & CR4_OSFXSR_MASK) {
1129 /* XXX: finish it */
Blue Swirld3eb5ea2012-04-28 21:28:09 +00001130 cpu_stl_data(env, ptr + 0x18, env->mxcsr); /* mxcsr */
1131 cpu_stl_data(env, ptr + 0x1c, 0x0000ffff); /* mxcsr_mask */
Blue Swirlf299f432012-04-28 20:21:41 +00001132 if (env->hflags & HF_CS64_MASK) {
1133 nb_xmm_regs = 16;
1134 } else {
1135 nb_xmm_regs = 8;
1136 }
1137 addr = ptr + 0xa0;
1138 /* Fast FXSAVE leaves out the XMM registers */
1139 if (!(env->efer & MSR_EFER_FFXSR)
1140 || (env->hflags & HF_CPL_MASK)
1141 || !(env->hflags & HF_LMA_MASK)) {
1142 for (i = 0; i < nb_xmm_regs; i++) {
Blue Swirld3eb5ea2012-04-28 21:28:09 +00001143 cpu_stq_data(env, addr, env->xmm_regs[i].XMM_Q(0));
1144 cpu_stq_data(env, addr + 8, env->xmm_regs[i].XMM_Q(1));
Blue Swirlf299f432012-04-28 20:21:41 +00001145 addr += 16;
1146 }
1147 }
1148 }
1149}
1150
Blue Swirld3eb5ea2012-04-28 21:28:09 +00001151void helper_fxrstor(CPUX86State *env, target_ulong ptr, int data64)
Blue Swirlf299f432012-04-28 20:21:41 +00001152{
1153 int i, fpus, fptag, nb_xmm_regs;
1154 floatx80 tmp;
1155 target_ulong addr;
1156
1157 /* The operand must be 16 byte aligned */
1158 if (ptr & 0xf) {
1159 raise_exception(env, EXCP0D_GPF);
1160 }
1161
Blue Swirld3eb5ea2012-04-28 21:28:09 +00001162 env->fpuc = cpu_lduw_data(env, ptr);
1163 fpus = cpu_lduw_data(env, ptr + 2);
1164 fptag = cpu_lduw_data(env, ptr + 4);
Blue Swirlf299f432012-04-28 20:21:41 +00001165 env->fpstt = (fpus >> 11) & 7;
1166 env->fpus = fpus & ~0x3800;
1167 fptag ^= 0xff;
1168 for (i = 0; i < 8; i++) {
1169 env->fptags[i] = ((fptag >> i) & 1);
1170 }
1171
1172 addr = ptr + 0x20;
1173 for (i = 0; i < 8; i++) {
Blue Swirld3eb5ea2012-04-28 21:28:09 +00001174 tmp = helper_fldt(env, addr);
Blue Swirlf299f432012-04-28 20:21:41 +00001175 ST(i) = tmp;
1176 addr += 16;
1177 }
1178
1179 if (env->cr[4] & CR4_OSFXSR_MASK) {
1180 /* XXX: finish it */
Blue Swirld3eb5ea2012-04-28 21:28:09 +00001181 env->mxcsr = cpu_ldl_data(env, ptr + 0x18);
1182 /* cpu_ldl_data(env, ptr + 0x1c); */
Blue Swirlf299f432012-04-28 20:21:41 +00001183 if (env->hflags & HF_CS64_MASK) {
1184 nb_xmm_regs = 16;
1185 } else {
1186 nb_xmm_regs = 8;
1187 }
1188 addr = ptr + 0xa0;
1189 /* Fast FXRESTORE leaves out the XMM registers */
1190 if (!(env->efer & MSR_EFER_FFXSR)
1191 || (env->hflags & HF_CPL_MASK)
1192 || !(env->hflags & HF_LMA_MASK)) {
1193 for (i = 0; i < nb_xmm_regs; i++) {
Blue Swirld3eb5ea2012-04-28 21:28:09 +00001194 env->xmm_regs[i].XMM_Q(0) = cpu_ldq_data(env, addr);
1195 env->xmm_regs[i].XMM_Q(1) = cpu_ldq_data(env, addr + 8);
Blue Swirlf299f432012-04-28 20:21:41 +00001196 addr += 16;
1197 }
1198 }
1199 }
1200}
1201
1202void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, floatx80 f)
1203{
1204 CPU_LDoubleU temp;
1205
1206 temp.d = f;
1207 *pmant = temp.l.lower;
1208 *pexp = temp.l.upper;
1209}
1210
1211floatx80 cpu_set_fp80(uint64_t mant, uint16_t upper)
1212{
1213 CPU_LDoubleU temp;
1214
1215 temp.l.upper = upper;
1216 temp.l.lower = mant;
1217 return temp.d;
1218}
1219
1220/* MMX/SSE */
1221/* XXX: optimize by storing fptt and fptags in the static cpu state */
1222
1223#define SSE_DAZ 0x0040
1224#define SSE_RC_MASK 0x6000
1225#define SSE_RC_NEAR 0x0000
1226#define SSE_RC_DOWN 0x2000
1227#define SSE_RC_UP 0x4000
1228#define SSE_RC_CHOP 0x6000
1229#define SSE_FZ 0x8000
1230
Blue Swirld3eb5ea2012-04-28 21:28:09 +00001231static void update_sse_status(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +00001232{
1233 int rnd_type;
1234
1235 /* set rounding mode */
1236 switch (env->mxcsr & SSE_RC_MASK) {
1237 default:
1238 case SSE_RC_NEAR:
1239 rnd_type = float_round_nearest_even;
1240 break;
1241 case SSE_RC_DOWN:
1242 rnd_type = float_round_down;
1243 break;
1244 case SSE_RC_UP:
1245 rnd_type = float_round_up;
1246 break;
1247 case SSE_RC_CHOP:
1248 rnd_type = float_round_to_zero;
1249 break;
1250 }
1251 set_float_rounding_mode(rnd_type, &env->sse_status);
1252
1253 /* set denormals are zero */
1254 set_flush_inputs_to_zero((env->mxcsr & SSE_DAZ) ? 1 : 0, &env->sse_status);
1255
1256 /* set flush to zero */
1257 set_flush_to_zero((env->mxcsr & SSE_FZ) ? 1 : 0, &env->fp_status);
1258}
1259
Blue Swirld3eb5ea2012-04-28 21:28:09 +00001260void helper_ldmxcsr(CPUX86State *env, uint32_t val)
Blue Swirlf299f432012-04-28 20:21:41 +00001261{
1262 env->mxcsr = val;
Blue Swirld3eb5ea2012-04-28 21:28:09 +00001263 update_sse_status(env);
Blue Swirlf299f432012-04-28 20:21:41 +00001264}
1265
Blue Swirld3eb5ea2012-04-28 21:28:09 +00001266void helper_enter_mmx(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +00001267{
1268 env->fpstt = 0;
1269 *(uint32_t *)(env->fptags) = 0;
1270 *(uint32_t *)(env->fptags + 4) = 0;
1271}
1272
Blue Swirld3eb5ea2012-04-28 21:28:09 +00001273void helper_emms(CPUX86State *env)
Blue Swirlf299f432012-04-28 20:21:41 +00001274{
1275 /* set to empty state */
1276 *(uint32_t *)(env->fptags) = 0x01010101;
1277 *(uint32_t *)(env->fptags + 4) = 0x01010101;
1278}
1279
1280/* XXX: suppress */
Blue Swirld3eb5ea2012-04-28 21:28:09 +00001281void helper_movq(CPUX86State *env, void *d, void *s)
Blue Swirlf299f432012-04-28 20:21:41 +00001282{
1283 *(uint64_t *)d = *(uint64_t *)s;
1284}
1285
1286#define SHIFT 0
1287#include "ops_sse.h"
1288
1289#define SHIFT 1
1290#include "ops_sse.h"