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