Create the AHCI branch for Aman's work
[reactos.git] / sdk / lib / fast486 / opcodes.c
1 /*
2 * Fast486 386/486 CPU Emulation Library
3 * opcodes.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 "opgroups.h"
32 #include "extraops.h"
33 #include "common.h"
34 #include "fpu.h"
35
36 /* PUBLIC VARIABLES ***********************************************************/
37
38 FAST486_OPCODE_HANDLER_PROC
39 Fast486OpcodeHandlers[FAST486_NUM_OPCODE_HANDLERS] =
40 {
41 Fast486OpcodeAddByteModrm, /* 0x00 - 0x03 */
42 Fast486OpcodeAddModrm,
43 Fast486OpcodeAddByteModrm,
44 Fast486OpcodeAddModrm,
45 Fast486OpcodeAddAl, /* 0x04 */
46 Fast486OpcodeAddEax, /* 0x05 */
47 Fast486OpcodePushEs, /* 0x06 */
48 Fast486OpcodePopEs, /* 0x07 */
49 Fast486OpcodeOrByteModrm, /* 0x08 - 0x0B */
50 Fast486OpcodeOrModrm,
51 Fast486OpcodeOrByteModrm,
52 Fast486OpcodeOrModrm,
53 Fast486OpcodeOrAl, /* 0x0C */
54 Fast486OpcodeOrEax, /* 0x0D */
55 Fast486OpcodePushCs, /* 0x0E */
56 Fast486OpcodeExtended, /* 0x0F */
57 Fast486OpcodeAdcByteModrm, /* 0x10 - 0x13 */
58 Fast486OpcodeAdcModrm,
59 Fast486OpcodeAdcByteModrm,
60 Fast486OpcodeAdcModrm,
61 Fast486OpcodeAdcAl, /* 0x14 */
62 Fast486OpcodeAdcEax, /* 0x15 */
63 Fast486OpcodePushSs, /* 0x16 */
64 Fast486OpcodePopSs, /* 0x17 */
65 Fast486OpcodeSbbByteModrm, /* 0x18 - 0x1B */
66 Fast486OpcodeSbbModrm,
67 Fast486OpcodeSbbByteModrm,
68 Fast486OpcodeSbbModrm,
69 Fast486OpcodeSbbAl, /* 0x1C */
70 Fast486OpcodeSbbEax, /* 0x1D */
71 Fast486OpcodePushDs, /* 0x1E */
72 Fast486OpcodePopDs, /* 0x1F */
73 Fast486OpcodeAndByteModrm, /* 0x20 - 0x23 */
74 Fast486OpcodeAndModrm,
75 Fast486OpcodeAndByteModrm,
76 Fast486OpcodeAndModrm,
77 Fast486OpcodeAndAl, /* 0x24 */
78 Fast486OpcodeAndEax, /* 0x25 */
79 Fast486OpcodePrefix, /* 0x26 */
80 Fast486OpcodeDaa, /* 0x27 */
81 Fast486OpcodeCmpSubByteModrm, /* 0x28 - 0x2B */
82 Fast486OpcodeCmpSubModrm,
83 Fast486OpcodeCmpSubByteModrm,
84 Fast486OpcodeCmpSubModrm,
85 Fast486OpcodeCmpSubAl, /* 0x2C */
86 Fast486OpcodeCmpSubEax, /* 0x2D */
87 Fast486OpcodePrefix, /* 0x2E */
88 Fast486OpcodeDas, /* 0x2F */
89 Fast486OpcodeXorByteModrm, /* 0x30 - 0x33 */
90 Fast486OpcodeXorModrm,
91 Fast486OpcodeXorByteModrm,
92 Fast486OpcodeXorModrm,
93 Fast486OpcodeXorAl, /* 0x34 */
94 Fast486OpcodeXorEax, /* 0x35 */
95 Fast486OpcodePrefix, /* 0x36 */
96 Fast486OpcodeAaa, /* 0x37 */
97 Fast486OpcodeCmpSubByteModrm, /* 0x38 - 0x3B */
98 Fast486OpcodeCmpSubModrm,
99 Fast486OpcodeCmpSubByteModrm,
100 Fast486OpcodeCmpSubModrm,
101 Fast486OpcodeCmpSubAl, /* 0x3C */
102 Fast486OpcodeCmpSubEax, /* 0x3D */
103 Fast486OpcodePrefix, /* 0x3E */
104 Fast486OpcodeAas, /* 0x3F */
105 Fast486OpcodeIncrement, /* 0x40 - 0x47 */
106 Fast486OpcodeIncrement,
107 Fast486OpcodeIncrement,
108 Fast486OpcodeIncrement,
109 Fast486OpcodeIncrement,
110 Fast486OpcodeIncrement,
111 Fast486OpcodeIncrement,
112 Fast486OpcodeIncrement,
113 Fast486OpcodeDecrement, /* 0x48 - 0x4F */
114 Fast486OpcodeDecrement,
115 Fast486OpcodeDecrement,
116 Fast486OpcodeDecrement,
117 Fast486OpcodeDecrement,
118 Fast486OpcodeDecrement,
119 Fast486OpcodeDecrement,
120 Fast486OpcodeDecrement,
121 Fast486OpcodePushReg, /* 0x50 - 0x57 */
122 Fast486OpcodePushReg,
123 Fast486OpcodePushReg,
124 Fast486OpcodePushReg,
125 Fast486OpcodePushReg,
126 Fast486OpcodePushReg,
127 Fast486OpcodePushReg,
128 Fast486OpcodePushReg,
129 Fast486OpcodePopReg, /* 0x58 - 0x5F */
130 Fast486OpcodePopReg,
131 Fast486OpcodePopReg,
132 Fast486OpcodePopReg,
133 Fast486OpcodePopReg,
134 Fast486OpcodePopReg,
135 Fast486OpcodePopReg,
136 Fast486OpcodePopReg,
137 Fast486OpcodePushAll, /* 0x60 */
138 Fast486OpcodePopAll, /* 0x61 */
139 Fast486OpcodeBound, /* 0x62 */
140 Fast486OpcodeArpl, /* 0x63 */
141 Fast486OpcodePrefix, /* 0x64 - 0x67 */
142 Fast486OpcodePrefix,
143 Fast486OpcodePrefix,
144 Fast486OpcodePrefix,
145 Fast486OpcodePushImm, /* 0x68 */
146 Fast486OpcodeImulModrmImm, /* 0x69 */
147 Fast486OpcodePushByteImm, /* 0x6A */
148 Fast486OpcodeImulModrmImm, /* 0x6B */
149 Fast486OpcodeIns, /* 0x6C */
150 Fast486OpcodeIns, /* 0x6D */
151 Fast486OpcodeOuts, /* 0x6E */
152 Fast486OpcodeOuts, /* 0x6F */
153 Fast486OpcodeShortConditionalJmp, /* 0x70 - 0x7F */
154 Fast486OpcodeShortConditionalJmp,
155 Fast486OpcodeShortConditionalJmp,
156 Fast486OpcodeShortConditionalJmp,
157 Fast486OpcodeShortConditionalJmp,
158 Fast486OpcodeShortConditionalJmp,
159 Fast486OpcodeShortConditionalJmp,
160 Fast486OpcodeShortConditionalJmp,
161 Fast486OpcodeShortConditionalJmp,
162 Fast486OpcodeShortConditionalJmp,
163 Fast486OpcodeShortConditionalJmp,
164 Fast486OpcodeShortConditionalJmp,
165 Fast486OpcodeShortConditionalJmp,
166 Fast486OpcodeShortConditionalJmp,
167 Fast486OpcodeShortConditionalJmp,
168 Fast486OpcodeShortConditionalJmp,
169 Fast486OpcodeGroup8082, /* 0x80 */
170 Fast486OpcodeGroup81, /* 0x81 */
171 Fast486OpcodeGroup8082, /* 0x82 */
172 Fast486OpcodeGroup83, /* 0x83 */
173 Fast486OpcodeTestByteModrm, /* 0x84 */
174 Fast486OpcodeTestModrm, /* 0x85 */
175 Fast486OpcodeXchgByteModrm, /* 0x86 */
176 Fast486OpcodeXchgModrm, /* 0x87 */
177 Fast486OpcodeMovByteModrm, /* 0x88 */
178 Fast486OpcodeMovModrm, /* 0x89 */
179 Fast486OpcodeMovByteModrm, /* 0x8A */
180 Fast486OpcodeMovModrm, /* 0x8B */
181 Fast486OpcodeMovStoreSeg, /* 0x8C */
182 Fast486OpcodeLea, /* 0x8D */
183 Fast486OpcodeMovLoadSeg, /* 0x8E */
184 Fast486OpcodeGroup8F, /* 0x8F */
185 Fast486OpcodeNop, /* 0x90 */
186 Fast486OpcodeExchangeEax, /* 0x91 - 0x97 */
187 Fast486OpcodeExchangeEax,
188 Fast486OpcodeExchangeEax,
189 Fast486OpcodeExchangeEax,
190 Fast486OpcodeExchangeEax,
191 Fast486OpcodeExchangeEax,
192 Fast486OpcodeExchangeEax,
193 Fast486OpcodeCwde, /* 0x98 */
194 Fast486OpcodeCdq, /* 0x99 */
195 Fast486OpcodeCallAbs, /* 0x9A */
196 Fast486OpcodeWait, /* 0x9B */
197 Fast486OpcodePushFlags, /* 0x9C */
198 Fast486OpcodePopFlags, /* 0x9D */
199 Fast486OpcodeSahf, /* 0x9E */
200 Fast486OpcodeLahf, /* 0x9F */
201 Fast486OpcodeMovAlOffset, /* 0xA0 */
202 Fast486OpcodeMovEaxOffset, /* 0xA1 */
203 Fast486OpcodeMovOffsetAl, /* 0xA2 */
204 Fast486OpcodeMovOffsetEax, /* 0xA3 */
205 Fast486OpcodeMovs, /* 0xA4 */
206 Fast486OpcodeMovs, /* 0xA5 */
207 Fast486OpcodeCmps, /* 0xA6 */
208 Fast486OpcodeCmps, /* 0xA7 */
209 Fast486OpcodeTestAl, /* 0xA8 */
210 Fast486OpcodeTestEax, /* 0xA9 */
211 Fast486OpcodeStos, /* 0xAA */
212 Fast486OpcodeStos, /* 0xAB */
213 Fast486OpcodeLods, /* 0xAC */
214 Fast486OpcodeLods, /* 0xAD */
215 Fast486OpcodeScas, /* 0xAE */
216 Fast486OpcodeScas, /* 0xAF */
217 Fast486OpcodeMovByteRegImm, /* 0xB0 - 0xB7 */
218 Fast486OpcodeMovByteRegImm,
219 Fast486OpcodeMovByteRegImm,
220 Fast486OpcodeMovByteRegImm,
221 Fast486OpcodeMovByteRegImm,
222 Fast486OpcodeMovByteRegImm,
223 Fast486OpcodeMovByteRegImm,
224 Fast486OpcodeMovByteRegImm,
225 Fast486OpcodeMovRegImm, /* 0xB8 - 0xBF */
226 Fast486OpcodeMovRegImm,
227 Fast486OpcodeMovRegImm,
228 Fast486OpcodeMovRegImm,
229 Fast486OpcodeMovRegImm,
230 Fast486OpcodeMovRegImm,
231 Fast486OpcodeMovRegImm,
232 Fast486OpcodeMovRegImm,
233 Fast486OpcodeGroupC0, /* 0xC0 */
234 Fast486OpcodeGroupC1, /* 0xC1 */
235 Fast486OpcodeRet, /* 0xC2 */
236 Fast486OpcodeRet, /* 0xC3 */
237 Fast486OpcodeLdsLes, /* 0xC4 */
238 Fast486OpcodeLdsLes, /* 0xC5 */
239 Fast486OpcodeGroupC6, /* 0xC6 */
240 Fast486OpcodeGroupC7, /* 0xC7 */
241 Fast486OpcodeEnter, /* 0xC8 */
242 Fast486OpcodeLeave, /* 0xC9 */
243 Fast486OpcodeRetFar, /* 0xCA */
244 Fast486OpcodeRetFar, /* 0xCB */
245 Fast486OpcodeInt, /* 0xCC */
246 Fast486OpcodeInt, /* 0xCD */
247 Fast486OpcodeInt, /* 0xCE */
248 Fast486OpcodeIret, /* 0xCF */
249 Fast486OpcodeGroupD0, /* 0xD0 - 0xD3 */
250 Fast486OpcodeGroupD1,
251 Fast486OpcodeGroupD2,
252 Fast486OpcodeGroupD3,
253 Fast486OpcodeAam, /* 0xD4 */
254 Fast486OpcodeAad, /* 0xD5 */
255 Fast486OpcodeSalc, /* 0xD6 */
256 Fast486OpcodeXlat, /* 0xD7 */
257 Fast486FpuOpcodeD8, /* 0xD8 - 0xDF */
258 Fast486FpuOpcodeD9,
259 Fast486FpuOpcodeDA,
260 Fast486FpuOpcodeDB,
261 Fast486FpuOpcodeDC,
262 Fast486FpuOpcodeDD,
263 Fast486FpuOpcodeDE,
264 Fast486FpuOpcodeDF,
265 Fast486OpcodeLoop, /* 0xE0 - 0xE2 */
266 Fast486OpcodeLoop,
267 Fast486OpcodeLoop,
268 Fast486OpcodeJecxz, /* 0xE3 */
269 Fast486OpcodeInByte, /* 0xE4 */
270 Fast486OpcodeIn, /* 0xE5 */
271 Fast486OpcodeOutByte, /* 0xE6 */
272 Fast486OpcodeOut, /* 0xE7 */
273 Fast486OpcodeCall, /* 0xE8 */
274 Fast486OpcodeJmp, /* 0xE9 */
275 Fast486OpcodeJmpAbs, /* 0xEA */
276 Fast486OpcodeShortJump, /* 0xEB */
277 Fast486OpcodeInByte, /* 0xEC */
278 Fast486OpcodeIn, /* 0xED */
279 Fast486OpcodeOutByte, /* 0xEE */
280 Fast486OpcodeOut, /* 0xEF */
281 Fast486OpcodePrefix, /* 0xF0 */
282 Fast486OpcodeInvalid, /* 0xF1 */ // Invalid opcode -- ICEBP/INT01 opcode
283 Fast486OpcodePrefix, /* 0xF2 */
284 Fast486OpcodePrefix, /* 0xF3 */
285 Fast486OpcodeHalt, /* 0xF4 */
286 Fast486OpcodeComplCarry, /* 0xF5 */
287 Fast486OpcodeGroupF6, /* 0xF6 */
288 Fast486OpcodeGroupF7, /* 0xF7 */
289 Fast486OpcodeClearCarry, /* 0xF8 */
290 Fast486OpcodeSetCarry, /* 0xF9 */
291 Fast486OpcodeClearInt, /* 0xFA */
292 Fast486OpcodeSetInt, /* 0xFB */
293 Fast486OpcodeClearDir, /* 0xFC */
294 Fast486OpcodeSetDir, /* 0xFD */
295 Fast486OpcodeGroupFE, /* 0xFE */
296 Fast486OpcodeGroupFF, /* 0xFF */
297 };
298
299 /* PUBLIC FUNCTIONS ***********************************************************/
300
301 FAST486_OPCODE_HANDLER(Fast486OpcodeInvalid)
302 {
303 /*
304 * This is not a valid opcode.
305 * Well, not totally: see http://www.rcollins.org/secrets/opcodes/ICEBP.html
306 * for more details.
307 */
308 DPRINT1("FAST486 -- Calling ICEBP opcode\n");
309 Fast486Exception(State, FAST486_EXCEPTION_UD);
310 }
311
312 FAST486_OPCODE_HANDLER(Fast486OpcodePrefix)
313 {
314 switch (Opcode)
315 {
316 /* ES: */
317 case 0x26:
318 {
319 State->PrefixFlags |= FAST486_PREFIX_SEG;
320 State->SegmentOverride = FAST486_REG_ES;
321 break;
322 }
323
324 /* CS: */
325 case 0x2E:
326 {
327 State->PrefixFlags |= FAST486_PREFIX_SEG;
328 State->SegmentOverride = FAST486_REG_CS;
329 break;
330 }
331
332 /* SS: */
333 case 0x36:
334 {
335 State->PrefixFlags |= FAST486_PREFIX_SEG;
336 State->SegmentOverride = FAST486_REG_SS;
337 break;
338 }
339
340 /* DS: */
341 case 0x3E:
342 {
343 State->PrefixFlags |= FAST486_PREFIX_SEG;
344 State->SegmentOverride = FAST486_REG_DS;
345 break;
346 }
347
348 /* FS: */
349 case 0x64:
350 {
351 State->PrefixFlags |= FAST486_PREFIX_SEG;
352 State->SegmentOverride = FAST486_REG_FS;
353 break;
354 }
355
356 /* GS: */
357 case 0x65:
358 {
359 State->PrefixFlags |= FAST486_PREFIX_SEG;
360 State->SegmentOverride = FAST486_REG_GS;
361 break;
362 }
363
364 /* OPSIZE */
365 case 0x66:
366 {
367 State->PrefixFlags |= FAST486_PREFIX_OPSIZE;
368 break;
369 }
370
371 /* ADSIZE */
372 case 0x67:
373 {
374 State->PrefixFlags |= FAST486_PREFIX_ADSIZE;
375 break;
376 }
377
378 /* LOCK */
379 case 0xF0:
380 {
381 State->PrefixFlags |= FAST486_PREFIX_LOCK;
382 break;
383 }
384
385 /* REPNZ */
386 case 0xF2:
387 {
388 /* Mutually exclusive with REP */
389 State->PrefixFlags |= FAST486_PREFIX_REPNZ;
390 State->PrefixFlags &= ~FAST486_PREFIX_REP;
391 break;
392 }
393
394 /* REP / REPZ */
395 case 0xF3:
396 {
397 /* Mutually exclusive with REPNZ */
398 State->PrefixFlags |= FAST486_PREFIX_REP;
399 State->PrefixFlags &= ~FAST486_PREFIX_REPNZ;
400 break;
401 }
402
403 default:
404 {
405 /* Shouldn't happen */
406 ASSERT(FALSE);
407 }
408 }
409 }
410
411 FAST486_OPCODE_HANDLER(Fast486OpcodeIncrement)
412 {
413 ULONG Value;
414 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
415
416 TOGGLE_OPSIZE(Size);
417 NO_LOCK_PREFIX();
418
419 /* Make sure this is the right instruction */
420 ASSERT((Opcode & 0xF8) == 0x40);
421
422 if (Size)
423 {
424 Value = ++State->GeneralRegs[Opcode & 0x07].Long;
425
426 State->Flags.Of = (Value == SIGN_FLAG_LONG);
427 State->Flags.Sf = ((Value & SIGN_FLAG_LONG) != 0);
428 }
429 else
430 {
431 Value = ++State->GeneralRegs[Opcode & 0x07].LowWord;
432
433 State->Flags.Of = (Value == SIGN_FLAG_WORD);
434 State->Flags.Sf = ((Value & SIGN_FLAG_WORD) != 0);
435 }
436
437 State->Flags.Zf = (Value == 0);
438 State->Flags.Af = ((Value & 0x0F) == 0);
439 State->Flags.Pf = Fast486CalculateParity(LOBYTE(Value));
440 }
441
442 FAST486_OPCODE_HANDLER(Fast486OpcodeDecrement)
443 {
444 ULONG Value;
445 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
446
447 TOGGLE_OPSIZE(Size);
448 NO_LOCK_PREFIX();
449
450 /* Make sure this is the right instruction */
451 ASSERT((Opcode & 0xF8) == 0x48);
452
453 if (Size)
454 {
455 Value = --State->GeneralRegs[Opcode & 0x07].Long;
456
457 State->Flags.Of = (Value == (SIGN_FLAG_LONG - 1));
458 State->Flags.Sf = ((Value & SIGN_FLAG_LONG) != 0);
459 }
460 else
461 {
462 Value = --State->GeneralRegs[Opcode & 0x07].LowWord;
463
464 State->Flags.Of = (Value == (SIGN_FLAG_WORD - 1));
465 State->Flags.Sf = ((Value & SIGN_FLAG_WORD) != 0);
466 }
467
468 State->Flags.Zf = (Value == 0);
469 State->Flags.Af = ((Value & 0x0F) == 0x0F);
470 State->Flags.Pf = Fast486CalculateParity(LOBYTE(Value));
471 }
472
473 FAST486_OPCODE_HANDLER(Fast486OpcodePushReg)
474 {
475 NO_LOCK_PREFIX();
476
477 /* Make sure this is the right instruction */
478 ASSERT((Opcode & 0xF8) == 0x50);
479
480 /* Call the internal function */
481 Fast486StackPush(State, State->GeneralRegs[Opcode & 0x07].Long);
482 }
483
484 FAST486_OPCODE_HANDLER(Fast486OpcodePopReg)
485 {
486 ULONG Value;
487 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
488
489 TOGGLE_OPSIZE(Size);
490 NO_LOCK_PREFIX();
491
492 /* Make sure this is the right instruction */
493 ASSERT((Opcode & 0xF8) == 0x58);
494
495 /* Call the internal function */
496 if (!Fast486StackPop(State, &Value)) return;
497
498 /* Store the value */
499 if (Size) State->GeneralRegs[Opcode & 0x07].Long = Value;
500 else State->GeneralRegs[Opcode & 0x07].LowWord = Value;
501 }
502
503 FAST486_OPCODE_HANDLER(Fast486OpcodeNop)
504 {
505 }
506
507 FAST486_OPCODE_HANDLER(Fast486OpcodeExchangeEax)
508 {
509 INT Reg = Opcode & 0x07;
510 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
511
512 TOGGLE_OPSIZE(Size);
513 NO_LOCK_PREFIX();
514
515 /* Make sure this is the right instruction */
516 ASSERT((Opcode & 0xF8) == 0x90);
517
518 /* Exchange the values */
519 if (Size)
520 {
521 ULONG Value;
522
523 Value = State->GeneralRegs[Reg].Long;
524 State->GeneralRegs[Reg].Long = State->GeneralRegs[FAST486_REG_EAX].Long;
525 State->GeneralRegs[FAST486_REG_EAX].Long = Value;
526 }
527 else
528 {
529 USHORT Value;
530
531 Value = State->GeneralRegs[Reg].LowWord;
532 State->GeneralRegs[Reg].LowWord = State->GeneralRegs[FAST486_REG_EAX].LowWord;
533 State->GeneralRegs[FAST486_REG_EAX].LowWord = Value;
534 }
535 }
536
537 FAST486_OPCODE_HANDLER(Fast486OpcodeShortConditionalJmp)
538 {
539 BOOLEAN Jump = FALSE;
540 CHAR Offset = 0;
541 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
542
543 /* Make sure this is the right instruction */
544 ASSERT((Opcode & 0xF0) == 0x70);
545
546 TOGGLE_OPSIZE(Size);
547
548 /* Fetch the offset */
549 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
550 {
551 /* An exception occurred */
552 return;
553 }
554
555 switch ((Opcode & 0x0F) >> 1)
556 {
557 /* JO / JNO */
558 case 0:
559 {
560 Jump = State->Flags.Of;
561 break;
562 }
563
564 /* JC / JNC */
565 case 1:
566 {
567 Jump = State->Flags.Cf;
568 break;
569 }
570
571 /* JZ / JNZ */
572 case 2:
573 {
574 Jump = State->Flags.Zf;
575 break;
576 }
577
578 /* JBE / JNBE */
579 case 3:
580 {
581 Jump = State->Flags.Cf || State->Flags.Zf;
582 break;
583 }
584
585 /* JS / JNS */
586 case 4:
587 {
588 Jump = State->Flags.Sf;
589 break;
590 }
591
592 /* JP / JNP */
593 case 5:
594 {
595 Jump = State->Flags.Pf;
596 break;
597 }
598
599 /* JL / JNL */
600 case 6:
601 {
602 Jump = State->Flags.Sf != State->Flags.Of;
603 break;
604 }
605
606 /* JLE / JNLE */
607 case 7:
608 {
609 Jump = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
610 break;
611 }
612 }
613
614 if (Opcode & 1)
615 {
616 /* Invert the result */
617 Jump = !Jump;
618 }
619
620 if (Jump)
621 {
622 /* Move the instruction pointer */
623 State->InstPtr.Long += Offset;
624
625 if (!Size)
626 {
627 /* Clear the top half of EIP */
628 State->InstPtr.Long &= 0xFFFF;
629 }
630 }
631 }
632
633 FAST486_OPCODE_HANDLER(Fast486OpcodeClearCarry)
634 {
635 /* Make sure this is the right instruction */
636 ASSERT(Opcode == 0xF8);
637
638 NO_LOCK_PREFIX();
639
640 /* Clear CF and return success */
641 State->Flags.Cf = FALSE;
642 }
643
644 FAST486_OPCODE_HANDLER(Fast486OpcodeSetCarry)
645 {
646 /* Make sure this is the right instruction */
647 ASSERT(Opcode == 0xF9);
648
649 NO_LOCK_PREFIX();
650
651 /* Set CF and return success*/
652 State->Flags.Cf = TRUE;
653 }
654
655 FAST486_OPCODE_HANDLER(Fast486OpcodeComplCarry)
656 {
657 /* Make sure this is the right instruction */
658 ASSERT(Opcode == 0xF5);
659
660 NO_LOCK_PREFIX();
661
662 /* Toggle CF and return success */
663 State->Flags.Cf = !State->Flags.Cf;
664 return;
665 }
666
667 FAST486_OPCODE_HANDLER(Fast486OpcodeClearInt)
668 {
669 /* Make sure this is the right instruction */
670 ASSERT(Opcode == 0xFA);
671
672 NO_LOCK_PREFIX();
673
674 /* Check for protected mode */
675 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
676 {
677 /* Check IOPL */
678 if (State->Flags.Iopl >= Fast486GetCurrentPrivLevel(State))
679 {
680 /* Clear the interrupt flag */
681 State->Flags.If = FALSE;
682 }
683 else
684 {
685 /* General Protection Fault */
686 Fast486Exception(State, FAST486_EXCEPTION_GP);
687 return;
688 }
689 }
690 else
691 {
692 /* Just clear the interrupt flag */
693 State->Flags.If = FALSE;
694 }
695 }
696
697 FAST486_OPCODE_HANDLER(Fast486OpcodeSetInt)
698 {
699 /* Make sure this is the right instruction */
700 ASSERT(Opcode == 0xFB);
701
702 NO_LOCK_PREFIX();
703
704 /* Check for protected mode */
705 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
706 {
707 /* Check IOPL */
708 if (State->Flags.Iopl >= Fast486GetCurrentPrivLevel(State))
709 {
710 /* Set the interrupt flag */
711 State->Flags.If = TRUE;
712 }
713 else
714 {
715 /* General Protection Fault */
716 Fast486Exception(State, FAST486_EXCEPTION_GP);
717 return;
718 }
719 }
720 else
721 {
722 /* Just set the interrupt flag */
723 State->Flags.If = TRUE;
724 }
725 }
726
727 FAST486_OPCODE_HANDLER(Fast486OpcodeClearDir)
728 {
729 /* Make sure this is the right instruction */
730 ASSERT(Opcode == 0xFC);
731
732 NO_LOCK_PREFIX();
733
734 /* Clear DF */
735 State->Flags.Df = FALSE;
736 }
737
738 FAST486_OPCODE_HANDLER(Fast486OpcodeSetDir)
739 {
740 /* Make sure this is the right instruction */
741 ASSERT(Opcode == 0xFD);
742
743 NO_LOCK_PREFIX();
744
745 /* Set DF */
746 State->Flags.Df = TRUE;
747 }
748
749 FAST486_OPCODE_HANDLER(Fast486OpcodeHalt)
750 {
751 /* Make sure this is the right instruction */
752 ASSERT(Opcode == 0xF4);
753
754 NO_LOCK_PREFIX();
755
756 /* Privileged instructions can only be executed under CPL = 0 */
757 if (Fast486GetCurrentPrivLevel(State) != 0)
758 {
759 Fast486Exception(State, FAST486_EXCEPTION_GP);
760 return;
761 }
762
763 /* Halt */
764 State->Halted = TRUE;
765 }
766
767 FAST486_OPCODE_HANDLER(Fast486OpcodeInByte)
768 {
769 UCHAR Data;
770 ULONG Port;
771
772 /* Make sure this is the right instruction */
773 ASSERT((Opcode & 0xF7) == 0xE4);
774
775 if (Opcode == 0xE4)
776 {
777 /* Fetch the parameter */
778 if (!Fast486FetchByte(State, &Data))
779 {
780 /* Exception occurred */
781 return;
782 }
783
784 /* Set the port number to the parameter */
785 Port = Data;
786 }
787 else
788 {
789 /* The port number is in DX */
790 Port = State->GeneralRegs[FAST486_REG_EDX].LowWord;
791 }
792
793 if (!Fast486IoPrivilegeCheck(State, Port)) return;
794
795 /* Read a byte from the I/O port */
796 State->IoReadCallback(State, Port, &Data, 1, sizeof(UCHAR));
797
798 /* Store the result in AL */
799 State->GeneralRegs[FAST486_REG_EAX].LowByte = Data;
800 }
801
802 FAST486_OPCODE_HANDLER(Fast486OpcodeIn)
803 {
804 ULONG Port;
805 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
806
807 /* Make sure this is the right instruction */
808 ASSERT((Opcode & 0xF7) == 0xE5);
809
810 TOGGLE_OPSIZE(Size);
811 NO_LOCK_PREFIX();
812
813 if (Opcode == 0xE5)
814 {
815 UCHAR Data;
816
817 /* Fetch the parameter */
818 if (!Fast486FetchByte(State, &Data))
819 {
820 /* Exception occurred */
821 return;
822 }
823
824 /* Set the port number to the parameter */
825 Port = Data;
826 }
827 else
828 {
829 /* The port number is in DX */
830 Port = State->GeneralRegs[FAST486_REG_EDX].LowWord;
831 }
832
833 if (!Fast486IoPrivilegeCheck(State, Port)) return;
834
835 if (Size)
836 {
837 ULONG Data;
838
839 /* Read a dword from the I/O port */
840 State->IoReadCallback(State, Port, &Data, 1, sizeof(ULONG));
841
842 /* Store the value in EAX */
843 State->GeneralRegs[FAST486_REG_EAX].Long = Data;
844 }
845 else
846 {
847 USHORT Data;
848
849 /* Read a word from the I/O port */
850 State->IoReadCallback(State, Port, &Data, 1, sizeof(USHORT));
851
852 /* Store the value in AX */
853 State->GeneralRegs[FAST486_REG_EAX].LowWord = Data;
854 }
855 }
856
857 FAST486_OPCODE_HANDLER(Fast486OpcodeOutByte)
858 {
859 UCHAR Data;
860 ULONG Port;
861
862 /* Make sure this is the right instruction */
863 ASSERT((Opcode & 0xF7) == 0xE6);
864
865 if (Opcode == 0xE6)
866 {
867 /* Fetch the parameter */
868 if (!Fast486FetchByte(State, &Data))
869 {
870 /* Exception occurred */
871 return;
872 }
873
874 /* Set the port number to the parameter */
875 Port = Data;
876 }
877 else
878 {
879 /* The port number is in DX */
880 Port = State->GeneralRegs[FAST486_REG_EDX].LowWord;
881 }
882
883 if (!Fast486IoPrivilegeCheck(State, Port)) return;
884
885 /* Read the value from AL */
886 Data = State->GeneralRegs[FAST486_REG_EAX].LowByte;
887
888 /* Write the byte to the I/O port */
889 State->IoWriteCallback(State, Port, &Data, 1, sizeof(UCHAR));
890 }
891
892 FAST486_OPCODE_HANDLER(Fast486OpcodeOut)
893 {
894 ULONG Port;
895 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
896
897 /* Make sure this is the right instruction */
898 ASSERT((Opcode & 0xF7) == 0xE7);
899
900 TOGGLE_OPSIZE(Size);
901 NO_LOCK_PREFIX();
902
903 if (Opcode == 0xE7)
904 {
905 UCHAR Data;
906
907 /* Fetch the parameter */
908 if (!Fast486FetchByte(State, &Data))
909 {
910 /* Exception occurred */
911 return;
912 }
913
914 /* Set the port number to the parameter */
915 Port = Data;
916 }
917 else
918 {
919 /* The port number is in DX */
920 Port = State->GeneralRegs[FAST486_REG_EDX].LowWord;
921 }
922
923 if (!Fast486IoPrivilegeCheck(State, Port)) return;
924
925 if (Size)
926 {
927 /* Get the value from EAX */
928 ULONG Data = State->GeneralRegs[FAST486_REG_EAX].Long;
929
930 /* Write a dword to the I/O port */
931 State->IoWriteCallback(State, Port, &Data, 1, sizeof(ULONG));
932 }
933 else
934 {
935 /* Get the value from AX */
936 USHORT Data = State->GeneralRegs[FAST486_REG_EAX].LowWord;
937
938 /* Write a word to the I/O port */
939 State->IoWriteCallback(State, Port, &Data, 1, sizeof(USHORT));
940 }
941 }
942
943 FAST486_OPCODE_HANDLER(Fast486OpcodeShortJump)
944 {
945 CHAR Offset = 0;
946 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
947
948 TOGGLE_OPSIZE(Size);
949
950 /* Make sure this is the right instruction */
951 ASSERT(Opcode == 0xEB);
952
953 /* Fetch the offset */
954 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
955 {
956 /* An exception occurred */
957 return;
958 }
959
960 /* Move the instruction pointer */
961 State->InstPtr.Long += Offset;
962
963 if (!Size)
964 {
965 /* Clear the top half of EIP */
966 State->InstPtr.Long &= 0xFFFF;
967 }
968 }
969
970 FAST486_OPCODE_HANDLER(Fast486OpcodeMovRegImm)
971 {
972 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
973
974 /* Make sure this is the right instruction */
975 ASSERT((Opcode & 0xF8) == 0xB8);
976
977 TOGGLE_OPSIZE(Size);
978 NO_LOCK_PREFIX();
979
980 if (Size)
981 {
982 ULONG Value;
983
984 /* Fetch the dword */
985 if (!Fast486FetchDword(State, &Value))
986 {
987 /* Exception occurred */
988 return;
989 }
990
991 /* Store the value in the register */
992 State->GeneralRegs[Opcode & 0x07].Long = Value;
993 }
994 else
995 {
996 USHORT Value;
997
998 /* Fetch the word */
999 if (!Fast486FetchWord(State, &Value))
1000 {
1001 /* Exception occurred */
1002 return;
1003 }
1004
1005 /* Store the value in the register */
1006 State->GeneralRegs[Opcode & 0x07].LowWord = Value;
1007 }
1008 }
1009
1010 FAST486_OPCODE_HANDLER(Fast486OpcodeMovByteRegImm)
1011 {
1012 UCHAR Value;
1013
1014 /* Make sure this is the right instruction */
1015 ASSERT((Opcode & 0xF8) == 0xB0);
1016
1017 NO_LOCK_PREFIX();
1018
1019 /* Fetch the byte */
1020 if (!Fast486FetchByte(State, &Value))
1021 {
1022 /* Exception occurred */
1023 return;
1024 }
1025
1026 if (Opcode & 0x04)
1027 {
1028 /* AH, CH, DH or BH */
1029 State->GeneralRegs[Opcode & 0x03].HighByte = Value;
1030 }
1031 else
1032 {
1033 /* AL, CL, DL or BL */
1034 State->GeneralRegs[Opcode & 0x03].LowByte = Value;
1035 }
1036 }
1037
1038 FAST486_OPCODE_HANDLER(Fast486OpcodeAddByteModrm)
1039 {
1040 UCHAR FirstValue, SecondValue, Result;
1041 FAST486_MOD_REG_RM ModRegRm;
1042 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1043
1044 /* Make sure this is the right instruction */
1045 ASSERT((Opcode & 0xFD) == 0x00);
1046
1047 TOGGLE_ADSIZE(AddressSize);
1048
1049 /* Get the operands */
1050 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1051 {
1052 /* Exception occurred */
1053 return;
1054 }
1055
1056 if (!Fast486ReadModrmByteOperands(State,
1057 &ModRegRm,
1058 &FirstValue,
1059 &SecondValue))
1060 {
1061 /* Exception occurred */
1062 return;
1063 }
1064
1065 /* Calculate the result */
1066 Result = FirstValue + SecondValue;
1067
1068 /* Update the flags */
1069 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
1070 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) == (SecondValue & SIGN_FLAG_BYTE))
1071 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
1072 State->Flags.Af = ((((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) != 0);
1073 State->Flags.Zf = (Result == 0);
1074 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1075 State->Flags.Pf = Fast486CalculateParity(Result);
1076
1077 /* Write back the result */
1078 Fast486WriteModrmByteOperands(State,
1079 &ModRegRm,
1080 Opcode & FAST486_OPCODE_WRITE_REG,
1081 Result);
1082 }
1083
1084 FAST486_OPCODE_HANDLER(Fast486OpcodeAddModrm)
1085 {
1086 FAST486_MOD_REG_RM ModRegRm;
1087 BOOLEAN OperandSize, AddressSize;
1088
1089 /* Make sure this is the right instruction */
1090 ASSERT((Opcode & 0xFD) == 0x01);
1091
1092 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1093
1094 TOGGLE_ADSIZE(AddressSize);
1095 TOGGLE_OPSIZE(OperandSize);
1096
1097 /* Get the operands */
1098 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1099 {
1100 /* Exception occurred */
1101 return;
1102 }
1103
1104 /* Check the operand size */
1105 if (OperandSize)
1106 {
1107 ULONG FirstValue, SecondValue, Result;
1108
1109 if (!Fast486ReadModrmDwordOperands(State,
1110 &ModRegRm,
1111 &FirstValue,
1112 &SecondValue))
1113 {
1114 /* Exception occurred */
1115 return;
1116 }
1117
1118 /* Calculate the result */
1119 Result = FirstValue + SecondValue;
1120
1121 /* Update the flags */
1122 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
1123 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) == (SecondValue & SIGN_FLAG_LONG))
1124 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
1125 State->Flags.Af = ((((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) != 0);
1126 State->Flags.Zf = (Result == 0);
1127 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1128 State->Flags.Pf = Fast486CalculateParity(Result);
1129
1130 /* Write back the result */
1131 Fast486WriteModrmDwordOperands(State,
1132 &ModRegRm,
1133 Opcode & FAST486_OPCODE_WRITE_REG,
1134 Result);
1135 }
1136 else
1137 {
1138 USHORT FirstValue, SecondValue, Result;
1139
1140 if (!Fast486ReadModrmWordOperands(State,
1141 &ModRegRm,
1142 &FirstValue,
1143 &SecondValue))
1144 {
1145 /* Exception occurred */
1146 return;
1147 }
1148
1149 /* Calculate the result */
1150 Result = FirstValue + SecondValue;
1151
1152 /* Update the flags */
1153 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
1154 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) == (SecondValue & SIGN_FLAG_WORD))
1155 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
1156 State->Flags.Af = ((((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) != 0);
1157 State->Flags.Zf = (Result == 0);
1158 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1159 State->Flags.Pf = Fast486CalculateParity(Result);
1160
1161 /* Write back the result */
1162 Fast486WriteModrmWordOperands(State,
1163 &ModRegRm,
1164 Opcode & FAST486_OPCODE_WRITE_REG,
1165 Result);
1166 }
1167 }
1168
1169 FAST486_OPCODE_HANDLER(Fast486OpcodeAddAl)
1170 {
1171 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
1172 UCHAR SecondValue, Result;
1173
1174 /* Make sure this is the right instruction */
1175 ASSERT(Opcode == 0x04);
1176
1177 NO_LOCK_PREFIX();
1178
1179 if (!Fast486FetchByte(State, &SecondValue))
1180 {
1181 /* Exception occurred */
1182 return;
1183 }
1184
1185 /* Calculate the result */
1186 Result = FirstValue + SecondValue;
1187
1188 /* Update the flags */
1189 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
1190 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) == (SecondValue & SIGN_FLAG_BYTE))
1191 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
1192 State->Flags.Af = ((((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) != 0);
1193 State->Flags.Zf = (Result == 0);
1194 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1195 State->Flags.Pf = Fast486CalculateParity(Result);
1196
1197 /* Write back the result */
1198 State->GeneralRegs[FAST486_REG_EAX].LowByte = Result;
1199 }
1200
1201 FAST486_OPCODE_HANDLER(Fast486OpcodeAddEax)
1202 {
1203 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1204
1205 /* Make sure this is the right instruction */
1206 ASSERT(Opcode == 0x05);
1207
1208 NO_LOCK_PREFIX();
1209 TOGGLE_OPSIZE(Size);
1210
1211 if (Size)
1212 {
1213 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
1214 ULONG SecondValue, Result;
1215
1216 if (!Fast486FetchDword(State, &SecondValue))
1217 {
1218 /* Exception occurred */
1219 return;
1220 }
1221
1222 /* Calculate the result */
1223 Result = FirstValue + SecondValue;
1224
1225 /* Update the flags */
1226 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
1227 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) == (SecondValue & SIGN_FLAG_LONG))
1228 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
1229 State->Flags.Af = ((((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) != 0);
1230 State->Flags.Zf = (Result == 0);
1231 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1232 State->Flags.Pf = Fast486CalculateParity(Result);
1233
1234 /* Write back the result */
1235 State->GeneralRegs[FAST486_REG_EAX].Long = Result;
1236 }
1237 else
1238 {
1239 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
1240 USHORT SecondValue, Result;
1241
1242 if (!Fast486FetchWord(State, &SecondValue))
1243 {
1244 /* Exception occurred */
1245 return;
1246 }
1247
1248 /* Calculate the result */
1249 Result = FirstValue + SecondValue;
1250
1251 /* Update the flags */
1252 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
1253 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) == (SecondValue & SIGN_FLAG_WORD))
1254 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
1255 State->Flags.Af = ((((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) != 0);
1256 State->Flags.Zf = (Result == 0);
1257 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1258 State->Flags.Pf = Fast486CalculateParity(Result);
1259
1260 /* Write back the result */
1261 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
1262 }
1263 }
1264
1265 FAST486_OPCODE_HANDLER(Fast486OpcodeOrByteModrm)
1266 {
1267 UCHAR FirstValue, SecondValue, Result;
1268 FAST486_MOD_REG_RM ModRegRm;
1269 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1270
1271 /* Make sure this is the right instruction */
1272 ASSERT((Opcode & 0xFD) == 0x08);
1273
1274 TOGGLE_ADSIZE(AddressSize);
1275
1276 /* Get the operands */
1277 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1278 {
1279 /* Exception occurred */
1280 return;
1281 }
1282
1283 if (!Fast486ReadModrmByteOperands(State,
1284 &ModRegRm,
1285 &FirstValue,
1286 &SecondValue))
1287 {
1288 /* Exception occurred */
1289 return;
1290 }
1291
1292 /* Calculate the result */
1293 Result = FirstValue | SecondValue;
1294
1295 /* Update the flags */
1296 State->Flags.Cf = FALSE;
1297 State->Flags.Of = FALSE;
1298 State->Flags.Zf = (Result == 0);
1299 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1300 State->Flags.Pf = Fast486CalculateParity(Result);
1301
1302 /* Write back the result */
1303 Fast486WriteModrmByteOperands(State,
1304 &ModRegRm,
1305 Opcode & FAST486_OPCODE_WRITE_REG,
1306 Result);
1307 }
1308
1309 FAST486_OPCODE_HANDLER(Fast486OpcodeOrModrm)
1310 {
1311 FAST486_MOD_REG_RM ModRegRm;
1312 BOOLEAN OperandSize, AddressSize;
1313
1314 /* Make sure this is the right instruction */
1315 ASSERT((Opcode & 0xFD) == 0x09);
1316
1317 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1318
1319 TOGGLE_ADSIZE(AddressSize);
1320 TOGGLE_OPSIZE(OperandSize);
1321
1322 /* Get the operands */
1323 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1324 {
1325 /* Exception occurred */
1326 return;
1327 }
1328
1329 /* Check the operand size */
1330 if (OperandSize)
1331 {
1332 ULONG FirstValue, SecondValue, Result;
1333
1334 if (!Fast486ReadModrmDwordOperands(State,
1335 &ModRegRm,
1336 &FirstValue,
1337 &SecondValue))
1338 {
1339 /* Exception occurred */
1340 return;
1341 }
1342
1343 /* Calculate the result */
1344 Result = FirstValue | SecondValue;
1345
1346 /* Update the flags */
1347 State->Flags.Cf = FALSE;
1348 State->Flags.Of = FALSE;
1349 State->Flags.Zf = (Result == 0);
1350 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1351 State->Flags.Pf = Fast486CalculateParity(Result);
1352
1353 /* Write back the result */
1354 Fast486WriteModrmDwordOperands(State,
1355 &ModRegRm,
1356 Opcode & FAST486_OPCODE_WRITE_REG,
1357 Result);
1358 }
1359 else
1360 {
1361 USHORT FirstValue, SecondValue, Result;
1362
1363 if (!Fast486ReadModrmWordOperands(State,
1364 &ModRegRm,
1365 &FirstValue,
1366 &SecondValue))
1367 {
1368 /* Exception occurred */
1369 return;
1370 }
1371
1372 /* Calculate the result */
1373 Result = FirstValue | SecondValue;
1374
1375 /* Update the flags */
1376 State->Flags.Cf = FALSE;
1377 State->Flags.Of = FALSE;
1378 State->Flags.Zf = (Result == 0);
1379 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1380 State->Flags.Pf = Fast486CalculateParity(Result);
1381
1382 /* Write back the result */
1383 Fast486WriteModrmWordOperands(State,
1384 &ModRegRm,
1385 Opcode & FAST486_OPCODE_WRITE_REG,
1386 Result);
1387 }
1388 }
1389
1390 FAST486_OPCODE_HANDLER(Fast486OpcodeOrAl)
1391 {
1392 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
1393 UCHAR SecondValue, Result;
1394
1395 /* Make sure this is the right instruction */
1396 ASSERT(Opcode == 0x0C);
1397
1398 NO_LOCK_PREFIX();
1399
1400 if (!Fast486FetchByte(State, &SecondValue))
1401 {
1402 /* Exception occurred */
1403 return;
1404 }
1405
1406 /* Calculate the result */
1407 Result = FirstValue | SecondValue;
1408
1409 /* Update the flags */
1410 State->Flags.Cf = FALSE;
1411 State->Flags.Of = FALSE;
1412 State->Flags.Zf = (Result == 0);
1413 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1414 State->Flags.Pf = Fast486CalculateParity(Result);
1415
1416 /* Write back the result */
1417 State->GeneralRegs[FAST486_REG_EAX].LowByte = Result;
1418 }
1419
1420 FAST486_OPCODE_HANDLER(Fast486OpcodeOrEax)
1421 {
1422 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1423
1424 /* Make sure this is the right instruction */
1425 ASSERT(Opcode == 0x0D);
1426
1427 NO_LOCK_PREFIX();
1428 TOGGLE_OPSIZE(Size);
1429
1430 if (Size)
1431 {
1432 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
1433 ULONG SecondValue, Result;
1434
1435 if (!Fast486FetchDword(State, &SecondValue))
1436 {
1437 /* Exception occurred */
1438 return;
1439 }
1440
1441 /* Calculate the result */
1442 Result = FirstValue | SecondValue;
1443
1444 /* Update the flags */
1445 State->Flags.Cf = FALSE;
1446 State->Flags.Of = FALSE;
1447 State->Flags.Zf = (Result == 0);
1448 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1449 State->Flags.Pf = Fast486CalculateParity(Result);
1450
1451 /* Write back the result */
1452 State->GeneralRegs[FAST486_REG_EAX].Long = Result;
1453 }
1454 else
1455 {
1456 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
1457 USHORT SecondValue, Result;
1458
1459 if (!Fast486FetchWord(State, &SecondValue))
1460 {
1461 /* Exception occurred */
1462 return;
1463 }
1464
1465 /* Calculate the result */
1466 Result = FirstValue | SecondValue;
1467
1468 /* Update the flags */
1469 State->Flags.Cf = FALSE;
1470 State->Flags.Of = FALSE;
1471 State->Flags.Zf = (Result == 0);
1472 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1473 State->Flags.Pf = Fast486CalculateParity(Result);
1474
1475 /* Write back the result */
1476 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
1477 }
1478 }
1479
1480 FAST486_OPCODE_HANDLER(Fast486OpcodeAndByteModrm)
1481 {
1482 UCHAR FirstValue, SecondValue, Result;
1483 FAST486_MOD_REG_RM ModRegRm;
1484 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1485
1486 /* Make sure this is the right instruction */
1487 ASSERT((Opcode & 0xFD) == 0x20);
1488
1489 TOGGLE_ADSIZE(AddressSize);
1490
1491 /* Get the operands */
1492 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1493 {
1494 /* Exception occurred */
1495 return;
1496 }
1497
1498 if (!Fast486ReadModrmByteOperands(State,
1499 &ModRegRm,
1500 &FirstValue,
1501 &SecondValue))
1502 {
1503 /* Exception occurred */
1504 return;
1505 }
1506
1507 /* Calculate the result */
1508 Result = FirstValue & SecondValue;
1509
1510 /* Update the flags */
1511 State->Flags.Cf = FALSE;
1512 State->Flags.Of = FALSE;
1513 State->Flags.Zf = (Result == 0);
1514 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1515 State->Flags.Pf = Fast486CalculateParity(Result);
1516
1517 /* Write back the result */
1518 Fast486WriteModrmByteOperands(State,
1519 &ModRegRm,
1520 Opcode & FAST486_OPCODE_WRITE_REG,
1521 Result);
1522 }
1523
1524 FAST486_OPCODE_HANDLER(Fast486OpcodeAndModrm)
1525 {
1526 FAST486_MOD_REG_RM ModRegRm;
1527 BOOLEAN OperandSize, AddressSize;
1528
1529 /* Make sure this is the right instruction */
1530 ASSERT((Opcode & 0xFD) == 0x21);
1531
1532 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1533
1534 TOGGLE_ADSIZE(AddressSize);
1535 TOGGLE_OPSIZE(OperandSize);
1536
1537 /* Get the operands */
1538 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1539 {
1540 /* Exception occurred */
1541 return;
1542 }
1543
1544 /* Check the operand size */
1545 if (OperandSize)
1546 {
1547 ULONG FirstValue, SecondValue, Result;
1548
1549 if (!Fast486ReadModrmDwordOperands(State,
1550 &ModRegRm,
1551 &FirstValue,
1552 &SecondValue))
1553 {
1554 /* Exception occurred */
1555 return;
1556 }
1557
1558 /* Calculate the result */
1559 Result = FirstValue & SecondValue;
1560
1561 /* Update the flags */
1562 State->Flags.Cf = FALSE;
1563 State->Flags.Of = FALSE;
1564 State->Flags.Zf = (Result == 0);
1565 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1566 State->Flags.Pf = Fast486CalculateParity(Result);
1567
1568 /* Write back the result */
1569 Fast486WriteModrmDwordOperands(State,
1570 &ModRegRm,
1571 Opcode & FAST486_OPCODE_WRITE_REG,
1572 Result);
1573 }
1574 else
1575 {
1576 USHORT FirstValue, SecondValue, Result;
1577
1578 if (!Fast486ReadModrmWordOperands(State,
1579 &ModRegRm,
1580 &FirstValue,
1581 &SecondValue))
1582 {
1583 /* Exception occurred */
1584 return;
1585 }
1586
1587 /* Calculate the result */
1588 Result = FirstValue & SecondValue;
1589
1590 /* Update the flags */
1591 State->Flags.Cf = FALSE;
1592 State->Flags.Of = FALSE;
1593 State->Flags.Zf = (Result == 0);
1594 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1595 State->Flags.Pf = Fast486CalculateParity(Result);
1596
1597 /* Write back the result */
1598 Fast486WriteModrmWordOperands(State,
1599 &ModRegRm,
1600 Opcode & FAST486_OPCODE_WRITE_REG,
1601 Result);
1602 }
1603 }
1604
1605 FAST486_OPCODE_HANDLER(Fast486OpcodeAndAl)
1606 {
1607 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
1608 UCHAR SecondValue, Result;
1609
1610 /* Make sure this is the right instruction */
1611 ASSERT(Opcode == 0x24);
1612
1613 NO_LOCK_PREFIX();
1614
1615 if (!Fast486FetchByte(State, &SecondValue))
1616 {
1617 /* Exception occurred */
1618 return;
1619 }
1620
1621 /* Calculate the result */
1622 Result = FirstValue & SecondValue;
1623
1624 /* Update the flags */
1625 State->Flags.Cf = FALSE;
1626 State->Flags.Of = FALSE;
1627 State->Flags.Zf = (Result == 0);
1628 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1629 State->Flags.Pf = Fast486CalculateParity(Result);
1630
1631 /* Write back the result */
1632 State->GeneralRegs[FAST486_REG_EAX].LowByte = Result;
1633 }
1634
1635 FAST486_OPCODE_HANDLER(Fast486OpcodeAndEax)
1636 {
1637 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1638
1639 /* Make sure this is the right instruction */
1640 ASSERT(Opcode == 0x25);
1641
1642 NO_LOCK_PREFIX();
1643 TOGGLE_OPSIZE(Size);
1644
1645 if (Size)
1646 {
1647 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
1648 ULONG SecondValue, Result;
1649
1650 if (!Fast486FetchDword(State, &SecondValue))
1651 {
1652 /* Exception occurred */
1653 return;
1654 }
1655
1656 /* Calculate the result */
1657 Result = FirstValue & SecondValue;
1658
1659 /* Update the flags */
1660 State->Flags.Cf = FALSE;
1661 State->Flags.Of = FALSE;
1662 State->Flags.Zf = (Result == 0);
1663 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1664 State->Flags.Pf = Fast486CalculateParity(Result);
1665
1666 /* Write back the result */
1667 State->GeneralRegs[FAST486_REG_EAX].Long = Result;
1668 }
1669 else
1670 {
1671 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
1672 USHORT SecondValue, Result;
1673
1674 if (!Fast486FetchWord(State, &SecondValue))
1675 {
1676 /* Exception occurred */
1677 return;
1678 }
1679
1680 /* Calculate the result */
1681 Result = FirstValue & SecondValue;
1682
1683 /* Update the flags */
1684 State->Flags.Cf = FALSE;
1685 State->Flags.Of = FALSE;
1686 State->Flags.Zf = (Result == 0);
1687 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1688 State->Flags.Pf = Fast486CalculateParity(Result);
1689
1690 /* Write back the result */
1691 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
1692 }
1693 }
1694
1695 FAST486_OPCODE_HANDLER(Fast486OpcodeXorByteModrm)
1696 {
1697 UCHAR FirstValue, SecondValue, Result;
1698 FAST486_MOD_REG_RM ModRegRm;
1699 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1700
1701 /* Make sure this is the right instruction */
1702 ASSERT((Opcode & 0xFD) == 0x30);
1703
1704 TOGGLE_ADSIZE(AddressSize);
1705
1706 /* Get the operands */
1707 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1708 {
1709 /* Exception occurred */
1710 return;
1711 }
1712
1713 if (!Fast486ReadModrmByteOperands(State,
1714 &ModRegRm,
1715 &FirstValue,
1716 &SecondValue))
1717 {
1718 /* Exception occurred */
1719 return;
1720 }
1721
1722 /* Calculate the result */
1723 Result = FirstValue ^ SecondValue;
1724
1725 /* Update the flags */
1726 State->Flags.Cf = FALSE;
1727 State->Flags.Of = FALSE;
1728 State->Flags.Zf = (Result == 0);
1729 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1730 State->Flags.Pf = Fast486CalculateParity(Result);
1731
1732 /* Write back the result */
1733 Fast486WriteModrmByteOperands(State,
1734 &ModRegRm,
1735 Opcode & FAST486_OPCODE_WRITE_REG,
1736 Result);
1737 }
1738
1739 FAST486_OPCODE_HANDLER(Fast486OpcodeXorModrm)
1740 {
1741 FAST486_MOD_REG_RM ModRegRm;
1742 BOOLEAN OperandSize, AddressSize;
1743
1744 /* Make sure this is the right instruction */
1745 ASSERT((Opcode & 0xFD) == 0x31);
1746
1747 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1748
1749 TOGGLE_ADSIZE(AddressSize);
1750 TOGGLE_OPSIZE(OperandSize);
1751
1752 /* Get the operands */
1753 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1754 {
1755 /* Exception occurred */
1756 return;
1757 }
1758
1759 /* Check the operand size */
1760 if (OperandSize)
1761 {
1762 ULONG FirstValue, SecondValue, Result;
1763
1764 if (!Fast486ReadModrmDwordOperands(State,
1765 &ModRegRm,
1766 &FirstValue,
1767 &SecondValue))
1768 {
1769 /* Exception occurred */
1770 return;
1771 }
1772
1773 /* Calculate the result */
1774 Result = FirstValue ^ SecondValue;
1775
1776 /* Update the flags */
1777 State->Flags.Cf = FALSE;
1778 State->Flags.Of = FALSE;
1779 State->Flags.Zf = (Result == 0);
1780 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1781 State->Flags.Pf = Fast486CalculateParity(Result);
1782
1783 /* Write back the result */
1784 Fast486WriteModrmDwordOperands(State,
1785 &ModRegRm,
1786 Opcode & FAST486_OPCODE_WRITE_REG,
1787 Result);
1788 }
1789 else
1790 {
1791 USHORT FirstValue, SecondValue, Result;
1792
1793 if (!Fast486ReadModrmWordOperands(State,
1794 &ModRegRm,
1795 &FirstValue,
1796 &SecondValue))
1797 {
1798 /* Exception occurred */
1799 return;
1800 }
1801
1802 /* Calculate the result */
1803 Result = FirstValue ^ SecondValue;
1804
1805 /* Update the flags */
1806 State->Flags.Cf = FALSE;
1807 State->Flags.Of = FALSE;
1808 State->Flags.Zf = (Result == 0);
1809 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1810 State->Flags.Pf = Fast486CalculateParity(Result);
1811
1812 /* Write back the result */
1813 Fast486WriteModrmWordOperands(State,
1814 &ModRegRm,
1815 Opcode & FAST486_OPCODE_WRITE_REG,
1816 Result);
1817 }
1818 }
1819
1820 FAST486_OPCODE_HANDLER(Fast486OpcodeXorAl)
1821 {
1822 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
1823 UCHAR SecondValue, Result;
1824
1825 /* Make sure this is the right instruction */
1826 ASSERT(Opcode == 0x34);
1827
1828 NO_LOCK_PREFIX();
1829
1830 if (!Fast486FetchByte(State, &SecondValue))
1831 {
1832 /* Exception occurred */
1833 return;
1834 }
1835
1836 /* Calculate the result */
1837 Result = FirstValue ^ SecondValue;
1838
1839 /* Update the flags */
1840 State->Flags.Cf = FALSE;
1841 State->Flags.Of = FALSE;
1842 State->Flags.Zf = (Result == 0);
1843 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1844 State->Flags.Pf = Fast486CalculateParity(Result);
1845
1846 /* Write back the result */
1847 State->GeneralRegs[FAST486_REG_EAX].LowByte = Result;
1848 }
1849
1850 FAST486_OPCODE_HANDLER(Fast486OpcodeXorEax)
1851 {
1852 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1853
1854 /* Make sure this is the right instruction */
1855 ASSERT(Opcode == 0x35);
1856
1857 NO_LOCK_PREFIX();
1858 TOGGLE_OPSIZE(Size);
1859
1860 if (Size)
1861 {
1862 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
1863 ULONG SecondValue, Result;
1864
1865 if (!Fast486FetchDword(State, &SecondValue))
1866 {
1867 /* Exception occurred */
1868 return;
1869 }
1870
1871 /* Calculate the result */
1872 Result = FirstValue ^ SecondValue;
1873
1874 /* Update the flags */
1875 State->Flags.Cf = FALSE;
1876 State->Flags.Of = FALSE;
1877 State->Flags.Zf = (Result == 0);
1878 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1879 State->Flags.Pf = Fast486CalculateParity(Result);
1880
1881 /* Write back the result */
1882 State->GeneralRegs[FAST486_REG_EAX].Long = Result;
1883 }
1884 else
1885 {
1886 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
1887 USHORT SecondValue, Result;
1888
1889 if (!Fast486FetchWord(State, &SecondValue))
1890 {
1891 /* Exception occurred */
1892 return;
1893 }
1894
1895 /* Calculate the result */
1896 Result = FirstValue ^ SecondValue;
1897
1898 /* Update the flags */
1899 State->Flags.Cf = FALSE;
1900 State->Flags.Of = FALSE;
1901 State->Flags.Zf = (Result == 0);
1902 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1903 State->Flags.Pf = Fast486CalculateParity(Result);
1904
1905 /* Write back the result */
1906 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
1907 }
1908 }
1909
1910 FAST486_OPCODE_HANDLER(Fast486OpcodeTestByteModrm)
1911 {
1912 UCHAR FirstValue, SecondValue, Result;
1913 FAST486_MOD_REG_RM ModRegRm;
1914 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1915
1916 /* Make sure this is the right instruction */
1917 ASSERT(Opcode == 0x84);
1918
1919 TOGGLE_ADSIZE(AddressSize);
1920
1921 /* Get the operands */
1922 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1923 {
1924 /* Exception occurred */
1925 return;
1926 }
1927
1928 if (!Fast486ReadModrmByteOperands(State,
1929 &ModRegRm,
1930 &FirstValue,
1931 &SecondValue))
1932 {
1933 /* Exception occurred */
1934 return;
1935 }
1936 /* Calculate the result */
1937 Result = FirstValue & SecondValue;
1938
1939 /* Update the flags */
1940 State->Flags.Cf = FALSE;
1941 State->Flags.Of = FALSE;
1942 State->Flags.Zf = (Result == 0);
1943 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1944 State->Flags.Pf = Fast486CalculateParity(Result);
1945 }
1946
1947 FAST486_OPCODE_HANDLER(Fast486OpcodeTestModrm)
1948 {
1949 FAST486_MOD_REG_RM ModRegRm;
1950 BOOLEAN OperandSize, AddressSize;
1951
1952 /* Make sure this is the right instruction */
1953 ASSERT(Opcode == 0x85);
1954
1955 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1956
1957 TOGGLE_ADSIZE(AddressSize);
1958 TOGGLE_OPSIZE(OperandSize);
1959
1960 /* Get the operands */
1961 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1962 {
1963 /* Exception occurred */
1964 return;
1965 }
1966
1967 /* Check the operand size */
1968 if (OperandSize)
1969 {
1970 ULONG FirstValue, SecondValue, Result;
1971
1972 if (!Fast486ReadModrmDwordOperands(State,
1973 &ModRegRm,
1974 &FirstValue,
1975 &SecondValue))
1976 {
1977 /* Exception occurred */
1978 return;
1979 }
1980
1981 /* Calculate the result */
1982 Result = FirstValue & SecondValue;
1983
1984 /* Update the flags */
1985 State->Flags.Cf = FALSE;
1986 State->Flags.Of = FALSE;
1987 State->Flags.Zf = (Result == 0);
1988 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1989 State->Flags.Pf = Fast486CalculateParity(Result);
1990 }
1991 else
1992 {
1993 USHORT FirstValue, SecondValue, Result;
1994
1995 if (!Fast486ReadModrmWordOperands(State,
1996 &ModRegRm,
1997 &FirstValue,
1998 &SecondValue))
1999 {
2000 /* Exception occurred */
2001 return;
2002 }
2003
2004 /* Calculate the result */
2005 Result = FirstValue & SecondValue;
2006
2007 /* Update the flags */
2008 State->Flags.Cf = FALSE;
2009 State->Flags.Of = FALSE;
2010 State->Flags.Zf = (Result == 0);
2011 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2012 State->Flags.Pf = Fast486CalculateParity(Result);
2013 }
2014 }
2015
2016 FAST486_OPCODE_HANDLER(Fast486OpcodeTestAl)
2017 {
2018 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
2019 UCHAR SecondValue, Result;
2020
2021 /* Make sure this is the right instruction */
2022 ASSERT(Opcode == 0xA8);
2023
2024 NO_LOCK_PREFIX();
2025
2026 if (!Fast486FetchByte(State, &SecondValue))
2027 {
2028 /* Exception occurred */
2029 return;
2030 }
2031
2032 /* Calculate the result */
2033 Result = FirstValue & SecondValue;
2034
2035 /* Update the flags */
2036 State->Flags.Cf = FALSE;
2037 State->Flags.Of = FALSE;
2038 State->Flags.Zf = (Result == 0);
2039 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2040 State->Flags.Pf = Fast486CalculateParity(Result);
2041 }
2042
2043 FAST486_OPCODE_HANDLER(Fast486OpcodeTestEax)
2044 {
2045 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
2046
2047 /* Make sure this is the right instruction */
2048 ASSERT(Opcode == 0xA9);
2049
2050 NO_LOCK_PREFIX();
2051 TOGGLE_OPSIZE(Size);
2052
2053 if (Size)
2054 {
2055 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
2056 ULONG SecondValue, Result;
2057
2058 if (!Fast486FetchDword(State, &SecondValue))
2059 {
2060 /* Exception occurred */
2061 return;
2062 }
2063
2064 /* Calculate the result */
2065 Result = FirstValue & SecondValue;
2066
2067 /* Update the flags */
2068 State->Flags.Cf = FALSE;
2069 State->Flags.Of = FALSE;
2070 State->Flags.Zf = (Result == 0);
2071 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2072 State->Flags.Pf = Fast486CalculateParity(Result);
2073 }
2074 else
2075 {
2076 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
2077 USHORT SecondValue, Result;
2078
2079 if (!Fast486FetchWord(State, &SecondValue))
2080 {
2081 /* Exception occurred */
2082 return;
2083 }
2084
2085 /* Calculate the result */
2086 Result = FirstValue & SecondValue;
2087
2088 /* Update the flags */
2089 State->Flags.Cf = FALSE;
2090 State->Flags.Of = FALSE;
2091 State->Flags.Zf = (Result == 0);
2092 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2093 State->Flags.Pf = Fast486CalculateParity(Result);
2094 }
2095 }
2096
2097 FAST486_OPCODE_HANDLER(Fast486OpcodeXchgByteModrm)
2098 {
2099 UCHAR FirstValue, SecondValue;
2100 FAST486_MOD_REG_RM ModRegRm;
2101 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2102
2103 /* Make sure this is the right instruction */
2104 ASSERT(Opcode == 0x86);
2105
2106 TOGGLE_ADSIZE(AddressSize);
2107
2108 /* Get the operands */
2109 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2110 {
2111 /* Exception occurred */
2112 return;
2113 }
2114
2115 if (!Fast486ReadModrmByteOperands(State,
2116 &ModRegRm,
2117 &FirstValue,
2118 &SecondValue))
2119 {
2120 /* Exception occurred */
2121 return;
2122 }
2123
2124 /* Write the value from the register to the R/M */
2125 if (!Fast486WriteModrmByteOperands(State,
2126 &ModRegRm,
2127 FALSE,
2128 FirstValue))
2129 {
2130 /* Exception occurred */
2131 return;
2132 }
2133
2134 /* Write the value from the R/M to the register */
2135 Fast486WriteModrmByteOperands(State,
2136 &ModRegRm,
2137 TRUE,
2138 SecondValue);
2139 }
2140
2141 FAST486_OPCODE_HANDLER(Fast486OpcodeXchgModrm)
2142 {
2143 FAST486_MOD_REG_RM ModRegRm;
2144 BOOLEAN OperandSize, AddressSize;
2145
2146 /* Make sure this is the right instruction */
2147 ASSERT(Opcode == 0x87);
2148
2149 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2150
2151 TOGGLE_ADSIZE(AddressSize);
2152 TOGGLE_OPSIZE(OperandSize);
2153
2154 /* Get the operands */
2155 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2156 {
2157 /* Exception occurred */
2158 return;
2159 }
2160
2161 /* Check the operand size */
2162 if (OperandSize)
2163 {
2164 ULONG FirstValue, SecondValue;
2165
2166 if (!Fast486ReadModrmDwordOperands(State,
2167 &ModRegRm,
2168 &FirstValue,
2169 &SecondValue))
2170 {
2171 /* Exception occurred */
2172 return;
2173 }
2174
2175 /* Write the value from the register to the R/M */
2176 if (!Fast486WriteModrmDwordOperands(State,
2177 &ModRegRm,
2178 FALSE,
2179 FirstValue))
2180 {
2181 /* Exception occurred */
2182 return;
2183 }
2184
2185 /* Write the value from the R/M to the register */
2186 Fast486WriteModrmDwordOperands(State,
2187 &ModRegRm,
2188 TRUE,
2189 SecondValue);
2190 }
2191 else
2192 {
2193 USHORT FirstValue, SecondValue;
2194
2195 if (!Fast486ReadModrmWordOperands(State,
2196 &ModRegRm,
2197 &FirstValue,
2198 &SecondValue))
2199 {
2200 /* Exception occurred */
2201 return;
2202 }
2203
2204 /* Write the value from the register to the R/M */
2205 if (!Fast486WriteModrmWordOperands(State,
2206 &ModRegRm,
2207 FALSE,
2208 FirstValue))
2209 {
2210 /* Exception occurred */
2211 return;
2212 }
2213
2214 /* Write the value from the R/M to the register */
2215 Fast486WriteModrmWordOperands(State,
2216 &ModRegRm,
2217 TRUE,
2218 SecondValue);
2219 }
2220 }
2221
2222 FAST486_OPCODE_HANDLER(Fast486OpcodePushEs)
2223 {
2224 /* Call the internal API */
2225 Fast486StackPush(State, State->SegmentRegs[FAST486_REG_ES].Selector);
2226 }
2227
2228 FAST486_OPCODE_HANDLER(Fast486OpcodePopEs)
2229 {
2230 ULONG NewSelector;
2231
2232 if (!Fast486StackPop(State, &NewSelector))
2233 {
2234 /* Exception occurred */
2235 return;
2236 }
2237
2238 /* Call the internal API */
2239 Fast486LoadSegment(State, FAST486_REG_ES, LOWORD(NewSelector));
2240 }
2241
2242 FAST486_OPCODE_HANDLER(Fast486OpcodePushCs)
2243 {
2244 /* Call the internal API */
2245 Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector);
2246 }
2247
2248 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcByteModrm)
2249 {
2250 UCHAR FirstValue, SecondValue, Result;
2251 FAST486_MOD_REG_RM ModRegRm;
2252 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2253
2254 /* Make sure this is the right instruction */
2255 ASSERT((Opcode & 0xFD) == 0x10);
2256
2257 TOGGLE_ADSIZE(AddressSize);
2258
2259 /* Get the operands */
2260 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2261 {
2262 /* Exception occurred */
2263 return;
2264 }
2265
2266 if (!Fast486ReadModrmByteOperands(State,
2267 &ModRegRm,
2268 &FirstValue,
2269 &SecondValue))
2270 {
2271 /* Exception occurred */
2272 return;
2273 }
2274
2275 /* Calculate the result */
2276 Result = FirstValue + SecondValue + State->Flags.Cf;
2277
2278 /* Special exception for CF */
2279 State->Flags.Cf = State->Flags.Cf
2280 && ((FirstValue == 0xFF) || (SecondValue == 0xFF));
2281
2282 /* Update the flags */
2283 State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < SecondValue));
2284 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) == (SecondValue & SIGN_FLAG_BYTE))
2285 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
2286 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2287 State->Flags.Zf = (Result == 0);
2288 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2289 State->Flags.Pf = Fast486CalculateParity(Result);
2290
2291 /* Write back the result */
2292 Fast486WriteModrmByteOperands(State,
2293 &ModRegRm,
2294 Opcode & FAST486_OPCODE_WRITE_REG,
2295 Result);
2296 }
2297
2298 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcModrm)
2299 {
2300 FAST486_MOD_REG_RM ModRegRm;
2301 BOOLEAN OperandSize, AddressSize;
2302
2303 /* Make sure this is the right instruction */
2304 ASSERT((Opcode & 0xFD) == 0x11);
2305
2306 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2307
2308 TOGGLE_ADSIZE(AddressSize);
2309 TOGGLE_OPSIZE(OperandSize);
2310
2311 /* Get the operands */
2312 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2313 {
2314 /* Exception occurred */
2315 return;
2316 }
2317
2318 /* Check the operand size */
2319 if (OperandSize)
2320 {
2321 ULONG FirstValue, SecondValue, Result;
2322
2323 if (!Fast486ReadModrmDwordOperands(State,
2324 &ModRegRm,
2325 &FirstValue,
2326 &SecondValue))
2327 {
2328 /* Exception occurred */
2329 return;
2330 }
2331
2332 /* Calculate the result */
2333 Result = FirstValue + SecondValue + State->Flags.Cf;
2334
2335 /* Special exception for CF */
2336 State->Flags.Cf = State->Flags.Cf
2337 && ((FirstValue == 0xFFFFFFFF) || (SecondValue == 0xFFFFFFFF));
2338
2339 /* Update the flags */
2340 State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < SecondValue));
2341 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) == (SecondValue & SIGN_FLAG_LONG))
2342 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
2343 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2344 State->Flags.Zf = (Result == 0);
2345 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2346 State->Flags.Pf = Fast486CalculateParity(Result);
2347
2348 /* Write back the result */
2349 Fast486WriteModrmDwordOperands(State,
2350 &ModRegRm,
2351 Opcode & FAST486_OPCODE_WRITE_REG,
2352 Result);
2353 }
2354 else
2355 {
2356 USHORT FirstValue, SecondValue, Result;
2357
2358 if (!Fast486ReadModrmWordOperands(State,
2359 &ModRegRm,
2360 &FirstValue,
2361 &SecondValue))
2362 {
2363 /* Exception occurred */
2364 return;
2365 }
2366
2367 /* Calculate the result */
2368 Result = FirstValue + SecondValue + State->Flags.Cf;
2369
2370 /* Special exception for CF */
2371 State->Flags.Cf = State->Flags.Cf
2372 && ((FirstValue == 0xFFFF) || (SecondValue == 0xFFFF));
2373
2374 /* Update the flags */
2375 State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < SecondValue));
2376 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) == (SecondValue & SIGN_FLAG_WORD))
2377 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
2378 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2379 State->Flags.Zf = (Result == 0);
2380 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2381 State->Flags.Pf = Fast486CalculateParity(Result);
2382
2383 /* Write back the result */
2384 Fast486WriteModrmWordOperands(State,
2385 &ModRegRm,
2386 Opcode & FAST486_OPCODE_WRITE_REG,
2387 Result);
2388 }
2389
2390 }
2391
2392 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcAl)
2393 {
2394 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
2395 UCHAR SecondValue, Result;
2396
2397 /* Make sure this is the right instruction */
2398 ASSERT(Opcode == 0x14);
2399
2400 NO_LOCK_PREFIX();
2401
2402 if (!Fast486FetchByte(State, &SecondValue))
2403 {
2404 /* Exception occurred */
2405 return;
2406 }
2407
2408 /* Calculate the result */
2409 Result = FirstValue + SecondValue + State->Flags.Cf;
2410
2411 /* Special exception for CF */
2412 State->Flags.Cf = State->Flags.Cf &&
2413 ((FirstValue == 0xFF) || (SecondValue == 0xFF));
2414
2415 /* Update the flags */
2416 State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < SecondValue));
2417 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) == (SecondValue & SIGN_FLAG_BYTE))
2418 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
2419 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2420 State->Flags.Zf = (Result == 0);
2421 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2422 State->Flags.Pf = Fast486CalculateParity(Result);
2423
2424 /* Write back the result */
2425 State->GeneralRegs[FAST486_REG_EAX].LowByte = Result;
2426 }
2427
2428 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcEax)
2429 {
2430 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
2431
2432 /* Make sure this is the right instruction */
2433 ASSERT(Opcode == 0x15);
2434
2435 NO_LOCK_PREFIX();
2436 TOGGLE_OPSIZE(Size);
2437
2438 if (Size)
2439 {
2440 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
2441 ULONG SecondValue, Result;
2442
2443 if (!Fast486FetchDword(State, &SecondValue))
2444 {
2445 /* Exception occurred */
2446 return;
2447 }
2448
2449 /* Calculate the result */
2450 Result = FirstValue + SecondValue + State->Flags.Cf;
2451
2452 /* Special exception for CF */
2453 State->Flags.Cf = State->Flags.Cf &&
2454 ((FirstValue == 0xFFFFFFFF) || (SecondValue == 0xFFFFFFFF));
2455
2456 /* Update the flags */
2457 State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < SecondValue));
2458 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) == (SecondValue & SIGN_FLAG_LONG))
2459 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
2460 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2461 State->Flags.Zf = (Result == 0);
2462 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2463 State->Flags.Pf = Fast486CalculateParity(Result);
2464
2465 /* Write back the result */
2466 State->GeneralRegs[FAST486_REG_EAX].Long = Result;
2467 }
2468 else
2469 {
2470 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
2471 USHORT SecondValue, Result;
2472
2473 if (!Fast486FetchWord(State, &SecondValue))
2474 {
2475 /* Exception occurred */
2476 return;
2477 }
2478
2479 /* Calculate the result */
2480 Result = FirstValue + SecondValue + State->Flags.Cf;
2481
2482 /* Special exception for CF */
2483 State->Flags.Cf = State->Flags.Cf &&
2484 ((FirstValue == 0xFFFF) || (SecondValue == 0xFFFF));
2485
2486 /* Update the flags */
2487 State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < SecondValue));
2488 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) == (SecondValue & SIGN_FLAG_WORD))
2489 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
2490 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2491 State->Flags.Zf = (Result == 0);
2492 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2493 State->Flags.Pf = Fast486CalculateParity(Result);
2494
2495 /* Write back the result */
2496 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
2497 }
2498 }
2499
2500 FAST486_OPCODE_HANDLER(Fast486OpcodePushSs)
2501 {
2502 /* Call the internal API */
2503 Fast486StackPush(State, State->SegmentRegs[FAST486_REG_SS].Selector);
2504 }
2505
2506 FAST486_OPCODE_HANDLER(Fast486OpcodePopSs)
2507 {
2508 ULONG NewSelector;
2509
2510 if (!Fast486StackPop(State, &NewSelector))
2511 {
2512 /* Exception occurred */
2513 return;
2514 }
2515
2516 /* Call the internal API */
2517 if (Fast486LoadSegment(State, FAST486_REG_SS, LOWORD(NewSelector)))
2518 {
2519 /* Inhibit all interrupts until the next instruction */
2520 State->DoNotInterrupt = TRUE;
2521 }
2522 }
2523
2524 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbByteModrm)
2525 {
2526 UCHAR FirstValue, SecondValue, Result;
2527 FAST486_MOD_REG_RM ModRegRm;
2528 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2529 INT Carry = State->Flags.Cf ? 1 : 0;
2530
2531 /* Make sure this is the right instruction */
2532 ASSERT((Opcode & 0xFD) == 0x18);
2533
2534 TOGGLE_ADSIZE(AddressSize);
2535
2536 /* Get the operands */
2537 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2538 {
2539 /* Exception occurred */
2540 return;
2541 }
2542
2543 if (!Fast486ReadModrmByteOperands(State,
2544 &ModRegRm,
2545 &FirstValue,
2546 &SecondValue))
2547 {
2548 /* Exception occurred */
2549 return;
2550 }
2551
2552 /* Check if this is the instruction that writes to R/M */
2553 if (!(Opcode & FAST486_OPCODE_WRITE_REG))
2554 {
2555 /* Swap the order */
2556 SWAP(FirstValue, SecondValue);
2557 }
2558
2559 /* Calculate the result */
2560 Result = FirstValue - SecondValue - Carry;
2561
2562 /* Update the flags */
2563 State->Flags.Cf = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue);
2564 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) != (SecondValue & SIGN_FLAG_BYTE))
2565 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
2566 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2567 State->Flags.Zf = (Result == 0);
2568 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2569 State->Flags.Pf = Fast486CalculateParity(Result);
2570
2571 /* Write back the result */
2572 Fast486WriteModrmByteOperands(State,
2573 &ModRegRm,
2574 Opcode & FAST486_OPCODE_WRITE_REG,
2575 Result);
2576 }
2577
2578 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbModrm)
2579 {
2580 FAST486_MOD_REG_RM ModRegRm;
2581 BOOLEAN OperandSize, AddressSize;
2582 INT Carry = State->Flags.Cf ? 1 : 0;
2583
2584 /* Make sure this is the right instruction */
2585 ASSERT((Opcode & 0xFD) == 0x19);
2586
2587 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2588
2589 TOGGLE_ADSIZE(AddressSize);
2590 TOGGLE_OPSIZE(OperandSize);
2591
2592 /* Get the operands */
2593 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2594 {
2595 /* Exception occurred */
2596 return;
2597 }
2598
2599 /* Check the operand size */
2600 if (OperandSize)
2601 {
2602 ULONG FirstValue, SecondValue, Result;
2603
2604 if (!Fast486ReadModrmDwordOperands(State,
2605 &ModRegRm,
2606 &FirstValue,
2607 &SecondValue))
2608 {
2609 /* Exception occurred */
2610 return;
2611 }
2612
2613 /* Check if this is the instruction that writes to R/M */
2614 if (!(Opcode & FAST486_OPCODE_WRITE_REG))
2615 {
2616 /* Swap the order */
2617 SWAP(FirstValue, SecondValue);
2618 }
2619
2620 /* Calculate the result */
2621 Result = FirstValue - SecondValue - Carry;
2622
2623 /* Update the flags */
2624 State->Flags.Cf = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue);
2625 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) != (SecondValue & SIGN_FLAG_LONG))
2626 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
2627 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2628 State->Flags.Zf = (Result == 0);
2629 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2630 State->Flags.Pf = Fast486CalculateParity(Result);
2631
2632 /* Write back the result */
2633 Fast486WriteModrmDwordOperands(State,
2634 &ModRegRm,
2635 Opcode & FAST486_OPCODE_WRITE_REG,
2636 Result);
2637 }
2638 else
2639 {
2640 USHORT FirstValue, SecondValue, Result;
2641
2642 if (!Fast486ReadModrmWordOperands(State,
2643 &ModRegRm,
2644 &FirstValue,
2645 &SecondValue))
2646 {
2647 /* Exception occurred */
2648 return;
2649 }
2650
2651 /* Check if this is the instruction that writes to R/M */
2652 if (!(Opcode & FAST486_OPCODE_WRITE_REG))
2653 {
2654 /* Swap the order */
2655 SWAP(FirstValue, SecondValue);
2656 }
2657
2658 /* Calculate the result */
2659 Result = FirstValue - SecondValue - Carry;
2660
2661 /* Update the flags */
2662 State->Flags.Cf = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue);
2663 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) != (SecondValue & SIGN_FLAG_WORD))
2664 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
2665 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2666 State->Flags.Zf = (Result == 0);
2667 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2668 State->Flags.Pf = Fast486CalculateParity(Result);
2669
2670 /* Write back the result */
2671 Fast486WriteModrmWordOperands(State,
2672 &ModRegRm,
2673 Opcode & FAST486_OPCODE_WRITE_REG,
2674 Result);
2675 }
2676 }
2677
2678 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbAl)
2679 {
2680 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
2681 UCHAR SecondValue, Result;
2682 INT Carry = State->Flags.Cf ? 1 : 0;
2683
2684 /* Make sure this is the right instruction */
2685 ASSERT(Opcode == 0x1C);
2686
2687 NO_LOCK_PREFIX();
2688
2689 if (!Fast486FetchByte(State, &SecondValue))
2690 {
2691 /* Exception occurred */
2692 return;
2693 }
2694
2695 /* Calculate the result */
2696 Result = FirstValue - SecondValue - Carry;
2697
2698 /* Update the flags */
2699 State->Flags.Cf = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue);
2700 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) != (SecondValue & SIGN_FLAG_BYTE))
2701 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
2702 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2703 State->Flags.Zf = (Result == 0);
2704 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2705 State->Flags.Pf = Fast486CalculateParity(Result);
2706
2707 /* Write back the result */
2708 State->GeneralRegs[FAST486_REG_EAX].LowByte = Result;
2709 }
2710
2711 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbEax)
2712 {
2713 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
2714 INT Carry = State->Flags.Cf ? 1 : 0;
2715
2716 /* Make sure this is the right instruction */
2717 ASSERT(Opcode == 0x1D);
2718
2719 NO_LOCK_PREFIX();
2720 TOGGLE_OPSIZE(Size);
2721
2722 if (Size)
2723 {
2724 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
2725 ULONG SecondValue, Result;
2726
2727 if (!Fast486FetchDword(State, &SecondValue))
2728 {
2729 /* Exception occurred */
2730 return;
2731 }
2732
2733 /* Calculate the result */
2734 Result = FirstValue - SecondValue - Carry;
2735
2736 /* Update the flags */
2737 State->Flags.Cf = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue);
2738 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) != (SecondValue & SIGN_FLAG_LONG))
2739 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
2740 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2741 State->Flags.Zf = (Result == 0);
2742 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2743 State->Flags.Pf = Fast486CalculateParity(Result);
2744
2745 /* Write back the result */
2746 State->GeneralRegs[FAST486_REG_EAX].Long = Result;
2747 }
2748 else
2749 {
2750 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
2751 USHORT SecondValue, Result;
2752
2753 if (!Fast486FetchWord(State, &SecondValue))
2754 {
2755 /* Exception occurred */
2756 return;
2757 }
2758
2759 /* Calculate the result */
2760 Result = FirstValue - SecondValue - Carry;
2761
2762 /* Update the flags */
2763 State->Flags.Cf = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue);
2764 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) != (SecondValue & SIGN_FLAG_WORD))
2765 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
2766 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2767 State->Flags.Zf = (Result == 0);
2768 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2769 State->Flags.Pf = Fast486CalculateParity(Result);
2770
2771 /* Write back the result */
2772 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
2773 }
2774 }
2775
2776 FAST486_OPCODE_HANDLER(Fast486OpcodePushDs)
2777 {
2778 /* Call the internal API */
2779 Fast486StackPush(State, State->SegmentRegs[FAST486_REG_DS].Selector);
2780 }
2781
2782 FAST486_OPCODE_HANDLER(Fast486OpcodePopDs)
2783 {
2784 ULONG NewSelector;
2785
2786 if (!Fast486StackPop(State, &NewSelector))
2787 {
2788 /* Exception occurred */
2789 return;
2790 }
2791
2792 /* Call the internal API */
2793 Fast486LoadSegment(State, FAST486_REG_DS, LOWORD(NewSelector));
2794 }
2795
2796 FAST486_OPCODE_HANDLER(Fast486OpcodeDaa)
2797 {
2798 UCHAR Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
2799 BOOLEAN Carry = State->Flags.Cf;
2800
2801 /* Clear the carry flag */
2802 State->Flags.Cf = FALSE;
2803
2804 /* Check if the first BCD digit is invalid or there was a carry from it */
2805 if (((Value & 0x0F) > 9) || State->Flags.Af)
2806 {
2807 /* Correct it */
2808 State->GeneralRegs[FAST486_REG_EAX].LowByte += 0x06;
2809 if (State->GeneralRegs[FAST486_REG_EAX].LowByte < 0x06)
2810 {
2811 /* A carry occurred */
2812 State->Flags.Cf = TRUE;
2813 }
2814
2815 /* Set the adjust flag */
2816 State->Flags.Af = TRUE;
2817 }
2818
2819 /* Check if the second BCD digit is invalid or there was a carry from it */
2820 if ((Value > 0x99) || Carry)
2821 {
2822 /* Correct it */
2823 State->GeneralRegs[FAST486_REG_EAX].LowByte += 0x60;
2824
2825 /* There was a carry */
2826 State->Flags.Cf = TRUE;
2827 }
2828
2829 Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
2830
2831 /* Update the flags */
2832 State->Flags.Sf = (Value & SIGN_FLAG_BYTE) != 0;
2833 State->Flags.Zf = (Value == 0);
2834 State->Flags.Pf = Fast486CalculateParity(Value);
2835 }
2836
2837 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubByteModrm)
2838 {
2839 UCHAR FirstValue, SecondValue, Result;
2840 FAST486_MOD_REG_RM ModRegRm;
2841 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2842
2843 /* Make sure this is the right instruction */
2844 ASSERT((Opcode & 0xED) == 0x28);
2845
2846 TOGGLE_ADSIZE(AddressSize);
2847
2848 /* Get the operands */
2849 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2850 {
2851 /* Exception occurred */
2852 return;
2853 }
2854
2855 if (!Fast486ReadModrmByteOperands(State,
2856 &ModRegRm,
2857 &FirstValue,
2858 &SecondValue))
2859 {
2860 /* Exception occurred */
2861 return;
2862 }
2863
2864 /* Check if this is the instruction that writes to R/M */
2865 if (!(Opcode & FAST486_OPCODE_WRITE_REG))
2866 {
2867 /* Swap the order */
2868 SWAP(FirstValue, SecondValue);
2869 }
2870
2871 /* Calculate the result */
2872 Result = FirstValue - SecondValue;
2873
2874 /* Update the flags */
2875 State->Flags.Cf = (FirstValue < SecondValue);
2876 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) != (SecondValue & SIGN_FLAG_BYTE))
2877 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
2878 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
2879 State->Flags.Zf = (Result == 0);
2880 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2881 State->Flags.Pf = Fast486CalculateParity(Result);
2882
2883 /* Check if this is not a CMP */
2884 if (!(Opcode & 0x10))
2885 {
2886 /* Write back the result */
2887 Fast486WriteModrmByteOperands(State,
2888 &ModRegRm,
2889 Opcode & FAST486_OPCODE_WRITE_REG,
2890 Result);
2891 }
2892 }
2893
2894 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubModrm)
2895 {
2896 FAST486_MOD_REG_RM ModRegRm;
2897 BOOLEAN OperandSize, AddressSize;
2898
2899 /* Make sure this is the right instruction */
2900 ASSERT((Opcode & 0xED) == 0x29);
2901
2902 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2903
2904 TOGGLE_ADSIZE(AddressSize);
2905 TOGGLE_OPSIZE(OperandSize);
2906
2907 /* Get the operands */
2908 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2909 {
2910 /* Exception occurred */
2911 return;
2912 }
2913
2914 /* Check the operand size */
2915 if (OperandSize)
2916 {
2917 ULONG FirstValue, SecondValue, Result;
2918
2919 if (!Fast486ReadModrmDwordOperands(State,
2920 &ModRegRm,
2921 &FirstValue,
2922 &SecondValue))
2923 {
2924 /* Exception occurred */
2925 return;
2926 }
2927
2928 /* Check if this is the instruction that writes to R/M */
2929 if (!(Opcode & FAST486_OPCODE_WRITE_REG))
2930 {
2931 /* Swap the order */
2932 SWAP(FirstValue, SecondValue);
2933 }
2934
2935 /* Calculate the result */
2936 Result = FirstValue - SecondValue;
2937
2938 /* Update the flags */
2939 State->Flags.Cf = (FirstValue < SecondValue);
2940 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) != (SecondValue & SIGN_FLAG_LONG))
2941 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
2942 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
2943 State->Flags.Zf = (Result == 0);
2944 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2945 State->Flags.Pf = Fast486CalculateParity(Result);
2946
2947 /* Check if this is not a CMP */
2948 if (!(Opcode & 0x10))
2949 {
2950 /* Write back the result */
2951 Fast486WriteModrmDwordOperands(State,
2952 &ModRegRm,
2953 Opcode & FAST486_OPCODE_WRITE_REG,
2954 Result);
2955 }
2956 }
2957 else
2958 {
2959 USHORT FirstValue, SecondValue, Result;
2960
2961 if (!Fast486ReadModrmWordOperands(State,
2962 &ModRegRm,
2963 &FirstValue,
2964 &SecondValue))
2965 {
2966 /* Exception occurred */
2967 return;
2968 }
2969
2970 /* Check if this is the instruction that writes to R/M */
2971 if (!(Opcode & FAST486_OPCODE_WRITE_REG))
2972 {
2973 /* Swap the order */
2974 SWAP(FirstValue, SecondValue);
2975 }
2976
2977 /* Calculate the result */
2978 Result = FirstValue - SecondValue;
2979
2980 /* Update the flags */
2981 State->Flags.Cf = (FirstValue < SecondValue);
2982 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) != (SecondValue & SIGN_FLAG_WORD))
2983 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
2984 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
2985 State->Flags.Zf = (Result == 0);
2986 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2987 State->Flags.Pf = Fast486CalculateParity(Result);
2988
2989 /* Check if this is not a CMP */
2990 if (!(Opcode & 0x10))
2991 {
2992 /* Write back the result */
2993 Fast486WriteModrmWordOperands(State,
2994 &ModRegRm,
2995 Opcode & FAST486_OPCODE_WRITE_REG,
2996 Result);
2997 }
2998 }
2999 }
3000
3001 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubAl)
3002 {
3003 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
3004 UCHAR SecondValue, Result;
3005
3006 /* Make sure this is the right instruction */
3007 ASSERT((Opcode & 0xEF) == 0x2C);
3008
3009 NO_LOCK_PREFIX();
3010
3011 if (!Fast486FetchByte(State, &SecondValue))
3012 {
3013 /* Exception occurred */
3014 return;
3015 }
3016
3017 /* Calculate the result */
3018 Result = FirstValue - SecondValue;
3019
3020 /* Update the flags */
3021 State->Flags.Cf = (FirstValue < SecondValue);
3022 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) != (SecondValue & SIGN_FLAG_BYTE))
3023 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
3024 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3025 State->Flags.Zf = (Result == 0);
3026 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
3027 State->Flags.Pf = Fast486CalculateParity(Result);
3028
3029 /* Check if this is not a CMP */
3030 if (!(Opcode & 0x10))
3031 {
3032 /* Write back the result */
3033 State->GeneralRegs[FAST486_REG_EAX].LowByte = Result;
3034 }
3035 }
3036
3037 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubEax)
3038 {
3039 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
3040
3041 /* Make sure this is the right instruction */
3042 ASSERT((Opcode & 0xEF) == 0x2D);
3043
3044 NO_LOCK_PREFIX();
3045 TOGGLE_OPSIZE(Size);
3046
3047 if (Size)
3048 {
3049 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
3050 ULONG SecondValue, Result;
3051
3052 if (!Fast486FetchDword(State, &SecondValue))
3053 {
3054 /* Exception occurred */
3055 return;
3056 }
3057
3058 /* Calculate the result */
3059 Result = FirstValue - SecondValue;
3060
3061 /* Update the flags */
3062 State->Flags.Cf = (FirstValue < SecondValue);
3063 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) != (SecondValue & SIGN_FLAG_LONG))
3064 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
3065 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3066 State->Flags.Zf = (Result == 0);
3067 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
3068 State->Flags.Pf = Fast486CalculateParity(Result);
3069
3070 /* Check if this is not a CMP */
3071 if (!(Opcode & 0x10))
3072 {
3073 /* Write back the result */
3074 State->GeneralRegs[FAST486_REG_EAX].Long = Result;
3075 }
3076 }
3077 else
3078 {
3079 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
3080 USHORT SecondValue, Result;
3081
3082 if (!Fast486FetchWord(State, &SecondValue))
3083 {
3084 /* Exception occurred */
3085 return;
3086 }
3087
3088 /* Calculate the result */
3089 Result = FirstValue - SecondValue;
3090
3091 /* Update the flags */
3092 State->Flags.Cf = (FirstValue < SecondValue);
3093 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) != (SecondValue & SIGN_FLAG_WORD))
3094 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
3095 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3096 State->Flags.Zf = (Result == 0);
3097 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
3098 State->Flags.Pf = Fast486CalculateParity(Result);
3099
3100 /* Check if this is not a CMP */
3101 if (!(Opcode & 0x10))
3102 {
3103 /* Write back the result */
3104 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
3105 }
3106 }
3107 }
3108
3109 FAST486_OPCODE_HANDLER(Fast486OpcodeDas)
3110 {
3111 UCHAR Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
3112 BOOLEAN Carry = State->Flags.Cf;
3113
3114 /* Clear the carry flag */
3115 State->Flags.Cf = FALSE;
3116
3117 /* Check if the first BCD digit is invalid or there was a borrow */
3118 if (((Value & 0x0F) > 9) || State->Flags.Af)
3119 {
3120 /* Correct it */
3121 State->GeneralRegs[FAST486_REG_EAX].LowByte -= 0x06;
3122 if (State->GeneralRegs[FAST486_REG_EAX].LowByte > 0xFB)
3123 {
3124 /* A borrow occurred */
3125 State->Flags.Cf = TRUE;
3126 }
3127
3128 /* Set the adjust flag */
3129 State->Flags.Af = TRUE;
3130 }
3131
3132 /* Check if the second BCD digit is invalid or there was a borrow */
3133 if ((Value > 0x99) || Carry)
3134 {
3135 /* Correct it */
3136 State->GeneralRegs[FAST486_REG_EAX].LowByte -= 0x60;
3137
3138 /* There was a borrow */
3139 State->Flags.Cf = TRUE;
3140 }
3141
3142 Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
3143
3144 /* Update the flags */
3145 State->Flags.Sf = (Value & SIGN_FLAG_BYTE) != 0;
3146 State->Flags.Zf = (Value == 0);
3147 State->Flags.Pf = Fast486CalculateParity(Value);
3148 }
3149
3150 FAST486_OPCODE_HANDLER(Fast486OpcodeAaa)
3151 {
3152 UCHAR Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
3153
3154 /*
3155 * Check if the value in AL is not a valid BCD digit,
3156 * or there was a carry from the lowest 4 bits of AL
3157 */
3158 if (((Value & 0x0F) > 9) || State->Flags.Af)
3159 {
3160 /* Correct it */
3161 State->GeneralRegs[FAST486_REG_EAX].LowWord += 0x06;
3162 State->GeneralRegs[FAST486_REG_EAX].HighByte++;
3163
3164 /* Set CF and AF */
3165 State->Flags.Cf = State->Flags.Af = TRUE;
3166 }
3167 else
3168 {
3169 /* Clear CF and AF */
3170 State->Flags.Cf = State->Flags.Af = FALSE;
3171 }
3172
3173 /* Keep only the lowest 4 bits of AL */
3174 State->GeneralRegs[FAST486_REG_EAX].LowByte &= 0x0F;
3175 }
3176
3177 FAST486_OPCODE_HANDLER(Fast486OpcodeAas)
3178 {
3179 UCHAR Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
3180
3181 /*
3182 * Check if the value in AL is not a valid BCD digit,
3183 * or there was a borrow from the lowest 4 bits of AL
3184 */
3185 if (((Value & 0x0F) > 9) || State->Flags.Af)
3186 {
3187 /* Correct it */
3188 State->GeneralRegs[FAST486_REG_EAX].LowWord -= 0x06;
3189 State->GeneralRegs[FAST486_REG_EAX].HighByte--;
3190
3191 /* Set CF and AF */
3192 State->Flags.Cf = State->Flags.Af = TRUE;
3193 }
3194 else
3195 {
3196 /* Clear CF and AF */
3197 State->Flags.Cf = State->Flags.Af = FALSE;
3198 }
3199
3200 /* Keep only the lowest 4 bits of AL */
3201 State->GeneralRegs[FAST486_REG_EAX].LowByte &= 0x0F;
3202 }
3203
3204 FAST486_OPCODE_HANDLER(Fast486OpcodePushAll)
3205 {
3206 INT i;
3207 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
3208 FAST486_REG SavedEsp = State->GeneralRegs[FAST486_REG_ESP];
3209
3210 /* Make sure this is the right instruction */
3211 ASSERT(Opcode == 0x60);
3212
3213 TOGGLE_OPSIZE(Size);
3214 NO_LOCK_PREFIX();
3215
3216 /* Push all the registers in order */
3217 for (i = 0; i < FAST486_NUM_GEN_REGS; i++)
3218 {
3219 if (i == FAST486_REG_ESP)
3220 {
3221 /* Use the saved ESP instead */
3222 if (!Fast486StackPush(State, Size ? SavedEsp.Long : SavedEsp.LowWord))
3223 {
3224 /* Exception occurred */
3225 return;
3226 }
3227 }
3228 else
3229 {
3230 /* Push the register */
3231 if (!Fast486StackPush(State, Size ? State->GeneralRegs[i].Long
3232 : State->GeneralRegs[i].LowWord))
3233 {
3234 /* Exception occurred */
3235 return;
3236 }
3237 }
3238 }
3239 }
3240
3241 FAST486_OPCODE_HANDLER(Fast486OpcodePopAll)
3242 {
3243 INT i;
3244 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
3245 ULONG Value;
3246
3247 /* Make sure this is the right instruction */
3248 ASSERT(Opcode == 0x61);
3249
3250 TOGGLE_OPSIZE(Size);
3251 NO_LOCK_PREFIX();
3252
3253 /* Pop all the registers in reverse order */
3254 for (i = FAST486_NUM_GEN_REGS - 1; i >= 0; i--)
3255 {
3256 /* Pop the value */
3257 if (!Fast486StackPop(State, &Value))
3258 {
3259 /* Exception occurred */
3260 return;
3261 }
3262
3263 /* Don't modify ESP */
3264 if (i != FAST486_REG_ESP)
3265 {
3266 if (Size) State->GeneralRegs[i].Long = Value;
3267 else State->GeneralRegs[i].LowWord = LOWORD(Value);
3268 }
3269 }
3270 }
3271
3272 FAST486_OPCODE_HANDLER(Fast486OpcodeBound)
3273 {
3274 BOOLEAN OperandSize, AddressSize;
3275 FAST486_MOD_REG_RM ModRegRm;
3276 FAST486_SEG_REGS Segment = FAST486_REG_DS;
3277
3278 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3279
3280 NO_LOCK_PREFIX();
3281 TOGGLE_OPSIZE(OperandSize);
3282 TOGGLE_ADSIZE(AddressSize);
3283
3284 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3285 {
3286 /* Exception occurred */
3287 return;
3288 }
3289
3290 if (!ModRegRm.Memory)
3291 {
3292 /* Invalid */
3293 Fast486Exception(State, FAST486_EXCEPTION_UD);
3294 return;
3295 }
3296
3297 /* Check for the segment override */
3298 if (State->PrefixFlags & FAST486_PREFIX_SEG)
3299 {
3300 /* Use the override segment instead */
3301 Segment = State->SegmentOverride;
3302 }
3303
3304 if (OperandSize)
3305 {
3306 LONG Index, LowerBound, UpperBound;
3307
3308 /* Read the operands */
3309 if (!Fast486ReadModrmDwordOperands(State,
3310 &ModRegRm,
3311 (PULONG)&Index,
3312 (PULONG)&LowerBound))
3313 {
3314 /* Exception occurred */
3315 return;
3316 }
3317
3318 if (!Fast486ReadMemory(State,
3319 Segment,
3320 ModRegRm.MemoryAddress + sizeof(ULONG),
3321 FALSE,
3322 &UpperBound,
3323 sizeof(ULONG)))
3324 {
3325 /* Exception occurred */
3326 return;
3327 }
3328
3329 if ((Index < LowerBound) || (Index > UpperBound))
3330 {
3331 /* Out of bounds */
3332 Fast486Exception(State, FAST486_EXCEPTION_BR);
3333 }
3334 }
3335 else
3336 {
3337 SHORT Index, LowerBound, UpperBound;
3338
3339 /* Read the operands */
3340 if (!Fast486ReadModrmWordOperands(State,
3341 &ModRegRm,
3342 (PUSHORT)&Index,
3343 (PUSHORT)&LowerBound))
3344 {
3345 /* Exception occurred */
3346 return;
3347 }
3348
3349 if (!Fast486ReadMemory(State,
3350 Segment,
3351 ModRegRm.MemoryAddress + sizeof(USHORT),
3352 FALSE,
3353 &UpperBound,
3354 sizeof(USHORT)))
3355 {
3356 /* Exception occurred */
3357 return;
3358 }
3359
3360 if ((Index < LowerBound) || (Index > UpperBound))
3361 {
3362 /* Out of bounds */
3363 Fast486Exception(State, FAST486_EXCEPTION_BR);
3364 }
3365 }
3366 }
3367
3368 FAST486_OPCODE_HANDLER(Fast486OpcodeArpl)
3369 {
3370 USHORT FirstValue, SecondValue;
3371 FAST486_MOD_REG_RM ModRegRm;
3372 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3373
3374 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
3375 || State->Flags.Vm
3376 || (State->PrefixFlags & FAST486_PREFIX_LOCK))
3377 {
3378 /* Cannot be used in real mode or with a LOCK prefix */
3379 Fast486Exception(State, FAST486_EXCEPTION_UD);
3380 return;
3381 }
3382
3383 TOGGLE_ADSIZE(AddressSize);
3384
3385 /* Get the operands */
3386 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3387 {
3388 /* Exception occurred */
3389 return;
3390 }
3391
3392 /* Read the operands */
3393 if (!Fast486ReadModrmWordOperands(State,
3394 &ModRegRm,
3395 &FirstValue,
3396 &SecondValue))
3397 {
3398 /* Exception occurred */
3399 return;
3400 }
3401
3402 /* Check if the RPL needs adjusting */
3403 if ((SecondValue & 3) < (FirstValue & 3))
3404 {
3405 /* Adjust the RPL */
3406 SecondValue &= ~3;
3407 SecondValue |= FirstValue & 3;
3408
3409 /* Set ZF */
3410 State->Flags.Zf = TRUE;
3411
3412 /* Write back the result */
3413 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, SecondValue);
3414 }
3415 else
3416 {
3417 /* Clear ZF */
3418 State->Flags.Zf = FALSE;
3419 }
3420 }
3421
3422 FAST486_OPCODE_HANDLER(Fast486OpcodePushImm)
3423 {
3424 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
3425
3426 /* Make sure this is the right instruction */
3427 ASSERT(Opcode == 0x68);
3428
3429 NO_LOCK_PREFIX();
3430 TOGGLE_OPSIZE(Size);
3431