529 lines
16 KiB
C
529 lines
16 KiB
C
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
floatfns.c
|
|
|
|
Abstract:
|
|
|
|
Floating point instruction decoder.
|
|
|
|
Author:
|
|
|
|
16-Aug-1995 BarryBo
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include "threadst.h"
|
|
#include "instr.h"
|
|
#include "decoderp.h"
|
|
|
|
extern DWORD pfnNPXNPHandler;
|
|
extern BOOLEAN fUseNPXEM;
|
|
|
|
typedef float *PFLOAT;
|
|
typedef double *PDOUBLE;
|
|
|
|
typedef void (*pfnFrag0)(PCPUDATA);
|
|
typedef void (*pfnFrag1INT)(PCPUDATA, INT);
|
|
typedef void (*pfnFrag1FLOAT)(PCPUDATA, PFLOAT);
|
|
typedef void (*pfnFrag1DOUBLE)(PCPUDATA, PDOUBLE);
|
|
typedef void (*pfnFrag1PLONG)(PCPUDATA, PLONG);
|
|
typedef void (*pfnFrag2INTINT)(PCPUDATA, INT, INT);
|
|
typedef void (*pfnFrag1PUSHORT)(PCPUDATA, PUSHORT);
|
|
|
|
OPERATION GP0Mem[8] = {OP_FP_FADD32,
|
|
OP_FP_FMUL32,
|
|
OP_FP_FCOM32,
|
|
OP_FP_FCOMP32,
|
|
OP_FP_FSUB32,
|
|
OP_FP_FSUBR32,
|
|
OP_FP_FDIV32,
|
|
OP_FP_FDIVR32};
|
|
|
|
|
|
OPERATION GP0Top[8] = {OP_FP_FADD_ST_STi,
|
|
OP_FP_FMUL_ST_STi,
|
|
OP_FP_FCOM_STi,
|
|
OP_FP_FCOMP_STi,
|
|
OP_FP_FSUB_ST_STi,
|
|
OP_FP_FSUBR_ST_STi,
|
|
OP_FP_FDIV_ST_STi,
|
|
OP_FP_FDIVR_ST_STi};
|
|
|
|
OPERATION GP1GroupFCHS[8] = {OP_FP_FCHS,
|
|
OP_FP_FABS,
|
|
OP_BadInstruction,
|
|
OP_BadInstruction,
|
|
OP_FP_FTST,
|
|
OP_FP_FXAM,
|
|
OP_BadInstruction,
|
|
OP_BadInstruction};
|
|
|
|
OPERATION GP1GroupFLD1[8] = {OP_FP_FLD1,
|
|
OP_FP_FLDL2T,
|
|
OP_FP_FLDL2E,
|
|
OP_FP_FLDPI,
|
|
OP_FP_FLDLG2,
|
|
OP_FP_FLDLN2,
|
|
OP_FP_FLDZ,
|
|
OP_BadInstruction};
|
|
|
|
OPERATION GP1GroupF2XM1[8] = {OP_FP_F2XM1,
|
|
OP_FP_FYL2X,
|
|
OP_FP_FPTAN,
|
|
OP_FP_FPATAN,
|
|
OP_FP_FXTRACT,
|
|
OP_FP_FPREM1,
|
|
OP_FP_FDECSTP,
|
|
OP_FP_FINCSTP};
|
|
|
|
OPERATION GP1GroupFPREM[8] = {OP_FP_FPREM,
|
|
OP_FP_FYL2XP1,
|
|
OP_FP_FSQRT,
|
|
OP_FP_FSINCOS,
|
|
OP_FP_FRNDINT,
|
|
OP_FP_FSCALE,
|
|
OP_FP_FSIN,
|
|
OP_FP_FCOS};
|
|
|
|
OPERATION GP1Mem[8] = {OP_FP_FLD32,
|
|
OP_BadInstruction, // never called
|
|
OP_FP_FST32,
|
|
OP_FP_FSTP32,
|
|
OP_FP_FLDENV,
|
|
OP_FP_FLDCW,
|
|
OP_FP_FNSTENV,
|
|
OP_FP_FNSTCW};
|
|
|
|
OPERATION GP2Mem[8] = {OP_FP_FIADD32,
|
|
OP_FP_FIMUL32,
|
|
OP_FP_FICOM32,
|
|
OP_FP_FICOMP32,
|
|
OP_FP_FISUB32,
|
|
OP_FP_FISUBR32,
|
|
OP_FP_FIDIV32,
|
|
OP_FP_FIDIVR32};
|
|
|
|
OPERATION GP4Mem[8] = {OP_FP_FADD64,
|
|
OP_FP_FMUL64,
|
|
OP_FP_FCOM64,
|
|
OP_FP_FCOMP64,
|
|
OP_FP_FSUB64,
|
|
OP_FP_FSUBR64,
|
|
OP_FP_FDIV64,
|
|
OP_FP_FDIVR64};
|
|
|
|
OPERATION GP4Reg[8] = {OP_FP_FADD_STi_ST,
|
|
OP_FP_FMUL_STi_ST,
|
|
OP_FP_FCOM_STi,
|
|
OP_FP_FCOMP_STi,
|
|
OP_FP_FSUB_STi_ST,
|
|
OP_FP_FSUBR_STi_ST,
|
|
OP_FP_FDIV_STi_ST,
|
|
OP_FP_FDIVR_STi_ST};
|
|
|
|
OPERATION GP5Mem[8] = {OP_FP_FLD64,
|
|
OP_BadInstruction,
|
|
OP_FP_FST64,
|
|
OP_FP_FSTP64,
|
|
OP_FP_FRSTOR,
|
|
OP_BadInstruction,
|
|
OP_FP_FNSAVE,
|
|
OP_FP_FNSTSW};
|
|
|
|
OPERATION GP5Reg[8] = {OP_FP_FFREE,
|
|
OP_FP_FXCH_STi,
|
|
OP_FP_FST_STi,
|
|
OP_FP_FSTP_STi,
|
|
OP_FP_FUCOM,
|
|
OP_FP_FUCOMP,
|
|
OP_BadInstruction,
|
|
OP_BadInstruction};
|
|
|
|
OPERATION GP6Mem[8] = {OP_FP_FIADD16,
|
|
OP_FP_FIMUL16,
|
|
OP_FP_FICOM16,
|
|
OP_FP_FICOMP16,
|
|
OP_FP_FISUB16,
|
|
OP_FP_FISUBR16,
|
|
OP_FP_FIDIV16,
|
|
OP_FP_FIDIVR16};
|
|
|
|
OPERATION GP6Reg[8] = {OP_FP_FADDP_STi_ST,
|
|
OP_FP_FMULP_STi_ST,
|
|
OP_FP_FCOMP_STi,
|
|
OP_FP_FCOMPP,
|
|
OP_FP_FSUBP_STi_ST,
|
|
OP_FP_FSUBRP_STi_ST,
|
|
OP_FP_FDIVP_STi_ST,
|
|
OP_FP_FDIVRP_STi_ST};
|
|
|
|
OPERATION GP7Mem[8] = {OP_FP_FILD16,
|
|
OP_BadInstruction,
|
|
OP_FP_FIST16,
|
|
OP_FP_FISTP16,
|
|
OP_FP_FBLD,
|
|
OP_FP_FILD64,
|
|
OP_FP_FBSTP,
|
|
OP_FP_FISTP64};
|
|
|
|
OPERATION GP7Reg[8] = {OP_FP_FFREE, // not in Intel docs, but NTSD knows it
|
|
OP_FP_FXCH_STi, // not in Intel docs, but NTSD knows it
|
|
OP_FP_FST_STi,
|
|
OP_FP_FSTP_STi,
|
|
OP_BadInstruction,
|
|
OP_BadInstruction,
|
|
OP_BadInstruction,
|
|
OP_BadInstruction};
|
|
|
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
|
DISPATCH(FLOAT_GP0) // d8 XX
|
|
{
|
|
BYTE secondByte;
|
|
|
|
secondByte = *((PBYTE)(eipTemp+1));
|
|
|
|
if (secondByte < 0xc0) {
|
|
// memory format
|
|
|
|
int cbInstr = mod_rm_reg32(State, &Instr->Operand1, NULL);
|
|
Instr->Operation = GP0Mem[(secondByte>>3) & 7];
|
|
Instr->Size = cbInstr+1;
|
|
} else {
|
|
// register format
|
|
|
|
Instr->Operation = GP0Top[(secondByte>>3) & 7];
|
|
Instr->Operand1.Type = OPND_IMM;
|
|
Instr->Operand1.Immed = secondByte & 7;
|
|
Instr->Size = 2;
|
|
}
|
|
|
|
if (fUseNPXEM) {
|
|
// generate a "CALL pfnNPXNPHandler" instruction, with a length
|
|
// the same as the FP instruction we're emulating.
|
|
Instr->Operation = OP_CTRL_UNCOND_Call;
|
|
Instr->Operand1.Type = OPND_IMM;
|
|
Instr->Operand1.Immed = pfnNPXNPHandler; // dest of call
|
|
Instr->Operand2.Type = OPND_IMM;
|
|
Instr->Operand2.Immed = eipTemp; // addr of FP instr
|
|
}
|
|
}
|
|
|
|
|
|
|
|
DISPATCH(FLOAT_GP1) // d9 XX
|
|
{
|
|
BYTE secondByte, inst;
|
|
|
|
secondByte = *((PBYTE)(eipTemp+1));
|
|
inst = (secondByte>>3) & 7;
|
|
|
|
if (secondByte < 0xc0) {
|
|
// memory format
|
|
|
|
if (inst == 1) {
|
|
Instr->Operation = OP_BadInstruction;
|
|
} else {
|
|
int cbInstr = mod_rm_reg32(State, &Instr->Operand1, NULL);
|
|
Instr->Operation = GP1Mem[(secondByte>>3) & 7];
|
|
Instr->Size = cbInstr+1;
|
|
}
|
|
} else {
|
|
// register format
|
|
switch ( inst ) {
|
|
case 0: // d9 c0+i
|
|
Instr->Operation = OP_FP_FLD_STi;
|
|
Instr->Operand1.Type = OPND_IMM;
|
|
Instr->Operand1.Immed = secondByte & 7;
|
|
break;
|
|
case 1: // d9 c8+i
|
|
Instr->Operation = OP_FP_FXCH_STi;
|
|
Instr->Operand1.Type = OPND_IMM;
|
|
Instr->Operand1.Immed = secondByte & 7;
|
|
break;
|
|
case 2:
|
|
if (secondByte == 0xd0) {
|
|
Instr->Operation = OP_FP_FNOP; // FNOP (d9 d0)
|
|
} else {
|
|
Instr->Operation = OP_BadInstruction; // (d9 d1..d7)
|
|
}
|
|
break;
|
|
case 3: // d9 d8+i
|
|
Instr->Operation = OP_BadInstruction;
|
|
//UNDONE: emstore.asm says FSTP Special Form 1
|
|
break;
|
|
case 4: // d9 e0+i
|
|
Instr->Operation = GP1GroupFCHS[secondByte&7];
|
|
break;
|
|
case 5:
|
|
Instr->Operation = GP1GroupFLD1[secondByte&7];
|
|
break;
|
|
case 6:
|
|
Instr->Operation = GP1GroupF2XM1[secondByte&7];
|
|
break;
|
|
default:
|
|
case 7:
|
|
Instr->Operation = GP1GroupFPREM[secondByte&7];
|
|
break;
|
|
}
|
|
Instr->Size = 2;
|
|
}
|
|
|
|
if (fUseNPXEM) {
|
|
// generate a "CALL pfnNPXNPHandler" instruction, with a length
|
|
// the same as the FP instruction we're emulating.
|
|
Instr->Operation = OP_CTRL_UNCOND_Call;
|
|
Instr->Operand1.Type = OPND_IMM;
|
|
Instr->Operand1.Immed = pfnNPXNPHandler;
|
|
Instr->Operand2.Type = OPND_IMM;
|
|
Instr->Operand2.Immed = eipTemp; // addr of FP instr
|
|
}
|
|
}
|
|
|
|
|
|
DISPATCH(FLOAT_GP2) // da XX
|
|
{
|
|
BYTE secondByte;
|
|
|
|
secondByte = *((PBYTE)(eipTemp+1));
|
|
|
|
if (secondByte < 0xc0) {
|
|
// memory format
|
|
|
|
int cbInstr = mod_rm_reg32(State, &Instr->Operand1, NULL);
|
|
Instr->Operation = GP2Mem[(secondByte>>3) & 7];
|
|
Instr->Size = cbInstr+1;
|
|
|
|
} else if (secondByte == 0xe9) {
|
|
Instr->Operation = OP_FP_FUCOMPP;
|
|
Instr->Size = 2;
|
|
} else {
|
|
Instr->Operation = OP_BadInstruction;
|
|
}
|
|
|
|
if (fUseNPXEM) {
|
|
// generate a "CALL pfnNPXNPHandler" instruction, with a length
|
|
// the same as the FP instruction we're emulating.
|
|
Instr->Operation = OP_CTRL_UNCOND_Call;
|
|
Instr->Operand1.Type = OPND_IMM;
|
|
Instr->Operand1.Immed = pfnNPXNPHandler;
|
|
Instr->Operand2.Type = OPND_IMM;
|
|
Instr->Operand2.Immed = eipTemp; // addr of FP instr
|
|
}
|
|
}
|
|
|
|
|
|
DISPATCH(FLOAT_GP3) // db XX
|
|
{
|
|
BYTE secondByte;
|
|
|
|
secondByte = *((PBYTE)(eipTemp+1));
|
|
|
|
if (secondByte < 0xc0) {
|
|
// memory format
|
|
int cbInstr = mod_rm_reg32(State, &Instr->Operand1, NULL);
|
|
|
|
switch ((secondByte>>3) & 7) {
|
|
case 0:
|
|
Instr->Operation = OP_FP_FILD32;
|
|
break;
|
|
case 1:
|
|
case 4:
|
|
case 6:
|
|
Instr->Operation = OP_BadInstruction;
|
|
break;
|
|
case 2:
|
|
Instr->Operation = OP_FP_FIST32;
|
|
break;
|
|
case 3:
|
|
Instr->Operation = OP_FP_FISTP32;
|
|
break;
|
|
case 5:
|
|
Instr->Operation = OP_FP_FLD80;
|
|
break;
|
|
case 7:
|
|
Instr->Operation = OP_FP_FSTP80;
|
|
break;
|
|
}
|
|
Instr->Size = cbInstr+1;
|
|
} else {
|
|
Instr->Size = 2;
|
|
|
|
if (secondByte == 0xe2) {
|
|
Instr->Operation = OP_FP_FNCLEX;
|
|
} else if (secondByte == 0xe3) {
|
|
Instr->Operation = OP_FP_FNINIT;
|
|
} else {
|
|
Instr->Operation = OP_FP_FNOP; // FDISI, FENI, FSETPM are 2-byte FNOPs
|
|
}
|
|
}
|
|
|
|
if (fUseNPXEM) {
|
|
// generate a "CALL pfnNPXNPHandler" instruction, with a length
|
|
// the same as the FP instruction we're emulating.
|
|
Instr->Operation = OP_CTRL_UNCOND_Call;
|
|
Instr->Operand1.Type = OPND_IMM;
|
|
Instr->Operand1.Immed = pfnNPXNPHandler;
|
|
Instr->Operand2.Type = OPND_IMM;
|
|
Instr->Operand2.Immed = eipTemp; // addr of FP instr
|
|
}
|
|
}
|
|
|
|
|
|
|
|
DISPATCH(FLOAT_GP4) // dc XX
|
|
{
|
|
BYTE secondByte;
|
|
|
|
secondByte = *((PBYTE)(eipTemp+1));
|
|
|
|
if (secondByte < 0xc0) {
|
|
// memory format
|
|
|
|
int cbInstr = mod_rm_reg32(State, &Instr->Operand1, NULL);
|
|
Instr->Operation = GP4Mem[(secondByte>>3) & 7];
|
|
Instr->Size = cbInstr+1;
|
|
} else {
|
|
// register format - "OP ST(i)"
|
|
|
|
Instr->Operation = GP4Reg[(secondByte>>3) & 7];
|
|
Instr->Operand1.Type = OPND_IMM;
|
|
Instr->Operand1.Immed = secondByte & 7;
|
|
Instr->Size = 2;
|
|
}
|
|
|
|
if (fUseNPXEM) {
|
|
// generate a "CALL pfnNPXNPHandler" instruction, with a length
|
|
// the same as the FP instruction we're emulating.
|
|
Instr->Operation = OP_CTRL_UNCOND_Call;
|
|
Instr->Operand1.Type = OPND_IMM;
|
|
Instr->Operand1.Immed = pfnNPXNPHandler;
|
|
Instr->Operand2.Type = OPND_IMM;
|
|
Instr->Operand2.Immed = eipTemp; // addr of FP instr
|
|
}
|
|
}
|
|
|
|
|
|
DISPATCH(FLOAT_GP5) // dd XX
|
|
{
|
|
BYTE secondByte;
|
|
|
|
secondByte = *((PBYTE)(eipTemp+1));
|
|
|
|
if (secondByte < 0xc0) {
|
|
// memory format
|
|
|
|
int cbInstr = mod_rm_reg32(State, &Instr->Operand1, NULL);
|
|
Instr->Operation = GP5Mem[(secondByte>>3)&7];
|
|
Instr->Size = cbInstr+1;
|
|
} else {
|
|
// register format "OP ST(i)"
|
|
|
|
Instr->Operation = GP5Reg[(secondByte>>3)&7];
|
|
Instr->Operand1.Type = OPND_IMM;
|
|
Instr->Operand1.Immed = secondByte & 7;
|
|
Instr->Size = 2;
|
|
}
|
|
|
|
if (fUseNPXEM) {
|
|
// generate a "CALL pfnNPXNPHandler" instruction, with a length
|
|
// the same as the FP instruction we're emulating.
|
|
Instr->Operation = OP_CTRL_UNCOND_Call;
|
|
Instr->Operand1.Type = OPND_IMM;
|
|
Instr->Operand1.Immed = pfnNPXNPHandler;
|
|
Instr->Operand2.Type = OPND_IMM;
|
|
Instr->Operand2.Immed = eipTemp; // addr of FP instr
|
|
}
|
|
}
|
|
|
|
|
|
DISPATCH(FLOAT_GP6) // de XX
|
|
{
|
|
BYTE secondByte, inst;
|
|
|
|
secondByte = *((PBYTE)(eipTemp+1));
|
|
inst = (secondByte>>3) & 7;
|
|
|
|
if (secondByte < 0xc0) {
|
|
// memory format
|
|
|
|
int cbInstr = mod_rm_reg32(State, &Instr->Operand1, NULL);
|
|
Instr->Operation = GP6Mem[(secondByte>>3)&7];
|
|
Instr->Size = cbInstr+1;
|
|
} else {
|
|
// register format
|
|
|
|
if (inst == 3 && secondByte != 0xd9) {
|
|
Instr->Operation = OP_BadInstruction;
|
|
} else {
|
|
Instr->Operation = GP6Reg[inst];
|
|
Instr->Operand1.Type = OPND_IMM;
|
|
Instr->Operand1.Immed = secondByte & 7;
|
|
Instr->Size = 2;
|
|
}
|
|
}
|
|
|
|
if (fUseNPXEM) {
|
|
// generate a "CALL pfnNPXNPHandler" instruction, with a length
|
|
// the same as the FP instruction we're emulating.
|
|
Instr->Operation = OP_CTRL_UNCOND_Call;
|
|
Instr->Operand1.Type = OPND_IMM;
|
|
Instr->Operand1.Immed = pfnNPXNPHandler;
|
|
Instr->Operand2.Type = OPND_IMM;
|
|
Instr->Operand2.Immed = eipTemp; // addr of FP instr
|
|
}
|
|
}
|
|
|
|
|
|
DISPATCH(FLOAT_GP7) // df XX
|
|
{
|
|
BYTE secondByte, inst;
|
|
|
|
secondByte = *((PBYTE)(eipTemp+1));
|
|
inst = (secondByte>>3) & 7;
|
|
|
|
if (secondByte < 0xc0) {
|
|
// memory format
|
|
|
|
int cbInstr = mod_rm_reg32(State, &Instr->Operand1, NULL);
|
|
Instr->Operation = GP7Mem[(secondByte>>3)&7];
|
|
Instr->Size = cbInstr+1;
|
|
} else {
|
|
// register format
|
|
if (inst == 4) {
|
|
Instr->Operation = OP_FP_FNSTSW;
|
|
Instr->Operand1.Type = OPND_REGREF;
|
|
Instr->Operand1.Reg = GP_AX;
|
|
} else {
|
|
Instr->Operation = GP7Reg[inst];
|
|
Instr->Operand1.Type = OPND_IMM;
|
|
Instr->Operand1.Immed = secondByte & 7;
|
|
}
|
|
Instr->Size = 2;
|
|
}
|
|
|
|
if (fUseNPXEM) {
|
|
// generate a "CALL pfnNPXNPHandler" instruction, with a length
|
|
// the same as the FP instruction we're emulating.
|
|
Instr->Operation = OP_CTRL_UNCOND_Call;
|
|
Instr->Operand1.Type = OPND_IMM;
|
|
Instr->Operand1.Immed = pfnNPXNPHandler;
|
|
Instr->Operand2.Type = OPND_IMM;
|
|
Instr->Operand2.Immed = eipTemp; // addr of FP instr
|
|
}
|
|
}
|