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 *******************************************************************/
24 // #define WIN32_NO_STATUS
25 // #define _INC_WINDOWS
37 /* PUBLIC VARIABLES ***********************************************************/
39 FAST486_OPCODE_HANDLER_PROC
40 Fast486ExtendedHandlers
[FAST486_NUM_OPCODE_HANDLERS
] =
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
49 NULL
, // TODO: OPCODE 0x07 NOT IMPLEMENTED
50 NULL
, // TODO: OPCODE 0x08 NOT IMPLEMENTED
51 NULL
, // TODO: OPCODE 0x09 NOT IMPLEMENTED
53 NULL
, // Reserved (UD1)
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
74 Fast486ExtOpcodeStoreControlReg
,
75 Fast486ExtOpcodeStoreDebugReg
,
76 Fast486ExtOpcodeLoadControlReg
,
77 Fast486ExtOpcodeLoadDebugReg
,
78 NULL
, // TODO: OPCODE 0x24 NOT IMPLEMENTED
80 NULL
, // TODO: OPCODE 0x26 NOT IMPLEMENTED
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
,
205 Fast486ExtOpcodeBitTest
,
206 NULL
, // TODO: OPCODE 0xA4 NOT IMPLEMENTED
207 NULL
, // TODO: OPCODE 0xA5 NOT IMPLEMENTED
210 Fast486ExtOpcodePushGs
,
211 Fast486ExtOpcodePopGs
,
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
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
,
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
242 Fast486ExtOpcodeBswap
,
243 Fast486ExtOpcodeBswap
,
244 Fast486ExtOpcodeBswap
,
245 Fast486ExtOpcodeBswap
,
246 Fast486ExtOpcodeBswap
,
247 Fast486ExtOpcodeBswap
,
248 Fast486ExtOpcodeBswap
,
249 Fast486ExtOpcodeBswap
,
300 /* PUBLIC FUNCTIONS ***********************************************************/
302 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeClts
)
306 /* The current privilege level must be zero */
307 if (Fast486GetCurrentPrivLevel(State
) != 0)
309 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
313 /* Clear the task switch bit */
314 State
->ControlRegisters
[FAST486_REG_CR0
] &= ~FAST486_CR0_TS
;
319 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreControlReg
)
321 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
322 FAST486_MOD_REG_RM ModRegRm
;
325 TOGGLE_ADSIZE(AddressSize
);
327 /* Get the operands */
328 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
330 /* Exception occurred */
334 /* The current privilege level must be zero */
335 if (Fast486GetCurrentPrivLevel(State
) != 0)
337 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
341 if ((ModRegRm
.Register
== 1) || (ModRegRm
.Register
> 3))
343 /* CR1, CR4, CR5, CR6 and CR7 don't exist */
344 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
348 if (ModRegRm
.Register
!= 0)
350 /* CR2 and CR3 and are stored in array indexes 1 and 2 */
354 /* Store the value of the control register */
355 State
->GeneralRegs
[ModRegRm
.SecondRegister
].Long
= State
->ControlRegisters
[ModRegRm
.Register
];
361 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreDebugReg
)
363 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
364 FAST486_MOD_REG_RM ModRegRm
;
367 TOGGLE_ADSIZE(AddressSize
);
369 /* Get the operands */
370 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
372 /* Exception occurred */
376 /* The current privilege level must be zero */
377 if (Fast486GetCurrentPrivLevel(State
) != 0)
379 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
383 if ((ModRegRm
.Register
== 6) || (ModRegRm
.Register
== 7))
385 /* DR6 and DR7 are aliases to DR4 and DR5 */
386 ModRegRm
.Register
-= 2;
389 if (State
->DebugRegisters
[FAST486_REG_DR5
] & FAST486_DR5_GD
)
391 /* Disallow access to debug registers */
392 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
396 /* Store the value of the debug register */
397 State
->GeneralRegs
[ModRegRm
.SecondRegister
].Long
= State
->DebugRegisters
[ModRegRm
.Register
];
403 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadControlReg
)
406 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
407 FAST486_MOD_REG_RM ModRegRm
;
410 TOGGLE_ADSIZE(AddressSize
);
412 /* Get the operands */
413 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
415 /* Exception occurred */
419 /* The current privilege level must be zero */
420 if (Fast486GetCurrentPrivLevel(State
) != 0)
422 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
426 if ((ModRegRm
.Register
== 1) || (ModRegRm
.Register
> 3))
428 /* CR1, CR4, CR5, CR6 and CR7 don't exist */
429 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
433 if (ModRegRm
.Register
!= 0)
435 /* CR2 and CR3 and are stored in array indexes 1 and 2 */
440 Value
= State
->GeneralRegs
[ModRegRm
.SecondRegister
].Long
;
442 if (ModRegRm
.Register
== (INT
)FAST486_REG_CR0
)
446 if (((Value
& (FAST486_CR0_PG
| FAST486_CR0_PE
)) == FAST486_CR0_PG
)
447 || ((Value
& (FAST486_CR0_CD
| FAST486_CR0_NW
)) == FAST486_CR0_NW
))
450 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
455 /* Load a value to the control register */
456 State
->ControlRegisters
[ModRegRm
.Register
] = Value
;
462 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadDebugReg
)
464 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
465 FAST486_MOD_REG_RM ModRegRm
;
468 TOGGLE_ADSIZE(AddressSize
);
470 /* Get the operands */
471 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
473 /* Exception occurred */
477 /* The current privilege level must be zero */
478 if (Fast486GetCurrentPrivLevel(State
) != 0)
480 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
484 if ((ModRegRm
.Register
== 6) || (ModRegRm
.Register
== 7))
486 /* DR6 and DR7 are aliases to DR4 and DR5 */
487 ModRegRm
.Register
-= 2;
490 if (State
->DebugRegisters
[FAST486_REG_DR5
] & FAST486_DR5_GD
)
492 /* Disallow access to debug registers */
493 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
497 /* Load a value to the debug register */
498 State
->DebugRegisters
[ModRegRm
.Register
] = State
->GeneralRegs
[ModRegRm
.SecondRegister
].Long
;
500 if (ModRegRm
.Register
== (INT
)FAST486_REG_DR4
)
502 /* The reserved bits are 1 */
503 State
->DebugRegisters
[ModRegRm
.Register
] |= FAST486_DR4_RESERVED
;
505 else if (ModRegRm
.Register
== (INT
)FAST486_REG_DR5
)
507 /* The reserved bits are 0 */
508 State
->DebugRegisters
[ModRegRm
.Register
] &= ~FAST486_DR5_RESERVED
;
515 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushFs
)
517 /* Call the internal API */
518 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_FS
].Selector
);
521 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopFs
)
525 if (!Fast486StackPop(State
, &NewSelector
))
527 /* Exception occurred */
531 /* Call the internal API */
532 return Fast486LoadSegment(State
, FAST486_REG_FS
, LOWORD(NewSelector
));
535 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBitTest
)
537 BOOLEAN OperandSize
, AddressSize
;
538 FAST486_MOD_REG_RM ModRegRm
;
542 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
543 TOGGLE_OPSIZE(OperandSize
);
544 TOGGLE_ADSIZE(AddressSize
);
546 /* Get the number of bits */
547 if (OperandSize
) DataSize
= 32;
550 /* Get the operands */
551 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
553 /* Exception occurred */
557 /* Get the bit number */
558 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
559 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
564 * For memory operands, add the bit offset divided by
565 * the data size to the address
567 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
570 /* Normalize the bit number */
571 BitNumber
&= (1 << DataSize
) - 1;
578 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
580 /* Exception occurred */
584 /* Set CF to the bit value */
585 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
592 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
594 /* Exception occurred */
598 /* Set CF to the bit value */
599 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
606 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushGs
)
608 /* Call the internal API */
609 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_GS
].Selector
);
612 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopGs
)
616 if (!Fast486StackPop(State
, &NewSelector
))
618 /* Exception occurred */
622 /* Call the internal API */
623 return Fast486LoadSegment(State
, FAST486_REG_GS
, LOWORD(NewSelector
));
626 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBts
)
628 BOOLEAN OperandSize
, AddressSize
;
629 FAST486_MOD_REG_RM ModRegRm
;
633 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
634 TOGGLE_OPSIZE(OperandSize
);
635 TOGGLE_ADSIZE(AddressSize
);
637 /* Get the number of bits */
638 if (OperandSize
) DataSize
= 32;
641 /* Get the operands */
642 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
644 /* Exception occurred */
648 /* Get the bit number */
649 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
650 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
655 * For memory operands, add the bit offset divided by
656 * the data size to the address
658 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
661 /* Normalize the bit number */
662 BitNumber
&= (1 << DataSize
) - 1;
669 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
671 /* Exception occurred */
675 /* Set CF to the bit value */
676 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
679 Value
|= 1 << BitNumber
;
681 /* Write back the result */
682 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
))
684 /* Exception occurred */
693 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
695 /* Exception occurred */
699 /* Set CF to the bit value */
700 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
703 Value
|= 1 << BitNumber
;
705 /* Write back the result */
706 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
))
708 /* Exception occurred */
717 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchgByte
)
719 FAST486_MOD_REG_RM ModRegRm
;
720 UCHAR Accumulator
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
721 UCHAR Source
, Destination
, Result
;
722 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
724 TOGGLE_ADSIZE(AddressSize
);
726 /* Get the operands */
727 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
729 /* Exception occurred */
733 /* Read the operands */
734 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Source
, &Destination
))
736 /* Exception occurred */
740 /* Compare AL with the destination */
741 Result
= Accumulator
- Destination
;
743 /* Update the flags */
744 State
->Flags
.Cf
= Accumulator
< Destination
;
745 State
->Flags
.Of
= ((Accumulator
& SIGN_FLAG_BYTE
) != (Destination
& SIGN_FLAG_BYTE
))
746 && ((Accumulator
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
747 State
->Flags
.Af
= (Accumulator
& 0x0F) < (Destination
& 0x0F);
748 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
749 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
750 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
754 /* Load the source operand into the destination */
755 return Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Source
);
759 /* Load the destination into AL */
760 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Destination
;
767 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchg
)
769 FAST486_MOD_REG_RM ModRegRm
;
770 BOOLEAN OperandSize
, AddressSize
;
772 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
774 TOGGLE_OPSIZE(OperandSize
);
775 TOGGLE_ADSIZE(AddressSize
);
777 /* Get the operands */
778 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
780 /* Exception occurred */
786 ULONG Source
, Destination
, Result
;
787 ULONG Accumulator
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
789 /* Read the operands */
790 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Source
, &Destination
))
792 /* Exception occurred */
796 /* Compare EAX with the destination */
797 Result
= Accumulator
- Destination
;
799 /* Update the flags */
800 State
->Flags
.Cf
= Accumulator
< Destination
;
801 State
->Flags
.Of
= ((Accumulator
& SIGN_FLAG_LONG
) != (Destination
& SIGN_FLAG_LONG
))
802 && ((Accumulator
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
803 State
->Flags
.Af
= (Accumulator
& 0x0F) < (Destination
& 0x0F);
804 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
805 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
806 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
810 /* Load the source operand into the destination */
811 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Source
);
815 /* Load the destination into EAX */
816 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Destination
;
821 USHORT Source
, Destination
, Result
;
822 USHORT Accumulator
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
824 /* Read the operands */
825 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Source
, &Destination
))
827 /* Exception occurred */
831 /* Compare AX with the destination */
832 Result
= Accumulator
- Destination
;
834 /* Update the flags */
835 State
->Flags
.Cf
= Accumulator
< Destination
;
836 State
->Flags
.Of
= ((Accumulator
& SIGN_FLAG_WORD
) != (Destination
& SIGN_FLAG_WORD
))
837 && ((Accumulator
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
838 State
->Flags
.Af
= (Accumulator
& 0x0F) < (Destination
& 0x0F);
839 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
840 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
841 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
845 /* Load the source operand into the destination */
846 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Source
);
850 /* Load the destination into AX */
851 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Destination
;
859 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtr
)
861 BOOLEAN OperandSize
, AddressSize
;
862 FAST486_MOD_REG_RM ModRegRm
;
866 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
867 TOGGLE_OPSIZE(OperandSize
);
868 TOGGLE_ADSIZE(AddressSize
);
870 /* Get the number of bits */
871 if (OperandSize
) DataSize
= 32;
874 /* Get the operands */
875 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
877 /* Exception occurred */
881 /* Get the bit number */
882 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
883 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
888 * For memory operands, add the bit offset divided by
889 * the data size to the address
891 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
894 /* Normalize the bit number */
895 BitNumber
&= (1 << DataSize
) - 1;
902 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
904 /* Exception occurred */
908 /* Set CF to the bit value */
909 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
912 Value
&= ~(1 << BitNumber
);
914 /* Write back the result */
915 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
))
917 /* Exception occurred */
926 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
928 /* Exception occurred */
932 /* Set CF to the bit value */
933 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
936 Value
&= ~(1 << BitNumber
);
938 /* Write back the result */
939 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
))
941 /* Exception occurred */
950 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtc
)
952 BOOLEAN OperandSize
, AddressSize
;
953 FAST486_MOD_REG_RM ModRegRm
;
957 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
958 TOGGLE_OPSIZE(OperandSize
);
959 TOGGLE_ADSIZE(AddressSize
);
961 /* Get the number of bits */
962 if (OperandSize
) DataSize
= 32;
965 /* Get the operands */
966 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
968 /* Exception occurred */
972 /* Get the bit number */
973 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
974 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
979 * For memory operands, add the bit offset divided by
980 * the data size to the address
982 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
985 /* Normalize the bit number */
986 BitNumber
&= (1 << DataSize
) - 1;
993 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
995 /* Exception occurred */
999 /* Set CF to the bit value */
1000 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1002 /* Toggle the bit */
1003 Value
^= 1 << BitNumber
;
1005 /* Write back the result */
1006 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
))
1008 /* Exception occurred */
1014 USHORT Dummy
, Value
;
1016 /* Read the value */
1017 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1019 /* Exception occurred */
1023 /* Set CF to the bit value */
1024 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1026 /* Toggle the bit */
1027 Value
^= 1 << BitNumber
;
1029 /* Write back the result */
1030 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
))
1032 /* Exception occurred */
1037 /* Return success */
1041 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalJmp
)
1043 BOOLEAN Jump
= FALSE
;
1045 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1047 TOGGLE_OPSIZE(Size
);
1050 /* Make sure this is the right instruction */
1051 ASSERT((Opcode
& 0xF0) == 0x80);
1053 /* Fetch the offset */
1056 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
1058 /* Exception occurred */
1066 if (!Fast486FetchWord(State
, (PUSHORT
)&Value
))
1068 /* Exception occurred */
1073 Offset
= (LONG
)Value
;
1076 switch ((Opcode
& 0x0F) >> 1)
1081 Jump
= State
->Flags
.Of
;
1088 Jump
= State
->Flags
.Cf
;
1095 Jump
= State
->Flags
.Zf
;
1102 Jump
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
1109 Jump
= State
->Flags
.Sf
;
1116 Jump
= State
->Flags
.Pf
;
1123 Jump
= State
->Flags
.Sf
!= State
->Flags
.Of
;
1130 Jump
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
1137 /* Invert the result */
1143 /* Move the instruction pointer */
1144 State
->InstPtr
.Long
+= Offset
;
1147 /* Return success */
1151 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalSet
)
1153 BOOLEAN Value
= FALSE
;
1154 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1155 FAST486_MOD_REG_RM ModRegRm
;
1157 TOGGLE_ADSIZE(AddressSize
);
1159 /* Get the operands */
1160 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1162 /* Exception occurred */
1166 /* Make sure this is the right instruction */
1167 ASSERT((Opcode
& 0xF0) == 0x90);
1169 switch ((Opcode
& 0x0F) >> 1)
1174 Value
= State
->Flags
.Of
;
1181 Value
= State
->Flags
.Cf
;
1188 Value
= State
->Flags
.Zf
;
1192 /* SETBE / SETNBE */
1195 Value
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
1202 Value
= State
->Flags
.Sf
;
1209 Value
= State
->Flags
.Pf
;
1216 Value
= State
->Flags
.Sf
!= State
->Flags
.Of
;
1220 /* SETLE / SETNLE */
1223 Value
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
1230 /* Invert the result */
1234 /* Write back the result */
1235 return Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Value
);
1238 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBswap
)
1244 /* Get a pointer to the value */
1245 Pointer
= (PUCHAR
)&State
->GeneralRegs
[Opcode
& 0x07].Long
;
1247 /* Swap the byte order */
1248 SWAP(Pointer
[0], Pointer
[3]);
1249 SWAP(Pointer
[1], Pointer
[2]);
1251 /* Return success */
1255 FAST486_OPCODE_HANDLER(Fast486OpcodeExtended
)
1259 /* Fetch the second operation code */
1260 if (!Fast486FetchByte(State
, &SecondOpcode
))
1262 /* Exception occurred */
1266 if (Fast486ExtendedHandlers
[SecondOpcode
] != NULL
)
1268 /* Call the extended opcode handler */
1269 return Fast486ExtendedHandlers
[SecondOpcode
](State
, SecondOpcode
);
1273 /* This is not a valid opcode */
1274 Fast486Exception(State
, FAST486_EXCEPTION_UD
);