pcem/src/codegen_timing_p6.c

2154 lines
101 KiB
C

#include "ibm.h"
#include "cpu.h"
#include "model.h"
#include "x86.h"
#include "x86_ops.h"
#include "x87.h"
#include "386_common.h"
#include "mem.h"
#include "codegen.h"
#include "codegen_ops.h"
#include "codegen_timing_common.h"
typedef enum uop_type_t
{
UOP_ALU0 = 0, /*Executes in port 0 ALU*/
UOP_ALU1, /*Executes in port 1 ALU*/
UOP_ALU01, /*Executes in either port 0 or 1 ALU*/
UOP_BRANCH, /*Executes in port 1 branch*/
UOP_LOAD, /*Executes in port 2 Load unit*/
UOP_STOREADDR, /*Executes in port 3 Store Address unit*/
UOP_STOREDATA, /*Executes in port 4 Store Data unit*/
UOP_FLOAT, /*Executes in port 0 Floating Point unit*/
UOP_ALU0_SEG /*Executes in port 0 ALU, loads segment, causing pipeline flush on PPro*/
} uop_type_t;
#define MAX_UOPS 300
typedef struct p6_uop_t
{
uop_type_t type;
int throughput;
int latency;
} p6_uop_t;
typedef struct p6_instruction_t
{
int nr_uops;
p6_uop_t uop[MAX_UOPS];
} p6_instruction_t;
static const p6_instruction_t alu_op =
{
.nr_uops = 1,
.uop[0] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}
};
static const p6_instruction_t alu0_op =
{
.nr_uops = 1,
.uop[0] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}
};
static const p6_instruction_t alu1_op =
{
.nr_uops = 1,
.uop[0] = {.type = UOP_ALU1, .throughput = 1, .latency = 1}
};
static const p6_instruction_t alu01_op =
{
.nr_uops = 1,
.uop[0] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}
};
static const p6_instruction_t alu4_op =
{
.nr_uops = 4,
.uop[0] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[3] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}
};
static const p6_instruction_t alu6_op =
{
.nr_uops = 6,
.uop[0] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[3] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[4] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[5] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}
};
static const p6_instruction_t aluc_op =
{
.nr_uops = 2,
.uop[0] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[0] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}
};
static const p6_instruction_t load_alu_op =
{
.nr_uops = 2,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}
};
static const p6_instruction_t load_aluc_op =
{
.nr_uops = 3,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}
};
static const p6_instruction_t alu_store_op =
{
.nr_uops = 4,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[3] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}
};
static const p6_instruction_t alu0_store_op =
{
.nr_uops = 4,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[3] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}
};
static const p6_instruction_t aluc_store_op =
{
.nr_uops = 6,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[3] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[4] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[5] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}
};
static const p6_instruction_t branch_op =
{
.nr_uops = 1,
.uop[0] = {.type = UOP_BRANCH, .throughput = 1, .latency = 1}
};
static const p6_instruction_t load_op =
{
.nr_uops = 1,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}
};
static const p6_instruction_t store_op =
{
.nr_uops = 2,
.uop[0] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[1] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}
};
static const p6_instruction_t bswap_op =
{
.nr_uops = 2,
.uop[0] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[0] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}
};
static const p6_instruction_t leave_op =
{
.nr_uops = 3,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}
};
static const p6_instruction_t lods_op =
{
.nr_uops = 2,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 1}
};
static const p6_instruction_t loop_op =
{
.nr_uops = 11,
.uop[0] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[1] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_ALU1, .throughput = 1, .latency = 1},
.uop[3] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[4] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[5] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[6] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[7] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[8] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[9] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[10] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
};
static const p6_instruction_t movs_op =
{
.nr_uops = 6,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_LOAD, .throughput = 1, .latency = 1},
.uop[3] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[4] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1},
.uop[5] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
};
static const p6_instruction_t pop_reg_op =
{
.nr_uops = 2,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}
};
static const p6_instruction_t pop_mem_op =
{
.nr_uops = 8,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[3] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[4] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[5] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[6] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1},
.uop[7] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}
};
static const p6_instruction_t push_imm_op =
{
.nr_uops = 3,
.uop[0] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[1] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}
};
static const p6_instruction_t push_mem_op =
{
.nr_uops = 4,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[3] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1},
};
static const p6_instruction_t push_seg_op =
{
.nr_uops = 4,
.uop[0] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[3] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}
};
static const p6_instruction_t rcx_op =
{
.nr_uops = 8,
.uop[0] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[1] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[3] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[4] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[5] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[6] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[7] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
};
static const p6_instruction_t rcx_store_op =
{
.nr_uops = 11,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[3] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[4] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[5] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[6] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[7] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[8] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[9] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[10] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}
};
static const p6_instruction_t stos_op =
{
.nr_uops = 3,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 1},
.uop[1] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}
};
static const p6_instruction_t xchg_op =
{
.nr_uops = 3,
.uop[0] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}
};
static const p6_instruction_t mmx_op =
{
.nr_uops = 1,
.uop[0] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}
};
static const p6_instruction_t mmx_mul_op =
{
.nr_uops = 1,
.uop[0] = {.type = UOP_ALU0, .throughput = 1, .latency = 3}
};
static const p6_instruction_t mmx_shift_op =
{
.nr_uops = 1,
.uop[0] = {.type = UOP_ALU1, .throughput = 1, .latency = 1}
};
static const p6_instruction_t load_mmx_op =
{
.nr_uops = 2,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}
};
static const p6_instruction_t load_mmx_mul_op =
{
.nr_uops = 2,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}
};
static const p6_instruction_t load_mmx_shift_op =
{
.nr_uops = 2,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_ALU1, .throughput = 1, .latency = 1}
};
static const p6_instruction_t faddsub_op =
{
.nr_uops = 1,
.uop[0] = {.type = UOP_FLOAT, .throughput = 1, .latency = 3}
};
static const p6_instruction_t load_faddsub_op =
{
.nr_uops = 2,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_FLOAT, .throughput = 1, .latency = 3}
};
static const p6_instruction_t fbstp_op =
{
.nr_uops = 5,
.uop[0] = {.type = UOP_FLOAT, .throughput = 165, .latency = 165},
.uop[1] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1},
.uop[3] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[4] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}
};
static const p6_instruction_t fcom_op =
{
.nr_uops = 1,
.uop[0] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1}
};
static const p6_instruction_t load_fcom_op =
{
.nr_uops = 2,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1}
};
static const p6_instruction_t fcompp_op =
{
.nr_uops = 1,
.uop[0] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1},
.uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}
};
static const p6_instruction_t fild_op =
{
.nr_uops = 4,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1},
.uop[3] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1}
};
static const p6_instruction_t load_fi_op =
{
.nr_uops = 7,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1},
.uop[3] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1},
.uop[4] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1},
.uop[5] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1},
.uop[6] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1}
};
static const p6_instruction_t fmul_op =
{
.nr_uops = 1,
.uop[0] = {.type = UOP_FLOAT, .throughput = 1, .latency = 5}
};
static const p6_instruction_t load_fmul_op =
{
.nr_uops = 2,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_FLOAT, .throughput = 1, .latency = 5}
};
static const p6_instruction_t fxch_op =
{
.nr_uops = 0
};
static const p6_instruction_t fist_op =
{
.nr_uops = 4,
.uop[0] = {.type = UOP_FLOAT, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[3] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}
};
static const p6_instruction_t fdiv_op =
{
.nr_uops = 1,
.uop[0] = {.type = UOP_FLOAT, .throughput = 37, .latency = 38}
};
static const p6_instruction_t fdiv_mem_op =
{
.nr_uops = 2,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_FLOAT, .throughput = 37, .latency = 38}
};
static const p6_instruction_t fsin_op =
{
.nr_uops = 1,
.uop[0] = {.type = UOP_FLOAT, .throughput = 62, .latency = 62}
};
static const p6_instruction_t fsqrt_op =
{
.nr_uops = 1,
.uop[0] = {.type = UOP_FLOAT, .throughput = 69, .latency = 69}
};
static const p6_instruction_t float_op =
{
.nr_uops = 1,
.uop[0] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1}
};
static const p6_instruction_t fldcw_op =
{
.nr_uops = 3,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_FLOAT, .throughput = 7, .latency = 7},
};
static const p6_instruction_t flde_op =
{
.nr_uops = 4,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[2] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1},
.uop[3] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1}
};
static const p6_instruction_t frstor_op =
{
.nr_uops = 1,
.uop[0] = {.type = UOP_FLOAT, .throughput = 72, .latency = 72}
};
static const p6_instruction_t fsave_op =
{
.nr_uops = 1,
.uop[0] = {.type = UOP_FLOAT, .throughput = 141, .latency = 141}
};
static const p6_instruction_t fste_op =
{
.nr_uops = 6,
.uop[0] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1},
.uop[1] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[3] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1},
.uop[4] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[5] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}
};
static const p6_instruction_t fstsw_ax_op =
{
.nr_uops = 3,
.uop[0] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1},
.uop[1] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}
};
static const p6_instruction_t fstsw_mem_op =
{
.nr_uops = 3,
.uop[0] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1},
.uop[1] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}
};
static const p6_instruction_t aad_op =
{
.nr_uops = 3,
.uop[0] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[1] = {.type = UOP_ALU0, .throughput = 1, .latency = 4},
.uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}
};
static const p6_instruction_t aam_op =
{
.nr_uops = 3,
.uop[0] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[1] = {.type = UOP_ALU0, .throughput = 1, .latency = 4},
.uop[2] = {.type = UOP_ALU1, .throughput = 1, .latency = 9},
.uop[3] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}
};
static const p6_instruction_t arpl_op =
{
.nr_uops = 2,
.uop[0] = {.type = UOP_ALU01, .throughput = 3, .latency = 3},
.uop[1] = {.type = UOP_ALU01, .throughput = 3, .latency = 3}
};
static const p6_instruction_t bound_op =
{
.nr_uops = 4,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[2] = {.type = UOP_ALU0, .throughput = 7, .latency = 7},
.uop[3] = {.type = UOP_ALU01, .throughput = 6, .latency = 6}
};
static const p6_instruction_t bsx_op =
{
.nr_uops = 2,
.uop[0] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[1] = {.type = UOP_ALU1, .throughput = 1, .latency = 1}
};
static const p6_instruction_t load_bsx_op =
{
.nr_uops = 3,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_ALU1, .throughput = 1, .latency = 1}
};
static const p6_instruction_t call_far_op =
{
.nr_uops = 6,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1},
.uop[3] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[4] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1},
.uop[5] = {.type = UOP_ALU0_SEG, .throughput = 28, .latency = 28}
};
static const p6_instruction_t load_call_far_op =
{
.nr_uops = 7,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[2] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[3] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1},
.uop[4] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[5] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1},
.uop[6] = {.type = UOP_ALU0_SEG, .throughput = 28, .latency = 28}
};
static const p6_instruction_t cli_op =
{
.nr_uops = 1,
.uop[0] = {.type = UOP_ALU01, .throughput = 9, .latency = 9}
};
static const p6_instruction_t sti_op =
{
.nr_uops = 1,
.uop[0] = {.type = UOP_ALU01, .throughput = 17, .latency = 17}
};
static const p6_instruction_t cmps_op =
{
.nr_uops = 6,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[3] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[4] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[5] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}
};
static const p6_instruction_t cmpxchg_op =
{
.nr_uops = 4,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[3] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}
};
static const p6_instruction_t cpuid_op =
{
.nr_uops = 1,
.uop[0] = {.type = UOP_ALU0, .throughput = 48, .latency = 48}
};
/*static const p6_instruction_t div8_op =
{
.nr_uops = 3,
.uop[0] = {.type = UOP_ALU0, .throughput = 12, .latency = 17},
.uop[1] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}
};*/
/*static const p6_instruction_t div8_mem_op =
{
.nr_uops = 4,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[0] = {.type = UOP_ALU0, .throughput = 12, .latency = 17},
.uop[1] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}
};*/
static const p6_instruction_t div16_op =
{
.nr_uops = 3,
.uop[0] = {.type = UOP_ALU0, .throughput = 21, .latency = 21},
.uop[1] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}
};
static const p6_instruction_t div16_mem_op =
{
.nr_uops = 4,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[0] = {.type = UOP_ALU0, .throughput = 21, .latency = 21},
.uop[1] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}
};
static const p6_instruction_t div32_op =
{
.nr_uops = 3,
.uop[0] = {.type = UOP_ALU0, .throughput = 35, .latency = 35},
.uop[1] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}
};
static const p6_instruction_t div32_mem_op =
{
.nr_uops = 4,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[0] = {.type = UOP_ALU0, .throughput = 35, .latency = 35},
.uop[1] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}
};
static const p6_instruction_t emms_op =
{
.nr_uops = 11,
.uop[0] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[1] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[3] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[4] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[5] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[6] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[7] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[8] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[9] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[10] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}
};
static const p6_instruction_t enter_op =
{
.nr_uops = 14,
.uop[0] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[3] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[4] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[5] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[6] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[7] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[8] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[9] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[10] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[11] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[12] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1},
.uop[13] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}
};
static const p6_instruction_t io_op =
{
.nr_uops = 1,
.uop[0] = {.type = UOP_LOAD, .throughput = 18, .latency = 18}
};
static const p6_instruction_t ins_op =
{
.nr_uops = 4,
.uop[0] = {.type = UOP_ALU0, .throughput = 18, .latency = 18},
.uop[1] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}
};
static const p6_instruction_t int_op =
{
.nr_uops = 7,
.uop[0] = {.type = UOP_ALU0, .throughput = 20, .latency = 20},
.uop[1] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1},
.uop[3] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[4] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1},
.uop[5] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[6] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1},
};
static const p6_instruction_t iret_op =
{
.nr_uops = 4,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[2] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[3] = {.type = UOP_ALU01, .throughput = 20, .latency = 20},
};
static const p6_instruction_t invd_op =
{
.nr_uops = 1,
.uop[0] = {.type = UOP_ALU01, .throughput = 1000, .latency = 1000}
};
static const p6_instruction_t jmp_far_op =
{
.nr_uops = 2,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_ALU0_SEG, .throughput = 21, .latency = 21}
};
static const p6_instruction_t load_jmp_far_op =
{
.nr_uops = 3,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[2] = {.type = UOP_ALU0_SEG, .throughput = 21, .latency = 21}
};
static const p6_instruction_t lss_op =
{
.nr_uops = 11,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[2] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[3] = {.type = UOP_ALU0_SEG,.throughput = 1, .latency = 1},
.uop[4] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[5] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[6] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[7] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[8] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[9] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[10] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}
};
/*static const p6_instruction_t mov_mem_seg_op =
{
.nr_uops = 3,
.uop[0] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[1] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1},
};*/
static const p6_instruction_t mov_seg_mem_op =
{
.nr_uops = 9,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_ALU0_SEG,.throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[3] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[4] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[5] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[6] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[7] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[8] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}
};
static const p6_instruction_t mov_seg_reg_op =
{
.nr_uops = 8,
.uop[0] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[1] = {.type = UOP_ALU0_SEG,.throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[3] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[4] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[5] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[6] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[7] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}
};
static const p6_instruction_t mul_op =
{
.nr_uops = 1,
.uop[0] = {.type = UOP_ALU0, .throughput = 1, .latency = 4}
};
static const p6_instruction_t mul_mem_op =
{
.nr_uops = 2,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_ALU0, .throughput = 1, .latency = 4}
};
static const p6_instruction_t outs_op =
{
.nr_uops = 3,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 1},
.uop[1] = {.type = UOP_ALU0, .throughput = 18, .latency = 18},
.uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}
};
static const p6_instruction_t pusha_op =
{
.nr_uops = 18,
.uop[0] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[1] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[3] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1},
.uop[4] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[5] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1},
.uop[6] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[7] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1},
.uop[8] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[9] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1},
.uop[10] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[11] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1},
.uop[12] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[13] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1},
.uop[14] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[15] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1},
.uop[16] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[17] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}
};
static const p6_instruction_t popa_op =
{
.nr_uops = 10,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 1},
.uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_LOAD, .throughput = 1, .latency = 1},
.uop[3] = {.type = UOP_LOAD, .throughput = 1, .latency = 1},
.uop[4] = {.type = UOP_LOAD, .throughput = 1, .latency = 1},
.uop[5] = {.type = UOP_LOAD, .throughput = 1, .latency = 1},
.uop[6] = {.type = UOP_LOAD, .throughput = 1, .latency = 1},
.uop[7] = {.type = UOP_LOAD, .throughput = 1, .latency = 1},
.uop[8] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[9] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}
};
static const p6_instruction_t popf_op =
{
.nr_uops = 17,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[3] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[4] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[5] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[6] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[7] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[8] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[9] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[10] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[11] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[12] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[13] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[14] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[15] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[16] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
};
static const p6_instruction_t pushf_op =
{
.nr_uops = 16,
.uop[0] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[1] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[3] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[4] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[5] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[6] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[7] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[8] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[9] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[10] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[11] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[12] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[13] = {.type = UOP_ALU0, .throughput = 1, .latency = 1},
.uop[14] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[15] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}
};
static const p6_instruction_t ret_op =
{
.nr_uops = 4,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[3] = {.type = UOP_ALU1, .throughput = 1, .latency = 1}
};
static const p6_instruction_t reti_op =
{
.nr_uops = 5,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[3] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[4] = {.type = UOP_ALU1, .throughput = 1, .latency = 1}
};
static const p6_instruction_t retf_op =
{
.nr_uops = 4,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[2] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[3] = {.type = UOP_ALU0, .throughput = 23, .latency = 23},
};
static const p6_instruction_t scas_op =
{
.nr_uops = 3,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 2},
.uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}
};
static const p6_instruction_t xchg_mem_op =
{
.nr_uops = 7,
.uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 1},
.uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[3] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[4] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1},
.uop[5] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1},
.uop[6] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}
};
static const p6_instruction_t xlat_op =
{
.nr_uops = 2,
.uop[0] = {.type = UOP_ALU01, .throughput = 1, .latency = 1},
.uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}
};
static const p6_instruction_t wbinvd_op =
{
.nr_uops = 1,
.uop[0] = {.type = UOP_ALU0, .throughput = 10000, .latency = 10000}
};
#define INVALID NULL
static const p6_instruction_t *opcode_timings[256] =
{
/* ADD ADD ADD ADD*/
/*00*/ &alu_store_op, &alu_store_op, &load_alu_op, &load_alu_op,
/* ADD ADD PUSH ES POP ES*/
&alu_op, &alu_op, &push_seg_op, &mov_seg_mem_op,
/* OR OR OR OR*/
&alu_store_op, &alu_store_op, &load_alu_op, &load_alu_op,
/* OR OR PUSH CS */
&alu_op, &alu_op, &push_seg_op, INVALID,
/* ADC ADC ADC ADC*/
/*10*/ &aluc_store_op, &aluc_store_op, &load_aluc_op, &load_aluc_op,
/* ADC ADC PUSH SS POP SS*/
&aluc_op, &aluc_op, &push_seg_op, &mov_seg_mem_op,
/* SBB SBB SBB SBB*/
/*10*/ &aluc_store_op, &aluc_store_op, &load_aluc_op, &load_aluc_op,
/* SBB SBB PUSH DS POP DS*/
&aluc_op, &aluc_op, &push_seg_op, &mov_seg_mem_op,
/* AND AND AND AND*/
/*20*/ &alu_store_op, &alu_store_op, &load_alu_op, &load_alu_op,
/* AND AND DAA*/
&alu_op, &alu_op, INVALID, &alu1_op,
/* SUB SUB SUB SUB*/
&alu_store_op, &alu_store_op, &load_alu_op, &load_alu_op,
/* SUB SUB DAS*/
&alu_op, &alu_op, INVALID, &alu1_op,
/* XOR XOR XOR XOR*/
/*30*/ &alu_store_op, &alu_store_op, &load_alu_op, &load_alu_op,
/* XOR XOR AAA*/
&alu_op, &alu_op, INVALID, &alu1_op,
/* CMP CMP CMP CMP*/
&load_alu_op, &load_alu_op, &load_alu_op, &load_alu_op,
/* CMP CMP AAS*/
&alu_op, &alu_op, INVALID, &alu1_op,
/* INC EAX INC ECX INC EDX INC EBX*/
/*40*/ &alu_op, &alu_op, &alu_op, &alu_op,
/* INC ESP INC EBP INC ESI INC EDI*/
&alu_op, &alu_op, &alu_op, &alu_op,
/* DEC EAX DEC ECX DEC EDX DEC EBX*/
&alu_op, &alu_op, &alu_op, &alu_op,
/* DEC ESP DEC EBP DEC ESI DEC EDI*/
&alu_op, &alu_op, &alu_op, &alu_op,
/* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/
/*50*/ &store_op, &store_op, &store_op, &store_op,
/* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/
&store_op, &store_op, &store_op, &store_op,
/* POP EAX POP ECX POP EDX POP EBX*/
&pop_reg_op, &pop_reg_op, &pop_reg_op, &pop_reg_op,
/* POP ESP POP EBP POP ESI POP EDI*/
&pop_reg_op, &pop_reg_op, &pop_reg_op, &pop_reg_op,
/* PUSHA POPA BOUND ARPL*/
/*60*/ &pusha_op, &popa_op, &bound_op, &arpl_op,
INVALID, INVALID, INVALID, INVALID,
/* PUSH imm IMUL PUSH imm IMUL*/
&push_imm_op, &mul_op, &push_imm_op, &mul_op,
/* INSB INSW OUTSB OUTSW*/
&ins_op, &ins_op, &outs_op, &outs_op,
/* Jxx*/
/*70*/ &branch_op, &branch_op, &branch_op, &branch_op,
&branch_op, &branch_op, &branch_op, &branch_op,
&branch_op, &branch_op, &branch_op, &branch_op,
&branch_op, &branch_op, &branch_op, &branch_op,
/*80*/ INVALID, INVALID, INVALID, INVALID,
/* TEST TEST XCHG XCHG*/
&load_alu_op, &load_alu_op, &xchg_mem_op, &xchg_mem_op,
/* MOV MOV MOV MOV*/
&store_op, &store_op, &load_op, &load_op,
/* MOV from seg LEA MOV to seg POP*/
&store_op, &alu0_op, &mov_seg_mem_op, &pop_mem_op,
/* NOP XCHG XCHG XCHG*/
/*90*/ &alu_op, &xchg_op, &xchg_op, &xchg_op,
/* XCHG XCHG XCHG XCHG*/
&xchg_op, &xchg_op, &xchg_op, &xchg_op,
/* CBW CWD CALL far WAIT*/
&alu_op, &alu0_op, &call_far_op, &alu_op,
/* PUSHF POPF SAHF LAHF*/
&pushf_op, &popf_op, &alu_op, &alu_op,
/* MOV MOV MOV MOV*/
/*a0*/ &load_op, &load_op, &store_op, &store_op,
/* MOVSB MOVSW CMPSB CMPSW*/
&movs_op, &movs_op, &cmps_op, &cmps_op,
/* TEST TEST STOSB STOSW*/
&load_alu_op, &load_alu_op, &stos_op, &stos_op,
/* LODSB LODSW SCASB SCASW*/
&lods_op, &lods_op, &scas_op, &scas_op,
/* MOV*/
/*b0*/ &alu_op, &alu_op, &alu_op, &alu_op,
&alu_op, &alu_op, &alu_op, &alu_op,
&alu_op, &alu_op, &alu_op, &alu_op,
&alu_op, &alu_op, &alu_op, &alu_op,
/* RET imm RET*/
/*c0*/ INVALID, INVALID, &reti_op, &ret_op,
/* LES LDS MOV MOV*/
&lss_op, &lss_op, &store_op, &store_op,
/* ENTER LEAVE RETF RETF*/
&enter_op, &leave_op, &retf_op, &retf_op,
/* INT3 INT INTO IRET*/
&int_op, &int_op, &int_op, &iret_op,
/*d0*/ INVALID, INVALID, INVALID, INVALID,
/* AAM AAD SETALC XLAT*/
&aam_op, &aad_op, &alu_op, &xlat_op,
INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
/* LOOPNE LOOPE LOOP JCXZ*/
/*e0*/ &loop_op, &loop_op, &loop_op, &loop_op,
/* IN AL IN AX OUT_AL OUT_AX*/
&io_op, &io_op, &io_op, &io_op,
/* CALL JMP JMP JMP*/
&store_op, &branch_op, &jmp_far_op, &branch_op,
/* IN AL IN AX OUT_AL OUT_AX*/
&io_op, &io_op, &io_op, &io_op,
/* REPNE REPE*/
/*f0*/ INVALID, INVALID, INVALID, INVALID,
/* HLT CMC*/
&alu4_op, &alu_op, INVALID, INVALID,
/* CLC STC CLI STI*/
&alu_op, &alu_op, &cli_op, &sti_op,
/* CLD STD INCDEC*/
&alu4_op, &alu4_op, &store_op, INVALID
};
static const p6_instruction_t *opcode_timings_mod3[256] =
{
/* ADD ADD ADD ADD*/
/*00*/ &alu_op, &alu_op, &alu_op, &alu_op,
/* ADD ADD PUSH ES POP ES*/
&alu_op, &alu_op, &push_seg_op, &mov_seg_mem_op,
/* OR OR OR OR*/
&alu_op, &alu_op, &alu_op, &alu_op,
/* OR OR PUSH CS */
&alu_op, &alu_op, &push_seg_op, INVALID,
/* ADC ADC ADC ADC*/
/*10*/ &aluc_op, &aluc_op, &aluc_op, &aluc_op,
/* ADC ADC PUSH SS POP SS*/
&aluc_op, &aluc_op, &push_seg_op, &mov_seg_mem_op,
/* SBB SBB SBB SBB*/
&aluc_op, &aluc_op, &aluc_op, &aluc_op,
/* SBB SBB PUSH DS POP DS*/
&aluc_op, &aluc_op, &push_seg_op, &mov_seg_mem_op,
/* AND AND AND AND*/
/*20*/ &alu_op, &alu_op, &alu_op, &alu_op,
/* AND AND DAA*/
&alu_op, &alu_op, INVALID, &alu1_op,
/* SUB SUB SUB SUB*/
&alu_op, &alu_op, &alu_op, &alu_op,
/* SUB SUB DAS*/
&alu_op, &alu_op, INVALID, &alu1_op,
/* XOR XOR XOR XOR*/
/*30*/ &alu_op, &alu_op, &alu_op, &alu_op,
/* XOR XOR AAA*/
&alu_op, &alu_op, INVALID, &alu1_op,
/* CMP CMP CMP CMP*/
&alu_op, &alu_op, &alu_op, &alu_op,
/* CMP CMP AAS*/
&alu_op, &alu_op, INVALID, &alu1_op,
/* INC EAX INC ECX INC EDX INC EBX*/
/*40*/ &alu_op, &alu_op, &alu_op, &alu_op,
/* INC ESP INC EBP INC ESI INC EDI*/
&alu_op, &alu_op, &alu_op, &alu_op,
/* DEC EAX DEC ECX DEC EDX DEC EBX*/
&alu_op, &alu_op, &alu_op, &alu_op,
/* DEC ESP DEC EBP DEC ESI DEC EDI*/
&alu_op, &alu_op, &alu_op, &alu_op,
/* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/
/*50*/ &store_op, &store_op, &store_op, &store_op,
/* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/
&store_op, &store_op, &store_op, &store_op,
/* POP EAX POP ECX POP EDX POP EBX*/
&pop_reg_op, &pop_reg_op, &pop_reg_op, &pop_reg_op,
/* POP ESP POP EBP POP ESI POP EDI*/
&pop_reg_op, &pop_reg_op, &pop_reg_op, &pop_reg_op,
/* PUSHA POPA BOUND ARPL*/
/*60*/ &pusha_op, &popa_op, &bound_op, &arpl_op,
INVALID, INVALID, INVALID, INVALID,
/* PUSH imm IMUL PUSH imm IMUL*/
&push_imm_op, &mul_op, &push_imm_op, &mul_op,
/* INSB INSW OUTSB OUTSW*/
&ins_op, &ins_op, &outs_op, &outs_op,
/* Jxx*/
/*70*/ &branch_op, &branch_op, &branch_op, &branch_op,
&branch_op, &branch_op, &branch_op, &branch_op,
&branch_op, &branch_op, &branch_op, &branch_op,
&branch_op, &branch_op, &branch_op, &branch_op,
/*80*/ INVALID, INVALID, INVALID, INVALID,
/* TEST TEST XCHG XCHG*/
&alu_op, &alu_op, &xchg_op, &xchg_op,
/* MOV MOV MOV MOV*/
&store_op, &store_op, &load_op, &load_op,
/* MOV from seg LEA MOV to seg POP*/
&alu_op, &alu0_op, &mov_seg_reg_op, &pop_reg_op,
/* NOP XCHG XCHG XCHG*/
/*90*/ &alu_op, &xchg_op, &xchg_op, &xchg_op,
/* XCHG XCHG XCHG XCHG*/
&xchg_op, &xchg_op, &xchg_op, &xchg_op,
/* CBW CWD CALL far WAIT*/
&alu_op, &alu0_op, &call_far_op, &alu_op,
/* PUSHF POPF SAHF LAHF*/
&pushf_op, &popf_op, &alu_op, &alu_op,
/* MOV MOV MOV MOV*/
/*a0*/ &load_op, &load_op, &store_op, &store_op,
/* MOVSB MOVSW CMPSB CMPSW*/
&movs_op, &movs_op, &cmps_op, &cmps_op,
/* TEST TEST STOSB STOSW*/
&alu_op, &alu_op, &stos_op, &stos_op,
/* LODSB LODSW SCASB SCASW*/
&lods_op, &lods_op, &scas_op, &scas_op,
/* MOV*/
/*b0*/ &alu_op, &alu_op, &alu_op, &alu_op,
&alu_op, &alu_op, &alu_op, &alu_op,
&alu_op, &alu_op, &alu_op, &alu_op,
&alu_op, &alu_op, &alu_op, &alu_op,
/* RET imm RET*/
/*c0*/ INVALID, INVALID, &reti_op, &ret_op,
/* LES LDS MOV MOV*/
&lss_op, &lss_op, &store_op, &store_op,
/* ENTER LEAVE RETF RETF*/
&enter_op, &leave_op, &retf_op, &retf_op,
/* INT3 INT INTO IRET*/
&int_op, &int_op, &int_op, &iret_op,
/*d0*/ INVALID, INVALID, INVALID, INVALID,
/* AAM AAD SETALC XLAT*/
&aam_op, &aad_op, &alu_op, &xlat_op,
INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
/* LOOPNE LOOPE LOOP JCXZ*/
/*e0*/ &loop_op, &loop_op, &loop_op, &loop_op,
/* IN AL IN AX OUT_AL OUT_AX*/
&io_op, &io_op, &io_op, &io_op,
/* CALL JMP JMP JMP*/
&store_op, &branch_op, &jmp_far_op, &branch_op,
/* IN AL IN AX OUT_AL OUT_AX*/
&io_op, &io_op, &io_op, &io_op,
/* REPNE REPE*/
/*f0*/ INVALID, INVALID, INVALID, INVALID,
/* HLT CMC*/
&alu4_op, &alu_op, INVALID, INVALID,
/* CLC STC CLI STI*/
&alu_op, &alu_op, &cli_op, &sti_op,
/* CLD STD INCDEC*/
&alu4_op, &alu4_op, &alu_op, INVALID
};
static const p6_instruction_t *opcode_timings_0f[256] =
{
/*00*/ &alu6_op, &alu6_op, &alu6_op, &alu6_op,
INVALID, &alu6_op, &alu6_op, INVALID,
&invd_op, &wbinvd_op, INVALID, INVALID,
INVALID, &load_op, INVALID, INVALID,
/*10*/ INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
/*20*/ &alu6_op, &alu6_op, &alu6_op, &alu6_op,
&alu6_op, &alu6_op, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
/*30*/ &alu6_op, &alu6_op, &alu6_op, INVALID,
INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
/*40*/ INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
/*50*/ INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
/*60*/ &load_mmx_op, &load_mmx_op, &load_mmx_op, &load_mmx_op,
&load_mmx_op, &load_mmx_op, &load_mmx_op, &load_mmx_op,
&load_mmx_op, &load_mmx_op, &load_mmx_op, &load_mmx_op,
INVALID, INVALID, &load_op, &load_op,
/*70*/ INVALID, &load_mmx_shift_op, &load_mmx_shift_op, &load_mmx_shift_op,
&load_mmx_op, &load_mmx_op, &load_mmx_op, &emms_op,
INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, &store_op, &store_op,
/*80*/ &branch_op, &branch_op, &branch_op, &branch_op,
&branch_op, &branch_op, &branch_op, &branch_op,
&branch_op, &branch_op, &branch_op, &branch_op,
&branch_op, &branch_op, &branch_op, &branch_op,
/*90*/ &alu_op, &alu_op, &alu_op, &alu_op,
&alu_op, &alu_op, &alu_op, &alu_op,
&alu_op, &alu_op, &alu_op, &alu_op,
&alu_op, &alu_op, &alu_op, &alu_op,
/*a0*/ &push_seg_op, &mov_seg_mem_op, &cpuid_op, &load_alu_op,
&alu_store_op, &alu_store_op, INVALID, INVALID,
&push_seg_op, &mov_seg_mem_op, INVALID, &load_alu_op,
&alu_store_op, &alu_store_op, INVALID, &mul_op,
/*b0*/ &cmpxchg_op, &cmpxchg_op, &lss_op, &load_alu_op,
&lss_op, &lss_op, &load_alu_op, &load_alu_op,
INVALID, INVALID, &load_alu_op, &load_alu_op,
&load_bsx_op, &load_bsx_op, &load_alu_op, &load_alu_op,
/*c0*/ &alu_store_op, &alu_store_op, INVALID, INVALID,
INVALID, INVALID, INVALID, &cmpxchg_op,
&bswap_op, &bswap_op, &bswap_op, &bswap_op,
&bswap_op, &bswap_op, &bswap_op, &bswap_op,
/*d0*/ INVALID, &load_mmx_shift_op, &load_mmx_shift_op, &load_mmx_shift_op,
INVALID, &load_mmx_mul_op, INVALID, INVALID,
&load_mmx_op, &load_mmx_op, INVALID, &load_mmx_op,
&load_mmx_op, &load_mmx_op, INVALID, &load_mmx_op,
/*e0*/ &load_mmx_op, &load_mmx_shift_op, &load_mmx_shift_op, INVALID,
INVALID, &load_mmx_mul_op, INVALID, INVALID,
&load_mmx_op, &load_mmx_op, INVALID, &load_mmx_op,
&load_mmx_op, &load_mmx_op, INVALID, &load_mmx_op,
/*f0*/ INVALID, &load_mmx_shift_op, &load_mmx_shift_op, &load_mmx_shift_op,
INVALID, &load_mmx_mul_op, INVALID, INVALID,
&load_mmx_op, &load_mmx_op, &load_mmx_op, INVALID,
&load_mmx_op, &load_mmx_op, &load_mmx_op, INVALID,
};
static const p6_instruction_t *opcode_timings_0f_mod3[256] =
{
/*00*/ &alu6_op, &alu6_op, &alu6_op, &alu6_op,
INVALID, &alu6_op, &alu6_op, INVALID,
&invd_op, &wbinvd_op, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
/*10*/ INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
/*20*/ &alu6_op, &alu6_op, &alu6_op, &alu6_op,
&alu6_op, &alu6_op, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
/*30*/ &alu6_op, &alu6_op, &alu6_op, INVALID,
INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
/*40*/ INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
/*50*/ INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
/*60*/ &mmx_op, &mmx_op, &mmx_op, &mmx_op,
&mmx_op, &mmx_op, &mmx_op, &mmx_op,
&mmx_op, &mmx_op, &mmx_op, &mmx_op,
INVALID, INVALID, &mmx_op, &mmx_op,
/*70*/ INVALID, &mmx_shift_op, &mmx_shift_op, &mmx_shift_op,
&mmx_op, &mmx_op, &mmx_op, &emms_op,
INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, &mmx_op, &mmx_op,
/*80*/ &branch_op, &branch_op, &branch_op, &branch_op,
&branch_op, &branch_op, &branch_op, &branch_op,
&branch_op, &branch_op, &branch_op, &branch_op,
&branch_op, &branch_op, &branch_op, &branch_op,
/*90*/ &alu_op, &alu_op, &alu_op, &alu_op,
&alu_op, &alu_op, &alu_op, &alu_op,
&alu_op, &alu_op, &alu_op, &alu_op,
&alu_op, &alu_op, &alu_op, &alu_op,
/*a0*/ &push_seg_op, &mov_seg_mem_op, &cpuid_op, &alu_op,
&alu_op, &alu_op, INVALID, INVALID,
&push_seg_op, &mov_seg_mem_op, INVALID, &alu_op,
&alu_op, &alu_op, INVALID, &mul_op,
/*b0*/ &cmpxchg_op, &cmpxchg_op, &lss_op, &alu_op,
&lss_op, &lss_op, &alu_op, &alu_op,
INVALID, INVALID, &alu_op, &alu_op,
&bsx_op, &bsx_op, &alu_op, &alu_op,
/*c0*/ &alu_op, &alu_op, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
&bswap_op, &bswap_op, &bswap_op, &bswap_op,
&bswap_op, &bswap_op, &bswap_op, &bswap_op,
/*d0*/ INVALID, &mmx_shift_op, &mmx_shift_op, &mmx_shift_op,
INVALID, &mmx_mul_op, INVALID, INVALID,
&mmx_op, &mmx_op, INVALID, &mmx_op,
&mmx_op, &mmx_op, INVALID, &mmx_op,
/*e0*/ &mmx_op, &mmx_shift_op, &mmx_shift_op, INVALID,
INVALID, &mmx_mul_op, INVALID, INVALID,
&mmx_op, &mmx_op, INVALID, &mmx_op,
&mmx_op, &mmx_op, INVALID, &mmx_op,
/*f0*/ INVALID, &mmx_shift_op, &mmx_shift_op, &mmx_shift_op,
INVALID, &mmx_mul_op, INVALID, INVALID,
&mmx_op, &mmx_op, &mmx_op, INVALID,
&mmx_op, &mmx_op, &mmx_op, INVALID,
};
static const p6_instruction_t *opcode_timings_shift[8] =
{
&alu0_store_op, &alu0_store_op, &rcx_store_op, &rcx_store_op,
&alu0_store_op, &alu0_store_op, &alu0_store_op, &alu0_store_op
};
static const p6_instruction_t *opcode_timings_shift_mod3[8] =
{
&alu0_op, &alu0_op, &rcx_op, &rcx_op,
&alu0_op, &alu0_op, &alu0_op, &alu0_op
};
static const p6_instruction_t *opcode_timings_8x[8] =
{
&alu_store_op, &alu_store_op, &aluc_store_op, &aluc_store_op,
&alu_store_op, &alu_store_op, &alu_store_op, &alu_store_op,
};
static const p6_instruction_t *opcode_timings_8x_mod3[8] =
{
&alu_op, &alu_op, &aluc_op, &aluc_op,
&alu_op, &alu_op, &alu_op, &alu_op,
};
static const p6_instruction_t *opcode_timings_f6[8] =
{
/* TST NOT NEG*/
&load_alu_op, INVALID, &alu_store_op, &alu_store_op,
/* MUL IMUL DIV IDIV*/
&mul_mem_op, &mul_mem_op, &div16_mem_op, &div16_mem_op,
};
static const p6_instruction_t *opcode_timings_f6_mod3[8] =
{
/* TST NOT NEG*/
&alu_op, INVALID, &alu_op, &alu_op,
/* MUL IMUL DIV IDIV*/
&mul_op, &mul_op, &div16_op, &div16_op,
};
static const p6_instruction_t *opcode_timings_f7[8] =
{
/* TST NOT NEG*/
&load_alu_op, INVALID, &alu_store_op, &alu_store_op,
/* MUL IMUL DIV IDIV*/
&mul_mem_op, &mul_mem_op, &div32_mem_op, &div32_mem_op,
};
static const p6_instruction_t *opcode_timings_f7_mod3[8] =
{
/* TST NOT NEG*/
&alu_op, INVALID, &alu_op, &alu_op,
/* MUL IMUL DIV IDIV*/
&mul_op, &mul_op, &div32_op, &div32_op,
};
static const p6_instruction_t *opcode_timings_ff[8] =
{
/* INC DEC CALL CALL far*/
&alu_store_op, &alu_store_op, &store_op, &load_call_far_op,
/* JMP JMP far PUSH*/
&branch_op, &load_jmp_far_op, &push_mem_op, INVALID
};
static const p6_instruction_t *opcode_timings_ff_mod3[8] =
{
/* INC DEC CALL CALL far*/
&alu_op, &alu_op, &store_op, &call_far_op,
/* JMP JMP far PUSH*/
&branch_op, &load_jmp_far_op, &push_mem_op, INVALID
};
static const p6_instruction_t *opcode_timings_d8[8] =
{
/* FADDs FMULs FCOMs FCOMPs*/
&load_faddsub_op, &load_fmul_op, &fcom_op, &load_fcom_op,
/* FSUBs FSUBRs FDIVs FDIVRs*/
&load_faddsub_op, &load_faddsub_op, &fdiv_mem_op, &fdiv_mem_op,
};
static const p6_instruction_t *opcode_timings_d8_mod3[8] =
{
/* FADD FMUL FCOM FCOMP*/
&faddsub_op, &fmul_op, &fcom_op, &fcom_op,
/* FSUB FSUBR FDIV FDIVR*/
&faddsub_op, &faddsub_op, &fdiv_op, &fdiv_op,
};
static const p6_instruction_t *opcode_timings_d9[8] =
{
/* FLDs FSTs FSTPs*/
&load_op, INVALID, &store_op, &store_op,
/* FLDENV FLDCW FSTENV FSTCW*/
&flde_op, &fldcw_op, &fste_op, &fstsw_mem_op
};
static const p6_instruction_t *opcode_timings_d9_mod3[64] =
{
/*FLD*/
&float_op, &float_op, &float_op, &float_op,
&float_op, &float_op, &float_op, &float_op,
/*FXCH*/
&fxch_op, &fxch_op, &fxch_op, &fxch_op,
&fxch_op, &fxch_op, &fxch_op, &fxch_op,
/*FNOP*/
&float_op, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
/*FSTP*/
&float_op, &float_op, &float_op, &float_op,
&float_op, &float_op, &float_op, &float_op,
/* opFCHS opFABS*/
&float_op, &float_op, INVALID, INVALID,
/* opFTST opFXAM*/
&float_op, &float_op, INVALID, INVALID,
/* opFLD1 opFLDL2T opFLDL2E opFLDPI*/
&float_op, &float_op, &float_op, &float_op,
/* opFLDEG2 opFLDLN2 opFLDZ*/
&float_op, &float_op, &float_op, INVALID,
/* opF2XM1 opFYL2X opFPTAN opFPATAN*/
&fsin_op, &fsin_op, &fsin_op, &fsin_op,
/* opFDECSTP opFINCSTP,*/
INVALID, INVALID, &float_op, &float_op,
/* opFPREM opFSQRT opFSINCOS*/
&fdiv_op, INVALID, &fsqrt_op, &fsin_op,
/* opFRNDINT opFSCALE opFSIN opFCOS*/
&float_op, &fdiv_op, &fsin_op, &fsin_op
};
static const p6_instruction_t *opcode_timings_da[8] =
{
/* FIADDl FIMULl FICOMl FICOMPl*/
&load_fi_op, &load_fi_op, &load_fcom_op, &load_fcom_op,
/* FISUBl FISUBRl FIDIVl FIDIVRl*/
&load_fi_op, &load_fi_op, &load_fi_op, &load_fi_op,
};
static const p6_instruction_t *opcode_timings_da_mod3[8] =
{
INVALID, INVALID, INVALID, INVALID,
/* FCOMPP*/
INVALID, &fcompp_op, INVALID, INVALID
};
static const p6_instruction_t *opcode_timings_db[8] =
{
/* FLDil FSTil FSTPil*/
&fild_op, INVALID, &fist_op, &fist_op,
/* FLDe FSTPe*/
INVALID, &flde_op, INVALID, &fste_op
};
static const p6_instruction_t *opcode_timings_db_mod3[64] =
{
INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
/* opFNOP opFCLEX opFINIT*/
INVALID, &float_op, &float_op, &float_op,
/* opFNOP opFNOP*/
&float_op, &float_op, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
INVALID, INVALID, INVALID, INVALID,
};
static const p6_instruction_t *opcode_timings_dc[8] =
{
/* FADDd FMULd FCOMd FCOMPd*/
&load_faddsub_op, &load_fmul_op, &load_fcom_op, &load_fcom_op,
/* FSUBd FSUBRd FDIVd FDIVRd*/
&load_faddsub_op, &load_faddsub_op, &fdiv_mem_op, &fdiv_mem_op,
};
static const p6_instruction_t *opcode_timings_dc_mod3[8] =
{
/* opFADDr opFMULr*/
&faddsub_op, &fmul_op, INVALID, INVALID,
/* opFSUBRr opFSUBr opFDIVRr opFDIVr*/
&faddsub_op, &faddsub_op, &fdiv_op, &fdiv_op
};
static const p6_instruction_t *opcode_timings_dd[8] =
{
/* FLDd FSTd FSTPd*/
&load_op, INVALID, &store_op, &store_op,
/* FRSTOR FSAVE FSTSW*/
&frstor_op, INVALID, &fsave_op, &fstsw_mem_op
};
static const p6_instruction_t *opcode_timings_dd_mod3[8] =
{
/* FFFREE FST FSTP*/
&float_op, INVALID, &float_op, &float_op,
/* FUCOM FUCOMP*/
&float_op, &float_op, INVALID, INVALID
};
static const p6_instruction_t *opcode_timings_de[8] =
{
/* FIADDw FIMULw FICOMw FICOMPw*/
&load_fi_op, &load_fi_op, &load_fcom_op, &load_fcom_op,
/* FISUBw FISUBRw FIDIVw FIDIVRw*/
&load_fi_op, &load_fi_op, &load_fi_op, &load_fi_op,
};
static const p6_instruction_t *opcode_timings_de_mod3[8] =
{
/* FADDP FMULP FCOMPP*/
&faddsub_op, &fmul_op, INVALID, &fcompp_op,
/* FSUBP FSUBRP FDIVP FDIVRP*/
&faddsub_op, &faddsub_op, &fdiv_op, &fdiv_op,
};
static const p6_instruction_t *opcode_timings_df[8] =
{
/* FILDiw FISTiw FISTPiw*/
&fild_op, INVALID, &fist_op, &fist_op,
/* FILDiq FBSTP FISTPiq*/
INVALID, &fild_op, &fbstp_op, &fist_op,
};
static const p6_instruction_t *opcode_timings_df_mod3[8] =
{
INVALID, INVALID, INVALID, INVALID,
/* FSTSW AX*/
&fstsw_ax_op, INVALID, INVALID, INVALID
};
static uint8_t last_prefix;
static int prefixes;
static int decode_timestamp;
static int last_complete_timestamp;
typedef struct p6_unit_t
{
const uint32_t uop_mask;
const int port;
int first_available_cycle;
} p6_unit_t;
enum
{
UNIT_INT0 = 0,
UNIT_INT1,
UNIT_FPU,
UNIT_MMX_ADD,
UNIT_MMX_MUL,
UNIT_JUMP,
UNIT_LOAD,
UNIT_STORE_ADDR,
UNIT_STORE_DATA
};
/*Each port can only be used once per clock*/
typedef struct p6_port_t
{
uint32_t unit_mask;
} p6_port_t;
static int port_last_timestamps[5];
static const p6_port_t ports[] =
{
{UNIT_INT0 | UNIT_FPU | UNIT_MMX_MUL},
{UNIT_INT1 | UNIT_MMX_ADD | UNIT_JUMP},
{UNIT_LOAD},
{UNIT_STORE_ADDR},
{UNIT_STORE_DATA}
};
const int nr_ports = (sizeof(ports) / sizeof(p6_port_t));
static p6_unit_t units[] =
{
[UNIT_INT0] = {.uop_mask = (1 << UOP_ALU0) | (1 << UOP_ALU0_SEG) | (1 << UOP_ALU01), .port = 0}, /*Integer 0*/
[UNIT_INT1] = {.uop_mask = (1 << UOP_ALU1) | (1 << UOP_ALU01), .port = 1}, /*Integer 1*/
[UNIT_FPU] = {.uop_mask = 1 << UOP_FLOAT, .port = 0},
[UNIT_MMX_ADD] = {.uop_mask = 0, .port = 1},
[UNIT_MMX_MUL] = {.uop_mask = 0, .port = 0},
[UNIT_JUMP] = {.uop_mask = 1 << UOP_BRANCH, .port = 1},
[UNIT_LOAD] = {.uop_mask = 1 << UOP_LOAD, .port = 2},
[UNIT_STORE_ADDR] = {.uop_mask = 1 << UOP_STOREADDR, .port = 3},
[UNIT_STORE_DATA] = {.uop_mask = 1 << UOP_STOREDATA, .port = 4}
};
const int nr_units = (sizeof(units) / sizeof(p6_unit_t));
static int rat_timestamp = 0;
static int rat_uops = 0;
static int uop_run(const p6_uop_t *uop, int decode_time)
{
int c;
p6_unit_t *best_unit = NULL;
int best_start_cycle = 99999;
/*Peak of 3 uOPs from decode to RAT per cycle*/
if (decode_time < rat_timestamp)
decode_time = rat_timestamp;
else if (decode_time > rat_timestamp)
{
rat_timestamp = decode_time;
rat_uops = 0;
}
rat_uops++;
if (rat_uops == 3)
{
rat_timestamp++;
rat_uops = 0;
}
/*Find execution unit for this uOP*/
for (c = 0; c < nr_units; c++)
{
p6_unit_t *unit = &units[c];
if (unit->uop_mask & (1 << uop->type))
{
int start_cycle = MAX(unit->first_available_cycle,
port_last_timestamps[units[c].port]);
if (start_cycle < best_start_cycle)
{
best_unit = unit;
best_start_cycle = start_cycle;
}
}
}
if (!best_unit)
fatal("uop_run: can not find execution unit %x\n", uop->type);
if (cpu_s->cpu_type == CPU_PENTIUMPRO && uop->type == UOP_ALU0_SEG)
{
/*Pentium Pro will flush pipeline on a segment load. Find last
execution unit to complete, then set earliest start times on
_all_ execution units to after this point*/
int last_start_cycle = 0;
for (c = 0; c < nr_units; c++)
{
p6_unit_t *unit = &units[c];
int start_cycle = unit->first_available_cycle;
if (start_cycle > last_start_cycle)
last_start_cycle = start_cycle;
}
for (c = 0; c < nr_units; c++)
units[c].first_available_cycle = last_start_cycle+1;
}
if (best_start_cycle < decode_time)
best_start_cycle = decode_time;
best_unit->first_available_cycle = best_start_cycle + uop->throughput;
port_last_timestamps[best_unit->port] = best_start_cycle + 1;
return best_start_cycle + uop->throughput;
// return decode_time+1;
}
/*The P6 decoder can decode up to three instructions per clock
First can be up to 4 uOPs
Second and third must be 1 uOP each
Up to 16 bytes per cycle
1 cycle per prefix beyond 1 prefix
0x66 causes delays if instruction has immediate
0x67 causes delays if modr/m present (and mod != 3)
*/
static struct
{
int nr_ins;
int nr_uops;
const p6_uop_t *uops[6];
/*Earliest time a uop can start. If the timestamp is -1, then the uop is
part of a dependency chain and the start time is the completion time of
the previous uop*/
int earliest_start[6];
} decode_buffer;
#define NR_REGS 8
/*Timestamp of when last operation on an integer register completed*/
static int reg_available_timestamp[NR_REGS];
/*Timestamp of when last operation on an FPU register completed*/
static int fpu_st_timestamp[8];
/*Completion time of the last uop to be processed. Used to calculate timing of
dependent uop chains*/
static int last_uop_timestamp = 0;
static int ifetch_length = 0;
static int has_66_prefix, has_67_prefix;
static void decode_flush()
{
int c;
int uop_timestamp = 0;
/*Ensure that uops can not be submitted before they have been decoded*/
if (decode_timestamp > last_uop_timestamp)
last_uop_timestamp = decode_timestamp;
/*Submit uops to execution units, and determine the latest completion time*/
for (c = 0; c < decode_buffer.nr_uops; c++)
{
int start_timestamp;
// pclog("uOP %i, %p\n", c, decode_buffer.uops[c]);
if (decode_buffer.earliest_start[c] == -1)
start_timestamp = last_uop_timestamp;
else
start_timestamp = decode_buffer.earliest_start[c];
last_uop_timestamp = uop_run(decode_buffer.uops[c], start_timestamp);
if (last_uop_timestamp > uop_timestamp)
uop_timestamp = last_uop_timestamp;
}
/*Calculate opquad completion time. Since opquads complete in order, it
must be after the last completion.*/
if (uop_timestamp <= last_complete_timestamp)
last_complete_timestamp = last_complete_timestamp + 1;
else
last_complete_timestamp = uop_timestamp;
decode_timestamp++;
decode_buffer.nr_uops = 0;
decode_buffer.nr_ins = 0;
ifetch_length = 0;
}
/*The instruction is only of interest here if it's longer than 8 bytes, as that's the
limit on P6 short decoding*/
static int codegen_timing_instr_length(uint64_t deps, uint32_t fetchdat, int op_32)
{
int len = prefixes + 1; /*Opcode*/
if (deps & MODRM)
{
len++; /*ModR/M*/
if (deps & HAS_IMM8)
len++;
if (deps & HAS_IMM1632)
len += (op_32 & 0x100) ? 4 : 2;
if (op_32 & 0x200)
{
if ((fetchdat & 7) == 4 && (fetchdat & 0xc0) != 0xc0)
{
/* Has SIB*/
len++;
if ((fetchdat & 0xc0) == 0x40)
len++;
else if ((fetchdat & 0xc0) == 0x80)
len += 4;
else if ((fetchdat & 0x700) == 0x500)
len += 4;
}
else
{
if ((fetchdat & 0xc0) == 0x40)
len++;
else if ((fetchdat & 0xc0) == 0x80)
len += 4;
else if ((fetchdat & 0xc7) == 0x05)
len += 4;
}
}
else
{
if ((fetchdat & 0xc0) == 0x40)
len++;
else if ((fetchdat & 0xc0) == 0x80)
len += 2;
else if ((fetchdat & 0xc7) == 0x06)
len += 2;
}
}
return len;
}
static void decode_instruction(const p6_instruction_t *ins, uint64_t deps, uint32_t fetchdat, int op_32, uint32_t op_pc, int bit8)
{
uint32_t regmask_required;
uint32_t regmask_modified;
int c, d;
int earliest_start;
int instr_length = codegen_timing_instr_length(deps, fetchdat, op_32);
if (has_66_prefix && (deps & HAS_IMM1632))
decode_timestamp += 2;
if (has_67_prefix && (deps & MODRM))
decode_timestamp += 4;
earliest_start = decode_timestamp;
/*Generate input register mask, and determine the earliest time this
instruction can start. This is not accurate, as this is calculated per
x86 instruction when it should be handled per uop*/
regmask_required = get_dstdep_mask(deps, fetchdat, bit8);
regmask_required |= get_addr_regmask(deps, fetchdat, op_32);
for (c = 0; c < 8; c++)
{
if (regmask_required & (1 << c))
{
if (reg_available_timestamp[c] > decode_timestamp)
earliest_start = reg_available_timestamp[c];
}
}
if ((deps & FPU_RW_ST0) && fpu_st_timestamp[0] > decode_timestamp)
earliest_start = fpu_st_timestamp[0];
if ((deps & FPU_RW_ST1) && fpu_st_timestamp[1] > decode_timestamp)
earliest_start = fpu_st_timestamp[1];
if ((deps & FPU_RW_STREG))
{
int reg = fetchdat & 7;
if (fpu_st_timestamp[reg] > decode_timestamp)
earliest_start = fpu_st_timestamp[reg];
}
// pclog("ins->nr_uops=%i decode_buffer.nr_uops=%i decode_buffer.nr_ins=%i instr_length=%i\n", ins->nr_uops, decode_buffer.nr_uops, decode_buffer.nr_ins, instr_length);
/*Can only decode 16 bytes per cycle*/
if ((ifetch_length + instr_length) > 16)
decode_flush();
else
ifetch_length += instr_length;
if (ins->nr_uops > 4)
{
// pclog("Long decode\n");
/*Multi-cycle decode (> 4 uOPs) instruction*/
if (decode_buffer.nr_ins)
decode_flush();
d = 0;
for (c = 0; c < ins->nr_uops; c++)
{
decode_buffer.uops[d] = &ins->uop[c];
if (c == 0)
decode_buffer.earliest_start[d] = earliest_start;
else
decode_buffer.earliest_start[d] = -1;
d++;
if (d == 4)
{
d = 0;
decode_buffer.nr_uops = 4;
decode_flush();
}
}
if (d)
{
decode_buffer.nr_uops = d;
decode_flush();
}
}
else if (ins->nr_uops > 1 || instr_length > 8)
{
// pclog("Mid decode\n");
/*Long (> 1 uOPs) instruction*/
if (decode_buffer.nr_ins)
decode_flush();
decode_buffer.nr_uops = ins->nr_uops;
for (c = 0; c < ins->nr_uops; c++)
{
decode_buffer.uops[c] = &ins->uop[c];
if (c == 0)
decode_buffer.earliest_start[c] = earliest_start;
else
decode_buffer.earliest_start[c] = -1;
}
decode_buffer.nr_ins++;
}
else if (ins->nr_uops == 1)
{
// pclog("Short decode\n");
/*Short (1 uOP) instruction*/
decode_buffer.uops[decode_buffer.nr_uops] = &ins->uop[0];
decode_buffer.earliest_start[decode_buffer.nr_uops] = earliest_start;
decode_buffer.nr_ins++;
decode_buffer.nr_uops++;
if (decode_buffer.nr_ins == 3)
decode_flush();
}
/*Update write timestamps for any output registers*/
regmask_modified = get_dstdep_mask(deps, fetchdat, bit8);
for (c = 0; c < 8; c++)
{
if (regmask_modified & (1 << c))
reg_available_timestamp[c] = last_complete_timestamp;
}
if (deps & FPU_POP)
{
for (c = 0; c < 7; c++)
fpu_st_timestamp[c] = fpu_st_timestamp[c+1];
fpu_st_timestamp[7] = 0;
}
if (deps & FPU_POP2)
{
for (c = 0; c < 6; c++)
fpu_st_timestamp[c] = fpu_st_timestamp[c+2];
fpu_st_timestamp[6] = fpu_st_timestamp[7] = 0;
}
if (deps & FPU_PUSH)
{
for (c = 0; c < 7; c++)
fpu_st_timestamp[c+1] = fpu_st_timestamp[c];
fpu_st_timestamp[0] = 0;
}
if (deps & FPU_WRITE_ST0)
fpu_st_timestamp[0] = last_complete_timestamp;
if (deps & FPU_WRITE_ST1)
fpu_st_timestamp[1] = last_complete_timestamp;
if (deps & FPU_WRITE_STREG)
{
int reg = fetchdat & 7;
if (deps & FPU_POP)
reg--;
if (reg >= 0 &&
!(reg == 0 && (deps & FPU_WRITE_ST0)) &&
!(reg == 1 && (deps & FPU_WRITE_ST1)))
fpu_st_timestamp[reg] = last_complete_timestamp;
}
}
void codegen_timing_p6_block_start()
{
int c;
for (c = 0; c < nr_units; c++)
units[c].first_available_cycle = 0;
decode_timestamp = 0;
last_complete_timestamp = 0;
rat_timestamp = 0;
rat_uops = 0;
for (c = 0; c < 5; c++)
port_last_timestamps[c] = 0;
for (c = 0; c < NR_REGS; c++)
reg_available_timestamp[c] = 0;
for (c = 0; c < 8; c++)
fpu_st_timestamp[c] = 0;
ifetch_length = 0;
}
void codegen_timing_p6_start()
{
// units = p6_units;
// nr_units = NR_P6_UNITS;
last_prefix = 0;
prefixes = 0;
has_66_prefix = 0;
has_67_prefix = 0;
}
/*Prefixes :
- first is free
- operand size prefix has a penalty of 'a few clocks' if instruction has 16 or
32 bit immediate
- address size prefix has penalty if instruction has explicit memory operand*/
void codegen_timing_p6_prefix(uint8_t prefix, uint32_t fetchdat)
{
if (last_prefix) /*First prefix is free*/
decode_timestamp++;
if (prefix == 0x66)
has_66_prefix = 1;
if (prefix == 0x67)
has_67_prefix = 1;
last_prefix = prefix;
prefixes++;
}
void codegen_timing_p6_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, uint32_t op_pc)
{
const p6_instruction_t **ins_table;
uint64_t *deps;
int mod3 = ((fetchdat & 0xc0) == 0xc0);
int old_last_complete_timestamp = last_complete_timestamp;
int bit8 = !(opcode & 1);
// pclog("timing_opcode %02x\n", opcode);
switch (last_prefix)
{
case 0x0f:
ins_table = mod3 ? opcode_timings_0f_mod3 : opcode_timings_0f;
deps = mod3 ? opcode_deps_0f_mod3 : opcode_deps_0f;
// pclog("timings 0f\n");
break;
case 0xd8:
ins_table = 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:
ins_table = 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:
ins_table = 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:
ins_table = 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:
ins_table = 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:
ins_table = 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:
ins_table = 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:
ins_table = 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 0x81: case 0x82: case 0x83:
ins_table = mod3 ? opcode_timings_8x_mod3 : opcode_timings_8x;
deps = mod3 ? opcode_deps_8x_mod3 : opcode_deps_8x;
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 0xd0: case 0xd2:
case 0xc1: case 0xd1: case 0xd3:
ins_table = mod3 ? opcode_timings_shift_mod3 : opcode_timings_shift;
deps = mod3 ? opcode_deps_shift_mod3 : opcode_deps_shift;
opcode = (fetchdat >> 3) & 7;
// pclog("timings c1\n");
break;
case 0xf6:
ins_table = 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:
ins_table = 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:
ins_table = 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:
ins_table = mod3 ? opcode_timings_mod3 : opcode_timings;
deps = mod3 ? opcode_deps_mod3 : opcode_deps;
// pclog("timings normal\n");
break;
}
}
if (ins_table[opcode])
decode_instruction(ins_table[opcode], deps[opcode], fetchdat, op_32, op_pc, bit8);
else
decode_instruction(&alu01_op, 0, fetchdat, op_32, op_pc, bit8);
codegen_block_cycles += (last_complete_timestamp - old_last_complete_timestamp);
}
void codegen_timing_p6_block_end()
{
if (decode_buffer.nr_ins)
{
int old_last_complete_timestamp = last_complete_timestamp;
decode_flush();
codegen_block_cycles += (last_complete_timestamp - old_last_complete_timestamp);
}
// pclog("codegen_block_cycles=%i\n", codegen_block_cycles);
}
int codegen_timing_p6_jump_cycles()
{
if (decode_buffer.nr_uops)
return 1;
return 0;
}
codegen_timing_t codegen_timing_p6 =
{
codegen_timing_p6_start,
codegen_timing_p6_prefix,
codegen_timing_p6_opcode,
codegen_timing_p6_block_start,
codegen_timing_p6_block_end,
codegen_timing_p6_jump_cycles
};