[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 NULL, // TODO: OPCODE 0x06 NOT IMPLEMENTED
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 NULL, // TODO: OPCODE 0x20 NOT IMPLEMENTED
75 NULL, // TODO: OPCODE 0x21 NOT IMPLEMENTED
76 NULL, // TODO: OPCODE 0x22 NOT IMPLEMENTED
77 NULL, // TODO: OPCODE 0x23 NOT IMPLEMENTED
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, // TODO: OPCODE 0xAA NOT IMPLEMENTED
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(Fast486ExtOpcodePushFs)
303 {
304 /* Call the internal API */
305 return Fast486StackPush(State, State->SegmentRegs[FAST486_REG_FS].Selector);
306 }
307
308 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopFs)
309 {
310 ULONG NewSelector;
311
312 if (!Fast486StackPop(State, &NewSelector))
313 {
314 /* Exception occurred */
315 return FALSE;
316 }
317
318 /* Call the internal API */
319 return Fast486LoadSegment(State, FAST486_REG_FS, LOWORD(NewSelector));
320 }
321
322 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBitTest)
323 {
324 BOOLEAN OperandSize, AddressSize;
325 FAST486_MOD_REG_RM ModRegRm;
326 UINT DataSize;
327 ULONG BitNumber;
328
329 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
330 TOGGLE_OPSIZE(OperandSize);
331 TOGGLE_ADSIZE(AddressSize);
332
333 /* Get the number of bits */
334 if (OperandSize) DataSize = 32;
335 else DataSize = 16;
336
337 /* Get the operands */
338 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
339 {
340 /* Exception occurred */
341 return FALSE;
342 }
343
344 /* Get the bit number */
345 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
346 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
347
348 if (ModRegRm.Memory)
349 {
350 /*
351 * For memory operands, add the bit offset divided by
352 * the data size to the address
353 */
354 ModRegRm.MemoryAddress += BitNumber / DataSize;
355 }
356
357 /* Normalize the bit number */
358 BitNumber &= (1 << DataSize) - 1;
359
360 if (OperandSize)
361 {
362 ULONG Dummy, Value;
363
364 /* Read the value */
365 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
366 {
367 /* Exception occurred */
368 return FALSE;
369 }
370
371 /* Set CF to the bit value */
372 State->Flags.Cf = (Value >> BitNumber) & 1;
373 }
374 else
375 {
376 USHORT Dummy, Value;
377
378 /* Read the value */
379 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
380 {
381 /* Exception occurred */
382 return FALSE;
383 }
384
385 /* Set CF to the bit value */
386 State->Flags.Cf = (Value >> BitNumber) & 1;
387 }
388
389 /* Return success */
390 return TRUE;
391 }
392
393 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushGs)
394 {
395 /* Call the internal API */
396 return Fast486StackPush(State, State->SegmentRegs[FAST486_REG_GS].Selector);
397 }
398
399 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopGs)
400 {
401 ULONG NewSelector;
402
403 if (!Fast486StackPop(State, &NewSelector))
404 {
405 /* Exception occurred */
406 return FALSE;
407 }
408
409 /* Call the internal API */
410 return Fast486LoadSegment(State, FAST486_REG_GS, LOWORD(NewSelector));
411 }
412
413 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBts)
414 {
415 BOOLEAN OperandSize, AddressSize;
416 FAST486_MOD_REG_RM ModRegRm;
417 UINT DataSize;
418 ULONG BitNumber;
419
420 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
421 TOGGLE_OPSIZE(OperandSize);
422 TOGGLE_ADSIZE(AddressSize);
423
424 /* Get the number of bits */
425 if (OperandSize) DataSize = 32;
426 else DataSize = 16;
427
428 /* Get the operands */
429 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
430 {
431 /* Exception occurred */
432 return FALSE;
433 }
434
435 /* Get the bit number */
436 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
437 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
438
439 if (ModRegRm.Memory)
440 {
441 /*
442 * For memory operands, add the bit offset divided by
443 * the data size to the address
444 */
445 ModRegRm.MemoryAddress += BitNumber / DataSize;
446 }
447
448 /* Normalize the bit number */
449 BitNumber &= (1 << DataSize) - 1;
450
451 if (OperandSize)
452 {
453 ULONG Dummy, Value;
454
455 /* Read the value */
456 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
457 {
458 /* Exception occurred */
459 return FALSE;
460 }
461
462 /* Set CF to the bit value */
463 State->Flags.Cf = (Value >> BitNumber) & 1;
464
465 /* Set the bit */
466 Value |= 1 << BitNumber;
467
468 /* Write back the result */
469 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
470 {
471 /* Exception occurred */
472 return FALSE;
473 }
474 }
475 else
476 {
477 USHORT Dummy, Value;
478
479 /* Read the value */
480 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
481 {
482 /* Exception occurred */
483 return FALSE;
484 }
485
486 /* Set CF to the bit value */
487 State->Flags.Cf = (Value >> BitNumber) & 1;
488
489 /* Set the bit */
490 Value |= 1 << BitNumber;
491
492 /* Write back the result */
493 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
494 {
495 /* Exception occurred */
496 return FALSE;
497 }
498 }
499
500 /* Return success */
501 return TRUE;
502 }
503
504 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchgByte)
505 {
506 FAST486_MOD_REG_RM ModRegRm;
507 UCHAR Accumulator = State->GeneralRegs[FAST486_REG_EAX].LowByte;
508 UCHAR Source, Destination, Result;
509 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
510
511 TOGGLE_ADSIZE(AddressSize);
512
513 /* Get the operands */
514 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
515 {
516 /* Exception occurred */
517 return FALSE;
518 }
519
520 /* Read the operands */
521 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, &Source, &Destination))
522 {
523 /* Exception occurred */
524 return FALSE;
525 }
526
527 /* Compare AL with the destination */
528 Result = Accumulator - Destination;
529
530 /* Update the flags */
531 State->Flags.Cf = Accumulator < Destination;
532 State->Flags.Of = ((Accumulator & SIGN_FLAG_BYTE) != (Destination & SIGN_FLAG_BYTE))
533 && ((Accumulator & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
534 State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F);
535 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
536 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
537 State->Flags.Pf = Fast486CalculateParity(Result);
538
539 if (State->Flags.Zf)
540 {
541 /* Load the source operand into the destination */
542 return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Source);
543 }
544 else
545 {
546 /* Load the destination into AL */
547 State->GeneralRegs[FAST486_REG_EAX].LowByte = Destination;
548 }
549
550 /* Return success */
551 return TRUE;
552 }
553
554 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchg)
555 {
556 FAST486_MOD_REG_RM ModRegRm;
557 BOOLEAN OperandSize, AddressSize;
558
559 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
560
561 TOGGLE_OPSIZE(OperandSize);
562 TOGGLE_ADSIZE(AddressSize);
563
564 /* Get the operands */
565 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
566 {
567 /* Exception occurred */
568 return FALSE;
569 }
570
571 if (OperandSize)
572 {
573 ULONG Source, Destination, Result;
574 ULONG Accumulator = State->GeneralRegs[FAST486_REG_EAX].Long;
575
576 /* Read the operands */
577 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Source, &Destination))
578 {
579 /* Exception occurred */
580 return FALSE;
581 }
582
583 /* Compare EAX with the destination */
584 Result = Accumulator - Destination;
585
586 /* Update the flags */
587 State->Flags.Cf = Accumulator < Destination;
588 State->Flags.Of = ((Accumulator & SIGN_FLAG_LONG) != (Destination & SIGN_FLAG_LONG))
589 && ((Accumulator & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
590 State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F);
591 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
592 State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
593 State->Flags.Pf = Fast486CalculateParity(Result);
594
595 if (State->Flags.Zf)
596 {
597 /* Load the source operand into the destination */
598 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Source);
599 }
600 else
601 {
602 /* Load the destination into EAX */
603 State->GeneralRegs[FAST486_REG_EAX].Long = Destination;
604 }
605 }
606 else
607 {
608 USHORT Source, Destination, Result;
609 USHORT Accumulator = State->GeneralRegs[FAST486_REG_EAX].LowWord;
610
611 /* Read the operands */
612 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Source, &Destination))
613 {
614 /* Exception occurred */
615 return FALSE;
616 }
617
618 /* Compare AX with the destination */
619 Result = Accumulator - Destination;
620
621 /* Update the flags */
622 State->Flags.Cf = Accumulator < Destination;
623 State->Flags.Of = ((Accumulator & SIGN_FLAG_WORD) != (Destination & SIGN_FLAG_WORD))
624 && ((Accumulator & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
625 State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F);
626 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
627 State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
628 State->Flags.Pf = Fast486CalculateParity(Result);
629
630 if (State->Flags.Zf)
631 {
632 /* Load the source operand into the destination */
633 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Source);
634 }
635 else
636 {
637 /* Load the destination into AX */
638 State->GeneralRegs[FAST486_REG_EAX].LowWord = Destination;
639 }
640 }
641
642 /* Return success */
643 return TRUE;
644 }
645
646 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtr)
647 {
648 BOOLEAN OperandSize, AddressSize;
649 FAST486_MOD_REG_RM ModRegRm;
650 UINT DataSize;
651 ULONG BitNumber;
652
653 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
654 TOGGLE_OPSIZE(OperandSize);
655 TOGGLE_ADSIZE(AddressSize);
656
657 /* Get the number of bits */
658 if (OperandSize) DataSize = 32;
659 else DataSize = 16;
660
661 /* Get the operands */
662 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
663 {
664 /* Exception occurred */
665 return FALSE;
666 }
667
668 /* Get the bit number */
669 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
670 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
671
672 if (ModRegRm.Memory)
673 {
674 /*
675 * For memory operands, add the bit offset divided by
676 * the data size to the address
677 */
678 ModRegRm.MemoryAddress += BitNumber / DataSize;
679 }
680
681 /* Normalize the bit number */
682 BitNumber &= (1 << DataSize) - 1;
683
684 if (OperandSize)
685 {
686 ULONG Dummy, Value;
687
688 /* Read the value */
689 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
690 {
691 /* Exception occurred */
692 return FALSE;
693 }
694
695 /* Set CF to the bit value */
696 State->Flags.Cf = (Value >> BitNumber) & 1;
697
698 /* Clear the bit */
699 Value &= ~(1 << BitNumber);
700
701 /* Write back the result */
702 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
703 {
704 /* Exception occurred */
705 return FALSE;
706 }
707 }
708 else
709 {
710 USHORT Dummy, Value;
711
712 /* Read the value */
713 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
714 {
715 /* Exception occurred */
716 return FALSE;
717 }
718
719 /* Set CF to the bit value */
720 State->Flags.Cf = (Value >> BitNumber) & 1;
721
722 /* Clear the bit */
723 Value &= ~(1 << BitNumber);
724
725 /* Write back the result */
726 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
727 {
728 /* Exception occurred */
729 return FALSE;
730 }
731 }
732
733 /* Return success */
734 return TRUE;
735 }
736
737 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtc)
738 {
739 BOOLEAN OperandSize, AddressSize;
740 FAST486_MOD_REG_RM ModRegRm;
741 UINT DataSize;
742 ULONG BitNumber;
743
744 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
745 TOGGLE_OPSIZE(OperandSize);
746 TOGGLE_ADSIZE(AddressSize);
747
748 /* Get the number of bits */
749 if (OperandSize) DataSize = 32;
750 else DataSize = 16;
751
752 /* Get the operands */
753 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
754 {
755 /* Exception occurred */
756 return FALSE;
757 }
758
759 /* Get the bit number */
760 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
761 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
762
763 if (ModRegRm.Memory)
764 {
765 /*
766 * For memory operands, add the bit offset divided by
767 * the data size to the address
768 */
769 ModRegRm.MemoryAddress += BitNumber / DataSize;
770 }
771
772 /* Normalize the bit number */
773 BitNumber &= (1 << DataSize) - 1;
774
775 if (OperandSize)
776 {
777 ULONG Dummy, Value;
778
779 /* Read the value */
780 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
781 {
782 /* Exception occurred */
783 return FALSE;
784 }
785
786 /* Set CF to the bit value */
787 State->Flags.Cf = (Value >> BitNumber) & 1;
788
789 /* Toggle the bit */
790 Value ^= 1 << BitNumber;
791
792 /* Write back the result */
793 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
794 {
795 /* Exception occurred */
796 return FALSE;
797 }
798 }
799 else
800 {
801 USHORT Dummy, Value;
802
803 /* Read the value */
804 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
805 {
806 /* Exception occurred */
807 return FALSE;
808 }
809
810 /* Set CF to the bit value */
811 State->Flags.Cf = (Value >> BitNumber) & 1;
812
813 /* Toggle the bit */
814 Value ^= 1 << BitNumber;
815
816 /* Write back the result */
817 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
818 {
819 /* Exception occurred */
820 return FALSE;
821 }
822 }
823
824 /* Return success */
825 return TRUE;
826 }
827
828 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalJmp)
829 {
830 BOOLEAN Jump = FALSE;
831 LONG Offset = 0;
832 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
833
834 TOGGLE_OPSIZE(Size);
835 NO_LOCK_PREFIX();
836
837 /* Make sure this is the right instruction */
838 ASSERT((Opcode & 0xF0) == 0x80);
839
840 /* Fetch the offset */
841 if (Size)
842 {
843 if (!Fast486FetchDword(State, (PULONG)&Offset))
844 {
845 /* Exception occurred */
846 return FALSE;
847 }
848 }
849 else
850 {
851 SHORT Value;
852
853 if (!Fast486FetchWord(State, (PUSHORT)&Value))
854 {
855 /* Exception occurred */
856 return FALSE;
857 }
858
859 /* Sign-extend */
860 Offset = (LONG)Value;
861 }
862
863 switch ((Opcode & 0x0F) >> 1)
864 {
865 /* JO / JNO */
866 case 0:
867 {
868 Jump = State->Flags.Of;
869 break;
870 }
871
872 /* JC / JNC */
873 case 1:
874 {
875 Jump = State->Flags.Cf;
876 break;
877 }
878
879 /* JZ / JNZ */
880 case 2:
881 {
882 Jump = State->Flags.Zf;
883 break;
884 }
885
886 /* JBE / JNBE */
887 case 3:
888 {
889 Jump = State->Flags.Cf || State->Flags.Zf;
890 break;
891 }
892
893 /* JS / JNS */
894 case 4:
895 {
896 Jump = State->Flags.Sf;
897 break;
898 }
899
900 /* JP / JNP */
901 case 5:
902 {
903 Jump = State->Flags.Pf;
904 break;
905 }
906
907 /* JL / JNL */
908 case 6:
909 {
910 Jump = State->Flags.Sf != State->Flags.Of;
911 break;
912 }
913
914 /* JLE / JNLE */
915 case 7:
916 {
917 Jump = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
918 break;
919 }
920 }
921
922 if (Opcode & 1)
923 {
924 /* Invert the result */
925 Jump = !Jump;
926 }
927
928 if (Jump)
929 {
930 /* Move the instruction pointer */
931 State->InstPtr.Long += Offset;
932 }
933
934 /* Return success */
935 return TRUE;
936 }
937
938 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalSet)
939 {
940 BOOLEAN Value = FALSE;
941 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
942 FAST486_MOD_REG_RM ModRegRm;
943
944 TOGGLE_ADSIZE(AddressSize);
945
946 /* Get the operands */
947 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
948 {
949 /* Exception occurred */
950 return FALSE;
951 }
952
953 /* Make sure this is the right instruction */
954 ASSERT((Opcode & 0xF0) == 0x90);
955
956 switch ((Opcode & 0x0F) >> 1)
957 {
958 /* SETO / SETNO */
959 case 0:
960 {
961 Value = State->Flags.Of;
962 break;
963 }
964
965 /* SETC / SETNC */
966 case 1:
967 {
968 Value = State->Flags.Cf;
969 break;
970 }
971
972 /* SETZ / SETNZ */
973 case 2:
974 {
975 Value = State->Flags.Zf;
976 break;
977 }
978
979 /* SETBE / SETNBE */
980 case 3:
981 {
982 Value = State->Flags.Cf || State->Flags.Zf;
983 break;
984 }
985
986 /* SETS / SETNS */
987 case 4:
988 {
989 Value = State->Flags.Sf;
990 break;
991 }
992
993 /* SETP / SETNP */
994 case 5:
995 {
996 Value = State->Flags.Pf;
997 break;
998 }
999
1000 /* SETL / SETNL */
1001 case 6:
1002 {
1003 Value = State->Flags.Sf != State->Flags.Of;
1004 break;
1005 }
1006
1007 /* SETLE / SETNLE */
1008 case 7:
1009 {
1010 Value = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
1011 break;
1012 }
1013 }
1014
1015 if (Opcode & 1)
1016 {
1017 /* Invert the result */
1018 Value = !Value;
1019 }
1020
1021 /* Write back the result */
1022 return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
1023 }
1024
1025 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBswap)
1026 {
1027 PUCHAR Pointer;
1028
1029 NO_LOCK_PREFIX();
1030
1031 /* Get a pointer to the value */
1032 Pointer = (PUCHAR)&State->GeneralRegs[Opcode & 0x07].Long;
1033
1034 /* Swap the byte order */
1035 SWAP(Pointer[0], Pointer[3]);
1036 SWAP(Pointer[1], Pointer[2]);
1037
1038 /* Return success */
1039 return TRUE;
1040 }
1041
1042 FAST486_OPCODE_HANDLER(Fast486OpcodeExtended)
1043 {
1044 UCHAR SecondOpcode;
1045
1046 /* Fetch the second operation code */
1047 if (!Fast486FetchByte(State, &SecondOpcode))
1048 {
1049 /* Exception occurred */
1050 return FALSE;
1051 }
1052
1053 if (Fast486ExtendedHandlers[SecondOpcode] != NULL)
1054 {
1055 /* Call the extended opcode handler */
1056 return Fast486ExtendedHandlers[SecondOpcode](State, SecondOpcode);
1057 }
1058 else
1059 {
1060 /* This is not a valid opcode */
1061 Fast486Exception(State, FAST486_EXCEPTION_UD);
1062 return FALSE;
1063 }
1064 }