Implemented Pentium FPU latencies.
This commit is contained in:
parent
59b5cf50dd
commit
fb4e1f0715
1 changed files with 367 additions and 176 deletions
|
|
@ -2,10 +2,10 @@
|
|||
- U/V integer pairing
|
||||
- FPU/FXCH pairing
|
||||
- Prefix decode delay (including shadowing)
|
||||
- FPU latencies
|
||||
Elements not taken into account :
|
||||
- Branch prediction (beyond most simplistic approximation)
|
||||
- PMMX decode queue
|
||||
- FPU latencies
|
||||
- MMX latencies
|
||||
*/
|
||||
|
||||
|
|
@ -17,6 +17,8 @@
|
|||
#include "mem.h"
|
||||
#include "codegen.h"
|
||||
|
||||
|
||||
|
||||
/*Instruction has different execution time for 16 and 32 bit data. Does not pair */
|
||||
#define CYCLES_HAS_MULTI (1 << 28)
|
||||
|
||||
|
|
@ -37,76 +39,126 @@ static int pair_timings[4][4] =
|
|||
|
||||
/*Instruction follows either register timing, read-modify, or read-modify-write.
|
||||
May be pairable*/
|
||||
#define CYCLES_REG (0 << 0)
|
||||
#define CYCLES_RM (1 << 0)
|
||||
#define CYCLES_RMW (2 << 0)
|
||||
#define CYCLES_BRANCH (3 << 0)
|
||||
#define CYCLES_REG (0ull << 0)
|
||||
#define CYCLES_RM (1ull << 0)
|
||||
#define CYCLES_RMW (2ull << 0)
|
||||
#define CYCLES_BRANCH (3ull << 0)
|
||||
|
||||
/*Instruction has immediate data. Can only be used with PAIR_U/PAIR_V/PAIR_UV*/
|
||||
#define CYCLES_HASIMM (3 << 2)
|
||||
#define CYCLES_IMM8 (1 << 2)
|
||||
#define CYCLES_IMM1632 (2 << 2)
|
||||
#define CYCLES_HASIMM (3ull << 2)
|
||||
#define CYCLES_IMM8 (1ull << 2)
|
||||
#define CYCLES_IMM1632 (2ull << 2)
|
||||
|
||||
#define CYCLES_MASK ((1 << 7) - 1)
|
||||
#define CYCLES_MASK ((1ull << 7) - 1)
|
||||
|
||||
/*Instruction is MMX shift or pack/unpack instruction*/
|
||||
#define MMX_SHIFTPACK (1 << 7)
|
||||
#define MMX_SHIFTPACK (1ull << 7)
|
||||
/*Instruction is MMX multiply instruction*/
|
||||
#define MMX_MULTIPLY (1 << 8)
|
||||
#define MMX_MULTIPLY (1ull << 8)
|
||||
|
||||
/*Instruction does not pair*/
|
||||
#define PAIR_NP (0 << 29)
|
||||
#define PAIR_NP (0ull << 29)
|
||||
/*Instruction pairs in U pipe only*/
|
||||
#define PAIR_U (1 << 29)
|
||||
#define PAIR_U (1ull << 29)
|
||||
/*Instruction pairs in V pipe only*/
|
||||
#define PAIR_V (2 << 29)
|
||||
#define PAIR_V (2ull << 29)
|
||||
/*Instruction pairs in both U and V pipes*/
|
||||
#define PAIR_UV (3 << 29)
|
||||
#define PAIR_UV (3ull << 29)
|
||||
/*Instruction pairs in U pipe only and only with FXCH*/
|
||||
#define PAIR_FX (5 << 29)
|
||||
#define PAIR_FX (5ull << 29)
|
||||
/*Instruction is FXCH and only pairs in V pipe with FX pairable instruction*/
|
||||
#define PAIR_FXCH (6 << 29)
|
||||
#define PAIR_FXCH (6ull << 29)
|
||||
|
||||
#define PAIR_FPU (4 << 29)
|
||||
#define PAIR_FPU (4ull << 29)
|
||||
|
||||
#define PAIR_MASK (7 << 29)
|
||||
#define PAIR_MASK (7ull << 29)
|
||||
|
||||
/*Instruction has input dependency on register in REG field*/
|
||||
#define SRCDEP_REG (1 << 9)
|
||||
#define SRCDEP_REG (1ull << 9)
|
||||
/*Instruction has input dependency on register in R/M field*/
|
||||
#define SRCDEP_RM (1 << 10)
|
||||
#define SRCDEP_RM (1ull << 10)
|
||||
/*Instruction modifies register in REG field*/
|
||||
#define DSTDEP_REG (1 << 11)
|
||||
#define DSTDEP_REG (1ull << 11)
|
||||
/*Instruction modifies register in R/M field*/
|
||||
#define DSTDEP_RM (1 << 12)
|
||||
#define DSTDEP_RM (1ull << 12)
|
||||
|
||||
/*Instruction has input dependency on given register*/
|
||||
#define SRCDEP_EAX (1 << 13)
|
||||
#define SRCDEP_ECX (1 << 14)
|
||||
#define SRCDEP_EDX (1 << 15)
|
||||
#define SRCDEP_EBX (1 << 16)
|
||||
#define SRCDEP_ESP (1 << 17)
|
||||
#define SRCDEP_EBP (1 << 18)
|
||||
#define SRCDEP_ESI (1 << 19)
|
||||
#define SRCDEP_EDI (1 << 20)
|
||||
#define SRCDEP_EAX (1ull << 13)
|
||||
#define SRCDEP_ECX (1ull << 14)
|
||||
#define SRCDEP_EDX (1ull << 15)
|
||||
#define SRCDEP_EBX (1ull << 16)
|
||||
#define SRCDEP_ESP (1ull << 17)
|
||||
#define SRCDEP_EBP (1ull << 18)
|
||||
#define SRCDEP_ESI (1ull << 19)
|
||||
#define SRCDEP_EDI (1ull << 20)
|
||||
|
||||
/*Instruction modifies given register*/
|
||||
#define DSTDEP_EAX (1 << 21)
|
||||
#define DSTDEP_ECX (1 << 22)
|
||||
#define DSTDEP_EDX (1 << 23)
|
||||
#define DSTDEP_EBX (1 << 24)
|
||||
#define DSTDEP_ESP (1 << 25)
|
||||
#define DSTDEP_EBP (1 << 26)
|
||||
#define DSTDEP_ESI (1 << 27)
|
||||
#define DSTDEP_EDI (1 << 28)
|
||||
#define DSTDEP_EAX (1ull << 21)
|
||||
#define DSTDEP_ECX (1ull << 22)
|
||||
#define DSTDEP_EDX (1ull << 23)
|
||||
#define DSTDEP_EBX (1ull << 24)
|
||||
#define DSTDEP_ESP (1ull << 25)
|
||||
#define DSTDEP_EBP (1ull << 26)
|
||||
#define DSTDEP_ESI (1ull << 27)
|
||||
#define DSTDEP_EDI (1ull << 28)
|
||||
|
||||
/*Instruction pops the FPU stack*/
|
||||
#define FPU_POP (1ull << 32)
|
||||
/*Instruction pops the FPU stack twice*/
|
||||
#define FPU_POP2 (1ull << 33)
|
||||
/*Instruction pushes onto the FPU stack*/
|
||||
#define FPU_PUSH (1ull << 34)
|
||||
|
||||
/*Instruction writes to ST(0)*/
|
||||
#define FPU_WRITE_ST0 (1ull << 35)
|
||||
/*Instruction reads from ST(0)*/
|
||||
#define FPU_READ_ST0 (1ull << 36)
|
||||
/*Instruction reads from and writes to ST(0)*/
|
||||
#define FPU_RW_ST0 (3ull << 35)
|
||||
|
||||
/*Instruction reads from ST(1)*/
|
||||
#define FPU_READ_ST1 (1ull << 37)
|
||||
/*Instruction writes to ST(1)*/
|
||||
#define FPU_WRITE_ST1 (1ull << 38)
|
||||
/*Instruction reads from and writes to ST(1)*/
|
||||
#define FPU_RW_ST1 (3ull << 37)
|
||||
|
||||
/*Instruction reads from ST(reg)*/
|
||||
#define FPU_READ_STREG (1ull << 39)
|
||||
/*Instruction writes to ST(reg)*/
|
||||
#define FPU_WRITE_STREG (1ull << 40)
|
||||
/*Instruction reads from and writes to ST(reg)*/
|
||||
#define FPU_RW_STREG (3ull << 39)
|
||||
|
||||
/*comp_time = cycles until instruction complete
|
||||
i_overlap = cycles that overlap with integer
|
||||
f_overlap = cycles that overlap with subsequent FPU*/
|
||||
#define FPU_CYCLES(comp_time, i_overlap, f_overlap) ((uint64_t)comp_time) | ((uint64_t)i_overlap << 41) | ((uint64_t)f_overlap << 49) | PAIR_FPU
|
||||
|
||||
#define FPU_COMP_TIME(timing) (timing & 0xff)
|
||||
#define FPU_I_OVERLAP(timing) ((timing >> 41) & 0xff)
|
||||
#define FPU_F_OVERLAP(timing) ((timing >> 49) & 0xff)
|
||||
|
||||
#define FPU_I_LATENCY(timing) (FPU_COMP_TIME(timing) - FPU_I_OVERLAP(timing))
|
||||
|
||||
#define FPU_F_LATENCY(timing) (FPU_I_OVERLAP(timing) - FPU_F_OVERLAP(timing))
|
||||
|
||||
#define FPU_RESULT_LATENCY(timing) ((timing >> 41) & 0xff)
|
||||
|
||||
#define FPU_FXCH (1ull << 56)
|
||||
|
||||
#define INVALID 0
|
||||
|
||||
static int u_pipe_full;
|
||||
static uint32_t u_pipe_opcode;
|
||||
static uint32_t *u_pipe_timings;
|
||||
static uint64_t *u_pipe_timings;
|
||||
static uint32_t u_pipe_op_32;
|
||||
static uint32_t u_pipe_regmask;
|
||||
static uint32_t u_pipe_fetchdat;
|
||||
static int u_pipe_decode_delay_offset;
|
||||
|
||||
static int fpu_latency;
|
||||
static int fpu_st_latency[8];
|
||||
|
||||
#define REGMASK_SHIFTPACK (1 << 8)
|
||||
#define REGMASK_MULTIPLY (1 << 8)
|
||||
|
|
@ -162,7 +214,7 @@ static uint32_t get_dstdep_mask(uint32_t data, uint32_t fetchdat, int bit8)
|
|||
|
||||
return mask;
|
||||
}
|
||||
static uint32_t opcode_timings[256] =
|
||||
static uint64_t opcode_timings[256] =
|
||||
{
|
||||
/* ADD ADD ADD ADD*/
|
||||
/*00*/ PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, PAIR_UV | CYCLES_RM | SRCDEP_REG | DSTDEP_REG,
|
||||
|
|
@ -298,7 +350,7 @@ static uint32_t opcode_timings[256] =
|
|||
PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_UV | CYCLES_RMW, INVALID
|
||||
};
|
||||
|
||||
static uint32_t opcode_timings_mod3[256] =
|
||||
static uint64_t opcode_timings_mod3[256] =
|
||||
{
|
||||
/* ADD ADD ADD ADD*/
|
||||
/*00*/ PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG,
|
||||
|
|
@ -435,7 +487,7 @@ static uint32_t opcode_timings_mod3[256] =
|
|||
PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_UV | CYCLES_REG, INVALID
|
||||
};
|
||||
|
||||
static uint32_t opcode_timings_0f[256] =
|
||||
static uint64_t opcode_timings_0f[256] =
|
||||
{
|
||||
/*00*/ PAIR_NP | CYCLES(20), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(10),
|
||||
INVALID, PAIR_NP | CYCLES(195), PAIR_NP | CYCLES(7), INVALID,
|
||||
|
|
@ -517,7 +569,7 @@ static uint32_t opcode_timings_0f[256] =
|
|||
PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID,
|
||||
PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID,
|
||||
};
|
||||
static uint32_t opcode_timings_0f_mod3[256] =
|
||||
static uint64_t opcode_timings_0f_mod3[256] =
|
||||
{
|
||||
/*00*/ PAIR_NP | CYCLES(20), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(10),
|
||||
INVALID, PAIR_NP | CYCLES(195), PAIR_NP | CYCLES(7), INVALID,
|
||||
|
|
@ -600,53 +652,53 @@ static uint32_t opcode_timings_0f_mod3[256] =
|
|||
PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID,
|
||||
};
|
||||
|
||||
static uint32_t opcode_timings_shift[8] =
|
||||
static uint64_t opcode_timings_shift[8] =
|
||||
{
|
||||
PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW,
|
||||
PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW,
|
||||
};
|
||||
static uint32_t opcode_timings_shift_mod3[8] =
|
||||
static uint64_t opcode_timings_shift_mod3[8] =
|
||||
{
|
||||
PAIR_U | CYCLES_REG | DSTDEP_RM, PAIR_U | CYCLES_REG | DSTDEP_RM, PAIR_U | CYCLES_REG | DSTDEP_RM, PAIR_U | CYCLES_REG | DSTDEP_RM,
|
||||
PAIR_U | CYCLES_REG | DSTDEP_RM, PAIR_U | CYCLES_REG | DSTDEP_RM, PAIR_U | CYCLES_REG | DSTDEP_RM, PAIR_U | CYCLES_REG | DSTDEP_RM,
|
||||
};
|
||||
|
||||
static uint32_t opcode_timings_f6[8] =
|
||||
static uint64_t opcode_timings_f6[8] =
|
||||
{
|
||||
/* TST NOT NEG*/
|
||||
PAIR_UV | CYCLES_RM, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3),
|
||||
/* MUL IMUL DIV IDIV*/
|
||||
PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(17), PAIR_NP | CYCLES(22)
|
||||
};
|
||||
static uint32_t opcode_timings_f6_mod3[8] =
|
||||
static uint64_t opcode_timings_f6_mod3[8] =
|
||||
{
|
||||
/* TST NOT NEG*/
|
||||
PAIR_UV | CYCLES_REG | SRCDEP_RM, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3),
|
||||
/* MUL IMUL DIV IDIV*/
|
||||
PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(17), PAIR_NP | CYCLES(22)
|
||||
};
|
||||
static uint32_t opcode_timings_f7[8] =
|
||||
static uint64_t opcode_timings_f7[8] =
|
||||
{
|
||||
/* TST NOT NEG*/
|
||||
PAIR_UV | CYCLES_RM, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3),
|
||||
/* MUL IMUL DIV IDIV*/
|
||||
PAIR_NP | CYCLES_MULTI(11,10), PAIR_NP | CYCLES_MULTI(11,10), PAIR_NP | CYCLES_MULTI(25,41), PAIR_NP | CYCLES_MULTI(30,46)
|
||||
};
|
||||
static uint32_t opcode_timings_f7_mod3[8] =
|
||||
static uint64_t opcode_timings_f7_mod3[8] =
|
||||
{
|
||||
/* TST NOT NEG*/
|
||||
PAIR_UV | CYCLES_REG | SRCDEP_RM, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3),
|
||||
/* MUL IMUL DIV IDIV*/
|
||||
PAIR_NP | CYCLES_MULTI(11,10), PAIR_NP | CYCLES_MULTI(11,10), PAIR_NP | CYCLES_MULTI(25,41), PAIR_NP | CYCLES_MULTI(30,46)
|
||||
};
|
||||
static uint32_t opcode_timings_ff[8] =
|
||||
static uint64_t opcode_timings_ff[8] =
|
||||
{
|
||||
/* INC DEC CALL CALL far*/
|
||||
PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RMW, PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(0),
|
||||
/* JMP JMP far PUSH*/
|
||||
PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(2), INVALID
|
||||
};
|
||||
static uint32_t opcode_timings_ff_mod3[8] =
|
||||
static uint64_t opcode_timings_ff_mod3[8] =
|
||||
{
|
||||
/* INC DEC CALL CALL far*/
|
||||
PAIR_UV | CYCLES_REG | SRCDEP_RM | DSTDEP_RM, PAIR_UV | CYCLES_REG | SRCDEP_RM | DSTDEP_RM, PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(0),
|
||||
|
|
@ -654,82 +706,83 @@ static uint32_t opcode_timings_ff_mod3[8] =
|
|||
PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(2), INVALID
|
||||
};
|
||||
|
||||
static uint32_t opcode_timings_d8[8] =
|
||||
static uint64_t opcode_timings_d8[8] =
|
||||
{
|
||||
/* FADDs FMULs FCOMs FCOMPs*/
|
||||
PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1),
|
||||
/* FSUBs FSUBRs FDIVs FDIVRs*/
|
||||
PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(39), PAIR_FX | CYCLES(39)
|
||||
/* FADDs FMULs FCOMs FCOMPs*/
|
||||
PAIR_FX | FPU_RW_ST0 | FPU_CYCLES(3,2,2), PAIR_FX | FPU_RW_ST0 | FPU_CYCLES(3,2,2), PAIR_FX | FPU_READ_ST0 | FPU_CYCLES(1,0,0), PAIR_FX | FPU_POP | FPU_READ_ST0 | FPU_CYCLES(1,0,0),
|
||||
/* FSUBs FSUBRs FDIVs FDIVRs*/
|
||||
PAIR_FX | FPU_RW_ST0 | FPU_CYCLES(3,2,2), PAIR_FX | FPU_RW_ST0 | FPU_CYCLES(3,2,2), PAIR_FX | FPU_RW_ST0 | FPU_CYCLES(39,38,2), PAIR_FX | FPU_RW_ST0 | FPU_CYCLES(39,38,2)
|
||||
};
|
||||
static uint32_t opcode_timings_d8_mod3[8] =
|
||||
static uint64_t opcode_timings_d8_mod3[8] =
|
||||
{
|
||||
/* FADD FMUL FCOM FCOMP*/
|
||||
PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1),
|
||||
/* FSUB FSUBR FDIV FDIVR*/
|
||||
PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(39), PAIR_FX | CYCLES(39)
|
||||
/* FADD FMUL FCOM FCOMP*/
|
||||
PAIR_FX | FPU_RW_ST0 | FPU_READ_STREG | FPU_CYCLES(3,2,2), PAIR_FX | FPU_RW_ST0 | FPU_READ_STREG | FPU_CYCLES(3,2,2), PAIR_FX | FPU_READ_ST0 | FPU_READ_STREG | FPU_CYCLES(1,0,0), PAIR_FX | FPU_POP | FPU_READ_ST0 | FPU_READ_STREG | FPU_CYCLES(1,0,0),
|
||||
/* FSUB FSUBR FDIV FDIVR*/
|
||||
PAIR_FX | FPU_RW_ST0 | FPU_READ_STREG | FPU_CYCLES(3,2,2), PAIR_FX | FPU_RW_ST0 | FPU_READ_STREG | FPU_CYCLES(3,2,2), PAIR_FX | FPU_RW_ST0 | FPU_READ_STREG | FPU_CYCLES(39,38,2), PAIR_FX | FPU_RW_ST0 | FPU_READ_STREG | FPU_CYCLES(39,38,2)
|
||||
};
|
||||
|
||||
static uint32_t opcode_timings_d9[8] =
|
||||
static uint64_t opcode_timings_d9[8] =
|
||||
{
|
||||
/* FLDs FSTs FSTPs*/
|
||||
PAIR_FX | CYCLES(1), INVALID, PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2),
|
||||
/* FLDENV FLDCW FSTENV FSTCW*/
|
||||
PAIR_NP | CYCLES(32), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(48), PAIR_NP | CYCLES(2)
|
||||
/* FLDs FSTs FSTPs*/
|
||||
PAIR_FX | FPU_PUSH | FPU_CYCLES(1,0,0), INVALID, PAIR_NP | FPU_READ_ST0 | FPU_CYCLES(2,0,0), PAIR_NP | FPU_READ_ST0 | FPU_POP | FPU_CYCLES(2,0,0),
|
||||
/* FLDENV FLDCW FSTENV FSTCW*/
|
||||
PAIR_NP | FPU_CYCLES(32,0,0), PAIR_NP | FPU_CYCLES(8,0,0), PAIR_NP | FPU_CYCLES(48,0,0), PAIR_NP | FPU_CYCLES(2,0,0)
|
||||
};
|
||||
static uint32_t opcode_timings_d9_mod3[64] =
|
||||
static uint64_t opcode_timings_d9_mod3[64] =
|
||||
{
|
||||
/*FLD*/
|
||||
PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1),
|
||||
PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1),
|
||||
PAIR_FX | FPU_PUSH | FPU_READ_STREG | FPU_CYCLES(1,0,0), PAIR_FX | FPU_PUSH | FPU_READ_STREG | FPU_CYCLES(1,0,0), PAIR_FX | FPU_PUSH | FPU_READ_STREG | FPU_CYCLES(1,0,0), PAIR_FX | FPU_PUSH | FPU_READ_STREG | FPU_CYCLES(1,0,0),
|
||||
PAIR_FX | FPU_PUSH | FPU_READ_STREG | FPU_CYCLES(1,0,0), PAIR_FX | FPU_PUSH | FPU_READ_STREG | FPU_CYCLES(1,0,0), PAIR_FX | FPU_PUSH | FPU_READ_STREG | FPU_CYCLES(1,0,0), PAIR_FX | FPU_PUSH | FPU_READ_STREG | FPU_CYCLES(1,0,0),
|
||||
/*FXCH*/
|
||||
PAIR_V | CYCLES(0), PAIR_V | CYCLES(0), PAIR_V | CYCLES(0), PAIR_V | CYCLES(0),
|
||||
PAIR_V | CYCLES(0), PAIR_V | CYCLES(0), PAIR_V | CYCLES(0), PAIR_V | CYCLES(0),
|
||||
PAIR_FXCH | FPU_FXCH | CYCLES(0), PAIR_FXCH | FPU_FXCH | CYCLES(0), PAIR_FXCH | FPU_FXCH | CYCLES(0), PAIR_FXCH | FPU_FXCH | CYCLES(0),
|
||||
PAIR_FXCH | FPU_FXCH | CYCLES(0), PAIR_FXCH | FPU_FXCH | CYCLES(0), PAIR_FXCH | FPU_FXCH | CYCLES(0), PAIR_FXCH | FPU_FXCH | CYCLES(0),
|
||||
/*FNOP*/
|
||||
PAIR_NP | CYCLES(3), INVALID, INVALID, INVALID,
|
||||
INVALID, INVALID, INVALID, INVALID,
|
||||
PAIR_NP | FPU_CYCLES(3,0,0), INVALID, INVALID, INVALID,
|
||||
INVALID, INVALID, INVALID, INVALID,
|
||||
/*FSTP*/
|
||||
PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1),
|
||||
PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1),
|
||||
/* opFCHS opFABS*/
|
||||
PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(3), INVALID, INVALID,
|
||||
/* opFTST opFXAM*/
|
||||
PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(21), INVALID, INVALID,
|
||||
/* opFLD1 opFLDL2T opFLDL2E opFLDPI*/
|
||||
PAIR_NP | CYCLES(2), CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3),
|
||||
/* opFLDEG2 opFLDLN2 opFLDZ*/
|
||||
PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(2), INVALID,
|
||||
/* opF2XM1 opFYL2X opFPTAN opFPATAN*/
|
||||
PAIR_NP | CYCLES(13), PAIR_NP | CYCLES(22), PAIR_NP | CYCLES(100), PAIR_NP | CYCLES(100),
|
||||
/* opFDECSTP opFINCSTP,*/
|
||||
INVALID, INVALID, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1),
|
||||
/* opFPREM opFSQRT opFSINCOS*/
|
||||
PAIR_NP | CYCLES(70), INVALID, PAIR_NP | CYCLES(70), PAIR_NP | CYCLES(50),
|
||||
/* opFRNDINT opFSCALE opFSIN opFCOS*/
|
||||
PAIR_NP | CYCLES(9), PAIR_NP | CYCLES(20), PAIR_NP | CYCLES(50), PAIR_NP | CYCLES(50)
|
||||
PAIR_NP | FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP | FPU_CYCLES(1,0,0),
|
||||
PAIR_NP | FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP | FPU_CYCLES(1,0,0),
|
||||
/* opFCHS opFABS*/
|
||||
PAIR_FX | FPU_CYCLES(1,0,0), PAIR_FX | FPU_CYCLES(1,0,0), INVALID, INVALID,
|
||||
/* opFTST opFXAM*/
|
||||
PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(21,4,0), INVALID, INVALID,
|
||||
/* opFLD1 opFLDL2T opFLDL2E opFLDPI*/
|
||||
PAIR_NP | FPU_PUSH | FPU_CYCLES(2,0,0), PAIR_NP | FPU_PUSH | FPU_CYCLES(5,2,2), PAIR_NP | FPU_PUSH | FPU_CYCLES(5,2,2), PAIR_NP | FPU_PUSH | FPU_CYCLES(5,2,2),
|
||||
/* opFLDEG2 opFLDLN2 opFLDZ*/
|
||||
PAIR_NP | FPU_PUSH | FPU_CYCLES(5,2,2), PAIR_NP | FPU_PUSH | FPU_CYCLES(5,2,2), PAIR_NP | FPU_PUSH | FPU_CYCLES(2,0,0), INVALID,
|
||||
/* opF2XM1 opFYL2X opFPTAN opFPATAN*/
|
||||
PAIR_NP | FPU_CYCLES(53,2,2), PAIR_NP | FPU_CYCLES(103,2,2), PAIR_NP | FPU_CYCLES(120,36,0), PAIR_NP | FPU_CYCLES(112,2,2),
|
||||
/* opFDECSTP opFINCSTP,*/
|
||||
INVALID, INVALID, PAIR_NP | FPU_CYCLES(2,0,0), PAIR_NP | FPU_CYCLES(2,0,0),
|
||||
/* opFPREM opFSQRT opFSINCOS*/
|
||||
PAIR_NP | FPU_CYCLES(64,2,2), INVALID, PAIR_NP | FPU_CYCLES(70,69,2), PAIR_NP | FPU_CYCLES(89,2,2),
|
||||
/* opFRNDINT opFSCALE opFSIN opFCOS*/
|
||||
PAIR_NP | FPU_CYCLES(9,0,0), PAIR_NP | FPU_CYCLES(20,5,0), PAIR_NP | FPU_CYCLES(65,2,2), PAIR_NP | FPU_CYCLES(65,2,2)
|
||||
};
|
||||
|
||||
static uint32_t opcode_timings_da[8] =
|
||||
static uint64_t opcode_timings_da[8] =
|
||||
{
|
||||
/* FIADDl FIMULl FICOMl FICOMPl*/
|
||||
PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4),
|
||||
/* FISUBl FISUBRl FIDIVl FIDIVRl*/
|
||||
PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(42), PAIR_NP | CYCLES(42)
|
||||
/* FIADDl FIMULl FICOMl FICOMPl*/
|
||||
PAIR_NP | FPU_RW_ST0 | FPU_CYCLES(6,2,2), PAIR_NP | FPU_RW_ST0 | FPU_CYCLES(6,2,2), PAIR_NP | FPU_READ_ST0 | FPU_CYCLES(4,0,0), PAIR_NP | FPU_READ_ST0 | FPU_POP | FPU_CYCLES(4,0,0),
|
||||
/* FISUBl FISUBRl FIDIVl FIDIVRl*/
|
||||
PAIR_NP | FPU_RW_ST0 | FPU_CYCLES(6,2,2), PAIR_NP | FPU_RW_ST0 | FPU_CYCLES(6,2,2), PAIR_NP | FPU_RW_ST0 | FPU_CYCLES(42,38,2), PAIR_NP | FPU_RW_ST0 | FPU_CYCLES(42,38,2)
|
||||
};
|
||||
static uint32_t opcode_timings_da_mod3[8] =
|
||||
static uint64_t opcode_timings_da_mod3[8] =
|
||||
{
|
||||
INVALID, INVALID, INVALID, INVALID,
|
||||
INVALID, PAIR_NP | CYCLES(5), INVALID, INVALID
|
||||
INVALID, INVALID, INVALID, INVALID,
|
||||
/* FCOMPP*/
|
||||
INVALID, PAIR_NP | FPU_POP2 | FPU_CYCLES(1,0,0), INVALID, INVALID
|
||||
};
|
||||
|
||||
|
||||
static uint32_t opcode_timings_db[8] =
|
||||
static uint64_t opcode_timings_db[8] =
|
||||
{
|
||||
/* FLDil FSTil FSTPil*/
|
||||
PAIR_NP | CYCLES(1), INVALID, PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6),
|
||||
/* FLDe FSTPe*/
|
||||
INVALID, PAIR_NP | CYCLES(3), INVALID, PAIR_NP | CYCLES(3)
|
||||
/* FLDil FSTil FSTPil*/
|
||||
PAIR_NP | FPU_PUSH | FPU_CYCLES(3,2,2), INVALID, PAIR_NP | FPU_READ_ST0 | FPU_CYCLES(6,0,0), PAIR_NP | FPU_READ_ST0 | FPU_POP | FPU_CYCLES(6,0,0),
|
||||
/* FLDe FSTPe*/
|
||||
INVALID, PAIR_NP | FPU_PUSH | FPU_CYCLES(3,0,0), INVALID, PAIR_NP | FPU_READ_ST0 | FPU_POP | FPU_CYCLES(3,0,0)
|
||||
};
|
||||
static uint32_t opcode_timings_db_mod3[64] =
|
||||
static uint64_t opcode_timings_db_mod3[64] =
|
||||
{
|
||||
INVALID, INVALID, INVALID, INVALID,
|
||||
INVALID, INVALID, INVALID, INVALID,
|
||||
|
|
@ -743,10 +796,10 @@ static uint32_t opcode_timings_db_mod3[64] =
|
|||
INVALID, INVALID, INVALID, INVALID,
|
||||
INVALID, INVALID, INVALID, INVALID,
|
||||
|
||||
/* opFNOP opFCLEX opFINIT*/
|
||||
INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(17),
|
||||
/* opFNOP opFNOP*/
|
||||
PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), INVALID, INVALID,
|
||||
/* opFNOP opFCLEX opFINIT*/
|
||||
INVALID, PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(7,0,0), PAIR_NP | FPU_CYCLES(17,0,0),
|
||||
/* opFNOP opFNOP*/
|
||||
PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), INVALID, INVALID,
|
||||
|
||||
INVALID, INVALID, INVALID, INVALID,
|
||||
INVALID, INVALID, INVALID, INVALID,
|
||||
|
|
@ -758,82 +811,84 @@ static uint32_t opcode_timings_db_mod3[64] =
|
|||
INVALID, INVALID, INVALID, INVALID,
|
||||
};
|
||||
|
||||
static uint32_t opcode_timings_dc[8] =
|
||||
static uint64_t opcode_timings_dc[8] =
|
||||
{
|
||||
/* FADDd FMULd FCOMd FCOMPd*/
|
||||
PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1),
|
||||
/* FSUBd FSUBRd FDIVd FDIVRd*/
|
||||
PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(39), PAIR_FX | CYCLES(39)
|
||||
/* FADDd FMULd FCOMd FCOMPd*/
|
||||
PAIR_FX | FPU_RW_ST0 | FPU_CYCLES(3,2,2), PAIR_FX | FPU_RW_ST0 | FPU_CYCLES(3,2,2), PAIR_FX | FPU_READ_ST0 | FPU_CYCLES(1,0,0), PAIR_FX | FPU_READ_ST0 | FPU_POP | FPU_CYCLES(1,0,0),
|
||||
/* FSUBd FSUBRd FDIVd FDIVRd*/
|
||||
PAIR_FX | FPU_RW_ST0 | FPU_CYCLES(3,2,2), PAIR_FX | FPU_RW_ST0 | FPU_CYCLES(3,2,2), PAIR_FX | FPU_RW_ST0 | FPU_CYCLES(39,38,2), PAIR_FX | FPU_RW_ST0 | FPU_CYCLES(39,38,2)
|
||||
};
|
||||
static uint32_t opcode_timings_dc_mod3[8] =
|
||||
static uint64_t opcode_timings_dc_mod3[8] =
|
||||
{
|
||||
/* opFADDr opFMULr*/
|
||||
PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), INVALID, INVALID,
|
||||
/* opFSUBRr opFSUBr opFDIVRr opFDIVr*/
|
||||
PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(39), PAIR_FX | CYCLES(39)
|
||||
/* opFADDr opFMULr*/
|
||||
PAIR_FX | FPU_READ_ST0 | FPU_RW_STREG | FPU_CYCLES(3,2,2), PAIR_FX | FPU_READ_ST0 | FPU_RW_STREG | FPU_CYCLES(3,2,2), INVALID, INVALID,
|
||||
/* opFSUBRr opFSUBr opFDIVRr opFDIVr*/
|
||||
PAIR_FX | FPU_READ_ST0 | FPU_RW_STREG | FPU_CYCLES(3,2,2), PAIR_FX | FPU_READ_ST0 | FPU_RW_STREG | FPU_CYCLES(3,2,2), PAIR_FX | FPU_READ_ST0 | FPU_RW_STREG | FPU_CYCLES(39,38,2), PAIR_FX | FPU_READ_ST0 | FPU_RW_STREG | FPU_CYCLES(39,38,2)
|
||||
};
|
||||
|
||||
static uint32_t opcode_timings_dd[8] =
|
||||
static uint64_t opcode_timings_dd[8] =
|
||||
{
|
||||
/* FLDd FSTd FSTPd*/
|
||||
PAIR_FX | CYCLES(1), INVALID, PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2),
|
||||
/* FRSTOR FSAVE FSTSW*/
|
||||
PAIR_NP | CYCLES(70), INVALID, PAIR_NP | CYCLES(127), PAIR_NP | CYCLES(2)
|
||||
/* FLDd FSTd FSTPd*/
|
||||
PAIR_FX | FPU_PUSH | FPU_CYCLES(1,0,0), INVALID, PAIR_NP | FPU_READ_ST0 | FPU_CYCLES(2,0,0), PAIR_NP | FPU_READ_ST0 | FPU_POP | FPU_CYCLES(2,0,0),
|
||||
/* FRSTOR FSAVE FSTSW*/
|
||||
PAIR_NP | FPU_CYCLES(70,0,0), INVALID, PAIR_NP | FPU_CYCLES(127,0,0), PAIR_NP | FPU_CYCLES(6,0,0)
|
||||
};
|
||||
static uint32_t opcode_timings_dd_mod3[8] =
|
||||
static uint64_t opcode_timings_dd_mod3[8] =
|
||||
{
|
||||
/* FFFREE FST FSTP*/
|
||||
PAIR_NP | CYCLES(3), INVALID, PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2),
|
||||
/* FUCOM FUCOMP*/
|
||||
PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), INVALID, INVALID
|
||||
/* FFFREE FST FSTP*/
|
||||
PAIR_NP | FPU_CYCLES(2,0,0), INVALID, PAIR_NP | FPU_READ_ST0 | FPU_WRITE_STREG | FPU_CYCLES(1,0,0), PAIR_NP | FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP | FPU_CYCLES(1,0,0),
|
||||
/* FUCOM FUCOMP*/
|
||||
PAIR_NP | FPU_READ_ST0 | FPU_READ_STREG | FPU_CYCLES(1,0,0), PAIR_NP | FPU_READ_ST0 | FPU_READ_STREG | FPU_POP | FPU_CYCLES(1,0,0), INVALID, INVALID
|
||||
};
|
||||
|
||||
static uint32_t opcode_timings_de[8] =
|
||||
static uint64_t opcode_timings_de[8] =
|
||||
{
|
||||
/* FIADDw FIMULw FICOMw FICOMPw*/
|
||||
PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4),
|
||||
/* FISUBw FISUBRw FIDIVw FIDIVRw*/
|
||||
PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(42), PAIR_NP | CYCLES(42)
|
||||
/* FIADDw FIMULw FICOMw FICOMPw*/
|
||||
PAIR_NP | FPU_RW_ST0 | FPU_CYCLES(6,2,2), PAIR_NP | FPU_RW_ST0 | FPU_CYCLES(6,2,2), PAIR_NP | FPU_READ_ST0 | FPU_CYCLES(4,0,0), PAIR_NP | FPU_READ_ST0 | FPU_POP | FPU_CYCLES(4,0,0),
|
||||
/* FISUBw FISUBRw FIDIVw FIDIVRw*/
|
||||
PAIR_NP | FPU_RW_ST0 | FPU_CYCLES(6,2,2), PAIR_NP | FPU_RW_ST0 | FPU_CYCLES(6,2,2), PAIR_NP | FPU_RW_ST0 | FPU_CYCLES(42,38,2), PAIR_NP | FPU_RW_ST0 | FPU_CYCLES(42,38,2)
|
||||
};
|
||||
static uint32_t opcode_timings_de_mod3[8] =
|
||||
static uint64_t opcode_timings_de_mod3[8] =
|
||||
{
|
||||
/* FADD FMUL FCOMPP*/
|
||||
PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), INVALID, PAIR_FX | CYCLES(1),
|
||||
/* FSUB FSUBR FDIV FDIVR*/
|
||||
PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(39), PAIR_FX | CYCLES(39)
|
||||
/* FADDP FMULP FCOMPP*/
|
||||
PAIR_FX | FPU_READ_ST0 | FPU_RW_STREG | FPU_POP | FPU_CYCLES(3,2,2), PAIR_FX | FPU_READ_ST0 | FPU_RW_STREG | FPU_POP | FPU_CYCLES(3,2,2), INVALID, PAIR_FX | FPU_READ_ST0 | FPU_READ_ST1 | FPU_POP2 | FPU_CYCLES(1,0,0),
|
||||
/* FSUBP FSUBRP FDIVP FDIVRP*/
|
||||
PAIR_FX | FPU_READ_ST0 | FPU_RW_STREG | FPU_POP | FPU_CYCLES(3,2,2), PAIR_FX | FPU_READ_ST0 | FPU_RW_STREG | FPU_POP | FPU_CYCLES(3,2,2), PAIR_FX | FPU_READ_ST0 | FPU_RW_STREG | FPU_POP | FPU_CYCLES(39,38,2), PAIR_FX | FPU_READ_ST0 | FPU_RW_STREG | FPU_POP | FPU_CYCLES(39,38,2)
|
||||
};
|
||||
|
||||
static uint32_t opcode_timings_df[8] =
|
||||
static uint64_t opcode_timings_df[8] =
|
||||
{
|
||||
/* FILDiw FISTiw FISTPiw*/
|
||||
PAIR_NP | CYCLES(1), INVALID, PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6),
|
||||
/* FILDiq FBSTP FISTPiq*/
|
||||
INVALID, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(148), PAIR_NP | CYCLES(6)
|
||||
/* FILDiw FISTiw FISTPiw*/
|
||||
PAIR_NP | FPU_PUSH | FPU_CYCLES(3,2,2), INVALID, PAIR_NP | FPU_READ_ST0 | FPU_CYCLES(6,0,0), PAIR_NP | FPU_READ_ST0 | FPU_POP | FPU_CYCLES(6,0,0),
|
||||
/* FILDiq FBSTP FISTPiq*/
|
||||
INVALID, PAIR_NP | FPU_PUSH | FPU_CYCLES(3,2,2), PAIR_NP | FPU_READ_ST0 | FPU_POP | FPU_CYCLES(148,0,0), PAIR_NP | FPU_READ_ST0 | FPU_POP | FPU_CYCLES(6,0,0)
|
||||
};
|
||||
static uint32_t opcode_timings_df_mod3[8] =
|
||||
static uint64_t opcode_timings_df_mod3[8] =
|
||||
{
|
||||
INVALID, INVALID, INVALID, INVALID,
|
||||
INVALID, INVALID, INVALID, INVALID,
|
||||
/* FSTSW AX*/
|
||||
PAIR_NP | CYCLES(2), INVALID, INVALID, INVALID
|
||||
PAIR_NP | FPU_CYCLES(6,0,0), INVALID, INVALID, INVALID
|
||||
};
|
||||
|
||||
static uint32_t opcode_timings_81[8] =
|
||||
static uint64_t opcode_timings_81[8] =
|
||||
{
|
||||
PAIR_UV | CYCLES_RMW | SRCDEP_REG | CYCLES_IMM1632, PAIR_UV | CYCLES_RMW | SRCDEP_REG | CYCLES_IMM1632, PAIR_UV | CYCLES_RMW | SRCDEP_REG | CYCLES_IMM1632, PAIR_UV | CYCLES_RMW | SRCDEP_REG | CYCLES_IMM1632,
|
||||
PAIR_UV | CYCLES_RMW | SRCDEP_REG | CYCLES_IMM1632, PAIR_UV | CYCLES_RMW | SRCDEP_REG | CYCLES_IMM1632, PAIR_UV | CYCLES_RMW | SRCDEP_REG | CYCLES_IMM1632, PAIR_UV | CYCLES_RM | SRCDEP_REG | CYCLES_IMM1632
|
||||
};
|
||||
static uint32_t opcode_timings_8x[8] =
|
||||
static uint64_t opcode_timings_8x[8] =
|
||||
{
|
||||
PAIR_UV | CYCLES_RMW | SRCDEP_REG | CYCLES_IMM8, PAIR_UV | CYCLES_RMW | SRCDEP_REG | CYCLES_IMM8, PAIR_UV | CYCLES_RMW | SRCDEP_REG | CYCLES_IMM8, PAIR_UV | CYCLES_RMW | SRCDEP_REG | CYCLES_IMM8,
|
||||
PAIR_UV | CYCLES_RMW | SRCDEP_REG | CYCLES_IMM8, PAIR_UV | CYCLES_RMW | SRCDEP_REG | CYCLES_IMM8, PAIR_UV | CYCLES_RMW | SRCDEP_REG | CYCLES_IMM8, PAIR_UV | CYCLES_RM | SRCDEP_REG | CYCLES_IMM8
|
||||
};
|
||||
|
||||
static int decode_delay;
|
||||
static int decode_delay, decode_delay_offset;
|
||||
static uint8_t last_prefix;
|
||||
static int prefixes;
|
||||
|
||||
static inline int COUNT(uint32_t c, int op_32)
|
||||
static inline int COUNT(uint64_t c, int op_32)
|
||||
{
|
||||
if ((c & PAIR_FPU) && !(c & FPU_FXCH))
|
||||
return FPU_I_LATENCY(c);
|
||||
if (c & CYCLES_HAS_MULTI)
|
||||
{
|
||||
if (op_32 & 0x100)
|
||||
|
|
@ -860,11 +915,43 @@ static inline int COUNT(uint32_t c, int op_32)
|
|||
return cpu_hasMMX ? 1 : 2;
|
||||
}
|
||||
|
||||
fatal("Illegal COUNT %08x\n", c);
|
||||
fatal("Illegal COUNT %016llx\n", c);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static int codegen_fpu_latencies(uint64_t timings, int reg)
|
||||
{
|
||||
int latency = fpu_latency;
|
||||
|
||||
if ((timings & FPU_RW_ST0) && fpu_st_latency[0] && fpu_st_latency[0] > latency)
|
||||
latency = fpu_st_latency[0];
|
||||
if ((timings & FPU_RW_ST1) && fpu_st_latency[1] && fpu_st_latency[1] > latency)
|
||||
latency = fpu_st_latency[1];
|
||||
if ((timings & FPU_RW_STREG) && fpu_st_latency[reg] && fpu_st_latency[reg] > latency)
|
||||
latency = fpu_st_latency[reg];
|
||||
|
||||
return latency;
|
||||
}
|
||||
|
||||
#define SUB_AND_CLAMP(latency, count) \
|
||||
latency -= count; \
|
||||
if (latency < 0) \
|
||||
latency = 0
|
||||
|
||||
static void codegen_fpu_latency_clock(int count)
|
||||
{
|
||||
SUB_AND_CLAMP(fpu_latency, count);
|
||||
SUB_AND_CLAMP(fpu_st_latency[0], count);
|
||||
SUB_AND_CLAMP(fpu_st_latency[1], count);
|
||||
SUB_AND_CLAMP(fpu_st_latency[2], count);
|
||||
SUB_AND_CLAMP(fpu_st_latency[3], count);
|
||||
SUB_AND_CLAMP(fpu_st_latency[4], count);
|
||||
SUB_AND_CLAMP(fpu_st_latency[5], count);
|
||||
SUB_AND_CLAMP(fpu_st_latency[6], count);
|
||||
SUB_AND_CLAMP(fpu_st_latency[7], count);
|
||||
}
|
||||
|
||||
static inline int codegen_timing_has_displacement(uint32_t fetchdat, int op_32)
|
||||
{
|
||||
if (op_32 & 0x200)
|
||||
|
|
@ -891,7 +978,7 @@ static inline int codegen_timing_has_displacement(uint32_t fetchdat, int op_32)
|
|||
|
||||
/*The instruction is only of interest here if it's longer than 7 bytes, as that's the
|
||||
limit on Pentium MMX parallel decoding*/
|
||||
static inline int codegen_timing_instr_length(uint32_t timing, uint32_t fetchdat, int op_32)
|
||||
static inline int codegen_timing_instr_length(uint64_t timing, uint32_t fetchdat, int op_32)
|
||||
{
|
||||
int len = prefixes;
|
||||
if ((timing & CYCLES_MASK) == CYCLES_RM || (timing & CYCLES_MASK) == CYCLES_RMW)
|
||||
|
|
@ -941,7 +1028,7 @@ static inline int codegen_timing_instr_length(uint32_t timing, uint32_t fetchdat
|
|||
|
||||
void codegen_timing_pentium_block_start()
|
||||
{
|
||||
u_pipe_full = decode_delay = 0;
|
||||
u_pipe_full = decode_delay = decode_delay_offset = 0;
|
||||
}
|
||||
|
||||
void codegen_timing_pentium_start()
|
||||
|
|
@ -954,6 +1041,11 @@ void codegen_timing_pentium_start()
|
|||
void codegen_timing_pentium_prefix(uint8_t prefix, uint32_t fetchdat)
|
||||
{
|
||||
prefixes++;
|
||||
if ((prefix & 0xf8) == 0xd8)
|
||||
{
|
||||
last_prefix = prefix;
|
||||
return;
|
||||
}
|
||||
if (cpu_hasMMX && prefix == 0x0f)
|
||||
{
|
||||
/*On Pentium MMX 0fh prefix is 'free'*/
|
||||
|
|
@ -963,7 +1055,7 @@ void codegen_timing_pentium_prefix(uint8_t prefix, uint32_t fetchdat)
|
|||
if (cpu_hasMMX && (prefix == 0x66 || prefix == 0x67))
|
||||
{
|
||||
/*On Pentium MMX 66h and 67h prefixes take 2 clocks*/
|
||||
decode_delay += 2;
|
||||
decode_delay_offset += 2;
|
||||
last_prefix = prefix;
|
||||
return;
|
||||
}
|
||||
|
|
@ -975,13 +1067,100 @@ void codegen_timing_pentium_prefix(uint8_t prefix, uint32_t fetchdat)
|
|||
}
|
||||
/*On Pentium all prefixes take 1 cycle to decode. Decode may be shadowed
|
||||
by execution of previous instructions*/
|
||||
decode_delay++;
|
||||
decode_delay_offset++;
|
||||
last_prefix = prefix;
|
||||
}
|
||||
|
||||
static void codegen_instruction(uint64_t *timings, uint8_t opcode, uint32_t fetchdat, int decode_delay_offset, int op_32)
|
||||
{
|
||||
int instr_cycles, latency = 0;
|
||||
|
||||
if ((timings[opcode] & PAIR_FPU) && !(timings[opcode] & FPU_FXCH))
|
||||
instr_cycles = latency = codegen_fpu_latencies(timings[opcode], fetchdat & 7);
|
||||
else
|
||||
{
|
||||
/* if (timings[opcode] & FPU_WRITE_ST0)
|
||||
fatal("FPU_WRITE_ST0\n");
|
||||
if (timings[opcode] & FPU_WRITE_ST1)
|
||||
fatal("FPU_WRITE_ST1\n");
|
||||
if (timings[opcode] & FPU_WRITE_STREG)
|
||||
fatal("FPU_WRITE_STREG\n");*/
|
||||
instr_cycles = 0;
|
||||
}
|
||||
|
||||
if ((decode_delay + decode_delay_offset) > 0)
|
||||
codegen_fpu_latency_clock(decode_delay + decode_delay_offset + instr_cycles);
|
||||
else
|
||||
codegen_fpu_latency_clock(instr_cycles);
|
||||
instr_cycles += COUNT(timings[opcode], op_32);
|
||||
if ((decode_delay + decode_delay_offset) > 0)
|
||||
codegen_block_cycles += instr_cycles + decode_delay + decode_delay_offset;
|
||||
else
|
||||
codegen_block_cycles += instr_cycles;
|
||||
decode_delay = (-instr_cycles) + 1;
|
||||
|
||||
if (timings[opcode] & FPU_POP)
|
||||
{
|
||||
int c;
|
||||
|
||||
for (c = 0; c < 7; c++)
|
||||
fpu_st_latency[c] = fpu_st_latency[c+1];
|
||||
fpu_st_latency[7] = 0;
|
||||
}
|
||||
if (timings[opcode] & FPU_POP2)
|
||||
{
|
||||
int c;
|
||||
|
||||
for (c = 0; c < 6; c++)
|
||||
fpu_st_latency[c] = fpu_st_latency[c+2];
|
||||
fpu_st_latency[6] = fpu_st_latency[7] = 0;
|
||||
}
|
||||
if ((timings[opcode] & PAIR_FPU) && !(timings[opcode] & FPU_FXCH))
|
||||
{
|
||||
/* if (fpu_latency)
|
||||
fatal("Bad latency FPU\n");*/
|
||||
fpu_latency = FPU_F_LATENCY(timings[opcode]);
|
||||
}
|
||||
|
||||
if (timings[opcode] & FPU_PUSH)
|
||||
{
|
||||
int c;
|
||||
|
||||
for (c = 0; c < 7; c++)
|
||||
fpu_st_latency[c+1] = fpu_st_latency[c];
|
||||
fpu_st_latency[0] = 0;
|
||||
}
|
||||
if (timings[opcode] & FPU_WRITE_ST0)
|
||||
{
|
||||
/* if (fpu_st_latency[0])
|
||||
fatal("Bad latency ST0\n");*/
|
||||
fpu_st_latency[0] = FPU_RESULT_LATENCY(timings[opcode]);
|
||||
}
|
||||
if (timings[opcode] & FPU_WRITE_ST1)
|
||||
{
|
||||
/* if (fpu_st_latency[1])
|
||||
fatal("Bad latency ST1\n");*/
|
||||
fpu_st_latency[1] = FPU_RESULT_LATENCY(timings[opcode]);
|
||||
}
|
||||
if (timings[opcode] & FPU_WRITE_STREG)
|
||||
{
|
||||
int reg = fetchdat & 7;
|
||||
if (timings[opcode] & FPU_POP)
|
||||
reg--;
|
||||
if (reg >= 0 &&
|
||||
!(reg == 0 && (timings[opcode] & FPU_WRITE_ST0)) &&
|
||||
!(reg == 1 && (timings[opcode] & FPU_WRITE_ST1)))
|
||||
{
|
||||
/* if (fpu_st_latency[reg])
|
||||
fatal("Bad latency STREG %i %08x %i %016llx %02x\n",fpu_st_latency[reg], fetchdat, reg, timings[opcode], opcode);*/
|
||||
fpu_st_latency[reg] = FPU_RESULT_LATENCY(timings[opcode]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void codegen_timing_pentium_opcode(uint8_t opcode, uint32_t fetchdat, int op_32)
|
||||
{
|
||||
uint32_t *timings;
|
||||
uint64_t *timings;
|
||||
int mod3 = ((fetchdat & 0xc0) == 0xc0);
|
||||
int bit8 = !(opcode & 1);
|
||||
|
||||
|
|
@ -1078,9 +1257,6 @@ void codegen_timing_pentium_opcode(uint8_t opcode, uint32_t fetchdat, int op_32)
|
|||
}
|
||||
}
|
||||
|
||||
if (decode_delay < 0)
|
||||
decode_delay = 0;
|
||||
|
||||
if (u_pipe_full)
|
||||
{
|
||||
uint8_t regmask = get_srcdep_mask(timings[opcode], fetchdat, bit8);
|
||||
|
|
@ -1092,8 +1268,24 @@ void codegen_timing_pentium_opcode(uint8_t opcode, uint32_t fetchdat, int op_32)
|
|||
if ((timings[opcode] & PAIR_MASK) == PAIR_FXCH &&
|
||||
(u_pipe_timings[u_pipe_opcode] & PAIR_MASK) != PAIR_FX)
|
||||
goto nopair;
|
||||
|
||||
if ((u_pipe_timings[u_pipe_opcode] & PAIR_MASK) == PAIR_FX &&
|
||||
(timings[opcode] & PAIR_MASK) == PAIR_FXCH)
|
||||
{
|
||||
int temp;
|
||||
|
||||
codegen_instruction(u_pipe_timings, u_pipe_opcode, u_pipe_fetchdat, u_pipe_decode_delay_offset, u_pipe_op_32);
|
||||
|
||||
temp = fpu_st_latency[fetchdat & 7];
|
||||
fpu_st_latency[fetchdat & 7] = fpu_st_latency[0];
|
||||
fpu_st_latency[0] = temp;
|
||||
|
||||
u_pipe_full = 0;
|
||||
decode_delay_offset = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((timings[opcode] & PAIR_V) && !(u_pipe_regmask & regmask) && !decode_delay)
|
||||
if ((timings[opcode] & PAIR_V) && !(u_pipe_regmask & regmask) && (decode_delay+decode_delay_offset+u_pipe_decode_delay_offset) <= 0)
|
||||
{
|
||||
int has_displacement;
|
||||
|
||||
|
|
@ -1107,6 +1299,7 @@ void codegen_timing_pentium_opcode(uint8_t opcode, uint32_t fetchdat, int op_32)
|
|||
int t1 = u_pipe_timings[u_pipe_opcode] & CYCLES_MASK;
|
||||
int t2 = timings[opcode] & CYCLES_MASK;
|
||||
int t_pair;
|
||||
uint64_t temp_timing;
|
||||
|
||||
if (!(u_pipe_timings[u_pipe_opcode] & PAIR_FPU))
|
||||
t1 &= 3;
|
||||
|
|
@ -1119,26 +1312,23 @@ void codegen_timing_pentium_opcode(uint8_t opcode, uint32_t fetchdat, int op_32)
|
|||
t_pair = pair_timings[t1][t2];
|
||||
if (t_pair < 1)
|
||||
fatal("Illegal pair timings : t1=%i t2=%i u_opcode=%02x v_opcode=%02x\n", t1, t2, u_pipe_opcode, opcode);
|
||||
|
||||
// pclog("Paired timings : t_pair=%i t1=%i t2=%i u_opcode=%02x v_opcode=%02x %08x:%08x\n", t_pair, t1, t2, u_pipe_opcode, opcode, cs, pc);
|
||||
codegen_block_cycles += t_pair;
|
||||
decode_delay = (-t_pair) + 1;
|
||||
|
||||
|
||||
/*Instruction can pair with previous*/
|
||||
temp_timing = t_pair;
|
||||
codegen_instruction(&temp_timing, 0, 0, 0, 0);
|
||||
u_pipe_full = 0;
|
||||
decode_delay_offset = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
nopair:
|
||||
/*Instruction can not pair with previous*/
|
||||
/*Run previous now*/
|
||||
codegen_block_cycles += COUNT(u_pipe_timings[u_pipe_opcode], u_pipe_op_32) + decode_delay;
|
||||
decode_delay = (-COUNT(u_pipe_timings[u_pipe_opcode], u_pipe_op_32)) + 1;
|
||||
codegen_instruction(u_pipe_timings, u_pipe_opcode, u_pipe_fetchdat, u_pipe_decode_delay_offset, u_pipe_op_32);
|
||||
u_pipe_full = 0;
|
||||
// pclog("Evicited U-pipe timings : t1=%i u_opcode=%02x decode_delay=%i %08x:%08x\n", COUNT(u_pipe_timings[u_pipe_opcode], u_pipe_op_32), u_pipe_opcode, decode_delay, cs, pc);
|
||||
}
|
||||
|
||||
if ((timings[opcode] & PAIR_U) && !decode_delay)
|
||||
if ((timings[opcode] & PAIR_U) && (decode_delay + decode_delay_offset) <= 0)
|
||||
{
|
||||
int has_displacement;
|
||||
|
||||
|
|
@ -1155,14 +1345,15 @@ nopair:
|
|||
u_pipe_timings = timings;
|
||||
u_pipe_op_32 = op_32;
|
||||
u_pipe_regmask = get_dstdep_mask(timings[opcode], fetchdat, bit8);
|
||||
u_pipe_fetchdat = fetchdat;
|
||||
u_pipe_decode_delay_offset = decode_delay_offset;
|
||||
decode_delay_offset = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/*Instruction can not pair and must run now*/
|
||||
|
||||
codegen_block_cycles += COUNT(timings[opcode], op_32) + decode_delay;
|
||||
decode_delay = (-COUNT(timings[opcode], op_32)) + 1;
|
||||
// pclog("Non-pairable timings : %08x t1=%i opcode=%02x mod3=%i decode_delay=%i %08x:%08x %08x %p %p\n", timings[opcode], COUNT(timings[opcode], op_32), opcode, mod3, decode_delay, cs, pc, opcode_timings[0x04], (void *)timings, (void *)opcode_timings);
|
||||
codegen_instruction(timings, opcode, fetchdat, decode_delay_offset, op_32);
|
||||
decode_delay_offset = 0;
|
||||
}
|
||||
|
||||
void codegen_timing_pentium_block_end()
|
||||
|
|
@ -1170,7 +1361,7 @@ void codegen_timing_pentium_block_end()
|
|||
if (u_pipe_full)
|
||||
{
|
||||
/*Run previous now*/
|
||||
codegen_block_cycles += COUNT(u_pipe_timings[u_pipe_opcode], u_pipe_op_32) + decode_delay;
|
||||
codegen_block_cycles += COUNT(u_pipe_timings[u_pipe_opcode], u_pipe_op_32) + decode_delay + decode_delay_offset;
|
||||
u_pipe_full = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue