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