1
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/*--------------------------------------------------------------------*/
1708