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