4416 lines
173 KiB
C
4416 lines
173 KiB
C
/*
|
|
* 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, <https://pcem-emulator.co.uk/>
|
|
* leilei,
|
|
* Miran Grca, <mgrca8@gmail.com>
|
|
* Fred N. van Kempen, <decwiz@yahoo.com>
|
|
*
|
|
* Copyright 2008-2020 Sarah Walker.
|
|
* Copyright 2016-2018 leilei.
|
|
* Copyright 2016-2020 Miran Grca.
|
|
* Copyright 2018-2021 Fred N. van Kempen.
|
|
*/
|
|
#include <inttypes.h>
|
|
#include <math.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <wchar.h>
|
|
|
|
#define HAVE_STDARG_H
|
|
#include <86box/86box.h>
|
|
#include "cpu.h"
|
|
#include "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;
|
|
}
|