PCem
view src/x86_ops_misc.h @ 142:bd46c39a78e8
Implemented selector limits on some instructions - fixes LBA2.
GPFs in real mode now work.
Selectors correctly zeroed on far return to lower privilege.
| author | TomW |
|---|---|
| date | Wed Aug 13 20:33:56 2014 +0100 |
| parents | 9bc3bcf7c871 |
| children | 1dda97300a32 |
line source
1 static int opCBW(uint32_t fetchdat)
2 {
3 AH = (AL & 0x80) ? 0xff : 0;
4 cycles -= 3;
5 return 0;
6 }
7 static int opCWDE(uint32_t fetchdat)
8 {
9 EAX = (AX & 0x8000) ? (0xffff0000 | AX) : AX;
10 cycles -= 3;
11 return 0;
12 }
13 static int opCWD(uint32_t fetchdat)
14 {
15 DX = (AX & 0x8000) ? 0xFFFF : 0;
16 cycles -= 2;
17 return 0;
18 }
19 static int opCDQ(uint32_t fetchdat)
20 {
21 EDX = (EAX & 0x80000000) ? 0xffffffff : 0;
22 cycles -= 2;
23 return 0;
24 }
26 static int opNOP(uint32_t fetchdat)
27 {
28 cycles -= (is486) ? 1 : 3;
29 return 0;
30 }
32 static int opSETALC(uint32_t fetchdat)
33 {
34 AL = (CF_SET()) ? 0xff : 0;
35 cycles -= timing_rr;
36 return 0;
37 }
41 static int opF6_a16(uint32_t fetchdat)
42 {
43 int tempws, tempws2;
44 uint16_t tempw, src16;
45 uint8_t src, dst;
46 int8_t temps;
48 fetch_ea_16(fetchdat);
49 dst = geteab(); if (abrt) return 0;
50 switch (rmdat & 0x38)
51 {
52 case 0x00: /*TEST b,#8*/
53 src = readmemb(cs, pc); pc++; if (abrt) return 0;
54 setznp8(src & dst);
55 if (is486) cycles -= ((mod == 3) ? 1 : 2);
56 else cycles -= ((mod == 3) ? 2 : 5);
57 break;
58 case 0x10: /*NOT b*/
59 seteab(~dst);
60 cycles -= (mod == 3) ? timing_rr : timing_mm;
61 break;
62 case 0x18: /*NEG b*/
63 setsub8(0, dst);
64 seteab(0 - dst);
65 cycles -= (mod == 3) ? timing_rr : timing_mm;
66 break;
67 case 0x20: /*MUL AL,b*/
68 AX = AL * dst;
69 flags_rebuild();
70 if (AH) flags |= (C_FLAG | V_FLAG);
71 else flags &= ~(C_FLAG | V_FLAG);
72 cycles -= 13;
73 break;
74 case 0x28: /*IMUL AL,b*/
75 tempws = (int)((int8_t)AL) * (int)((int8_t)dst);
76 AX = tempws & 0xffff;
77 flags_rebuild();
78 if (AH && AH != 0xff) flags |= (C_FLAG | V_FLAG);
79 else flags &= ~(C_FLAG | V_FLAG);
80 cycles -= 14;
81 break;
82 case 0x30: /*DIV AL,b*/
83 src16 = AX;
84 if (dst) tempw = src16 / dst;
85 if (dst && !(tempw & 0xff00))
86 {
87 AH = src16 % dst;
88 AL = (src16 / dst) &0xff;
89 if (!cpu_iscyrix)
90 {
91 flags_rebuild();
92 flags |= 0x8D5; /*Not a Cyrix*/
93 }
94 }
95 else
96 {
97 x86_int(0);
98 }
99 cycles -= is486 ? 16 : 14;
100 break;
101 case 0x38: /*IDIV AL,b*/
102 tempws = (int)(int16_t)AX;
103 if (dst != 0) tempws2 = tempws / (int)((int8_t)dst);
104 temps = tempws2 & 0xff;
105 if (dst && ((int)temps == tempws2))
106 {
107 AH = (tempws % (int)((int8_t)dst)) & 0xff;
108 AL = tempws2 & 0xff;
109 if (!cpu_iscyrix)
110 {
111 flags_rebuild();
112 flags|=0x8D5; /*Not a Cyrix*/
113 }
114 }
115 else
116 {
117 // pclog("IDIVb exception - %X / %08X = %X\n", tempws, dst, tempws2);
118 x86_int(0);
119 }
120 cycles -= 19;
121 break;
123 default:
124 pclog("Bad F6 opcode %02X\n", rmdat & 0x38);
125 x86illegal();
126 }
127 return 0;
128 }
129 static int opF6_a32(uint32_t fetchdat)
130 {
131 int tempws, tempws2;
132 uint16_t tempw, src16;
133 uint8_t src, dst;
134 int8_t temps;
136 fetch_ea_32(fetchdat);
137 dst = geteab(); if (abrt) return 0;
138 switch (rmdat & 0x38)
139 {
140 case 0x00: /*TEST b,#8*/
141 src = readmemb(cs, pc); pc++; if (abrt) return 0;
142 setznp8(src & dst);
143 if (is486) cycles -= ((mod == 3) ? 1 : 2);
144 else cycles -= ((mod == 3) ? 2 : 5);
145 break;
146 case 0x10: /*NOT b*/
147 seteab(~dst);
148 cycles -= (mod == 3) ? timing_rr : timing_mm;
149 break;
150 case 0x18: /*NEG b*/
151 setsub8(0, dst);
152 seteab(0 - dst);
153 cycles -= (mod == 3) ? timing_rr : timing_mm;
154 break;
155 case 0x20: /*MUL AL,b*/
156 AX = AL * dst;
157 flags_rebuild();
158 if (AH) flags |= (C_FLAG | V_FLAG);
159 else flags &= ~(C_FLAG | V_FLAG);
160 cycles -= 13;
161 break;
162 case 0x28: /*IMUL AL,b*/
163 tempws = (int)((int8_t)AL) * (int)((int8_t)dst);
164 AX = tempws & 0xffff;
165 flags_rebuild();
166 if (AH && AH != 0xff) flags |= (C_FLAG | V_FLAG);
167 else flags &= ~(C_FLAG | V_FLAG);
168 cycles -= 14;
169 break;
170 case 0x30: /*DIV AL,b*/
171 src16 = AX;
172 if (dst) tempw = src16 / dst;
173 if (dst && !(tempw & 0xff00))
174 {
175 AH = src16 % dst;
176 AL = (src16 / dst) &0xff;
177 if (!cpu_iscyrix)
178 {
179 flags_rebuild();
180 flags |= 0x8D5; /*Not a Cyrix*/
181 }
182 }
183 else
184 {
185 x86_int(0);
186 }
187 cycles -= is486 ? 16 : 14;
188 break;
189 case 0x38: /*IDIV AL,b*/
190 tempws = (int)(int16_t)AX;
191 if (dst != 0) tempws2 = tempws / (int)((int8_t)dst);
192 temps = tempws2 & 0xff;
193 if (dst && ((int)temps == tempws2))
194 {
195 AH = (tempws % (int)((int8_t)dst)) & 0xff;
196 AL = tempws2 & 0xff;
197 if (!cpu_iscyrix)
198 {
199 flags_rebuild();
200 flags|=0x8D5; /*Not a Cyrix*/
201 }
202 }
203 else
204 {
205 // pclog("IDIVb exception - %X / %08X = %X\n", tempws, dst, tempws2);
206 x86_int(0);
207 }
208 cycles -= 19;
209 break;
211 default:
212 pclog("Bad F6 opcode %02X\n", rmdat & 0x38);
213 x86illegal();
214 }
215 return 0;
216 }
220 static int opF7_w_a16(uint32_t fetchdat)
221 {
222 uint32_t templ, templ2;
223 int tempws, tempws2;
224 int16_t temps16;
225 uint16_t src, dst;
227 fetch_ea_16(fetchdat);
228 dst = geteaw(); if (abrt) return 0;
229 switch (rmdat & 0x38)
230 {
231 case 0x00: /*TEST w*/
232 src = getword(); if (abrt) return 0;
233 setznp16(src & dst);
234 if (is486) cycles -= ((mod == 3) ? 1 : 2);
235 else cycles -= ((mod == 3) ? 2 : 5);
236 break;
237 case 0x10: /*NOT w*/
238 seteaw(~dst);
239 cycles -= (mod == 3) ? timing_rr : timing_mm;
240 break;
241 case 0x18: /*NEG w*/
242 setsub16(0, dst);
243 seteaw(0 - dst);
244 cycles -= (mod == 3) ? timing_rr : timing_mm;
245 break;
246 case 0x20: /*MUL AX,w*/
247 templ = AX * dst;
248 AX = templ & 0xFFFF;
249 DX = templ >> 16;
250 flags_rebuild();
251 if (DX) flags |= (C_FLAG | V_FLAG);
252 else flags &= ~(C_FLAG | V_FLAG);
253 cycles -= 21;
254 break;
255 case 0x28: /*IMUL AX,w*/
256 templ = (int)((int16_t)AX) * (int)((int16_t)dst);
257 AX = templ & 0xFFFF;
258 DX = templ >> 16;
259 flags_rebuild();
260 if (DX && DX != 0xFFFF) flags |= (C_FLAG | V_FLAG);
261 else flags &= ~(C_FLAG | V_FLAG);
262 cycles -= 22;
263 break;
264 case 0x30: /*DIV AX,w*/
265 templ = (DX << 16) | AX;
266 if (dst) templ2 = templ / dst;
267 if (dst && !(templ2 & 0xffff0000))
268 {
269 DX = templ % dst;
270 AX = (templ / dst) & 0xffff;
271 if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/
272 }
273 else
274 {
275 // fatal("DIVw BY 0 %04X:%04X %i\n",cs>>4,pc,ins);
276 x86_int(0);
277 }
278 cycles -= is486 ? 24 : 22;
279 break;
280 case 0x38: /*IDIV AX,w*/
281 tempws = (int)((DX << 16)|AX);
282 if (dst) tempws2 = tempws / (int)((int16_t)dst);
283 temps16 = tempws2 & 0xffff;
284 if ((dst != 0) && ((int)temps16 == tempws2))
285 {
286 DX = tempws % (int)((int16_t)dst);
287 AX = tempws2 & 0xffff;
288 if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/
289 }
290 else
291 {
292 // pclog("IDIVw exception - %X / %08X = %X\n",tempws, dst, tempws2);
293 x86_int(0);
294 }
295 cycles -= 27;
296 break;
298 default:
299 pclog("Bad F7 opcode %02X\n", rmdat & 0x38);
300 x86illegal();
301 }
302 return 0;
303 }
304 static int opF7_w_a32(uint32_t fetchdat)
305 {
306 uint32_t templ, templ2;
307 int tempws, tempws2;
308 int16_t temps16;
309 uint16_t src, dst;
311 fetch_ea_32(fetchdat);
312 dst = geteaw(); if (abrt) return 0;
313 switch (rmdat & 0x38)
314 {
315 case 0x00: /*TEST w*/
316 src = getword(); if (abrt) return 0;
317 setznp16(src & dst);
318 if (is486) cycles -= ((mod == 3) ? 1 : 2);
319 else cycles -= ((mod == 3) ? 2 : 5);
320 break;
321 case 0x10: /*NOT w*/
322 seteaw(~dst);
323 cycles -= (mod == 3) ? timing_rr : timing_mm;
324 break;
325 case 0x18: /*NEG w*/
326 setsub16(0, dst);
327 seteaw(0 - dst);
328 cycles -= (mod == 3) ? timing_rr : timing_mm;
329 break;
330 case 0x20: /*MUL AX,w*/
331 templ = AX * dst;
332 AX = templ & 0xFFFF;
333 DX = templ >> 16;
334 flags_rebuild();
335 if (DX) flags |= (C_FLAG | V_FLAG);
336 else flags &= ~(C_FLAG | V_FLAG);
337 cycles -= 21;
338 break;
339 case 0x28: /*IMUL AX,w*/
340 templ = (int)((int16_t)AX) * (int)((int16_t)dst);
341 AX = templ & 0xFFFF;
342 DX = templ >> 16;
343 flags_rebuild();
344 if (DX && DX != 0xFFFF) flags |= (C_FLAG | V_FLAG);
345 else flags &= ~(C_FLAG | V_FLAG);
346 cycles -= 22;
347 break;
348 case 0x30: /*DIV AX,w*/
349 templ = (DX << 16) | AX;
350 if (dst) templ2 = templ / dst;
351 if (dst && !(templ2 & 0xffff0000))
352 {
353 DX = templ % dst;
354 AX = (templ / dst) & 0xffff;
355 if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/
356 }
357 else
358 {
359 // fatal("DIVw BY 0 %04X:%04X %i\n",cs>>4,pc,ins);
360 x86_int(0);
361 }
362 cycles -= is486 ? 24 : 22;
363 break;
364 case 0x38: /*IDIV AX,w*/
365 tempws = (int)((DX << 16)|AX);
366 if (dst) tempws2 = tempws / (int)((int16_t)dst);
367 temps16 = tempws2 & 0xffff;
368 if ((dst != 0) && ((int)temps16 == tempws2))
369 {
370 DX = tempws % (int)((int16_t)dst);
371 AX = tempws2 & 0xffff;
372 if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/
373 }
374 else
375 {
376 // pclog("IDIVw exception - %X / %08X = %X\n", tempws, dst, tempws2);
377 x86_int(0);
378 }
379 cycles -= 27;
380 break;
382 default:
383 pclog("Bad F7 opcode %02X\n", rmdat & 0x38);
384 x86illegal();
385 }
386 return 0;
387 }
389 static int opF7_l_a16(uint32_t fetchdat)
390 {
391 uint64_t temp64;
392 uint32_t src, dst;
394 fetch_ea_16(fetchdat);
395 dst = geteal(); if (abrt) return 0;
397 switch (rmdat & 0x38)
398 {
399 case 0x00: /*TEST l*/
400 src = getlong(); if (abrt) return 0;
401 setznp32(src & dst);
402 if (is486) cycles -= ((mod == 3) ? 1 : 2);
403 else cycles -= ((mod == 3) ? 2 : 5);
404 break;
405 case 0x10: /*NOT l*/
406 seteal(~dst);
407 cycles -= (mod == 3) ? timing_rr : timing_mml;
408 break;
409 case 0x18: /*NEG l*/
410 setsub32(0, dst);
411 seteal(0 - dst);
412 cycles -= (mod == 3) ? timing_rr : timing_mml;
413 break;
414 case 0x20: /*MUL EAX,l*/
415 temp64 = (uint64_t)EAX * (uint64_t)dst;
416 EAX = temp64 & 0xffffffff;
417 EDX = temp64 >> 32;
418 flags_rebuild();
419 if (EDX) flags |= (C_FLAG|V_FLAG);
420 else flags &= ~(C_FLAG|V_FLAG);
421 cycles -= 21;
422 break;
423 case 0x28: /*IMUL EAX,l*/
424 temp64 = (int64_t)(int32_t)EAX * (int64_t)(int32_t)dst;
425 EAX = temp64 & 0xffffffff;
426 EDX = temp64 >> 32;
427 flags_rebuild();
428 if (EDX && EDX != 0xffffffff) flags |= (C_FLAG|V_FLAG);
429 else flags &= ~(C_FLAG|V_FLAG);
430 cycles -= 38;
431 break;
432 case 0x30: /*DIV EAX,l*/
433 divl(dst);
434 if (!cpu_iscyrix) setznp32(EAX); /*Not a Cyrix*/
435 cycles -= (is486) ? 40 : 38;
436 break;
437 case 0x38: /*IDIV EAX,l*/
438 idivl((int32_t)dst);
439 if (!cpu_iscyrix) setznp32(EAX); /*Not a Cyrix*/
440 cycles -= 43;
441 break;
443 default:
444 pclog("Bad F7 opcode %02X\n", rmdat & 0x38);
445 x86illegal();
446 }
447 return 0;
448 }
449 static int opF7_l_a32(uint32_t fetchdat)
450 {
451 uint64_t temp64;
452 uint32_t src, dst;
454 fetch_ea_32(fetchdat);
455 dst = geteal(); if (abrt) return 0;
457 switch (rmdat & 0x38)
458 {
459 case 0x00: /*TEST l*/
460 src = getlong(); if (abrt) return 0;
461 setznp32(src & dst);
462 if (is486) cycles -= ((mod == 3) ? 1 : 2);
463 else cycles -= ((mod == 3) ? 2 : 5);
464 break;
465 case 0x10: /*NOT l*/
466 seteal(~dst);
467 cycles -= (mod == 3) ? timing_rr : timing_mml;
468 break;
469 case 0x18: /*NEG l*/
470 setsub32(0, dst);
471 seteal(0 - dst);
472 cycles -= (mod == 3) ? timing_rr : timing_mml;
473 break;
474 case 0x20: /*MUL EAX,l*/
475 temp64 = (uint64_t)EAX * (uint64_t)dst;
476 EAX = temp64 & 0xffffffff;
477 EDX = temp64 >> 32;
478 flags_rebuild();
479 if (EDX) flags |= (C_FLAG|V_FLAG);
480 else flags &= ~(C_FLAG|V_FLAG);
481 cycles -= 21;
482 break;
483 case 0x28: /*IMUL EAX,l*/
484 temp64 = (int64_t)(int32_t)EAX * (int64_t)(int32_t)dst;
485 EAX = temp64 & 0xffffffff;
486 EDX = temp64 >> 32;
487 flags_rebuild();
488 if (EDX && EDX != 0xffffffff) flags |= (C_FLAG|V_FLAG);
489 else flags &= ~(C_FLAG|V_FLAG);
490 cycles -= 38;
491 break;
492 case 0x30: /*DIV EAX,l*/
493 divl(dst);
494 if (!cpu_iscyrix) setznp32(EAX); /*Not a Cyrix*/
495 cycles -= (is486) ? 40 : 38;
496 break;
497 case 0x38: /*IDIV EAX,l*/
498 idivl((int32_t)dst);
499 if (!cpu_iscyrix) setznp32(EAX); /*Not a Cyrix*/
500 cycles -= 43;
501 break;
503 default:
504 pclog("Bad F7 opcode %02X\n", rmdat & 0x38);
505 x86illegal();
506 }
507 return 0;
508 }
511 static int opHLT(uint32_t fetchdat)
512 {
513 if ((CPL || (eflags&VM_FLAG)) && (cr0&1))
514 {
515 x86gpf(NULL,0);
516 return 0;
517 }
518 if (!((flags&I_FLAG) && pic_intpending))
519 {
520 cycles -= 100;
521 pc--;
522 }
523 else
524 cycles -= 5;
525 return 0;
526 }
529 static int opLOCK(uint32_t fetchdat)
530 {
531 cycles -= 4;
532 return 0;
533 }
537 static int opBOUND_w_a16(uint32_t fetchdat)
538 {
539 int16_t low, high;
541 fetch_ea_16(fetchdat);
542 ILLEGAL_ON(mod == 3);
543 low = geteaw();
544 high = readmemw(easeg, eaaddr + 2); if (abrt) return 0;
546 if (((int16_t)regs[reg].w < low) || ((int16_t)regs[reg].w > high))
547 {
548 x86_int(5);
549 }
551 cycles -= is486 ? 7 : 10;
552 return 0;
553 }
554 static int opBOUND_w_a32(uint32_t fetchdat)
555 {
556 int16_t low, high;
558 fetch_ea_32(fetchdat);
559 ILLEGAL_ON(mod == 3);
560 low = geteaw();
561 high = readmemw(easeg, eaaddr + 2); if (abrt) return 0;
563 if (((int16_t)regs[reg].w < low) || ((int16_t)regs[reg].w > high))
564 {
565 x86_int(5);
566 }
568 cycles -= is486 ? 7 : 10;
569 return 0;
570 }
572 static int opBOUND_l_a16(uint32_t fetchdat)
573 {
574 int32_t low, high;
576 fetch_ea_16(fetchdat);
577 ILLEGAL_ON(mod == 3);
578 low = geteal();
579 high = readmeml(easeg, eaaddr + 4); if (abrt) return 0;
581 if (((int32_t)regs[reg].l < low) || ((int32_t)regs[reg].l > high))
582 {
583 x86_int(5);
584 }
586 cycles -= is486 ? 7 : 10;
587 return 0;
588 }
589 static int opBOUND_l_a32(uint32_t fetchdat)
590 {
591 int32_t low, high;
593 fetch_ea_32(fetchdat);
594 ILLEGAL_ON(mod == 3);
595 low = geteal();
596 high = readmeml(easeg, eaaddr + 4); if (abrt) return 0;
598 if (((int32_t)regs[reg].l < low) || ((int32_t)regs[reg].l > high))
599 {
600 x86_int(5);
601 }
603 cycles -= is486 ? 7 : 10;
604 return 0;
605 }
608 static int opCLTS(uint32_t fetchdat)
609 {
610 if ((CPL || (eflags&VM_FLAG)) && (cr0&1))
611 {
612 pclog("Can't CLTS\n");
613 x86gpf(NULL,0);
614 return 0;
615 }
616 cr0 &= ~8;
617 cycles -= 5;
618 return 0;
619 }
621 static int opINVD(uint32_t fetchdat)
622 {
623 if (!is486)
624 {
625 x86illegal();
626 return 0;
627 }
628 cycles -= 1000;
629 return 0;
630 }
631 static int opWBINVD(uint32_t fetchdat)
632 {
633 if (!is486)
634 {
635 x86illegal();
636 return 0;
637 }
638 cycles -= 10000;
639 return 0;
640 }
644 static int opLOADALL(uint32_t fetchdat)
645 {
646 flags = (readmemw(0, 0x818) & 0xffd5) | 2;
647 flags_extract();
648 pc = readmemw(0, 0x81A);
649 DS = readmemw(0, 0x81E);
650 SS = readmemw(0, 0x820);
651 CS = readmemw(0, 0x822);
652 ES = readmemw(0, 0x824);
653 DI = readmemw(0, 0x826);
654 SI = readmemw(0, 0x828);
655 BP = readmemw(0, 0x82A);
656 SP = readmemw(0, 0x82C);
657 BX = readmemw(0, 0x82E);
658 DX = readmemw(0, 0x830);
659 CX = readmemw(0, 0x832);
660 AX = readmemw(0, 0x834);
661 es = readmemw(0, 0x836) | (readmemb(0, 0x838) << 16);
662 cs = readmemw(0, 0x83C) | (readmemb(0, 0x83E) << 16);
663 ss = readmemw(0, 0x842) | (readmemb(0, 0x844) << 16);
664 ds = readmemw(0, 0x848) | (readmemb(0, 0x84A) << 16);
665 cycles-=195;
666 return 0;
667 }
669 static int opCPUID(uint32_t fetchdat)
670 {
671 if (CPUID)
672 {
673 cpu_CPUID();
674 cycles -= 9;
675 return 0;
676 }
677 pc = oldpc;
678 x86illegal();
679 return 0;
680 }
682 static int opRDMSR(uint32_t fetchdat)
683 {
684 if (cpu_hasMSR)
685 {
686 cpu_RDMSR();
687 cycles -= 9;
688 return 0;
689 }
690 pc = oldpc;
691 x86illegal();
692 return 0;
693 }
695 static int opWRMSR(uint32_t fetchdat)
696 {
697 if (cpu_hasMSR)
698 {
699 cpu_WRMSR();
700 cycles -= 9;
701 return 0;
702 }
703 pc = oldpc;
704 x86illegal();
705 return 0;
706 }
