01ce601bdb
Convert all DEBUG_SMBUS, DEBUG_SMI, and DEBUG_RAM_SETUP custom and local #defines into globally configurable kconfig options (and Options.lb options for as long as newconfig still exists) which can be enabled by the user in the "Debugging" menu. The respective menu items only appear if a board is selected where the chipset code actually provides such additional DEBUG output. All three variables default to 0 / off for now. Also, drop a small chunk of dead/useless code in the src/northbridge/via/cn700/raminit.c file, which would otherwise break compilation. Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de> Reworked to still apply to trunk, added X86EMU_DEBUG (and make the x86emu/yabel code only work printf instead of a redefined version of printk and Acked-by: Stefan Reinauer <stepan@coresystems.de> git-svn-id: svn://svn.coreboot.org/coreboot/trunk@5185 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
945 lines
26 KiB
C
945 lines
26 KiB
C
/****************************************************************************
|
|
*
|
|
* Realmode X86 Emulator Library
|
|
*
|
|
* Copyright (C) 1991-2004 SciTech Software, Inc.
|
|
* Copyright (C) David Mosberger-Tang
|
|
* Copyright (C) 1999 Egbert Eich
|
|
*
|
|
* ========================================================================
|
|
*
|
|
* Permission to use, copy, modify, distribute, and sell this software and
|
|
* its documentation for any purpose is hereby granted without fee,
|
|
* provided that the above copyright notice appear in all copies and that
|
|
* both that copyright notice and this permission notice appear in
|
|
* supporting documentation, and that the name of the authors not be used
|
|
* in advertising or publicity pertaining to distribution of the software
|
|
* without specific, written prior permission. The authors makes no
|
|
* representations about the suitability of this software for any purpose.
|
|
* It is provided "as is" without express or implied warranty.
|
|
*
|
|
* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
|
* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
|
|
* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
* PERFORMANCE OF THIS SOFTWARE.
|
|
*
|
|
* ========================================================================
|
|
*
|
|
* Language: ANSI C
|
|
* Environment: Any
|
|
* Developer: Kendall Bennett
|
|
*
|
|
* Description: This file contains the code to implement the decoding and
|
|
* emulation of the FPU instructions.
|
|
*
|
|
****************************************************************************/
|
|
|
|
#include "x86emui.h"
|
|
|
|
/*----------------------------- Implementation ----------------------------*/
|
|
|
|
/* opcode=0xd8 */
|
|
void x86emuOp_esc_coprocess_d8(u8 X86EMU_UNUSED(op1))
|
|
{
|
|
START_OF_INSTR();
|
|
DECODE_PRINTF("ESC D8\n");
|
|
DECODE_CLEAR_SEGOVR();
|
|
END_OF_INSTR_NO_TRACE();
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
static const char *x86emu_fpu_op_d9_tab[] = {
|
|
"FLD\tDWORD PTR ", "ESC_D9\t", "FST\tDWORD PTR ", "FSTP\tDWORD PTR ",
|
|
"FLDENV\t", "FLDCW\t", "FSTENV\t", "FSTCW\t",
|
|
|
|
"FLD\tDWORD PTR ", "ESC_D9\t", "FST\tDWORD PTR ", "FSTP\tDWORD PTR ",
|
|
"FLDENV\t", "FLDCW\t", "FSTENV\t", "FSTCW\t",
|
|
|
|
"FLD\tDWORD PTR ", "ESC_D9\t", "FST\tDWORD PTR ", "FSTP\tDWORD PTR ",
|
|
"FLDENV\t", "FLDCW\t", "FSTENV\t", "FSTCW\t",
|
|
};
|
|
|
|
static const char *x86emu_fpu_op_d9_tab1[] = {
|
|
"FLD\t", "FLD\t", "FLD\t", "FLD\t",
|
|
"FLD\t", "FLD\t", "FLD\t", "FLD\t",
|
|
|
|
"FXCH\t", "FXCH\t", "FXCH\t", "FXCH\t",
|
|
"FXCH\t", "FXCH\t", "FXCH\t", "FXCH\t",
|
|
|
|
"FNOP", "ESC_D9", "ESC_D9", "ESC_D9",
|
|
"ESC_D9", "ESC_D9", "ESC_D9", "ESC_D9",
|
|
|
|
"FSTP\t", "FSTP\t", "FSTP\t", "FSTP\t",
|
|
"FSTP\t", "FSTP\t", "FSTP\t", "FSTP\t",
|
|
|
|
"FCHS", "FABS", "ESC_D9", "ESC_D9",
|
|
"FTST", "FXAM", "ESC_D9", "ESC_D9",
|
|
|
|
"FLD1", "FLDL2T", "FLDL2E", "FLDPI",
|
|
"FLDLG2", "FLDLN2", "FLDZ", "ESC_D9",
|
|
|
|
"F2XM1", "FYL2X", "FPTAN", "FPATAN",
|
|
"FXTRACT", "ESC_D9", "FDECSTP", "FINCSTP",
|
|
|
|
"FPREM", "FYL2XP1", "FSQRT", "ESC_D9",
|
|
"FRNDINT", "FSCALE", "ESC_D9", "ESC_D9",
|
|
};
|
|
|
|
#endif /* DEBUG */
|
|
|
|
/* opcode=0xd9 */
|
|
void x86emuOp_esc_coprocess_d9(u8 X86EMU_UNUSED(op1))
|
|
{
|
|
int mod, rl, rh;
|
|
uint destoffset;
|
|
u8 stkelem;
|
|
|
|
START_OF_INSTR();
|
|
FETCH_DECODE_MODRM(mod, rh, rl);
|
|
#ifdef DEBUG
|
|
if (mod != 3) {
|
|
DECODE_PRINTINSTR32(x86emu_fpu_op_d9_tab, mod, rh, rl);
|
|
} else {
|
|
DECODE_PRINTF(x86emu_fpu_op_d9_tab1[(rh << 3) + rl]);
|
|
}
|
|
#endif
|
|
switch (mod) {
|
|
case 0:
|
|
destoffset = decode_rm00_address(rl);
|
|
DECODE_PRINTF("\n");
|
|
break;
|
|
case 1:
|
|
destoffset = decode_rm01_address(rl);
|
|
DECODE_PRINTF("\n");
|
|
break;
|
|
case 2:
|
|
destoffset = decode_rm10_address(rl);
|
|
DECODE_PRINTF("\n");
|
|
break;
|
|
case 3: /* register to register */
|
|
stkelem = (u8)rl;
|
|
if (rh < 4) {
|
|
DECODE_PRINTF2("ST(%d)\n", stkelem);
|
|
} else {
|
|
DECODE_PRINTF("\n");
|
|
}
|
|
break;
|
|
}
|
|
#ifdef X86EMU_FPU_PRESENT
|
|
/* execute */
|
|
switch (mod) {
|
|
case 3:
|
|
switch (rh) {
|
|
case 0:
|
|
x86emu_fpu_R_fld(X86EMU_FPU_STKTOP, stkelem);
|
|
break;
|
|
case 1:
|
|
x86emu_fpu_R_fxch(X86EMU_FPU_STKTOP, stkelem);
|
|
break;
|
|
case 2:
|
|
switch (rl) {
|
|
case 0:
|
|
x86emu_fpu_R_nop();
|
|
break;
|
|
default:
|
|
x86emu_fpu_illegal();
|
|
break;
|
|
}
|
|
case 3:
|
|
x86emu_fpu_R_fstp(X86EMU_FPU_STKTOP, stkelem);
|
|
break;
|
|
case 4:
|
|
switch (rl) {
|
|
case 0:
|
|
x86emu_fpu_R_fchs(X86EMU_FPU_STKTOP);
|
|
break;
|
|
case 1:
|
|
x86emu_fpu_R_fabs(X86EMU_FPU_STKTOP);
|
|
break;
|
|
case 4:
|
|
x86emu_fpu_R_ftst(X86EMU_FPU_STKTOP);
|
|
break;
|
|
case 5:
|
|
x86emu_fpu_R_fxam(X86EMU_FPU_STKTOP);
|
|
break;
|
|
default:
|
|
/* 2,3,6,7 */
|
|
x86emu_fpu_illegal();
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 5:
|
|
switch (rl) {
|
|
case 0:
|
|
x86emu_fpu_R_fld1(X86EMU_FPU_STKTOP);
|
|
break;
|
|
case 1:
|
|
x86emu_fpu_R_fldl2t(X86EMU_FPU_STKTOP);
|
|
break;
|
|
case 2:
|
|
x86emu_fpu_R_fldl2e(X86EMU_FPU_STKTOP);
|
|
break;
|
|
case 3:
|
|
x86emu_fpu_R_fldpi(X86EMU_FPU_STKTOP);
|
|
break;
|
|
case 4:
|
|
x86emu_fpu_R_fldlg2(X86EMU_FPU_STKTOP);
|
|
break;
|
|
case 5:
|
|
x86emu_fpu_R_fldln2(X86EMU_FPU_STKTOP);
|
|
break;
|
|
case 6:
|
|
x86emu_fpu_R_fldz(X86EMU_FPU_STKTOP);
|
|
break;
|
|
default:
|
|
/* 7 */
|
|
x86emu_fpu_illegal();
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 6:
|
|
switch (rl) {
|
|
case 0:
|
|
x86emu_fpu_R_f2xm1(X86EMU_FPU_STKTOP);
|
|
break;
|
|
case 1:
|
|
x86emu_fpu_R_fyl2x(X86EMU_FPU_STKTOP);
|
|
break;
|
|
case 2:
|
|
x86emu_fpu_R_fptan(X86EMU_FPU_STKTOP);
|
|
break;
|
|
case 3:
|
|
x86emu_fpu_R_fpatan(X86EMU_FPU_STKTOP);
|
|
break;
|
|
case 4:
|
|
x86emu_fpu_R_fxtract(X86EMU_FPU_STKTOP);
|
|
break;
|
|
case 5:
|
|
x86emu_fpu_illegal();
|
|
break;
|
|
case 6:
|
|
x86emu_fpu_R_decstp();
|
|
break;
|
|
case 7:
|
|
x86emu_fpu_R_incstp();
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 7:
|
|
switch (rl) {
|
|
case 0:
|
|
x86emu_fpu_R_fprem(X86EMU_FPU_STKTOP);
|
|
break;
|
|
case 1:
|
|
x86emu_fpu_R_fyl2xp1(X86EMU_FPU_STKTOP);
|
|
break;
|
|
case 2:
|
|
x86emu_fpu_R_fsqrt(X86EMU_FPU_STKTOP);
|
|
break;
|
|
case 3:
|
|
x86emu_fpu_illegal();
|
|
break;
|
|
case 4:
|
|
x86emu_fpu_R_frndint(X86EMU_FPU_STKTOP);
|
|
break;
|
|
case 5:
|
|
x86emu_fpu_R_fscale(X86EMU_FPU_STKTOP);
|
|
break;
|
|
case 6:
|
|
case 7:
|
|
default:
|
|
x86emu_fpu_illegal();
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
switch (rh) {
|
|
case 0:
|
|
x86emu_fpu_M_fld(X86EMU_FPU_FLOAT, destoffset);
|
|
break;
|
|
case 1:
|
|
x86emu_fpu_illegal();
|
|
break;
|
|
case 2:
|
|
x86emu_fpu_M_fst(X86EMU_FPU_FLOAT, destoffset);
|
|
break;
|
|
case 3:
|
|
x86emu_fpu_M_fstp(X86EMU_FPU_FLOAT, destoffset);
|
|
break;
|
|
case 4:
|
|
x86emu_fpu_M_fldenv(X86EMU_FPU_WORD, destoffset);
|
|
break;
|
|
case 5:
|
|
x86emu_fpu_M_fldcw(X86EMU_FPU_WORD, destoffset);
|
|
break;
|
|
case 6:
|
|
x86emu_fpu_M_fstenv(X86EMU_FPU_WORD, destoffset);
|
|
break;
|
|
case 7:
|
|
x86emu_fpu_M_fstcw(X86EMU_FPU_WORD, destoffset);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif /* X86EMU_FPU_PRESENT */
|
|
DECODE_CLEAR_SEGOVR();
|
|
END_OF_INSTR_NO_TRACE();
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
static const char *x86emu_fpu_op_da_tab[] = {
|
|
"FIADD\tDWORD PTR ", "FIMUL\tDWORD PTR ", "FICOM\tDWORD PTR ",
|
|
"FICOMP\tDWORD PTR ",
|
|
"FISUB\tDWORD PTR ", "FISUBR\tDWORD PTR ", "FIDIV\tDWORD PTR ",
|
|
"FIDIVR\tDWORD PTR ",
|
|
|
|
"FIADD\tDWORD PTR ", "FIMUL\tDWORD PTR ", "FICOM\tDWORD PTR ",
|
|
"FICOMP\tDWORD PTR ",
|
|
"FISUB\tDWORD PTR ", "FISUBR\tDWORD PTR ", "FIDIV\tDWORD PTR ",
|
|
"FIDIVR\tDWORD PTR ",
|
|
|
|
"FIADD\tDWORD PTR ", "FIMUL\tDWORD PTR ", "FICOM\tDWORD PTR ",
|
|
"FICOMP\tDWORD PTR ",
|
|
"FISUB\tDWORD PTR ", "FISUBR\tDWORD PTR ", "FIDIV\tDWORD PTR ",
|
|
"FIDIVR\tDWORD PTR ",
|
|
|
|
"ESC_DA ", "ESC_DA ", "ESC_DA ", "ESC_DA ",
|
|
"ESC_DA ", "ESC_DA ", "ESC_DA ", "ESC_DA ",
|
|
};
|
|
|
|
#endif /* DEBUG */
|
|
|
|
/* opcode=0xda */
|
|
void x86emuOp_esc_coprocess_da(u8 X86EMU_UNUSED(op1))
|
|
{
|
|
int mod, rl, rh;
|
|
uint destoffset;
|
|
u8 stkelem;
|
|
|
|
START_OF_INSTR();
|
|
FETCH_DECODE_MODRM(mod, rh, rl);
|
|
DECODE_PRINTINSTR32(x86emu_fpu_op_da_tab, mod, rh, rl);
|
|
switch (mod) {
|
|
case 0:
|
|
destoffset = decode_rm00_address(rl);
|
|
DECODE_PRINTF("\n");
|
|
break;
|
|
case 1:
|
|
destoffset = decode_rm01_address(rl);
|
|
DECODE_PRINTF("\n");
|
|
break;
|
|
case 2:
|
|
destoffset = decode_rm10_address(rl);
|
|
DECODE_PRINTF("\n");
|
|
break;
|
|
case 3: /* register to register */
|
|
stkelem = (u8)rl;
|
|
DECODE_PRINTF2("\tST(%d),ST\n", stkelem);
|
|
break;
|
|
}
|
|
#ifdef X86EMU_FPU_PRESENT
|
|
switch (mod) {
|
|
case 3:
|
|
x86emu_fpu_illegal();
|
|
break;
|
|
default:
|
|
switch (rh) {
|
|
case 0:
|
|
x86emu_fpu_M_iadd(X86EMU_FPU_SHORT, destoffset);
|
|
break;
|
|
case 1:
|
|
x86emu_fpu_M_imul(X86EMU_FPU_SHORT, destoffset);
|
|
break;
|
|
case 2:
|
|
x86emu_fpu_M_icom(X86EMU_FPU_SHORT, destoffset);
|
|
break;
|
|
case 3:
|
|
x86emu_fpu_M_icomp(X86EMU_FPU_SHORT, destoffset);
|
|
break;
|
|
case 4:
|
|
x86emu_fpu_M_isub(X86EMU_FPU_SHORT, destoffset);
|
|
break;
|
|
case 5:
|
|
x86emu_fpu_M_isubr(X86EMU_FPU_SHORT, destoffset);
|
|
break;
|
|
case 6:
|
|
x86emu_fpu_M_idiv(X86EMU_FPU_SHORT, destoffset);
|
|
break;
|
|
case 7:
|
|
x86emu_fpu_M_idivr(X86EMU_FPU_SHORT, destoffset);
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
DECODE_CLEAR_SEGOVR();
|
|
END_OF_INSTR_NO_TRACE();
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
static const char *x86emu_fpu_op_db_tab[] = {
|
|
"FILD\tDWORD PTR ", "ESC_DB\t19", "FIST\tDWORD PTR ", "FISTP\tDWORD PTR ",
|
|
"ESC_DB\t1C", "FLD\tTBYTE PTR ", "ESC_DB\t1E", "FSTP\tTBYTE PTR ",
|
|
|
|
"FILD\tDWORD PTR ", "ESC_DB\t19", "FIST\tDWORD PTR ", "FISTP\tDWORD PTR ",
|
|
"ESC_DB\t1C", "FLD\tTBYTE PTR ", "ESC_DB\t1E", "FSTP\tTBYTE PTR ",
|
|
|
|
"FILD\tDWORD PTR ", "ESC_DB\t19", "FIST\tDWORD PTR ", "FISTP\tDWORD PTR ",
|
|
"ESC_DB\t1C", "FLD\tTBYTE PTR ", "ESC_DB\t1E", "FSTP\tTBYTE PTR ",
|
|
};
|
|
|
|
#endif /* DEBUG */
|
|
|
|
/* opcode=0xdb */
|
|
void x86emuOp_esc_coprocess_db(u8 X86EMU_UNUSED(op1))
|
|
{
|
|
int mod, rl, rh;
|
|
uint destoffset;
|
|
|
|
START_OF_INSTR();
|
|
FETCH_DECODE_MODRM(mod, rh, rl);
|
|
#ifdef DEBUG
|
|
if (mod != 3) {
|
|
DECODE_PRINTINSTR32(x86emu_fpu_op_db_tab, mod, rh, rl);
|
|
} else if (rh == 4) { /* === 11 10 0 nnn */
|
|
switch (rl) {
|
|
case 0:
|
|
DECODE_PRINTF("FENI\n");
|
|
break;
|
|
case 1:
|
|
DECODE_PRINTF("FDISI\n");
|
|
break;
|
|
case 2:
|
|
DECODE_PRINTF("FCLEX\n");
|
|
break;
|
|
case 3:
|
|
DECODE_PRINTF("FINIT\n");
|
|
break;
|
|
}
|
|
} else {
|
|
DECODE_PRINTF2("ESC_DB %0x\n", (mod << 6) + (rh << 3) + (rl));
|
|
}
|
|
#endif /* DEBUG */
|
|
switch (mod) {
|
|
case 0:
|
|
destoffset = decode_rm00_address(rl);
|
|
break;
|
|
case 1:
|
|
destoffset = decode_rm01_address(rl);
|
|
break;
|
|
case 2:
|
|
destoffset = decode_rm10_address(rl);
|
|
break;
|
|
case 3: /* register to register */
|
|
break;
|
|
}
|
|
#ifdef X86EMU_FPU_PRESENT
|
|
/* execute */
|
|
switch (mod) {
|
|
case 3:
|
|
switch (rh) {
|
|
case 4:
|
|
switch (rl) {
|
|
case 0:
|
|
x86emu_fpu_R_feni();
|
|
break;
|
|
case 1:
|
|
x86emu_fpu_R_fdisi();
|
|
break;
|
|
case 2:
|
|
x86emu_fpu_R_fclex();
|
|
break;
|
|
case 3:
|
|
x86emu_fpu_R_finit();
|
|
break;
|
|
default:
|
|
x86emu_fpu_illegal();
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
x86emu_fpu_illegal();
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
switch (rh) {
|
|
case 0:
|
|
x86emu_fpu_M_fild(X86EMU_FPU_SHORT, destoffset);
|
|
break;
|
|
case 1:
|
|
x86emu_fpu_illegal();
|
|
break;
|
|
case 2:
|
|
x86emu_fpu_M_fist(X86EMU_FPU_SHORT, destoffset);
|
|
break;
|
|
case 3:
|
|
x86emu_fpu_M_fistp(X86EMU_FPU_SHORT, destoffset);
|
|
break;
|
|
case 4:
|
|
x86emu_fpu_illegal();
|
|
break;
|
|
case 5:
|
|
x86emu_fpu_M_fld(X86EMU_FPU_LDBL, destoffset);
|
|
break;
|
|
case 6:
|
|
x86emu_fpu_illegal();
|
|
break;
|
|
case 7:
|
|
x86emu_fpu_M_fstp(X86EMU_FPU_LDBL, destoffset);
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
DECODE_CLEAR_SEGOVR();
|
|
END_OF_INSTR_NO_TRACE();
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
static const char *x86emu_fpu_op_dc_tab[] = {
|
|
"FADD\tQWORD PTR ", "FMUL\tQWORD PTR ", "FCOM\tQWORD PTR ",
|
|
"FCOMP\tQWORD PTR ",
|
|
"FSUB\tQWORD PTR ", "FSUBR\tQWORD PTR ", "FDIV\tQWORD PTR ",
|
|
"FDIVR\tQWORD PTR ",
|
|
|
|
"FADD\tQWORD PTR ", "FMUL\tQWORD PTR ", "FCOM\tQWORD PTR ",
|
|
"FCOMP\tQWORD PTR ",
|
|
"FSUB\tQWORD PTR ", "FSUBR\tQWORD PTR ", "FDIV\tQWORD PTR ",
|
|
"FDIVR\tQWORD PTR ",
|
|
|
|
"FADD\tQWORD PTR ", "FMUL\tQWORD PTR ", "FCOM\tQWORD PTR ",
|
|
"FCOMP\tQWORD PTR ",
|
|
"FSUB\tQWORD PTR ", "FSUBR\tQWORD PTR ", "FDIV\tQWORD PTR ",
|
|
"FDIVR\tQWORD PTR ",
|
|
|
|
"FADD\t", "FMUL\t", "FCOM\t", "FCOMP\t",
|
|
"FSUBR\t", "FSUB\t", "FDIVR\t", "FDIV\t",
|
|
};
|
|
#endif /* DEBUG */
|
|
|
|
/* opcode=0xdc */
|
|
void x86emuOp_esc_coprocess_dc(u8 X86EMU_UNUSED(op1))
|
|
{
|
|
int mod, rl, rh;
|
|
uint destoffset;
|
|
u8 stkelem;
|
|
|
|
START_OF_INSTR();
|
|
FETCH_DECODE_MODRM(mod, rh, rl);
|
|
DECODE_PRINTINSTR32(x86emu_fpu_op_dc_tab, mod, rh, rl);
|
|
switch (mod) {
|
|
case 0:
|
|
destoffset = decode_rm00_address(rl);
|
|
DECODE_PRINTF("\n");
|
|
break;
|
|
case 1:
|
|
destoffset = decode_rm01_address(rl);
|
|
DECODE_PRINTF("\n");
|
|
break;
|
|
case 2:
|
|
destoffset = decode_rm10_address(rl);
|
|
DECODE_PRINTF("\n");
|
|
break;
|
|
case 3: /* register to register */
|
|
stkelem = (u8)rl;
|
|
DECODE_PRINTF2("\tST(%d),ST\n", stkelem);
|
|
break;
|
|
}
|
|
#ifdef X86EMU_FPU_PRESENT
|
|
/* execute */
|
|
switch (mod) {
|
|
case 3:
|
|
switch (rh) {
|
|
case 0:
|
|
x86emu_fpu_R_fadd(stkelem, X86EMU_FPU_STKTOP);
|
|
break;
|
|
case 1:
|
|
x86emu_fpu_R_fmul(stkelem, X86EMU_FPU_STKTOP);
|
|
break;
|
|
case 2:
|
|
x86emu_fpu_R_fcom(stkelem, X86EMU_FPU_STKTOP);
|
|
break;
|
|
case 3:
|
|
x86emu_fpu_R_fcomp(stkelem, X86EMU_FPU_STKTOP);
|
|
break;
|
|
case 4:
|
|
x86emu_fpu_R_fsubr(stkelem, X86EMU_FPU_STKTOP);
|
|
break;
|
|
case 5:
|
|
x86emu_fpu_R_fsub(stkelem, X86EMU_FPU_STKTOP);
|
|
break;
|
|
case 6:
|
|
x86emu_fpu_R_fdivr(stkelem, X86EMU_FPU_STKTOP);
|
|
break;
|
|
case 7:
|
|
x86emu_fpu_R_fdiv(stkelem, X86EMU_FPU_STKTOP);
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
switch (rh) {
|
|
case 0:
|
|
x86emu_fpu_M_fadd(X86EMU_FPU_DOUBLE, destoffset);
|
|
break;
|
|
case 1:
|
|
x86emu_fpu_M_fmul(X86EMU_FPU_DOUBLE, destoffset);
|
|
break;
|
|
case 2:
|
|
x86emu_fpu_M_fcom(X86EMU_FPU_DOUBLE, destoffset);
|
|
break;
|
|
case 3:
|
|
x86emu_fpu_M_fcomp(X86EMU_FPU_DOUBLE, destoffset);
|
|
break;
|
|
case 4:
|
|
x86emu_fpu_M_fsub(X86EMU_FPU_DOUBLE, destoffset);
|
|
break;
|
|
case 5:
|
|
x86emu_fpu_M_fsubr(X86EMU_FPU_DOUBLE, destoffset);
|
|
break;
|
|
case 6:
|
|
x86emu_fpu_M_fdiv(X86EMU_FPU_DOUBLE, destoffset);
|
|
break;
|
|
case 7:
|
|
x86emu_fpu_M_fdivr(X86EMU_FPU_DOUBLE, destoffset);
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
DECODE_CLEAR_SEGOVR();
|
|
END_OF_INSTR_NO_TRACE();
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
static const char *x86emu_fpu_op_dd_tab[] = {
|
|
"FLD\tQWORD PTR ", "ESC_DD\t29,", "FST\tQWORD PTR ", "FSTP\tQWORD PTR ",
|
|
"FRSTOR\t", "ESC_DD\t2D,", "FSAVE\t", "FSTSW\t",
|
|
|
|
"FLD\tQWORD PTR ", "ESC_DD\t29,", "FST\tQWORD PTR ", "FSTP\tQWORD PTR ",
|
|
"FRSTOR\t", "ESC_DD\t2D,", "FSAVE\t", "FSTSW\t",
|
|
|
|
"FLD\tQWORD PTR ", "ESC_DD\t29,", "FST\tQWORD PTR ", "FSTP\tQWORD PTR ",
|
|
"FRSTOR\t", "ESC_DD\t2D,", "FSAVE\t", "FSTSW\t",
|
|
|
|
"FFREE\t", "FXCH\t", "FST\t", "FSTP\t",
|
|
"ESC_DD\t2C,", "ESC_DD\t2D,", "ESC_DD\t2E,", "ESC_DD\t2F,",
|
|
};
|
|
|
|
#endif /* DEBUG */
|
|
|
|
/* opcode=0xdd */
|
|
void x86emuOp_esc_coprocess_dd(u8 X86EMU_UNUSED(op1))
|
|
{
|
|
int mod, rl, rh;
|
|
uint destoffset;
|
|
u8 stkelem;
|
|
|
|
START_OF_INSTR();
|
|
FETCH_DECODE_MODRM(mod, rh, rl);
|
|
DECODE_PRINTINSTR32(x86emu_fpu_op_dd_tab, mod, rh, rl);
|
|
switch (mod) {
|
|
case 0:
|
|
destoffset = decode_rm00_address(rl);
|
|
DECODE_PRINTF("\n");
|
|
break;
|
|
case 1:
|
|
destoffset = decode_rm01_address(rl);
|
|
DECODE_PRINTF("\n");
|
|
break;
|
|
case 2:
|
|
destoffset = decode_rm10_address(rl);
|
|
DECODE_PRINTF("\n");
|
|
break;
|
|
case 3: /* register to register */
|
|
stkelem = (u8)rl;
|
|
DECODE_PRINTF2("\tST(%d),ST\n", stkelem);
|
|
break;
|
|
}
|
|
#ifdef X86EMU_FPU_PRESENT
|
|
switch (mod) {
|
|
case 3:
|
|
switch (rh) {
|
|
case 0:
|
|
x86emu_fpu_R_ffree(stkelem);
|
|
break;
|
|
case 1:
|
|
x86emu_fpu_R_fxch(stkelem);
|
|
break;
|
|
case 2:
|
|
x86emu_fpu_R_fst(stkelem); /* register version */
|
|
break;
|
|
case 3:
|
|
x86emu_fpu_R_fstp(stkelem); /* register version */
|
|
break;
|
|
default:
|
|
x86emu_fpu_illegal();
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
switch (rh) {
|
|
case 0:
|
|
x86emu_fpu_M_fld(X86EMU_FPU_DOUBLE, destoffset);
|
|
break;
|
|
case 1:
|
|
x86emu_fpu_illegal();
|
|
break;
|
|
case 2:
|
|
x86emu_fpu_M_fst(X86EMU_FPU_DOUBLE, destoffset);
|
|
break;
|
|
case 3:
|
|
x86emu_fpu_M_fstp(X86EMU_FPU_DOUBLE, destoffset);
|
|
break;
|
|
case 4:
|
|
x86emu_fpu_M_frstor(X86EMU_FPU_WORD, destoffset);
|
|
break;
|
|
case 5:
|
|
x86emu_fpu_illegal();
|
|
break;
|
|
case 6:
|
|
x86emu_fpu_M_fsave(X86EMU_FPU_WORD, destoffset);
|
|
break;
|
|
case 7:
|
|
x86emu_fpu_M_fstsw(X86EMU_FPU_WORD, destoffset);
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
DECODE_CLEAR_SEGOVR();
|
|
END_OF_INSTR_NO_TRACE();
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
static const char *x86emu_fpu_op_de_tab[] =
|
|
{
|
|
"FIADD\tWORD PTR ", "FIMUL\tWORD PTR ", "FICOM\tWORD PTR ",
|
|
"FICOMP\tWORD PTR ",
|
|
"FISUB\tWORD PTR ", "FISUBR\tWORD PTR ", "FIDIV\tWORD PTR ",
|
|
"FIDIVR\tWORD PTR ",
|
|
|
|
"FIADD\tWORD PTR ", "FIMUL\tWORD PTR ", "FICOM\tWORD PTR ",
|
|
"FICOMP\tWORD PTR ",
|
|
"FISUB\tWORD PTR ", "FISUBR\tWORD PTR ", "FIDIV\tWORD PTR ",
|
|
"FIDIVR\tWORD PTR ",
|
|
|
|
"FIADD\tWORD PTR ", "FIMUL\tWORD PTR ", "FICOM\tWORD PTR ",
|
|
"FICOMP\tWORD PTR ",
|
|
"FISUB\tWORD PTR ", "FISUBR\tWORD PTR ", "FIDIV\tWORD PTR ",
|
|
"FIDIVR\tWORD PTR ",
|
|
|
|
"FADDP\t", "FMULP\t", "FCOMP\t", "FCOMPP\t",
|
|
"FSUBRP\t", "FSUBP\t", "FDIVRP\t", "FDIVP\t",
|
|
};
|
|
|
|
#endif /* DEBUG */
|
|
|
|
/* opcode=0xde */
|
|
void x86emuOp_esc_coprocess_de(u8 X86EMU_UNUSED(op1))
|
|
{
|
|
int mod, rl, rh;
|
|
uint destoffset;
|
|
u8 stkelem;
|
|
|
|
START_OF_INSTR();
|
|
FETCH_DECODE_MODRM(mod, rh, rl);
|
|
DECODE_PRINTINSTR32(x86emu_fpu_op_de_tab, mod, rh, rl);
|
|
switch (mod) {
|
|
case 0:
|
|
destoffset = decode_rm00_address(rl);
|
|
DECODE_PRINTF("\n");
|
|
break;
|
|
case 1:
|
|
destoffset = decode_rm01_address(rl);
|
|
DECODE_PRINTF("\n");
|
|
break;
|
|
case 2:
|
|
destoffset = decode_rm10_address(rl);
|
|
DECODE_PRINTF("\n");
|
|
break;
|
|
case 3: /* register to register */
|
|
stkelem = (u8)rl;
|
|
DECODE_PRINTF2("\tST(%d),ST\n", stkelem);
|
|
break;
|
|
}
|
|
#ifdef X86EMU_FPU_PRESENT
|
|
switch (mod) {
|
|
case 3:
|
|
switch (rh) {
|
|
case 0:
|
|
x86emu_fpu_R_faddp(stkelem, X86EMU_FPU_STKTOP);
|
|
break;
|
|
case 1:
|
|
x86emu_fpu_R_fmulp(stkelem, X86EMU_FPU_STKTOP);
|
|
break;
|
|
case 2:
|
|
x86emu_fpu_R_fcomp(stkelem, X86EMU_FPU_STKTOP);
|
|
break;
|
|
case 3:
|
|
if (stkelem == 1)
|
|
x86emu_fpu_R_fcompp(stkelem, X86EMU_FPU_STKTOP);
|
|
else
|
|
x86emu_fpu_illegal();
|
|
break;
|
|
case 4:
|
|
x86emu_fpu_R_fsubrp(stkelem, X86EMU_FPU_STKTOP);
|
|
break;
|
|
case 5:
|
|
x86emu_fpu_R_fsubp(stkelem, X86EMU_FPU_STKTOP);
|
|
break;
|
|
case 6:
|
|
x86emu_fpu_R_fdivrp(stkelem, X86EMU_FPU_STKTOP);
|
|
break;
|
|
case 7:
|
|
x86emu_fpu_R_fdivp(stkelem, X86EMU_FPU_STKTOP);
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
switch (rh) {
|
|
case 0:
|
|
x86emu_fpu_M_fiadd(X86EMU_FPU_WORD, destoffset);
|
|
break;
|
|
case 1:
|
|
x86emu_fpu_M_fimul(X86EMU_FPU_WORD, destoffset);
|
|
break;
|
|
case 2:
|
|
x86emu_fpu_M_ficom(X86EMU_FPU_WORD, destoffset);
|
|
break;
|
|
case 3:
|
|
x86emu_fpu_M_ficomp(X86EMU_FPU_WORD, destoffset);
|
|
break;
|
|
case 4:
|
|
x86emu_fpu_M_fisub(X86EMU_FPU_WORD, destoffset);
|
|
break;
|
|
case 5:
|
|
x86emu_fpu_M_fisubr(X86EMU_FPU_WORD, destoffset);
|
|
break;
|
|
case 6:
|
|
x86emu_fpu_M_fidiv(X86EMU_FPU_WORD, destoffset);
|
|
break;
|
|
case 7:
|
|
x86emu_fpu_M_fidivr(X86EMU_FPU_WORD, destoffset);
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
DECODE_CLEAR_SEGOVR();
|
|
END_OF_INSTR_NO_TRACE();
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
static const char *x86emu_fpu_op_df_tab[] = {
|
|
/* mod == 00 */
|
|
"FILD\tWORD PTR ", "ESC_DF\t39\n", "FIST\tWORD PTR ", "FISTP\tWORD PTR ",
|
|
"FBLD\tTBYTE PTR ", "FILD\tQWORD PTR ", "FBSTP\tTBYTE PTR ",
|
|
"FISTP\tQWORD PTR ",
|
|
|
|
/* mod == 01 */
|
|
"FILD\tWORD PTR ", "ESC_DF\t39 ", "FIST\tWORD PTR ", "FISTP\tWORD PTR ",
|
|
"FBLD\tTBYTE PTR ", "FILD\tQWORD PTR ", "FBSTP\tTBYTE PTR ",
|
|
"FISTP\tQWORD PTR ",
|
|
|
|
/* mod == 10 */
|
|
"FILD\tWORD PTR ", "ESC_DF\t39 ", "FIST\tWORD PTR ", "FISTP\tWORD PTR ",
|
|
"FBLD\tTBYTE PTR ", "FILD\tQWORD PTR ", "FBSTP\tTBYTE PTR ",
|
|
"FISTP\tQWORD PTR ",
|
|
|
|
/* mod == 11 */
|
|
"FFREE\t", "FXCH\t", "FST\t", "FSTP\t",
|
|
"ESC_DF\t3C,", "ESC_DF\t3D,", "ESC_DF\t3E,", "ESC_DF\t3F,"
|
|
};
|
|
|
|
#endif /* DEBUG */
|
|
|
|
/* opcode=0xdf */
|
|
void x86emuOp_esc_coprocess_df(u8 X86EMU_UNUSED(op1))
|
|
{
|
|
int mod, rl, rh;
|
|
uint destoffset;
|
|
u8 stkelem;
|
|
|
|
START_OF_INSTR();
|
|
FETCH_DECODE_MODRM(mod, rh, rl);
|
|
DECODE_PRINTINSTR32(x86emu_fpu_op_df_tab, mod, rh, rl);
|
|
switch (mod) {
|
|
case 0:
|
|
destoffset = decode_rm00_address(rl);
|
|
DECODE_PRINTF("\n");
|
|
break;
|
|
case 1:
|
|
destoffset = decode_rm01_address(rl);
|
|
DECODE_PRINTF("\n");
|
|
break;
|
|
case 2:
|
|
destoffset = decode_rm10_address(rl);
|
|
DECODE_PRINTF("\n");
|
|
break;
|
|
case 3: /* register to register */
|
|
stkelem = (u8)rl;
|
|
DECODE_PRINTF2("\tST(%d)\n", stkelem);
|
|
break;
|
|
}
|
|
#ifdef X86EMU_FPU_PRESENT
|
|
switch (mod) {
|
|
case 3:
|
|
switch (rh) {
|
|
case 0:
|
|
x86emu_fpu_R_ffree(stkelem);
|
|
break;
|
|
case 1:
|
|
x86emu_fpu_R_fxch(stkelem);
|
|
break;
|
|
case 2:
|
|
x86emu_fpu_R_fst(stkelem); /* register version */
|
|
break;
|
|
case 3:
|
|
x86emu_fpu_R_fstp(stkelem); /* register version */
|
|
break;
|
|
default:
|
|
x86emu_fpu_illegal();
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
switch (rh) {
|
|
case 0:
|
|
x86emu_fpu_M_fild(X86EMU_FPU_WORD, destoffset);
|
|
break;
|
|
case 1:
|
|
x86emu_fpu_illegal();
|
|
break;
|
|
case 2:
|
|
x86emu_fpu_M_fist(X86EMU_FPU_WORD, destoffset);
|
|
break;
|
|
case 3:
|
|
x86emu_fpu_M_fistp(X86EMU_FPU_WORD, destoffset);
|
|
break;
|
|
case 4:
|
|
x86emu_fpu_M_fbld(X86EMU_FPU_BSD, destoffset);
|
|
break;
|
|
case 5:
|
|
x86emu_fpu_M_fild(X86EMU_FPU_LONG, destoffset);
|
|
break;
|
|
case 6:
|
|
x86emu_fpu_M_fbstp(X86EMU_FPU_BSD, destoffset);
|
|
break;
|
|
case 7:
|
|
x86emu_fpu_M_fistp(X86EMU_FPU_LONG, destoffset);
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
DECODE_CLEAR_SEGOVR();
|
|
END_OF_INSTR_NO_TRACE();
|
|
}
|