1/****************************************************************************
2*
3*						Realmode X86 Emulator Library
4*
5*            	Copyright (C) 1996-1999 SciTech Software, Inc.
6* 				     Copyright (C) David Mosberger-Tang
7* 					   Copyright (C) 1999 Egbert Eich
8*
9*  ========================================================================
10*
11*  Permission to use, copy, modify, distribute, and sell this software and
12*  its documentation for any purpose is hereby granted without fee,
13*  provided that the above copyright notice appear in all copies and that
14*  both that copyright notice and this permission notice appear in
15*  supporting documentation, and that the name of the authors not be used
16*  in advertising or publicity pertaining to distribution of the software
17*  without specific, written prior permission.  The authors makes no
18*  representations about the suitability of this software for any purpose.
19*  It is provided "as is" without express or implied warranty.
20*
21*  THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
22*  INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
23*  EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
24*  CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
25*  USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
26*  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
27*  PERFORMANCE OF THIS SOFTWARE.
28*
29*  ========================================================================
30*
31* Language:		ANSI C
32* Environment:	Any
33* Developer:    Kendall Bennett
34*
35* Description:  This file contains the code to implement the decoding and
36*               emulation of the FPU instructions.
37*
38****************************************************************************/
39
40#include "x86emu/x86emui.h"
41
42/*----------------------------- Implementation ----------------------------*/
43
44/* opcode=0xd8 */
45void
46x86emuOp_esc_coprocess_d8(u8 X86EMU_UNUSED(op1))
47{
48    START_OF_INSTR();
49    DECODE_PRINTF("ESC D8\n");
50    DECODE_CLEAR_SEGOVR();
51    END_OF_INSTR_NO_TRACE();
52}
53
54#ifdef DEBUG
55
56static const char *x86emu_fpu_op_d9_tab[] = {
57    "FLD\tDWORD PTR ", "ESC_D9\t", "FST\tDWORD PTR ", "FSTP\tDWORD PTR ",
58    "FLDENV\t", "FLDCW\t", "FSTENV\t", "FSTCW\t",
59
60    "FLD\tDWORD PTR ", "ESC_D9\t", "FST\tDWORD PTR ", "FSTP\tDWORD PTR ",
61    "FLDENV\t", "FLDCW\t", "FSTENV\t", "FSTCW\t",
62
63    "FLD\tDWORD PTR ", "ESC_D9\t", "FST\tDWORD PTR ", "FSTP\tDWORD PTR ",
64    "FLDENV\t", "FLDCW\t", "FSTENV\t", "FSTCW\t",
65};
66
67static const char *x86emu_fpu_op_d9_tab1[] = {
68    "FLD\t", "FLD\t", "FLD\t", "FLD\t",
69    "FLD\t", "FLD\t", "FLD\t", "FLD\t",
70
71    "FXCH\t", "FXCH\t", "FXCH\t", "FXCH\t",
72    "FXCH\t", "FXCH\t", "FXCH\t", "FXCH\t",
73
74    "FNOP", "ESC_D9", "ESC_D9", "ESC_D9",
75    "ESC_D9", "ESC_D9", "ESC_D9", "ESC_D9",
76
77    "FSTP\t", "FSTP\t", "FSTP\t", "FSTP\t",
78    "FSTP\t", "FSTP\t", "FSTP\t", "FSTP\t",
79
80    "FCHS", "FABS", "ESC_D9", "ESC_D9",
81    "FTST", "FXAM", "ESC_D9", "ESC_D9",
82
83    "FLD1", "FLDL2T", "FLDL2E", "FLDPI",
84    "FLDLG2", "FLDLN2", "FLDZ", "ESC_D9",
85
86    "F2XM1", "FYL2X", "FPTAN", "FPATAN",
87    "FXTRACT", "ESC_D9", "FDECSTP", "FINCSTP",
88
89    "FPREM", "FYL2XP1", "FSQRT", "ESC_D9",
90    "FRNDINT", "FSCALE", "ESC_D9", "ESC_D9",
91};
92
93#endif                          /* DEBUG */
94
95/* opcode=0xd9 */
96void
97x86emuOp_esc_coprocess_d9(u8 X86EMU_UNUSED(op1))
98{
99    int mod, rl, rh;
100    uint destoffset = 0;
101    u8 stkelem = 0;
102
103    START_OF_INSTR();
104    FETCH_DECODE_MODRM(mod, rh, rl);
105#ifdef DEBUG
106    if (mod != 3) {
107        DECODE_PRINTINSTR32(x86emu_fpu_op_d9_tab, mod, rh, rl);
108    }
109    else {
110        DECODE_PRINTF(x86emu_fpu_op_d9_tab1[(rh << 3) + rl]);
111    }
112#endif
113    switch (mod) {
114    case 0:
115        destoffset = decode_rm00_address(rl);
116        DECODE_PRINTF("\n");
117        break;
118    case 1:
119        destoffset = decode_rm01_address(rl);
120        DECODE_PRINTF("\n");
121        break;
122    case 2:
123        destoffset = decode_rm10_address(rl);
124        DECODE_PRINTF("\n");
125        break;
126    case 3:                    /* register to register */
127        stkelem = (u8) rl;
128        if (rh < 4) {
129            DECODE_PRINTF2("ST(%d)\n", stkelem);
130        }
131        else {
132            DECODE_PRINTF("\n");
133        }
134        break;
135    }
136#ifdef X86EMU_FPU_PRESENT
137    /* execute */
138    switch (mod) {
139    case 3:
140        switch (rh) {
141        case 0:
142            x86emu_fpu_R_fld(X86EMU_FPU_STKTOP, stkelem);
143            break;
144        case 1:
145            x86emu_fpu_R_fxch(X86EMU_FPU_STKTOP, stkelem);
146            break;
147        case 2:
148            switch (rl) {
149            case 0:
150                x86emu_fpu_R_nop();
151                break;
152            default:
153                x86emu_fpu_illegal();
154                break;
155            }
156        case 3:
157            x86emu_fpu_R_fstp(X86EMU_FPU_STKTOP, stkelem);
158            break;
159        case 4:
160            switch (rl) {
161            case 0:
162                x86emu_fpu_R_fchs(X86EMU_FPU_STKTOP);
163                break;
164            case 1:
165                x86emu_fpu_R_fabs(X86EMU_FPU_STKTOP);
166                break;
167            case 4:
168                x86emu_fpu_R_ftst(X86EMU_FPU_STKTOP);
169                break;
170            case 5:
171                x86emu_fpu_R_fxam(X86EMU_FPU_STKTOP);
172                break;
173            default:
174                /* 2,3,6,7 */
175                x86emu_fpu_illegal();
176                break;
177            }
178            break;
179
180        case 5:
181            switch (rl) {
182            case 0:
183                x86emu_fpu_R_fld1(X86EMU_FPU_STKTOP);
184                break;
185            case 1:
186                x86emu_fpu_R_fldl2t(X86EMU_FPU_STKTOP);
187                break;
188            case 2:
189                x86emu_fpu_R_fldl2e(X86EMU_FPU_STKTOP);
190                break;
191            case 3:
192                x86emu_fpu_R_fldpi(X86EMU_FPU_STKTOP);
193                break;
194            case 4:
195                x86emu_fpu_R_fldlg2(X86EMU_FPU_STKTOP);
196                break;
197            case 5:
198                x86emu_fpu_R_fldln2(X86EMU_FPU_STKTOP);
199                break;
200            case 6:
201                x86emu_fpu_R_fldz(X86EMU_FPU_STKTOP);
202                break;
203            default:
204                /* 7 */
205                x86emu_fpu_illegal();
206                break;
207            }
208            break;
209
210        case 6:
211            switch (rl) {
212            case 0:
213                x86emu_fpu_R_f2xm1(X86EMU_FPU_STKTOP);
214                break;
215            case 1:
216                x86emu_fpu_R_fyl2x(X86EMU_FPU_STKTOP);
217                break;
218            case 2:
219                x86emu_fpu_R_fptan(X86EMU_FPU_STKTOP);
220                break;
221            case 3:
222                x86emu_fpu_R_fpatan(X86EMU_FPU_STKTOP);
223                break;
224            case 4:
225                x86emu_fpu_R_fxtract(X86EMU_FPU_STKTOP);
226                break;
227            case 5:
228                x86emu_fpu_illegal();
229                break;
230            case 6:
231                x86emu_fpu_R_decstp();
232                break;
233            case 7:
234                x86emu_fpu_R_incstp();
235                break;
236            }
237            break;
238
239        case 7:
240            switch (rl) {
241            case 0:
242                x86emu_fpu_R_fprem(X86EMU_FPU_STKTOP);
243                break;
244            case 1:
245                x86emu_fpu_R_fyl2xp1(X86EMU_FPU_STKTOP);
246                break;
247            case 2:
248                x86emu_fpu_R_fsqrt(X86EMU_FPU_STKTOP);
249                break;
250            case 3:
251                x86emu_fpu_illegal();
252                break;
253            case 4:
254                x86emu_fpu_R_frndint(X86EMU_FPU_STKTOP);
255                break;
256            case 5:
257                x86emu_fpu_R_fscale(X86EMU_FPU_STKTOP);
258                break;
259            case 6:
260            case 7:
261            default:
262                x86emu_fpu_illegal();
263                break;
264            }
265            break;
266
267        default:
268            switch (rh) {
269            case 0:
270                x86emu_fpu_M_fld(X86EMU_FPU_FLOAT, destoffset);
271                break;
272            case 1:
273                x86emu_fpu_illegal();
274                break;
275            case 2:
276                x86emu_fpu_M_fst(X86EMU_FPU_FLOAT, destoffset);
277                break;
278            case 3:
279                x86emu_fpu_M_fstp(X86EMU_FPU_FLOAT, destoffset);
280                break;
281            case 4:
282                x86emu_fpu_M_fldenv(X86EMU_FPU_WORD, destoffset);
283                break;
284            case 5:
285                x86emu_fpu_M_fldcw(X86EMU_FPU_WORD, destoffset);
286                break;
287            case 6:
288                x86emu_fpu_M_fstenv(X86EMU_FPU_WORD, destoffset);
289                break;
290            case 7:
291                x86emu_fpu_M_fstcw(X86EMU_FPU_WORD, destoffset);
292                break;
293            }
294        }
295    }
296#else
297    (void) destoffset;
298    (void) stkelem;
299#endif                          /* X86EMU_FPU_PRESENT */
300    DECODE_CLEAR_SEGOVR();
301    END_OF_INSTR_NO_TRACE();
302}
303
304#ifdef DEBUG
305
306static const char *x86emu_fpu_op_da_tab[] = {
307    "FIADD\tDWORD PTR ", "FIMUL\tDWORD PTR ", "FICOM\tDWORD PTR ",
308    "FICOMP\tDWORD PTR ",
309    "FISUB\tDWORD PTR ", "FISUBR\tDWORD PTR ", "FIDIV\tDWORD PTR ",
310    "FIDIVR\tDWORD PTR ",
311
312    "FIADD\tDWORD PTR ", "FIMUL\tDWORD PTR ", "FICOM\tDWORD PTR ",
313    "FICOMP\tDWORD PTR ",
314    "FISUB\tDWORD PTR ", "FISUBR\tDWORD PTR ", "FIDIV\tDWORD PTR ",
315    "FIDIVR\tDWORD PTR ",
316
317    "FIADD\tDWORD PTR ", "FIMUL\tDWORD PTR ", "FICOM\tDWORD PTR ",
318    "FICOMP\tDWORD PTR ",
319    "FISUB\tDWORD PTR ", "FISUBR\tDWORD PTR ", "FIDIV\tDWORD PTR ",
320    "FIDIVR\tDWORD PTR ",
321
322    "ESC_DA ", "ESC_DA ", "ESC_DA ", "ESC_DA ",
323    "ESC_DA     ", "ESC_DA ", "ESC_DA   ", "ESC_DA ",
324};
325
326#endif                          /* DEBUG */
327
328/* opcode=0xda */
329void
330x86emuOp_esc_coprocess_da(u8 X86EMU_UNUSED(op1))
331{
332    int mod, rl, rh;
333    uint destoffset = 0;
334    u8 stkelem = 0;
335
336    START_OF_INSTR();
337    FETCH_DECODE_MODRM(mod, rh, rl);
338    DECODE_PRINTINSTR32(x86emu_fpu_op_da_tab, mod, rh, rl);
339    switch (mod) {
340    case 0:
341        destoffset = decode_rm00_address(rl);
342        DECODE_PRINTF("\n");
343        break;
344    case 1:
345        destoffset = decode_rm01_address(rl);
346        DECODE_PRINTF("\n");
347        break;
348    case 2:
349        destoffset = decode_rm10_address(rl);
350        DECODE_PRINTF("\n");
351        break;
352    case 3:                    /* register to register */
353        stkelem = (u8) rl;
354        DECODE_PRINTF2("\tST(%d),ST\n", stkelem);
355        break;
356    }
357#ifdef X86EMU_FPU_PRESENT
358    switch (mod) {
359    case 3:
360        x86emu_fpu_illegal();
361        break;
362    default:
363        switch (rh) {
364        case 0:
365            x86emu_fpu_M_iadd(X86EMU_FPU_SHORT, destoffset);
366            break;
367        case 1:
368            x86emu_fpu_M_imul(X86EMU_FPU_SHORT, destoffset);
369            break;
370        case 2:
371            x86emu_fpu_M_icom(X86EMU_FPU_SHORT, destoffset);
372            break;
373        case 3:
374            x86emu_fpu_M_icomp(X86EMU_FPU_SHORT, destoffset);
375            break;
376        case 4:
377            x86emu_fpu_M_isub(X86EMU_FPU_SHORT, destoffset);
378            break;
379        case 5:
380            x86emu_fpu_M_isubr(X86EMU_FPU_SHORT, destoffset);
381            break;
382        case 6:
383            x86emu_fpu_M_idiv(X86EMU_FPU_SHORT, destoffset);
384            break;
385        case 7:
386            x86emu_fpu_M_idivr(X86EMU_FPU_SHORT, destoffset);
387            break;
388        }
389    }
390#else
391    (void) destoffset;
392    (void) stkelem;
393#endif
394    DECODE_CLEAR_SEGOVR();
395    END_OF_INSTR_NO_TRACE();
396}
397
398#ifdef DEBUG
399
400static const char *x86emu_fpu_op_db_tab[] = {
401    "FILD\tDWORD PTR ", "ESC_DB\t19", "FIST\tDWORD PTR ", "FISTP\tDWORD PTR ",
402    "ESC_DB\t1C", "FLD\tTBYTE PTR ", "ESC_DB\t1E", "FSTP\tTBYTE PTR ",
403
404    "FILD\tDWORD PTR ", "ESC_DB\t19", "FIST\tDWORD PTR ", "FISTP\tDWORD PTR ",
405    "ESC_DB\t1C", "FLD\tTBYTE PTR ", "ESC_DB\t1E", "FSTP\tTBYTE PTR ",
406
407    "FILD\tDWORD PTR ", "ESC_DB\t19", "FIST\tDWORD PTR ", "FISTP\tDWORD PTR ",
408    "ESC_DB\t1C", "FLD\tTBYTE PTR ", "ESC_DB\t1E", "FSTP\tTBYTE PTR ",
409};
410
411#endif                          /* DEBUG */
412
413/* opcode=0xdb */
414void
415x86emuOp_esc_coprocess_db(u8 X86EMU_UNUSED(op1))
416{
417    int mod, rl, rh;
418    uint destoffset = 0;
419
420    START_OF_INSTR();
421    FETCH_DECODE_MODRM(mod, rh, rl);
422#ifdef DEBUG
423    if (mod != 3) {
424        DECODE_PRINTINSTR32(x86emu_fpu_op_db_tab, mod, rh, rl);
425    }
426    else if (rh == 4) {         /* === 11 10 0 nnn */
427        switch (rl) {
428        case 0:
429            DECODE_PRINTF("FENI\n");
430            break;
431        case 1:
432            DECODE_PRINTF("FDISI\n");
433            break;
434        case 2:
435            DECODE_PRINTF("FCLEX\n");
436            break;
437        case 3:
438            DECODE_PRINTF("FINIT\n");
439            break;
440        }
441    }
442    else {
443        DECODE_PRINTF2("ESC_DB %0x\n", (mod << 6) + (rh << 3) + (rl));
444    }
445#endif                          /* DEBUG */
446    switch (mod) {
447    case 0:
448        destoffset = decode_rm00_address(rl);
449        break;
450    case 1:
451        destoffset = decode_rm01_address(rl);
452        break;
453    case 2:
454        destoffset = decode_rm10_address(rl);
455        break;
456    case 3:                    /* register to register */
457        break;
458    }
459#ifdef X86EMU_FPU_PRESENT
460    /* execute */
461    switch (mod) {
462    case 3:
463        switch (rh) {
464        case 4:
465            switch (rl) {
466            case 0:
467                x86emu_fpu_R_feni();
468                break;
469            case 1:
470                x86emu_fpu_R_fdisi();
471                break;
472            case 2:
473                x86emu_fpu_R_fclex();
474                break;
475            case 3:
476                x86emu_fpu_R_finit();
477                break;
478            default:
479                x86emu_fpu_illegal();
480                break;
481            }
482            break;
483        default:
484            x86emu_fpu_illegal();
485            break;
486        }
487        break;
488    default:
489        switch (rh) {
490        case 0:
491            x86emu_fpu_M_fild(X86EMU_FPU_SHORT, destoffset);
492            break;
493        case 1:
494            x86emu_fpu_illegal();
495            break;
496        case 2:
497            x86emu_fpu_M_fist(X86EMU_FPU_SHORT, destoffset);
498            break;
499        case 3:
500            x86emu_fpu_M_fistp(X86EMU_FPU_SHORT, destoffset);
501            break;
502        case 4:
503            x86emu_fpu_illegal();
504            break;
505        case 5:
506            x86emu_fpu_M_fld(X86EMU_FPU_LDBL, destoffset);
507            break;
508        case 6:
509            x86emu_fpu_illegal();
510            break;
511        case 7:
512            x86emu_fpu_M_fstp(X86EMU_FPU_LDBL, destoffset);
513            break;
514        }
515    }
516#else
517    (void) destoffset;
518#endif
519    DECODE_CLEAR_SEGOVR();
520    END_OF_INSTR_NO_TRACE();
521}
522
523#ifdef DEBUG
524static const char *x86emu_fpu_op_dc_tab[] = {
525    "FADD\tQWORD PTR ", "FMUL\tQWORD PTR ", "FCOM\tQWORD PTR ",
526    "FCOMP\tQWORD PTR ",
527    "FSUB\tQWORD PTR ", "FSUBR\tQWORD PTR ", "FDIV\tQWORD PTR ",
528    "FDIVR\tQWORD PTR ",
529
530    "FADD\tQWORD PTR ", "FMUL\tQWORD PTR ", "FCOM\tQWORD PTR ",
531    "FCOMP\tQWORD PTR ",
532    "FSUB\tQWORD PTR ", "FSUBR\tQWORD PTR ", "FDIV\tQWORD PTR ",
533    "FDIVR\tQWORD PTR ",
534
535    "FADD\tQWORD PTR ", "FMUL\tQWORD PTR ", "FCOM\tQWORD PTR ",
536    "FCOMP\tQWORD PTR ",
537    "FSUB\tQWORD PTR ", "FSUBR\tQWORD PTR ", "FDIV\tQWORD PTR ",
538    "FDIVR\tQWORD PTR ",
539
540    "FADD\t", "FMUL\t", "FCOM\t", "FCOMP\t",
541    "FSUBR\t", "FSUB\t", "FDIVR\t", "FDIV\t",
542};
543#endif                          /* DEBUG */
544
545/* opcode=0xdc */
546void
547x86emuOp_esc_coprocess_dc(u8 X86EMU_UNUSED(op1))
548{
549    int mod, rl, rh;
550    uint destoffset = 0;
551    u8 stkelem = 0;
552
553    START_OF_INSTR();
554    FETCH_DECODE_MODRM(mod, rh, rl);
555    DECODE_PRINTINSTR32(x86emu_fpu_op_dc_tab, mod, rh, rl);
556    switch (mod) {
557    case 0:
558        destoffset = decode_rm00_address(rl);
559        DECODE_PRINTF("\n");
560        break;
561    case 1:
562        destoffset = decode_rm01_address(rl);
563        DECODE_PRINTF("\n");
564        break;
565    case 2:
566        destoffset = decode_rm10_address(rl);
567        DECODE_PRINTF("\n");
568        break;
569    case 3:                    /* register to register */
570        stkelem = (u8) rl;
571        DECODE_PRINTF2("\tST(%d),ST\n", stkelem);
572        break;
573    }
574#ifdef X86EMU_FPU_PRESENT
575    /* execute */
576    switch (mod) {
577    case 3:
578        switch (rh) {
579        case 0:
580            x86emu_fpu_R_fadd(stkelem, X86EMU_FPU_STKTOP);
581            break;
582        case 1:
583            x86emu_fpu_R_fmul(stkelem, X86EMU_FPU_STKTOP);
584            break;
585        case 2:
586            x86emu_fpu_R_fcom(stkelem, X86EMU_FPU_STKTOP);
587            break;
588        case 3:
589            x86emu_fpu_R_fcomp(stkelem, X86EMU_FPU_STKTOP);
590            break;
591        case 4:
592            x86emu_fpu_R_fsubr(stkelem, X86EMU_FPU_STKTOP);
593            break;
594        case 5:
595            x86emu_fpu_R_fsub(stkelem, X86EMU_FPU_STKTOP);
596            break;
597        case 6:
598            x86emu_fpu_R_fdivr(stkelem, X86EMU_FPU_STKTOP);
599            break;
600        case 7:
601            x86emu_fpu_R_fdiv(stkelem, X86EMU_FPU_STKTOP);
602            break;
603        }
604        break;
605    default:
606        switch (rh) {
607        case 0:
608            x86emu_fpu_M_fadd(X86EMU_FPU_DOUBLE, destoffset);
609            break;
610        case 1:
611            x86emu_fpu_M_fmul(X86EMU_FPU_DOUBLE, destoffset);
612            break;
613        case 2:
614            x86emu_fpu_M_fcom(X86EMU_FPU_DOUBLE, destoffset);
615            break;
616        case 3:
617            x86emu_fpu_M_fcomp(X86EMU_FPU_DOUBLE, destoffset);
618            break;
619        case 4:
620            x86emu_fpu_M_fsub(X86EMU_FPU_DOUBLE, destoffset);
621            break;
622        case 5:
623            x86emu_fpu_M_fsubr(X86EMU_FPU_DOUBLE, destoffset);
624            break;
625        case 6:
626            x86emu_fpu_M_fdiv(X86EMU_FPU_DOUBLE, destoffset);
627            break;
628        case 7:
629            x86emu_fpu_M_fdivr(X86EMU_FPU_DOUBLE, destoffset);
630            break;
631        }
632    }
633#else
634    (void) destoffset;
635    (void) stkelem;
636#endif
637    DECODE_CLEAR_SEGOVR();
638    END_OF_INSTR_NO_TRACE();
639}
640
641#ifdef DEBUG
642
643static const char *x86emu_fpu_op_dd_tab[] = {
644    "FLD\tQWORD PTR ", "ESC_DD\t29,", "FST\tQWORD PTR ", "FSTP\tQWORD PTR ",
645    "FRSTOR\t", "ESC_DD\t2D,", "FSAVE\t", "FSTSW\t",
646
647    "FLD\tQWORD PTR ", "ESC_DD\t29,", "FST\tQWORD PTR ", "FSTP\tQWORD PTR ",
648    "FRSTOR\t", "ESC_DD\t2D,", "FSAVE\t", "FSTSW\t",
649
650    "FLD\tQWORD PTR ", "ESC_DD\t29,", "FST\tQWORD PTR ", "FSTP\tQWORD PTR ",
651    "FRSTOR\t", "ESC_DD\t2D,", "FSAVE\t", "FSTSW\t",
652
653    "FFREE\t", "FXCH\t", "FST\t", "FSTP\t",
654    "ESC_DD\t2C,", "ESC_DD\t2D,", "ESC_DD\t2E,", "ESC_DD\t2F,",
655};
656
657#endif                          /* DEBUG */
658
659/* opcode=0xdd */
660void
661x86emuOp_esc_coprocess_dd(u8 X86EMU_UNUSED(op1))
662{
663    int mod, rl, rh;
664    uint destoffset = 0;
665    u8 stkelem = 0;
666
667    START_OF_INSTR();
668    FETCH_DECODE_MODRM(mod, rh, rl);
669    DECODE_PRINTINSTR32(x86emu_fpu_op_dd_tab, mod, rh, rl);
670    switch (mod) {
671    case 0:
672        destoffset = decode_rm00_address(rl);
673        DECODE_PRINTF("\n");
674        break;
675    case 1:
676        destoffset = decode_rm01_address(rl);
677        DECODE_PRINTF("\n");
678        break;
679    case 2:
680        destoffset = decode_rm10_address(rl);
681        DECODE_PRINTF("\n");
682        break;
683    case 3:                    /* register to register */
684        stkelem = (u8) rl;
685        DECODE_PRINTF2("\tST(%d),ST\n", stkelem);
686        break;
687    }
688#ifdef X86EMU_FPU_PRESENT
689    switch (mod) {
690    case 3:
691        switch (rh) {
692        case 0:
693            x86emu_fpu_R_ffree(stkelem);
694            break;
695        case 1:
696            x86emu_fpu_R_fxch(stkelem);
697            break;
698        case 2:
699            x86emu_fpu_R_fst(stkelem);  /* register version */
700            break;
701        case 3:
702            x86emu_fpu_R_fstp(stkelem); /* register version */
703            break;
704        default:
705            x86emu_fpu_illegal();
706            break;
707        }
708        break;
709    default:
710        switch (rh) {
711        case 0:
712            x86emu_fpu_M_fld(X86EMU_FPU_DOUBLE, destoffset);
713            break;
714        case 1:
715            x86emu_fpu_illegal();
716            break;
717        case 2:
718            x86emu_fpu_M_fst(X86EMU_FPU_DOUBLE, destoffset);
719            break;
720        case 3:
721            x86emu_fpu_M_fstp(X86EMU_FPU_DOUBLE, destoffset);
722            break;
723        case 4:
724            x86emu_fpu_M_frstor(X86EMU_FPU_WORD, destoffset);
725            break;
726        case 5:
727            x86emu_fpu_illegal();
728            break;
729        case 6:
730            x86emu_fpu_M_fsave(X86EMU_FPU_WORD, destoffset);
731            break;
732        case 7:
733            x86emu_fpu_M_fstsw(X86EMU_FPU_WORD, destoffset);
734            break;
735        }
736    }
737#else
738    (void) destoffset;
739    (void) stkelem;
740#endif
741    DECODE_CLEAR_SEGOVR();
742    END_OF_INSTR_NO_TRACE();
743}
744
745#ifdef DEBUG
746
747static const char *x86emu_fpu_op_de_tab[] = {
748    "FIADD\tWORD PTR ", "FIMUL\tWORD PTR ", "FICOM\tWORD PTR ",
749    "FICOMP\tWORD PTR ",
750    "FISUB\tWORD PTR ", "FISUBR\tWORD PTR ", "FIDIV\tWORD PTR ",
751    "FIDIVR\tWORD PTR ",
752
753    "FIADD\tWORD PTR ", "FIMUL\tWORD PTR ", "FICOM\tWORD PTR ",
754    "FICOMP\tWORD PTR ",
755    "FISUB\tWORD PTR ", "FISUBR\tWORD PTR ", "FIDIV\tWORD PTR ",
756    "FIDIVR\tWORD PTR ",
757
758    "FIADD\tWORD PTR ", "FIMUL\tWORD PTR ", "FICOM\tWORD PTR ",
759    "FICOMP\tWORD PTR ",
760    "FISUB\tWORD PTR ", "FISUBR\tWORD PTR ", "FIDIV\tWORD PTR ",
761    "FIDIVR\tWORD PTR ",
762
763    "FADDP\t", "FMULP\t", "FCOMP\t", "FCOMPP\t",
764    "FSUBRP\t", "FSUBP\t", "FDIVRP\t", "FDIVP\t",
765};
766
767#endif                          /* DEBUG */
768
769/* opcode=0xde */
770void
771x86emuOp_esc_coprocess_de(u8 X86EMU_UNUSED(op1))
772{
773    int mod, rl, rh;
774    uint destoffset = 0;
775    u8 stkelem = 0;
776
777    START_OF_INSTR();
778    FETCH_DECODE_MODRM(mod, rh, rl);
779    DECODE_PRINTINSTR32(x86emu_fpu_op_de_tab, mod, rh, rl);
780    switch (mod) {
781    case 0:
782        destoffset = decode_rm00_address(rl);
783        DECODE_PRINTF("\n");
784        break;
785    case 1:
786        destoffset = decode_rm01_address(rl);
787        DECODE_PRINTF("\n");
788        break;
789    case 2:
790        destoffset = decode_rm10_address(rl);
791        DECODE_PRINTF("\n");
792        break;
793    case 3:                    /* register to register */
794        stkelem = (u8) rl;
795        DECODE_PRINTF2("\tST(%d),ST\n", stkelem);
796        break;
797    }
798#ifdef X86EMU_FPU_PRESENT
799    switch (mod) {
800    case 3:
801        switch (rh) {
802        case 0:
803            x86emu_fpu_R_faddp(stkelem, X86EMU_FPU_STKTOP);
804            break;
805        case 1:
806            x86emu_fpu_R_fmulp(stkelem, X86EMU_FPU_STKTOP);
807            break;
808        case 2:
809            x86emu_fpu_R_fcomp(stkelem, X86EMU_FPU_STKTOP);
810            break;
811        case 3:
812            if (stkelem == 1)
813                x86emu_fpu_R_fcompp(stkelem, X86EMU_FPU_STKTOP);
814            else
815                x86emu_fpu_illegal();
816            break;
817        case 4:
818            x86emu_fpu_R_fsubrp(stkelem, X86EMU_FPU_STKTOP);
819            break;
820        case 5:
821            x86emu_fpu_R_fsubp(stkelem, X86EMU_FPU_STKTOP);
822            break;
823        case 6:
824            x86emu_fpu_R_fdivrp(stkelem, X86EMU_FPU_STKTOP);
825            break;
826        case 7:
827            x86emu_fpu_R_fdivp(stkelem, X86EMU_FPU_STKTOP);
828            break;
829        }
830        break;
831    default:
832        switch (rh) {
833        case 0:
834            x86emu_fpu_M_fiadd(X86EMU_FPU_WORD, destoffset);
835            break;
836        case 1:
837            x86emu_fpu_M_fimul(X86EMU_FPU_WORD, destoffset);
838            break;
839        case 2:
840            x86emu_fpu_M_ficom(X86EMU_FPU_WORD, destoffset);
841            break;
842        case 3:
843            x86emu_fpu_M_ficomp(X86EMU_FPU_WORD, destoffset);
844            break;
845        case 4:
846            x86emu_fpu_M_fisub(X86EMU_FPU_WORD, destoffset);
847            break;
848        case 5:
849            x86emu_fpu_M_fisubr(X86EMU_FPU_WORD, destoffset);
850            break;
851        case 6:
852            x86emu_fpu_M_fidiv(X86EMU_FPU_WORD, destoffset);
853            break;
854        case 7:
855            x86emu_fpu_M_fidivr(X86EMU_FPU_WORD, destoffset);
856            break;
857        }
858    }
859#else
860    (void) destoffset;
861    (void) stkelem;
862#endif
863    DECODE_CLEAR_SEGOVR();
864    END_OF_INSTR_NO_TRACE();
865}
866
867#ifdef DEBUG
868
869static const char *x86emu_fpu_op_df_tab[] = {
870    /* mod == 00 */
871    "FILD\tWORD PTR ", "ESC_DF\t39\n", "FIST\tWORD PTR ", "FISTP\tWORD PTR ",
872    "FBLD\tTBYTE PTR ", "FILD\tQWORD PTR ", "FBSTP\tTBYTE PTR ",
873    "FISTP\tQWORD PTR ",
874
875    /* mod == 01 */
876    "FILD\tWORD PTR ", "ESC_DF\t39 ", "FIST\tWORD PTR ", "FISTP\tWORD PTR ",
877    "FBLD\tTBYTE PTR ", "FILD\tQWORD PTR ", "FBSTP\tTBYTE PTR ",
878    "FISTP\tQWORD PTR ",
879
880    /* mod == 10 */
881    "FILD\tWORD PTR ", "ESC_DF\t39 ", "FIST\tWORD PTR ", "FISTP\tWORD PTR ",
882    "FBLD\tTBYTE PTR ", "FILD\tQWORD PTR ", "FBSTP\tTBYTE PTR ",
883    "FISTP\tQWORD PTR ",
884
885    /* mod == 11 */
886    "FFREE\t", "FXCH\t", "FST\t", "FSTP\t",
887    "ESC_DF\t3C,", "ESC_DF\t3D,", "ESC_DF\t3E,", "ESC_DF\t3F,"
888};
889
890#endif                          /* DEBUG */
891
892/* opcode=0xdf */
893void
894x86emuOp_esc_coprocess_df(u8 X86EMU_UNUSED(op1))
895{
896    int mod, rl, rh;
897    uint destoffset = 0;
898    u8 stkelem = 0;
899
900    START_OF_INSTR();
901    FETCH_DECODE_MODRM(mod, rh, rl);
902    DECODE_PRINTINSTR32(x86emu_fpu_op_df_tab, mod, rh, rl);
903    switch (mod) {
904    case 0:
905        destoffset = decode_rm00_address(rl);
906        DECODE_PRINTF("\n");
907        break;
908    case 1:
909        destoffset = decode_rm01_address(rl);
910        DECODE_PRINTF("\n");
911        break;
912    case 2:
913        destoffset = decode_rm10_address(rl);
914        DECODE_PRINTF("\n");
915        break;
916    case 3:                    /* register to register */
917        stkelem = (u8) rl;
918        DECODE_PRINTF2("\tST(%d)\n", stkelem);
919        break;
920    }
921#ifdef X86EMU_FPU_PRESENT
922    switch (mod) {
923    case 3:
924        switch (rh) {
925        case 0:
926            x86emu_fpu_R_ffree(stkelem);
927            break;
928        case 1:
929            x86emu_fpu_R_fxch(stkelem);
930            break;
931        case 2:
932            x86emu_fpu_R_fst(stkelem);  /* register version */
933            break;
934        case 3:
935            x86emu_fpu_R_fstp(stkelem); /* register version */
936            break;
937        default:
938            x86emu_fpu_illegal();
939            break;
940        }
941        break;
942    default:
943        switch (rh) {
944        case 0:
945            x86emu_fpu_M_fild(X86EMU_FPU_WORD, destoffset);
946            break;
947        case 1:
948            x86emu_fpu_illegal();
949            break;
950        case 2:
951            x86emu_fpu_M_fist(X86EMU_FPU_WORD, destoffset);
952            break;
953        case 3:
954            x86emu_fpu_M_fistp(X86EMU_FPU_WORD, destoffset);
955            break;
956        case 4:
957            x86emu_fpu_M_fbld(X86EMU_FPU_BSD, destoffset);
958            break;
959        case 5:
960            x86emu_fpu_M_fild(X86EMU_FPU_LONG, destoffset);
961            break;
962        case 6:
963            x86emu_fpu_M_fbstp(X86EMU_FPU_BSD, destoffset);
964            break;
965        case 7:
966            x86emu_fpu_M_fistp(X86EMU_FPU_LONG, destoffset);
967            break;
968        }
969    }
970#else
971    (void) destoffset;
972    (void) stkelem;
973#endif
974    DECODE_CLEAR_SEGOVR();
975    END_OF_INSTR_NO_TRACE();
976}
977