ab7b22260e670db96ace23c6f075143d87eb0364
[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 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 Value;
759
760 /* Read the value */
761 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &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 Value;
783
784 /* Read the value */
785 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &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 Value;
1220
1221 /* Read the value */
1222 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &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 Value;
1244
1245 /* Read the value */
1246 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &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 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, NULL, &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 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, NULL, &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 Value;
1445
1446 /* Read the value */
1447 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &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 Value;
1469
1470 /* Read the value */
1471 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &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 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, NULL, &Value))
1526 {
1527 /* Exception occurred */
1528 return FALSE;
1529 }
1530 }
1531 else
1532 {
1533 if (!Fast486ReadModrmWordOperands(State,
1534 &ModRegRm,
1535 (PUSHORT)NULL,
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 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, NULL, &Value))
1611 {
1612 /* Exception occurred */
1613 return FALSE;
1614 }
1615 }
1616 else
1617 {
1618 if (!Fast486ReadModrmWordOperands(State,
1619 &ModRegRm,
1620 (PUSHORT)NULL,
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 CHAR Value;
1668 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1669 FAST486_MOD_REG_RM ModRegRm;
1670
1671 TOGGLE_ADSIZE(AddressSize);
1672
1673 /* Make sure this is the right instruction */
1674 ASSERT(Opcode == 0xBE);
1675
1676 /* Get the operands */
1677 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1678 {
1679 /* Exception occurred */
1680 return FALSE;
1681 }
1682
1683 /* Read the operands */
1684 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, (PUCHAR)&Value))
1685 {
1686 /* Exception occurred */
1687 return FALSE;
1688 }
1689
1690 /* Write back the sign-extended value */
1691 return Fast486WriteModrmDwordOperands(State,
1692 &ModRegRm,
1693 TRUE,
1694 (ULONG)((LONG)Value));
1695 }
1696
1697 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxWord)
1698 {
1699 SHORT Value;
1700 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1701 FAST486_MOD_REG_RM ModRegRm;
1702
1703 TOGGLE_ADSIZE(AddressSize);
1704
1705 /* Make sure this is the right instruction */
1706 ASSERT(Opcode == 0xBF);
1707
1708 /* Get the operands */
1709 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1710 {
1711 /* Exception occurred */
1712 return FALSE;
1713 }
1714
1715 /* Read the operands */
1716 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, (PUSHORT)&Value))
1717 {
1718 /* Exception occurred */
1719 return FALSE;
1720 }
1721
1722 /* Write back the sign-extended value */
1723 return Fast486WriteModrmDwordOperands(State,
1724 &ModRegRm,
1725 TRUE,
1726 (ULONG)((LONG)Value));
1727 }
1728
1729 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalJmp)
1730 {
1731 BOOLEAN Jump = FALSE;
1732 LONG Offset = 0;
1733 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1734
1735 TOGGLE_OPSIZE(Size);
1736 NO_LOCK_PREFIX();
1737
1738 /* Make sure this is the right instruction */
1739 ASSERT((Opcode & 0xF0) == 0x80);
1740
1741 /* Fetch the offset */
1742 if (Size)
1743 {
1744 if (!Fast486FetchDword(State, (PULONG)&Offset))
1745 {
1746 /* Exception occurred */
1747 return FALSE;
1748 }
1749 }
1750 else
1751 {
1752 SHORT Value;
1753
1754 if (!Fast486FetchWord(State, (PUSHORT)&Value))
1755 {
1756 /* Exception occurred */
1757 return FALSE;
1758 }
1759
1760 /* Sign-extend */
1761 Offset = (LONG)Value;
1762 }
1763
1764 switch ((Opcode & 0x0F) >> 1)
1765 {
1766 /* JO / JNO */
1767 case 0:
1768 {
1769 Jump = State->Flags.Of;
1770 break;
1771 }
1772
1773 /* JC / JNC */
1774 case 1:
1775 {
1776 Jump = State->Flags.Cf;
1777 break;
1778 }
1779
1780 /* JZ / JNZ */
1781 case 2:
1782 {
1783 Jump = State->Flags.Zf;
1784 break;
1785 }
1786
1787 /* JBE / JNBE */
1788 case 3:
1789 {
1790 Jump = State->Flags.Cf || State->Flags.Zf;
1791 break;
1792 }
1793
1794 /* JS / JNS */
1795 case 4:
1796 {
1797 Jump = State->Flags.Sf;
1798 break;
1799 }
1800
1801 /* JP / JNP */
1802 case 5:
1803 {
1804 Jump = State->Flags.Pf;
1805 break;
1806 }
1807
1808 /* JL / JNL */
1809 case 6:
1810 {
1811 Jump = State->Flags.Sf != State->Flags.Of;
1812 break;
1813 }
1814
1815 /* JLE / JNLE */
1816 case 7:
1817 {
1818 Jump = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
1819 break;
1820 }
1821 }
1822
1823 if (Opcode & 1)
1824 {
1825 /* Invert the result */
1826 Jump = !Jump;
1827 }
1828
1829 if (Jump)
1830 {
1831 /* Move the instruction pointer */
1832 State->InstPtr.Long += Offset;
1833 }
1834
1835 /* Return success */
1836 return TRUE;
1837 }
1838
1839 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalSet)
1840 {
1841 BOOLEAN Value = FALSE;
1842 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1843 FAST486_MOD_REG_RM ModRegRm;
1844
1845 TOGGLE_ADSIZE(AddressSize);
1846
1847 /* Get the operands */
1848 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1849 {
1850 /* Exception occurred */
1851 return FALSE;
1852 }
1853
1854 /* Make sure this is the right instruction */
1855 ASSERT((Opcode & 0xF0) == 0x90);
1856
1857 switch ((Opcode & 0x0F) >> 1)
1858 {
1859 /* SETO / SETNO */
1860 case 0:
1861 {
1862 Value = State->Flags.Of;
1863 break;
1864 }
1865
1866 /* SETC / SETNC */
1867 case 1:
1868 {
1869 Value = State->Flags.Cf;
1870 break;
1871 }
1872
1873 /* SETZ / SETNZ */
1874 case 2:
1875 {
1876 Value = State->Flags.Zf;
1877 break;
1878 }
1879
1880 /* SETBE / SETNBE */
1881 case 3:
1882 {
1883 Value = State->Flags.Cf || State->Flags.Zf;
1884 break;
1885 }
1886
1887 /* SETS / SETNS */
1888 case 4:
1889 {
1890 Value = State->Flags.Sf;
1891 break;
1892 }
1893
1894 /* SETP / SETNP */
1895 case 5:
1896 {
1897 Value = State->Flags.Pf;
1898 break;
1899 }
1900
1901 /* SETL / SETNL */
1902 case 6:
1903 {
1904 Value = State->Flags.Sf != State->Flags.Of;
1905 break;
1906 }
1907
1908 /* SETLE / SETNLE */
1909 case 7:
1910 {
1911 Value = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
1912 break;
1913 }
1914 }
1915
1916 if (Opcode & 1)
1917 {
1918 /* Invert the result */
1919 Value = !Value;
1920 }
1921
1922 /* Write back the result */
1923 return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
1924 }
1925
1926 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXaddByte)
1927 {
1928 UCHAR Source, Destination, Result;
1929 FAST486_MOD_REG_RM ModRegRm;
1930 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1931
1932 /* Make sure this is the right instruction */
1933 ASSERT(Opcode == 0xC0);
1934
1935 TOGGLE_ADSIZE(AddressSize);
1936
1937 /* Get the operands */
1938 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1939 {
1940 /* Exception occurred */
1941 return FALSE;
1942 }
1943
1944 if (!Fast486ReadModrmByteOperands(State,
1945 &ModRegRm,
1946 &Source,
1947 &Destination))
1948 {
1949 /* Exception occurred */
1950 return FALSE;
1951 }
1952
1953 /* Calculate the result */
1954 Result = Source + Destination;
1955
1956 /* Update the flags */
1957 State->Flags.Cf = (Result < Source) && (Result < Destination);
1958 State->Flags.Of = ((Source & SIGN_FLAG_BYTE) == (Destination & SIGN_FLAG_BYTE))
1959 && ((Source & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
1960 State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0);
1961 State->Flags.Zf = (Result == 0);
1962 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1963 State->Flags.Pf = Fast486CalculateParity(Result);
1964
1965 /* Write the sum to the destination */
1966 if (!Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Result))
1967 {
1968 /* Exception occurred */
1969 return FALSE;
1970 }
1971
1972 /* Write the old value of the destination to the source */
1973 if (!Fast486WriteModrmByteOperands(State, &ModRegRm, TRUE, Destination))
1974 {
1975 /* Exception occurred */
1976 return FALSE;
1977 }
1978
1979 return TRUE;
1980 }
1981
1982 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXadd)
1983 {
1984 FAST486_MOD_REG_RM ModRegRm;
1985 BOOLEAN OperandSize, AddressSize;
1986
1987 /* Make sure this is the right instruction */
1988 ASSERT(Opcode == 0xC1);
1989
1990 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1991
1992 TOGGLE_ADSIZE(AddressSize);
1993 TOGGLE_OPSIZE(OperandSize);
1994
1995 /* Get the operands */
1996 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1997 {
1998 /* Exception occurred */
1999 return FALSE;
2000 }
2001
2002 /* Check the operand size */
2003 if (OperandSize)
2004 {
2005 ULONG Source, Destination, Result;
2006
2007 if (!Fast486ReadModrmDwordOperands(State,
2008 &ModRegRm,
2009 &Source,
2010 &Destination))
2011 {
2012 /* Exception occurred */
2013 return FALSE;
2014 }
2015
2016 /* Calculate the result */
2017 Result = Source + Destination;
2018
2019 /* Update the flags */
2020 State->Flags.Cf = (Result < Source) && (Result < Destination);
2021 State->Flags.Of = ((Source & SIGN_FLAG_LONG) == (Destination & SIGN_FLAG_LONG))
2022 && ((Source & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
2023 State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0);
2024 State->Flags.Zf = (Result == 0);
2025 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2026 State->Flags.Pf = Fast486CalculateParity(Result);
2027
2028 /* Write the old value of the destination to the source */
2029 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, Destination))
2030 {
2031 /* Exception occurred */
2032 return FALSE;
2033 }
2034
2035 /* Write the sum to the destination */
2036 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result))
2037 {
2038 /* Exception occurred */
2039 return FALSE;
2040 }
2041 }
2042 else
2043 {
2044 USHORT Source, Destination, Result;
2045
2046 if (!Fast486ReadModrmWordOperands(State,
2047 &ModRegRm,
2048 &Source,
2049 &Destination))
2050 {
2051 /* Exception occurred */
2052 return FALSE;
2053 }
2054
2055 /* Calculate the result */
2056 Result = Source + Destination;
2057
2058 /* Update the flags */
2059 State->Flags.Cf = (Result < Source) && (Result < Destination);
2060 State->Flags.Of = ((Source & SIGN_FLAG_WORD) == (Destination & SIGN_FLAG_WORD))
2061 && ((Source & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
2062 State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0);
2063 State->Flags.Zf = (Result == 0);
2064 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2065 State->Flags.Pf = Fast486CalculateParity(Result);
2066
2067 /* Write the old value of the destination to the source */
2068 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, Destination))
2069 {
2070 /* Exception occurred */
2071 return FALSE;
2072 }
2073
2074 /* Write the sum to the destination */
2075 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Result))
2076 {
2077 /* Exception occurred */
2078 return FALSE;
2079 }
2080 }
2081
2082 return TRUE;
2083 }
2084
2085 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBswap)
2086 {
2087 PUCHAR Pointer;
2088
2089 NO_LOCK_PREFIX();
2090
2091 /* Get a pointer to the value */
2092 Pointer = (PUCHAR)&State->GeneralRegs[Opcode & 0x07].Long;
2093
2094 /* Swap the byte order */
2095 SWAP(Pointer[0], Pointer[3]);
2096 SWAP(Pointer[1], Pointer[2]);
2097
2098 /* Return success */
2099 return TRUE;
2100 }
2101
2102 FAST486_OPCODE_HANDLER(Fast486OpcodeExtended)
2103 {
2104 UCHAR SecondOpcode;
2105
2106 /* Fetch the second operation code */
2107 if (!Fast486FetchByte(State, &SecondOpcode))
2108 {
2109 /* Exception occurred */
2110 return FALSE;
2111 }
2112
2113 if (Fast486ExtendedHandlers[SecondOpcode] != NULL)
2114 {
2115 /* Call the extended opcode handler */
2116 return Fast486ExtendedHandlers[SecondOpcode](State, SecondOpcode);
2117 }
2118 else
2119 {
2120 /* This is not a valid opcode */
2121 Fast486Exception(State, FAST486_EXCEPTION_UD);
2122 return FALSE;
2123 }
2124 }
2125