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