2 * Fast486 386/486 CPU Emulation Library
5 * Copyright (C) 2014 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 Fast486OpcodeGroup0F00
, /* 0x00 - 0x01 */
41 Fast486OpcodeGroup0F01
,
42 Fast486ExtOpcodeLar
, /* 0x02 */
43 Fast486ExtOpcodeLsl
, /* 0x03 */
44 Fast486ExtOpcodeInvalid
, /* 0x04 - 0x05 */ // Invalid
45 Fast486ExtOpcodeInvalid
, // Invalid
46 Fast486ExtOpcodeClts
, /* 0x06 */
47 Fast486ExtOpcodeInvalid
, /* 0x07 */ // Invalid
48 Fast486ExtOpcodeUnimplemented
, // TODO: OPCODE 0x08 NOT IMPLEMENTED
49 Fast486ExtOpcodeUnimplemented
, // TODO: OPCODE 0x09 NOT IMPLEMENTED
50 Fast486ExtOpcodeInvalid
, /* 0x0A */ // Invalid
51 Fast486ExtOpcode0F0B
, /* 0x0B */ // Reserved (UD2)
52 Fast486ExtOpcodeInvalid
, /* 0x0C - 0x1F */ // Invalid
53 Fast486ExtOpcodeInvalid
, // Invalid
54 Fast486ExtOpcodeInvalid
, // Invalid
55 Fast486ExtOpcodeInvalid
, // Invalid
56 Fast486ExtOpcodeInvalid
, // Invalid
57 Fast486ExtOpcodeInvalid
, // Invalid
58 Fast486ExtOpcodeInvalid
, // Invalid
59 Fast486ExtOpcodeInvalid
, // Invalid
60 Fast486ExtOpcodeInvalid
, // Invalid
61 Fast486ExtOpcodeInvalid
, // Invalid
62 Fast486ExtOpcodeInvalid
, // Invalid
63 Fast486ExtOpcodeInvalid
, // Invalid
64 Fast486ExtOpcodeInvalid
, // Invalid
65 Fast486ExtOpcodeInvalid
, // Invalid
66 Fast486ExtOpcodeInvalid
, // Invalid
67 Fast486ExtOpcodeInvalid
, // Invalid
68 Fast486ExtOpcodeInvalid
, // Invalid
69 Fast486ExtOpcodeInvalid
, // Invalid
70 Fast486ExtOpcodeInvalid
, // Invalid
71 Fast486ExtOpcodeInvalid
, // Invalid
72 Fast486ExtOpcodeStoreControlReg
, /* 0x20 */
73 Fast486ExtOpcodeStoreDebugReg
, /* 0x21 */
74 Fast486ExtOpcodeLoadControlReg
, /* 0x22 */
75 Fast486ExtOpcodeLoadDebugReg
, /* 0x23 */
76 Fast486ExtOpcodeUnimplemented
, // TODO: OPCODE 0x24 NOT IMPLEMENTED
77 Fast486ExtOpcodeInvalid
, /* 0x25 */ // Invalid
78 Fast486ExtOpcodeUnimplemented
, // TODO: OPCODE 0x26 NOT IMPLEMENTED
79 Fast486ExtOpcodeInvalid
, /* 0x27 - 0x7F */ // Invalid
80 Fast486ExtOpcodeInvalid
, // Invalid
81 Fast486ExtOpcodeInvalid
, // Invalid
82 Fast486ExtOpcodeInvalid
, // Invalid
83 Fast486ExtOpcodeInvalid
, // Invalid
84 Fast486ExtOpcodeInvalid
, // Invalid
85 Fast486ExtOpcodeInvalid
, // Invalid
86 Fast486ExtOpcodeInvalid
, // Invalid
87 Fast486ExtOpcodeInvalid
, // Invalid
88 Fast486ExtOpcodeInvalid
, // Invalid
89 Fast486ExtOpcodeInvalid
, // Invalid
90 Fast486ExtOpcodeInvalid
, // Invalid
91 Fast486ExtOpcodeInvalid
, // Invalid
92 Fast486ExtOpcodeInvalid
, // Invalid
93 Fast486ExtOpcodeInvalid
, // Invalid
94 Fast486ExtOpcodeInvalid
, // Invalid
95 Fast486ExtOpcodeInvalid
, // Invalid
96 Fast486ExtOpcodeInvalid
, // Invalid
97 Fast486ExtOpcodeInvalid
, // Invalid
98 Fast486ExtOpcodeInvalid
, // Invalid
99 Fast486ExtOpcodeInvalid
, // Invalid
100 Fast486ExtOpcodeInvalid
, // Invalid
101 Fast486ExtOpcodeInvalid
, // Invalid
102 Fast486ExtOpcodeInvalid
, // Invalid
103 Fast486ExtOpcodeInvalid
, // Invalid
104 Fast486ExtOpcodeInvalid
, // Invalid
105 Fast486ExtOpcodeInvalid
, // Invalid
106 Fast486ExtOpcodeInvalid
, // Invalid
107 Fast486ExtOpcodeInvalid
, // Invalid
108 Fast486ExtOpcodeInvalid
, // Invalid
109 Fast486ExtOpcodeInvalid
, // Invalid
110 Fast486ExtOpcodeInvalid
, // Invalid
111 Fast486ExtOpcodeInvalid
, // Invalid
112 Fast486ExtOpcodeInvalid
, // Invalid
113 Fast486ExtOpcodeInvalid
, // Invalid
114 Fast486ExtOpcodeInvalid
, // Invalid
115 Fast486ExtOpcodeInvalid
, // Invalid
116 Fast486ExtOpcodeInvalid
, // Invalid
117 Fast486ExtOpcodeInvalid
, // Invalid
118 Fast486ExtOpcodeInvalid
, // Invalid
119 Fast486ExtOpcodeInvalid
, // Invalid
120 Fast486ExtOpcodeInvalid
, // Invalid
121 Fast486ExtOpcodeInvalid
, // Invalid
122 Fast486ExtOpcodeInvalid
, // Invalid
123 Fast486ExtOpcodeInvalid
, // Invalid
124 Fast486ExtOpcodeInvalid
, // Invalid
125 Fast486ExtOpcodeInvalid
, // Invalid
126 Fast486ExtOpcodeInvalid
, // Invalid
127 Fast486ExtOpcodeInvalid
, // Invalid
128 Fast486ExtOpcodeInvalid
, // Invalid
129 Fast486ExtOpcodeInvalid
, // Invalid
130 Fast486ExtOpcodeInvalid
, // Invalid
131 Fast486ExtOpcodeInvalid
, // Invalid
132 Fast486ExtOpcodeInvalid
, // Invalid
133 Fast486ExtOpcodeInvalid
, // Invalid
134 Fast486ExtOpcodeInvalid
, // Invalid
135 Fast486ExtOpcodeInvalid
, // Invalid
136 Fast486ExtOpcodeInvalid
, // Invalid
137 Fast486ExtOpcodeInvalid
, // Invalid
138 Fast486ExtOpcodeInvalid
, // Invalid
139 Fast486ExtOpcodeInvalid
, // Invalid
140 Fast486ExtOpcodeInvalid
, // Invalid
141 Fast486ExtOpcodeInvalid
, // Invalid
142 Fast486ExtOpcodeInvalid
, // Invalid
143 Fast486ExtOpcodeInvalid
, // Invalid
144 Fast486ExtOpcodeInvalid
, // Invalid
145 Fast486ExtOpcodeInvalid
, // Invalid
146 Fast486ExtOpcodeInvalid
, // Invalid
147 Fast486ExtOpcodeInvalid
, // Invalid
148 Fast486ExtOpcodeInvalid
, // Invalid
149 Fast486ExtOpcodeInvalid
, // Invalid
150 Fast486ExtOpcodeInvalid
, // Invalid
151 Fast486ExtOpcodeInvalid
, // Invalid
152 Fast486ExtOpcodeInvalid
, // Invalid
153 Fast486ExtOpcodeInvalid
, // Invalid
154 Fast486ExtOpcodeInvalid
, // Invalid
155 Fast486ExtOpcodeInvalid
, // Invalid
156 Fast486ExtOpcodeInvalid
, // Invalid
157 Fast486ExtOpcodeInvalid
, // Invalid
158 Fast486ExtOpcodeInvalid
, // Invalid
159 Fast486ExtOpcodeInvalid
, // Invalid
160 Fast486ExtOpcodeInvalid
, // Invalid
161 Fast486ExtOpcodeInvalid
, // Invalid
162 Fast486ExtOpcodeInvalid
, // Invalid
163 Fast486ExtOpcodeInvalid
, // Invalid
164 Fast486ExtOpcodeInvalid
, // Invalid
165 Fast486ExtOpcodeInvalid
, // Invalid
166 Fast486ExtOpcodeInvalid
, // Invalid
167 Fast486ExtOpcodeInvalid
, // Invalid
168 Fast486ExtOpcodeConditionalJmp
, /* 0x80 - 0x8F */
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
, /* 0x90 - 0x9F */
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
, /* 0xA0 */
201 Fast486ExtOpcodePopFs
, /* 0xA1 */
202 Fast486ExtOpcodeInvalid
, /* 0xA2 */ // Invalid
203 Fast486ExtOpcodeBitTest
, /* 0xA3 */
204 Fast486ExtOpcodeShld
, /* 0xA4 - 0xA5 */
205 Fast486ExtOpcodeShld
,
206 Fast486ExtOpcodeInvalid
, /* 0xA6 - 0xA7 */ // Invalid
207 Fast486ExtOpcodeInvalid
, // Invalid
208 Fast486ExtOpcodePushGs
, /* 0xA8 - 0xA9 */
209 Fast486ExtOpcodePopGs
,
210 Fast486ExtOpcodeInvalid
, /* 0xAA */ // Invalid
211 Fast486ExtOpcodeBts
, /* 0xAB */
212 Fast486ExtOpcodeShrd
, /* 0xAC - 0xAD */
213 Fast486ExtOpcodeShrd
,
214 Fast486ExtOpcodeInvalid
, /* 0xAE */ // Invalid
215 Fast486ExtOpcodeImul
, /* 0xAF */
216 Fast486ExtOpcodeCmpXchgByte
, /* 0xB0 */
217 Fast486ExtOpcodeCmpXchg
, /* 0xB1 */
218 Fast486ExtOpcodeLss
, /* 0xB2 */
219 Fast486ExtOpcodeBtr
, /* 0xB3 */
220 Fast486ExtOpcodeLfsLgs
, /* 0xB4 - 0xB5 */
221 Fast486ExtOpcodeLfsLgs
,
222 Fast486ExtOpcodeMovzxByte
, /* 0xB6 - 0xB7 */
223 Fast486ExtOpcodeMovzxWord
,
224 Fast486ExtOpcodeInvalid
, /* 0xB8 */ // Invalid
225 Fast486OpcodeGroup0FB9
, /* 0xB9 */
226 Fast486OpcodeGroup0FBA
, /* 0xBA */
227 Fast486ExtOpcodeBtc
, /* 0xBB */
228 Fast486ExtOpcodeBsf
, /* 0xBC */
229 Fast486ExtOpcodeBsr
, /* 0xBD */
230 Fast486ExtOpcodeMovsxByte
, /* 0xBE - 0xBF */
231 Fast486ExtOpcodeMovsxWord
,
232 Fast486ExtOpcodeXaddByte
, /* 0xC0 - 0xC1 */
233 Fast486ExtOpcodeXadd
,
234 Fast486ExtOpcodeInvalid
, /* 0xC2 - 0xC7 */ // Invalid
235 Fast486ExtOpcodeInvalid
, // Invalid
236 Fast486ExtOpcodeInvalid
, // Invalid
237 Fast486ExtOpcodeInvalid
, // Invalid
238 Fast486ExtOpcodeInvalid
, // Invalid
239 Fast486ExtOpcodeInvalid
, // Invalid
240 Fast486ExtOpcodeBswap
, /* 0xC8 - 0xCF */
241 Fast486ExtOpcodeBswap
,
242 Fast486ExtOpcodeBswap
,
243 Fast486ExtOpcodeBswap
,
244 Fast486ExtOpcodeBswap
,
245 Fast486ExtOpcodeBswap
,
246 Fast486ExtOpcodeBswap
,
247 Fast486ExtOpcodeBswap
,
248 Fast486ExtOpcodeInvalid
, /* 0xD0 - 0xFF */ // Invalid
249 Fast486ExtOpcodeInvalid
, // Invalid
250 Fast486ExtOpcodeInvalid
, // Invalid
251 Fast486ExtOpcodeInvalid
, // Invalid
252 Fast486ExtOpcodeInvalid
, // Invalid
253 Fast486ExtOpcodeInvalid
, // Invalid
254 Fast486ExtOpcodeInvalid
, // Invalid
255 Fast486ExtOpcodeInvalid
, // Invalid
256 Fast486ExtOpcodeInvalid
, // Invalid
257 Fast486ExtOpcodeInvalid
, // Invalid
258 Fast486ExtOpcodeInvalid
, // Invalid
259 Fast486ExtOpcodeInvalid
, // Invalid
260 Fast486ExtOpcodeInvalid
, // Invalid
261 Fast486ExtOpcodeInvalid
, // Invalid
262 Fast486ExtOpcodeInvalid
, // Invalid
263 Fast486ExtOpcodeInvalid
, // Invalid
264 Fast486ExtOpcodeInvalid
, // Invalid
265 Fast486ExtOpcodeInvalid
, // Invalid
266 Fast486ExtOpcodeInvalid
, // Invalid
267 Fast486ExtOpcodeInvalid
, // Invalid
268 Fast486ExtOpcodeInvalid
, // Invalid
269 Fast486ExtOpcodeInvalid
, // Invalid
270 Fast486ExtOpcodeInvalid
, // Invalid
271 Fast486ExtOpcodeInvalid
, // Invalid
272 Fast486ExtOpcodeInvalid
, // Invalid
273 Fast486ExtOpcodeInvalid
, // Invalid
274 Fast486ExtOpcodeInvalid
, // Invalid
275 Fast486ExtOpcodeInvalid
, // Invalid
276 Fast486ExtOpcodeInvalid
, // Invalid
277 Fast486ExtOpcodeInvalid
, // Invalid
278 Fast486ExtOpcodeInvalid
, // Invalid
279 Fast486ExtOpcodeInvalid
, // Invalid
280 Fast486ExtOpcodeInvalid
, // Invalid
281 Fast486ExtOpcodeInvalid
, // Invalid
282 Fast486ExtOpcodeInvalid
, // Invalid
283 Fast486ExtOpcodeInvalid
, // Invalid
284 Fast486ExtOpcodeInvalid
, // Invalid
285 Fast486ExtOpcodeInvalid
, // Invalid
286 Fast486ExtOpcodeInvalid
, // Invalid
287 Fast486ExtOpcodeInvalid
, // Invalid
288 Fast486ExtOpcodeInvalid
, // Invalid
289 Fast486ExtOpcodeInvalid
, // Invalid
290 Fast486ExtOpcodeInvalid
, // Invalid
291 Fast486ExtOpcodeInvalid
, // Invalid
292 Fast486ExtOpcodeInvalid
, // Invalid
293 Fast486ExtOpcodeInvalid
, // Invalid
294 Fast486ExtOpcodeInvalid
, // Invalid
295 Fast486ExtOpcodeInvalid
, // Invalid
298 /* PUBLIC FUNCTIONS ***********************************************************/
300 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeInvalid
)
302 DPRINT1("FAST486 -- Extended opcode 0x%02X is INVALID!\n", Opcode
);
303 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
307 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeUnimplemented
)
309 DPRINT1("FAST486 -- Extended opcode 0x%02X is UNIMPLEMENTED\n", Opcode
);
310 // Fast486Exception(State, FAST486_EXCEPTION_UD);
314 FAST486_OPCODE_HANDLER(Fast486ExtOpcode0F0B
)
316 /* Reserved opcode (UD2) */
317 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
321 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLar
)
323 BOOLEAN OperandSize
, AddressSize
;
324 FAST486_MOD_REG_RM ModRegRm
;
326 FAST486_GDT_ENTRY GdtEntry
;
329 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
331 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
335 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
340 TOGGLE_OPSIZE(OperandSize
);
341 TOGGLE_ADSIZE(AddressSize
);
343 /* Get the operands */
344 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
346 /* Exception occurred */
355 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
357 /* Exception occurred */
361 Selector
= LOWORD(Value
);
366 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Selector
))
368 /* Exception occurred */
373 if (!(Selector
& SEGMENT_TABLE_INDICATOR
))
375 /* Check if the GDT contains the entry */
376 if (GET_SEGMENT_INDEX(Selector
) >= (State
->Gdtr
.Size
+ 1))
378 State
->Flags
.Zf
= FALSE
;
383 if (!Fast486ReadLinearMemory(State
,
385 + GET_SEGMENT_INDEX(Selector
),
389 /* Exception occurred */
395 /* Check if the LDT contains the entry */
396 if (GET_SEGMENT_INDEX(Selector
) >= (State
->Ldtr
.Limit
+ 1))
398 State
->Flags
.Zf
= FALSE
;
403 if (!Fast486ReadLinearMemory(State
,
405 + GET_SEGMENT_INDEX(Selector
),
409 /* Exception occurred */
414 /* Privilege check */
415 if (((GET_SEGMENT_RPL(Selector
) > GdtEntry
.Dpl
))
416 || (Fast486GetCurrentPrivLevel(State
) > GdtEntry
.Dpl
))
418 State
->Flags
.Zf
= FALSE
;
423 State
->Flags
.Zf
= TRUE
;
425 /* Get the access rights */
426 AccessRights
= ((PDWORD
)&GdtEntry
)[1] & 0x00F0FF00;
428 /* Return the access rights */
431 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, AccessRights
))
433 /* Exception occurred */
439 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, LOWORD(AccessRights
)))
441 /* Exception occurred */
449 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLsl
)
451 BOOLEAN OperandSize
, AddressSize
;
452 FAST486_MOD_REG_RM ModRegRm
;
455 FAST486_GDT_ENTRY GdtEntry
;
457 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
459 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
463 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
468 TOGGLE_OPSIZE(OperandSize
);
469 TOGGLE_ADSIZE(AddressSize
);
471 /* Get the operands */
472 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
474 /* Exception occurred */
483 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
485 /* Exception occurred */
489 Selector
= LOWORD(Value
);
494 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Selector
))
496 /* Exception occurred */
501 if (!(Selector
& SEGMENT_TABLE_INDICATOR
))
503 /* Check if the GDT contains the entry */
504 if (GET_SEGMENT_INDEX(Selector
) >= (State
->Gdtr
.Size
+ 1))
506 State
->Flags
.Zf
= FALSE
;
511 if (!Fast486ReadLinearMemory(State
,
513 + GET_SEGMENT_INDEX(Selector
),
517 /* Exception occurred */
523 /* Check if the LDT contains the entry */
524 if (GET_SEGMENT_INDEX(Selector
) >= (State
->Ldtr
.Limit
+ 1))
526 State
->Flags
.Zf
= FALSE
;
531 if (!Fast486ReadLinearMemory(State
,
533 + GET_SEGMENT_INDEX(Selector
),
537 /* Exception occurred */
542 /* Privilege check */
543 if (((GET_SEGMENT_RPL(Selector
) > GdtEntry
.Dpl
))
544 || (Fast486GetCurrentPrivLevel(State
) > GdtEntry
.Dpl
))
546 State
->Flags
.Zf
= FALSE
;
550 /* Calculate the limit */
551 Limit
= GdtEntry
.Limit
| (GdtEntry
.LimitHigh
<< 16);
552 if (GdtEntry
.Granularity
) Limit
<<= 12;
555 State
->Flags
.Zf
= TRUE
;
559 /* Return the limit */
560 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, Limit
))
562 /* Exception occurred */
568 /* Return the limit */
569 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, LOWORD(Limit
)))
571 /* Exception occurred */
579 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeClts
)
583 /* The current privilege level must be zero */
584 if (Fast486GetCurrentPrivLevel(State
) != 0)
586 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
590 /* Clear the task switch bit */
591 State
->ControlRegisters
[FAST486_REG_CR0
] &= ~FAST486_CR0_TS
;
596 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreControlReg
)
598 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
599 FAST486_MOD_REG_RM ModRegRm
;
602 TOGGLE_ADSIZE(AddressSize
);
604 /* Get the operands */
605 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
607 /* Exception occurred */
611 /* The current privilege level must be zero */
612 if (Fast486GetCurrentPrivLevel(State
) != 0)
614 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
618 if ((ModRegRm
.Register
== 1) || (ModRegRm
.Register
> 3))
620 /* CR1, CR4, CR5, CR6 and CR7 don't exist */
621 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
625 if (ModRegRm
.Register
!= 0)
627 /* CR2 and CR3 and are stored in array indexes 1 and 2 */
631 /* Store the value of the control register */
632 State
->GeneralRegs
[ModRegRm
.SecondRegister
].Long
= State
->ControlRegisters
[ModRegRm
.Register
];
638 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreDebugReg
)
640 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
641 FAST486_MOD_REG_RM ModRegRm
;
644 TOGGLE_ADSIZE(AddressSize
);
646 /* Get the operands */
647 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
649 /* Exception occurred */
653 /* The current privilege level must be zero */
654 if (Fast486GetCurrentPrivLevel(State
) != 0)
656 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
660 if ((ModRegRm
.Register
== 6) || (ModRegRm
.Register
== 7))
662 /* DR6 and DR7 are aliases to DR4 and DR5 */
663 ModRegRm
.Register
-= 2;
666 if (State
->DebugRegisters
[FAST486_REG_DR5
] & FAST486_DR5_GD
)
668 /* Disallow access to debug registers */
669 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
673 /* Store the value of the debug register */
674 State
->GeneralRegs
[ModRegRm
.SecondRegister
].Long
= State
->DebugRegisters
[ModRegRm
.Register
];
680 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadControlReg
)
683 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
684 FAST486_MOD_REG_RM ModRegRm
;
687 TOGGLE_ADSIZE(AddressSize
);
689 /* Get the operands */
690 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
692 /* Exception occurred */
696 /* The current privilege level must be zero */
697 if (Fast486GetCurrentPrivLevel(State
) != 0)
699 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
703 if ((ModRegRm
.Register
== 1) || (ModRegRm
.Register
> 3))
705 /* CR1, CR4, CR5, CR6 and CR7 don't exist */
706 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
710 if (ModRegRm
.Register
!= 0)
712 /* CR2 and CR3 and are stored in array indexes 1 and 2 */
717 Value
= State
->GeneralRegs
[ModRegRm
.SecondRegister
].Long
;
719 if (ModRegRm
.Register
== (INT
)FAST486_REG_CR0
)
723 if (((Value
& (FAST486_CR0_PG
| FAST486_CR0_PE
)) == FAST486_CR0_PG
)
724 || ((Value
& (FAST486_CR0_CD
| FAST486_CR0_NW
)) == FAST486_CR0_NW
))
727 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
732 /* Load a value to the control register */
733 State
->ControlRegisters
[ModRegRm
.Register
] = Value
;
739 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadDebugReg
)
741 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
742 FAST486_MOD_REG_RM ModRegRm
;
745 TOGGLE_ADSIZE(AddressSize
);
747 /* Get the operands */
748 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
750 /* Exception occurred */
754 /* The current privilege level must be zero */
755 if (Fast486GetCurrentPrivLevel(State
) != 0)
757 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
761 if ((ModRegRm
.Register
== 6) || (ModRegRm
.Register
== 7))
763 /* DR6 and DR7 are aliases to DR4 and DR5 */
764 ModRegRm
.Register
-= 2;
767 if (State
->DebugRegisters
[FAST486_REG_DR5
] & FAST486_DR5_GD
)
769 /* Disallow access to debug registers */
770 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
774 /* Load a value to the debug register */
775 State
->DebugRegisters
[ModRegRm
.Register
] = State
->GeneralRegs
[ModRegRm
.SecondRegister
].Long
;
777 if (ModRegRm
.Register
== (INT
)FAST486_REG_DR4
)
779 /* The reserved bits are 1 */
780 State
->DebugRegisters
[ModRegRm
.Register
] |= FAST486_DR4_RESERVED
;
782 else if (ModRegRm
.Register
== (INT
)FAST486_REG_DR5
)
784 /* The reserved bits are 0 */
785 State
->DebugRegisters
[ModRegRm
.Register
] &= ~FAST486_DR5_RESERVED
;
792 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushFs
)
794 /* Call the internal API */
795 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_FS
].Selector
);
798 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopFs
)
802 if (!Fast486StackPop(State
, &NewSelector
))
804 /* Exception occurred */
808 /* Call the internal API */
809 return Fast486LoadSegment(State
, FAST486_REG_FS
, LOWORD(NewSelector
));
812 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBitTest
)
814 BOOLEAN OperandSize
, AddressSize
;
815 FAST486_MOD_REG_RM ModRegRm
;
819 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
820 TOGGLE_OPSIZE(OperandSize
);
821 TOGGLE_ADSIZE(AddressSize
);
823 /* Get the number of bits */
824 if (OperandSize
) DataSize
= 32;
827 /* Get the operands */
828 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
830 /* Exception occurred */
834 /* Get the bit number */
835 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
836 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
841 * For memory operands, add the bit offset divided by
842 * the data size to the address
844 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
847 /* Normalize the bit number */
848 BitNumber
%= DataSize
;
855 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
857 /* Exception occurred */
861 /* Set CF to the bit value */
862 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
869 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
871 /* Exception occurred */
875 /* Set CF to the bit value */
876 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
883 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShld
)
885 BOOLEAN OperandSize
, AddressSize
;
886 FAST486_MOD_REG_RM ModRegRm
;
889 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
890 TOGGLE_OPSIZE(OperandSize
);
891 TOGGLE_ADSIZE(AddressSize
);
893 /* Make sure this is the right instruction */
894 ASSERT((Opcode
& 0xFE) == 0xA4);
896 /* Get the operands */
897 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
899 /* Exception occurred */
905 /* Fetch the count */
906 if (!Fast486FetchByte(State
, &Count
))
908 /* Exception occurred */
914 /* The count is in CL */
915 Count
= State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
;
918 /* Normalize the count */
921 /* Do nothing if the count is zero */
922 if (Count
== 0) return TRUE
;
926 ULONG Source
, Destination
, Result
;
928 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Source
, &Destination
))
930 /* Exception occurred */
934 /* Calculate the result */
935 Result
= (Destination
<< Count
) | (Source
>> (32 - Count
));
938 State
->Flags
.Cf
= (Destination
>> (32 - Count
)) & 1;
939 if (Count
== 1) State
->Flags
.Of
= (Result
& SIGN_FLAG_LONG
)
940 != (Destination
& SIGN_FLAG_LONG
);
941 State
->Flags
.Zf
= (Result
== 0);
942 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
943 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
945 /* Write back the result */
946 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
);
950 USHORT Source
, Destination
, Result
;
953 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Source
, &Destination
))
955 /* Exception occurred */
959 DoubleSource
= Source
| (Source
<< 16);
961 /* Calculate the result */
962 Result
= (Destination
<< Count
) | (DoubleSource
>> (32 - Count
));
965 if (Count
<= 16) State
->Flags
.Cf
= (Destination
>> (16 - Count
)) & 1;
966 else State
->Flags
.Cf
= (Source
>> (32 - Count
)) & 1;
968 if (Count
== 1) State
->Flags
.Of
= (Result
& SIGN_FLAG_WORD
)
969 != (Destination
& SIGN_FLAG_WORD
);
970 State
->Flags
.Zf
= (Result
== 0);
971 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
972 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
974 /* Write back the result */
975 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Result
);
979 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushGs
)
981 /* Call the internal API */
982 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_GS
].Selector
);
985 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopGs
)
989 if (!Fast486StackPop(State
, &NewSelector
))
991 /* Exception occurred */
995 /* Call the internal API */
996 return Fast486LoadSegment(State
, FAST486_REG_GS
, LOWORD(NewSelector
));
999 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBts
)
1001 BOOLEAN OperandSize
, AddressSize
;
1002 FAST486_MOD_REG_RM ModRegRm
;
1006 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1007 TOGGLE_OPSIZE(OperandSize
);
1008 TOGGLE_ADSIZE(AddressSize
);
1010 /* Get the number of bits */
1011 if (OperandSize
) DataSize
= 32;
1014 /* Get the operands */
1015 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1017 /* Exception occurred */
1021 /* Get the bit number */
1022 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
1023 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
1025 if (ModRegRm
.Memory
)
1028 * For memory operands, add the bit offset divided by
1029 * the data size to the address
1031 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
1034 /* Normalize the bit number */
1035 BitNumber
%= DataSize
;
1041 /* Read the value */
1042 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
1044 /* Exception occurred */
1048 /* Set CF to the bit value */
1049 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1052 Value
|= 1 << BitNumber
;
1054 /* Write back the result */
1055 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
))
1057 /* Exception occurred */
1065 /* Read the value */
1066 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
1068 /* Exception occurred */
1072 /* Set CF to the bit value */
1073 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1076 Value
|= 1 << BitNumber
;
1078 /* Write back the result */
1079 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
))
1081 /* Exception occurred */
1086 /* Return success */
1090 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShrd
)
1092 BOOLEAN OperandSize
, AddressSize
;
1093 FAST486_MOD_REG_RM ModRegRm
;
1096 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1097 TOGGLE_OPSIZE(OperandSize
);
1098 TOGGLE_ADSIZE(AddressSize
);
1100 /* Make sure this is the right instruction */
1101 ASSERT((Opcode
& 0xFE) == 0xAC);
1103 /* Get the operands */
1104 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1106 /* Exception occurred */
1112 /* Fetch the count */
1113 if (!Fast486FetchByte(State
, &Count
))
1115 /* Exception occurred */
1121 /* The count is in CL */
1122 Count
= State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
;
1125 /* Normalize the count */
1128 /* Do nothing if the count is zero */
1129 if (Count
== 0) return TRUE
;
1133 ULONG Source
, Destination
, Result
;
1135 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Source
, &Destination
))
1137 /* Exception occurred */
1141 /* Calculate the result */
1142 Result
= (Destination
>> Count
) | (Source
<< (32 - Count
));
1145 State
->Flags
.Cf
= (Destination
>> (Count
- 1)) & 1;
1146 if (Count
== 1) State
->Flags
.Of
= (Result
& SIGN_FLAG_LONG
)
1147 != (Destination
& SIGN_FLAG_LONG
);
1148 State
->Flags
.Zf
= (Result
== 0);
1149 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1150 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1152 /* Write back the result */
1153 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
);
1157 USHORT Source
, Destination
, Result
;
1159 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Source
, &Destination
))
1161 /* Exception occurred */
1165 /* Calculate the result */
1166 Result
= (Destination
>> Count
) | (Source
<< (16 - Count
));
1168 if (Count
>= 16) Result
|= (ULONG
)(Source
| (Source
<< 16)) >> (Count
- 16);
1171 if (Count
<= 16) State
->Flags
.Cf
= (Destination
>> (Count
- 1)) & 1;
1172 else State
->Flags
.Cf
= (Source
>> (Count
- 17)) & 1;
1174 if (Count
== 1) State
->Flags
.Of
= (Result
& SIGN_FLAG_WORD
)
1175 != (Destination
& SIGN_FLAG_WORD
);
1176 State
->Flags
.Zf
= (Result
== 0);
1177 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1178 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1180 /* Write back the result */
1181 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Result
);
1185 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeImul
)
1187 BOOLEAN OperandSize
, AddressSize
;
1188 FAST486_MOD_REG_RM ModRegRm
;
1190 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1192 TOGGLE_OPSIZE(OperandSize
);
1193 TOGGLE_ADSIZE(AddressSize
);
1195 /* Get the operands */
1196 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1198 /* Exception occurred */
1204 LONG Source
, Destination
;
1207 /* Read the operands */
1208 if (!Fast486ReadModrmDwordOperands(State
,
1210 (PULONG
)&Destination
,
1213 /* Exception occurred */
1217 /* Calculate the result */
1218 Result
= (LONGLONG
)Source
* (LONGLONG
)Destination
;
1220 /* Update the flags */
1221 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -2147483648LL) || (Result
> 2147483647LL));
1223 /* Write back the result */
1224 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, (ULONG
)((LONG
)Result
));
1228 SHORT Source
, Destination
;
1231 /* Read the operands */
1232 if (!Fast486ReadModrmWordOperands(State
,
1234 (PUSHORT
)&Destination
,
1237 /* Exception occurred */
1241 /* Calculate the result */
1242 Result
= (LONG
)Source
* (LONG
)Destination
;
1244 /* Update the flags */
1245 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -32768) || (Result
> 32767));
1247 /* Write back the result */
1248 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, (USHORT
)((SHORT
)Result
));
1252 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchgByte
)
1254 FAST486_MOD_REG_RM ModRegRm
;
1255 UCHAR Accumulator
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1256 UCHAR Source
, Destination
, Result
;
1257 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1259 TOGGLE_ADSIZE(AddressSize
);
1261 /* Get the operands */
1262 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1264 /* Exception occurred */
1268 /* Read the operands */
1269 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Source
, &Destination
))
1271 /* Exception occurred */
1275 /* Compare AL with the destination */
1276 Result
= Accumulator
- Destination
;
1278 /* Update the flags */
1279 State
->Flags
.Cf
= (Accumulator
< Destination
);
1280 State
->Flags
.Of
= ((Accumulator
& SIGN_FLAG_BYTE
) != (Destination
& SIGN_FLAG_BYTE
))
1281 && ((Accumulator
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1282 State
->Flags
.Af
= (Accumulator
& 0x0F) < (Destination
& 0x0F);
1283 State
->Flags
.Zf
= (Result
== 0);
1284 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1285 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1287 if (State
->Flags
.Zf
)
1289 /* Load the source operand into the destination */
1290 return Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Source
);
1294 /* Load the destination into AL */
1295 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Destination
;
1298 /* Return success */
1302 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchg
)
1304 FAST486_MOD_REG_RM ModRegRm
;
1305 BOOLEAN OperandSize
, AddressSize
;
1307 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1309 TOGGLE_OPSIZE(OperandSize
);
1310 TOGGLE_ADSIZE(AddressSize
);
1312 /* Get the operands */
1313 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1315 /* Exception occurred */
1321 ULONG Source
, Destination
, Result
;
1322 ULONG Accumulator
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1324 /* Read the operands */
1325 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Source
, &Destination
))
1327 /* Exception occurred */
1331 /* Compare EAX with the destination */
1332 Result
= Accumulator
- Destination
;
1334 /* Update the flags */
1335 State
->Flags
.Cf
= (Accumulator
< Destination
);
1336 State
->Flags
.Of
= ((Accumulator
& SIGN_FLAG_LONG
) != (Destination
& SIGN_FLAG_LONG
))
1337 && ((Accumulator
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1338 State
->Flags
.Af
= (Accumulator
& 0x0F) < (Destination
& 0x0F);
1339 State
->Flags
.Zf
= (Result
== 0);
1340 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1341 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1343 if (State
->Flags
.Zf
)
1345 /* Load the source operand into the destination */
1346 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Source
);
1350 /* Load the destination into EAX */
1351 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Destination
;
1356 USHORT Source
, Destination
, Result
;
1357 USHORT Accumulator
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1359 /* Read the operands */
1360 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Source
, &Destination
))
1362 /* Exception occurred */
1366 /* Compare AX with the destination */
1367 Result
= Accumulator
- Destination
;
1369 /* Update the flags */
1370 State
->Flags
.Cf
= (Accumulator
< Destination
);
1371 State
->Flags
.Of
= ((Accumulator
& SIGN_FLAG_WORD
) != (Destination
& SIGN_FLAG_WORD
))
1372 && ((Accumulator
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1373 State
->Flags
.Af
= (Accumulator
& 0x0F) < (Destination
& 0x0F);
1374 State
->Flags
.Zf
= (Result
== 0);
1375 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1376 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1378 if (State
->Flags
.Zf
)
1380 /* Load the source operand into the destination */
1381 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Source
);
1385 /* Load the destination into AX */
1386 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Destination
;
1390 /* Return success */
1394 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLss
)
1396 UCHAR FarPointer
[6];
1397 BOOLEAN OperandSize
, AddressSize
;
1398 FAST486_MOD_REG_RM ModRegRm
;
1400 /* Make sure this is the right instruction */
1401 ASSERT(Opcode
== 0xB2);
1403 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1405 TOGGLE_OPSIZE(OperandSize
);
1406 TOGGLE_ADSIZE(AddressSize
);
1408 /* Get the operands */
1409 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1411 /* Exception occurred */
1415 if (!ModRegRm
.Memory
)
1418 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1422 if (!Fast486ReadMemory(State
,
1423 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1424 ? State
->SegmentOverride
: FAST486_REG_DS
,
1425 ModRegRm
.MemoryAddress
,
1428 OperandSize
? 6 : 4))
1430 /* Exception occurred */
1436 ULONG Offset
= *((PULONG
)FarPointer
);
1437 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
1439 /* Set the register to the offset */
1440 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
1442 /* Load the segment */
1443 return Fast486LoadSegment(State
,
1449 USHORT Offset
= *((PUSHORT
)FarPointer
);
1450 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
1452 /* Set the register to the offset */
1453 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
1455 /* Load the segment */
1456 return Fast486LoadSegment(State
,
1462 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtr
)
1464 BOOLEAN OperandSize
, AddressSize
;
1465 FAST486_MOD_REG_RM ModRegRm
;
1469 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1470 TOGGLE_OPSIZE(OperandSize
);
1471 TOGGLE_ADSIZE(AddressSize
);
1473 /* Get the number of bits */
1474 if (OperandSize
) DataSize
= 32;
1477 /* Get the operands */
1478 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1480 /* Exception occurred */
1484 /* Get the bit number */
1485 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
1486 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
1488 if (ModRegRm
.Memory
)
1491 * For memory operands, add the bit offset divided by
1492 * the data size to the address
1494 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
1497 /* Normalize the bit number */
1498 BitNumber
%= DataSize
;
1504 /* Read the value */
1505 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
1507 /* Exception occurred */
1511 /* Set CF to the bit value */
1512 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1515 Value
&= ~(1 << BitNumber
);
1517 /* Write back the result */
1518 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
))
1520 /* Exception occurred */
1528 /* Read the value */
1529 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
1531 /* Exception occurred */
1535 /* Set CF to the bit value */
1536 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1539 Value
&= ~(1 << BitNumber
);
1541 /* Write back the result */
1542 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
))
1544 /* Exception occurred */
1549 /* Return success */
1553 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLfsLgs
)
1555 UCHAR FarPointer
[6];
1556 BOOLEAN OperandSize
, AddressSize
;
1557 FAST486_MOD_REG_RM ModRegRm
;
1559 /* Make sure this is the right instruction */
1560 ASSERT((Opcode
& 0xFE) == 0xB4);
1562 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1564 TOGGLE_OPSIZE(OperandSize
);
1565 TOGGLE_ADSIZE(AddressSize
);
1567 /* Get the operands */
1568 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1570 /* Exception occurred */
1574 if (!ModRegRm
.Memory
)
1577 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1581 if (!Fast486ReadMemory(State
,
1582 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1583 ? State
->SegmentOverride
: FAST486_REG_DS
,
1584 ModRegRm
.MemoryAddress
,
1587 OperandSize
? 6 : 4))
1589 /* Exception occurred */
1595 ULONG Offset
= *((PULONG
)FarPointer
);
1596 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
1598 /* Set the register to the offset */
1599 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
1601 /* Load the segment */
1602 return Fast486LoadSegment(State
,
1604 ? FAST486_REG_FS
: FAST486_REG_GS
,
1609 USHORT Offset
= *((PUSHORT
)FarPointer
);
1610 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
1612 /* Set the register to the offset */
1613 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
1615 /* Load the segment */
1616 return Fast486LoadSegment(State
,
1618 ? FAST486_REG_FS
: FAST486_REG_GS
,
1623 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxByte
)
1626 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1627 FAST486_MOD_REG_RM ModRegRm
;
1629 TOGGLE_ADSIZE(AddressSize
);
1631 /* Make sure this is the right instruction */
1632 ASSERT(Opcode
== 0xB6);
1634 /* Get the operands */
1635 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1637 /* Exception occurred */
1641 /* Read the operands */
1642 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, NULL
, &Value
))
1644 /* Exception occurred */
1648 /* Write back the zero-extended value */
1649 return Fast486WriteModrmDwordOperands(State
,
1655 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxWord
)
1658 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1659 FAST486_MOD_REG_RM ModRegRm
;
1661 TOGGLE_ADSIZE(AddressSize
);
1663 /* Make sure this is the right instruction */
1664 ASSERT(Opcode
== 0xB7);
1666 /* Get the operands */
1667 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1669 /* Exception occurred */
1673 /* Read the operands */
1674 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
1676 /* Exception occurred */
1680 /* Write back the zero-extended value */
1681 return Fast486WriteModrmDwordOperands(State
,
1687 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtc
)
1689 BOOLEAN OperandSize
, AddressSize
;
1690 FAST486_MOD_REG_RM ModRegRm
;
1694 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1695 TOGGLE_OPSIZE(OperandSize
);
1696 TOGGLE_ADSIZE(AddressSize
);
1698 /* Get the number of bits */
1699 if (OperandSize
) DataSize
= 32;
1702 /* Get the operands */
1703 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1705 /* Exception occurred */
1709 /* Get the bit number */
1710 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
1711 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
1713 if (ModRegRm
.Memory
)
1716 * For memory operands, add the bit offset divided by
1717 * the data size to the address
1719 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
1722 /* Normalize the bit number */
1723 BitNumber
%= DataSize
;
1729 /* Read the value */
1730 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
1732 /* Exception occurred */
1736 /* Set CF to the bit value */
1737 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1739 /* Toggle the bit */
1740 Value
^= 1 << BitNumber
;
1742 /* Write back the result */
1743 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
))
1745 /* Exception occurred */
1753 /* Read the value */
1754 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
1756 /* Exception occurred */
1760 /* Set CF to the bit value */
1761 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1763 /* Toggle the bit */
1764 Value
^= 1 << BitNumber
;
1766 /* Write back the result */
1767 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
))
1769 /* Exception occurred */
1774 /* Return success */
1778 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsf
)
1782 BOOLEAN OperandSize
, AddressSize
;
1783 FAST486_MOD_REG_RM ModRegRm
;
1787 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1788 TOGGLE_OPSIZE(OperandSize
);
1789 TOGGLE_ADSIZE(AddressSize
);
1791 /* Make sure this is the right instruction */
1792 ASSERT(Opcode
== 0xBC);
1794 /* Get the number of bits */
1795 if (OperandSize
) DataSize
= 32;
1798 /* Get the operands */
1799 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1801 /* Exception occurred */
1805 /* Read the value */
1808 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
1810 /* Exception occurred */
1816 if (!Fast486ReadModrmWordOperands(State
,
1821 /* Exception occurred */
1827 State
->Flags
.Zf
= (Value
== 0);
1828 if (State
->Flags
.Zf
) return TRUE
;
1830 for (i
= 0; i
< DataSize
; i
++)
1832 if(Value
& (1 << i
))
1834 /* Save the bit number */
1842 /* Write back the result */
1845 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, BitNumber
))
1847 /* Exception occurred */
1853 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, LOWORD(BitNumber
)))
1855 /* Exception occurred */
1863 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsr
)
1867 BOOLEAN OperandSize
, AddressSize
;
1868 FAST486_MOD_REG_RM ModRegRm
;
1872 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1873 TOGGLE_OPSIZE(OperandSize
);
1874 TOGGLE_ADSIZE(AddressSize
);
1876 /* Make sure this is the right instruction */
1877 ASSERT(Opcode
== 0xBD);
1879 /* Get the number of bits */
1880 if (OperandSize
) DataSize
= 32;
1883 /* Get the operands */
1884 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1886 /* Exception occurred */
1890 /* Read the value */
1893 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
1895 /* Exception occurred */
1901 if (!Fast486ReadModrmWordOperands(State
,
1906 /* Exception occurred */
1911 /* Set ZF according to the value */
1912 State
->Flags
.Zf
= (Value
== 0);
1913 if (State
->Flags
.Zf
) return TRUE
;
1915 for (i
= DataSize
- 1; i
>= 0; i
--)
1917 if(Value
& (1 << i
))
1919 /* Save the bit number */
1927 /* Write back the result */
1930 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, BitNumber
))
1932 /* Exception occurred */
1938 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, LOWORD(BitNumber
)))
1940 /* Exception occurred */
1948 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxByte
)
1951 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1952 FAST486_MOD_REG_RM ModRegRm
;
1954 TOGGLE_ADSIZE(AddressSize
);
1956 /* Make sure this is the right instruction */
1957 ASSERT(Opcode
== 0xBE);
1959 /* Get the operands */
1960 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1962 /* Exception occurred */
1966 /* Read the operands */
1967 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, NULL
, (PUCHAR
)&Value
))
1969 /* Exception occurred */
1973 /* Write back the sign-extended value */
1974 return Fast486WriteModrmDwordOperands(State
,
1977 (ULONG
)((LONG
)Value
));
1980 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxWord
)
1983 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1984 FAST486_MOD_REG_RM ModRegRm
;
1986 TOGGLE_ADSIZE(AddressSize
);
1988 /* Make sure this is the right instruction */
1989 ASSERT(Opcode
== 0xBF);
1991 /* Get the operands */
1992 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1994 /* Exception occurred */
1998 /* Read the operands */
1999 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, (PUSHORT
)&Value
))
2001 /* Exception occurred */
2005 /* Write back the sign-extended value */
2006 return Fast486WriteModrmDwordOperands(State
,
2009 (ULONG
)((LONG
)Value
));
2012 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalJmp
)
2014 BOOLEAN Jump
= FALSE
;
2016 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2018 TOGGLE_OPSIZE(Size
);
2021 /* Make sure this is the right instruction */
2022 ASSERT((Opcode
& 0xF0) == 0x80);
2024 /* Fetch the offset */
2027 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
2029 /* Exception occurred */
2037 if (!Fast486FetchWord(State
, (PUSHORT
)&Value
))
2039 /* Exception occurred */
2044 Offset
= (LONG
)Value
;
2047 switch ((Opcode
& 0x0F) >> 1)
2052 Jump
= State
->Flags
.Of
;
2059 Jump
= State
->Flags
.Cf
;
2066 Jump
= State
->Flags
.Zf
;
2073 Jump
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
2080 Jump
= State
->Flags
.Sf
;
2087 Jump
= State
->Flags
.Pf
;
2094 Jump
= State
->Flags
.Sf
!= State
->Flags
.Of
;
2101 Jump
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
2108 /* Invert the result */
2114 /* Move the instruction pointer */
2115 State
->InstPtr
.Long
+= Offset
;
2118 /* Return success */
2122 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalSet
)
2124 BOOLEAN Value
= FALSE
;
2125 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2126 FAST486_MOD_REG_RM ModRegRm
;
2128 TOGGLE_ADSIZE(AddressSize
);
2130 /* Get the operands */
2131 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2133 /* Exception occurred */
2137 /* Make sure this is the right instruction */
2138 ASSERT((Opcode
& 0xF0) == 0x90);
2140 switch ((Opcode
& 0x0F) >> 1)
2145 Value
= State
->Flags
.Of
;
2152 Value
= State
->Flags
.Cf
;
2159 Value
= State
->Flags
.Zf
;
2163 /* SETBE / SETNBE */
2166 Value
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
2173 Value
= State
->Flags
.Sf
;
2180 Value
= State
->Flags
.Pf
;
2187 Value
= State
->Flags
.Sf
!= State
->Flags
.Of
;
2191 /* SETLE / SETNLE */
2194 Value
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
2201 /* Invert the result */
2205 /* Write back the result */
2206 return Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Value
);
2209 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXaddByte
)
2211 UCHAR Source
, Destination
, Result
;
2212 FAST486_MOD_REG_RM ModRegRm
;
2213 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2215 /* Make sure this is the right instruction */
2216 ASSERT(Opcode
== 0xC0);
2218 TOGGLE_ADSIZE(AddressSize
);
2220 /* Get the operands */
2221 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2223 /* Exception occurred */
2227 if (!Fast486ReadModrmByteOperands(State
,
2232 /* Exception occurred */
2236 /* Calculate the result */
2237 Result
= Source
+ Destination
;
2239 /* Update the flags */
2240 State
->Flags
.Cf
= (Result
< Source
) && (Result
< Destination
);
2241 State
->Flags
.Of
= ((Source
& SIGN_FLAG_BYTE
) == (Destination
& SIGN_FLAG_BYTE
))
2242 && ((Source
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2243 State
->Flags
.Af
= ((((Source
& 0x0F) + (Destination
& 0x0F)) & 0x10) != 0);
2244 State
->Flags
.Zf
= (Result
== 0);
2245 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2246 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2248 /* Write the sum to the destination */
2249 if (!Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Result
))
2251 /* Exception occurred */
2255 /* Write the old value of the destination to the source */
2256 if (!Fast486WriteModrmByteOperands(State
, &ModRegRm
, TRUE
, Destination
))
2258 /* Exception occurred */
2265 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXadd
)
2267 FAST486_MOD_REG_RM ModRegRm
;
2268 BOOLEAN OperandSize
, AddressSize
;
2270 /* Make sure this is the right instruction */
2271 ASSERT(Opcode
== 0xC1);
2273 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2275 TOGGLE_ADSIZE(AddressSize
);
2276 TOGGLE_OPSIZE(OperandSize
);
2278 /* Get the operands */
2279 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2281 /* Exception occurred */
2285 /* Check the operand size */
2288 ULONG Source
, Destination
, Result
;
2290 if (!Fast486ReadModrmDwordOperands(State
,
2295 /* Exception occurred */
2299 /* Calculate the result */
2300 Result
= Source
+ Destination
;
2302 /* Update the flags */
2303 State
->Flags
.Cf
= (Result
< Source
) && (Result
< Destination
);
2304 State
->Flags
.Of
= ((Source
& SIGN_FLAG_LONG
) == (Destination
& SIGN_FLAG_LONG
))
2305 && ((Source
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2306 State
->Flags
.Af
= ((((Source
& 0x0F) + (Destination
& 0x0F)) & 0x10) != 0);
2307 State
->Flags
.Zf
= (Result
== 0);
2308 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2309 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2311 /* Write the old value of the destination to the source */
2312 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, Destination
))
2314 /* Exception occurred */
2318 /* Write the sum to the destination */
2319 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
))
2321 /* Exception occurred */
2327 USHORT Source
, Destination
, Result
;
2329 if (!Fast486ReadModrmWordOperands(State
,
2334 /* Exception occurred */
2338 /* Calculate the result */
2339 Result
= Source
+ Destination
;
2341 /* Update the flags */
2342 State
->Flags
.Cf
= (Result
< Source
) && (Result
< Destination
);
2343 State
->Flags
.Of
= ((Source
& SIGN_FLAG_WORD
) == (Destination
& SIGN_FLAG_WORD
))
2344 && ((Source
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2345 State
->Flags
.Af
= ((((Source
& 0x0F) + (Destination
& 0x0F)) & 0x10) != 0);
2346 State
->Flags
.Zf
= (Result
== 0);
2347 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2348 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2350 /* Write the old value of the destination to the source */
2351 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, Destination
))
2353 /* Exception occurred */
2357 /* Write the sum to the destination */
2358 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Result
))
2360 /* Exception occurred */
2368 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBswap
)
2374 /* Get a pointer to the value */
2375 Pointer
= (PUCHAR
)&State
->GeneralRegs
[Opcode
& 0x07].Long
;
2377 /* Swap the byte order */
2378 SWAP(Pointer
[0], Pointer
[3]);
2379 SWAP(Pointer
[1], Pointer
[2]);
2381 /* Return success */
2385 FAST486_OPCODE_HANDLER(Fast486OpcodeExtended
)
2389 /* Fetch the second operation code */
2390 if (!Fast486FetchByte(State
, &SecondOpcode
))
2392 /* Exception occurred */
2396 /* Call the extended opcode handler */
2397 return Fast486ExtendedHandlers
[SecondOpcode
](State
, SecondOpcode
);