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
;
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);
478 if (GdtEntry
.Granularity
) Limit
<<= 12;
481 State
->Flags
.Zf
= TRUE
;
483 /* Return the limit */
484 if (OperandSize
) Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, Limit
);
485 else Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, LOWORD(Limit
));
488 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeClts
)
492 /* The current privilege level must be zero */
493 if (Fast486GetCurrentPrivLevel(State
) != 0)
495 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
499 /* Clear the task switch bit */
500 State
->ControlRegisters
[FAST486_REG_CR0
] &= ~FAST486_CR0_TS
;
503 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreControlReg
)
505 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
506 FAST486_MOD_REG_RM ModRegRm
;
509 TOGGLE_ADSIZE(AddressSize
);
511 /* Get the operands */
512 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
514 /* Exception occurred */
518 /* The current privilege level must be zero */
519 if (Fast486GetCurrentPrivLevel(State
) != 0)
521 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
525 if ((ModRegRm
.Register
== 1) || (ModRegRm
.Register
> 3))
527 /* CR1, CR4, CR5, CR6 and CR7 don't exist */
528 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
532 if (ModRegRm
.Register
!= 0)
534 /* CR2 and CR3 and are stored in array indexes 1 and 2 */
538 /* Store the value of the control register */
539 State
->GeneralRegs
[ModRegRm
.SecondRegister
].Long
= State
->ControlRegisters
[ModRegRm
.Register
];
542 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreDebugReg
)
544 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
545 FAST486_MOD_REG_RM ModRegRm
;
548 TOGGLE_ADSIZE(AddressSize
);
550 /* Get the operands */
551 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
553 /* Exception occurred */
557 /* The current privilege level must be zero */
558 if (Fast486GetCurrentPrivLevel(State
) != 0)
560 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
564 if ((ModRegRm
.Register
== 6) || (ModRegRm
.Register
== 7))
566 /* DR6 and DR7 are aliases to DR4 and DR5 */
567 ModRegRm
.Register
-= 2;
570 if (State
->DebugRegisters
[FAST486_REG_DR5
] & FAST486_DR5_GD
)
572 /* Disallow access to debug registers */
573 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
577 /* Store the value of the debug register */
578 State
->GeneralRegs
[ModRegRm
.SecondRegister
].Long
= State
->DebugRegisters
[ModRegRm
.Register
];
581 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadControlReg
)
584 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
585 FAST486_MOD_REG_RM ModRegRm
;
588 TOGGLE_ADSIZE(AddressSize
);
590 /* Get the operands */
591 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
593 /* Exception occurred */
597 /* The current privilege level must be zero */
598 if (Fast486GetCurrentPrivLevel(State
) != 0)
600 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
604 if ((ModRegRm
.Register
== 1) || (ModRegRm
.Register
> 3))
606 /* CR1, CR4, CR5, CR6 and CR7 don't exist */
607 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
611 if (ModRegRm
.Register
!= 0)
613 /* CR2 and CR3 and are stored in array indexes 1 and 2 */
618 Value
= State
->GeneralRegs
[ModRegRm
.SecondRegister
].Long
;
620 if (ModRegRm
.Register
== (INT
)FAST486_REG_CR0
)
624 if (((Value
& (FAST486_CR0_PG
| FAST486_CR0_PE
)) == FAST486_CR0_PG
)
625 || ((Value
& (FAST486_CR0_CD
| FAST486_CR0_NW
)) == FAST486_CR0_NW
))
628 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
633 #ifndef FAST486_NO_PREFETCH
634 /* Changing CR0 or CR3 can interfere with prefetching (because of paging) */
635 State
->PrefetchValid
= FALSE
;
638 if (State
->Tlb
&& (ModRegRm
.Register
== (INT
)FAST486_REG_CR3
))
641 RtlZeroMemory(State
->Tlb
, NUM_TLB_ENTRIES
* sizeof(ULONG
));
644 /* Load a value to the control register */
645 State
->ControlRegisters
[ModRegRm
.Register
] = Value
;
648 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadDebugReg
)
650 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
651 FAST486_MOD_REG_RM ModRegRm
;
654 TOGGLE_ADSIZE(AddressSize
);
656 /* Get the operands */
657 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
659 /* Exception occurred */
663 /* The current privilege level must be zero */
664 if (Fast486GetCurrentPrivLevel(State
) != 0)
666 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
670 if ((ModRegRm
.Register
== 6) || (ModRegRm
.Register
== 7))
672 /* DR6 and DR7 are aliases to DR4 and DR5 */
673 ModRegRm
.Register
-= 2;
676 if (State
->DebugRegisters
[FAST486_REG_DR5
] & FAST486_DR5_GD
)
678 /* Disallow access to debug registers */
679 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
683 /* Load a value to the debug register */
684 State
->DebugRegisters
[ModRegRm
.Register
] = State
->GeneralRegs
[ModRegRm
.SecondRegister
].Long
;
686 if (ModRegRm
.Register
== (INT
)FAST486_REG_DR4
)
688 /* The reserved bits are 1 */
689 State
->DebugRegisters
[ModRegRm
.Register
] |= FAST486_DR4_RESERVED
;
691 else if (ModRegRm
.Register
== (INT
)FAST486_REG_DR5
)
693 /* The reserved bits are 0 */
694 State
->DebugRegisters
[ModRegRm
.Register
] &= ~FAST486_DR5_RESERVED
;
698 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushFs
)
700 /* Call the internal API */
701 Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_FS
].Selector
);
704 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopFs
)
708 if (!Fast486StackPop(State
, &NewSelector
))
710 /* Exception occurred */
714 /* Call the internal API */
715 Fast486LoadSegment(State
, FAST486_REG_FS
, LOWORD(NewSelector
));
718 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBitTest
)
720 BOOLEAN OperandSize
, AddressSize
;
721 FAST486_MOD_REG_RM ModRegRm
;
725 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
726 TOGGLE_OPSIZE(OperandSize
);
727 TOGGLE_ADSIZE(AddressSize
);
729 /* Get the number of bits */
730 if (OperandSize
) DataSize
= 32;
733 /* Get the operands */
734 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
736 /* Exception occurred */
740 /* Get the bit number */
741 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
742 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
747 * For memory operands, add the bit offset divided by
748 * the data size to the address
750 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
753 /* Normalize the bit number */
754 BitNumber
%= DataSize
;
761 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
763 /* Exception occurred */
767 /* Set CF to the bit value */
768 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
775 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
777 /* Exception occurred */
781 /* Set CF to the bit value */
782 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
786 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShld
)
788 BOOLEAN OperandSize
, AddressSize
;
789 FAST486_MOD_REG_RM ModRegRm
;
792 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
793 TOGGLE_OPSIZE(OperandSize
);
794 TOGGLE_ADSIZE(AddressSize
);
796 /* Make sure this is the right instruction */
797 ASSERT((Opcode
& 0xFE) == 0xA4);
799 /* Get the operands */
800 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
802 /* Exception occurred */
808 /* Fetch the count */
809 if (!Fast486FetchByte(State
, &Count
))
811 /* Exception occurred */
817 /* The count is in CL */
818 Count
= State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
;
821 /* Normalize the count */
824 /* Do nothing if the count is zero */
825 if (Count
== 0) return;
829 ULONG Source
, Destination
, Result
;
831 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Source
, &Destination
))
833 /* Exception occurred */
837 /* Calculate the result */
838 Result
= (Destination
<< Count
) | (Source
>> (32 - Count
));
841 State
->Flags
.Cf
= (Destination
>> (32 - Count
)) & 1;
842 if (Count
== 1) State
->Flags
.Of
= (Result
& SIGN_FLAG_LONG
)
843 != (Destination
& SIGN_FLAG_LONG
);
844 State
->Flags
.Zf
= (Result
== 0);
845 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
846 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
848 /* Write back the result */
849 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
);
853 USHORT Source
, Destination
, Result
;
856 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Source
, &Destination
))
858 /* Exception occurred */
862 DoubleSource
= Source
| (Source
<< 16);
864 /* Calculate the result */
865 Result
= (Destination
<< Count
) | (DoubleSource
>> (32 - Count
));
868 if (Count
<= 16) State
->Flags
.Cf
= (Destination
>> (16 - Count
)) & 1;
869 else State
->Flags
.Cf
= (Source
>> (32 - Count
)) & 1;
871 if (Count
== 1) State
->Flags
.Of
= (Result
& SIGN_FLAG_WORD
)
872 != (Destination
& SIGN_FLAG_WORD
);
873 State
->Flags
.Zf
= (Result
== 0);
874 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
875 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
877 /* Write back the result */
878 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Result
);
882 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushGs
)
884 /* Call the internal API */
885 Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_GS
].Selector
);
888 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopGs
)
892 if (!Fast486StackPop(State
, &NewSelector
))
894 /* Exception occurred */
898 /* Call the internal API */
899 Fast486LoadSegment(State
, FAST486_REG_GS
, LOWORD(NewSelector
));
902 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBts
)
904 BOOLEAN OperandSize
, AddressSize
;
905 FAST486_MOD_REG_RM ModRegRm
;
909 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
910 TOGGLE_OPSIZE(OperandSize
);
911 TOGGLE_ADSIZE(AddressSize
);
913 /* Get the number of bits */
914 if (OperandSize
) DataSize
= 32;
917 /* Get the operands */
918 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
920 /* Exception occurred */
924 /* Get the bit number */
925 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
926 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
931 * For memory operands, add the bit offset divided by
932 * the data size to the address
934 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
937 /* Normalize the bit number */
938 BitNumber
%= DataSize
;
945 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
947 /* Exception occurred */
951 /* Set CF to the bit value */
952 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
955 Value
|= 1 << BitNumber
;
957 /* Write back the result */
958 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
965 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
967 /* Exception occurred */
971 /* Set CF to the bit value */
972 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
975 Value
|= 1 << BitNumber
;
977 /* Write back the result */
978 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
982 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShrd
)
984 BOOLEAN OperandSize
, AddressSize
;
985 FAST486_MOD_REG_RM ModRegRm
;
988 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
989 TOGGLE_OPSIZE(OperandSize
);
990 TOGGLE_ADSIZE(AddressSize
);
992 /* Make sure this is the right instruction */
993 ASSERT((Opcode
& 0xFE) == 0xAC);
995 /* Get the operands */
996 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
998 /* Exception occurred */
1004 /* Fetch the count */
1005 if (!Fast486FetchByte(State
, &Count
))
1007 /* Exception occurred */
1013 /* The count is in CL */
1014 Count
= State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
;
1017 /* Normalize the count */
1020 /* Do nothing if the count is zero */
1021 if (Count
== 0) return;
1025 ULONG Source
, Destination
, Result
;
1027 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Source
, &Destination
))
1029 /* Exception occurred */
1033 /* Calculate the result */
1034 Result
= (Destination
>> Count
) | (Source
<< (32 - Count
));
1037 State
->Flags
.Cf
= (Destination
>> (Count
- 1)) & 1;
1038 if (Count
== 1) State
->Flags
.Of
= (Result
& SIGN_FLAG_LONG
)
1039 != (Destination
& SIGN_FLAG_LONG
);
1040 State
->Flags
.Zf
= (Result
== 0);
1041 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1042 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1044 /* Write back the result */
1045 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
);
1049 USHORT Source
, Destination
, Result
;
1051 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Source
, &Destination
))
1053 /* Exception occurred */
1057 /* Calculate the result */
1058 Result
= (Destination
>> Count
) | (Source
<< (16 - Count
));
1060 if (Count
>= 16) Result
|= (ULONG
)(Source
| (Source
<< 16)) >> (Count
- 16);
1063 if (Count
<= 16) State
->Flags
.Cf
= (Destination
>> (Count
- 1)) & 1;
1064 else State
->Flags
.Cf
= (Source
>> (Count
- 17)) & 1;
1066 if (Count
== 1) State
->Flags
.Of
= (Result
& SIGN_FLAG_WORD
)
1067 != (Destination
& SIGN_FLAG_WORD
);
1068 State
->Flags
.Zf
= (Result
== 0);
1069 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1070 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1072 /* Write back the result */
1073 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Result
);
1077 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeImul
)
1079 BOOLEAN OperandSize
, AddressSize
;
1080 FAST486_MOD_REG_RM ModRegRm
;
1082 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1084 TOGGLE_OPSIZE(OperandSize
);
1085 TOGGLE_ADSIZE(AddressSize
);
1087 /* Get the operands */
1088 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1090 /* Exception occurred */
1096 LONG Source
, Destination
;
1099 /* Read the operands */
1100 if (!Fast486ReadModrmDwordOperands(State
,
1102 (PULONG
)&Destination
,
1105 /* Exception occurred */
1109 /* Calculate the result */
1110 Result
= (LONGLONG
)Source
* (LONGLONG
)Destination
;
1112 /* Update the flags */
1113 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -2147483648LL) || (Result
> 2147483647LL));
1115 /* Write back the result */
1116 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, (ULONG
)((LONG
)Result
));
1120 SHORT Source
, Destination
;
1123 /* Read the operands */
1124 if (!Fast486ReadModrmWordOperands(State
,
1126 (PUSHORT
)&Destination
,
1129 /* Exception occurred */
1133 /* Calculate the result */
1134 Result
= (LONG
)Source
* (LONG
)Destination
;
1136 /* Update the flags */
1137 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -32768) || (Result
> 32767));
1139 /* Write back the result */
1140 Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, (USHORT
)((SHORT
)Result
));
1144 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchgByte
)
1146 FAST486_MOD_REG_RM ModRegRm
;
1147 UCHAR Accumulator
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1148 UCHAR Source
, Destination
, Result
;
1149 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1151 TOGGLE_ADSIZE(AddressSize
);
1153 /* Get the operands */
1154 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1156 /* Exception occurred */
1160 /* Read the operands */
1161 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Source
, &Destination
))
1163 /* Exception occurred */
1167 /* Compare AL with the destination */
1168 Result
= Accumulator
- Destination
;
1170 /* Update the flags */
1171 State
->Flags
.Cf
= (Accumulator
< Destination
);
1172 State
->Flags
.Of
= ((Accumulator
& SIGN_FLAG_BYTE
) != (Destination
& SIGN_FLAG_BYTE
))
1173 && ((Accumulator
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1174 State
->Flags
.Af
= (Accumulator
& 0x0F) < (Destination
& 0x0F);
1175 State
->Flags
.Zf
= (Result
== 0);
1176 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1177 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1179 if (State
->Flags
.Zf
)
1181 /* Load the source operand into the destination */
1182 Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Source
);
1186 /* Load the destination into AL */
1187 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Destination
;
1191 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchg
)
1193 FAST486_MOD_REG_RM ModRegRm
;
1194 BOOLEAN OperandSize
, AddressSize
;
1196 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1198 TOGGLE_OPSIZE(OperandSize
);
1199 TOGGLE_ADSIZE(AddressSize
);
1201 /* Get the operands */
1202 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1204 /* Exception occurred */
1210 ULONG Source
, Destination
, Result
;
1211 ULONG Accumulator
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1213 /* Read the operands */
1214 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Source
, &Destination
))
1216 /* Exception occurred */
1220 /* Compare EAX with the destination */
1221 Result
= Accumulator
- Destination
;
1223 /* Update the flags */
1224 State
->Flags
.Cf
= (Accumulator
< Destination
);
1225 State
->Flags
.Of
= ((Accumulator
& SIGN_FLAG_LONG
) != (Destination
& SIGN_FLAG_LONG
))
1226 && ((Accumulator
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1227 State
->Flags
.Af
= (Accumulator
& 0x0F) < (Destination
& 0x0F);
1228 State
->Flags
.Zf
= (Result
== 0);
1229 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1230 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1232 if (State
->Flags
.Zf
)
1234 /* Load the source operand into the destination */
1235 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Source
);
1239 /* Load the destination into EAX */
1240 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Destination
;
1245 USHORT Source
, Destination
, Result
;
1246 USHORT Accumulator
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1248 /* Read the operands */
1249 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Source
, &Destination
))
1251 /* Exception occurred */
1255 /* Compare AX with the destination */
1256 Result
= Accumulator
- Destination
;
1258 /* Update the flags */
1259 State
->Flags
.Cf
= (Accumulator
< Destination
);
1260 State
->Flags
.Of
= ((Accumulator
& SIGN_FLAG_WORD
) != (Destination
& SIGN_FLAG_WORD
))
1261 && ((Accumulator
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1262 State
->Flags
.Af
= (Accumulator
& 0x0F) < (Destination
& 0x0F);
1263 State
->Flags
.Zf
= (Result
== 0);
1264 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1265 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1267 if (State
->Flags
.Zf
)
1269 /* Load the source operand into the destination */
1270 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Source
);
1274 /* Load the destination into AX */
1275 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Destination
;
1280 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLss
)
1282 UCHAR FarPointer
[6];
1283 BOOLEAN OperandSize
, AddressSize
;
1284 FAST486_MOD_REG_RM ModRegRm
;
1286 /* Make sure this is the right instruction */
1287 ASSERT(Opcode
== 0xB2);
1289 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1291 TOGGLE_OPSIZE(OperandSize
);
1292 TOGGLE_ADSIZE(AddressSize
);
1294 /* Get the operands */
1295 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1297 /* Exception occurred */
1301 if (!ModRegRm
.Memory
)
1304 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1308 if (!Fast486ReadMemory(State
,
1309 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1310 ? State
->SegmentOverride
: FAST486_REG_DS
,
1311 ModRegRm
.MemoryAddress
,
1314 OperandSize
? 6 : 4))
1316 /* Exception occurred */
1322 ULONG Offset
= *((PULONG
)FarPointer
);
1323 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
1325 /* Set the register to the offset */
1326 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
1328 /* Load the segment */
1329 Fast486LoadSegment(State
, FAST486_REG_SS
, Segment
);
1333 USHORT Offset
= *((PUSHORT
)FarPointer
);
1334 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
1336 /* Set the register to the offset */
1337 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
1339 /* Load the segment */
1340 Fast486LoadSegment(State
, FAST486_REG_SS
, Segment
);
1344 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtr
)
1346 BOOLEAN OperandSize
, AddressSize
;
1347 FAST486_MOD_REG_RM ModRegRm
;
1351 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1352 TOGGLE_OPSIZE(OperandSize
);
1353 TOGGLE_ADSIZE(AddressSize
);
1355 /* Get the number of bits */
1356 if (OperandSize
) DataSize
= 32;
1359 /* Get the operands */
1360 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1362 /* Exception occurred */
1366 /* Get the bit number */
1367 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
1368 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
1370 if (ModRegRm
.Memory
)
1373 * For memory operands, add the bit offset divided by
1374 * the data size to the address
1376 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
1379 /* Normalize the bit number */
1380 BitNumber
%= DataSize
;
1386 /* Read the value */
1387 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
1389 /* Exception occurred */
1393 /* Set CF to the bit value */
1394 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1397 Value
&= ~(1 << BitNumber
);
1399 /* Write back the result */
1400 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
1406 /* Read the value */
1407 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
1409 /* Exception occurred */
1413 /* Set CF to the bit value */
1414 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1417 Value
&= ~(1 << BitNumber
);
1419 /* Write back the result */
1420 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
1424 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLfsLgs
)
1426 UCHAR FarPointer
[6];
1427 BOOLEAN OperandSize
, AddressSize
;
1428 FAST486_MOD_REG_RM ModRegRm
;
1430 /* Make sure this is the right instruction */
1431 ASSERT((Opcode
& 0xFE) == 0xB4);
1433 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1435 TOGGLE_OPSIZE(OperandSize
);
1436 TOGGLE_ADSIZE(AddressSize
);
1438 /* Get the operands */
1439 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1441 /* Exception occurred */
1445 if (!ModRegRm
.Memory
)
1448 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1452 if (!Fast486ReadMemory(State
,
1453 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1454 ? State
->SegmentOverride
: FAST486_REG_DS
,
1455 ModRegRm
.MemoryAddress
,
1458 OperandSize
? 6 : 4))
1460 /* Exception occurred */
1466 ULONG Offset
= *((PULONG
)FarPointer
);
1467 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
1469 /* Set the register to the offset */
1470 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
1472 /* Load the segment */
1473 Fast486LoadSegment(State
,
1475 ? FAST486_REG_FS
: FAST486_REG_GS
,
1480 USHORT Offset
= *((PUSHORT
)FarPointer
);
1481 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
1483 /* Set the register to the offset */
1484 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
1486 /* Load the segment */
1487 Fast486LoadSegment(State
,
1489 ? FAST486_REG_FS
: FAST486_REG_GS
,
1494 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxByte
)
1497 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1498 FAST486_MOD_REG_RM ModRegRm
;
1500 TOGGLE_ADSIZE(AddressSize
);
1502 /* Make sure this is the right instruction */
1503 ASSERT(Opcode
== 0xB6);
1505 /* Get the operands */
1506 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1508 /* Exception occurred */
1512 /* Read the operands */
1513 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, NULL
, &Value
))
1515 /* Exception occurred */
1519 /* Write back the zero-extended value */
1520 Fast486WriteModrmDwordOperands(State
,
1526 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxWord
)
1529 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1530 FAST486_MOD_REG_RM ModRegRm
;
1532 TOGGLE_ADSIZE(AddressSize
);
1534 /* Make sure this is the right instruction */
1535 ASSERT(Opcode
== 0xB7);
1537 /* Get the operands */
1538 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1540 /* Exception occurred */
1544 /* Read the operands */
1545 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
1547 /* Exception occurred */
1551 /* Write back the zero-extended value */
1552 Fast486WriteModrmDwordOperands(State
,
1558 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtc
)
1560 BOOLEAN OperandSize
, AddressSize
;
1561 FAST486_MOD_REG_RM ModRegRm
;
1565 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1566 TOGGLE_OPSIZE(OperandSize
);
1567 TOGGLE_ADSIZE(AddressSize
);
1569 /* Get the number of bits */
1570 if (OperandSize
) DataSize
= 32;
1573 /* Get the operands */
1574 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1576 /* Exception occurred */
1580 /* Get the bit number */
1581 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
1582 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
1584 if (ModRegRm
.Memory
)
1587 * For memory operands, add the bit offset divided by
1588 * the data size to the address
1590 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
1593 /* Normalize the bit number */
1594 BitNumber
%= DataSize
;
1600 /* Read the value */
1601 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
1603 /* Exception occurred */
1607 /* Set CF to the bit value */
1608 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1610 /* Toggle the bit */
1611 Value
^= 1 << BitNumber
;
1613 /* Write back the result */
1614 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
1620 /* Read the value */
1621 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
1623 /* Exception occurred */
1627 /* Set CF to the bit value */
1628 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1630 /* Toggle the bit */
1631 Value
^= 1 << BitNumber
;
1633 /* Write back the result */
1634 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
1638 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsf
)
1642 BOOLEAN OperandSize
, AddressSize
;
1643 FAST486_MOD_REG_RM ModRegRm
;
1647 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1648 TOGGLE_OPSIZE(OperandSize
);
1649 TOGGLE_ADSIZE(AddressSize
);
1651 /* Make sure this is the right instruction */
1652 ASSERT(Opcode
== 0xBC);
1654 /* Get the number of bits */
1655 if (OperandSize
) DataSize
= 32;
1658 /* Get the operands */
1659 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1661 /* Exception occurred */
1665 /* Read the value */
1668 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
1670 /* Exception occurred */
1676 if (!Fast486ReadModrmWordOperands(State
,
1681 /* Exception occurred */
1687 State
->Flags
.Zf
= (Value
== 0);
1688 if (State
->Flags
.Zf
) return;
1690 for (i
= 0; i
< DataSize
; i
++)
1692 if(Value
& (1 << i
))
1694 /* Save the bit number */
1702 /* Write back the result */
1703 if (OperandSize
) Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, BitNumber
);
1704 else Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, LOWORD(BitNumber
));
1707 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsr
)
1711 BOOLEAN OperandSize
, AddressSize
;
1712 FAST486_MOD_REG_RM ModRegRm
;
1716 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1717 TOGGLE_OPSIZE(OperandSize
);
1718 TOGGLE_ADSIZE(AddressSize
);
1720 /* Make sure this is the right instruction */
1721 ASSERT(Opcode
== 0xBD);
1723 /* Get the number of bits */
1724 if (OperandSize
) DataSize
= 32;
1727 /* Get the operands */
1728 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1730 /* Exception occurred */
1734 /* Read the value */
1737 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
1739 /* Exception occurred */
1745 if (!Fast486ReadModrmWordOperands(State
,
1750 /* Exception occurred */
1755 /* Set ZF according to the value */
1756 State
->Flags
.Zf
= (Value
== 0);
1757 if (State
->Flags
.Zf
) return;
1759 for (i
= DataSize
- 1; i
>= 0; i
--)
1761 if(Value
& (1 << i
))
1763 /* Save the bit number */
1771 /* Write back the result */
1772 if (OperandSize
) Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, BitNumber
);
1773 else Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, LOWORD(BitNumber
));
1776 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxByte
)
1779 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1780 FAST486_MOD_REG_RM ModRegRm
;
1782 TOGGLE_ADSIZE(AddressSize
);
1784 /* Make sure this is the right instruction */
1785 ASSERT(Opcode
== 0xBE);
1787 /* Get the operands */
1788 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1790 /* Exception occurred */
1794 /* Read the operands */
1795 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, NULL
, (PUCHAR
)&Value
))
1797 /* Exception occurred */
1801 /* Write back the sign-extended value */
1802 Fast486WriteModrmDwordOperands(State
,
1805 (ULONG
)((LONG
)Value
));
1808 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxWord
)
1811 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1812 FAST486_MOD_REG_RM ModRegRm
;
1814 TOGGLE_ADSIZE(AddressSize
);
1816 /* Make sure this is the right instruction */
1817 ASSERT(Opcode
== 0xBF);
1819 /* Get the operands */
1820 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1822 /* Exception occurred */
1826 /* Read the operands */
1827 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, (PUSHORT
)&Value
))
1829 /* Exception occurred */
1833 /* Write back the sign-extended value */
1834 Fast486WriteModrmDwordOperands(State
,
1837 (ULONG
)((LONG
)Value
));
1840 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalJmp
)
1842 BOOLEAN Jump
= FALSE
;
1844 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1846 TOGGLE_OPSIZE(Size
);
1849 /* Make sure this is the right instruction */
1850 ASSERT((Opcode
& 0xF0) == 0x80);
1852 /* Fetch the offset */
1855 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
1857 /* Exception occurred */
1865 if (!Fast486FetchWord(State
, (PUSHORT
)&Value
))
1867 /* Exception occurred */
1872 Offset
= (LONG
)Value
;
1875 switch ((Opcode
& 0x0F) >> 1)
1880 Jump
= State
->Flags
.Of
;
1887 Jump
= State
->Flags
.Cf
;
1894 Jump
= State
->Flags
.Zf
;
1901 Jump
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
1908 Jump
= State
->Flags
.Sf
;
1915 Jump
= State
->Flags
.Pf
;
1922 Jump
= State
->Flags
.Sf
!= State
->Flags
.Of
;
1929 Jump
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
1936 /* Invert the result */
1942 /* Move the instruction pointer */
1943 State
->InstPtr
.Long
+= Offset
;
1947 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalSet
)
1949 BOOLEAN Value
= FALSE
;
1950 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1951 FAST486_MOD_REG_RM ModRegRm
;
1953 TOGGLE_ADSIZE(AddressSize
);
1955 /* Get the operands */
1956 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1958 /* Exception occurred */
1962 /* Make sure this is the right instruction */
1963 ASSERT((Opcode
& 0xF0) == 0x90);
1965 switch ((Opcode
& 0x0F) >> 1)
1970 Value
= State
->Flags
.Of
;
1977 Value
= State
->Flags
.Cf
;
1984 Value
= State
->Flags
.Zf
;
1988 /* SETBE / SETNBE */
1991 Value
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
1998 Value
= State
->Flags
.Sf
;
2005 Value
= State
->Flags
.Pf
;
2012 Value
= State
->Flags
.Sf
!= State
->Flags
.Of
;
2016 /* SETLE / SETNLE */
2019 Value
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
2026 /* Invert the result */
2030 /* Write back the result */
2031 Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Value
);
2034 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXaddByte
)
2036 UCHAR Source
, Destination
, Result
;
2037 FAST486_MOD_REG_RM ModRegRm
;
2038 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2040 /* Make sure this is the right instruction */
2041 ASSERT(Opcode
== 0xC0);
2043 TOGGLE_ADSIZE(AddressSize
);
2045 /* Get the operands */
2046 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2048 /* Exception occurred */
2052 if (!Fast486ReadModrmByteOperands(State
,
2057 /* Exception occurred */
2061 /* Calculate the result */
2062 Result
= Source
+ Destination
;
2064 /* Update the flags */
2065 State
->Flags
.Cf
= (Result
< Source
) && (Result
< Destination
);
2066 State
->Flags
.Of
= ((Source
& SIGN_FLAG_BYTE
) == (Destination
& SIGN_FLAG_BYTE
))
2067 && ((Source
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2068 State
->Flags
.Af
= ((((Source
& 0x0F) + (Destination
& 0x0F)) & 0x10) != 0);
2069 State
->Flags
.Zf
= (Result
== 0);
2070 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2071 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2073 /* Write the sum to the destination */
2074 if (!Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Result
))
2076 /* Exception occurred */
2080 /* Write the old value of the destination to the source */
2081 Fast486WriteModrmByteOperands(State
, &ModRegRm
, TRUE
, Destination
);
2084 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXadd
)
2086 FAST486_MOD_REG_RM ModRegRm
;
2087 BOOLEAN OperandSize
, AddressSize
;
2089 /* Make sure this is the right instruction */
2090 ASSERT(Opcode
== 0xC1);
2092 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2094 TOGGLE_ADSIZE(AddressSize
);
2095 TOGGLE_OPSIZE(OperandSize
);
2097 /* Get the operands */
2098 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2100 /* Exception occurred */
2104 /* Check the operand size */
2107 ULONG Source
, Destination
, Result
;
2109 if (!Fast486ReadModrmDwordOperands(State
,
2114 /* Exception occurred */
2118 /* Calculate the result */
2119 Result
= Source
+ Destination
;
2121 /* Update the flags */
2122 State
->Flags
.Cf
= (Result
< Source
) && (Result
< Destination
);
2123 State
->Flags
.Of
= ((Source
& SIGN_FLAG_LONG
) == (Destination
& SIGN_FLAG_LONG
))
2124 && ((Source
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2125 State
->Flags
.Af
= ((((Source
& 0x0F) + (Destination
& 0x0F)) & 0x10) != 0);
2126 State
->Flags
.Zf
= (Result
== 0);
2127 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2128 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2130 /* Write the old value of the destination to the source */
2131 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, Destination
))
2133 /* Exception occurred */
2137 /* Write the sum to the destination */
2138 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
);
2142 USHORT Source
, Destination
, Result
;
2144 if (!Fast486ReadModrmWordOperands(State
,
2149 /* Exception occurred */
2153 /* Calculate the result */
2154 Result
= Source
+ Destination
;
2156 /* Update the flags */
2157 State
->Flags
.Cf
= (Result
< Source
) && (Result
< Destination
);
2158 State
->Flags
.Of
= ((Source
& SIGN_FLAG_WORD
) == (Destination
& SIGN_FLAG_WORD
))
2159 && ((Source
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2160 State
->Flags
.Af
= ((((Source
& 0x0F) + (Destination
& 0x0F)) & 0x10) != 0);
2161 State
->Flags
.Zf
= (Result
== 0);
2162 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2163 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2165 /* Write the old value of the destination to the source */
2166 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, Destination
))
2168 /* Exception occurred */
2172 /* Write the sum to the destination */
2173 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Result
);
2177 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBswap
)
2183 /* Get a pointer to the value */
2184 Pointer
= (PUCHAR
)&State
->GeneralRegs
[Opcode
& 0x07].Long
;
2186 /* Swap the byte order */
2187 SWAP(Pointer
[0], Pointer
[3]);
2188 SWAP(Pointer
[1], Pointer
[2]);
2191 FAST486_OPCODE_HANDLER(Fast486OpcodeExtended
)
2195 /* Fetch the second operation code */
2196 if (!Fast486FetchByte(State
, &SecondOpcode
))
2198 /* Exception occurred */
2202 /* Call the extended opcode handler */
2203 Fast486ExtendedHandlers
[SecondOpcode
](State
, SecondOpcode
);