[FAST486]
[reactos.git] / lib / fast486 / extraops.c
1 /*
2 * Fast486 386/486 CPU Emulation Library
3 * extraops.c
4 *
5 * Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22 /* INCLUDES *******************************************************************/
23
24 // #define WIN32_NO_STATUS
25 // #define _INC_WINDOWS
26 #include <windef.h>
27
28 // #define NDEBUG
29 #include <debug.h>
30
31 #include <fast486.h>
32 #include "opcodes.h"
33 #include "common.h"
34 #include "opgroups.h"
35 #include "extraops.h"
36
37 /* PUBLIC VARIABLES ***********************************************************/
38
39 FAST486_OPCODE_HANDLER_PROC
40 Fast486ExtendedHandlers[FAST486_NUM_OPCODE_HANDLERS] =
41 {
42 NULL, // TODO: OPCODE 0x00 NOT IMPLEMENTED
43 NULL, // TODO: OPCODE 0x01 NOT IMPLEMENTED
44 NULL, // TODO: OPCODE 0x02 NOT IMPLEMENTED
45 NULL, // TODO: OPCODE 0x03 NOT IMPLEMENTED
46 NULL, // TODO: OPCODE 0x04 NOT IMPLEMENTED
47 NULL, // TODO: OPCODE 0x05 NOT IMPLEMENTED
48 Fast486ExtOpcodeClts,
49 NULL, // TODO: OPCODE 0x07 NOT IMPLEMENTED
50 NULL, // TODO: OPCODE 0x08 NOT IMPLEMENTED
51 NULL, // TODO: OPCODE 0x09 NOT IMPLEMENTED
52 NULL, // Invalid
53 NULL, // Reserved (UD1)
54 NULL, // Invalid
55 NULL, // Invalid
56 NULL, // Invalid
57 NULL, // Invalid
58 NULL, // TODO: OPCODE 0x10 NOT IMPLEMENTED
59 NULL, // TODO: OPCODE 0x11 NOT IMPLEMENTED
60 NULL, // TODO: OPCODE 0x12 NOT IMPLEMENTED
61 NULL, // TODO: OPCODE 0x13 NOT IMPLEMENTED
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 NULL, // Invalid
73 NULL, // Invalid
74 Fast486ExtOpcodeStoreControlReg,
75 Fast486ExtOpcodeStoreDebugReg,
76 Fast486ExtOpcodeLoadControlReg,
77 Fast486ExtOpcodeLoadDebugReg,
78 NULL, // TODO: OPCODE 0x24 NOT IMPLEMENTED
79 NULL, // Invalid
80 NULL, // TODO: OPCODE 0x26 NOT IMPLEMENTED
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 NULL, // Invalid
169 NULL, // Invalid
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 Fast486ExtOpcodeConditionalJmp,
185 Fast486ExtOpcodeConditionalJmp,
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 Fast486ExtOpcodeConditionalSet,
201 Fast486ExtOpcodeConditionalSet,
202 Fast486ExtOpcodePushFs,
203 Fast486ExtOpcodePopFs,
204 NULL, // Invalid
205 Fast486ExtOpcodeBitTest,
206 NULL, // TODO: OPCODE 0xA4 NOT IMPLEMENTED
207 NULL, // TODO: OPCODE 0xA5 NOT IMPLEMENTED
208 NULL, // Invalid
209 NULL, // Invalid
210 Fast486ExtOpcodePushGs,
211 Fast486ExtOpcodePopGs,
212 NULL, // Invalid
213 Fast486ExtOpcodeBts,
214 NULL, // TODO: OPCODE 0xAC NOT IMPLEMENTED
215 NULL, // TODO: OPCODE 0xAD NOT IMPLEMENTED
216 NULL, // TODO: OPCODE 0xAE NOT IMPLEMENTED
217 NULL, // TODO: OPCODE 0xAF NOT IMPLEMENTED
218 Fast486ExtOpcodeCmpXchgByte,
219 Fast486ExtOpcodeCmpXchg,
220 NULL, // TODO: OPCODE 0xB2 NOT IMPLEMENTED
221 Fast486ExtOpcodeBtr,
222 NULL, // TODO: OPCODE 0xB4 NOT IMPLEMENTED
223 NULL, // TODO: OPCODE 0xB5 NOT IMPLEMENTED
224 NULL, // TODO: OPCODE 0xB6 NOT IMPLEMENTED
225 NULL, // TODO: OPCODE 0xB7 NOT IMPLEMENTED
226 NULL, // TODO: OPCODE 0xB8 NOT IMPLEMENTED
227 Fast486OpcodeGroup0FB9,
228 Fast486OpcodeGroup0FBA,
229 Fast486ExtOpcodeBtc,
230 NULL, // TODO: OPCODE 0xBC NOT IMPLEMENTED
231 NULL, // TODO: OPCODE 0xBD NOT IMPLEMENTED
232 NULL, // TODO: OPCODE 0xBE NOT IMPLEMENTED
233 NULL, // TODO: OPCODE 0xBF NOT IMPLEMENTED
234 NULL, // TODO: OPCODE 0xC0 NOT IMPLEMENTED
235 NULL, // TODO: OPCODE 0xC1 NOT IMPLEMENTED
236 NULL, // Invalid
237 NULL, // Invalid
238 NULL, // Invalid
239 NULL, // Invalid
240 NULL, // Invalid
241 NULL, // Invalid
242 Fast486ExtOpcodeBswap,
243 Fast486ExtOpcodeBswap,
244 Fast486ExtOpcodeBswap,
245 Fast486ExtOpcodeBswap,
246 Fast486ExtOpcodeBswap,
247 Fast486ExtOpcodeBswap,
248 Fast486ExtOpcodeBswap,
249 Fast486ExtOpcodeBswap,
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 NULL, // Invalid
297 NULL, // Invalid
298 };
299
300 /* PUBLIC FUNCTIONS ***********************************************************/
301
302 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeClts)
303 {
304 NO_LOCK_PREFIX();
305
306 /* The current privilege level must be zero */
307 if (Fast486GetCurrentPrivLevel(State) != 0)
308 {
309 Fast486Exception(State, FAST486_EXCEPTION_GP);
310 return FALSE;
311 }
312
313 /* Clear the task switch bit */
314 State->ControlRegisters[FAST486_REG_CR0] &= ~FAST486_CR0_TS;
315
316 return TRUE;
317 }
318
319 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreControlReg)
320 {
321 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
322 FAST486_MOD_REG_RM ModRegRm;
323
324 NO_LOCK_PREFIX();
325 TOGGLE_ADSIZE(AddressSize);
326
327 /* Get the operands */
328 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
329 {
330 /* Exception occurred */
331 return FALSE;
332 }
333
334 /* The current privilege level must be zero */
335 if (Fast486GetCurrentPrivLevel(State) != 0)
336 {
337 Fast486Exception(State, FAST486_EXCEPTION_GP);
338 return FALSE;
339 }
340
341 if ((ModRegRm.Register == 1) || (ModRegRm.Register > 3))
342 {
343 /* CR1, CR4, CR5, CR6 and CR7 don't exist */
344 Fast486Exception(State, FAST486_EXCEPTION_UD);
345 return FALSE;
346 }
347
348 if (ModRegRm.Register != 0)
349 {
350 /* CR2 and CR3 and are stored in array indexes 1 and 2 */
351 ModRegRm.Register--;
352 }
353
354 /* Store the value of the control register */
355 State->GeneralRegs[ModRegRm.SecondRegister].Long = State->ControlRegisters[ModRegRm.Register];
356
357 /* Return success */
358 return TRUE;
359 }
360
361 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreDebugReg)
362 {
363 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
364 FAST486_MOD_REG_RM ModRegRm;
365
366 NO_LOCK_PREFIX();
367 TOGGLE_ADSIZE(AddressSize);
368
369 /* Get the operands */
370 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
371 {
372 /* Exception occurred */
373 return FALSE;
374 }
375
376 /* The current privilege level must be zero */
377 if (Fast486GetCurrentPrivLevel(State) != 0)
378 {
379 Fast486Exception(State, FAST486_EXCEPTION_GP);
380 return FALSE;
381 }
382
383 if ((ModRegRm.Register == 6) || (ModRegRm.Register == 7))
384 {
385 /* DR6 and DR7 are aliases to DR4 and DR5 */
386 ModRegRm.Register -= 2;
387 }
388
389 if (State->DebugRegisters[FAST486_REG_DR5] & FAST486_DR5_GD)
390 {
391 /* Disallow access to debug registers */
392 Fast486Exception(State, FAST486_EXCEPTION_GP);
393 return FALSE;
394 }
395
396 /* Store the value of the debug register */
397 State->GeneralRegs[ModRegRm.SecondRegister].Long = State->DebugRegisters[ModRegRm.Register];
398
399 /* Return success */
400 return TRUE;
401 }
402
403 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadControlReg)
404 {
405 ULONG Value;
406 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
407 FAST486_MOD_REG_RM ModRegRm;
408
409 NO_LOCK_PREFIX();
410 TOGGLE_ADSIZE(AddressSize);
411
412 /* Get the operands */
413 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
414 {
415 /* Exception occurred */
416 return FALSE;
417 }
418
419 /* The current privilege level must be zero */
420 if (Fast486GetCurrentPrivLevel(State) != 0)
421 {
422 Fast486Exception(State, FAST486_EXCEPTION_GP);
423 return FALSE;
424 }
425
426 if ((ModRegRm.Register == 1) || (ModRegRm.Register > 3))
427 {
428 /* CR1, CR4, CR5, CR6 and CR7 don't exist */
429 Fast486Exception(State, FAST486_EXCEPTION_UD);
430 return FALSE;
431 }
432
433 if (ModRegRm.Register != 0)
434 {
435 /* CR2 and CR3 and are stored in array indexes 1 and 2 */
436 ModRegRm.Register--;
437 }
438
439 /* Get the value */
440 Value = State->GeneralRegs[ModRegRm.SecondRegister].Long;
441
442 if (ModRegRm.Register == (INT)FAST486_REG_CR0)
443 {
444 /* CR0 checks */
445
446 if (((Value & (FAST486_CR0_PG | FAST486_CR0_PE)) == FAST486_CR0_PG)
447 || ((Value & (FAST486_CR0_CD | FAST486_CR0_NW)) == FAST486_CR0_NW))
448 {
449 /* Invalid value */
450 Fast486Exception(State, FAST486_EXCEPTION_GP);
451 return FALSE;
452 }
453 }
454
455 /* Load a value to the control register */
456 State->ControlRegisters[ModRegRm.Register] = Value;
457
458 /* Return success */
459 return TRUE;
460 }
461
462 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadDebugReg)
463 {
464 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
465 FAST486_MOD_REG_RM ModRegRm;
466
467 NO_LOCK_PREFIX();
468 TOGGLE_ADSIZE(AddressSize);
469
470 /* Get the operands */
471 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
472 {
473 /* Exception occurred */
474 return FALSE;
475 }
476
477 /* The current privilege level must be zero */
478 if (Fast486GetCurrentPrivLevel(State) != 0)
479 {
480 Fast486Exception(State, FAST486_EXCEPTION_GP);
481 return FALSE;
482 }
483
484 if ((ModRegRm.Register == 6) || (ModRegRm.Register == 7))
485 {
486 /* DR6 and DR7 are aliases to DR4 and DR5 */
487 ModRegRm.Register -= 2;
488 }
489
490 if (State->DebugRegisters[FAST486_REG_DR5] & FAST486_DR5_GD)
491 {
492 /* Disallow access to debug registers */
493 Fast486Exception(State, FAST486_EXCEPTION_GP);
494 return FALSE;
495 }
496
497 /* Load a value to the debug register */
498 State->DebugRegisters[ModRegRm.Register] = State->GeneralRegs[ModRegRm.SecondRegister].Long;
499
500 if (ModRegRm.Register == (INT)FAST486_REG_DR4)
501 {
502 /* The reserved bits are 1 */
503 State->DebugRegisters[ModRegRm.Register] |= FAST486_DR4_RESERVED;
504 }
505 else if (ModRegRm.Register == (INT)FAST486_REG_DR5)
506 {
507 /* The reserved bits are 0 */
508 State->DebugRegisters[ModRegRm.Register] &= ~FAST486_DR5_RESERVED;
509 }
510
511 /* Return success */
512 return TRUE;
513 }
514
515 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushFs)
516 {
517 /* Call the internal API */
518 return Fast486StackPush(State, State->SegmentRegs[FAST486_REG_FS].Selector);
519 }
520
521 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopFs)
522 {
523 ULONG NewSelector;
524
525 if (!Fast486StackPop(State, &NewSelector))
526 {
527 /* Exception occurred */
528 return FALSE;
529 }
530
531 /* Call the internal API */
532 return Fast486LoadSegment(State, FAST486_REG_FS, LOWORD(NewSelector));
533 }
534
535 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBitTest)
536 {
537 BOOLEAN OperandSize, AddressSize;
538 FAST486_MOD_REG_RM ModRegRm;
539 UINT DataSize;
540 ULONG BitNumber;
541
542 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
543 TOGGLE_OPSIZE(OperandSize);
544 TOGGLE_ADSIZE(AddressSize);
545
546 /* Get the number of bits */
547 if (OperandSize) DataSize = 32;
548 else DataSize = 16;
549
550 /* Get the operands */
551 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
552 {
553 /* Exception occurred */
554 return FALSE;
555 }
556
557 /* Get the bit number */
558 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
559 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
560
561 if (ModRegRm.Memory)
562 {
563 /*
564 * For memory operands, add the bit offset divided by
565 * the data size to the address
566 */
567 ModRegRm.MemoryAddress += BitNumber / DataSize;
568 }
569
570 /* Normalize the bit number */
571 BitNumber &= (1 << DataSize) - 1;
572
573 if (OperandSize)
574 {
575 ULONG Dummy, Value;
576
577 /* Read the value */
578 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
579 {
580 /* Exception occurred */
581 return FALSE;
582 }
583
584 /* Set CF to the bit value */
585 State->Flags.Cf = (Value >> BitNumber) & 1;
586 }
587 else
588 {
589 USHORT Dummy, Value;
590
591 /* Read the value */
592 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
593 {
594 /* Exception occurred */
595 return FALSE;
596 }
597
598 /* Set CF to the bit value */
599 State->Flags.Cf = (Value >> BitNumber) & 1;
600 }
601
602 /* Return success */
603 return TRUE;
604 }
605
606 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushGs)
607 {
608 /* Call the internal API */
609 return Fast486StackPush(State, State->SegmentRegs[FAST486_REG_GS].Selector);
610 }
611
612 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopGs)
613 {
614 ULONG NewSelector;
615
616 if (!Fast486StackPop(State, &NewSelector))
617 {
618 /* Exception occurred */
619 return FALSE;
620 }
621
622 /* Call the internal API */
623 return Fast486LoadSegment(State, FAST486_REG_GS, LOWORD(NewSelector));
624 }
625
626 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBts)
627 {
628 BOOLEAN OperandSize, AddressSize;
629 FAST486_MOD_REG_RM ModRegRm;
630 UINT DataSize;
631 ULONG BitNumber;
632
633 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
634 TOGGLE_OPSIZE(OperandSize);
635 TOGGLE_ADSIZE(AddressSize);
636
637 /* Get the number of bits */
638 if (OperandSize) DataSize = 32;
639 else DataSize = 16;
640
641 /* Get the operands */
642 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
643 {
644 /* Exception occurred */
645 return FALSE;
646 }
647
648 /* Get the bit number */
649 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
650 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
651
652 if (ModRegRm.Memory)
653 {
654 /*
655 * For memory operands, add the bit offset divided by
656 * the data size to the address
657 */
658 ModRegRm.MemoryAddress += BitNumber / DataSize;
659 }
660
661 /* Normalize the bit number */
662 BitNumber &= (1 << DataSize) - 1;
663
664 if (OperandSize)
665 {
666 ULONG Dummy, Value;
667
668 /* Read the value */
669 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
670 {
671 /* Exception occurred */
672 return FALSE;
673 }
674
675 /* Set CF to the bit value */
676 State->Flags.Cf = (Value >> BitNumber) & 1;
677
678 /* Set the bit */
679 Value |= 1 << BitNumber;
680
681 /* Write back the result */
682 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
683 {
684 /* Exception occurred */
685 return FALSE;
686 }
687 }
688 else
689 {
690 USHORT Dummy, Value;
691
692 /* Read the value */
693 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
694 {
695 /* Exception occurred */
696 return FALSE;
697 }
698
699 /* Set CF to the bit value */
700 State->Flags.Cf = (Value >> BitNumber) & 1;
701
702 /* Set the bit */
703 Value |= 1 << BitNumber;
704
705 /* Write back the result */
706 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
707 {
708 /* Exception occurred */
709 return FALSE;
710 }
711 }
712
713 /* Return success */
714 return TRUE;
715 }
716
717 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchgByte)
718 {
719 FAST486_MOD_REG_RM ModRegRm;
720 UCHAR Accumulator = State->GeneralRegs[FAST486_REG_EAX].LowByte;
721 UCHAR Source, Destination, Result;
722 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
723
724 TOGGLE_ADSIZE(AddressSize);
725
726 /* Get the operands */
727 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
728 {
729 /* Exception occurred */
730 return FALSE;
731 }
732
733 /* Read the operands */
734 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, &Source, &Destination))
735 {
736 /* Exception occurred */
737 return FALSE;
738 }
739
740 /* Compare AL with the destination */
741 Result = Accumulator - Destination;
742
743 /* Update the flags */
744 State->Flags.Cf = Accumulator < Destination;
745 State->Flags.Of = ((Accumulator & SIGN_FLAG_BYTE) != (Destination & SIGN_FLAG_BYTE))
746 && ((Accumulator & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
747 State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F);
748 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
749 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
750 State->Flags.Pf = Fast486CalculateParity(Result);
751
752 if (State->Flags.Zf)
753 {
754 /* Load the source operand into the destination */
755 return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Source);
756 }
757 else
758 {
759 /* Load the destination into AL */
760 State->GeneralRegs[FAST486_REG_EAX].LowByte = Destination;
761 }
762
763 /* Return success */
764 return TRUE;
765 }
766
767 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchg)
768 {
769 FAST486_MOD_REG_RM ModRegRm;
770 BOOLEAN OperandSize, AddressSize;
771
772 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
773
774 TOGGLE_OPSIZE(OperandSize);
775 TOGGLE_ADSIZE(AddressSize);
776
777 /* Get the operands */
778 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
779 {
780 /* Exception occurred */
781 return FALSE;
782 }
783
784 if (OperandSize)
785 {
786 ULONG Source, Destination, Result;
787 ULONG Accumulator = State->GeneralRegs[FAST486_REG_EAX].Long;
788
789 /* Read the operands */
790 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Source, &Destination))
791 {
792 /* Exception occurred */
793 return FALSE;
794 }
795
796 /* Compare EAX with the destination */
797 Result = Accumulator - Destination;
798
799 /* Update the flags */
800 State->Flags.Cf = Accumulator < Destination;
801 State->Flags.Of = ((Accumulator & SIGN_FLAG_LONG) != (Destination & SIGN_FLAG_LONG))
802 && ((Accumulator & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
803 State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F);
804 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
805 State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
806 State->Flags.Pf = Fast486CalculateParity(Result);
807
808 if (State->Flags.Zf)
809 {
810 /* Load the source operand into the destination */
811 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Source);
812 }
813 else
814 {
815 /* Load the destination into EAX */
816 State->GeneralRegs[FAST486_REG_EAX].Long = Destination;
817 }
818 }
819 else
820 {
821 USHORT Source, Destination, Result;
822 USHORT Accumulator = State->GeneralRegs[FAST486_REG_EAX].LowWord;
823
824 /* Read the operands */
825 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Source, &Destination))
826 {
827 /* Exception occurred */
828 return FALSE;
829 }
830
831 /* Compare AX with the destination */
832 Result = Accumulator - Destination;
833
834 /* Update the flags */
835 State->Flags.Cf = Accumulator < Destination;
836 State->Flags.Of = ((Accumulator & SIGN_FLAG_WORD) != (Destination & SIGN_FLAG_WORD))
837 && ((Accumulator & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
838 State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F);
839 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
840 State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
841 State->Flags.Pf = Fast486CalculateParity(Result);
842
843 if (State->Flags.Zf)
844 {
845 /* Load the source operand into the destination */
846 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Source);
847 }
848 else
849 {
850 /* Load the destination into AX */
851 State->GeneralRegs[FAST486_REG_EAX].LowWord = Destination;
852 }
853 }
854
855 /* Return success */
856 return TRUE;
857 }
858
859 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtr)
860 {
861 BOOLEAN OperandSize, AddressSize;
862 FAST486_MOD_REG_RM ModRegRm;
863 UINT DataSize;
864 ULONG BitNumber;
865
866 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
867 TOGGLE_OPSIZE(OperandSize);
868 TOGGLE_ADSIZE(AddressSize);
869
870 /* Get the number of bits */
871 if (OperandSize) DataSize = 32;
872 else DataSize = 16;
873
874 /* Get the operands */
875 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
876 {
877 /* Exception occurred */
878 return FALSE;
879 }
880
881 /* Get the bit number */
882 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
883 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
884
885 if (ModRegRm.Memory)
886 {
887 /*
888 * For memory operands, add the bit offset divided by
889 * the data size to the address
890 */
891 ModRegRm.MemoryAddress += BitNumber / DataSize;
892 }
893
894 /* Normalize the bit number */
895 BitNumber &= (1 << DataSize) - 1;
896
897 if (OperandSize)
898 {
899 ULONG Dummy, Value;
900
901 /* Read the value */
902 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
903 {
904 /* Exception occurred */
905 return FALSE;
906 }
907
908 /* Set CF to the bit value */
909 State->Flags.Cf = (Value >> BitNumber) & 1;
910
911 /* Clear the bit */
912 Value &= ~(1 << BitNumber);
913
914 /* Write back the result */
915 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
916 {
917 /* Exception occurred */
918 return FALSE;
919 }
920 }
921 else
922 {
923 USHORT Dummy, Value;
924
925 /* Read the value */
926 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
927 {
928 /* Exception occurred */
929 return FALSE;
930 }
931
932 /* Set CF to the bit value */
933 State->Flags.Cf = (Value >> BitNumber) & 1;
934
935 /* Clear the bit */
936 Value &= ~(1 << BitNumber);
937
938 /* Write back the result */
939 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
940 {
941 /* Exception occurred */
942 return FALSE;
943 }
944 }
945
946 /* Return success */
947 return TRUE;
948 }
949
950 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtc)
951 {
952 BOOLEAN OperandSize, AddressSize;
953 FAST486_MOD_REG_RM ModRegRm;
954 UINT DataSize;
955 ULONG BitNumber;
956
957 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
958 TOGGLE_OPSIZE(OperandSize);
959 TOGGLE_ADSIZE(AddressSize);
960
961 /* Get the number of bits */
962 if (OperandSize) DataSize = 32;
963 else DataSize = 16;
964
965 /* Get the operands */
966 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
967 {
968 /* Exception occurred */
969 return FALSE;
970 }
971
972 /* Get the bit number */
973 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
974 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
975
976 if (ModRegRm.Memory)
977 {
978 /*
979 * For memory operands, add the bit offset divided by
980 * the data size to the address
981 */
982 ModRegRm.MemoryAddress += BitNumber / DataSize;
983 }
984
985 /* Normalize the bit number */
986 BitNumber &= (1 << DataSize) - 1;
987
988 if (OperandSize)
989 {
990 ULONG Dummy, Value;
991
992 /* Read the value */
993 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
994 {
995 /* Exception occurred */
996 return FALSE;
997 }
998
999 /* Set CF to the bit value */
1000 State->Flags.Cf = (Value >> BitNumber) & 1;
1001
1002 /* Toggle the bit */
1003 Value ^= 1 << BitNumber;
1004
1005 /* Write back the result */
1006 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
1007 {
1008 /* Exception occurred */
1009 return FALSE;
1010 }
1011 }
1012 else
1013 {
1014 USHORT Dummy, Value;
1015
1016 /* Read the value */
1017 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
1018 {
1019 /* Exception occurred */
1020 return FALSE;
1021 }
1022
1023 /* Set CF to the bit value */
1024 State->Flags.Cf = (Value >> BitNumber) & 1;
1025
1026 /* Toggle the bit */
1027 Value ^= 1 << BitNumber;
1028
1029 /* Write back the result */
1030 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
1031 {
1032 /* Exception occurred */
1033 return FALSE;
1034 }
1035 }
1036
1037 /* Return success */
1038 return TRUE;
1039 }
1040
1041 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalJmp)
1042 {
1043 BOOLEAN Jump = FALSE;
1044 LONG Offset = 0;
1045 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1046
1047 TOGGLE_OPSIZE(Size);
1048 NO_LOCK_PREFIX();
1049
1050 /* Make sure this is the right instruction */
1051 ASSERT((Opcode & 0xF0) == 0x80);
1052
1053 /* Fetch the offset */
1054 if (Size)
1055 {
1056 if (!Fast486FetchDword(State, (PULONG)&Offset))
1057 {
1058 /* Exception occurred */
1059 return FALSE;
1060 }
1061 }
1062 else
1063 {
1064 SHORT Value;
1065
1066 if (!Fast486FetchWord(State, (PUSHORT)&Value))
1067 {
1068 /* Exception occurred */
1069 return FALSE;
1070 }
1071
1072 /* Sign-extend */
1073 Offset = (LONG)Value;
1074 }
1075
1076 switch ((Opcode & 0x0F) >> 1)
1077 {
1078 /* JO / JNO */
1079 case 0:
1080 {
1081 Jump = State->Flags.Of;
1082 break;
1083 }
1084
1085 /* JC / JNC */
1086 case 1:
1087 {
1088 Jump = State->Flags.Cf;
1089 break;
1090 }
1091
1092 /* JZ / JNZ */
1093 case 2:
1094 {
1095 Jump = State->Flags.Zf;
1096 break;
1097 }
1098
1099 /* JBE / JNBE */
1100 case 3:
1101 {
1102 Jump = State->Flags.Cf || State->Flags.Zf;
1103 break;
1104 }
1105
1106 /* JS / JNS */
1107 case 4:
1108 {
1109 Jump = State->Flags.Sf;
1110 break;
1111 }
1112
1113 /* JP / JNP */
1114 case 5:
1115 {
1116 Jump = State->Flags.Pf;
1117 break;
1118 }
1119
1120 /* JL / JNL */
1121 case 6:
1122 {
1123 Jump = State->Flags.Sf != State->Flags.Of;
1124 break;
1125 }
1126
1127 /* JLE / JNLE */
1128 case 7:
1129 {
1130 Jump = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
1131 break;
1132 }
1133 }
1134
1135 if (Opcode & 1)
1136 {
1137 /* Invert the result */
1138 Jump = !Jump;
1139 }
1140
1141 if (Jump)
1142 {
1143 /* Move the instruction pointer */
1144 State->InstPtr.Long += Offset;
1145 }
1146
1147 /* Return success */
1148 return TRUE;
1149 }
1150
1151 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalSet)
1152 {
1153 BOOLEAN Value = FALSE;
1154 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1155 FAST486_MOD_REG_RM ModRegRm;
1156
1157 TOGGLE_ADSIZE(AddressSize);
1158
1159 /* Get the operands */
1160 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1161 {
1162 /* Exception occurred */
1163 return FALSE;
1164 }
1165
1166 /* Make sure this is the right instruction */
1167 ASSERT((Opcode & 0xF0) == 0x90);
1168
1169 switch ((Opcode & 0x0F) >> 1)
1170 {
1171 /* SETO / SETNO */
1172 case 0:
1173 {
1174 Value = State->Flags.Of;
1175 break;
1176 }
1177
1178 /* SETC / SETNC */
1179 case 1:
1180 {
1181 Value = State->Flags.Cf;
1182 break;
1183 }
1184
1185 /* SETZ / SETNZ */
1186 case 2:
1187 {
1188 Value = State->Flags.Zf;
1189 break;
1190 }
1191
1192 /* SETBE / SETNBE */
1193 case 3:
1194 {
1195 Value = State->Flags.Cf || State->Flags.Zf;
1196 break;
1197 }
1198
1199 /* SETS / SETNS */
1200 case 4:
1201 {
1202 Value = State->Flags.Sf;
1203 break;
1204 }
1205
1206 /* SETP / SETNP */
1207 case 5:
1208 {
1209 Value = State->Flags.Pf;
1210 break;
1211 }
1212
1213 /* SETL / SETNL */
1214 case 6:
1215 {
1216 Value = State->Flags.Sf != State->Flags.Of;
1217 break;
1218 }
1219
1220 /* SETLE / SETNLE */
1221 case 7:
1222 {
1223 Value = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
1224 break;
1225 }
1226 }
1227
1228 if (Opcode & 1)
1229 {
1230 /* Invert the result */
1231 Value = !Value;
1232 }
1233
1234 /* Write back the result */
1235 return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
1236 }
1237
1238 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBswap)
1239 {
1240 PUCHAR Pointer;
1241
1242 NO_LOCK_PREFIX();
1243
1244 /* Get a pointer to the value */
1245 Pointer = (PUCHAR)&State->GeneralRegs[Opcode & 0x07].Long;
1246
1247 /* Swap the byte order */
1248 SWAP(Pointer[0], Pointer[3]);
1249 SWAP(Pointer[1], Pointer[2]);
1250
1251 /* Return success */
1252 return TRUE;
1253 }
1254
1255 FAST486_OPCODE_HANDLER(Fast486OpcodeExtended)
1256 {
1257 UCHAR SecondOpcode;
1258
1259 /* Fetch the second operation code */
1260 if (!Fast486FetchByte(State, &SecondOpcode))
1261 {
1262 /* Exception occurred */
1263 return FALSE;
1264 }
1265
1266 if (Fast486ExtendedHandlers[SecondOpcode] != NULL)
1267 {
1268 /* Call the extended opcode handler */
1269 return Fast486ExtendedHandlers[SecondOpcode](State, SecondOpcode);
1270 }
1271 else
1272 {
1273 /* This is not a valid opcode */
1274 Fast486Exception(State, FAST486_EXCEPTION_UD);
1275 return FALSE;
1276 }
1277 }
1278