/*
 * 86Box	A hypervisor and IBM PC system emulator that specializes in
 *		running old operating systems and software designed for IBM
 *		PC systems and compatibles from 1981 through fairly recent
 *		system designs based on the PCI bus.
 *
 *		This file is part of the 86Box distribution.
 *
 *		CPU type handler.
 *
 * Authors:	Sarah Walker, <tommowalker@tommowalker.co.uk>
 *		leilei,
 *		Miran Grca, <mgrca8@gmail.com>
 *		Fred N. van Kempen, <decwiz@yahoo.com>
 *
 *		Copyright 2008-2018 Sarah Walker.
 *		Copyright 2016-2018 leilei.
 *		Copyright 2016-2018 Miran Grca.
 *		Copyright 2018 Fred N. van Kempen.
 */
#include <math.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <wchar.h>

#define HAVE_STDARG_H
#include <86box/86box.h>
#include "cpu.h"
#include <86box/device.h>
#include <86box/machine.h>
#include <86box/io.h>
#include "x86_ops.h"
#include <86box/mem.h>
#include <86box/nmi.h>
#include <86box/pic.h>
#include <86box/pci.h>
#include <86box/gdbstub.h>
#ifdef USE_DYNAREC
# include "codegen.h"
#endif
#include "x87_timings.h"

#define CCR1_USE_SMI  (1 << 1)
#define CCR1_SMAC     (1 << 2)
#define CCR1_SM3      (1 << 7)

#define CCR3_SMI_LOCK (1 << 0)
#define CCR3_NMI_EN   (1 << 1)


enum {
        CPUID_FPU = (1 << 0),
        CPUID_VME = (1 << 1),
        CPUID_PSE = (1 << 3),
        CPUID_TSC = (1 << 4),
        CPUID_MSR = (1 << 5),
        CPUID_PAE = (1 << 6),
        CPUID_MCE = (1 << 7),
        CPUID_CMPXCHG8B = (1 << 8),
	CPUID_AMDSEP = (1 << 10),
	CPUID_SEP = (1 << 11),
	CPUID_MTRR = (1 << 12),
        CPUID_MCA = (1 << 14),
        CPUID_CMOV = (1 << 15),
        CPUID_MMX = (1 << 23),
	CPUID_FXSR = (1 << 24)
};

/*Addition flags returned by CPUID function 0x80000001*/
#define CPUID_3DNOW	(1UL << 31UL)


/* Make sure this is as low as possible. */
cpu_state_t	cpu_state;

#ifdef USE_DYNAREC
const OpFn	*x86_dynarec_opcodes, *x86_dynarec_opcodes_0f,
		*x86_dynarec_opcodes_d8_a16, *x86_dynarec_opcodes_d8_a32,
		*x86_dynarec_opcodes_d9_a16, *x86_dynarec_opcodes_d9_a32,
		*x86_dynarec_opcodes_da_a16, *x86_dynarec_opcodes_da_a32,
		*x86_dynarec_opcodes_db_a16, *x86_dynarec_opcodes_db_a32,
		*x86_dynarec_opcodes_dc_a16, *x86_dynarec_opcodes_dc_a32,
		*x86_dynarec_opcodes_dd_a16, *x86_dynarec_opcodes_dd_a32,
		*x86_dynarec_opcodes_de_a16, *x86_dynarec_opcodes_de_a32,
		*x86_dynarec_opcodes_df_a16, *x86_dynarec_opcodes_df_a32,
		*x86_dynarec_opcodes_REPE, *x86_dynarec_opcodes_REPNE,
		*x86_dynarec_opcodes_3DNOW;
#endif

const OpFn	*x86_opcodes, *x86_opcodes_0f,
		*x86_opcodes_d8_a16, *x86_opcodes_d8_a32,
		*x86_opcodes_d9_a16, *x86_opcodes_d9_a32,
		*x86_opcodes_da_a16, *x86_opcodes_da_a32,
		*x86_opcodes_db_a16, *x86_opcodes_db_a32,
		*x86_opcodes_dc_a16, *x86_opcodes_dc_a32,
		*x86_opcodes_dd_a16, *x86_opcodes_dd_a32,
		*x86_opcodes_de_a16, *x86_opcodes_de_a32,
		*x86_opcodes_df_a16, *x86_opcodes_df_a32,
		*x86_opcodes_REPE, *x86_opcodes_REPNE,
		*x86_opcodes_3DNOW;

uint16_t	cpu_fast_off_count, cpu_fast_off_val;
uint16_t	temp_seg_data[4] = {0, 0, 0, 0};

int		isa_cycles, cpu_inited,

		cpu_cycles_read, cpu_cycles_read_l, cpu_cycles_write, cpu_cycles_write_l,
		cpu_prefetch_cycles, cpu_prefetch_width, cpu_mem_prefetch_cycles, cpu_rom_prefetch_cycles,
		cpu_waitstates, cpu_cache_int_enabled, cpu_cache_ext_enabled,
		cpu_isa_speed, cpu_pci_speed, cpu_isa_pci_div, cpu_agp_speed, cpu_alt_reset,

		cpu_override, cpu_effective, cpu_multi, cpu_16bitbus, cpu_64bitbus, cpu_busspeed,
		cpu_cyrix_alignment, CPUID,

 		is286, is386, is486 = 1,
		cpu_isintel, cpu_iscyrix, hascache, isibm486, israpidcad, is_vpc,
		is_am486, is_am486dxl, is_pentium, is_k5, is_k6, is_p6, is_cxsmm, hasfpu,

		timing_rr, timing_mr, timing_mrl, timing_rm, timing_rml,
		timing_mm, timing_mml, timing_bt, timing_bnt,
		timing_int, timing_int_rm, timing_int_v86, timing_int_pm,
		timing_int_pm_outer, timing_iret_rm, timing_iret_v86, timing_iret_pm,
		timing_iret_pm_outer, timing_call_rm, timing_call_pm, timing_call_pm_gate,
		timing_call_pm_gate_inner, timing_retf_rm, timing_retf_pm, timing_retf_pm_outer,
		timing_jmp_rm, timing_jmp_pm, timing_jmp_pm_gate, timing_misaligned;
uint32_t	cpu_features, cpu_fast_off_flags;

uint32_t	_tr[8] = {0, 0, 0, 0, 0, 0, 0, 0};
uint32_t	cache_index = 0;
uint8_t		_cache[2048];

uint64_t	cpu_CR4_mask, tsc = 0;
uint64_t	pmc[2] = {0, 0};

double		cpu_dmulti;

msr_t		msr;

cyrix_t		cyrix;

cpu_family_t	*cpu_f;
CPU		*cpu_s;

uint8_t		do_translate = 0, do_translate2 = 0;

void		(*cpu_exec)(int cycs);


static uint8_t	ccr0, ccr1, ccr2, ccr3, ccr4, ccr5, ccr6;

static int	cyrix_addr;


static void	cpu_write(uint16_t addr, uint8_t val, void *priv);
static uint8_t	cpu_read(uint16_t addr, void *priv);


#ifdef ENABLE_CPU_LOG
int cpu_do_log = ENABLE_CPU_LOG;


void
cpu_log(const char *fmt, ...)
{
    va_list ap;

    if (cpu_do_log) {
	va_start(ap, fmt);
	pclog_ex(fmt, ap);
	va_end(ap);
    }
}
#else
#define cpu_log(fmt, ...)
#endif


int
cpu_has_feature(int feature)
{
    return cpu_features & feature;
}


void
cpu_dynamic_switch(int new_cpu)
{
    int c;

    if (cpu_effective == new_cpu)
	return;

    c = cpu;
    cpu = new_cpu;
    cpu_set();
    pc_speed_changed();
    cpu = c;
}


void
cpu_set_edx(void)
{
    EDX = cpu_s->edx_reset;
}


cpu_family_t *
cpu_get_family(const char *internal_name)
{
    int c = 0;

    while (cpu_families[c].package) {
	if (!strcmp(internal_name, cpu_families[c].internal_name))
		return (cpu_family_t *) &cpu_families[c];
	c++;
    }

    return NULL;
}


uint8_t
cpu_is_eligible(const cpu_family_t *cpu_family, int cpu, int machine)
{
    const machine_t *machine_s = &machines[machine];
    const CPU *cpu_s = &cpu_family->cpus[cpu];
    uint32_t packages, bus_speed;
    uint8_t i;
    double multi;

    /* Full override. */
    if (cpu_override > 1)
	return 1;

    /* Add implicit CPU package compatibility. */
    packages = machine_s->cpu_package;
    if (packages & CPU_PKG_SOCKET3)
	packages |= CPU_PKG_SOCKET1;
    else if (packages & CPU_PKG_SLOT1)
	packages |= CPU_PKG_SOCKET370;

    /* Package type. */
    if (!(cpu_family->package & packages))
	return 0;

    /* Partial override. */
    if (cpu_override)
	return 1;

    /* Check CPU blocklist. */
    if (machine_s->cpu_block) {
	i = 0;

	while (machine_s->cpu_block[i]) {
		if (machine_s->cpu_block[i++] == cpu_s->cpu_type)
			return 0;
	}
    }

    bus_speed = cpu_s->rspeed / cpu_s->multi;

    /* Minimum bus speed with ~0.84 MHz (for 8086) tolerance. */
    if (machine_s->cpu_min_bus && (bus_speed < (machine_s->cpu_min_bus - 840907)))
	return 0;

    /* Maximum bus speed with ~0.84 MHz (for 8086) tolerance. */
    if (machine_s->cpu_max_bus && (bus_speed > (machine_s->cpu_max_bus + 840907)))
	return 0;

    /* Minimum voltage with 0.1V tolerance. */
    if (machine_s->cpu_min_voltage && (cpu_s->voltage < (machine_s->cpu_min_voltage - 100)))
	return 0;

    /* Maximum voltage with 0.1V tolerance. */
    if (machine_s->cpu_max_voltage && (cpu_s->voltage > (machine_s->cpu_max_voltage + 100)))
	return 0;

    /* Account for CPUs which use a different internal multiplier than specified by jumpers. */
    multi = cpu_s->multi;

    /* Don't care about multiplier compatibility on fixed multiplier CPUs. */
    if (cpu_s->cpu_flags & CPU_FIXED_MULTIPLIER)
	return 1;
    else if (cpu_family->package & CPU_PKG_SOCKET5_7) {
	if ((multi == 1.5) && (cpu_s->cpu_type == CPU_5K86) && (machine_s->cpu_min_multi > 1.5)) /* K5 5k86 */
		multi = 2.0;
	else if (multi == 1.75)				/* K5 5k86 */
		multi = 2.5;
	else if (multi == 2.0) {
		if (cpu_s->cpu_type == CPU_5K86)	/* K5 5k86 */
			multi = 3.0;
		/* K6-2+ / K6-3+ */
		else if ((cpu_s->cpu_type == CPU_K6_2P) || (cpu_s->cpu_type == CPU_K6_3P))
			multi = 2.5;
		else if (((cpu_s->cpu_type == CPU_WINCHIP) || (cpu_s->cpu_type == CPU_WINCHIP2)) &&
			 (machine_s->cpu_min_multi > 2.0))	/* WinChip (2) */
			multi = 2.5;
	}
	else if (multi == (7.0 / 3.0))	/* WinChip 2A - 2.33x */
		multi = 5.0;
	else if (multi == (8.0 / 3.0))	/* WinChip 2A - 2.66x */
		multi = 5.5;
	else if ((multi == 3.0) && (cpu_s->cpu_type == CPU_Cx6x86 || cpu_s->cpu_type == CPU_Cx6x86L))	/* 6x86(L) */
		multi = 1.5;
	else if (multi == (10.0 / 3.0))	/* WinChip 2A - 3.33x */
		multi = 2.0;
	else if (multi == 3.5)		/* standard set by the Pentium MMX */
		multi = 1.5;
	else if (multi == 4.0) {
		/* WinChip (2) */
		if ((cpu_s->cpu_type == CPU_WINCHIP) || (cpu_s->cpu_type ==  CPU_WINCHIP2)) {
			if (machine_s->cpu_min_multi >= 1.5)
				multi = 1.5;
			else if (machine_s->cpu_min_multi >= 3.5)
				multi = 3.5;
			else if (machine_s->cpu_min_multi >= 4.5)
				multi = 4.5;
		} else if ((cpu_s->cpu_type == CPU_Cx6x86) || (cpu_s->cpu_type == CPU_Cx6x86L))	/* 6x86(L) */
			multi = 3.0;
	} else if ((multi == 5.0) && ((cpu_s->cpu_type == CPU_WINCHIP) || (cpu_s->cpu_type == CPU_WINCHIP2)) &&
		   (machine_s->cpu_min_multi > 5.0))	/* WinChip (2) */
		multi = 5.5;
	else if (multi == 6.0)	/* K6-2(+) / K6-3(+) */
		multi = 2.0;
    }

    /* Minimum multiplier, */
    if (multi < machine_s->cpu_min_multi)
	return 0;

    /* Maximum multiplier. */
    if (machine_s->cpu_max_multi && (multi > machine_s->cpu_max_multi))
	return 0;

    return 1;
}


uint8_t
cpu_family_is_eligible(const cpu_family_t *cpu_family, int machine)
{
    int c = 0;

    while (cpu_family->cpus[c].cpu_type) {
	if (cpu_is_eligible(cpu_family, c, machine))
		return 1;
	c++;
    }

    return 0;
}


void
cpu_set(void)
{
    cpu_inited = 1;

    cpu_effective = cpu;
    cpu_s = (CPU *) &cpu_f->cpus[cpu_effective];

#ifdef USE_ACYCS
    acycs = 0;
#endif

    soft_reset_pci = 0;

    cpu_alt_reset = 0;
    unmask_a20_in_smm = 0;

    CPUID        = cpu_s->cpuid_model;
    is8086       = (cpu_s->cpu_type > CPU_8088);
    is286        = (cpu_s->cpu_type >= CPU_286);
    is386        = (cpu_s->cpu_type >= CPU_386SX);
    israpidcad   = (cpu_s->cpu_type == CPU_RAPIDCAD);
    isibm486     = (cpu_s->cpu_type == CPU_IBM386SLC) || (cpu_s->cpu_type == CPU_IBM486SLC) ||
		   (cpu_s->cpu_type == CPU_IBM486BL);
    is486        = (cpu_s->cpu_type >= CPU_RAPIDCAD);
    is_am486     = (cpu_s->cpu_type == CPU_ENH_Am486DX);
    is_am486dxl  = (cpu_s->cpu_type == CPU_Am486DXL);

    cpu_isintel = !strcmp(cpu_f->manufacturer, "Intel");
    cpu_iscyrix = !strcmp(cpu_f->manufacturer, "Cyrix") || !strcmp(cpu_f->manufacturer, "ST");

    /* SL-Enhanced Intel 486s have the same SMM save state table layout as Pentiums,
       and the WinChip datasheet claims those are Pentium-compatible as well. AMD Am486DXL/DXL2 also has compatible SMM, or would if not for it's different SMBase*/
    is_pentium   = (cpu_isintel && (cpu_s->cpu_type >= CPU_i486SX_SLENH) && (cpu_s->cpu_type < CPU_PENTIUMPRO)) ||
		   !strcmp(cpu_f->manufacturer, "IDT") || (cpu_s->cpu_type == CPU_Am486DXL);
    is_k5        = !strcmp(cpu_f->manufacturer, "AMD") && (cpu_s->cpu_type > CPU_ENH_Am486DX) && (cpu_s->cpu_type < CPU_K6);
    is_k6        = (cpu_s->cpu_type >= CPU_K6) && !strcmp(cpu_f->manufacturer, "AMD");
    /* The Samuel 2 datasheet claims it's Celeron-compatible. */
    is_p6        = (cpu_isintel && (cpu_s->cpu_type >= CPU_PENTIUMPRO)) || !strcmp(cpu_f->manufacturer, "VIA");
    is_cxsmm     = (!strcmp(cpu_f->manufacturer, "Cyrix") || !strcmp(cpu_f->manufacturer, "ST")) &&
		   (cpu_s->cpu_type >= CPU_Cx486S);

    hasfpu       = (fpu_type != FPU_NONE);
    hascache     = (cpu_s->cpu_type >= CPU_486SLC) || (cpu_s->cpu_type == CPU_IBM386SLC) ||
		   (cpu_s->cpu_type == CPU_IBM486SLC) || (cpu_s->cpu_type == CPU_IBM486BL);

    cpu_16bitbus = (cpu_s->cpu_type == CPU_286) || (cpu_s->cpu_type == CPU_386SX) ||
		   (cpu_s->cpu_type == CPU_486SLC) || (cpu_s->cpu_type == CPU_IBM386SLC) ||
		   (cpu_s->cpu_type == CPU_IBM486SLC);
    cpu_64bitbus = (cpu_s->cpu_type >= CPU_WINCHIP);

    if (cpu_s->multi)
	cpu_busspeed = cpu_s->rspeed / cpu_s->multi;
    else
	cpu_busspeed = cpu_s->rspeed;
    cpu_multi = (int) ceil(cpu_s->multi);
    cpu_dmulti = cpu_s->multi;
    ccr0 = ccr1 = ccr2 = ccr3 = ccr4 = ccr5 = ccr6 = 0;

    cpu_update_waitstates();

    isa_cycles = cpu_s->atclk_div;

    if (cpu_s->rspeed <= 8000000)
	cpu_rom_prefetch_cycles = cpu_mem_prefetch_cycles;
    else
	cpu_rom_prefetch_cycles = cpu_s->rspeed / 1000000;

    cpu_set_isa_pci_div(0);
    cpu_set_pci_speed(0);
    cpu_set_agp_speed(0);

    io_handler(cpu_iscyrix, 0x0022, 0x0002, cpu_read, NULL, NULL, cpu_write, NULL, NULL, NULL);

    io_handler(hasfpu, 0x00f0, 0x000f, cpu_read, NULL, NULL, cpu_write, NULL, NULL, NULL);
    io_handler(hasfpu, 0xf007, 0x0001, cpu_read, NULL, NULL, cpu_write, NULL, NULL, NULL);

#ifdef USE_DYNAREC
    x86_setopcodes(ops_386, ops_386_0f, dynarec_ops_386, dynarec_ops_386_0f);
#else
    x86_setopcodes(ops_386, ops_386_0f);
#endif
    x86_opcodes_REPE = ops_REPE;
    x86_opcodes_REPNE = ops_REPNE;
    x86_opcodes_3DNOW = ops_3DNOW;
#ifdef USE_DYNAREC
    x86_dynarec_opcodes_REPE = dynarec_ops_REPE;
    x86_dynarec_opcodes_REPNE = dynarec_ops_REPNE;
    x86_dynarec_opcodes_3DNOW = dynarec_ops_3DNOW;
#endif

    if (hasfpu) {
#ifdef USE_DYNAREC
	x86_dynarec_opcodes_d8_a16 = dynarec_ops_fpu_d8_a16;
	x86_dynarec_opcodes_d8_a32 = dynarec_ops_fpu_d8_a32;
	x86_dynarec_opcodes_d9_a16 = dynarec_ops_fpu_d9_a16;
	x86_dynarec_opcodes_d9_a32 = dynarec_ops_fpu_d9_a32;
	x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_da_a16;
	x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_da_a32;
	x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_db_a16;
	x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_db_a32;
	x86_dynarec_opcodes_dc_a16 = dynarec_ops_fpu_dc_a16;
	x86_dynarec_opcodes_dc_a32 = dynarec_ops_fpu_dc_a32;
	x86_dynarec_opcodes_dd_a16 = dynarec_ops_fpu_dd_a16;
	x86_dynarec_opcodes_dd_a32 = dynarec_ops_fpu_dd_a32;
	x86_dynarec_opcodes_de_a16 = dynarec_ops_fpu_de_a16;
	x86_dynarec_opcodes_de_a32 = dynarec_ops_fpu_de_a32;
	x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_df_a16;
	x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_df_a32;
#endif
	x86_opcodes_d8_a16 = ops_fpu_d8_a16;
	x86_opcodes_d8_a32 = ops_fpu_d8_a32;
	x86_opcodes_d9_a16 = ops_fpu_d9_a16;
	x86_opcodes_d9_a32 = ops_fpu_d9_a32;
	x86_opcodes_da_a16 = ops_fpu_da_a16;
	x86_opcodes_da_a32 = ops_fpu_da_a32;
	x86_opcodes_db_a16 = ops_fpu_db_a16;
	x86_opcodes_db_a32 = ops_fpu_db_a32;
	x86_opcodes_dc_a16 = ops_fpu_dc_a16;
	x86_opcodes_dc_a32 = ops_fpu_dc_a32;
	x86_opcodes_dd_a16 = ops_fpu_dd_a16;
	x86_opcodes_dd_a32 = ops_fpu_dd_a32;
	x86_opcodes_de_a16 = ops_fpu_de_a16;
	x86_opcodes_de_a32 = ops_fpu_de_a32;
	x86_opcodes_df_a16 = ops_fpu_df_a16;
	x86_opcodes_df_a32 = ops_fpu_df_a32;
    } else {
#ifdef USE_DYNAREC
	x86_dynarec_opcodes_d8_a16 = dynarec_ops_nofpu_a16;
	x86_dynarec_opcodes_d8_a32 = dynarec_ops_nofpu_a32;
	x86_dynarec_opcodes_d9_a16 = dynarec_ops_nofpu_a16;
	x86_dynarec_opcodes_d9_a32 = dynarec_ops_nofpu_a32;
	x86_dynarec_opcodes_da_a16 = dynarec_ops_nofpu_a16;
	x86_dynarec_opcodes_da_a32 = dynarec_ops_nofpu_a32;
	x86_dynarec_opcodes_db_a16 = dynarec_ops_nofpu_a16;
	x86_dynarec_opcodes_db_a32 = dynarec_ops_nofpu_a32;
	x86_dynarec_opcodes_dc_a16 = dynarec_ops_nofpu_a16;
	x86_dynarec_opcodes_dc_a32 = dynarec_ops_nofpu_a32;
	x86_dynarec_opcodes_dd_a16 = dynarec_ops_nofpu_a16;
	x86_dynarec_opcodes_dd_a32 = dynarec_ops_nofpu_a32;
	x86_dynarec_opcodes_de_a16 = dynarec_ops_nofpu_a16;
	x86_dynarec_opcodes_de_a32 = dynarec_ops_nofpu_a32;
	x86_dynarec_opcodes_df_a16 = dynarec_ops_nofpu_a16;
	x86_dynarec_opcodes_df_a32 = dynarec_ops_nofpu_a32;
#endif
	x86_opcodes_d8_a16 = ops_nofpu_a16;
	x86_opcodes_d8_a32 = ops_nofpu_a32;
	x86_opcodes_d9_a16 = ops_nofpu_a16;
	x86_opcodes_d9_a32 = ops_nofpu_a32;
	x86_opcodes_da_a16 = ops_nofpu_a16;
	x86_opcodes_da_a32 = ops_nofpu_a32;
	x86_opcodes_db_a16 = ops_nofpu_a16;
	x86_opcodes_db_a32 = ops_nofpu_a32;
	x86_opcodes_dc_a16 = ops_nofpu_a16;
	x86_opcodes_dc_a32 = ops_nofpu_a32;
	x86_opcodes_dd_a16 = ops_nofpu_a16;
	x86_opcodes_dd_a32 = ops_nofpu_a32;
	x86_opcodes_de_a16 = ops_nofpu_a16;
	x86_opcodes_de_a32 = ops_nofpu_a32;
	x86_opcodes_df_a16 = ops_nofpu_a16;
	x86_opcodes_df_a32 = ops_nofpu_a32;
    }

#ifdef USE_DYNAREC
    codegen_timing_set(&codegen_timing_486);
#endif

    memset(&msr, 0, sizeof(msr));

    timing_misaligned = 0;
    cpu_cyrix_alignment = 0;
    cpu_CR4_mask = 0;

    switch (cpu_s->cpu_type) {
	case CPU_8088:
	case CPU_8086:
		break;

	case CPU_286:
#ifdef USE_DYNAREC
		x86_setopcodes(ops_286, ops_286_0f, dynarec_ops_286, dynarec_ops_286_0f);
#else
		x86_setopcodes(ops_286, ops_286_0f);
#endif

		if (fpu_type == FPU_287) {
#ifdef USE_DYNAREC
			x86_dynarec_opcodes_d9_a16 = dynarec_ops_fpu_287_d9_a16;
			x86_dynarec_opcodes_d9_a32 = dynarec_ops_fpu_287_d9_a32;
			x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_287_da_a16;
			x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_287_da_a32;
			x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_287_db_a16;
			x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_287_db_a32;
			x86_dynarec_opcodes_dc_a16 = dynarec_ops_fpu_287_dc_a16;
			x86_dynarec_opcodes_dc_a32 = dynarec_ops_fpu_287_dc_a32;
			x86_dynarec_opcodes_dd_a16 = dynarec_ops_fpu_287_dd_a16;
			x86_dynarec_opcodes_dd_a32 = dynarec_ops_fpu_287_dd_a32;
			x86_dynarec_opcodes_de_a16 = dynarec_ops_fpu_287_de_a16;
			x86_dynarec_opcodes_de_a32 = dynarec_ops_fpu_287_de_a32;
			x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_287_df_a16;
			x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_287_df_a32;
#endif
			x86_opcodes_d9_a16 = ops_fpu_287_d9_a16;
			x86_opcodes_d9_a32 = ops_fpu_287_d9_a32;
			x86_opcodes_da_a16 = ops_fpu_287_da_a16;
			x86_opcodes_da_a32 = ops_fpu_287_da_a32;
			x86_opcodes_db_a16 = ops_fpu_287_db_a16;
			x86_opcodes_db_a32 = ops_fpu_287_db_a32;
			x86_opcodes_dc_a16 = ops_fpu_287_dc_a16;
			x86_opcodes_dc_a32 = ops_fpu_287_dc_a32;
			x86_opcodes_dd_a16 = ops_fpu_287_dd_a16;
			x86_opcodes_dd_a32 = ops_fpu_287_dd_a32;
			x86_opcodes_de_a16 = ops_fpu_287_de_a16;
			x86_opcodes_de_a32 = ops_fpu_287_de_a32;
			x86_opcodes_df_a16 = ops_fpu_287_df_a16;
			x86_opcodes_df_a32 = ops_fpu_287_df_a32;
		}

		timing_rr			=   2;	/* register dest - register src */
		timing_rm			=   7;	/* register dest - memory src */
		timing_mr			=   7;	/* memory dest   - register src */
		timing_mm			=   7;	/* memory dest   - memory src */
		timing_rml			=   9;	/* register dest - memory src long */
		timing_mrl			=  11;	/* memory dest   - register src long */
		timing_mml			=  11;	/* memory dest   - memory src */
		timing_bt			=   4;	/* branch taken */
		timing_bnt			=   3;	/* branch not taken */

		timing_int			=   0;
		timing_int_rm			=  23;
		timing_int_v86			=   0;
		timing_int_pm			=  40;
		timing_int_pm_outer		=  78;
		timing_iret_rm			=  17;
		timing_iret_v86			=   0;
		timing_iret_pm			=  31;
		timing_iret_pm_outer		=  55;
		timing_call_rm			=  13;
		timing_call_pm			=  26;
		timing_call_pm_gate		=  52;
		timing_call_pm_gate_inner	=  82;
		timing_retf_rm			=  15;
		timing_retf_pm			=  25;
		timing_retf_pm_outer		=  55;
		timing_jmp_rm			=  11;
		timing_jmp_pm			=  23;
		timing_jmp_pm_gate		=  38;
		break;

	case CPU_IBM486SLC:
	case CPU_IBM386SLC:
	case CPU_IBM486BL:
#ifdef USE_DYNAREC
		x86_setopcodes(ops_386, ops_ibm486_0f, dynarec_ops_386, dynarec_ops_ibm486_0f);
#else
		x86_setopcodes(ops_386, ops_ibm486_0f);
#endif
		cpu_features = CPU_FEATURE_MSR;
		/* FALLTHROUGH */
	case CPU_386SX:
	case CPU_386DX:
		if (fpu_type == FPU_287) {	/* In case we get Deskpro 386 emulation */
#ifdef USE_DYNAREC
			x86_dynarec_opcodes_d9_a16 = dynarec_ops_fpu_287_d9_a16;
			x86_dynarec_opcodes_d9_a32 = dynarec_ops_fpu_287_d9_a32;
			x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_287_da_a16;
			x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_287_da_a32;
			x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_287_db_a16;
			x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_287_db_a32;
			x86_dynarec_opcodes_dc_a16 = dynarec_ops_fpu_287_dc_a16;
			x86_dynarec_opcodes_dc_a32 = dynarec_ops_fpu_287_dc_a32;
			x86_dynarec_opcodes_dd_a16 = dynarec_ops_fpu_287_dd_a16;
			x86_dynarec_opcodes_dd_a32 = dynarec_ops_fpu_287_dd_a32;
			x86_dynarec_opcodes_de_a16 = dynarec_ops_fpu_287_de_a16;
			x86_dynarec_opcodes_de_a32 = dynarec_ops_fpu_287_de_a32;
			x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_287_df_a16;
			x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_287_df_a32;
#endif
			x86_opcodes_d9_a16 = ops_fpu_287_d9_a16;
			x86_opcodes_d9_a32 = ops_fpu_287_d9_a32;
			x86_opcodes_da_a16 = ops_fpu_287_da_a16;
			x86_opcodes_da_a32 = ops_fpu_287_da_a32;
			x86_opcodes_db_a16 = ops_fpu_287_db_a16;
			x86_opcodes_db_a32 = ops_fpu_287_db_a32;
			x86_opcodes_dc_a16 = ops_fpu_287_dc_a16;
			x86_opcodes_dc_a32 = ops_fpu_287_dc_a32;
			x86_opcodes_dd_a16 = ops_fpu_287_dd_a16;
			x86_opcodes_dd_a32 = ops_fpu_287_dd_a32;
			x86_opcodes_de_a16 = ops_fpu_287_de_a16;
			x86_opcodes_de_a32 = ops_fpu_287_de_a32;
			x86_opcodes_df_a16 = ops_fpu_287_df_a16;
			x86_opcodes_df_a32 = ops_fpu_287_df_a32;
		}

		timing_rr			=   2;	/* register dest - register src */
		timing_rm			=   6;	/* register dest - memory src */
		timing_mr			=   7;	/* memory dest   - register src */
		timing_mm			=   6;	/* memory dest   - memory src */
		if (cpu_s->cpu_type >= CPU_386DX) {
			timing_rml			=   6;	/* register dest - memory src long */
			timing_mrl			=   7;	/* memory dest   - register src long */
			timing_mml			=   6;	/* memory dest   - memory src */
		} else {
			timing_rml			=   8;	/* register dest - memory src long */
			timing_mrl			=  11;	/* memory dest   - register src long */
			timing_mml			=  10;	/* memory dest   - memory src */
		}
		timing_bt			=   4;	/* branch taken */
		timing_bnt			=   3;	/* branch not taken */

		timing_int			=   0;
		timing_int_rm			=  37;
		timing_int_v86			=  59;
		timing_int_pm			=  99;
		timing_int_pm_outer		= 119;
		timing_iret_rm			=  22;
		timing_iret_v86			=  60;
		timing_iret_pm			=  38;
		timing_iret_pm_outer		=  82;
		timing_call_rm			=  17;
		timing_call_pm			=  34;
		timing_call_pm_gate		=  52;
		timing_call_pm_gate_inner	=  86;
		timing_retf_rm			=  18;
		timing_retf_pm			=  32;
		timing_retf_pm_outer		=  68;
		timing_jmp_rm			=  12;
		timing_jmp_pm			=  27;
		timing_jmp_pm_gate		=  45;
		break;

	case CPU_486SLC:
#ifdef USE_DYNAREC
		x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f);
#else
		x86_setopcodes(ops_386, ops_486_0f);
#endif

		timing_rr			=   1;	/* register dest - register src */
		timing_rm			=   3;	/* register dest - memory src */
		timing_mr			=   5;	/* memory dest   - register src */
		timing_mm			=   3;
		timing_rml			=   5;	/* register dest - memory src long */
		timing_mrl			=   7;	/* memory dest   - register src long */
		timing_mml			=   7;
		timing_bt			=   5;	/* branch taken */
		timing_bnt			=   1;	/* branch not taken */

		timing_int			=   4;	/* unknown */
		timing_int_rm			=  14;
		timing_int_v86			=  82;
		timing_int_pm			=  49;
		timing_int_pm_outer		=  77;
		timing_iret_rm			=  14;
		timing_iret_v86			=  66;
		timing_iret_pm			=  31;
		timing_iret_pm_outer		=  66;
		timing_call_rm			=  12;
		timing_call_pm			=  30;
		timing_call_pm_gate		=  41;
		timing_call_pm_gate_inner	=  83;
		timing_retf_rm			=  13;
		timing_retf_pm			=  26;
		timing_retf_pm_outer		=  61;
		timing_jmp_rm			=   9;
		timing_jmp_pm			=  26;
		timing_jmp_pm_gate		=  37;
		timing_misaligned		=   3;
		break;

	case CPU_486DLC:
#ifdef USE_DYNAREC
		x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f);
#else
		x86_setopcodes(ops_386, ops_486_0f);
#endif

		timing_rr			=   1;	/* register dest - register src */
		timing_rm			=   3;	/* register dest - memory src */
		timing_mr			=   3;	/* memory dest   - register src */
		timing_mm			=   3;
		timing_rml			=   3;	/* register dest - memory src long */
		timing_mrl			=   3;	/* memory dest   - register src long */
		timing_mml			=   3;
		timing_bt			=   5;	/* branch taken */
		timing_bnt			=   1;	/* branch not taken */

		timing_int			=   4;	/* unknown */
		timing_int_rm			=  14;
		timing_int_v86			=  82;
		timing_int_pm			=  49;
		timing_int_pm_outer		=  77;
		timing_iret_rm			=  14;
		timing_iret_v86			=  66;
		timing_iret_pm			=  31;
		timing_iret_pm_outer		=  66;
		timing_call_rm			=  12;
		timing_call_pm			=  30;
		timing_call_pm_gate		=  41;
		timing_call_pm_gate_inner	=  83;
		timing_retf_rm			=  13;
		timing_retf_pm			=  26;
		timing_retf_pm_outer		=  61;
		timing_jmp_rm			=   9;
		timing_jmp_pm			=  26;
		timing_jmp_pm_gate		=  37;

		timing_misaligned		=   3;
		break;

	case CPU_i486SX_SLENH:
	case CPU_i486DX_SLENH:
		cpu_features = CPU_FEATURE_CR4 | CPU_FEATURE_VME;
		cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_VME;
		/* FALLTHROUGH */
	case CPU_RAPIDCAD:
	case CPU_i486SX:
	case CPU_i486DX:
	case CPU_Am486SX:
	case CPU_Am486DX:
	case CPU_Am486DXL:
	case CPU_ENH_Am486DX:
		/*AMD timing identical to Intel*/
#ifdef USE_DYNAREC
		x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f);
#else
		x86_setopcodes(ops_386, ops_486_0f);
#endif

		timing_rr			=   1;	/* register dest - register src */
		timing_rm			=   2;	/* register dest - memory src */
		timing_mr			=   3;	/* memory dest   - register src */
		timing_mm			=   3;
		timing_rml			=   2;	/* register dest - memory src long */
		timing_mrl			=   3;	/* memory dest   - register src long */
		timing_mml			=   3;
		timing_bt			=   2;	/* branch taken */
		timing_bnt			=   1;	/* branch not taken */

		timing_int			=   4;
		timing_int_rm			=  26;
		timing_int_v86			=  82;
		timing_int_pm			=  44;
		timing_int_pm_outer		=  71;
		timing_iret_rm			=  15;
		timing_iret_v86			=  36;	/* unknown */
		timing_iret_pm			=  20;
		timing_iret_pm_outer		=  36;
		timing_call_rm			=  18;
		timing_call_pm			=  20;
		timing_call_pm_gate		=  35;
		timing_call_pm_gate_inner	=  69;
		timing_retf_rm			=  13;
		timing_retf_pm			=  17;
		timing_retf_pm_outer		=  35;
		timing_jmp_rm			=  17;
		timing_jmp_pm			=  19;
		timing_jmp_pm_gate		=  32;

		timing_misaligned		=   3;
		break;

	case CPU_Cx486S:
	case CPU_Cx486DX:
	case CPU_STPC:
#ifdef USE_DYNAREC
		if (cpu_s->cpu_type == CPU_STPC)
			x86_setopcodes(ops_386, ops_stpc_0f, dynarec_ops_386, dynarec_ops_stpc_0f);
		else
			x86_setopcodes(ops_386, ops_c486_0f, dynarec_ops_386, dynarec_ops_c486_0f);
#else
		if (cpu_s->cpu_type == CPU_STPC)
			x86_setopcodes(ops_386, ops_stpc_0f);
		else
			x86_setopcodes(ops_386, ops_c486_0f);
#endif

                timing_rr			=   1;	/* register dest - register src */
                timing_rm			=   3;	/* register dest - memory src */
                timing_mr			=   3;	/* memory dest   - register src */
                timing_mm			=   3;
                timing_rml			=   3;	/* register dest - memory src long */
                timing_mrl			=   3;	/* memory dest   - register src long */
                timing_mml			=   3;
                timing_bt			=   3;	/* branch taken */
		timing_bnt			=   1;	/* branch not taken */

		timing_int			=   4;
		timing_int_rm			=  14;
		timing_int_v86			=  82;
		timing_int_pm			=  49;
		timing_int_pm_outer		=  77;
		timing_iret_rm			=  14;
		timing_iret_v86			=  66;	/* unknown */
		timing_iret_pm			=  31;
		timing_iret_pm_outer		=  66;
		timing_call_rm			=  12;
		timing_call_pm			=  30;
		timing_call_pm_gate		=  41;
		timing_call_pm_gate_inner	=  83;
		timing_retf_rm			=  13;
		timing_retf_pm			=  26;
		timing_retf_pm_outer		=  61;
		timing_jmp_rm			=   9;
		timing_jmp_pm			=  26;
		timing_jmp_pm_gate		=  37;

		timing_misaligned		=   3;

		if (cpu_s->cpu_type == CPU_STPC)
			cpu_features = CPU_FEATURE_RDTSC;
		break;

	case CPU_Cx5x86:
#ifdef USE_DYNAREC
		x86_setopcodes(ops_386, ops_c486_0f, dynarec_ops_386, dynarec_ops_c486_0f);
#else
		x86_setopcodes(ops_386, ops_c486_0f);
#endif

		timing_rr			=   1;	/* register dest - register src */
		timing_rm			=   1;	/* register dest - memory src */
		timing_mr			=   2;	/* memory dest   - register src */
		timing_mm			=   2;
		timing_rml			=   1;	/* register dest - memory src long */
		timing_mrl			=   2;	/* memory dest   - register src long */
		timing_mml			=   2;
		timing_bt			=   4;	/* branch taken */
		timing_bnt			=   1;	/* branch not taken */

		timing_int			=   0;
		timing_int_rm			=   9;
		timing_int_v86			=  82;	/* unknown */
		timing_int_pm			=  21;
		timing_int_pm_outer		=  32;
		timing_iret_rm			=   7;
		timing_iret_v86			=  26;	/* unknown */
		timing_iret_pm			=  10;
		timing_iret_pm_outer		=  26;
		timing_call_rm			=   4;
		timing_call_pm			=  15;
		timing_call_pm_gate		=  26;
		timing_call_pm_gate_inner	=  35;
		timing_retf_rm			=   4;
		timing_retf_pm			=   7;
		timing_retf_pm_outer		=  23;
		timing_jmp_rm			=   5;
		timing_jmp_pm			=   7;
		timing_jmp_pm_gate		=  17;

		timing_misaligned		=   2;

		cpu_cyrix_alignment = 1;
		break;

	case CPU_WINCHIP:
	case CPU_WINCHIP2:
#ifdef USE_DYNAREC
		if (cpu_s->cpu_type == CPU_WINCHIP2)
			x86_setopcodes(ops_386, ops_winchip2_0f, dynarec_ops_386, dynarec_ops_winchip2_0f);
		else
			x86_setopcodes(ops_386, ops_winchip_0f, dynarec_ops_386, dynarec_ops_winchip_0f);
#else
		if (cpu_s->cpu_type == CPU_WINCHIP2)
			x86_setopcodes(ops_386, ops_winchip2_0f);
		else
			x86_setopcodes(ops_386, ops_winchip_0f);
#endif

                timing_rr			=   1;	/* register dest - register src */
                timing_rm			=   2;	/* register dest - memory src */
                timing_mr			=   2;	/* memory dest   - register src */
                timing_mm			=   3;
		timing_rml			=   2;	/* register dest - memory src long */
		timing_mrl			=   2;	/* memory dest   - register src long */
		timing_mml			=   3;
		timing_bt			=   2;	/* branch taken */
		timing_bnt			=   1;	/* branch not taken */

                /*unknown*/
                timing_int_rm			=  26;
                timing_int_v86			=  82;
                timing_int_pm			=  44;
		timing_int_pm_outer		=  71;
		timing_iret_rm			=   7;
		timing_iret_v86			=  26;
		timing_iret_pm			=  10;
		timing_iret_pm_outer		=  26;
		timing_call_rm			=   4;
		timing_call_pm			=  15;
		timing_call_pm_gate		=  26;
		timing_call_pm_gate_inner	=  35;
		timing_retf_rm			=   4;
		timing_retf_pm			=   7;
		timing_retf_pm_outer		=  23;
		timing_jmp_rm			=   5;
		timing_jmp_pm			=   7;
		timing_jmp_pm_gate		=  17;

		timing_misaligned		=   2;

		cpu_cyrix_alignment = 1;

		cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MMX | CPU_FEATURE_MSR | CPU_FEATURE_CR4;
		if (cpu_s->cpu_type == CPU_WINCHIP2)
			cpu_features |= CPU_FEATURE_3DNOW;
		msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) |  (1 << 16) | (1 << 19) | (1 << 21);
		if (cpu_s->cpu_type == CPU_WINCHIP2)
			msr.fcr |= (1 << 18) | (1 << 20);
		cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE;

#ifdef USE_DYNAREC
		if (cpu_s->cpu_type == CPU_WINCHIP2)
			codegen_timing_set(&codegen_timing_winchip2);
		else
			codegen_timing_set(&codegen_timing_winchip);
#endif
		break;

	case CPU_P24T:
	case CPU_PENTIUM:
	case CPU_PENTIUMMMX:
#ifdef USE_DYNAREC
		if (cpu_s->cpu_type == CPU_PENTIUMMMX)
			x86_setopcodes(ops_386, ops_pentiummmx_0f, dynarec_ops_386, dynarec_ops_pentiummmx_0f);
		else
			x86_setopcodes(ops_386, ops_pentium_0f, dynarec_ops_386, dynarec_ops_pentium_0f);
#else
		if (cpu_s->cpu_type == CPU_PENTIUMMMX)
			x86_setopcodes(ops_386, ops_pentiummmx_0f);
		else
			x86_setopcodes(ops_386, ops_pentium_0f);
#endif

		timing_rr			=   1;	/* register dest - register src */
		timing_rm			=   2;	/* register dest - memory src */
		timing_mr			=   3;	/* memory dest   - register src */
		timing_mm			=   3;
		timing_rml			=   2;	/* register dest - memory src long */
		timing_mrl			=   3;	/* memory dest   - register src long */
		timing_mml			=   3;
		timing_bt			=   0;	/* branch taken */
		if (cpu_s->cpu_type == CPU_PENTIUMMMX)
			timing_bnt			=   1;	/* branch not taken */
		else
			timing_bnt			=   2;	/* branch not taken */

		timing_int			=   6;
		timing_int_rm			=  11;
		timing_int_v86			=  54;
		timing_int_pm			=  25;
		timing_int_pm_outer		=  42;
		timing_iret_rm			=   7;
		timing_iret_v86			=  27;	/* unknown */
		timing_iret_pm			=  10;
		timing_iret_pm_outer		=  27;
		timing_call_rm			=   4;
		timing_call_pm			=   4;
		timing_call_pm_gate		=  22;
		timing_call_pm_gate_inner	=  44;
		timing_retf_rm			=   4;
		timing_retf_pm			=   4;
		timing_retf_pm_outer		=  23;
		timing_jmp_rm			=   3;
		timing_jmp_pm			=   3;
		timing_jmp_pm_gate		=  18;

		timing_misaligned		=   3;

		cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME;
		if (cpu_s->cpu_type == CPU_PENTIUMMMX)
			cpu_features |= CPU_FEATURE_MMX;
		msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) |  (1 << 16) | (1 << 19) | (1 << 21);
		cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PCE;
#ifdef USE_DYNAREC
		codegen_timing_set(&codegen_timing_pentium);
#endif
		break;

#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86)
	case CPU_Cx6x86:
	case CPU_Cx6x86L:
	case CPU_CxGX1:
  	case CPU_Cx6x86MX:
		if (cpu_s->cpu_type == CPU_Cx6x86MX) {
#ifdef USE_DYNAREC
			x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_686_da_a16;
			x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_686_da_a32;
			x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_686_db_a16;
			x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_686_db_a32;
			x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_686_df_a16;
			x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_686_df_a32;
#endif
			x86_opcodes_da_a16 = ops_fpu_686_da_a16;
			x86_opcodes_da_a32 = ops_fpu_686_da_a32;
			x86_opcodes_db_a16 = ops_fpu_686_db_a16;
			x86_opcodes_db_a32 = ops_fpu_686_db_a32;
			x86_opcodes_df_a16 = ops_fpu_686_df_a16;
			x86_opcodes_df_a32 = ops_fpu_686_df_a32;
		}

#ifdef USE_DYNAREC
		if (cpu_s->cpu_type == CPU_Cx6x86MX)
			x86_setopcodes(ops_386, ops_c6x86mx_0f, dynarec_ops_386, dynarec_ops_c6x86mx_0f);
		else if (cpu_s->cpu_type == CPU_Cx6x86L)
			x86_setopcodes(ops_386, ops_pentium_0f, dynarec_ops_386, dynarec_ops_pentium_0f);
		else
			x86_setopcodes(ops_386, ops_c6x86mx_0f, dynarec_ops_386, dynarec_ops_c6x86mx_0f);
			// x86_setopcodes(ops_386, ops_c6x86_0f, dynarec_ops_386, dynarec_ops_c6x86_0f);
#else
		if (cpu_s->cpu_type == CPU_Cx6x86MX)
			x86_setopcodes(ops_386, ops_c6x86mx_0f);
		else if (cpu_s->cpu_type == CPU_Cx6x86L)
			x86_setopcodes(ops_386, ops_pentium_0f);
		else
			x86_setopcodes(ops_386, ops_c6x86_0f);
#endif

                timing_rr			=   1;	/* register dest - register src */
                timing_rm			=   1;	/* register dest - memory src */
                timing_mr			=   2;	/* memory dest   - register src */
                timing_mm			=   2;
                timing_rml			=   1;	/* register dest - memory src long */
                timing_mrl			=   2;	/* memory dest   - register src long */
                timing_mml			=   2;
		if (cpu_s->cpu_type == CPU_CxGX1) {
			timing_bt			=   4;	/* branch taken */
			timing_bnt			=   1;	/* branch not taken */
		} else {
	                timing_bt			=   0;	/* branch taken */
        	        timing_bnt			=   2;	/* branch not taken */
		}

		/* Make the CxGX1 share the timings with most other Cyrix C6x86's due to the real
		   ones still being unknown. */
		timing_int_rm			=   9;
		timing_int_v86			=  46;
		timing_int_pm			=  21;
		timing_int_pm_outer		=  32;
		timing_iret_rm			=   7;
		timing_iret_v86			=  26;
		timing_iret_pm			=  10;
		timing_iret_pm_outer		=  26;
		timing_call_rm			=   3;
		timing_call_pm			=   4;
		timing_call_pm_gate		=  15;
		timing_call_pm_gate_inner	=  26;
		timing_retf_rm			=   4;
		timing_retf_pm			=   4;
		timing_retf_pm_outer		=  23;
		timing_jmp_rm			=   1;
		timing_jmp_pm			=   4;
		timing_jmp_pm_gate		=  14;

		timing_misaligned		=   2;

		cpu_cyrix_alignment = 1;

		cpu_features = CPU_FEATURE_RDTSC;
		if (cpu_s->cpu_type >= CPU_CxGX1)
			cpu_features |= CPU_FEATURE_MSR | CPU_FEATURE_CR4;
		if (cpu_s->cpu_type == CPU_Cx6x86MX)
			cpu_features |= CPU_FEATURE_MMX;
		msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) |  (1 << 16) | (1 << 19) | (1 << 21);
		if (cpu_s->cpu_type >= CPU_CxGX1)
			cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_PCE;

#ifdef USE_DYNAREC
		codegen_timing_set(&codegen_timing_686);
#endif

		if ((cpu_s->cpu_type == CPU_Cx6x86L) || (cpu_s->cpu_type == CPU_Cx6x86MX))
			ccr4 = 0x80;
		else if (CPU_Cx6x86)
			CPUID = 0;	/* Disabled on powerup by default */
		break;
#endif

#if defined(DEV_BRANCH) && defined(USE_AMD_K5)
	case CPU_K5:
	case CPU_5K86:
#endif
	case CPU_K6:
	case CPU_K6_2:
	case CPU_K6_2C:
	case CPU_K6_3:
	case CPU_K6_2P:
	case CPU_K6_3P:
#ifdef USE_DYNAREC
		if (cpu_s->cpu_type >= CPU_K6_2)
			x86_setopcodes(ops_386, ops_k62_0f, dynarec_ops_386, dynarec_ops_k62_0f);
#if defined(DEV_BRANCH) && defined(USE_AMD_K5)
		else if (cpu_s->cpu_type == CPU_K6)
			x86_setopcodes(ops_386, ops_k6_0f, dynarec_ops_386, dynarec_ops_k6_0f);
		else
			x86_setopcodes(ops_386, ops_pentiummmx_0f, dynarec_ops_386, dynarec_ops_pentiummmx_0f);
#else
		else
			x86_setopcodes(ops_386, ops_k6_0f, dynarec_ops_386, dynarec_ops_k6_0f);
#endif
#else
		if (cpu_s->cpu_type >= CPU_K6_2)
			x86_setopcodes(ops_386, ops_k62_0f);
#if defined(DEV_BRANCH) && defined(USE_AMD_K5)
		else if (cpu_s->cpu_type = CPU_K6)
			x86_setopcodes(ops_386, ops_k6_0f);
		else
			x86_setopcodes(ops_386, ops_pentiummmx_0f);
#else
		else
			x86_setopcodes(ops_386, ops_k6_0f);
#endif
#endif

                timing_rr			=   1;	/* register dest - register src */
                timing_rm			=   2;	/* register dest - memory src */
                timing_mr			=   3;	/* memory dest   - register src */
                timing_mm			=   3;
                timing_rml			=   2;	/* register dest - memory src long */
                timing_mrl			=   3;	/* memory dest   - register src long */
                timing_mml			=   3;
                timing_bt			=   0;	/* branch taken */
		timing_bnt			=   1;	/* branch not taken */

                timing_int			=   6;
                timing_int_rm			=  11;
                timing_int_v86			=  54;
                timing_int_pm			=  25;
                timing_int_pm_outer		=  42;
                timing_iret_rm			=   7;
                timing_iret_v86			=  27;	/* unknown */
                timing_iret_pm			=  10;
                timing_iret_pm_outer		=  27;
                timing_call_rm			=   4;
                timing_call_pm			=   4;
                timing_call_pm_gate		=  22;
                timing_call_pm_gate_inner	=  44;
                timing_retf_rm			=   4;
                timing_retf_pm			=   4;
                timing_retf_pm_outer		=  23;
                timing_jmp_rm			=   3;
                timing_jmp_pm			=   3;
                timing_jmp_pm_gate		=  18;

                timing_misaligned		=   3;

		cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME | CPU_FEATURE_MMX;
		if (cpu_s->cpu_type >= CPU_K6_2)
			cpu_features |= CPU_FEATURE_3DNOW;
		msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) |  (1 << 16) | (1 << 19) | (1 << 21);
#if defined(DEV_BRANCH) && defined(USE_AMD_K5)
		cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE;
		if (cpu_s->cpu_type >= CPU_K6) {
			cpu_CR4_mask |= (CR4_VME | CR4_PVI | CR4_PSE);
			if (cpu_s->cpu_type <= CPU_K6)
				cpu_CR4_mask |= CR4_PCE;
		}
#else
		cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE;
		if (cpu_s->cpu_type == CPU_K6)
			cpu_CR4_mask |= CR4_PCE;
#endif

#ifdef USE_DYNAREC
		codegen_timing_set(&codegen_timing_k6);
#endif
		break;

	case CPU_PENTIUMPRO:
	case CPU_PENTIUM2:
	case CPU_PENTIUM2D:
#ifdef USE_DYNAREC
		/* TODO: Perhaps merge the three opcode tables with some instructions UD#'ing depending on
			 CPU type. */
		if (cpu_s->cpu_type == CPU_PENTIUM2D)
                	x86_setopcodes(ops_386, ops_pentium2d_0f, dynarec_ops_386, dynarec_ops_pentium2d_0f);
		else if (cpu_s->cpu_type == CPU_PENTIUM2)
                	x86_setopcodes(ops_386, ops_pentium2_0f, dynarec_ops_386, dynarec_ops_pentium2_0f);
		else
                	x86_setopcodes(ops_386, ops_pentiumpro_0f, dynarec_ops_386, dynarec_ops_pentiumpro_0f);
                x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_686_da_a16;
                x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_686_da_a32;
                x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_686_db_a16;
                x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_686_db_a32;
                x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_686_df_a16;
                x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_686_df_a32;
#else
		if (cpu_s->cpu_type == CPU_PENTIUM2D)
			x86_setopcodes(ops_386, ops_pentium2d_0f);
		else
			x86_setopcodes(ops_386, ops_pentium2_0f);
#endif
		x86_opcodes_da_a16 = ops_fpu_686_da_a16;
		x86_opcodes_da_a32 = ops_fpu_686_da_a32;
		x86_opcodes_db_a16 = ops_fpu_686_db_a16;
		x86_opcodes_db_a32 = ops_fpu_686_db_a32;
		x86_opcodes_df_a16 = ops_fpu_686_df_a16;
		x86_opcodes_df_a32 = ops_fpu_686_df_a32;

		timing_rr			=   1;	/* register dest - register src */
		timing_rm			=   2;	/* register dest - memory src */
		timing_mr			=   3;	/* memory dest   - register src */
		timing_mm			=   3;
		timing_rml			=   2;	/* register dest - memory src long */
		timing_mrl			=   3;	/* memory dest   - register src long */
		timing_mml			=   3;
		timing_bt			=   0;	/* branch taken */
		timing_bnt			=   1;	/* branch not taken */

		timing_int			=   6;
		timing_int_rm       		=  11;
		timing_int_v86      		=  54;
		timing_int_pm       		=  25;
		timing_int_pm_outer		=  42;
		timing_iret_rm			=   7;
		timing_iret_v86			=  27;	/* unknown */
		timing_iret_pm			=  10;
		timing_iret_pm_outer		=  27;
		timing_call_rm			=   4;
		timing_call_pm			=   4;
		timing_call_pm_gate		=  22;
		timing_call_pm_gate_inner	=  44;
		timing_retf_rm       		=   4;
		timing_retf_pm       		=   4;
		timing_retf_pm_outer		=  23;
		timing_jmp_rm			=   3;
		timing_jmp_pm			=   3;
		timing_jmp_pm_gate		=  18;

		timing_misaligned		=   3;

                cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME;
		if (cpu_s->cpu_type >= CPU_PENTIUM2)
			cpu_features |= CPU_FEATURE_MMX;
                msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) |  (1 << 16) | (1 << 19) | (1 << 21);
                cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PAE | CR4_PCE;
		if (cpu_s->cpu_type == CPU_PENTIUM2D)
	                cpu_CR4_mask |= CR4_OSFXSR;

#ifdef USE_DYNAREC
		codegen_timing_set(&codegen_timing_p6);
#endif
                break;

	case CPU_CYRIX3S:
#ifdef USE_DYNAREC
		x86_setopcodes(ops_386, ops_winchip2_0f, dynarec_ops_386, dynarec_ops_winchip2_0f);
#else
		x86_setopcodes(ops_386, ops_winchip2_0f);
#endif
		timing_rr			=   1;	/* register dest - register src */
		timing_rm			=   2;	/* register dest - memory src */
		timing_mr			=   2;	/* memory dest   - register src */
		timing_mm			=   3;
		timing_rml			=   2;	/* register dest - memory src long */
		timing_mrl			=   2;	/* memory dest   - register src long */
		timing_mml			=   3;
		timing_bt			=   2;	/* branch taken */
		timing_bnt			=   1;	/* branch not taken */

                timing_int_rm			=  26;	/* unknown */
                timing_int_v86			=  82;
                timing_int_pm			=  44;
                timing_int_pm_outer		=  71;
                timing_iret_rm			=   7;
                timing_iret_v86			=  26;
                timing_iret_pm			=  10;
                timing_iret_pm_outer		=  26;
                timing_call_rm			=   4;
                timing_call_pm			=  15;
                timing_call_pm_gate		=  26;
                timing_call_pm_gate_inner	=  35;
                timing_retf_rm			=   4;
                timing_retf_pm			=   7;
                timing_retf_pm_outer		=  23;
                timing_jmp_rm			=   5;
                timing_jmp_pm			=   7;
                timing_jmp_pm_gate		=  17;

                timing_misaligned		=   2;

		cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MMX | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_3DNOW;
		msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) |  (1 << 16) | (1 << 18) | (1 << 19) | (1 << 20) | (1 << 21);
		cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE;

		cpu_cyrix_alignment = 1;

#ifdef USE_DYNAREC
		codegen_timing_set(&codegen_timing_winchip);
#endif
		break;

	default:
		fatal("cpu_set : unknown CPU type %i\n", cpu_s->cpu_type);
    }

    switch (fpu_type) {
	case FPU_NONE:
		break;

	case FPU_8087:
		x87_timings = x87_timings_8087;
		break;

	case FPU_287:
		x87_timings = x87_timings_287;
		break;

	case FPU_287XL:
	case FPU_387:
		x87_timings = x87_timings_387;
		break;

	case FPU_487SX:
	default:
		x87_timings = x87_timings_486;
		x87_concurrency = x87_concurrency_486;
    }

    if (is386) {
#ifdef USE_DYNAREC
	if (cpu_use_dynarec)
		cpu_exec = exec386_dynarec;
	else
#endif
		cpu_exec = exec386;
    } else if (cpu_s->cpu_type >= CPU_286)
	cpu_exec = exec386;
    else
	cpu_exec = execx86;
    gdbstub_cpu_init();
}


void
cpu_close(void)
{
    cpu_inited = 0;
}


void
cpu_set_isa_speed(int speed)
{
    if (speed) {
	cpu_isa_speed = speed;
	pc_speed_changed();
    } else if (cpu_busspeed >= 8000000)
	cpu_isa_speed = 8000000;
    else
	cpu_isa_speed = cpu_busspeed;

    cpu_log("cpu_set_isa_speed(%d) = %d\n", speed, cpu_isa_speed);
}


void
cpu_set_pci_speed(int speed)
{
    if (speed)
	cpu_pci_speed = speed;
    else if (cpu_busspeed < 42500000)
	cpu_pci_speed = cpu_busspeed;
    else if (cpu_busspeed < 84000000)
	cpu_pci_speed = cpu_busspeed / 2;
    else if (cpu_busspeed < 120000000)
	cpu_pci_speed = cpu_busspeed / 3;
    else
	cpu_pci_speed = cpu_busspeed / 4;

    if (cpu_isa_pci_div)
	cpu_set_isa_pci_div(cpu_isa_pci_div);
    else if (speed)
	pc_speed_changed();

    pci_burst_time = cpu_s->rspeed / cpu_pci_speed;
    pci_nonburst_time = 4 * pci_burst_time;

    cpu_log("cpu_set_pci_speed(%d) = %d\n", speed, cpu_pci_speed);
}


void
cpu_set_isa_pci_div(int div)
{
    cpu_isa_pci_div = div;

    cpu_log("cpu_set_isa_pci_div(%d)\n", cpu_isa_pci_div);

    if (cpu_isa_pci_div)
	cpu_set_isa_speed(cpu_pci_speed / cpu_isa_pci_div);
    else
	cpu_set_isa_speed(0);
}


void
cpu_set_agp_speed(int speed)
{
    if (speed) {
	cpu_agp_speed = speed;
	pc_speed_changed();
    }
    else if (cpu_busspeed < 84000000)
	cpu_agp_speed = cpu_busspeed;
    else if (cpu_busspeed < 120000000)
	cpu_agp_speed = cpu_busspeed / 1.5;
    else
	cpu_agp_speed = cpu_busspeed / 2;

    agp_burst_time = cpu_s->rspeed / cpu_agp_speed;
    agp_nonburst_time = 4 * agp_burst_time;

    cpu_log("cpu_set_agp_speed(%d) = %d\n", speed, cpu_agp_speed);
}


char *
cpu_current_pc(char *bufp)
{
    static char buff[10];

    if (bufp == NULL)
	bufp = buff;

    sprintf(bufp, "%04X:%04X", CS, cpu_state.pc);

    return(bufp);
}


void
cpu_CPUID(void)
{
    switch (cpu_s->cpu_type) {
	case CPU_i486SX_SLENH:
		if (!EAX) {
			EAX = 0x00000001;
			EBX = 0x756e6547;
			EDX = 0x49656e69;
			ECX = 0x6c65746e;
		} else if (EAX == 1) {
			EAX = CPUID;
			EBX = ECX = 0;
			EDX = CPUID_VME;
		} else
			EAX = EBX = ECX = EDX = 0;
		break;

	case CPU_i486DX_SLENH:
		if (!EAX) {
			EAX = 0x00000001;
			EBX = 0x756e6547;
			EDX = 0x49656e69;
			ECX = 0x6c65746e;
		} else if (EAX == 1) {
			EAX = CPUID;
			EBX = ECX = 0;
			EDX = CPUID_FPU | CPUID_VME;
		} else
			EAX = EBX = ECX = EDX = 0;
		break;

	case CPU_ENH_Am486DX:
		if (!EAX) {
			EAX = 1;
			EBX = 0x68747541;
			ECX = 0x444D4163;
			EDX = 0x69746E65;
		} else if (EAX == 1) {
			EAX = CPUID;
			EBX = ECX = 0;
			EDX = CPUID_FPU;	/*FPU*/
		} else
			EAX = EBX = ECX = EDX = 0;
		break;

	case CPU_WINCHIP:
		if (!EAX) {
			EAX = 1;
			if (msr.fcr2 & (1 << 14)) {
				EBX = msr.fcr3 >> 32;
				ECX = msr.fcr3 & 0xffffffff;
				EDX = msr.fcr2 >> 32;
			} else {
				EBX = 0x746e6543;	/* CentaurHauls */
				ECX = 0x736c7561;
				EDX = 0x48727561;
			}
		} else if (EAX == 1) {
			EAX = 0x540;
			EBX = ECX = 0;
			EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR;
			if (cpu_has_feature(CPU_FEATURE_CX8))
				EDX |= CPUID_CMPXCHG8B;
			if (msr.fcr & (1 << 9))
				EDX |= CPUID_MMX;
		} else
			EAX = EBX = ECX = EDX = 0;
		break;

	case CPU_WINCHIP2:
		switch (EAX) {
			case 0:
				EAX = 1;
				if (msr.fcr2 & (1 << 14)) {
					EBX = msr.fcr3 >> 32;
					ECX = msr.fcr3 & 0xffffffff;
					EDX = msr.fcr2 >> 32;
				} else {
					EBX = 0x746e6543;	/* CentaurHauls */
					ECX = 0x736c7561;
					EDX = 0x48727561;
				}
				break;
			case 1:
				EAX = CPUID;
				EBX = ECX = 0;
				EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR;
				if (cpu_has_feature(CPU_FEATURE_CX8))
					EDX |= CPUID_CMPXCHG8B;
				if (msr.fcr & (1 << 9))
					EDX |= CPUID_MMX;
				break;
			case 0x80000000:
				EAX = 0x80000005;
				break;
			case 0x80000001:
				EAX = CPUID;
				EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR;
				if (cpu_has_feature(CPU_FEATURE_CX8))
					EDX |= CPUID_CMPXCHG8B;
				if (msr.fcr & (1 << 9))
					EDX |= CPUID_MMX;
				if (cpu_has_feature(CPU_FEATURE_3DNOW))
					EDX |= CPUID_3DNOW;
				break;

			case 0x80000002:	/* Processor name string */
				EAX = 0x20544449;	/* IDT WinChip 2-3D */
				EBX = 0x436e6957;
				ECX = 0x20706968;
				EDX = 0x44332d32;
				break;

			case 0x80000005: /*Cache information*/
				EBX = 0x08800880; /*TLBs*/
				ECX = 0x20040120; /*L1 data cache*/
				EDX = 0x20020120; /*L1 instruction cache*/
				break;

			default:
				EAX = EBX = ECX = EDX = 0;
				break;
		}
		break;

	case CPU_P24T:
	case CPU_PENTIUM:
		if (!EAX) {
			EAX = 0x00000001;
			EBX = 0x756e6547;
			EDX = 0x49656e69;
			ECX = 0x6c65746e;
		} else if (EAX == 1) {
			EAX = CPUID;
			EBX = ECX = 0;
			EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B;
		} else
			EAX = EBX = ECX = EDX = 0;
		break;

#if defined(DEV_BRANCH) && defined(USE_AMD_K5)
	case CPU_K5:
		if (!EAX) {
			EAX = 0x00000001;
			EBX = 0x68747541;
			EDX = 0x69746E65;
			ECX = 0x444D4163;
		} else if (EAX == 1) {
			EAX = CPUID;
			EBX = ECX = 0;
			EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B;
		} else
			EAX = EBX = ECX = EDX = 0;
		break;

	case CPU_5K86:
		if (!EAX) {
			EAX = 0x00000001;
			EBX = 0x68747541;
			EDX = 0x69746E65;
			ECX = 0x444D4163;
		} else if (EAX == 1) {
			EAX = CPUID;
			EBX = ECX = 0;
			EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B;
		} else if (EAX == 0x80000000) {
			EAX = 0x80000005;
			EBX = ECX = EDX = 0;
		} else if (EAX == 0x80000001) {
			EAX = CPUID;
			EBX = ECX = 0;
			EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B;
		} else if (EAX == 0x80000002) {
			EAX = 0x2D444D41;
			EBX = 0x7428354B;
			ECX = 0x5020296D;
			EDX = 0x65636F72;
		} else if (EAX == 0x80000003) {
			EAX = 0x726F7373;
			EBX = ECX = EDX = 0;
		} else if (EAX == 0x80000004)
			EAX = EBX = ECX = EDX = 0;
		else if (EAX == 0x80000005) {
			EAX = 0;
			EBX = 0x04800000;
			ECX = 0x08040120;
			EDX = 0x10040120;
		} else
			EAX = EBX = ECX = EDX = 0;
		break;
#endif

	case CPU_K6:
		if (!EAX) {
			EAX = 0x00000001;
			EBX = 0x68747541;
			EDX = 0x69746E65;
			ECX = 0x444D4163;
		} else if (EAX == 1) {
			EAX = CPUID;
			EBX = ECX = 0;
			EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_MMX;
		} else if (EAX == 0x80000000) {
			EAX = 0x80000005;
			EBX = ECX = EDX = 0;
		} else if (EAX == 0x80000001) {
			EAX = CPUID + 0x100;
			EBX = ECX = 0;
			EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_AMDSEP | CPUID_MMX;
		} else if (EAX == 0x80000002) {
			EAX = 0x2D444D41;
			EBX = 0x6D74364B;
			ECX = 0x202F7720;
			EDX = 0x746C756D;
		} else if (EAX == 0x80000003) {
			EAX = 0x64656D69;
			EBX = 0x65206169;
			ECX = 0x6E657478;
			EDX = 0x6E6F6973;
		} else if (EAX == 0x80000004) {
			EAX = 0x73;
			EBX = ECX = EDX = 0;
		} else if (EAX == 0x80000005) {
			EAX = 0;
			EBX = 0x02800140;
			ECX = 0x20020220;
			EDX = 0x20020220;
		} else if (EAX == 0x8FFFFFFF) {
			EAX = 0x4778654E;
			EBX = 0x72656E65;
			ECX = 0x6F697461;
			EDX = 0x444D416E;
		} else
			EAX = EBX = ECX = EDX = 0;
		break;

	case CPU_K6_2:
	case CPU_K6_2C:
		switch (EAX) {
			case 0:
				EAX = 1;
				EBX = 0x68747541;	/* AuthenticAMD */
				ECX = 0x444d4163;
				EDX = 0x69746e65;
				break;
			case 1:
				EAX = CPUID;
				EBX = ECX = 0;
				EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_MMX;
				break;
			case 0x80000000:
				EAX = 0x80000005;
				break;
			case 0x80000001:
				EAX = CPUID + 0x100;
				EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_AMDSEP | CPUID_MMX | CPUID_3DNOW;
				break;
			case 0x80000002:	/* Processor name string */
				EAX = 0x2d444d41;	/* AMD-K6(tm) 3D pr */
				EBX = 0x7428364b;
				ECX = 0x3320296d;
				EDX = 0x72702044;
				break;
			case 0x80000003:	/* Processor name string */
				EAX = 0x7365636f;	/* ocessor */
				EBX = 0x00726f73;
				ECX = 0x00000000;
				EDX = 0x00000000;
				break;
			case 0x80000005:	/*Cache information*/
				EBX = 0x02800140;	/*TLBs*/
				ECX = 0x20020220;	/*L1 data cache*/
				EDX = 0x20020220;	/*L1 instruction cache*/
				break;
			default:
				EAX = EBX = ECX = EDX = 0;
				break;
		}
		break;

	case CPU_K6_3:
		switch (EAX) {
			case 0:
				EAX = 1;
				EBX = 0x68747541;	/* AuthenticAMD */
				ECX = 0x444d4163;
				EDX = 0x69746e65;
				break;
			case 1:
				EAX = CPUID;
				EBX = ECX = 0;
				EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_MMX;
				break;
			case 0x80000000:
				EAX = 0x80000006;
				break;
			case 0x80000001:
				EAX = CPUID + 0x100;
				EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_AMDSEP | CPUID_MMX | CPUID_3DNOW;
				break;
			case 0x80000002:	/* Processor name string */
				EAX = 0x2d444d41;	/* AMD-K6(tm) 3D+ P */
				EBX = 0x7428364b;
				ECX = 0x3320296d;
				EDX = 0x50202b44;
				break;
			case 0x80000003:	/* Processor name string */
				EAX = 0x65636f72;	/* rocessor */
				EBX = 0x726f7373;
				ECX = 0x00000000;
				EDX = 0x00000000;
				break;
			case 0x80000005:	/* Cache information */
				EBX = 0x02800140;	/* TLBs */
				ECX = 0x20020220; /*L1 data cache*/
				EDX = 0x20020220; /*L1 instruction cache*/
				break;
			case 0x80000006:	/* L2 Cache information */
				ECX = 0x01004220;
				break;
			default:
				EAX = EBX = ECX = EDX = 0;
				break;
		}
		break;

	case CPU_K6_2P:
	case CPU_K6_3P:
		switch (EAX) {
			case 0:
				EAX = 1;
				EBX = 0x68747541;	/* AuthenticAMD */
				ECX = 0x444d4163;
				EDX = 0x69746e65;
				break;
			case 1:
				EAX = CPUID;
				EBX = ECX = 0;
				EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_MMX;
				break;
			case 0x80000000:
				EAX = 0x80000007;
				break;
			case 0x80000001:
				EAX = CPUID + 0x100;
				EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_AMDSEP | CPUID_MMX | CPUID_3DNOW;
				break;
			case 0x80000002:	/* Processor name string */
				EAX = 0x2d444d41;	/* AMD-K6(tm)-III P */
				EBX = 0x7428364b;
				ECX = 0x492d296d;
				EDX = 0x50204949;
				break;
			case 0x80000003:	/* Processor name string */
				EAX = 0x65636f72;	/* rocessor */
				EBX = 0x726f7373;
				ECX = 0x00000000;
				EDX = 0x00000000;
				break;
			case 0x80000005:	/* Cache information */
				EBX = 0x02800140;	/* TLBs */
				ECX = 0x20020220;	/* L1 data cache */
				EDX = 0x20020220;	/* L1 instruction cache */
				break;
			case 0x80000006:	/* L2 Cache information */
				if (cpu_s->cpu_type == CPU_K6_3P)
					ECX = 0x01004220;
				else
					ECX = 0x00804220;
				break;
			case 0x80000007:	/* PowerNow information */
				EDX = 7;
				break;
			default:
				EAX = EBX = ECX = EDX = 0;
				break;
		}
		break;

	case CPU_PENTIUMMMX:
		if (!EAX) {
			EAX = 0x00000001;
			EBX = 0x756e6547;
			EDX = 0x49656e69;
			ECX = 0x6c65746e;
		} else if (EAX == 1) {
			EAX = CPUID;
			EBX = ECX = 0;
			EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_MMX;
		} else
			EAX = EBX = ECX = EDX = 0;
		break;

#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86)
	case CPU_Cx6x86:
		if (!EAX) {
			EAX = 0x00000001;
			EBX = 0x69727943;
			EDX = 0x736e4978;
			ECX = 0x64616574;
		} else if (EAX == 1) {
			EAX = CPUID;
			EBX = ECX = 0;
			EDX = CPUID_FPU;
		} else
			EAX = EBX = ECX = EDX = 0;
		break;

	case CPU_Cx6x86L:
		if (!EAX) {
			EAX = 0x00000001;
			EBX = 0x69727943;
			EDX = 0x736e4978;
			ECX = 0x64616574;
		} else if (EAX == 1) {
			EAX = CPUID;
			EBX = ECX = 0;
			EDX = CPUID_FPU | CPUID_CMPXCHG8B;
		} else
			EAX = EBX = ECX = EDX = 0;
		break;

	case CPU_CxGX1:
		if (!EAX) {
			EAX = 0x00000001;
			EBX = 0x69727943;
			EDX = 0x736e4978;
			ECX = 0x64616574;
		} else if (EAX == 1) {
			EAX = CPUID;
			EBX = ECX = 0;
			EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B;
		} else
			EAX = EBX = ECX = EDX = 0;
		break;

	case CPU_Cx6x86MX:
		if (!EAX) {
			EAX = 0x00000001;
			EBX = 0x69727943;
			EDX = 0x736e4978;
			ECX = 0x64616574;
		} else if (EAX == 1) {
			EAX = CPUID;
			EBX = ECX = 0;
			EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_CMOV | CPUID_MMX;
		} else
			EAX = EBX = ECX = EDX = 0;
		break;
#endif

	case CPU_PENTIUMPRO:
		if (!EAX) {
			EAX = 0x00000002;
			EBX = 0x756e6547;
			EDX = 0x49656e69;
			ECX = 0x6c65746e;
		} else if (EAX == 1) {
			EAX = CPUID;
			EBX = ECX = 0;
			EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_MTRR | CPUID_MCA | CPUID_SEP | CPUID_CMOV;
		} else if (EAX == 2) {
			EAX = 0x00000001;
			EBX = ECX = 0;
			EDX = 0x00000000;
		} else
			EAX = EBX = ECX = EDX = 0;
		break;

	case CPU_PENTIUM2:
		if (!EAX) {
			EAX = 0x00000002;
			EBX = 0x756e6547;
			EDX = 0x49656e69;
			ECX = 0x6c65746e;
		} else if (EAX == 1) {
			EAX = CPUID;
			EBX = ECX = 0;
			EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_MTRR | CPUID_MCA | CPUID_SEP | CPUID_CMOV;
		} else if (EAX == 2) {
			EAX = 0x00000001;
			EBX = ECX = 0;
			EDX = 0x00000000;
		} else
			EAX = EBX = ECX = EDX = 0;
		break;

	case CPU_PENTIUM2D:
		if (!EAX) {
			EAX = 0x00000002;
			EBX = 0x756e6547;
			EDX = 0x49656e69;
			ECX = 0x6c65746e;
		} else if (EAX == 1) {
			EAX = CPUID;
			EBX = ECX = 0;
			EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_MTRR | CPUID_MCA | CPUID_SEP | CPUID_FXSR | CPUID_CMOV;
		} else if (EAX == 2) {
			EAX = 0x00000001;
			EBX = ECX = 0;
			EDX = 0x00000000;
		} else
			EAX = EBX = ECX = EDX = 0;
		break;

	case CPU_CYRIX3S:
		switch (EAX) {
			case 0:
				EAX = 1;
				if (msr.fcr2 & (1 << 14)) {
					EBX = msr.fcr3 >> 32;
					ECX = msr.fcr3 & 0xffffffff;
					EDX = msr.fcr2 >> 32;
				} else {
					EBX = 0x746e6543;	/* CentaurHauls */
					ECX = 0x736c7561;
					EDX = 0x48727561;
				}
				break;
			case 1:
				EAX = CPUID;
				EBX = ECX = 0;
				EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_MMX | CPUID_MTRR;
				if (cpu_has_feature(CPU_FEATURE_CX8))
					EDX |= CPUID_CMPXCHG8B;
				break;
			case 0x80000000:
				EAX = 0x80000005;
				break;
			case 0x80000001:
				EAX = CPUID;
				EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_MMX | CPUID_MTRR | CPUID_3DNOW;
				if (cpu_has_feature(CPU_FEATURE_CX8))
					EDX |= CPUID_CMPXCHG8B;
				break;
			case 0x80000002:	/* Processor name string */
				EAX = 0x20414956;	/* VIA Samuel */
				EBX = 0x756d6153;
				ECX = 0x00006c65;
				EDX = 0x00000000;
				break;
			case 0x80000005:	/* Cache information */
				EBX = 0x08800880;	/* TLBs */
				ECX = 0x40040120;	/* L1 data cache */
				EDX = 0x40020120;	/* L1 instruction cache */
				break;
			default:
				EAX = EBX = ECX = EDX = 0;
				break;
		}
		break;
    }
}


void
cpu_ven_reset(void)
{
    memset(&msr, 0, sizeof(msr));

    switch (cpu_s->cpu_type) {
	case CPU_K6_2P:
	case CPU_K6_3P:
	case CPU_K6_3:
	case CPU_K6_2C:
		msr.amd_psor = (cpu_s->cpu_type >= CPU_K6_3) ? 0x008cULL : 0x018cULL;
		/* FALLTHROUGH */
	case CPU_K6_2:
#if defined(DEV_BRANCH) && defined(USE_AMD_K5)
	case CPU_K5:
	case CPU_5K86:
#endif
	case CPU_K6:
		msr.amd_efer = (cpu_s->cpu_type >= CPU_K6_2C) ? 2ULL : 0ULL;
		break;

	case CPU_PENTIUMPRO:
	case CPU_PENTIUM2:
	case CPU_PENTIUM2D:
		msr.mtrr_cap = 0x00000508ULL;
		/* FALLTHROUGH */
		break;
    }
}


void
cpu_RDMSR(void)
{
    switch (cpu_s->cpu_type) {
	case CPU_IBM386SLC:
	case CPU_IBM486SLC:
	case CPU_IBM486BL:
		EAX = EDX = 0;
		switch (ECX) {
			case 0x1000:
				EAX = msr.ibm_por & ((cpu_s->cpu_type > CPU_IBM386SLC) ? 0xffeff : 0xfeff);
				break;

			case 0x1001:
				EAX = msr.ibm_crcr & 0xffffffffff;
				break;

			case 0x1002:
				if ((cpu_s->cpu_type > CPU_IBM386SLC) && cpu_s->multi)
					EAX = msr.ibm_por2 & 0x3f000000;
				break;
		}
		break;

	case CPU_WINCHIP:
	case CPU_WINCHIP2:
		EAX = EDX = 0;
		switch (ECX) {
			case 0x02:
				EAX = msr.tr1;
				break;
			case 0x0e:
				EAX = msr.tr12;
				break;
			case 0x10:
				EAX = tsc & 0xffffffff;
				EDX = tsc >> 32;
				break;
			case 0x11:
				EAX = msr.cesr;
				break;
			case 0x107:
				EAX = msr.fcr;
				break;
			case 0x108:
				EAX = msr.fcr2 & 0xffffffff;
				EDX = msr.fcr2 >> 32;
				break;
			case 0x10a:
				EAX = cpu_multi & 3;
				break;
		}
		break;

	case CPU_CYRIX3S:
		EAX = EDX = 0;
		switch (ECX) {
			case 0x00: case 0x01:
				break;
			case 0x10:
				EAX = tsc & 0xffffffff;
				EDX = tsc >> 32;
				break;
			case 0x2a:
				EAX = 0xc4000000;
				EDX = 0;
				if (cpu_dmulti == 3)
					EAX |= ((0 << 25) | (0 << 24) | (0 << 23) | (1 << 22));
				else if (cpu_dmulti == 3.5)
					EAX |= ((0 << 25) | (1 << 24) | (0 << 23) | (1 << 22));
				else if (cpu_dmulti == 4)
					EAX |= ((0 << 25) | (0 << 24) | (1 << 23) | (0 << 22));
				else if (cpu_dmulti == 4.5)
					EAX |= ((0 << 25) | (1 << 24) | (1 << 23) | (0 << 22));
				else if (cpu_dmulti == 5)
					EAX |= 0;
				else if (cpu_dmulti == 5.5)
					EAX |= ((0 << 25) | (1 << 24) | (0 << 23) | (0 << 22));
				else if (cpu_dmulti == 6)
					EAX |= ((1 << 25) | (0 << 24) | (1 << 23) | (1 << 22));
				else if (cpu_dmulti == 6.5)
					EAX |= ((1 << 25) | (1 << 24) | (1 << 23) | (1 << 22));
				else if (cpu_dmulti == 7)
					EAX |= ((1 << 25) | (0 << 24) | (0 << 23) | (1 << 22));
				else
					EAX |= ((0 << 25) | (0 << 24) | (0 << 23) | (1 << 22));
				if (cpu_busspeed >= 84000000)
				EAX |= (1 << 19);
				break;
			case 0x1107:
				EAX = msr.fcr;
				break;
			case 0x1108:
				EAX = msr.fcr2 & 0xffffffff;
				EDX = msr.fcr2 >> 32;
				break;
			case 0x200: case 0x201: case 0x202: case 0x203:
			case 0x204: case 0x205: case 0x206: case 0x207:
			case 0x208: case 0x209: case 0x20a: case 0x20b:
			case 0x20c: case 0x20d: case 0x20e: case 0x20f:
				if (ECX & 1) {
					EAX = msr.mtrr_physmask[(ECX - 0x200) >> 1] & 0xffffffff;
					EDX = msr.mtrr_physmask[(ECX - 0x200) >> 1] >> 32;
				} else {
					EAX = msr.mtrr_physbase[(ECX - 0x200) >> 1] & 0xffffffff;
					EDX = msr.mtrr_physbase[(ECX - 0x200) >> 1] >> 32;
				}
				break;
			case 0x250:
				EAX = msr.mtrr_fix64k_8000 & 0xffffffff;
				EDX = msr.mtrr_fix64k_8000 >> 32;
				break;
			case 0x258:
				EAX = msr.mtrr_fix16k_8000 & 0xffffffff;
				EDX = msr.mtrr_fix16k_8000 >> 32;
				break;
			case 0x259:
				EAX = msr.mtrr_fix16k_a000 & 0xffffffff;
				EDX = msr.mtrr_fix16k_a000 >> 32;
				break;
			case 0x268: case 0x269: case 0x26a: case 0x26b:
			case 0x26c: case 0x26d: case 0x26e: case 0x26f:
				EAX = msr.mtrr_fix4k[ECX - 0x268] & 0xffffffff;
				EDX = msr.mtrr_fix4k[ECX - 0x268] >> 32;
				break;
			case 0x2ff:
				EAX = msr.mtrr_deftype & 0xffffffff;
				EDX = msr.mtrr_deftype >> 32;
				break;
		}
		break;

#if defined(DEV_BRANCH) && defined(USE_AMD_K5)
	case CPU_K5:
	case CPU_5K86:
#endif
	case CPU_K6:
	case CPU_K6_2:
	case CPU_K6_2C:
	case CPU_K6_3:
	case CPU_K6_2P:
	case CPU_K6_3P:
		EAX = EDX = 0;
		switch (ECX) {
			case 0x00000000:
			case 0x00000001:
				break;
			case 0x0000000e:
				EAX = msr.tr12;
				break;
			case 0x00000010:
				EAX = tsc & 0xffffffff;
				EDX = tsc >> 32;
				break;
			case 0x00000083:
				EAX = msr.ecx83 & 0xffffffff;
				EDX = msr.ecx83 >> 32;
				break;
			case 0xc0000080:
				EAX = msr.amd_efer & 0xffffffff;
				EDX = msr.amd_efer >> 32;
				break;
			case 0xc0000081:
				if (cpu_s->cpu_type < CPU_K6_2)
					goto amd_k_invalid_rdmsr;

				EAX = msr.star & 0xffffffff;
				EDX = msr.star >> 32;
				break;
			case 0xc0000082:
				EAX = msr.amd_whcr & 0xffffffff;
				EDX = msr.amd_whcr >> 32;
				break;
			case 0xc0000085:
				if (cpu_s->cpu_type < CPU_K6_2C)
					goto amd_k_invalid_rdmsr;

				EAX = msr.amd_uwccr & 0xffffffff;
				EDX = msr.amd_uwccr >> 32;
				break;
			case 0xc0000086:
				if (cpu_s->cpu_type < CPU_K6_2P)
					goto amd_k_invalid_rdmsr;

				EAX = msr.amd_epmr & 0xffffffff;
				EDX = msr.amd_epmr >> 32;
				break;
			case 0xc0000087:
				if (cpu_s->cpu_type < CPU_K6_2C)
					goto amd_k_invalid_rdmsr;

				EAX = msr.amd_psor & 0xffffffff;
				EDX = msr.amd_psor >> 32;
				break;
			case 0xc0000088:
				if (cpu_s->cpu_type < CPU_K6_2C)
					goto amd_k_invalid_rdmsr;

				EAX = msr.amd_pfir & 0xffffffff;
				EDX = msr.amd_pfir >> 32;
				break;
			case 0xc0000089:
				if (cpu_s->cpu_type < CPU_K6_3)
					goto amd_k_invalid_rdmsr;

				EAX = msr.amd_l2aar & 0xffffffff;
				EDX = msr.amd_l2aar >> 32;
				break;
			default:
amd_k_invalid_rdmsr:
				x86gpf(NULL, 0);
				break;
		}
		break;

	case CPU_P24T:
	case CPU_PENTIUM:
	case CPU_PENTIUMMMX:
#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86)
	case CPU_Cx6x86:
	case CPU_Cx6x86L:
	case CPU_CxGX1:
	case CPU_Cx6x86MX:
		if (cpu_s->cpu_type < CPU_Cx6x86)
#endif
			EAX = EDX = 0;
		switch (ECX) {
			case 0x00: case 0x01:
				break;
			case 0x10:
				EAX = tsc & 0xffffffff;
				EDX = tsc >> 32;
				break;
		}
		cpu_log("RDMSR: ECX = %08X, val = %08X%08X\n", ECX, EDX, EAX);
		break;

	case CPU_PENTIUMPRO:
	case CPU_PENTIUM2:
	case CPU_PENTIUM2D:
		EAX = EDX = 0;
		switch (ECX) {
			case 0x00: case 0x01:
				break;
			case 0x10:
				EAX = tsc & 0xffffffff;
				EDX = tsc >> 32;
				break;
			case 0x17:
				if (cpu_s->cpu_type != CPU_PENTIUM2D)
					goto i686_invalid_rdmsr;

				if (cpu_f->package == CPU_PKG_SLOT2)
					EDX |= 0x80000;
				else if (cpu_f->package == CPU_PKG_SOCKET370)
					EDX |= 0x100000;
				break;
			case 0x1B:
				EAX = msr.apic_base & 0xffffffff;
				EDX = msr.apic_base >> 32;
				cpu_log("APIC_BASE read : %08X%08X\n", EDX, EAX);
				break;
			case 0x2a:
				EAX = 0xc4000000;
				EDX = 0;
				if (cpu_dmulti == 2.5)
					EAX |= ((0 << 25) | (1 << 24) | (1 << 23) | (1 << 22));
				else if (cpu_dmulti == 3)
					EAX |= ((0 << 25) | (0 << 24) | (0 << 23) | (1 << 22));
				else if (cpu_dmulti == 3.5)
					EAX |= ((0 << 25) | (1 << 24) | (0 << 23) | (1 << 22));
				else if (cpu_dmulti == 4)
					EAX |= ((0 << 25) | (0 << 24) | (1 << 23) | (0 << 22));
				else if (cpu_dmulti == 4.5)
					EAX |= ((0 << 25) | (1 << 24) | (1 << 23) | (0 << 22));
				else if (cpu_dmulti == 5)
					EAX |= 0;
				else if (cpu_dmulti == 5.5)
					EAX |= ((0 << 25) | (1 << 24) | (0 << 23) | (0 << 22));
				else if (cpu_dmulti == 6)
					EAX |= ((1 << 25) | (0 << 24) | (1 << 23) | (1 << 22));
				else if (cpu_dmulti == 6.5)
					EAX |= ((1 << 25) | (1 << 24) | (1 << 23) | (1 << 22));
				else if (cpu_dmulti == 7)
					EAX |= ((1 << 25) | (0 << 24) | (0 << 23) | (1 << 22));
				else if (cpu_dmulti == 7.5)
					EAX |= ((1 << 25) | (1 << 24) | (0 << 23) | (1 << 22));
				else if (cpu_dmulti == 8)
					EAX |= ((1 << 25) | (0 << 24) | (1 << 23) | (0 << 22));
				else
					EAX |= ((0 << 25) | (1 << 24) | (1 << 23) | (1 << 22));
				if (cpu_s->cpu_type != CPU_PENTIUMPRO) {
					if (cpu_busspeed >= 84000000)
						EAX |= (1 << 19);
				}
				break;
			case 0x79:
				EAX = msr.ecx79 & 0xffffffff;
				EDX = msr.ecx79 >> 32;
				break;
			case 0x88: case 0x89: case 0x8a: case 0x8b:
				EAX = msr.ecx8x[ECX - 0x88] & 0xffffffff;
				EDX = msr.ecx8x[ECX - 0x88] >> 32;
				break;
			case 0xc1: case 0xc2: case 0xc3: case 0xc4:
			case 0xc5: case 0xc6: case 0xc7: case 0xc8:
				EAX = msr.ia32_pmc[ECX - 0xC1] & 0xffffffff;
				EDX = msr.ia32_pmc[ECX - 0xC1] >> 32;
				break;
			case 0xfe:
				EAX = msr.mtrr_cap & 0xffffffff;
				EDX = msr.mtrr_cap >> 32;
				break;
			case 0x116:
				EAX = msr.ecx116 & 0xffffffff;
				EDX = msr.ecx116 >> 32;
				break;
			case 0x118: case 0x119: case 0x11a: case 0x11b:
				EAX = msr.ecx11x[ECX - 0x118] & 0xffffffff;
				EDX = msr.ecx11x[ECX - 0x118] >> 32;
				break;
			case 0x11e:
				EAX = msr.ecx11e & 0xffffffff;
				EDX = msr.ecx11e >> 32;
				break;
			case 0x174:
				if (cpu_s->cpu_type == CPU_PENTIUMPRO)
					goto i686_invalid_rdmsr;

				EAX &= 0xffff0000;
				EAX |= msr.sysenter_cs;
				EDX = 0x00000000;
				break;
			case 0x175:
				if (cpu_s->cpu_type == CPU_PENTIUMPRO)
					goto i686_invalid_rdmsr;

				EAX = msr.sysenter_esp;
				EDX = 0x00000000;
				break;
			case 0x176:
				if (cpu_s->cpu_type == CPU_PENTIUMPRO)
					goto i686_invalid_rdmsr;

				EAX = msr.sysenter_eip;
				EDX = 0x00000000;
				break;
			case 0x179:
				EAX = 0x00000105;
				EDX = 0x00000000;
				break;
			case 0x17a:
				break;
			case 0x17b:
				EAX = msr.mcg_ctl & 0xffffffff;
				EDX = msr.mcg_ctl >> 32;
				break;
			case 0x186:
				EAX = msr.ecx186 & 0xffffffff;
				EDX = msr.ecx186 >> 32;
				break;
			case 0x187:
				EAX = msr.ecx187 & 0xffffffff;
				EDX = msr.ecx187 >> 32;
				break;
			case 0x1e0:
				EAX = msr.ecx1e0 & 0xffffffff;
				EDX = msr.ecx1e0 >> 32;
				break;
			case 0x200: case 0x201: case 0x202: case 0x203:
			case 0x204: case 0x205: case 0x206: case 0x207:
			case 0x208: case 0x209: case 0x20a: case 0x20b:
			case 0x20c: case 0x20d: case 0x20e: case 0x20f:
				if (ECX & 1) {
					EAX = msr.mtrr_physmask[(ECX - 0x200) >> 1] & 0xffffffff;
					EDX = msr.mtrr_physmask[(ECX - 0x200) >> 1] >> 32;
				} else {
					EAX = msr.mtrr_physbase[(ECX - 0x200) >> 1] & 0xffffffff;
					EDX = msr.mtrr_physbase[(ECX - 0x200) >> 1] >> 32;
				}
				break;
			case 0x250:
				EAX = msr.mtrr_fix64k_8000 & 0xffffffff;
				EDX = msr.mtrr_fix64k_8000 >> 32;
				break;
			case 0x258:
				EAX = msr.mtrr_fix16k_8000 & 0xffffffff;
				EDX = msr.mtrr_fix16k_8000 >> 32;
				break;
			case 0x259:
				EAX = msr.mtrr_fix16k_a000 & 0xffffffff;
				EDX = msr.mtrr_fix16k_a000 >> 32;
				break;
			case 0x268: case 0x269: case 0x26a: case 0x26b:
			case 0x26c: case 0x26d: case 0x26e: case 0x26f:
				EAX = msr.mtrr_fix4k[ECX - 0x268] & 0xffffffff;
				EDX = msr.mtrr_fix4k[ECX - 0x268] >> 32;
				break;
			case 0x277:
				EAX = msr.pat & 0xffffffff;
				EDX = msr.pat >> 32;
				break;
			case 0x2ff:
				EAX = msr.mtrr_deftype & 0xffffffff;
				EDX = msr.mtrr_deftype >> 32;
				break;
			case 0x400: case 0x404: case 0x408: case 0x40c:
			case 0x410:
				EAX = msr.mca_ctl[(ECX - 0x400) >> 2] & 0xffffffff;
				EDX = msr.mca_ctl[(ECX - 0x400) >> 2] >> 32;
				break;
			case 0x401: case 0x402: case 0x405: case 0x406:
			case 0x407: case 0x409: case 0x40d: case 0x40e:
			case 0x411: case 0x412:
				break;
			case 0x570:
				EAX = msr.ecx570 & 0xffffffff;
				EDX = msr.ecx570 >> 32;
				break;
			case 0x1002ff:
				EAX = msr.ecx1002ff & 0xffffffff;
				EDX = msr.ecx1002ff >> 32;
				break;
			case 0xf0f00250:
				EAX = msr.ecxf0f00250 & 0xffffffff;
				EDX = msr.ecxf0f00250 >> 32;
				break;
			case 0xf0f00258:
				EAX = msr.ecxf0f00258 & 0xffffffff;
				EDX = msr.ecxf0f00258 >> 32;
				break;
			case 0xf0f00259:
				EAX = msr.ecxf0f00259 & 0xffffffff;
				EDX = msr.ecxf0f00259 >> 32;
				break;
			default:
i686_invalid_rdmsr:
				cpu_log("RDMSR: Invalid MSR: %08X\n", ECX);
				x86gpf(NULL, 0);
				break;
		}
		break;
    }

    cpu_log("RDMSR %08X %08X%08X\n", ECX, EDX, EAX);
}


void
cpu_WRMSR(void)
{
    uint64_t temp;

    cpu_log("WRMSR %08X %08X%08X\n", ECX, EDX, EAX);

    switch (cpu_s->cpu_type) {
	case CPU_IBM386SLC:
	case CPU_IBM486BL:
	case CPU_IBM486SLC:
		switch (ECX) {
			case 0x1000:
				msr.ibm_por = EAX & ((cpu_s->cpu_type > CPU_IBM386SLC) ? 0xffeff : 0xfeff);
				cpu_cache_int_enabled = (EAX & (1 << 7));
				break;
			case 0x1001:
				msr.ibm_crcr = EAX & 0xffffffffff;
				break;
			case 0x1002:
				if ((cpu_s->cpu_type > CPU_IBM386SLC) && cpu_s->multi)
					msr.ibm_por2 = EAX & 0x3f000000;
                       		break;
		}
		break;

	case CPU_WINCHIP:
	case CPU_WINCHIP2:
		switch (ECX) {
			case 0x02:
				msr.tr1 = EAX & 2;
				break;
			case 0x0e:
				msr.tr12 = EAX & 0x228;
				break;
			case 0x10:
				tsc = EAX | ((uint64_t)EDX << 32);
				break;
			case 0x11:
				msr.cesr = EAX & 0xff00ff;
				break;
			case 0x107:
				msr.fcr = EAX;
				if (EAX & (1 << 9))
					cpu_features |= CPU_FEATURE_MMX;
				else
					cpu_features &= ~CPU_FEATURE_MMX;
				if (EAX & (1 << 1))
					cpu_features |= CPU_FEATURE_CX8;
				else
					cpu_features &= ~CPU_FEATURE_CX8;
				if ((EAX & (1 << 20)) && cpu_s->cpu_type >= CPU_WINCHIP2)
					cpu_features |= CPU_FEATURE_3DNOW;
				else
					cpu_features &= ~CPU_FEATURE_3DNOW;
				if (EAX & (1 << 29))
					CPUID = 0;
				else
					CPUID = cpu_s->cpuid_model;
				break;
			case 0x108:
				msr.fcr2 = EAX | ((uint64_t)EDX << 32);
				break;
			case 0x109:
				msr.fcr3 = EAX | ((uint64_t)EDX << 32);
				break;
		}
		break;

	case CPU_CYRIX3S:
		switch (ECX) {
			case 0x00: case 0x01:
				break;
			case 0x10:
				tsc = EAX | ((uint64_t)EDX << 32);
				break;
			case 0x1107:
				msr.fcr = EAX;
				if (EAX & (1 << 1))
					cpu_features |= CPU_FEATURE_CX8;
				else
					cpu_features &= ~CPU_FEATURE_CX8;
				break;
			case 0x1108:
				msr.fcr2 = EAX | ((uint64_t)EDX << 32);
				break;
			case 0x1109:
				msr.fcr3 = EAX | ((uint64_t)EDX << 32);
				break;
			case 0x200: case 0x201: case 0x202: case 0x203:
			case 0x204: case 0x205: case 0x206: case 0x207:
			case 0x208: case 0x209: case 0x20a: case 0x20b:
			case 0x20c: case 0x20d: case 0x20e: case 0x20f:
				if (ECX & 1)
					msr.mtrr_physmask[(ECX - 0x200) >> 1] = EAX | ((uint64_t)EDX << 32);
				else
					msr.mtrr_physbase[(ECX - 0x200) >> 1] = EAX | ((uint64_t)EDX << 32);
				break;
			case 0x250:
				msr.mtrr_fix64k_8000 = EAX | ((uint64_t)EDX << 32);
				break;
			case 0x258:
				msr.mtrr_fix16k_8000 = EAX | ((uint64_t)EDX << 32);
				break;
			case 0x259:
				msr.mtrr_fix16k_a000 = EAX | ((uint64_t)EDX << 32);
				break;
			case 0x268: case 0x269: case 0x26A: case 0x26B: case 0x26C: case 0x26D: case 0x26E: case 0x26F:
				msr.mtrr_fix4k[ECX - 0x268] = EAX | ((uint64_t)EDX << 32);
				break;
			case 0x2ff:
				msr.mtrr_deftype = EAX | ((uint64_t)EDX << 32);
				break;
		}
		break;

#if defined(DEV_BRANCH) && defined(USE_AMD_K5)
	case CPU_K5:
	case CPU_5K86:
#endif
	case CPU_K6:
	case CPU_K6_2:
	case CPU_K6_2C:
	case CPU_K6_3:
	case CPU_K6_2P:
	case CPU_K6_3P:
		switch (ECX) {
			case 0x00: case 0x01:
				break;
			case 0x0e:
				msr.tr12 = EAX & 0x228;
				break;
			case 0x10:
				tsc = EAX | ((uint64_t)EDX << 32);
				break;
			case 0x83:
				msr.ecx83 = EAX | ((uint64_t)EDX << 32);
				break;
			case 0xc0000080:
				temp = EAX | ((uint64_t)EDX << 32);
				if (temp & ~1ULL)
					x86gpf(NULL, 0);
				else
					msr.amd_efer = temp;
				break;
			case 0xc0000081:
				if (cpu_s->cpu_type < CPU_K6_2)
					goto amd_k_invalid_wrmsr;

				msr.star = EAX | ((uint64_t)EDX << 32);
				break;
			case 0xc0000082:
				msr.amd_whcr = EAX | ((uint64_t)EDX << 32);
				break;
			case 0xc0000085:
				if (cpu_s->cpu_type < CPU_K6_2C)
					goto amd_k_invalid_wrmsr;

				msr.amd_uwccr = EAX | ((uint64_t)EDX << 32);
				break;
			case 0xc0000086:
				if (cpu_s->cpu_type < CPU_K6_2P)
					goto amd_k_invalid_wrmsr;

				msr.amd_epmr = EAX | ((uint64_t)EDX << 32);
				break;
			case 0xc0000087:
				if (cpu_s->cpu_type < CPU_K6_2C)
					goto amd_k_invalid_wrmsr;

				msr.amd_psor = EAX | ((uint64_t)EDX << 32);
				break;
			case 0xc0000088:
				if (cpu_s->cpu_type < CPU_K6_2C)
					goto amd_k_invalid_wrmsr;

				msr.amd_pfir = EAX | ((uint64_t)EDX << 32);
				break;
			case 0xc0000089:
				if (cpu_s->cpu_type < CPU_K6_3)
					goto amd_k_invalid_wrmsr;

				msr.amd_l2aar = EAX | ((uint64_t)EDX << 32);
				break;
			default:
amd_k_invalid_wrmsr:
				x86gpf(NULL, 0);
				break;
		}
		break;

	case CPU_P24T:
	case CPU_PENTIUM:
	case CPU_PENTIUMMMX:
#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86)
	case CPU_Cx6x86:
	case CPU_Cx6x86L:
	case CPU_CxGX1:
	case CPU_Cx6x86MX:
#endif
		cpu_log("WRMSR: ECX = %08X, val = %08X%08X\n", ECX, EDX, EAX);
		switch (ECX) {
			case 0x00: case 0x01:
				break;
			case 0x10:
				tsc = EAX | ((uint64_t)EDX << 32);
				break;
			case 0x8b:
#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86)
				if (cpu_s->cpu_type < CPU_Cx6x86) {
#endif
					cpu_log("WRMSR: Invalid MSR: 0x8B\n");
					x86gpf(NULL, 0);	/* Needed for Vista to correctly break on Pentium */
#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86)
				}
#endif
				break;
		}
		break;

	case CPU_PENTIUMPRO:
	case CPU_PENTIUM2:
	case CPU_PENTIUM2D:
		switch (ECX) {
			case 0x00: case 0x01:
				if (EAX || EDX)
					x86gpf(NULL, 0);
				break;
			case 0x10:
				tsc = EAX | ((uint64_t)EDX << 32);
				break;
			case 0x1b:
				cpu_log("APIC_BASE write: %08X%08X\n", EDX, EAX);
				// msr.apic_base = EAX | ((uint64_t)EDX << 32);
				break;
			case 0x2a:
				break;
			case 0x79:
				msr.ecx79 = EAX | ((uint64_t)EDX << 32);
				break;
			case 0x88: case 0x89: case 0x8a: case 0x8b:
				msr.ecx8x[ECX - 0x88] = EAX | ((uint64_t)EDX << 32);
				break;
			case 0xc1: case 0xc2: case 0xc3: case 0xc4:
			case 0xc5: case 0xc6: case 0xc7: case 0xc8:
				msr.ia32_pmc[ECX - 0xC1] = EAX | ((uint64_t)EDX << 32);
				break;
			case 0xfe:
				msr.mtrr_cap = EAX | ((uint64_t)EDX << 32);
				break;
			case 0x116:
				msr.ecx116 = EAX | ((uint64_t)EDX << 32);
				break;
			case 0x118: case 0x119: case 0x11a: case 0x11b:
				msr.ecx11x[ECX - 0x118] = EAX | ((uint64_t)EDX << 32);
				break;
			case 0x11e:
				msr.ecx11e = EAX | ((uint64_t)EDX << 32);
				break;
			case 0x174:
				if (cpu_s->cpu_type == CPU_PENTIUMPRO)
					goto i686_invalid_wrmsr;

				msr.sysenter_cs = EAX & 0xFFFF;
				break;
			case 0x175:
				if (cpu_s->cpu_type == CPU_PENTIUMPRO)
					goto i686_invalid_wrmsr;

				msr.sysenter_esp = EAX;
				break;
			case 0x176:
				if (cpu_s->cpu_type == CPU_PENTIUMPRO)
					goto i686_invalid_wrmsr;

				msr.sysenter_eip = EAX;
				break;
			case 0x179:
				break;
			case 0x17a:
				if (EAX || EDX)
					x86gpf(NULL, 0);
				break;
			case 0x17b:
				msr.mcg_ctl = EAX | ((uint64_t)EDX << 32);
				break;
			case 0x186:
				msr.ecx186 = EAX | ((uint64_t)EDX << 32);
				break;
			case 0x187:
				msr.ecx187 = EAX | ((uint64_t)EDX << 32);
				break;
			case 0x1e0:
				msr.ecx1e0 = EAX | ((uint64_t)EDX << 32);
				break;
			case 0x200: case 0x201: case 0x202: case 0x203:
			case 0x204: case 0x205: case 0x206: case 0x207:
			case 0x208: case 0x209: case 0x20a: case 0x20b:
			case 0x20c: case 0x20d: case 0x20e: case 0x20f:
				if (ECX & 1)
					msr.mtrr_physmask[(ECX - 0x200) >> 1] = EAX | ((uint64_t)EDX << 32);
				else
					msr.mtrr_physbase[(ECX - 0x200) >> 1] = EAX | ((uint64_t)EDX << 32);
				break;
			case 0x250:
				msr.mtrr_fix64k_8000 = EAX | ((uint64_t)EDX << 32);
				break;
			case 0x258:
				msr.mtrr_fix16k_8000 = EAX | ((uint64_t)EDX << 32);
				break;
			case 0x259:
				msr.mtrr_fix16k_a000 = EAX | ((uint64_t)EDX << 32);
				break;
			case 0x268: case 0x269: case 0x26a: case 0x26b:
			case 0x26c: case 0x26d: case 0x26e: case 0x26f:
				msr.mtrr_fix4k[ECX - 0x268] = EAX | ((uint64_t)EDX << 32);
				break;
			case 0x277:
				msr.pat = EAX | ((uint64_t)EDX << 32);
				break;
			case 0x2ff:
				msr.mtrr_deftype = EAX | ((uint64_t)EDX << 32);
				break;
			case 0x400: case 0x404: case 0x408: case 0x40c:
			case 0x410:
				msr.mca_ctl[(ECX - 0x400) >> 2] = EAX | ((uint64_t)EDX << 32);
				break;
			case 0x401: case 0x402: case 0x405: case 0x406:
			case 0x407: case 0x409: case 0x40d: case 0x40e:
			case 0x411: case 0x412:
				if (EAX || EDX)
					x86gpf(NULL, 0);
				break;
			case 0x570:
				msr.ecx570 = EAX | ((uint64_t)EDX << 32);
				break;
			case 0x1002ff:
				msr.ecx1002ff = EAX | ((uint64_t)EDX << 32);
				break;
			case 0xf0f00250:
				msr.ecxf0f00250 = EAX | ((uint64_t)EDX << 32);
				break;
			case 0xf0f00258:
				msr.ecxf0f00258 = EAX | ((uint64_t)EDX << 32);
				break;
			case 0xf0f00259:
				msr.ecxf0f00259 = EAX | ((uint64_t)EDX << 32);
				break;
			default:
i686_invalid_wrmsr:
				cpu_log("WRMSR: Invalid MSR: %08X\n", ECX);
				x86gpf(NULL, 0);
				break;
		}
		break;
    }
}


static void
cpu_write(uint16_t addr, uint8_t val, void *priv)
{
    if (addr == 0xf0) {
	/* Writes to F0 clear FPU error and deassert the interrupt. */
	if (is286)
		picintc(1 << 13);
	else
		nmi = 0;
	return;
    } else if (addr >= 0xf1)
	return;		/* FPU stuff */

    if (!(addr & 1))
	cyrix_addr = val;
    else switch (cyrix_addr) {
	case 0xc0:	/* CCR0 */
		ccr0 = val;
		break;
	case 0xc1:	/* CCR1 */
		if ((ccr3 & CCR3_SMI_LOCK) && !in_smm)
			val = (val & ~(CCR1_USE_SMI | CCR1_SMAC | CCR1_SM3)) | (ccr1 & (CCR1_USE_SMI | CCR1_SMAC | CCR1_SM3));
		ccr1 = val;
		break;
	case 0xc2:	/* CCR2 */
		ccr2 = val;
		break;
	case 0xc3:	/* CCR3 */
		if ((ccr3 & CCR3_SMI_LOCK) && !in_smm)
			val = (val & ~(CCR3_NMI_EN)) | (ccr3 & CCR3_NMI_EN) | CCR3_SMI_LOCK;
		ccr3 = val;
		break;
	case 0xcd:
		if (!(ccr3 & CCR3_SMI_LOCK) || in_smm) {
			cyrix.arr[3].base = (cyrix.arr[3].base & ~0xff000000) | (val << 24);
			cyrix.smhr &= ~SMHR_VALID;
		}
		break;
	case 0xce:
		if (!(ccr3 & CCR3_SMI_LOCK) || in_smm) {
			cyrix.arr[3].base = (cyrix.arr[3].base & ~0x00ff0000) | (val << 16);
			cyrix.smhr &= ~SMHR_VALID;
		}
		break;
	case 0xcf:
		if (!(ccr3 & CCR3_SMI_LOCK) || in_smm) {
			cyrix.arr[3].base = (cyrix.arr[3].base & ~0x0000f000) | ((val & 0xf0) << 8);
			if ((val & 0xf) == 0xf)
				cyrix.arr[3].size = 1ull << 32;		/* 4 GB */
			else if (val & 0xf)
				cyrix.arr[3].size = 2048 << (val & 0xf);
			else
				cyrix.arr[3].size = 0;			/* Disabled */
			cyrix.smhr &= ~SMHR_VALID;
		}
		break;

	case 0xe8:	/* CCR4 */
		if ((ccr3 & 0xf0) == 0x10) {
			ccr4 = val;
#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86)
			if (cpu_s->cpu_type >= CPU_Cx6x86) {
				if (val & 0x80)
					CPUID = cpu_s->cpuid_model;
				else
					CPUID = 0;
			}
#endif
		}
		break;
	case 0xe9:	/* CCR5 */
		if ((ccr3 & 0xf0) == 0x10)
			ccr5 = val;
		break;
	case 0xea:	/* CCR6 */
		if ((ccr3 & 0xf0) == 0x10)
			ccr6 = val;
		break;
    }
}


static uint8_t
cpu_read(uint16_t addr, void *priv)
{
    if (addr == 0xf007)
	return 0x7f;

    if (addr >= 0xf0)
	return 0xff;		/* FPU stuff */

    if (addr & 1) {
	switch (cyrix_addr) {
		case 0xc0:
			return ccr0;
		case 0xc1:
			return ccr1;
		case 0xc2:
			return ccr2;
		case 0xc3:
			return ccr3;
		case 0xe8:
			return ((ccr3 & 0xf0) == 0x10) ? ccr4 : 0xff;
		case 0xe9:
			return ((ccr3 & 0xf0) == 0x10) ? ccr5 : 0xff;
		case 0xea:
			return ((ccr3 & 0xf0) == 0x10) ? ccr6 : 0xff;
		case 0xfe:
			return cpu_s->cyrix_id & 0xff;
		case 0xff:
			return cpu_s->cyrix_id >> 8;
	}

	if ((cyrix_addr & 0xf0) == 0xc0)
		return 0xff;

	if (cyrix_addr == 0x20 && (cpu_s->cpu_type == CPU_Cx5x86))
		return 0xff;
    }

    return 0xff;
}


void
#ifdef USE_DYNAREC
x86_setopcodes(const OpFn *opcodes, const OpFn *opcodes_0f,
	       const OpFn *dynarec_opcodes, const OpFn *dynarec_opcodes_0f)
{
    x86_opcodes = opcodes;
    x86_opcodes_0f = opcodes_0f;
    x86_dynarec_opcodes = dynarec_opcodes;
    x86_dynarec_opcodes_0f = dynarec_opcodes_0f;
}
#else
x86_setopcodes(const OpFn *opcodes, const OpFn *opcodes_0f)
{
    x86_opcodes = opcodes;
    x86_opcodes_0f = opcodes_0f;
}
#endif


void
cpu_update_waitstates(void)
{
    cpu_s = (CPU *) &cpu_f->cpus[cpu_effective];

    if (is486)
	cpu_prefetch_width = 16;
    else
	cpu_prefetch_width = cpu_16bitbus ? 2 : 4;

    if (cpu_cache_int_enabled) {
	/* Disable prefetch emulation */
	cpu_prefetch_cycles = 0;
    } else if (cpu_waitstates && (cpu_s->cpu_type >= CPU_286 && cpu_s->cpu_type <= CPU_386DX)) {
	/* Waitstates override */
	cpu_prefetch_cycles = cpu_waitstates+1;
	cpu_cycles_read = cpu_waitstates+1;
	cpu_cycles_read_l = (cpu_16bitbus ? 2 : 1) * (cpu_waitstates+1);
	cpu_cycles_write = cpu_waitstates+1;
	cpu_cycles_write_l = (cpu_16bitbus ? 2 : 1) * (cpu_waitstates+1);
    } else if (cpu_cache_ext_enabled) {
	/* Use cache timings */
	cpu_prefetch_cycles = cpu_s->cache_read_cycles;
	cpu_cycles_read = cpu_s->cache_read_cycles;
	cpu_cycles_read_l = (cpu_16bitbus ? 2 : 1) * cpu_s->cache_read_cycles;
	cpu_cycles_write = cpu_s->cache_write_cycles;
	cpu_cycles_write_l = (cpu_16bitbus ? 2 : 1) * cpu_s->cache_write_cycles;
    } else {
	/* Use memory timings */
	cpu_prefetch_cycles = cpu_s->mem_read_cycles;
	cpu_cycles_read = cpu_s->mem_read_cycles;
	cpu_cycles_read_l = (cpu_16bitbus ? 2 : 1) * cpu_s->mem_read_cycles;
	cpu_cycles_write = cpu_s->mem_write_cycles;
	cpu_cycles_write_l = (cpu_16bitbus ? 2 : 1) * cpu_s->mem_write_cycles;
    }

    if (is486)
	cpu_prefetch_cycles = (cpu_prefetch_cycles * 11) / 16;

    cpu_mem_prefetch_cycles = cpu_prefetch_cycles;

    if (cpu_s->rspeed <= 8000000)
	cpu_rom_prefetch_cycles = cpu_mem_prefetch_cycles;
}
