2 * Fast486 386/486 CPU Emulation Library
5 * Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
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.
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.
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.
22 /* INCLUDES *******************************************************************/
35 /* PUBLIC VARIABLES ***********************************************************/
37 FAST486_OPCODE_HANDLER_PROC
38 Fast486ExtendedHandlers
[FAST486_NUM_OPCODE_HANDLERS
] =
40 NULL
, // TODO: OPCODE 0x00 NOT IMPLEMENTED
41 Fast486OpcodeGroup0F01
,
42 NULL
, // TODO: OPCODE 0x02 NOT IMPLEMENTED
43 NULL
, // TODO: OPCODE 0x03 NOT IMPLEMENTED
44 NULL
, // TODO: OPCODE 0x04 NOT IMPLEMENTED
45 NULL
, // TODO: OPCODE 0x05 NOT IMPLEMENTED
47 NULL
, // TODO: OPCODE 0x07 NOT IMPLEMENTED
48 NULL
, // TODO: OPCODE 0x08 NOT IMPLEMENTED
49 NULL
, // TODO: OPCODE 0x09 NOT IMPLEMENTED
51 NULL
, // Reserved (UD1)
56 NULL
, // TODO: OPCODE 0x10 NOT IMPLEMENTED
57 NULL
, // TODO: OPCODE 0x11 NOT IMPLEMENTED
58 NULL
, // TODO: OPCODE 0x12 NOT IMPLEMENTED
59 NULL
, // TODO: OPCODE 0x13 NOT IMPLEMENTED
72 Fast486ExtOpcodeStoreControlReg
,
73 Fast486ExtOpcodeStoreDebugReg
,
74 Fast486ExtOpcodeLoadControlReg
,
75 Fast486ExtOpcodeLoadDebugReg
,
76 NULL
, // TODO: OPCODE 0x24 NOT IMPLEMENTED
78 NULL
, // TODO: OPCODE 0x26 NOT IMPLEMENTED
168 Fast486ExtOpcodeConditionalJmp
,
169 Fast486ExtOpcodeConditionalJmp
,
170 Fast486ExtOpcodeConditionalJmp
,
171 Fast486ExtOpcodeConditionalJmp
,
172 Fast486ExtOpcodeConditionalJmp
,
173 Fast486ExtOpcodeConditionalJmp
,
174 Fast486ExtOpcodeConditionalJmp
,
175 Fast486ExtOpcodeConditionalJmp
,
176 Fast486ExtOpcodeConditionalJmp
,
177 Fast486ExtOpcodeConditionalJmp
,
178 Fast486ExtOpcodeConditionalJmp
,
179 Fast486ExtOpcodeConditionalJmp
,
180 Fast486ExtOpcodeConditionalJmp
,
181 Fast486ExtOpcodeConditionalJmp
,
182 Fast486ExtOpcodeConditionalJmp
,
183 Fast486ExtOpcodeConditionalJmp
,
184 Fast486ExtOpcodeConditionalSet
,
185 Fast486ExtOpcodeConditionalSet
,
186 Fast486ExtOpcodeConditionalSet
,
187 Fast486ExtOpcodeConditionalSet
,
188 Fast486ExtOpcodeConditionalSet
,
189 Fast486ExtOpcodeConditionalSet
,
190 Fast486ExtOpcodeConditionalSet
,
191 Fast486ExtOpcodeConditionalSet
,
192 Fast486ExtOpcodeConditionalSet
,
193 Fast486ExtOpcodeConditionalSet
,
194 Fast486ExtOpcodeConditionalSet
,
195 Fast486ExtOpcodeConditionalSet
,
196 Fast486ExtOpcodeConditionalSet
,
197 Fast486ExtOpcodeConditionalSet
,
198 Fast486ExtOpcodeConditionalSet
,
199 Fast486ExtOpcodeConditionalSet
,
200 Fast486ExtOpcodePushFs
,
201 Fast486ExtOpcodePopFs
,
203 Fast486ExtOpcodeBitTest
,
204 NULL
, // TODO: OPCODE 0xA4 NOT IMPLEMENTED
205 NULL
, // TODO: OPCODE 0xA5 NOT IMPLEMENTED
208 Fast486ExtOpcodePushGs
,
209 Fast486ExtOpcodePopGs
,
212 NULL
, // TODO: OPCODE 0xAC NOT IMPLEMENTED
213 NULL
, // TODO: OPCODE 0xAD NOT IMPLEMENTED
214 NULL
, // TODO: OPCODE 0xAE NOT IMPLEMENTED
215 NULL
, // TODO: OPCODE 0xAF NOT IMPLEMENTED
216 Fast486ExtOpcodeCmpXchgByte
,
217 Fast486ExtOpcodeCmpXchg
,
218 NULL
, // TODO: OPCODE 0xB2 NOT IMPLEMENTED
220 NULL
, // TODO: OPCODE 0xB4 NOT IMPLEMENTED
221 NULL
, // TODO: OPCODE 0xB5 NOT IMPLEMENTED
222 NULL
, // TODO: OPCODE 0xB6 NOT IMPLEMENTED
223 NULL
, // TODO: OPCODE 0xB7 NOT IMPLEMENTED
224 NULL
, // TODO: OPCODE 0xB8 NOT IMPLEMENTED
225 Fast486OpcodeGroup0FB9
,
226 Fast486OpcodeGroup0FBA
,
228 NULL
, // TODO: OPCODE 0xBC NOT IMPLEMENTED
229 NULL
, // TODO: OPCODE 0xBD NOT IMPLEMENTED
230 NULL
, // TODO: OPCODE 0xBE NOT IMPLEMENTED
231 NULL
, // TODO: OPCODE 0xBF NOT IMPLEMENTED
232 Fast486ExtOpcodeXaddByte
,
233 Fast486ExtOpcodeXadd
,
240 Fast486ExtOpcodeBswap
,
241 Fast486ExtOpcodeBswap
,
242 Fast486ExtOpcodeBswap
,
243 Fast486ExtOpcodeBswap
,
244 Fast486ExtOpcodeBswap
,
245 Fast486ExtOpcodeBswap
,
246 Fast486ExtOpcodeBswap
,
247 Fast486ExtOpcodeBswap
,
298 /* PUBLIC FUNCTIONS ***********************************************************/
300 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeClts
)
304 /* The current privilege level must be zero */
305 if (Fast486GetCurrentPrivLevel(State
) != 0)
307 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
311 /* Clear the task switch bit */
312 State
->ControlRegisters
[FAST486_REG_CR0
] &= ~FAST486_CR0_TS
;
317 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreControlReg
)
319 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
320 FAST486_MOD_REG_RM ModRegRm
;
323 TOGGLE_ADSIZE(AddressSize
);
325 /* Get the operands */
326 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
328 /* Exception occurred */
332 /* The current privilege level must be zero */
333 if (Fast486GetCurrentPrivLevel(State
) != 0)
335 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
339 if ((ModRegRm
.Register
== 1) || (ModRegRm
.Register
> 3))
341 /* CR1, CR4, CR5, CR6 and CR7 don't exist */
342 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
346 if (ModRegRm
.Register
!= 0)
348 /* CR2 and CR3 and are stored in array indexes 1 and 2 */
352 /* Store the value of the control register */
353 State
->GeneralRegs
[ModRegRm
.SecondRegister
].Long
= State
->ControlRegisters
[ModRegRm
.Register
];
359 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreDebugReg
)
361 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
362 FAST486_MOD_REG_RM ModRegRm
;
365 TOGGLE_ADSIZE(AddressSize
);
367 /* Get the operands */
368 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
370 /* Exception occurred */
374 /* The current privilege level must be zero */
375 if (Fast486GetCurrentPrivLevel(State
) != 0)
377 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
381 if ((ModRegRm
.Register
== 6) || (ModRegRm
.Register
== 7))
383 /* DR6 and DR7 are aliases to DR4 and DR5 */
384 ModRegRm
.Register
-= 2;
387 if (State
->DebugRegisters
[FAST486_REG_DR5
] & FAST486_DR5_GD
)
389 /* Disallow access to debug registers */
390 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
394 /* Store the value of the debug register */
395 State
->GeneralRegs
[ModRegRm
.SecondRegister
].Long
= State
->DebugRegisters
[ModRegRm
.Register
];
401 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadControlReg
)
404 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
405 FAST486_MOD_REG_RM ModRegRm
;
408 TOGGLE_ADSIZE(AddressSize
);
410 /* Get the operands */
411 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
413 /* Exception occurred */
417 /* The current privilege level must be zero */
418 if (Fast486GetCurrentPrivLevel(State
) != 0)
420 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
424 if ((ModRegRm
.Register
== 1) || (ModRegRm
.Register
> 3))
426 /* CR1, CR4, CR5, CR6 and CR7 don't exist */
427 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
431 if (ModRegRm
.Register
!= 0)
433 /* CR2 and CR3 and are stored in array indexes 1 and 2 */
438 Value
= State
->GeneralRegs
[ModRegRm
.SecondRegister
].Long
;
440 if (ModRegRm
.Register
== (INT
)FAST486_REG_CR0
)
444 if (((Value
& (FAST486_CR0_PG
| FAST486_CR0_PE
)) == FAST486_CR0_PG
)
445 || ((Value
& (FAST486_CR0_CD
| FAST486_CR0_NW
)) == FAST486_CR0_NW
))
448 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
453 /* Load a value to the control register */
454 State
->ControlRegisters
[ModRegRm
.Register
] = Value
;
460 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadDebugReg
)
462 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
463 FAST486_MOD_REG_RM ModRegRm
;
466 TOGGLE_ADSIZE(AddressSize
);
468 /* Get the operands */
469 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
471 /* Exception occurred */
475 /* The current privilege level must be zero */
476 if (Fast486GetCurrentPrivLevel(State
) != 0)
478 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
482 if ((ModRegRm
.Register
== 6) || (ModRegRm
.Register
== 7))
484 /* DR6 and DR7 are aliases to DR4 and DR5 */
485 ModRegRm
.Register
-= 2;
488 if (State
->DebugRegisters
[FAST486_REG_DR5
] & FAST486_DR5_GD
)
490 /* Disallow access to debug registers */
491 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
495 /* Load a value to the debug register */
496 State
->DebugRegisters
[ModRegRm
.Register
] = State
->GeneralRegs
[ModRegRm
.SecondRegister
].Long
;
498 if (ModRegRm
.Register
== (INT
)FAST486_REG_DR4
)
500 /* The reserved bits are 1 */
501 State
->DebugRegisters
[ModRegRm
.Register
] |= FAST486_DR4_RESERVED
;
503 else if (ModRegRm
.Register
== (INT
)FAST486_REG_DR5
)
505 /* The reserved bits are 0 */
506 State
->DebugRegisters
[ModRegRm
.Register
] &= ~FAST486_DR5_RESERVED
;
513 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushFs
)
515 /* Call the internal API */
516 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_FS
].Selector
);
519 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopFs
)
523 if (!Fast486StackPop(State
, &NewSelector
))
525 /* Exception occurred */
529 /* Call the internal API */
530 return Fast486LoadSegment(State
, FAST486_REG_FS
, LOWORD(NewSelector
));
533 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBitTest
)
535 BOOLEAN OperandSize
, AddressSize
;
536 FAST486_MOD_REG_RM ModRegRm
;
540 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
541 TOGGLE_OPSIZE(OperandSize
);
542 TOGGLE_ADSIZE(AddressSize
);
544 /* Get the number of bits */
545 if (OperandSize
) DataSize
= 32;
548 /* Get the operands */
549 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
551 /* Exception occurred */
555 /* Get the bit number */
556 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
557 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
562 * For memory operands, add the bit offset divided by
563 * the data size to the address
565 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
568 /* Normalize the bit number */
569 BitNumber
&= (1 << DataSize
) - 1;
576 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
578 /* Exception occurred */
582 /* Set CF to the bit value */
583 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
590 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
592 /* Exception occurred */
596 /* Set CF to the bit value */
597 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
604 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushGs
)
606 /* Call the internal API */
607 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_GS
].Selector
);
610 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopGs
)
614 if (!Fast486StackPop(State
, &NewSelector
))
616 /* Exception occurred */
620 /* Call the internal API */
621 return Fast486LoadSegment(State
, FAST486_REG_GS
, LOWORD(NewSelector
));
624 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBts
)
626 BOOLEAN OperandSize
, AddressSize
;
627 FAST486_MOD_REG_RM ModRegRm
;
631 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
632 TOGGLE_OPSIZE(OperandSize
);
633 TOGGLE_ADSIZE(AddressSize
);
635 /* Get the number of bits */
636 if (OperandSize
) DataSize
= 32;
639 /* Get the operands */
640 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
642 /* Exception occurred */
646 /* Get the bit number */
647 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
648 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
653 * For memory operands, add the bit offset divided by
654 * the data size to the address
656 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
659 /* Normalize the bit number */
660 BitNumber
&= (1 << DataSize
) - 1;
667 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
669 /* Exception occurred */
673 /* Set CF to the bit value */
674 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
677 Value
|= 1 << BitNumber
;
679 /* Write back the result */
680 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
))
682 /* Exception occurred */
691 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
693 /* Exception occurred */
697 /* Set CF to the bit value */
698 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
701 Value
|= 1 << BitNumber
;
703 /* Write back the result */
704 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
))
706 /* Exception occurred */
715 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchgByte
)
717 FAST486_MOD_REG_RM ModRegRm
;
718 UCHAR Accumulator
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
719 UCHAR Source
, Destination
, Result
;
720 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
722 TOGGLE_ADSIZE(AddressSize
);
724 /* Get the operands */
725 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
727 /* Exception occurred */
731 /* Read the operands */
732 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Source
, &Destination
))
734 /* Exception occurred */
738 /* Compare AL with the destination */
739 Result
= Accumulator
- Destination
;
741 /* Update the flags */
742 State
->Flags
.Cf
= (Accumulator
< Destination
);
743 State
->Flags
.Of
= ((Accumulator
& SIGN_FLAG_BYTE
) != (Destination
& SIGN_FLAG_BYTE
))
744 && ((Accumulator
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
745 State
->Flags
.Af
= (Accumulator
& 0x0F) < (Destination
& 0x0F);
746 State
->Flags
.Zf
= (Result
== 0);
747 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
748 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
752 /* Load the source operand into the destination */
753 return Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Source
);
757 /* Load the destination into AL */
758 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Destination
;
765 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchg
)
767 FAST486_MOD_REG_RM ModRegRm
;
768 BOOLEAN OperandSize
, AddressSize
;
770 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
772 TOGGLE_OPSIZE(OperandSize
);
773 TOGGLE_ADSIZE(AddressSize
);
775 /* Get the operands */
776 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
778 /* Exception occurred */
784 ULONG Source
, Destination
, Result
;
785 ULONG Accumulator
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
787 /* Read the operands */
788 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Source
, &Destination
))
790 /* Exception occurred */
794 /* Compare EAX with the destination */
795 Result
= Accumulator
- Destination
;
797 /* Update the flags */
798 State
->Flags
.Cf
= (Accumulator
< Destination
);
799 State
->Flags
.Of
= ((Accumulator
& SIGN_FLAG_LONG
) != (Destination
& SIGN_FLAG_LONG
))
800 && ((Accumulator
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
801 State
->Flags
.Af
= (Accumulator
& 0x0F) < (Destination
& 0x0F);
802 State
->Flags
.Zf
= (Result
== 0);
803 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
804 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
808 /* Load the source operand into the destination */
809 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Source
);
813 /* Load the destination into EAX */
814 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Destination
;
819 USHORT Source
, Destination
, Result
;
820 USHORT Accumulator
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
822 /* Read the operands */
823 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Source
, &Destination
))
825 /* Exception occurred */
829 /* Compare AX with the destination */
830 Result
= Accumulator
- Destination
;
832 /* Update the flags */
833 State
->Flags
.Cf
= (Accumulator
< Destination
);
834 State
->Flags
.Of
= ((Accumulator
& SIGN_FLAG_WORD
) != (Destination
& SIGN_FLAG_WORD
))
835 && ((Accumulator
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
836 State
->Flags
.Af
= (Accumulator
& 0x0F) < (Destination
& 0x0F);
837 State
->Flags
.Zf
= (Result
== 0);
838 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
839 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
843 /* Load the source operand into the destination */
844 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Source
);
848 /* Load the destination into AX */
849 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Destination
;
857 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtr
)
859 BOOLEAN OperandSize
, AddressSize
;
860 FAST486_MOD_REG_RM ModRegRm
;
864 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
865 TOGGLE_OPSIZE(OperandSize
);
866 TOGGLE_ADSIZE(AddressSize
);
868 /* Get the number of bits */
869 if (OperandSize
) DataSize
= 32;
872 /* Get the operands */
873 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
875 /* Exception occurred */
879 /* Get the bit number */
880 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
881 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
886 * For memory operands, add the bit offset divided by
887 * the data size to the address
889 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
892 /* Normalize the bit number */
893 BitNumber
&= (1 << DataSize
) - 1;
900 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
902 /* Exception occurred */
906 /* Set CF to the bit value */
907 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
910 Value
&= ~(1 << BitNumber
);
912 /* Write back the result */
913 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
))
915 /* Exception occurred */
924 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
926 /* Exception occurred */
930 /* Set CF to the bit value */
931 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
934 Value
&= ~(1 << BitNumber
);
936 /* Write back the result */
937 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
))
939 /* Exception occurred */
948 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtc
)
950 BOOLEAN OperandSize
, AddressSize
;
951 FAST486_MOD_REG_RM ModRegRm
;
955 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
956 TOGGLE_OPSIZE(OperandSize
);
957 TOGGLE_ADSIZE(AddressSize
);
959 /* Get the number of bits */
960 if (OperandSize
) DataSize
= 32;
963 /* Get the operands */
964 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
966 /* Exception occurred */
970 /* Get the bit number */
971 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
972 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
977 * For memory operands, add the bit offset divided by
978 * the data size to the address
980 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
983 /* Normalize the bit number */
984 BitNumber
&= (1 << DataSize
) - 1;
991 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
993 /* Exception occurred */
997 /* Set CF to the bit value */
998 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1000 /* Toggle the bit */
1001 Value
^= 1 << BitNumber
;
1003 /* Write back the result */
1004 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
))
1006 /* Exception occurred */
1012 USHORT Dummy
, Value
;
1014 /* Read the value */
1015 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1017 /* Exception occurred */
1021 /* Set CF to the bit value */
1022 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1024 /* Toggle the bit */
1025 Value
^= 1 << BitNumber
;
1027 /* Write back the result */
1028 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
))
1030 /* Exception occurred */
1035 /* Return success */
1039 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalJmp
)
1041 BOOLEAN Jump
= FALSE
;
1043 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1045 TOGGLE_OPSIZE(Size
);
1048 /* Make sure this is the right instruction */
1049 ASSERT((Opcode
& 0xF0) == 0x80);
1051 /* Fetch the offset */
1054 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
1056 /* Exception occurred */
1064 if (!Fast486FetchWord(State
, (PUSHORT
)&Value
))
1066 /* Exception occurred */
1071 Offset
= (LONG
)Value
;
1074 switch ((Opcode
& 0x0F) >> 1)
1079 Jump
= State
->Flags
.Of
;
1086 Jump
= State
->Flags
.Cf
;
1093 Jump
= State
->Flags
.Zf
;
1100 Jump
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
1107 Jump
= State
->Flags
.Sf
;
1114 Jump
= State
->Flags
.Pf
;
1121 Jump
= State
->Flags
.Sf
!= State
->Flags
.Of
;
1128 Jump
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
1135 /* Invert the result */
1141 /* Move the instruction pointer */
1142 State
->InstPtr
.Long
+= Offset
;
1145 /* Return success */
1149 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalSet
)
1151 BOOLEAN Value
= FALSE
;
1152 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1153 FAST486_MOD_REG_RM ModRegRm
;
1155 TOGGLE_ADSIZE(AddressSize
);
1157 /* Get the operands */
1158 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1160 /* Exception occurred */
1164 /* Make sure this is the right instruction */
1165 ASSERT((Opcode
& 0xF0) == 0x90);
1167 switch ((Opcode
& 0x0F) >> 1)
1172 Value
= State
->Flags
.Of
;
1179 Value
= State
->Flags
.Cf
;
1186 Value
= State
->Flags
.Zf
;
1190 /* SETBE / SETNBE */
1193 Value
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
1200 Value
= State
->Flags
.Sf
;
1207 Value
= State
->Flags
.Pf
;
1214 Value
= State
->Flags
.Sf
!= State
->Flags
.Of
;
1218 /* SETLE / SETNLE */
1221 Value
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
1228 /* Invert the result */
1232 /* Write back the result */
1233 return Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Value
);
1236 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXaddByte
)
1238 UCHAR Source
, Destination
, Result
;
1239 FAST486_MOD_REG_RM ModRegRm
;
1240 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1242 /* Make sure this is the right instruction */
1243 ASSERT(Opcode
== 0xC0);
1245 TOGGLE_ADSIZE(AddressSize
);
1247 /* Get the operands */
1248 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1250 /* Exception occurred */
1254 if (!Fast486ReadModrmByteOperands(State
,
1259 /* Exception occurred */
1263 /* Calculate the result */
1264 Result
= Source
+ Destination
;
1266 /* Update the flags */
1267 State
->Flags
.Cf
= (Result
< Source
) && (Result
< Destination
);
1268 State
->Flags
.Of
= ((Source
& SIGN_FLAG_BYTE
) == (Destination
& SIGN_FLAG_BYTE
))
1269 && ((Source
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1270 State
->Flags
.Af
= ((((Source
& 0x0F) + (Destination
& 0x0F)) & 0x10) != 0);
1271 State
->Flags
.Zf
= (Result
== 0);
1272 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1273 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1275 /* Write the sum to the destination */
1276 if (!Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Result
))
1278 /* Exception occurred */
1282 /* Write the old value of the destination to the source */
1283 if (!Fast486WriteModrmByteOperands(State
, &ModRegRm
, TRUE
, Destination
))
1285 /* Exception occurred */
1292 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXadd
)
1294 FAST486_MOD_REG_RM ModRegRm
;
1295 BOOLEAN OperandSize
, AddressSize
;
1297 /* Make sure this is the right instruction */
1298 ASSERT(Opcode
== 0xC1);
1300 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1302 TOGGLE_ADSIZE(AddressSize
);
1303 TOGGLE_OPSIZE(OperandSize
);
1305 /* Get the operands */
1306 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1308 /* Exception occurred */
1312 /* Check the operand size */
1315 ULONG Source
, Destination
, Result
;
1317 if (!Fast486ReadModrmDwordOperands(State
,
1322 /* Exception occurred */
1326 /* Calculate the result */
1327 Result
= Source
+ Destination
;
1329 /* Update the flags */
1330 State
->Flags
.Cf
= (Result
< Source
) && (Result
< Destination
);
1331 State
->Flags
.Of
= ((Source
& SIGN_FLAG_LONG
) == (Destination
& SIGN_FLAG_LONG
))
1332 && ((Source
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1333 State
->Flags
.Af
= ((((Source
& 0x0F) + (Destination
& 0x0F)) & 0x10) != 0);
1334 State
->Flags
.Zf
= (Result
== 0);
1335 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1336 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1338 /* Write the sum to the destination */
1339 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
))
1341 /* Exception occurred */
1345 /* Write the old value of the destination to the source */
1346 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, Destination
))
1348 /* Exception occurred */
1354 USHORT Source
, Destination
, Result
;
1356 if (!Fast486ReadModrmWordOperands(State
,
1361 /* Exception occurred */
1365 /* Calculate the result */
1366 Result
= Source
+ Destination
;
1368 /* Update the flags */
1369 State
->Flags
.Cf
= (Result
< Source
) && (Result
< Destination
);
1370 State
->Flags
.Of
= ((Source
& SIGN_FLAG_WORD
) == (Destination
& SIGN_FLAG_WORD
))
1371 && ((Source
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1372 State
->Flags
.Af
= ((((Source
& 0x0F) + (Destination
& 0x0F)) & 0x10) != 0);
1373 State
->Flags
.Zf
= (Result
== 0);
1374 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1375 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1377 /* Write the sum to the destination */
1378 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Result
))
1380 /* Exception occurred */
1384 /* Write the old value of the destination to the source */
1385 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, Destination
))
1387 /* Exception occurred */
1395 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBswap
)
1401 /* Get a pointer to the value */
1402 Pointer
= (PUCHAR
)&State
->GeneralRegs
[Opcode
& 0x07].Long
;
1404 /* Swap the byte order */
1405 SWAP(Pointer
[0], Pointer
[3]);
1406 SWAP(Pointer
[1], Pointer
[2]);
1408 /* Return success */
1412 FAST486_OPCODE_HANDLER(Fast486OpcodeExtended
)
1416 /* Fetch the second operation code */
1417 if (!Fast486FetchByte(State
, &SecondOpcode
))
1419 /* Exception occurred */
1423 if (Fast486ExtendedHandlers
[SecondOpcode
] != NULL
)
1425 /* Call the extended opcode handler */
1426 return Fast486ExtendedHandlers
[SecondOpcode
](State
, SecondOpcode
);
1430 /* This is not a valid opcode */
1431 Fast486Exception(State
, FAST486_EXCEPTION_UD
);