#include "ibm.h"
#include "cpu.h"
#include "x86.h"
#include "x86_ops.h"
#include "x87.h"
#include "mem.h"
#include "codegen.h"
#include "codegen_ops.h"
#include "codegen_timing_common.h"

#define CYCLES(c) (int *)c
#define CYCLES2(c16, c32) (int *)((-1 & ~0xffff) | c16 | (c32 << 8))

static int *opcode_timings[256] =
	{
/*00*/  &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), NULL,
/*10*/  &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3),
/*20*/  &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3),
/*30*/  &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2),

/*40*/  &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr,
/*50*/  CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1),
/*60*/  CYCLES(11), CYCLES(9), CYCLES(7), CYCLES(9), CYCLES(4), CYCLES(4), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES2(17, 25), CYCLES(1), CYCLES2(17, 20), CYCLES(17), CYCLES(17), CYCLES(17), CYCLES(17),
/*70*/  &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt,
		&timing_bnt, &timing_bnt,

/*80*/  &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm, &timing_rm, CYCLES(5), CYCLES(5), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(3), CYCLES(1), CYCLES(5), CYCLES(6),
/*90*/  CYCLES(1), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(0), CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(2), CYCLES(3),
/*a0*/  CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(7), CYCLES(7), CYCLES(8), CYCLES(8), CYCLES(1), CYCLES(1), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6),
/*b0*/  &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr,

/*c0*/  CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), CYCLES(1), CYCLES(1), CYCLES(14), CYCLES(5), CYCLES(0), CYCLES(0), &timing_int, &timing_int, CYCLES(3), CYCLES(0),
/*d0*/  CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(15), CYCLES(14), CYCLES(2), CYCLES(4), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*e0*/  CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(5), CYCLES(14), CYCLES(14), CYCLES(16), CYCLES(16), CYCLES(3), CYCLES(3), CYCLES(17), CYCLES(3), CYCLES(14), CYCLES(14), CYCLES(14), CYCLES(14),
/*f0*/  CYCLES(4), CYCLES(0), CYCLES(0), CYCLES(0), CYCLES(4), CYCLES(2), NULL, NULL, CYCLES(2), CYCLES(2), CYCLES(3), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(3), NULL
	};

static int *opcode_timings_mod3[256] =
	{
/*00*/  &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), NULL,
/*10*/  &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3),
/*20*/  &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3),
/*30*/  &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2),

/*40*/  &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr,
/*50*/  CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1),
/*60*/  CYCLES(11), CYCLES(9), CYCLES(7), CYCLES(9), CYCLES(4), CYCLES(4), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES2(14, 25), CYCLES(1), CYCLES2(17, 20), CYCLES(17), CYCLES(17), CYCLES(17), CYCLES(17),
/*70*/  &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt,
		&timing_bnt, &timing_bnt,

/*80*/  &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(5), CYCLES(5), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(1), CYCLES(2), CYCLES(1),
/*90*/  CYCLES(1), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(0), CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(2), CYCLES(3),
/*a0*/  CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(7), CYCLES(7), CYCLES(8), CYCLES(8), CYCLES(1), CYCLES(1), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6),
/*b0*/  &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr,

/*c0*/  CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), CYCLES(1), CYCLES(1), CYCLES(14), CYCLES(5), CYCLES(0), CYCLES(0), &timing_int, &timing_int, CYCLES(3), CYCLES(0),
/*d0*/  CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(15), CYCLES(14), CYCLES(2), CYCLES(4), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*e0*/  CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(5), CYCLES(14), CYCLES(14), CYCLES(16), CYCLES(16), CYCLES(3), CYCLES(3), CYCLES(17), CYCLES(3), CYCLES(14), CYCLES(14), CYCLES(14), CYCLES(14),
/*f0*/  CYCLES(4), CYCLES(0), CYCLES(0), CYCLES(0), CYCLES(4), CYCLES(2), NULL, NULL, CYCLES(2), CYCLES(2), CYCLES(3), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(3), NULL
	};

static int *opcode_timings_0f[256] =
	{
/*00*/  CYCLES(20), CYCLES(11), CYCLES(11), CYCLES(10), NULL, CYCLES(195), CYCLES(7), NULL, CYCLES(1000), CYCLES(10000), NULL, NULL, NULL, NULL, NULL, NULL,
/*10*/  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*20*/  CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*30*/  CYCLES(9), CYCLES(1), CYCLES(9), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,

/*40*/  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*50*/  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*60*/  &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, NULL, NULL, &timing_rm, &timing_rm,
/*70*/  NULL, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, CYCLES(100), NULL, NULL, NULL, NULL, NULL, NULL, &timing_rm, &timing_rm,

/*80*/  &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt,
		&timing_bnt, &timing_bnt,
/*90*/  CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3),
/*a0*/  CYCLES(3), CYCLES(3), CYCLES(14), CYCLES(8), CYCLES(3), CYCLES(4), NULL, NULL, CYCLES(3), CYCLES(3), NULL, CYCLES(13), CYCLES(3), CYCLES(3), NULL, CYCLES2(18, 30),
/*b0*/  CYCLES(10), CYCLES(10), CYCLES(6), CYCLES(13), CYCLES(6), CYCLES(6), CYCLES(3), CYCLES(3), NULL, NULL, CYCLES(6), CYCLES(13), CYCLES(7), CYCLES(7), CYCLES(3), CYCLES(3),

/*c0*/  CYCLES(4), CYCLES(4), NULL, NULL, NULL, NULL, NULL, CYCLES(3), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1),
/*d0*/  NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm,
/*e0*/  NULL, &timing_rm, &timing_rm, NULL, NULL, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm,
/*f0*/  NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, &timing_rm, &timing_rm, NULL,
	};
static int *opcode_timings_0f_mod3[256] =
	{
/*00*/  CYCLES(20), CYCLES(11), CYCLES(11), CYCLES(10), NULL, CYCLES(195), CYCLES(7), NULL, CYCLES(1000), CYCLES(10000), NULL, NULL, NULL, NULL, NULL, NULL,
/*10*/  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*20*/  CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*30*/  CYCLES(9), CYCLES(1), CYCLES(9), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,

/*40*/  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*50*/  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*60*/  &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, NULL, NULL, &timing_rr, &timing_rr,
/*70*/  NULL, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(100), NULL, NULL, NULL, NULL, NULL, NULL, &timing_rr, &timing_rr,

/*80*/  &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt,
		&timing_bnt, &timing_bnt,
/*90*/  CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3),
/*a0*/  CYCLES(3), CYCLES(3), CYCLES(14), CYCLES(8), CYCLES(3), CYCLES(4), NULL, NULL, CYCLES(3), CYCLES(3), NULL, CYCLES(13), CYCLES(3), CYCLES(3), NULL, CYCLES2(18, 30),
/*b0*/  CYCLES(10), CYCLES(10), CYCLES(6), CYCLES(13), CYCLES(6), CYCLES(6), CYCLES(3), CYCLES(3), NULL, NULL, CYCLES(6), CYCLES(13), CYCLES(7), CYCLES(7), CYCLES(3), CYCLES(3),

/*c0*/  CYCLES(4), CYCLES(4), NULL, NULL, NULL, NULL, NULL, CYCLES(3), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1),
/*d0*/  NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr,
/*e0*/  NULL, &timing_rr, &timing_rr, NULL, NULL, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr,
/*f0*/  NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, &timing_rr, &timing_rr, NULL,
	};

static int *opcode_timings_shift[8] =
	{
		CYCLES(7), CYCLES(7), CYCLES(10), CYCLES(10), CYCLES(7), CYCLES(7), CYCLES(7), CYCLES(7)
	};
static int *opcode_timings_shift_mod3[8] =
	{
		CYCLES(3), CYCLES(3), CYCLES(9), CYCLES(9), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3)
	};

static int *opcode_timings_f6[8] =
	{
		&timing_rm, NULL, &timing_mm, &timing_mm, CYCLES(13), CYCLES(14), CYCLES(16), CYCLES(19)
	};
static int *opcode_timings_f6_mod3[8] =
	{
		&timing_rr, NULL, &timing_rr, &timing_rr, CYCLES(13), CYCLES(14), CYCLES(16), CYCLES(19)
	};
static int *opcode_timings_f7[8] =
	{
		&timing_rm, NULL, &timing_mm, &timing_mm, CYCLES(21), CYCLES2(22, 38), CYCLES2(24, 40), CYCLES2(27, 43)
	};
static int *opcode_timings_f7_mod3[8] =
	{
		&timing_rr, NULL, &timing_rr, &timing_rr, CYCLES(21), CYCLES2(22, 38), CYCLES2(24, 40), CYCLES2(27, 43)
	};
static int *opcode_timings_ff[8] =
	{
		&timing_mm, &timing_mm, CYCLES(5), CYCLES(0), CYCLES(5), CYCLES(0), CYCLES(5), NULL
	};
static int *opcode_timings_ff_mod3[8] =
	{
		&timing_rr, &timing_rr, CYCLES(5), CYCLES(0), CYCLES(5), CYCLES(0), CYCLES(5), NULL
	};

static int *opcode_timings_d8[8] =
	{
/*      FADDil          FMULil          FCOMil          FCOMPil         FSUBil          FSUBRil         FDIVil          FDIVRil*/
		CYCLES(10), CYCLES(12), CYCLES(9), CYCLES(9), CYCLES(10), CYCLES(10), CYCLES(78), CYCLES(78)
	};
static int *opcode_timings_d8_mod3[8] =
	{
/*      FADD            FMUL            FCOM            FCOMP           FSUB            FSUBR           FDIV            FDIVR*/
		CYCLES(4), CYCLES(6), CYCLES(3), CYCLES(3), CYCLES(4), CYCLES(4), CYCLES(72), CYCLES(72)
	};

static int *opcode_timings_d9[8] =
	{
/*      FLDs                            FSTs            FSTPs           FLDENV          FLDCW           FSTENV          FSTCW*/
		CYCLES(2), NULL, CYCLES(7), CYCLES(7), CYCLES(34), CYCLES(4), CYCLES(67), CYCLES(3)
	};
static int *opcode_timings_d9_mod3[64] =
	{
		/*FLD*/
		CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1),
		/*FXCH*/
		CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4),
		/*FNOP*/
		CYCLES(7), NULL, NULL, NULL, NULL, NULL, NULL, NULL,
		/*FSTP*/
		CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1),
/*      opFCHS          opFABS                                          opFTST          opFXAM*/
		CYCLES(2), CYCLES(2), NULL, NULL, CYCLES(5), CYCLES(7), NULL, NULL,
/*      opFLD1          opFLDL2T        opFLDL2E        opFLDPI         opFLDEG2        opFLDLN2        opFLDZ*/
		CYCLES(5), CYCLES(7), CYCLES(7), CYCLES(7), CYCLES(7), CYCLES(7), CYCLES(5), NULL,
/*      opF2XM1         opFYL2X         opFPTAN         opFPATAN                                        opFDECSTP       opFINCSTP,*/
		CYCLES(300), CYCLES(58), CYCLES(676), CYCLES(355), NULL, NULL, CYCLES(3), CYCLES(3),
/*      opFPREM                         opFSQRT         opFSINCOS       opFRNDINT       opFSCALE        opFSIN          opFCOS*/
		CYCLES(70), NULL, CYCLES(72), CYCLES(292), CYCLES(21), CYCLES(30), CYCLES(474), CYCLES(474)
	};

static int *opcode_timings_da[8] =
	{
/*      FADDil          FMULil          FCOMil          FCOMPil         FSUBil          FSUBRil         FDIVil          FDIVRil*/
		CYCLES(10), CYCLES(12), CYCLES(9), CYCLES(9), CYCLES(10), CYCLES(10), CYCLES(78), CYCLES(78)
	};
static int *opcode_timings_da_mod3[8] =
	{
		NULL, NULL, NULL, NULL, NULL, CYCLES(5), NULL, NULL
	};

static int *opcode_timings_db[8] =
	{
/*      FLDil                           FSTil           FSTPil                          FLDe                            FSTPe*/
		CYCLES(6), NULL, CYCLES(7), CYCLES(7), NULL, CYCLES(8), NULL, CYCLES(8)
	};
static int *opcode_timings_db_mod3[64] =
	{
		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*                      opFNOP          opFCLEX         opFINIT         opFNOP          opFNOP*/
		NULL, CYCLES(7), CYCLES(18), CYCLES(27), CYCLES(7), CYCLES(7), NULL,
		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	};

static int *opcode_timings_dc[8] =
	{
/*      opFADDd_a16     opFMULd_a16     opFCOMd_a16     opFCOMPd_a16    opFSUBd_a16     opFSUBRd_a16    opFDIVd_a16     opFDIVRd_a16*/
		CYCLES(6), CYCLES(8), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), CYCLES(74), CYCLES(74)
	};
static int *opcode_timings_dc_mod3[8] =
	{
/*      opFADDr         opFMULr                                         opFSUBRr        opFSUBr         opFDIVRr        opFDIVr*/
		CYCLES(4), CYCLES(6), NULL, NULL, CYCLES(4), CYCLES(4), CYCLES(72), CYCLES(72)
	};

static int *opcode_timings_dd[8] =
	{
/*      FLDd                            FSTd            FSTPd           FRSTOR                           FSAVE          FSTSW*/
		CYCLES(2), NULL, CYCLES(8), CYCLES(8), CYCLES(131), NULL, CYCLES(154), CYCLES(5)
	};
static int *opcode_timings_dd_mod3[8] =
	{
/*      FFFREE                          FST             FSTP            FUCOM            FUCOMP*/
		CYCLES(3), NULL, CYCLES(1), CYCLES(1), CYCLES(3), CYCLES(3), NULL, NULL
	};

static int *opcode_timings_de[8] =
	{
/*      FADDiw          FMULiw          FCOMiw          FCOMPiw         FSUBil          FSUBRil         FDIVil          FDIVRil*/
		CYCLES(10), CYCLES(12), CYCLES(9), CYCLES(9), CYCLES(10), CYCLES(10), CYCLES(78), CYCLES(78)
	};
static int *opcode_timings_de_mod3[8] =
	{
/*      FADD            FMUL                            FCOMPP          FSUB            FSUBR           FDIV            FDIVR*/
		CYCLES(4), CYCLES(6), NULL, CYCLES(3), CYCLES(4), CYCLES(4), CYCLES(72), CYCLES(72)
	};

static int *opcode_timings_df[8] =
	{
/*      FILDiw                          FISTiw          FISTPiw                          FILDiq          FBSTP          FISTPiq*/
		CYCLES(6), NULL, CYCLES(7), CYCLES(7), NULL, CYCLES(8), CYCLES(172), CYCLES(8)
	};
static int *opcode_timings_df_mod3[8] =
	{
/*      FFREE                           FST             FSTP            FUCOM            FUCOMP*/
		CYCLES(3), NULL, CYCLES(1), CYCLES(1), CYCLES(3), CYCLES(3), NULL, NULL
	};

static int *opcode_timings_8x[8] =
	{
		&timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm
	};
static int *opcode_timings_8x_mod3[8] =
	{
		&timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm
	};
static int *opcode_timings_81[8] =
	{
		&timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm
	};
static int *opcode_timings_81_mod3[8] =
	{
		&timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm
	};

static int timing_count;
static uint8_t last_prefix;
static uint32_t regmask_modified;

static inline int COUNT(int *c, int op_32) {
	if ((uintptr_t)c <= 10000)
		return (int)(uintptr_t)c;
	if (((uintptr_t)c & ~0xffff) == (-1 & ~0xffff)) {
		if (op_32 & 0x100)
			return ((uintptr_t)c >> 8) & 0xff;
		return (uintptr_t)c & 0xff;
	}
	return *c;
}

void codegen_timing_winchip_block_start() {
	regmask_modified = 0;
}

void codegen_timing_winchip_start() {
	timing_count = 0;
	last_prefix = 0;
}

void codegen_timing_winchip_prefix(uint8_t prefix, uint32_t fetchdat) {
	timing_count += COUNT(opcode_timings[prefix], 0);
	last_prefix = prefix;
}

void codegen_timing_winchip_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, uint32_t op_pc) {
	int **timings;
	uint64_t *deps;
	int mod3 = ((fetchdat & 0xc0) == 0xc0);
	int bit8 = !(opcode & 1);

	switch (last_prefix) {
	case 0x0f:timings = mod3 ? opcode_timings_0f_mod3 : opcode_timings_0f;
		deps = mod3 ? opcode_deps_0f_mod3 : opcode_deps_0f;
//                pclog("timings 0f\n");
		break;

	case 0xd8:timings = mod3 ? opcode_timings_d8_mod3 : opcode_timings_d8;
		deps = mod3 ? opcode_deps_d8_mod3 : opcode_deps_d8;
		opcode = (opcode >> 3) & 7;
//                pclog("timings d8\n");
		break;
	case 0xd9:timings = mod3 ? opcode_timings_d9_mod3 : opcode_timings_d9;
		deps = mod3 ? opcode_deps_d9_mod3 : opcode_deps_d9;
		opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7;
//                pclog("timings d9\n");
		break;
	case 0xda:timings = mod3 ? opcode_timings_da_mod3 : opcode_timings_da;
		deps = mod3 ? opcode_deps_da_mod3 : opcode_deps_da;
		opcode = (opcode >> 3) & 7;
//                pclog("timings da\n");
		break;
	case 0xdb:timings = mod3 ? opcode_timings_db_mod3 : opcode_timings_db;
		deps = mod3 ? opcode_deps_db_mod3 : opcode_deps_db;
		opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7;
//                pclog("timings db\n");
		break;
	case 0xdc:timings = mod3 ? opcode_timings_dc_mod3 : opcode_timings_dc;
		deps = mod3 ? opcode_deps_dc_mod3 : opcode_deps_dc;
		opcode = (opcode >> 3) & 7;
//                pclog("timings dc\n");
		break;
	case 0xdd:timings = mod3 ? opcode_timings_dd_mod3 : opcode_timings_dd;
		deps = mod3 ? opcode_deps_dd_mod3 : opcode_deps_dd;
		opcode = (opcode >> 3) & 7;
//                pclog("timings dd\n");
		break;
	case 0xde:timings = mod3 ? opcode_timings_de_mod3 : opcode_timings_de;
		deps = mod3 ? opcode_deps_de_mod3 : opcode_deps_de;
		opcode = (opcode >> 3) & 7;
//                pclog("timings de\n");
		break;
	case 0xdf:timings = mod3 ? opcode_timings_df_mod3 : opcode_timings_df;
		deps = mod3 ? opcode_deps_df_mod3 : opcode_deps_df;
		opcode = (opcode >> 3) & 7;
//                pclog("timings df\n");
		break;

	default:
		switch (opcode) {
		case 0x80:
		case 0x82:
		case 0x83:timings = mod3 ? opcode_timings_8x_mod3 : opcode_timings_8x;
			deps = mod3 ? opcode_deps_8x_mod3 : opcode_deps_8x_mod3;
			opcode = (fetchdat >> 3) & 7;
//                        pclog("timings 80 %p %p %p\n", (void *)timings, (void *)opcode_timings_mod3, (void *)opcode_timings_8x);
			break;
		case 0x81:timings = mod3 ? opcode_timings_81_mod3 : opcode_timings_81;
			deps = mod3 ? opcode_deps_81_mod3 : opcode_deps_81;
			opcode = (fetchdat >> 3) & 7;
//                        pclog("timings 80 %p %p %p\n", (void *)timings, (void *)opcode_timings_mod3, (void *)opcode_timings_8x);
			break;

		case 0xc0:
		case 0xc1:
		case 0xd0:
		case 0xd1:
		case 0xd2:
		case 0xd3:timings = mod3 ? opcode_timings_shift_mod3 : opcode_timings_shift;
			deps = mod3 ? opcode_deps_shift_mod3 : opcode_deps_shift;
			opcode = (fetchdat >> 3) & 7;
//                        pclog("timings c0\n");
			break;

		case 0xf6:timings = mod3 ? opcode_timings_f6_mod3 : opcode_timings_f6;
			deps = mod3 ? opcode_deps_f6_mod3 : opcode_deps_f6;
			opcode = (fetchdat >> 3) & 7;
//                        pclog("timings f6\n");
			break;
		case 0xf7:timings = mod3 ? opcode_timings_f7_mod3 : opcode_timings_f7;
			deps = mod3 ? opcode_deps_f7_mod3 : opcode_deps_f7;
			opcode = (fetchdat >> 3) & 7;
//                        pclog("timings f7\n");
			break;
		case 0xff:timings = mod3 ? opcode_timings_ff_mod3 : opcode_timings_ff;
			deps = mod3 ? opcode_deps_ff_mod3 : opcode_deps_ff;
			opcode = (fetchdat >> 3) & 7;
//                        pclog("timings ff\n");
			break;

		default:timings = mod3 ? opcode_timings_mod3 : opcode_timings;
			deps = mod3 ? opcode_deps_mod3 : opcode_deps;
//                        pclog("timings normal\n");
			break;
		}
	}

	timing_count += COUNT(timings[opcode], op_32);
	if (regmask_modified & get_addr_regmask(deps[opcode], fetchdat, op_32))
		timing_count++; /*AGI stall*/
	codegen_block_cycles += timing_count;

	regmask_modified = get_dstdep_mask(deps[opcode], fetchdat, bit8);
}

void codegen_timing_winchip_block_end() {
}

int codegen_timing_winchip_jump_cycles() {
	return 0;
}

codegen_timing_t codegen_timing_winchip =
	{
		codegen_timing_winchip_start,
		codegen_timing_winchip_prefix,
		codegen_timing_winchip_opcode,
		codegen_timing_winchip_block_start,
		codegen_timing_winchip_block_end,
		codegen_timing_winchip_jump_cycles
	};
