From fb4e1f071582da4f2d31a6c1858e58b93e6b5837 Mon Sep 17 00:00:00 2001 From: SarahW Date: Sun, 18 Jun 2017 15:48:20 +0100 Subject: [PATCH] Implemented Pentium FPU latencies. --- src/codegen_timing_pentium.c | 543 +++++++++++++++++++++++------------ 1 file changed, 367 insertions(+), 176 deletions(-) diff --git a/src/codegen_timing_pentium.c b/src/codegen_timing_pentium.c index 05b0f91..fbac3b8 100644 --- a/src/codegen_timing_pentium.c +++ b/src/codegen_timing_pentium.c @@ -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; } }