[FAST486]
[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, // Invalid
57 NULL, // Invalid
58 NULL, // Invalid
59 NULL, // Invalid
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 Fast486ExtOpcodeShld,
205 Fast486ExtOpcodeShld,
206 NULL, // Invalid
207 NULL, // Invalid
208 Fast486ExtOpcodePushGs,
209 Fast486ExtOpcodePopGs,
210 NULL, // Invalid
211 Fast486ExtOpcodeBts,
212 Fast486ExtOpcodeShrd,
213 Fast486ExtOpcodeShrd,
214 NULL, // TODO: OPCODE 0xAE NOT IMPLEMENTED
215 Fast486ExtOpcodeImul,
216 Fast486ExtOpcodeCmpXchgByte,
217 Fast486ExtOpcodeCmpXchg,
218 Fast486ExtOpcodeLss,
219 Fast486ExtOpcodeBtr,
220 Fast486ExtOpcodeLfsLgs,
221 Fast486ExtOpcodeLfsLgs,
222 Fast486ExtOpcodeMovzxByte,
223 Fast486ExtOpcodeMovzxWord,
224 NULL, // Invalid
225 Fast486OpcodeGroup0FB9,
226 Fast486OpcodeGroup0FBA,
227 Fast486ExtOpcodeBtc,
228 Fast486ExtOpcodeBsf,
229 Fast486ExtOpcodeBsr,
230 Fast486ExtOpcodeMovsxByte,
231 Fast486ExtOpcodeMovsxWord,
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 %= DataSize;
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(Fast486ExtOpcodeShld)
605 {
606 BOOLEAN OperandSize, AddressSize;
607 FAST486_MOD_REG_RM ModRegRm;
608 UCHAR Count;
609
610 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
611 TOGGLE_OPSIZE(OperandSize);
612 TOGGLE_ADSIZE(AddressSize);
613
614 /* Make sure this is the right instruction */
615 ASSERT((Opcode & 0xFE) == 0xA4);
616
617 /* Get the operands */
618 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
619 {
620 /* Exception occurred */
621 return FALSE;
622 }
623
624 if (Opcode == 0xA4)
625 {
626 /* Fetch the count */
627 if (!Fast486FetchByte(State, &Count))
628 {
629 /* Exception occurred */
630 return FALSE;
631 }
632 }
633 else
634 {
635 /* The count is in CL */
636 Count = State->GeneralRegs[FAST486_REG_ECX].LowByte;
637 }
638
639 /* Normalize the count */
640 Count &= 0x1F;
641
642 /* Do nothing if the count is zero */
643 if (Count == 0) return TRUE;
644
645 if (OperandSize)
646 {
647 ULONG Source, Destination, Result;
648
649 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Source, &Destination))
650 {
651 /* Exception occurred */
652 return FALSE;
653 }
654
655 /* Calculate the result */
656 Result = (Destination << Count) | (Source >> (32 - Count));
657
658 /* Update flags */
659 State->Flags.Cf = (Destination >> (32 - Count)) & 1;
660 if (Count == 1) State->Flags.Of = (Result & SIGN_FLAG_LONG)
661 != (Destination & SIGN_FLAG_LONG);
662 State->Flags.Zf = (Result == 0);
663 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
664 State->Flags.Pf = Fast486CalculateParity(Result);
665
666 /* Write back the result */
667 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result);
668 }
669 else
670 {
671 USHORT Source, Destination, Result;
672
673 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Source, &Destination))
674 {
675 /* Exception occurred */
676 return FALSE;
677 }
678
679 /* Calculate the result */
680 Result = (Destination << Count) | (Source >> (16 - Count));
681
682 /* Update flags */
683 State->Flags.Cf = (Destination >> (16 - Count)) & 1;
684 if (Count == 1) State->Flags.Of = (Result & SIGN_FLAG_WORD)
685 != (Destination & SIGN_FLAG_WORD);
686 State->Flags.Zf = (Result == 0);
687 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
688 State->Flags.Pf = Fast486CalculateParity(Result);
689
690 /* Write back the result */
691 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Result);
692 }
693 }
694
695 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushGs)
696 {
697 /* Call the internal API */
698 return Fast486StackPush(State, State->SegmentRegs[FAST486_REG_GS].Selector);
699 }
700
701 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopGs)
702 {
703 ULONG NewSelector;
704
705 if (!Fast486StackPop(State, &NewSelector))
706 {
707 /* Exception occurred */
708 return FALSE;
709 }
710
711 /* Call the internal API */
712 return Fast486LoadSegment(State, FAST486_REG_GS, LOWORD(NewSelector));
713 }
714
715 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBts)
716 {
717 BOOLEAN OperandSize, AddressSize;
718 FAST486_MOD_REG_RM ModRegRm;
719 UINT DataSize;
720 ULONG BitNumber;
721
722 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
723 TOGGLE_OPSIZE(OperandSize);
724 TOGGLE_ADSIZE(AddressSize);
725
726 /* Get the number of bits */
727 if (OperandSize) DataSize = 32;
728 else DataSize = 16;
729
730 /* Get the operands */
731 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
732 {
733 /* Exception occurred */
734 return FALSE;
735 }
736
737 /* Get the bit number */
738 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
739 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
740
741 if (ModRegRm.Memory)
742 {
743 /*
744 * For memory operands, add the bit offset divided by
745 * the data size to the address
746 */
747 ModRegRm.MemoryAddress += BitNumber / DataSize;
748 }
749
750 /* Normalize the bit number */
751 BitNumber %= DataSize;
752
753 if (OperandSize)
754 {
755 ULONG Dummy, Value;
756
757 /* Read the value */
758 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
759 {
760 /* Exception occurred */
761 return FALSE;
762 }
763
764 /* Set CF to the bit value */
765 State->Flags.Cf = (Value >> BitNumber) & 1;
766
767 /* Set the bit */
768 Value |= 1 << BitNumber;
769
770 /* Write back the result */
771 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
772 {
773 /* Exception occurred */
774 return FALSE;
775 }
776 }
777 else
778 {
779 USHORT Dummy, Value;
780
781 /* Read the value */
782 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
783 {
784 /* Exception occurred */
785 return FALSE;
786 }
787
788 /* Set CF to the bit value */
789 State->Flags.Cf = (Value >> BitNumber) & 1;
790
791 /* Set the bit */
792 Value |= 1 << BitNumber;
793
794 /* Write back the result */
795 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
796 {
797 /* Exception occurred */
798 return FALSE;
799 }
800 }
801
802 /* Return success */
803 return TRUE;
804 }
805
806 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShrd)
807 {
808 BOOLEAN OperandSize, AddressSize;
809 FAST486_MOD_REG_RM ModRegRm;
810 UCHAR Count;
811
812 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
813 TOGGLE_OPSIZE(OperandSize);
814 TOGGLE_ADSIZE(AddressSize);
815
816 /* Make sure this is the right instruction */
817 ASSERT((Opcode & 0xFE) == 0xAC);
818
819 /* Get the operands */
820 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
821 {
822 /* Exception occurred */
823 return FALSE;
824 }
825
826 if (Opcode == 0xAC)
827 {
828 /* Fetch the count */
829 if (!Fast486FetchByte(State, &Count))
830 {
831 /* Exception occurred */
832 return FALSE;
833 }
834 }
835 else
836 {
837 /* The count is in CL */
838 Count = State->GeneralRegs[FAST486_REG_ECX].LowByte;
839 }
840
841 /* Normalize the count */
842 Count &= 0x1F;
843
844 /* Do nothing if the count is zero */
845 if (Count == 0) return TRUE;
846
847 if (OperandSize)
848 {
849 ULONG Source, Destination, Result;
850
851 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Source, &Destination))
852 {
853 /* Exception occurred */
854 return FALSE;
855 }
856
857 /* Calculate the result */
858 Result = (Destination >> Count) | (Source << (32 - Count));
859
860 /* Update flags */
861 State->Flags.Cf = (Destination >> (Count - 1)) & 1;
862 if (Count == 1) State->Flags.Of = (Result & SIGN_FLAG_LONG)
863 != (Destination & SIGN_FLAG_LONG);
864 State->Flags.Zf = (Result == 0);
865 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
866 State->Flags.Pf = Fast486CalculateParity(Result);
867
868 /* Write back the result */
869 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result);
870 }
871 else
872 {
873 USHORT Source, Destination, Result;
874
875 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Source, &Destination))
876 {
877 /* Exception occurred */
878 return FALSE;
879 }
880
881 /* Calculate the result */
882 Result = (Destination >> Count) | (Source << (16 - Count));
883
884 /* Update flags */
885 State->Flags.Cf = (Result >> (Count - 1)) & 1;
886 if (Count == 1) State->Flags.Of = (Result & SIGN_FLAG_WORD)
887 != (Destination & SIGN_FLAG_WORD);
888 State->Flags.Zf = (Result == 0);
889 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
890 State->Flags.Pf = Fast486CalculateParity(Result);
891
892 /* Write back the result */
893 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Result);
894 }
895 }
896
897 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeImul)
898 {
899 BOOLEAN OperandSize, AddressSize;
900 FAST486_MOD_REG_RM ModRegRm;
901
902 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
903
904 TOGGLE_OPSIZE(OperandSize);
905 TOGGLE_ADSIZE(AddressSize);
906
907 /* Get the operands */
908 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
909 {
910 /* Exception occurred */
911 return FALSE;
912 }
913
914 if (OperandSize)
915 {
916 LONG Source, Destination;
917 LONGLONG Result;
918
919 /* Read the operands */
920 if (!Fast486ReadModrmDwordOperands(State,
921 &ModRegRm,
922 (PULONG)&Destination,
923 (PULONG)&Source))
924 {
925 /* Exception occurred */
926 return FALSE;
927 }
928
929 /* Calculate the result */
930 Result = (LONGLONG)Source * (LONGLONG)Destination;
931
932 /* Update the flags */
933 State->Flags.Cf = State->Flags.Of = ((Result < -2147483648LL) || (Result > 2147483647LL));
934
935 /* Write back the result */
936 return Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, (ULONG)((LONG)Result));
937 }
938 else
939 {
940 SHORT Source, Destination;
941 LONG Result;
942
943 /* Read the operands */
944 if (!Fast486ReadModrmWordOperands(State,
945 &ModRegRm,
946 (PUSHORT)&Destination,
947 (PUSHORT)&Source))
948 {
949 /* Exception occurred */
950 return FALSE;
951 }
952
953 /* Calculate the result */
954 Result = (LONG)Source * (LONG)Destination;
955
956 /* Update the flags */
957 State->Flags.Cf = State->Flags.Of = ((Result < -32768) || (Result > 32767));
958
959 /* Write back the result */
960 return Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, (USHORT)((SHORT)Result));
961 }
962 }
963
964 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchgByte)
965 {
966 FAST486_MOD_REG_RM ModRegRm;
967 UCHAR Accumulator = State->GeneralRegs[FAST486_REG_EAX].LowByte;
968 UCHAR Source, Destination, Result;
969 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
970
971 TOGGLE_ADSIZE(AddressSize);
972
973 /* Get the operands */
974 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
975 {
976 /* Exception occurred */
977 return FALSE;
978 }
979
980 /* Read the operands */
981 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, &Source, &Destination))
982 {
983 /* Exception occurred */
984 return FALSE;
985 }
986
987 /* Compare AL with the destination */
988 Result = Accumulator - Destination;
989
990 /* Update the flags */
991 State->Flags.Cf = (Accumulator < Destination);
992 State->Flags.Of = ((Accumulator & SIGN_FLAG_BYTE) != (Destination & SIGN_FLAG_BYTE))
993 && ((Accumulator & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
994 State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F);
995 State->Flags.Zf = (Result == 0);
996 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
997 State->Flags.Pf = Fast486CalculateParity(Result);
998
999 if (State->Flags.Zf)
1000 {
1001 /* Load the source operand into the destination */
1002 return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Source);
1003 }
1004 else
1005 {
1006 /* Load the destination into AL */
1007 State->GeneralRegs[FAST486_REG_EAX].LowByte = Destination;
1008 }
1009
1010 /* Return success */
1011 return TRUE;
1012 }
1013
1014 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchg)
1015 {
1016 FAST486_MOD_REG_RM ModRegRm;
1017 BOOLEAN OperandSize, AddressSize;
1018
1019 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1020
1021 TOGGLE_OPSIZE(OperandSize);
1022 TOGGLE_ADSIZE(AddressSize);
1023
1024 /* Get the operands */
1025 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1026 {
1027 /* Exception occurred */
1028 return FALSE;
1029 }
1030
1031 if (OperandSize)
1032 {
1033 ULONG Source, Destination, Result;
1034 ULONG Accumulator = State->GeneralRegs[FAST486_REG_EAX].Long;
1035
1036 /* Read the operands */
1037 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Source, &Destination))
1038 {
1039 /* Exception occurred */
1040 return FALSE;
1041 }
1042
1043 /* Compare EAX with the destination */
1044 Result = Accumulator - Destination;
1045
1046 /* Update the flags */
1047 State->Flags.Cf = (Accumulator < Destination);
1048 State->Flags.Of = ((Accumulator & SIGN_FLAG_LONG) != (Destination & SIGN_FLAG_LONG))
1049 && ((Accumulator & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
1050 State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F);
1051 State->Flags.Zf = (Result == 0);
1052 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1053 State->Flags.Pf = Fast486CalculateParity(Result);
1054
1055 if (State->Flags.Zf)
1056 {
1057 /* Load the source operand into the destination */
1058 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Source);
1059 }
1060 else
1061 {
1062 /* Load the destination into EAX */
1063 State->GeneralRegs[FAST486_REG_EAX].Long = Destination;
1064 }
1065 }
1066 else
1067 {
1068 USHORT Source, Destination, Result;
1069 USHORT Accumulator = State->GeneralRegs[FAST486_REG_EAX].LowWord;
1070
1071 /* Read the operands */
1072 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Source, &Destination))
1073 {
1074 /* Exception occurred */
1075 return FALSE;
1076 }
1077
1078 /* Compare AX with the destination */
1079 Result = Accumulator - Destination;
1080
1081 /* Update the flags */
1082 State->Flags.Cf = (Accumulator < Destination);
1083 State->Flags.Of = ((Accumulator & SIGN_FLAG_WORD) != (Destination & SIGN_FLAG_WORD))
1084 && ((Accumulator & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
1085 State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F);
1086 State->Flags.Zf = (Result == 0);
1087 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1088 State->Flags.Pf = Fast486CalculateParity(Result);
1089
1090 if (State->Flags.Zf)
1091 {
1092 /* Load the source operand into the destination */
1093 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Source);
1094 }
1095 else
1096 {
1097 /* Load the destination into AX */
1098 State->GeneralRegs[FAST486_REG_EAX].LowWord = Destination;
1099 }
1100 }
1101
1102 /* Return success */
1103 return TRUE;
1104 }
1105
1106 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLss)
1107 {
1108 UCHAR FarPointer[6];
1109 BOOLEAN OperandSize, AddressSize;
1110 FAST486_MOD_REG_RM ModRegRm;
1111
1112 /* Make sure this is the right instruction */
1113 ASSERT(Opcode == 0xB2);
1114
1115 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1116
1117 TOGGLE_OPSIZE(OperandSize);
1118 TOGGLE_ADSIZE(AddressSize);
1119
1120 /* Get the operands */
1121 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1122 {
1123 /* Exception occurred */
1124 return FALSE;
1125 }
1126
1127 if (!ModRegRm.Memory)
1128 {
1129 /* Invalid */
1130 Fast486Exception(State, FAST486_EXCEPTION_UD);
1131 return FALSE;
1132 }
1133
1134 if (!Fast486ReadMemory(State,
1135 (State->PrefixFlags & FAST486_PREFIX_SEG)
1136 ? State->SegmentOverride : FAST486_REG_DS,
1137 ModRegRm.MemoryAddress,
1138 FALSE,
1139 FarPointer,
1140 OperandSize ? 6 : 4))
1141 {
1142 /* Exception occurred */
1143 return FALSE;
1144 }
1145
1146 if (OperandSize)
1147 {
1148 ULONG Offset = *((PULONG)FarPointer);
1149 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(ULONG)]);
1150
1151 /* Set the register to the offset */
1152 State->GeneralRegs[ModRegRm.Register].Long = Offset;
1153
1154 /* Load the segment */
1155 return Fast486LoadSegment(State,
1156 FAST486_REG_SS,
1157 Segment);
1158 }
1159 else
1160 {
1161 USHORT Offset = *((PUSHORT)FarPointer);
1162 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(USHORT)]);
1163
1164 /* Set the register to the offset */
1165 State->GeneralRegs[ModRegRm.Register].LowWord = Offset;
1166
1167 /* Load the segment */
1168 return Fast486LoadSegment(State,
1169 FAST486_REG_SS,
1170 Segment);
1171 }
1172 }
1173
1174 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtr)
1175 {
1176 BOOLEAN OperandSize, AddressSize;
1177 FAST486_MOD_REG_RM ModRegRm;
1178 UINT DataSize;
1179 ULONG BitNumber;
1180
1181 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1182 TOGGLE_OPSIZE(OperandSize);
1183 TOGGLE_ADSIZE(AddressSize);
1184
1185 /* Get the number of bits */
1186 if (OperandSize) DataSize = 32;
1187 else DataSize = 16;
1188
1189 /* Get the operands */
1190 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1191 {
1192 /* Exception occurred */
1193 return FALSE;
1194 }
1195
1196 /* Get the bit number */
1197 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
1198 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
1199
1200 if (ModRegRm.Memory)
1201 {
1202 /*
1203 * For memory operands, add the bit offset divided by
1204 * the data size to the address
1205 */
1206 ModRegRm.MemoryAddress += BitNumber / DataSize;
1207 }
1208
1209 /* Normalize the bit number */
1210 BitNumber %= DataSize;
1211
1212 if (OperandSize)
1213 {
1214 ULONG Dummy, Value;
1215
1216 /* Read the value */
1217 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
1218 {
1219 /* Exception occurred */
1220 return FALSE;
1221 }
1222
1223 /* Set CF to the bit value */
1224 State->Flags.Cf = (Value >> BitNumber) & 1;
1225
1226 /* Clear the bit */
1227 Value &= ~(1 << BitNumber);
1228
1229 /* Write back the result */
1230 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
1231 {
1232 /* Exception occurred */
1233 return FALSE;
1234 }
1235 }
1236 else
1237 {
1238 USHORT Dummy, Value;
1239
1240 /* Read the value */
1241 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
1242 {
1243 /* Exception occurred */
1244 return FALSE;
1245 }
1246
1247 /* Set CF to the bit value */
1248 State->Flags.Cf = (Value >> BitNumber) & 1;
1249
1250 /* Clear the bit */
1251 Value &= ~(1 << BitNumber);
1252
1253 /* Write back the result */
1254 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
1255 {
1256 /* Exception occurred */
1257 return FALSE;
1258 }
1259 }
1260
1261 /* Return success */
1262 return TRUE;
1263 }
1264
1265 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLfsLgs)
1266 {
1267 UCHAR FarPointer[6];
1268 BOOLEAN OperandSize, AddressSize;
1269 FAST486_MOD_REG_RM ModRegRm;
1270
1271 /* Make sure this is the right instruction */
1272 ASSERT((Opcode & 0xFE) == 0xB4);
1273
1274 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1275
1276 TOGGLE_OPSIZE(OperandSize);
1277 TOGGLE_ADSIZE(AddressSize);
1278
1279 /* Get the operands */
1280 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1281 {
1282 /* Exception occurred */
1283 return FALSE;
1284 }
1285
1286 if (!ModRegRm.Memory)
1287 {
1288 /* Invalid */
1289 Fast486Exception(State, FAST486_EXCEPTION_UD);
1290 return FALSE;
1291 }
1292
1293 if (!Fast486ReadMemory(State,
1294 (State->PrefixFlags & FAST486_PREFIX_SEG)
1295 ? State->SegmentOverride : FAST486_REG_DS,
1296 ModRegRm.MemoryAddress,
1297 FALSE,
1298 FarPointer,
1299 OperandSize ? 6 : 4))
1300 {
1301 /* Exception occurred */
1302 return FALSE;
1303 }
1304
1305 if (OperandSize)
1306 {
1307 ULONG Offset = *((PULONG)FarPointer);
1308 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(ULONG)]);
1309
1310 /* Set the register to the offset */
1311 State->GeneralRegs[ModRegRm.Register].Long = Offset;
1312
1313 /* Load the segment */
1314 return Fast486LoadSegment(State,
1315 (Opcode == 0xB4)
1316 ? FAST486_REG_FS : FAST486_REG_GS,
1317 Segment);
1318 }
1319 else
1320 {
1321 USHORT Offset = *((PUSHORT)FarPointer);
1322 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(USHORT)]);
1323
1324 /* Set the register to the offset */
1325 State->GeneralRegs[ModRegRm.Register].LowWord = Offset;
1326
1327 /* Load the segment */
1328 return Fast486LoadSegment(State,
1329 (Opcode == 0xB4)
1330 ? FAST486_REG_FS : FAST486_REG_GS,
1331 Segment);
1332 }
1333 }
1334
1335 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxByte)
1336 {
1337 UCHAR Dummy, Value;
1338 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1339 FAST486_MOD_REG_RM ModRegRm;
1340
1341 TOGGLE_ADSIZE(AddressSize);
1342
1343 /* Make sure this is the right instruction */
1344 ASSERT(Opcode == 0xB6);
1345
1346 /* Get the operands */
1347 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1348 {
1349 /* Exception occurred */
1350 return FALSE;
1351 }
1352
1353 /* Read the operands */
1354 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, &Dummy, &Value))
1355 {
1356 /* Exception occurred */
1357 return FALSE;
1358 }
1359
1360 /* Write back the zero-extended value */
1361 return Fast486WriteModrmDwordOperands(State,
1362 &ModRegRm,
1363 TRUE,
1364 (ULONG)Value);
1365 }
1366
1367 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxWord)
1368 {
1369 USHORT Dummy, Value;
1370 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1371 FAST486_MOD_REG_RM ModRegRm;
1372
1373 TOGGLE_ADSIZE(AddressSize);
1374
1375 /* Make sure this is the right instruction */
1376 ASSERT(Opcode == 0xB7);
1377
1378 /* Get the operands */
1379 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1380 {
1381 /* Exception occurred */
1382 return FALSE;
1383 }
1384
1385 /* Read the operands */
1386 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
1387 {
1388 /* Exception occurred */
1389 return FALSE;
1390 }
1391
1392 /* Write back the zero-extended value */
1393 return Fast486WriteModrmDwordOperands(State,
1394 &ModRegRm,
1395 TRUE,
1396 (ULONG)Value);
1397 }
1398
1399 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtc)
1400 {
1401 BOOLEAN OperandSize, AddressSize;
1402 FAST486_MOD_REG_RM ModRegRm;
1403 UINT DataSize;
1404 ULONG BitNumber;
1405
1406 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1407 TOGGLE_OPSIZE(OperandSize);
1408 TOGGLE_ADSIZE(AddressSize);
1409
1410 /* Get the number of bits */
1411 if (OperandSize) DataSize = 32;
1412 else DataSize = 16;
1413
1414 /* Get the operands */
1415 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1416 {
1417 /* Exception occurred */
1418 return FALSE;
1419 }
1420
1421 /* Get the bit number */
1422 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
1423 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
1424
1425 if (ModRegRm.Memory)
1426 {
1427 /*
1428 * For memory operands, add the bit offset divided by
1429 * the data size to the address
1430 */
1431 ModRegRm.MemoryAddress += BitNumber / DataSize;
1432 }
1433
1434 /* Normalize the bit number */
1435 BitNumber %= DataSize;
1436
1437 if (OperandSize)
1438 {
1439 ULONG Dummy, Value;
1440
1441 /* Read the value */
1442 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
1443 {
1444 /* Exception occurred */
1445 return FALSE;
1446 }
1447
1448 /* Set CF to the bit value */
1449 State->Flags.Cf = (Value >> BitNumber) & 1;
1450
1451 /* Toggle the bit */
1452 Value ^= 1 << BitNumber;
1453
1454 /* Write back the result */
1455 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
1456 {
1457 /* Exception occurred */
1458 return FALSE;
1459 }
1460 }
1461 else
1462 {
1463 USHORT Dummy, Value;
1464
1465 /* Read the value */
1466 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
1467 {
1468 /* Exception occurred */
1469 return FALSE;
1470 }
1471
1472 /* Set CF to the bit value */
1473 State->Flags.Cf = (Value >> BitNumber) & 1;
1474
1475 /* Toggle the bit */
1476 Value ^= 1 << BitNumber;
1477
1478 /* Write back the result */
1479 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
1480 {
1481 /* Exception occurred */
1482 return FALSE;
1483 }
1484 }
1485
1486 /* Return success */
1487 return TRUE;
1488 }
1489
1490 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsf)
1491 {
1492 INT i;
1493 ULONG Dummy = 0, Value = 0;
1494 BOOLEAN OperandSize, AddressSize;
1495 FAST486_MOD_REG_RM ModRegRm;
1496 ULONG BitNumber;
1497 UINT DataSize;
1498
1499 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1500 TOGGLE_OPSIZE(OperandSize);
1501 TOGGLE_ADSIZE(AddressSize);
1502
1503 /* Make sure this is the right instruction */
1504 ASSERT(Opcode == 0xBC);
1505
1506 /* Get the number of bits */
1507 if (OperandSize) DataSize = 32;
1508 else DataSize = 16;
1509
1510 /* Get the operands */
1511 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1512 {
1513 /* Exception occurred */
1514 return FALSE;
1515 }
1516
1517 /* Read the value */
1518 if (OperandSize)
1519 {
1520 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
1521 {
1522 /* Exception occurred */
1523 return FALSE;
1524 }
1525 }
1526 else
1527 {
1528 if (!Fast486ReadModrmWordOperands(State,
1529 &ModRegRm,
1530 (PUSHORT)&Dummy,
1531 (PUSHORT)&Value))
1532 {
1533 /* Exception occurred */
1534 return FALSE;
1535 }
1536 }
1537
1538 /* Clear ZF */
1539 State->Flags.Zf = FALSE;
1540
1541 for (i = 0; i < DataSize; i++)
1542 {
1543 if(Value & (1 << i))
1544 {
1545 /* Set ZF */
1546 State->Flags.Zf = TRUE;
1547
1548 /* Save the bit number */
1549 BitNumber = i;
1550
1551 /* Exit the loop */
1552 break;
1553 }
1554 }
1555
1556 if (State->Flags.Zf)
1557 {
1558 /* Write back the result */
1559 if (OperandSize)
1560 {
1561 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, BitNumber))
1562 {
1563 /* Exception occurred */
1564 return FALSE;
1565 }
1566 }
1567 else
1568 {
1569 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(BitNumber)))
1570 {
1571 /* Exception occurred */
1572 return FALSE;
1573 }
1574 }
1575 }
1576
1577 return TRUE;
1578 }
1579
1580 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsr)
1581 {
1582 INT i;
1583 ULONG Dummy = 0, Value = 0;
1584 BOOLEAN OperandSize, AddressSize;
1585 FAST486_MOD_REG_RM ModRegRm;
1586 ULONG BitNumber;
1587 UINT DataSize;
1588
1589 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1590 TOGGLE_OPSIZE(OperandSize);
1591 TOGGLE_ADSIZE(AddressSize);
1592
1593 /* Make sure this is the right instruction */
1594 ASSERT(Opcode == 0xBD);
1595
1596 /* Get the number of bits */
1597 if (OperandSize) DataSize = 32;
1598 else DataSize = 16;
1599
1600 /* Get the operands */
1601 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1602 {
1603 /* Exception occurred */
1604 return FALSE;
1605 }
1606
1607 /* Read the value */
1608 if (OperandSize)
1609 {
1610 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
1611 {
1612 /* Exception occurred */
1613 return FALSE;
1614 }
1615 }
1616 else
1617 {
1618 if (!Fast486ReadModrmWordOperands(State,
1619 &ModRegRm,
1620 (PUSHORT)&Dummy,
1621 (PUSHORT)&Value))
1622 {
1623 /* Exception occurred */
1624 return FALSE;
1625 }
1626 }
1627
1628 /* Clear ZF */
1629 State->Flags.Zf = FALSE;
1630
1631 for (i = DataSize - 1; i >= 0; i--)
1632 {
1633 if(Value & (1 << i))
1634 {
1635 /* Set ZF */
1636 State->Flags.Zf = TRUE;
1637
1638 /* Save the bit number */
1639 BitNumber = i;
1640
1641 /* Exit the loop */
1642 break;
1643 }
1644 }
1645
1646 if (State->Flags.Zf)
1647 {
1648 /* Write back the result */
1649 if (OperandSize)
1650 {
1651 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, BitNumber))
1652 {
1653 /* Exception occurred */
1654 return FALSE;
1655 }
1656 }
1657 else
1658 {
1659 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(BitNumber)))
1660 {
1661 /* Exception occurred */
1662 return FALSE;
1663 }
1664 }
1665 }
1666
1667 return TRUE;
1668 }
1669
1670 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxByte)
1671 {
1672 UCHAR Dummy;
1673 CHAR Value;
1674 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1675 FAST486_MOD_REG_RM ModRegRm;
1676
1677 TOGGLE_ADSIZE(AddressSize);
1678
1679 /* Make sure this is the right instruction */
1680 ASSERT(Opcode == 0xBE);
1681
1682 /* Get the operands */
1683 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1684 {
1685 /* Exception occurred */
1686 return FALSE;
1687 }
1688
1689 /* Read the operands */
1690 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, &Dummy, (PUCHAR)&Value))
1691 {
1692 /* Exception occurred */
1693 return FALSE;
1694 }
1695
1696 /* Write back the sign-extended value */
1697 return Fast486WriteModrmDwordOperands(State,
1698 &ModRegRm,
1699 TRUE,
1700 (ULONG)((LONG)Value));
1701 }
1702
1703 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxWord)
1704 {
1705 USHORT Dummy;
1706 SHORT Value;
1707 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1708 FAST486_MOD_REG_RM ModRegRm;
1709
1710 TOGGLE_ADSIZE(AddressSize);
1711
1712 /* Make sure this is the right instruction */
1713 ASSERT(Opcode == 0xBF);
1714
1715 /* Get the operands */
1716 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1717 {
1718 /* Exception occurred */
1719 return FALSE;
1720 }
1721
1722 /* Read the operands */
1723 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, (PUSHORT)&Value))
1724 {
1725 /* Exception occurred */
1726 return FALSE;
1727 }
1728
1729 /* Write back the sign-extended value */
1730 return Fast486WriteModrmDwordOperands(State,
1731 &ModRegRm,
1732 TRUE,
1733 (ULONG)((LONG)Value));
1734 }
1735
1736 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalJmp)
1737 {
1738 BOOLEAN Jump = FALSE;
1739 LONG Offset = 0;
1740 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1741
1742 TOGGLE_OPSIZE(Size);
1743 NO_LOCK_PREFIX();
1744
1745 /* Make sure this is the right instruction */
1746 ASSERT((Opcode & 0xF0) == 0x80);
1747
1748 /* Fetch the offset */
1749 if (Size)
1750 {
1751 if (!Fast486FetchDword(State, (PULONG)&Offset))
1752 {
1753 /* Exception occurred */
1754 return FALSE;
1755 }
1756 }
1757 else
1758 {
1759 SHORT Value;
1760
1761 if (!Fast486FetchWord(State, (PUSHORT)&Value))
1762 {
1763 /* Exception occurred */
1764 return FALSE;
1765 }
1766
1767 /* Sign-extend */
1768 Offset = (LONG)Value;
1769 }
1770
1771 switch ((Opcode & 0x0F) >> 1)
1772 {
1773 /* JO / JNO */
1774 case 0:
1775 {
1776 Jump = State->Flags.Of;
1777 break;
1778 }
1779
1780 /* JC / JNC */
1781 case 1:
1782 {
1783 Jump = State->Flags.Cf;
1784 break;
1785 }
1786
1787 /* JZ / JNZ */
1788 case 2:
1789 {
1790 Jump = State->Flags.Zf;
1791 break;
1792 }
1793
1794 /* JBE / JNBE */
1795 case 3:
1796 {
1797 Jump = State->Flags.Cf || State->Flags.Zf;
1798 break;
1799 }
1800
1801 /* JS / JNS */
1802 case 4:
1803 {
1804 Jump = State->Flags.Sf;
1805 break;
1806 }
1807
1808 /* JP / JNP */
1809 case 5:
1810 {
1811 Jump = State->Flags.Pf;
1812 break;
1813 }
1814
1815 /* JL / JNL */
1816 case 6:
1817 {
1818 Jump = State->Flags.Sf != State->Flags.Of;
1819 break;
1820 }
1821
1822 /* JLE / JNLE */
1823 case 7:
1824 {
1825 Jump = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
1826 break;
1827 }
1828 }
1829
1830 if (Opcode & 1)
1831 {
1832 /* Invert the result */
1833 Jump = !Jump;
1834 }
1835
1836 if (Jump)
1837 {
1838 /* Move the instruction pointer */
1839 State->InstPtr.Long += Offset;
1840 }
1841
1842 /* Return success */
1843 return TRUE;
1844 }
1845
1846 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalSet)
1847 {
1848 BOOLEAN Value = FALSE;
1849 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1850 FAST486_MOD_REG_RM ModRegRm;
1851
1852 TOGGLE_ADSIZE(AddressSize);
1853
1854 /* Get the operands */
1855 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1856 {
1857 /* Exception occurred */
1858 return FALSE;
1859 }
1860
1861 /* Make sure this is the right instruction */
1862 ASSERT((Opcode & 0xF0) == 0x90);
1863
1864 switch ((Opcode & 0x0F) >> 1)
1865 {
1866 /* SETO / SETNO */
1867 case 0:
1868 {
1869 Value = State->Flags.Of;
1870 break;
1871 }
1872
1873 /* SETC / SETNC */
1874 case 1:
1875 {
1876 Value = State->Flags.Cf;
1877 break;
1878 }
1879
1880 /* SETZ / SETNZ */
1881 case 2:
1882 {
1883 Value = State->Flags.Zf;
1884 break;
1885 }
1886
1887 /* SETBE / SETNBE */
1888 case 3:
1889 {
1890 Value = State->Flags.Cf || State->Flags.Zf;
1891 break;
1892 }
1893
1894 /* SETS / SETNS */
1895 case 4:
1896 {
1897 Value = State->Flags.Sf;
1898 break;
1899 }
1900
1901 /* SETP / SETNP */
1902 case 5:
1903 {
1904 Value = State->Flags.Pf;
1905 break;
1906 }
1907
1908 /* SETL / SETNL */
1909 case 6:
1910 {
1911 Value = State->Flags.Sf != State->Flags.Of;
1912 break;
1913 }
1914
1915 /* SETLE / SETNLE */
1916 case 7:
1917 {
1918 Value = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
1919 break;
1920 }
1921 }
1922
1923 if (Opcode & 1)
1924 {
1925 /* Invert the result */
1926 Value = !Value;
1927 }
1928
1929 /* Write back the result */
1930 return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
1931 }
1932
1933 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXaddByte)
1934 {
1935 UCHAR Source, Destination, Result;
1936 FAST486_MOD_REG_RM ModRegRm;
1937 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1938
1939 /* Make sure this is the right instruction */
1940 ASSERT(Opcode == 0xC0);
1941
1942 TOGGLE_ADSIZE(AddressSize);
1943
1944 /* Get the operands */
1945 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1946 {
1947 /* Exception occurred */
1948 return FALSE;
1949 }
1950
1951 if (!Fast486ReadModrmByteOperands(State,
1952 &ModRegRm,
1953 &Source,
1954 &Destination))
1955 {
1956 /* Exception occurred */
1957 return FALSE;
1958 }
1959
1960 /* Calculate the result */
1961 Result = Source + Destination;
1962
1963 /* Update the flags */
1964 State->Flags.Cf = (Result < Source) && (Result < Destination);
1965 State->Flags.Of = ((Source & SIGN_FLAG_BYTE) == (Destination & SIGN_FLAG_BYTE))
1966 && ((Source & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
1967 State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0);
1968 State->Flags.Zf = (Result == 0);
1969 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1970 State->Flags.Pf = Fast486CalculateParity(Result);
1971
1972 /* Write the sum to the destination */
1973 if (!Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Result))
1974 {
1975 /* Exception occurred */
1976 return FALSE;
1977 }
1978
1979 /* Write the old value of the destination to the source */
1980 if (!Fast486WriteModrmByteOperands(State, &ModRegRm, TRUE, Destination))
1981 {
1982 /* Exception occurred */
1983 return FALSE;
1984 }
1985
1986 return TRUE;
1987 }
1988
1989 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXadd)
1990 {
1991 FAST486_MOD_REG_RM ModRegRm;
1992 BOOLEAN OperandSize, AddressSize;
1993
1994 /* Make sure this is the right instruction */
1995 ASSERT(Opcode == 0xC1);
1996
1997 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1998
1999 TOGGLE_ADSIZE(AddressSize);
2000 TOGGLE_OPSIZE(OperandSize);
2001
2002 /* Get the operands */
2003 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2004 {
2005 /* Exception occurred */
2006 return FALSE;
2007 }
2008
2009 /* Check the operand size */
2010 if (OperandSize)
2011 {
2012 ULONG Source, Destination, Result;
2013
2014 if (!Fast486ReadModrmDwordOperands(State,
2015 &ModRegRm,
2016 &Source,
2017 &Destination))
2018 {
2019 /* Exception occurred */
2020 return FALSE;
2021 }
2022
2023 /* Calculate the result */
2024 Result = Source + Destination;
2025
2026 /* Update the flags */
2027 State->Flags.Cf = (Result < Source) && (Result < Destination);
2028 State->Flags.Of = ((Source & SIGN_FLAG_LONG) == (Destination & SIGN_FLAG_LONG))
2029 && ((Source & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
2030 State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0);
2031 State->Flags.Zf = (Result == 0);
2032 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2033 State->Flags.Pf = Fast486CalculateParity(Result);
2034
2035 /* Write the old value of the destination to the source */
2036 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, Destination))
2037 {
2038 /* Exception occurred */
2039 return FALSE;
2040 }
2041
2042 /* Write the sum to the destination */
2043 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result))
2044 {
2045 /* Exception occurred */
2046 return FALSE;
2047 }
2048 }
2049 else
2050 {
2051 USHORT Source, Destination, Result;
2052
2053 if (!Fast486ReadModrmWordOperands(State,
2054 &ModRegRm,
2055 &Source,
2056 &Destination))
2057 {
2058 /* Exception occurred */
2059 return FALSE;
2060 }
2061
2062 /* Calculate the result */
2063 Result = Source + Destination;
2064
2065 /* Update the flags */
2066 State->Flags.Cf = (Result < Source) && (Result < Destination);
2067 State->Flags.Of = ((Source & SIGN_FLAG_WORD) == (Destination & SIGN_FLAG_WORD))
2068 && ((Source & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
2069 State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0);
2070 State->Flags.Zf = (Result == 0);
2071 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2072 State->Flags.Pf = Fast486CalculateParity(Result);
2073
2074 /* Write the old value of the destination to the source */
2075 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, Destination))
2076 {
2077 /* Exception occurred */
2078 return FALSE;
2079 }
2080
2081 /* Write the sum to the destination */
2082 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Result))
2083 {
2084 /* Exception occurred */
2085 return FALSE;
2086 }
2087 }
2088
2089 return TRUE;
2090 }
2091
2092 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBswap)
2093 {
2094 PUCHAR Pointer;
2095
2096 NO_LOCK_PREFIX();
2097
2098 /* Get a pointer to the value */
2099 Pointer = (PUCHAR)&State->GeneralRegs[Opcode & 0x07].Long;
2100
2101 /* Swap the byte order */
2102 SWAP(Pointer[0], Pointer[3]);
2103 SWAP(Pointer[1], Pointer[2]);
2104
2105 /* Return success */
2106 return TRUE;
2107 }
2108
2109 FAST486_OPCODE_HANDLER(Fast486OpcodeExtended)
2110 {
2111 UCHAR SecondOpcode;
2112
2113 /* Fetch the second operation code */
2114 if (!Fast486FetchByte(State, &SecondOpcode))
2115 {
2116 /* Exception occurred */
2117 return FALSE;
2118 }
2119
2120 if (Fast486ExtendedHandlers[SecondOpcode] != NULL)
2121 {
2122 /* Call the extended opcode handler */
2123 return Fast486ExtendedHandlers[SecondOpcode](State, SecondOpcode);
2124 }
2125 else
2126 {
2127 /* This is not a valid opcode */
2128 Fast486Exception(State, FAST486_EXCEPTION_UD);
2129 return FALSE;
2130 }
2131 }
2132