[FAST486]
[reactos.git] / lib / fast486 / extraops.c
1 /*
2 * Fast486 386/486 CPU Emulation Library
3 * extraops.c
4 *
5 * Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22 /* INCLUDES *******************************************************************/
23
24 #include <windef.h>
25
26 // #define NDEBUG
27 #include <debug.h>
28
29 #include <fast486.h>
30 #include "opcodes.h"
31 #include "common.h"
32 #include "opgroups.h"
33 #include "extraops.h"
34
35 /* PUBLIC VARIABLES ***********************************************************/
36
37 FAST486_OPCODE_HANDLER_PROC
38 Fast486ExtendedHandlers[FAST486_NUM_OPCODE_HANDLERS] =
39 {
40 NULL, // TODO: OPCODE 0x00 NOT IMPLEMENTED
41 Fast486OpcodeGroup0F01,
42 NULL, // TODO: OPCODE 0x02 NOT IMPLEMENTED
43 NULL, // TODO: OPCODE 0x03 NOT IMPLEMENTED
44 NULL, // TODO: OPCODE 0x04 NOT IMPLEMENTED
45 NULL, // TODO: OPCODE 0x05 NOT IMPLEMENTED
46 Fast486ExtOpcodeClts,
47 NULL, // TODO: OPCODE 0x07 NOT IMPLEMENTED
48 NULL, // TODO: OPCODE 0x08 NOT IMPLEMENTED
49 NULL, // TODO: OPCODE 0x09 NOT IMPLEMENTED
50 NULL, // Invalid
51 NULL, // Reserved (UD1)
52 NULL, // Invalid
53 NULL, // Invalid
54 NULL, // Invalid
55 NULL, // Invalid
56 NULL, // Invalid
57 NULL, // Invalid
58 NULL, // Invalid
59 NULL, // Invalid
60 NULL, // Invalid
61 NULL, // Invalid
62 NULL, // Invalid
63 NULL, // Invalid
64 NULL, // Invalid
65 NULL, // Invalid
66 NULL, // Invalid
67 NULL, // Invalid
68 NULL, // Invalid
69 NULL, // Invalid
70 NULL, // Invalid
71 NULL, // Invalid
72 Fast486ExtOpcodeStoreControlReg,
73 Fast486ExtOpcodeStoreDebugReg,
74 Fast486ExtOpcodeLoadControlReg,
75 Fast486ExtOpcodeLoadDebugReg,
76 NULL, // TODO: OPCODE 0x24 NOT IMPLEMENTED
77 NULL, // Invalid
78 NULL, // TODO: OPCODE 0x26 NOT IMPLEMENTED
79 NULL, // Invalid
80 NULL, // Invalid
81 NULL, // Invalid
82 NULL, // Invalid
83 NULL, // Invalid
84 NULL, // Invalid
85 NULL, // Invalid
86 NULL, // Invalid
87 NULL, // Invalid
88 NULL, // Invalid
89 NULL, // Invalid
90 NULL, // Invalid
91 NULL, // Invalid
92 NULL, // Invalid
93 NULL, // Invalid
94 NULL, // Invalid
95 NULL, // Invalid
96 NULL, // Invalid
97 NULL, // Invalid
98 NULL, // Invalid
99 NULL, // Invalid
100 NULL, // Invalid
101 NULL, // Invalid
102 NULL, // Invalid
103 NULL, // Invalid
104 NULL, // Invalid
105 NULL, // Invalid
106 NULL, // Invalid
107 NULL, // Invalid
108 NULL, // Invalid
109 NULL, // Invalid
110 NULL, // Invalid
111 NULL, // Invalid
112 NULL, // Invalid
113 NULL, // Invalid
114 NULL, // Invalid
115 NULL, // Invalid
116 NULL, // Invalid
117 NULL, // Invalid
118 NULL, // Invalid
119 NULL, // Invalid
120 NULL, // Invalid
121 NULL, // Invalid
122 NULL, // Invalid
123 NULL, // Invalid
124 NULL, // Invalid
125 NULL, // Invalid
126 NULL, // Invalid
127 NULL, // Invalid
128 NULL, // Invalid
129 NULL, // Invalid
130 NULL, // Invalid
131 NULL, // Invalid
132 NULL, // Invalid
133 NULL, // Invalid
134 NULL, // Invalid
135 NULL, // Invalid
136 NULL, // Invalid
137 NULL, // Invalid
138 NULL, // Invalid
139 NULL, // Invalid
140 NULL, // Invalid
141 NULL, // Invalid
142 NULL, // Invalid
143 NULL, // Invalid
144 NULL, // Invalid
145 NULL, // Invalid
146 NULL, // Invalid
147 NULL, // Invalid
148 NULL, // Invalid
149 NULL, // Invalid
150 NULL, // Invalid
151 NULL, // Invalid
152 NULL, // Invalid
153 NULL, // Invalid
154 NULL, // Invalid
155 NULL, // Invalid
156 NULL, // Invalid
157 NULL, // Invalid
158 NULL, // Invalid
159 NULL, // Invalid
160 NULL, // Invalid
161 NULL, // Invalid
162 NULL, // Invalid
163 NULL, // Invalid
164 NULL, // Invalid
165 NULL, // Invalid
166 NULL, // Invalid
167 NULL, // Invalid
168 Fast486ExtOpcodeConditionalJmp,
169 Fast486ExtOpcodeConditionalJmp,
170 Fast486ExtOpcodeConditionalJmp,
171 Fast486ExtOpcodeConditionalJmp,
172 Fast486ExtOpcodeConditionalJmp,
173 Fast486ExtOpcodeConditionalJmp,
174 Fast486ExtOpcodeConditionalJmp,
175 Fast486ExtOpcodeConditionalJmp,
176 Fast486ExtOpcodeConditionalJmp,
177 Fast486ExtOpcodeConditionalJmp,
178 Fast486ExtOpcodeConditionalJmp,
179 Fast486ExtOpcodeConditionalJmp,
180 Fast486ExtOpcodeConditionalJmp,
181 Fast486ExtOpcodeConditionalJmp,
182 Fast486ExtOpcodeConditionalJmp,
183 Fast486ExtOpcodeConditionalJmp,
184 Fast486ExtOpcodeConditionalSet,
185 Fast486ExtOpcodeConditionalSet,
186 Fast486ExtOpcodeConditionalSet,
187 Fast486ExtOpcodeConditionalSet,
188 Fast486ExtOpcodeConditionalSet,
189 Fast486ExtOpcodeConditionalSet,
190 Fast486ExtOpcodeConditionalSet,
191 Fast486ExtOpcodeConditionalSet,
192 Fast486ExtOpcodeConditionalSet,
193 Fast486ExtOpcodeConditionalSet,
194 Fast486ExtOpcodeConditionalSet,
195 Fast486ExtOpcodeConditionalSet,
196 Fast486ExtOpcodeConditionalSet,
197 Fast486ExtOpcodeConditionalSet,
198 Fast486ExtOpcodeConditionalSet,
199 Fast486ExtOpcodeConditionalSet,
200 Fast486ExtOpcodePushFs,
201 Fast486ExtOpcodePopFs,
202 NULL, // Invalid
203 Fast486ExtOpcodeBitTest,
204 Fast486ExtOpcodeShld,
205 Fast486ExtOpcodeShld,
206 NULL, // Invalid
207 NULL, // Invalid
208 Fast486ExtOpcodePushGs,
209 Fast486ExtOpcodePopGs,
210 NULL, // Invalid
211 Fast486ExtOpcodeBts,
212 Fast486ExtOpcodeShrd,
213 Fast486ExtOpcodeShrd,
214 NULL, // TODO: OPCODE 0xAE NOT IMPLEMENTED
215 Fast486ExtOpcodeImul,
216 Fast486ExtOpcodeCmpXchgByte,
217 Fast486ExtOpcodeCmpXchg,
218 Fast486ExtOpcodeLss,
219 Fast486ExtOpcodeBtr,
220 Fast486ExtOpcodeLfsLgs,
221 Fast486ExtOpcodeLfsLgs,
222 Fast486ExtOpcodeMovzxByte,
223 Fast486ExtOpcodeMovzxWord,
224 NULL, // Invalid
225 Fast486OpcodeGroup0FB9,
226 Fast486OpcodeGroup0FBA,
227 Fast486ExtOpcodeBtc,
228 Fast486ExtOpcodeBsf,
229 Fast486ExtOpcodeBsr,
230 Fast486ExtOpcodeMovsxByte,
231 Fast486ExtOpcodeMovsxWord,
232 Fast486ExtOpcodeXaddByte,
233 Fast486ExtOpcodeXadd,
234 NULL, // Invalid
235 NULL, // Invalid
236 NULL, // Invalid
237 NULL, // Invalid
238 NULL, // Invalid
239 NULL, // Invalid
240 Fast486ExtOpcodeBswap,
241 Fast486ExtOpcodeBswap,
242 Fast486ExtOpcodeBswap,
243 Fast486ExtOpcodeBswap,
244 Fast486ExtOpcodeBswap,
245 Fast486ExtOpcodeBswap,
246 Fast486ExtOpcodeBswap,
247 Fast486ExtOpcodeBswap,
248 NULL, // Invalid
249 NULL, // Invalid
250 NULL, // Invalid
251 NULL, // Invalid
252 NULL, // Invalid
253 NULL, // Invalid
254 NULL, // Invalid
255 NULL, // Invalid
256 NULL, // Invalid
257 NULL, // Invalid
258 NULL, // Invalid
259 NULL, // Invalid
260 NULL, // Invalid
261 NULL, // Invalid
262 NULL, // Invalid
263 NULL, // Invalid
264 NULL, // Invalid
265 NULL, // Invalid
266 NULL, // Invalid
267 NULL, // Invalid
268 NULL, // Invalid
269 NULL, // Invalid
270 NULL, // Invalid
271 NULL, // Invalid
272 NULL, // Invalid
273 NULL, // Invalid
274 NULL, // Invalid
275 NULL, // Invalid
276 NULL, // Invalid
277 NULL, // Invalid
278 NULL, // Invalid
279 NULL, // Invalid
280 NULL, // Invalid
281 NULL, // Invalid
282 NULL, // Invalid
283 NULL, // Invalid
284 NULL, // Invalid
285 NULL, // Invalid
286 NULL, // Invalid
287 NULL, // Invalid
288 NULL, // Invalid
289 NULL, // Invalid
290 NULL, // Invalid
291 NULL, // Invalid
292 NULL, // Invalid
293 NULL, // Invalid
294 NULL, // Invalid
295 NULL, // Invalid
296 };
297
298 /* PUBLIC FUNCTIONS ***********************************************************/
299
300 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeClts)
301 {
302 NO_LOCK_PREFIX();
303
304 /* The current privilege level must be zero */
305 if (Fast486GetCurrentPrivLevel(State) != 0)
306 {
307 Fast486Exception(State, FAST486_EXCEPTION_GP);
308 return FALSE;
309 }
310
311 /* Clear the task switch bit */
312 State->ControlRegisters[FAST486_REG_CR0] &= ~FAST486_CR0_TS;
313
314 return TRUE;
315 }
316
317 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreControlReg)
318 {
319 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
320 FAST486_MOD_REG_RM ModRegRm;
321
322 NO_LOCK_PREFIX();
323 TOGGLE_ADSIZE(AddressSize);
324
325 /* Get the operands */
326 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
327 {
328 /* Exception occurred */
329 return FALSE;
330 }
331
332 /* The current privilege level must be zero */
333 if (Fast486GetCurrentPrivLevel(State) != 0)
334 {
335 Fast486Exception(State, FAST486_EXCEPTION_GP);
336 return FALSE;
337 }
338
339 if ((ModRegRm.Register == 1) || (ModRegRm.Register > 3))
340 {
341 /* CR1, CR4, CR5, CR6 and CR7 don't exist */
342 Fast486Exception(State, FAST486_EXCEPTION_UD);
343 return FALSE;
344 }
345
346 if (ModRegRm.Register != 0)
347 {
348 /* CR2 and CR3 and are stored in array indexes 1 and 2 */
349 ModRegRm.Register--;
350 }
351
352 /* Store the value of the control register */
353 State->GeneralRegs[ModRegRm.SecondRegister].Long = State->ControlRegisters[ModRegRm.Register];
354
355 /* Return success */
356 return TRUE;
357 }
358
359 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreDebugReg)
360 {
361 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
362 FAST486_MOD_REG_RM ModRegRm;
363
364 NO_LOCK_PREFIX();
365 TOGGLE_ADSIZE(AddressSize);
366
367 /* Get the operands */
368 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
369 {
370 /* Exception occurred */
371 return FALSE;
372 }
373
374 /* The current privilege level must be zero */
375 if (Fast486GetCurrentPrivLevel(State) != 0)
376 {
377 Fast486Exception(State, FAST486_EXCEPTION_GP);
378 return FALSE;
379 }
380
381 if ((ModRegRm.Register == 6) || (ModRegRm.Register == 7))
382 {
383 /* DR6 and DR7 are aliases to DR4 and DR5 */
384 ModRegRm.Register -= 2;
385 }
386
387 if (State->DebugRegisters[FAST486_REG_DR5] & FAST486_DR5_GD)
388 {
389 /* Disallow access to debug registers */
390 Fast486Exception(State, FAST486_EXCEPTION_GP);
391 return FALSE;
392 }
393
394 /* Store the value of the debug register */
395 State->GeneralRegs[ModRegRm.SecondRegister].Long = State->DebugRegisters[ModRegRm.Register];
396
397 /* Return success */
398 return TRUE;
399 }
400
401 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadControlReg)
402 {
403 ULONG Value;
404 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
405 FAST486_MOD_REG_RM ModRegRm;
406
407 NO_LOCK_PREFIX();
408 TOGGLE_ADSIZE(AddressSize);
409
410 /* Get the operands */
411 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
412 {
413 /* Exception occurred */
414 return FALSE;
415 }
416
417 /* The current privilege level must be zero */
418 if (Fast486GetCurrentPrivLevel(State) != 0)
419 {
420 Fast486Exception(State, FAST486_EXCEPTION_GP);
421 return FALSE;
422 }
423
424 if ((ModRegRm.Register == 1) || (ModRegRm.Register > 3))
425 {
426 /* CR1, CR4, CR5, CR6 and CR7 don't exist */
427 Fast486Exception(State, FAST486_EXCEPTION_UD);
428 return FALSE;
429 }
430
431 if (ModRegRm.Register != 0)
432 {
433 /* CR2 and CR3 and are stored in array indexes 1 and 2 */
434 ModRegRm.Register--;
435 }
436
437 /* Get the value */
438 Value = State->GeneralRegs[ModRegRm.SecondRegister].Long;
439
440 if (ModRegRm.Register == (INT)FAST486_REG_CR0)
441 {
442 /* CR0 checks */
443
444 if (((Value & (FAST486_CR0_PG | FAST486_CR0_PE)) == FAST486_CR0_PG)
445 || ((Value & (FAST486_CR0_CD | FAST486_CR0_NW)) == FAST486_CR0_NW))
446 {
447 /* Invalid value */
448 Fast486Exception(State, FAST486_EXCEPTION_GP);
449 return FALSE;
450 }
451 }
452
453 /* Load a value to the control register */
454 State->ControlRegisters[ModRegRm.Register] = Value;
455
456 /* Return success */
457 return TRUE;
458 }
459
460 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadDebugReg)
461 {
462 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
463 FAST486_MOD_REG_RM ModRegRm;
464
465 NO_LOCK_PREFIX();
466 TOGGLE_ADSIZE(AddressSize);
467
468 /* Get the operands */
469 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
470 {
471 /* Exception occurred */
472 return FALSE;
473 }
474
475 /* The current privilege level must be zero */
476 if (Fast486GetCurrentPrivLevel(State) != 0)
477 {
478 Fast486Exception(State, FAST486_EXCEPTION_GP);
479 return FALSE;
480 }
481
482 if ((ModRegRm.Register == 6) || (ModRegRm.Register == 7))
483 {
484 /* DR6 and DR7 are aliases to DR4 and DR5 */
485 ModRegRm.Register -= 2;
486 }
487
488 if (State->DebugRegisters[FAST486_REG_DR5] & FAST486_DR5_GD)
489 {
490 /* Disallow access to debug registers */
491 Fast486Exception(State, FAST486_EXCEPTION_GP);
492 return FALSE;
493 }
494
495 /* Load a value to the debug register */
496 State->DebugRegisters[ModRegRm.Register] = State->GeneralRegs[ModRegRm.SecondRegister].Long;
497
498 if (ModRegRm.Register == (INT)FAST486_REG_DR4)
499 {
500 /* The reserved bits are 1 */
501 State->DebugRegisters[ModRegRm.Register] |= FAST486_DR4_RESERVED;
502 }
503 else if (ModRegRm.Register == (INT)FAST486_REG_DR5)
504 {
505 /* The reserved bits are 0 */
506 State->DebugRegisters[ModRegRm.Register] &= ~FAST486_DR5_RESERVED;
507 }
508
509 /* Return success */
510 return TRUE;
511 }
512
513 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushFs)
514 {
515 /* Call the internal API */
516 return Fast486StackPush(State, State->SegmentRegs[FAST486_REG_FS].Selector);
517 }
518
519 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopFs)
520 {
521 ULONG NewSelector;
522
523 if (!Fast486StackPop(State, &NewSelector))
524 {
525 /* Exception occurred */
526 return FALSE;
527 }
528
529 /* Call the internal API */
530 return Fast486LoadSegment(State, FAST486_REG_FS, LOWORD(NewSelector));
531 }
532
533 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBitTest)
534 {
535 BOOLEAN OperandSize, AddressSize;
536 FAST486_MOD_REG_RM ModRegRm;
537 UINT DataSize;
538 ULONG BitNumber;
539
540 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
541 TOGGLE_OPSIZE(OperandSize);
542 TOGGLE_ADSIZE(AddressSize);
543
544 /* Get the number of bits */
545 if (OperandSize) DataSize = 32;
546 else DataSize = 16;
547
548 /* Get the operands */
549 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
550 {
551 /* Exception occurred */
552 return FALSE;
553 }
554
555 /* Get the bit number */
556 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
557 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
558
559 if (ModRegRm.Memory)
560 {
561 /*
562 * For memory operands, add the bit offset divided by
563 * the data size to the address
564 */
565 ModRegRm.MemoryAddress += BitNumber / DataSize;
566 }
567
568 /* Normalize the bit number */
569 BitNumber %= DataSize;
570
571 if (OperandSize)
572 {
573 ULONG Value;
574
575 /* Read the value */
576 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &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 Value;
588
589 /* Read the value */
590 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
591 {
592 /* Exception occurred */
593 return FALSE;
594 }
595
596 /* Set CF to the bit value */
597 State->Flags.Cf = (Value >> BitNumber) & 1;
598 }
599
600 /* Return success */
601 return TRUE;
602 }
603
604 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShld)
605 {
606 BOOLEAN OperandSize, AddressSize;
607 FAST486_MOD_REG_RM ModRegRm;
608 UCHAR Count;
609
610 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
611 TOGGLE_OPSIZE(OperandSize);
612 TOGGLE_ADSIZE(AddressSize);
613
614 /* Make sure this is the right instruction */
615 ASSERT((Opcode & 0xFE) == 0xA4);
616
617 /* Get the operands */
618 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
619 {
620 /* Exception occurred */
621 return FALSE;
622 }
623
624 if (Opcode == 0xA4)
625 {
626 /* Fetch the count */
627 if (!Fast486FetchByte(State, &Count))
628 {
629 /* Exception occurred */
630 return FALSE;
631 }
632 }
633 else
634 {
635 /* The count is in CL */
636 Count = State->GeneralRegs[FAST486_REG_ECX].LowByte;
637 }
638
639 /* Normalize the count */
640 Count &= 0x1F;
641
642 /* Do nothing if the count is zero */
643 if (Count == 0) return TRUE;
644
645 if (OperandSize)
646 {
647 ULONG Source, Destination, Result;
648
649 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Source, &Destination))
650 {
651 /* Exception occurred */
652 return FALSE;
653 }
654
655 /* Calculate the result */
656 Result = (Destination << Count) | (Source >> (32 - Count));
657
658 /* Update flags */
659 State->Flags.Cf = (Destination >> (32 - Count)) & 1;
660 if (Count == 1) State->Flags.Of = (Result & SIGN_FLAG_LONG)
661 != (Destination & SIGN_FLAG_LONG);
662 State->Flags.Zf = (Result == 0);
663 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
664 State->Flags.Pf = Fast486CalculateParity(Result);
665
666 /* Write back the result */
667 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result);
668 }
669 else
670 {
671 USHORT Source, Destination, Result;
672 ULONG DoubleSource;
673
674 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Source, &Destination))
675 {
676 /* Exception occurred */
677 return FALSE;
678 }
679
680 DoubleSource = Source | (Source << 16);
681
682 /* Calculate the result */
683 Result = (Destination << Count) | (DoubleSource >> (32 - Count));
684
685 /* Update flags */
686 if (Count <= 16) State->Flags.Cf = (Destination >> (16 - Count)) & 1;
687 else State->Flags.Cf = (Source >> (32 - Count)) & 1;
688
689 if (Count == 1) State->Flags.Of = (Result & SIGN_FLAG_WORD)
690 != (Destination & SIGN_FLAG_WORD);
691 State->Flags.Zf = (Result == 0);
692 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
693 State->Flags.Pf = Fast486CalculateParity(Result);
694
695 /* Write back the result */
696 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Result);
697 }
698 }
699
700 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushGs)
701 {
702 /* Call the internal API */
703 return Fast486StackPush(State, State->SegmentRegs[FAST486_REG_GS].Selector);
704 }
705
706 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopGs)
707 {
708 ULONG NewSelector;
709
710 if (!Fast486StackPop(State, &NewSelector))
711 {
712 /* Exception occurred */
713 return FALSE;
714 }
715
716 /* Call the internal API */
717 return Fast486LoadSegment(State, FAST486_REG_GS, LOWORD(NewSelector));
718 }
719
720 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBts)
721 {
722 BOOLEAN OperandSize, AddressSize;
723 FAST486_MOD_REG_RM ModRegRm;
724 UINT DataSize;
725 ULONG BitNumber;
726
727 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
728 TOGGLE_OPSIZE(OperandSize);
729 TOGGLE_ADSIZE(AddressSize);
730
731 /* Get the number of bits */
732 if (OperandSize) DataSize = 32;
733 else DataSize = 16;
734
735 /* Get the operands */
736 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
737 {
738 /* Exception occurred */
739 return FALSE;
740 }
741
742 /* Get the bit number */
743 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
744 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
745
746 if (ModRegRm.Memory)
747 {
748 /*
749 * For memory operands, add the bit offset divided by
750 * the data size to the address
751 */
752 ModRegRm.MemoryAddress += BitNumber / DataSize;
753 }
754
755 /* Normalize the bit number */
756 BitNumber %= DataSize;
757
758 if (OperandSize)
759 {
760 ULONG Value;
761
762 /* Read the value */
763 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
764 {
765 /* Exception occurred */
766 return FALSE;
767 }
768
769 /* Set CF to the bit value */
770 State->Flags.Cf = (Value >> BitNumber) & 1;
771
772 /* Set the bit */
773 Value |= 1 << BitNumber;
774
775 /* Write back the result */
776 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
777 {
778 /* Exception occurred */
779 return FALSE;
780 }
781 }
782 else
783 {
784 USHORT Value;
785
786 /* Read the value */
787 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
788 {
789 /* Exception occurred */
790 return FALSE;
791 }
792
793 /* Set CF to the bit value */
794 State->Flags.Cf = (Value >> BitNumber) & 1;
795
796 /* Set the bit */
797 Value |= 1 << BitNumber;
798
799 /* Write back the result */
800 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
801 {
802 /* Exception occurred */
803 return FALSE;
804 }
805 }
806
807 /* Return success */
808 return TRUE;
809 }
810
811 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShrd)
812 {
813 BOOLEAN OperandSize, AddressSize;
814 FAST486_MOD_REG_RM ModRegRm;
815 UCHAR Count;
816
817 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
818 TOGGLE_OPSIZE(OperandSize);
819 TOGGLE_ADSIZE(AddressSize);
820
821 /* Make sure this is the right instruction */
822 ASSERT((Opcode & 0xFE) == 0xAC);
823
824 /* Get the operands */
825 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
826 {
827 /* Exception occurred */
828 return FALSE;
829 }
830
831 if (Opcode == 0xAC)
832 {
833 /* Fetch the count */
834 if (!Fast486FetchByte(State, &Count))
835 {
836 /* Exception occurred */
837 return FALSE;
838 }
839 }
840 else
841 {
842 /* The count is in CL */
843 Count = State->GeneralRegs[FAST486_REG_ECX].LowByte;
844 }
845
846 /* Normalize the count */
847 Count &= 0x1F;
848
849 /* Do nothing if the count is zero */
850 if (Count == 0) return TRUE;
851
852 if (OperandSize)
853 {
854 ULONG Source, Destination, Result;
855
856 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Source, &Destination))
857 {
858 /* Exception occurred */
859 return FALSE;
860 }
861
862 /* Calculate the result */
863 Result = (Destination >> Count) | (Source << (32 - Count));
864
865 /* Update flags */
866 State->Flags.Cf = (Destination >> (Count - 1)) & 1;
867 if (Count == 1) State->Flags.Of = (Result & SIGN_FLAG_LONG)
868 != (Destination & SIGN_FLAG_LONG);
869 State->Flags.Zf = (Result == 0);
870 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
871 State->Flags.Pf = Fast486CalculateParity(Result);
872
873 /* Write back the result */
874 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result);
875 }
876 else
877 {
878 USHORT Source, Destination, Result;
879
880 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Source, &Destination))
881 {
882 /* Exception occurred */
883 return FALSE;
884 }
885
886 /* Calculate the result */
887 Result = (Destination >> Count) | (Source << (16 - Count));
888
889 if (Count >= 16) Result |= (ULONG)(Source | (Source << 16)) >> (Count - 16);
890
891 /* Update flags */
892 if (Count <= 16) State->Flags.Cf = (Destination >> (Count - 1)) & 1;
893 else State->Flags.Cf = (Source >> (Count - 17)) & 1;
894
895 if (Count == 1) State->Flags.Of = (Result & SIGN_FLAG_WORD)
896 != (Destination & SIGN_FLAG_WORD);
897 State->Flags.Zf = (Result == 0);
898 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
899 State->Flags.Pf = Fast486CalculateParity(Result);
900
901 /* Write back the result */
902 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Result);
903 }
904 }
905
906 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeImul)
907 {
908 BOOLEAN OperandSize, AddressSize;
909 FAST486_MOD_REG_RM ModRegRm;
910
911 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
912
913 TOGGLE_OPSIZE(OperandSize);
914 TOGGLE_ADSIZE(AddressSize);
915
916 /* Get the operands */
917 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
918 {
919 /* Exception occurred */
920 return FALSE;
921 }
922
923 if (OperandSize)
924 {
925 LONG Source, Destination;
926 LONGLONG Result;
927
928 /* Read the operands */
929 if (!Fast486ReadModrmDwordOperands(State,
930 &ModRegRm,
931 (PULONG)&Destination,
932 (PULONG)&Source))
933 {
934 /* Exception occurred */
935 return FALSE;
936 }
937
938 /* Calculate the result */
939 Result = (LONGLONG)Source * (LONGLONG)Destination;
940
941 /* Update the flags */
942 State->Flags.Cf = State->Flags.Of = ((Result < -2147483648LL) || (Result > 2147483647LL));
943
944 /* Write back the result */
945 return Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, (ULONG)((LONG)Result));
946 }
947 else
948 {
949 SHORT Source, Destination;
950 LONG Result;
951
952 /* Read the operands */
953 if (!Fast486ReadModrmWordOperands(State,
954 &ModRegRm,
955 (PUSHORT)&Destination,
956 (PUSHORT)&Source))
957 {
958 /* Exception occurred */
959 return FALSE;
960 }
961
962 /* Calculate the result */
963 Result = (LONG)Source * (LONG)Destination;
964
965 /* Update the flags */
966 State->Flags.Cf = State->Flags.Of = ((Result < -32768) || (Result > 32767));
967
968 /* Write back the result */
969 return Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, (USHORT)((SHORT)Result));
970 }
971 }
972
973 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchgByte)
974 {
975 FAST486_MOD_REG_RM ModRegRm;
976 UCHAR Accumulator = State->GeneralRegs[FAST486_REG_EAX].LowByte;
977 UCHAR Source, Destination, Result;
978 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
979
980 TOGGLE_ADSIZE(AddressSize);
981
982 /* Get the operands */
983 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
984 {
985 /* Exception occurred */
986 return FALSE;
987 }
988
989 /* Read the operands */
990 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, &Source, &Destination))
991 {
992 /* Exception occurred */
993 return FALSE;
994 }
995
996 /* Compare AL with the destination */
997 Result = Accumulator - Destination;
998
999 /* Update the flags */
1000 State->Flags.Cf = (Accumulator < Destination);
1001 State->Flags.Of = ((Accumulator & SIGN_FLAG_BYTE) != (Destination & SIGN_FLAG_BYTE))
1002 && ((Accumulator & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
1003 State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F);
1004 State->Flags.Zf = (Result == 0);
1005 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1006 State->Flags.Pf = Fast486CalculateParity(Result);
1007
1008 if (State->Flags.Zf)
1009 {
1010 /* Load the source operand into the destination */
1011 return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Source);
1012 }
1013 else
1014 {
1015 /* Load the destination into AL */
1016 State->GeneralRegs[FAST486_REG_EAX].LowByte = Destination;
1017 }
1018
1019 /* Return success */
1020 return TRUE;
1021 }
1022
1023 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchg)
1024 {
1025 FAST486_MOD_REG_RM ModRegRm;
1026 BOOLEAN OperandSize, AddressSize;
1027
1028 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1029
1030 TOGGLE_OPSIZE(OperandSize);
1031 TOGGLE_ADSIZE(AddressSize);
1032
1033 /* Get the operands */
1034 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1035 {
1036 /* Exception occurred */
1037 return FALSE;
1038 }
1039
1040 if (OperandSize)
1041 {
1042 ULONG Source, Destination, Result;
1043 ULONG Accumulator = State->GeneralRegs[FAST486_REG_EAX].Long;
1044
1045 /* Read the operands */
1046 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Source, &Destination))
1047 {
1048 /* Exception occurred */
1049 return FALSE;
1050 }
1051
1052 /* Compare EAX with the destination */
1053 Result = Accumulator - Destination;
1054
1055 /* Update the flags */
1056 State->Flags.Cf = (Accumulator < Destination);
1057 State->Flags.Of = ((Accumulator & SIGN_FLAG_LONG) != (Destination & SIGN_FLAG_LONG))
1058 && ((Accumulator & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
1059 State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F);
1060 State->Flags.Zf = (Result == 0);
1061 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1062 State->Flags.Pf = Fast486CalculateParity(Result);
1063
1064 if (State->Flags.Zf)
1065 {
1066 /* Load the source operand into the destination */
1067 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Source);
1068 }
1069 else
1070 {
1071 /* Load the destination into EAX */
1072 State->GeneralRegs[FAST486_REG_EAX].Long = Destination;
1073 }
1074 }
1075 else
1076 {
1077 USHORT Source, Destination, Result;
1078 USHORT Accumulator = State->GeneralRegs[FAST486_REG_EAX].LowWord;
1079
1080 /* Read the operands */
1081 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Source, &Destination))
1082 {
1083 /* Exception occurred */
1084 return FALSE;
1085 }
1086
1087 /* Compare AX with the destination */
1088 Result = Accumulator - Destination;
1089
1090 /* Update the flags */
1091 State->Flags.Cf = (Accumulator < Destination);
1092 State->Flags.Of = ((Accumulator & SIGN_FLAG_WORD) != (Destination & SIGN_FLAG_WORD))
1093 && ((Accumulator & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
1094 State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F);
1095 State->Flags.Zf = (Result == 0);
1096 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1097 State->Flags.Pf = Fast486CalculateParity(Result);
1098
1099 if (State->Flags.Zf)
1100 {
1101 /* Load the source operand into the destination */
1102 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Source);
1103 }
1104 else
1105 {
1106 /* Load the destination into AX */
1107 State->GeneralRegs[FAST486_REG_EAX].LowWord = Destination;
1108 }
1109 }
1110
1111 /* Return success */
1112 return TRUE;
1113 }
1114
1115 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLss)
1116 {
1117 UCHAR FarPointer[6];
1118 BOOLEAN OperandSize, AddressSize;
1119 FAST486_MOD_REG_RM ModRegRm;
1120
1121 /* Make sure this is the right instruction */
1122 ASSERT(Opcode == 0xB2);
1123
1124 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1125
1126 TOGGLE_OPSIZE(OperandSize);
1127 TOGGLE_ADSIZE(AddressSize);
1128
1129 /* Get the operands */
1130 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1131 {
1132 /* Exception occurred */
1133 return FALSE;
1134 }
1135
1136 if (!ModRegRm.Memory)
1137 {
1138 /* Invalid */
1139 Fast486Exception(State, FAST486_EXCEPTION_UD);
1140 return FALSE;
1141 }
1142
1143 if (!Fast486ReadMemory(State,
1144 (State->PrefixFlags & FAST486_PREFIX_SEG)
1145 ? State->SegmentOverride : FAST486_REG_DS,
1146 ModRegRm.MemoryAddress,
1147 FALSE,
1148 FarPointer,
1149 OperandSize ? 6 : 4))
1150 {
1151 /* Exception occurred */
1152 return FALSE;
1153 }
1154
1155 if (OperandSize)
1156 {
1157 ULONG Offset = *((PULONG)FarPointer);
1158 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(ULONG)]);
1159
1160 /* Set the register to the offset */
1161 State->GeneralRegs[ModRegRm.Register].Long = Offset;
1162
1163 /* Load the segment */
1164 return Fast486LoadSegment(State,
1165 FAST486_REG_SS,
1166 Segment);
1167 }
1168 else
1169 {
1170 USHORT Offset = *((PUSHORT)FarPointer);
1171 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(USHORT)]);
1172
1173 /* Set the register to the offset */
1174 State->GeneralRegs[ModRegRm.Register].LowWord = Offset;
1175
1176 /* Load the segment */
1177 return Fast486LoadSegment(State,
1178 FAST486_REG_SS,
1179 Segment);
1180 }
1181 }
1182
1183 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtr)
1184 {
1185 BOOLEAN OperandSize, AddressSize;
1186 FAST486_MOD_REG_RM ModRegRm;
1187 UINT DataSize;
1188 ULONG BitNumber;
1189
1190 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1191 TOGGLE_OPSIZE(OperandSize);
1192 TOGGLE_ADSIZE(AddressSize);
1193
1194 /* Get the number of bits */
1195 if (OperandSize) DataSize = 32;
1196 else DataSize = 16;
1197
1198 /* Get the operands */
1199 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1200 {
1201 /* Exception occurred */
1202 return FALSE;
1203 }
1204
1205 /* Get the bit number */
1206 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
1207 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
1208
1209 if (ModRegRm.Memory)
1210 {
1211 /*
1212 * For memory operands, add the bit offset divided by
1213 * the data size to the address
1214 */
1215 ModRegRm.MemoryAddress += BitNumber / DataSize;
1216 }
1217
1218 /* Normalize the bit number */
1219 BitNumber %= DataSize;
1220
1221 if (OperandSize)
1222 {
1223 ULONG Value;
1224
1225 /* Read the value */
1226 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1227 {
1228 /* Exception occurred */
1229 return FALSE;
1230 }
1231
1232 /* Set CF to the bit value */
1233 State->Flags.Cf = (Value >> BitNumber) & 1;
1234
1235 /* Clear the bit */
1236 Value &= ~(1 << BitNumber);
1237
1238 /* Write back the result */
1239 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
1240 {
1241 /* Exception occurred */
1242 return FALSE;
1243 }
1244 }
1245 else
1246 {
1247 USHORT Value;
1248
1249 /* Read the value */
1250 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
1251 {
1252 /* Exception occurred */
1253 return FALSE;
1254 }
1255
1256 /* Set CF to the bit value */
1257 State->Flags.Cf = (Value >> BitNumber) & 1;
1258
1259 /* Clear the bit */
1260 Value &= ~(1 << BitNumber);
1261
1262 /* Write back the result */
1263 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
1264 {
1265 /* Exception occurred */
1266 return FALSE;
1267 }
1268 }
1269
1270 /* Return success */
1271 return TRUE;
1272 }
1273
1274 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLfsLgs)
1275 {
1276 UCHAR FarPointer[6];
1277 BOOLEAN OperandSize, AddressSize;
1278 FAST486_MOD_REG_RM ModRegRm;
1279
1280 /* Make sure this is the right instruction */
1281 ASSERT((Opcode & 0xFE) == 0xB4);
1282
1283 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1284
1285 TOGGLE_OPSIZE(OperandSize);
1286 TOGGLE_ADSIZE(AddressSize);
1287
1288 /* Get the operands */
1289 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1290 {
1291 /* Exception occurred */
1292 return FALSE;
1293 }
1294
1295 if (!ModRegRm.Memory)
1296 {
1297 /* Invalid */
1298 Fast486Exception(State, FAST486_EXCEPTION_UD);
1299 return FALSE;
1300 }
1301
1302 if (!Fast486ReadMemory(State,
1303 (State->PrefixFlags & FAST486_PREFIX_SEG)
1304 ? State->SegmentOverride : FAST486_REG_DS,
1305 ModRegRm.MemoryAddress,
1306 FALSE,
1307 FarPointer,
1308 OperandSize ? 6 : 4))
1309 {
1310 /* Exception occurred */
1311 return FALSE;
1312 }
1313
1314 if (OperandSize)
1315 {
1316 ULONG Offset = *((PULONG)FarPointer);
1317 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(ULONG)]);
1318
1319 /* Set the register to the offset */
1320 State->GeneralRegs[ModRegRm.Register].Long = Offset;
1321
1322 /* Load the segment */
1323 return Fast486LoadSegment(State,
1324 (Opcode == 0xB4)
1325 ? FAST486_REG_FS : FAST486_REG_GS,
1326 Segment);
1327 }
1328 else
1329 {
1330 USHORT Offset = *((PUSHORT)FarPointer);
1331 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(USHORT)]);
1332
1333 /* Set the register to the offset */
1334 State->GeneralRegs[ModRegRm.Register].LowWord = Offset;
1335
1336 /* Load the segment */
1337 return Fast486LoadSegment(State,
1338 (Opcode == 0xB4)
1339 ? FAST486_REG_FS : FAST486_REG_GS,
1340 Segment);
1341 }
1342 }
1343
1344 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxByte)
1345 {
1346 UCHAR Value;
1347 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1348 FAST486_MOD_REG_RM ModRegRm;
1349
1350 TOGGLE_ADSIZE(AddressSize);
1351
1352 /* Make sure this is the right instruction */
1353 ASSERT(Opcode == 0xB6);
1354
1355 /* Get the operands */
1356 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1357 {
1358 /* Exception occurred */
1359 return FALSE;
1360 }
1361
1362 /* Read the operands */
1363 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
1364 {
1365 /* Exception occurred */
1366 return FALSE;
1367 }
1368
1369 /* Write back the zero-extended value */
1370 return Fast486WriteModrmDwordOperands(State,
1371 &ModRegRm,
1372 TRUE,
1373 (ULONG)Value);
1374 }
1375
1376 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxWord)
1377 {
1378 USHORT Value;
1379 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1380 FAST486_MOD_REG_RM ModRegRm;
1381
1382 TOGGLE_ADSIZE(AddressSize);
1383
1384 /* Make sure this is the right instruction */
1385 ASSERT(Opcode == 0xB7);
1386
1387 /* Get the operands */
1388 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1389 {
1390 /* Exception occurred */
1391 return FALSE;
1392 }
1393
1394 /* Read the operands */
1395 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
1396 {
1397 /* Exception occurred */
1398 return FALSE;
1399 }
1400
1401 /* Write back the zero-extended value */
1402 return Fast486WriteModrmDwordOperands(State,
1403 &ModRegRm,
1404 TRUE,
1405 (ULONG)Value);
1406 }
1407
1408 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtc)
1409 {
1410 BOOLEAN OperandSize, AddressSize;
1411 FAST486_MOD_REG_RM ModRegRm;
1412 UINT DataSize;
1413 ULONG BitNumber;
1414
1415 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1416 TOGGLE_OPSIZE(OperandSize);
1417 TOGGLE_ADSIZE(AddressSize);
1418
1419 /* Get the number of bits */
1420 if (OperandSize) DataSize = 32;
1421 else DataSize = 16;
1422
1423 /* Get the operands */
1424 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1425 {
1426 /* Exception occurred */
1427 return FALSE;
1428 }
1429
1430 /* Get the bit number */
1431 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
1432 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
1433
1434 if (ModRegRm.Memory)
1435 {
1436 /*
1437 * For memory operands, add the bit offset divided by
1438 * the data size to the address
1439 */
1440 ModRegRm.MemoryAddress += BitNumber / DataSize;
1441 }
1442
1443 /* Normalize the bit number */
1444 BitNumber %= DataSize;
1445
1446 if (OperandSize)
1447 {
1448 ULONG Value;
1449
1450 /* Read the value */
1451 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1452 {
1453 /* Exception occurred */
1454 return FALSE;
1455 }
1456
1457 /* Set CF to the bit value */
1458 State->Flags.Cf = (Value >> BitNumber) & 1;
1459
1460 /* Toggle the bit */
1461 Value ^= 1 << BitNumber;
1462
1463 /* Write back the result */
1464 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
1465 {
1466 /* Exception occurred */
1467 return FALSE;
1468 }
1469 }
1470 else
1471 {
1472 USHORT Value;
1473
1474 /* Read the value */
1475 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
1476 {
1477 /* Exception occurred */
1478 return FALSE;
1479 }
1480
1481 /* Set CF to the bit value */
1482 State->Flags.Cf = (Value >> BitNumber) & 1;
1483
1484 /* Toggle the bit */
1485 Value ^= 1 << BitNumber;
1486
1487 /* Write back the result */
1488 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
1489 {
1490 /* Exception occurred */
1491 return FALSE;
1492 }
1493 }
1494
1495 /* Return success */
1496 return TRUE;
1497 }
1498
1499 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsf)
1500 {
1501 INT i;
1502 ULONG Value = 0;
1503 BOOLEAN OperandSize, AddressSize;
1504 FAST486_MOD_REG_RM ModRegRm;
1505 ULONG BitNumber;
1506 UINT DataSize;
1507
1508 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1509 TOGGLE_OPSIZE(OperandSize);
1510 TOGGLE_ADSIZE(AddressSize);
1511
1512 /* Make sure this is the right instruction */
1513 ASSERT(Opcode == 0xBC);
1514
1515 /* Get the number of bits */
1516 if (OperandSize) DataSize = 32;
1517 else DataSize = 16;
1518
1519 /* Get the operands */
1520 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1521 {
1522 /* Exception occurred */
1523 return FALSE;
1524 }
1525
1526 /* Read the value */
1527 if (OperandSize)
1528 {
1529 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1530 {
1531 /* Exception occurred */
1532 return FALSE;
1533 }
1534 }
1535 else
1536 {
1537 if (!Fast486ReadModrmWordOperands(State,
1538 &ModRegRm,
1539 (PUSHORT)NULL,
1540 (PUSHORT)&Value))
1541 {
1542 /* Exception occurred */
1543 return FALSE;
1544 }
1545 }
1546
1547 /* Set ZF */
1548 State->Flags.Zf = (Value == 0);
1549 if (State->Flags.Zf) return TRUE;
1550
1551 for (i = 0; i < DataSize; i++)
1552 {
1553 if(Value & (1 << i))
1554 {
1555 /* Save the bit number */
1556 BitNumber = i;
1557
1558 /* Exit the loop */
1559 break;
1560 }
1561 }
1562
1563 /* Write back the result */
1564 if (OperandSize)
1565 {
1566 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, BitNumber))
1567 {
1568 /* Exception occurred */
1569 return FALSE;
1570 }
1571 }
1572 else
1573 {
1574 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(BitNumber)))
1575 {
1576 /* Exception occurred */
1577 return FALSE;
1578 }
1579 }
1580
1581 return TRUE;
1582 }
1583
1584 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsr)
1585 {
1586 INT i;
1587 ULONG Value = 0;
1588 BOOLEAN OperandSize, AddressSize;
1589 FAST486_MOD_REG_RM ModRegRm;
1590 ULONG BitNumber;
1591 UINT DataSize;
1592
1593 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1594 TOGGLE_OPSIZE(OperandSize);
1595 TOGGLE_ADSIZE(AddressSize);
1596
1597 /* Make sure this is the right instruction */
1598 ASSERT(Opcode == 0xBD);
1599
1600 /* Get the number of bits */
1601 if (OperandSize) DataSize = 32;
1602 else DataSize = 16;
1603
1604 /* Get the operands */
1605 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1606 {
1607 /* Exception occurred */
1608 return FALSE;
1609 }
1610
1611 /* Read the value */
1612 if (OperandSize)
1613 {
1614 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1615 {
1616 /* Exception occurred */
1617 return FALSE;
1618 }
1619 }
1620 else
1621 {
1622 if (!Fast486ReadModrmWordOperands(State,
1623 &ModRegRm,
1624 (PUSHORT)NULL,
1625 (PUSHORT)&Value))
1626 {
1627 /* Exception occurred */
1628 return FALSE;
1629 }
1630 }
1631
1632 /* Set ZF according to the value */
1633 State->Flags.Zf = (Value == 0);
1634 if (State->Flags.Zf) return TRUE;
1635
1636 for (i = DataSize - 1; i >= 0; i--)
1637 {
1638 if(Value & (1 << i))
1639 {
1640 /* Save the bit number */
1641 BitNumber = i;
1642
1643 /* Exit the loop */
1644 break;
1645 }
1646 }
1647
1648 /* Write back the result */
1649 if (OperandSize)
1650 {
1651 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, BitNumber))
1652 {
1653 /* Exception occurred */
1654 return FALSE;
1655 }
1656 }
1657 else
1658 {
1659 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(BitNumber)))
1660 {
1661 /* Exception occurred */
1662 return FALSE;
1663 }
1664 }
1665
1666 return TRUE;
1667 }
1668
1669 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxByte)
1670 {
1671 CHAR Value;
1672 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1673 FAST486_MOD_REG_RM ModRegRm;
1674
1675 TOGGLE_ADSIZE(AddressSize);
1676
1677 /* Make sure this is the right instruction */
1678 ASSERT(Opcode == 0xBE);
1679
1680 /* Get the operands */
1681 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1682 {
1683 /* Exception occurred */
1684 return FALSE;
1685 }
1686
1687 /* Read the operands */
1688 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, (PUCHAR)&Value))
1689 {
1690 /* Exception occurred */
1691 return FALSE;
1692 }
1693
1694 /* Write back the sign-extended value */
1695 return Fast486WriteModrmDwordOperands(State,
1696 &ModRegRm,
1697 TRUE,
1698 (ULONG)((LONG)Value));
1699 }
1700
1701 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxWord)
1702 {
1703 SHORT Value;
1704 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1705 FAST486_MOD_REG_RM ModRegRm;
1706
1707 TOGGLE_ADSIZE(AddressSize);
1708
1709 /* Make sure this is the right instruction */
1710 ASSERT(Opcode == 0xBF);
1711
1712 /* Get the operands */
1713 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1714 {
1715 /* Exception occurred */
1716 return FALSE;
1717 }
1718
1719 /* Read the operands */
1720 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, (PUSHORT)&Value))
1721 {
1722 /* Exception occurred */
1723 return FALSE;
1724 }
1725
1726 /* Write back the sign-extended value */
1727 return Fast486WriteModrmDwordOperands(State,
1728 &ModRegRm,
1729 TRUE,
1730 (ULONG)((LONG)Value));
1731 }
1732
1733 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalJmp)
1734 {
1735 BOOLEAN Jump = FALSE;
1736 LONG Offset = 0;
1737 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1738
1739 TOGGLE_OPSIZE(Size);
1740 NO_LOCK_PREFIX();
1741
1742 /* Make sure this is the right instruction */
1743 ASSERT((Opcode & 0xF0) == 0x80);
1744
1745 /* Fetch the offset */
1746 if (Size)
1747 {
1748 if (!Fast486FetchDword(State, (PULONG)&Offset))
1749 {
1750 /* Exception occurred */
1751 return FALSE;
1752 }
1753 }
1754 else
1755 {
1756 SHORT Value;
1757
1758 if (!Fast486FetchWord(State, (PUSHORT)&Value))
1759 {
1760 /* Exception occurred */
1761 return FALSE;
1762 }
1763
1764 /* Sign-extend */
1765 Offset = (LONG)Value;
1766 }
1767
1768 switch ((Opcode & 0x0F) >> 1)
1769 {
1770 /* JO / JNO */
1771 case 0:
1772 {
1773 Jump = State->Flags.Of;
1774 break;
1775 }
1776
1777 /* JC / JNC */
1778 case 1:
1779 {
1780 Jump = State->Flags.Cf;
1781 break;
1782 }
1783
1784 /* JZ / JNZ */
1785 case 2:
1786 {
1787 Jump = State->Flags.Zf;
1788 break;
1789 }
1790
1791 /* JBE / JNBE */
1792 case 3:
1793 {
1794 Jump = State->Flags.Cf || State->Flags.Zf;
1795 break;
1796 }
1797
1798 /* JS / JNS */
1799 case 4:
1800 {
1801 Jump = State->Flags.Sf;
1802 break;
1803 }
1804
1805 /* JP / JNP */
1806 case 5:
1807 {
1808 Jump = State->Flags.Pf;
1809 break;
1810 }
1811
1812 /* JL / JNL */
1813 case 6:
1814 {
1815 Jump = State->Flags.Sf != State->Flags.Of;
1816 break;
1817 }
1818
1819 /* JLE / JNLE */
1820 case 7:
1821 {
1822 Jump = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
1823 break;
1824 }
1825 }
1826
1827 if (Opcode & 1)
1828 {
1829 /* Invert the result */
1830 Jump = !Jump;
1831 }
1832
1833 if (Jump)
1834 {
1835 /* Move the instruction pointer */
1836 State->InstPtr.Long += Offset;
1837 }
1838
1839 /* Return success */
1840 return TRUE;
1841 }
1842
1843 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalSet)
1844 {
1845 BOOLEAN Value = FALSE;
1846 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1847 FAST486_MOD_REG_RM ModRegRm;
1848
1849 TOGGLE_ADSIZE(AddressSize);
1850
1851 /* Get the operands */
1852 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1853 {
1854 /* Exception occurred */
1855 return FALSE;
1856 }
1857
1858 /* Make sure this is the right instruction */
1859 ASSERT((Opcode & 0xF0) == 0x90);
1860
1861 switch ((Opcode & 0x0F) >> 1)
1862 {
1863 /* SETO / SETNO */
1864 case 0:
1865 {
1866 Value = State->Flags.Of;
1867 break;
1868 }
1869
1870 /* SETC / SETNC */
1871 case 1:
1872 {
1873 Value = State->Flags.Cf;
1874 break;
1875 }
1876
1877 /* SETZ / SETNZ */
1878 case 2:
1879 {
1880 Value = State->Flags.Zf;
1881 break;
1882 }
1883
1884 /* SETBE / SETNBE */
1885 case 3:
1886 {
1887 Value = State->Flags.Cf || State->Flags.Zf;
1888 break;
1889 }
1890
1891 /* SETS / SETNS */
1892 case 4:
1893 {
1894 Value = State->Flags.Sf;
1895 break;
1896 }
1897
1898 /* SETP / SETNP */
1899 case 5:
1900 {
1901 Value = State->Flags.Pf;
1902 break;
1903 }
1904
1905 /* SETL / SETNL */
1906 case 6:
1907 {
1908 Value = State->Flags.Sf != State->Flags.Of;
1909 break;
1910 }
1911
1912 /* SETLE / SETNLE */
1913 case 7:
1914 {
1915 Value = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
1916 break;
1917 }
1918 }
1919
1920 if (Opcode & 1)
1921 {
1922 /* Invert the result */
1923 Value = !Value;
1924 }
1925
1926 /* Write back the result */
1927 return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
1928 }
1929
1930 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXaddByte)
1931 {
1932 UCHAR Source, Destination, Result;
1933 FAST486_MOD_REG_RM ModRegRm;
1934 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1935
1936 /* Make sure this is the right instruction */
1937 ASSERT(Opcode == 0xC0);
1938
1939 TOGGLE_ADSIZE(AddressSize);
1940
1941 /* Get the operands */
1942 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1943 {
1944 /* Exception occurred */
1945 return FALSE;
1946 }
1947
1948 if (!Fast486ReadModrmByteOperands(State,
1949 &ModRegRm,
1950 &Source,
1951 &Destination))
1952 {
1953 /* Exception occurred */
1954 return FALSE;
1955 }
1956
1957 /* Calculate the result */
1958 Result = Source + Destination;
1959
1960 /* Update the flags */
1961 State->Flags.Cf = (Result < Source) && (Result < Destination);
1962 State->Flags.Of = ((Source & SIGN_FLAG_BYTE) == (Destination & SIGN_FLAG_BYTE))
1963 && ((Source & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
1964 State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0);
1965 State->Flags.Zf = (Result == 0);
1966 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1967 State->Flags.Pf = Fast486CalculateParity(Result);
1968
1969 /* Write the sum to the destination */
1970 if (!Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Result))
1971 {
1972 /* Exception occurred */
1973 return FALSE;
1974 }
1975
1976 /* Write the old value of the destination to the source */
1977 if (!Fast486WriteModrmByteOperands(State, &ModRegRm, TRUE, Destination))
1978 {
1979 /* Exception occurred */
1980 return FALSE;
1981 }
1982
1983 return TRUE;
1984 }
1985
1986 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXadd)
1987 {
1988 FAST486_MOD_REG_RM ModRegRm;
1989 BOOLEAN OperandSize, AddressSize;
1990
1991 /* Make sure this is the right instruction */
1992 ASSERT(Opcode == 0xC1);
1993
1994 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1995
1996 TOGGLE_ADSIZE(AddressSize);
1997 TOGGLE_OPSIZE(OperandSize);
1998
1999 /* Get the operands */
2000 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2001 {
2002 /* Exception occurred */
2003 return FALSE;
2004 }
2005
2006 /* Check the operand size */
2007 if (OperandSize)
2008 {
2009 ULONG Source, Destination, Result;
2010
2011 if (!Fast486ReadModrmDwordOperands(State,
2012 &ModRegRm,
2013 &Source,
2014 &Destination))
2015 {
2016 /* Exception occurred */
2017 return FALSE;
2018 }
2019
2020 /* Calculate the result */
2021 Result = Source + Destination;
2022
2023 /* Update the flags */
2024 State->Flags.Cf = (Result < Source) && (Result < Destination);
2025 State->Flags.Of = ((Source & SIGN_FLAG_LONG) == (Destination & SIGN_FLAG_LONG))
2026 && ((Source & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
2027 State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0);
2028 State->Flags.Zf = (Result == 0);
2029 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2030 State->Flags.Pf = Fast486CalculateParity(Result);
2031
2032 /* Write the old value of the destination to the source */
2033 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, Destination))
2034 {
2035 /* Exception occurred */
2036 return FALSE;
2037 }
2038
2039 /* Write the sum to the destination */
2040 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result))
2041 {
2042 /* Exception occurred */
2043 return FALSE;
2044 }
2045 }
2046 else
2047 {
2048 USHORT Source, Destination, Result;
2049
2050 if (!Fast486ReadModrmWordOperands(State,
2051 &ModRegRm,
2052 &Source,
2053 &Destination))
2054 {
2055 /* Exception occurred */
2056 return FALSE;
2057 }
2058
2059 /* Calculate the result */
2060 Result = Source + Destination;
2061
2062 /* Update the flags */
2063 State->Flags.Cf = (Result < Source) && (Result < Destination);
2064 State->Flags.Of = ((Source & SIGN_FLAG_WORD) == (Destination & SIGN_FLAG_WORD))
2065 && ((Source & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
2066 State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0);
2067 State->Flags.Zf = (Result == 0);
2068 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2069 State->Flags.Pf = Fast486CalculateParity(Result);
2070
2071 /* Write the old value of the destination to the source */
2072 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, Destination))
2073 {
2074 /* Exception occurred */
2075 return FALSE;
2076 }
2077
2078 /* Write the sum to the destination */
2079 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Result))
2080 {
2081 /* Exception occurred */
2082 return FALSE;
2083 }
2084 }
2085
2086 return TRUE;
2087 }
2088
2089 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBswap)
2090 {
2091 PUCHAR Pointer;
2092
2093 NO_LOCK_PREFIX();
2094
2095 /* Get a pointer to the value */
2096 Pointer = (PUCHAR)&State->GeneralRegs[Opcode & 0x07].Long;
2097
2098 /* Swap the byte order */
2099 SWAP(Pointer[0], Pointer[3]);
2100 SWAP(Pointer[1], Pointer[2]);
2101
2102 /* Return success */
2103 return TRUE;
2104 }
2105
2106 FAST486_OPCODE_HANDLER(Fast486OpcodeExtended)
2107 {
2108 UCHAR SecondOpcode;
2109
2110 /* Fetch the second operation code */
2111 if (!Fast486FetchByte(State, &SecondOpcode))
2112 {
2113 /* Exception occurred */
2114 return FALSE;
2115 }
2116
2117 if (Fast486ExtendedHandlers[SecondOpcode] != NULL)
2118 {
2119 /* Call the extended opcode handler */
2120 return Fast486ExtendedHandlers[SecondOpcode](State, SecondOpcode);
2121 }
2122 else
2123 {
2124 /* This is not a valid opcode */
2125 Fast486Exception(State, FAST486_EXCEPTION_UD);
2126 return FALSE;
2127 }
2128 }
2129