2 * Fast486 386/486 CPU Emulation Library
5 * Copyright (C) 2015 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
;
325 FAST486_GDT_ENTRY GdtEntry
;
328 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
330 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
334 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
339 TOGGLE_OPSIZE(OperandSize
);
340 TOGGLE_ADSIZE(AddressSize
);
342 /* Get the operands */
343 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
345 /* Exception occurred */
354 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
356 /* Exception occurred */
360 Selector
= LOWORD(Value
);
365 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Selector
))
367 /* Exception occurred */
372 if (!Fast486ReadDescriptorEntry(State
, Selector
, &Valid
, &GdtEntry
))
374 /* Exception occurred */
380 State
->Flags
.Zf
= FALSE
;
384 /* Privilege check */
385 if (((GET_SEGMENT_RPL(Selector
) > GdtEntry
.Dpl
))
386 || (Fast486GetCurrentPrivLevel(State
) > GdtEntry
.Dpl
))
388 State
->Flags
.Zf
= FALSE
;
393 State
->Flags
.Zf
= TRUE
;
395 /* Get the access rights */
396 AccessRights
= ((PDWORD
)&GdtEntry
)[1] & 0x00F0FF00;
398 /* Return the access rights */
399 if (OperandSize
) Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, AccessRights
);
400 else Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, LOWORD(AccessRights
));
403 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLsl
)
405 BOOLEAN OperandSize
, AddressSize
;
406 FAST486_MOD_REG_RM ModRegRm
;
410 FAST486_GDT_ENTRY GdtEntry
;
412 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
414 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
418 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
423 TOGGLE_OPSIZE(OperandSize
);
424 TOGGLE_ADSIZE(AddressSize
);
426 /* Get the operands */
427 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
429 /* Exception occurred */
438 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
440 /* Exception occurred */
444 Selector
= LOWORD(Value
);
449 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Selector
))
451 /* Exception occurred */
456 if (!Fast486ReadDescriptorEntry(State
, Selector
, &Valid
, &GdtEntry
))
458 /* Exception occurred */
464 State
->Flags
.Zf
= FALSE
;
468 /* Privilege check */
469 if (((GET_SEGMENT_RPL(Selector
) > GdtEntry
.Dpl
))
470 || (Fast486GetCurrentPrivLevel(State
) > GdtEntry
.Dpl
))
472 State
->Flags
.Zf
= FALSE
;
476 /* Calculate the limit */
477 Limit
= GdtEntry
.Limit
| (GdtEntry
.LimitHigh
<< 16);
479 if (GdtEntry
.Granularity
)
486 State
->Flags
.Zf
= TRUE
;
488 /* Return the limit */
489 if (OperandSize
) Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, Limit
);
490 else Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, LOWORD(Limit
));
493 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeClts
)
497 /* The current privilege level must be zero */
498 if (Fast486GetCurrentPrivLevel(State
) != 0)
500 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
504 /* Clear the task switch bit */
505 State
->ControlRegisters
[FAST486_REG_CR0
] &= ~FAST486_CR0_TS
;
508 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreControlReg
)
510 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
511 FAST486_MOD_REG_RM ModRegRm
;
514 TOGGLE_ADSIZE(AddressSize
);
516 /* Get the operands */
517 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
519 /* Exception occurred */
523 /* The current privilege level must be zero */
524 if (Fast486GetCurrentPrivLevel(State
) != 0)
526 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
530 if ((ModRegRm
.Register
== 1) || (ModRegRm
.Register
> 3))
532 /* CR1, CR4, CR5, CR6 and CR7 don't exist */
533 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
537 if (ModRegRm
.Register
!= 0)
539 /* CR2 and CR3 and are stored in array indexes 1 and 2 */
543 /* Store the value of the control register */
544 State
->GeneralRegs
[ModRegRm
.SecondRegister
].Long
= State
->ControlRegisters
[ModRegRm
.Register
];
547 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreDebugReg
)
549 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
550 FAST486_MOD_REG_RM ModRegRm
;
553 TOGGLE_ADSIZE(AddressSize
);
555 /* Get the operands */
556 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
558 /* Exception occurred */
562 /* The current privilege level must be zero */
563 if (Fast486GetCurrentPrivLevel(State
) != 0)
565 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
569 if ((ModRegRm
.Register
== 6) || (ModRegRm
.Register
== 7))
571 /* DR6 and DR7 are aliases to DR4 and DR5 */
572 ModRegRm
.Register
-= 2;
575 if (State
->DebugRegisters
[FAST486_REG_DR5
] & FAST486_DR5_GD
)
577 /* Disallow access to debug registers */
578 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
582 /* Store the value of the debug register */
583 State
->GeneralRegs
[ModRegRm
.SecondRegister
].Long
= State
->DebugRegisters
[ModRegRm
.Register
];
586 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadControlReg
)
589 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
590 FAST486_MOD_REG_RM ModRegRm
;
593 TOGGLE_ADSIZE(AddressSize
);
595 /* Get the operands */
596 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
598 /* Exception occurred */
602 /* The current privilege level must be zero */
603 if (Fast486GetCurrentPrivLevel(State
) != 0)
605 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
609 if ((ModRegRm
.Register
== 1) || (ModRegRm
.Register
> 3))
611 /* CR1, CR4, CR5, CR6 and CR7 don't exist */
612 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
616 if (ModRegRm
.Register
!= 0)
618 /* CR2 and CR3 and are stored in array indexes 1 and 2 */
623 Value
= State
->GeneralRegs
[ModRegRm
.SecondRegister
].Long
;
625 if (ModRegRm
.Register
== (INT
)FAST486_REG_CR0
)
629 if (((Value
& (FAST486_CR0_PG
| FAST486_CR0_PE
)) == FAST486_CR0_PG
)
630 || ((Value
& (FAST486_CR0_CD
| FAST486_CR0_NW
)) == FAST486_CR0_NW
))
633 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
638 #ifndef FAST486_NO_PREFETCH
639 /* Changing CR0 or CR3 can interfere with prefetching (because of paging) */
640 State
->PrefetchValid
= FALSE
;
643 if (ModRegRm
.Register
== (INT
)FAST486_REG_CR3
)
646 Fast486FlushTlb(State
);
649 /* Load a value to the control register */
650 State
->ControlRegisters
[ModRegRm
.Register
] = Value
;
653 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadDebugReg
)
655 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
656 FAST486_MOD_REG_RM ModRegRm
;
659 TOGGLE_ADSIZE(AddressSize
);
661 /* Get the operands */
662 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
664 /* Exception occurred */
668 /* The current privilege level must be zero */
669 if (Fast486GetCurrentPrivLevel(State
) != 0)
671 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
675 if ((ModRegRm
.Register
== 6) || (ModRegRm
.Register
== 7))
677 /* DR6 and DR7 are aliases to DR4 and DR5 */
678 ModRegRm
.Register
-= 2;
681 if (State
->DebugRegisters
[FAST486_REG_DR5
] & FAST486_DR5_GD
)
683 /* Disallow access to debug registers */
684 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
688 /* Load a value to the debug register */
689 State
->DebugRegisters
[ModRegRm
.Register
] = State
->GeneralRegs
[ModRegRm
.SecondRegister
].Long
;
691 if (ModRegRm
.Register
== (INT
)FAST486_REG_DR4
)
693 /* The reserved bits are 1 */
694 State
->DebugRegisters
[ModRegRm
.Register
] |= FAST486_DR4_RESERVED
;
696 else if (ModRegRm
.Register
== (INT
)FAST486_REG_DR5
)
698 /* The reserved bits are 0 */
699 State
->DebugRegisters
[ModRegRm
.Register
] &= ~FAST486_DR5_RESERVED
;
703 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushFs
)
705 /* Call the internal API */
706 Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_FS
].Selector
);
709 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopFs
)
713 if (!Fast486StackPop(State
, &NewSelector
))
715 /* Exception occurred */
719 /* Call the internal API */
720 Fast486LoadSegment(State
, FAST486_REG_FS
, LOWORD(NewSelector
));
723 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBitTest
)
725 BOOLEAN OperandSize
, AddressSize
;
726 FAST486_MOD_REG_RM ModRegRm
;
730 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
731 TOGGLE_OPSIZE(OperandSize
);
732 TOGGLE_ADSIZE(AddressSize
);
734 /* Get the number of bits */
735 if (OperandSize
) DataSize
= 32;
738 /* Get the operands */
739 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
741 /* Exception occurred */
745 /* Get the bit number */
746 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
747 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
752 * For memory operands, add the bit offset divided by
753 * the data size to the address
755 ModRegRm
.MemoryAddress
+= (BitNumber
/ DataSize
) * (DataSize
/ 8);
758 /* Normalize the bit number */
759 BitNumber
%= DataSize
;
766 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
768 /* Exception occurred */
772 /* Set CF to the bit value */
773 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
780 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
782 /* Exception occurred */
786 /* Set CF to the bit value */
787 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
791 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShld
)
793 BOOLEAN OperandSize
, AddressSize
;
794 FAST486_MOD_REG_RM ModRegRm
;
797 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
798 TOGGLE_OPSIZE(OperandSize
);
799 TOGGLE_ADSIZE(AddressSize
);
801 /* Make sure this is the right instruction */
802 ASSERT((Opcode
& 0xFE) == 0xA4);
804 /* Get the operands */
805 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
807 /* Exception occurred */
813 /* Fetch the count */
814 if (!Fast486FetchByte(State
, &Count
))
816 /* Exception occurred */
822 /* The count is in CL */
823 Count
= State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
;
826 /* Normalize the count */
829 /* Do nothing if the count is zero */
830 if (Count
== 0) return;
834 ULONG Source
, Destination
, Result
;
836 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Source
, &Destination
))
838 /* Exception occurred */
842 /* Calculate the result */
843 Result
= (Destination
<< Count
) | (Source
>> (32 - Count
));
846 State
->Flags
.Cf
= (Destination
>> (32 - Count
)) & 1;
847 if (Count
== 1) State
->Flags
.Of
= (Result
& SIGN_FLAG_LONG
)
848 != (Destination
& SIGN_FLAG_LONG
);
849 State
->Flags
.Zf
= (Result
== 0);
850 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
851 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
853 /* Write back the result */
854 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
);
858 USHORT Source
, Destination
, Result
;
861 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Source
, &Destination
))
863 /* Exception occurred */
867 DoubleSource
= Source
| (Source
<< 16);
869 /* Calculate the result */
870 Result
= (Destination
<< Count
) | (DoubleSource
>> (32 - Count
));
873 if (Count
<= 16) State
->Flags
.Cf
= (Destination
>> (16 - Count
)) & 1;
874 else State
->Flags
.Cf
= (Source
>> (32 - Count
)) & 1;
876 if (Count
== 1) State
->Flags
.Of
= (Result
& SIGN_FLAG_WORD
)
877 != (Destination
& SIGN_FLAG_WORD
);
878 State
->Flags
.Zf
= (Result
== 0);
879 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
880 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
882 /* Write back the result */
883 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Result
);
887 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushGs
)
889 /* Call the internal API */
890 Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_GS
].Selector
);
893 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopGs
)
897 if (!Fast486StackPop(State
, &NewSelector
))
899 /* Exception occurred */
903 /* Call the internal API */
904 Fast486LoadSegment(State
, FAST486_REG_GS
, LOWORD(NewSelector
));
907 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBts
)
909 BOOLEAN OperandSize
, AddressSize
;
910 FAST486_MOD_REG_RM ModRegRm
;
914 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
915 TOGGLE_OPSIZE(OperandSize
);
916 TOGGLE_ADSIZE(AddressSize
);
918 /* Get the number of bits */
919 if (OperandSize
) DataSize
= 32;
922 /* Get the operands */
923 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
925 /* Exception occurred */
929 /* Get the bit number */
930 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
931 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
936 * For memory operands, add the bit offset divided by
937 * the data size to the address
939 ModRegRm
.MemoryAddress
+= (BitNumber
/ DataSize
) * (DataSize
/ 8);
942 /* Normalize the bit number */
943 BitNumber
%= DataSize
;
950 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
952 /* Exception occurred */
956 /* Set CF to the bit value */
957 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
960 Value
|= 1 << BitNumber
;
962 /* Write back the result */
963 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
970 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
972 /* Exception occurred */
976 /* Set CF to the bit value */
977 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
980 Value
|= 1 << BitNumber
;
982 /* Write back the result */
983 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
987 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShrd
)
989 BOOLEAN OperandSize
, AddressSize
;
990 FAST486_MOD_REG_RM ModRegRm
;
993 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
994 TOGGLE_OPSIZE(OperandSize
);
995 TOGGLE_ADSIZE(AddressSize
);
997 /* Make sure this is the right instruction */
998 ASSERT((Opcode
& 0xFE) == 0xAC);
1000 /* Get the operands */
1001 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1003 /* Exception occurred */
1009 /* Fetch the count */
1010 if (!Fast486FetchByte(State
, &Count
))
1012 /* Exception occurred */
1018 /* The count is in CL */
1019 Count
= State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
;
1022 /* Normalize the count */
1025 /* Do nothing if the count is zero */
1026 if (Count
== 0) return;
1030 ULONG Source
, Destination
, Result
;
1032 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Source
, &Destination
))
1034 /* Exception occurred */
1038 /* Calculate the result */
1039 Result
= (Destination
>> Count
) | (Source
<< (32 - Count
));
1042 State
->Flags
.Cf
= (Destination
>> (Count
- 1)) & 1;
1043 if (Count
== 1) State
->Flags
.Of
= (Result
& SIGN_FLAG_LONG
)
1044 != (Destination
& SIGN_FLAG_LONG
);
1045 State
->Flags
.Zf
= (Result
== 0);
1046 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1047 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1049 /* Write back the result */
1050 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
);
1054 USHORT Source
, Destination
, Result
;
1056 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Source
, &Destination
))
1058 /* Exception occurred */
1062 /* Calculate the result */
1063 Result
= (Destination
>> Count
) | (Source
<< (16 - Count
));
1065 if (Count
>= 16) Result
|= (ULONG
)(Source
| (Source
<< 16)) >> (Count
- 16);
1068 if (Count
<= 16) State
->Flags
.Cf
= (Destination
>> (Count
- 1)) & 1;
1069 else State
->Flags
.Cf
= (Source
>> (Count
- 17)) & 1;
1071 if (Count
== 1) State
->Flags
.Of
= (Result
& SIGN_FLAG_WORD
)
1072 != (Destination
& SIGN_FLAG_WORD
);
1073 State
->Flags
.Zf
= (Result
== 0);
1074 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1075 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1077 /* Write back the result */
1078 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Result
);
1082 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeImul
)
1084 BOOLEAN OperandSize
, AddressSize
;
1085 FAST486_MOD_REG_RM ModRegRm
;
1087 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1089 TOGGLE_OPSIZE(OperandSize
);
1090 TOGGLE_ADSIZE(AddressSize
);
1092 /* Get the operands */
1093 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1095 /* Exception occurred */
1101 LONG Source
, Destination
;
1104 /* Read the operands */
1105 if (!Fast486ReadModrmDwordOperands(State
,
1107 (PULONG
)&Destination
,
1110 /* Exception occurred */
1114 /* Calculate the result */
1115 Result
= (LONGLONG
)Source
* (LONGLONG
)Destination
;
1117 /* Update the flags */
1118 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -2147483648LL) || (Result
> 2147483647LL));
1120 /* Write back the result */
1121 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, (ULONG
)((LONG
)Result
));
1125 SHORT Source
, Destination
;
1128 /* Read the operands */
1129 if (!Fast486ReadModrmWordOperands(State
,
1131 (PUSHORT
)&Destination
,
1134 /* Exception occurred */
1138 /* Calculate the result */
1139 Result
= (LONG
)Source
* (LONG
)Destination
;
1141 /* Update the flags */
1142 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -32768) || (Result
> 32767));
1144 /* Write back the result */
1145 Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, (USHORT
)((SHORT
)Result
));
1149 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchgByte
)
1151 FAST486_MOD_REG_RM ModRegRm
;
1152 UCHAR Accumulator
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1153 UCHAR Source
, Destination
, Result
;
1154 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1156 TOGGLE_ADSIZE(AddressSize
);
1158 /* Get the operands */
1159 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1161 /* Exception occurred */
1165 /* Read the operands */
1166 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Source
, &Destination
))
1168 /* Exception occurred */
1172 /* Compare AL with the destination */
1173 Result
= Accumulator
- Destination
;
1175 /* Update the flags */
1176 State
->Flags
.Cf
= (Accumulator
< Destination
);
1177 State
->Flags
.Of
= ((Accumulator
& SIGN_FLAG_BYTE
) != (Destination
& SIGN_FLAG_BYTE
))
1178 && ((Accumulator
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1179 State
->Flags
.Af
= (Accumulator
& 0x0F) < (Destination
& 0x0F);
1180 State
->Flags
.Zf
= (Result
== 0);
1181 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1182 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1184 if (State
->Flags
.Zf
)
1186 /* Load the source operand into the destination */
1187 Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Source
);
1191 /* Load the destination into AL */
1192 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Destination
;
1196 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchg
)
1198 FAST486_MOD_REG_RM ModRegRm
;
1199 BOOLEAN OperandSize
, AddressSize
;
1201 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1203 TOGGLE_OPSIZE(OperandSize
);
1204 TOGGLE_ADSIZE(AddressSize
);
1206 /* Get the operands */
1207 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1209 /* Exception occurred */
1215 ULONG Source
, Destination
, Result
;
1216 ULONG Accumulator
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1218 /* Read the operands */
1219 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Source
, &Destination
))
1221 /* Exception occurred */
1225 /* Compare EAX with the destination */
1226 Result
= Accumulator
- Destination
;
1228 /* Update the flags */
1229 State
->Flags
.Cf
= (Accumulator
< Destination
);
1230 State
->Flags
.Of
= ((Accumulator
& SIGN_FLAG_LONG
) != (Destination
& SIGN_FLAG_LONG
))
1231 && ((Accumulator
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1232 State
->Flags
.Af
= (Accumulator
& 0x0F) < (Destination
& 0x0F);
1233 State
->Flags
.Zf
= (Result
== 0);
1234 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1235 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1237 if (State
->Flags
.Zf
)
1239 /* Load the source operand into the destination */
1240 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Source
);
1244 /* Load the destination into EAX */
1245 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Destination
;
1250 USHORT Source
, Destination
, Result
;
1251 USHORT Accumulator
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1253 /* Read the operands */
1254 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Source
, &Destination
))
1256 /* Exception occurred */
1260 /* Compare AX with the destination */
1261 Result
= Accumulator
- Destination
;
1263 /* Update the flags */
1264 State
->Flags
.Cf
= (Accumulator
< Destination
);
1265 State
->Flags
.Of
= ((Accumulator
& SIGN_FLAG_WORD
) != (Destination
& SIGN_FLAG_WORD
))
1266 && ((Accumulator
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1267 State
->Flags
.Af
= (Accumulator
& 0x0F) < (Destination
& 0x0F);
1268 State
->Flags
.Zf
= (Result
== 0);
1269 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1270 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1272 if (State
->Flags
.Zf
)
1274 /* Load the source operand into the destination */
1275 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Source
);
1279 /* Load the destination into AX */
1280 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Destination
;
1285 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLss
)
1287 UCHAR FarPointer
[6];
1288 BOOLEAN OperandSize
, AddressSize
;
1289 FAST486_MOD_REG_RM ModRegRm
;
1291 /* Make sure this is the right instruction */
1292 ASSERT(Opcode
== 0xB2);
1294 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1296 TOGGLE_OPSIZE(OperandSize
);
1297 TOGGLE_ADSIZE(AddressSize
);
1299 /* Get the operands */
1300 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1302 /* Exception occurred */
1306 if (!ModRegRm
.Memory
)
1309 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1313 if (!Fast486ReadMemory(State
,
1314 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1315 ? State
->SegmentOverride
: FAST486_REG_DS
,
1316 ModRegRm
.MemoryAddress
,
1319 OperandSize
? 6 : 4))
1321 /* Exception occurred */
1327 ULONG Offset
= *((PULONG
)FarPointer
);
1328 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
1330 /* Set the register to the offset */
1331 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
1333 /* Load the segment */
1334 Fast486LoadSegment(State
, FAST486_REG_SS
, Segment
);
1338 USHORT Offset
= *((PUSHORT
)FarPointer
);
1339 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
1341 /* Set the register to the offset */
1342 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
1344 /* Load the segment */
1345 Fast486LoadSegment(State
, FAST486_REG_SS
, Segment
);
1349 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtr
)
1351 BOOLEAN OperandSize
, AddressSize
;
1352 FAST486_MOD_REG_RM ModRegRm
;
1356 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1357 TOGGLE_OPSIZE(OperandSize
);
1358 TOGGLE_ADSIZE(AddressSize
);
1360 /* Get the number of bits */
1361 if (OperandSize
) DataSize
= 32;
1364 /* Get the operands */
1365 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1367 /* Exception occurred */
1371 /* Get the bit number */
1372 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
1373 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
1375 if (ModRegRm
.Memory
)
1378 * For memory operands, add the bit offset divided by
1379 * the data size to the address
1381 ModRegRm
.MemoryAddress
+= (BitNumber
/ DataSize
) * (DataSize
/ 8);
1384 /* Normalize the bit number */
1385 BitNumber
%= DataSize
;
1391 /* Read the value */
1392 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
1394 /* Exception occurred */
1398 /* Set CF to the bit value */
1399 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1402 Value
&= ~(1 << BitNumber
);
1404 /* Write back the result */
1405 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
1411 /* Read the value */
1412 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
1414 /* Exception occurred */
1418 /* Set CF to the bit value */
1419 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1422 Value
&= ~(1 << BitNumber
);
1424 /* Write back the result */
1425 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
1429 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLfsLgs
)
1431 UCHAR FarPointer
[6];
1432 BOOLEAN OperandSize
, AddressSize
;
1433 FAST486_MOD_REG_RM ModRegRm
;
1435 /* Make sure this is the right instruction */
1436 ASSERT((Opcode
& 0xFE) == 0xB4);
1438 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1440 TOGGLE_OPSIZE(OperandSize
);
1441 TOGGLE_ADSIZE(AddressSize
);
1443 /* Get the operands */
1444 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1446 /* Exception occurred */
1450 if (!ModRegRm
.Memory
)
1453 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1457 if (!Fast486ReadMemory(State
,
1458 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1459 ? State
->SegmentOverride
: FAST486_REG_DS
,
1460 ModRegRm
.MemoryAddress
,
1463 OperandSize
? 6 : 4))
1465 /* Exception occurred */
1471 ULONG Offset
= *((PULONG
)FarPointer
);
1472 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
1474 /* Set the register to the offset */
1475 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
1477 /* Load the segment */
1478 Fast486LoadSegment(State
,
1480 ? FAST486_REG_FS
: FAST486_REG_GS
,
1485 USHORT Offset
= *((PUSHORT
)FarPointer
);
1486 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
1488 /* Set the register to the offset */
1489 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
1491 /* Load the segment */
1492 Fast486LoadSegment(State
,
1494 ? FAST486_REG_FS
: FAST486_REG_GS
,
1499 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxByte
)
1502 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1503 FAST486_MOD_REG_RM ModRegRm
;
1505 TOGGLE_ADSIZE(AddressSize
);
1507 /* Make sure this is the right instruction */
1508 ASSERT(Opcode
== 0xB6);
1510 /* Get the operands */
1511 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1513 /* Exception occurred */
1517 /* Read the operands */
1518 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, NULL
, &Value
))
1520 /* Exception occurred */
1524 /* Write back the zero-extended value */
1525 Fast486WriteModrmDwordOperands(State
,
1531 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxWord
)
1534 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1535 FAST486_MOD_REG_RM ModRegRm
;
1537 TOGGLE_ADSIZE(AddressSize
);
1539 /* Make sure this is the right instruction */
1540 ASSERT(Opcode
== 0xB7);
1542 /* Get the operands */
1543 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1545 /* Exception occurred */
1549 /* Read the operands */
1550 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
1552 /* Exception occurred */
1556 /* Write back the zero-extended value */
1557 Fast486WriteModrmDwordOperands(State
,
1563 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtc
)
1565 BOOLEAN OperandSize
, AddressSize
;
1566 FAST486_MOD_REG_RM ModRegRm
;
1570 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1571 TOGGLE_OPSIZE(OperandSize
);
1572 TOGGLE_ADSIZE(AddressSize
);
1574 /* Get the number of bits */
1575 if (OperandSize
) DataSize
= 32;
1578 /* Get the operands */
1579 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1581 /* Exception occurred */
1585 /* Get the bit number */
1586 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
1587 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
1589 if (ModRegRm
.Memory
)
1592 * For memory operands, add the bit offset divided by
1593 * the data size to the address
1595 ModRegRm
.MemoryAddress
+= (BitNumber
/ DataSize
) * (DataSize
/ 8);
1598 /* Normalize the bit number */
1599 BitNumber
%= DataSize
;
1605 /* Read the value */
1606 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
1608 /* Exception occurred */
1612 /* Set CF to the bit value */
1613 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1615 /* Toggle the bit */
1616 Value
^= 1 << BitNumber
;
1618 /* Write back the result */
1619 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
1625 /* Read the value */
1626 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
1628 /* Exception occurred */
1632 /* Set CF to the bit value */
1633 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1635 /* Toggle the bit */
1636 Value
^= 1 << BitNumber
;
1638 /* Write back the result */
1639 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
1643 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsf
)
1647 BOOLEAN OperandSize
, AddressSize
;
1648 FAST486_MOD_REG_RM ModRegRm
;
1652 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1653 TOGGLE_OPSIZE(OperandSize
);
1654 TOGGLE_ADSIZE(AddressSize
);
1656 /* Make sure this is the right instruction */
1657 ASSERT(Opcode
== 0xBC);
1659 /* Get the number of bits */
1660 if (OperandSize
) DataSize
= 32;
1663 /* Get the operands */
1664 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1666 /* Exception occurred */
1670 /* Read the value */
1673 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
1675 /* Exception occurred */
1681 if (!Fast486ReadModrmWordOperands(State
,
1686 /* Exception occurred */
1692 State
->Flags
.Zf
= (Value
== 0);
1693 if (State
->Flags
.Zf
) return;
1695 for (i
= 0; i
< DataSize
; i
++)
1697 if (Value
& (1 << i
))
1699 /* Save the bit number */
1707 /* Write back the result */
1708 if (OperandSize
) Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, BitNumber
);
1709 else Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, LOWORD(BitNumber
));
1712 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsr
)
1716 BOOLEAN OperandSize
, AddressSize
;
1717 FAST486_MOD_REG_RM ModRegRm
;
1721 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1722 TOGGLE_OPSIZE(OperandSize
);
1723 TOGGLE_ADSIZE(AddressSize
);
1725 /* Make sure this is the right instruction */
1726 ASSERT(Opcode
== 0xBD);
1728 /* Get the number of bits */
1729 if (OperandSize
) DataSize
= 32;
1732 /* Get the operands */
1733 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1735 /* Exception occurred */
1739 /* Read the value */
1742 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
1744 /* Exception occurred */
1750 if (!Fast486ReadModrmWordOperands(State
,
1755 /* Exception occurred */
1760 /* Set ZF according to the value */
1761 State
->Flags
.Zf
= (Value
== 0);
1762 if (State
->Flags
.Zf
) return;
1764 for (i
= DataSize
- 1; i
>= 0; i
--)
1766 if (Value
& (1 << i
))
1768 /* Save the bit number */
1776 /* Write back the result */
1777 if (OperandSize
) Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, BitNumber
);
1778 else Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, LOWORD(BitNumber
));
1781 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxByte
)
1784 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1785 FAST486_MOD_REG_RM ModRegRm
;
1787 TOGGLE_ADSIZE(AddressSize
);
1789 /* Make sure this is the right instruction */
1790 ASSERT(Opcode
== 0xBE);
1792 /* Get the operands */
1793 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1795 /* Exception occurred */
1799 /* Read the operands */
1800 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, NULL
, (PUCHAR
)&Value
))
1802 /* Exception occurred */
1806 /* Write back the sign-extended value */
1807 Fast486WriteModrmDwordOperands(State
,
1810 (ULONG
)((LONG
)Value
));
1813 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxWord
)
1816 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1817 FAST486_MOD_REG_RM ModRegRm
;
1819 TOGGLE_ADSIZE(AddressSize
);
1821 /* Make sure this is the right instruction */
1822 ASSERT(Opcode
== 0xBF);
1824 /* Get the operands */
1825 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1827 /* Exception occurred */
1831 /* Read the operands */
1832 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, (PUSHORT
)&Value
))
1834 /* Exception occurred */
1838 /* Write back the sign-extended value */
1839 Fast486WriteModrmDwordOperands(State
,
1842 (ULONG
)((LONG
)Value
));
1845 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalJmp
)
1847 BOOLEAN Jump
= FALSE
;
1849 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1851 TOGGLE_OPSIZE(Size
);
1854 /* Make sure this is the right instruction */
1855 ASSERT((Opcode
& 0xF0) == 0x80);
1857 /* Fetch the offset */
1860 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
1862 /* Exception occurred */
1870 if (!Fast486FetchWord(State
, (PUSHORT
)&Value
))
1872 /* Exception occurred */
1877 Offset
= (LONG
)Value
;
1880 switch ((Opcode
& 0x0F) >> 1)
1885 Jump
= State
->Flags
.Of
;
1892 Jump
= State
->Flags
.Cf
;
1899 Jump
= State
->Flags
.Zf
;
1906 Jump
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
1913 Jump
= State
->Flags
.Sf
;
1920 Jump
= State
->Flags
.Pf
;
1927 Jump
= State
->Flags
.Sf
!= State
->Flags
.Of
;
1934 Jump
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
1941 /* Invert the result */
1947 /* Move the instruction pointer */
1948 State
->InstPtr
.Long
+= Offset
;
1952 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalSet
)
1954 BOOLEAN Value
= FALSE
;
1955 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1956 FAST486_MOD_REG_RM ModRegRm
;
1958 TOGGLE_ADSIZE(AddressSize
);
1960 /* Get the operands */
1961 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1963 /* Exception occurred */
1967 /* Make sure this is the right instruction */
1968 ASSERT((Opcode
& 0xF0) == 0x90);
1970 switch ((Opcode
& 0x0F) >> 1)
1975 Value
= State
->Flags
.Of
;
1982 Value
= State
->Flags
.Cf
;
1989 Value
= State
->Flags
.Zf
;
1993 /* SETBE / SETNBE */
1996 Value
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
2003 Value
= State
->Flags
.Sf
;
2010 Value
= State
->Flags
.Pf
;
2017 Value
= State
->Flags
.Sf
!= State
->Flags
.Of
;
2021 /* SETLE / SETNLE */
2024 Value
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
2031 /* Invert the result */
2035 /* Write back the result */
2036 Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Value
);
2039 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXaddByte
)
2041 UCHAR Source
, Destination
, Result
;
2042 FAST486_MOD_REG_RM ModRegRm
;
2043 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2045 /* Make sure this is the right instruction */
2046 ASSERT(Opcode
== 0xC0);
2048 TOGGLE_ADSIZE(AddressSize
);
2050 /* Get the operands */
2051 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2053 /* Exception occurred */
2057 if (!Fast486ReadModrmByteOperands(State
,
2062 /* Exception occurred */
2066 /* Calculate the result */
2067 Result
= Source
+ Destination
;
2069 /* Update the flags */
2070 State
->Flags
.Cf
= (Result
< Source
) && (Result
< Destination
);
2071 State
->Flags
.Of
= ((Source
& SIGN_FLAG_BYTE
) == (Destination
& SIGN_FLAG_BYTE
))
2072 && ((Source
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2073 State
->Flags
.Af
= ((((Source
& 0x0F) + (Destination
& 0x0F)) & 0x10) != 0);
2074 State
->Flags
.Zf
= (Result
== 0);
2075 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2076 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2078 /* Write the sum to the destination */
2079 if (!Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Result
))
2081 /* Exception occurred */
2085 /* Write the old value of the destination to the source */
2086 Fast486WriteModrmByteOperands(State
, &ModRegRm
, TRUE
, Destination
);
2089 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXadd
)
2091 FAST486_MOD_REG_RM ModRegRm
;
2092 BOOLEAN OperandSize
, AddressSize
;
2094 /* Make sure this is the right instruction */
2095 ASSERT(Opcode
== 0xC1);
2097 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2099 TOGGLE_ADSIZE(AddressSize
);
2100 TOGGLE_OPSIZE(OperandSize
);
2102 /* Get the operands */
2103 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2105 /* Exception occurred */
2109 /* Check the operand size */
2112 ULONG Source
, Destination
, Result
;
2114 if (!Fast486ReadModrmDwordOperands(State
,
2119 /* Exception occurred */
2123 /* Calculate the result */
2124 Result
= Source
+ Destination
;
2126 /* Update the flags */
2127 State
->Flags
.Cf
= (Result
< Source
) && (Result
< Destination
);
2128 State
->Flags
.Of
= ((Source
& SIGN_FLAG_LONG
) == (Destination
& SIGN_FLAG_LONG
))
2129 && ((Source
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2130 State
->Flags
.Af
= ((((Source
& 0x0F) + (Destination
& 0x0F)) & 0x10) != 0);
2131 State
->Flags
.Zf
= (Result
== 0);
2132 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2133 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2135 /* Write the old value of the destination to the source */
2136 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, Destination
))
2138 /* Exception occurred */
2142 /* Write the sum to the destination */
2143 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
);
2147 USHORT Source
, Destination
, Result
;
2149 if (!Fast486ReadModrmWordOperands(State
,
2154 /* Exception occurred */
2158 /* Calculate the result */
2159 Result
= Source
+ Destination
;
2161 /* Update the flags */
2162 State
->Flags
.Cf
= (Result
< Source
) && (Result
< Destination
);
2163 State
->Flags
.Of
= ((Source
& SIGN_FLAG_WORD
) == (Destination
& SIGN_FLAG_WORD
))
2164 && ((Source
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2165 State
->Flags
.Af
= ((((Source
& 0x0F) + (Destination
& 0x0F)) & 0x10) != 0);
2166 State
->Flags
.Zf
= (Result
== 0);
2167 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2168 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2170 /* Write the old value of the destination to the source */
2171 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, Destination
))
2173 /* Exception occurred */
2177 /* Write the sum to the destination */
2178 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Result
);
2182 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBswap
)
2188 /* Get a pointer to the value */
2189 Pointer
= (PUCHAR
)&State
->GeneralRegs
[Opcode
& 0x07].Long
;
2191 /* Swap the byte order */
2192 SWAP(Pointer
[0], Pointer
[3]);
2193 SWAP(Pointer
[1], Pointer
[2]);
2196 FAST486_OPCODE_HANDLER(Fast486OpcodeExtended
)
2200 /* Fetch the second operation code */
2201 if (!Fast486FetchByte(State
, &SecondOpcode
))
2203 /* Exception occurred */
2207 /* Call the extended opcode handler */
2208 Fast486ExtendedHandlers
[SecondOpcode
](State
, SecondOpcode
);