/*
* 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,
* leilei,
* Miran Grca,
* Fred N. van Kempen,
*
* Copyright 2008-2020 Sarah Walker.
* Copyright 2016-2018 leilei.
* Copyright 2016-2020 Miran Grca.
* Copyright 2018-2021 Fred N. van Kempen.
*/
#include
#include
#include
#include
#include
#include
#include
#define HAVE_STDARG_H
#include <86box/86box.h>
#include "cpu.h"
#include "x86.h"
#include "x87_sf.h"
#include <86box/device.h>
#include <86box/machine.h>
#include <86box/io.h>
#include "x86_ops.h"
#include "x86seg_common.h"
#include <86box/mem.h>
#include <86box/nmi.h>
#include <86box/pic.h>
#include <86box/pci.h>
#include <86box/timer.h>
#include <86box/gdbstub.h>
#include <86box/plat_fallthrough.h>
#include <86box/plat_unused.h>
#ifdef USE_DYNAREC
# include "codegen.h"
#endif /* USE_DYNAREC */
#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), /* On-chip Floating Point Unit */
CPUID_VME = (1 << 1), /* Virtual 8086 mode extensions */
CPUID_DE = (1 << 2), /* Debugging extensions */
CPUID_PSE = (1 << 3), /* Page Size Extension */
CPUID_TSC = (1 << 4), /* Time Stamp Counter */
CPUID_MSR = (1 << 5), /* Model-specific registers */
CPUID_PAE = (1 << 6), /* Physical Address Extension */
CPUID_MCE = (1 << 7), /* Machine Check Exception */
CPUID_CMPXCHG8B = (1 << 8), /* CMPXCHG8B instruction */
CPUID_APIC = (1 << 9), /* On-chip APIC */
CPUID_AMDPGE = (1 << 9), /* Global Page Enable (AMD K5 Model 0 only) */
CPUID_AMDSEP = (1 << 10), /* SYSCALL and SYSRET instructions (AMD K6 only) */
CPUID_SEP = (1 << 11), /* SYSENTER and SYSEXIT instructions (SYSCALL and SYSRET if EAX=80000001h) */
CPUID_MTRR = (1 << 12), /* Memory type range registers */
CPUID_PGE = (1 << 13), /* Page Global Enable */
CPUID_MCA = (1 << 14), /* Machine Check Architecture */
CPUID_CMOV = (1 << 15), /* Conditional move instructions */
CPUID_PAT = (1 << 16), /* Page Attribute Table */
CPUID_PSE36 = (1 << 17), /* 36-bit Page Size Extension */
CPUID_MMX = (1 << 23), /* MMX technology */
CPUID_FXSR = (1 << 24) /* FXSAVE and FXRSTOR instructions */
};
/* Additional flags returned by CPUID function 0x80000001 */
#define CPUID_3DNOWE (1UL << 30UL) /* Extended 3DNow! instructions */
#define CPUID_3DNOW (1UL << 31UL) /* 3DNow! instructions */
/* Remove the Debugging Extensions CPUID flag if not compiled
with debug register support for 486 and later CPUs. */
#ifndef USE_DEBUG_REGS_486
# define CPUID_DE 0
#endif
/* Make sure this is as low as possible. */
cpu_state_t cpu_state;
fpu_state_t fpu_state;
/* Place this immediately after. */
uint32_t abrt_error;
#ifdef USE_DYNAREC
const OpFn *x86_dynarec_opcodes;
const OpFn *x86_dynarec_opcodes_0f;
const OpFn *x86_dynarec_opcodes_d8_a16;
const OpFn *x86_dynarec_opcodes_d8_a32;
const OpFn *x86_dynarec_opcodes_d9_a16;
const OpFn *x86_dynarec_opcodes_d9_a32;
const OpFn *x86_dynarec_opcodes_da_a16;
const OpFn *x86_dynarec_opcodes_da_a32;
const OpFn *x86_dynarec_opcodes_db_a16;
const OpFn *x86_dynarec_opcodes_db_a32;
const OpFn *x86_dynarec_opcodes_dc_a16;
const OpFn *x86_dynarec_opcodes_dc_a32;
const OpFn *x86_dynarec_opcodes_dd_a16;
const OpFn *x86_dynarec_opcodes_dd_a32;
const OpFn *x86_dynarec_opcodes_de_a16;
const OpFn *x86_dynarec_opcodes_de_a32;
const OpFn *x86_dynarec_opcodes_df_a16;
const OpFn *x86_dynarec_opcodes_df_a32;
const OpFn *x86_dynarec_opcodes_REPE;
const OpFn *x86_dynarec_opcodes_REPNE;
const OpFn *x86_dynarec_opcodes_3DNOW;
#endif /* USE_DYNAREC */
const OpFn *x86_opcodes;
const OpFn *x86_opcodes_0f;
const OpFn *x86_opcodes_d8_a16;
const OpFn *x86_opcodes_d8_a32;
const OpFn *x86_opcodes_d9_a16;
const OpFn *x86_opcodes_d9_a32;
const OpFn *x86_opcodes_da_a16;
const OpFn *x86_opcodes_da_a32;
const OpFn *x86_opcodes_db_a16;
const OpFn *x86_opcodes_db_a32;
const OpFn *x86_opcodes_dc_a16;
const OpFn *x86_opcodes_dc_a32;
const OpFn *x86_opcodes_dd_a16;
const OpFn *x86_opcodes_dd_a32;
const OpFn *x86_opcodes_de_a16;
const OpFn *x86_opcodes_de_a32;
const OpFn *x86_opcodes_df_a16;
const OpFn *x86_opcodes_df_a32;
const OpFn *x86_opcodes_REPE;
const OpFn *x86_opcodes_REPNE;
const OpFn *x86_opcodes_3DNOW;
const OpFn *x86_2386_opcodes;
const OpFn *x86_2386_opcodes_0f;
const OpFn *x86_2386_opcodes_d8_a16;
const OpFn *x86_2386_opcodes_d8_a32;
const OpFn *x86_2386_opcodes_d9_a16;
const OpFn *x86_2386_opcodes_d9_a32;
const OpFn *x86_2386_opcodes_da_a16;
const OpFn *x86_2386_opcodes_da_a32;
const OpFn *x86_2386_opcodes_db_a16;
const OpFn *x86_2386_opcodes_db_a32;
const OpFn *x86_2386_opcodes_dc_a16;
const OpFn *x86_2386_opcodes_dc_a32;
const OpFn *x86_2386_opcodes_dd_a16;
const OpFn *x86_2386_opcodes_dd_a32;
const OpFn *x86_2386_opcodes_de_a16;
const OpFn *x86_2386_opcodes_de_a32;
const OpFn *x86_2386_opcodes_df_a16;
const OpFn *x86_2386_opcodes_df_a32;
const OpFn *x86_2386_opcodes_REPE;
const OpFn *x86_2386_opcodes_REPNE;
uint16_t cpu_fast_off_count;
uint16_t cpu_fast_off_val;
uint16_t temp_seg_data[4] = { 0, 0, 0, 0 };
int isa_cycles;
int cpu_inited;
int cpu_cycles_read;
int cpu_cycles_read_l;
int cpu_cycles_write;
int cpu_cycles_write_l;
int cpu_prefetch_cycles;
int cpu_prefetch_width;
int cpu_mem_prefetch_cycles;
int cpu_rom_prefetch_cycles;
int cpu_waitstates;
int cpu_cache_int_enabled;
int cpu_cache_ext_enabled;
int cpu_flush_pending;
int cpu_old_paging;
int cpu_isa_speed;
int cpu_pci_speed;
int cpu_isa_pci_div;
int cpu_agp_speed;
int cpu_alt_reset;
int cpu_override;
int cpu_effective;
int cpu_multi;
int cpu_16bitbus;
int cpu_64bitbus;
int cpu_cyrix_alignment;
int cpu_cpurst_on_sr;
int cpu_use_exec = 0;
int cpu_override_interpreter;
int CPUID;
int is186;
int is_mazovia;
int is_nec;
int is286;
int is386;
int is6117;
int is486 = 1;
int cpu_isintel;
int cpu_iscyrix;
int hascache;
int isibm486;
int israpidcad;
int is_vpc;
int is_am486;
int is_am486dxl;
int is_pentium;
int is_k5;
int is_k6;
int is_p6;
int is_cxsmm;
int hasfpu;
int timing_rr;
int timing_mr;
int timing_mrl;
int timing_rm;
int timing_rml;
int timing_mm;
int timing_mml;
int timing_bt;
int timing_bnt;
int timing_int;
int timing_int_rm;
int timing_int_v86;
int timing_int_pm;
int timing_int_pm_outer;
int timing_iret_rm;
int timing_iret_v86;
int timing_iret_pm;
int timing_iret_pm_outer;
int timing_call_rm;
int timing_call_pm;
int timing_call_pm_gate;
int timing_call_pm_gate_inner;
int timing_retf_rm;
int timing_retf_pm;
int timing_retf_pm_outer;
int timing_jmp_rm;
int timing_jmp_pm;
int timing_jmp_pm_gate;
int timing_misaligned;
uint32_t cpu_features;
uint32_t 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;
uint64_t tsc = 0;
double cpu_dmulti;
double cpu_busspeed;
msr_t msr;
cyrix_t cyrix;
cpu_family_t *cpu_f;
CPU *cpu_s;
uint8_t do_translate = 0;
uint8_t do_translate2 = 0;
void (*cpu_exec)(int32_t cycs);
static uint8_t ccr0;
static uint8_t ccr1;
static uint8_t ccr2;
static uint8_t ccr3;
static uint8_t ccr4;
static uint8_t ccr5;
static uint8_t 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;
if (fpu_softfloat)
SF_FPU_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;
uint32_t 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
SF_FPU_reset(void)
{
if (fpu_type != FPU_NONE) {
fpu_state.cwd = 0x0040;
fpu_state.swd = 0;
fpu_state.tos = 0;
fpu_state.tag = 0x5555;
fpu_state.foo = 0;
fpu_state.fip = 0;
fpu_state.fcs = 0;
fpu_state.fds = 0;
fpu_state.fdp = 0;
memset(fpu_state.st_space, 0, sizeof(floatx80) * 8);
}
}
void
cpu_set(void)
{
cpu_inited = 1;
cpu_effective = cpu;
cpu_s = (CPU *) &cpu_f->cpus[cpu_effective];
#ifdef USE_ACYCS
acycs = 0;
#endif /* USE_ACYCS */
soft_reset_pci = 0;
cpu_init = 0;
cpu_alt_reset = 0;
unmask_a20_in_smm = 0;
CPUID = cpu_s->cpuid_model;
is8086 = (cpu_s->cpu_type > CPU_8088) && (cpu_s->cpu_type != CPU_V20) && (cpu_s->cpu_type != CPU_188);
is_mazovia = (cpu_s->cpu_type == CPU_8086_MAZOVIA);
is_nec = (cpu_s->cpu_type == CPU_V20) || (cpu_s->cpu_type == CPU_V30);
is186 = (cpu_s->cpu_type == CPU_186) || (cpu_s->cpu_type == CPU_188) || (cpu_s->cpu_type == CPU_V20) || (cpu_s->cpu_type == CPU_V30);
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);
is6117 = !strcmp(cpu_f->manufacturer, "ALi");
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);
cpu_isintel = cpu_isintel || !strcmp(cpu_f->manufacturer, "AMD");
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 /* USE_DYNAREC */
x86_setopcodes_2386(ops_2386_386, ops_2386_386_0f);
x86_opcodes_REPE = ops_REPE;
x86_opcodes_REPNE = ops_REPNE;
x86_2386_opcodes_REPE = ops_2386_REPE;
x86_2386_opcodes_REPNE = ops_2386_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 /* USE_DYNAREC */
if (hasfpu) {
#ifdef USE_DYNAREC
if (fpu_softfloat) {
x86_dynarec_opcodes_d8_a16 = dynarec_ops_sf_fpu_d8_a16;
x86_dynarec_opcodes_d8_a32 = dynarec_ops_sf_fpu_d8_a32;
x86_dynarec_opcodes_d9_a16 = dynarec_ops_sf_fpu_d9_a16;
x86_dynarec_opcodes_d9_a32 = dynarec_ops_sf_fpu_d9_a32;
x86_dynarec_opcodes_da_a16 = dynarec_ops_sf_fpu_da_a16;
x86_dynarec_opcodes_da_a32 = dynarec_ops_sf_fpu_da_a32;
x86_dynarec_opcodes_db_a16 = dynarec_ops_sf_fpu_db_a16;
x86_dynarec_opcodes_db_a32 = dynarec_ops_sf_fpu_db_a32;
x86_dynarec_opcodes_dc_a16 = dynarec_ops_sf_fpu_dc_a16;
x86_dynarec_opcodes_dc_a32 = dynarec_ops_sf_fpu_dc_a32;
x86_dynarec_opcodes_dd_a16 = dynarec_ops_sf_fpu_dd_a16;
x86_dynarec_opcodes_dd_a32 = dynarec_ops_sf_fpu_dd_a32;
x86_dynarec_opcodes_de_a16 = dynarec_ops_sf_fpu_de_a16;
x86_dynarec_opcodes_de_a32 = dynarec_ops_sf_fpu_de_a32;
x86_dynarec_opcodes_df_a16 = dynarec_ops_sf_fpu_df_a16;
x86_dynarec_opcodes_df_a32 = dynarec_ops_sf_fpu_df_a32;
} else {
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 /* USE_DYNAREC */
if (fpu_softfloat) {
x86_opcodes_d8_a16 = ops_sf_fpu_d8_a16;
x86_opcodes_d8_a32 = ops_sf_fpu_d8_a32;
x86_opcodes_d9_a16 = ops_sf_fpu_d9_a16;
x86_opcodes_d9_a32 = ops_sf_fpu_d9_a32;
x86_opcodes_da_a16 = ops_sf_fpu_da_a16;
x86_opcodes_da_a32 = ops_sf_fpu_da_a32;
x86_opcodes_db_a16 = ops_sf_fpu_db_a16;
x86_opcodes_db_a32 = ops_sf_fpu_db_a32;
x86_opcodes_dc_a16 = ops_sf_fpu_dc_a16;
x86_opcodes_dc_a32 = ops_sf_fpu_dc_a32;
x86_opcodes_dd_a16 = ops_sf_fpu_dd_a16;
x86_opcodes_dd_a32 = ops_sf_fpu_dd_a32;
x86_opcodes_de_a16 = ops_sf_fpu_de_a16;
x86_opcodes_de_a32 = ops_sf_fpu_de_a32;
x86_opcodes_df_a16 = ops_sf_fpu_df_a16;
x86_opcodes_df_a32 = ops_sf_fpu_df_a32;
x86_2386_opcodes_d8_a16 = ops_2386_sf_fpu_d8_a16;
x86_2386_opcodes_d8_a32 = ops_2386_sf_fpu_d8_a32;
x86_2386_opcodes_d9_a16 = ops_2386_sf_fpu_d9_a16;
x86_2386_opcodes_d9_a32 = ops_2386_sf_fpu_d9_a32;
x86_2386_opcodes_da_a16 = ops_2386_sf_fpu_da_a16;
x86_2386_opcodes_da_a32 = ops_2386_sf_fpu_da_a32;
x86_2386_opcodes_db_a16 = ops_2386_sf_fpu_db_a16;
x86_2386_opcodes_db_a32 = ops_2386_sf_fpu_db_a32;
x86_2386_opcodes_dc_a16 = ops_2386_sf_fpu_dc_a16;
x86_2386_opcodes_dc_a32 = ops_2386_sf_fpu_dc_a32;
x86_2386_opcodes_dd_a16 = ops_2386_sf_fpu_dd_a16;
x86_2386_opcodes_dd_a32 = ops_2386_sf_fpu_dd_a32;
x86_2386_opcodes_de_a16 = ops_2386_sf_fpu_de_a16;
x86_2386_opcodes_de_a32 = ops_2386_sf_fpu_de_a32;
x86_2386_opcodes_df_a16 = ops_2386_sf_fpu_df_a16;
x86_2386_opcodes_df_a32 = ops_2386_sf_fpu_df_a32;
} else {
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;
x86_2386_opcodes_d8_a16 = ops_2386_fpu_d8_a16;
x86_2386_opcodes_d8_a32 = ops_2386_fpu_d8_a32;
x86_2386_opcodes_d9_a16 = ops_2386_fpu_d9_a16;
x86_2386_opcodes_d9_a32 = ops_2386_fpu_d9_a32;
x86_2386_opcodes_da_a16 = ops_2386_fpu_da_a16;
x86_2386_opcodes_da_a32 = ops_2386_fpu_da_a32;
x86_2386_opcodes_db_a16 = ops_2386_fpu_db_a16;
x86_2386_opcodes_db_a32 = ops_2386_fpu_db_a32;
x86_2386_opcodes_dc_a16 = ops_2386_fpu_dc_a16;
x86_2386_opcodes_dc_a32 = ops_2386_fpu_dc_a32;
x86_2386_opcodes_dd_a16 = ops_2386_fpu_dd_a16;
x86_2386_opcodes_dd_a32 = ops_2386_fpu_dd_a32;
x86_2386_opcodes_de_a16 = ops_2386_fpu_de_a16;
x86_2386_opcodes_de_a32 = ops_2386_fpu_de_a32;
x86_2386_opcodes_df_a16 = ops_2386_fpu_df_a16;
x86_2386_opcodes_df_a32 = ops_2386_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 /* USE_DYNAREC */
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;
x86_2386_opcodes_d8_a16 = ops_2386_nofpu_a16;
x86_2386_opcodes_d8_a32 = ops_2386_nofpu_a32;
x86_2386_opcodes_d9_a16 = ops_2386_nofpu_a16;
x86_2386_opcodes_d9_a32 = ops_2386_nofpu_a32;
x86_2386_opcodes_da_a16 = ops_2386_nofpu_a16;
x86_2386_opcodes_da_a32 = ops_2386_nofpu_a32;
x86_2386_opcodes_db_a16 = ops_2386_nofpu_a16;
x86_2386_opcodes_db_a32 = ops_2386_nofpu_a32;
x86_2386_opcodes_dc_a16 = ops_2386_nofpu_a16;
x86_2386_opcodes_dc_a32 = ops_2386_nofpu_a32;
x86_2386_opcodes_dd_a16 = ops_2386_nofpu_a16;
x86_2386_opcodes_dd_a32 = ops_2386_nofpu_a32;
x86_2386_opcodes_de_a16 = ops_2386_nofpu_a16;
x86_2386_opcodes_de_a32 = ops_2386_nofpu_a32;
x86_2386_opcodes_df_a16 = ops_2386_nofpu_a16;
x86_2386_opcodes_df_a32 = ops_2386_nofpu_a32;
}
#ifdef USE_DYNAREC
codegen_timing_set(&codegen_timing_486);
#endif /* USE_DYNAREC */
memset(&msr, 0, sizeof(msr));
timing_misaligned = 0;
cpu_cyrix_alignment = 0;
cpu_cpurst_on_sr = 0;
cpu_CR4_mask = 0;
switch (cpu_s->cpu_type) {
case CPU_8088:
case CPU_8086:
case CPU_8086_MAZOVIA:
break;
case CPU_V20:
case CPU_V30:
case CPU_186:
case CPU_188:
#ifdef USE_DYNAREC
x86_setopcodes(ops_186, ops_186_0f, dynarec_ops_186, dynarec_ops_186_0f);
#else
x86_setopcodes(ops_186, ops_186_0f);
#endif /* USE_DYNAREC */
x86_setopcodes_2386(ops_2386_186, ops_2386_186_0f);
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 /* USE_DYNAREC */
x86_setopcodes_2386(ops_2386_286, ops_2386_286_0f);
if (fpu_type == FPU_287) {
#ifdef USE_DYNAREC
if (fpu_softfloat) {
x86_dynarec_opcodes_d9_a16 = dynarec_ops_sf_fpu_287_d9_a16;
x86_dynarec_opcodes_d9_a32 = dynarec_ops_sf_fpu_287_d9_a32;
x86_dynarec_opcodes_da_a16 = dynarec_ops_sf_fpu_287_da_a16;
x86_dynarec_opcodes_da_a32 = dynarec_ops_sf_fpu_287_da_a32;
x86_dynarec_opcodes_db_a16 = dynarec_ops_sf_fpu_287_db_a16;
x86_dynarec_opcodes_db_a32 = dynarec_ops_sf_fpu_287_db_a32;
x86_dynarec_opcodes_dc_a16 = dynarec_ops_sf_fpu_287_dc_a16;
x86_dynarec_opcodes_dc_a32 = dynarec_ops_sf_fpu_287_dc_a32;
x86_dynarec_opcodes_dd_a16 = dynarec_ops_sf_fpu_287_dd_a16;
x86_dynarec_opcodes_dd_a32 = dynarec_ops_sf_fpu_287_dd_a32;
x86_dynarec_opcodes_de_a16 = dynarec_ops_sf_fpu_287_de_a16;
x86_dynarec_opcodes_de_a32 = dynarec_ops_sf_fpu_287_de_a32;
x86_dynarec_opcodes_df_a16 = dynarec_ops_sf_fpu_287_df_a16;
x86_dynarec_opcodes_df_a32 = dynarec_ops_sf_fpu_287_df_a32;
} else {
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 /* USE_DYNAREC */
if (fpu_softfloat) {
x86_opcodes_d9_a16 = ops_sf_fpu_287_d9_a16;
x86_opcodes_d9_a32 = ops_sf_fpu_287_d9_a32;
x86_opcodes_da_a16 = ops_sf_fpu_287_da_a16;
x86_opcodes_da_a32 = ops_sf_fpu_287_da_a32;
x86_opcodes_db_a16 = ops_sf_fpu_287_db_a16;
x86_opcodes_db_a32 = ops_sf_fpu_287_db_a32;
x86_opcodes_dc_a16 = ops_sf_fpu_287_dc_a16;
x86_opcodes_dc_a32 = ops_sf_fpu_287_dc_a32;
x86_opcodes_dd_a16 = ops_sf_fpu_287_dd_a16;
x86_opcodes_dd_a32 = ops_sf_fpu_287_dd_a32;
x86_opcodes_de_a16 = ops_sf_fpu_287_de_a16;
x86_opcodes_de_a32 = ops_sf_fpu_287_de_a32;
x86_opcodes_df_a16 = ops_sf_fpu_287_df_a16;
x86_opcodes_df_a32 = ops_sf_fpu_287_df_a32;
x86_2386_opcodes_d9_a16 = ops_2386_sf_fpu_287_d9_a16;
x86_2386_opcodes_d9_a32 = ops_2386_sf_fpu_287_d9_a32;
x86_2386_opcodes_da_a16 = ops_2386_sf_fpu_287_da_a16;
x86_2386_opcodes_da_a32 = ops_2386_sf_fpu_287_da_a32;
x86_2386_opcodes_db_a16 = ops_2386_sf_fpu_287_db_a16;
x86_2386_opcodes_db_a32 = ops_2386_sf_fpu_287_db_a32;
x86_2386_opcodes_dc_a16 = ops_2386_sf_fpu_287_dc_a16;
x86_2386_opcodes_dc_a32 = ops_2386_sf_fpu_287_dc_a32;
x86_2386_opcodes_dd_a16 = ops_2386_sf_fpu_287_dd_a16;
x86_2386_opcodes_dd_a32 = ops_2386_sf_fpu_287_dd_a32;
x86_2386_opcodes_de_a16 = ops_2386_sf_fpu_287_de_a16;
x86_2386_opcodes_de_a32 = ops_2386_sf_fpu_287_de_a32;
x86_2386_opcodes_df_a16 = ops_2386_sf_fpu_287_df_a16;
x86_2386_opcodes_df_a32 = ops_2386_sf_fpu_287_df_a32;
} else {
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;
x86_2386_opcodes_d9_a16 = ops_2386_fpu_287_d9_a16;
x86_2386_opcodes_d9_a32 = ops_2386_fpu_287_d9_a32;
x86_2386_opcodes_da_a16 = ops_2386_fpu_287_da_a16;
x86_2386_opcodes_da_a32 = ops_2386_fpu_287_da_a32;
x86_2386_opcodes_db_a16 = ops_2386_fpu_287_db_a16;
x86_2386_opcodes_db_a32 = ops_2386_fpu_287_db_a32;
x86_2386_opcodes_dc_a16 = ops_2386_fpu_287_dc_a16;
x86_2386_opcodes_dc_a32 = ops_2386_fpu_287_dc_a32;
x86_2386_opcodes_dd_a16 = ops_2386_fpu_287_dd_a16;
x86_2386_opcodes_dd_a32 = ops_2386_fpu_287_dd_a32;
x86_2386_opcodes_de_a16 = ops_2386_fpu_287_de_a16;
x86_2386_opcodes_de_a32 = ops_2386_fpu_287_de_a32;
x86_2386_opcodes_df_a16 = ops_2386_fpu_287_df_a16;
x86_2386_opcodes_df_a32 = ops_2386_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 /* USE_DYNAREC */
x86_setopcodes_2386(ops_2386_386, ops_2386_ibm486_0f);
cpu_features = CPU_FEATURE_MSR;
fallthrough;
case CPU_386SX:
case CPU_386DX:
/* In case we get Deskpro 386 emulation */
if (fpu_type == FPU_287) {
#ifdef USE_DYNAREC
if (fpu_softfloat) {
x86_dynarec_opcodes_d9_a16 = dynarec_ops_sf_fpu_287_d9_a16;
x86_dynarec_opcodes_d9_a32 = dynarec_ops_sf_fpu_287_d9_a32;
x86_dynarec_opcodes_da_a16 = dynarec_ops_sf_fpu_287_da_a16;
x86_dynarec_opcodes_da_a32 = dynarec_ops_sf_fpu_287_da_a32;
x86_dynarec_opcodes_db_a16 = dynarec_ops_sf_fpu_287_db_a16;
x86_dynarec_opcodes_db_a32 = dynarec_ops_sf_fpu_287_db_a32;
x86_dynarec_opcodes_dc_a16 = dynarec_ops_sf_fpu_287_dc_a16;
x86_dynarec_opcodes_dc_a32 = dynarec_ops_sf_fpu_287_dc_a32;
x86_dynarec_opcodes_dd_a16 = dynarec_ops_sf_fpu_287_dd_a16;
x86_dynarec_opcodes_dd_a32 = dynarec_ops_sf_fpu_287_dd_a32;
x86_dynarec_opcodes_de_a16 = dynarec_ops_sf_fpu_287_de_a16;
x86_dynarec_opcodes_de_a32 = dynarec_ops_sf_fpu_287_de_a32;
x86_dynarec_opcodes_df_a16 = dynarec_ops_sf_fpu_287_df_a16;
x86_dynarec_opcodes_df_a32 = dynarec_ops_sf_fpu_287_df_a32;
} else {
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 /* USE_DYNAREC */
if (fpu_softfloat) {
x86_opcodes_d9_a16 = ops_sf_fpu_287_d9_a16;
x86_opcodes_d9_a32 = ops_sf_fpu_287_d9_a32;
x86_opcodes_da_a16 = ops_sf_fpu_287_da_a16;
x86_opcodes_da_a32 = ops_sf_fpu_287_da_a32;
x86_opcodes_db_a16 = ops_sf_fpu_287_db_a16;
x86_opcodes_db_a32 = ops_sf_fpu_287_db_a32;
x86_opcodes_dc_a16 = ops_sf_fpu_287_dc_a16;
x86_opcodes_dc_a32 = ops_sf_fpu_287_dc_a32;
x86_opcodes_dd_a16 = ops_sf_fpu_287_dd_a16;
x86_opcodes_dd_a32 = ops_sf_fpu_287_dd_a32;
x86_opcodes_de_a16 = ops_sf_fpu_287_de_a16;
x86_opcodes_de_a32 = ops_sf_fpu_287_de_a32;
x86_opcodes_df_a16 = ops_sf_fpu_287_df_a16;
x86_opcodes_df_a32 = ops_sf_fpu_287_df_a32;
x86_2386_opcodes_d9_a16 = ops_2386_sf_fpu_287_d9_a16;
x86_2386_opcodes_d9_a32 = ops_2386_sf_fpu_287_d9_a32;
x86_2386_opcodes_da_a16 = ops_2386_sf_fpu_287_da_a16;
x86_2386_opcodes_da_a32 = ops_2386_sf_fpu_287_da_a32;
x86_2386_opcodes_db_a16 = ops_2386_sf_fpu_287_db_a16;
x86_2386_opcodes_db_a32 = ops_2386_sf_fpu_287_db_a32;
x86_2386_opcodes_dc_a16 = ops_2386_sf_fpu_287_dc_a16;
x86_2386_opcodes_dc_a32 = ops_2386_sf_fpu_287_dc_a32;
x86_2386_opcodes_dd_a16 = ops_2386_sf_fpu_287_dd_a16;
x86_2386_opcodes_dd_a32 = ops_2386_sf_fpu_287_dd_a32;
x86_2386_opcodes_de_a16 = ops_2386_sf_fpu_287_de_a16;
x86_2386_opcodes_de_a32 = ops_2386_sf_fpu_287_de_a32;
x86_2386_opcodes_df_a16 = ops_2386_sf_fpu_287_df_a16;
x86_2386_opcodes_df_a32 = ops_2386_sf_fpu_287_df_a32;
} else {
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;
x86_2386_opcodes_d9_a16 = ops_2386_fpu_287_d9_a16;
x86_2386_opcodes_d9_a32 = ops_2386_fpu_287_d9_a32;
x86_2386_opcodes_da_a16 = ops_2386_fpu_287_da_a16;
x86_2386_opcodes_da_a32 = ops_2386_fpu_287_da_a32;
x86_2386_opcodes_db_a16 = ops_2386_fpu_287_db_a16;
x86_2386_opcodes_db_a32 = ops_2386_fpu_287_db_a32;
x86_2386_opcodes_dc_a16 = ops_2386_fpu_287_dc_a16;
x86_2386_opcodes_dc_a32 = ops_2386_fpu_287_dc_a32;
x86_2386_opcodes_dd_a16 = ops_2386_fpu_287_dd_a16;
x86_2386_opcodes_dd_a32 = ops_2386_fpu_287_dd_a32;
x86_2386_opcodes_de_a16 = ops_2386_fpu_287_de_a16;
x86_2386_opcodes_de_a32 = ops_2386_fpu_287_de_a32;
x86_2386_opcodes_df_a16 = ops_2386_fpu_287_df_a16;
x86_2386_opcodes_df_a32 = ops_2386_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 /* USE_DYNAREC */
x86_setopcodes_2386(ops_2386_386, ops_2386_486_0f);
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 /* USE_DYNAREC */
x86_setopcodes_2386(ops_2386_386, ops_2386_486_0f);
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 /* USE_DYNAREC */
x86_setopcodes_2386(ops_2386_386, ops_2386_486_0f);
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 /* USE_DYNAREC */
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 /* USE_DYNAREC */
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 /* USE_DYNAREC */
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 /* USE_DYNAREC */
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 /* USE_DYNAREC */
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;
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 /* USE_DYNAREC */
break;
#ifdef 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
if (fpu_softfloat) {
x86_dynarec_opcodes_da_a16 = dynarec_ops_sf_fpu_686_da_a16;
x86_dynarec_opcodes_da_a32 = dynarec_ops_sf_fpu_686_da_a32;
x86_dynarec_opcodes_db_a16 = dynarec_ops_sf_fpu_686_db_a16;
x86_dynarec_opcodes_db_a32 = dynarec_ops_sf_fpu_686_db_a32;
x86_dynarec_opcodes_df_a16 = dynarec_ops_sf_fpu_686_df_a16;
x86_dynarec_opcodes_df_a32 = dynarec_ops_sf_fpu_686_df_a32;
} else {
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 /* USE_DYNAREC */
if (fpu_softfloat) {
x86_opcodes_da_a16 = ops_sf_fpu_686_da_a16;
x86_opcodes_da_a32 = ops_sf_fpu_686_da_a32;
x86_opcodes_db_a16 = ops_sf_fpu_686_db_a16;
x86_opcodes_db_a32 = ops_sf_fpu_686_db_a32;
x86_opcodes_df_a16 = ops_sf_fpu_686_df_a16;
x86_opcodes_df_a32 = ops_sf_fpu_686_df_a32;
} else {
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);
# if 0
x86_setopcodes(ops_386, ops_c6x86_0f, dynarec_ops_386, dynarec_ops_c6x86_0f);
# endif
# 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_c6x86mx_0f);
# if 0
x86_setopcodes(ops_386, ops_c6x86_0f);
# endif
# endif /* USE_DYNAREC */
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;
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 /* USE_DYNAREC */
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 /* USE_CYRIX_6X86 */
#ifdef USE_AMD_K5
case CPU_K5:
case CPU_5K86:
#ifdef USE_DYNAREC
x86_setopcodes(ops_386, ops_pentiummmx_0f, dynarec_ops_386, dynarec_ops_pentiummmx_0f);
#else
x86_setopcodes(ops_386, ops_pentiummmx_0f);
#endif /* USE_DYNAREC */
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;
cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PGE;
#ifdef USE_DYNAREC
codegen_timing_set(&codegen_timing_k5);
#endif /* USE_DYNAREC */
break;
#endif /* USE_AMD_K5 */
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);
else
x86_setopcodes(ops_386, ops_k6_0f, dynarec_ops_386, dynarec_ops_k6_0f);
#else
if (cpu_s->cpu_type >= CPU_K6_2)
x86_setopcodes(ops_386, ops_k62_0f);
else
x86_setopcodes(ops_386, ops_k6_0f);
#endif /* USE_DYNAREC */
if ((cpu_s->cpu_type == CPU_K6_2P) || (cpu_s->cpu_type == CPU_K6_3P)) {
x86_opcodes_3DNOW = ops_3DNOWE;
#ifdef USE_DYNAREC
x86_dynarec_opcodes_3DNOW = dynarec_ops_3DNOWE;
#endif /* USE_DYNAREC */
}
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;
if ((cpu_s->cpu_type == CPU_K6_2P) || (cpu_s->cpu_type == CPU_K6_3P))
cpu_features |= CPU_FEATURE_3DNOWE;
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;
else if (cpu_s->cpu_type >= CPU_K6_2C)
cpu_CR4_mask |= CR4_PGE;
#ifdef USE_DYNAREC
codegen_timing_set(&codegen_timing_k6);
#endif /* USE_DYNAREC */
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);
if (fpu_softfloat) {
x86_dynarec_opcodes_da_a16 = dynarec_ops_sf_fpu_686_da_a16;
x86_dynarec_opcodes_da_a32 = dynarec_ops_sf_fpu_686_da_a32;
x86_dynarec_opcodes_db_a16 = dynarec_ops_sf_fpu_686_db_a16;
x86_dynarec_opcodes_db_a32 = dynarec_ops_sf_fpu_686_db_a32;
x86_dynarec_opcodes_df_a16 = dynarec_ops_sf_fpu_686_df_a16;
x86_dynarec_opcodes_df_a32 = dynarec_ops_sf_fpu_686_df_a32;
} else {
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 /* USE_DYNAREC */
if (fpu_softfloat) {
x86_opcodes_da_a16 = ops_sf_fpu_686_da_a16;
x86_opcodes_da_a32 = ops_sf_fpu_686_da_a32;
x86_opcodes_db_a16 = ops_sf_fpu_686_db_a16;
x86_opcodes_db_a32 = ops_sf_fpu_686_db_a32;
x86_opcodes_df_a16 = ops_sf_fpu_686_df_a16;
x86_opcodes_df_a32 = ops_sf_fpu_686_df_a32;
} else {
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;
cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PAE | CR4_PCE | CR4_PGE;
if (cpu_s->cpu_type == CPU_PENTIUM2D) {
cpu_CR4_mask |= CR4_OSFXSR;
cpu_features |= CPU_FEATURE_PSE36;
}
#ifdef USE_DYNAREC
codegen_timing_set(&codegen_timing_p6);
#endif /* USE_DYNAREC */
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 /* USE_DYNAREC */
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 << 7) | (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 | CR4_PGE;
cpu_cyrix_alignment = 1;
#ifdef USE_DYNAREC
codegen_timing_set(&codegen_timing_winchip);
#endif /* USE_DYNAREC */
break;
default:
fatal("cpu_set : unknown CPU type %" PRIu64 "\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;
}
cpu_use_exec = 0;
if (is386) {
#if defined(USE_DYNAREC) && !defined(USE_GDBSTUB)
if (cpu_use_dynarec) {
cpu_exec = exec386_dynarec;
cpu_use_exec = 1;
} else
#endif /* defined(USE_DYNAREC) && !defined(USE_GDBSTUB) */
/* Use exec386 for CPU_IBM486SLC because it can reach 100 MHz. */
if ((cpu_s->cpu_type == CPU_IBM486SLC) || (cpu_s->cpu_type == CPU_IBM486BL) ||
cpu_iscyrix || (cpu_s->cpu_type > CPU_486DLC) || cpu_override_interpreter) {
cpu_exec = exec386;
cpu_use_exec = 1;
} else
cpu_exec = exec386_2386;
} else if (cpu_s->cpu_type >= CPU_286)
cpu_exec = exec386_2386;
else
cpu_exec = execx86;
mmx_init();
gdbstub_cpu_init();
}
void
cpu_close(void)
{
cpu_inited = 0;
}
void
cpu_set_isa_speed(int speed)
{
if (speed) {
cpu_isa_speed = speed;
} else if (cpu_busspeed >= 8000000)
cpu_isa_speed = 8000000;
else
cpu_isa_speed = cpu_busspeed;
pc_speed_changed();
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; /* GenuineIntel */
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; /* GenuineIntel */
EDX = 0x49656e69;
ECX = 0x6c65746e;
} else if (EAX == 1) {
if ((CPUID == 0x0436) && (cr0 & (1 << 29)))
EAX = 0x0470;
else
EAX = CPUID;
EBX = ECX = 0;
EDX = CPUID_FPU | CPUID_VME;
} else
EAX = EBX = ECX = EDX = 0;
break;
case CPU_ENH_Am486DX:
if (!EAX) {
EAX = 0x00000001;
EBX = 0x68747541;/* AuthenticAMD */
ECX = 0x444D4163;
EDX = 0x69746E65;
} else if (EAX == 1) {
EAX = CPUID;
EBX = ECX = 0;
EDX = CPUID_FPU;
} else
EAX = EBX = ECX = EDX = 0;
break;
case CPU_WINCHIP:
if (!EAX) {
EAX = 0x00000001;
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 = ((msr.fcr2 & 0x0ff0) ? ((msr.fcr2 & 0x0ff0) | (CPUID & 0xf00f)) : CPUID);
EBX = ECX = 0;
EDX = CPUID_FPU | CPUID_DE | 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 = 0x00000001;
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 = ((msr.fcr2 & 0x0ff0) ? ((msr.fcr2 & 0x0ff0) | (CPUID & 0xf00f)) : CPUID);
EBX = ECX = 0;
EDX = CPUID_FPU | CPUID_DE | 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_DE | 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; /* GenuineIntel */
EDX = 0x49656e69;
ECX = 0x6c65746e;
} else if (EAX == 1) {
EAX = CPUID;
EBX = ECX = 0;
EDX = CPUID_FPU | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B;
if (cpu_s->cpu_type != CPU_P24T)
EDX |= CPUID_MCE;
} else
EAX = EBX = ECX = EDX = 0;
break;
#ifdef USE_AMD_K5
case CPU_K5:
if (!EAX) {
EAX = 0x00000001;
EBX = 0x68747541; /* AuthenticAMD */
EDX = 0x69746E65;
ECX = 0x444D4163;
} else if (EAX == 1) {
EAX = CPUID;
EBX = ECX = 0;
EDX = CPUID_FPU | CPUID_DE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_AMDPGE;
} else
EAX = EBX = ECX = EDX = 0;
break;
case CPU_5K86:
switch (EAX) {
case 0:
EAX = 0x00000001;
EBX = 0x68747541; /* AuthenticAMD */
EDX = 0x69746E65;
ECX = 0x444D4163;
break;
case 1:
EAX = CPUID;
EBX = ECX = 0;
EDX = CPUID_FPU | CPUID_DE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_PGE;
break;
case 0x80000000:
EAX = 0x80000005;
EBX = ECX = EDX = 0;
break;
case 0x80000001:
EAX = CPUID;
EBX = ECX = 0;
EDX = CPUID_FPU | CPUID_DE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_PGE;
break;
case 0x80000002: /* Processor name string */
EAX = 0x2D444D41; /* AMD-K5(tm) Proce */
EBX = 0x7428354B;
ECX = 0x5020296D;
EDX = 0x65636F72;
break;
case 0x80000003: /* Processor name string */
EAX = 0x726F7373; /* ssor */
EBX = ECX = EDX = 0;
break;
case 0x80000005: /* Cache information */
EAX = 0;
EBX = 0x04800000; /* TLBs */
ECX = 0x08040120; /* L1 data cache */
EDX = 0x10040120; /* L1 instruction cache */
break;
default:
EAX = EBX = ECX = EDX = 0;
break;
}
break;
#endif /* USE_AMD_K5 */
case CPU_K6:
switch (EAX) {
case 0:
EAX = 0x00000001;
EBX = 0x68747541; /* AuthenticAMD */
EDX = 0x69746E65;
ECX = 0x444D4163;
break;
case 1:
EAX = CPUID;
EBX = ECX = 0;
EDX = CPUID_FPU | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_MMX;
break;
case 0x80000000:
EAX = 0x80000005;
EBX = ECX = EDX = 0;
break;
case 0x80000001:
EAX = CPUID + 0x100;
EBX = ECX = 0;
EDX = CPUID_FPU | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_AMDSEP | CPUID_MMX;
break;
case 0x80000002: /* Processor name string */
EAX = 0x2D444D41; /* AMD-K6tm w/ mult */
EBX = 0x6D74364B;
ECX = 0x202F7720;
EDX = 0x746C756D;
break;
case 0x80000003: /* Processor name string */
EAX = 0x64656D69; /* imedia extension */
EBX = 0x65206169;
ECX = 0x6E657478;
EDX = 0x6E6F6973;
break;
case 0x80000004: /* Processor name string */
EAX = 0x73; /* s */
EBX = ECX = EDX = 0;
break;
case 0x80000005: /* Cache information */
EAX = 0;
EBX = 0x02800140; /* TLBs */
ECX = 0x20020220; /* L1 data cache */
EDX = 0x20020220; /* L1 instruction cache */
break;
case 0x8FFFFFFF: /* Easter egg */
EAX = 0x4778654E; /* NexGenerationAMD */
EBX = 0x72656E65;
ECX = 0x6F697461;
EDX = 0x444D416E;
break;
default:
EAX = EBX = ECX = EDX = 0;
break;
}
break;
case CPU_K6_2:
case CPU_K6_2C:
switch (EAX) {
case 0:
EAX = 0x00000001;
EBX = 0x68747541; /* AuthenticAMD */
ECX = 0x444d4163;
EDX = 0x69746e65;
break;
case 1:
EAX = CPUID;
EBX = ECX = 0;
EDX = CPUID_FPU | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_MMX;
if (cpu_s->cpu_type == CPU_K6_2C)
EDX |= CPUID_PGE;
break;
case 0x80000000:
EAX = 0x80000005;
EBX = ECX = EDX = 0;
break;
case 0x80000001:
EAX = CPUID + 0x100;
EBX = ECX = 0;
EDX = CPUID_FPU | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_SEP | CPUID_MMX | CPUID_3DNOW;
if (cpu_s->cpu_type == CPU_K6_2C)
EDX |= CPUID_PGE;
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 */
EAX = 0;
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 = 0x00000001;
EBX = 0x68747541; /* AuthenticAMD */
ECX = 0x444d4163;
EDX = 0x69746e65;
break;
case 1:
EAX = CPUID;
EBX = ECX = 0;
EDX = CPUID_FPU | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_PGE | CPUID_MMX;
break;
case 0x80000000:
EAX = 0x80000006;
EBX = ECX = EDX = 0;
break;
case 0x80000001:
EAX = CPUID + 0x100;
EBX = ECX = 0;
EDX = CPUID_FPU | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_SEP | CPUID_PGE | 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 */
EAX = 0;
EBX = 0x02800140; /* TLBs */
ECX = 0x20020220; /* L1 data cache */
EDX = 0x20020220; /* L1 instruction cache */
break;
case 0x80000006: /* L2 Cache information */
EAX = EBX = EDX = 0;
ECX = 0x01004220;
break;
default:
EAX = EBX = ECX = EDX = 0;
break;
}
break;
case CPU_K6_2P:
case CPU_K6_3P:
switch (EAX) {
case 0:
EAX = 0x00000001;
EBX = 0x68747541; /* AuthenticAMD */
ECX = 0x444d4163;
EDX = 0x69746e65;
break;
case 1:
EAX = CPUID;
EBX = ECX = 0;
EDX = CPUID_FPU | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_PGE | CPUID_MMX;
break;
case 0x80000000:
EAX = 0x80000007;
EBX = ECX = EDX = 0;
break;
case 0x80000001:
EAX = CPUID + 0x100;
EBX = ECX = 0;
EDX = CPUID_FPU | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_SEP | CPUID_MMX | CPUID_PGE | CPUID_3DNOW | CPUID_3DNOWE;
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 */
EAX = 0;
EBX = 0x02800140; /* TLBs */
ECX = 0x20020220; /* L1 data cache */
EDX = 0x20020220; /* L1 instruction cache */
break;
case 0x80000006: /* L2 Cache information */
EAX = EBX = EDX = 0;
if (cpu_s->cpu_type == CPU_K6_3P)
ECX = 0x01004220;
else
ECX = 0x00804220;
break;
case 0x80000007: /* PowerNow information */
EAX = EBX = ECX = 0;
EDX = 7;
break;
default:
EAX = EBX = ECX = EDX = 0;
break;
}
break;
case CPU_PENTIUMMMX:
if (!EAX) {
EAX = 0x00000001;
EBX = 0x756e6547; /* GenuineIntel */
EDX = 0x49656e69;
ECX = 0x6c65746e;
} else if (EAX == 1) {
EAX = CPUID;
EBX = ECX = 0;
EDX = CPUID_FPU | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_MMX;
} else
EAX = EBX = ECX = EDX = 0;
break;
#ifdef USE_CYRIX_6X86
case CPU_Cx6x86:
if (!EAX) {
EAX = 0x00000001;
EBX = 0x69727943; /* CyrixInstead */
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; /* CyrixInstead */
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; /* CyrixInstead */
EDX = 0x736e4978;
ECX = 0x64616574;
} else if (EAX == 1) {
EAX = CPUID;
EBX = ECX = 0;
EDX = CPUID_FPU | CPUID_DE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B;
} else
EAX = EBX = ECX = EDX = 0;
break;
case CPU_Cx6x86MX:
if (!EAX) {
EAX = 0x00000001;
EBX = 0x69727943; /* CyrixInstead */
EDX = 0x736e4978;
ECX = 0x64616574;
} else if (EAX == 1) {
EAX = CPUID;
EBX = ECX = 0;
EDX = CPUID_FPU | CPUID_DE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_CMOV | CPUID_MMX;
/*
Return anything non-zero in bits 32-63 of the BIOS signature MSR
to indicate there has been an update.
*/
msr.bbl_cr_dx[3] = 0xffffffff00000000ULL;
} else
EAX = EBX = ECX = EDX = 0;
break;
#endif /* USE_CYRIX_6X86 */
case CPU_PENTIUMPRO:
if (!EAX) {
EAX = 0x00000002;
EBX = 0x756e6547; /* GenuineIntel */
EDX = 0x49656e69;
ECX = 0x6c65746e;
} else if (EAX == 1) {
EAX = CPUID;
EBX = ECX = 0;
EDX = CPUID_FPU | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_SEP | CPUID_CMOV;
} else if (EAX == 2) {
EAX = 0x03020101; /* Instruction TLB: 4 KB pages, 4-way set associative, 32 entries
Instruction TLB: 4 MB pages, fully associative, 2 entries
Data TLB: 4 KB pages, 4-way set associative, 64 entries */
EBX = ECX = 0;
EDX = 0x06040a42; /* 2nd-level cache: 256 KB, 4-way set associative, 32-byte line size
1st-level data cache: 8 KB, 2-way set associative, 32-byte line size
Data TLB: 4 MB pages, 4-way set associative, 8 entries
1st-level instruction cache: 8 KB, 4-way set associative, 32-byte line size */
} else
EAX = EBX = ECX = EDX = 0;
break;
case CPU_PENTIUM2:
if (!EAX) {
EAX = 0x00000002;
EBX = 0x756e6547; /* GenuineIntel */
EDX = 0x49656e69;
ECX = 0x6c65746e;
} else if (EAX == 1) {
EAX = CPUID;
EBX = ECX = 0;
EDX = CPUID_FPU | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_SEP | CPUID_CMOV;
/*
Return anything non-zero in bits 32-63 of the BIOS signature MSR
to indicate there has been an update.
*/
msr.bbl_cr_dx[3] = 0xffffffff00000000ULL;
} else if (EAX == 2) {
EAX = 0x03020101; /* Instruction TLB: 4 KB pages, 4-way set associative, 32 entries
Instruction TLB: 4 MB pages, fully associative, 2 entries
Data TLB: 4 KB pages, 4-way set associative, 64 entries */
EBX = ECX = 0;
EDX = 0x0c040843; /* 2nd-level cache: 512 KB, 4-way set associative, 32-byte line size
1st-level data cache: 16 KB, 4-way set associative, 32-byte line size
Data TLB: 4 MB pages, 4-way set associative, 8 entries
1st-level instruction cache: 16 KB, 4-way set associative, 32-byte line size */
} else
EAX = EBX = ECX = EDX = 0;
break;
case CPU_PENTIUM2D:
if (!EAX) {
EAX = 0x00000002;
EBX = 0x756e6547; /* GenuineIntel */
EDX = 0x49656e69;
ECX = 0x6c65746e;
} else if (EAX == 1) {
EAX = CPUID;
EBX = ECX = 0;
EDX = CPUID_FPU | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_SEP | CPUID_FXSR | CPUID_CMOV | CPUID_PSE36;
/*
Return anything non-zero in bits 32-63 of the BIOS signature MSR
to indicate there has been an update.
*/
msr.bbl_cr_dx[3] = 0xffffffff00000000ULL;
} else if (EAX == 2) {
EAX = 0x03020101; /* Instruction TLB: 4 KB pages, 4-way set associative, 32 entries
Instruction TLB: 4 MB pages, fully associative, 2 entries
Data TLB: 4 KB pages, 4-way set associative, 64 entries */
EBX = ECX = 0;
if (cpu_f->package == CPU_PKG_SLOT2) /* Pentium II Xeon Drake */
EDX = 0x0c040844; /* 2nd-level cache: 1 MB, 4-way set associative, 32-byte line size
1st-level data cache: 16 KB, 4-way set associative, 32-byte line size
Data TLB: 4 MB pages, 4-way set associative, 8 entries
1st-level instruction cache: 16 KB, 4-way set associative, 32-byte line size */
else if (!strncmp(cpu_f->internal_name, "celeron", 7)) { /* Celeron */
if (CPUID >= 0x660) /* Mendocino */
EDX = 0x0c040841; /* 2nd-level cache: 128 KB, 4-way set associative, 32-byte line size */
else /* Covington */
EDX = 0x0c040840; /* No 2nd-level cache */
} else /* Pentium II Deschutes and OverDrive */
EDX = 0x0c040843; /* 2nd-level cache: 512 KB, 4-way set associative, 32-byte line size */
} else
EAX = EBX = ECX = EDX = 0;
break;
case CPU_CYRIX3S:
switch (EAX) {
case 0:
EAX = 0x00000001;
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 = ((msr.fcr2 & 0x0ff0) ? ((msr.fcr2 & 0x0ff0) | (CPUID & 0xf00f)) : CPUID);
EBX = ECX = 0;
EDX = CPUID_FPU | CPUID_DE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_MMX | CPUID_MTRR;
if (cpu_has_feature(CPU_FEATURE_CX8))
EDX |= CPUID_CMPXCHG8B;
if (msr.fcr & (1 << 7))
EDX |= CPUID_PGE;
break;
case 0x80000000:
EAX = 0x80000005;
break;
case 0x80000001:
EAX = CPUID;
EDX = CPUID_FPU | CPUID_DE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_MMX | CPUID_MTRR | CPUID_3DNOW;
if (cpu_has_feature(CPU_FEATURE_CX8))
EDX |= CPUID_CMPXCHG8B;
if (msr.fcr & (1 << 7))
EDX |= CPUID_PGE;
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_WINCHIP:
case CPU_WINCHIP2:
msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21);
msr.mcr_ctrl = 0xf8000000;
if (cpu_s->cpu_type == CPU_WINCHIP2) {
msr.fcr |= (1 << 18) | (1 << 20);
msr.mcr_ctrl |= (1 << 17);
}
break;
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:
#ifdef USE_AMD_K5
case CPU_K5:
case CPU_5K86:
#endif /* USE_AMD_K5 */
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;
break;
case CPU_CYRIX3S:
msr.fcr = (1 << 7) | (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 18) | (1 << 19) |
(1 << 20) | (1 << 21);
break;
}
}
void
cpu_RDMSR(void)
{
if ((CPL || (cpu_state.eflags & VM_FLAG)) && (cr0 & 1))
x86gpf(NULL, 0);
else switch (cpu_s->cpu_type) {
case CPU_IBM386SLC:
case CPU_IBM486SLC:
case CPU_IBM486BL:
EAX = EDX = 0;
switch (ECX) {
/* Processor Operation Register */
case 0x1000:
EAX = msr.ibm_por & ((cpu_s->cpu_type > CPU_IBM386SLC) ? 0xffeff : 0xfeff);
break;
/* Cache Region Control Register */
case 0x1001:
EAX = msr.ibm_crcr & 0xffffffff;
EDX = (msr.ibm_crcr >> 32) & 0x0000ffff;
break;
/* Processor Operation Register */
case 0x1002:
if ((cpu_s->cpu_type > CPU_IBM386SLC) && cpu_s->multi)
EAX = msr.ibm_por2 & 0x3f000000;
break;
/* Processor Control Register */
case 0x1004:
if (cpu_s->cpu_type > CPU_IBM486SLC)
EAX = msr.ibm_pcr & 0x00d6001a;
break;
}
break;
case CPU_WINCHIP:
case CPU_WINCHIP2:
EAX = EDX = 0;
switch (ECX) {
/* Pentium Processor Parity Reversal Register */
case 0x02:
EAX = msr.tr1;
break;
/* Pentium Processor New Feature Control */
case 0x0e:
EAX = msr.tr12;
break;
/* Time Stamp Counter */
case 0x10:
EAX = tsc & 0xffffffff;
EDX = tsc >> 32;
break;
/* Performance Monitor - Control and Event Select */
case 0x11:
EAX = msr.cesr;
break;
/* Performance Monitor - Event Counter 0 */
case 0x12:
EAX = msr.pmc[0] & 0xffffffff;
EDX = msr.pmc[0] >> 32;
break;
/* Performance Monitor - Event Counter 1 */
case 0x13:
EAX = msr.pmc[1] & 0xffffffff;
EDX = msr.pmc[1] >> 32;
break;
/* Feature Control Register */
case 0x107:
EAX = msr.fcr;
break;
/* Feature Control Register 2 */
case 0x108:
EAX = msr.fcr2 & 0xffffffff;
EDX = msr.fcr2 >> 32;
break;
/* Feature Control Register 4 */
case 0x10a:
EAX = cpu_multi & 3;
break;
/* Memory Configuration Register Control */
case 0x120:
EAX = msr.mcr_ctrl;
break;
/* Unknown */
case 0x131:
case 0x142 ... 0x145:
case 0x147:
case 0x150:
case 0x151:
break;
}
break;
case CPU_CYRIX3S:
EAX = EDX = 0;
switch (ECX) {
/* Machine Check Exception Address */
case 0x00:
/* Machine Check Exception Type */
case 0x01:
break;
/* Time Stamp Counter */
case 0x10:
EAX = tsc & 0xffffffff;
EDX = tsc >> 32;
break;
/* EBL_CR_POWERON - Processor Hard Power-On Configuration */
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;
/* PERFCTR0 - Performance Counter Register 0 - aliased to TSC */
case 0xc1:
EAX = tsc & 0xffffffff;
EDX = (tsc >> 32) & 0xff;
break;
/* PERFCTR1 - Performance Counter Register 1 */
case 0xc2:
EAX = msr.perfctr[1] & 0xffffffff;
EDX = msr.perfctr[1] >> 32;
break;
/* BBL_CR_CTL3 - L2 Cache Control Register 3 */
case 0x11e:
EAX = 0x800000; /* L2 cache disabled */
break;
/* EVNTSEL0 - Performance Counter Event Select 0 - hardcoded */
case 0x186:
EAX = 0x470079;
break;
/* EVNTSEL1 - Performance Counter Event Select 1 */
case 0x187:
EAX = msr.evntsel[1] & 0xffffffff;
EDX = msr.evntsel[1] >> 32;
break;
/* Feature Control Register */
case 0x1107:
EAX = msr.fcr;
break;
/* Feature Control Register 2 */
case 0x1108:
EAX = msr.fcr2 & 0xffffffff;
EDX = msr.fcr2 >> 32;
break;
/* ECX & 0: MTRRphysBase0 ... MTRRphysBase7
ECX & 1: MTRRphysMask0 ... MTRRphysMask7 */
case 0x200 ... 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;
/* MTRRfix64K_00000 */
case 0x250:
EAX = msr.mtrr_fix64k_8000 & 0xffffffff;
EDX = msr.mtrr_fix64k_8000 >> 32;
break;
/* MTRRfix16K_80000 */
case 0x258:
EAX = msr.mtrr_fix16k_8000 & 0xffffffff;
EDX = msr.mtrr_fix16k_8000 >> 32;
break;
/* MTRRfix16K_A0000 */
case 0x259:
EAX = msr.mtrr_fix16k_a000 & 0xffffffff;
EDX = msr.mtrr_fix16k_a000 >> 32;
break;
/* MTRRfix4K_C0000 ... MTRRfix4K_F8000 */
case 0x268 ... 0x26f:
EAX = msr.mtrr_fix4k[ECX - 0x268] & 0xffffffff;
EDX = msr.mtrr_fix4k[ECX - 0x268] >> 32;
break;
/* MTRRdefType */
case 0x2ff:
EAX = msr.mtrr_deftype & 0xffffffff;
EDX = msr.mtrr_deftype >> 32;
break;
}
break;
#ifdef USE_AMD_K5
case CPU_K5:
case CPU_5K86:
#endif /* USE_AMD_K5 */
case CPU_K6:
case CPU_K6_2:
case CPU_K6_2C:
case CPU_K6_3:
case CPU_K6_2P:
case CPU_K6_3P:
EAX = 0;
/* EDX is left unchanged when reading this MSR! */
if (ECX != 0x82)
EDX = 0;
switch (ECX) {
/* Machine Check Address Register */
case 0x00000000:
EAX = msr.mcar & 0xffffffff;
EDX = msr.mcar >> 32;
break;
/* Machine Check Type Register */
case 0x00000001:
EAX = msr.mctr & 0xffffffff;
EDX = msr.mctr >> 32;
break;
/* Test Register 12 */
case 0x0000000e:
EAX = msr.tr12;
break;
/* Time Stamp Counter */
case 0x00000010:
EAX = tsc & 0xffffffff;
EDX = tsc >> 32;
break;
/* Array Access Register */
case 0x00000082:
if (cpu_s->cpu_type > CPU_5K86)
goto amd_k_invalid_rdmsr;
EAX = msr.amd_aar & 0xffffffff;
/* EDX is left unchanged! */
break;
/* Hardware Configuration Register */
case 0x00000083:
EAX = msr.amd_hwcr & 0xffffffff;
EDX = msr.amd_hwcr >> 32;
break;
/* Write Allocate Top-of-Memory and Control Register */
case 0x00000085:
if (cpu_s->cpu_type != CPU_5K86)
goto amd_k_invalid_rdmsr;
EAX = msr.amd_watmcr & 0xffffffff;
EDX = msr.amd_watmcr >> 32;
break;
/* Write Allocate Programmable Memory Range Register */
case 0x00000086:
if (cpu_s->cpu_type != CPU_5K86)
goto amd_k_invalid_rdmsr;
EAX = msr.amd_wapmrr & 0xffffffff;
EDX = msr.amd_wapmrr >> 32;
break;
/* Extended Feature Enable Register */
case 0xc0000080:
EAX = msr.amd_efer & 0xffffffff;
EDX = msr.amd_efer >> 32;
break;
/* SYSCALL Target Address Register */
case 0xc0000081:
if (cpu_s->cpu_type < CPU_K6_2)
goto amd_k_invalid_rdmsr;
EAX = msr.amd_star & 0xffffffff;
EDX = msr.amd_star >> 32;
break;
/* Write-Handling Control Register */
case 0xc0000082:
EAX = msr.amd_whcr & 0xffffffff;
EDX = msr.amd_whcr >> 32;
break;
/* UC/WC Cacheability Control Register */
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;
/* Enhanced Power Management Register */
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;
/* Processor State Observability Register */
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;
/* Page Flush/Invalidate Register */
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;
/* Level-2 Cache Array Access Register */
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:
EAX = EDX = 0;
/* Filter out the upper 27 bits when ECX value is over 0x80000000, as per:
Ralf Brown, Pentium Model-Specific Registers and What They Reveal.
https://www.cs.cmu.edu/~ralf/papers/highmsr.html
But leave the bit 31 intact to be able to handle both low and high
MSRs in a single switch block. */
switch (ECX & (ECX > 0x7fffffff ? 0x8000001f : 0x7fffffff)) {
/* Machine Check Exception Address */
case 0x00000000:
case 0x80000000:
EAX = msr.mcar & 0xffffffff;
EDX = msr.mcar >> 32;
break;
/* Machine Check Exception Type */
case 0x00000001:
case 0x80000001:
EAX = msr.mctr & 0xffffffff;
EDX = msr.mctr >> 32;
msr.mctr &= ~0x1; /* clear the machine check pending bit */
break;
/* TR1 - Parity Reversal Test Register */
case 0x00000002:
case 0x80000002:
EAX = msr.tr1;
break;
/* TR2 - Instruction Cache End Bit */
case 0x00000004:
case 0x80000004:
if (cpu_s->cpu_type == CPU_PENTIUMMMX)
goto pentium_invalid_rdmsr;
EAX = msr.tr2;
break;
/* TR3 - Cache Test Data */
case 0x00000005:
case 0x80000005:
EAX = msr.tr3;
break;
/* TR4 - Cache Test Tag */
case 0x00000006:
case 0x80000006:
EAX = msr.tr4;
break;
/* TR5 - Cache Test Control */
case 0x00000007:
case 0x80000007:
EAX = msr.tr5;
break;
/* TR6 - TLB Test Command */
case 0x00000008:
case 0x80000008:
EAX = msr.tr6;
break;
/* TR7 - TLB Test Data */
case 0x00000009:
case 0x80000009:
EAX = msr.tr7;
break;
/* TR9 - Branch Target Buffer Tag */
case 0x0000000b:
case 0x8000000b:
EAX = msr.tr9;
break;
/* TR10 - Branch Target Buffer Target */
case 0x0000000c:
case 0x8000000c:
EAX = msr.tr10;
break;
/* TR11 - Branch Target Buffer Control */
case 0x0000000d:
case 0x8000000d:
EAX = msr.tr11;
break;
/* TR12 - New Feature Control */
case 0x0000000e:
case 0x8000000e:
EAX = msr.tr12;
break;
/* Time Stamp Counter */
case 0x00000010:
case 0x80000010:
EAX = tsc & 0xffffffff;
EDX = tsc >> 32;
break;
/* Performance Monitor - Control and Event Select */
case 0x00000011:
case 0x80000011:
EAX = msr.cesr;
break;
/* Performance Monitor - Event Counter 0 */
case 0x00000012:
case 0x80000012:
EAX = msr.pmc[0] & 0xffffffff;
EDX = msr.pmc[0] >> 32;
break;
/* Performance Monitor - Event Counter 1 */
case 0x00000013:
case 0x80000013:
EAX = msr.pmc[1] & 0xffffffff;
EDX = msr.pmc[1] >> 32;
break;
/* Unknown */
case 0x00000014:
case 0x80000014:
if ((CPUID & 0xfff) <= 0x520)
goto pentium_invalid_rdmsr;
break;
/* Unknown, possibly paging-related; initial value is 0004h,
becomes 0008h once paging is enabled */
case 0x80000018:
EAX = ((cr0 & (1 << 31)) ? 0x00000008 : 0x00000004);
break;
/* Floating point - last prefetched opcode
bits 10-8: low three bits of first byte of FP instruction
bits 7-0: second byte of floating-point instruction */
case 0x80000019:
EAX = 0;
break;
/* Floating point - last executed non-control opcode */
case 0x8000001a:
EAX = 0;
break;
/* Floating point - last non-control exception opcode - part
of FSTENV/FSAVE'd environment */
case 0x8000001b:
EAX = msr.fp_last_xcpt;
break;
/* Unknown */
case 0x8000001c:
EAX = 0x00000004;
break;
/* Probe Mode Control */
case 0x8000001d:
EAX = msr.probe_ctl;
break;
/* Unknown, possibly scratchpad register */
case 0x8000001e:
EAX = msr.ecx8000001e;
break;
/* Unknown, possibly scratchpad register */
case 0x8000001f:
EAX = msr.ecx8000001f;
break;
/* Reserved/Unimplemented */
case 0x80000003:
case 0x8000000a:
case 0x8000000f:
case 0x80000015 ... 0x80000017:
EAX = (ECX & 0x1f) * 2;
break;
default:
pentium_invalid_rdmsr:
cpu_log("RDMSR: Invalid MSR: %08X\n", ECX);
x86gpf(NULL, 0);
break;
}
cpu_log("RDMSR: ECX = %08X, val = %08X%08X\n", ECX, EDX, EAX);
break;
#ifdef USE_CYRIX_6X86
case CPU_Cx6x86:
case CPU_Cx6x86L:
case CPU_CxGX1:
case CPU_Cx6x86MX:
switch (ECX) {
/* Test Data */
case 0x03:
EAX = msr.tr3;
break;
/* Test Address */
case 0x04:
EAX = msr.tr4;
break;
/* Test Command/Status */
case 0x05:
EAX = msr.tr5;
break;
/* Time Stamp Counter */
case 0x10:
EAX = tsc & 0xffffffff;
EDX = tsc >> 32;
break;
/* Performance Monitor - Control and Event Select */
case 0x11:
EAX = msr.cesr;
break;
/* Performance Monitor - Event Counter 0 */
case 0x12:
EAX = msr.pmc[0] & 0xffffffff;
EDX = msr.pmc[0] >> 32;
break;
/* Performance Monitor - Event Counter 1 */
case 0x13:
EAX = msr.pmc[1] & 0xffffffff;
EDX = msr.pmc[1] >> 32;
break;
}
cpu_log("RDMSR: ECX = %08X, val = %08X%08X\n", ECX, EDX, EAX);
break;
#endif /* USE_CYRIX_6X86 */
case CPU_PENTIUMPRO:
case CPU_PENTIUM2:
case CPU_PENTIUM2D:
EAX = EDX = 0;
/* Per RichardG's probing of a real Deschutes using my RDMSR tool,
we have discovered that the top 18 bits are filtered out. */
switch (ECX & 0x00003fff) {
/* Machine Check Exception Address */
case 0x00:
/* Machine Check Exception Type */
case 0x01:
break;
/* Time Stamp Counter */
case 0x10:
EAX = tsc & 0xffffffff;
EDX = tsc >> 32;
break;
/* IA32_PLATFORM_ID - Platform ID */
case 0x17:
if (cpu_s->cpu_type < CPU_PENTIUM2D)
goto i686_invalid_rdmsr;
if (cpu_f->package == CPU_PKG_SLOT2)
EDX |= (1 << 19);
else if (cpu_f->package == CPU_PKG_SOCKET370)
EDX |= (1 << 20);
break;
/* Unknown */
case 0x18:
break;
/* IA32_APIC_BASE - APIC Base Address */
case 0x1B:
EAX = msr.apic_base & 0xffffffff;
EDX = msr.apic_base >> 32;
cpu_log("APIC_BASE read : %08X%08X\n", EDX, EAX);
break;
/* Unknown (undocumented?) MSR used by the Hyper-V BIOS */
case 0x20:
EAX = msr.ecx20 & 0xffffffff;
EDX = msr.ecx20 >> 32;
break;
/* Unknown */
case 0x21:
if (cpu_s->cpu_type == CPU_PENTIUMPRO)
goto i686_invalid_rdmsr;
break;
/* EBL_CR_POWERON - Processor Hard Power-On Configuration */
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;
/* Unknown */
case 0x32:
if (cpu_s->cpu_type == CPU_PENTIUMPRO)
goto i686_invalid_rdmsr;
break;
/* TEST_CTL - Test Control Register */
case 0x33:
EAX = msr.test_ctl;
break;
/* Unknown */
case 0x34:
case 0x3a:
case 0x3b:
case 0x50 ... 0x54:
break;
/* BIOS_UPDT_TRIG - BIOS Update Trigger */
case 0x79:
EAX = msr.bios_updt & 0xffffffff;
EDX = msr.bios_updt >> 32;
break;
/* BBL_CR_D0 ... BBL_CR_D3 - Chunk 0..3 Data Register
8Bh: BIOS_SIGN - BIOS Update Signature */
case 0x88 ... 0x8b:
EAX = msr.bbl_cr_dx[ECX - 0x88] & 0xffffffff;
EDX = msr.bbl_cr_dx[ECX - 0x88] >> 32;
// EDX |= 0xffffffff;
break;
/* Unknown */
case 0xae:
break;
/* PERFCTR0 - Performance Counter Register 0 */
case 0xc1:
/* PERFCTR1 - Performance Counter Register 1 */
case 0xc2:
EAX = msr.perfctr[ECX - 0xC1] & 0xffffffff;
EDX = msr.perfctr[ECX - 0xC1] >> 32;
break;
/* MTRRcap */
case 0xfe:
EAX = msr.mtrr_cap & 0xffffffff;
EDX = msr.mtrr_cap >> 32;
break;
/* BBL_CR_ADDR - L2 Cache Address Register */
case 0x116:
EAX = msr.bbl_cr_addr & 0xffffffff;
EDX = msr.bbl_cr_addr >> 32;
break;
/* BBL_CR_DECC - L2 Cache Date ECC Register */
case 0x118:
EAX = msr.bbl_cr_decc & 0xffffffff;
EDX = msr.bbl_cr_decc >> 32;
break;
/* BBL_CR_CTL - L2 Cache Control Register */
case 0x119:
EAX = msr.bbl_cr_ctl & 0xffffffff;
EDX = msr.bbl_cr_ctl >> 32;
break;
/* BBL_CR_TRIG - L2 Cache Trigger Register */
case 0x11a:
EAX = msr.bbl_cr_trig & 0xffffffff;
EDX = msr.bbl_cr_trig >> 32;
break;
/* BBL_CR_BUSY - L2 Cache Busy Register */
case 0x11b:
EAX = msr.bbl_cr_busy & 0xffffffff;
EDX = msr.bbl_cr_busy >> 32;
break;
/* BBL_CR_CTL3 - L2 Cache Control Register 3 */
case 0x11e:
EAX = msr.bbl_cr_ctl3 & 0xffffffff;
EDX = msr.bbl_cr_ctl3 >> 32;
break;
/* Unknown */
case 0x131:
case 0x14e ... 0x151:
case 0x154:
case 0x15b:
case 0x15f:
break;
/* SYSENTER_CS - SYSENTER target CS */
case 0x174:
EAX &= 0xffff0000;
EAX |= msr.sysenter_cs;
EDX = 0x00000000;
break;
/* SYSENTER_ESP - SYSENTER target ESP */
case 0x175:
EAX = msr.sysenter_esp;
EDX = 0x00000000;
break;
/* SYSENTER_EIP - SYSENTER target EIP */
case 0x176:
EAX = msr.sysenter_eip;
EDX = 0x00000000;
break;
/* MCG_CAP - Machine Check Global Capability */
case 0x179:
EAX = 0x00000105;
EDX = 0x00000000;
break;
/* MCG_STATUS - Machine Check Global Status */
case 0x17a:
break;
/* MCG_CTL - Machine Check Global Control */
case 0x17b:
EAX = msr.mcg_ctl & 0xffffffff;
EDX = msr.mcg_ctl >> 32;
break;
/* EVNTSEL0 - Performance Counter Event Select 0 */
case 0x186:
/* EVNTSEL1 - Performance Counter Event Select 1 */
case 0x187:
EAX = msr.evntsel[ECX - 0x186] & 0xffffffff;
EDX = msr.evntsel[ECX - 0x186] >> 32;
break;
/* Unknown */
case 0x1d3:
break;
/* DEBUGCTLMSR - Debugging Control Register */
case 0x1d9:
EAX = msr.debug_ctl;
break;
/* LASTBRANCHFROMIP - address from which a branch was last taken */
case 0x1db:
/* LASTBRANCHTOIP - destination address of the last taken branch instruction */
case 0x1dc:
/* LASTINTFROMIP - address at which an interrupt last occurred */
case 0x1dd:
/* LASTINTTOIP - address to which the last interrupt caused a branch */
case 0x1de:
break;
/* ROB_CR_BKUPTMPDR6 */
case 0x1e0:
EAX = msr.rob_cr_bkuptmpdr6;
break;
/* ECX & 0: MTRRphysBase0 ... MTRRphysBase7
ECX & 1: MTRRphysMask0 ... MTRRphysMask7 */
case 0x200 ... 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;
/* MTRRfix64K_00000 */
case 0x250:
EAX = msr.mtrr_fix64k_8000 & 0xffffffff;
EDX = msr.mtrr_fix64k_8000 >> 32;
break;
/* MTRRfix16K_80000 */
case 0x258:
EAX = msr.mtrr_fix16k_8000 & 0xffffffff;
EDX = msr.mtrr_fix16k_8000 >> 32;
break;
/* MTRRfix16K_A0000 */
case 0x259:
EAX = msr.mtrr_fix16k_a000 & 0xffffffff;
EDX = msr.mtrr_fix16k_a000 >> 32;
break;
/* MTRRfix4K_C0000 ... MTRRfix4K_F8000 */
case 0x268 ... 0x26f:
EAX = msr.mtrr_fix4k[ECX - 0x268] & 0xffffffff;
EDX = msr.mtrr_fix4k[ECX - 0x268] >> 32;
break;
/* Page Attribute Table */
case 0x277:
if (cpu_s->cpu_type < CPU_PENTIUM2D)
goto i686_invalid_rdmsr;
EAX = msr.pat & 0xffffffff;
EDX = msr.pat >> 32;
break;
/* Unknown */
case 0x280:
if (cpu_s->cpu_type == CPU_PENTIUMPRO)
goto i686_invalid_rdmsr;
break;
/* MTRRdefType */
case 0x2ff:
EAX = msr.mtrr_deftype & 0xffffffff;
EDX = msr.mtrr_deftype >> 32;
break;
/* MC0_CTL - Machine Check 0 Control */
case 0x400:
/* MC1_CTL - Machine Check 1 Control */
case 0x404:
/* MC2_CTL - Machine Check 2 Control */
case 0x408:
/* MC4_CTL - Machine Check 4 Control */
case 0x40c:
/* MC3_CTL - Machine Check 3 Control */
case 0x410:
EAX = msr.mca_ctl[(ECX - 0x400) >> 2] & 0xffffffff;
EDX = msr.mca_ctl[(ECX - 0x400) >> 2] >> 32;
break;
/* MC0_STATUS - Machine Check 0 Status */
case 0x401:
/* MC0_ADDR - Machine Check 0 Address */
case 0x402:
/* MC1_STATUS - Machine Check 1 Status */
case 0x405:
/* MC1_ADDR - Machine Check 1 Address */
case 0x406:
/* MC2_STATUS - Machine Check 2 Status */
case 0x409:
/* MC2_ADDR - Machine Check 2 Address */
case 0x40a:
/* MC4_STATUS - Machine Check 4 Status */
case 0x40d:
/* MC4_ADDR - Machine Check 4 Address */
case 0x40e:
/* MC3_STATUS - Machine Check 3 Status */
case 0x411:
/* MC3_ADDR - Machine Check 3 Address */
case 0x412:
break;
/* Unknown */
case 0x570:
EAX = msr.ecx570 & 0xffffffff;
EDX = msr.ecx570 >> 32;
break;
/* Unknown, possibly debug registers? */
case 0x1000 ... 0x1007:
/* Unknown, possibly control registers? */
case 0x2000:
case 0x2002 ... 0x2004:
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);
if ((CPL || (cpu_state.eflags & VM_FLAG)) && (cr0 & 1))
x86gpf(NULL, 0);
else switch (cpu_s->cpu_type) {
case CPU_IBM386SLC:
case CPU_IBM486SLC:
case CPU_IBM486BL:
switch (ECX) {
/* Processor Operation Register */
case 0x1000:
msr.ibm_por = EAX & ((cpu_s->cpu_type > CPU_IBM386SLC) ? 0xffeff : 0xfeff);
cpu_cache_int_enabled = (EAX & (1 << 7));
break;
/* Cache Region Control Register */
case 0x1001:
msr.ibm_crcr = EAX | ((uint64_t) (EDX & 0x0000ffff) << 32);
break;
/* Processor Operation Register */
case 0x1002:
if ((cpu_s->cpu_type > CPU_IBM386SLC) && cpu_s->multi)
msr.ibm_por2 = EAX & 0x3f000000;
break;
/* Processor Control Register */
case 0x1004:
if (cpu_s->cpu_type > CPU_IBM486SLC)
msr.ibm_pcr = EAX & 0x00d6001a;
break;
}
break;
case CPU_WINCHIP:
case CPU_WINCHIP2:
switch (ECX) {
/* Pentium Processor Parity Reversal Register */
case 0x02:
msr.tr1 = EAX & 2;
break;
/* Pentium Processor New Feature Control */
case 0x0e:
msr.tr12 = EAX & 0x248;
break;
/* Time Stamp Counter */
case 0x10:
timer_set_new_tsc(EAX | ((uint64_t) EDX << 32));
break;
/* Performance Monitor - Control and Event Select */
case 0x11:
msr.cesr = EAX & 0xff00ff;
break;
/* Performance Monitor - Event Counter 0 */
case 0x12:
msr.pmc[0] = EAX | ((uint64_t) EDX << 32);
break;
/* Performance Monitor - Event Counter 1 */
case 0x13:
msr.pmc[1] = EAX | ((uint64_t) EDX << 32);
break;
/* Feature Control Register */
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;
/* Feature Control Register 2 */
case 0x108:
msr.fcr2 = EAX | ((uint64_t) EDX << 32);
break;
/* Feature Control Register 3 */
case 0x109:
msr.fcr3 = EAX | ((uint64_t) EDX << 32);
break;
/* Memory Configuration Register 0..7 */
case 0x110 ... 0x117:
temp = ECX - 0x110;
if (cpu_s->cpu_type == CPU_WINCHIP2) {
if (EAX & 0x1f)
msr.mcr_ctrl |= (1 << (temp + 9));
else
msr.mcr_ctrl &= ~(1 << (temp + 9));
}
msr.mcr[temp] = EAX | ((uint64_t) EDX << 32);
break;
/* Memory Configuration Register Control */
case 0x120:
msr.mcr_ctrl = EAX & ((cpu_s->cpu_type == CPU_WINCHIP2) ? 0x1df : 0x1f);
break;
/* Unknown */
case 0x131:
case 0x142 ... 0x145:
case 0x147:
case 0x150:
case 0x151:
break;
}
break;
case CPU_CYRIX3S:
switch (ECX) {
/* Machine Check Exception Address */
case 0x00:
/* Machine Check Exception Type */
case 0x01:
break;
/* Time Stamp Counter */
case 0x10:
timer_set_new_tsc(EAX | ((uint64_t) EDX << 32));
break;
/* PERFCTR0 - Performance Counter Register 0 - aliased to TSC */
case 0xc1:
break;
/* PERFCTR0 - Performance Counter Register 1 */
case 0xc2:
msr.perfctr[1] = EAX | ((uint64_t) EDX << 32);
break;
/* BBL_CR_CTL3 - L2 Cache Control Register 3 */
case 0x11e:
/* EVNTSEL0 - Performance Counter Event Select 0 - hardcoded */
case 0x186:
break;
/* EVNTSEL1 - Performance Counter Event Select 1 */
case 0x187:
msr.evntsel[1] = EAX | ((uint64_t) EDX << 32);
break;
/* Feature Control Register */
case 0x1107:
msr.fcr = EAX;
if (EAX & (1 << 1))
cpu_features |= CPU_FEATURE_CX8;
else
cpu_features &= ~CPU_FEATURE_CX8;
if (EAX & (1 << 7))
cpu_CR4_mask |= CR4_PGE;
else
cpu_CR4_mask &= ~CR4_PGE;
break;
/* Feature Control Register 2 */
case 0x1108:
msr.fcr2 = EAX | ((uint64_t) EDX << 32);
break;
/* Feature Control Register 3 */
case 0x1109:
msr.fcr3 = EAX | ((uint64_t) EDX << 32);
break;
/* ECX & 0: MTRRphysBase0 ... MTRRphysBase7
ECX & 1: MTRRphysMask0 ... MTRRphysMask7 */
case 0x200 ... 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;
/* MTRRfix64K_00000 */
case 0x250:
msr.mtrr_fix64k_8000 = EAX | ((uint64_t) EDX << 32);
break;
/* MTRRfix16K_80000 */
case 0x258:
msr.mtrr_fix16k_8000 = EAX | ((uint64_t) EDX << 32);
break;
/* MTRRfix16K_A0000 */
case 0x259:
msr.mtrr_fix16k_a000 = EAX | ((uint64_t) EDX << 32);
break;
/* MTRRfix4K_C0000 ... MTRRfix4K_F8000 */
case 0x268 ... 0x26f:
msr.mtrr_fix4k[ECX - 0x268] = EAX | ((uint64_t) EDX << 32);
break;
/* MTRRdefType */
case 0x2ff:
msr.mtrr_deftype = EAX | ((uint64_t) EDX << 32);
break;
}
break;
#ifdef USE_AMD_K5
case CPU_K5:
case CPU_5K86:
#endif /* USE_AMD_K5 */
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) {
/* Machine Check Address Register */
case 0x00000000:
if (cpu_s->cpu_type > CPU_5K86)
msr.mcar = EAX | ((uint64_t) EDX << 32);
break;
/* Machine Check Type Register */
case 0x00000001:
if (cpu_s->cpu_type > CPU_5K86)
msr.mctr = EAX | ((uint64_t) EDX << 32);
break;
/* Test Register 12 */
case 0x0000000e:
msr.tr12 = EAX & 0x8;
break;
/* Time Stamp Counter */
case 0x00000010:
timer_set_new_tsc(EAX | ((uint64_t) EDX << 32));
break;
/* Array Access Register */
case 0x00000082:
if (cpu_s->cpu_type > CPU_5K86)
goto amd_k_invalid_wrmsr;
msr.amd_aar = EAX | ((uint64_t) EDX << 32);
break;
/* Hardware Configuration Register */
case 0x00000083:
msr.amd_hwcr = EAX | ((uint64_t) EDX << 32);
break;
/* Write Allocate Top-of-Memory and Control Register */
case 0x00000085:
if (cpu_s->cpu_type != CPU_5K86)
goto amd_k_invalid_wrmsr;
msr.amd_watmcr = EAX | ((uint64_t) EDX << 32);
break;
/* Write Allocate Programmable Memory Range Register */
case 0x00000086:
if (cpu_s->cpu_type != CPU_5K86)
goto amd_k_invalid_wrmsr;
msr.amd_wapmrr = EAX | ((uint64_t) EDX << 32);
break;
/* Extended Feature Enable Register */
case 0xc0000080:
temp = EAX | ((uint64_t) EDX << 32);
if (temp & ~0x1fULL)
x86gpf(NULL, 0);
else
msr.amd_efer = temp;
break;
/* SYSCALL Target Address Register */
case 0xc0000081:
if (cpu_s->cpu_type < CPU_K6_2)
goto amd_k_invalid_wrmsr;
msr.amd_star = EAX | ((uint64_t) EDX << 32);
break;
/* Write-Handling Control Register */
case 0xc0000082:
msr.amd_whcr = EAX | ((uint64_t) EDX << 32);
break;
/* UC/WC Cacheability Control Register */
case 0xc0000085:
if (cpu_s->cpu_type < CPU_K6_2C)
goto amd_k_invalid_wrmsr;
msr.amd_uwccr = EAX | ((uint64_t) EDX << 32);
break;
/* Enhanced Power Management Register */
case 0xc0000086:
if (cpu_s->cpu_type < CPU_K6_2P)
goto amd_k_invalid_wrmsr;
msr.amd_epmr = EAX | ((uint64_t) EDX << 32);
break;
/* Processor State Observability Register */
case 0xc0000087:
if (cpu_s->cpu_type < CPU_K6_2C)
goto amd_k_invalid_wrmsr;
msr.amd_psor = EAX | ((uint64_t) EDX << 32);
break;
/* Page Flush/Invalidate Register */
case 0xc0000088:
if (cpu_s->cpu_type < CPU_K6_2C)
goto amd_k_invalid_wrmsr;
msr.amd_pfir = EAX | ((uint64_t) EDX << 32);
break;
/* Level-2 Cache Array Access Register */
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:
cpu_log("WRMSR: ECX = %08X, val = %08X%08X\n", ECX, EDX, EAX);
/* Filter out the upper 27 bits when ECX value is over 0x80000000, as per:
Ralf Brown, Pentium Model-Specific Registers and What They Reveal.
https://www.cs.cmu.edu/~ralf/papers/highmsr.html
But leave the bit 31 intact to be able to handle both low and high
MSRs in a single switch block. */
switch (ECX & (ECX > 0x7fffffff ? 0x8000001f : 0x7fffffff)) {
/* Machine Check Exception Address */
case 0x00000000:
case 0x80000000:
/* Machine Check Exception Type */
case 0x00000001:
case 0x80000001:
break;
/* TR1 - Parity Reversal Test Register */
case 0x00000002:
case 0x80000002:
msr.tr1 = EAX & 0x3fff;
break;
/* TR2 - Instruction Cache End Bit */
case 0x00000004:
case 0x80000004:
if (cpu_s->cpu_type == CPU_PENTIUMMMX)
goto pentium_invalid_wrmsr;
msr.tr2 = EAX & 0xf;
break;
/* TR3 - Cache Test Data */
case 0x00000005:
case 0x80000005:
msr.tr3 = EAX;
break;
/* TR4 - Cache Test Tag */
case 0x00000006:
case 0x80000006:
msr.tr4 = EAX & ((cpu_s->cpu_type == CPU_PENTIUMMMX) ? 0xffffff1f : 0xffffff07);
break;
/* TR5 - Cache Test Control */
case 0x00000007:
case 0x80000007:
msr.tr5 = EAX & ((cpu_s->cpu_type == CPU_PENTIUMMMX) ? 0x87fff : 0x7fff);
break;
/* TR6 - TLB Test Command */
case 0x00000008:
case 0x80000008:
msr.tr6 = EAX & 0xffffff07;
break;
/* TR7 - TLB Test Data */
case 0x00000009:
case 0x80000009:
msr.tr7 = EAX & ((cpu_s->cpu_type == CPU_PENTIUMMMX) ? 0xfffffc7f : 0xffffff9c);
break;
/* TR9 - Branch Target Buffer Tag */
case 0x0000000b:
case 0x8000000b:
msr.tr9 = EAX & ((cpu_s->cpu_type == CPU_PENTIUMMMX) ? 0xffffffff : 0xffffffc3);
break;
/* TR10 - Branch Target Buffer Target */
case 0x0000000c:
case 0x8000000c:
msr.tr10 = EAX;
break;
/* TR11 - Branch Target Buffer Control */
case 0x0000000d:
case 0x8000000d:
msr.tr11 = EAX & ((cpu_s->cpu_type >= CPU_PENTIUMMMX) ? 0x3001fcf : 0xfcf);
break;
/* TR12 - New Feature Control */
case 0x0000000e:
case 0x8000000e:
if (cpu_s->cpu_type == CPU_PENTIUMMMX)
temp = EAX & 0x38034f;
else if ((CPUID & 0xfff) >= 0x52b)
temp = EAX & 0x20435f;
else if ((CPUID & 0xfff) >= 0x520)
temp = EAX & 0x20035f;
else
temp = EAX & 0x20030f;
msr.tr12 = temp;
break;
/* Time Stamp Counter */
case 0x00000010:
case 0x80000010:
timer_set_new_tsc(EAX | ((uint64_t) EDX << 32));
break;
/* Performance Monitor - Control and Event Select */
case 0x00000011:
case 0x80000011:
msr.cesr = EAX & 0x3ff03ff;
break;
/* Performance Monitor - Event Counter 0 */
case 0x00000012:
case 0x80000012:
msr.pmc[0] = EAX | ((uint64_t) EDX << 32);
break;
/* Performance Monitor - Event Counter 1 */
case 0x00000013:
case 0x80000013:
msr.pmc[1] = EAX | ((uint64_t) EDX << 32);
break;
/* Unknown */
case 0x00000014:
case 0x80000014:
if ((CPUID & 0xfff) <= 0x520)
goto pentium_invalid_wrmsr;
break;
/* Unknown, possibly paging-related; initial value is 0004h,
becomes 0008h once paging is enabled */
case 0x80000018:
/* Floating point - last prefetched opcode
bits 10-8: low three bits of first byte of FP instruction
bits 7-0: second byte of floating-point instruction */
case 0x80000019:
/* Floating point - last executed non-control opcode */
case 0x8000001a:
break;
/* Floating point - last non-control exception opcode - part
of FSTENV/FSAVE'd environment */
case 0x8000001b:
EAX = msr.fp_last_xcpt & 0x7ff;
break;
/* Unknown */
case 0x8000001c:
break;
/* Probe Mode Control */
case 0x8000001d:
EAX = msr.probe_ctl & 0x7;
break;
/* Unknown, possibly scratchpad register */
case 0x8000001e:
msr.ecx8000001e = EAX;
break;
/* Unknown, possibly scratchpad register */
case 0x8000001f:
msr.ecx8000001f = EAX;
break;
/* Reserved/Unimplemented */
case 0x80000003:
case 0x8000000a:
case 0x8000000f:
case 0x80000015 ... 0x80000017:
break;
default:
pentium_invalid_wrmsr:
cpu_log("WRMSR: Invalid MSR: %08X\n", ECX);
x86gpf(NULL, 0);
break;
}
break;
#ifdef USE_CYRIX_6X86
case CPU_Cx6x86:
case CPU_Cx6x86L:
case CPU_CxGX1:
case CPU_Cx6x86MX:
cpu_log("WRMSR: ECX = %08X, val = %08X%08X\n", ECX, EDX, EAX);
switch (ECX) {
/* Test Data */
case 0x03:
msr.tr3 = EAX;
/* Test Address */
case 0x04:
msr.tr4 = EAX;
/* Test Command/Status */
case 0x05:
msr.tr5 = EAX & 0x008f0f3b;
/* Time Stamp Counter */
case 0x10:
timer_set_new_tsc(EAX | ((uint64_t) EDX << 32));
break;
/* Performance Monitor - Control and Event Select */
case 0x11:
msr.cesr = EAX & 0x7ff07ff;
break;
/* Performance Monitor - Event Counter 0 */
case 0x12:
msr.pmc[0] = EAX | ((uint64_t) EDX << 32);
break;
/* Performance Monitor - Event Counter 1 */
case 0x13:
msr.pmc[1] = EAX | ((uint64_t) EDX << 32);
break;
}
break;
#endif /* USE_CYRIX_6X86 */
case CPU_PENTIUMPRO:
case CPU_PENTIUM2:
case CPU_PENTIUM2D:
/* Per RichardG's probing of a real Deschutes using my RDMSR tool,
we have discovered that the top 18 bits are filtered out. */
switch (ECX & 0x00003fff) {
/* Machine Check Exception Address */
case 0x00:
/* Machine Check Exception Type */
case 0x01:
if (EAX || EDX)
x86gpf(NULL, 0);
break;
/* Time Stamp Counter */
case 0x10:
timer_set_new_tsc(EAX | ((uint64_t) EDX << 32));
break;
/* Unknown */
case 0x18:
break;
/* IA32_APIC_BASE - APIC Base Address */
case 0x1b:
cpu_log("APIC_BASE write: %08X%08X\n", EDX, EAX);
#if 0
msr.apic_base = EAX | ((uint64_t) EDX << 32);
#endif
break;
/* Unknown (undocumented?) MSR used by the Hyper-V BIOS */
case 0x20:
msr.ecx20 = EAX | ((uint64_t) EDX << 32);
break;
/* Unknown */
case 0x21:
if (cpu_s->cpu_type == CPU_PENTIUMPRO)
goto i686_invalid_wrmsr;
break;
/* EBL_CR_POWERON - Processor Hard Power-On Configuration */
case 0x2a:
break;
/* Unknown */
case 0x32:
if (cpu_s->cpu_type == CPU_PENTIUMPRO)
goto i686_invalid_wrmsr;
break;
/* TEST_CTL - Test Control Register */
case 0x33:
msr.test_ctl = EAX;
break;
/* Unknown */
case 0x34:
case 0x3a:
case 0x3b:
case 0x50 ... 0x54:
break;
/* BIOS_UPDT_TRIG - BIOS Update Trigger */
case 0x79:
msr.bios_updt = EAX | ((uint64_t) EDX << 32);
break;
/* BBL_CR_D0 ... BBL_CR_D3 - Chunk 0..3 Data Register
8Bh: BIOS_SIGN - BIOS Update Signature */
case 0x88 ... 0x8b:
msr.bbl_cr_dx[ECX - 0x88] = EAX | ((uint64_t) EDX << 32);
break;
/* Unknown */
case 0xae:
break;
/* PERFCTR0 - Performance Counter Register 0 */
case 0xc1:
/* PERFCTR1 - Performance Counter Register 1 */
case 0xc2:
msr.perfctr[ECX - 0xC1] = EAX | ((uint64_t) EDX << 32);
break;
/* MTRRcap */
case 0xfe:
msr.mtrr_cap = EAX | ((uint64_t) EDX << 32);
break;
/* BBL_CR_ADDR - L2 Cache Address Register */
case 0x116:
msr.bbl_cr_addr = EAX | ((uint64_t) EDX << 32);
break;
/* BBL_CR_DECC - L2 Cache Date ECC Register */
case 0x118:
msr.bbl_cr_decc = EAX | ((uint64_t) EDX << 32);
break;
/* BBL_CR_CTL - L2 Cache Control Register */
case 0x119:
msr.bbl_cr_ctl = EAX | ((uint64_t) EDX << 32);
break;
/* BBL_CR_TRIG - L2 Cache Trigger Register */
case 0x11a:
msr.bbl_cr_trig = EAX | ((uint64_t) EDX << 32);
break;
/* BBL_CR_BUSY - L2 Cache Busy Register */
case 0x11b:
msr.bbl_cr_busy = EAX | ((uint64_t) EDX << 32);
break;
/* BBL_CR_CTL3 - L2 Cache Control Register 3 */
case 0x11e:
msr.bbl_cr_ctl3 = EAX | ((uint64_t) EDX << 32);
break;
/* Unknown */
case 0x131:
case 0x14e ... 0x151:
case 0x154:
case 0x15b:
case 0x15f:
break;
/* SYSENTER_CS - SYSENTER target CS */
case 0x174:
msr.sysenter_cs = EAX & 0xFFFF;
break;
/* SYSENTER_ESP - SYSENTER target ESP */
case 0x175:
msr.sysenter_esp = EAX;
break;
/* SYSENTER_EIP - SYSENTER target EIP */
case 0x176:
msr.sysenter_eip = EAX;
break;
/* MCG_CAP - Machine Check Global Capability */
case 0x179:
break;
/* MCG_STATUS - Machine Check Global Status */
case 0x17a:
if (EAX || EDX)
x86gpf(NULL, 0);
break;
/* MCG_CTL - Machine Check Global Control */
case 0x17b:
msr.mcg_ctl = EAX | ((uint64_t) EDX << 32);
break;
/* EVNTSEL0 - Performance Counter Event Select 0 */
case 0x186:
/* EVNTSEL1 - Performance Counter Event Select 1 */
case 0x187:
msr.evntsel[ECX - 0x186] = EAX | ((uint64_t) EDX << 32);
break;
case 0x1d3:
break;
/* DEBUGCTLMSR - Debugging Control Register */
case 0x1d9:
msr.debug_ctl = EAX;
break;
/* ROB_CR_BKUPTMPDR6 */
case 0x1e0:
msr.rob_cr_bkuptmpdr6 = EAX;
break;
/* ECX & 0: MTRRphysBase0 ... MTRRphysBase7
ECX & 1: MTRRphysMask0 ... MTRRphysMask7 */
case 0x200 ... 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;
/* MTRRfix64K_00000 */
case 0x250:
msr.mtrr_fix64k_8000 = EAX | ((uint64_t) EDX << 32);
break;
/* MTRRfix16K_80000 */
case 0x258:
msr.mtrr_fix16k_8000 = EAX | ((uint64_t) EDX << 32);
break;
/* MTRRfix16K_A0000 */
case 0x259:
msr.mtrr_fix16k_a000 = EAX | ((uint64_t) EDX << 32);
break;
/* MTRRfix4K_C0000 ... MTRRfix4K_F8000 */
case 0x268 ... 0x26f:
msr.mtrr_fix4k[ECX - 0x268] = EAX | ((uint64_t) EDX << 32);
break;
/* Page Attribute Table */
case 0x277:
if (cpu_s->cpu_type < CPU_PENTIUM2D)
goto i686_invalid_wrmsr;
msr.pat = EAX | ((uint64_t) EDX << 32);
break;
/* Unknown */
case 0x280:
if (cpu_s->cpu_type == CPU_PENTIUMPRO)
goto i686_invalid_wrmsr;
break;
/* MTRRdefType */
case 0x2ff:
msr.mtrr_deftype = EAX | ((uint64_t) EDX << 32);
break;
/* MC0_CTL - Machine Check 0 Control */
case 0x400:
/* MC1_CTL - Machine Check 1 Control */
case 0x404:
/* MC2_CTL - Machine Check 2 Control */
case 0x408:
/* MC4_CTL - Machine Check 4 Control */
case 0x40c:
/* MC3_CTL - Machine Check 3 Control */
case 0x410:
msr.mca_ctl[(ECX - 0x400) >> 2] = EAX | ((uint64_t) EDX << 32);
break;
/* MC0_STATUS - Machine Check 0 Status */
case 0x401:
/* MC0_ADDR - Machine Check 0 Address */
case 0x402:
/* MC1_STATUS - Machine Check 1 Status */
case 0x405:
/* MC1_ADDR - Machine Check 1 Address */
case 0x406:
/* MC2_STATUS - Machine Check 2 Status */
case 0x409:
/* MC2_ADDR - Machine Check 2 Address */
case 0x40a:
/* MC4_STATUS - Machine Check 4 Status */
case 0x40d:
/* MC4_ADDR - Machine Check 4 Address */
case 0x40e:
/* MC3_STATUS - Machine Check 3 Status */
case 0x411:
/* MC3_ADDR - Machine Check 3 Address */
case 0x412:
if (EAX || EDX)
x86gpf(NULL, 0);
break;
/* Unknown */
case 0x570:
msr.ecx570 = EAX | ((uint64_t) EDX << 32);
break;
/* Unknown, possibly debug registers? */
case 0x1000 ... 0x1007:
/* Unknown, possibly control registers? */
case 0x2000:
case 0x2002 ... 0x2004:
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, UNUSED(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;
#ifdef USE_CYRIX_6X86
if (cpu_s->cpu_type >= CPU_Cx6x86) {
if (val & 0x80)
CPUID = cpu_s->cpuid_model;
else
CPUID = 0;
}
#endif /* USE_CYRIX_6X86 */
}
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, UNUSED(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;
default:
break;
}
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 /* USE_DYNAREC */
void
x86_setopcodes_2386(const OpFn *opcodes, const OpFn *opcodes_0f)
{
x86_2386_opcodes = opcodes;
x86_2386_opcodes_0f = opcodes_0f;
}
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;
}