blob: 300702916e6fd6651145acc5486b256bba93a1f2 [file] [log] [blame]
sewardj9d12c432004-09-02 12:24:06 +00001
2/*--------------------------------------------------------------------*/
3/*--- Implementation of the floating point instruction set. ---*/
4/*--- hd_fpu.c ---*/
5/*--------------------------------------------------------------------*/
6
7/*
8 This file is part of Heimdall, an x86 protected-mode emulator
9 designed for debugging and profiling binaries on x86-Unixes.
10
11 Copyright (C) 2000 Julian Seward
12 jseward@acm.org
13 Julian_Seward@muraroa.demon.co.uk
14
15 This program is free software; you can redistribute it and/or
16 modify it under the terms of the GNU General Public License as
17 published by the Free Software Foundation; either version 2 of the
18 License, or (at your option) any later version.
19
20 This program is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 General Public License for more details.
24
25 You should have received a copy of the GNU General Public License
26 along with this program; if not, write to the Free Software
27 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
28 02111-1307, USA.
29
30 The GNU General Public License is contained in the file LICENSE.
31*/
32
33#include "hd_include.h"
34
35
36/* ---------------------------------------------------------------------
37 Packing and unpacking the FPU data registers.
38 ------------------------------------------------------------------ */
39
40INLINE
41UInt fp_get_tos ( void )
42{
43 return (m_fpu_state.env[FP_ENV_STAT] >> FP_F_TOS_LO) & 7;
44}
45
46static
47UInt read_bit_array ( UChar* arr, UInt n )
48{
49 UChar c = arr[n >> 3];
50 c >>= (n&7);
51 return c & 1;
52}
53
54static
55void write_bit_array ( UChar* arr, UInt n, UInt b )
56{
57 UChar c = arr[n >> 3];
58 c &= ~(1 << (n&7));
59 b &= 1;
60 c |= (b << (n&7));
61 arr[n >> 3] = c;
62}
63
64/* Read an IEEE double from the memory image of an Intel 80-bit
65 extended floating-point number.
66*/
67static
68double fp_double_from_extended ( UChar* e_lsb )
69{
70 int i;
71 double d;
72 UChar* d_lsb = (UChar*)(&d);
73
74 UInt sign = e_lsb[9] >> 7;
75 Int bexp = ((UInt)e_lsb[9] << 8) | (UInt)e_lsb[8];
76 bexp &= 0x7fff;
77
78 if (bexp == 0)
79 bexp = 0; /* preserve zeroes */
80 else
81 if (bexp == 0x7FFF)
82 bexp = 0x7FF; /* preserve Infs/Nans */
83 else {
84 bexp -= (16383 - 1023);
85 if (bexp < 0) bexp = 0;
86 if (bexp > 0x7FF) bexp = 0x7FF;
87 }
88
89 d_lsb[6] = (bexp & 0xF) << 4;
90 d_lsb[7] = ((bexp >> 4) & 0x7F) | ((sign & 0x1) << 7);
91
92 for (i = 0; i < 52; i++)
93 write_bit_array ( d_lsb,
94 i,
95 read_bit_array ( e_lsb, i+11 ) );
96 return d;
97}
98
99/* Given an IEEE double, create the memory image of an Intel 80-bit
100 extended floating-point number.
101*/
102static
103void fp_extended_from_double ( UChar* e_lsb, double d )
104{
105 int i;
106 UChar* d_lsb = (UChar*)(&d);
107
108 UInt sign = d_lsb[7] >> 7;
109 Int bexp = ((UInt)d_lsb[7] << 4) |
110 ((((UInt)d_lsb[6]) >> 4) & 0xF);
111 bexp &= 0x7ff;
112
113 if (bexp == 0)
114 bexp = 0; /* preserve zeroes */
115 else
116 if (bexp == 0x7FF)
117 bexp = 0x7FFF; /* preserve Infs/Nans */
118 else
119 bexp += (16383 - 1023);
120
121 e_lsb[9] = ((bexp >> 8) & 0x7F) | ((sign & 0x1) << 7);
122 e_lsb[8] = bexp & 0xFF;
123
124 for (i = 0; i < 52; i++)
125 write_bit_array ( e_lsb,
126 i+11,
127 read_bit_array ( d_lsb, i ) );
128 for (i = 0; i < 11; i++)
129 write_bit_array ( e_lsb, i, 0 );
130
131 /* this isn't really right, but I can't get fpclassify to work. */
132 i = 0;
133 if (isnan(d) || isinf(d) || d != 0.0) i = 1;
134 write_bit_array ( e_lsb, 63, i );
135}
136
137/* For the transition Real CPU -> Simulated CPU, copy the
138 .reg values in m_fpu_state, which are in stack order, to
139 the m_fpu_data_regs array, in register (non-stack) order.
140*/
141void fp_unpack_data_regs ( void )
142{
143 Int reg, st;
144 reg = fp_get_tos();
145 for (st = 0; st < 8; st++) {
146 m_fpu_data_regs[reg]
147 = fp_double_from_extended ( &m_fpu_state.reg[FP_REG(st)] );
148 if (reg == 7) reg = 0; else reg++;
149 }
150}
151
152void fp_repack_data_regs ( void )
153{
154 Int reg, st;
155 st = fp_get_tos();
156 for (reg = 0; reg < 8; reg++) {
157 fp_extended_from_double ( &m_fpu_state.reg[FP_REG(reg)],
158 m_fpu_data_regs[st] );
159 if (st == 7) st = 0; else st++;
160 }
161}
162
163/* ---------------------------------------------------------------------
164 Helper functions for the floating point unit.
165 ------------------------------------------------------------------ */
166
167static
168INLINE
169void setFMem ( UInt addr, double f )
170{
171 * ((float*)addr) = (float)f;
172}
173
174static
175INLINE
176double getFMem ( UInt addr )
177{
178 return (double) (* ((float*)addr));
179}
180
181static
182INLINE
183void setDMem ( UInt addr, double f )
184{
185 * ((double*)addr) = f;
186}
187
188static
189INLINE
190double getDMem ( UInt addr )
191{
192 return (* ((double*)addr));
193}
194
195static
196INLINE
197void setTMem ( UInt addr, double f )
198{
199 fp_extended_from_double ( (Addr)addr, f );
200}
201
202static
203INLINE
204double getTMem ( UInt addr )
205{
206 return fp_double_from_extended ( (Addr)addr );
207}
208
209#define fp_extended_from_double ERROR__fp_extended_from_double_used
210#define fp_double_from_extended ERROR__fp_double_from_extended_used
211
212static
213INLINE
214UInt fp_get_statusword_flag ( UInt flagno )
215{
216 if (flagno < 0 || flagno > 15) panic("fp_get_statusword_flag");
217 return (m_fpu_state.env[FP_ENV_STAT] >> flagno) & 0x1;
218}
219
220#if DEBUG
221static
222UInt fp_get_controlword_flag ( UInt flagno )
223{
224 if (flagno < 0 || flagno > 15) panic("fp_get_controlword_flag");
225 return (m_fpu_state.env[FP_ENV_CTRL] >> flagno) & 0x1;
226}
227#endif
228
229static
230INLINE
231void fp_set_statusword_flag_to ( UInt flagno, UInt bit )
232{
233 if (flagno < 0 || flagno > 15) panic("fp_set_statusword_flag_to");
234 if (bit)
235 m_fpu_state.env[FP_ENV_STAT] |= (1 << flagno);
236 else
237 m_fpu_state.env[FP_ENV_STAT] &= ~(1 << flagno);
238}
239
240static
241void fp_set_stack_overflow ( void )
242{
243 fprintf(stderr, "--- FP STACK OVERFLOW!\n" );
244 fp_set_statusword_flag_to(FP_E_INVAL,1);
245 fp_set_statusword_flag_to(FP_E_STACKF,1);
246 fp_set_statusword_flag_to(FP_F_C1,1);
247}
248
249static
250void fp_set_stack_underflow ( void )
251{
252 fprintf(stderr, "--- FP STACK UNDERFLOW!\n" );
253 fp_set_statusword_flag_to(FP_E_INVAL,1);
254 fp_set_statusword_flag_to(FP_E_STACKF,1);
255 fp_set_statusword_flag_to(FP_F_C1,0);
256}
257
258static
259INLINE
260void fp_set_tos ( UInt tos )
261{
262 if (tos < 0 || tos > 7) panic("fp_set_tos");
263 fp_set_statusword_flag_to(FP_F_TOS_LO,0);
264 fp_set_statusword_flag_to(FP_F_TOS_LO+1,0);
265 fp_set_statusword_flag_to(FP_F_TOS_HI,0);
266 m_fpu_state.env[FP_ENV_STAT] |= (tos << FP_F_TOS_LO);
267}
268
269static
270INLINE
271UInt fp_STno_to_regno ( UInt stregno )
272{
273 UInt regno = fp_get_tos();
274 assert(regno >= 0 && regno < 8);
275 regno += stregno;
276 if (regno >= 8) regno -= 8;
277 assert(regno >= 0 && regno < 8);
278 return regno;
279}
280
281static
282INLINE
283void fp_dec_tos ( void )
284{
285 fp_set_tos ( fp_STno_to_regno ( 7 ));
286}
287
288static
289INLINE
290void fp_inc_tos ( void )
291{
292 fp_set_tos ( fp_STno_to_regno ( 1 ));
293}
294
295static
296INLINE
297Bool fp_is_empty_tag ( UInt tag )
298{
299 return tag == FP_TAG_EMPTY;
300}
301
302static
303INLINE
304UInt fp_get_tag ( UInt regno )
305{
306 if (regno < 0 || regno > 7) panic("fp_get_tag");
307 return (m_fpu_state.env[FP_ENV_TAG] >> (2*regno)) & 3;
308}
309
310static
311INLINE
312UInt fp_get_tag_ST ( UInt stregno )
313{
314 if (stregno < 0 || stregno > 7) panic("fp_get_tag_ST");
315 return fp_get_tag ( fp_STno_to_regno(stregno) );
316}
317
318static
319INLINE
320void fp_set_tag ( UInt regno, UInt val )
321{
322 if (regno < 0 || regno > 7 ||
323 val < 0 || val > 3) panic("fp_get_tag");
324 m_fpu_state.env[FP_ENV_TAG] &= ~(3 << (2*regno));
325 m_fpu_state.env[FP_ENV_TAG] |= (val << (2*regno));
326}
327
328static
329INLINE
330void fp_set_tag_ST ( UInt stregno, UInt val )
331{
332 if (stregno < 0 || stregno > 7) panic("fp_set_tag_ST");
333 fp_set_tag ( fp_STno_to_regno(stregno), val );
334}
335
336
337static
338INLINE
339void fp_set_reg ( UInt r, double d )
340{
341 if (r < 0 || r > 7) panic("fp_set_reg");
342 m_fpu_data_regs[r] = d;
343 fp_set_tag ( r, d==0.0 ? FP_TAG_ZERO
344 : (finite(d) ? FP_TAG_VALID : FP_TAG_SPEC) );
345}
346
347static
348INLINE
349void fp_set_reg_ST ( UInt str, double d )
350{
351 UInt r;
352 if (str < 0 || str > 7) panic("fp_set_reg_ST");
353 r = fp_STno_to_regno(str);
354 fp_set_reg ( r, d );
355}
356
357static
358INLINE
359double fp_get_reg ( UInt r )
360{
361 double d;
362 if (r < 0 || r > 7) panic("fp_get_reg");
363 d = m_fpu_data_regs[r];
364 return d;
365}
366
367static
368INLINE
369double fp_get_reg_ST ( UInt str )
370{
371 UInt r;
372 if (str < 0 || str > 7) panic("fp_get_reg_ST");
373 r = fp_STno_to_regno(str);
374 return fp_get_reg(r);
375}
376
377static
378INLINE
379void fp_set_tos_reg ( double d )
380{
381 fp_set_reg ( fp_get_tos(), d );
382}
383
384static
385INLINE
386double fp_get_tos_reg ( void )
387{
388 return fp_get_reg ( fp_get_tos() );
389}
390
391static
392INLINE
393void fp_set_tos_reg_QNaN ( void )
394{
395 fp_set_reg ( fp_get_tos(), NAN /* see <nan.h> */ );
396}
397
398static
399INLINE
400double fp_pop ( void )
401{
402 double d = fp_get_tos_reg();
403 fp_set_tag ( fp_get_tos(), FP_TAG_EMPTY );
404 fp_inc_tos();
405 return d;
406}
407
408/* Push d and update flags. */
409static
410INLINE
411void fp_push ( double d )
412{
413 if (fp_is_empty_tag(fp_get_tag_ST(7))) {
414 fp_dec_tos();
415 fp_set_tos_reg(d);
416 fp_set_statusword_flag_to(FP_F_C1, d == 0.0);
417 } else {
418 fp_dec_tos();
419 fp_set_tos_reg_QNaN();
420 fp_set_stack_overflow();
421 }
422}
423
424static
425void fp_set_statusword_flags_COM ( double vd_dst, double vd_src )
426{
427 UInt vis_dst;
428 if (isnan(vd_src) || isnan(vd_dst)) vis_dst = 7;
429 else if (vd_dst > vd_src) vis_dst = 0;
430 else if (vd_dst < vd_src) vis_dst = 1;
431 else if (vd_dst == vd_src) vis_dst = 4;
432 else vis_dst = 7;
433 fp_set_statusword_flag_to(FP_F_C3, (vis_dst >> 2) & 1);
434 fp_set_statusword_flag_to(FP_F_C2, (vis_dst >> 1) & 1);
435 fp_set_statusword_flag_to(FP_F_C0, vis_dst & 1);
436}
437
438static
439void fp_set_statusword_flags_COM_STACKF ( void )
440{
441 UInt vis_dst = 7;
442 fp_set_statusword_flag_to(FP_F_C3, (vis_dst >> 2) & 1);
443 fp_set_statusword_flag_to(FP_F_C2, (vis_dst >> 1) & 1);
444 fp_set_statusword_flag_to(FP_F_C0, vis_dst & 1);
445}
446
447static
448double fp_calc_yl2xp1 ( double st_0, double st_1 )
449{
450 st_0 += 1.0;
451 st_0 = log(st_0) / log(2.0);
452 st_0 *= st_1;
453 return st_0;
454}
455
456static
457double fp_calc_yl2x ( double st_0, double st_1 )
458{
459 st_0 = log(st_0) / log(2.0);
460 st_0 *= st_1;
461 return st_0;
462}
463
464static
465double fp_calc_2xm1 ( double st_0 )
466{
467 st_0 = st_0 * 0.69314718055994530942;
468 st_0 = exp(st_0);
469 st_0 = st_0 - 1.0;
470 return st_0;
471}
472
473static
474double fp_calc_scale ( double st_0, double st_1 )
475{
476 Int n = 0;
477 if (st_1 > 0.0) {
478 if (st_1 > 2.0*308.0) st_1 = 2.0*308.0;
479 n = (Int)(floor(st_1));
480 if (n < 0) n = 0; /* impossible, but ... */
481 if (n > 2*308) n = 2*308; /* limit exponent change */
482 while (n > 0) { n--; st_0 *= 2.0; };
483 }
484 else
485 if (st_1 < 0.0) {
486 if (st_1 < -2.0*308.0) st_1 = -2.0*308.0;
487 n = ((Int)(floor(-st_1)));
488 if (n < 0) n = 0;
489 if (n > 2*308) n = 2*308;
490 while (n > 0) { n--; st_0 *= 0.5; };
491 }
492 return st_0;
493}
494
495static
496void fp_calc_fprem ( Int* qq, double* result, double st_0, double st_1 )
497{
498 double tmp = st_0 / st_1;
499 if (tmp < 0)
500 *qq = - (Int)floor(-tmp);
501 else
502 *qq = (Int)floor(tmp);
503 *result = st_0 - (st_1 * (double)(*qq));
504}
505
506#if DEBUG
507static
508void printFpuState ( void )
509{
510 Int i;
511 assert(sizeof(Fpu_State)==108);
512 for (i = 7; i >= 0; i--) {
513 printf ( " %s fpreg%d: 0x",
514 (UInt)i == fp_get_tos() ? "**" : " ", i );
515 //for (j = FP_REG(i+1)-1; j >= FP_REG(i); j--)
516 // printf ( "%2x", (UInt)m_fpu_state.reg[j]);
517 printf ( " %5s ", fp_tag_names[fp_get_tag(i)] );
518 printf ( "%20.16e\n", fp_get_reg(i) );
519 }
520 printf(" fctrl: 0x%4x masked: ",
521 (UInt)m_fpu_state.env[FP_ENV_CTRL] );
522 for (i = FP_E_INVAL; i <= FP_E_LOS; i++)
523 if (fp_get_controlword_flag(i))
524 printf ( "%s ", fp_exception_names[i] );
525 printf ( "\n" );
526
527 printf(" fstat: 0x%4x except:",
528 (UInt)m_fpu_state.env[FP_ENV_STAT] );
529 for (i = FP_E_INVAL; i <= FP_E_LOS; i++)
530 if (fp_get_statusword_flag(i))
531 printf ( "%s ", fp_exception_names[i] );
532 printf ( " top: %d ", fp_get_tos() );
533 printf ( "c3210: %d%d%d%d",
534 fp_get_statusword_flag(FP_F_C3),
535 fp_get_statusword_flag(FP_F_C2),
536 fp_get_statusword_flag(FP_F_C1),
537 fp_get_statusword_flag(FP_F_C0) );
538 printf ( " STACKF: %d\n", fp_get_statusword_flag(FP_E_STACKF) );
539
540 printf(" ftag: 0x%4x ", (UInt)m_fpu_state.env[FP_ENV_TAG] );
541 for (i = 7; i >= 0; i--)
542 printf ( "%s ", fp_tag_names[fp_get_tag(i)] );
543 printf("\n");
544
545 printf(" fip: 0x%8x\n",
546 (((UInt)m_fpu_state.env[FP_ENV_IP+1]) << 16) |
547 ((UInt)m_fpu_state.env[FP_ENV_IP]) );
548 printf(" fcs: 0x%4x\n",
549 ((UInt)m_fpu_state.env[FP_ENV_CS]) );
550 printf(" fopoff: 0x%8x\n",
551 (((UInt)m_fpu_state.env[FP_ENV_OPOFF+1]) << 16) |
552 ((UInt)m_fpu_state.env[FP_ENV_OPOFF]) );
553 printf(" fopsel: 0x%4x\n",
554 ((UInt)m_fpu_state.env[FP_ENV_OPSEL]) );
555}
556#endif
557
558/* ---------------------------------------------------------------------
559 Implementation of the floating point instruction set.
560 ------------------------------------------------------------------ */
561
562/* A pretty nasty kludge. Arithmetic is done using standard IEEE
563 doubles, which means that programs which rely on the extra accuracy
564 supplied by Intel's internal 80-bit format will get different
565 results.
566
567 To make exception handling tractable, we assume that the FPU is
568 running with all exceptions masked, so we do the "default fixup"
569 action for all exceptions. Fortunately that's fairly simple.
570
571 Support for non-normal numbers (infinities, nans, denorms, etc) is
572 minimal and probably wrong.
573*/
574
575typedef
576 enum { Fp_Add, Fp_Sub, Fp_Mul, Fp_Div, Fp_SubR, Fp_DivR }
577 Fp_Op;
578
579#if DEBUG
580char* fp_Op_name ( Fp_Op op )
581{
582 switch (op) {
583 case Fp_Add: return "add"; case Fp_Sub: return "sub";
584 case Fp_Mul: return "mul"; case Fp_Div: return "div";
585 case Fp_SubR: return "subr"; case Fp_DivR: return "divr";
586 default: panic("fp_Op_name");
587 }
588 return NULL; /*notreached*/
589}
590#endif
591
592static
593void fp_do_op_ST_ST ( UInt a_src, UInt a_dst, Fp_Op op, Bool pop )
594{
595 double vd_src, vd_dst;
596 IFDB( if (dis) printf("\tf%s%s\t%%st(%d),%%st(%d)\n",
597 fp_Op_name(op), pop?"p":"",
598 a_src, a_dst ); )
599 if (!fp_is_empty_tag(fp_get_tag_ST(a_src)) &&
600 !fp_is_empty_tag(fp_get_tag_ST(a_dst))) {
601 vd_dst = fp_get_reg_ST(a_dst);
602 vd_src = fp_get_reg_ST(a_src);
603 switch (op) {
604 case Fp_Add: vd_dst = vd_dst + vd_src; break;
605 case Fp_Sub: vd_dst = vd_dst - vd_src; break;
606 case Fp_Mul: vd_dst = vd_dst * vd_src; break;
607 case Fp_Div: vd_dst = vd_dst / vd_src; break;
608 case Fp_SubR: vd_dst = vd_src - vd_dst; break;
609 case Fp_DivR: vd_dst = vd_src / vd_dst; break;
610 default: panic("fp_do_op_ST_ST");
611 }
612 } else {
613 vd_dst = NAN;
614 fp_set_stack_underflow();
615 }
616 fp_set_reg_ST(a_dst,vd_dst);
617 if (pop) (void)fp_pop();
618}
619
620static
621void fp_do_COM_ST_ST ( UInt a_src, UInt a_dst, UInt nPops )
622{
623 double vd_src, vd_dst;
624 IFDB( if (dis) printf("\tfcom%s\t%%st(%d),%%st(%d)\n",
625 nPops==0 ? "" : (nPops==1 ? "p" : "pp"),
626 a_src, a_dst ); )
627 if (!fp_is_empty_tag(fp_get_tag_ST(a_src)) &&
628 !fp_is_empty_tag(fp_get_tag_ST(a_dst))) {
629 vd_dst = fp_get_reg_ST(a_dst);
630 vd_src = fp_get_reg_ST(a_src);
631 fp_set_statusword_flags_COM(vd_dst,vd_src);
632 } else {
633 fp_set_statusword_flags_COM_STACKF();
634 fp_set_stack_underflow();
635 }
636 while (nPops > 0) {
637 (void)fp_pop();
638 nPops--;
639 }
640}
641
642static
643void fp_do_op_mem_ST_0 ( UInt a_src,
644 IFDB(Text t_src CC)
645 Fp_Op op, Bool dbl )
646{
647 double vd_src, vd_dst;
648 IFDB( if (dis) printf("\tf%s%c\t%s,%%st(0)\n",
649 fp_Op_name(op), dbl?'D':'F', t_src ); )
650 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
651 vd_dst = fp_get_reg_ST(0);
652 vd_src = dbl ? getDMem(a_src) : getFMem(a_src);
653 switch (op) {
654 case Fp_Add: vd_dst = vd_dst + vd_src; break;
655 case Fp_Sub: vd_dst = vd_dst - vd_src; break;
656 case Fp_Mul: vd_dst = vd_dst * vd_src; break;
657 case Fp_Div: vd_dst = vd_dst / vd_src; break;
658 case Fp_SubR: vd_dst = vd_src - vd_dst; break;
659 case Fp_DivR: vd_dst = vd_src / vd_dst; break;
660 default: panic("fp_do_op_mem_ST_0");
661 }
662 } else {
663 vd_dst = NAN;
664 fp_set_stack_underflow();
665 }
666 fp_set_reg_ST(0,vd_dst);
667}
668
669static
670void fp_do_COM_mem_ST_0 ( UInt a_src,
671 IFDB( Text t_src CC)
672 Bool dbl, Bool pop )
673{
674 double vd_src, vd_dst;
675 IFDB( if (dis) printf("\tfcom%s%c\t%s,%%st(0)\n",
676 pop?"p":"", dbl?'D':'F', t_src ); )
677 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
678 vd_dst = fp_get_reg_ST(0);
679 vd_src = dbl ? getDMem(a_src) : getFMem(a_src);
680 fp_set_statusword_flags_COM(vd_dst,vd_src);
681 } else {
682 fp_set_statusword_flags_COM_STACKF();
683 fp_set_stack_underflow();
684 }
685 if (pop) (void)fp_pop();
686}
687
688
689Addr do_one_insn_fp ( Addr r_eip, UChar first_opcode )
690{
691 UChar modrm;
692 UInt a_addr, a_src, a_dst;
693 UInt opc_aux;
694 Bool isreg;
695 Int vis_addr;
696 Int vis_dst;
697 double vd_addr, vd_src, vd_dst;
698
699# if DEBUG
700 Text t_opc_aux;
701 Text t_addr, t_dst;
702 Bool ppFpuState = False;
703
704 if (ppFpuState) {
705 printf("\n\nBEFORE\n");
706 printFpuState();
707 printf("\n");
708 }
709# endif
710
711 /* assert that we are running with all exceptions masked */
712 assert( (m_fpu_state.env[FP_ENV_CTRL] & 0x3F) == 0x3F );
713 /* and the implication is that there are no unmasked exceptions
714 reported by the exception status flag. */
715 assert( fp_get_statusword_flag(FP_E_SUMMARY) == 0 );
716
717 modrm = *r_eip;
718
719 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD8 opcodes +-+-+-+-+-+-+-+ */
720
721 if (first_opcode == 0xD8) {
722 if (modrm < 0xC0) {
723 /* bits 5,4,3 are an opcode extension, and the modRM also
724 specifies an address. */
725 opc_aux = regno_from_modRM ( r_eip, 4 IFDB(CC &t_opc_aux) );
726 r_eip = amode_from_modRM ( r_eip, 4, &a_addr
727 IFDB(CC &t_addr), &isreg );
728 assert(!isreg);
729 switch (opc_aux) {
730
731 case 0: /* FADD single-real */
732 fp_do_op_mem_ST_0 ( a_addr, IFDB(t_addr CC)
733 Fp_Add, False );
734 break;
735
736 case 1: /* FMUL single-real */
737 fp_do_op_mem_ST_0 ( a_addr, IFDB(t_addr CC)
738 Fp_Mul, False );
739 break;
740
741 case 2: /* FCOM single-real */
742 fp_do_COM_mem_ST_0 ( a_addr, IFDB(t_addr CC)
743 False, False );
744 break;
745
746 case 3: /* FCOMP single-real */
747 fp_do_COM_mem_ST_0 ( a_addr, IFDB(t_addr CC)
748 False, True );
749 break;
750
751 case 4: /* FSUB single-real */
752 fp_do_op_mem_ST_0 ( a_addr, IFDB(t_addr CC)
753 Fp_Sub, False );
754 break;
755
756 case 5: /* FSUBR single-real */
757 fp_do_op_mem_ST_0 ( a_addr, IFDB(t_addr CC)
758 Fp_SubR, False );
759 break;
760
761 case 6: /* FDIV single-real */
762 fp_do_op_mem_ST_0 ( a_addr, IFDB(t_addr CC)
763 Fp_Div, False );
764 break;
765
766 case 7: /* FDIVR single-real */
767 fp_do_op_mem_ST_0 ( a_addr, IFDB(t_addr CC)
768 Fp_DivR, False );
769 break;
770
771 default:
772 printf("unhandled opc_aux = 0x%2x\n", opc_aux);
773 panic("do_one_insn_fp: first_opcode == 0xD8");
774 break;
775 }
776 } else {
777 /* The entire modRM byte is an opcode extension. */
778 r_eip++;
779 switch (modrm) {
780
781 case 0xC0 ... 0xC7: /* FADD %st(?),%st(0) */
782 fp_do_op_ST_ST ( modrm - 0xC0, 0, Fp_Add, False );
783 break;
784
785 case 0xC8 ... 0xCF: /* FMUL %st(?),%st(0) */
786 fp_do_op_ST_ST ( modrm - 0xC8, 0, Fp_Mul, False );
787 break;
788
789 case 0xD0 ... 0xD7: /* FCOM %st(?),%st(0) */
790 fp_do_COM_ST_ST ( modrm - 0xD0, 0, 0 );
791 break;
792
793 case 0xD8 ... 0xDF: /* FCOMP %st(?),%st(0) */
794 fp_do_COM_ST_ST ( modrm - 0xD8, 0, 1 );
795 break;
796
797 case 0xE0 ... 0xE7: /* FSUB %st(?),%st(0) */
798 fp_do_op_ST_ST ( modrm - 0xE0, 0, Fp_Sub, False );
799 break;
800
801 case 0xE8 ... 0xEF: /* FSUBR %st(?),%st(0) */
802 fp_do_op_ST_ST ( modrm - 0xE8, 0, Fp_SubR, False );
803 break;
804
805 case 0xF0 ... 0xF7: /* FDIV %st(?),%st(0) */
806 fp_do_op_ST_ST ( modrm - 0xF0, 0, Fp_Div, False );
807 break;
808
809 case 0xF8 ... 0xFF: /* FDIVR %st(?),%st(0) */
810 fp_do_op_ST_ST ( modrm - 0xF8, 0, Fp_DivR, False );
811 break;
812
813 default:
814 goto unhandled;
815 }
816 }
817 }
818
819 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD9 opcodes +-+-+-+-+-+-+-+ */
820 else
821 if (first_opcode == 0xD9) {
822 if (modrm < 0xC0) {
823 /* bits 5,4,3 are an opcode extension, and the modRM also
824 specifies an address. */
825 opc_aux = regno_from_modRM ( r_eip, 4 IFDB(CC &t_opc_aux) );
826 r_eip = amode_from_modRM ( r_eip, 4, &a_addr
827 IFDB(CC &t_addr), &isreg );
828 assert(!isreg);
829 switch (opc_aux) {
830
831 case 0: /* FLD single-real */
832 IFDB( if (dis) printf("\tfldF\t%s\n",t_addr); )
833 vd_addr = getFMem(a_addr);
834 fp_push(vd_addr);
835 break;
836
837 case 2: /* FST single-real */
838 IFDB( if (dis) printf("\tfstF\t%s\n",t_addr); )
839 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
840 vd_addr = fp_get_reg_ST(0);
841 } else {
842 vd_addr = NAN;
843 fp_set_stack_underflow();
844 }
845 setFMem(a_addr,vd_addr);
846 break;
847
848 case 3: /* FSTP single-real */
849 IFDB( if (dis) printf("\tfstpF\t%s\n",t_addr); )
850 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
851 vd_addr = fp_pop();
852 } else {
853 vd_addr = fp_pop(); /* then throw away result */
854 vd_addr = NAN;
855 fp_set_stack_underflow();
856 }
857 setFMem(a_addr,vd_addr);
858 break;
859
860 case 5: /* FLDCW */
861 IFDB( if (dis) printf("\tfldcw\t%s\n",t_addr); )
862 m_fpu_state.env[FP_ENV_CTRL] = (UShort)getIMem2(a_addr);
863 break;
864
865 case 7: /* FNSTCW */
866 IFDB( if (dis) printf("\tfnstcw\t%s\n",t_addr); )
867 setIMem2(a_addr,(UInt)m_fpu_state.env[FP_ENV_CTRL]);
868 break;
869
870 default:
871 printf("unhandled opc_aux = 0x%2x\n", opc_aux);
872 panic("do_one_insn_fp: first_opcode == 0xD9");
873 break;
874 }
875 } else {
876 /* The entire modRM byte is an opcode extension. */
877 r_eip++;
878 switch (modrm) {
879
880 case 0xC0 ... 0xC7: /* FLD %st(?) */
881 a_dst = (UInt)modrm - 0xC0;
882 IFDB( if (dis) printf("\tfld\t%%st(%d)\n",a_dst); )
883 if (!fp_is_empty_tag(fp_get_tag_ST(a_dst)) &&
884 fp_is_empty_tag(fp_get_tag_ST(7))) {
885 vd_dst = fp_get_reg_ST(a_dst);
886 } else {
887 vd_dst = NAN;
888 fp_set_stack_underflow();
889 }
890 fp_push(vd_dst);
891 break;
892
893 case 0xC8 ... 0xCF: /* FXCH %st(?) */
894 a_dst = (UInt)modrm - 0xC8;
895 IFDB( if (dis) printf("\tfxch\t%%st(%d)\n",a_dst); )
896 if (!fp_is_empty_tag(fp_get_tag_ST(a_dst)) &&
897 !fp_is_empty_tag(fp_get_tag_ST(0))) {
898 vd_dst = fp_get_reg_ST(a_dst);
899 vd_src = fp_get_reg_ST(0);
900 } else {
901 vd_dst = NAN;
902 vd_src = NAN;
903 fp_set_stack_underflow();
904 }
905 fp_set_reg_ST(a_dst,vd_src);
906 fp_set_reg_ST(0,vd_dst);
907 break;
908
909 case 0xE0: /* FCHS */
910 IFDB( if (dis) printf("\tfchs\n"); )
911 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
912 vd_dst = - fp_get_reg_ST(0);
913 } else {
914 vd_dst = NAN;
915 fp_set_stack_underflow();
916 }
917 fp_set_reg_ST(0,vd_dst);
918 break;
919
920 case 0xE1: /* FABS */
921 IFDB( if (dis) printf("\tfabs\n"); )
922 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
923 vd_dst = fabs(fp_get_reg_ST(0));
924 } else {
925 vd_dst = NAN;
926 fp_set_stack_underflow();
927 }
928 fp_set_reg_ST(0,vd_dst);
929 break;
930
931 case 0xE5:
932 /* An approximation to the correct behaviour */
933 IFDB( if (dis) printf("\tfxam\n"); )
934 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
935 vd_dst = fabs(fp_get_reg_ST(0));
936 if (isnan(vd_dst))
937 vis_dst = 1; /* C320 = 001 */
938 else if (isinf(vd_dst))
939 vis_dst = 3; /* C320 = 011 */
940 else if (vd_dst == 0.0 || vd_dst == -0.0)
941 vis_dst = 4; /* C320 = 100 */
942 else
943 vis_dst = 2; /* C320 = 010 */
944 fp_set_statusword_flag_to(FP_F_C1,
945 vd_dst < 0.0 ? 1 : 0);
946 } else {
947 vis_dst = 5; /* C320 = 101 */
948 /* no idea if this is right */
949 fp_set_statusword_flag_to(FP_F_C1, 0);
950 }
951 fp_set_statusword_flag_to(FP_F_C3, (vis_dst >> 2) & 1);
952 fp_set_statusword_flag_to(FP_F_C2, (vis_dst >> 1) & 1);
953 fp_set_statusword_flag_to(FP_F_C0, vis_dst & 1);
954 break;
955
956 case 0xE8: /* FLD1 */
957 IFDB( t_dst = "1"; )
958 vd_dst = 1.0;
959 goto do_fld_CONST;
960 case 0xEC: /* FLDLG2 */
961 IFDB( t_dst = "lg2"; )
962 vd_dst = 0.301029995663981143;
963 goto do_fld_CONST;
964 case 0xED: /* FLDLN2 */
965 IFDB( t_dst = "ln2"; )
966 vd_dst = 0.69314718055994530942;
967 goto do_fld_CONST;
968 case 0xEE: /* FLDZ */
969 IFDB( t_dst = "z"; )
970 vd_dst = 0.0;
971 goto do_fld_CONST;
972 do_fld_CONST:
973 IFDB( if (dis) printf("\tfld%s\n",t_dst); )
974 fp_push(vd_dst);
975 break;
976
977 case 0xF0: /* F2XM1 */
978 IFDB( if (dis) printf("\tf2xm1\n"); )
979 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
980 vd_dst = fp_calc_2xm1(fp_get_reg_ST(0));
981 } else {
982 vd_dst = NAN;
983 fp_set_stack_underflow();
984 }
985 fp_set_reg_ST(0,vd_dst);
986 break;
987
988 case 0xF1: /* FYL2X */
989 IFDB( if (dis) printf("\tfyl2x\n"); )
990 if (!fp_is_empty_tag(fp_get_tag_ST(0)) &&
991 !fp_is_empty_tag(fp_get_tag_ST(1))) {
992 vd_dst = fp_calc_yl2x(
993 fp_get_reg_ST(0), fp_get_reg_ST(1));
994 } else {
995 vd_dst = NAN;
996 fp_set_stack_underflow();
997 }
998 fp_set_reg_ST(1,vd_dst);
999 (void)fp_pop();
1000 break;
1001
1002 case 0xF3: /* FPATAN */
1003 IFDB( if (dis) printf("\tfpatan\n"); )
1004 if (!fp_is_empty_tag(fp_get_tag_ST(0)) &&
1005 !fp_is_empty_tag(fp_get_tag_ST(1))) {
1006 vd_dst = atan2(
1007 fp_get_reg_ST(1), fp_get_reg_ST(0));
1008 } else {
1009 vd_dst = NAN;
1010 fp_set_stack_underflow();
1011 }
1012 fp_set_reg_ST(1,vd_dst);
1013 (void)fp_pop();
1014 break;
1015
1016 case 0xF8: { /* FPREM */
1017 /* Very incomplete implementation. */
1018 Int qq;
1019 IFDB( if (dis) printf("\tfprem\n"); )
1020 if (!fp_is_empty_tag(fp_get_tag_ST(0)) &&
1021 !fp_is_empty_tag(fp_get_tag_ST(1))) {
1022 fp_calc_fprem( &qq, &vd_dst,
1023 fp_get_reg_ST(0), fp_get_reg_ST(1) );
1024 fp_set_statusword_flag_to(FP_F_C0, (qq & 4) ? 1 : 0);
1025 fp_set_statusword_flag_to(FP_F_C1, (qq & 1) ? 1 : 0);
1026 fp_set_statusword_flag_to(FP_F_C2, 0); /* reduction complete */
1027 fp_set_statusword_flag_to(FP_F_C3, (qq & 2) ? 1 : 0);
1028 } else {
1029 vd_dst = NAN;
1030 fp_set_stack_underflow();
1031 fp_set_statusword_flag_to(FP_F_C1, 0); /* stack underflow */
1032 }
1033 fp_set_reg_ST(0,vd_dst);
1034 break;
1035 }
1036 case 0xF9: /* FYL2XP1 */
1037 IFDB( if (dis) printf("\tfyl2xp1\n"); )
1038 if (!fp_is_empty_tag(fp_get_tag_ST(0)) &&
1039 !fp_is_empty_tag(fp_get_tag_ST(1))) {
1040 vd_dst = fp_calc_yl2xp1(
1041 fp_get_reg_ST(0), fp_get_reg_ST(1));
1042 } else {
1043 vd_dst = NAN;
1044 fp_set_stack_underflow();
1045 }
1046 fp_set_reg_ST(1,vd_dst);
1047 (void)fp_pop();
1048 break;
1049
1050 case 0xFA: /* FSQRT */
1051 IFDB( if (dis) printf("\tfsqrt\n"); )
1052 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1053 vd_dst = sqrt(fp_get_reg_ST(0));
1054 } else {
1055 vd_dst = NAN;
1056 fp_set_stack_underflow();
1057 }
1058 fp_set_reg_ST(0,vd_dst);
1059 break;
1060
1061 case 0xFC: /* FRNDINT */
1062 IFDB( if (dis) printf("\tfrndint\n"); )
1063 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1064 vd_dst = rint(fp_get_reg_ST(0));
1065 } else {
1066 vd_dst = NAN;
1067 fp_set_stack_underflow();
1068 }
1069 fp_set_reg_ST(0,vd_dst);
1070 break;
1071
1072 case 0xFD: /* FSCALE */
1073 IFDB( if (dis) printf("\tfscale\n"); )
1074 if (!fp_is_empty_tag(fp_get_tag_ST(0)) &&
1075 !fp_is_empty_tag(fp_get_tag_ST(1))) {
1076 vd_dst = fp_calc_scale(
1077 fp_get_reg_ST(0), fp_get_reg_ST(1));
1078 } else {
1079 vd_dst = NAN;
1080 fp_set_stack_underflow();
1081 }
1082 fp_set_reg_ST(0,vd_dst);
1083 break;
1084
1085 case 0xFE: /* FSIN */
1086 IFDB( if (dis) printf("\tfsin\n"); )
1087 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1088 vd_dst = sin(fp_get_reg_ST(0));
1089 } else {
1090 vd_dst = NAN;
1091 fp_set_stack_underflow();
1092 }
1093 fp_set_reg_ST(0,vd_dst);
1094 break;
1095
1096 case 0xFF: /* FCOS */
1097 IFDB( if (dis) printf("\tfcos\n"); )
1098 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1099 vd_dst = cos(fp_get_reg_ST(0));
1100 } else {
1101 vd_dst = NAN;
1102 fp_set_stack_underflow();
1103 }
1104 fp_set_reg_ST(0,vd_dst);
1105 break;
1106
1107 default:
1108 goto unhandled;
1109 }
1110 }
1111 }
1112
1113 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDA opcodes +-+-+-+-+-+-+-+ */
1114 else
1115 if (first_opcode == 0xDA) {
1116 if (modrm < 0xC0) {
1117 /* bits 5,4,3 are an opcode extension, and the modRM also
1118 specifies an address. */
1119 opc_aux = regno_from_modRM ( r_eip, 4 IFDB(CC &t_opc_aux) );
1120 r_eip = amode_from_modRM ( r_eip, 4, &a_addr
1121 IFDB(CC &t_addr), &isreg );
1122 assert(!isreg);
1123 switch (opc_aux) {
1124
1125 case 0: /* FIADD m32int */
1126 IFDB( if (dis) printf("\tfiaddl\t%s\n",t_addr); )
1127 vis_addr = getIMem4(a_addr);
1128 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1129 vd_addr = fp_get_reg_ST(0) + (double)vis_addr;
1130 fp_set_reg_ST(0, vd_addr);
1131 /* we should set C1 here */
1132 } else {
1133 fp_set_reg_ST(0, NAN);
1134 fp_set_stack_underflow();
1135 }
1136 break;
1137
1138 case 1: /* FIMUL m32int */
1139 IFDB( if (dis) printf("\tfimull\t%s\n",t_addr); )
1140 vis_addr = getIMem4(a_addr);
1141 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1142 vd_addr = fp_get_reg_ST(0) * (double)vis_addr;
1143 fp_set_reg_ST(0, vd_addr);
1144 /* we should set C1 here */
1145 } else {
1146 fp_set_reg_ST(0, NAN);
1147 fp_set_stack_underflow();
1148 }
1149 break;
1150
1151 case 2: /* FICOM m32int */
1152 IFDB( if (dis) printf("\tficoml\t%s\n",t_addr); )
1153 vis_addr = getIMem4(a_addr);
1154 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1155 vd_dst = fp_get_reg_ST(0);
1156 vd_src = (double)vis_addr;
1157 fp_set_statusword_flags_COM(vd_dst,vd_src);
1158 /* we should set C1 here */
1159 } else {
1160 fp_set_statusword_flags_COM_STACKF();
1161 fp_set_stack_underflow();
1162 }
1163 break;
1164
1165 case 3: /* FICOMP m32int */
1166 IFDB( if (dis) printf("\tficompl\t%s\n",t_addr); )
1167 vis_addr = getIMem4(a_addr);
1168 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1169 vd_dst = fp_get_reg_ST(0);
1170 vd_src = (double)vis_addr;
1171 fp_set_statusword_flags_COM(vd_dst,vd_src);
1172 /* we should set C1 here */
1173 } else {
1174 fp_set_statusword_flags_COM_STACKF();
1175 fp_set_stack_underflow();
1176 }
1177 (void)fp_pop();
1178 break;
1179
1180 case 4: /* FISUB m32int */
1181 IFDB( if (dis) printf("\tfisubl\t%s\n",t_addr); )
1182 vis_addr = getIMem4(a_addr);
1183 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1184 vd_addr = fp_get_reg_ST(0) - (double)vis_addr;
1185 fp_set_reg_ST(0, vd_addr);
1186 /* we should set C1 here */
1187 } else {
1188 fp_set_reg_ST(0, NAN);
1189 fp_set_stack_underflow();
1190 }
1191 break;
1192
1193 case 5: /* FISUBR m32int */
1194 IFDB( if (dis) printf("\tfisubrl\t%s\n",t_addr); )
1195 vis_addr = getIMem4(a_addr);
1196 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1197 vd_addr = (double)vis_addr - fp_get_reg_ST(0);
1198 fp_set_reg_ST(0, vd_addr);
1199 /* we should set C1 here */
1200 } else {
1201 fp_set_reg_ST(0, NAN);
1202 fp_set_stack_underflow();
1203 }
1204 break;
1205
1206 case 6: /* FIDIV m32int */
1207 IFDB( if (dis) printf("\tfidivl\t%s\n",t_addr); )
1208 vis_addr = getIMem4(a_addr);
1209 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1210 vd_addr = fp_get_reg_ST(0) / (double)vis_addr;
1211 fp_set_reg_ST(0, vd_addr);
1212 /* we should set C1 here */
1213 } else {
1214 fp_set_reg_ST(0, NAN);
1215 fp_set_stack_underflow();
1216 }
1217 break;
1218
1219 case 7: /* FIDIVR m32int */
1220 IFDB( if (dis) printf("\tfidivl\t%s\n",t_addr); )
1221 vis_addr = getIMem4(a_addr);
1222 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1223 vd_addr = (double)vis_addr / fp_get_reg_ST(0);
1224 fp_set_reg_ST(0, vd_addr);
1225 /* we should set C1 here */
1226 } else {
1227 fp_set_reg_ST(0, NAN);
1228 fp_set_stack_underflow();
1229 }
1230 break;
1231
1232 default:
1233 printf("unhandled opc_aux = 0x%2x\n", opc_aux);
1234 panic("do_one_insn_fp: first_opcode == 0xDA");
1235 break;
1236 }
1237 } else {
1238 /* The entire modRM byte is an opcode extension. */
1239 r_eip++;
1240 switch (modrm) {
1241
1242 case 0xE9: /* FUCOMPP %st(0),%st(1) */
1243 /* seems the wrong way round. */
1244 fp_do_COM_ST_ST ( 1, 0, 2 );
1245 break;
1246
1247 default:
1248 goto unhandled;
1249 }
1250 }
1251 }
1252
1253 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDB opcodes +-+-+-+-+-+-+-+ */
1254 else
1255 if (first_opcode == 0xDB) {
1256 if (modrm < 0xC0) {
1257 /* bits 5,4,3 are an opcode extension, and the modRM also
1258 specifies an address. */
1259 opc_aux = regno_from_modRM ( r_eip, 4 IFDB(CC &t_opc_aux) );
1260 r_eip = amode_from_modRM ( r_eip, 4, &a_addr
1261 IFDB(CC &t_addr), &isreg );
1262 assert(!isreg);
1263 switch (opc_aux) {
1264
1265 case 0: /* FILD m32int */
1266 IFDB( if (dis) printf("\tfildl\t%s\n",t_addr); )
1267 vis_addr = getIMem4(a_addr);
1268 fp_push ( (double)vis_addr );
1269 break;
1270
1271 case 2: /* FIST m32 */
1272 IFDB( if (dis) printf("\tfistl\t%s\n",t_addr); )
1273 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1274 vd_addr = fp_get_reg_ST(0);
1275 if (vd_addr <= -2147483648.5 ||
1276 vd_addr >= 2147483647.5)
1277 vis_addr = 0x80000000; /* 32-bit int indefinite */
1278 else
1279 vis_addr = (Int)vd_addr;
1280 } else {
1281 vis_addr = 0x80000000; /* 32-bit indefinite */
1282 fp_set_stack_underflow();
1283 }
1284 setIMem4(a_addr,vis_addr);
1285 break;
1286
1287 case 3: /* FISTP m32 */
1288 IFDB( if (dis) printf("\tfistpl\t%s\n",t_addr); )
1289 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1290 vd_addr = fp_pop();
1291 if (vd_addr <= -2147483648.5 ||
1292 vd_addr >= 2147483647.5)
1293 vis_addr = 0x80000000; /* 32-bit int indefinite */
1294 else
1295 vis_addr = (Int)vd_addr;
1296 } else {
1297 vd_addr = fp_pop(); /* then throw away result */
1298 vis_addr = 0x80000000; /* 32-bit indefinite */
1299 fp_set_stack_underflow();
1300 }
1301 setIMem4(a_addr,vis_addr);
1302 break;
1303
1304 case 5: /* FLD extended-real */
1305 IFDB( if (dis) printf("\tfldT\t%s\n",t_addr); )
1306 vd_addr = getTMem(a_addr);
1307 fp_push(vd_addr);
1308 break;
1309
1310 case 7: /* FSTP extended-real */
1311 IFDB( if (dis) printf("\tfstpT\t%s\n",t_addr); )
1312 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1313 vd_addr = fp_pop();
1314 } else {
1315 vd_addr = fp_pop(); /* then throw away result */
1316 vd_addr = NAN;
1317 fp_set_stack_underflow();
1318 }
1319 setTMem(a_addr,vd_addr);
1320 break;
1321
1322 default:
1323 printf("unhandled opc_aux = 0x%2x\n", opc_aux);
1324 panic("do_one_insn_fp: first_opcode == 0xDB");
1325 break;
1326 }
1327 } else {
1328 /* The entire modRM byte is an opcode extension. */
1329 r_eip++;
1330 switch (modrm) {
1331 default:
1332 goto unhandled;
1333 }
1334 }
1335 }
1336
1337 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDC opcodes +-+-+-+-+-+-+-+ */
1338 else
1339 if (first_opcode == 0xDC) {
1340 if (modrm < 0xC0) {
1341 /* bits 5,4,3 are an opcode extension, and the modRM also
1342 specifies an address. */
1343 opc_aux = regno_from_modRM ( r_eip, 4 IFDB(CC &t_opc_aux) );
1344 r_eip = amode_from_modRM ( r_eip, 4, &a_addr
1345 IFDB(CC &t_addr), &isreg );
1346 assert(!isreg);
1347 switch (opc_aux) {
1348
1349 case 0: /* FADD double-real */
1350 fp_do_op_mem_ST_0 ( a_addr, IFDB(t_addr CC) Fp_Add, True );
1351 break;
1352
1353 case 1: /* FMUL double-real */
1354 fp_do_op_mem_ST_0 ( a_addr, IFDB(t_addr CC) Fp_Mul, True );
1355 break;
1356
1357 case 2: /* FCOM double-real */
1358 fp_do_COM_mem_ST_0 ( a_addr, IFDB(t_addr CC) True, False );
1359 break;
1360
1361 case 3: /* FCOMP double-real */
1362 fp_do_COM_mem_ST_0 ( a_addr, IFDB(t_addr CC) True, True );
1363 break;
1364
1365 case 4: /* FSUB double-real */
1366 fp_do_op_mem_ST_0 ( a_addr, IFDB(t_addr CC) Fp_Sub, True );
1367 break;
1368
1369 case 5: /* FSUBR double-real */
1370 fp_do_op_mem_ST_0 ( a_addr, IFDB(t_addr CC) Fp_SubR, True );
1371 break;
1372
1373 case 6: /* FDIV double-real */
1374 fp_do_op_mem_ST_0 ( a_addr, IFDB(t_addr CC) Fp_Div, True );
1375 break;
1376
1377 case 7: /* FDIVR double-real */
1378 fp_do_op_mem_ST_0 ( a_addr, IFDB(t_addr CC) Fp_DivR, True );
1379 break;
1380
1381 default:
1382 printf("unhandled opc_aux = 0x%2x\n", opc_aux);
1383 panic("do_one_insn_fp: first_opcode == 0xDC");
1384 break;
1385 }
1386 } else {
1387 /* The entire modRM byte is an opcode extension. */
1388 r_eip++;
1389 switch (modrm) {
1390
1391 case 0xC0 ... 0xC7: /* FADD %st(0),%st(?) */
1392 fp_do_op_ST_ST ( 0, modrm - 0xC0, Fp_Add, False );
1393 break;
1394
1395 case 0xC8 ... 0xCF: /* FMUL %st(0),%st(?) */
1396 fp_do_op_ST_ST ( 0, modrm - 0xC8, Fp_Mul, False );
1397 break;
1398
1399 case 0xE0 ... 0xE7: /* FSUBR %st(0),%st(?) */
1400 fp_do_op_ST_ST ( 0, modrm - 0xE0, Fp_SubR, False );
1401 break;
1402
1403 case 0xE8 ... 0xEF: /* FSUB %st(0),%st(?) */
1404 fp_do_op_ST_ST ( 0, modrm - 0xE8, Fp_Sub, False );
1405 break;
1406
1407 case 0xF8 ... 0xFF: /* FDIV %st(0),%st(?) */
1408 fp_do_op_ST_ST ( 0, modrm - 0xF8, Fp_Div, False );
1409 break;
1410
1411 default:
1412 goto unhandled;
1413 }
1414 }
1415 }
1416
1417 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDD opcodes +-+-+-+-+-+-+-+ */
1418 else
1419 if (first_opcode == 0xDD) {
1420 if (modrm < 0xC0) {
1421 /* bits 5,4,3 are an opcode extension, and the modRM also
1422 specifies an address. */
1423 opc_aux = regno_from_modRM ( r_eip, 4 IFDB(CC &t_opc_aux) );
1424 r_eip = amode_from_modRM ( r_eip, 4, &a_addr
1425 IFDB(CC &t_addr), &isreg );
1426 assert(!isreg);
1427 switch (opc_aux) {
1428
1429 case 0: /* FLD double-real */
1430 IFDB( if (dis) printf("\tfldD\t%s\n",t_addr); )
1431 vd_addr = getDMem(a_addr);
1432 fp_push(vd_addr);
1433 break;
1434
1435 case 2: /* FST double-real */
1436 IFDB( if (dis) printf("\tfstD\t%s\n",t_addr); )
1437 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1438 vd_addr = fp_get_reg_ST(0);
1439 } else {
1440 vd_addr = NAN;
1441 fp_set_stack_underflow();
1442 }
1443 setDMem(a_addr,vd_addr);
1444 break;
1445
1446 case 3: /* FSTP double-real */
1447 IFDB( if (dis) printf("\tfstpD\t%s\n",t_addr); )
1448 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1449 vd_addr = fp_pop();
1450 } else {
1451 vd_addr = fp_pop(); /* then throw away result */
1452 vd_addr = NAN;
1453 fp_set_stack_underflow();
1454 }
1455 setDMem(a_addr,vd_addr);
1456 break;
1457 default:
1458 printf("unhandled opc_aux = 0x%2x\n", opc_aux);
1459 panic("do_one_insn_fp: first_opcode == 0xDD");
1460 break;
1461 }
1462 } else {
1463 /* The entire modRM byte is an opcode extension. */
1464 r_eip++;
1465 switch (modrm) {
1466
1467 case 0xC0 ... 0xC7: /* FFREE %st(?) */
1468 a_dst = (UInt)modrm - 0xC0;
1469 IFDB( if (dis) printf("\tffree\t%%st(%d)\n", a_dst); )
1470 fp_set_tag_ST( a_dst, FP_TAG_EMPTY );
1471 break;
1472
1473 case 0xD0 ... 0xD7: /* FST %st(0),%st(?) */
1474 a_dst = (UInt)modrm - 0xD0;
1475 IFDB( if (dis) printf("\tfst\t%%st(0),%%st(%d)\n",
1476 a_dst); )
1477 if ( /* don't check the destination tag */
1478 !fp_is_empty_tag(fp_get_tag_ST(0))) {
1479 vd_dst = fp_get_reg_ST(0);
1480 } else {
1481 vd_dst = NAN;
1482 fp_set_stack_underflow();
1483 }
1484 fp_set_reg_ST(a_dst,vd_dst);
1485 break;
1486
1487 case 0xD8 ... 0xDF: /* FSTP %st(0),%st(?) */
1488 a_dst = (UInt)modrm - 0xD8;
1489 IFDB( if (dis) printf("\tfstp\t%%st(0),%%st(%d)\n",
1490 a_dst); )
1491 if ( /* don't check the destination tag */
1492 !fp_is_empty_tag(fp_get_tag_ST(0))) {
1493 vd_dst = fp_get_reg_ST(0);
1494 } else {
1495 vd_dst = NAN;
1496 fp_set_stack_underflow();
1497 }
1498 fp_set_reg_ST(a_dst,vd_dst);
1499 (void)fp_pop();
1500 break;
1501
1502 case 0xE0 ... 0xE7: /* FUCOM %st(0),%st(?) */
1503 a_src = (UInt)modrm - 0xE0;
1504 IFDB( if (dis) printf("\tfucom\t%%st(0),%%st(%d)\n",
1505 a_src); )
1506 if (!fp_is_empty_tag(fp_get_tag_ST(a_src)) &&
1507 !fp_is_empty_tag(fp_get_tag_ST(0))) {
1508 vd_src = fp_get_reg_ST(a_src);
1509 vd_dst = fp_get_reg_ST(0);
1510 fp_set_statusword_flags_COM(vd_dst,vd_src);
1511 } else {
1512 fp_set_statusword_flags_COM_STACKF();
1513 fp_set_stack_underflow();
1514 }
1515 break;
1516
1517 case 0xE8 ... 0xEF: /* FUCOMP %st(0),%st(?) */
1518 a_src = (UInt)modrm - 0xE8;
1519 IFDB( if (dis) printf("\tfucomp\t%%st(0),%%st(%d)\n",
1520 a_src); )
1521 if (!fp_is_empty_tag(fp_get_tag_ST(a_src)) &&
1522 !fp_is_empty_tag(fp_get_tag_ST(0))) {
1523 vd_src = fp_get_reg_ST(a_src);
1524 vd_dst = fp_get_reg_ST(0);
1525 fp_set_statusword_flags_COM(vd_dst,vd_src);
1526 } else {
1527 fp_set_statusword_flags_COM_STACKF();
1528 fp_set_stack_underflow();
1529 }
1530 (void)fp_pop();
1531 break;
1532
1533 default:
1534 goto unhandled;
1535 }
1536 }
1537 }
1538
1539 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDE opcodes +-+-+-+-+-+-+-+ */
1540 else
1541 if (first_opcode == 0xDE) {
1542 if (modrm < 0xC0) {
1543 /* bits 5,4,3 are an opcode extension, and the modRM also
1544 specifies an address. */
1545 opc_aux = regno_from_modRM ( r_eip, 4 IFDB(CC &t_opc_aux) );
1546 r_eip = amode_from_modRM ( r_eip, 4, &a_addr
1547 IFDB(CC &t_addr), &isreg );
1548 assert(!isreg);
1549 switch (opc_aux) {
1550 default:
1551 printf("unhandled opc_aux = 0x%2x\n", opc_aux);
1552 panic("do_one_insn_fp: first_opcode == 0xDE");
1553 break;
1554 }
1555 } else {
1556 /* The entire modRM byte is an opcode extension. */
1557 r_eip++;
1558 switch (modrm) {
1559
1560 case 0xC0 ... 0xC7: /* FADDP %st(0),%st(?) */
1561 fp_do_op_ST_ST ( 0, modrm - 0xC0, Fp_Add, True );
1562 break;
1563
1564 case 0xC8 ... 0xCF: /* FMULP %st(0),%st(?) */
1565 fp_do_op_ST_ST ( 0, modrm - 0xC8, Fp_Mul, True );
1566 break;
1567
1568 case 0xD9: /* FCOMPP %st(0),%st(1) */
1569 /* seems the wrong way round. */
1570 fp_do_COM_ST_ST ( 1, 0, 2 );
1571 break;
1572
1573 case 0xE0 ... 0xE7: /* FSUBRP %st(0),%st(?) */
1574 fp_do_op_ST_ST ( 0, modrm - 0xE0, Fp_SubR, True );
1575 break;
1576
1577 case 0xE8 ... 0xEF: /* FSUBP %st(0),%st(?) */
1578 fp_do_op_ST_ST ( 0, modrm - 0xE8, Fp_Sub, True );
1579 break;
1580
1581 case 0xF0 ... 0xF7: /* FDIVRP %st(0),%st(?) */
1582 fp_do_op_ST_ST ( 0, modrm - 0xF0, Fp_DivR, True );
1583 break;
1584
1585 case 0xF8 ... 0xFF: /* FDIVP %st(0),%st(?) */
1586 fp_do_op_ST_ST ( 0, modrm - 0xF8, Fp_Div, True );
1587 break;
1588
1589 default:
1590 goto unhandled;
1591 }
1592 }
1593 }
1594
1595 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDF opcodes +-+-+-+-+-+-+-+ */
1596 else
1597 if (first_opcode == 0xDF) {
1598 if (modrm < 0xC0) {
1599 /* bits 5,4,3 are an opcode extension, and the modRM also
1600 specifies an address. */
1601 opc_aux = regno_from_modRM ( r_eip, 4 IFDB(CC &t_opc_aux) );
1602 r_eip = amode_from_modRM ( r_eip, 4, &a_addr
1603 IFDB(CC &t_addr), &isreg );
1604 assert(!isreg);
1605 switch (opc_aux) {
1606
1607 case 0: /* FILD m16int */
1608 IFDB( if (dis) printf("\tfildw\t%s\n",t_addr); )
1609 vis_addr = extend_s_16to32(getIMem2(a_addr));
1610 fp_push ( (double) vis_addr );
1611 break;
1612
1613 case 3: /* FISTP m16 */
1614 IFDB( if (dis) printf("\tfistpw\t%s\n",t_addr); )
1615 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1616 vd_addr = fp_pop();
1617 if (vd_addr <= -32768.50 ||
1618 vd_addr >= 32767.50)
1619 vis_addr = 0x00008000; /* 16-bit int indefinite */
1620 else
1621 vis_addr = (Short)vd_addr;
1622 } else {
1623 vd_addr = fp_pop(); /* then throw away result */
1624 vis_addr = 0x00008000; /* 32-bit indefinite */
1625 fp_set_stack_underflow();
1626 }
1627 setIMem2(a_addr,vis_addr);
1628 break;
1629
1630 case 5: { /* FILD m64int */
1631 ULong vis_addr64;
1632 IFDB( if (dis) printf("\tfildq\t%s\n",t_addr); )
1633 vis_addr = getIMem4(a_addr+4);
1634 vis_addr64 = ((ULong)vis_addr) << 32;
1635 vis_addr = getIMem4(a_addr);
1636 vis_addr64 += (ULong)vis_addr;
1637 fp_push ( (double) ((Long)vis_addr64) );
1638 break;
1639 }
1640
1641 case 7: { /* FISTP m64int */
1642 ULong vis_addr64;
1643 IFDB( if (dis) printf("\tfistpq\t%s\n",t_addr); )
1644 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1645 vd_addr = fp_pop();
1646 if (vd_addr <= -9223372036854775808.5 ||
1647 vd_addr >= 9223372036854775807.5)
1648 vis_addr64 = 0x8000000000000000LL;
1649 /* 64-bit int indefinite */
1650 else
1651 vis_addr64 = (Long)vd_addr;
1652 } else {
1653 vd_addr = fp_pop(); /* then throw away result */
1654 vis_addr64 = 0x8000000000000000LL; /* 64-bit indefinite */
1655 fp_set_stack_underflow();
1656 }
1657 setIMem4(a_addr,vis_addr64 & 0xFFFFFFFFLL);
1658 setIMem4(a_addr+4, (((Long)vis_addr64) >> 32)
1659 & 0xFFFFFFFFLL);
1660 break;
1661 }
1662
1663 default:
1664 printf("unhandled opc_aux = 0x%2x\n", opc_aux);
1665 panic("do_one_insn_fp: first_opcode == 0xDF");
1666 break;
1667 }
1668 } else {
1669 /* The entire modRM byte is an opcode extension. */
1670 r_eip++;
1671 switch (modrm) {
1672
1673 case 0xE0: /* FNSTSW %ax */
1674 IFDB( if (dis) printf("\tfnstsw\t%%ax\n"); )
1675 setIReg2(R_EAX, (UInt)m_fpu_state.env[FP_ENV_STAT]);
1676 break;
1677
1678 default:
1679 goto unhandled;
1680 }
1681 }
1682 }
1683
1684 /* -+-+-+-+-+-+-+-+-+-+-+-+ Unhandled ESC opcode +-+-+-+ */
1685 else goto unhandled;
1686
1687# if DEBUG
1688 if (ppFpuState) {
1689 printf("\nAFTER\n");
1690 printFpuState();
1691 printf("\n");
1692 }
1693# endif
1694
1695 return r_eip;
1696
1697 unhandled:
1698 hd_message(Hd_DebugMsg,
1699 "first opcode = 0x%x, modRM = 0x%x",
1700 (UInt)first_opcode, (UInt)modrm );
1701 panic("do_one_insn_fp: unhandled first_opcode/modrm combination");
1702 assert(0);
1703}
1704
1705/*--------------------------------------------------------------------*/
1706/*--- end hd_fpu.c ---*/
1707/*--------------------------------------------------------------------*/