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