/* $Id: event_set_p6.c,v 1.1 2003/02/16 21:08:54 mikpe Exp $
 * Performance counter event descriptions for the Intel P6 family.
 *
 * Copyright (C) 2003  Mikael Pettersson
 *
 * References
 * ----------
 * [IA32, Volume 3] "Intel Architecture Software Developer's Manual,
 * Volume 3: System Programming Guide". Intel document number 245472-009.
 * (at http://developer.intel.com/)
 */
#include <stddef.h>	/* for NULL */
#include "libperfctr.h"
#include "event_set.h"

/*
 * Intel Pentium Pro (P6) events.
 */

static const struct perfctr_unit_mask_4 p6_um_mesi = {
    { .type = perfctr_um_type_bitmask,
      .default_value = 0x0F,
      .nvalues = 4 },
    { { 0x08, "M (modified cache state)" },
      { 0x04, "E (exclusive cache state)" },
      { 0x02, "S (shared cache state)" },
      { 0x01, "I (invalid cache state)" } }
};

static const struct perfctr_unit_mask_2 p6_um_ebl = {
    { .type = perfctr_um_type_exclusive,
      .default_value = 0x20,
      .nvalues = 2 },
    { { 0x20, "transactions from any processor" },
      { 0x00, "self-generated transactions" } }
};

static const struct perfctr_event p6_events[] = {
    /* Data Cache Unit (DCU) */
    { 0x43, 0x3, NULL, "DATA_MEM_REFS" },
    { 0x45, 0x3, NULL, "DCU_LINES_IN" },
    { 0x46, 0x3, NULL, "DCU_M_LINES_IN" },
    { 0x47, 0x3, NULL, "DCU_M_LINES_OUT" },
    { 0x48, 0x3, NULL, "DCU_MISS_OUTSTANDING" },
    /* Instruction Fetch Unit (IFU) */
    { 0x80, 0x3, NULL, "IFU_IFETCH" },		/* XXX: was IFU_FETCH */
    { 0x81, 0x3, NULL, "IFU_IFETCH_MISS" },	/* XXX: was IFU_FETCH_MISS */
    { 0x85, 0x3, NULL, "ITLB_MISS" },
    { 0x86, 0x3, NULL, "IFU_MEM_STALL" },
    { 0x87, 0x3, NULL, "ILD_STALL" },
    /* L2 Cache */
    { 0x28, 0x3, UM(p6_um_mesi), "L2_IFETCH" },
    { 0x29, 0x3, UM(p6_um_mesi), "L2_LD" },
    { 0x2A, 0x3, UM(p6_um_mesi), "L2_ST" },
    { 0x24, 0x3, NULL, "L2_LINES_IN" },
    { 0x26, 0x3, NULL, "L2_LINES_OUT" },
    { 0x25, 0x3, NULL, "L2_M_LINES_INM" },
    { 0x27, 0x3, NULL, "L2_M_LINES_OUTM" },
    { 0x2E, 0x3, UM(p6_um_mesi), "L2_RQSTS" },
    { 0x21, 0x3, NULL, "L2_ADS" },
    { 0x22, 0x3, NULL, "L2_DBUS_BUSY" },
    { 0x23, 0x3, NULL, "L2_DBUS_BUSY_RD" },
    /* External Bus Logic (EBL) */
    { 0x62, 0x3, UM(p6_um_ebl), "BUS_DRDY_CLOCKS" },
    { 0x63, 0x3, UM(p6_um_ebl), "BUS_LOCK_CLOCKS" },
    { 0x60, 0x3, NULL, "BUS_REQ_OUTSTANDING" },
    { 0x65, 0x3, UM(p6_um_ebl), "BUS_TRAN_BRD" },
    { 0x66, 0x3, UM(p6_um_ebl), "BUS_TRAN_RFO" },
    { 0x67, 0x3, UM(p6_um_ebl), "BUS_TRANS_WB" },
    { 0x68, 0x3, UM(p6_um_ebl), "BUS_TRAN_IFETCH" },
    { 0x69, 0x3, UM(p6_um_ebl), "BUS_TRAN_INVAL" },
    { 0x6A, 0x3, UM(p6_um_ebl), "BUS_TRAN_PWR" },
    { 0x6B, 0x3, UM(p6_um_ebl), "BUS_TRANS_P" },
    { 0x6C, 0x3, UM(p6_um_ebl), "BUS_TRANS_IO" },
    { 0x6D, 0x3, UM(p6_um_ebl), "BUS_TRAN_DEF" },
    { 0x6E, 0x3, UM(p6_um_ebl), "BUS_TRAN_BURST" },
    { 0x70, 0x3, UM(p6_um_ebl), "BUS_TRAN_ANY" },
    { 0x6F, 0x3, UM(p6_um_ebl), "BUS_TRAN_MEM" },
    { 0x64, 0x3, NULL, "BUS_DATA_RCV" },
    { 0x61, 0x3, NULL, "BUS_BNR_DRV" },
    { 0x7A, 0x3, NULL, "BUS_HIT_DRV" },
    { 0x7B, 0x3, NULL, "BUS_HITM_DRV" },
    { 0x7E, 0x3, NULL, "BUS_SNOOP_STALL" },
    /* Floating-Point Unit */
    { 0xC1, 0x1, NULL, "FLOPS" },
    { 0x10, 0x1, NULL, "FP_COMP_OPS_EXE" },
    { 0x11, 0x2, NULL, "FP_ASSIST" },
    { 0x12, 0x2, NULL, "MUL" },
    { 0x13, 0x2, NULL, "DIV" },
    { 0x14, 0x1, NULL, "CYCLES_DIV_BUSY" },
    /* Memory Ordering */
    { 0x03, 0x3, NULL, "LD_BLOCKS" },
    { 0x04, 0x3, NULL, "SB_DRAINS" },
    { 0x05, 0x3, NULL, "MISALIGN_MEM_REF" },
    /* Instruction Decoding and Retirement */
    { 0xC0, 0x3, NULL, "INST_RETIRED" },
    { 0xC2, 0x3, NULL, "UOPS_RETIRED" },
    { 0xD0, 0x3, NULL, "INST_DECODED" },
    /* Interrupts */
    { 0xC8, 0x3, NULL, "HW_INT_RX" },
    { 0xC6, 0x3, NULL, "CYCLES_INT_MASKED" },
    { 0xC7, 0x3, NULL, "CYCLES_INT_PENDING_AND_MASKED" },
    /* Branches */
    { 0xC4, 0x3, NULL, "BR_INST_RETIRED" },
    { 0xC5, 0x3, NULL, "BR_MISS_PRED_RETIRED" },
    { 0xC9, 0x3, NULL, "BR_TAKEN_RETIRED" },
    { 0xCA, 0x3, NULL, "BR_MISS_PRED_TAKEN_RET" },
    { 0xE0, 0x3, NULL, "BR_INST_DECODED" },
    { 0xE2, 0x3, NULL, "BTB_MISSES" },
    { 0xE4, 0x3, NULL, "BR_BOGUS" },
    { 0xE6, 0x3, NULL, "BACLEARS" },
    /* Stalls */
    { 0xA2, 0x3, NULL, "RESOURCE_STALLS" },
    { 0xD2, 0x3, NULL, "PARTIAL_RAT_STALLS" },
    /* Segment Register Loads */
    { 0x06, 0x3, NULL, "SEGMENT_REG_LOADS" },
    /* Clocks */
    { 0x79, 0x3, NULL, "CPU_CLK_UNHALTED" },
};

const struct perfctr_event_set perfctr_p6_event_set = {
    .cpu_type = PERFCTR_X86_INTEL_P6,
    .event_prefix = "P6_",
    .include = NULL,
    .nevents = ARRAY_SIZE(p6_events),
    .events = p6_events,
};

/*
 * Intel Pentium II events.
 * Note that two PII events (0xB0 and 0xCE) are unavailable in the PIII.
 */

static const struct perfctr_unit_mask_0 p2_um_mmx_uops_exec = {
    { .type = perfctr_um_type_fixed,
      .default_value = 0x0F,
      .nvalues = 0 }
};

static const struct perfctr_unit_mask_6 p2_um_mmx_instr_type_exec = {
    { .type = perfctr_um_type_bitmask,
      .default_value = 0x3F,
      .nvalues = 6 },
    { { 0x01, "MMX packed multiplies" },
      { 0x02, "MMX packed shifts" },
      { 0x04, "MMX pack operations" },
      { 0x08, "MMX unpack operations" },
      { 0x10, "MMX packed logical instructions" },
      { 0x20, "MMX packed arithmetic instructions" } }
};

static const struct perfctr_unit_mask_2 p2_um_fp_mmx_trans = {
    { .type = perfctr_um_type_exclusive,
      .default_value = 0x00,
      .nvalues = 2 },
    { { 0x00, "MMX to FP transitions" },
      { 0x01, "FP to MMX transitions" } }
};

static const struct perfctr_unit_mask_4 p2_um_seg_reg_rename = {
    { .type = perfctr_um_type_bitmask,
      .default_value = 0x0F,
      .nvalues = 4 },
    { { 0x01, "segment register ES" },
      { 0x02, "segment register DS" },
      { 0x04, "segment register FS" },
      { 0x08, "segment register GS" } }
};

static const struct perfctr_event p2andp3_events[] = {
    /* MMX Unit */
    { 0xB1, 0x3, NULL, "MMX_SAT_INSTR_EXEC" },
    { 0xB2, 0x3, UM(p2_um_mmx_uops_exec), "MMX_UOPS_EXEC" },
    { 0xB3, 0x3, UM(p2_um_mmx_instr_type_exec), "MMX_INSTR_TYPE_EXEC" },
    { 0xCC, 0x3, UM(p2_um_fp_mmx_trans), "FP_MMX_TRANS" },
    { 0xCD, 0x3, NULL, "MMX_ASSIST" },
    /* Segment Register Renaming */
    { 0xD4, 0x3, UM(p2_um_seg_reg_rename), "SEG_RENAME_STALLS" },
    { 0xD5, 0x3, UM(p2_um_seg_reg_rename), "SEG_REG_RENAMES" },
    { 0xD6, 0x3, NULL, "RET_SEG_RENAMES" },
};

static const struct perfctr_event_set p2andp3_event_set = {
    .cpu_type = PERFCTR_X86_INTEL_PII,
    .event_prefix = "PII_",
    .include = &perfctr_p6_event_set,
    .nevents = ARRAY_SIZE(p2andp3_events),
    .events = p2andp3_events,
};

static const struct perfctr_event p2_events[] = {	/* not in PIII :-( */
    /* MMX Unit */
    { 0xB0, 0x3, NULL, "MMX_INSTR_EXEC" },
    { 0xCE, 0x3, NULL, "MMX_INSTR_RET" },
};

const struct perfctr_event_set perfctr_p2_event_set = {
    .cpu_type = PERFCTR_X86_INTEL_PII,
    .event_prefix = "PII_",
    .include = &p2andp3_event_set,
    .nevents = ARRAY_SIZE(p2_events),
    .events = p2_events,
};

/*
 * Intel Pentium III events.
 */

static const struct perfctr_unit_mask_4 p3_um_kni_prefetch = {
    { .type = perfctr_um_type_exclusive,
      .default_value = 0x00,
      .nvalues = 4 },
    { { 0x00, "prefetch NTA" },
      { 0x01, "prefetch T1" },
      { 0x02, "prefetch T2" },
      { 0x03, "weakly ordered stores" } }
};

static const struct perfctr_unit_mask_2 p3_um_kni_inst_retired = {
    { .type = perfctr_um_type_exclusive,
      .default_value = 0x00,
      .nvalues = 2 },
    { { 0x00, "packed and scalar" },
      { 0x01, "scalar" } }
};

static const struct perfctr_event p3_events[] = {
    /* Memory Ordering */
    { 0x07, 0x3, UM(p3_um_kni_prefetch), "EMON_KNI_PREF_DISPATCHED" },
    { 0x4B, 0x3, UM(p3_um_kni_prefetch), "EMON_KNI_PREF_MISS" },
    /* Instruction Decoding and Retirement */
    { 0xD8, 0x3, UM(p3_um_kni_inst_retired), "EMON_KNI_INST_RETIRED" },
    { 0xD9, 0x3, UM(p3_um_kni_inst_retired), "EMON_KNI_COMP_INST_RET" },
};

const struct perfctr_event_set perfctr_p3_event_set = {
    .cpu_type = PERFCTR_X86_INTEL_PIII,
    .event_prefix = "PIII_",
    .include = &p2andp3_event_set,
    .nevents = ARRAY_SIZE(p3_events),
    .events = p3_events,
};
