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