PCem

view src/cpu.c @ 150:871b132c6158

Implemented CR4 register for Winchip. Currently only Time Stamp Disable (TSD) has an effect. Fixed stupid bug in WRMSR - MSRs can now be written with values other than zero.
author TomW
date Sat Aug 23 16:28:16 2014 +0100
parents 4081a8dbce5b
children
line source
1 #include "ibm.h"
2 #include "cpu.h"
3 #include "model.h"
4 #include "io.h"
5 #include "x86_ops.h"
7 enum
8 {
9 CPUID_FPU = (1 << 0),
10 CPUID_TSC = (1 << 4),
11 CPUID_MSR = (1 << 5),
12 CPUID_MMX = (1 << 23)
13 };
15 int cpu = 3, cpu_manufacturer = 0;
16 CPU *cpu_s;
17 int cpu_multi;
18 int cpu_iscyrix;
19 int cpu_16bitbus;
20 int cpu_busspeed;
21 int cpu_hasrdtsc;
22 int cpu_hasMMX, cpu_hasMSR;
23 int cpu_hasCR4;
25 uint64_t cpu_CR4_mask;
27 uint64_t tsc = 0;
29 int timing_rr;
30 int timing_mr, timing_mrl;
31 int timing_rm, timing_rml;
32 int timing_mm, timing_mml;
33 int timing_bt, timing_bnt;
35 static struct
36 {
37 uint32_t tr1, tr12;
38 uint32_t cesr;
39 uint32_t fcr;
40 uint64_t fcr2, fcr3;
41 } msr;
43 /*Available cpuspeeds :
44 0 = 16 MHz
45 1 = 20 MHz
46 2 = 25 MHz
47 3 = 33 MHz
48 4 = 40 MHz
49 5 = 50 MHz
50 6 = 66 MHz
51 7 = 75 MHz
52 8 = 80 MHz
53 9 = 90 MHz
54 10 = 100 MHz
55 11 = 120 MHz
56 12 = 133 MHz
57 13 = 150 MHz
58 14 = 160 MHz
59 15 = 166 MHz
60 16 = 180 MHz
61 17 = 200 MHz
62 */
64 CPU cpus_8088[] =
65 {
66 /*8088 standard*/
67 {"8088/4.77", CPU_8088, 0, 4772727, 1, 0, 0, 0},
68 {"8088/8", CPU_8088, 1, 8000000, 1, 0, 0, 0},
69 {"8088/10", CPU_8088, 2, 10000000, 1, 0, 0, 0},
70 {"8088/12", CPU_8088, 3, 12000000, 1, 0, 0, 0},
71 {"8088/16", CPU_8088, 4, 16000000, 1, 0, 0, 0},
72 {"", -1, 0, 0, 0, 0}
73 };
75 CPU cpus_pcjr[] =
76 {
77 /*8088 PCjr*/
78 {"8088/4.77", CPU_8088, 0, 4772727, 1, 0, 0, 0},
79 {"", -1, 0, 0, 0, 0}
80 };
82 CPU cpus_8086[] =
83 {
84 /*8086 standard*/
85 {"8086/7.16", CPU_8086, 1, 3579545*2, 1, 0, 0, 0},
86 {"8086/8", CPU_8086, 1, 8000000, 1, 0, 0, 0},
87 {"8086/9.54", CPU_8086, 1, (3579545*8)/3, 1, 0, 0, 0},
88 {"8086/10", CPU_8086, 2, 10000000, 1, 0, 0, 0},
89 {"8086/12", CPU_8086, 3, 12000000, 1, 0, 0, 0},
90 {"8086/16", CPU_8086, 4, 16000000, 1, 0, 0, 0},
91 {"", -1, 0, 0, 0, 0}
92 };
94 CPU cpus_pc1512[] =
95 {
96 /*8086 Amstrad*/
97 {"8086/8", CPU_8086, 1, 8000000, 1, 0, 0, 0},
98 {"", -1, 0, 0, 0, 0}
99 };
101 CPU cpus_286[] =
102 {
103 /*286*/
104 {"286/6", CPU_286, 0, 6000000, 1, 0, 0, 0},
105 {"286/8", CPU_286, 1, 8000000, 1, 0, 0, 0},
106 {"286/10", CPU_286, 2, 10000000, 1, 0, 0, 0},
107 {"286/12", CPU_286, 3, 12000000, 1, 0, 0, 0},
108 {"286/16", CPU_286, 4, 16000000, 1, 0, 0, 0},
109 {"286/20", CPU_286, 5, 20000000, 1, 0, 0, 0},
110 {"286/25", CPU_286, 6, 25000000, 1, 0, 0, 0},
111 {"", -1, 0, 0, 0, 0}
112 };
114 CPU cpus_ibmat[] =
115 {
116 /*286*/
117 {"286/6", CPU_286, 0, 6000000, 1, 0, 0, 0},
118 {"286/8", CPU_286, 0, 8000000, 1, 0, 0, 0},
119 {"", -1, 0, 0, 0, 0}
120 };
122 CPU cpus_i386[] =
123 {
124 /*i386*/
125 {"i386SX/16", CPU_386SX, 0, 16000000, 1, 0x2308, 0, 0},
126 {"i386SX/20", CPU_386SX, 1, 20000000, 1, 0x2308, 0, 0},
127 {"i386SX/25", CPU_386SX, 2, 25000000, 1, 0x2308, 0, 0},
128 {"i386SX/33", CPU_386SX, 3, 33333333, 1, 0x2308, 0, 0},
129 {"i386DX/16", CPU_386DX, 0, 16000000, 1, 0x0308, 0, 0},
130 {"i386DX/20", CPU_386DX, 1, 20000000, 1, 0x0308, 0, 0},
131 {"i386DX/25", CPU_386DX, 2, 25000000, 1, 0x0308, 0, 0},
132 {"i386DX/33", CPU_386DX, 3, 33333333, 1, 0x0308, 0, 0},
133 {"", -1, 0, 0, 0}
134 };
136 CPU cpus_acer[] =
137 {
138 /*i386*/
139 {"i386SX/25", CPU_386SX, 2, 25000000, 1, 0x2308, 0, 0},
140 {"", -1, 0, 0, 0}
141 };
143 CPU cpus_Am386[] =
144 {
145 /*Am386*/
146 {"Am386SX/16", CPU_386SX, 0, 16000000, 1, 0x2308, 0, 0},
147 {"Am386SX/20", CPU_386SX, 1, 20000000, 1, 0x2308, 0, 0},
148 {"Am386SX/25", CPU_386SX, 2, 25000000, 1, 0x2308, 0, 0},
149 {"Am386SX/33", CPU_386SX, 3, 33333333, 1, 0x2308, 0, 0},
150 {"Am386SX/40", CPU_386SX, 4, 40000000, 1, 0x2308, 0, 0},
151 {"Am386DX/25", CPU_386DX, 2, 25000000, 1, 0x0308, 0, 0},
152 {"Am386DX/33", CPU_386DX, 3, 33333333, 1, 0x0308, 0, 0},
153 {"Am386DX/40", CPU_386DX, 4, 40000000, 1, 0x0308, 0, 0},
154 {"", -1, 0, 0, 0}
155 };
157 CPU cpus_486SDLC[] =
158 {
159 /*Cx486SLC/DLC*/
160 {"Cx486SLC/20", CPU_486SLC, 1, 20000000, 1, 0, 0, 0x0000},
161 {"Cx486SLC/25", CPU_486SLC, 2, 25000000, 1, 0, 0, 0x0000},
162 {"Cx486SLC/33", CPU_486SLC, 3, 33333333, 1, 0, 0, 0x0000},
163 {"Cx486SRx2/32", CPU_486SLC, 3, 32000000, 2, 0, 0, 0x0006},
164 {"Cx486SRx2/40", CPU_486SLC, 4, 40000000, 2, 0, 0, 0x0006},
165 {"Cx486SRx2/50", CPU_486SLC, 5, 50000000, 2, 0, 0, 0x0006},
166 {"Cx486DLC/25", CPU_486DLC, 2, 25000000, 1, 0, 0, 0x0001},
167 {"Cx486DLC/33", CPU_486DLC, 3, 33333333, 1, 0, 0, 0x0001},
168 {"Cx486DLC/40", CPU_486DLC, 4, 40000000, 1, 0, 0, 0x0001},
169 {"Cx486DRx2/32", CPU_486DLC, 3, 32000000, 2, 0, 0, 0x0007},
170 {"Cx486DRx2/40", CPU_486DLC, 4, 40000000, 2, 0, 0, 0x0007},
171 {"Cx486DRx2/50", CPU_486DLC, 5, 50000000, 2, 0, 0, 0x0007},
172 {"Cx486DRx2/66", CPU_486DLC, 6, 66666666, 2, 0, 0, 0x0007},
173 {"", -1, 0, 0, 0}
174 };
176 CPU cpus_i486[] =
177 {
178 /*i486*/
179 {"i486SX/16", CPU_i486SX, 0, 16000000, 1, 0x42a, 0, 0},
180 {"i486SX/20", CPU_i486SX, 1, 20000000, 1, 0x42a, 0, 0},
181 {"i486SX/25", CPU_i486SX, 2, 25000000, 1, 0x42a, 0, 0},
182 {"i486SX/33", CPU_i486SX, 3, 33333333, 1, 0x42a, 0, 0},
183 {"i486SX2/50", CPU_i486SX, 5, 50000000, 2, 0x45b, 0, 0},
184 {"i486DX/25", CPU_i486DX, 2, 25000000, 1, 0x404, 0, 0},
185 {"i486DX/33", CPU_i486DX, 3, 33333333, 1, 0x404, 0, 0},
186 {"i486DX/50", CPU_i486DX, 5, 50000000, 1, 0x404, 0, 0},
187 {"i486DX2/40", CPU_i486DX, 4, 40000000, 2, 0x430, 0, 0},
188 {"i486DX2/50", CPU_i486DX, 5, 50000000, 2, 0x430, 0, 0},
189 {"i486DX2/66", CPU_i486DX, 6, 66666666, 2, 0x430, 0, 0},
190 {"iDX4/75", CPU_i486DX, 7, 75000000, 3, 0x481, 0x481, 0}, /*CPUID available on DX4, >= 75 MHz*/
191 {"iDX4/100", CPU_i486DX,10, 100000000, 3, 0x481, 0x481, 0}, /*Is on some real Intel DX2s, limit here is pretty arbitary*/
192 {"", -1, 0, 0, 0}
193 };
195 CPU cpus_Am486[] =
196 {
197 /*Am486/5x86*/
198 {"Am486SX/33", CPU_Am486SX, 3, 33333333, 1, 0x42a, 0, 0},
199 {"Am486SX/40", CPU_Am486SX, 4, 40000000, 1, 0x42a, 0, 0},
200 {"Am486SX2/50", CPU_Am486SX, 5, 50000000, 2, 0x45b, 0x45b, 0}, /*CPUID available on SX2, DX2, DX4, 5x86, >= 50 MHz*/
201 {"Am486SX2/66", CPU_Am486SX, 6, 66666666, 2, 0x45b, 0x45b, 0}, /*Isn't on all real AMD SX2s and DX2s, availability here is pretty arbitary (and distinguishes them from the Intel chips)*/
202 {"Am486DX/33", CPU_Am486DX, 3, 33333333, 1, 0x430, 0, 0},
203 {"Am486DX/40", CPU_Am486DX, 4, 40000000, 1, 0x430, 0, 0},
204 {"Am486DX2/50", CPU_Am486DX, 5, 50000000, 2, 0x470, 0x470, 0},
205 {"Am486DX2/66", CPU_Am486DX, 6, 66666666, 2, 0x470, 0x470, 0},
206 {"Am486DX2/80", CPU_Am486DX, 8, 80000000, 2, 0x470, 0x470, 0},
207 {"Am486DX4/75", CPU_Am486DX, 7, 75000000, 3, 0x482, 0x482, 0},
208 {"Am486DX4/90", CPU_Am486DX, 9, 90000000, 3, 0x482, 0x482, 0},
209 {"Am486DX4/100", CPU_Am486DX, 10, 100000000, 3, 0x482, 0x482, 0},
210 {"Am486DX4/120", CPU_Am486DX, 11, 120000000, 3, 0x482, 0x482, 0},
211 {"Am5x86/P75", CPU_Am486DX, 12, 133333333, 4, 0x4e0, 0x4e0, 0},
212 {"Am5x86/P75+", CPU_Am486DX, 13, 150000000, 4, 0x4e0, 0x4e0, 0},
213 {"", -1, 0, 0, 0}
214 };
216 CPU cpus_Cx486[] =
217 {
218 /*Cx486/5x86*/
219 {"Cx486S/25", CPU_Cx486S, 2, 25000000, 1, 0x420, 0, 0x0010},
220 {"Cx486S/33", CPU_Cx486S, 3, 33333333, 1, 0x420, 0, 0x0010},
221 {"Cx486S/40", CPU_Cx486S, 4, 40000000, 1, 0x420, 0, 0x0010},
222 {"Cx486DX/33", CPU_Cx486DX, 3, 33333333, 1, 0x430, 0, 0x051a},
223 {"Cx486DX/40", CPU_Cx486DX, 4, 40000000, 1, 0x430, 0, 0x051a},
224 {"Cx486DX2/50", CPU_Cx486DX, 5, 50000000, 2, 0x430, 0, 0x081b},
225 {"Cx486DX2/66", CPU_Cx486DX, 6, 66666666, 2, 0x430, 0, 0x0b1b},
226 {"Cx486DX2/80", CPU_Cx486DX, 8, 80000000, 2, 0x430, 0, 0x311b},
227 {"Cx486DX4/75", CPU_Cx486DX, 7, 75000000, 3, 0x480, 0, 0x361f},
228 {"Cx486DX4/100", CPU_Cx486DX, 10, 100000000, 3, 0x480, 0, 0x361f},
229 {"Cx5x86/100", CPU_Cx5x86, 10, 100000000, 3, 0x480, 0, 0x002f},
230 {"Cx5x86/120", CPU_Cx5x86, 11, 120000000, 3, 0x480, 0, 0x002f},
231 {"Cx5x86/133", CPU_Cx5x86, 12, 133333333, 4, 0x480, 0, 0x002f},
232 {"", -1, 0, 0, 0}
233 };
235 CPU cpus_WinChip[] =
236 {
237 /*IDT WinChip*/
238 {"WinChip 75", CPU_WINCHIP, 7, 75000000, 2, 0x540, 0x540, 0},
239 {"WinChip 90", CPU_WINCHIP, 9, 90000000, 2, 0x540, 0x540, 0},
240 {"WinChip 100", CPU_WINCHIP, 10, 100000000, 2, 0x540, 0x540, 0},
241 {"WinChip 120", CPU_WINCHIP, 11, 120000000, 2, 0x540, 0x540, 0},
242 {"WinChip 133", CPU_WINCHIP, 12, 133333333, 2, 0x540, 0x540, 0},
243 {"WinChip 150", CPU_WINCHIP, 13, 150000000, 3, 0x540, 0x540, 0},
244 {"WinChip 166", CPU_WINCHIP, 15, 166666666, 3, 0x540, 0x540, 0},
245 {"WinChip 180", CPU_WINCHIP, 16, 180000000, 3, 0x540, 0x540, 0},
246 {"WinChip 200", CPU_WINCHIP, 17, 200000000, 3, 0x540, 0x540, 0},
247 {"WinChip 225", CPU_WINCHIP, 17, 225000000, 3, 0x540, 0x540, 0},
248 {"WinChip 240", CPU_WINCHIP, 17, 240000000, 6, 0x540, 0x540, 0},
249 {"", -1, 0, 0, 0}
250 };
252 void cpu_set_edx()
253 {
254 EDX = models[model].cpu[cpu_manufacturer].cpus[cpu].edx_reset;
255 }
257 void cpu_set()
258 {
259 CPU *cpu_s = &models[model].cpu[cpu_manufacturer].cpus[cpu];
261 CPUID = cpu_s->cpuid_model;
262 cpuspeed = cpu_s->speed;
263 is8086 = (cpu_s->cpu_type >= CPU_8088);
264 is486 = (cpu_s->cpu_type >= CPU_i486SX) || (cpu_s->cpu_type == CPU_486SLC || cpu_s->cpu_type == CPU_486DLC);
265 hasfpu = (cpu_s->cpu_type >= CPU_i486DX);
266 cpu_iscyrix = (cpu_s->cpu_type == CPU_486SLC || cpu_s->cpu_type == CPU_486DLC || cpu_s->cpu_type == CPU_Cx486S || cpu_s->cpu_type == CPU_Cx486DX || cpu_s->cpu_type == CPU_Cx5x86);
267 cpu_16bitbus = (cpu_s->cpu_type == CPU_386SX || cpu_s->cpu_type == CPU_486SLC);
268 if (cpu_s->multi)
269 cpu_busspeed = cpu_s->rspeed / cpu_s->multi;
270 cpu_multi = cpu_s->multi;
271 cpu_hasrdtsc = 0;
272 cpu_hasMMX = 0;
273 cpu_hasMSR = 0;
274 cpu_hasCR4 = 0;
276 if (cpu_iscyrix)
277 io_sethandler(0x0022, 0x0002, cyrix_read, NULL, NULL, cyrix_write, NULL, NULL, NULL);
278 else
279 io_removehandler(0x0022, 0x0002, cyrix_read, NULL, NULL, cyrix_write, NULL, NULL, NULL);
281 pclog("hasfpu - %i\n",hasfpu);
282 pclog("is486 - %i %i\n",is486,cpu_s->cpu_type);
284 x86_setopcodes(ops_386, ops_386_0f);
286 memset(&msr, 0, sizeof(msr));
288 switch (cpu_s->cpu_type)
289 {
290 case CPU_8088:
291 case CPU_8086:
292 break;
294 case CPU_286:
295 x86_setopcodes(ops_286, ops_286_0f);
296 timing_rr = 2; /*register dest - register src*/
297 timing_rm = 7; /*register dest - memory src*/
298 timing_mr = 7; /*memory dest - register src*/
299 timing_mm = 7; /*memory dest - memory src*/
300 timing_rml = 9; /*register dest - memory src long*/
301 timing_mrl = 11; /*memory dest - register src long*/
302 timing_mml = 11; /*memory dest - memory src*/
303 timing_bt = 7-3; /*branch taken*/
304 timing_bnt = 3; /*branch not taken*/
305 break;
307 case CPU_386SX:
308 timing_rr = 2; /*register dest - register src*/
309 timing_rm = 6; /*register dest - memory src*/
310 timing_mr = 7; /*memory dest - register src*/
311 timing_mm = 6; /*memory dest - memory src*/
312 timing_rml = 8; /*register dest - memory src long*/
313 timing_mrl = 11; /*memory dest - register src long*/
314 timing_mml = 10; /*memory dest - memory src*/
315 timing_bt = 7-3; /*branch taken*/
316 timing_bnt = 3; /*branch not taken*/
317 break;
319 case CPU_386DX:
320 timing_rr = 2; /*register dest - register src*/
321 timing_rm = 6; /*register dest - memory src*/
322 timing_mr = 7; /*memory dest - register src*/
323 timing_mm = 6; /*memory dest - memory src*/
324 timing_rml = 6; /*register dest - memory src long*/
325 timing_mrl = 7; /*memory dest - register src long*/
326 timing_mml = 6; /*memory dest - memory src*/
327 timing_bt = 7-3; /*branch taken*/
328 timing_bnt = 3; /*branch not taken*/
329 break;
331 case CPU_486SLC:
332 timing_rr = 1; /*register dest - register src*/
333 timing_rm = 3; /*register dest - memory src*/
334 timing_mr = 5; /*memory dest - register src*/
335 timing_mm = 3;
336 timing_rml = 5; /*register dest - memory src long*/
337 timing_mrl = 7; /*memory dest - register src long*/
338 timing_mml = 7;
339 timing_bt = 6-1; /*branch taken*/
340 timing_bnt = 1; /*branch not taken*/
341 break;
343 case CPU_486DLC:
344 timing_rr = 1; /*register dest - register src*/
345 timing_rm = 3; /*register dest - memory src*/
346 timing_mr = 3; /*memory dest - register src*/
347 timing_mm = 3;
348 timing_rml = 3; /*register dest - memory src long*/
349 timing_mrl = 3; /*memory dest - register src long*/
350 timing_mml = 3;
351 timing_bt = 6-1; /*branch taken*/
352 timing_bnt = 1; /*branch not taken*/
353 break;
355 case CPU_i486SX:
356 case CPU_i486DX:
357 timing_rr = 1; /*register dest - register src*/
358 timing_rm = 2; /*register dest - memory src*/
359 timing_mr = 3; /*memory dest - register src*/
360 timing_mm = 3;
361 timing_rml = 2; /*register dest - memory src long*/
362 timing_mrl = 3; /*memory dest - register src long*/
363 timing_mml = 3;
364 timing_bt = 3-1; /*branch taken*/
365 timing_bnt = 1; /*branch not taken*/
366 break;
368 case CPU_Am486SX:
369 case CPU_Am486DX:
370 /*AMD timing identical to Intel*/
371 timing_rr = 1; /*register dest - register src*/
372 timing_rm = 2; /*register dest - memory src*/
373 timing_mr = 3; /*memory dest - register src*/
374 timing_mm = 3;
375 timing_rml = 2; /*register dest - memory src long*/
376 timing_mrl = 3; /*memory dest - register src long*/
377 timing_mml = 3;
378 timing_bt = 3-1; /*branch taken*/
379 timing_bnt = 1; /*branch not taken*/
380 break;
382 case CPU_Cx486S:
383 case CPU_Cx486DX:
384 timing_rr = 1; /*register dest - register src*/
385 timing_rm = 3; /*register dest - memory src*/
386 timing_mr = 3; /*memory dest - register src*/
387 timing_mm = 3;
388 timing_rml = 3; /*register dest - memory src long*/
389 timing_mrl = 3; /*memory dest - register src long*/
390 timing_mml = 3;
391 timing_bt = 4-1; /*branch taken*/
392 timing_bnt = 1; /*branch not taken*/
393 break;
395 case CPU_Cx5x86:
396 timing_rr = 1; /*register dest - register src*/
397 timing_rm = 1; /*register dest - memory src*/
398 timing_mr = 2; /*memory dest - register src*/
399 timing_mm = 2;
400 timing_rml = 1; /*register dest - memory src long*/
401 timing_mrl = 2; /*memory dest - register src long*/
402 timing_mml = 2;
403 timing_bt = 5-1; /*branch taken*/
404 timing_bnt = 1; /*branch not taken*/
405 break;
407 case CPU_WINCHIP:
408 x86_setopcodes(ops_386, ops_winchip_0f);
409 timing_rr = 1; /*register dest - register src*/
410 timing_rm = 2; /*register dest - memory src*/
411 timing_mr = 3; /*memory dest - register src*/
412 timing_mm = 3;
413 timing_rml = 2; /*register dest - memory src long*/
414 timing_mrl = 3; /*memory dest - register src long*/
415 timing_mml = 3;
416 timing_bt = 3-1; /*branch taken*/
417 timing_bnt = 1; /*branch not taken*/
418 cpu_hasrdtsc = 1;
419 msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21);
420 cpu_hasMMX = cpu_hasMSR = 1;
421 cpu_hasCR4 = 1;
422 cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE;
423 break;
425 default:
426 fatal("cpu_set : unknown CPU type %i\n", cpu_s->cpu_type);
427 }
428 }
430 void cpu_CPUID()
431 {
432 switch (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type)
433 {
434 case CPU_i486DX:
435 if (!EAX)
436 {
437 EAX = 0x00000001;
438 EBX = 0x756e6547;
439 EDX = 0x49656e69;
440 ECX = 0x6c65746e;
441 }
442 else if (EAX == 1)
443 {
444 EAX = CPUID;
445 EBX = ECX = 0;
446 EDX = CPUID_FPU; /*FPU*/
447 }
448 else
449 EAX = 0;
450 break;
452 case CPU_Am486SX:
453 if (!EAX)
454 {
455 EAX = 1;
456 EBX = 0x68747541;
457 ECX = 0x444D4163;
458 EDX = 0x69746E65;
459 }
460 else if (EAX == 1)
461 {
462 EAX = CPUID;
463 EBX = ECX = EDX = 0; /*No FPU*/
464 }
465 else
466 EAX = 0;
467 break;
469 case CPU_Am486DX:
470 if (!EAX)
471 {
472 EAX = 1;
473 EBX = 0x68747541;
474 ECX = 0x444D4163;
475 EDX = 0x69746E65;
476 }
477 else if (EAX == 1)
478 {
479 EAX = CPUID;
480 EBX = ECX = 0;
481 EDX = CPUID_FPU; /*FPU*/
482 }
483 else
484 EAX = 0;
485 break;
487 case CPU_WINCHIP:
488 if (!EAX)
489 {
490 EAX = 1;
491 if (msr.fcr2 & (1 << 14))
492 {
493 EBX = msr.fcr3 >> 32;
494 ECX = msr.fcr3 & 0xffffffff;
495 EDX = msr.fcr2 >> 32;
496 }
497 else
498 {
499 EBX = 0x746e6543; /*CentaurHauls*/
500 ECX = 0x736c7561;
501 EDX = 0x48727561;
502 }
503 }
504 else if (EAX == 1)
505 {
506 EAX = 0x540;
507 EBX = ECX = 0;
508 EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR;
509 if (msr.fcr & (1 << 9))
510 EDX |= CPUID_MMX;
511 }
512 else
513 EAX = 0;
514 break;
515 }
516 }
518 void cpu_RDMSR()
519 {
520 switch (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type)
521 {
522 case CPU_WINCHIP:
523 EAX = EDX = 0;
524 switch (ECX)
525 {
526 case 0x02:
527 EAX = msr.tr1;
528 break;
529 case 0x0e:
530 EAX = msr.tr12;
531 break;
532 case 0x10:
533 EAX = tsc & 0xffffffff;
534 EDX = tsc >> 32;
535 break;
536 case 0x11:
537 EAX = msr.cesr;
538 break;
539 case 0x107:
540 EAX = msr.fcr;
541 break;
542 case 0x108:
543 EAX = msr.fcr2 & 0xffffffff;
544 EDX = msr.fcr2 >> 32;
545 break;
546 case 0x10a:
547 EAX = cpu_multi & 3;
548 break;
549 }
550 break;
551 }
552 }
554 void cpu_WRMSR()
555 {
556 switch (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type)
557 {
558 case CPU_WINCHIP:
559 switch (ECX)
560 {
561 case 0x02:
562 msr.tr1 = EAX & 2;
563 break;
564 case 0x0e:
565 msr.tr12 = EAX & 0x228;
566 break;
567 case 0x10:
568 tsc = EAX | ((uint64_t)EDX << 32);
569 break;
570 case 0x11:
571 msr.cesr = EAX & 0xff00ff;
572 break;
573 case 0x107:
574 msr.fcr = EAX;
575 cpu_hasMMX = EAX & (1 << 9);
576 if (EAX & (1 << 29))
577 CPUID = 0;
578 else
579 CPUID = models[model].cpu[cpu_manufacturer].cpus[cpu].cpuid_model;
580 break;
581 case 0x108:
582 msr.fcr2 = EAX | ((uint64_t)EDX << 32);
583 break;
584 case 0x109:
585 msr.fcr3 = EAX | ((uint64_t)EDX << 32);
586 break;
587 }
588 break;
589 }
590 }
592 static int cyrix_addr;
594 void cyrix_write(uint16_t addr, uint8_t val, void *priv)
595 {
596 if (!(addr & 1)) cyrix_addr = val;
597 // else pclog("Write Cyrix %02X %02X\n",cyrix_addr,val);
598 }
600 uint8_t cyrix_read(uint16_t addr, void *priv)
601 {
602 if (addr & 1)
603 {
604 switch (cyrix_addr)
605 {
606 case 0xfe: return models[model].cpu[cpu_manufacturer].cpus[cpu].cyrix_id & 0xff;
607 case 0xff: return models[model].cpu[cpu_manufacturer].cpus[cpu].cyrix_id >> 8;
608 }
609 if ((cyrix_addr & ~0xf0) == 0xc0) return 0xff;
610 if (cyrix_addr == 0x20 && models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_Cx5x86) return 0xff;
611 }
612 return 0xff;
613 }