2 * Fast486 386/486 CPU Emulation Library
5 * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 /* INCLUDES *******************************************************************/
35 /* PUBLIC VARIABLES ***********************************************************/
37 FAST486_OPCODE_HANDLER_PROC
38 Fast486ExtendedHandlers
[FAST486_NUM_OPCODE_HANDLERS
] =
40 Fast486ExtOpcodeGroup0F00
, /* 0x00 - 0x01 */
41 Fast486ExtOpcodeGroup0F01
,
42 Fast486ExtOpcodeLar
, /* 0x02 */
43 Fast486ExtOpcodeLsl
, /* 0x03 */
44 Fast486ExtOpcodeInvalid
, /* 0x04 - 0x05 */ // Invalid
45 Fast486ExtOpcodeInvalid
, // Invalid
46 Fast486ExtOpcodeClts
, /* 0x06 */
47 Fast486ExtOpcodeInvalid
, /* 0x07 */ // Invalid
48 Fast486ExtOpcodeUnimplemented
, // TODO: OPCODE 0x08 NOT IMPLEMENTED
49 Fast486ExtOpcodeUnimplemented
, // TODO: OPCODE 0x09 NOT IMPLEMENTED
50 Fast486ExtOpcodeInvalid
, /* 0x0A */ // Invalid
51 Fast486ExtOpcode0F0B
, /* 0x0B */ // Reserved (UD2)
52 Fast486ExtOpcodeInvalid
, /* 0x0C - 0x1F */ // Invalid
53 Fast486ExtOpcodeInvalid
, // Invalid
54 Fast486ExtOpcodeInvalid
, // Invalid
55 Fast486ExtOpcodeInvalid
, // Invalid
56 Fast486ExtOpcodeInvalid
, // Invalid
57 Fast486ExtOpcodeInvalid
, // Invalid
58 Fast486ExtOpcodeInvalid
, // Invalid
59 Fast486ExtOpcodeInvalid
, // Invalid
60 Fast486ExtOpcodeInvalid
, // Invalid
61 Fast486ExtOpcodeInvalid
, // Invalid
62 Fast486ExtOpcodeInvalid
, // Invalid
63 Fast486ExtOpcodeInvalid
, // Invalid
64 Fast486ExtOpcodeInvalid
, // Invalid
65 Fast486ExtOpcodeInvalid
, // Invalid
66 Fast486ExtOpcodeInvalid
, // Invalid
67 Fast486ExtOpcodeInvalid
, // Invalid
68 Fast486ExtOpcodeInvalid
, // Invalid
69 Fast486ExtOpcodeInvalid
, // Invalid
70 Fast486ExtOpcodeInvalid
, // Invalid
71 Fast486ExtOpcodeInvalid
, // Invalid
72 Fast486ExtOpcodeStoreControlReg
, /* 0x20 */
73 Fast486ExtOpcodeStoreDebugReg
, /* 0x21 */
74 Fast486ExtOpcodeLoadControlReg
, /* 0x22 */
75 Fast486ExtOpcodeLoadDebugReg
, /* 0x23 */
76 Fast486ExtOpcodeUnimplemented
, // TODO: OPCODE 0x24 NOT IMPLEMENTED
77 Fast486ExtOpcodeInvalid
, /* 0x25 */ // Invalid
78 Fast486ExtOpcodeUnimplemented
, // TODO: OPCODE 0x26 NOT IMPLEMENTED
79 Fast486ExtOpcodeInvalid
, /* 0x27 - 0x7F */ // Invalid
80 Fast486ExtOpcodeInvalid
, // Invalid
81 Fast486ExtOpcodeInvalid
, // Invalid
82 Fast486ExtOpcodeInvalid
, // Invalid
83 Fast486ExtOpcodeInvalid
, // Invalid
84 Fast486ExtOpcodeInvalid
, // Invalid
85 Fast486ExtOpcodeInvalid
, // Invalid
86 Fast486ExtOpcodeInvalid
, // Invalid
87 Fast486ExtOpcodeInvalid
, // Invalid
88 Fast486ExtOpcodeInvalid
, // Invalid
89 Fast486ExtOpcodeInvalid
, // Invalid
90 Fast486ExtOpcodeInvalid
, // Invalid
91 Fast486ExtOpcodeInvalid
, // Invalid
92 Fast486ExtOpcodeInvalid
, // Invalid
93 Fast486ExtOpcodeInvalid
, // Invalid
94 Fast486ExtOpcodeInvalid
, // Invalid
95 Fast486ExtOpcodeInvalid
, // Invalid
96 Fast486ExtOpcodeInvalid
, // Invalid
97 Fast486ExtOpcodeInvalid
, // Invalid
98 Fast486ExtOpcodeInvalid
, // Invalid
99 Fast486ExtOpcodeInvalid
, // Invalid
100 Fast486ExtOpcodeInvalid
, // Invalid
101 Fast486ExtOpcodeInvalid
, // Invalid
102 Fast486ExtOpcodeInvalid
, // Invalid
103 Fast486ExtOpcodeInvalid
, // Invalid
104 Fast486ExtOpcodeInvalid
, // Invalid
105 Fast486ExtOpcodeInvalid
, // Invalid
106 Fast486ExtOpcodeInvalid
, // Invalid
107 Fast486ExtOpcodeInvalid
, // Invalid
108 Fast486ExtOpcodeInvalid
, // Invalid
109 Fast486ExtOpcodeInvalid
, // Invalid
110 Fast486ExtOpcodeInvalid
, // Invalid
111 Fast486ExtOpcodeInvalid
, // Invalid
112 Fast486ExtOpcodeInvalid
, // Invalid
113 Fast486ExtOpcodeInvalid
, // Invalid
114 Fast486ExtOpcodeInvalid
, // Invalid
115 Fast486ExtOpcodeInvalid
, // Invalid
116 Fast486ExtOpcodeInvalid
, // Invalid
117 Fast486ExtOpcodeInvalid
, // Invalid
118 Fast486ExtOpcodeInvalid
, // Invalid
119 Fast486ExtOpcodeInvalid
, // Invalid
120 Fast486ExtOpcodeInvalid
, // Invalid
121 Fast486ExtOpcodeInvalid
, // Invalid
122 Fast486ExtOpcodeInvalid
, // Invalid
123 Fast486ExtOpcodeInvalid
, // Invalid
124 Fast486ExtOpcodeInvalid
, // Invalid
125 Fast486ExtOpcodeInvalid
, // Invalid
126 Fast486ExtOpcodeInvalid
, // Invalid
127 Fast486ExtOpcodeInvalid
, // Invalid
128 Fast486ExtOpcodeInvalid
, // Invalid
129 Fast486ExtOpcodeInvalid
, // Invalid
130 Fast486ExtOpcodeInvalid
, // Invalid
131 Fast486ExtOpcodeInvalid
, // Invalid
132 Fast486ExtOpcodeInvalid
, // Invalid
133 Fast486ExtOpcodeInvalid
, // Invalid
134 Fast486ExtOpcodeInvalid
, // Invalid
135 Fast486ExtOpcodeInvalid
, // Invalid
136 Fast486ExtOpcodeInvalid
, // Invalid
137 Fast486ExtOpcodeInvalid
, // Invalid
138 Fast486ExtOpcodeInvalid
, // Invalid
139 Fast486ExtOpcodeInvalid
, // Invalid
140 Fast486ExtOpcodeInvalid
, // Invalid
141 Fast486ExtOpcodeInvalid
, // Invalid
142 Fast486ExtOpcodeInvalid
, // Invalid
143 Fast486ExtOpcodeInvalid
, // Invalid
144 Fast486ExtOpcodeInvalid
, // Invalid
145 Fast486ExtOpcodeInvalid
, // Invalid
146 Fast486ExtOpcodeInvalid
, // Invalid
147 Fast486ExtOpcodeInvalid
, // Invalid
148 Fast486ExtOpcodeInvalid
, // Invalid
149 Fast486ExtOpcodeInvalid
, // Invalid
150 Fast486ExtOpcodeInvalid
, // Invalid
151 Fast486ExtOpcodeInvalid
, // Invalid
152 Fast486ExtOpcodeInvalid
, // Invalid
153 Fast486ExtOpcodeInvalid
, // Invalid
154 Fast486ExtOpcodeInvalid
, // Invalid
155 Fast486ExtOpcodeInvalid
, // Invalid
156 Fast486ExtOpcodeInvalid
, // Invalid
157 Fast486ExtOpcodeInvalid
, // Invalid
158 Fast486ExtOpcodeInvalid
, // Invalid
159 Fast486ExtOpcodeInvalid
, // Invalid
160 Fast486ExtOpcodeInvalid
, // Invalid
161 Fast486ExtOpcodeInvalid
, // Invalid
162 Fast486ExtOpcodeInvalid
, // Invalid
163 Fast486ExtOpcodeInvalid
, // Invalid
164 Fast486ExtOpcodeInvalid
, // Invalid
165 Fast486ExtOpcodeInvalid
, // Invalid
166 Fast486ExtOpcodeInvalid
, // Invalid
167 Fast486ExtOpcodeInvalid
, // Invalid
168 Fast486ExtOpcodeConditionalJmp
, /* 0x80 - 0x8F */
169 Fast486ExtOpcodeConditionalJmp
,
170 Fast486ExtOpcodeConditionalJmp
,
171 Fast486ExtOpcodeConditionalJmp
,
172 Fast486ExtOpcodeConditionalJmp
,
173 Fast486ExtOpcodeConditionalJmp
,
174 Fast486ExtOpcodeConditionalJmp
,
175 Fast486ExtOpcodeConditionalJmp
,
176 Fast486ExtOpcodeConditionalJmp
,
177 Fast486ExtOpcodeConditionalJmp
,
178 Fast486ExtOpcodeConditionalJmp
,
179 Fast486ExtOpcodeConditionalJmp
,
180 Fast486ExtOpcodeConditionalJmp
,
181 Fast486ExtOpcodeConditionalJmp
,
182 Fast486ExtOpcodeConditionalJmp
,
183 Fast486ExtOpcodeConditionalJmp
,
184 Fast486ExtOpcodeConditionalSet
, /* 0x90 - 0x9F */
185 Fast486ExtOpcodeConditionalSet
,
186 Fast486ExtOpcodeConditionalSet
,
187 Fast486ExtOpcodeConditionalSet
,
188 Fast486ExtOpcodeConditionalSet
,
189 Fast486ExtOpcodeConditionalSet
,
190 Fast486ExtOpcodeConditionalSet
,
191 Fast486ExtOpcodeConditionalSet
,
192 Fast486ExtOpcodeConditionalSet
,
193 Fast486ExtOpcodeConditionalSet
,
194 Fast486ExtOpcodeConditionalSet
,
195 Fast486ExtOpcodeConditionalSet
,
196 Fast486ExtOpcodeConditionalSet
,
197 Fast486ExtOpcodeConditionalSet
,
198 Fast486ExtOpcodeConditionalSet
,
199 Fast486ExtOpcodeConditionalSet
,
200 Fast486ExtOpcodePushFs
, /* 0xA0 */
201 Fast486ExtOpcodePopFs
, /* 0xA1 */
202 Fast486ExtOpcodeInvalid
, /* 0xA2 */ // Invalid
203 Fast486ExtOpcodeBitTest
, /* 0xA3 */
204 Fast486ExtOpcodeShld
, /* 0xA4 - 0xA5 */
205 Fast486ExtOpcodeShld
,
206 Fast486ExtOpcodeInvalid
, /* 0xA6 - 0xA7 */ // Invalid
207 Fast486ExtOpcodeInvalid
, // Invalid
208 Fast486ExtOpcodePushGs
, /* 0xA8 - 0xA9 */
209 Fast486ExtOpcodePopGs
,
210 Fast486ExtOpcodeInvalid
, /* 0xAA */ // Invalid
211 Fast486ExtOpcodeBts
, /* 0xAB */
212 Fast486ExtOpcodeShrd
, /* 0xAC - 0xAD */
213 Fast486ExtOpcodeShrd
,
214 Fast486ExtOpcodeInvalid
, /* 0xAE */ // Invalid
215 Fast486ExtOpcodeImul
, /* 0xAF */
216 Fast486ExtOpcodeCmpXchgByte
, /* 0xB0 */
217 Fast486ExtOpcodeCmpXchg
, /* 0xB1 */
218 Fast486ExtOpcodeLss
, /* 0xB2 */
219 Fast486ExtOpcodeBtr
, /* 0xB3 */
220 Fast486ExtOpcodeLfsLgs
, /* 0xB4 - 0xB5 */
221 Fast486ExtOpcodeLfsLgs
,
222 Fast486ExtOpcodeMovzxByte
, /* 0xB6 - 0xB7 */
223 Fast486ExtOpcodeMovzxWord
,
224 Fast486ExtOpcodeInvalid
, /* 0xB8 */ // Invalid
225 Fast486ExtOpcodeGroup0FB9
, /* 0xB9 */
226 Fast486ExtOpcodeGroup0FBA
, /* 0xBA */
227 Fast486ExtOpcodeBtc
, /* 0xBB */
228 Fast486ExtOpcodeBsf
, /* 0xBC */
229 Fast486ExtOpcodeBsr
, /* 0xBD */
230 Fast486ExtOpcodeMovsxByte
, /* 0xBE - 0xBF */
231 Fast486ExtOpcodeMovsxWord
,
232 Fast486ExtOpcodeXaddByte
, /* 0xC0 - 0xC1 */
233 Fast486ExtOpcodeXadd
,
234 Fast486ExtOpcodeInvalid
, /* 0xC2 - 0xC7 */ // Invalid
235 Fast486ExtOpcodeInvalid
, // Invalid
236 Fast486ExtOpcodeInvalid
, // Invalid
237 Fast486ExtOpcodeInvalid
, // Invalid
238 Fast486ExtOpcodeInvalid
, // Invalid
239 Fast486ExtOpcodeInvalid
, // Invalid
240 Fast486ExtOpcodeBswap
, /* 0xC8 - 0xCF */
241 Fast486ExtOpcodeBswap
,
242 Fast486ExtOpcodeBswap
,
243 Fast486ExtOpcodeBswap
,
244 Fast486ExtOpcodeBswap
,
245 Fast486ExtOpcodeBswap
,
246 Fast486ExtOpcodeBswap
,
247 Fast486ExtOpcodeBswap
,
248 Fast486ExtOpcodeInvalid
, /* 0xD0 - 0xFF */ // Invalid
249 Fast486ExtOpcodeInvalid
, // Invalid
250 Fast486ExtOpcodeInvalid
, // Invalid
251 Fast486ExtOpcodeInvalid
, // Invalid
252 Fast486ExtOpcodeInvalid
, // Invalid
253 Fast486ExtOpcodeInvalid
, // Invalid
254 Fast486ExtOpcodeInvalid
, // Invalid
255 Fast486ExtOpcodeInvalid
, // Invalid
256 Fast486ExtOpcodeInvalid
, // Invalid
257 Fast486ExtOpcodeInvalid
, // Invalid
258 Fast486ExtOpcodeInvalid
, // Invalid
259 Fast486ExtOpcodeInvalid
, // Invalid
260 Fast486ExtOpcodeInvalid
, // Invalid
261 Fast486ExtOpcodeInvalid
, // Invalid
262 Fast486ExtOpcodeInvalid
, // Invalid
263 Fast486ExtOpcodeInvalid
, // Invalid
264 Fast486ExtOpcodeInvalid
, // Invalid
265 Fast486ExtOpcodeInvalid
, // Invalid
266 Fast486ExtOpcodeInvalid
, // Invalid
267 Fast486ExtOpcodeInvalid
, // Invalid
268 Fast486ExtOpcodeInvalid
, // Invalid
269 Fast486ExtOpcodeInvalid
, // Invalid
270 Fast486ExtOpcodeInvalid
, // Invalid
271 Fast486ExtOpcodeInvalid
, // Invalid
272 Fast486ExtOpcodeInvalid
, // Invalid
273 Fast486ExtOpcodeInvalid
, // Invalid
274 Fast486ExtOpcodeInvalid
, // Invalid
275 Fast486ExtOpcodeInvalid
, // Invalid
276 Fast486ExtOpcodeInvalid
, // Invalid
277 Fast486ExtOpcodeInvalid
, // Invalid
278 Fast486ExtOpcodeInvalid
, // Invalid
279 Fast486ExtOpcodeInvalid
, // Invalid
280 Fast486ExtOpcodeInvalid
, // Invalid
281 Fast486ExtOpcodeInvalid
, // Invalid
282 Fast486ExtOpcodeInvalid
, // Invalid
283 Fast486ExtOpcodeInvalid
, // Invalid
284 Fast486ExtOpcodeInvalid
, // Invalid
285 Fast486ExtOpcodeInvalid
, // Invalid
286 Fast486ExtOpcodeInvalid
, // Invalid
287 Fast486ExtOpcodeInvalid
, // Invalid
288 Fast486ExtOpcodeInvalid
, // Invalid
289 Fast486ExtOpcodeInvalid
, // Invalid
290 Fast486ExtOpcodeInvalid
, // Invalid
291 Fast486ExtOpcodeInvalid
, // Invalid
292 Fast486ExtOpcodeInvalid
, // Invalid
293 Fast486ExtOpcodeInvalid
, // Invalid
294 Fast486ExtOpcodeInvalid
, // Invalid
295 Fast486ExtOpcodeInvalid
, // Invalid
298 /* PUBLIC FUNCTIONS ***********************************************************/
300 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeInvalid
)
302 DPRINT1("FAST486 -- Extended opcode 0x%02X is INVALID!\n", Opcode
);
303 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
307 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeUnimplemented
)
309 DPRINT1("FAST486 -- Extended opcode 0x%02X is UNIMPLEMENTED\n", Opcode
);
310 // Fast486Exception(State, FAST486_EXCEPTION_UD);
313 FAST486_OPCODE_HANDLER(Fast486ExtOpcode0F0B
)
315 /* Reserved opcode (UD2) */
316 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
319 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLar
)
321 BOOLEAN OperandSize
, AddressSize
;
322 FAST486_MOD_REG_RM ModRegRm
;
324 FAST486_GDT_ENTRY GdtEntry
;
327 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
329 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
333 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
338 TOGGLE_OPSIZE(OperandSize
);
339 TOGGLE_ADSIZE(AddressSize
);
341 /* Get the operands */
342 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
344 /* Exception occurred */
353 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
355 /* Exception occurred */
359 Selector
= LOWORD(Value
);
364 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Selector
))
366 /* Exception occurred */
371 if (!(Selector
& SEGMENT_TABLE_INDICATOR
))
373 /* Check if the GDT contains the entry */
374 if (GET_SEGMENT_INDEX(Selector
) >= (State
->Gdtr
.Size
+ 1))
376 State
->Flags
.Zf
= FALSE
;
381 if (!Fast486ReadLinearMemory(State
,
383 + GET_SEGMENT_INDEX(Selector
),
387 /* Exception occurred */
393 /* Check if the LDT contains the entry */
394 if (GET_SEGMENT_INDEX(Selector
) >= (State
->Ldtr
.Limit
+ 1))
396 State
->Flags
.Zf
= FALSE
;
401 if (!Fast486ReadLinearMemory(State
,
403 + GET_SEGMENT_INDEX(Selector
),
407 /* Exception occurred */
412 /* Privilege check */
413 if (((GET_SEGMENT_RPL(Selector
) > GdtEntry
.Dpl
))
414 || (Fast486GetCurrentPrivLevel(State
) > GdtEntry
.Dpl
))
416 State
->Flags
.Zf
= FALSE
;
421 State
->Flags
.Zf
= TRUE
;
423 /* Get the access rights */
424 AccessRights
= ((PDWORD
)&GdtEntry
)[1] & 0x00F0FF00;
426 /* Return the access rights */
427 if (OperandSize
) Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, AccessRights
);
428 else Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, LOWORD(AccessRights
));
431 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLsl
)
433 BOOLEAN OperandSize
, AddressSize
;
434 FAST486_MOD_REG_RM ModRegRm
;
437 FAST486_GDT_ENTRY GdtEntry
;
439 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
441 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
445 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
450 TOGGLE_OPSIZE(OperandSize
);
451 TOGGLE_ADSIZE(AddressSize
);
453 /* Get the operands */
454 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
456 /* Exception occurred */
465 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
467 /* Exception occurred */
471 Selector
= LOWORD(Value
);
476 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Selector
))
478 /* Exception occurred */
483 if (!(Selector
& SEGMENT_TABLE_INDICATOR
))
485 /* Check if the GDT contains the entry */
486 if (GET_SEGMENT_INDEX(Selector
) >= (State
->Gdtr
.Size
+ 1))
488 State
->Flags
.Zf
= FALSE
;
493 if (!Fast486ReadLinearMemory(State
,
495 + GET_SEGMENT_INDEX(Selector
),
499 /* Exception occurred */
505 /* Check if the LDT contains the entry */
506 if (GET_SEGMENT_INDEX(Selector
) >= (State
->Ldtr
.Limit
+ 1))
508 State
->Flags
.Zf
= FALSE
;
513 if (!Fast486ReadLinearMemory(State
,
515 + GET_SEGMENT_INDEX(Selector
),
519 /* Exception occurred */
524 /* Privilege check */
525 if (((GET_SEGMENT_RPL(Selector
) > GdtEntry
.Dpl
))
526 || (Fast486GetCurrentPrivLevel(State
) > GdtEntry
.Dpl
))
528 State
->Flags
.Zf
= FALSE
;
532 /* Calculate the limit */
533 Limit
= GdtEntry
.Limit
| (GdtEntry
.LimitHigh
<< 16);
534 if (GdtEntry
.Granularity
) Limit
<<= 12;
537 State
->Flags
.Zf
= TRUE
;
539 /* Return the limit */
540 if (OperandSize
) Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, Limit
);
541 else Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, LOWORD(Limit
));
544 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeClts
)
548 /* The current privilege level must be zero */
549 if (Fast486GetCurrentPrivLevel(State
) != 0)
551 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
555 /* Clear the task switch bit */
556 State
->ControlRegisters
[FAST486_REG_CR0
] &= ~FAST486_CR0_TS
;
559 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreControlReg
)
561 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
562 FAST486_MOD_REG_RM ModRegRm
;
565 TOGGLE_ADSIZE(AddressSize
);
567 /* Get the operands */
568 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
570 /* Exception occurred */
574 /* The current privilege level must be zero */
575 if (Fast486GetCurrentPrivLevel(State
) != 0)
577 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
581 if ((ModRegRm
.Register
== 1) || (ModRegRm
.Register
> 3))
583 /* CR1, CR4, CR5, CR6 and CR7 don't exist */
584 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
588 if (ModRegRm
.Register
!= 0)
590 /* CR2 and CR3 and are stored in array indexes 1 and 2 */
594 /* Store the value of the control register */
595 State
->GeneralRegs
[ModRegRm
.SecondRegister
].Long
= State
->ControlRegisters
[ModRegRm
.Register
];
598 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreDebugReg
)
600 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
601 FAST486_MOD_REG_RM ModRegRm
;
604 TOGGLE_ADSIZE(AddressSize
);
606 /* Get the operands */
607 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
609 /* Exception occurred */
613 /* The current privilege level must be zero */
614 if (Fast486GetCurrentPrivLevel(State
) != 0)
616 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
620 if ((ModRegRm
.Register
== 6) || (ModRegRm
.Register
== 7))
622 /* DR6 and DR7 are aliases to DR4 and DR5 */
623 ModRegRm
.Register
-= 2;
626 if (State
->DebugRegisters
[FAST486_REG_DR5
] & FAST486_DR5_GD
)
628 /* Disallow access to debug registers */
629 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
633 /* Store the value of the debug register */
634 State
->GeneralRegs
[ModRegRm
.SecondRegister
].Long
= State
->DebugRegisters
[ModRegRm
.Register
];
637 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadControlReg
)
640 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
641 FAST486_MOD_REG_RM ModRegRm
;
644 TOGGLE_ADSIZE(AddressSize
);
646 /* Get the operands */
647 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
649 /* Exception occurred */
653 /* The current privilege level must be zero */
654 if (Fast486GetCurrentPrivLevel(State
) != 0)
656 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
660 if ((ModRegRm
.Register
== 1) || (ModRegRm
.Register
> 3))
662 /* CR1, CR4, CR5, CR6 and CR7 don't exist */
663 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
667 if (ModRegRm
.Register
!= 0)
669 /* CR2 and CR3 and are stored in array indexes 1 and 2 */
674 Value
= State
->GeneralRegs
[ModRegRm
.SecondRegister
].Long
;
676 if (ModRegRm
.Register
== (INT
)FAST486_REG_CR0
)
680 if (((Value
& (FAST486_CR0_PG
| FAST486_CR0_PE
)) == FAST486_CR0_PG
)
681 || ((Value
& (FAST486_CR0_CD
| FAST486_CR0_NW
)) == FAST486_CR0_NW
))
684 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
689 /* Load a value to the control register */
690 State
->ControlRegisters
[ModRegRm
.Register
] = Value
;
693 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadDebugReg
)
695 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
696 FAST486_MOD_REG_RM ModRegRm
;
699 TOGGLE_ADSIZE(AddressSize
);
701 /* Get the operands */
702 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
704 /* Exception occurred */
708 /* The current privilege level must be zero */
709 if (Fast486GetCurrentPrivLevel(State
) != 0)
711 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
715 if ((ModRegRm
.Register
== 6) || (ModRegRm
.Register
== 7))
717 /* DR6 and DR7 are aliases to DR4 and DR5 */
718 ModRegRm
.Register
-= 2;
721 if (State
->DebugRegisters
[FAST486_REG_DR5
] & FAST486_DR5_GD
)
723 /* Disallow access to debug registers */
724 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
728 /* Load a value to the debug register */
729 State
->DebugRegisters
[ModRegRm
.Register
] = State
->GeneralRegs
[ModRegRm
.SecondRegister
].Long
;
731 if (ModRegRm
.Register
== (INT
)FAST486_REG_DR4
)
733 /* The reserved bits are 1 */
734 State
->DebugRegisters
[ModRegRm
.Register
] |= FAST486_DR4_RESERVED
;
736 else if (ModRegRm
.Register
== (INT
)FAST486_REG_DR5
)
738 /* The reserved bits are 0 */
739 State
->DebugRegisters
[ModRegRm
.Register
] &= ~FAST486_DR5_RESERVED
;
743 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushFs
)
745 /* Call the internal API */
746 Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_FS
].Selector
);
749 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopFs
)
753 if (!Fast486StackPop(State
, &NewSelector
))
755 /* Exception occurred */
759 /* Call the internal API */
760 Fast486LoadSegment(State
, FAST486_REG_FS
, LOWORD(NewSelector
));
763 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBitTest
)
765 BOOLEAN OperandSize
, AddressSize
;
766 FAST486_MOD_REG_RM ModRegRm
;
770 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
771 TOGGLE_OPSIZE(OperandSize
);
772 TOGGLE_ADSIZE(AddressSize
);
774 /* Get the number of bits */
775 if (OperandSize
) DataSize
= 32;
778 /* Get the operands */
779 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
781 /* Exception occurred */
785 /* Get the bit number */
786 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
787 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
792 * For memory operands, add the bit offset divided by
793 * the data size to the address
795 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
798 /* Normalize the bit number */
799 BitNumber
%= DataSize
;
806 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
808 /* Exception occurred */
812 /* Set CF to the bit value */
813 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
820 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
822 /* Exception occurred */
826 /* Set CF to the bit value */
827 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
831 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShld
)
833 BOOLEAN OperandSize
, AddressSize
;
834 FAST486_MOD_REG_RM ModRegRm
;
837 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
838 TOGGLE_OPSIZE(OperandSize
);
839 TOGGLE_ADSIZE(AddressSize
);
841 /* Make sure this is the right instruction */
842 ASSERT((Opcode
& 0xFE) == 0xA4);
844 /* Get the operands */
845 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
847 /* Exception occurred */
853 /* Fetch the count */
854 if (!Fast486FetchByte(State
, &Count
))
856 /* Exception occurred */
862 /* The count is in CL */
863 Count
= State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
;
866 /* Normalize the count */
869 /* Do nothing if the count is zero */
870 if (Count
== 0) return;
874 ULONG Source
, Destination
, Result
;
876 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Source
, &Destination
))
878 /* Exception occurred */
882 /* Calculate the result */
883 Result
= (Destination
<< Count
) | (Source
>> (32 - Count
));
886 State
->Flags
.Cf
= (Destination
>> (32 - Count
)) & 1;
887 if (Count
== 1) State
->Flags
.Of
= (Result
& SIGN_FLAG_LONG
)
888 != (Destination
& SIGN_FLAG_LONG
);
889 State
->Flags
.Zf
= (Result
== 0);
890 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
891 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
893 /* Write back the result */
894 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
);
898 USHORT Source
, Destination
, Result
;
901 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Source
, &Destination
))
903 /* Exception occurred */
907 DoubleSource
= Source
| (Source
<< 16);
909 /* Calculate the result */
910 Result
= (Destination
<< Count
) | (DoubleSource
>> (32 - Count
));
913 if (Count
<= 16) State
->Flags
.Cf
= (Destination
>> (16 - Count
)) & 1;
914 else State
->Flags
.Cf
= (Source
>> (32 - Count
)) & 1;
916 if (Count
== 1) State
->Flags
.Of
= (Result
& SIGN_FLAG_WORD
)
917 != (Destination
& SIGN_FLAG_WORD
);
918 State
->Flags
.Zf
= (Result
== 0);
919 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
920 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
922 /* Write back the result */
923 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Result
);
927 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushGs
)
929 /* Call the internal API */
930 Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_GS
].Selector
);
933 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopGs
)
937 if (!Fast486StackPop(State
, &NewSelector
))
939 /* Exception occurred */
943 /* Call the internal API */
944 Fast486LoadSegment(State
, FAST486_REG_GS
, LOWORD(NewSelector
));
947 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBts
)
949 BOOLEAN OperandSize
, AddressSize
;
950 FAST486_MOD_REG_RM ModRegRm
;
954 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
955 TOGGLE_OPSIZE(OperandSize
);
956 TOGGLE_ADSIZE(AddressSize
);
958 /* Get the number of bits */
959 if (OperandSize
) DataSize
= 32;
962 /* Get the operands */
963 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
965 /* Exception occurred */
969 /* Get the bit number */
970 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
971 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
976 * For memory operands, add the bit offset divided by
977 * the data size to the address
979 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
982 /* Normalize the bit number */
983 BitNumber
%= DataSize
;
990 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
992 /* Exception occurred */
996 /* Set CF to the bit value */
997 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1000 Value
|= 1 << BitNumber
;
1002 /* Write back the result */
1003 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
1009 /* Read the value */
1010 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
1012 /* Exception occurred */
1016 /* Set CF to the bit value */
1017 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1020 Value
|= 1 << BitNumber
;
1022 /* Write back the result */
1023 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
1027 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShrd
)
1029 BOOLEAN OperandSize
, AddressSize
;
1030 FAST486_MOD_REG_RM ModRegRm
;
1033 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1034 TOGGLE_OPSIZE(OperandSize
);
1035 TOGGLE_ADSIZE(AddressSize
);
1037 /* Make sure this is the right instruction */
1038 ASSERT((Opcode
& 0xFE) == 0xAC);
1040 /* Get the operands */
1041 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1043 /* Exception occurred */
1049 /* Fetch the count */
1050 if (!Fast486FetchByte(State
, &Count
))
1052 /* Exception occurred */
1058 /* The count is in CL */
1059 Count
= State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
;
1062 /* Normalize the count */
1065 /* Do nothing if the count is zero */
1066 if (Count
== 0) return;
1070 ULONG Source
, Destination
, Result
;
1072 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Source
, &Destination
))
1074 /* Exception occurred */
1078 /* Calculate the result */
1079 Result
= (Destination
>> Count
) | (Source
<< (32 - Count
));
1082 State
->Flags
.Cf
= (Destination
>> (Count
- 1)) & 1;
1083 if (Count
== 1) State
->Flags
.Of
= (Result
& SIGN_FLAG_LONG
)
1084 != (Destination
& SIGN_FLAG_LONG
);
1085 State
->Flags
.Zf
= (Result
== 0);
1086 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1087 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1089 /* Write back the result */
1090 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
);
1094 USHORT Source
, Destination
, Result
;
1096 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Source
, &Destination
))
1098 /* Exception occurred */
1102 /* Calculate the result */
1103 Result
= (Destination
>> Count
) | (Source
<< (16 - Count
));
1105 if (Count
>= 16) Result
|= (ULONG
)(Source
| (Source
<< 16)) >> (Count
- 16);
1108 if (Count
<= 16) State
->Flags
.Cf
= (Destination
>> (Count
- 1)) & 1;
1109 else State
->Flags
.Cf
= (Source
>> (Count
- 17)) & 1;
1111 if (Count
== 1) State
->Flags
.Of
= (Result
& SIGN_FLAG_WORD
)
1112 != (Destination
& SIGN_FLAG_WORD
);
1113 State
->Flags
.Zf
= (Result
== 0);
1114 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1115 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1117 /* Write back the result */
1118 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Result
);
1122 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeImul
)
1124 BOOLEAN OperandSize
, AddressSize
;
1125 FAST486_MOD_REG_RM ModRegRm
;
1127 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1129 TOGGLE_OPSIZE(OperandSize
);
1130 TOGGLE_ADSIZE(AddressSize
);
1132 /* Get the operands */
1133 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1135 /* Exception occurred */
1141 LONG Source
, Destination
;
1144 /* Read the operands */
1145 if (!Fast486ReadModrmDwordOperands(State
,
1147 (PULONG
)&Destination
,
1150 /* Exception occurred */
1154 /* Calculate the result */
1155 Result
= (LONGLONG
)Source
* (LONGLONG
)Destination
;
1157 /* Update the flags */
1158 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -2147483648LL) || (Result
> 2147483647LL));
1160 /* Write back the result */
1161 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, (ULONG
)((LONG
)Result
));
1165 SHORT Source
, Destination
;
1168 /* Read the operands */
1169 if (!Fast486ReadModrmWordOperands(State
,
1171 (PUSHORT
)&Destination
,
1174 /* Exception occurred */
1178 /* Calculate the result */
1179 Result
= (LONG
)Source
* (LONG
)Destination
;
1181 /* Update the flags */
1182 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -32768) || (Result
> 32767));
1184 /* Write back the result */
1185 Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, (USHORT
)((SHORT
)Result
));
1189 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchgByte
)
1191 FAST486_MOD_REG_RM ModRegRm
;
1192 UCHAR Accumulator
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1193 UCHAR Source
, Destination
, Result
;
1194 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1196 TOGGLE_ADSIZE(AddressSize
);
1198 /* Get the operands */
1199 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1201 /* Exception occurred */
1205 /* Read the operands */
1206 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Source
, &Destination
))
1208 /* Exception occurred */
1212 /* Compare AL with the destination */
1213 Result
= Accumulator
- Destination
;
1215 /* Update the flags */
1216 State
->Flags
.Cf
= (Accumulator
< Destination
);
1217 State
->Flags
.Of
= ((Accumulator
& SIGN_FLAG_BYTE
) != (Destination
& SIGN_FLAG_BYTE
))
1218 && ((Accumulator
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1219 State
->Flags
.Af
= (Accumulator
& 0x0F) < (Destination
& 0x0F);
1220 State
->Flags
.Zf
= (Result
== 0);
1221 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1222 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1224 if (State
->Flags
.Zf
)
1226 /* Load the source operand into the destination */
1227 Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Source
);
1231 /* Load the destination into AL */
1232 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Destination
;
1236 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchg
)
1238 FAST486_MOD_REG_RM ModRegRm
;
1239 BOOLEAN OperandSize
, AddressSize
;
1241 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1243 TOGGLE_OPSIZE(OperandSize
);
1244 TOGGLE_ADSIZE(AddressSize
);
1246 /* Get the operands */
1247 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1249 /* Exception occurred */
1255 ULONG Source
, Destination
, Result
;
1256 ULONG Accumulator
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1258 /* Read the operands */
1259 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Source
, &Destination
))
1261 /* Exception occurred */
1265 /* Compare EAX with the destination */
1266 Result
= Accumulator
- Destination
;
1268 /* Update the flags */
1269 State
->Flags
.Cf
= (Accumulator
< Destination
);
1270 State
->Flags
.Of
= ((Accumulator
& SIGN_FLAG_LONG
) != (Destination
& SIGN_FLAG_LONG
))
1271 && ((Accumulator
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1272 State
->Flags
.Af
= (Accumulator
& 0x0F) < (Destination
& 0x0F);
1273 State
->Flags
.Zf
= (Result
== 0);
1274 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1275 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1277 if (State
->Flags
.Zf
)
1279 /* Load the source operand into the destination */
1280 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Source
);
1284 /* Load the destination into EAX */
1285 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Destination
;
1290 USHORT Source
, Destination
, Result
;
1291 USHORT Accumulator
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1293 /* Read the operands */
1294 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Source
, &Destination
))
1296 /* Exception occurred */
1300 /* Compare AX with the destination */
1301 Result
= Accumulator
- Destination
;
1303 /* Update the flags */
1304 State
->Flags
.Cf
= (Accumulator
< Destination
);
1305 State
->Flags
.Of
= ((Accumulator
& SIGN_FLAG_WORD
) != (Destination
& SIGN_FLAG_WORD
))
1306 && ((Accumulator
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1307 State
->Flags
.Af
= (Accumulator
& 0x0F) < (Destination
& 0x0F);
1308 State
->Flags
.Zf
= (Result
== 0);
1309 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1310 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1312 if (State
->Flags
.Zf
)
1314 /* Load the source operand into the destination */
1315 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Source
);
1319 /* Load the destination into AX */
1320 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Destination
;
1325 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLss
)
1327 UCHAR FarPointer
[6];
1328 BOOLEAN OperandSize
, AddressSize
;
1329 FAST486_MOD_REG_RM ModRegRm
;
1331 /* Make sure this is the right instruction */
1332 ASSERT(Opcode
== 0xB2);
1334 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1336 TOGGLE_OPSIZE(OperandSize
);
1337 TOGGLE_ADSIZE(AddressSize
);
1339 /* Get the operands */
1340 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1342 /* Exception occurred */
1346 if (!ModRegRm
.Memory
)
1349 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1353 if (!Fast486ReadMemory(State
,
1354 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1355 ? State
->SegmentOverride
: FAST486_REG_DS
,
1356 ModRegRm
.MemoryAddress
,
1359 OperandSize
? 6 : 4))
1361 /* Exception occurred */
1367 ULONG Offset
= *((PULONG
)FarPointer
);
1368 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
1370 /* Set the register to the offset */
1371 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
1373 /* Load the segment */
1374 Fast486LoadSegment(State
, FAST486_REG_SS
, Segment
);
1378 USHORT Offset
= *((PUSHORT
)FarPointer
);
1379 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
1381 /* Set the register to the offset */
1382 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
1384 /* Load the segment */
1385 Fast486LoadSegment(State
, FAST486_REG_SS
, Segment
);
1389 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtr
)
1391 BOOLEAN OperandSize
, AddressSize
;
1392 FAST486_MOD_REG_RM ModRegRm
;
1396 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1397 TOGGLE_OPSIZE(OperandSize
);
1398 TOGGLE_ADSIZE(AddressSize
);
1400 /* Get the number of bits */
1401 if (OperandSize
) DataSize
= 32;
1404 /* Get the operands */
1405 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1407 /* Exception occurred */
1411 /* Get the bit number */
1412 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
1413 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
1415 if (ModRegRm
.Memory
)
1418 * For memory operands, add the bit offset divided by
1419 * the data size to the address
1421 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
1424 /* Normalize the bit number */
1425 BitNumber
%= DataSize
;
1431 /* Read the value */
1432 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
1434 /* Exception occurred */
1438 /* Set CF to the bit value */
1439 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1442 Value
&= ~(1 << BitNumber
);
1444 /* Write back the result */
1445 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
1451 /* Read the value */
1452 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
1454 /* Exception occurred */
1458 /* Set CF to the bit value */
1459 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1462 Value
&= ~(1 << BitNumber
);
1464 /* Write back the result */
1465 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
1469 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLfsLgs
)
1471 UCHAR FarPointer
[6];
1472 BOOLEAN OperandSize
, AddressSize
;
1473 FAST486_MOD_REG_RM ModRegRm
;
1475 /* Make sure this is the right instruction */
1476 ASSERT((Opcode
& 0xFE) == 0xB4);
1478 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1480 TOGGLE_OPSIZE(OperandSize
);
1481 TOGGLE_ADSIZE(AddressSize
);
1483 /* Get the operands */
1484 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1486 /* Exception occurred */
1490 if (!ModRegRm
.Memory
)
1493 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1497 if (!Fast486ReadMemory(State
,
1498 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1499 ? State
->SegmentOverride
: FAST486_REG_DS
,
1500 ModRegRm
.MemoryAddress
,
1503 OperandSize
? 6 : 4))
1505 /* Exception occurred */
1511 ULONG Offset
= *((PULONG
)FarPointer
);
1512 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
1514 /* Set the register to the offset */
1515 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
1517 /* Load the segment */
1518 Fast486LoadSegment(State
,
1520 ? FAST486_REG_FS
: FAST486_REG_GS
,
1525 USHORT Offset
= *((PUSHORT
)FarPointer
);
1526 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
1528 /* Set the register to the offset */
1529 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
1531 /* Load the segment */
1532 Fast486LoadSegment(State
,
1534 ? FAST486_REG_FS
: FAST486_REG_GS
,
1539 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxByte
)
1542 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1543 FAST486_MOD_REG_RM ModRegRm
;
1545 TOGGLE_ADSIZE(AddressSize
);
1547 /* Make sure this is the right instruction */
1548 ASSERT(Opcode
== 0xB6);
1550 /* Get the operands */
1551 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1553 /* Exception occurred */
1557 /* Read the operands */
1558 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, NULL
, &Value
))
1560 /* Exception occurred */
1564 /* Write back the zero-extended value */
1565 Fast486WriteModrmDwordOperands(State
,
1571 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxWord
)
1574 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1575 FAST486_MOD_REG_RM ModRegRm
;
1577 TOGGLE_ADSIZE(AddressSize
);
1579 /* Make sure this is the right instruction */
1580 ASSERT(Opcode
== 0xB7);
1582 /* Get the operands */
1583 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1585 /* Exception occurred */
1589 /* Read the operands */
1590 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
1592 /* Exception occurred */
1596 /* Write back the zero-extended value */
1597 Fast486WriteModrmDwordOperands(State
,
1603 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtc
)
1605 BOOLEAN OperandSize
, AddressSize
;
1606 FAST486_MOD_REG_RM ModRegRm
;
1610 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1611 TOGGLE_OPSIZE(OperandSize
);
1612 TOGGLE_ADSIZE(AddressSize
);
1614 /* Get the number of bits */
1615 if (OperandSize
) DataSize
= 32;
1618 /* Get the operands */
1619 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1621 /* Exception occurred */
1625 /* Get the bit number */
1626 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
1627 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
1629 if (ModRegRm
.Memory
)
1632 * For memory operands, add the bit offset divided by
1633 * the data size to the address
1635 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
1638 /* Normalize the bit number */
1639 BitNumber
%= DataSize
;
1645 /* Read the value */
1646 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
1648 /* Exception occurred */
1652 /* Set CF to the bit value */
1653 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1655 /* Toggle the bit */
1656 Value
^= 1 << BitNumber
;
1658 /* Write back the result */
1659 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
1665 /* Read the value */
1666 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
1668 /* Exception occurred */
1672 /* Set CF to the bit value */
1673 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1675 /* Toggle the bit */
1676 Value
^= 1 << BitNumber
;
1678 /* Write back the result */
1679 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
1683 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsf
)
1687 BOOLEAN OperandSize
, AddressSize
;
1688 FAST486_MOD_REG_RM ModRegRm
;
1692 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1693 TOGGLE_OPSIZE(OperandSize
);
1694 TOGGLE_ADSIZE(AddressSize
);
1696 /* Make sure this is the right instruction */
1697 ASSERT(Opcode
== 0xBC);
1699 /* Get the number of bits */
1700 if (OperandSize
) DataSize
= 32;
1703 /* Get the operands */
1704 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1706 /* Exception occurred */
1710 /* Read the value */
1713 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
1715 /* Exception occurred */
1721 if (!Fast486ReadModrmWordOperands(State
,
1726 /* Exception occurred */
1732 State
->Flags
.Zf
= (Value
== 0);
1733 if (State
->Flags
.Zf
) return;
1735 for (i
= 0; i
< DataSize
; i
++)
1737 if(Value
& (1 << i
))
1739 /* Save the bit number */
1747 /* Write back the result */
1748 if (OperandSize
) Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, BitNumber
);
1749 else Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, LOWORD(BitNumber
));
1752 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsr
)
1756 BOOLEAN OperandSize
, AddressSize
;
1757 FAST486_MOD_REG_RM ModRegRm
;
1761 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1762 TOGGLE_OPSIZE(OperandSize
);
1763 TOGGLE_ADSIZE(AddressSize
);
1765 /* Make sure this is the right instruction */
1766 ASSERT(Opcode
== 0xBD);
1768 /* Get the number of bits */
1769 if (OperandSize
) DataSize
= 32;
1772 /* Get the operands */
1773 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1775 /* Exception occurred */
1779 /* Read the value */
1782 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
1784 /* Exception occurred */
1790 if (!Fast486ReadModrmWordOperands(State
,
1795 /* Exception occurred */
1800 /* Set ZF according to the value */
1801 State
->Flags
.Zf
= (Value
== 0);
1802 if (State
->Flags
.Zf
) return;
1804 for (i
= DataSize
- 1; i
>= 0; i
--)
1806 if(Value
& (1 << i
))
1808 /* Save the bit number */
1816 /* Write back the result */
1817 if (OperandSize
) Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, BitNumber
);
1818 else Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, LOWORD(BitNumber
));
1821 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxByte
)
1824 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1825 FAST486_MOD_REG_RM ModRegRm
;
1827 TOGGLE_ADSIZE(AddressSize
);
1829 /* Make sure this is the right instruction */
1830 ASSERT(Opcode
== 0xBE);
1832 /* Get the operands */
1833 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1835 /* Exception occurred */
1839 /* Read the operands */
1840 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, NULL
, (PUCHAR
)&Value
))
1842 /* Exception occurred */
1846 /* Write back the sign-extended value */
1847 Fast486WriteModrmDwordOperands(State
,
1850 (ULONG
)((LONG
)Value
));
1853 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxWord
)
1856 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1857 FAST486_MOD_REG_RM ModRegRm
;
1859 TOGGLE_ADSIZE(AddressSize
);
1861 /* Make sure this is the right instruction */
1862 ASSERT(Opcode
== 0xBF);
1864 /* Get the operands */
1865 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1867 /* Exception occurred */
1871 /* Read the operands */
1872 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, (PUSHORT
)&Value
))
1874 /* Exception occurred */
1878 /* Write back the sign-extended value */
1879 Fast486WriteModrmDwordOperands(State
,
1882 (ULONG
)((LONG
)Value
));
1885 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalJmp
)
1887 BOOLEAN Jump
= FALSE
;
1889 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1891 TOGGLE_OPSIZE(Size
);
1894 /* Make sure this is the right instruction */
1895 ASSERT((Opcode
& 0xF0) == 0x80);
1897 /* Fetch the offset */
1900 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
1902 /* Exception occurred */
1910 if (!Fast486FetchWord(State
, (PUSHORT
)&Value
))
1912 /* Exception occurred */
1917 Offset
= (LONG
)Value
;
1920 switch ((Opcode
& 0x0F) >> 1)
1925 Jump
= State
->Flags
.Of
;
1932 Jump
= State
->Flags
.Cf
;
1939 Jump
= State
->Flags
.Zf
;
1946 Jump
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
1953 Jump
= State
->Flags
.Sf
;
1960 Jump
= State
->Flags
.Pf
;
1967 Jump
= State
->Flags
.Sf
!= State
->Flags
.Of
;
1974 Jump
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
1981 /* Invert the result */
1987 /* Move the instruction pointer */
1988 State
->InstPtr
.Long
+= Offset
;
1992 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalSet
)
1994 BOOLEAN Value
= FALSE
;
1995 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1996 FAST486_MOD_REG_RM ModRegRm
;
1998 TOGGLE_ADSIZE(AddressSize
);
2000 /* Get the operands */
2001 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2003 /* Exception occurred */
2007 /* Make sure this is the right instruction */
2008 ASSERT((Opcode
& 0xF0) == 0x90);
2010 switch ((Opcode
& 0x0F) >> 1)
2015 Value
= State
->Flags
.Of
;
2022 Value
= State
->Flags
.Cf
;
2029 Value
= State
->Flags
.Zf
;
2033 /* SETBE / SETNBE */
2036 Value
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
2043 Value
= State
->Flags
.Sf
;
2050 Value
= State
->Flags
.Pf
;
2057 Value
= State
->Flags
.Sf
!= State
->Flags
.Of
;
2061 /* SETLE / SETNLE */
2064 Value
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
2071 /* Invert the result */
2075 /* Write back the result */
2076 Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Value
);
2079 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXaddByte
)
2081 UCHAR Source
, Destination
, Result
;
2082 FAST486_MOD_REG_RM ModRegRm
;
2083 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2085 /* Make sure this is the right instruction */
2086 ASSERT(Opcode
== 0xC0);
2088 TOGGLE_ADSIZE(AddressSize
);
2090 /* Get the operands */
2091 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2093 /* Exception occurred */
2097 if (!Fast486ReadModrmByteOperands(State
,
2102 /* Exception occurred */
2106 /* Calculate the result */
2107 Result
= Source
+ Destination
;
2109 /* Update the flags */
2110 State
->Flags
.Cf
= (Result
< Source
) && (Result
< Destination
);
2111 State
->Flags
.Of
= ((Source
& SIGN_FLAG_BYTE
) == (Destination
& SIGN_FLAG_BYTE
))
2112 && ((Source
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2113 State
->Flags
.Af
= ((((Source
& 0x0F) + (Destination
& 0x0F)) & 0x10) != 0);
2114 State
->Flags
.Zf
= (Result
== 0);
2115 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2116 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2118 /* Write the sum to the destination */
2119 if (!Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Result
))
2121 /* Exception occurred */
2125 /* Write the old value of the destination to the source */
2126 Fast486WriteModrmByteOperands(State
, &ModRegRm
, TRUE
, Destination
);
2129 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXadd
)
2131 FAST486_MOD_REG_RM ModRegRm
;
2132 BOOLEAN OperandSize
, AddressSize
;
2134 /* Make sure this is the right instruction */
2135 ASSERT(Opcode
== 0xC1);
2137 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2139 TOGGLE_ADSIZE(AddressSize
);
2140 TOGGLE_OPSIZE(OperandSize
);
2142 /* Get the operands */
2143 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2145 /* Exception occurred */
2149 /* Check the operand size */
2152 ULONG Source
, Destination
, Result
;
2154 if (!Fast486ReadModrmDwordOperands(State
,
2159 /* Exception occurred */
2163 /* Calculate the result */
2164 Result
= Source
+ Destination
;
2166 /* Update the flags */
2167 State
->Flags
.Cf
= (Result
< Source
) && (Result
< Destination
);
2168 State
->Flags
.Of
= ((Source
& SIGN_FLAG_LONG
) == (Destination
& SIGN_FLAG_LONG
))
2169 && ((Source
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2170 State
->Flags
.Af
= ((((Source
& 0x0F) + (Destination
& 0x0F)) & 0x10) != 0);
2171 State
->Flags
.Zf
= (Result
== 0);
2172 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2173 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2175 /* Write the old value of the destination to the source */
2176 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, Destination
))
2178 /* Exception occurred */
2182 /* Write the sum to the destination */
2183 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
);
2187 USHORT Source
, Destination
, Result
;
2189 if (!Fast486ReadModrmWordOperands(State
,
2194 /* Exception occurred */
2198 /* Calculate the result */
2199 Result
= Source
+ Destination
;
2201 /* Update the flags */
2202 State
->Flags
.Cf
= (Result
< Source
) && (Result
< Destination
);
2203 State
->Flags
.Of
= ((Source
& SIGN_FLAG_WORD
) == (Destination
& SIGN_FLAG_WORD
))
2204 && ((Source
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2205 State
->Flags
.Af
= ((((Source
& 0x0F) + (Destination
& 0x0F)) & 0x10) != 0);
2206 State
->Flags
.Zf
= (Result
== 0);
2207 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2208 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2210 /* Write the old value of the destination to the source */
2211 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, Destination
))
2213 /* Exception occurred */
2217 /* Write the sum to the destination */
2218 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Result
);
2222 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBswap
)
2228 /* Get a pointer to the value */
2229 Pointer
= (PUCHAR
)&State
->GeneralRegs
[Opcode
& 0x07].Long
;
2231 /* Swap the byte order */
2232 SWAP(Pointer
[0], Pointer
[3]);
2233 SWAP(Pointer
[1], Pointer
[2]);
2236 FAST486_OPCODE_HANDLER(Fast486OpcodeExtended
)
2240 /* Fetch the second operation code */
2241 if (!Fast486FetchByte(State
, &SecondOpcode
))
2243 /* Exception occurred */
2247 /* Call the extended opcode handler */
2248 Fast486ExtendedHandlers
[SecondOpcode
](State
, SecondOpcode
);