* Sync up to trunk head (r64995).
[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 /* Load a value to the control register */
690 State->ControlRegisters[ModRegRm.Register] = Value;
691 }
692
693 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadDebugReg)
694 {
695 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
696 FAST486_MOD_REG_RM ModRegRm;
697
698 NO_LOCK_PREFIX();
699 TOGGLE_ADSIZE(AddressSize);
700
701 /* Get the operands */
702 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
703 {
704 /* Exception occurred */
705 return;
706 }
707
708 /* The current privilege level must be zero */
709 if (Fast486GetCurrentPrivLevel(State) != 0)
710 {
711 Fast486Exception(State, FAST486_EXCEPTION_GP);
712 return;
713 }
714
715 if ((ModRegRm.Register == 6) || (ModRegRm.Register == 7))
716 {
717 /* DR6 and DR7 are aliases to DR4 and DR5 */
718 ModRegRm.Register -= 2;
719 }
720
721 if (State->DebugRegisters[FAST486_REG_DR5] & FAST486_DR5_GD)
722 {
723 /* Disallow access to debug registers */
724 Fast486Exception(State, FAST486_EXCEPTION_GP);
725 return;
726 }
727
728 /* Load a value to the debug register */
729 State->DebugRegisters[ModRegRm.Register] = State->GeneralRegs[ModRegRm.SecondRegister].Long;
730
731 if (ModRegRm.Register == (INT)FAST486_REG_DR4)
732 {
733 /* The reserved bits are 1 */
734 State->DebugRegisters[ModRegRm.Register] |= FAST486_DR4_RESERVED;
735 }
736 else if (ModRegRm.Register == (INT)FAST486_REG_DR5)
737 {
738 /* The reserved bits are 0 */
739 State->DebugRegisters[ModRegRm.Register] &= ~FAST486_DR5_RESERVED;
740 }
741 }
742
743 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushFs)
744 {
745 /* Call the internal API */
746 Fast486StackPush(State, State->SegmentRegs[FAST486_REG_FS].Selector);
747 }
748
749 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopFs)
750 {
751 ULONG NewSelector;
752
753 if (!Fast486StackPop(State, &NewSelector))
754 {
755 /* Exception occurred */
756 return;
757 }
758
759 /* Call the internal API */
760 Fast486LoadSegment(State, FAST486_REG_FS, LOWORD(NewSelector));
761 }
762
763 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBitTest)
764 {
765 BOOLEAN OperandSize, AddressSize;
766 FAST486_MOD_REG_RM ModRegRm;
767 UINT DataSize;
768 ULONG BitNumber;
769
770 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
771 TOGGLE_OPSIZE(OperandSize);
772 TOGGLE_ADSIZE(AddressSize);
773
774 /* Get the number of bits */
775 if (OperandSize) DataSize = 32;
776 else DataSize = 16;
777
778 /* Get the operands */
779 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
780 {
781 /* Exception occurred */
782 return;
783 }
784
785 /* Get the bit number */
786 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
787 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
788
789 if (ModRegRm.Memory)
790 {
791 /*
792 * For memory operands, add the bit offset divided by
793 * the data size to the address
794 */
795 ModRegRm.MemoryAddress += BitNumber / DataSize;
796 }
797
798 /* Normalize the bit number */
799 BitNumber %= DataSize;
800
801 if (OperandSize)
802 {
803 ULONG Value;
804
805 /* Read the value */
806 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
807 {
808 /* Exception occurred */
809 return;
810 }
811
812 /* Set CF to the bit value */
813 State->Flags.Cf = (Value >> BitNumber) & 1;
814 }
815 else
816 {
817 USHORT Value;
818
819 /* Read the value */
820 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
821 {
822 /* Exception occurred */
823 return;
824 }
825
826 /* Set CF to the bit value */
827 State->Flags.Cf = (Value >> BitNumber) & 1;
828 }
829 }
830
831 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShld)
832 {
833 BOOLEAN OperandSize, AddressSize;
834 FAST486_MOD_REG_RM ModRegRm;
835 UCHAR Count;
836
837 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
838 TOGGLE_OPSIZE(OperandSize);
839 TOGGLE_ADSIZE(AddressSize);
840
841 /* Make sure this is the right instruction */
842 ASSERT((Opcode & 0xFE) == 0xA4);
843
844 /* Get the operands */
845 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
846 {
847 /* Exception occurred */
848 return;
849 }
850
851 if (Opcode == 0xA4)
852 {
853 /* Fetch the count */
854 if (!Fast486FetchByte(State, &Count))
855 {
856 /* Exception occurred */
857 return;
858 }
859 }
860 else
861 {
862 /* The count is in CL */
863 Count = State->GeneralRegs[FAST486_REG_ECX].LowByte;
864 }
865
866 /* Normalize the count */
867 Count &= 0x1F;
868
869 /* Do nothing if the count is zero */
870 if (Count == 0) return;
871
872 if (OperandSize)
873 {
874 ULONG Source, Destination, Result;
875
876 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Source, &Destination))
877 {
878 /* Exception occurred */
879 return;
880 }
881
882 /* Calculate the result */
883 Result = (Destination << Count) | (Source >> (32 - Count));
884
885 /* Update flags */
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);
892
893 /* Write back the result */
894 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result);
895 }
896 else
897 {
898 USHORT Source, Destination, Result;
899 ULONG DoubleSource;
900
901 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Source, &Destination))
902 {
903 /* Exception occurred */
904 return;
905 }
906
907 DoubleSource = Source | (Source << 16);
908
909 /* Calculate the result */
910 Result = (Destination << Count) | (DoubleSource >> (32 - Count));
911
912 /* Update flags */
913 if (Count <= 16) State->Flags.Cf = (Destination >> (16 - Count)) & 1;
914 else State->Flags.Cf = (Source >> (32 - Count)) & 1;
915
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);
921
922 /* Write back the result */
923 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Result);
924 }
925 }
926
927 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushGs)
928 {
929 /* Call the internal API */
930 Fast486StackPush(State, State->SegmentRegs[FAST486_REG_GS].Selector);
931 }
932
933 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopGs)
934 {
935 ULONG NewSelector;
936
937 if (!Fast486StackPop(State, &NewSelector))
938 {
939 /* Exception occurred */
940 return;
941 }
942
943 /* Call the internal API */
944 Fast486LoadSegment(State, FAST486_REG_GS, LOWORD(NewSelector));
945 }
946
947 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBts)
948 {
949 BOOLEAN OperandSize, AddressSize;
950 FAST486_MOD_REG_RM ModRegRm;
951 UINT DataSize;
952 ULONG BitNumber;
953
954 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
955 TOGGLE_OPSIZE(OperandSize);
956 TOGGLE_ADSIZE(AddressSize);
957
958 /* Get the number of bits */
959 if (OperandSize) DataSize = 32;
960 else DataSize = 16;
961
962 /* Get the operands */
963 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
964 {
965 /* Exception occurred */
966 return;
967 }
968
969 /* Get the bit number */
970 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
971 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
972
973 if (ModRegRm.Memory)
974 {
975 /*
976 * For memory operands, add the bit offset divided by
977 * the data size to the address
978 */
979 ModRegRm.MemoryAddress += BitNumber / DataSize;
980 }
981
982 /* Normalize the bit number */
983 BitNumber %= DataSize;
984
985 if (OperandSize)
986 {
987 ULONG Value;
988
989 /* Read the value */
990 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
991 {
992 /* Exception occurred */
993 return;
994 }
995
996 /* Set CF to the bit value */
997 State->Flags.Cf = (Value >> BitNumber) & 1;
998
999 /* Set the bit */
1000 Value |= 1 << BitNumber;
1001
1002 /* Write back the result */
1003 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
1004 }
1005 else
1006 {
1007 USHORT Value;
1008
1009 /* Read the value */
1010 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
1011 {
1012 /* Exception occurred */
1013 return;
1014 }
1015
1016 /* Set CF to the bit value */
1017 State->Flags.Cf = (Value >> BitNumber) & 1;
1018
1019 /* Set the bit */
1020 Value |= 1 << BitNumber;
1021
1022 /* Write back the result */
1023 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
1024 }
1025 }
1026
1027 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShrd)
1028 {
1029 BOOLEAN OperandSize, AddressSize;
1030 FAST486_MOD_REG_RM ModRegRm;
1031 UCHAR Count;
1032
1033 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1034 TOGGLE_OPSIZE(OperandSize);
1035 TOGGLE_ADSIZE(AddressSize);
1036
1037 /* Make sure this is the right instruction */
1038 ASSERT((Opcode & 0xFE) == 0xAC);
1039
1040 /* Get the operands */
1041 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1042 {
1043 /* Exception occurred */
1044 return;
1045 }
1046
1047 if (Opcode == 0xAC)
1048 {
1049 /* Fetch the count */
1050 if (!Fast486FetchByte(State, &Count))
1051 {
1052 /* Exception occurred */
1053 return;
1054 }
1055 }
1056 else
1057 {
1058 /* The count is in CL */
1059 Count = State->GeneralRegs[FAST486_REG_ECX].LowByte;
1060 }
1061
1062 /* Normalize the count */
1063 Count &= 0x1F;
1064
1065 /* Do nothing if the count is zero */
1066 if (Count == 0) return;
1067
1068 if (OperandSize)
1069 {
1070 ULONG Source, Destination, Result;
1071
1072 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Source, &Destination))
1073 {
1074 /* Exception occurred */
1075 return;
1076 }
1077
1078 /* Calculate the result */
1079 Result = (Destination >> Count) | (Source << (32 - Count));
1080
1081 /* Update flags */
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);
1088
1089 /* Write back the result */
1090 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result);
1091 }
1092 else
1093 {
1094 USHORT Source, Destination, Result;
1095
1096 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Source, &Destination))
1097 {
1098 /* Exception occurred */
1099 return;
1100 }
1101
1102 /* Calculate the result */
1103 Result = (Destination >> Count) | (Source << (16 - Count));
1104
1105 if (Count >= 16) Result |= (ULONG)(Source | (Source << 16)) >> (Count - 16);
1106
1107 /* Update flags */
1108 if (Count <= 16) State->Flags.Cf = (Destination >> (Count - 1)) & 1;
1109 else State->Flags.Cf = (Source >> (Count - 17)) & 1;
1110
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);
1116
1117 /* Write back the result */
1118 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Result);
1119 }
1120 }
1121
1122 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeImul)
1123 {
1124 BOOLEAN OperandSize, AddressSize;
1125 FAST486_MOD_REG_RM ModRegRm;
1126
1127 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1128
1129 TOGGLE_OPSIZE(OperandSize);
1130 TOGGLE_ADSIZE(AddressSize);
1131
1132 /* Get the operands */
1133 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1134 {
1135 /* Exception occurred */
1136 return;
1137 }
1138
1139 if (OperandSize)
1140 {
1141 LONG Source, Destination;
1142 LONGLONG Result;
1143
1144 /* Read the operands */
1145 if (!Fast486ReadModrmDwordOperands(State,
1146 &ModRegRm,
1147 (PULONG)&Destination,
1148 (PULONG)&Source))
1149 {
1150 /* Exception occurred */
1151 return;
1152 }
1153
1154 /* Calculate the result */
1155 Result = (LONGLONG)Source * (LONGLONG)Destination;
1156
1157 /* Update the flags */
1158 State->Flags.Cf = State->Flags.Of = ((Result < -2147483648LL) || (Result > 2147483647LL));
1159
1160 /* Write back the result */
1161 Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, (ULONG)((LONG)Result));
1162 }
1163 else
1164 {
1165 SHORT Source, Destination;
1166 LONG Result;
1167
1168 /* Read the operands */
1169 if (!Fast486ReadModrmWordOperands(State,
1170 &ModRegRm,
1171 (PUSHORT)&Destination,
1172 (PUSHORT)&Source))
1173 {
1174 /* Exception occurred */
1175 return;
1176 }
1177
1178 /* Calculate the result */
1179 Result = (LONG)Source * (LONG)Destination;
1180
1181 /* Update the flags */
1182 State->Flags.Cf = State->Flags.Of = ((Result < -32768) || (Result > 32767));
1183
1184 /* Write back the result */
1185 Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, (USHORT)((SHORT)Result));
1186 }
1187 }
1188
1189 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchgByte)
1190 {
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;
1195
1196 TOGGLE_ADSIZE(AddressSize);
1197
1198 /* Get the operands */
1199 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1200 {
1201 /* Exception occurred */
1202 return;
1203 }
1204
1205 /* Read the operands */
1206 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, &Source, &Destination))
1207 {
1208 /* Exception occurred */
1209 return;
1210 }
1211
1212 /* Compare AL with the destination */
1213 Result = Accumulator - Destination;
1214
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);
1223
1224 if (State->Flags.Zf)
1225 {
1226 /* Load the source operand into the destination */
1227 Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Source);
1228 }
1229 else
1230 {
1231 /* Load the destination into AL */
1232 State->GeneralRegs[FAST486_REG_EAX].LowByte = Destination;
1233 }
1234 }
1235
1236 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchg)
1237 {
1238 FAST486_MOD_REG_RM ModRegRm;
1239 BOOLEAN OperandSize, AddressSize;
1240
1241 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1242
1243 TOGGLE_OPSIZE(OperandSize);
1244 TOGGLE_ADSIZE(AddressSize);
1245
1246 /* Get the operands */
1247 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1248 {
1249 /* Exception occurred */
1250 return;
1251 }
1252
1253 if (OperandSize)
1254 {
1255 ULONG Source, Destination, Result;
1256 ULONG Accumulator = State->GeneralRegs[FAST486_REG_EAX].Long;
1257
1258 /* Read the operands */
1259 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Source, &Destination))
1260 {
1261 /* Exception occurred */
1262 return;
1263 }
1264
1265 /* Compare EAX with the destination */
1266 Result = Accumulator - Destination;
1267
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);
1276
1277 if (State->Flags.Zf)
1278 {
1279 /* Load the source operand into the destination */
1280 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Source);
1281 }
1282 else
1283 {
1284 /* Load the destination into EAX */
1285 State->GeneralRegs[FAST486_REG_EAX].Long = Destination;
1286 }
1287 }
1288 else
1289 {
1290 USHORT Source, Destination, Result;
1291 USHORT Accumulator = State->GeneralRegs[FAST486_REG_EAX].LowWord;
1292
1293 /* Read the operands */
1294 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Source, &Destination))
1295 {
1296 /* Exception occurred */
1297 return;
1298 }
1299
1300 /* Compare AX with the destination */
1301 Result = Accumulator - Destination;
1302
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);
1311
1312 if (State->Flags.Zf)
1313 {
1314 /* Load the source operand into the destination */
1315 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Source);
1316 }
1317 else
1318 {
1319 /* Load the destination into AX */
1320 State->GeneralRegs[FAST486_REG_EAX].LowWord = Destination;
1321 }
1322 }
1323 }
1324
1325 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLss)
1326 {
1327 UCHAR FarPointer[6];
1328 BOOLEAN OperandSize, AddressSize;
1329 FAST486_MOD_REG_RM ModRegRm;
1330
1331 /* Make sure this is the right instruction */
1332 ASSERT(Opcode == 0xB2);
1333
1334 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1335
1336 TOGGLE_OPSIZE(OperandSize);
1337 TOGGLE_ADSIZE(AddressSize);
1338
1339 /* Get the operands */
1340 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1341 {
1342 /* Exception occurred */
1343 return;
1344 }
1345
1346 if (!ModRegRm.Memory)
1347 {
1348 /* Invalid */
1349 Fast486Exception(State, FAST486_EXCEPTION_UD);
1350 return;
1351 }
1352
1353 if (!Fast486ReadMemory(State,
1354 (State->PrefixFlags & FAST486_PREFIX_SEG)
1355 ? State->SegmentOverride : FAST486_REG_DS,
1356 ModRegRm.MemoryAddress,
1357 FALSE,
1358 FarPointer,
1359 OperandSize ? 6 : 4))
1360 {
1361 /* Exception occurred */
1362 return;
1363 }
1364
1365 if (OperandSize)
1366 {
1367 ULONG Offset = *((PULONG)FarPointer);
1368 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(ULONG)]);
1369
1370 /* Set the register to the offset */
1371 State->GeneralRegs[ModRegRm.Register].Long = Offset;
1372
1373 /* Load the segment */
1374 Fast486LoadSegment(State, FAST486_REG_SS, Segment);
1375 }
1376 else
1377 {
1378 USHORT Offset = *((PUSHORT)FarPointer);
1379 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(USHORT)]);
1380
1381 /* Set the register to the offset */
1382 State->GeneralRegs[ModRegRm.Register].LowWord = Offset;
1383
1384 /* Load the segment */
1385 Fast486LoadSegment(State, FAST486_REG_SS, Segment);
1386 }
1387 }
1388
1389 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtr)
1390 {
1391 BOOLEAN OperandSize, AddressSize;
1392 FAST486_MOD_REG_RM ModRegRm;
1393 UINT DataSize;
1394 ULONG BitNumber;
1395
1396 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1397 TOGGLE_OPSIZE(OperandSize);
1398 TOGGLE_ADSIZE(AddressSize);
1399
1400 /* Get the number of bits */
1401 if (OperandSize) DataSize = 32;
1402 else DataSize = 16;
1403
1404 /* Get the operands */
1405 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1406 {
1407 /* Exception occurred */
1408 return;
1409 }
1410
1411 /* Get the bit number */
1412 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
1413 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
1414
1415 if (ModRegRm.Memory)
1416 {
1417 /*
1418 * For memory operands, add the bit offset divided by
1419 * the data size to the address
1420 */
1421 ModRegRm.MemoryAddress += BitNumber / DataSize;
1422 }
1423
1424 /* Normalize the bit number */
1425 BitNumber %= DataSize;
1426
1427 if (OperandSize)
1428 {
1429 ULONG Value;
1430
1431 /* Read the value */
1432 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1433 {
1434 /* Exception occurred */
1435 return;
1436 }
1437
1438 /* Set CF to the bit value */
1439 State->Flags.Cf = (Value >> BitNumber) & 1;
1440
1441 /* Clear the bit */
1442 Value &= ~(1 << BitNumber);
1443
1444 /* Write back the result */
1445 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
1446 }
1447 else
1448 {
1449 USHORT Value;
1450
1451 /* Read the value */
1452 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
1453 {
1454 /* Exception occurred */
1455 return;
1456 }
1457
1458 /* Set CF to the bit value */
1459 State->Flags.Cf = (Value >> BitNumber) & 1;
1460
1461 /* Clear the bit */
1462 Value &= ~(1 << BitNumber);
1463
1464 /* Write back the result */
1465 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
1466 }
1467 }
1468
1469 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLfsLgs)
1470 {
1471 UCHAR FarPointer[6];
1472 BOOLEAN OperandSize, AddressSize;
1473 FAST486_MOD_REG_RM ModRegRm;
1474
1475 /* Make sure this is the right instruction */
1476 ASSERT((Opcode & 0xFE) == 0xB4);
1477
1478 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1479
1480 TOGGLE_OPSIZE(OperandSize);
1481 TOGGLE_ADSIZE(AddressSize);
1482
1483 /* Get the operands */
1484 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1485 {
1486 /* Exception occurred */
1487 return;
1488 }
1489
1490 if (!ModRegRm.Memory)
1491 {
1492 /* Invalid */
1493 Fast486Exception(State, FAST486_EXCEPTION_UD);
1494 return;
1495 }
1496
1497 if (!Fast486ReadMemory(State,
1498 (State->PrefixFlags & FAST486_PREFIX_SEG)
1499 ? State->SegmentOverride : FAST486_REG_DS,
1500 ModRegRm.MemoryAddress,
1501 FALSE,
1502 FarPointer,
1503 OperandSize ? 6 : 4))
1504 {
1505 /* Exception occurred */
1506 return;
1507 }
1508
1509 if (OperandSize)
1510 {
1511 ULONG Offset = *((PULONG)FarPointer);
1512 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(ULONG)]);
1513
1514 /* Set the register to the offset */
1515 State->GeneralRegs[ModRegRm.Register].Long = Offset;
1516
1517 /* Load the segment */
1518 Fast486LoadSegment(State,
1519 (Opcode == 0xB4)
1520 ? FAST486_REG_FS : FAST486_REG_GS,
1521 Segment);
1522 }
1523 else
1524 {
1525 USHORT Offset = *((PUSHORT)FarPointer);
1526 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(USHORT)]);
1527
1528 /* Set the register to the offset */
1529 State->GeneralRegs[ModRegRm.Register].LowWord = Offset;
1530
1531 /* Load the segment */
1532 Fast486LoadSegment(State,
1533 (Opcode == 0xB4)
1534 ? FAST486_REG_FS : FAST486_REG_GS,
1535 Segment);
1536 }
1537 }
1538
1539 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxByte)
1540 {
1541 UCHAR Value;
1542 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1543 FAST486_MOD_REG_RM ModRegRm;
1544
1545 TOGGLE_ADSIZE(AddressSize);
1546
1547 /* Make sure this is the right instruction */
1548 ASSERT(Opcode == 0xB6);
1549
1550 /* Get the operands */
1551 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1552 {
1553 /* Exception occurred */
1554 return;
1555 }
1556
1557 /* Read the operands */
1558 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
1559 {
1560 /* Exception occurred */
1561 return;
1562 }
1563
1564 /* Write back the zero-extended value */
1565 Fast486WriteModrmDwordOperands(State,
1566 &ModRegRm,
1567 TRUE,
1568 (ULONG)Value);
1569 }
1570
1571 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxWord)
1572 {
1573 USHORT Value;
1574 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1575 FAST486_MOD_REG_RM ModRegRm;
1576
1577 TOGGLE_ADSIZE(AddressSize);
1578
1579 /* Make sure this is the right instruction */
1580 ASSERT(Opcode == 0xB7);
1581
1582 /* Get the operands */
1583 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1584 {
1585 /* Exception occurred */
1586 return;
1587 }
1588
1589 /* Read the operands */
1590 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
1591 {
1592 /* Exception occurred */
1593 return;
1594 }
1595
1596 /* Write back the zero-extended value */
1597 Fast486WriteModrmDwordOperands(State,
1598 &ModRegRm,
1599 TRUE,
1600 (ULONG)Value);
1601 }
1602
1603 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtc)
1604 {
1605 BOOLEAN OperandSize, AddressSize;
1606 FAST486_MOD_REG_RM ModRegRm;
1607 UINT DataSize;
1608 ULONG BitNumber;
1609
1610 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1611 TOGGLE_OPSIZE(OperandSize);
1612 TOGGLE_ADSIZE(AddressSize);
1613
1614 /* Get the number of bits */
1615 if (OperandSize) DataSize = 32;
1616 else DataSize = 16;
1617
1618 /* Get the operands */
1619 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1620 {
1621 /* Exception occurred */
1622 return;
1623 }
1624
1625 /* Get the bit number */
1626 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
1627 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
1628
1629 if (ModRegRm.Memory)
1630 {
1631 /*
1632 * For memory operands, add the bit offset divided by
1633 * the data size to the address
1634 */
1635 ModRegRm.MemoryAddress += BitNumber / DataSize;
1636 }
1637
1638 /* Normalize the bit number */
1639 BitNumber %= DataSize;
1640
1641 if (OperandSize)
1642 {
1643 ULONG Value;
1644
1645 /* Read the value */
1646 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1647 {
1648 /* Exception occurred */
1649 return;
1650 }
1651
1652 /* Set CF to the bit value */
1653 State->Flags.Cf = (Value >> BitNumber) & 1;
1654
1655 /* Toggle the bit */
1656 Value ^= 1 << BitNumber;
1657
1658 /* Write back the result */
1659 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
1660 }
1661 else
1662 {
1663 USHORT Value;
1664
1665 /* Read the value */
1666 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
1667 {
1668 /* Exception occurred */
1669 return;
1670 }
1671
1672 /* Set CF to the bit value */
1673 State->Flags.Cf = (Value >> BitNumber) & 1;
1674
1675 /* Toggle the bit */
1676 Value ^= 1 << BitNumber;
1677
1678 /* Write back the result */
1679 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
1680 }
1681 }
1682
1683 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsf)
1684 {
1685 INT i;
1686 ULONG Value = 0;
1687 BOOLEAN OperandSize, AddressSize;
1688 FAST486_MOD_REG_RM ModRegRm;
1689 ULONG BitNumber;
1690 UINT DataSize;
1691
1692 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1693 TOGGLE_OPSIZE(OperandSize);
1694 TOGGLE_ADSIZE(AddressSize);
1695
1696 /* Make sure this is the right instruction */
1697 ASSERT(Opcode == 0xBC);
1698
1699 /* Get the number of bits */
1700 if (OperandSize) DataSize = 32;
1701 else DataSize = 16;
1702
1703 /* Get the operands */
1704 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1705 {
1706 /* Exception occurred */
1707 return;
1708 }
1709
1710 /* Read the value */
1711 if (OperandSize)
1712 {
1713 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1714 {
1715 /* Exception occurred */
1716 return;
1717 }
1718 }
1719 else
1720 {
1721 if (!Fast486ReadModrmWordOperands(State,
1722 &ModRegRm,
1723 (PUSHORT)NULL,
1724 (PUSHORT)&Value))
1725 {
1726 /* Exception occurred */
1727 return;
1728 }
1729 }
1730
1731 /* Set ZF */
1732 State->Flags.Zf = (Value == 0);
1733 if (State->Flags.Zf) return;
1734
1735 for (i = 0; i < DataSize; i++)
1736 {
1737 if(Value & (1 << i))
1738 {
1739 /* Save the bit number */
1740 BitNumber = i;
1741
1742 /* Exit the loop */
1743 break;
1744 }
1745 }
1746
1747 /* Write back the result */
1748 if (OperandSize) Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, BitNumber);
1749 else Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(BitNumber));
1750 }
1751
1752 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsr)
1753 {
1754 INT i;
1755 ULONG Value = 0;
1756 BOOLEAN OperandSize, AddressSize;
1757 FAST486_MOD_REG_RM ModRegRm;
1758 ULONG BitNumber;
1759 UINT DataSize;
1760
1761 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1762 TOGGLE_OPSIZE(OperandSize);
1763 TOGGLE_ADSIZE(AddressSize);
1764
1765 /* Make sure this is the right instruction */
1766 ASSERT(Opcode == 0xBD);
1767
1768 /* Get the number of bits */
1769 if (OperandSize) DataSize = 32;
1770 else DataSize = 16;
1771
1772 /* Get the operands */
1773 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1774 {
1775 /* Exception occurred */
1776 return;
1777 }
1778
1779 /* Read the value */
1780 if (OperandSize)
1781 {
1782 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1783 {
1784 /* Exception occurred */
1785 return;
1786 }
1787 }
1788 else
1789 {
1790 if (!Fast486ReadModrmWordOperands(State,
1791 &ModRegRm,
1792 (PUSHORT)NULL,
1793 (PUSHORT)&Value))
1794 {
1795 /* Exception occurred */
1796 return;
1797 }
1798 }
1799
1800 /* Set ZF according to the value */
1801 State->Flags.Zf = (Value == 0);
1802 if (State->Flags.Zf) return;
1803
1804 for (i = DataSize - 1; i >= 0; i--)
1805 {
1806 if(Value & (1 << i))
1807 {
1808 /* Save the bit number */
1809 BitNumber = i;
1810
1811 /* Exit the loop */
1812 break;
1813 }
1814 }
1815
1816 /* Write back the result */
1817 if (OperandSize) Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, BitNumber);
1818 else Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(BitNumber));
1819 }
1820
1821 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxByte)
1822 {
1823 CHAR Value;
1824 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1825 FAST486_MOD_REG_RM ModRegRm;
1826
1827 TOGGLE_ADSIZE(AddressSize);
1828
1829 /* Make sure this is the right instruction */
1830 ASSERT(Opcode == 0xBE);
1831
1832 /* Get the operands */
1833 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1834 {
1835 /* Exception occurred */
1836 return;
1837 }
1838
1839 /* Read the operands */
1840 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, (PUCHAR)&Value))
1841 {
1842 /* Exception occurred */
1843 return;
1844 }
1845
1846 /* Write back the sign-extended value */
1847 Fast486WriteModrmDwordOperands(State,
1848 &ModRegRm,
1849 TRUE,
1850 (ULONG)((LONG)Value));
1851 }
1852
1853 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxWord)
1854 {
1855 SHORT Value;
1856 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1857 FAST486_MOD_REG_RM ModRegRm;
1858
1859 TOGGLE_ADSIZE(AddressSize);
1860
1861 /* Make sure this is the right instruction */
1862 ASSERT(Opcode == 0xBF);
1863
1864 /* Get the operands */
1865 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1866 {
1867 /* Exception occurred */
1868 return;
1869 }
1870
1871 /* Read the operands */
1872 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, (PUSHORT)&Value))
1873 {
1874 /* Exception occurred */
1875 return;
1876 }
1877
1878 /* Write back the sign-extended value */
1879 Fast486WriteModrmDwordOperands(State,
1880 &ModRegRm,
1881 TRUE,
1882 (ULONG)((LONG)Value));
1883 }
1884
1885 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalJmp)
1886 {
1887 BOOLEAN Jump = FALSE;
1888 LONG Offset = 0;
1889 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1890
1891 TOGGLE_OPSIZE(Size);
1892 NO_LOCK_PREFIX();
1893
1894 /* Make sure this is the right instruction */
1895 ASSERT((Opcode & 0xF0) == 0x80);
1896
1897 /* Fetch the offset */
1898 if (Size)
1899 {
1900 if (!Fast486FetchDword(State, (PULONG)&Offset))
1901 {
1902 /* Exception occurred */
1903 return;
1904 }
1905 }
1906 else
1907 {
1908 SHORT Value;
1909
1910 if (!Fast486FetchWord(State, (PUSHORT)&Value))
1911 {
1912 /* Exception occurred */
1913 return;
1914 }
1915
1916 /* Sign-extend */
1917 Offset = (LONG)Value;
1918 }
1919
1920 switch ((Opcode & 0x0F) >> 1)
1921 {
1922 /* JO / JNO */
1923 case 0:
1924 {
1925 Jump = State->Flags.Of;
1926 break;
1927 }
1928
1929 /* JC / JNC */
1930 case 1:
1931 {
1932 Jump = State->Flags.Cf;
1933 break;
1934 }
1935
1936 /* JZ / JNZ */
1937 case 2:
1938 {
1939 Jump = State->Flags.Zf;
1940 break;
1941 }
1942
1943 /* JBE / JNBE */
1944 case 3:
1945 {
1946 Jump = State->Flags.Cf || State->Flags.Zf;
1947 break;
1948 }
1949
1950 /* JS / JNS */
1951 case 4:
1952 {
1953 Jump = State->Flags.Sf;
1954 break;
1955 }
1956
1957 /* JP / JNP */
1958 case 5:
1959 {
1960 Jump = State->Flags.Pf;
1961 break;
1962 }
1963
1964 /* JL / JNL */
1965 case 6:
1966 {
1967 Jump = State->Flags.Sf != State->Flags.Of;
1968 break;
1969 }
1970
1971 /* JLE / JNLE */
1972 case 7:
1973 {
1974 Jump = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
1975 break;
1976 }
1977 }
1978
1979 if (Opcode & 1)
1980 {
1981 /* Invert the result */
1982 Jump = !Jump;
1983 }
1984
1985 if (Jump)
1986 {
1987 /* Move the instruction pointer */
1988 State->InstPtr.Long += Offset;
1989 }
1990 }
1991
1992 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalSet)
1993 {
1994 BOOLEAN Value = FALSE;
1995 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1996 FAST486_MOD_REG_RM ModRegRm;
1997
1998 TOGGLE_ADSIZE(AddressSize);
1999
2000 /* Get the operands */
2001 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2002 {
2003 /* Exception occurred */
2004 return;
2005 }
2006
2007 /* Make sure this is the right instruction */
2008 ASSERT((Opcode & 0xF0) == 0x90);
2009
2010 switch ((Opcode & 0x0F) >> 1)
2011 {
2012 /* SETO / SETNO */
2013 case 0:
2014 {
2015 Value = State->Flags.Of;
2016 break;
2017 }
2018
2019 /* SETC / SETNC */
2020 case 1:
2021 {
2022 Value = State->Flags.Cf;
2023 break;
2024 }
2025
2026 /* SETZ / SETNZ */
2027 case 2:
2028 {
2029 Value = State->Flags.Zf;
2030 break;
2031 }
2032
2033 /* SETBE / SETNBE */
2034 case 3:
2035 {
2036 Value = State->Flags.Cf || State->Flags.Zf;
2037 break;
2038 }
2039
2040 /* SETS / SETNS */
2041 case 4:
2042 {
2043 Value = State->Flags.Sf;
2044 break;
2045 }
2046
2047 /* SETP / SETNP */
2048 case 5:
2049 {
2050 Value = State->Flags.Pf;
2051 break;
2052 }
2053
2054 /* SETL / SETNL */
2055 case 6:
2056 {
2057 Value = State->Flags.Sf != State->Flags.Of;
2058 break;
2059 }
2060
2061 /* SETLE / SETNLE */
2062 case 7:
2063 {
2064 Value = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
2065 break;
2066 }
2067 }
2068
2069 if (Opcode & 1)
2070 {
2071 /* Invert the result */
2072 Value = !Value;
2073 }
2074
2075 /* Write back the result */
2076 Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
2077 }
2078
2079 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXaddByte)
2080 {
2081 UCHAR Source, Destination, Result;
2082 FAST486_MOD_REG_RM ModRegRm;
2083 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2084
2085 /* Make sure this is the right instruction */
2086 ASSERT(Opcode == 0xC0);
2087
2088 TOGGLE_ADSIZE(AddressSize);
2089
2090 /* Get the operands */
2091 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2092 {
2093 /* Exception occurred */
2094 return;
2095 }
2096
2097 if (!Fast486ReadModrmByteOperands(State,
2098 &ModRegRm,
2099 &Source,
2100 &Destination))
2101 {
2102 /* Exception occurred */
2103 return;
2104 }
2105
2106 /* Calculate the result */
2107 Result = Source + Destination;
2108
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);
2117
2118 /* Write the sum to the destination */
2119 if (!Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Result))
2120 {
2121 /* Exception occurred */
2122 return;
2123 }
2124
2125 /* Write the old value of the destination to the source */
2126 Fast486WriteModrmByteOperands(State, &ModRegRm, TRUE, Destination);
2127 }
2128
2129 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXadd)
2130 {
2131 FAST486_MOD_REG_RM ModRegRm;
2132 BOOLEAN OperandSize, AddressSize;
2133
2134 /* Make sure this is the right instruction */
2135 ASSERT(Opcode == 0xC1);
2136
2137 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2138
2139 TOGGLE_ADSIZE(AddressSize);
2140 TOGGLE_OPSIZE(OperandSize);
2141
2142 /* Get the operands */
2143 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2144 {
2145 /* Exception occurred */
2146 return;
2147 }
2148
2149 /* Check the operand size */
2150 if (OperandSize)
2151 {
2152 ULONG Source, Destination, Result;
2153
2154 if (!Fast486ReadModrmDwordOperands(State,
2155 &ModRegRm,
2156 &Source,
2157 &Destination))
2158 {
2159 /* Exception occurred */
2160 return;
2161 }
2162
2163 /* Calculate the result */
2164 Result = Source + Destination;
2165
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);
2174
2175 /* Write the old value of the destination to the source */
2176 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, Destination))
2177 {
2178 /* Exception occurred */
2179 return;
2180 }
2181
2182 /* Write the sum to the destination */
2183 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result);
2184 }
2185 else
2186 {
2187 USHORT Source, Destination, Result;
2188
2189 if (!Fast486ReadModrmWordOperands(State,
2190 &ModRegRm,
2191 &Source,
2192 &Destination))
2193 {
2194 /* Exception occurred */
2195 return;
2196 }
2197
2198 /* Calculate the result */
2199 Result = Source + Destination;
2200
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);
2209
2210 /* Write the old value of the destination to the source */
2211 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, Destination))
2212 {
2213 /* Exception occurred */
2214 return;
2215 }
2216
2217 /* Write the sum to the destination */
2218 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Result);
2219 }
2220 }
2221
2222 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBswap)
2223 {
2224 PUCHAR Pointer;
2225
2226 NO_LOCK_PREFIX();
2227
2228 /* Get a pointer to the value */
2229 Pointer = (PUCHAR)&State->GeneralRegs[Opcode & 0x07].Long;
2230
2231 /* Swap the byte order */
2232 SWAP(Pointer[0], Pointer[3]);
2233 SWAP(Pointer[1], Pointer[2]);
2234 }
2235
2236 FAST486_OPCODE_HANDLER(Fast486OpcodeExtended)
2237 {
2238 UCHAR SecondOpcode;
2239
2240 /* Fetch the second operation code */
2241 if (!Fast486FetchByte(State, &SecondOpcode))
2242 {
2243 /* Exception occurred */
2244 return;
2245 }
2246
2247 /* Call the extended opcode handler */
2248 Fast486ExtendedHandlers[SecondOpcode](State, SecondOpcode);
2249 }
2250
2251 /* EOF */