Preliminary VIA Cyrix III emulation

This adds preliminary emulation of the first-gen Samuel core, used in the VIA Cyrix III CPU, at clock speeds from 66 to 700 MHz. This also moves the 440BX emulation out of the dev-branch.

Things working:
- CPUID
- Windows 98SE
- Timings seem identical between WinChip/W2's integer section and this

Things left to do:
- 3DNow on old dynarec
- Half-speed FPU (currently simulated with WinChip 1 timings instead of WinChip 2)
This commit is contained in:
nerd73
2020-03-01 15:06:35 -07:00
parent 5c4542283d
commit 111d82fa0c
10 changed files with 267 additions and 113 deletions

View File

@@ -1601,6 +1601,61 @@ cpu_set(void)
#endif
break;
#endif
case CPU_CYRIX3S:
#ifdef USE_DYNAREC
#ifdef USE_NEW_DYNAREC
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);
#endif
#else
#ifdef USE_NEW_DYNAREC
x86_setopcodes(ops_386, ops_winchip2_0f);
#else
x86_setopcodes(ops_386, ops_winchip_0f);
#endif
#endif
timing_rr = 1; /*register dest - register src*/
timing_rm = 2; /*register dest - memory src*/
timing_mr = 2; /*memory dest - register src*/
timing_mm = 3;
timing_rml = 2; /*register dest - memory src long*/
timing_mrl = 2; /*memory dest - register src long*/
timing_mml = 3;
timing_bt = 3-1; /*branch taken*/
timing_bnt = 1; /*branch not taken*/
#ifdef USE_NEW_DYNAREC
cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MMX | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_3DNOW;
#else
cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MMX | CPU_FEATURE_MSR | CPU_FEATURE_CR4;
#endif
msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 18) | (1 << 19) | (1 << 20) | (1 << 21);
cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE;
/*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;
#ifdef USE_DYNAREC
codegen_timing_set(&codegen_timing_winchip);
#endif
break;
default:
fatal("cpu_set : unknown CPU type %i\n", cpu_s->cpu_type);
@@ -1755,7 +1810,7 @@ cpu_CPUID(void)
}
break;
case 1:
EAX = 0x580;
EAX = CPUID;
EBX = ECX = 0;
EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR;
if (cpu_has_feature(CPU_FEATURE_CX8))
@@ -1767,7 +1822,7 @@ cpu_CPUID(void)
EAX = 0x80000005;
break;
case 0x80000001:
EAX = 0x580;
EAX = CPUID;
EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR;
if (cpu_has_feature(CPU_FEATURE_CX8))
EDX |= CPUID_CMPXCHG8B;
@@ -2281,7 +2336,67 @@ cpu_CPUID(void)
break;
#endif
#endif
case CPU_CYRIX3S:
switch (EAX)
{
case 0:
EAX = 1;
if (msr.fcr2 & (1 << 14))
{
EBX = msr.fcr3 >> 32;
ECX = msr.fcr3 & 0xffffffff;
EDX = msr.fcr2 >> 32;
}
else
{
EBX = 0x746e6543; /*CentaurHauls*/
ECX = 0x736c7561;
EDX = 0x48727561;
}
break;
case 1:
EAX = CPUID;
EBX = ECX = 0;
EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR;
if (cpu_has_feature(CPU_FEATURE_CX8))
EDX |= CPUID_CMPXCHG8B;
if (msr.fcr & (1 << 9))
EDX |= CPUID_MMX;
break;
case 0x80000000:
EAX = 0x80000005;
break;
case 0x80000001:
EAX = CPUID;
EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR;
if (cpu_has_feature(CPU_FEATURE_CX8))
EDX |= CPUID_CMPXCHG8B;
if (msr.fcr & (1 << 9))
EDX |= CPUID_MMX;
#ifdef USE_NEW_DYNAREC
if (cpu_has_feature(CPU_FEATURE_3DNOW))
EDX |= CPUID_3DNOW;
#endif
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;
}
}
@@ -2295,11 +2410,11 @@ void cpu_ven_reset(void)
case CPU_K6:
amd_efer = amd_whcr = 0ULL;
break;
#ifdef USE_NEW_DYNAREC
case CPU_K6_2:
amd_efer = amd_whcr = 0ULL;
star = 0ULL;
break;
#ifdef USE_NEW_DYNAREC
case CPU_K6_2C:
amd_efer = 2ULL;
amd_whcr = star = 0ULL;
@@ -2363,7 +2478,37 @@ void cpu_RDMSR()
break;
}
break;
case CPU_CYRIX3S:
EAX = EDX = 0;
switch (ECX)
{
case 0x02:
EAX = msr.tr1;
break;
case 0x0e:
EAX = msr.tr12;
break;
case 0x10:
EAX = tsc & 0xffffffff;
EDX = tsc >> 32;
break;
case 0x11:
EAX = msr.cesr;
break;
case 0x1107:
EAX = msr.fcr;
break;
case 0x108:
EAX = msr.fcr2 & 0xffffffff;
EDX = msr.fcr2 >> 32;
break;
case 0x10a:
EAX = cpu_multi & 3;
break;
}
break;
#if defined(USE_NEW_DYNAREC) || (defined(DEV_BRANCH) && defined(USE_AMD_K))
case CPU_K5:
case CPU_5K86:
@@ -2778,6 +2923,50 @@ void cpu_WRMSR()
cpu_features |= CPU_FEATURE_3DNOW;
else
cpu_features &= ~CPU_FEATURE_3DNOW;
#endif
if (EAX & (1 << 29))
CPUID = 0;
else
CPUID = machines[machine].cpu[cpu_manufacturer].cpus[cpu].cpuid_model;
break;
case 0x108:
msr.fcr2 = EAX | ((uint64_t)EDX << 32);
break;
case 0x109:
msr.fcr3 = EAX | ((uint64_t)EDX << 32);
break;
}
break;
case CPU_CYRIX3S:
switch (ECX)
{
case 0x02:
msr.tr1 = EAX & 2;
break;
case 0x0e:
msr.tr12 = EAX & 0x228;
break;
case 0x10:
tsc = EAX | ((uint64_t)EDX << 32);
break;
case 0x11:
msr.cesr = EAX & 0xff00ff;
break;
case 0x1107:
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;
#ifdef USE_NEW_DYNAREC
if (EAX & (1 << 20))
cpu_features |= CPU_FEATURE_3DNOW;
else
cpu_features &= ~CPU_FEATURE_3DNOW;
#endif
if (EAX & (1 << 29))
CPUID = 0;
@@ -2792,7 +2981,7 @@ void cpu_WRMSR()
break;
}
break;
#if defined(USE_NEW_DYNAREC) || (defined(DEV_BRANCH) && defined(USE_AMD_K))
case CPU_K5:
case CPU_5K86:

View File

@@ -76,6 +76,7 @@ enum {
CPU_K6_2P,
CPU_K6_3P,
#endif
CPU_CYRIX3S,
#if defined(DEV_BRANCH) && defined(USE_I686)
CPU_PENTIUMPRO, /* 686 class CPUs */
CPU_PENTIUM2,
@@ -152,6 +153,7 @@ extern CPU cpus_6x86[];
#ifdef USE_NEW_DYNAREC
extern CPU cpus_6x86SS7[];
#endif
extern CPU cpus_Cyrix3[];
#if defined(DEV_BRANCH) && defined(USE_I686)
extern CPU cpus_PentiumPro[];
extern CPU cpus_PentiumII[];

View File

@@ -714,6 +714,24 @@ CPU cpus_PentiumII[] = {
{"Pentium II Deschutes 400", CPU_PENTIUM2D, 400000000, 4, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 36,36,12,12, 48},
{"Pentium II Deschutes 450", CPU_PENTIUM2D, 450000000, 9/2, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 41,41,14,14, 54},
{"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
};
#endif
#endif
CPU cpus_Cyrix3[] = {
/*VIA Cyrix III (Samuel)*/
{"Cyrix III 66", CPU_CYRIX3S, 66666666, 1, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC, 6, 6, 3, 3, 8}, /*66 MHz version*/
{"Cyrix III 233", CPU_CYRIX3S, 233333333, 7/2, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC, 21, 21, 9, 9, 28},
{"Cyrix III 266", CPU_CYRIX3S, 266666666, 4, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC, 24, 24, 12, 12, 32},
{"Cyrix III 300", CPU_CYRIX3S, 300000000, 9/2, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC, 27, 27, 13, 13, 36},
{"Cyrix III 333", CPU_CYRIX3S, 333333333, 5, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC, 30, 30, 15, 15, 40},
{"Cyrix III 350", CPU_CYRIX3S, 350000000, 7/2, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC, 32, 32, 11, 11, 42},
{"Cyrix III 400", CPU_CYRIX3S, 400000000, 4, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC, 36, 36, 12, 12, 48},
{"Cyrix III 450", CPU_CYRIX3S, 450000000, 9/2, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC, 41, 41, 14, 14, 54}, /*^ is lower P2 speeds to allow emulation below 466 mhz*/
{"Cyrix III 500", CPU_CYRIX3S, 500000000, 5, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC, 45, 45, 15, 15, 60},
{"Cyrix III 550", CPU_CYRIX3S, 550000000, 11/2, 0x662, 0x662, 0, CPU_SUPPORTS_DYNAREC, 50, 50, 17, 17, 66},
{"Cyrix III 600", CPU_CYRIX3S, 600000000, 6, 0x662, 0x662, 0, CPU_SUPPORTS_DYNAREC, 54, 54, 18, 18, 72},
{"Cyrix III 650", CPU_CYRIX3S, 650000000, 13/2, 0x662, 0x662, 0, CPU_SUPPORTS_DYNAREC, 58, 58, 20, 20, 78},
{"Cyrix III 700", CPU_CYRIX3S, 700000000, 7, 0x662, 0x662, 0, CPU_SUPPORTS_DYNAREC, 62, 62, 21, 21, 84},
{"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
};