* Sync up to trunk head (r65120).
[reactos.git] / lib / fast486 / extraops.c
1 /*
2 * Fast486 386/486 CPU Emulation Library
3 * extraops.c
4 *
5 * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
6 *
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.
11 *
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.
16 *
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.
20 */
21
22 /* INCLUDES *******************************************************************/
23
24 #include <windef.h>
25
26 // #define NDEBUG
27 #include <debug.h>
28
29 #include <fast486.h>
30 #include "opcodes.h"
31 #include "common.h"
32 #include "opgroups.h"
33 #include "extraops.h"
34
35 /* PUBLIC VARIABLES ***********************************************************/
36
37 FAST486_OPCODE_HANDLER_PROC
38 Fast486ExtendedHandlers[FAST486_NUM_OPCODE_HANDLERS] =
39 {
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
296 };
297
298 /* PUBLIC FUNCTIONS ***********************************************************/
299
300 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeInvalid)
301 {
302 DPRINT1("FAST486 -- Extended opcode 0x%02X is INVALID!\n", Opcode);
303 Fast486Exception(State, FAST486_EXCEPTION_UD);
304 return;
305 }
306
307 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeUnimplemented)
308 {
309 DPRINT1("FAST486 -- Extended opcode 0x%02X is UNIMPLEMENTED\n", Opcode);
310 // Fast486Exception(State, FAST486_EXCEPTION_UD);
311 }
312
313 FAST486_OPCODE_HANDLER(Fast486ExtOpcode0F0B)
314 {
315 /* Reserved opcode (UD2) */
316 Fast486Exception(State, FAST486_EXCEPTION_UD);
317 }
318
319 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLar)
320 {
321 BOOLEAN OperandSize, AddressSize;
322 FAST486_MOD_REG_RM ModRegRm;
323 USHORT Selector;
324 FAST486_GDT_ENTRY GdtEntry;
325 DWORD AccessRights;
326
327 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
328
329 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
330 || State->Flags.Vm)
331 {
332 /* Not recognized */
333 Fast486Exception(State, FAST486_EXCEPTION_UD);
334 return;
335 }
336
337 NO_LOCK_PREFIX();
338 TOGGLE_OPSIZE(OperandSize);
339 TOGGLE_ADSIZE(AddressSize);
340
341 /* Get the operands */
342 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
343 {
344 /* Exception occurred */
345 return;
346 }
347
348 if (OperandSize)
349 {
350 ULONG Value;
351
352 /* Read the value */
353 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
354 {
355 /* Exception occurred */
356 return;
357 }
358
359 Selector = LOWORD(Value);
360 }
361 else
362 {
363 /* Read the value */
364 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Selector))
365 {
366 /* Exception occurred */
367 return;
368 }
369 }
370
371 if (!(Selector & SEGMENT_TABLE_INDICATOR))
372 {
373 /* Check if the GDT contains the entry */
374 if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
375 {
376 State->Flags.Zf = FALSE;
377 return;
378 }
379
380 /* Read the GDT */
381 if (!Fast486ReadLinearMemory(State,
382 State->Gdtr.Address
383 + GET_SEGMENT_INDEX(Selector),
384 &GdtEntry,
385 sizeof(GdtEntry)))
386 {
387 /* Exception occurred */
388 return;
389 }
390 }
391 else
392 {
393 /* Check if the LDT contains the entry */
394 if (GET_SEGMENT_INDEX(Selector) >= (State->Ldtr.Limit + 1))
395 {
396 State->Flags.Zf = FALSE;
397 return;
398 }
399
400 /* Read the LDT */
401 if (!Fast486ReadLinearMemory(State,
402 State->Ldtr.Base
403 + GET_SEGMENT_INDEX(Selector),
404 &GdtEntry,
405 sizeof(GdtEntry)))
406 {
407 /* Exception occurred */
408 return;
409 }
410 }
411
412 /* Privilege check */
413 if (((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl))
414 || (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl))
415 {
416 State->Flags.Zf = FALSE;
417 return;
418 }
419
420 /* Set ZF */
421 State->Flags.Zf = TRUE;
422
423 /* Get the access rights */
424 AccessRights = ((PDWORD)&GdtEntry)[1] & 0x00F0FF00;
425
426 /* Return the access rights */
427 if (OperandSize) Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, AccessRights);
428 else Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(AccessRights));
429 }
430
431 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLsl)
432 {
433 BOOLEAN OperandSize, AddressSize;
434 FAST486_MOD_REG_RM ModRegRm;
435 USHORT Selector;
436 ULONG Limit;
437 FAST486_GDT_ENTRY GdtEntry;
438
439 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
440
441 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
442 || State->Flags.Vm)
443 {
444 /* Not recognized */
445 Fast486Exception(State, FAST486_EXCEPTION_UD);
446 return;
447 }
448
449 NO_LOCK_PREFIX();
450 TOGGLE_OPSIZE(OperandSize);
451 TOGGLE_ADSIZE(AddressSize);
452
453 /* Get the operands */
454 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
455 {
456 /* Exception occurred */
457 return;
458 }
459
460 if (OperandSize)
461 {
462 ULONG Value;
463
464 /* Read the value */
465 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
466 {
467 /* Exception occurred */
468 return;
469 }
470
471 Selector = LOWORD(Value);
472 }
473 else
474 {
475 /* Read the value */
476 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Selector))
477 {
478 /* Exception occurred */
479 return;
480 }
481 }
482
483 if (!(Selector & SEGMENT_TABLE_INDICATOR))
484 {
485 /* Check if the GDT contains the entry */
486 if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
487 {
488 State->Flags.Zf = FALSE;
489 return;
490 }
491
492 /* Read the GDT */
493 if (!Fast486ReadLinearMemory(State,
494 State->Gdtr.Address
495 + GET_SEGMENT_INDEX(Selector),
496 &GdtEntry,
497 sizeof(GdtEntry)))
498 {
499 /* Exception occurred */
500 return;
501 }
502 }
503 else
504 {
505 /* Check if the LDT contains the entry */
506 if (GET_SEGMENT_INDEX(Selector) >= (State->Ldtr.Limit + 1))
507 {
508 State->Flags.Zf = FALSE;
509 return;
510 }
511
512 /* Read the LDT */
513 if (!Fast486ReadLinearMemory(State,
514 State->Ldtr.Base
515 + GET_SEGMENT_INDEX(Selector),
516 &GdtEntry,
517 sizeof(GdtEntry)))
518 {
519 /* Exception occurred */
520 return;
521 }
522 }
523
524 /* Privilege check */
525 if (((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl))
526 || (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl))
527 {
528 State->Flags.Zf = FALSE;
529 return;
530 }
531
532 /* Calculate the limit */
533 Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
534 if (GdtEntry.Granularity) Limit <<= 12;
535
536 /* Set ZF */
537 State->Flags.Zf = TRUE;
538
539 /* Return the limit */
540 if (OperandSize) Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, Limit);
541 else Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(Limit));
542 }
543
544 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeClts)
545 {
546 NO_LOCK_PREFIX();
547
548 /* The current privilege level must be zero */
549 if (Fast486GetCurrentPrivLevel(State) != 0)
550 {
551 Fast486Exception(State, FAST486_EXCEPTION_GP);
552 return;
553 }
554
555 /* Clear the task switch bit */
556 State->ControlRegisters[FAST486_REG_CR0] &= ~FAST486_CR0_TS;
557 }
558
559 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreControlReg)
560 {
561 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
562 FAST486_MOD_REG_RM ModRegRm;
563
564 NO_LOCK_PREFIX();
565 TOGGLE_ADSIZE(AddressSize);
566
567 /* Get the operands */
568 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
569 {
570 /* Exception occurred */
571 return;
572 }
573
574 /* The current privilege level must be zero */
575 if (Fast486GetCurrentPrivLevel(State) != 0)
576 {
577 Fast486Exception(State, FAST486_EXCEPTION_GP);
578 return;
579 }
580
581 if ((ModRegRm.Register == 1) || (ModRegRm.Register > 3))
582 {
583 /* CR1, CR4, CR5, CR6 and CR7 don't exist */
584 Fast486Exception(State, FAST486_EXCEPTION_UD);
585 return;
586 }
587
588 if (ModRegRm.Register != 0)
589 {
590 /* CR2 and CR3 and are stored in array indexes 1 and 2 */
591 ModRegRm.Register--;
592 }
593
594 /* Store the value of the control register */
595 State->GeneralRegs[ModRegRm.SecondRegister].Long = State->ControlRegisters[ModRegRm.Register];
596 }
597
598 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreDebugReg)
599 {
600 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
601 FAST486_MOD_REG_RM ModRegRm;
602
603 NO_LOCK_PREFIX();
604 TOGGLE_ADSIZE(AddressSize);
605
606 /* Get the operands */
607 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
608 {
609 /* Exception occurred */
610 return;
611 }
612
613 /* The current privilege level must be zero */
614 if (Fast486GetCurrentPrivLevel(State) != 0)
615 {
616 Fast486Exception(State, FAST486_EXCEPTION_GP);
617 return;
618 }
619
620 if ((ModRegRm.Register == 6) || (ModRegRm.Register == 7))
621 {
622 /* DR6 and DR7 are aliases to DR4 and DR5 */
623 ModRegRm.Register -= 2;
624 }
625
626 if (State->DebugRegisters[FAST486_REG_DR5] & FAST486_DR5_GD)
627 {
628 /* Disallow access to debug registers */
629 Fast486Exception(State, FAST486_EXCEPTION_GP);
630 return;
631 }
632
633 /* Store the value of the debug register */
634 State->GeneralRegs[ModRegRm.SecondRegister].Long = State->DebugRegisters[ModRegRm.Register];
635 }
636
637 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadControlReg)
638 {
639 ULONG Value;
640 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
641 FAST486_MOD_REG_RM ModRegRm;
642
643 NO_LOCK_PREFIX();
644 TOGGLE_ADSIZE(AddressSize);
645
646 /* Get the operands */
647 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
648 {
649 /* Exception occurred */
650 return;
651 }
652
653 /* The current privilege level must be zero */
654 if (Fast486GetCurrentPrivLevel(State) != 0)
655 {
656 Fast486Exception(State, FAST486_EXCEPTION_GP);
657 return;
658 }
659
660 if ((ModRegRm.Register == 1) || (ModRegRm.Register > 3))
661 {
662 /* CR1, CR4, CR5, CR6 and CR7 don't exist */
663 Fast486Exception(State, FAST486_EXCEPTION_UD);
664 return;
665 }
666
667 if (ModRegRm.Register != 0)
668 {
669 /* CR2 and CR3 and are stored in array indexes 1 and 2 */
670 ModRegRm.Register--;
671 }
672
673 /* Get the value */
674 Value = State->GeneralRegs[ModRegRm.SecondRegister].Long;
675
676 if (ModRegRm.Register == (INT)FAST486_REG_CR0)
677 {
678 /* CR0 checks */
679
680 if (((Value & (FAST486_CR0_PG | FAST486_CR0_PE)) == FAST486_CR0_PG)
681 || ((Value & (FAST486_CR0_CD | FAST486_CR0_NW)) == FAST486_CR0_NW))
682 {
683 /* Invalid value */
684 Fast486Exception(State, FAST486_EXCEPTION_GP);
685 return;
686 }
687 }
688
689 #ifndef FAST486_NO_PREFETCH
690 /* Changing CR0 or CR3 can interfere with prefetching (because of paging) */
691 State->PrefetchValid = FALSE;
692 #endif
693
694 /* Load a value to the control register */
695 State->ControlRegisters[ModRegRm.Register] = Value;
696 }
697
698 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadDebugReg)
699 {
700 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
701 FAST486_MOD_REG_RM ModRegRm;
702
703 NO_LOCK_PREFIX();
704 TOGGLE_ADSIZE(AddressSize);
705
706 /* Get the operands */
707 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
708 {
709 /* Exception occurred */
710 return;
711 }
712
713 /* The current privilege level must be zero */
714 if (Fast486GetCurrentPrivLevel(State) != 0)
715 {
716 Fast486Exception(State, FAST486_EXCEPTION_GP);
717 return;
718 }
719
720 if ((ModRegRm.Register == 6) || (ModRegRm.Register == 7))
721 {
722 /* DR6 and DR7 are aliases to DR4 and DR5 */
723 ModRegRm.Register -= 2;
724 }
725
726 if (State->DebugRegisters[FAST486_REG_DR5] & FAST486_DR5_GD)
727 {
728 /* Disallow access to debug registers */
729 Fast486Exception(State, FAST486_EXCEPTION_GP);
730 return;
731 }
732
733 /* Load a value to the debug register */
734 State->DebugRegisters[ModRegRm.Register] = State->GeneralRegs[ModRegRm.SecondRegister].Long;
735
736 if (ModRegRm.Register == (INT)FAST486_REG_DR4)
737 {
738 /* The reserved bits are 1 */
739 State->DebugRegisters[ModRegRm.Register] |= FAST486_DR4_RESERVED;
740 }
741 else if (ModRegRm.Register == (INT)FAST486_REG_DR5)
742 {
743 /* The reserved bits are 0 */
744 State->DebugRegisters[ModRegRm.Register] &= ~FAST486_DR5_RESERVED;
745 }
746 }
747
748 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushFs)
749 {
750 /* Call the internal API */
751 Fast486StackPush(State, State->SegmentRegs[FAST486_REG_FS].Selector);
752 }
753
754 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopFs)
755 {
756 ULONG NewSelector;
757
758 if (!Fast486StackPop(State, &NewSelector))
759 {
760 /* Exception occurred */
761 return;
762 }
763
764 /* Call the internal API */
765 Fast486LoadSegment(State, FAST486_REG_FS, LOWORD(NewSelector));
766 }
767
768 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBitTest)
769 {
770 BOOLEAN OperandSize, AddressSize;
771 FAST486_MOD_REG_RM ModRegRm;
772 UINT DataSize;
773 ULONG BitNumber;
774
775 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
776 TOGGLE_OPSIZE(OperandSize);
777 TOGGLE_ADSIZE(AddressSize);
778
779 /* Get the number of bits */
780 if (OperandSize) DataSize = 32;
781 else DataSize = 16;
782
783 /* Get the operands */
784 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
785 {
786 /* Exception occurred */
787 return;
788 }
789
790 /* Get the bit number */
791 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
792 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
793
794 if (ModRegRm.Memory)
795 {
796 /*
797 * For memory operands, add the bit offset divided by
798 * the data size to the address
799 */
800 ModRegRm.MemoryAddress += BitNumber / DataSize;
801 }
802
803 /* Normalize the bit number */
804 BitNumber %= DataSize;
805
806 if (OperandSize)
807 {
808 ULONG Value;
809
810 /* Read the value */
811 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
812 {
813 /* Exception occurred */
814 return;
815 }
816
817 /* Set CF to the bit value */
818 State->Flags.Cf = (Value >> BitNumber) & 1;
819 }
820 else
821 {
822 USHORT Value;
823
824 /* Read the value */
825 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
826 {
827 /* Exception occurred */
828 return;
829 }
830
831 /* Set CF to the bit value */
832 State->Flags.Cf = (Value >> BitNumber) & 1;
833 }
834 }
835
836 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShld)
837 {
838 BOOLEAN OperandSize, AddressSize;
839 FAST486_MOD_REG_RM ModRegRm;
840 UCHAR Count;
841
842 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
843 TOGGLE_OPSIZE(OperandSize);
844 TOGGLE_ADSIZE(AddressSize);
845
846 /* Make sure this is the right instruction */
847 ASSERT((Opcode & 0xFE) == 0xA4);
848
849 /* Get the operands */
850 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
851 {
852 /* Exception occurred */
853 return;
854 }
855
856 if (Opcode == 0xA4)
857 {
858 /* Fetch the count */
859 if (!Fast486FetchByte(State, &Count))
860 {
861 /* Exception occurred */
862 return;
863 }
864 }
865 else
866 {
867 /* The count is in CL */
868 Count = State->GeneralRegs[FAST486_REG_ECX].LowByte;
869 }
870
871 /* Normalize the count */
872 Count &= 0x1F;
873
874 /* Do nothing if the count is zero */
875 if (Count == 0) return;
876
877 if (OperandSize)
878 {
879 ULONG Source, Destination, Result;
880
881 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Source, &Destination))
882 {
883 /* Exception occurred */
884 return;
885 }
886
887 /* Calculate the result */
888 Result = (Destination << Count) | (Source >> (32 - Count));
889
890 /* Update flags */
891 State->Flags.Cf = (Destination >> (32 - Count)) & 1;
892 if (Count == 1) State->Flags.Of = (Result & SIGN_FLAG_LONG)
893 != (Destination & SIGN_FLAG_LONG);
894 State->Flags.Zf = (Result == 0);
895 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
896 State->Flags.Pf = Fast486CalculateParity(Result);
897
898 /* Write back the result */
899 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result);
900 }
901 else
902 {
903 USHORT Source, Destination, Result;
904 ULONG DoubleSource;
905
906 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Source, &Destination))
907 {
908 /* Exception occurred */
909 return;
910 }
911
912 DoubleSource = Source | (Source << 16);
913
914 /* Calculate the result */
915 Result = (Destination << Count) | (DoubleSource >> (32 - Count));
916
917 /* Update flags */
918 if (Count <= 16) State->Flags.Cf = (Destination >> (16 - Count)) & 1;
919 else State->Flags.Cf = (Source >> (32 - Count)) & 1;
920
921 if (Count == 1) State->Flags.Of = (Result & SIGN_FLAG_WORD)
922 != (Destination & SIGN_FLAG_WORD);
923 State->Flags.Zf = (Result == 0);
924 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
925 State->Flags.Pf = Fast486CalculateParity(Result);
926
927 /* Write back the result */
928 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Result);
929 }
930 }
931
932 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushGs)
933 {
934 /* Call the internal API */
935 Fast486StackPush(State, State->SegmentRegs[FAST486_REG_GS].Selector);
936 }
937
938 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopGs)
939 {
940 ULONG NewSelector;
941
942 if (!Fast486StackPop(State, &NewSelector))
943 {
944 /* Exception occurred */
945 return;
946 }
947
948 /* Call the internal API */
949 Fast486LoadSegment(State, FAST486_REG_GS, LOWORD(NewSelector));
950 }
951
952 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBts)
953 {
954 BOOLEAN OperandSize, AddressSize;
955 FAST486_MOD_REG_RM ModRegRm;
956 UINT DataSize;
957 ULONG BitNumber;
958
959 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
960 TOGGLE_OPSIZE(OperandSize);
961 TOGGLE_ADSIZE(AddressSize);
962
963 /* Get the number of bits */
964 if (OperandSize) DataSize = 32;
965 else DataSize = 16;
966
967 /* Get the operands */
968 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
969 {
970 /* Exception occurred */
971 return;
972 }
973
974 /* Get the bit number */
975 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
976 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
977
978 if (ModRegRm.Memory)
979 {
980 /*
981 * For memory operands, add the bit offset divided by
982 * the data size to the address
983 */
984 ModRegRm.MemoryAddress += BitNumber / DataSize;
985 }
986
987 /* Normalize the bit number */
988 BitNumber %= DataSize;
989
990 if (OperandSize)
991 {
992 ULONG Value;
993
994 /* Read the value */
995 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
996 {
997 /* Exception occurred */
998 return;
999 }
1000
1001 /* Set CF to the bit value */
1002 State->Flags.Cf = (Value >> BitNumber) & 1;
1003
1004 /* Set the bit */
1005 Value |= 1 << BitNumber;
1006
1007 /* Write back the result */
1008 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
1009 }
1010 else
1011 {
1012 USHORT Value;
1013
1014 /* Read the value */
1015 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
1016 {
1017 /* Exception occurred */
1018 return;
1019 }
1020
1021 /* Set CF to the bit value */
1022 State->Flags.Cf = (Value >> BitNumber) & 1;
1023
1024 /* Set the bit */
1025 Value |= 1 << BitNumber;
1026
1027 /* Write back the result */
1028 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
1029 }
1030 }
1031
1032 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShrd)
1033 {
1034 BOOLEAN OperandSize, AddressSize;
1035 FAST486_MOD_REG_RM ModRegRm;
1036 UCHAR Count;
1037
1038 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1039 TOGGLE_OPSIZE(OperandSize);
1040 TOGGLE_ADSIZE(AddressSize);
1041
1042 /* Make sure this is the right instruction */
1043 ASSERT((Opcode & 0xFE) == 0xAC);
1044
1045 /* Get the operands */
1046 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1047 {
1048 /* Exception occurred */
1049 return;
1050 }
1051
1052 if (Opcode == 0xAC)
1053 {
1054 /* Fetch the count */
1055 if (!Fast486FetchByte(State, &Count))
1056 {
1057 /* Exception occurred */
1058 return;
1059 }
1060 }
1061 else
1062 {
1063 /* The count is in CL */
1064 Count = State->GeneralRegs[FAST486_REG_ECX].LowByte;
1065 }
1066
1067 /* Normalize the count */
1068 Count &= 0x1F;
1069
1070 /* Do nothing if the count is zero */
1071 if (Count == 0) return;
1072
1073 if (OperandSize)
1074 {
1075 ULONG Source, Destination, Result;
1076
1077 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Source, &Destination))
1078 {
1079 /* Exception occurred */
1080 return;
1081 }
1082
1083 /* Calculate the result */
1084 Result = (Destination >> Count) | (Source << (32 - Count));
1085
1086 /* Update flags */
1087 State->Flags.Cf = (Destination >> (Count - 1)) & 1;
1088 if (Count == 1) State->Flags.Of = (Result & SIGN_FLAG_LONG)
1089 != (Destination & SIGN_FLAG_LONG);
1090 State->Flags.Zf = (Result == 0);
1091 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1092 State->Flags.Pf = Fast486CalculateParity(Result);
1093
1094 /* Write back the result */
1095 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result);
1096 }
1097 else
1098 {
1099 USHORT Source, Destination, Result;
1100
1101 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Source, &Destination))
1102 {
1103 /* Exception occurred */
1104 return;
1105 }
1106
1107 /* Calculate the result */
1108 Result = (Destination >> Count) | (Source << (16 - Count));
1109
1110 if (Count >= 16) Result |= (ULONG)(Source | (Source << 16)) >> (Count - 16);
1111
1112 /* Update flags */
1113 if (Count <= 16) State->Flags.Cf = (Destination >> (Count - 1)) & 1;
1114 else State->Flags.Cf = (Source >> (Count - 17)) & 1;
1115
1116 if (Count == 1) State->Flags.Of = (Result & SIGN_FLAG_WORD)
1117 != (Destination & SIGN_FLAG_WORD);
1118 State->Flags.Zf = (Result == 0);
1119 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1120 State->Flags.Pf = Fast486CalculateParity(Result);
1121
1122 /* Write back the result */
1123 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Result);
1124 }
1125 }
1126
1127 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeImul)
1128 {
1129 BOOLEAN OperandSize, AddressSize;
1130 FAST486_MOD_REG_RM ModRegRm;
1131
1132 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1133
1134 TOGGLE_OPSIZE(OperandSize);
1135 TOGGLE_ADSIZE(AddressSize);
1136
1137 /* Get the operands */
1138 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1139 {
1140 /* Exception occurred */
1141 return;
1142 }
1143
1144 if (OperandSize)
1145 {
1146 LONG Source, Destination;
1147 LONGLONG Result;
1148
1149 /* Read the operands */
1150 if (!Fast486ReadModrmDwordOperands(State,
1151 &ModRegRm,
1152 (PULONG)&Destination,
1153 (PULONG)&Source))
1154 {
1155 /* Exception occurred */
1156 return;
1157 }
1158
1159 /* Calculate the result */
1160 Result = (LONGLONG)Source * (LONGLONG)Destination;
1161
1162 /* Update the flags */
1163 State->Flags.Cf = State->Flags.Of = ((Result < -2147483648LL) || (Result > 2147483647LL));
1164
1165 /* Write back the result */
1166 Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, (ULONG)((LONG)Result));
1167 }
1168 else
1169 {
1170 SHORT Source, Destination;
1171 LONG Result;
1172
1173 /* Read the operands */
1174 if (!Fast486ReadModrmWordOperands(State,
1175 &ModRegRm,
1176 (PUSHORT)&Destination,
1177 (PUSHORT)&Source))
1178 {
1179 /* Exception occurred */
1180 return;
1181 }
1182
1183 /* Calculate the result */
1184 Result = (LONG)Source * (LONG)Destination;
1185
1186 /* Update the flags */
1187 State->Flags.Cf = State->Flags.Of = ((Result < -32768) || (Result > 32767));
1188
1189 /* Write back the result */
1190 Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, (USHORT)((SHORT)Result));
1191 }
1192 }
1193
1194 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchgByte)
1195 {
1196 FAST486_MOD_REG_RM ModRegRm;
1197 UCHAR Accumulator = State->GeneralRegs[FAST486_REG_EAX].LowByte;
1198 UCHAR Source, Destination, Result;
1199 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1200
1201 TOGGLE_ADSIZE(AddressSize);
1202
1203 /* Get the operands */
1204 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1205 {
1206 /* Exception occurred */
1207 return;
1208 }
1209
1210 /* Read the operands */
1211 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, &Source, &Destination))
1212 {
1213 /* Exception occurred */
1214 return;
1215 }
1216
1217 /* Compare AL with the destination */
1218 Result = Accumulator - Destination;
1219
1220 /* Update the flags */
1221 State->Flags.Cf = (Accumulator < Destination);
1222 State->Flags.Of = ((Accumulator & SIGN_FLAG_BYTE) != (Destination & SIGN_FLAG_BYTE))
1223 && ((Accumulator & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
1224 State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F);
1225 State->Flags.Zf = (Result == 0);
1226 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1227 State->Flags.Pf = Fast486CalculateParity(Result);
1228
1229 if (State->Flags.Zf)
1230 {
1231 /* Load the source operand into the destination */
1232 Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Source);
1233 }
1234 else
1235 {
1236 /* Load the destination into AL */
1237 State->GeneralRegs[FAST486_REG_EAX].LowByte = Destination;
1238 }
1239 }
1240
1241 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchg)
1242 {
1243 FAST486_MOD_REG_RM ModRegRm;
1244 BOOLEAN OperandSize, AddressSize;
1245
1246 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1247
1248 TOGGLE_OPSIZE(OperandSize);
1249 TOGGLE_ADSIZE(AddressSize);
1250
1251 /* Get the operands */
1252 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1253 {
1254 /* Exception occurred */
1255 return;
1256 }
1257
1258 if (OperandSize)
1259 {
1260 ULONG Source, Destination, Result;
1261 ULONG Accumulator = State->GeneralRegs[FAST486_REG_EAX].Long;
1262
1263 /* Read the operands */
1264 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Source, &Destination))
1265 {
1266 /* Exception occurred */
1267 return;
1268 }
1269
1270 /* Compare EAX with the destination */
1271 Result = Accumulator - Destination;
1272
1273 /* Update the flags */
1274 State->Flags.Cf = (Accumulator < Destination);
1275 State->Flags.Of = ((Accumulator & SIGN_FLAG_LONG) != (Destination & SIGN_FLAG_LONG))
1276 && ((Accumulator & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
1277 State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F);
1278 State->Flags.Zf = (Result == 0);
1279 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1280 State->Flags.Pf = Fast486CalculateParity(Result);
1281
1282 if (State->Flags.Zf)
1283 {
1284 /* Load the source operand into the destination */
1285 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Source);
1286 }
1287 else
1288 {
1289 /* Load the destination into EAX */
1290 State->GeneralRegs[FAST486_REG_EAX].Long = Destination;
1291 }
1292 }
1293 else
1294 {
1295 USHORT Source, Destination, Result;
1296 USHORT Accumulator = State->GeneralRegs[FAST486_REG_EAX].LowWord;
1297
1298 /* Read the operands */
1299 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Source, &Destination))
1300 {
1301 /* Exception occurred */
1302 return;
1303 }
1304
1305 /* Compare AX with the destination */
1306 Result = Accumulator - Destination;
1307
1308 /* Update the flags */
1309 State->Flags.Cf = (Accumulator < Destination);
1310 State->Flags.Of = ((Accumulator & SIGN_FLAG_WORD) != (Destination & SIGN_FLAG_WORD))
1311 && ((Accumulator & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
1312 State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F);
1313 State->Flags.Zf = (Result == 0);
1314 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1315 State->Flags.Pf = Fast486CalculateParity(Result);
1316
1317 if (State->Flags.Zf)
1318 {
1319 /* Load the source operand into the destination */
1320 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Source);
1321 }
1322 else
1323 {
1324 /* Load the destination into AX */
1325 State->GeneralRegs[FAST486_REG_EAX].LowWord = Destination;
1326 }
1327 }
1328 }
1329
1330 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLss)
1331 {
1332 UCHAR FarPointer[6];
1333 BOOLEAN OperandSize, AddressSize;
1334 FAST486_MOD_REG_RM ModRegRm;
1335
1336 /* Make sure this is the right instruction */
1337 ASSERT(Opcode == 0xB2);
1338
1339 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1340
1341 TOGGLE_OPSIZE(OperandSize);
1342 TOGGLE_ADSIZE(AddressSize);
1343
1344 /* Get the operands */
1345 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1346 {
1347 /* Exception occurred */
1348 return;
1349 }
1350
1351 if (!ModRegRm.Memory)
1352 {
1353 /* Invalid */
1354 Fast486Exception(State, FAST486_EXCEPTION_UD);
1355 return;
1356 }
1357
1358 if (!Fast486ReadMemory(State,
1359 (State->PrefixFlags & FAST486_PREFIX_SEG)
1360 ? State->SegmentOverride : FAST486_REG_DS,
1361 ModRegRm.MemoryAddress,
1362 FALSE,
1363 FarPointer,
1364 OperandSize ? 6 : 4))
1365 {
1366 /* Exception occurred */
1367 return;
1368 }
1369
1370 if (OperandSize)
1371 {
1372 ULONG Offset = *((PULONG)FarPointer);
1373 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(ULONG)]);
1374
1375 /* Set the register to the offset */
1376 State->GeneralRegs[ModRegRm.Register].Long = Offset;
1377
1378 /* Load the segment */
1379 Fast486LoadSegment(State, FAST486_REG_SS, Segment);
1380 }
1381 else
1382 {
1383 USHORT Offset = *((PUSHORT)FarPointer);
1384 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(USHORT)]);
1385
1386 /* Set the register to the offset */
1387 State->GeneralRegs[ModRegRm.Register].LowWord = Offset;
1388
1389 /* Load the segment */
1390 Fast486LoadSegment(State, FAST486_REG_SS, Segment);
1391 }
1392 }
1393
1394 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtr)
1395 {
1396 BOOLEAN OperandSize, AddressSize;
1397 FAST486_MOD_REG_RM ModRegRm;
1398 UINT DataSize;
1399 ULONG BitNumber;
1400
1401 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1402 TOGGLE_OPSIZE(OperandSize);
1403 TOGGLE_ADSIZE(AddressSize);
1404
1405 /* Get the number of bits */
1406 if (OperandSize) DataSize = 32;
1407 else DataSize = 16;
1408
1409 /* Get the operands */
1410 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1411 {
1412 /* Exception occurred */
1413 return;
1414 }
1415
1416 /* Get the bit number */
1417 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
1418 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
1419
1420 if (ModRegRm.Memory)
1421 {
1422 /*
1423 * For memory operands, add the bit offset divided by
1424 * the data size to the address
1425 */
1426 ModRegRm.MemoryAddress += BitNumber / DataSize;
1427 }
1428
1429 /* Normalize the bit number */
1430 BitNumber %= DataSize;
1431
1432 if (OperandSize)
1433 {
1434 ULONG Value;
1435
1436 /* Read the value */
1437 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1438 {
1439 /* Exception occurred */
1440 return;
1441 }
1442
1443 /* Set CF to the bit value */
1444 State->Flags.Cf = (Value >> BitNumber) & 1;
1445
1446 /* Clear the bit */
1447 Value &= ~(1 << BitNumber);
1448
1449 /* Write back the result */
1450 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
1451 }
1452 else
1453 {
1454 USHORT Value;
1455
1456 /* Read the value */
1457 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
1458 {
1459 /* Exception occurred */
1460 return;
1461 }
1462
1463 /* Set CF to the bit value */
1464 State->Flags.Cf = (Value >> BitNumber) & 1;
1465
1466 /* Clear the bit */
1467 Value &= ~(1 << BitNumber);
1468
1469 /* Write back the result */
1470 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
1471 }
1472 }
1473
1474 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLfsLgs)
1475 {
1476 UCHAR FarPointer[6];
1477 BOOLEAN OperandSize, AddressSize;
1478 FAST486_MOD_REG_RM ModRegRm;
1479
1480 /* Make sure this is the right instruction */
1481 ASSERT((Opcode & 0xFE) == 0xB4);
1482
1483 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1484
1485 TOGGLE_OPSIZE(OperandSize);
1486 TOGGLE_ADSIZE(AddressSize);
1487
1488 /* Get the operands */
1489 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1490 {
1491 /* Exception occurred */
1492 return;
1493 }
1494
1495 if (!ModRegRm.Memory)
1496 {
1497 /* Invalid */
1498 Fast486Exception(State, FAST486_EXCEPTION_UD);
1499 return;
1500 }
1501
1502 if (!Fast486ReadMemory(State,
1503 (State->PrefixFlags & FAST486_PREFIX_SEG)
1504 ? State->SegmentOverride : FAST486_REG_DS,
1505 ModRegRm.MemoryAddress,
1506 FALSE,
1507 FarPointer,
1508 OperandSize ? 6 : 4))
1509 {
1510 /* Exception occurred */
1511 return;
1512 }
1513
1514 if (OperandSize)
1515 {
1516 ULONG Offset = *((PULONG)FarPointer);
1517 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(ULONG)]);
1518
1519 /* Set the register to the offset */
1520 State->GeneralRegs[ModRegRm.Register].Long = Offset;
1521
1522 /* Load the segment */
1523 Fast486LoadSegment(State,
1524 (Opcode == 0xB4)
1525 ? FAST486_REG_FS : FAST486_REG_GS,
1526 Segment);
1527 }
1528 else
1529 {
1530 USHORT Offset = *((PUSHORT)FarPointer);
1531 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(USHORT)]);
1532
1533 /* Set the register to the offset */
1534 State->GeneralRegs[ModRegRm.Register].LowWord = Offset;
1535
1536 /* Load the segment */
1537 Fast486LoadSegment(State,
1538 (Opcode == 0xB4)
1539 ? FAST486_REG_FS : FAST486_REG_GS,
1540 Segment);
1541 }
1542 }
1543
1544 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxByte)
1545 {
1546 UCHAR Value;
1547 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1548 FAST486_MOD_REG_RM ModRegRm;
1549
1550 TOGGLE_ADSIZE(AddressSize);
1551
1552 /* Make sure this is the right instruction */
1553 ASSERT(Opcode == 0xB6);
1554
1555 /* Get the operands */
1556 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1557 {
1558 /* Exception occurred */
1559 return;
1560 }
1561
1562 /* Read the operands */
1563 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
1564 {
1565 /* Exception occurred */
1566 return;
1567 }
1568
1569 /* Write back the zero-extended value */
1570 Fast486WriteModrmDwordOperands(State,
1571 &ModRegRm,
1572 TRUE,
1573 (ULONG)Value);
1574 }
1575
1576 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxWord)
1577 {
1578 USHORT Value;
1579 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1580 FAST486_MOD_REG_RM ModRegRm;
1581
1582 TOGGLE_ADSIZE(AddressSize);
1583
1584 /* Make sure this is the right instruction */
1585 ASSERT(Opcode == 0xB7);
1586
1587 /* Get the operands */
1588 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1589 {
1590 /* Exception occurred */
1591 return;
1592 }
1593
1594 /* Read the operands */
1595 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
1596 {
1597 /* Exception occurred */
1598 return;
1599 }
1600
1601 /* Write back the zero-extended value */
1602 Fast486WriteModrmDwordOperands(State,
1603 &ModRegRm,
1604 TRUE,
1605 (ULONG)Value);
1606 }
1607
1608 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtc)
1609 {
1610 BOOLEAN OperandSize, AddressSize;
1611 FAST486_MOD_REG_RM ModRegRm;
1612 UINT DataSize;
1613 ULONG BitNumber;
1614
1615 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1616 TOGGLE_OPSIZE(OperandSize);
1617 TOGGLE_ADSIZE(AddressSize);
1618
1619 /* Get the number of bits */
1620 if (OperandSize) DataSize = 32;
1621 else DataSize = 16;
1622
1623 /* Get the operands */
1624 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1625 {
1626 /* Exception occurred */
1627 return;
1628 }
1629
1630 /* Get the bit number */
1631 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
1632 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
1633
1634 if (ModRegRm.Memory)
1635 {
1636 /*
1637 * For memory operands, add the bit offset divided by
1638 * the data size to the address
1639 */
1640 ModRegRm.MemoryAddress += BitNumber / DataSize;
1641 }
1642
1643 /* Normalize the bit number */
1644 BitNumber %= DataSize;
1645
1646 if (OperandSize)
1647 {
1648 ULONG Value;
1649
1650 /* Read the value */
1651 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1652 {
1653 /* Exception occurred */
1654 return;
1655 }
1656
1657 /* Set CF to the bit value */
1658 State->Flags.Cf = (Value >> BitNumber) & 1;
1659
1660 /* Toggle the bit */
1661 Value ^= 1 << BitNumber;
1662
1663 /* Write back the result */
1664 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
1665 }
1666 else
1667 {
1668 USHORT Value;
1669
1670 /* Read the value */
1671 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
1672 {
1673 /* Exception occurred */
1674 return;
1675 }
1676
1677 /* Set CF to the bit value */
1678 State->Flags.Cf = (Value >> BitNumber) & 1;
1679
1680 /* Toggle the bit */
1681 Value ^= 1 << BitNumber;
1682
1683 /* Write back the result */
1684 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
1685 }
1686 }
1687
1688 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsf)
1689 {
1690 INT i;
1691 ULONG Value = 0;
1692 BOOLEAN OperandSize, AddressSize;
1693 FAST486_MOD_REG_RM ModRegRm;
1694 ULONG BitNumber;
1695 UINT DataSize;
1696
1697 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1698 TOGGLE_OPSIZE(OperandSize);
1699 TOGGLE_ADSIZE(AddressSize);
1700
1701 /* Make sure this is the right instruction */
1702 ASSERT(Opcode == 0xBC);
1703
1704 /* Get the number of bits */
1705 if (OperandSize) DataSize = 32;
1706 else DataSize = 16;
1707
1708 /* Get the operands */
1709 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1710 {
1711 /* Exception occurred */
1712 return;
1713 }
1714
1715 /* Read the value */
1716 if (OperandSize)
1717 {
1718 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1719 {
1720 /* Exception occurred */
1721 return;
1722 }
1723 }
1724 else
1725 {
1726 if (!Fast486ReadModrmWordOperands(State,
1727 &ModRegRm,
1728 (PUSHORT)NULL,
1729 (PUSHORT)&Value))
1730 {
1731 /* Exception occurred */
1732 return;
1733 }
1734 }
1735
1736 /* Set ZF */
1737 State->Flags.Zf = (Value == 0);
1738 if (State->Flags.Zf) return;
1739
1740 for (i = 0; i < DataSize; i++)
1741 {
1742 if(Value & (1 << i))
1743 {
1744 /* Save the bit number */
1745 BitNumber = i;
1746
1747 /* Exit the loop */
1748 break;
1749 }
1750 }
1751
1752 /* Write back the result */
1753 if (OperandSize) Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, BitNumber);
1754 else Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(BitNumber));
1755 }
1756
1757 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsr)
1758 {
1759 INT i;
1760 ULONG Value = 0;
1761 BOOLEAN OperandSize, AddressSize;
1762 FAST486_MOD_REG_RM ModRegRm;
1763 ULONG BitNumber;
1764 UINT DataSize;
1765
1766 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1767 TOGGLE_OPSIZE(OperandSize);
1768 TOGGLE_ADSIZE(AddressSize);
1769
1770 /* Make sure this is the right instruction */
1771 ASSERT(Opcode == 0xBD);
1772
1773 /* Get the number of bits */
1774 if (OperandSize) DataSize = 32;
1775 else DataSize = 16;
1776
1777 /* Get the operands */
1778 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1779 {
1780 /* Exception occurred */
1781 return;
1782 }
1783
1784 /* Read the value */
1785 if (OperandSize)
1786 {
1787 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1788 {
1789 /* Exception occurred */
1790 return;
1791 }
1792 }
1793 else
1794 {
1795 if (!Fast486ReadModrmWordOperands(State,
1796 &ModRegRm,
1797 (PUSHORT)NULL,
1798 (PUSHORT)&Value))
1799 {
1800 /* Exception occurred */
1801 return;
1802 }
1803 }
1804
1805 /* Set ZF according to the value */
1806 State->Flags.Zf = (Value == 0);
1807 if (State->Flags.Zf) return;
1808
1809 for (i = DataSize - 1; i >= 0; i--)
1810 {
1811 if(Value & (1 << i))
1812 {
1813 /* Save the bit number */
1814 BitNumber = i;
1815
1816 /* Exit the loop */
1817 break;
1818 }
1819 }
1820
1821 /* Write back the result */
1822 if (OperandSize) Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, BitNumber);
1823 else Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(BitNumber));
1824 }
1825
1826 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxByte)
1827 {
1828 CHAR Value;
1829 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1830 FAST486_MOD_REG_RM ModRegRm;
1831
1832 TOGGLE_ADSIZE(AddressSize);
1833
1834 /* Make sure this is the right instruction */
1835 ASSERT(Opcode == 0xBE);
1836
1837 /* Get the operands */
1838 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1839 {
1840 /* Exception occurred */
1841 return;
1842 }
1843
1844 /* Read the operands */
1845 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, (PUCHAR)&Value))
1846 {
1847 /* Exception occurred */
1848 return;
1849 }
1850
1851 /* Write back the sign-extended value */
1852 Fast486WriteModrmDwordOperands(State,
1853 &ModRegRm,
1854 TRUE,
1855 (ULONG)((LONG)Value));
1856 }
1857
1858 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxWord)
1859 {
1860 SHORT Value;
1861 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1862 FAST486_MOD_REG_RM ModRegRm;
1863
1864 TOGGLE_ADSIZE(AddressSize);
1865
1866 /* Make sure this is the right instruction */
1867 ASSERT(Opcode == 0xBF);
1868
1869 /* Get the operands */
1870 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1871 {
1872 /* Exception occurred */
1873 return;
1874 }
1875
1876 /* Read the operands */
1877 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, (PUSHORT)&Value))
1878 {
1879 /* Exception occurred */
1880 return;
1881 }
1882
1883 /* Write back the sign-extended value */
1884 Fast486WriteModrmDwordOperands(State,
1885 &ModRegRm,
1886 TRUE,
1887 (ULONG)((LONG)Value));
1888 }
1889
1890 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalJmp)
1891 {
1892 BOOLEAN Jump = FALSE;
1893 LONG Offset = 0;
1894 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1895
1896 TOGGLE_OPSIZE(Size);
1897 NO_LOCK_PREFIX();
1898
1899 /* Make sure this is the right instruction */
1900 ASSERT((Opcode & 0xF0) == 0x80);
1901
1902 /* Fetch the offset */
1903 if (Size)
1904 {
1905 if (!Fast486FetchDword(State, (PULONG)&Offset))
1906 {
1907 /* Exception occurred */
1908 return;
1909 }
1910 }
1911 else
1912 {
1913 SHORT Value;
1914
1915 if (!Fast486FetchWord(State, (PUSHORT)&Value))
1916 {
1917 /* Exception occurred */
1918 return;
1919 }
1920
1921 /* Sign-extend */
1922 Offset = (LONG)Value;
1923 }
1924
1925 switch ((Opcode & 0x0F) >> 1)
1926 {
1927 /* JO / JNO */
1928 case 0:
1929 {
1930 Jump = State->Flags.Of;
1931 break;
1932 }
1933
1934 /* JC / JNC */
1935 case 1:
1936 {
1937 Jump = State->Flags.Cf;
1938 break;
1939 }
1940
1941 /* JZ / JNZ */
1942 case 2:
1943 {
1944 Jump = State->Flags.Zf;
1945 break;
1946 }
1947
1948 /* JBE / JNBE */
1949 case 3:
1950 {
1951 Jump = State->Flags.Cf || State->Flags.Zf;
1952 break;
1953 }
1954
1955 /* JS / JNS */
1956 case 4:
1957 {
1958 Jump = State->Flags.Sf;
1959 break;
1960 }
1961
1962 /* JP / JNP */
1963 case 5:
1964 {
1965 Jump = State->Flags.Pf;
1966 break;
1967 }
1968
1969 /* JL / JNL */
1970 case 6:
1971 {
1972 Jump = State->Flags.Sf != State->Flags.Of;
1973 break;
1974 }
1975
1976 /* JLE / JNLE */
1977 case 7:
1978 {
1979 Jump = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
1980 break;
1981 }
1982 }
1983
1984 if (Opcode & 1)
1985 {
1986 /* Invert the result */
1987 Jump = !Jump;
1988 }
1989
1990 if (Jump)
1991 {
1992 /* Move the instruction pointer */
1993 State->InstPtr.Long += Offset;
1994 }
1995 }
1996
1997 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalSet)
1998 {
1999 BOOLEAN Value = FALSE;
2000 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2001 FAST486_MOD_REG_RM ModRegRm;
2002
2003 TOGGLE_ADSIZE(AddressSize);
2004
2005 /* Get the operands */
2006 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2007 {
2008 /* Exception occurred */
2009 return;
2010 }
2011
2012 /* Make sure this is the right instruction */
2013 ASSERT((Opcode & 0xF0) == 0x90);
2014
2015 switch ((Opcode & 0x0F) >> 1)
2016 {
2017 /* SETO / SETNO */
2018 case 0:
2019 {
2020 Value = State->Flags.Of;
2021 break;
2022 }
2023
2024 /* SETC / SETNC */
2025 case 1:
2026 {
2027 Value = State->Flags.Cf;
2028 break;
2029 }
2030
2031 /* SETZ / SETNZ */
2032 case 2:
2033 {
2034 Value = State->Flags.Zf;
2035 break;
2036 }
2037
2038 /* SETBE / SETNBE */
2039 case 3:
2040 {
2041 Value = State->Flags.Cf || State->Flags.Zf;
2042 break;
2043 }
2044
2045 /* SETS / SETNS */
2046 case 4:
2047 {
2048 Value = State->Flags.Sf;
2049 break;
2050 }
2051
2052 /* SETP / SETNP */
2053 case 5:
2054 {
2055 Value = State->Flags.Pf;
2056 break;
2057 }
2058
2059 /* SETL / SETNL */
2060 case 6:
2061 {
2062 Value = State->Flags.Sf != State->Flags.Of;
2063 break;
2064 }
2065
2066 /* SETLE / SETNLE */
2067 case 7:
2068 {
2069 Value = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
2070 break;
2071 }
2072 }
2073
2074 if (Opcode & 1)
2075 {
2076 /* Invert the result */
2077 Value = !Value;
2078 }
2079
2080 /* Write back the result */
2081 Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
2082 }
2083
2084 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXaddByte)
2085 {
2086 UCHAR Source, Destination, Result;
2087 FAST486_MOD_REG_RM ModRegRm;
2088 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2089
2090 /* Make sure this is the right instruction */
2091 ASSERT(Opcode == 0xC0);
2092
2093 TOGGLE_ADSIZE(AddressSize);
2094
2095 /* Get the operands */
2096 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2097 {
2098 /* Exception occurred */
2099 return;
2100 }
2101
2102 if (!Fast486ReadModrmByteOperands(State,
2103 &ModRegRm,
2104 &Source,
2105 &Destination))
2106 {
2107 /* Exception occurred */
2108 return;
2109 }
2110
2111 /* Calculate the result */
2112 Result = Source + Destination;
2113
2114 /* Update the flags */
2115 State->Flags.Cf = (Result < Source) && (Result < Destination);
2116 State->Flags.Of = ((Source & SIGN_FLAG_BYTE) == (Destination & SIGN_FLAG_BYTE))
2117 && ((Source & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
2118 State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0);
2119 State->Flags.Zf = (Result == 0);
2120 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2121 State->Flags.Pf = Fast486CalculateParity(Result);
2122
2123 /* Write the sum to the destination */
2124 if (!Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Result))
2125 {
2126 /* Exception occurred */
2127 return;
2128 }
2129
2130 /* Write the old value of the destination to the source */
2131 Fast486WriteModrmByteOperands(State, &ModRegRm, TRUE, Destination);
2132 }
2133
2134 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXadd)
2135 {
2136 FAST486_MOD_REG_RM ModRegRm;
2137 BOOLEAN OperandSize, AddressSize;
2138
2139 /* Make sure this is the right instruction */
2140 ASSERT(Opcode == 0xC1);
2141
2142 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2143
2144 TOGGLE_ADSIZE(AddressSize);
2145 TOGGLE_OPSIZE(OperandSize);
2146
2147 /* Get the operands */
2148 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2149 {
2150 /* Exception occurred */
2151 return;
2152 }
2153
2154 /* Check the operand size */
2155 if (OperandSize)
2156 {
2157 ULONG Source, Destination, Result;
2158
2159 if (!Fast486ReadModrmDwordOperands(State,
2160 &ModRegRm,
2161 &Source,
2162 &Destination))
2163 {
2164 /* Exception occurred */
2165 return;
2166 }
2167
2168 /* Calculate the result */
2169 Result = Source + Destination;
2170
2171 /* Update the flags */
2172 State->Flags.Cf = (Result < Source) && (Result < Destination);
2173 State->Flags.Of = ((Source & SIGN_FLAG_LONG) == (Destination & SIGN_FLAG_LONG))
2174 && ((Source & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
2175 State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0);
2176 State->Flags.Zf = (Result == 0);
2177 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2178 State->Flags.Pf = Fast486CalculateParity(Result);
2179
2180 /* Write the old value of the destination to the source */
2181 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, Destination))
2182 {
2183 /* Exception occurred */
2184 return;
2185 }
2186
2187 /* Write the sum to the destination */
2188 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result);
2189 }
2190 else
2191 {
2192 USHORT Source, Destination, Result;
2193
2194 if (!Fast486ReadModrmWordOperands(State,
2195 &ModRegRm,
2196 &Source,
2197 &Destination))
2198 {
2199 /* Exception occurred */
2200 return;
2201 }
2202
2203 /* Calculate the result */
2204 Result = Source + Destination;
2205
2206 /* Update the flags */
2207 State->Flags.Cf = (Result < Source) && (Result < Destination);
2208 State->Flags.Of = ((Source & SIGN_FLAG_WORD) == (Destination & SIGN_FLAG_WORD))
2209 && ((Source & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
2210 State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0);
2211 State->Flags.Zf = (Result == 0);
2212 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2213 State->Flags.Pf = Fast486CalculateParity(Result);
2214
2215 /* Write the old value of the destination to the source */
2216 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, Destination))
2217 {
2218 /* Exception occurred */
2219 return;
2220 }
2221
2222 /* Write the sum to the destination */
2223 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Result);
2224 }
2225 }
2226
2227 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBswap)
2228 {
2229 PUCHAR Pointer;
2230
2231 NO_LOCK_PREFIX();
2232
2233 /* Get a pointer to the value */
2234 Pointer = (PUCHAR)&State->GeneralRegs[Opcode & 0x07].Long;
2235
2236 /* Swap the byte order */
2237 SWAP(Pointer[0], Pointer[3]);
2238 SWAP(Pointer[1], Pointer[2]);
2239 }
2240
2241 FAST486_OPCODE_HANDLER(Fast486OpcodeExtended)
2242 {
2243 UCHAR SecondOpcode;
2244
2245 /* Fetch the second operation code */
2246 if (!Fast486FetchByte(State, &SecondOpcode))
2247 {
2248 /* Exception occurred */
2249 return;
2250 }
2251
2252 /* Call the extended opcode handler */
2253 Fast486ExtendedHandlers[SecondOpcode](State, SecondOpcode);
2254 }
2255
2256 /* EOF */