windows-nt/Source/XPSP1/NT/base/wow64/mscpu/decoder/floatfns.c
2020-09-26 16:20:57 +08:00

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
}
}