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