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 Fast486ExtOpcodeGroup0F00
, /* 0x00 - 0x01 */
41 Fast486ExtOpcodeGroup0F01
,
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 Fast486ExtOpcodeGroup0FB9
, /* 0xB9 */
226 Fast486ExtOpcodeGroup0FBA
, /* 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);
313 FAST486_OPCODE_HANDLER(Fast486ExtOpcode0F0B
)
315 /* Reserved opcode (UD2) */
316 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
319 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLar
)
321 BOOLEAN OperandSize
, AddressSize
;
322 FAST486_MOD_REG_RM ModRegRm
;
324 FAST486_GDT_ENTRY GdtEntry
;
327 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
329 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
333 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
338 TOGGLE_OPSIZE(OperandSize
);
339 TOGGLE_ADSIZE(AddressSize
);
341 /* Get the operands */
342 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
344 /* Exception occurred */
353 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
355 /* Exception occurred */
359 Selector
= LOWORD(Value
);
364 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Selector
))
366 /* Exception occurred */
371 if (!(Selector
& SEGMENT_TABLE_INDICATOR
))
373 /* Check if the GDT contains the entry */
374 if (GET_SEGMENT_INDEX(Selector
) >= (State
->Gdtr
.Size
+ 1))
376 State
->Flags
.Zf
= FALSE
;
381 if (!Fast486ReadLinearMemory(State
,
383 + GET_SEGMENT_INDEX(Selector
),
387 /* Exception occurred */
393 /* Check if the LDT contains the entry */
394 if (GET_SEGMENT_INDEX(Selector
) >= (State
->Ldtr
.Limit
+ 1))
396 State
->Flags
.Zf
= FALSE
;
401 if (!Fast486ReadLinearMemory(State
,
403 + GET_SEGMENT_INDEX(Selector
),
407 /* Exception occurred */
412 /* Privilege check */
413 if (((GET_SEGMENT_RPL(Selector
) > GdtEntry
.Dpl
))
414 || (Fast486GetCurrentPrivLevel(State
) > GdtEntry
.Dpl
))
416 State
->Flags
.Zf
= FALSE
;
421 State
->Flags
.Zf
= TRUE
;
423 /* Get the access rights */
424 AccessRights
= ((PDWORD
)&GdtEntry
)[1] & 0x00F0FF00;
426 /* Return the access rights */
427 if (OperandSize
) Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, AccessRights
);
428 else Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, LOWORD(AccessRights
));
431 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLsl
)
433 BOOLEAN OperandSize
, AddressSize
;
434 FAST486_MOD_REG_RM ModRegRm
;
437 FAST486_GDT_ENTRY GdtEntry
;
439 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
441 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
445 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
450 TOGGLE_OPSIZE(OperandSize
);
451 TOGGLE_ADSIZE(AddressSize
);
453 /* Get the operands */
454 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
456 /* Exception occurred */
465 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
467 /* Exception occurred */
471 Selector
= LOWORD(Value
);
476 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Selector
))
478 /* Exception occurred */
483 if (!(Selector
& SEGMENT_TABLE_INDICATOR
))
485 /* Check if the GDT contains the entry */
486 if (GET_SEGMENT_INDEX(Selector
) >= (State
->Gdtr
.Size
+ 1))
488 State
->Flags
.Zf
= FALSE
;
493 if (!Fast486ReadLinearMemory(State
,
495 + GET_SEGMENT_INDEX(Selector
),
499 /* Exception occurred */
505 /* Check if the LDT contains the entry */
506 if (GET_SEGMENT_INDEX(Selector
) >= (State
->Ldtr
.Limit
+ 1))
508 State
->Flags
.Zf
= FALSE
;
513 if (!Fast486ReadLinearMemory(State
,
515 + GET_SEGMENT_INDEX(Selector
),
519 /* Exception occurred */
524 /* Privilege check */
525 if (((GET_SEGMENT_RPL(Selector
) > GdtEntry
.Dpl
))
526 || (Fast486GetCurrentPrivLevel(State
) > GdtEntry
.Dpl
))
528 State
->Flags
.Zf
= FALSE
;
532 /* Calculate the limit */
533 Limit
= GdtEntry
.Limit
| (GdtEntry
.LimitHigh
<< 16);
534 if (GdtEntry
.Granularity
) Limit
<<= 12;
537 State
->Flags
.Zf
= TRUE
;
539 /* Return the limit */
540 if (OperandSize
) Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, Limit
);
541 else Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, LOWORD(Limit
));
544 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeClts
)
548 /* The current privilege level must be zero */
549 if (Fast486GetCurrentPrivLevel(State
) != 0)
551 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
555 /* Clear the task switch bit */
556 State
->ControlRegisters
[FAST486_REG_CR0
] &= ~FAST486_CR0_TS
;
559 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreControlReg
)
561 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
562 FAST486_MOD_REG_RM ModRegRm
;
565 TOGGLE_ADSIZE(AddressSize
);
567 /* Get the operands */
568 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
570 /* Exception occurred */
574 /* The current privilege level must be zero */
575 if (Fast486GetCurrentPrivLevel(State
) != 0)
577 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
581 if ((ModRegRm
.Register
== 1) || (ModRegRm
.Register
> 3))
583 /* CR1, CR4, CR5, CR6 and CR7 don't exist */
584 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
588 if (ModRegRm
.Register
!= 0)
590 /* CR2 and CR3 and are stored in array indexes 1 and 2 */
594 /* Store the value of the control register */
595 State
->GeneralRegs
[ModRegRm
.SecondRegister
].Long
= State
->ControlRegisters
[ModRegRm
.Register
];
598 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreDebugReg
)
600 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
601 FAST486_MOD_REG_RM ModRegRm
;
604 TOGGLE_ADSIZE(AddressSize
);
606 /* Get the operands */
607 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
609 /* Exception occurred */
613 /* The current privilege level must be zero */
614 if (Fast486GetCurrentPrivLevel(State
) != 0)
616 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
620 if ((ModRegRm
.Register
== 6) || (ModRegRm
.Register
== 7))
622 /* DR6 and DR7 are aliases to DR4 and DR5 */
623 ModRegRm
.Register
-= 2;
626 if (State
->DebugRegisters
[FAST486_REG_DR5
] & FAST486_DR5_GD
)
628 /* Disallow access to debug registers */
629 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
633 /* Store the value of the debug register */
634 State
->GeneralRegs
[ModRegRm
.SecondRegister
].Long
= State
->DebugRegisters
[ModRegRm
.Register
];
637 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadControlReg
)
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
== 1) || (ModRegRm
.Register
> 3))
662 /* CR1, CR4, CR5, CR6 and CR7 don't exist */
663 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
667 if (ModRegRm
.Register
!= 0)
669 /* CR2 and CR3 and are stored in array indexes 1 and 2 */
674 Value
= State
->GeneralRegs
[ModRegRm
.SecondRegister
].Long
;
676 if (ModRegRm
.Register
== (INT
)FAST486_REG_CR0
)
680 if (((Value
& (FAST486_CR0_PG
| FAST486_CR0_PE
)) == FAST486_CR0_PG
)
681 || ((Value
& (FAST486_CR0_CD
| FAST486_CR0_NW
)) == FAST486_CR0_NW
))
684 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
689 #ifndef FAST486_NO_PREFETCH
690 /* Changing CR0 or CR3 can interfere with prefetching (because of paging) */
691 State
->PrefetchValid
= FALSE
;
694 /* Load a value to the control register */
695 State
->ControlRegisters
[ModRegRm
.Register
] = Value
;
698 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadDebugReg
)
700 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
701 FAST486_MOD_REG_RM ModRegRm
;
704 TOGGLE_ADSIZE(AddressSize
);
706 /* Get the operands */
707 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
709 /* Exception occurred */
713 /* The current privilege level must be zero */
714 if (Fast486GetCurrentPrivLevel(State
) != 0)
716 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
720 if ((ModRegRm
.Register
== 6) || (ModRegRm
.Register
== 7))
722 /* DR6 and DR7 are aliases to DR4 and DR5 */
723 ModRegRm
.Register
-= 2;
726 if (State
->DebugRegisters
[FAST486_REG_DR5
] & FAST486_DR5_GD
)
728 /* Disallow access to debug registers */
729 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
733 /* Load a value to the debug register */
734 State
->DebugRegisters
[ModRegRm
.Register
] = State
->GeneralRegs
[ModRegRm
.SecondRegister
].Long
;
736 if (ModRegRm
.Register
== (INT
)FAST486_REG_DR4
)
738 /* The reserved bits are 1 */
739 State
->DebugRegisters
[ModRegRm
.Register
] |= FAST486_DR4_RESERVED
;
741 else if (ModRegRm
.Register
== (INT
)FAST486_REG_DR5
)
743 /* The reserved bits are 0 */
744 State
->DebugRegisters
[ModRegRm
.Register
] &= ~FAST486_DR5_RESERVED
;
748 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushFs
)
750 /* Call the internal API */
751 Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_FS
].Selector
);
754 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopFs
)
758 if (!Fast486StackPop(State
, &NewSelector
))
760 /* Exception occurred */
764 /* Call the internal API */
765 Fast486LoadSegment(State
, FAST486_REG_FS
, LOWORD(NewSelector
));
768 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBitTest
)
770 BOOLEAN OperandSize
, AddressSize
;
771 FAST486_MOD_REG_RM ModRegRm
;
775 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
776 TOGGLE_OPSIZE(OperandSize
);
777 TOGGLE_ADSIZE(AddressSize
);
779 /* Get the number of bits */
780 if (OperandSize
) DataSize
= 32;
783 /* Get the operands */
784 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
786 /* Exception occurred */
790 /* Get the bit number */
791 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
792 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
797 * For memory operands, add the bit offset divided by
798 * the data size to the address
800 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
803 /* Normalize the bit number */
804 BitNumber
%= DataSize
;
811 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
813 /* Exception occurred */
817 /* Set CF to the bit value */
818 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
825 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
827 /* Exception occurred */
831 /* Set CF to the bit value */
832 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
836 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShld
)
838 BOOLEAN OperandSize
, AddressSize
;
839 FAST486_MOD_REG_RM ModRegRm
;
842 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
843 TOGGLE_OPSIZE(OperandSize
);
844 TOGGLE_ADSIZE(AddressSize
);
846 /* Make sure this is the right instruction */
847 ASSERT((Opcode
& 0xFE) == 0xA4);
849 /* Get the operands */
850 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
852 /* Exception occurred */
858 /* Fetch the count */
859 if (!Fast486FetchByte(State
, &Count
))
861 /* Exception occurred */
867 /* The count is in CL */
868 Count
= State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
;
871 /* Normalize the count */
874 /* Do nothing if the count is zero */
875 if (Count
== 0) return;
879 ULONG Source
, Destination
, Result
;
881 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Source
, &Destination
))
883 /* Exception occurred */
887 /* Calculate the result */
888 Result
= (Destination
<< Count
) | (Source
>> (32 - Count
));
891 State
->Flags
.Cf
= (Destination
>> (32 - Count
)) & 1;
892 if (Count
== 1) State
->Flags
.Of
= (Result
& SIGN_FLAG_LONG
)
893 != (Destination
& SIGN_FLAG_LONG
);
894 State
->Flags
.Zf
= (Result
== 0);
895 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
896 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
898 /* Write back the result */
899 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
);
903 USHORT Source
, Destination
, Result
;
906 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Source
, &Destination
))
908 /* Exception occurred */
912 DoubleSource
= Source
| (Source
<< 16);
914 /* Calculate the result */
915 Result
= (Destination
<< Count
) | (DoubleSource
>> (32 - Count
));
918 if (Count
<= 16) State
->Flags
.Cf
= (Destination
>> (16 - Count
)) & 1;
919 else State
->Flags
.Cf
= (Source
>> (32 - Count
)) & 1;
921 if (Count
== 1) State
->Flags
.Of
= (Result
& SIGN_FLAG_WORD
)
922 != (Destination
& SIGN_FLAG_WORD
);
923 State
->Flags
.Zf
= (Result
== 0);
924 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
925 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
927 /* Write back the result */
928 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Result
);
932 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushGs
)
934 /* Call the internal API */
935 Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_GS
].Selector
);
938 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopGs
)
942 if (!Fast486StackPop(State
, &NewSelector
))
944 /* Exception occurred */
948 /* Call the internal API */
949 Fast486LoadSegment(State
, FAST486_REG_GS
, LOWORD(NewSelector
));
952 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBts
)
954 BOOLEAN OperandSize
, AddressSize
;
955 FAST486_MOD_REG_RM ModRegRm
;
959 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
960 TOGGLE_OPSIZE(OperandSize
);
961 TOGGLE_ADSIZE(AddressSize
);
963 /* Get the number of bits */
964 if (OperandSize
) DataSize
= 32;
967 /* Get the operands */
968 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
970 /* Exception occurred */
974 /* Get the bit number */
975 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
976 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
981 * For memory operands, add the bit offset divided by
982 * the data size to the address
984 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
987 /* Normalize the bit number */
988 BitNumber
%= DataSize
;
995 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
997 /* Exception occurred */
1001 /* Set CF to the bit value */
1002 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1005 Value
|= 1 << BitNumber
;
1007 /* Write back the result */
1008 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
1014 /* Read the value */
1015 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
1017 /* Exception occurred */
1021 /* Set CF to the bit value */
1022 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1025 Value
|= 1 << BitNumber
;
1027 /* Write back the result */
1028 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
1032 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShrd
)
1034 BOOLEAN OperandSize
, AddressSize
;
1035 FAST486_MOD_REG_RM ModRegRm
;
1038 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1039 TOGGLE_OPSIZE(OperandSize
);
1040 TOGGLE_ADSIZE(AddressSize
);
1042 /* Make sure this is the right instruction */
1043 ASSERT((Opcode
& 0xFE) == 0xAC);
1045 /* Get the operands */
1046 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1048 /* Exception occurred */
1054 /* Fetch the count */
1055 if (!Fast486FetchByte(State
, &Count
))
1057 /* Exception occurred */
1063 /* The count is in CL */
1064 Count
= State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
;
1067 /* Normalize the count */
1070 /* Do nothing if the count is zero */
1071 if (Count
== 0) return;
1075 ULONG Source
, Destination
, Result
;
1077 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Source
, &Destination
))
1079 /* Exception occurred */
1083 /* Calculate the result */
1084 Result
= (Destination
>> Count
) | (Source
<< (32 - Count
));
1087 State
->Flags
.Cf
= (Destination
>> (Count
- 1)) & 1;
1088 if (Count
== 1) State
->Flags
.Of
= (Result
& SIGN_FLAG_LONG
)
1089 != (Destination
& SIGN_FLAG_LONG
);
1090 State
->Flags
.Zf
= (Result
== 0);
1091 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1092 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1094 /* Write back the result */
1095 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
);
1099 USHORT Source
, Destination
, Result
;
1101 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Source
, &Destination
))
1103 /* Exception occurred */
1107 /* Calculate the result */
1108 Result
= (Destination
>> Count
) | (Source
<< (16 - Count
));
1110 if (Count
>= 16) Result
|= (ULONG
)(Source
| (Source
<< 16)) >> (Count
- 16);
1113 if (Count
<= 16) State
->Flags
.Cf
= (Destination
>> (Count
- 1)) & 1;
1114 else State
->Flags
.Cf
= (Source
>> (Count
- 17)) & 1;
1116 if (Count
== 1) State
->Flags
.Of
= (Result
& SIGN_FLAG_WORD
)
1117 != (Destination
& SIGN_FLAG_WORD
);
1118 State
->Flags
.Zf
= (Result
== 0);
1119 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1120 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1122 /* Write back the result */
1123 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Result
);
1127 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeImul
)
1129 BOOLEAN OperandSize
, AddressSize
;
1130 FAST486_MOD_REG_RM ModRegRm
;
1132 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1134 TOGGLE_OPSIZE(OperandSize
);
1135 TOGGLE_ADSIZE(AddressSize
);
1137 /* Get the operands */
1138 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1140 /* Exception occurred */
1146 LONG Source
, Destination
;
1149 /* Read the operands */
1150 if (!Fast486ReadModrmDwordOperands(State
,
1152 (PULONG
)&Destination
,
1155 /* Exception occurred */
1159 /* Calculate the result */
1160 Result
= (LONGLONG
)Source
* (LONGLONG
)Destination
;
1162 /* Update the flags */
1163 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -2147483648LL) || (Result
> 2147483647LL));
1165 /* Write back the result */
1166 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, (ULONG
)((LONG
)Result
));
1170 SHORT Source
, Destination
;
1173 /* Read the operands */
1174 if (!Fast486ReadModrmWordOperands(State
,
1176 (PUSHORT
)&Destination
,
1179 /* Exception occurred */
1183 /* Calculate the result */
1184 Result
= (LONG
)Source
* (LONG
)Destination
;
1186 /* Update the flags */
1187 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -32768) || (Result
> 32767));
1189 /* Write back the result */
1190 Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, (USHORT
)((SHORT
)Result
));
1194 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchgByte
)
1196 FAST486_MOD_REG_RM ModRegRm
;
1197 UCHAR Accumulator
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1198 UCHAR Source
, Destination
, Result
;
1199 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1201 TOGGLE_ADSIZE(AddressSize
);
1203 /* Get the operands */
1204 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1206 /* Exception occurred */
1210 /* Read the operands */
1211 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Source
, &Destination
))
1213 /* Exception occurred */
1217 /* Compare AL with the destination */
1218 Result
= Accumulator
- Destination
;
1220 /* Update the flags */
1221 State
->Flags
.Cf
= (Accumulator
< Destination
);
1222 State
->Flags
.Of
= ((Accumulator
& SIGN_FLAG_BYTE
) != (Destination
& SIGN_FLAG_BYTE
))
1223 && ((Accumulator
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1224 State
->Flags
.Af
= (Accumulator
& 0x0F) < (Destination
& 0x0F);
1225 State
->Flags
.Zf
= (Result
== 0);
1226 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1227 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1229 if (State
->Flags
.Zf
)
1231 /* Load the source operand into the destination */
1232 Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Source
);
1236 /* Load the destination into AL */
1237 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Destination
;
1241 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchg
)
1243 FAST486_MOD_REG_RM ModRegRm
;
1244 BOOLEAN OperandSize
, AddressSize
;
1246 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1248 TOGGLE_OPSIZE(OperandSize
);
1249 TOGGLE_ADSIZE(AddressSize
);
1251 /* Get the operands */
1252 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1254 /* Exception occurred */
1260 ULONG Source
, Destination
, Result
;
1261 ULONG Accumulator
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1263 /* Read the operands */
1264 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Source
, &Destination
))
1266 /* Exception occurred */
1270 /* Compare EAX with the destination */
1271 Result
= Accumulator
- Destination
;
1273 /* Update the flags */
1274 State
->Flags
.Cf
= (Accumulator
< Destination
);
1275 State
->Flags
.Of
= ((Accumulator
& SIGN_FLAG_LONG
) != (Destination
& SIGN_FLAG_LONG
))
1276 && ((Accumulator
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1277 State
->Flags
.Af
= (Accumulator
& 0x0F) < (Destination
& 0x0F);
1278 State
->Flags
.Zf
= (Result
== 0);
1279 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1280 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1282 if (State
->Flags
.Zf
)
1284 /* Load the source operand into the destination */
1285 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Source
);
1289 /* Load the destination into EAX */
1290 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Destination
;
1295 USHORT Source
, Destination
, Result
;
1296 USHORT Accumulator
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1298 /* Read the operands */
1299 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Source
, &Destination
))
1301 /* Exception occurred */
1305 /* Compare AX with the destination */
1306 Result
= Accumulator
- Destination
;
1308 /* Update the flags */
1309 State
->Flags
.Cf
= (Accumulator
< Destination
);
1310 State
->Flags
.Of
= ((Accumulator
& SIGN_FLAG_WORD
) != (Destination
& SIGN_FLAG_WORD
))
1311 && ((Accumulator
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1312 State
->Flags
.Af
= (Accumulator
& 0x0F) < (Destination
& 0x0F);
1313 State
->Flags
.Zf
= (Result
== 0);
1314 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1315 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1317 if (State
->Flags
.Zf
)
1319 /* Load the source operand into the destination */
1320 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Source
);
1324 /* Load the destination into AX */
1325 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Destination
;
1330 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLss
)
1332 UCHAR FarPointer
[6];
1333 BOOLEAN OperandSize
, AddressSize
;
1334 FAST486_MOD_REG_RM ModRegRm
;
1336 /* Make sure this is the right instruction */
1337 ASSERT(Opcode
== 0xB2);
1339 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1341 TOGGLE_OPSIZE(OperandSize
);
1342 TOGGLE_ADSIZE(AddressSize
);
1344 /* Get the operands */
1345 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1347 /* Exception occurred */
1351 if (!ModRegRm
.Memory
)
1354 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1358 if (!Fast486ReadMemory(State
,
1359 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1360 ? State
->SegmentOverride
: FAST486_REG_DS
,
1361 ModRegRm
.MemoryAddress
,
1364 OperandSize
? 6 : 4))
1366 /* Exception occurred */
1372 ULONG Offset
= *((PULONG
)FarPointer
);
1373 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
1375 /* Set the register to the offset */
1376 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
1378 /* Load the segment */
1379 Fast486LoadSegment(State
, FAST486_REG_SS
, Segment
);
1383 USHORT Offset
= *((PUSHORT
)FarPointer
);
1384 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
1386 /* Set the register to the offset */
1387 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
1389 /* Load the segment */
1390 Fast486LoadSegment(State
, FAST486_REG_SS
, Segment
);
1394 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtr
)
1396 BOOLEAN OperandSize
, AddressSize
;
1397 FAST486_MOD_REG_RM ModRegRm
;
1401 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1402 TOGGLE_OPSIZE(OperandSize
);
1403 TOGGLE_ADSIZE(AddressSize
);
1405 /* Get the number of bits */
1406 if (OperandSize
) DataSize
= 32;
1409 /* Get the operands */
1410 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1412 /* Exception occurred */
1416 /* Get the bit number */
1417 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
1418 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
1420 if (ModRegRm
.Memory
)
1423 * For memory operands, add the bit offset divided by
1424 * the data size to the address
1426 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
1429 /* Normalize the bit number */
1430 BitNumber
%= DataSize
;
1436 /* Read the value */
1437 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
1439 /* Exception occurred */
1443 /* Set CF to the bit value */
1444 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1447 Value
&= ~(1 << BitNumber
);
1449 /* Write back the result */
1450 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
1456 /* Read the value */
1457 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
1459 /* Exception occurred */
1463 /* Set CF to the bit value */
1464 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1467 Value
&= ~(1 << BitNumber
);
1469 /* Write back the result */
1470 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
1474 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLfsLgs
)
1476 UCHAR FarPointer
[6];
1477 BOOLEAN OperandSize
, AddressSize
;
1478 FAST486_MOD_REG_RM ModRegRm
;
1480 /* Make sure this is the right instruction */
1481 ASSERT((Opcode
& 0xFE) == 0xB4);
1483 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1485 TOGGLE_OPSIZE(OperandSize
);
1486 TOGGLE_ADSIZE(AddressSize
);
1488 /* Get the operands */
1489 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1491 /* Exception occurred */
1495 if (!ModRegRm
.Memory
)
1498 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1502 if (!Fast486ReadMemory(State
,
1503 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1504 ? State
->SegmentOverride
: FAST486_REG_DS
,
1505 ModRegRm
.MemoryAddress
,
1508 OperandSize
? 6 : 4))
1510 /* Exception occurred */
1516 ULONG Offset
= *((PULONG
)FarPointer
);
1517 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
1519 /* Set the register to the offset */
1520 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
1522 /* Load the segment */
1523 Fast486LoadSegment(State
,
1525 ? FAST486_REG_FS
: FAST486_REG_GS
,
1530 USHORT Offset
= *((PUSHORT
)FarPointer
);
1531 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
1533 /* Set the register to the offset */
1534 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
1536 /* Load the segment */
1537 Fast486LoadSegment(State
,
1539 ? FAST486_REG_FS
: FAST486_REG_GS
,
1544 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxByte
)
1547 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1548 FAST486_MOD_REG_RM ModRegRm
;
1550 TOGGLE_ADSIZE(AddressSize
);
1552 /* Make sure this is the right instruction */
1553 ASSERT(Opcode
== 0xB6);
1555 /* Get the operands */
1556 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1558 /* Exception occurred */
1562 /* Read the operands */
1563 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, NULL
, &Value
))
1565 /* Exception occurred */
1569 /* Write back the zero-extended value */
1570 Fast486WriteModrmDwordOperands(State
,
1576 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxWord
)
1579 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1580 FAST486_MOD_REG_RM ModRegRm
;
1582 TOGGLE_ADSIZE(AddressSize
);
1584 /* Make sure this is the right instruction */
1585 ASSERT(Opcode
== 0xB7);
1587 /* Get the operands */
1588 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1590 /* Exception occurred */
1594 /* Read the operands */
1595 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
1597 /* Exception occurred */
1601 /* Write back the zero-extended value */
1602 Fast486WriteModrmDwordOperands(State
,
1608 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtc
)
1610 BOOLEAN OperandSize
, AddressSize
;
1611 FAST486_MOD_REG_RM ModRegRm
;
1615 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1616 TOGGLE_OPSIZE(OperandSize
);
1617 TOGGLE_ADSIZE(AddressSize
);
1619 /* Get the number of bits */
1620 if (OperandSize
) DataSize
= 32;
1623 /* Get the operands */
1624 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1626 /* Exception occurred */
1630 /* Get the bit number */
1631 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
1632 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
1634 if (ModRegRm
.Memory
)
1637 * For memory operands, add the bit offset divided by
1638 * the data size to the address
1640 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
1643 /* Normalize the bit number */
1644 BitNumber
%= DataSize
;
1650 /* Read the value */
1651 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
1653 /* Exception occurred */
1657 /* Set CF to the bit value */
1658 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1660 /* Toggle the bit */
1661 Value
^= 1 << BitNumber
;
1663 /* Write back the result */
1664 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
1670 /* Read the value */
1671 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
1673 /* Exception occurred */
1677 /* Set CF to the bit value */
1678 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1680 /* Toggle the bit */
1681 Value
^= 1 << BitNumber
;
1683 /* Write back the result */
1684 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
1688 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsf
)
1692 BOOLEAN OperandSize
, AddressSize
;
1693 FAST486_MOD_REG_RM ModRegRm
;
1697 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1698 TOGGLE_OPSIZE(OperandSize
);
1699 TOGGLE_ADSIZE(AddressSize
);
1701 /* Make sure this is the right instruction */
1702 ASSERT(Opcode
== 0xBC);
1704 /* Get the number of bits */
1705 if (OperandSize
) DataSize
= 32;
1708 /* Get the operands */
1709 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1711 /* Exception occurred */
1715 /* Read the value */
1718 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
1720 /* Exception occurred */
1726 if (!Fast486ReadModrmWordOperands(State
,
1731 /* Exception occurred */
1737 State
->Flags
.Zf
= (Value
== 0);
1738 if (State
->Flags
.Zf
) return;
1740 for (i
= 0; i
< DataSize
; i
++)
1742 if(Value
& (1 << i
))
1744 /* Save the bit number */
1752 /* Write back the result */
1753 if (OperandSize
) Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, BitNumber
);
1754 else Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, LOWORD(BitNumber
));
1757 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsr
)
1761 BOOLEAN OperandSize
, AddressSize
;
1762 FAST486_MOD_REG_RM ModRegRm
;
1766 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1767 TOGGLE_OPSIZE(OperandSize
);
1768 TOGGLE_ADSIZE(AddressSize
);
1770 /* Make sure this is the right instruction */
1771 ASSERT(Opcode
== 0xBD);
1773 /* Get the number of bits */
1774 if (OperandSize
) DataSize
= 32;
1777 /* Get the operands */
1778 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1780 /* Exception occurred */
1784 /* Read the value */
1787 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
1789 /* Exception occurred */
1795 if (!Fast486ReadModrmWordOperands(State
,
1800 /* Exception occurred */
1805 /* Set ZF according to the value */
1806 State
->Flags
.Zf
= (Value
== 0);
1807 if (State
->Flags
.Zf
) return;
1809 for (i
= DataSize
- 1; i
>= 0; i
--)
1811 if(Value
& (1 << i
))
1813 /* Save the bit number */
1821 /* Write back the result */
1822 if (OperandSize
) Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, BitNumber
);
1823 else Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, LOWORD(BitNumber
));
1826 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxByte
)
1829 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1830 FAST486_MOD_REG_RM ModRegRm
;
1832 TOGGLE_ADSIZE(AddressSize
);
1834 /* Make sure this is the right instruction */
1835 ASSERT(Opcode
== 0xBE);
1837 /* Get the operands */
1838 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1840 /* Exception occurred */
1844 /* Read the operands */
1845 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, NULL
, (PUCHAR
)&Value
))
1847 /* Exception occurred */
1851 /* Write back the sign-extended value */
1852 Fast486WriteModrmDwordOperands(State
,
1855 (ULONG
)((LONG
)Value
));
1858 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxWord
)
1861 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1862 FAST486_MOD_REG_RM ModRegRm
;
1864 TOGGLE_ADSIZE(AddressSize
);
1866 /* Make sure this is the right instruction */
1867 ASSERT(Opcode
== 0xBF);
1869 /* Get the operands */
1870 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1872 /* Exception occurred */
1876 /* Read the operands */
1877 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, (PUSHORT
)&Value
))
1879 /* Exception occurred */
1883 /* Write back the sign-extended value */
1884 Fast486WriteModrmDwordOperands(State
,
1887 (ULONG
)((LONG
)Value
));
1890 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalJmp
)
1892 BOOLEAN Jump
= FALSE
;
1894 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1896 TOGGLE_OPSIZE(Size
);
1899 /* Make sure this is the right instruction */
1900 ASSERT((Opcode
& 0xF0) == 0x80);
1902 /* Fetch the offset */
1905 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
1907 /* Exception occurred */
1915 if (!Fast486FetchWord(State
, (PUSHORT
)&Value
))
1917 /* Exception occurred */
1922 Offset
= (LONG
)Value
;
1925 switch ((Opcode
& 0x0F) >> 1)
1930 Jump
= State
->Flags
.Of
;
1937 Jump
= State
->Flags
.Cf
;
1944 Jump
= State
->Flags
.Zf
;
1951 Jump
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
1958 Jump
= State
->Flags
.Sf
;
1965 Jump
= State
->Flags
.Pf
;
1972 Jump
= State
->Flags
.Sf
!= State
->Flags
.Of
;
1979 Jump
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
1986 /* Invert the result */
1992 /* Move the instruction pointer */
1993 State
->InstPtr
.Long
+= Offset
;
1997 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalSet
)
1999 BOOLEAN Value
= FALSE
;
2000 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2001 FAST486_MOD_REG_RM ModRegRm
;
2003 TOGGLE_ADSIZE(AddressSize
);
2005 /* Get the operands */
2006 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2008 /* Exception occurred */
2012 /* Make sure this is the right instruction */
2013 ASSERT((Opcode
& 0xF0) == 0x90);
2015 switch ((Opcode
& 0x0F) >> 1)
2020 Value
= State
->Flags
.Of
;
2027 Value
= State
->Flags
.Cf
;
2034 Value
= State
->Flags
.Zf
;
2038 /* SETBE / SETNBE */
2041 Value
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
2048 Value
= State
->Flags
.Sf
;
2055 Value
= State
->Flags
.Pf
;
2062 Value
= State
->Flags
.Sf
!= State
->Flags
.Of
;
2066 /* SETLE / SETNLE */
2069 Value
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
2076 /* Invert the result */
2080 /* Write back the result */
2081 Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Value
);
2084 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXaddByte
)
2086 UCHAR Source
, Destination
, Result
;
2087 FAST486_MOD_REG_RM ModRegRm
;
2088 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2090 /* Make sure this is the right instruction */
2091 ASSERT(Opcode
== 0xC0);
2093 TOGGLE_ADSIZE(AddressSize
);
2095 /* Get the operands */
2096 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2098 /* Exception occurred */
2102 if (!Fast486ReadModrmByteOperands(State
,
2107 /* Exception occurred */
2111 /* Calculate the result */
2112 Result
= Source
+ Destination
;
2114 /* Update the flags */
2115 State
->Flags
.Cf
= (Result
< Source
) && (Result
< Destination
);
2116 State
->Flags
.Of
= ((Source
& SIGN_FLAG_BYTE
) == (Destination
& SIGN_FLAG_BYTE
))
2117 && ((Source
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2118 State
->Flags
.Af
= ((((Source
& 0x0F) + (Destination
& 0x0F)) & 0x10) != 0);
2119 State
->Flags
.Zf
= (Result
== 0);
2120 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2121 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2123 /* Write the sum to the destination */
2124 if (!Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Result
))
2126 /* Exception occurred */
2130 /* Write the old value of the destination to the source */
2131 Fast486WriteModrmByteOperands(State
, &ModRegRm
, TRUE
, Destination
);
2134 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXadd
)
2136 FAST486_MOD_REG_RM ModRegRm
;
2137 BOOLEAN OperandSize
, AddressSize
;
2139 /* Make sure this is the right instruction */
2140 ASSERT(Opcode
== 0xC1);
2142 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2144 TOGGLE_ADSIZE(AddressSize
);
2145 TOGGLE_OPSIZE(OperandSize
);
2147 /* Get the operands */
2148 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2150 /* Exception occurred */
2154 /* Check the operand size */
2157 ULONG Source
, Destination
, Result
;
2159 if (!Fast486ReadModrmDwordOperands(State
,
2164 /* Exception occurred */
2168 /* Calculate the result */
2169 Result
= Source
+ Destination
;
2171 /* Update the flags */
2172 State
->Flags
.Cf
= (Result
< Source
) && (Result
< Destination
);
2173 State
->Flags
.Of
= ((Source
& SIGN_FLAG_LONG
) == (Destination
& SIGN_FLAG_LONG
))
2174 && ((Source
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2175 State
->Flags
.Af
= ((((Source
& 0x0F) + (Destination
& 0x0F)) & 0x10) != 0);
2176 State
->Flags
.Zf
= (Result
== 0);
2177 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2178 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2180 /* Write the old value of the destination to the source */
2181 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, Destination
))
2183 /* Exception occurred */
2187 /* Write the sum to the destination */
2188 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
);
2192 USHORT Source
, Destination
, Result
;
2194 if (!Fast486ReadModrmWordOperands(State
,
2199 /* Exception occurred */
2203 /* Calculate the result */
2204 Result
= Source
+ Destination
;
2206 /* Update the flags */
2207 State
->Flags
.Cf
= (Result
< Source
) && (Result
< Destination
);
2208 State
->Flags
.Of
= ((Source
& SIGN_FLAG_WORD
) == (Destination
& SIGN_FLAG_WORD
))
2209 && ((Source
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2210 State
->Flags
.Af
= ((((Source
& 0x0F) + (Destination
& 0x0F)) & 0x10) != 0);
2211 State
->Flags
.Zf
= (Result
== 0);
2212 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2213 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2215 /* Write the old value of the destination to the source */
2216 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, Destination
))
2218 /* Exception occurred */
2222 /* Write the sum to the destination */
2223 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Result
);
2227 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBswap
)
2233 /* Get a pointer to the value */
2234 Pointer
= (PUCHAR
)&State
->GeneralRegs
[Opcode
& 0x07].Long
;
2236 /* Swap the byte order */
2237 SWAP(Pointer
[0], Pointer
[3]);
2238 SWAP(Pointer
[1], Pointer
[2]);
2241 FAST486_OPCODE_HANDLER(Fast486OpcodeExtended
)
2245 /* Fetch the second operation code */
2246 if (!Fast486FetchByte(State
, &SecondOpcode
))
2248 /* Exception occurred */
2252 /* Call the extended opcode handler */
2253 Fast486ExtendedHandlers
[SecondOpcode
](State
, SecondOpcode
);