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