[FAST486]: Code formatting only.
[reactos.git] / lib / fast486 / extraops.c
1 /*
2 * Fast486 386/486 CPU Emulation Library
3 * extraops.c
4 *
5 * Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22 /* INCLUDES *******************************************************************/
23
24 #include <windef.h>
25
26 // #define NDEBUG
27 #include <debug.h>
28
29 #include <fast486.h>
30 #include "opcodes.h"
31 #include "common.h"
32 #include "opgroups.h"
33 #include "extraops.h"
34
35 /* PUBLIC VARIABLES ***********************************************************/
36
37 FAST486_OPCODE_HANDLER_PROC
38 Fast486ExtendedHandlers[FAST486_NUM_OPCODE_HANDLERS] =
39 {
40 NULL, // TODO: OPCODE 0x00 NOT IMPLEMENTED
41 Fast486OpcodeGroup0F01,
42 NULL, // TODO: OPCODE 0x02 NOT IMPLEMENTED
43 NULL, // TODO: OPCODE 0x03 NOT IMPLEMENTED
44 NULL, // TODO: OPCODE 0x04 NOT IMPLEMENTED
45 NULL, // TODO: OPCODE 0x05 NOT IMPLEMENTED
46 Fast486ExtOpcodeClts,
47 NULL, // TODO: OPCODE 0x07 NOT IMPLEMENTED
48 NULL, // TODO: OPCODE 0x08 NOT IMPLEMENTED
49 NULL, // TODO: OPCODE 0x09 NOT IMPLEMENTED
50 NULL, // Invalid
51 NULL, // Reserved (UD1)
52 NULL, // Invalid
53 NULL, // Invalid
54 NULL, // Invalid
55 NULL, // Invalid
56 NULL, // TODO: OPCODE 0x10 NOT IMPLEMENTED
57 NULL, // TODO: OPCODE 0x11 NOT IMPLEMENTED
58 NULL, // TODO: OPCODE 0x12 NOT IMPLEMENTED
59 NULL, // TODO: OPCODE 0x13 NOT IMPLEMENTED
60 NULL, // Invalid
61 NULL, // Invalid
62 NULL, // Invalid
63 NULL, // Invalid
64 NULL, // Invalid
65 NULL, // Invalid
66 NULL, // Invalid
67 NULL, // Invalid
68 NULL, // Invalid
69 NULL, // Invalid
70 NULL, // Invalid
71 NULL, // Invalid
72 Fast486ExtOpcodeStoreControlReg,
73 Fast486ExtOpcodeStoreDebugReg,
74 Fast486ExtOpcodeLoadControlReg,
75 Fast486ExtOpcodeLoadDebugReg,
76 NULL, // TODO: OPCODE 0x24 NOT IMPLEMENTED
77 NULL, // Invalid
78 NULL, // TODO: OPCODE 0x26 NOT IMPLEMENTED
79 NULL, // Invalid
80 NULL, // Invalid
81 NULL, // Invalid
82 NULL, // Invalid
83 NULL, // Invalid
84 NULL, // Invalid
85 NULL, // Invalid
86 NULL, // Invalid
87 NULL, // Invalid
88 NULL, // Invalid
89 NULL, // Invalid
90 NULL, // Invalid
91 NULL, // Invalid
92 NULL, // Invalid
93 NULL, // Invalid
94 NULL, // Invalid
95 NULL, // Invalid
96 NULL, // Invalid
97 NULL, // Invalid
98 NULL, // Invalid
99 NULL, // Invalid
100 NULL, // Invalid
101 NULL, // Invalid
102 NULL, // Invalid
103 NULL, // Invalid
104 NULL, // Invalid
105 NULL, // Invalid
106 NULL, // Invalid
107 NULL, // Invalid
108 NULL, // Invalid
109 NULL, // Invalid
110 NULL, // Invalid
111 NULL, // Invalid
112 NULL, // Invalid
113 NULL, // Invalid
114 NULL, // Invalid
115 NULL, // Invalid
116 NULL, // Invalid
117 NULL, // Invalid
118 NULL, // Invalid
119 NULL, // Invalid
120 NULL, // Invalid
121 NULL, // Invalid
122 NULL, // Invalid
123 NULL, // Invalid
124 NULL, // Invalid
125 NULL, // Invalid
126 NULL, // Invalid
127 NULL, // Invalid
128 NULL, // Invalid
129 NULL, // Invalid
130 NULL, // Invalid
131 NULL, // Invalid
132 NULL, // Invalid
133 NULL, // Invalid
134 NULL, // Invalid
135 NULL, // Invalid
136 NULL, // Invalid
137 NULL, // Invalid
138 NULL, // Invalid
139 NULL, // Invalid
140 NULL, // Invalid
141 NULL, // Invalid
142 NULL, // Invalid
143 NULL, // Invalid
144 NULL, // Invalid
145 NULL, // Invalid
146 NULL, // Invalid
147 NULL, // Invalid
148 NULL, // Invalid
149 NULL, // Invalid
150 NULL, // Invalid
151 NULL, // Invalid
152 NULL, // Invalid
153 NULL, // Invalid
154 NULL, // Invalid
155 NULL, // Invalid
156 NULL, // Invalid
157 NULL, // Invalid
158 NULL, // Invalid
159 NULL, // Invalid
160 NULL, // Invalid
161 NULL, // Invalid
162 NULL, // Invalid
163 NULL, // Invalid
164 NULL, // Invalid
165 NULL, // Invalid
166 NULL, // Invalid
167 NULL, // Invalid
168 Fast486ExtOpcodeConditionalJmp,
169 Fast486ExtOpcodeConditionalJmp,
170 Fast486ExtOpcodeConditionalJmp,
171 Fast486ExtOpcodeConditionalJmp,
172 Fast486ExtOpcodeConditionalJmp,
173 Fast486ExtOpcodeConditionalJmp,
174 Fast486ExtOpcodeConditionalJmp,
175 Fast486ExtOpcodeConditionalJmp,
176 Fast486ExtOpcodeConditionalJmp,
177 Fast486ExtOpcodeConditionalJmp,
178 Fast486ExtOpcodeConditionalJmp,
179 Fast486ExtOpcodeConditionalJmp,
180 Fast486ExtOpcodeConditionalJmp,
181 Fast486ExtOpcodeConditionalJmp,
182 Fast486ExtOpcodeConditionalJmp,
183 Fast486ExtOpcodeConditionalJmp,
184 Fast486ExtOpcodeConditionalSet,
185 Fast486ExtOpcodeConditionalSet,
186 Fast486ExtOpcodeConditionalSet,
187 Fast486ExtOpcodeConditionalSet,
188 Fast486ExtOpcodeConditionalSet,
189 Fast486ExtOpcodeConditionalSet,
190 Fast486ExtOpcodeConditionalSet,
191 Fast486ExtOpcodeConditionalSet,
192 Fast486ExtOpcodeConditionalSet,
193 Fast486ExtOpcodeConditionalSet,
194 Fast486ExtOpcodeConditionalSet,
195 Fast486ExtOpcodeConditionalSet,
196 Fast486ExtOpcodeConditionalSet,
197 Fast486ExtOpcodeConditionalSet,
198 Fast486ExtOpcodeConditionalSet,
199 Fast486ExtOpcodeConditionalSet,
200 Fast486ExtOpcodePushFs,
201 Fast486ExtOpcodePopFs,
202 NULL, // Invalid
203 Fast486ExtOpcodeBitTest,
204 NULL, // TODO: OPCODE 0xA4 NOT IMPLEMENTED
205 NULL, // TODO: OPCODE 0xA5 NOT IMPLEMENTED
206 NULL, // Invalid
207 NULL, // Invalid
208 Fast486ExtOpcodePushGs,
209 Fast486ExtOpcodePopGs,
210 NULL, // Invalid
211 Fast486ExtOpcodeBts,
212 NULL, // TODO: OPCODE 0xAC NOT IMPLEMENTED
213 NULL, // TODO: OPCODE 0xAD NOT IMPLEMENTED
214 NULL, // TODO: OPCODE 0xAE NOT IMPLEMENTED
215 NULL, // TODO: OPCODE 0xAF NOT IMPLEMENTED
216 Fast486ExtOpcodeCmpXchgByte,
217 Fast486ExtOpcodeCmpXchg,
218 NULL, // TODO: OPCODE 0xB2 NOT IMPLEMENTED
219 Fast486ExtOpcodeBtr,
220 NULL, // TODO: OPCODE 0xB4 NOT IMPLEMENTED
221 NULL, // TODO: OPCODE 0xB5 NOT IMPLEMENTED
222 NULL, // TODO: OPCODE 0xB6 NOT IMPLEMENTED
223 NULL, // TODO: OPCODE 0xB7 NOT IMPLEMENTED
224 NULL, // TODO: OPCODE 0xB8 NOT IMPLEMENTED
225 Fast486OpcodeGroup0FB9,
226 Fast486OpcodeGroup0FBA,
227 Fast486ExtOpcodeBtc,
228 NULL, // TODO: OPCODE 0xBC NOT IMPLEMENTED
229 NULL, // TODO: OPCODE 0xBD NOT IMPLEMENTED
230 NULL, // TODO: OPCODE 0xBE NOT IMPLEMENTED
231 NULL, // TODO: OPCODE 0xBF NOT IMPLEMENTED
232 Fast486ExtOpcodeXaddByte,
233 Fast486ExtOpcodeXadd,
234 NULL, // Invalid
235 NULL, // Invalid
236 NULL, // Invalid
237 NULL, // Invalid
238 NULL, // Invalid
239 NULL, // Invalid
240 Fast486ExtOpcodeBswap,
241 Fast486ExtOpcodeBswap,
242 Fast486ExtOpcodeBswap,
243 Fast486ExtOpcodeBswap,
244 Fast486ExtOpcodeBswap,
245 Fast486ExtOpcodeBswap,
246 Fast486ExtOpcodeBswap,
247 Fast486ExtOpcodeBswap,
248 NULL, // Invalid
249 NULL, // Invalid
250 NULL, // Invalid
251 NULL, // Invalid
252 NULL, // Invalid
253 NULL, // Invalid
254 NULL, // Invalid
255 NULL, // Invalid
256 NULL, // Invalid
257 NULL, // Invalid
258 NULL, // Invalid
259 NULL, // Invalid
260 NULL, // Invalid
261 NULL, // Invalid
262 NULL, // Invalid
263 NULL, // Invalid
264 NULL, // Invalid
265 NULL, // Invalid
266 NULL, // Invalid
267 NULL, // Invalid
268 NULL, // Invalid
269 NULL, // Invalid
270 NULL, // Invalid
271 NULL, // Invalid
272 NULL, // Invalid
273 NULL, // Invalid
274 NULL, // Invalid
275 NULL, // Invalid
276 NULL, // Invalid
277 NULL, // Invalid
278 NULL, // Invalid
279 NULL, // Invalid
280 NULL, // Invalid
281 NULL, // Invalid
282 NULL, // Invalid
283 NULL, // Invalid
284 NULL, // Invalid
285 NULL, // Invalid
286 NULL, // Invalid
287 NULL, // Invalid
288 NULL, // Invalid
289 NULL, // Invalid
290 NULL, // Invalid
291 NULL, // Invalid
292 NULL, // Invalid
293 NULL, // Invalid
294 NULL, // Invalid
295 NULL, // Invalid
296 };
297
298 /* PUBLIC FUNCTIONS ***********************************************************/
299
300 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeClts)
301 {
302 NO_LOCK_PREFIX();
303
304 /* The current privilege level must be zero */
305 if (Fast486GetCurrentPrivLevel(State) != 0)
306 {
307 Fast486Exception(State, FAST486_EXCEPTION_GP);
308 return FALSE;
309 }
310
311 /* Clear the task switch bit */
312 State->ControlRegisters[FAST486_REG_CR0] &= ~FAST486_CR0_TS;
313
314 return TRUE;
315 }
316
317 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreControlReg)
318 {
319 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
320 FAST486_MOD_REG_RM ModRegRm;
321
322 NO_LOCK_PREFIX();
323 TOGGLE_ADSIZE(AddressSize);
324
325 /* Get the operands */
326 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
327 {
328 /* Exception occurred */
329 return FALSE;
330 }
331
332 /* The current privilege level must be zero */
333 if (Fast486GetCurrentPrivLevel(State) != 0)
334 {
335 Fast486Exception(State, FAST486_EXCEPTION_GP);
336 return FALSE;
337 }
338
339 if ((ModRegRm.Register == 1) || (ModRegRm.Register > 3))
340 {
341 /* CR1, CR4, CR5, CR6 and CR7 don't exist */
342 Fast486Exception(State, FAST486_EXCEPTION_UD);
343 return FALSE;
344 }
345
346 if (ModRegRm.Register != 0)
347 {
348 /* CR2 and CR3 and are stored in array indexes 1 and 2 */
349 ModRegRm.Register--;
350 }
351
352 /* Store the value of the control register */
353 State->GeneralRegs[ModRegRm.SecondRegister].Long = State->ControlRegisters[ModRegRm.Register];
354
355 /* Return success */
356 return TRUE;
357 }
358
359 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreDebugReg)
360 {
361 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
362 FAST486_MOD_REG_RM ModRegRm;
363
364 NO_LOCK_PREFIX();
365 TOGGLE_ADSIZE(AddressSize);
366
367 /* Get the operands */
368 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
369 {
370 /* Exception occurred */
371 return FALSE;
372 }
373
374 /* The current privilege level must be zero */
375 if (Fast486GetCurrentPrivLevel(State) != 0)
376 {
377 Fast486Exception(State, FAST486_EXCEPTION_GP);
378 return FALSE;
379 }
380
381 if ((ModRegRm.Register == 6) || (ModRegRm.Register == 7))
382 {
383 /* DR6 and DR7 are aliases to DR4 and DR5 */
384 ModRegRm.Register -= 2;
385 }
386
387 if (State->DebugRegisters[FAST486_REG_DR5] & FAST486_DR5_GD)
388 {
389 /* Disallow access to debug registers */
390 Fast486Exception(State, FAST486_EXCEPTION_GP);
391 return FALSE;
392 }
393
394 /* Store the value of the debug register */
395 State->GeneralRegs[ModRegRm.SecondRegister].Long = State->DebugRegisters[ModRegRm.Register];
396
397 /* Return success */
398 return TRUE;
399 }
400
401 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadControlReg)
402 {
403 ULONG Value;
404 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
405 FAST486_MOD_REG_RM ModRegRm;
406
407 NO_LOCK_PREFIX();
408 TOGGLE_ADSIZE(AddressSize);
409
410 /* Get the operands */
411 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
412 {
413 /* Exception occurred */
414 return FALSE;
415 }
416
417 /* The current privilege level must be zero */
418 if (Fast486GetCurrentPrivLevel(State) != 0)
419 {
420 Fast486Exception(State, FAST486_EXCEPTION_GP);
421 return FALSE;
422 }
423
424 if ((ModRegRm.Register == 1) || (ModRegRm.Register > 3))
425 {
426 /* CR1, CR4, CR5, CR6 and CR7 don't exist */
427 Fast486Exception(State, FAST486_EXCEPTION_UD);
428 return FALSE;
429 }
430
431 if (ModRegRm.Register != 0)
432 {
433 /* CR2 and CR3 and are stored in array indexes 1 and 2 */
434 ModRegRm.Register--;
435 }
436
437 /* Get the value */
438 Value = State->GeneralRegs[ModRegRm.SecondRegister].Long;
439
440 if (ModRegRm.Register == (INT)FAST486_REG_CR0)
441 {
442 /* CR0 checks */
443
444 if (((Value & (FAST486_CR0_PG | FAST486_CR0_PE)) == FAST486_CR0_PG)
445 || ((Value & (FAST486_CR0_CD | FAST486_CR0_NW)) == FAST486_CR0_NW))
446 {
447 /* Invalid value */
448 Fast486Exception(State, FAST486_EXCEPTION_GP);
449 return FALSE;
450 }
451 }
452
453 /* Load a value to the control register */
454 State->ControlRegisters[ModRegRm.Register] = Value;
455
456 /* Return success */
457 return TRUE;
458 }
459
460 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadDebugReg)
461 {
462 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
463 FAST486_MOD_REG_RM ModRegRm;
464
465 NO_LOCK_PREFIX();
466 TOGGLE_ADSIZE(AddressSize);
467
468 /* Get the operands */
469 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
470 {
471 /* Exception occurred */
472 return FALSE;
473 }
474
475 /* The current privilege level must be zero */
476 if (Fast486GetCurrentPrivLevel(State) != 0)
477 {
478 Fast486Exception(State, FAST486_EXCEPTION_GP);
479 return FALSE;
480 }
481
482 if ((ModRegRm.Register == 6) || (ModRegRm.Register == 7))
483 {
484 /* DR6 and DR7 are aliases to DR4 and DR5 */
485 ModRegRm.Register -= 2;
486 }
487
488 if (State->DebugRegisters[FAST486_REG_DR5] & FAST486_DR5_GD)
489 {
490 /* Disallow access to debug registers */
491 Fast486Exception(State, FAST486_EXCEPTION_GP);
492 return FALSE;
493 }
494
495 /* Load a value to the debug register */
496 State->DebugRegisters[ModRegRm.Register] = State->GeneralRegs[ModRegRm.SecondRegister].Long;
497
498 if (ModRegRm.Register == (INT)FAST486_REG_DR4)
499 {
500 /* The reserved bits are 1 */
501 State->DebugRegisters[ModRegRm.Register] |= FAST486_DR4_RESERVED;
502 }
503 else if (ModRegRm.Register == (INT)FAST486_REG_DR5)
504 {
505 /* The reserved bits are 0 */
506 State->DebugRegisters[ModRegRm.Register] &= ~FAST486_DR5_RESERVED;
507 }
508
509 /* Return success */
510 return TRUE;
511 }
512
513 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushFs)
514 {
515 /* Call the internal API */
516 return Fast486StackPush(State, State->SegmentRegs[FAST486_REG_FS].Selector);
517 }
518
519 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopFs)
520 {
521 ULONG NewSelector;
522
523 if (!Fast486StackPop(State, &NewSelector))
524 {
525 /* Exception occurred */
526 return FALSE;
527 }
528
529 /* Call the internal API */
530 return Fast486LoadSegment(State, FAST486_REG_FS, LOWORD(NewSelector));
531 }
532
533 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBitTest)
534 {
535 BOOLEAN OperandSize, AddressSize;
536 FAST486_MOD_REG_RM ModRegRm;
537 UINT DataSize;
538 ULONG BitNumber;
539
540 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
541 TOGGLE_OPSIZE(OperandSize);
542 TOGGLE_ADSIZE(AddressSize);
543
544 /* Get the number of bits */
545 if (OperandSize) DataSize = 32;
546 else DataSize = 16;
547
548 /* Get the operands */
549 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
550 {
551 /* Exception occurred */
552 return FALSE;
553 }
554
555 /* Get the bit number */
556 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
557 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
558
559 if (ModRegRm.Memory)
560 {
561 /*
562 * For memory operands, add the bit offset divided by
563 * the data size to the address
564 */
565 ModRegRm.MemoryAddress += BitNumber / DataSize;
566 }
567
568 /* Normalize the bit number */
569 BitNumber &= (1 << DataSize) - 1;
570
571 if (OperandSize)
572 {
573 ULONG Dummy, Value;
574
575 /* Read the value */
576 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
577 {
578 /* Exception occurred */
579 return FALSE;
580 }
581
582 /* Set CF to the bit value */
583 State->Flags.Cf = (Value >> BitNumber) & 1;
584 }
585 else
586 {
587 USHORT Dummy, Value;
588
589 /* Read the value */
590 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
591 {
592 /* Exception occurred */
593 return FALSE;
594 }
595
596 /* Set CF to the bit value */
597 State->Flags.Cf = (Value >> BitNumber) & 1;
598 }
599
600 /* Return success */
601 return TRUE;
602 }
603
604 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushGs)
605 {
606 /* Call the internal API */
607 return Fast486StackPush(State, State->SegmentRegs[FAST486_REG_GS].Selector);
608 }
609
610 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopGs)
611 {
612 ULONG NewSelector;
613
614 if (!Fast486StackPop(State, &NewSelector))
615 {
616 /* Exception occurred */
617 return FALSE;
618 }
619
620 /* Call the internal API */
621 return Fast486LoadSegment(State, FAST486_REG_GS, LOWORD(NewSelector));
622 }
623
624 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBts)
625 {
626 BOOLEAN OperandSize, AddressSize;
627 FAST486_MOD_REG_RM ModRegRm;
628 UINT DataSize;
629 ULONG BitNumber;
630
631 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
632 TOGGLE_OPSIZE(OperandSize);
633 TOGGLE_ADSIZE(AddressSize);
634
635 /* Get the number of bits */
636 if (OperandSize) DataSize = 32;
637 else DataSize = 16;
638
639 /* Get the operands */
640 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
641 {
642 /* Exception occurred */
643 return FALSE;
644 }
645
646 /* Get the bit number */
647 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
648 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
649
650 if (ModRegRm.Memory)
651 {
652 /*
653 * For memory operands, add the bit offset divided by
654 * the data size to the address
655 */
656 ModRegRm.MemoryAddress += BitNumber / DataSize;
657 }
658
659 /* Normalize the bit number */
660 BitNumber &= (1 << DataSize) - 1;
661
662 if (OperandSize)
663 {
664 ULONG Dummy, Value;
665
666 /* Read the value */
667 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
668 {
669 /* Exception occurred */
670 return FALSE;
671 }
672
673 /* Set CF to the bit value */
674 State->Flags.Cf = (Value >> BitNumber) & 1;
675
676 /* Set the bit */
677 Value |= 1 << BitNumber;
678
679 /* Write back the result */
680 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
681 {
682 /* Exception occurred */
683 return FALSE;
684 }
685 }
686 else
687 {
688 USHORT Dummy, Value;
689
690 /* Read the value */
691 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
692 {
693 /* Exception occurred */
694 return FALSE;
695 }
696
697 /* Set CF to the bit value */
698 State->Flags.Cf = (Value >> BitNumber) & 1;
699
700 /* Set the bit */
701 Value |= 1 << BitNumber;
702
703 /* Write back the result */
704 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
705 {
706 /* Exception occurred */
707 return FALSE;
708 }
709 }
710
711 /* Return success */
712 return TRUE;
713 }
714
715 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchgByte)
716 {
717 FAST486_MOD_REG_RM ModRegRm;
718 UCHAR Accumulator = State->GeneralRegs[FAST486_REG_EAX].LowByte;
719 UCHAR Source, Destination, Result;
720 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
721
722 TOGGLE_ADSIZE(AddressSize);
723
724 /* Get the operands */
725 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
726 {
727 /* Exception occurred */
728 return FALSE;
729 }
730
731 /* Read the operands */
732 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, &Source, &Destination))
733 {
734 /* Exception occurred */
735 return FALSE;
736 }
737
738 /* Compare AL with the destination */
739 Result = Accumulator - Destination;
740
741 /* Update the flags */
742 State->Flags.Cf = (Accumulator < Destination);
743 State->Flags.Of = ((Accumulator & SIGN_FLAG_BYTE) != (Destination & SIGN_FLAG_BYTE))
744 && ((Accumulator & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
745 State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F);
746 State->Flags.Zf = (Result == 0);
747 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
748 State->Flags.Pf = Fast486CalculateParity(Result);
749
750 if (State->Flags.Zf)
751 {
752 /* Load the source operand into the destination */
753 return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Source);
754 }
755 else
756 {
757 /* Load the destination into AL */
758 State->GeneralRegs[FAST486_REG_EAX].LowByte = Destination;
759 }
760
761 /* Return success */
762 return TRUE;
763 }
764
765 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchg)
766 {
767 FAST486_MOD_REG_RM ModRegRm;
768 BOOLEAN OperandSize, AddressSize;
769
770 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
771
772 TOGGLE_OPSIZE(OperandSize);
773 TOGGLE_ADSIZE(AddressSize);
774
775 /* Get the operands */
776 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
777 {
778 /* Exception occurred */
779 return FALSE;
780 }
781
782 if (OperandSize)
783 {
784 ULONG Source, Destination, Result;
785 ULONG Accumulator = State->GeneralRegs[FAST486_REG_EAX].Long;
786
787 /* Read the operands */
788 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Source, &Destination))
789 {
790 /* Exception occurred */
791 return FALSE;
792 }
793
794 /* Compare EAX with the destination */
795 Result = Accumulator - Destination;
796
797 /* Update the flags */
798 State->Flags.Cf = (Accumulator < Destination);
799 State->Flags.Of = ((Accumulator & SIGN_FLAG_LONG) != (Destination & SIGN_FLAG_LONG))
800 && ((Accumulator & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
801 State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F);
802 State->Flags.Zf = (Result == 0);
803 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
804 State->Flags.Pf = Fast486CalculateParity(Result);
805
806 if (State->Flags.Zf)
807 {
808 /* Load the source operand into the destination */
809 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Source);
810 }
811 else
812 {
813 /* Load the destination into EAX */
814 State->GeneralRegs[FAST486_REG_EAX].Long = Destination;
815 }
816 }
817 else
818 {
819 USHORT Source, Destination, Result;
820 USHORT Accumulator = State->GeneralRegs[FAST486_REG_EAX].LowWord;
821
822 /* Read the operands */
823 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Source, &Destination))
824 {
825 /* Exception occurred */
826 return FALSE;
827 }
828
829 /* Compare AX with the destination */
830 Result = Accumulator - Destination;
831
832 /* Update the flags */
833 State->Flags.Cf = (Accumulator < Destination);
834 State->Flags.Of = ((Accumulator & SIGN_FLAG_WORD) != (Destination & SIGN_FLAG_WORD))
835 && ((Accumulator & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
836 State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F);
837 State->Flags.Zf = (Result == 0);
838 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
839 State->Flags.Pf = Fast486CalculateParity(Result);
840
841 if (State->Flags.Zf)
842 {
843 /* Load the source operand into the destination */
844 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Source);
845 }
846 else
847 {
848 /* Load the destination into AX */
849 State->GeneralRegs[FAST486_REG_EAX].LowWord = Destination;
850 }
851 }
852
853 /* Return success */
854 return TRUE;
855 }
856
857 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtr)
858 {
859 BOOLEAN OperandSize, AddressSize;
860 FAST486_MOD_REG_RM ModRegRm;
861 UINT DataSize;
862 ULONG BitNumber;
863
864 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
865 TOGGLE_OPSIZE(OperandSize);
866 TOGGLE_ADSIZE(AddressSize);
867
868 /* Get the number of bits */
869 if (OperandSize) DataSize = 32;
870 else DataSize = 16;
871
872 /* Get the operands */
873 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
874 {
875 /* Exception occurred */
876 return FALSE;
877 }
878
879 /* Get the bit number */
880 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
881 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
882
883 if (ModRegRm.Memory)
884 {
885 /*
886 * For memory operands, add the bit offset divided by
887 * the data size to the address
888 */
889 ModRegRm.MemoryAddress += BitNumber / DataSize;
890 }
891
892 /* Normalize the bit number */
893 BitNumber &= (1 << DataSize) - 1;
894
895 if (OperandSize)
896 {
897 ULONG Dummy, Value;
898
899 /* Read the value */
900 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
901 {
902 /* Exception occurred */
903 return FALSE;
904 }
905
906 /* Set CF to the bit value */
907 State->Flags.Cf = (Value >> BitNumber) & 1;
908
909 /* Clear the bit */
910 Value &= ~(1 << BitNumber);
911
912 /* Write back the result */
913 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
914 {
915 /* Exception occurred */
916 return FALSE;
917 }
918 }
919 else
920 {
921 USHORT Dummy, Value;
922
923 /* Read the value */
924 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
925 {
926 /* Exception occurred */
927 return FALSE;
928 }
929
930 /* Set CF to the bit value */
931 State->Flags.Cf = (Value >> BitNumber) & 1;
932
933 /* Clear the bit */
934 Value &= ~(1 << BitNumber);
935
936 /* Write back the result */
937 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
938 {
939 /* Exception occurred */
940 return FALSE;
941 }
942 }
943
944 /* Return success */
945 return TRUE;
946 }
947
948 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtc)
949 {
950 BOOLEAN OperandSize, AddressSize;
951 FAST486_MOD_REG_RM ModRegRm;
952 UINT DataSize;
953 ULONG BitNumber;
954
955 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
956 TOGGLE_OPSIZE(OperandSize);
957 TOGGLE_ADSIZE(AddressSize);
958
959 /* Get the number of bits */
960 if (OperandSize) DataSize = 32;
961 else DataSize = 16;
962
963 /* Get the operands */
964 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
965 {
966 /* Exception occurred */
967 return FALSE;
968 }
969
970 /* Get the bit number */
971 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
972 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
973
974 if (ModRegRm.Memory)
975 {
976 /*
977 * For memory operands, add the bit offset divided by
978 * the data size to the address
979 */
980 ModRegRm.MemoryAddress += BitNumber / DataSize;
981 }
982
983 /* Normalize the bit number */
984 BitNumber &= (1 << DataSize) - 1;
985
986 if (OperandSize)
987 {
988 ULONG Dummy, Value;
989
990 /* Read the value */
991 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
992 {
993 /* Exception occurred */
994 return FALSE;
995 }
996
997 /* Set CF to the bit value */
998 State->Flags.Cf = (Value >> BitNumber) & 1;
999
1000 /* Toggle the bit */
1001 Value ^= 1 << BitNumber;
1002
1003 /* Write back the result */
1004 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
1005 {
1006 /* Exception occurred */
1007 return FALSE;
1008 }
1009 }
1010 else
1011 {
1012 USHORT Dummy, Value;
1013
1014 /* Read the value */
1015 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
1016 {
1017 /* Exception occurred */
1018 return FALSE;
1019 }
1020
1021 /* Set CF to the bit value */
1022 State->Flags.Cf = (Value >> BitNumber) & 1;
1023
1024 /* Toggle the bit */
1025 Value ^= 1 << BitNumber;
1026
1027 /* Write back the result */
1028 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
1029 {
1030 /* Exception occurred */
1031 return FALSE;
1032 }
1033 }
1034
1035 /* Return success */
1036 return TRUE;
1037 }
1038
1039 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalJmp)
1040 {
1041 BOOLEAN Jump = FALSE;
1042 LONG Offset = 0;
1043 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1044
1045 TOGGLE_OPSIZE(Size);
1046 NO_LOCK_PREFIX();
1047
1048 /* Make sure this is the right instruction */
1049 ASSERT((Opcode & 0xF0) == 0x80);
1050
1051 /* Fetch the offset */
1052 if (Size)
1053 {
1054 if (!Fast486FetchDword(State, (PULONG)&Offset))
1055 {
1056 /* Exception occurred */
1057 return FALSE;
1058 }
1059 }
1060 else
1061 {
1062 SHORT Value;
1063
1064 if (!Fast486FetchWord(State, (PUSHORT)&Value))
1065 {
1066 /* Exception occurred */
1067 return FALSE;
1068 }
1069
1070 /* Sign-extend */
1071 Offset = (LONG)Value;
1072 }
1073
1074 switch ((Opcode & 0x0F) >> 1)
1075 {
1076 /* JO / JNO */
1077 case 0:
1078 {
1079 Jump = State->Flags.Of;
1080 break;
1081 }
1082
1083 /* JC / JNC */
1084 case 1:
1085 {
1086 Jump = State->Flags.Cf;
1087 break;
1088 }
1089
1090 /* JZ / JNZ */
1091 case 2:
1092 {
1093 Jump = State->Flags.Zf;
1094 break;
1095 }
1096
1097 /* JBE / JNBE */
1098 case 3:
1099 {
1100 Jump = State->Flags.Cf || State->Flags.Zf;
1101 break;
1102 }
1103
1104 /* JS / JNS */
1105 case 4:
1106 {
1107 Jump = State->Flags.Sf;
1108 break;
1109 }
1110
1111 /* JP / JNP */
1112 case 5:
1113 {
1114 Jump = State->Flags.Pf;
1115 break;
1116 }
1117
1118 /* JL / JNL */
1119 case 6:
1120 {
1121 Jump = State->Flags.Sf != State->Flags.Of;
1122 break;
1123 }
1124
1125 /* JLE / JNLE */
1126 case 7:
1127 {
1128 Jump = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
1129 break;
1130 }
1131 }
1132
1133 if (Opcode & 1)
1134 {
1135 /* Invert the result */
1136 Jump = !Jump;
1137 }
1138
1139 if (Jump)
1140 {
1141 /* Move the instruction pointer */
1142 State->InstPtr.Long += Offset;
1143 }
1144
1145 /* Return success */
1146 return TRUE;
1147 }
1148
1149 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalSet)
1150 {
1151 BOOLEAN Value = FALSE;
1152 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1153 FAST486_MOD_REG_RM ModRegRm;
1154
1155 TOGGLE_ADSIZE(AddressSize);
1156
1157 /* Get the operands */
1158 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1159 {
1160 /* Exception occurred */
1161 return FALSE;
1162 }
1163
1164 /* Make sure this is the right instruction */
1165 ASSERT((Opcode & 0xF0) == 0x90);
1166
1167 switch ((Opcode & 0x0F) >> 1)
1168 {
1169 /* SETO / SETNO */
1170 case 0:
1171 {
1172 Value = State->Flags.Of;
1173 break;
1174 }
1175
1176 /* SETC / SETNC */
1177 case 1:
1178 {
1179 Value = State->Flags.Cf;
1180 break;
1181 }
1182
1183 /* SETZ / SETNZ */
1184 case 2:
1185 {
1186 Value = State->Flags.Zf;
1187 break;
1188 }
1189
1190 /* SETBE / SETNBE */
1191 case 3:
1192 {
1193 Value = State->Flags.Cf || State->Flags.Zf;
1194 break;
1195 }
1196
1197 /* SETS / SETNS */
1198 case 4:
1199 {
1200 Value = State->Flags.Sf;
1201 break;
1202 }
1203
1204 /* SETP / SETNP */
1205 case 5:
1206 {
1207 Value = State->Flags.Pf;
1208 break;
1209 }
1210
1211 /* SETL / SETNL */
1212 case 6:
1213 {
1214 Value = State->Flags.Sf != State->Flags.Of;
1215 break;
1216 }
1217
1218 /* SETLE / SETNLE */
1219 case 7:
1220 {
1221 Value = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
1222 break;
1223 }
1224 }
1225
1226 if (Opcode & 1)
1227 {
1228 /* Invert the result */
1229 Value = !Value;
1230 }
1231
1232 /* Write back the result */
1233 return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
1234 }
1235
1236 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXaddByte)
1237 {
1238 UCHAR Source, Destination, Result;
1239 FAST486_MOD_REG_RM ModRegRm;
1240 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1241
1242 /* Make sure this is the right instruction */
1243 ASSERT(Opcode == 0xC0);
1244
1245 TOGGLE_ADSIZE(AddressSize);
1246
1247 /* Get the operands */
1248 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1249 {
1250 /* Exception occurred */
1251 return FALSE;
1252 }
1253
1254 if (!Fast486ReadModrmByteOperands(State,
1255 &ModRegRm,
1256 &Source,
1257 &Destination))
1258 {
1259 /* Exception occurred */
1260 return FALSE;
1261 }
1262
1263 /* Calculate the result */
1264 Result = Source + Destination;
1265
1266 /* Update the flags */
1267 State->Flags.Cf = (Result < Source) && (Result < Destination);
1268 State->Flags.Of = ((Source & SIGN_FLAG_BYTE) == (Destination & SIGN_FLAG_BYTE))
1269 && ((Source & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
1270 State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0);
1271 State->Flags.Zf = (Result == 0);
1272 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1273 State->Flags.Pf = Fast486CalculateParity(Result);
1274
1275 /* Write the sum to the destination */
1276 if (!Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Result))
1277 {
1278 /* Exception occurred */
1279 return FALSE;
1280 }
1281
1282 /* Write the old value of the destination to the source */
1283 if (!Fast486WriteModrmByteOperands(State, &ModRegRm, TRUE, Destination))
1284 {
1285 /* Exception occurred */
1286 return FALSE;
1287 }
1288
1289 return TRUE;
1290 }
1291
1292 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXadd)
1293 {
1294 FAST486_MOD_REG_RM ModRegRm;
1295 BOOLEAN OperandSize, AddressSize;
1296
1297 /* Make sure this is the right instruction */
1298 ASSERT(Opcode == 0xC1);
1299
1300 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1301
1302 TOGGLE_ADSIZE(AddressSize);
1303 TOGGLE_OPSIZE(OperandSize);
1304
1305 /* Get the operands */
1306 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1307 {
1308 /* Exception occurred */
1309 return FALSE;
1310 }
1311
1312 /* Check the operand size */
1313 if (OperandSize)
1314 {
1315 ULONG Source, Destination, Result;
1316
1317 if (!Fast486ReadModrmDwordOperands(State,
1318 &ModRegRm,
1319 &Source,
1320 &Destination))
1321 {
1322 /* Exception occurred */
1323 return FALSE;
1324 }
1325
1326 /* Calculate the result */
1327 Result = Source + Destination;
1328
1329 /* Update the flags */
1330 State->Flags.Cf = (Result < Source) && (Result < Destination);
1331 State->Flags.Of = ((Source & SIGN_FLAG_LONG) == (Destination & SIGN_FLAG_LONG))
1332 && ((Source & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
1333 State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0);
1334 State->Flags.Zf = (Result == 0);
1335 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1336 State->Flags.Pf = Fast486CalculateParity(Result);
1337
1338 /* Write the sum to the destination */
1339 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result))
1340 {
1341 /* Exception occurred */
1342 return FALSE;
1343 }
1344
1345 /* Write the old value of the destination to the source */
1346 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, Destination))
1347 {
1348 /* Exception occurred */
1349 return FALSE;
1350 }
1351 }
1352 else
1353 {
1354 USHORT Source, Destination, Result;
1355
1356 if (!Fast486ReadModrmWordOperands(State,
1357 &ModRegRm,
1358 &Source,
1359 &Destination))
1360 {
1361 /* Exception occurred */
1362 return FALSE;
1363 }
1364
1365 /* Calculate the result */
1366 Result = Source + Destination;
1367
1368 /* Update the flags */
1369 State->Flags.Cf = (Result < Source) && (Result < Destination);
1370 State->Flags.Of = ((Source & SIGN_FLAG_WORD) == (Destination & SIGN_FLAG_WORD))
1371 && ((Source & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
1372 State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0);
1373 State->Flags.Zf = (Result == 0);
1374 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1375 State->Flags.Pf = Fast486CalculateParity(Result);
1376
1377 /* Write the sum to the destination */
1378 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Result))
1379 {
1380 /* Exception occurred */
1381 return FALSE;
1382 }
1383
1384 /* Write the old value of the destination to the source */
1385 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, Destination))
1386 {
1387 /* Exception occurred */
1388 return FALSE;
1389 }
1390 }
1391
1392 return TRUE;
1393 }
1394
1395 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBswap)
1396 {
1397 PUCHAR Pointer;
1398
1399 NO_LOCK_PREFIX();
1400
1401 /* Get a pointer to the value */
1402 Pointer = (PUCHAR)&State->GeneralRegs[Opcode & 0x07].Long;
1403
1404 /* Swap the byte order */
1405 SWAP(Pointer[0], Pointer[3]);
1406 SWAP(Pointer[1], Pointer[2]);
1407
1408 /* Return success */
1409 return TRUE;
1410 }
1411
1412 FAST486_OPCODE_HANDLER(Fast486OpcodeExtended)
1413 {
1414 UCHAR SecondOpcode;
1415
1416 /* Fetch the second operation code */
1417 if (!Fast486FetchByte(State, &SecondOpcode))
1418 {
1419 /* Exception occurred */
1420 return FALSE;
1421 }
1422
1423 if (Fast486ExtendedHandlers[SecondOpcode] != NULL)
1424 {
1425 /* Call the extended opcode handler */
1426 return Fast486ExtendedHandlers[SecondOpcode](State, SecondOpcode);
1427 }
1428 else
1429 {
1430 /* This is not a valid opcode */
1431 Fast486Exception(State, FAST486_EXCEPTION_UD);
1432 return FALSE;
1433 }
1434 }
1435