[FAST486]
[reactos.git] / reactos / lib / fast486 / opcodes.c
1 /*
2 * Fast486 386/486 CPU Emulation Library
3 * opcodes.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 "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 Fast486FpuOpcodeD8DC, /* 0xD8 - 0xDF */
258 Fast486FpuOpcodeD9,
259 Fast486FpuOpcodeDA,
260 Fast486FpuOpcodeDB,
261 Fast486FpuOpcodeD8DC,
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
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 /* This is not a valid opcode */
304 Fast486Exception(State, FAST486_EXCEPTION_UD);
305 return FALSE;
306 }
307
308 FAST486_OPCODE_HANDLER(Fast486OpcodePrefix)
309 {
310 BOOLEAN Valid = FALSE;
311
312 switch (Opcode)
313 {
314 /* ES: */
315 case 0x26:
316 {
317 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
318 {
319 State->PrefixFlags |= FAST486_PREFIX_SEG;
320 State->SegmentOverride = FAST486_REG_ES;
321 Valid = TRUE;
322 }
323
324 break;
325 }
326
327 /* CS: */
328 case 0x2E:
329 {
330 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
331 {
332 State->PrefixFlags |= FAST486_PREFIX_SEG;
333 State->SegmentOverride = FAST486_REG_CS;
334 Valid = TRUE;
335 }
336
337 break;
338 }
339
340 /* SS: */
341 case 0x36:
342 {
343 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
344 {
345 State->PrefixFlags |= FAST486_PREFIX_SEG;
346 State->SegmentOverride = FAST486_REG_SS;
347 Valid = TRUE;
348 }
349
350 break;
351 }
352
353 /* DS: */
354 case 0x3E:
355 {
356 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
357 {
358 State->PrefixFlags |= FAST486_PREFIX_SEG;
359 State->SegmentOverride = FAST486_REG_DS;
360 Valid = TRUE;
361 }
362
363 break;
364 }
365
366 /* FS: */
367 case 0x64:
368 {
369 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
370 {
371 State->PrefixFlags |= FAST486_PREFIX_SEG;
372 State->SegmentOverride = FAST486_REG_FS;
373 Valid = TRUE;
374 }
375
376 break;
377 }
378
379 /* GS: */
380 case 0x65:
381 {
382 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
383 {
384 State->PrefixFlags |= FAST486_PREFIX_SEG;
385 State->SegmentOverride = FAST486_REG_GS;
386 Valid = TRUE;
387 }
388
389 break;
390 }
391
392 /* OPSIZE */
393 case 0x66:
394 {
395 if (!(State->PrefixFlags & FAST486_PREFIX_OPSIZE))
396 {
397 State->PrefixFlags |= FAST486_PREFIX_OPSIZE;
398 Valid = TRUE;
399 }
400
401 break;
402 }
403
404 /* ADSIZE */
405 case 0x67:
406 {
407 if (!(State->PrefixFlags & FAST486_PREFIX_ADSIZE))
408 {
409 State->PrefixFlags |= FAST486_PREFIX_ADSIZE;
410 Valid = TRUE;
411 }
412 break;
413 }
414
415 /* LOCK */
416 case 0xF0:
417 {
418 if (!(State->PrefixFlags & FAST486_PREFIX_LOCK))
419 {
420 State->PrefixFlags |= FAST486_PREFIX_LOCK;
421 Valid = TRUE;
422 }
423
424 break;
425 }
426
427 /* REPNZ */
428 case 0xF2:
429 {
430 /* Mutually exclusive with REP */
431 if (!(State->PrefixFlags
432 & (FAST486_PREFIX_REPNZ | FAST486_PREFIX_REP)))
433 {
434 State->PrefixFlags |= FAST486_PREFIX_REPNZ;
435 Valid = TRUE;
436 }
437
438 break;
439 }
440
441 /* REP / REPZ */
442 case 0xF3:
443 {
444 /* Mutually exclusive with REPNZ */
445 if (!(State->PrefixFlags
446 & (FAST486_PREFIX_REPNZ | FAST486_PREFIX_REP)))
447 {
448 State->PrefixFlags |= FAST486_PREFIX_REP;
449 Valid = TRUE;
450 }
451
452 break;
453 }
454 }
455
456 if (!Valid)
457 {
458 /* Clear all prefixes */
459 State->PrefixFlags = 0;
460
461 /* Throw an exception */
462 Fast486Exception(State, FAST486_EXCEPTION_UD);
463 return FALSE;
464 }
465
466 return TRUE;
467 }
468
469 FAST486_OPCODE_HANDLER(Fast486OpcodeIncrement)
470 {
471 ULONG Value;
472 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
473
474 TOGGLE_OPSIZE(Size);
475 NO_LOCK_PREFIX();
476
477 /* Make sure this is the right instruction */
478 ASSERT((Opcode & 0xF8) == 0x40);
479
480 if (Size)
481 {
482 Value = ++State->GeneralRegs[Opcode & 0x07].Long;
483
484 State->Flags.Of = (Value == SIGN_FLAG_LONG);
485 State->Flags.Sf = ((Value & SIGN_FLAG_LONG) != 0);
486 }
487 else
488 {
489 Value = ++State->GeneralRegs[Opcode & 0x07].LowWord;
490
491 State->Flags.Of = (Value == SIGN_FLAG_WORD);
492 State->Flags.Sf = ((Value & SIGN_FLAG_WORD) != 0);
493 }
494
495 State->Flags.Zf = (Value == 0);
496 State->Flags.Af = ((Value & 0x0F) == 0);
497 State->Flags.Pf = Fast486CalculateParity(LOBYTE(Value));
498
499 /* Return success */
500 return TRUE;
501 }
502
503 FAST486_OPCODE_HANDLER(Fast486OpcodeDecrement)
504 {
505 ULONG Value;
506 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
507
508 TOGGLE_OPSIZE(Size);
509 NO_LOCK_PREFIX();
510
511 /* Make sure this is the right instruction */
512 ASSERT((Opcode & 0xF8) == 0x48);
513
514 if (Size)
515 {
516 Value = --State->GeneralRegs[Opcode & 0x07].Long;
517
518 State->Flags.Of = (Value == (SIGN_FLAG_LONG - 1));
519 State->Flags.Sf = ((Value & SIGN_FLAG_LONG) != 0);
520 }
521 else
522 {
523 Value = --State->GeneralRegs[Opcode & 0x07].LowWord;
524
525 State->Flags.Of = (Value == (SIGN_FLAG_WORD - 1));
526 State->Flags.Sf = ((Value & SIGN_FLAG_WORD) != 0);
527 }
528
529 State->Flags.Zf = (Value == 0);
530 State->Flags.Af = ((Value & 0x0F) == 0x0F);
531 State->Flags.Pf = Fast486CalculateParity(LOBYTE(Value));
532
533 /* Return success */
534 return TRUE;
535 }
536
537 FAST486_OPCODE_HANDLER(Fast486OpcodePushReg)
538 {
539 NO_LOCK_PREFIX();
540
541 /* Make sure this is the right instruction */
542 ASSERT((Opcode & 0xF8) == 0x50);
543
544 /* Call the internal function */
545 return Fast486StackPush(State, State->GeneralRegs[Opcode & 0x07].Long);
546 }
547
548 FAST486_OPCODE_HANDLER(Fast486OpcodePopReg)
549 {
550 ULONG Value;
551 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
552
553 TOGGLE_OPSIZE(Size);
554 NO_LOCK_PREFIX();
555
556 /* Make sure this is the right instruction */
557 ASSERT((Opcode & 0xF8) == 0x58);
558
559 /* Call the internal function */
560 if (!Fast486StackPop(State, &Value)) return FALSE;
561
562 /* Store the value */
563 if (Size) State->GeneralRegs[Opcode & 0x07].Long = Value;
564 else State->GeneralRegs[Opcode & 0x07].LowWord = Value;
565
566 /* Return success */
567 return TRUE;
568 }
569
570 FAST486_OPCODE_HANDLER(Fast486OpcodeNop)
571 {
572 if (State->PrefixFlags & FAST486_PREFIX_REP)
573 {
574 /* Idle cycle */
575 State->IdleCallback(State);
576 }
577
578 return TRUE;
579 }
580
581 FAST486_OPCODE_HANDLER(Fast486OpcodeExchangeEax)
582 {
583 INT Reg = Opcode & 0x07;
584 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
585
586 TOGGLE_OPSIZE(Size);
587 NO_LOCK_PREFIX();
588
589 /* Make sure this is the right instruction */
590 ASSERT((Opcode & 0xF8) == 0x90);
591
592 /* Exchange the values */
593 if (Size)
594 {
595 ULONG Value;
596
597 Value = State->GeneralRegs[Reg].Long;
598 State->GeneralRegs[Reg].Long = State->GeneralRegs[FAST486_REG_EAX].Long;
599 State->GeneralRegs[FAST486_REG_EAX].Long = Value;
600 }
601 else
602 {
603 USHORT Value;
604
605 Value = State->GeneralRegs[Reg].LowWord;
606 State->GeneralRegs[Reg].LowWord = State->GeneralRegs[FAST486_REG_EAX].LowWord;
607 State->GeneralRegs[FAST486_REG_EAX].LowWord = Value;
608 }
609
610 return TRUE;
611 }
612
613 FAST486_OPCODE_HANDLER(Fast486OpcodeShortConditionalJmp)
614 {
615 BOOLEAN Jump = FALSE;
616 CHAR Offset = 0;
617 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
618
619 /* Make sure this is the right instruction */
620 ASSERT((Opcode & 0xF0) == 0x70);
621
622 TOGGLE_OPSIZE(Size);
623
624 /* Fetch the offset */
625 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
626 {
627 /* An exception occurred */
628 return FALSE;
629 }
630
631 switch ((Opcode & 0x0F) >> 1)
632 {
633 /* JO / JNO */
634 case 0:
635 {
636 Jump = State->Flags.Of;
637 break;
638 }
639
640 /* JC / JNC */
641 case 1:
642 {
643 Jump = State->Flags.Cf;
644 break;
645 }
646
647 /* JZ / JNZ */
648 case 2:
649 {
650 Jump = State->Flags.Zf;
651 break;
652 }
653
654 /* JBE / JNBE */
655 case 3:
656 {
657 Jump = State->Flags.Cf || State->Flags.Zf;
658 break;
659 }
660
661 /* JS / JNS */
662 case 4:
663 {
664 Jump = State->Flags.Sf;
665 break;
666 }
667
668 /* JP / JNP */
669 case 5:
670 {
671 Jump = State->Flags.Pf;
672 break;
673 }
674
675 /* JL / JNL */
676 case 6:
677 {
678 Jump = State->Flags.Sf != State->Flags.Of;
679 break;
680 }
681
682 /* JLE / JNLE */
683 case 7:
684 {
685 Jump = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
686 break;
687 }
688 }
689
690 if (Opcode & 1)
691 {
692 /* Invert the result */
693 Jump = !Jump;
694 }
695
696 if (Jump)
697 {
698 /* Move the instruction pointer */
699 State->InstPtr.Long += Offset;
700
701 if (!Size)
702 {
703 /* Clear the top half of EIP */
704 State->InstPtr.Long &= 0xFFFF;
705 }
706 }
707
708 /* Return success */
709 return TRUE;
710 }
711
712 FAST486_OPCODE_HANDLER(Fast486OpcodeClearCarry)
713 {
714 /* Make sure this is the right instruction */
715 ASSERT(Opcode == 0xF8);
716
717 /* No prefixes allowed */
718 if (State->PrefixFlags)
719 {
720 Fast486Exception(State, FAST486_EXCEPTION_UD);
721 return FALSE;
722 }
723
724 /* Clear CF and return success */
725 State->Flags.Cf = FALSE;
726 return TRUE;
727 }
728
729 FAST486_OPCODE_HANDLER(Fast486OpcodeSetCarry)
730 {
731 /* Make sure this is the right instruction */
732 ASSERT(Opcode == 0xF9);
733
734 /* No prefixes allowed */
735 if (State->PrefixFlags)
736 {
737 Fast486Exception(State, FAST486_EXCEPTION_UD);
738 return FALSE;
739 }
740
741 /* Set CF and return success*/
742 State->Flags.Cf = TRUE;
743 return TRUE;
744 }
745
746 FAST486_OPCODE_HANDLER(Fast486OpcodeComplCarry)
747 {
748 /* Make sure this is the right instruction */
749 ASSERT(Opcode == 0xF5);
750
751 /* No prefixes allowed */
752 if (State->PrefixFlags)
753 {
754 Fast486Exception(State, FAST486_EXCEPTION_UD);
755 return FALSE;
756 }
757
758 /* Toggle CF and return success */
759 State->Flags.Cf = !State->Flags.Cf;
760 return TRUE;
761 }
762
763 FAST486_OPCODE_HANDLER(Fast486OpcodeClearInt)
764 {
765 /* Make sure this is the right instruction */
766 ASSERT(Opcode == 0xFA);
767
768 /* No prefixes allowed */
769 if (State->PrefixFlags)
770 {
771 Fast486Exception(State, FAST486_EXCEPTION_UD);
772 return FALSE;
773 }
774
775 /* Check for protected mode */
776 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
777 {
778 /* Check IOPL */
779 if (State->Flags.Iopl >= State->SegmentRegs[FAST486_REG_CS].Dpl)
780 {
781 /* Clear the interrupt flag */
782 State->Flags.If = FALSE;
783 }
784 else
785 {
786 /* General Protection Fault */
787 Fast486Exception(State, FAST486_EXCEPTION_GP);
788 return FALSE;
789 }
790 }
791 else
792 {
793 /* Just clear the interrupt flag */
794 State->Flags.If = FALSE;
795 }
796
797 /* Return success */
798 return TRUE;
799 }
800
801 FAST486_OPCODE_HANDLER(Fast486OpcodeSetInt)
802 {
803 /* Make sure this is the right instruction */
804 ASSERT(Opcode == 0xFB);
805
806 /* No prefixes allowed */
807 if (State->PrefixFlags)
808 {
809 Fast486Exception(State, FAST486_EXCEPTION_UD);
810 return FALSE;
811 }
812
813 /* Check for protected mode */
814 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
815 {
816 /* Check IOPL */
817 if (State->Flags.Iopl >= State->SegmentRegs[FAST486_REG_CS].Dpl)
818 {
819 /* Set the interrupt flag */
820 State->Flags.If = TRUE;
821 }
822 else
823 {
824 /* General Protection Fault */
825 Fast486Exception(State, FAST486_EXCEPTION_GP);
826 return FALSE;
827 }
828 }
829 else
830 {
831 /* Just set the interrupt flag */
832 State->Flags.If = TRUE;
833 }
834
835 /* Return success */
836 return TRUE;
837 }
838
839 FAST486_OPCODE_HANDLER(Fast486OpcodeClearDir)
840 {
841 /* Make sure this is the right instruction */
842 ASSERT(Opcode == 0xFC);
843
844 /* No prefixes allowed */
845 if (State->PrefixFlags)
846 {
847 Fast486Exception(State, FAST486_EXCEPTION_UD);
848 return FALSE;
849 }
850
851 /* Clear DF and return success */
852 State->Flags.Df = FALSE;
853 return TRUE;
854 }
855
856 FAST486_OPCODE_HANDLER(Fast486OpcodeSetDir)
857 {
858 /* Make sure this is the right instruction */
859 ASSERT(Opcode == 0xFD);
860
861 /* No prefixes allowed */
862 if (State->PrefixFlags)
863 {
864 Fast486Exception(State, FAST486_EXCEPTION_UD);
865 return FALSE;
866 }
867
868 /* Set DF and return success*/
869 State->Flags.Df = TRUE;
870 return TRUE;
871 }
872
873 FAST486_OPCODE_HANDLER(Fast486OpcodeHalt)
874 {
875 /* Make sure this is the right instruction */
876 ASSERT(Opcode == 0xF4);
877
878 /* No prefixes allowed */
879 if (State->PrefixFlags)
880 {
881 Fast486Exception(State, FAST486_EXCEPTION_UD);
882 return FALSE;
883 }
884
885 /* Privileged instructions can only be executed under CPL = 0 */
886 if (State->SegmentRegs[FAST486_REG_CS].Dpl != 0)
887 {
888 Fast486Exception(State, FAST486_EXCEPTION_GP);
889 return FALSE;
890 }
891
892 /* Halt */
893 // TODO: Halt the CPU until an interrupt occurs, using IdleCallback if needed.
894
895 /* Return success */
896 return TRUE;
897 }
898
899 FAST486_OPCODE_HANDLER(Fast486OpcodeInByte)
900 {
901 UCHAR Data;
902 ULONG Port;
903
904 /* Make sure this is the right instruction */
905 ASSERT((Opcode & 0xF7) == 0xE4);
906
907 if (Opcode == 0xE4)
908 {
909 /* Fetch the parameter */
910 if (!Fast486FetchByte(State, &Data))
911 {
912 /* Exception occurred */
913 return FALSE;
914 }
915
916 /* Set the port number to the parameter */
917 Port = Data;
918 }
919 else
920 {
921 /* The port number is in DX */
922 Port = State->GeneralRegs[FAST486_REG_EDX].LowWord;
923 }
924
925 /* Read a byte from the I/O port */
926 State->IoReadCallback(State, Port, &Data, 1, sizeof(UCHAR));
927
928 /* Store the result in AL */
929 State->GeneralRegs[FAST486_REG_EAX].LowByte = Data;
930
931 return TRUE;
932 }
933
934 FAST486_OPCODE_HANDLER(Fast486OpcodeIn)
935 {
936 ULONG Port;
937 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
938
939 /* Make sure this is the right instruction */
940 ASSERT((Opcode & 0xF7) == 0xE5);
941
942 TOGGLE_OPSIZE(Size);
943 NO_LOCK_PREFIX();
944
945 if (Opcode == 0xE5)
946 {
947 UCHAR Data;
948
949 /* Fetch the parameter */
950 if (!Fast486FetchByte(State, &Data))
951 {
952 /* Exception occurred */
953 return FALSE;
954 }
955
956 /* Set the port number to the parameter */
957 Port = Data;
958 }
959 else
960 {
961 /* The port number is in DX */
962 Port = State->GeneralRegs[FAST486_REG_EDX].LowWord;
963 }
964
965 if (Size)
966 {
967 ULONG Data;
968
969 /* Read a dword from the I/O port */
970 State->IoReadCallback(State, Port, &Data, 1, sizeof(ULONG));
971
972 /* Store the value in EAX */
973 State->GeneralRegs[FAST486_REG_EAX].Long = Data;
974 }
975 else
976 {
977 USHORT Data;
978
979 /* Read a word from the I/O port */
980 State->IoReadCallback(State, Port, &Data, 1, sizeof(USHORT));
981
982 /* Store the value in AX */
983 State->GeneralRegs[FAST486_REG_EAX].LowWord = Data;
984 }
985
986 return TRUE;
987 }
988
989 FAST486_OPCODE_HANDLER(Fast486OpcodeOutByte)
990 {
991 UCHAR Data;
992 ULONG Port;
993
994 /* Make sure this is the right instruction */
995 ASSERT((Opcode & 0xF7) == 0xE6);
996
997 if (Opcode == 0xE6)
998 {
999 /* Fetch the parameter */
1000 if (!Fast486FetchByte(State, &Data))
1001 {
1002 /* Exception occurred */
1003 return FALSE;
1004 }
1005
1006 /* Set the port number to the parameter */
1007 Port = Data;
1008 }
1009 else
1010 {
1011 /* The port number is in DX */
1012 Port = State->GeneralRegs[FAST486_REG_EDX].LowWord;
1013 }
1014
1015 /* Read the value from AL */
1016 Data = State->GeneralRegs[FAST486_REG_EAX].LowByte;
1017
1018 /* Write the byte to the I/O port */
1019 State->IoWriteCallback(State, Port, &Data, 1, sizeof(UCHAR));
1020
1021 return TRUE;
1022 }
1023
1024 FAST486_OPCODE_HANDLER(Fast486OpcodeOut)
1025 {
1026 ULONG Port;
1027 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1028
1029 /* Make sure this is the right instruction */
1030 ASSERT((Opcode & 0xF7) == 0xE7);
1031
1032 TOGGLE_OPSIZE(Size);
1033 NO_LOCK_PREFIX();
1034
1035 if (Opcode == 0xE7)
1036 {
1037 UCHAR Data;
1038
1039 /* Fetch the parameter */
1040 if (!Fast486FetchByte(State, &Data))
1041 {
1042 /* Exception occurred */
1043 return FALSE;
1044 }
1045
1046 /* Set the port number to the parameter */
1047 Port = Data;
1048 }
1049 else
1050 {
1051 /* The port number is in DX */
1052 Port = State->GeneralRegs[FAST486_REG_EDX].LowWord;
1053 }
1054
1055 if (Size)
1056 {
1057 /* Get the value from EAX */
1058 ULONG Data = State->GeneralRegs[FAST486_REG_EAX].Long;
1059
1060 /* Write a dword to the I/O port */
1061 State->IoWriteCallback(State, Port, &Data, 1, sizeof(ULONG));
1062 }
1063 else
1064 {
1065 /* Get the value from AX */
1066 USHORT Data = State->GeneralRegs[FAST486_REG_EAX].LowWord;
1067
1068 /* Write a word to the I/O port */
1069 State->IoWriteCallback(State, Port, &Data, 1, sizeof(USHORT));
1070 }
1071
1072 return TRUE;
1073 }
1074
1075 FAST486_OPCODE_HANDLER(Fast486OpcodeShortJump)
1076 {
1077 CHAR Offset = 0;
1078 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1079
1080 TOGGLE_OPSIZE(Size);
1081
1082 /* Make sure this is the right instruction */
1083 ASSERT(Opcode == 0xEB);
1084
1085 /* Fetch the offset */
1086 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
1087 {
1088 /* An exception occurred */
1089 return FALSE;
1090 }
1091
1092 /* Move the instruction pointer */
1093 State->InstPtr.Long += Offset;
1094
1095 if (!Size)
1096 {
1097 /* Clear the top half of EIP */
1098 State->InstPtr.Long &= 0xFFFF;
1099 }
1100
1101 return TRUE;
1102 }
1103
1104 FAST486_OPCODE_HANDLER(Fast486OpcodeMovRegImm)
1105 {
1106 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1107
1108 /* Make sure this is the right instruction */
1109 ASSERT((Opcode & 0xF8) == 0xB8);
1110
1111 TOGGLE_OPSIZE(Size);
1112 NO_LOCK_PREFIX();
1113
1114 if (Size)
1115 {
1116 ULONG Value;
1117
1118 /* Fetch the dword */
1119 if (!Fast486FetchDword(State, &Value))
1120 {
1121 /* Exception occurred */
1122 return FALSE;
1123 }
1124
1125 /* Store the value in the register */
1126 State->GeneralRegs[Opcode & 0x07].Long = Value;
1127 }
1128 else
1129 {
1130 USHORT Value;
1131
1132 /* Fetch the word */
1133 if (!Fast486FetchWord(State, &Value))
1134 {
1135 /* Exception occurred */
1136 return FALSE;
1137 }
1138
1139 /* Store the value in the register */
1140 State->GeneralRegs[Opcode & 0x07].LowWord = Value;
1141 }
1142
1143 return TRUE;
1144 }
1145
1146 FAST486_OPCODE_HANDLER(Fast486OpcodeMovByteRegImm)
1147 {
1148 UCHAR Value;
1149
1150 /* Make sure this is the right instruction */
1151 ASSERT((Opcode & 0xF8) == 0xB0);
1152
1153 if (State->PrefixFlags != 0)
1154 {
1155 /* Invalid prefix */
1156 Fast486Exception(State, FAST486_EXCEPTION_UD);
1157 return FALSE;
1158 }
1159
1160 /* Fetch the byte */
1161 if (!Fast486FetchByte(State, &Value))
1162 {
1163 /* Exception occurred */
1164 return FALSE;
1165 }
1166
1167 if (Opcode & 0x04)
1168 {
1169 /* AH, CH, DH or BH */
1170 State->GeneralRegs[Opcode & 0x03].HighByte = Value;
1171 }
1172 else
1173 {
1174 /* AL, CL, DL or BL */
1175 State->GeneralRegs[Opcode & 0x03].LowByte = Value;
1176 }
1177
1178 return TRUE;
1179 }
1180
1181 FAST486_OPCODE_HANDLER(Fast486OpcodeAddByteModrm)
1182 {
1183 UCHAR FirstValue, SecondValue, Result;
1184 FAST486_MOD_REG_RM ModRegRm;
1185 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1186
1187 /* Make sure this is the right instruction */
1188 ASSERT((Opcode & 0xFD) == 0x00);
1189
1190 TOGGLE_ADSIZE(AddressSize);
1191
1192 /* Get the operands */
1193 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1194 {
1195 /* Exception occurred */
1196 return FALSE;
1197 }
1198
1199 if (!Fast486ReadModrmByteOperands(State,
1200 &ModRegRm,
1201 &FirstValue,
1202 &SecondValue))
1203 {
1204 /* Exception occurred */
1205 return FALSE;
1206 }
1207
1208 /* Calculate the result */
1209 Result = FirstValue + SecondValue;
1210
1211 /* Update the flags */
1212 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
1213 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) == (SecondValue & SIGN_FLAG_BYTE))
1214 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
1215 State->Flags.Af = ((((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) != 0);
1216 State->Flags.Zf = (Result == 0);
1217 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1218 State->Flags.Pf = Fast486CalculateParity(Result);
1219
1220 /* Write back the result */
1221 return Fast486WriteModrmByteOperands(State,
1222 &ModRegRm,
1223 Opcode & FAST486_OPCODE_WRITE_REG,
1224 Result);
1225 }
1226
1227 FAST486_OPCODE_HANDLER(Fast486OpcodeAddModrm)
1228 {
1229 FAST486_MOD_REG_RM ModRegRm;
1230 BOOLEAN OperandSize, AddressSize;
1231
1232 /* Make sure this is the right instruction */
1233 ASSERT((Opcode & 0xFD) == 0x01);
1234
1235 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1236
1237 TOGGLE_ADSIZE(AddressSize);
1238 TOGGLE_OPSIZE(OperandSize);
1239
1240 /* Get the operands */
1241 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1242 {
1243 /* Exception occurred */
1244 return FALSE;
1245 }
1246
1247 /* Check the operand size */
1248 if (OperandSize)
1249 {
1250 ULONG FirstValue, SecondValue, Result;
1251
1252 if (!Fast486ReadModrmDwordOperands(State,
1253 &ModRegRm,
1254 &FirstValue,
1255 &SecondValue))
1256 {
1257 /* Exception occurred */
1258 return FALSE;
1259 }
1260
1261 /* Calculate the result */
1262 Result = FirstValue + SecondValue;
1263
1264 /* Update the flags */
1265 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
1266 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) == (SecondValue & SIGN_FLAG_LONG))
1267 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
1268 State->Flags.Af = ((((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) != 0);
1269 State->Flags.Zf = (Result == 0);
1270 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1271 State->Flags.Pf = Fast486CalculateParity(Result);
1272
1273 /* Write back the result */
1274 return Fast486WriteModrmDwordOperands(State,
1275 &ModRegRm,
1276 Opcode & FAST486_OPCODE_WRITE_REG,
1277 Result);
1278 }
1279 else
1280 {
1281 USHORT FirstValue, SecondValue, Result;
1282
1283 if (!Fast486ReadModrmWordOperands(State,
1284 &ModRegRm,
1285 &FirstValue,
1286 &SecondValue))
1287 {
1288 /* Exception occurred */
1289 return FALSE;
1290 }
1291
1292 /* Calculate the result */
1293 Result = FirstValue + SecondValue;
1294
1295 /* Update the flags */
1296 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
1297 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) == (SecondValue & SIGN_FLAG_WORD))
1298 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
1299 State->Flags.Af = ((((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) != 0);
1300 State->Flags.Zf = (Result == 0);
1301 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1302 State->Flags.Pf = Fast486CalculateParity(Result);
1303
1304 /* Write back the result */
1305 return Fast486WriteModrmWordOperands(State,
1306 &ModRegRm,
1307 Opcode & FAST486_OPCODE_WRITE_REG,
1308 Result);
1309 }
1310 }
1311
1312 FAST486_OPCODE_HANDLER(Fast486OpcodeAddAl)
1313 {
1314 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
1315 UCHAR SecondValue, Result;
1316
1317 /* Make sure this is the right instruction */
1318 ASSERT(Opcode == 0x04);
1319
1320 if (State->PrefixFlags)
1321 {
1322 /* This opcode doesn't take any prefixes */
1323 Fast486Exception(State, FAST486_EXCEPTION_UD);
1324 return FALSE;
1325 }
1326
1327 if (!Fast486FetchByte(State, &SecondValue))
1328 {
1329 /* Exception occurred */
1330 return FALSE;
1331 }
1332
1333 /* Calculate the result */
1334 Result = FirstValue + SecondValue;
1335
1336 /* Update the flags */
1337 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
1338 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) == (SecondValue & SIGN_FLAG_BYTE))
1339 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
1340 State->Flags.Af = ((((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) != 0);
1341 State->Flags.Zf = (Result == 0);
1342 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1343 State->Flags.Pf = Fast486CalculateParity(Result);
1344
1345 /* Write back the result */
1346 State->GeneralRegs[FAST486_REG_EAX].LowByte = Result;
1347
1348 return TRUE;
1349 }
1350
1351 FAST486_OPCODE_HANDLER(Fast486OpcodeAddEax)
1352 {
1353 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1354
1355 /* Make sure this is the right instruction */
1356 ASSERT(Opcode == 0x05);
1357
1358 NO_LOCK_PREFIX();
1359 TOGGLE_OPSIZE(Size);
1360
1361 if (Size)
1362 {
1363 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
1364 ULONG SecondValue, Result;
1365
1366 if (!Fast486FetchDword(State, &SecondValue))
1367 {
1368 /* Exception occurred */
1369 return FALSE;
1370 }
1371
1372 /* Calculate the result */
1373 Result = FirstValue + SecondValue;
1374
1375 /* Update the flags */
1376 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
1377 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) == (SecondValue & SIGN_FLAG_LONG))
1378 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
1379 State->Flags.Af = ((((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) != 0);
1380 State->Flags.Zf = (Result == 0);
1381 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1382 State->Flags.Pf = Fast486CalculateParity(Result);
1383
1384 /* Write back the result */
1385 State->GeneralRegs[FAST486_REG_EAX].Long = Result;
1386 }
1387 else
1388 {
1389 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
1390 USHORT SecondValue, Result;
1391
1392 if (!Fast486FetchWord(State, &SecondValue))
1393 {
1394 /* Exception occurred */
1395 return FALSE;
1396 }
1397
1398 /* Calculate the result */
1399 Result = FirstValue + SecondValue;
1400
1401 /* Update the flags */
1402 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
1403 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) == (SecondValue & SIGN_FLAG_WORD))
1404 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
1405 State->Flags.Af = ((((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) != 0);
1406 State->Flags.Zf = (Result == 0);
1407 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1408 State->Flags.Pf = Fast486CalculateParity(Result);
1409
1410 /* Write back the result */
1411 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
1412 }
1413
1414 return TRUE;
1415 }
1416
1417 FAST486_OPCODE_HANDLER(Fast486OpcodeOrByteModrm)
1418 {
1419 UCHAR FirstValue, SecondValue, Result;
1420 FAST486_MOD_REG_RM ModRegRm;
1421 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1422
1423 /* Make sure this is the right instruction */
1424 ASSERT((Opcode & 0xFD) == 0x08);
1425
1426 TOGGLE_ADSIZE(AddressSize);
1427
1428 /* Get the operands */
1429 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1430 {
1431 /* Exception occurred */
1432 return FALSE;
1433 }
1434
1435 if (!Fast486ReadModrmByteOperands(State,
1436 &ModRegRm,
1437 &FirstValue,
1438 &SecondValue))
1439 {
1440 /* Exception occurred */
1441 return FALSE;
1442 }
1443
1444 /* Calculate the result */
1445 Result = FirstValue | SecondValue;
1446
1447 /* Update the flags */
1448 State->Flags.Cf = FALSE;
1449 State->Flags.Of = FALSE;
1450 State->Flags.Zf = (Result == 0);
1451 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1452 State->Flags.Pf = Fast486CalculateParity(Result);
1453
1454 /* Write back the result */
1455 return Fast486WriteModrmByteOperands(State,
1456 &ModRegRm,
1457 Opcode & FAST486_OPCODE_WRITE_REG,
1458 Result);
1459 }
1460
1461 FAST486_OPCODE_HANDLER(Fast486OpcodeOrModrm)
1462 {
1463 FAST486_MOD_REG_RM ModRegRm;
1464 BOOLEAN OperandSize, AddressSize;
1465
1466 /* Make sure this is the right instruction */
1467 ASSERT((Opcode & 0xFD) == 0x09);
1468
1469 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1470
1471 TOGGLE_ADSIZE(AddressSize);
1472 TOGGLE_OPSIZE(OperandSize);
1473
1474 /* Get the operands */
1475 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1476 {
1477 /* Exception occurred */
1478 return FALSE;
1479 }
1480
1481 /* Check the operand size */
1482 if (OperandSize)
1483 {
1484 ULONG FirstValue, SecondValue, Result;
1485
1486 if (!Fast486ReadModrmDwordOperands(State,
1487 &ModRegRm,
1488 &FirstValue,
1489 &SecondValue))
1490 {
1491 /* Exception occurred */
1492 return FALSE;
1493 }
1494
1495 /* Calculate the result */
1496 Result = FirstValue | SecondValue;
1497
1498 /* Update the flags */
1499 State->Flags.Cf = FALSE;
1500 State->Flags.Of = FALSE;
1501 State->Flags.Zf = (Result == 0);
1502 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1503 State->Flags.Pf = Fast486CalculateParity(Result);
1504
1505 /* Write back the result */
1506 return Fast486WriteModrmDwordOperands(State,
1507 &ModRegRm,
1508 Opcode & FAST486_OPCODE_WRITE_REG,
1509 Result);
1510 }
1511 else
1512 {
1513 USHORT FirstValue, SecondValue, Result;
1514
1515 if (!Fast486ReadModrmWordOperands(State,
1516 &ModRegRm,
1517 &FirstValue,
1518 &SecondValue))
1519 {
1520 /* Exception occurred */
1521 return FALSE;
1522 }
1523
1524 /* Calculate the result */
1525 Result = FirstValue | SecondValue;
1526
1527 /* Update the flags */
1528 State->Flags.Cf = FALSE;
1529 State->Flags.Of = FALSE;
1530 State->Flags.Zf = (Result == 0);
1531 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1532 State->Flags.Pf = Fast486CalculateParity(Result);
1533
1534 /* Write back the result */
1535 return Fast486WriteModrmWordOperands(State,
1536 &ModRegRm,
1537 Opcode & FAST486_OPCODE_WRITE_REG,
1538 Result);
1539 }
1540 }
1541
1542 FAST486_OPCODE_HANDLER(Fast486OpcodeOrAl)
1543 {
1544 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
1545 UCHAR SecondValue, Result;
1546
1547 /* Make sure this is the right instruction */
1548 ASSERT(Opcode == 0x0C);
1549
1550 if (State->PrefixFlags)
1551 {
1552 /* This opcode doesn't take any prefixes */
1553 Fast486Exception(State, FAST486_EXCEPTION_UD);
1554 return FALSE;
1555 }
1556
1557 if (!Fast486FetchByte(State, &SecondValue))
1558 {
1559 /* Exception occurred */
1560 return FALSE;
1561 }
1562
1563 /* Calculate the result */
1564 Result = FirstValue | SecondValue;
1565
1566 /* Update the flags */
1567 State->Flags.Cf = FALSE;
1568 State->Flags.Of = FALSE;
1569 State->Flags.Zf = (Result == 0);
1570 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1571 State->Flags.Pf = Fast486CalculateParity(Result);
1572
1573 /* Write back the result */
1574 State->GeneralRegs[FAST486_REG_EAX].LowByte = Result;
1575
1576 return TRUE;
1577 }
1578
1579 FAST486_OPCODE_HANDLER(Fast486OpcodeOrEax)
1580 {
1581 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1582
1583 /* Make sure this is the right instruction */
1584 ASSERT(Opcode == 0x0D);
1585
1586 NO_LOCK_PREFIX();
1587 TOGGLE_OPSIZE(Size);
1588
1589 if (Size)
1590 {
1591 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
1592 ULONG SecondValue, Result;
1593
1594 if (!Fast486FetchDword(State, &SecondValue))
1595 {
1596 /* Exception occurred */
1597 return FALSE;
1598 }
1599
1600 /* Calculate the result */
1601 Result = FirstValue | SecondValue;
1602
1603 /* Update the flags */
1604 State->Flags.Cf = FALSE;
1605 State->Flags.Of = FALSE;
1606 State->Flags.Zf = (Result == 0);
1607 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1608 State->Flags.Pf = Fast486CalculateParity(Result);
1609
1610 /* Write back the result */
1611 State->GeneralRegs[FAST486_REG_EAX].Long = Result;
1612 }
1613 else
1614 {
1615 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
1616 USHORT SecondValue, Result;
1617
1618 if (!Fast486FetchWord(State, &SecondValue))
1619 {
1620 /* Exception occurred */
1621 return FALSE;
1622 }
1623
1624 /* Calculate the result */
1625 Result = FirstValue | SecondValue;
1626
1627 /* Update the flags */
1628 State->Flags.Cf = FALSE;
1629 State->Flags.Of = FALSE;
1630 State->Flags.Zf = (Result == 0);
1631 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1632 State->Flags.Pf = Fast486CalculateParity(Result);
1633
1634 /* Write back the result */
1635 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
1636 }
1637
1638 return TRUE;
1639 }
1640
1641 FAST486_OPCODE_HANDLER(Fast486OpcodeAndByteModrm)
1642 {
1643 UCHAR FirstValue, SecondValue, Result;
1644 FAST486_MOD_REG_RM ModRegRm;
1645 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1646
1647 /* Make sure this is the right instruction */
1648 ASSERT((Opcode & 0xFD) == 0x20);
1649
1650 TOGGLE_ADSIZE(AddressSize);
1651
1652 /* Get the operands */
1653 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1654 {
1655 /* Exception occurred */
1656 return FALSE;
1657 }
1658
1659 if (!Fast486ReadModrmByteOperands(State,
1660 &ModRegRm,
1661 &FirstValue,
1662 &SecondValue))
1663 {
1664 /* Exception occurred */
1665 return FALSE;
1666 }
1667
1668 /* Calculate the result */
1669 Result = FirstValue & SecondValue;
1670
1671 /* Update the flags */
1672 State->Flags.Cf = FALSE;
1673 State->Flags.Of = FALSE;
1674 State->Flags.Zf = (Result == 0);
1675 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1676 State->Flags.Pf = Fast486CalculateParity(Result);
1677
1678 /* Write back the result */
1679 return Fast486WriteModrmByteOperands(State,
1680 &ModRegRm,
1681 Opcode & FAST486_OPCODE_WRITE_REG,
1682 Result);
1683 }
1684
1685 FAST486_OPCODE_HANDLER(Fast486OpcodeAndModrm)
1686 {
1687 FAST486_MOD_REG_RM ModRegRm;
1688 BOOLEAN OperandSize, AddressSize;
1689
1690 /* Make sure this is the right instruction */
1691 ASSERT((Opcode & 0xFD) == 0x21);
1692
1693 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1694
1695 TOGGLE_ADSIZE(AddressSize);
1696 TOGGLE_OPSIZE(OperandSize);
1697
1698 /* Get the operands */
1699 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1700 {
1701 /* Exception occurred */
1702 return FALSE;
1703 }
1704
1705 /* Check the operand size */
1706 if (OperandSize)
1707 {
1708 ULONG FirstValue, SecondValue, Result;
1709
1710 if (!Fast486ReadModrmDwordOperands(State,
1711 &ModRegRm,
1712 &FirstValue,
1713 &SecondValue))
1714 {
1715 /* Exception occurred */
1716 return FALSE;
1717 }
1718
1719 /* Calculate the result */
1720 Result = FirstValue & SecondValue;
1721
1722 /* Update the flags */
1723 State->Flags.Cf = FALSE;
1724 State->Flags.Of = FALSE;
1725 State->Flags.Zf = (Result == 0);
1726 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1727 State->Flags.Pf = Fast486CalculateParity(Result);
1728
1729 /* Write back the result */
1730 return Fast486WriteModrmDwordOperands(State,
1731 &ModRegRm,
1732 Opcode & FAST486_OPCODE_WRITE_REG,
1733 Result);
1734 }
1735 else
1736 {
1737 USHORT FirstValue, SecondValue, Result;
1738
1739 if (!Fast486ReadModrmWordOperands(State,
1740 &ModRegRm,
1741 &FirstValue,
1742 &SecondValue))
1743 {
1744 /* Exception occurred */
1745 return FALSE;
1746 }
1747
1748 /* Calculate the result */
1749 Result = FirstValue & SecondValue;
1750
1751 /* Update the flags */
1752 State->Flags.Cf = FALSE;
1753 State->Flags.Of = FALSE;
1754 State->Flags.Zf = (Result == 0);
1755 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1756 State->Flags.Pf = Fast486CalculateParity(Result);
1757
1758 /* Write back the result */
1759 return Fast486WriteModrmWordOperands(State,
1760 &ModRegRm,
1761 Opcode & FAST486_OPCODE_WRITE_REG,
1762 Result);
1763 }
1764 }
1765
1766 FAST486_OPCODE_HANDLER(Fast486OpcodeAndAl)
1767 {
1768 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
1769 UCHAR SecondValue, Result;
1770
1771 /* Make sure this is the right instruction */
1772 ASSERT(Opcode == 0x24);
1773
1774 NO_LOCK_PREFIX();
1775
1776 if (!Fast486FetchByte(State, &SecondValue))
1777 {
1778 /* Exception occurred */
1779 return FALSE;
1780 }
1781
1782 /* Calculate the result */
1783 Result = FirstValue & SecondValue;
1784
1785 /* Update the flags */
1786 State->Flags.Cf = FALSE;
1787 State->Flags.Of = FALSE;
1788 State->Flags.Zf = (Result == 0);
1789 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1790 State->Flags.Pf = Fast486CalculateParity(Result);
1791
1792 /* Write back the result */
1793 State->GeneralRegs[FAST486_REG_EAX].LowByte = Result;
1794
1795 return TRUE;
1796 }
1797
1798 FAST486_OPCODE_HANDLER(Fast486OpcodeAndEax)
1799 {
1800 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1801
1802 /* Make sure this is the right instruction */
1803 ASSERT(Opcode == 0x25);
1804
1805 NO_LOCK_PREFIX();
1806 TOGGLE_OPSIZE(Size);
1807
1808 if (Size)
1809 {
1810 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
1811 ULONG SecondValue, Result;
1812
1813 if (!Fast486FetchDword(State, &SecondValue))
1814 {
1815 /* Exception occurred */
1816 return FALSE;
1817 }
1818
1819 /* Calculate the result */
1820 Result = FirstValue & SecondValue;
1821
1822 /* Update the flags */
1823 State->Flags.Cf = FALSE;
1824 State->Flags.Of = FALSE;
1825 State->Flags.Zf = (Result == 0);
1826 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1827 State->Flags.Pf = Fast486CalculateParity(Result);
1828
1829 /* Write back the result */
1830 State->GeneralRegs[FAST486_REG_EAX].Long = Result;
1831 }
1832 else
1833 {
1834 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
1835 USHORT SecondValue, Result;
1836
1837 if (!Fast486FetchWord(State, &SecondValue))
1838 {
1839 /* Exception occurred */
1840 return FALSE;
1841 }
1842
1843 /* Calculate the result */
1844 Result = FirstValue & SecondValue;
1845
1846 /* Update the flags */
1847 State->Flags.Cf = FALSE;
1848 State->Flags.Of = FALSE;
1849 State->Flags.Zf = (Result == 0);
1850 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1851 State->Flags.Pf = Fast486CalculateParity(Result);
1852
1853 /* Write back the result */
1854 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
1855 }
1856
1857 return TRUE;
1858 }
1859
1860 FAST486_OPCODE_HANDLER(Fast486OpcodeXorByteModrm)
1861 {
1862 UCHAR FirstValue, SecondValue, Result;
1863 FAST486_MOD_REG_RM ModRegRm;
1864 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1865
1866 /* Make sure this is the right instruction */
1867 ASSERT((Opcode & 0xFD) == 0x30);
1868
1869 TOGGLE_ADSIZE(AddressSize);
1870
1871 /* Get the operands */
1872 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1873 {
1874 /* Exception occurred */
1875 return FALSE;
1876 }
1877
1878 if (!Fast486ReadModrmByteOperands(State,
1879 &ModRegRm,
1880 &FirstValue,
1881 &SecondValue))
1882 {
1883 /* Exception occurred */
1884 return FALSE;
1885 }
1886
1887 /* Calculate the result */
1888 Result = FirstValue ^ SecondValue;
1889
1890 /* Update the flags */
1891 State->Flags.Cf = FALSE;
1892 State->Flags.Of = FALSE;
1893 State->Flags.Zf = (Result == 0);
1894 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1895 State->Flags.Pf = Fast486CalculateParity(Result);
1896
1897 /* Write back the result */
1898 return Fast486WriteModrmByteOperands(State,
1899 &ModRegRm,
1900 Opcode & FAST486_OPCODE_WRITE_REG,
1901 Result);
1902 }
1903
1904 FAST486_OPCODE_HANDLER(Fast486OpcodeXorModrm)
1905 {
1906 FAST486_MOD_REG_RM ModRegRm;
1907 BOOLEAN OperandSize, AddressSize;
1908
1909 /* Make sure this is the right instruction */
1910 ASSERT((Opcode & 0xFD) == 0x31);
1911
1912 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1913
1914 TOGGLE_ADSIZE(AddressSize);
1915 TOGGLE_OPSIZE(OperandSize);
1916
1917 /* Get the operands */
1918 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1919 {
1920 /* Exception occurred */
1921 return FALSE;
1922 }
1923
1924 /* Check the operand size */
1925 if (OperandSize)
1926 {
1927 ULONG FirstValue, SecondValue, Result;
1928
1929 if (!Fast486ReadModrmDwordOperands(State,
1930 &ModRegRm,
1931 &FirstValue,
1932 &SecondValue))
1933 {
1934 /* Exception occurred */
1935 return FALSE;
1936 }
1937
1938 /* Calculate the result */
1939 Result = FirstValue ^ SecondValue;
1940
1941 /* Update the flags */
1942 State->Flags.Cf = FALSE;
1943 State->Flags.Of = FALSE;
1944 State->Flags.Zf = (Result == 0);
1945 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1946 State->Flags.Pf = Fast486CalculateParity(Result);
1947
1948 /* Write back the result */
1949 return Fast486WriteModrmDwordOperands(State,
1950 &ModRegRm,
1951 Opcode & FAST486_OPCODE_WRITE_REG,
1952 Result);
1953 }
1954 else
1955 {
1956 USHORT FirstValue, SecondValue, Result;
1957
1958 if (!Fast486ReadModrmWordOperands(State,
1959 &ModRegRm,
1960 &FirstValue,
1961 &SecondValue))
1962 {
1963 /* Exception occurred */
1964 return FALSE;
1965 }
1966
1967 /* Calculate the result */
1968 Result = FirstValue ^ SecondValue;
1969
1970 /* Update the flags */
1971 State->Flags.Cf = FALSE;
1972 State->Flags.Of = FALSE;
1973 State->Flags.Zf = (Result == 0);
1974 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1975 State->Flags.Pf = Fast486CalculateParity(Result);
1976
1977 /* Write back the result */
1978 return Fast486WriteModrmWordOperands(State,
1979 &ModRegRm,
1980 Opcode & FAST486_OPCODE_WRITE_REG,
1981 Result);
1982 }
1983 }
1984
1985 FAST486_OPCODE_HANDLER(Fast486OpcodeXorAl)
1986 {
1987 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
1988 UCHAR SecondValue, Result;
1989
1990 /* Make sure this is the right instruction */
1991 ASSERT(Opcode == 0x34);
1992
1993 if (State->PrefixFlags)
1994 {
1995 /* This opcode doesn't take any prefixes */
1996 Fast486Exception(State, FAST486_EXCEPTION_UD);
1997 return FALSE;
1998 }
1999
2000 if (!Fast486FetchByte(State, &SecondValue))
2001 {
2002 /* Exception occurred */
2003 return FALSE;
2004 }
2005
2006 /* Calculate the result */
2007 Result = FirstValue ^ SecondValue;
2008
2009 /* Update the flags */
2010 State->Flags.Cf = FALSE;
2011 State->Flags.Of = FALSE;
2012 State->Flags.Zf = (Result == 0);
2013 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2014 State->Flags.Pf = Fast486CalculateParity(Result);
2015
2016 /* Write back the result */
2017 State->GeneralRegs[FAST486_REG_EAX].LowByte = Result;
2018
2019 return TRUE;
2020 }
2021
2022 FAST486_OPCODE_HANDLER(Fast486OpcodeXorEax)
2023 {
2024 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
2025
2026 /* Make sure this is the right instruction */
2027 ASSERT(Opcode == 0x35);
2028
2029 NO_LOCK_PREFIX();
2030 TOGGLE_OPSIZE(Size);
2031
2032 if (Size)
2033 {
2034 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
2035 ULONG SecondValue, Result;
2036
2037 if (!Fast486FetchDword(State, &SecondValue))
2038 {
2039 /* Exception occurred */
2040 return FALSE;
2041 }
2042
2043 /* Calculate the result */
2044 Result = FirstValue ^ SecondValue;
2045
2046 /* Update the flags */
2047 State->Flags.Cf = FALSE;
2048 State->Flags.Of = FALSE;
2049 State->Flags.Zf = (Result == 0);
2050 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2051 State->Flags.Pf = Fast486CalculateParity(Result);
2052
2053 /* Write back the result */
2054 State->GeneralRegs[FAST486_REG_EAX].Long = Result;
2055 }
2056 else
2057 {
2058 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
2059 USHORT SecondValue, Result;
2060
2061 if (!Fast486FetchWord(State, &SecondValue))
2062 {
2063 /* Exception occurred */
2064 return FALSE;
2065 }
2066
2067 /* Calculate the result */
2068 Result = FirstValue ^ SecondValue;
2069
2070 /* Update the flags */
2071 State->Flags.Cf = FALSE;
2072 State->Flags.Of = FALSE;
2073 State->Flags.Zf = (Result == 0);
2074 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2075 State->Flags.Pf = Fast486CalculateParity(Result);
2076
2077 /* Write back the result */
2078 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
2079 }
2080
2081 return TRUE;
2082 }
2083
2084 FAST486_OPCODE_HANDLER(Fast486OpcodeTestByteModrm)
2085 {
2086 UCHAR FirstValue, SecondValue, Result;
2087 FAST486_MOD_REG_RM ModRegRm;
2088 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2089
2090 /* Make sure this is the right instruction */
2091 ASSERT(Opcode == 0x84);
2092
2093 TOGGLE_ADSIZE(AddressSize);
2094
2095 /* Get the operands */
2096 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2097 {
2098 /* Exception occurred */
2099 return FALSE;
2100 }
2101
2102 if (!Fast486ReadModrmByteOperands(State,
2103 &ModRegRm,
2104 &FirstValue,
2105 &SecondValue))
2106 {
2107 /* Exception occurred */
2108 return FALSE;
2109 }
2110 /* Calculate the result */
2111 Result = FirstValue & SecondValue;
2112
2113 /* Update the flags */
2114 State->Flags.Cf = FALSE;
2115 State->Flags.Of = FALSE;
2116 State->Flags.Zf = (Result == 0);
2117 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2118 State->Flags.Pf = Fast486CalculateParity(Result);
2119
2120 /* The result is discarded */
2121 return TRUE;
2122 }
2123
2124 FAST486_OPCODE_HANDLER(Fast486OpcodeTestModrm)
2125 {
2126 FAST486_MOD_REG_RM ModRegRm;
2127 BOOLEAN OperandSize, AddressSize;
2128
2129 /* Make sure this is the right instruction */
2130 ASSERT(Opcode == 0x85);
2131
2132 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2133
2134 TOGGLE_ADSIZE(AddressSize);
2135 TOGGLE_OPSIZE(OperandSize);
2136
2137 /* Get the operands */
2138 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2139 {
2140 /* Exception occurred */
2141 return FALSE;
2142 }
2143
2144 /* Check the operand size */
2145 if (OperandSize)
2146 {
2147 ULONG FirstValue, SecondValue, Result;
2148
2149 if (!Fast486ReadModrmDwordOperands(State,
2150 &ModRegRm,
2151 &FirstValue,
2152 &SecondValue))
2153 {
2154 /* Exception occurred */
2155 return FALSE;
2156 }
2157
2158 /* Calculate the result */
2159 Result = FirstValue & SecondValue;
2160
2161 /* Update the flags */
2162 State->Flags.Cf = FALSE;
2163 State->Flags.Of = FALSE;
2164 State->Flags.Zf = (Result == 0);
2165 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2166 State->Flags.Pf = Fast486CalculateParity(Result);
2167 }
2168 else
2169 {
2170 USHORT FirstValue, SecondValue, Result;
2171
2172 if (!Fast486ReadModrmWordOperands(State,
2173 &ModRegRm,
2174 &FirstValue,
2175 &SecondValue))
2176 {
2177 /* Exception occurred */
2178 return FALSE;
2179 }
2180
2181 /* Calculate the result */
2182 Result = FirstValue & SecondValue;
2183
2184 /* Update the flags */
2185 State->Flags.Cf = FALSE;
2186 State->Flags.Of = FALSE;
2187 State->Flags.Zf = (Result == 0);
2188 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2189 State->Flags.Pf = Fast486CalculateParity(Result);
2190 }
2191
2192 /* The result is discarded */
2193 return TRUE;
2194 }
2195
2196 FAST486_OPCODE_HANDLER(Fast486OpcodeTestAl)
2197 {
2198 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
2199 UCHAR SecondValue, Result;
2200
2201 /* Make sure this is the right instruction */
2202 ASSERT(Opcode == 0xA8);
2203
2204 if (State->PrefixFlags)
2205 {
2206 /* This opcode doesn't take any prefixes */
2207 Fast486Exception(State, FAST486_EXCEPTION_UD);
2208 return FALSE;
2209 }
2210
2211 if (!Fast486FetchByte(State, &SecondValue))
2212 {
2213 /* Exception occurred */
2214 return FALSE;
2215 }
2216
2217 /* Calculate the result */
2218 Result = FirstValue & SecondValue;
2219
2220 /* Update the flags */
2221 State->Flags.Cf = FALSE;
2222 State->Flags.Of = FALSE;
2223 State->Flags.Zf = (Result == 0);
2224 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2225 State->Flags.Pf = Fast486CalculateParity(Result);
2226
2227 /* The result is discarded */
2228 return TRUE;
2229 }
2230
2231 FAST486_OPCODE_HANDLER(Fast486OpcodeTestEax)
2232 {
2233 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
2234
2235 /* Make sure this is the right instruction */
2236 ASSERT(Opcode == 0xA9);
2237
2238 NO_LOCK_PREFIX();
2239 TOGGLE_OPSIZE(Size);
2240
2241 if (Size)
2242 {
2243 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
2244 ULONG SecondValue, Result;
2245
2246 if (!Fast486FetchDword(State, &SecondValue))
2247 {
2248 /* Exception occurred */
2249 return FALSE;
2250 }
2251
2252 /* Calculate the result */
2253 Result = FirstValue & SecondValue;
2254
2255 /* Update the flags */
2256 State->Flags.Cf = FALSE;
2257 State->Flags.Of = FALSE;
2258 State->Flags.Zf = (Result == 0);
2259 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2260 State->Flags.Pf = Fast486CalculateParity(Result);
2261 }
2262 else
2263 {
2264 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
2265 USHORT SecondValue, Result;
2266
2267 if (!Fast486FetchWord(State, &SecondValue))
2268 {
2269 /* Exception occurred */
2270 return FALSE;
2271 }
2272
2273 /* Calculate the result */
2274 Result = FirstValue & SecondValue;
2275
2276 /* Update the flags */
2277 State->Flags.Cf = FALSE;
2278 State->Flags.Of = FALSE;
2279 State->Flags.Zf = (Result == 0);
2280 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2281 State->Flags.Pf = Fast486CalculateParity(Result);
2282 }
2283
2284 /* The result is discarded */
2285 return TRUE;
2286 }
2287
2288 FAST486_OPCODE_HANDLER(Fast486OpcodeXchgByteModrm)
2289 {
2290 UCHAR FirstValue, SecondValue;
2291 FAST486_MOD_REG_RM ModRegRm;
2292 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2293
2294 /* Make sure this is the right instruction */
2295 ASSERT(Opcode == 0x86);
2296
2297 TOGGLE_ADSIZE(AddressSize);
2298
2299 /* Get the operands */
2300 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2301 {
2302 /* Exception occurred */
2303 return FALSE;
2304 }
2305
2306 if (!Fast486ReadModrmByteOperands(State,
2307 &ModRegRm,
2308 &FirstValue,
2309 &SecondValue))
2310 {
2311 /* Exception occurred */
2312 return FALSE;
2313 }
2314
2315 /* Write the value from the register to the R/M */
2316 if (!Fast486WriteModrmByteOperands(State,
2317 &ModRegRm,
2318 FALSE,
2319 FirstValue))
2320 {
2321 /* Exception occurred */
2322 return FALSE;
2323 }
2324
2325 /* Write the value from the R/M to the register */
2326 if (!Fast486WriteModrmByteOperands(State,
2327 &ModRegRm,
2328 TRUE,
2329 SecondValue))
2330 {
2331 /* Exception occurred */
2332 return FALSE;
2333 }
2334
2335 return TRUE;
2336 }
2337
2338 FAST486_OPCODE_HANDLER(Fast486OpcodeXchgModrm)
2339 {
2340 FAST486_MOD_REG_RM ModRegRm;
2341 BOOLEAN OperandSize, AddressSize;
2342
2343 /* Make sure this is the right instruction */
2344 ASSERT(Opcode == 0x87);
2345
2346 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2347
2348 TOGGLE_ADSIZE(AddressSize);
2349 TOGGLE_OPSIZE(OperandSize);
2350
2351 /* Get the operands */
2352 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2353 {
2354 /* Exception occurred */
2355 return FALSE;
2356 }
2357
2358 /* Check the operand size */
2359 if (OperandSize)
2360 {
2361 ULONG FirstValue, SecondValue;
2362
2363 if (!Fast486ReadModrmDwordOperands(State,
2364 &ModRegRm,
2365 &FirstValue,
2366 &SecondValue))
2367 {
2368 /* Exception occurred */
2369 return FALSE;
2370 }
2371
2372 /* Write the value from the register to the R/M */
2373 if (!Fast486WriteModrmDwordOperands(State,
2374 &ModRegRm,
2375 FALSE,
2376 FirstValue))
2377 {
2378 /* Exception occurred */
2379 return FALSE;
2380 }
2381
2382 /* Write the value from the R/M to the register */
2383 if (!Fast486WriteModrmDwordOperands(State,
2384 &ModRegRm,
2385 TRUE,
2386 SecondValue))
2387 {
2388 /* Exception occurred */
2389 return FALSE;
2390 }
2391 }
2392 else
2393 {
2394 USHORT FirstValue, SecondValue;
2395
2396 if (!Fast486ReadModrmWordOperands(State,
2397 &ModRegRm,
2398 &FirstValue,
2399 &SecondValue))
2400 {
2401 /* Exception occurred */
2402 return FALSE;
2403 }
2404
2405 /* Write the value from the register to the R/M */
2406 if (!Fast486WriteModrmWordOperands(State,
2407 &ModRegRm,
2408 FALSE,
2409 FirstValue))
2410 {
2411 /* Exception occurred */
2412 return FALSE;
2413 }
2414
2415 /* Write the value from the R/M to the register */
2416 if (!Fast486WriteModrmWordOperands(State,
2417 &ModRegRm,
2418 TRUE,
2419 SecondValue))
2420 {
2421 /* Exception occurred */
2422 return FALSE;
2423 }
2424 }
2425
2426 /* The result is discarded */
2427 return TRUE;
2428 }
2429
2430 FAST486_OPCODE_HANDLER(Fast486OpcodePushEs)
2431 {
2432 /* Call the internal API */
2433 return Fast486StackPush(State, State->SegmentRegs[FAST486_REG_ES].Selector);
2434 }
2435
2436 FAST486_OPCODE_HANDLER(Fast486OpcodePopEs)
2437 {
2438 ULONG NewSelector;
2439
2440 if (!Fast486StackPop(State, &NewSelector))
2441 {
2442 /* Exception occurred */
2443 return FALSE;
2444 }
2445
2446 /* Call the internal API */
2447 return Fast486LoadSegment(State, FAST486_REG_ES, LOWORD(NewSelector));
2448 }
2449
2450 FAST486_OPCODE_HANDLER(Fast486OpcodePushCs)
2451 {
2452 /* Call the internal API */
2453 return Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector);
2454 }
2455
2456 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcByteModrm)
2457 {
2458 UCHAR FirstValue, SecondValue, Result;
2459 FAST486_MOD_REG_RM ModRegRm;
2460 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2461
2462 /* Make sure this is the right instruction */
2463 ASSERT((Opcode & 0xFD) == 0x10);
2464
2465 TOGGLE_ADSIZE(AddressSize);
2466
2467 /* Get the operands */
2468 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2469 {
2470 /* Exception occurred */
2471 return FALSE;
2472 }
2473
2474 if (!Fast486ReadModrmByteOperands(State,
2475 &ModRegRm,
2476 &FirstValue,
2477 &SecondValue))
2478 {
2479 /* Exception occurred */
2480 return FALSE;
2481 }
2482
2483 /* Calculate the result */
2484 Result = FirstValue + SecondValue + State->Flags.Cf;
2485
2486 /* Special exception for CF */
2487 State->Flags.Cf = State->Flags.Cf
2488 && ((FirstValue == 0xFF) || (SecondValue == 0xFF));
2489
2490 /* Update the flags */
2491 State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < SecondValue));
2492 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) == (SecondValue & SIGN_FLAG_BYTE))
2493 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
2494 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2495 State->Flags.Zf = (Result == 0);
2496 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2497 State->Flags.Pf = Fast486CalculateParity(Result);
2498
2499 /* Write back the result */
2500 return Fast486WriteModrmByteOperands(State,
2501 &ModRegRm,
2502 Opcode & FAST486_OPCODE_WRITE_REG,
2503 Result);
2504 }
2505
2506 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcModrm)
2507 {
2508 FAST486_MOD_REG_RM ModRegRm;
2509 BOOLEAN OperandSize, AddressSize;
2510
2511 /* Make sure this is the right instruction */
2512 ASSERT((Opcode & 0xFD) == 0x11);
2513
2514 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2515
2516 TOGGLE_ADSIZE(AddressSize);
2517 TOGGLE_OPSIZE(OperandSize);
2518
2519 /* Get the operands */
2520 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2521 {
2522 /* Exception occurred */
2523 return FALSE;
2524 }
2525
2526 /* Check the operand size */
2527 if (OperandSize)
2528 {
2529 ULONG FirstValue, SecondValue, Result;
2530
2531 if (!Fast486ReadModrmDwordOperands(State,
2532 &ModRegRm,
2533 &FirstValue,
2534 &SecondValue))
2535 {
2536 /* Exception occurred */
2537 return FALSE;
2538 }
2539
2540 /* Calculate the result */
2541 Result = FirstValue + SecondValue + State->Flags.Cf;
2542
2543 /* Special exception for CF */
2544 State->Flags.Cf = State->Flags.Cf
2545 && ((FirstValue == 0xFFFFFFFF) || (SecondValue == 0xFFFFFFFF));
2546
2547 /* Update the flags */
2548 State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < SecondValue));
2549 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) == (SecondValue & SIGN_FLAG_LONG))
2550 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
2551 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2552 State->Flags.Zf = (Result == 0);
2553 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2554 State->Flags.Pf = Fast486CalculateParity(Result);
2555
2556 /* Write back the result */
2557 return Fast486WriteModrmDwordOperands(State,
2558 &ModRegRm,
2559 Opcode & FAST486_OPCODE_WRITE_REG,
2560 Result);
2561 }
2562 else
2563 {
2564 USHORT FirstValue, SecondValue, Result;
2565
2566 if (!Fast486ReadModrmWordOperands(State,
2567 &ModRegRm,
2568 &FirstValue,
2569 &SecondValue))
2570 {
2571 /* Exception occurred */
2572 return FALSE;
2573 }
2574
2575 /* Calculate the result */
2576 Result = FirstValue + SecondValue + State->Flags.Cf;
2577
2578 /* Special exception for CF */
2579 State->Flags.Cf = State->Flags.Cf
2580 && ((FirstValue == 0xFFFF) || (SecondValue == 0xFFFF));
2581
2582 /* Update the flags */
2583 State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < SecondValue));
2584 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) == (SecondValue & SIGN_FLAG_WORD))
2585 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
2586 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2587 State->Flags.Zf = (Result == 0);
2588 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2589 State->Flags.Pf = Fast486CalculateParity(Result);
2590
2591 /* Write back the result */
2592 return Fast486WriteModrmWordOperands(State,
2593 &ModRegRm,
2594 Opcode & FAST486_OPCODE_WRITE_REG,
2595 Result);
2596 }
2597
2598 }
2599
2600 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcAl)
2601 {
2602 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
2603 UCHAR SecondValue, Result;
2604
2605 /* Make sure this is the right instruction */
2606 ASSERT(Opcode == 0x14);
2607
2608 if (State->PrefixFlags)
2609 {
2610 /* This opcode doesn't take any prefixes */
2611 Fast486Exception(State, FAST486_EXCEPTION_UD);
2612 return FALSE;
2613 }
2614
2615 if (!Fast486FetchByte(State, &SecondValue))
2616 {
2617 /* Exception occurred */
2618 return FALSE;
2619 }
2620
2621 /* Calculate the result */
2622 Result = FirstValue + SecondValue + State->Flags.Cf;
2623
2624 /* Special exception for CF */
2625 State->Flags.Cf = State->Flags.Cf &&
2626 ((FirstValue == 0xFF) || (SecondValue == 0xFF));
2627
2628 /* Update the flags */
2629 State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < SecondValue));
2630 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) == (SecondValue & SIGN_FLAG_BYTE))
2631 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
2632 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2633 State->Flags.Zf = (Result == 0);
2634 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2635 State->Flags.Pf = Fast486CalculateParity(Result);
2636
2637 /* Write back the result */
2638 State->GeneralRegs[FAST486_REG_EAX].LowByte = Result;
2639
2640 return TRUE;
2641 }
2642
2643 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcEax)
2644 {
2645 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
2646
2647 /* Make sure this is the right instruction */
2648 ASSERT(Opcode == 0x15);
2649
2650 NO_LOCK_PREFIX();
2651 TOGGLE_OPSIZE(Size);
2652
2653 if (Size)
2654 {
2655 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
2656 ULONG SecondValue, Result;
2657
2658 if (!Fast486FetchDword(State, &SecondValue))
2659 {
2660 /* Exception occurred */
2661 return FALSE;
2662 }
2663
2664 /* Calculate the result */
2665 Result = FirstValue + SecondValue + State->Flags.Cf;
2666
2667 /* Special exception for CF */
2668 State->Flags.Cf = State->Flags.Cf &&
2669 ((FirstValue == 0xFFFFFFFF) || (SecondValue == 0xFFFFFFFF));
2670
2671 /* Update the flags */
2672 State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < SecondValue));
2673 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) == (SecondValue & SIGN_FLAG_LONG))
2674 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
2675 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2676 State->Flags.Zf = (Result == 0);
2677 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2678 State->Flags.Pf = Fast486CalculateParity(Result);
2679
2680 /* Write back the result */
2681 State->GeneralRegs[FAST486_REG_EAX].Long = Result;
2682 }
2683 else
2684 {
2685 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
2686 USHORT SecondValue, Result;
2687
2688 if (!Fast486FetchWord(State, &SecondValue))
2689 {
2690 /* Exception occurred */
2691 return FALSE;
2692 }
2693
2694 /* Calculate the result */
2695 Result = FirstValue + SecondValue + State->Flags.Cf;
2696
2697 /* Special exception for CF */
2698 State->Flags.Cf = State->Flags.Cf &&
2699 ((FirstValue == 0xFFFF) || (SecondValue == 0xFFFF));
2700
2701 /* Update the flags */
2702 State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < SecondValue));
2703 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) == (SecondValue & SIGN_FLAG_WORD))
2704 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
2705 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2706 State->Flags.Zf = (Result == 0);
2707 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2708 State->Flags.Pf = Fast486CalculateParity(Result);
2709
2710 /* Write back the result */
2711 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
2712 }
2713
2714 return TRUE;
2715 }
2716
2717 FAST486_OPCODE_HANDLER(Fast486OpcodePushSs)
2718 {
2719 /* Call the internal API */
2720 return Fast486StackPush(State, State->SegmentRegs[FAST486_REG_SS].Selector);
2721 }
2722
2723 FAST486_OPCODE_HANDLER(Fast486OpcodePopSs)
2724 {
2725 ULONG NewSelector;
2726
2727 if (!Fast486StackPop(State, &NewSelector))
2728 {
2729 /* Exception occurred */
2730 return FALSE;
2731 }
2732
2733 /* Call the internal API */
2734 return Fast486LoadSegment(State, FAST486_REG_SS, LOWORD(NewSelector));
2735 }
2736
2737 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbByteModrm)
2738 {
2739 UCHAR FirstValue, SecondValue, Result;
2740 FAST486_MOD_REG_RM ModRegRm;
2741 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2742 INT Carry = State->Flags.Cf ? 1 : 0;
2743
2744 /* Make sure this is the right instruction */
2745 ASSERT((Opcode & 0xFD) == 0x18);
2746
2747 TOGGLE_ADSIZE(AddressSize);
2748
2749 /* Get the operands */
2750 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2751 {
2752 /* Exception occurred */
2753 return FALSE;
2754 }
2755
2756 if (!Fast486ReadModrmByteOperands(State,
2757 &ModRegRm,
2758 &FirstValue,
2759 &SecondValue))
2760 {
2761 /* Exception occurred */
2762 return FALSE;
2763 }
2764
2765 /* Check if this is the instruction that writes to R/M */
2766 if (!(Opcode & FAST486_OPCODE_WRITE_REG))
2767 {
2768 /* Swap the order */
2769 SWAP(FirstValue, SecondValue);
2770 }
2771
2772 /* Calculate the result */
2773 Result = FirstValue - SecondValue - Carry;
2774
2775 /* Update the flags */
2776 State->Flags.Cf = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue);
2777 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) != (SecondValue & SIGN_FLAG_BYTE))
2778 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
2779 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2780 State->Flags.Zf = (Result == 0);
2781 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2782 State->Flags.Pf = Fast486CalculateParity(Result);
2783
2784 /* Write back the result */
2785 return Fast486WriteModrmByteOperands(State,
2786 &ModRegRm,
2787 Opcode & FAST486_OPCODE_WRITE_REG,
2788 Result);
2789 }
2790
2791 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbModrm)
2792 {
2793 FAST486_MOD_REG_RM ModRegRm;
2794 BOOLEAN OperandSize, AddressSize;
2795 INT Carry = State->Flags.Cf ? 1 : 0;
2796
2797 /* Make sure this is the right instruction */
2798 ASSERT((Opcode & 0xFD) == 0x19);
2799
2800 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2801
2802 TOGGLE_ADSIZE(AddressSize);
2803 TOGGLE_OPSIZE(OperandSize);
2804
2805 /* Get the operands */
2806 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2807 {
2808 /* Exception occurred */
2809 return FALSE;
2810 }
2811
2812 /* Check the operand size */
2813 if (OperandSize)
2814 {
2815 ULONG FirstValue, SecondValue, Result;
2816
2817 if (!Fast486ReadModrmDwordOperands(State,
2818 &ModRegRm,
2819 &FirstValue,
2820 &SecondValue))
2821 {
2822 /* Exception occurred */
2823 return FALSE;
2824 }
2825
2826 /* Check if this is the instruction that writes to R/M */
2827 if (!(Opcode & FAST486_OPCODE_WRITE_REG))
2828 {
2829 /* Swap the order */
2830 SWAP(FirstValue, SecondValue);
2831 }
2832
2833 /* Calculate the result */
2834 Result = FirstValue - SecondValue - Carry;
2835
2836 /* Update the flags */
2837 State->Flags.Cf = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue);
2838 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) != (SecondValue & SIGN_FLAG_LONG))
2839 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
2840 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2841 State->Flags.Zf = (Result == 0);
2842 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2843 State->Flags.Pf = Fast486CalculateParity(Result);
2844
2845 /* Write back the result */
2846 return Fast486WriteModrmDwordOperands(State,
2847 &ModRegRm,
2848 Opcode & FAST486_OPCODE_WRITE_REG,
2849 Result);
2850 }
2851 else
2852 {
2853 USHORT FirstValue, SecondValue, Result;
2854
2855 if (!Fast486ReadModrmWordOperands(State,
2856 &ModRegRm,
2857 &FirstValue,
2858 &SecondValue))
2859 {
2860 /* Exception occurred */
2861 return FALSE;
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 - Carry;
2873
2874 /* Update the flags */
2875 State->Flags.Cf = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue);
2876 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) != (SecondValue & SIGN_FLAG_WORD))
2877 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
2878 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2879 State->Flags.Zf = (Result == 0);
2880 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2881 State->Flags.Pf = Fast486CalculateParity(Result);
2882
2883 /* Write back the result */
2884 return Fast486WriteModrmWordOperands(State,
2885 &ModRegRm,
2886 Opcode & FAST486_OPCODE_WRITE_REG,
2887 Result);
2888 }
2889 }
2890
2891 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbAl)
2892 {
2893 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
2894 UCHAR SecondValue, Result;
2895 INT Carry = State->Flags.Cf ? 1 : 0;
2896
2897 /* Make sure this is the right instruction */
2898 ASSERT(Opcode == 0x1C);
2899
2900 if (State->PrefixFlags)
2901 {
2902 /* This opcode doesn't take any prefixes */
2903 Fast486Exception(State, FAST486_EXCEPTION_UD);
2904 return FALSE;
2905 }
2906
2907 if (!Fast486FetchByte(State, &SecondValue))
2908 {
2909 /* Exception occurred */
2910 return FALSE;
2911 }
2912
2913 /* Calculate the result */
2914 Result = FirstValue - SecondValue - Carry;
2915
2916 /* Update the flags */
2917 State->Flags.Cf = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue);
2918 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) != (SecondValue & SIGN_FLAG_BYTE))
2919 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
2920 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2921 State->Flags.Zf = (Result == 0);
2922 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2923 State->Flags.Pf = Fast486CalculateParity(Result);
2924
2925 /* Write back the result */
2926 State->GeneralRegs[FAST486_REG_EAX].LowByte = Result;
2927
2928 return TRUE;
2929
2930 }
2931
2932 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbEax)
2933 {
2934 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
2935 INT Carry = State->Flags.Cf ? 1 : 0;
2936
2937 /* Make sure this is the right instruction */
2938 ASSERT(Opcode == 0x1D);
2939
2940 NO_LOCK_PREFIX();
2941 TOGGLE_OPSIZE(Size);
2942
2943 if (Size)
2944 {
2945 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
2946 ULONG SecondValue, Result;
2947
2948 if (!Fast486FetchDword(State, &SecondValue))
2949 {
2950 /* Exception occurred */
2951 return FALSE;
2952 }
2953
2954 /* Calculate the result */
2955 Result = FirstValue - SecondValue - Carry;
2956
2957 /* Update the flags */
2958 State->Flags.Cf = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue);
2959 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) != (SecondValue & SIGN_FLAG_LONG))
2960 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
2961 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2962 State->Flags.Zf = (Result == 0);
2963 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2964 State->Flags.Pf = Fast486CalculateParity(Result);
2965
2966 /* Write back the result */
2967 State->GeneralRegs[FAST486_REG_EAX].Long = Result;
2968 }
2969 else
2970 {
2971 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
2972 USHORT SecondValue, Result;
2973
2974 if (!Fast486FetchWord(State, &SecondValue))
2975 {
2976 /* Exception occurred */
2977 return FALSE;
2978 }
2979
2980 /* Calculate the result */
2981 Result = FirstValue - SecondValue - Carry;
2982
2983 /* Update the flags */
2984 State->Flags.Cf = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue);
2985 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) != (SecondValue & SIGN_FLAG_WORD))
2986 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
2987 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2988 State->Flags.Zf = (Result == 0);
2989 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2990 State->Flags.Pf = Fast486CalculateParity(Result);
2991
2992 /* Write back the result */
2993 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
2994 }
2995
2996 return TRUE;
2997
2998 }
2999
3000 FAST486_OPCODE_HANDLER(Fast486OpcodePushDs)
3001 {
3002 /* Call the internal API */
3003 return Fast486StackPush(State, State->SegmentRegs[FAST486_REG_DS].Selector);
3004 }
3005
3006 FAST486_OPCODE_HANDLER(Fast486OpcodePopDs)
3007 {
3008 ULONG NewSelector;
3009
3010 if (!Fast486StackPop(State, &NewSelector))
3011 {
3012 /* Exception occurred */
3013 return FALSE;
3014 }
3015
3016 /* Call the internal API */
3017 return Fast486LoadSegment(State, FAST486_REG_DS, LOWORD(NewSelector));
3018 }
3019
3020 FAST486_OPCODE_HANDLER(Fast486OpcodeDaa)
3021 {
3022 UCHAR Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
3023 BOOLEAN Carry = State->Flags.Cf;
3024
3025 /* Clear the carry flag */
3026 State->Flags.Cf = FALSE;
3027
3028 /* Check if the first BCD digit is invalid or there was a carry from it */
3029 if (((Value & 0x0F) > 9) || State->Flags.Af)
3030 {
3031 /* Correct it */
3032 State->GeneralRegs[FAST486_REG_EAX].LowByte += 0x06;
3033 if (State->GeneralRegs[FAST486_REG_EAX].LowByte < 0x06)
3034 {
3035 /* A carry occurred */
3036 State->Flags.Cf = TRUE;
3037 }
3038
3039 /* Set the adjust flag */
3040 State->Flags.Af = TRUE;
3041 }
3042
3043 /* Check if the second BCD digit is invalid or there was a carry from it */
3044 if ((Value > 0x99) || Carry)
3045 {
3046 /* Correct it */
3047 State->GeneralRegs[FAST486_REG_EAX].LowByte += 0x60;
3048
3049 /* There was a carry */
3050 State->Flags.Cf = TRUE;
3051 }
3052
3053 Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
3054
3055 /* Update the flags */
3056 State->Flags.Sf = (Value & SIGN_FLAG_BYTE) != 0;
3057 State->Flags.Zf = (Value == 0);
3058 State->Flags.Pf = Fast486CalculateParity(Value);
3059
3060 return TRUE;
3061 }
3062
3063 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubByteModrm)
3064 {
3065 UCHAR FirstValue, SecondValue, Result;
3066 FAST486_MOD_REG_RM ModRegRm;
3067 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3068
3069 /* Make sure this is the right instruction */
3070 ASSERT((Opcode & 0xED) == 0x28);
3071
3072 TOGGLE_ADSIZE(AddressSize);
3073
3074 /* Get the operands */
3075 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3076 {
3077 /* Exception occurred */
3078 return FALSE;
3079 }
3080
3081 if (!Fast486ReadModrmByteOperands(State,
3082 &ModRegRm,
3083 &FirstValue,
3084 &SecondValue))
3085 {
3086 /* Exception occurred */
3087 return FALSE;
3088 }
3089
3090 /* Check if this is the instruction that writes to R/M */
3091 if (!(Opcode & FAST486_OPCODE_WRITE_REG))
3092 {
3093 /* Swap the order */
3094 SWAP(FirstValue, SecondValue);
3095 }
3096
3097 /* Calculate the result */
3098 Result = FirstValue - SecondValue;
3099
3100 /* Update the flags */
3101 State->Flags.Cf = (FirstValue < SecondValue);
3102 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) != (SecondValue & SIGN_FLAG_BYTE))
3103 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
3104 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3105 State->Flags.Zf = (Result == 0);
3106 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
3107 State->Flags.Pf = Fast486CalculateParity(Result);
3108
3109 /* Check if this is not a CMP */
3110 if (!(Opcode & 0x10))
3111 {
3112 /* Write back the result */
3113 return Fast486WriteModrmByteOperands(State,
3114 &ModRegRm,
3115 Opcode & FAST486_OPCODE_WRITE_REG,
3116 Result);
3117 }
3118 else
3119 {
3120 /* Discard the result */
3121 return TRUE;
3122 }
3123 }
3124
3125 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubModrm)
3126 {
3127 FAST486_MOD_REG_RM ModRegRm;
3128 BOOLEAN OperandSize, AddressSize;
3129
3130 /* Make sure this is the right instruction */
3131 ASSERT((Opcode & 0xED) == 0x29);
3132
3133 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3134
3135 TOGGLE_ADSIZE(AddressSize);
3136 TOGGLE_OPSIZE(OperandSize);
3137
3138 /* Get the operands */
3139 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3140 {
3141 /* Exception occurred */
3142 return FALSE;
3143 }
3144
3145 /* Check the operand size */
3146 if (OperandSize)
3147 {
3148 ULONG FirstValue, SecondValue, Result;
3149
3150 if (!Fast486ReadModrmDwordOperands(State,
3151 &ModRegRm,
3152 &FirstValue,
3153 &SecondValue))
3154 {
3155 /* Exception occurred */
3156 return FALSE;
3157 }
3158
3159 /* Check if this is the instruction that writes to R/M */
3160 if (!(Opcode & FAST486_OPCODE_WRITE_REG))
3161 {
3162 /* Swap the order */
3163 SWAP(FirstValue, SecondValue);
3164 }
3165
3166 /* Calculate the result */
3167 Result = FirstValue - SecondValue;
3168
3169 /* Update the flags */
3170 State->Flags.Cf = (FirstValue < SecondValue);
3171 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) != (SecondValue & SIGN_FLAG_LONG))
3172 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
3173 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3174 State->Flags.Zf = (Result == 0);
3175 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
3176 State->Flags.Pf = Fast486CalculateParity(Result);
3177
3178 /* Check if this is not a CMP */
3179 if (!(Opcode & 0x10))
3180 {
3181 /* Write back the result */
3182 return Fast486WriteModrmDwordOperands(State,
3183 &ModRegRm,
3184 Opcode & FAST486_OPCODE_WRITE_REG,
3185 Result);
3186 }
3187 else
3188 {
3189 /* Discard the result */
3190 return TRUE;
3191 }
3192 }
3193 else
3194 {
3195 USHORT FirstValue, SecondValue, Result;
3196
3197 if (!Fast486ReadModrmWordOperands(State,
3198 &ModRegRm,
3199 &FirstValue,
3200 &SecondValue))
3201 {
3202 /* Exception occurred */
3203 return FALSE;
3204 }
3205
3206 /* Check if this is the instruction that writes to R/M */
3207 if (!(Opcode & FAST486_OPCODE_WRITE_REG))
3208 {
3209 /* Swap the order */
3210 SWAP(FirstValue, SecondValue);
3211 }
3212
3213 /* Calculate the result */
3214 Result = FirstValue - SecondValue;
3215
3216 /* Update the flags */
3217 State->Flags.Cf = (FirstValue < SecondValue);
3218 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) != (SecondValue & SIGN_FLAG_WORD))
3219 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
3220 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3221 State->Flags.Zf = (Result == 0);
3222 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
3223 State->Flags.Pf = Fast486CalculateParity(Result);
3224
3225 /* Check if this is not a CMP */
3226 if (!(Opcode & 0x10))
3227 {
3228 /* Write back the result */
3229 return Fast486WriteModrmWordOperands(State,
3230 &ModRegRm,
3231 Opcode & FAST486_OPCODE_WRITE_REG,
3232 Result);
3233 }
3234 else
3235 {
3236 /* Discard the result */
3237 return TRUE;
3238 }
3239 }
3240 }
3241
3242 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubAl)
3243 {
3244 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
3245 UCHAR SecondValue, Result;
3246
3247 /* Make sure this is the right instruction */
3248 ASSERT((Opcode & 0xEF) == 0x2C);
3249
3250 if (State->PrefixFlags)
3251 {
3252 /* This opcode doesn't take any prefixes */
3253 Fast486Exception(State, FAST486_EXCEPTION_UD);
3254 return FALSE;
3255 }
3256
3257 if (!Fast486FetchByte(State, &SecondValue))
3258 {
3259 /* Exception occurred */
3260 return FALSE;
3261 }
3262
3263 /* Calculate the result */
3264 Result = FirstValue - SecondValue;
3265
3266 /* Update the flags */
3267 State->Flags.Cf = (FirstValue < SecondValue);
3268 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) != (SecondValue & SIGN_FLAG_BYTE))
3269 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
3270 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3271 State->Flags.Zf = (Result == 0);
3272 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
3273 State->Flags.Pf = Fast486CalculateParity(Result);
3274
3275 /* Check if this is not a CMP */
3276 if (!(Opcode & 0x10))
3277 {
3278 /* Write back the result */
3279 State->GeneralRegs[FAST486_REG_EAX].LowByte = Result;
3280 }
3281
3282 return TRUE;
3283 }
3284
3285 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubEax)
3286 {
3287 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
3288
3289 /* Make sure this is the right instruction */
3290 ASSERT((Opcode & 0xEF) == 0x2D);
3291
3292 NO_LOCK_PREFIX();
3293 TOGGLE_OPSIZE(Size);
3294
3295 if (Size)
3296 {
3297 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
3298 ULONG SecondValue, Result;
3299
3300 if (!Fast486FetchDword(State, &SecondValue))
3301 {
3302 /* Exception occurred */
3303 return FALSE;
3304 }
3305
3306 /* Calculate the result */
3307 Result = FirstValue - SecondValue;
3308
3309 /* Update the flags */
3310 State->Flags.Cf = (FirstValue < SecondValue);
3311 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) != (SecondValue & SIGN_FLAG_LONG))
3312 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
3313 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3314 State->Flags.Zf = (Result == 0);
3315 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
3316 State->Flags.Pf = Fast486CalculateParity(Result);
3317
3318 /* Check if this is not a CMP */
3319 if (!(Opcode & 0x10))
3320 {
3321 /* Write back the result */
3322 State->GeneralRegs[FAST486_REG_EAX].Long = Result;
3323 }
3324 }
3325 else
3326 {
3327 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
3328 USHORT SecondValue, Result;
3329
3330 if (!Fast486FetchWord(State, &SecondValue))
3331 {
3332 /* Exception occurred */
3333 return FALSE;
3334 }
3335
3336 /* Calculate the result */
3337 Result = FirstValue - SecondValue;
3338
3339 /* Update the flags */
3340 State->Flags.Cf = (FirstValue < SecondValue);
3341 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) != (SecondValue & SIGN_FLAG_WORD))
3342 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
3343 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3344 State->Flags.Zf = (Result == 0);
3345 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
3346 State->Flags.Pf = Fast486CalculateParity(Result);
3347
3348 /* Check if this is not a CMP */
3349 if (!(Opcode & 0x10))
3350 {
3351 /* Write back the result */
3352 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
3353 }
3354 }
3355
3356 return TRUE;
3357 }
3358
3359 FAST486_OPCODE_HANDLER(Fast486OpcodeDas)
3360 {
3361 UCHAR Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
3362 BOOLEAN Carry = State->Flags.Cf;
3363
3364 /* Clear the carry flag */
3365 State->Flags.Cf = FALSE;
3366
3367 /* Check if the first BCD digit is invalid or there was a borrow */
3368 if (((Value & 0x0F) > 9) || State->Flags.Af)
3369 {
3370 /* Correct it */
3371 State->GeneralRegs[FAST486_REG_EAX].LowByte -= 0x06;
3372 if (State->GeneralRegs[FAST486_REG_EAX].LowByte > 0xFB)
3373 {
3374 /* A borrow occurred */
3375 State->Flags.Cf = TRUE;
3376 }
3377
3378 /* Set the adjust flag */
3379 State->Flags.Af = TRUE;
3380 }
3381
3382 /* Check if the second BCD digit is invalid or there was a borrow */
3383 if ((Value > 0x99) || Carry)
3384 {
3385 /* Correct it */
3386 State->GeneralRegs[FAST486_REG_EAX].LowByte -= 0x60;
3387
3388 /* There was a borrow */
3389 State->Flags.Cf = TRUE;
3390 }
3391
3392 Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
3393
3394 /* Update the flags */
3395 State->Flags.Sf = (Value & SIGN_FLAG_BYTE) != 0;
3396 State->Flags.Zf = (Value == 0);
3397 State->Flags.Pf = Fast486CalculateParity(Value);
3398
3399 return TRUE;
3400 }
3401
3402 FAST486_OPCODE_HANDLER(Fast486OpcodeAaa)
3403 {
3404 UCHAR Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
3405
3406 /*
3407 * Check if the value in AL is not a valid BCD digit,
3408 * or there was a carry from the lowest 4 bits of AL
3409 */
3410 if (((Value & 0x0F) > 9) || State->Flags.Af)
3411 {
3412 /* Correct it */
3413 State->GeneralRegs[FAST486_REG_EAX].LowWord += 0x06;
3414 State->GeneralRegs[FAST486_REG_EAX].HighByte++;
3415
3416 /* Set CF and AF */
3417 State->Flags.Cf = State->Flags.Af = TRUE;
3418 }
3419 else
3420 {
3421 /* Clear CF and AF */
3422 State->Flags.Cf = State->Flags.Af = FALSE;
3423 }
3424
3425 /* Keep only the lowest 4 bits of AL */
3426 State->GeneralRegs[FAST486_REG_EAX].LowByte &= 0x0F;
3427
3428 return TRUE;
3429 }
3430
3431 FAST486_OPCODE_HANDLER(Fast486OpcodeAas)
3432 {
3433 UCHAR Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
3434
3435 /*
3436 * Check if the value in AL is not a valid BCD digit,
3437 * or there was a borrow from the lowest 4 bits of AL
3438 */
3439 if (((Value & 0x0F) > 9) || State->Flags.Af)
3440 {
3441 /* Correct it */
3442 State->GeneralRegs[FAST486_REG_EAX].LowWord -= 0x06;
3443 State->GeneralRegs[FAST486_REG_EAX].HighByte--;
3444
3445 /* Set CF and AF */
3446 State->Flags.Cf = State->Flags.Af = TRUE;
3447 }
3448 else
3449 {
3450 /* Clear CF and AF */
3451 State->Flags.Cf = State->Flags.Af = FALSE;
3452 }
3453
3454 /* Keep only the lowest 4 bits of AL */
3455 State->GeneralRegs[FAST486_REG_EAX].LowByte &= 0x0F;
3456
3457 return TRUE;
3458 }
3459
3460 FAST486_OPCODE_HANDLER(Fast486OpcodePushAll)
3461 {
3462 INT i;
3463 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
3464 FAST486_REG SavedEsp = State->GeneralRegs[FAST486_REG_ESP];
3465
3466 /* Make sure this is the right instruction */
3467 ASSERT(Opcode == 0x60);
3468
3469 TOGGLE_OPSIZE(Size);
3470 NO_LOCK_PREFIX();
3471
3472 /* Push all the registers in order */
3473 for (i = 0; i < FAST486_NUM_GEN_REGS; i++)
3474 {
3475 if (i == FAST486_REG_ESP)
3476 {
3477 /* Use the saved ESP instead */
3478 if (!Fast486StackPush(State, Size ? SavedEsp.Long : SavedEsp.LowWord))
3479 {
3480 /* Exception occurred */
3481 return FALSE;
3482 }
3483 }
3484 else
3485 {
3486 /* Push the register */
3487 if (!Fast486StackPush(State, Size ? State->GeneralRegs[i].Long
3488 : State->GeneralRegs[i].LowWord))
3489 {
3490 /* Exception occurred */
3491 return FALSE;
3492 }
3493 }
3494 }
3495
3496 return TRUE;
3497 }
3498
3499 FAST486_OPCODE_HANDLER(Fast486OpcodePopAll)
3500 {
3501 INT i;
3502 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
3503 ULONG Value;
3504
3505 /* Make sure this is the right instruction */
3506 ASSERT(Opcode == 0x61);
3507
3508 TOGGLE_OPSIZE(Size);
3509 NO_LOCK_PREFIX();
3510
3511 /* Pop all the registers in reverse order */
3512 for (i = FAST486_NUM_GEN_REGS - 1; i >= 0; i--)
3513 {
3514 /* Pop the value */
3515 if (!Fast486StackPop(State, &Value))
3516 {
3517 /* Exception occurred */
3518 return FALSE;
3519 }
3520
3521 /* Don't modify ESP */
3522 if (i != FAST486_REG_ESP)
3523 {
3524 if (Size) State->GeneralRegs[i].Long = Value;
3525 else State->GeneralRegs[i].LowWord = LOWORD(Value);
3526 }
3527 }
3528
3529 return TRUE;
3530 }
3531
3532 FAST486_OPCODE_HANDLER(Fast486OpcodeBound)
3533 {
3534 BOOLEAN OperandSize, AddressSize;
3535 FAST486_MOD_REG_RM ModRegRm;
3536 FAST486_SEG_REGS Segment = FAST486_REG_DS;
3537
3538 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3539
3540 NO_LOCK_PREFIX();
3541 TOGGLE_OPSIZE(OperandSize);
3542 TOGGLE_ADSIZE(AddressSize);
3543
3544 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3545 {
3546 /* Exception occurred */
3547 return FALSE;
3548 }
3549
3550 if (!ModRegRm.Memory)
3551 {
3552 /* Invalid */
3553 Fast486Exception(State, FAST486_EXCEPTION_UD);
3554 return FALSE;
3555 }
3556
3557 /* Check for the segment override */
3558 if (State->PrefixFlags & FAST486_PREFIX_SEG)
3559 {
3560 /* Use the override segment instead */
3561 Segment = State->SegmentOverride;
3562 }
3563
3564 if (OperandSize)
3565 {
3566 LONG Index, LowerBound, UpperBound;
3567
3568 /* Read the operands */
3569 if (!Fast486ReadModrmDwordOperands(State,
3570 &ModRegRm,
3571 (PULONG)&Index,
3572 (PULONG)&LowerBound))
3573 {
3574 /* Exception occurred */
3575 return FALSE;
3576 }
3577
3578 if (!Fast486ReadMemory(State,
3579 Segment,
3580 ModRegRm.MemoryAddress + sizeof(ULONG),
3581 FALSE,
3582 &UpperBound,
3583 sizeof(ULONG)))
3584 {
3585 /* Exception occurred */
3586 return FALSE;
3587 }
3588
3589 if ((Index < LowerBound) || (Index > UpperBound))
3590 {
3591 /* Out of bounds */
3592 Fast486Exception(State, FAST486_EXCEPTION_BR);
3593 return FALSE;
3594 }
3595 }
3596 else
3597 {
3598 SHORT Index, LowerBound, UpperBound;
3599
3600 /* Read the operands */
3601 if (!Fast486ReadModrmWordOperands(State,
3602 &ModRegRm,
3603 (PUSHORT)&Index,
3604 (PUSHORT)&LowerBound))
3605 {
3606 /* Exception occurred */
3607 return FALSE;
3608 }
3609
3610 if (!Fast486ReadMemory(State,
3611 Segment,
3612 ModRegRm.MemoryAddress + sizeof(USHORT),
3613 FALSE,
3614 &UpperBound,
3615 sizeof(USHORT)))
3616 {
3617 /* Exception occurred */
3618 return FALSE;
3619 }
3620
3621 if ((Index < LowerBound) || (Index > UpperBound))
3622 {
3623 /* Out of bounds */
3624 Fast486Exception(State, FAST486_EXCEPTION_BR);
3625 return FALSE;
3626 }
3627 }
3628
3629 return TRUE;
3630 }
3631
3632 FAST486_OPCODE_HANDLER(Fast486OpcodeArpl)
3633 {
3634 USHORT FirstValue, SecondValue;
3635 FAST486_MOD_REG_RM ModRegRm;
3636 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3637
3638 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
3639 || State->Flags.Vm
3640 || (State->PrefixFlags & FAST486_PREFIX_LOCK))
3641 {
3642 /* Cannot be used in real mode or with a LOCK prefix */
3643 Fast486Exception(State, FAST486_EXCEPTION_UD);
3644 return FALSE;
3645 }
3646
3647 TOGGLE_ADSIZE(AddressSize);
3648
3649 /* Get the operands */
3650 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3651 {
3652 /* Exception occurred */
3653 return FALSE;
3654 }
3655
3656 /* Read the operands */
3657 if (!Fast486ReadModrmWordOperands(State,
3658 &ModRegRm,
3659 &FirstValue,
3660 &SecondValue))
3661 {
3662 /* Exception occurred */
3663 return FALSE;
3664 }
3665
3666 /* Check if the RPL needs adjusting */
3667 if ((SecondValue & 3) < (FirstValue & 3))
3668 {
3669 /* Adjust the RPL */
3670 SecondValue &= ~3;
3671 SecondValue |= FirstValue & 3;
3672
3673 /* Set ZF */
3674 State->Flags.Zf = TRUE;
3675
3676 /* Write back the result */
3677 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, SecondValue);
3678 }
3679 else
3680 {
3681 /* Clear ZF */
3682 State->Flags.Zf = FALSE;
3683 return TRUE;
3684 }
3685 }
3686
3687 FAST486_OPCODE_HANDLER(Fast486OpcodePushImm)
3688 {
3689 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
3690
3691 /* Make sure this is the right instruction */
3692 ASSERT(Opcode == 0x68);
3693
3694 NO_LOCK_PREFIX();
3695 TOGGLE_OPSIZE(Size);
3696
3697 if (Size)
3698 {
3699 ULONG Data;
3700
3701 if (!Fast486FetchDword(State, &Data))
3702 {
3703 /* Exception occurred */
3704 return FALSE;
3705 }
3706
3707 /* Call the internal API */
3708 return Fast486StackPush(State, Data);
3709 }
3710 else
3711 {
3712 SHORT Data;
3713
3714 if (!Fast486FetchWord(State, (PUSHORT)&Data))
3715 {
3716 /* Exception occurred */
3717 return FALSE;
3718 }
3719
3720 /* Call the internal API */
3721 return Fast486StackPush(State, Data);
3722 }
3723 }
3724
3725 FAST486_OPCODE_HANDLER(Fast486OpcodeImulModrmImm)
3726 {
3727 BOOLEAN OperandSize, AddressSize;
3728 FAST486_MOD_REG_RM ModRegRm;
3729 LONG Multiplier;
3730
3731 /* Make sure this is the right instruction */
3732 ASSERT((Opcode & 0xFD) == 0x69);
3733
3734 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3735
3736 TOGGLE_ADSIZE(AddressSize);
3737 TOGGLE_OPSIZE(OperandSize);
3738
3739 /* Fetch the parameters */
3740 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3741 {
3742 /* Exception occurred */
3743 return FALSE;
3744 }
3745
3746 if (Opcode == 0x6B)
3747 {
3748 CHAR Byte;
3749
3750 /* Fetch the immediate operand */
3751 if (!Fast486FetchByte(State, (PUCHAR)&Byte))
3752 {
3753 /* Exception occurred */
3754 return FALSE;
3755 }
3756
3757 Multiplier = (LONG)Byte;
3758 }
3759 else
3760 {
3761 if (OperandSize)
3762 {
3763 LONG Dword;
3764
3765 /* Fetch the immediate operand */
3766 if (!Fast486FetchDword(State, (PULONG)&Dword))
3767 {
3768 /* Exception occurred */
3769 return FALSE;
3770 }
3771
3772 Multiplier = Dword;
3773 }
3774 else
3775 {
3776 SHORT Word;
3777
3778 /* Fetch the immediate operand */
3779 if (!Fast486FetchWord(State, (PUSHORT)&Word))
3780 {
3781 /* Exception occurred */
3782 return FALSE;
3783 }
3784
3785 Multiplier = (LONG)Word;
3786 }
3787 }
3788
3789 if (OperandSize)
3790 {
3791 LONG RegValue, Multiplicand;
3792 LONGLONG Product;
3793
3794 /* Read the operands */
3795 if (!Fast486ReadModrmDwordOperands(State,
3796 &ModRegRm,
3797 (PULONG)&RegValue,
3798 (PULONG)&Multiplicand))
3799 {
3800 /* Exception occurred */
3801 return FALSE;
3802 }
3803
3804 /* Multiply */
3805 Product = (LONGLONG)Multiplicand * (LONGLONG)Multiplier;
3806
3807 /* Check for carry/overflow */
3808 State->Flags.Cf = State->Flags.Of = ((Product < MINLONG) || (Product > MAXLONG));
3809
3810 /* Write-back the result */
3811 return Fast486WriteModrmDwordOperands(State,
3812 &ModRegRm,
3813 TRUE,
3814 (ULONG)((LONG)Product));
3815 }
3816 else
3817 {
3818 SHORT RegValue, Multiplicand;
3819 LONG Product;
3820
3821 /* Read the operands */
3822 if (!Fast486ReadModrmWordOperands(State,
3823 &ModRegRm,
3824 (PUSHORT)&RegValue,
3825 (PUSHORT)&Multiplicand))
3826 {
3827 /* Exception occurred */
3828 return FALSE;
3829 }
3830
3831 /* Multiply */
3832 Product = (LONG)Multiplicand * (LONG)Multiplier;
3833
3834 /* Check for carry/overflow */
3835 State->Flags.Cf = State->Flags.Of = ((Product < MINSHORT) || (Product > MAXSHORT));
3836
3837 /* Write-back the result */
3838 return Fast486WriteModrmWordOperands(State,
3839 &ModRegRm,
3840 TRUE,
3841 (USHORT)((SHORT)Product));
3842 }
3843 }
3844
3845 FAST486_OPCODE_HANDLER(Fast486OpcodePushByteImm)
3846 {
3847 CHAR Data;
3848
3849 /* Make sure this is the right instruction */
3850 ASSERT(Opcode == 0x6A);
3851
3852 if (!Fast486FetchByte(State, (PUCHAR)&Data))
3853 {
3854 /* Exception occurred */
3855 return FALSE;
3856 }
3857
3858 /* Call the internal API */
3859 return Fast486StackPush(State, Data);
3860 }
3861
3862 FAST486_OPCODE_HANDLER(Fast486OpcodeMovByteModrm)
3863 {
3864 UCHAR FirstValue, SecondValue, Result;
3865 FAST486_MOD_REG_RM ModRegRm;
3866 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3867
3868 /* Make sure this is the right instruction */
3869 ASSERT((Opcode & 0xFD) == 0x88);
3870
3871 TOGGLE_ADSIZE(AddressSize);
3872
3873 /* Get the operands */
3874 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3875 {
3876 /* Exception occurred */
3877 return FALSE;
3878 }
3879
3880 if (!Fast486ReadModrmByteOperands(State,
3881 &ModRegRm,
3882 &FirstValue,
3883 &SecondValue))
3884 {
3885 /* Exception occurred */
3886 return FALSE;
3887 }
3888
3889 if (Opcode & FAST486_OPCODE_WRITE_REG) Result = SecondValue;
3890 else Result = FirstValue;
3891
3892 /* Write back the result */
3893 return Fast486WriteModrmByteOperands(State,
3894 &ModRegRm,
3895 Opcode & FAST486_OPCODE_WRITE_REG,
3896 Result);
3897
3898 }
3899
3900 FAST486_OPCODE_HANDLER(Fast486OpcodeMovModrm)
3901 {
3902 FAST486_MOD_REG_RM ModRegRm;
3903 BOOLEAN OperandSize, AddressSize;
3904
3905 /* Make sure this is the right instruction */
3906 ASSERT((Opcode & 0xFD) == 0x89);
3907
3908 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3909
3910 TOGGLE_ADSIZE(AddressSize);
3911 TOGGLE_OPSIZE(OperandSize);
3912
3913 /* Get the operands */
3914 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3915 {
3916 /* Exception occurred */
3917 return FALSE;
3918 }
3919
3920 /* Check the operand size */
3921 if (OperandSize)
3922 {
3923 ULONG FirstValue, SecondValue, Result;
3924
3925 if (!Fast486ReadModrmDwordOperands(State,
3926 &ModRegRm,
3927 &FirstValue,
3928 &SecondValue))
3929 {
3930 /* Exception occurred */
3931 return FALSE;
3932 }
3933
3934 if (Opcode & FAST486_OPCODE_WRITE_REG) Result = SecondValue;
3935 else Result = FirstValue;
3936
3937 /* Write back the result */
3938 return Fast486WriteModrmDwordOperands(State,
3939 &ModRegRm,
3940 Opcode & FAST486_OPCODE_WRITE_REG,
3941 Result);
3942 }
3943 else
3944 {
3945 USHORT FirstValue, SecondValue, Result;
3946
3947 if (!Fast486ReadModrmWordOperands(State,
3948 &ModRegRm,
3949 &FirstValue,
3950 &SecondValue))
3951 {
3952 /* Exception occurred */
3953 return FALSE;
3954 }
3955
3956 if (Opcode & FAST486_OPCODE_WRITE_REG) Result = SecondValue;
3957 else Result = FirstValue;
3958
3959 /* Write back the result */
3960 return Fast486WriteModrmWordOperands(State,
3961 &ModRegRm,
3962 Opcode & FAST486_OPCODE_WRITE_REG,
3963 Result);
3964 }
3965 }
3966
3967 FAST486_OPCODE_HANDLER(Fast486OpcodeMovStoreSeg)
3968 {
3969 BOOLEAN OperandSize, AddressSize;
3970 FAST486_MOD_REG_RM ModRegRm;
3971
3972 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3973
3974 /* Make sure this is the right instruction */
3975 ASSERT(Opcode == 0x8C);
3976
3977 TOGGLE_ADSIZE(AddressSize);
3978 TOGGLE_OPSIZE(OperandSize);
3979
3980 /* Get the operands */
3981 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3982 {
3983 /* Exception occurred */
3984 return FALSE;
3985 }
3986
3987 if (ModRegRm.Register >= FAST486_NUM_SEG_REGS)
3988 {
3989 /* Invalid */
3990 Fast486Exception(State, FAST486_EXCEPTION_UD);
3991 return FALSE;
3992 }
3993
3994 if (OperandSize)
3995 {
3996 return Fast486WriteModrmDwordOperands(State,
3997 &ModRegRm,
3998 FALSE,
3999 State->SegmentRegs[ModRegRm.Register].Selector);
4000 }
4001 else
4002 {
4003 return Fast486WriteModrmWordOperands(State,
4004 &ModRegRm,
4005 FALSE,
4006 State->SegmentRegs[ModRegRm.Register].Selector);
4007 }
4008 }
4009
4010 FAST486_OPCODE_HANDLER(Fast486OpcodeLea)
4011 {
4012 FAST486_MOD_REG_RM ModRegRm;
4013 BOOLEAN OperandSize, AddressSize;
4014
4015 /* Make sure this is the right instruction */
4016 ASSERT(Opcode == 0x8D);
4017
4018 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
4019
4020 TOGGLE_ADSIZE(AddressSize);
4021 TOGGLE_OPSIZE(OperandSize);
4022
4023 /* Get the operands */
4024 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
4025 {
4026 /* Exception occurred */
4027 return FALSE;
4028 }
4029
4030 /* The second operand must be memory */
4031 if (!ModRegRm.Memory)
4032 {
4033 /* Invalid */
4034 Fast486Exception(State, FAST486_EXCEPTION_UD);
4035 return FALSE;
4036 }
4037
4038 /* Write the address to the register */
4039 if (OperandSize)
4040 {
4041 return Fast486WriteModrmDwordOperands(State,
4042 &ModRegRm,
4043 TRUE,
4044 ModRegRm.MemoryAddress);
4045 }
4046 else
4047 {
4048 return Fast486WriteModrmWordOperands(State,
4049 &ModRegRm,
4050 TRUE,
4051 ModRegRm.MemoryAddress);
4052
4053 }
4054 }
4055
4056 FAST486_OPCODE_HANDLER(Fast486OpcodeMovLoadSeg)
4057 {
4058 BOOLEAN OperandSize, AddressSize;
4059 FAST486_MOD_REG_RM ModRegRm;
4060
4061 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
4062
4063 /* Make sure this is the right instruction */
4064 ASSERT(Opcode == 0x8E);
4065
4066 TOGGLE_ADSIZE(AddressSize);
4067 TOGGLE_OPSIZE(OperandSize);
4068
4069 /* Get the operands */
4070 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
4071 {
4072 /* Exception occurred */
4073 return FALSE;
4074 }
4075
4076 if ((ModRegRm.Register >= FAST486_NUM_SEG_REGS)
4077 || ((FAST486_SEG_REGS)ModRegRm.Register == FAST486_REG_CS))
4078 {
4079 /* Invalid */
4080 Fast486Exception(State, FAST486_EXCEPTION_UD);
4081 return FALSE;
4082 }
4083
4084 if (OperandSize)
4085 {
4086 ULONG Selector;
4087
4088 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Selector))
4089 {
4090 /* Exception occurred */
4091 return FALSE;
4092 }
4093
4094 return Fast486LoadSegment(State, ModRegRm.Register, LOWORD(Selector));
4095 }
4096 else
4097 {
4098 USHORT Selector;
4099
4100 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Selector))
4101 {
4102 /* Exception occurred */
4103 return FALSE;
4104 }
4105
4106 return Fast486LoadSegment(State, ModRegRm.Register, Selector);
4107 }
4108 }
4109
4110 FAST486_OPCODE_HANDLER(Fast486OpcodeCwde)
4111 {
4112 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4113
4114 /* Make sure this is the right instruction */
4115 ASSERT(Opcode == 0x98);
4116
4117 TOGGLE_OPSIZE(Size);
4118 NO_LOCK_PREFIX();
4119
4120 if (Size)
4121 {
4122 /* Sign extend AX to EAX */
4123 State->GeneralRegs[FAST486_REG_EAX].Long = MAKELONG
4124 (
4125 State->GeneralRegs[FAST486_REG_EAX].LowWord,
4126 (State->GeneralRegs[FAST486_REG_EAX].LowWord & SIGN_FLAG_WORD)
4127 ? 0xFFFF : 0x0000
4128 );
4129 }
4130 else
4131 {
4132 /* Sign extend AL to AX */
4133 State->GeneralRegs[FAST486_REG_EAX].HighByte =
4134 (State->GeneralRegs[FAST486_REG_EAX].LowByte & SIGN_FLAG_BYTE)
4135 ? 0xFF : 0x00;
4136 }
4137
4138 return TRUE;
4139 }
4140
4141 FAST486_OPCODE_HANDLER(Fast486OpcodeCdq)
4142 {
4143 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4144
4145 /* Make sure this is the right instruction */
4146 ASSERT(Opcode == 0x99);
4147
4148 TOGGLE_OPSIZE(Size);
4149 NO_LOCK_PREFIX();
4150
4151 if (Size)
4152 {
4153 /* Sign extend EAX to EDX:EAX */
4154 State->GeneralRegs[FAST486_REG_EDX].Long =
4155 (State->GeneralRegs[FAST486_REG_EAX].Long & SIGN_FLAG_LONG)
4156 ? 0xFFFFFFFF : 0x00000000;
4157 }
4158 else
4159 {
4160 /* Sign extend AX to DX:AX */
4161 State->GeneralRegs[FAST486_REG_EDX].LowWord =
4162 (State->GeneralRegs[FAST486_REG_EAX].LowWord & SIGN_FLAG_WORD)
4163 ? 0xFFFF : 0x0000;
4164 }
4165
4166 return TRUE;
4167 }
4168
4169 FAST486_OPCODE_HANDLER(Fast486OpcodeCallAbs)
4170 {
4171 USHORT Segment = 0;
4172 ULONG Offset = 0;
4173 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4174
4175 /* Make sure this is the right instruction */
4176 ASSERT(Opcode == 0x9A);
4177
4178 TOGGLE_OPSIZE(Size);
4179 NO_LOCK_PREFIX();
4180
4181 /* Fetch the offset */
4182 if (Size)
4183 {
4184 if (!Fast486FetchDword(State, &Offset))
4185 {
4186 /* Exception occurred */
4187 return FALSE;
4188 }
4189 }
4190 else
4191 {
4192 if (!Fast486FetchWord(State, (PUSHORT)&Offset))
4193 {
4194 /* Exception occurred */
4195 return FALSE;
4196 }
4197 }
4198
4199 /* Fetch the segment */
4200 if (!Fast486FetchWord(State, &Segment))
4201 {
4202 /* Exception occurred */
4203 return FALSE;
4204 }
4205
4206 /* Push the current code segment selector */
4207 if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector))
4208 {
4209 /* Exception occurred */
4210 return FALSE;
4211 }
4212
4213 /* Push the current value of the instruction pointer */
4214 if (!Fast486StackPush(State, State->InstPtr.Long))
4215 {
4216 /* Exception occurred */
4217 return FALSE;
4218 }
4219
4220 /* Load the new CS */
4221 if (!Fast486LoadSegment(State, FAST486_REG_CS, Segment))
4222 {
4223 /* Exception occurred */
4224 return FALSE;
4225 }
4226
4227 /* Load new (E)IP */
4228 if (Size) State->InstPtr.Long = Offset;
4229 else State->InstPtr.LowWord = LOWORD(Offset);
4230
4231 return TRUE;
4232 }
4233
4234 FAST486_OPCODE_HANDLER(Fast486OpcodeWait)
4235 {
4236 // TODO: NOT IMPLEMENTED
4237 UNIMPLEMENTED;
4238
4239 return FALSE;
4240 }
4241
4242 FAST486_OPCODE_HANDLER(Fast486OpcodePushFlags)
4243 {
4244 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4245
4246 NO_LOCK_PREFIX();
4247 TOGGLE_OPSIZE(Size);
4248
4249 /* Check for VM86 mode when IOPL is not 3 */
4250 if (State->Flags.Vm && (State->Flags.Iopl != 3))
4251 {
4252 /* Call the VM86 monitor */
4253 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, 0);
4254 return FALSE;
4255 }
4256
4257 /* Push the flags */
4258 if (Size) return Fast486StackPush(State, State->Flags.Long);
4259 else return Fast486StackPush(State, LOWORD(State->Flags.Long));
4260 }
4261
4262 FAST486_OPCODE_HANDLER(Fast486OpcodePopFlags)
4263 {
4264 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4265 INT Cpl = Fast486GetCurrentPrivLevel(State);
4266 FAST486_FLAGS_REG NewFlags;
4267
4268 NO_LOCK_PREFIX();
4269 TOGGLE_OPSIZE(Size);
4270
4271 /* Pop the new flags */
4272 if (!Fast486StackPop(State, &NewFlags.Long))
4273 {
4274 /* Exception occurred */
4275 return FALSE;
4276 }
4277
4278 /* Check for VM86 mode when IOPL is not 3 */
4279 if (State->Flags.Vm && (State->Flags.Iopl != 3))
4280 {
4281 /* Call the VM86 monitor */
4282 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, 0);
4283 return FALSE;
4284 }
4285
4286 State->Flags.Cf = NewFlags.Cf;
4287 State->Flags.Pf = NewFlags.Pf;
4288 State->Flags.Af = NewFlags.Af;
4289 State->Flags.Zf = NewFlags.Zf;
4290 State->Flags.Sf = NewFlags.Sf;
4291 State->Flags.Tf = NewFlags.Tf;
4292 State->Flags.Df = NewFlags.Df;
4293 State->Flags.Of = NewFlags.Of;
4294 State->Flags.Nt = NewFlags.Nt;
4295 State->Flags.Ac = NewFlags.Ac;
4296
4297 if (Cpl == 0) State->Flags.Iopl = NewFlags.Iopl;
4298 if (Cpl <= State->Flags.Iopl) State->Flags.If = NewFlags.If;
4299
4300 return TRUE;
4301 }
4302
4303 FAST486_OPCODE_HANDLER(Fast486OpcodeSahf)
4304 {
4305 /* Make sure this is the right instruction */
4306 ASSERT(Opcode == 0x9E);
4307
4308 /* Set the low-order byte of FLAGS to AH */
4309 State->Flags.Long &= 0xFFFFFF00;
4310 State->Flags.Long |= State->GeneralRegs[FAST486_REG_EAX].HighByte;
4311
4312 /* Restore the reserved bits of FLAGS */
4313 State->Flags.AlwaysSet = TRUE;
4314 State->Flags.Reserved0 = State->Flags.Reserved1 = FALSE;
4315
4316 return TRUE;
4317 }
4318
4319 FAST486_OPCODE_HANDLER(Fast486OpcodeLahf)
4320 {
4321 /* Make sure this is the right instruction */
4322 ASSERT(Opcode == 0x9F);
4323
4324 /* Set AH to the low-order byte of FLAGS */
4325 State->GeneralRegs[FAST486_REG_EAX].HighByte = LOBYTE(State->Flags.Long);
4326
4327 return TRUE;
4328 }
4329
4330 FAST486_OPCODE_HANDLER(Fast486OpcodeRet)
4331 {
4332 ULONG ReturnAddress;
4333 USHORT BytesToPop = 0;
4334 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4335
4336 /* Make sure this is the right instruction */
4337 ASSERT((Opcode & 0xFE) == 0xC2);
4338
4339 NO_LOCK_PREFIX();
4340 TOGGLE_OPSIZE(Size);
4341
4342 if (Opcode == 0xC2)
4343 {
4344 /* Fetch the number of bytes to pop after the return */
4345 if (!Fast486FetchWord(State, &BytesToPop)) return FALSE;
4346 }
4347
4348 /* Pop the return address */
4349 if (!Fast486StackPop(State, &ReturnAddress)) return FALSE;
4350
4351 /* Return to the calling procedure, and if necessary, pop the parameters */
4352 if (Size)
4353 {
4354 State->InstPtr.Long = ReturnAddress;
4355 State->GeneralRegs[FAST486_REG_ESP].Long += BytesToPop;
4356 }
4357 else
4358 {
4359 State->InstPtr.LowWord = LOWORD(ReturnAddress);
4360 State->GeneralRegs[FAST486_REG_ESP].LowWord += BytesToPop;
4361 }
4362
4363 return TRUE;
4364 }
4365
4366 FAST486_OPCODE_HANDLER(Fast486OpcodeLdsLes)
4367 {
4368 UCHAR FarPointer[6];
4369 BOOLEAN OperandSize, AddressSize;
4370 FAST486_MOD_REG_RM ModRegRm;
4371
4372 /* Make sure this is the right instruction */
4373 ASSERT((Opcode & 0xFE) == 0xC4);
4374
4375 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
4376
4377 TOGGLE_OPSIZE(OperandSize);
4378 TOGGLE_ADSIZE(AddressSize);
4379
4380 /* Get the operands */
4381 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
4382 {
4383 /* Exception occurred */
4384 return FALSE;
4385 }
4386
4387 if (!ModRegRm.Memory)
4388 {
4389 /* Check if this is a BOP and the host supports BOPs */
4390 if ((Opcode == 0xC4)
4391 && (ModRegRm.Register == FAST486_REG_EAX)
4392 && (ModRegRm.SecondRegister == FAST486_REG_ESP)
4393 && (State->BopCallback != NULL))
4394 {
4395 UCHAR BopCode;
4396
4397 /* Fetch the BOP code */
4398 if (!Fast486FetchByte(State, &BopCode))
4399 {
4400 /* Exception occurred */
4401 return FALSE;
4402 }
4403
4404 /* Call the BOP handler */
4405 State->BopCallback(State, BopCode);
4406
4407 /*
4408 * If an interrupt should occur at this time, delay it.
4409 * We must do this because if an interrupt begins and the BOP callback
4410 * changes the CS:IP, the interrupt handler won't execute and the
4411 * stack pointer will never be restored.
4412 */
4413 if (State->IntStatus == FAST486_INT_EXECUTE)
4414 {
4415 State->IntStatus = FAST486_INT_DELAYED;
4416 }
4417
4418 /* Return success */
4419 return TRUE;
4420 }
4421
4422 /* Invalid */
4423 Fast486Exception(State, FAST486_EXCEPTION_UD);
4424 return FALSE;
4425 }
4426
4427 if (!Fast486ReadMemory(State,
4428 (State->PrefixFlags & FAST486_PREFIX_SEG)
4429 ? State->SegmentOverride : FAST486_REG_DS,
4430 ModRegRm.MemoryAddress,
4431 FALSE,
4432 FarPointer,
4433 OperandSize ? 6 : 4))
4434 {
4435 /* Exception occurred */
4436 return FALSE;
4437 }
4438
4439 if (OperandSize)
4440 {
4441 ULONG Offset = *((PULONG)FarPointer);
4442 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(ULONG)]);
4443
4444 /* Set the register to the offset */
4445 State->GeneralRegs[ModRegRm.Register].Long = Offset;
4446
4447 /* Load the segment */
4448 return Fast486LoadSegment(State,
4449 (Opcode == 0xC4)
4450 ? FAST486_REG_ES : FAST486_REG_DS,
4451 Segment);
4452 }
4453 else
4454 {
4455 USHORT Offset = *((PUSHORT)FarPointer);
4456 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(USHORT)]);
4457
4458 /* Set the register to the offset */
4459 State->GeneralRegs[ModRegRm.Register].LowWord = Offset;
4460
4461 /* Load the segment */
4462 return Fast486LoadSegment(State,
4463 (Opcode == 0xC4)
4464 ? FAST486_REG_ES : FAST486_REG_DS,
4465 Segment);
4466 }
4467 }
4468
4469 FAST486_OPCODE_HANDLER(Fast486OpcodeEnter)
4470 {
4471 INT i;
4472 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4473 USHORT FrameSize;
4474 UCHAR NestingLevel;
4475 FAST486_REG FramePointer;
4476
4477 /* Make sure this is the right instruction */
4478 ASSERT(Opcode == 0xC8);
4479
4480 NO_LOCK_PREFIX();
4481 TOGGLE_OPSIZE(Size);
4482
4483 if (!Fast486FetchWord(State, &FrameSize))
4484 {
4485 /* Exception occurred */
4486 return FALSE;
4487 }
4488
4489 if (!Fast486FetchByte(State, &NestingLevel))
4490 {
4491 /* Exception occurred */
4492 return FALSE;
4493 }
4494
4495 /* Push EBP */
4496 if (!Fast486StackPush(State, State->GeneralRegs[FAST486_REG_EBP].Long))
4497 {
4498 /* Exception occurred */
4499 return FALSE;
4500 }
4501
4502 /* Save ESP */
4503 FramePointer = State->GeneralRegs[FAST486_REG_ESP];
4504
4505 /* Set up the nested procedure stacks */
4506 for (i = 1; i < NestingLevel; i++)
4507 {
4508 if (Size)
4509 {
4510 State->GeneralRegs[FAST486_REG_EBP].Long -= 4;
4511 Fast486StackPush(State, State->GeneralRegs[FAST486_REG_EBP].Long);
4512 }
4513 else
4514 {
4515 State->GeneralRegs[FAST486_REG_EBP].LowWord -= 2;
4516 Fast486StackPush(State, State->GeneralRegs[FAST486_REG_EBP].LowWord);
4517 }
4518 }
4519
4520 if (NestingLevel > 0) Fast486StackPush(State, FramePointer.Long);
4521
4522 /* Set EBP to the frame pointer */
4523 State->GeneralRegs[FAST486_REG_EBP] = FramePointer;
4524
4525 /* Reserve space for the frame */
4526 if (Size) State->GeneralRegs[FAST486_REG_ESP].Long -= (ULONG)FrameSize;
4527 else State->GeneralRegs[FAST486_REG_ESP].LowWord -= FrameSize;
4528
4529 return TRUE;
4530 }
4531
4532 FAST486_OPCODE_HANDLER(Fast486OpcodeLeave)
4533 {
4534 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4535
4536 /* Make sure this is the right instruction */
4537 ASSERT(Opcode == 0xC9);
4538
4539 NO_LOCK_PREFIX();
4540 TOGGLE_OPSIZE(Size);
4541
4542 if (Size)
4543 {
4544 /* Set the stack pointer (ESP) to the base pointer (EBP) */
4545 State->GeneralRegs[FAST486_REG_ESP].Long = State->GeneralRegs[FAST486_REG_EBP].Long;
4546
4547 /* Pop the saved base pointer from the stack */
4548 return Fast486StackPop(State, &State->GeneralRegs[FAST486_REG_EBP].Long);
4549 }
4550 else
4551 {
4552 ULONG Value;
4553
4554 /* Set the stack pointer (SP) to the base pointer (BP) */
4555 State->GeneralRegs[FAST486_REG_ESP].LowWord = State->GeneralRegs[FAST486_REG_EBP].LowWord;
4556
4557 /* Pop the saved base pointer from the stack */
4558 if (Fast486StackPop(State, &Value))
4559 {
4560 State->GeneralRegs[FAST486_REG_EBP].LowWord = LOWORD(Value);
4561 return TRUE;
4562 }
4563 else return FALSE;
4564 }
4565 }
4566
4567 FAST486_OPCODE_HANDLER(Fast486OpcodeRetFar)
4568 {
4569 ULONG Segment = 0;
4570 ULONG Offset = 0;
4571 USHORT BytesToPop = 0;
4572 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4573
4574 /* Make sure this is the right instruction */
4575 ASSERT((Opcode & 0xFE) == 0xCA);
4576
4577 TOGGLE_OPSIZE(Size);
4578 NO_LOCK_PREFIX();
4579
4580 if (Opcode == 0xCA)
4581 {
4582 /* Fetch the number of bytes to pop after the return */
4583 if (!Fast486FetchWord(State, &BytesToPop)) return FALSE;
4584 }
4585
4586 /* Pop the offset */
4587 if (!Fast486StackPop(State, &Offset))
4588 {
4589 /* Exception occurred */
4590 return FALSE;
4591 }
4592
4593 /* Pop the segment */
4594 if (!Fast486StackPop(State, &Segment))
4595 {
4596 /* Exception occurred */
4597 return FALSE;
4598 }
4599
4600 /* Load the new CS */
4601 if (!Fast486LoadSegment(State, FAST486_REG_CS, Segment))
4602 {
4603 /* Exception occurred */
4604 return FALSE;
4605 }
4606
4607 /* Load new (E)IP, and if necessary, pop the parameters */
4608 if (Size)
4609 {
4610 State->InstPtr.Long = Offset;
4611 State->GeneralRegs[FAST486_REG_ESP].Long += BytesToPop;
4612 }
4613 else
4614 {
4615 State->InstPtr.LowWord = LOWORD(Offset);
4616 State->GeneralRegs[FAST486_REG_ESP].LowWord += BytesToPop;
4617 }
4618
4619 return TRUE;
4620 }
4621
4622 FAST486_OPCODE_HANDLER(Fast486OpcodeInt)
4623 {
4624 UCHAR IntNum;
4625
4626 switch (Opcode)
4627 {
4628 case 0xCC:
4629 {
4630 /* This is the INT3 instruction */
4631 IntNum = 3;
4632 break;
4633 }
4634
4635 case 0xCD:
4636 {
4637 /* Fetch the interrupt number */
4638 if (!Fast486FetchByte(State, &IntNum))
4639 {
4640 /* Exception occurred */
4641 return FALSE;
4642 }
4643
4644 break;
4645 }
4646
4647 case 0xCE:
4648 {
4649 /* Don't do anything if OF is cleared */
4650 if (!State->Flags.Of) return TRUE;
4651
4652 /* Exception #OF */
4653 IntNum = FAST486_EXCEPTION_OF;
4654
4655 break;
4656 }
4657
4658 default:
4659 {
4660 /* Should not happen */
4661 ASSERT(FALSE);
4662 }
4663 }
4664
4665 /* Perform the interrupt */
4666 return Fast486PerformInterrupt(State, IntNum);
4667 }
4668
4669 FAST486_OPCODE_HANDLER(Fast486OpcodeIret)
4670 {
4671 FAST486_SEG_REGS i;
4672 ULONG InstPtr, CodeSel, StackPtr, StackSel;
4673 FAST486_FLAGS_REG NewFlags;
4674 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4675
4676 /* Make sure this is the right instruction */
4677 ASSERT(Opcode == 0xCF);
4678
4679 NO_LOCK_PREFIX();
4680 TOGGLE_OPSIZE(Size);
4681
4682 /* Pop EIP */
4683 if (!Fast486StackPop(State, &InstPtr))
4684 {
4685 /* Exception occurred */
4686 return FALSE;
4687 }
4688
4689 /* Pop CS */
4690 if (!Fast486StackPop(State, &CodeSel))
4691 {
4692 /* Exception occurred */
4693 return FALSE;
4694 }
4695
4696 /* Pop EFLAGS */
4697 if (!Fast486StackPop(State, &NewFlags.Long))
4698 {
4699 /* Exception occurred */
4700 return FALSE;
4701 }
4702
4703 /* Check for protected mode */
4704 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
4705 {
4706 INT Cpl = Fast486GetCurrentPrivLevel(State);
4707
4708 if (State->Flags.Vm)
4709 {
4710 /* Return from VM86 mode */
4711
4712 /* Check the IOPL */
4713 if (State->Flags.Iopl == 3)
4714 {
4715 /* Set new EIP */
4716 State->InstPtr.Long = LOWORD(InstPtr);
4717
4718 /* Load new CS */
4719 if (!Fast486LoadSegment(State, FAST486_REG_CS, CodeSel))
4720 {
4721 /* Exception occurred */
4722 return FALSE;
4723 }
4724
4725 /* Set the new flags */
4726 if (Size) State->Flags.Long = NewFlags.Long & REAL_MODE_FLAGS_MASK;
4727 else State->Flags.LowWord = NewFlags.LowWord & REAL_MODE_FLAGS_MASK;
4728 State->Flags.AlwaysSet = State->Flags.Vm = TRUE;
4729 State->Flags.Iopl = 3;
4730 }
4731 else
4732 {
4733 /* Call the VM86 monitor */
4734 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, 0);
4735 return FALSE;
4736 }
4737
4738 return TRUE;
4739 }
4740
4741 if (State->Flags.Nt)
4742 {
4743 /* Nested task return */
4744
4745 UNIMPLEMENTED;
4746 return FALSE;
4747 }
4748
4749 if (NewFlags.Vm)
4750 {
4751 /* Return to VM86 mode */
4752 ULONG Es, Ds, Fs, Gs;
4753
4754 /* Pop ESP, SS, ES, FS, GS */
4755 if (!Fast486StackPop(State, &StackPtr)) return FALSE;
4756 if (!Fast486StackPop(State, &StackSel)) return FALSE;
4757 if (!Fast486StackPop(State, &Es)) return FALSE;
4758 if (!Fast486StackPop(State, &Ds)) return FALSE;
4759 if (!Fast486StackPop(State, &Fs)) return FALSE;
4760 if (!Fast486StackPop(State, &Gs)) return FALSE;
4761
4762 /* Set the new IP */
4763 State->InstPtr.Long = LOWORD(InstPtr);
4764
4765 /* Set the new flags */
4766 if (Size) State->Flags.Long = NewFlags.Long & REAL_MODE_FLAGS_MASK;
4767 else State->Flags.LowWord = NewFlags.LowWord & REAL_MODE_FLAGS_MASK;
4768 State->Flags.AlwaysSet = State->Flags.Vm = TRUE;
4769
4770 /* Load the new segments */
4771 if (!Fast486LoadSegment(State, FAST486_REG_CS, CodeSel)) return FALSE;
4772 if (!Fast486LoadSegment(State, FAST486_REG_SS, StackSel)) return FALSE;
4773 if (!Fast486LoadSegment(State, FAST486_REG_ES, Es)) return FALSE;
4774 if (!Fast486LoadSegment(State, FAST486_REG_DS, Ds)) return FALSE;
4775 if (!Fast486LoadSegment(State, FAST486_REG_FS, Fs)) return FALSE;
4776 if (!Fast486LoadSegment(State, FAST486_REG_GS, Gs)) return FALSE;
4777
4778 return TRUE;
4779 }
4780
4781 /* Load the new CS */
4782 if (!Fast486LoadSegment(State, FAST486_REG_CS, CodeSel))
4783 {
4784 /* Exception occurred */
4785 return FALSE;
4786 }
4787
4788 /* Set EIP */
4789 if (Size) State->InstPtr.Long = InstPtr;
4790 else State->InstPtr.LowWord = LOWORD(InstPtr);
4791
4792 if (GET_SEGMENT_RPL(CodeSel) > Cpl)
4793 {
4794 /* Pop ESP */
4795 if (!Fast486StackPop(State, &StackPtr))
4796 {
4797 /* Exception */
4798 return FALSE;
4799 }
4800
4801 /* Pop SS */
4802 if (!Fast486StackPop(State, &StackSel))
4803 {
4804 /* Exception */
4805 return FALSE;
4806 }
4807
4808 /* Load new SS */
4809 if (!Fast486LoadSegment(State, FAST486_REG_SS, StackSel))
4810 {
4811 /* Exception */
4812 return FALSE;
4813 }
4814
4815 /* Set ESP */
4816 if (Size) State->GeneralRegs[FAST486_REG_ESP].Long = StackPtr;
4817 else State->GeneralRegs[FAST486_REG_ESP].LowWord = LOWORD(StackPtr);
4818 }
4819
4820 /* Set the new flags */
4821 if (Size) State->Flags.Long = NewFlags.Long & PROT_MODE_FLAGS_MASK;
4822 else State->Flags.LowWord = NewFlags.LowWord & PROT_MODE_FLAGS_MASK;
4823 State->Flags.AlwaysSet = TRUE;
4824
4825 /* Set additional flags */
4826 if (Cpl <= State->Flags.Iopl) State->Flags.If = NewFlags.If;
4827 if (Cpl == 0) State->Flags.Iopl = NewFlags.Iopl;
4828
4829 if (GET_SEGMENT_RPL(CodeSel) > Cpl)
4830 {
4831 /* Update the CPL */
4832 Cpl = Fast486GetCurrentPrivLevel(State);
4833
4834 /* Check segment security */
4835 for (i = 0; i < FAST486_NUM_SEG_REGS; i++)
4836 {
4837 /* Don't check CS or SS */
4838 if ((i == FAST486_REG_CS) || (i == FAST486_REG_SS)) continue;
4839
4840 if ((Cpl > State->SegmentRegs[i].Dpl)
4841 && (!State->SegmentRegs[i].Executable
4842 || !State->SegmentRegs[i].DirConf))
4843 {
4844 /* Load the NULL descriptor in the segment */
4845 if (!Fast486LoadSegment(State, i, 0)) return FALSE;
4846 }
4847 }
4848 }
4849 }
4850 else
4851 {
4852 if (Size && (InstPtr & 0xFFFF0000))
4853 {
4854 /* Invalid */
4855 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, 0);
4856 return FALSE;
4857 }
4858
4859 /* Set new EIP */
4860 State->InstPtr.Long = InstPtr;
4861
4862 /* Load new CS */
4863 if (!Fast486LoadSegment(State, FAST486_REG_CS, CodeSel))
4864 {
4865 /* Exception occurred */
4866 return FALSE;
4867 }
4868
4869 /* Set the new flags */
4870 if (Size) State->Flags.Long = NewFlags.Long & REAL_MODE_FLAGS_MASK;
4871 else State->Flags.LowWord = NewFlags.LowWord & REAL_MODE_FLAGS_MASK;
4872 State->Flags.AlwaysSet = TRUE;
4873 }
4874
4875 return TRUE;
4876 }
4877
4878 FAST486_OPCODE_HANDLER(Fast486OpcodeAam)
4879 {
4880 UCHAR Base;
4881 UCHAR Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
4882
4883 NO_LOCK_PREFIX();
4884
4885 /* Fetch the base */
4886 if (!Fast486FetchByte(State, &Base))
4887 {
4888 /* Exception occurred */
4889 return FALSE;
4890 }
4891
4892 /* Check if the base is zero */
4893 if (Base == 0)
4894 {
4895 /* Divide error */
4896 Fast486Exception(State, FAST486_EXCEPTION_DE);
4897 return FALSE;
4898 }
4899
4900 /* Adjust */
4901 State->GeneralRegs[FAST486_REG_EAX].HighByte = Value / Base;
4902 State->GeneralRegs[FAST486_REG_EAX].LowByte = Value %= Base;
4903
4904 /* Update flags */
4905 State->Flags.Af = FALSE;
4906 State->Flags.Zf = (Value == 0);
4907 State->Flags.Sf = ((Value & SIGN_FLAG_BYTE) != 0);
4908 State->Flags.Pf = Fast486CalculateParity(Value);
4909
4910 return TRUE;
4911 }
4912
4913 FAST486_OPCODE_HANDLER(Fast486OpcodeAad)
4914 {
4915 UCHAR Base;
4916 UCHAR Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
4917
4918 NO_LOCK_PREFIX();
4919
4920 /* Fetch the base */
4921 if (!Fast486FetchByte(State, &Base))
4922 {
4923 /* Exception occurred */
4924 return FALSE;
4925 }
4926
4927 /* Adjust */
4928 Value += State->GeneralRegs[FAST486_REG_EAX].HighByte * Base;
4929 State->GeneralRegs[FAST486_REG_EAX].LowWord = Value;
4930
4931 /* Update flags */
4932 State->Flags.Af = FALSE;
4933 State->Flags.Zf = (Value == 0);
4934 State->Flags.Sf = ((Value & SIGN_FLAG_BYTE) != 0);
4935 State->Flags.Pf = Fast486CalculateParity(Value);
4936
4937 return TRUE;
4938 }
4939
4940 FAST486_OPCODE_HANDLER(Fast486OpcodeXlat)
4941 {
4942 UCHAR Value;
4943 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
4944
4945 TOGGLE_ADSIZE(AddressSize);
4946
4947 /* Read a byte from DS:[(E)BX + AL] */
4948 if (!Fast486ReadMemory(State,
4949 (State->PrefixFlags & FAST486_PREFIX_SEG)
4950 ? State->SegmentOverride : FAST486_REG_DS,
4951 (AddressSize ? State->GeneralRegs[FAST486_REG_EBX].Long
4952 : State->GeneralRegs[FAST486_REG_EBX].LowWord)
4953 + State->GeneralRegs[FAST486_REG_EAX].LowByte,
4954 FALSE,
4955 &Value,
4956 sizeof(UCHAR)))
4957 {
4958 /* Exception occurred */
4959 return FALSE;
4960 }
4961
4962 /* Set AL to the result */
4963 State->GeneralRegs[FAST486_REG_EAX].LowByte = Value;
4964
4965 /* Return success */
4966 return TRUE;
4967 }
4968
4969 FAST486_OPCODE_HANDLER(Fast486OpcodeLoop)
4970 {
4971 BOOLEAN Condition;
4972 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4973 CHAR Offset = 0;
4974
4975 /* Make sure this is the right instruction */
4976 ASSERT((Opcode >= 0xE0) && (Opcode <= 0xE2));
4977
4978 NO_LOCK_PREFIX();
4979 TOGGLE_ADSIZE(Size);
4980
4981 if (Size) Condition = ((--State->GeneralRegs[FAST486_REG_ECX].Long) != 0);
4982 else Condition = ((--State->GeneralRegs[FAST486_REG_ECX].LowWord) != 0);
4983
4984 if (Opcode == 0xE0)
4985 {
4986 /* Additional rule for LOOPNZ */
4987 if (State->Flags.Zf) Condition = FALSE;
4988 }
4989
4990 if (Opcode == 0xE1)
4991 {
4992 /* Additional rule for LOOPZ */
4993 if (!State->Flags.Zf) Condition = FALSE;
4994 }
4995
4996 /* Fetch the offset */
4997 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
4998 {
4999 /* An exception occurred */
5000 return FALSE;
5001 }
5002
5003 if (Condition)
5004 {
5005 /* Move the instruction pointer */
5006 if (Size) State->InstPtr.Long += Offset;
5007 else State->InstPtr.LowWord += Offset;
5008 }
5009
5010 return TRUE;
5011 }
5012
5013 FAST486_OPCODE_HANDLER(Fast486OpcodeJecxz)
5014 {
5015 BOOLEAN Condition;
5016 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
5017 CHAR Offset = 0;
5018
5019 /* Make sure this is the right instruction */
5020 ASSERT(Opcode == 0xE3);
5021
5022 NO_LOCK_PREFIX();
5023 TOGGLE_ADSIZE(Size);
5024
5025 if (Size) Condition = (State->GeneralRegs[FAST486_REG_ECX].Long == 0);
5026 else Condition = (State->GeneralRegs[FAST486_REG_ECX].LowWord == 0);
5027
5028 /* Fetch the offset */
5029 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
5030 {
5031 /* An exception occurred */
5032 return FALSE;
5033 }
5034
5035 if (Condition)
5036 {
5037 /* Move the instruction pointer */
5038 if (Size) State->InstPtr.Long += Offset;
5039 else State->InstPtr.LowWord += Offset;
5040 }
5041
5042 return TRUE;
5043 }
5044
5045 FAST486_OPCODE_HANDLER(Fast486OpcodeCall)
5046 {
5047 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
5048
5049 /* Make sure this is the right instruction */
5050 ASSERT(Opcode == 0xE8);
5051
5052 TOGGLE_OPSIZE(Size);
5053 NO_LOCK_PREFIX();
5054
5055 if (Size)
5056 {
5057 LONG Offset = 0;
5058
5059 /* Fetch the offset */
5060 if (!Fast486FetchDword(State, (PULONG)&Offset))
5061 {
5062 /* An exception occurred */
5063 return FALSE;
5064 }
5065
5066 /* Push the current value of the instruction pointer */
5067 if (!Fast486StackPush(State, State->InstPtr.Long))
5068 {
5069 /* Exception occurred */
5070 return FALSE;
5071 }
5072
5073 /* Move the instruction pointer */
5074 State->InstPtr.Long += Offset;
5075 }
5076 else
5077 {
5078 SHORT Offset = 0;
5079
5080 /* Fetch the offset */
5081 if (!Fast486FetchWord(State, (PUSHORT)&Offset))
5082 {
5083 /* An exception occurred */
5084 return FALSE;
5085 }
5086
5087 /* Push the current value of the instruction pointer */
5088 if (!Fast486StackPush(State, State->InstPtr.Long))
5089 {
5090 /* Exception occurred */
5091 return FALSE;
5092 }
5093
5094 /* Move the instruction pointer */
5095 State->InstPtr.LowWord += Offset;
5096 }
5097
5098 return TRUE;
5099 }
5100
5101 FAST486_OPCODE_HANDLER(Fast486OpcodeJmp)
5102 {
5103 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
5104
5105 /* Make sure this is the right instruction */
5106 ASSERT(Opcode == 0xE9);
5107
5108 TOGGLE_OPSIZE(Size);
5109 NO_LOCK_PREFIX();
5110
5111 if (Size)
5112 {
5113 LONG Offset = 0;
5114
5115 /* Fetch the offset */
5116 if (!Fast486FetchDword(State, (PULONG)&Offset))
5117 {
5118 /* An exception occurred */
5119 return FALSE;
5120 }
5121
5122 /* Move the instruction pointer */
5123 State->InstPtr.Long += Offset;
5124 }
5125 else
5126 {
5127 SHORT Offset = 0;
5128
5129 /* Fetch the offset */
5130 if (!Fast486FetchWord(State, (PUSHORT)&Offset))
5131 {
5132 /* An exception occurred */
5133 return FALSE;
5134 }
5135
5136 /* Move the instruction pointer */
5137 State->InstPtr.Long += Offset;
5138
5139 /* Clear the top half of EIP */
5140 State->InstPtr.Long &= 0xFFFF;
5141 }
5142
5143 return TRUE;
5144 }
5145
5146 FAST486_OPCODE_HANDLER(Fast486OpcodeJmpAbs)
5147 {
5148 USHORT Segment = 0;
5149 ULONG Offset = 0;
5150 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
5151
5152 /* Make sure this is the right instruction */
5153 ASSERT(Opcode == 0xEA);
5154
5155 TOGGLE_OPSIZE(Size);
5156 NO_LOCK_PREFIX();
5157
5158 /* Fetch the offset */
5159 if (Size)
5160 {
5161 if (!Fast486FetchDword(State, &Offset))
5162 {
5163 /* Exception occurred */
5164 return FALSE;
5165 }
5166 }
5167 else
5168 {
5169 if (!Fast486FetchWord(State, (PUSHORT)&Offset))
5170 {
5171 /* Exception occurred */
5172 return FALSE;
5173 }
5174 }
5175
5176 /* Fetch the segment */
5177 if (!Fast486FetchWord(State, &Segment))
5178 {
5179 /* Exception occurred */
5180 return FALSE;
5181 }
5182
5183 /* Load the new CS */
5184 if (!Fast486LoadSegment(State, FAST486_REG_CS, Segment))
5185 {
5186 /* Exception occurred */
5187 return FALSE;
5188 }
5189
5190 /* Load new EIP */
5191 State->InstPtr.Long = Offset;
5192
5193 return TRUE;
5194 }
5195
5196 FAST486_OPCODE_HANDLER(Fast486OpcodeMovAlOffset)
5197 {
5198 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5199 ULONG Offset;
5200
5201 /* Make sure this is the right instruction */
5202 ASSERT(Opcode == 0xA0);
5203
5204 TOGGLE_ADSIZE(AddressSize);
5205
5206 if (AddressSize)
5207 {
5208 if (!Fast486FetchDword(State, &Offset))
5209 {
5210 /* Exception occurred */
5211 return FALSE;
5212 }
5213 }
5214 else
5215 {
5216 USHORT WordOffset;
5217
5218 if (!Fast486FetchWord(State, &WordOffset))
5219 {
5220 /* Exception occurred */
5221 return FALSE;
5222 }
5223
5224 Offset = (ULONG)WordOffset;
5225 }
5226
5227 /* Read from memory */
5228 return Fast486ReadMemory(State,
5229 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5230 State->SegmentOverride : FAST486_REG_DS,
5231 Offset,
5232 FALSE,
5233 &State->GeneralRegs[FAST486_REG_EAX].LowByte,
5234 sizeof(UCHAR));
5235 }
5236
5237 FAST486_OPCODE_HANDLER(Fast486OpcodeMovEaxOffset)
5238 {
5239 BOOLEAN OperandSize, AddressSize;
5240
5241 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5242
5243 /* Make sure this is the right instruction */
5244 ASSERT(Opcode == 0xA1);
5245
5246 TOGGLE_OPSIZE(OperandSize);
5247 TOGGLE_ADSIZE(AddressSize);
5248
5249 if (AddressSize)
5250 {
5251 ULONG Offset;
5252
5253 if (!Fast486FetchDword(State, &Offset))
5254 {
5255 /* Exception occurred */
5256 return FALSE;
5257 }
5258
5259 /* Read from memory */
5260 if (OperandSize)
5261 {
5262 return Fast486ReadMemory(State,
5263 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5264 State->SegmentOverride : FAST486_REG_DS,
5265 Offset,
5266 FALSE,
5267 &State->GeneralRegs[FAST486_REG_EAX].Long,
5268 sizeof(ULONG));
5269 }
5270 else
5271 {
5272 return Fast486ReadMemory(State,
5273 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5274 State->SegmentOverride : FAST486_REG_DS,
5275 Offset,
5276 FALSE,
5277 &State->GeneralRegs[FAST486_REG_EAX].LowWord,
5278 sizeof(USHORT));
5279 }
5280 }
5281 else
5282 {
5283 USHORT Offset;
5284
5285 if (!Fast486FetchWord(State, &Offset))
5286 {
5287 /* Exception occurred */
5288 return FALSE;
5289 }
5290
5291 /* Read from memory */
5292 if (OperandSize)
5293 {
5294 return Fast486ReadMemory(State,
5295 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5296 State->SegmentOverride : FAST486_REG_DS,
5297 Offset,
5298 FALSE,
5299 &State->GeneralRegs[FAST486_REG_EAX].Long,
5300 sizeof(ULONG));
5301 }
5302 else
5303 {
5304 return Fast486ReadMemory(State,
5305 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5306 State->SegmentOverride : FAST486_REG_DS,
5307 Offset,
5308 FALSE,
5309 &State->GeneralRegs[FAST486_REG_EAX].LowWord,
5310 sizeof(USHORT));
5311 }
5312 }
5313 }
5314
5315 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetAl)
5316 {
5317 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5318 ULONG Offset;
5319
5320 /* Make sure this is the right instruction */
5321 ASSERT(Opcode == 0xA2);
5322
5323 TOGGLE_ADSIZE(AddressSize);
5324
5325 if (AddressSize)
5326 {
5327 if (!Fast486FetchDword(State, &Offset))
5328 {
5329 /* Exception occurred */
5330 return FALSE;
5331 }
5332 }
5333 else
5334 {
5335 USHORT WordOffset;
5336
5337 if (!Fast486FetchWord(State, &WordOffset))
5338 {
5339 /* Exception occurred */
5340 return FALSE;
5341 }
5342
5343 Offset = (ULONG)WordOffset;
5344 }
5345
5346 /* Write to memory */
5347 return Fast486WriteMemory(State,
5348 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5349 State->SegmentOverride : FAST486_REG_DS,
5350 Offset,
5351 &State->GeneralRegs[FAST486_REG_EAX].LowByte,
5352 sizeof(UCHAR));
5353 }
5354
5355 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetEax)
5356 {
5357 BOOLEAN OperandSize, AddressSize;
5358
5359 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5360
5361 /* Make sure this is the right instruction */
5362 ASSERT(Opcode == 0xA3);
5363
5364 TOGGLE_OPSIZE(OperandSize);
5365 TOGGLE_ADSIZE(AddressSize);
5366
5367 if (AddressSize)
5368 {
5369 ULONG Offset;
5370
5371 if (!Fast486FetchDword(State, &Offset))
5372 {
5373 /* Exception occurred */
5374 return FALSE;
5375 }
5376
5377 /* Write to memory */
5378 if (OperandSize)
5379 {
5380 return Fast486WriteMemory(State,
5381 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5382 State->SegmentOverride : FAST486_REG_DS,
5383 Offset,
5384 &State->GeneralRegs[FAST486_REG_EAX].Long,
5385 sizeof(ULONG));
5386 }
5387 else
5388 {
5389 return Fast486WriteMemory(State,
5390 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5391 State->SegmentOverride : FAST486_REG_DS,
5392 Offset,
5393 &State->GeneralRegs[FAST486_REG_EAX].LowWord,
5394 sizeof(USHORT));
5395 }
5396 }
5397 else
5398 {
5399 USHORT Offset;
5400
5401 if (!Fast486FetchWord(State, &Offset))
5402 {
5403 /* Exception occurred */
5404 return FALSE;
5405 }
5406
5407 /* Write to memory */
5408 if (OperandSize)
5409 {
5410 return Fast486WriteMemory(State,
5411 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5412 State->SegmentOverride : FAST486_REG_DS,
5413 Offset,
5414 &State->GeneralRegs[FAST486_REG_EAX].Long,
5415 sizeof(ULONG));
5416 }
5417 else
5418 {
5419 return Fast486WriteMemory(State,
5420 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5421 State->SegmentOverride : FAST486_REG_DS,
5422 Offset,
5423 &State->GeneralRegs[FAST486_REG_EAX].LowWord,
5424 sizeof(USHORT));
5425 }
5426 }
5427 }
5428
5429 FAST486_OPCODE_HANDLER(Fast486OpcodeSalc)
5430 {
5431 /* Make sure this is the right instruction */
5432 ASSERT(Opcode == 0xD6);
5433
5434 NO_LOCK_PREFIX();
5435
5436 /* Set all the bits of AL to CF */
5437 State->GeneralRegs[FAST486_REG_EAX].LowByte = State->Flags.Cf ? 0xFF : 0x00;
5438
5439 return TRUE;
5440 }
5441
5442 FAST486_OPCODE_HANDLER(Fast486OpcodeMovs)
5443 {
5444 ULONG Data, DataSize;
5445 BOOLEAN OperandSize, AddressSize;
5446 FAST486_SEG_REGS Segment = FAST486_REG_DS;
5447
5448 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5449
5450 /* Make sure this is the right instruction */
5451 ASSERT((Opcode & 0xFE) == 0xA4);
5452
5453 TOGGLE_OPSIZE(OperandSize);
5454 TOGGLE_ADSIZE(AddressSize);
5455
5456 if (State->PrefixFlags & FAST486_PREFIX_SEG)
5457 {
5458 /* Use the override segment instead of DS */
5459 Segment = State->SegmentOverride;
5460 }
5461
5462 if (State->PrefixFlags & (FAST486_PREFIX_REP | FAST486_PREFIX_REPNZ))
5463 {
5464 if ((AddressSize && (State->GeneralRegs[FAST486_REG_ECX].Long == 0))
5465 || (!AddressSize && (State->GeneralRegs[FAST486_REG_ECX].LowWord == 0)))
5466 {
5467 /* Do nothing */
5468 return TRUE;
5469 }
5470 }
5471
5472 /* Calculate the size */
5473 if (Opcode == 0xA4) DataSize = sizeof(UCHAR);
5474 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
5475
5476 /* Read from the source operand */
5477 if (!Fast486ReadMemory(State,
5478 Segment,
5479 AddressSize ? State->GeneralRegs[FAST486_REG_ESI].Long
5480 : State->GeneralRegs[FAST486_REG_ESI].LowWord,
5481 FALSE,
5482 &Data,
5483 DataSize))
5484 {
5485 /* Exception occurred */
5486 return FALSE;
5487 }
5488
5489 /* Write to the destination operand */
5490 if (!Fast486WriteMemory(State,
5491 FAST486_REG_ES,
5492 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
5493 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
5494 &Data,
5495 DataSize))
5496 {
5497 /* Exception occurred */
5498 return FALSE;
5499 }
5500
5501 /* Increment/decrement ESI and EDI */
5502 if (AddressSize)
5503 {
5504 if (!State->Flags.Df)
5505 {
5506 State->GeneralRegs[FAST486_REG_ESI].Long += DataSize;
5507 State->GeneralRegs[FAST486_REG_EDI].Long += DataSize;
5508 }
5509 else
5510 {
5511 State->GeneralRegs[FAST486_REG_ESI].Long -= DataSize;
5512 State->GeneralRegs[FAST486_REG_EDI].Long -= DataSize;
5513 }
5514 }
5515 else
5516 {
5517 if (!State->Flags.Df)
5518 {
5519 State->GeneralRegs[FAST486_REG_ESI].LowWord += DataSize;
5520 State->GeneralRegs[FAST486_REG_EDI].LowWord += DataSize;
5521 }
5522 else
5523 {
5524 State->GeneralRegs[FAST486_REG_ESI].LowWord -= DataSize;
5525 State->GeneralRegs[FAST486_REG_EDI].LowWord -= DataSize;
5526 }
5527 }
5528
5529 // FIXME: This method is slow!
5530 if (State->PrefixFlags & (FAST486_PREFIX_REP | FAST486_PREFIX_REPNZ))
5531 {
5532 if (AddressSize)
5533 {
5534 if (--State->GeneralRegs[FAST486_REG_ECX].Long)
5535 {
5536 /* Repeat the instruction */
5537 State->InstPtr = State->SavedInstPtr;
5538 }
5539 }
5540 else
5541 {
5542 if (--State->GeneralRegs[FAST486_REG_ECX].LowWord)
5543 {
5544 /* Repeat the instruction */
5545 State->InstPtr = State->SavedInstPtr;
5546 }
5547 }
5548 }
5549
5550 /* Return success */
5551 return TRUE;
5552 }
5553
5554 FAST486_OPCODE_HANDLER(Fast486OpcodeCmps)
5555 {
5556 ULONG FirstValue = 0, SecondValue = 0, Result;
5557 ULONG DataSize, DataMask, SignFlag;
5558 BOOLEAN OperandSize, AddressSize;
5559 FAST486_SEG_REGS Segment = FAST486_REG_DS;
5560
5561 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5562
5563 /* Make sure this is the right instruction */
5564 ASSERT((Opcode & 0xFE) == 0xA6);
5565
5566 TOGGLE_OPSIZE(OperandSize);
5567 TOGGLE_ADSIZE(AddressSize);
5568
5569 if (State->PrefixFlags & FAST486_PREFIX_SEG)
5570 {
5571 /* Use the override segment instead of DS */
5572 Segment = State->SegmentOverride;
5573 }
5574
5575 if ((State->PrefixFlags & FAST486_PREFIX_REP)
5576 || (State->PrefixFlags & FAST486_PREFIX_REPNZ))
5577 {
5578 if ((AddressSize && (State->GeneralRegs[FAST486_REG_ECX].Long == 0))
5579 || (!AddressSize && (State->GeneralRegs[FAST486_REG_ECX].LowWord == 0)))
5580 {
5581 /* Do nothing */
5582 return TRUE;
5583 }
5584 }
5585
5586 /* Calculate the size */
5587 if (Opcode == 0xA6) DataSize = sizeof(UCHAR);
5588 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
5589
5590 /* Calculate the mask and sign flag */
5591 SignFlag = 1 << ((DataSize * 8) - 1);
5592 DataMask = SignFlag | (SignFlag - 1);
5593
5594 /* Read from the first source operand */
5595 if (!Fast486ReadMemory(State,
5596 Segment,
5597 AddressSize ? State->GeneralRegs[FAST486_REG_ESI].Long
5598 : State->GeneralRegs[FAST486_REG_ESI].LowWord,
5599 FALSE,
5600 &FirstValue,
5601 DataSize))
5602 {
5603 /* Exception occurred */
5604 return FALSE;
5605 }
5606
5607 /* Read from the second source operand */
5608 if (!Fast486ReadMemory(State,
5609 FAST486_REG_ES,
5610 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
5611 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
5612 FALSE,
5613 &SecondValue,
5614 DataSize))
5615 {
5616 /* Exception occurred */
5617 return FALSE;
5618 }
5619
5620 /* Calculate the result */
5621 FirstValue &= DataMask;
5622 SecondValue &= DataMask;
5623 Result = (FirstValue - SecondValue) & DataMask;
5624
5625 /* Update the flags */
5626 State->Flags.Cf = (FirstValue < SecondValue);
5627 State->Flags.Of = ((FirstValue & SignFlag) != (SecondValue & SignFlag))
5628 && ((FirstValue & SignFlag) != (Result & SignFlag));
5629 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
5630 State->Flags.Zf = (Result == 0);
5631 State->Flags.Sf = ((Result & SignFlag) != 0);
5632 State->Flags.Pf = Fast486CalculateParity(Result);
5633
5634 /* Increment/decrement ESI and EDI */
5635 if (AddressSize)
5636 {
5637 if (!State->Flags.Df)
5638 {
5639 State->GeneralRegs[FAST486_REG_ESI].Long += DataSize;
5640 State->GeneralRegs[FAST486_REG_EDI].Long += DataSize;
5641 }
5642 else
5643 {
5644 State->GeneralRegs[FAST486_REG_ESI].Long -= DataSize;
5645 State->GeneralRegs[FAST486_REG_EDI].Long -= DataSize;
5646 }
5647 }
5648 else
5649 {
5650 if (!State->Flags.Df)
5651 {
5652 State->GeneralRegs[FAST486_REG_ESI].LowWord += DataSize;
5653 State->GeneralRegs[FAST486_REG_EDI].LowWord += DataSize;
5654 }
5655 else
5656 {
5657 State->GeneralRegs[FAST486_REG_ESI].LowWord -= DataSize;
5658 State->GeneralRegs[FAST486_REG_EDI].LowWord -= DataSize;
5659 }
5660 }
5661
5662 // FIXME: This method is slow!
5663 if ((State->PrefixFlags & FAST486_PREFIX_REP)
5664 || (State->PrefixFlags & FAST486_PREFIX_REPNZ))
5665 {
5666 BOOLEAN Repeat = TRUE;
5667
5668 if (AddressSize)
5669 {
5670 if ((--State->GeneralRegs[FAST486_REG_ECX].Long) == 0)
5671 {
5672 /* ECX is 0 */
5673 Repeat = FALSE;
5674 }
5675 }
5676 else
5677 {
5678 if ((--State->GeneralRegs[FAST486_REG_ECX].LowWord) == 0)
5679 {
5680 /* CX is 0 */
5681 Repeat = FALSE;
5682 }
5683 }
5684
5685 if (((State->PrefixFlags & FAST486_PREFIX_REP) && !State->Flags.Zf)
5686 || ((State->PrefixFlags & FAST486_PREFIX_REPNZ) && State->Flags.Zf))
5687 {
5688 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
5689 Repeat = FALSE;
5690 }
5691
5692 if (Repeat)
5693 {
5694 /* Repeat the instruction */
5695 State->InstPtr = State->SavedInstPtr;
5696 }
5697 }
5698
5699 /* Return success */
5700 return TRUE;
5701 }
5702
5703 FAST486_OPCODE_HANDLER(Fast486OpcodeStos)
5704 {
5705 ULONG DataSize;
5706 BOOLEAN OperandSize, AddressSize;
5707
5708 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5709
5710 /* Make sure this is the right instruction */
5711 ASSERT((Opcode & 0xFE) == 0xAA);
5712
5713 TOGGLE_OPSIZE(OperandSize);
5714 TOGGLE_ADSIZE(AddressSize);
5715
5716 /* Calculate the size */
5717 if (Opcode == 0xAA) DataSize = sizeof(UCHAR);
5718 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
5719
5720 if (State->PrefixFlags & (FAST486_PREFIX_REP | FAST486_PREFIX_REPNZ))
5721 {
5722 UCHAR Block[STRING_BLOCK_SIZE];
5723 ULONG Count = AddressSize ? State->GeneralRegs[FAST486_REG_ECX].Long
5724 : State->GeneralRegs[FAST486_REG_ECX].LowWord;
5725
5726 /* Fill the memory block with the data */
5727 if (DataSize == sizeof(UCHAR))
5728 {
5729 RtlFillMemory(Block, sizeof(Block), State->GeneralRegs[FAST486_REG_EAX].LowByte);
5730 }
5731 else
5732 {
5733 ULONG i;
5734
5735 for (i = 0; i < STRING_BLOCK_SIZE / DataSize; i++)
5736 {
5737 if (DataSize == sizeof(USHORT))
5738 {
5739 ((PUSHORT)Block)[i] = State->GeneralRegs[FAST486_REG_EAX].LowWord;
5740 }
5741 else
5742 {
5743 ((PULONG)Block)[i] = State->GeneralRegs[FAST486_REG_EAX].Long;
5744 }
5745 }
5746 }
5747
5748 /* Transfer until finished */
5749 while (Count)
5750 {
5751 ULONG Processed = min(Count, STRING_BLOCK_SIZE / DataSize);
5752
5753 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
5754 if (!AddressSize)
5755 {
5756 ULONG MaxBytes = State->Flags.Df
5757 ? (ULONG)State->GeneralRegs[FAST486_REG_EDI].LowWord
5758 : (0x10000 - (ULONG)State->GeneralRegs[FAST486_REG_EDI].LowWord);
5759
5760 Processed = min(Processed, MaxBytes / DataSize);
5761 if (Processed == 0) Processed = 1;
5762 }
5763
5764 if (State->Flags.Df)
5765 {
5766 /* Set EDI to the starting location */
5767 if (AddressSize) State->GeneralRegs[FAST486_REG_EDI].Long -= (Processed - 1) * DataSize;
5768 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= (Processed - 1) * DataSize;
5769 }
5770
5771 /* Write to memory */
5772 if (!Fast486WriteMemory(State,
5773 FAST486_REG_ES,
5774 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
5775 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
5776 Block,
5777 Processed * DataSize))
5778 {
5779 /* Set ECX */
5780 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = Count;
5781 else State->GeneralRegs[FAST486_REG_ECX].LowWord = LOWORD(Count);
5782
5783 /* Exception occurred */
5784 return FALSE;
5785 }
5786
5787 if (!State->Flags.Df)
5788 {
5789 /* Increase EDI by the number of bytes transfered */
5790 if (AddressSize) State->GeneralRegs[FAST486_REG_EDI].Long += Processed * DataSize;
5791 else State->GeneralRegs[FAST486_REG_EDI].LowWord += Processed * DataSize;
5792 }
5793 else
5794 {
5795 /* Reduce EDI */
5796 if (AddressSize) State->GeneralRegs[FAST486_REG_EDI].Long -= DataSize;
5797 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= DataSize;
5798 }
5799
5800 /* Reduce the total count by the number processed in this run */
5801 Count -= Processed;
5802 }
5803
5804 /* Clear ECX */
5805 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = 0;
5806 else State->GeneralRegs[FAST486_REG_ECX].LowWord = 0;
5807 }
5808 else
5809 {
5810 /* Write to the destination operand */
5811 if (!Fast486WriteMemory(State,
5812 FAST486_REG_ES,
5813 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
5814 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
5815 &State->GeneralRegs[FAST486_REG_EAX].Long,
5816 DataSize))
5817 {
5818 /* Exception occurred */
5819 return FALSE;
5820 }
5821
5822 /* Increment/decrement EDI */
5823 if (AddressSize)
5824 {
5825 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_EDI].Long += DataSize;
5826 else State->GeneralRegs[FAST486_REG_EDI].Long -= DataSize;
5827 }
5828 else
5829 {
5830 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_EDI].LowWord += DataSize;
5831 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= DataSize;
5832 }
5833 }
5834
5835 /* Return success */
5836 return TRUE;
5837 }
5838
5839 FAST486_OPCODE_HANDLER(Fast486OpcodeLods)
5840 {
5841 ULONG DataSize;
5842 BOOLEAN OperandSize, AddressSize;
5843 FAST486_SEG_REGS Segment = FAST486_REG_DS;
5844
5845 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5846
5847 /* Make sure this is the right instruction */
5848 ASSERT((Opcode & 0xFE) == 0xAC);
5849
5850 TOGGLE_OPSIZE(OperandSize);
5851 TOGGLE_ADSIZE(AddressSize);
5852
5853 if (State->PrefixFlags & FAST486_PREFIX_SEG)
5854 {
5855 /* Use the override segment instead of DS */
5856 Segment = State->SegmentOverride;
5857 }
5858
5859 /* Calculate the size */
5860 if (Opcode == 0xAC) DataSize = sizeof(UCHAR);
5861 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
5862
5863 if (State->PrefixFlags & (FAST486_PREFIX_REP | FAST486_PREFIX_REPNZ))
5864 {
5865 ULONG Count = AddressSize ? State->GeneralRegs[FAST486_REG_ECX].Long
5866 : State->GeneralRegs[FAST486_REG_ECX].LowWord;
5867
5868 /* If the count is 0, do nothing */
5869 if (Count == 0) return TRUE;
5870
5871 /* Only the last entry will be loaded */
5872 if (!State->Flags.Df)
5873 {
5874 if (AddressSize) State->GeneralRegs[FAST486_REG_ESI].Long += (Count - 1) * DataSize;
5875 else State->GeneralRegs[FAST486_REG_ESI].LowWord += (Count - 1) * DataSize;
5876 }
5877 else
5878 {
5879 if (AddressSize) State->GeneralRegs[FAST486_REG_ESI].Long -= (Count - 1) * DataSize;
5880 else State->GeneralRegs[FAST486_REG_ESI].LowWord -= (Count - 1) * DataSize;
5881 }
5882
5883 /* Clear ECX */
5884 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = 0;
5885 else State->GeneralRegs[FAST486_REG_ECX].LowWord = 0;
5886 }
5887
5888 /* Read from the source operand */
5889 if (!Fast486ReadMemory(State,
5890 Segment,
5891 AddressSize ? State->GeneralRegs[FAST486_REG_ESI].Long
5892 : State->GeneralRegs[FAST486_REG_ESI].LowWord,
5893 FALSE,
5894 &State->GeneralRegs[FAST486_REG_EAX].Long,
5895 DataSize))
5896 {
5897 /* Exception occurred */
5898 return FALSE;
5899 }
5900
5901 /* Increment/decrement ESI */
5902 if (AddressSize)
5903 {
5904 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_ESI].Long += DataSize;
5905 else State->GeneralRegs[FAST486_REG_ESI].Long -= DataSize;
5906 }
5907 else
5908 {
5909 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_ESI].LowWord += DataSize;
5910 else State->GeneralRegs[FAST486_REG_ESI].LowWord -= DataSize;
5911 }
5912
5913 /* Return success */
5914 return TRUE;
5915 }
5916
5917 FAST486_OPCODE_HANDLER(Fast486OpcodeScas)
5918 {
5919 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
5920 ULONG SecondValue = 0;
5921 ULONG Result;
5922 ULONG DataSize, DataMask, SignFlag;
5923 BOOLEAN OperandSize, AddressSize;
5924
5925 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5926
5927 /* Make sure this is the right instruction */
5928 ASSERT((Opcode & 0xFE) == 0xAE);
5929
5930 TOGGLE_OPSIZE(OperandSize);
5931 TOGGLE_ADSIZE(AddressSize);
5932
5933 if ((State->PrefixFlags & FAST486_PREFIX_REP)
5934 || (State->PrefixFlags & FAST486_PREFIX_REPNZ))
5935 {
5936 if ((AddressSize && (State->GeneralRegs[FAST486_REG_ECX].Long == 0))
5937 || (!AddressSize && (State->GeneralRegs[FAST486_REG_ECX].LowWord == 0)))
5938 {
5939 /* Do nothing */
5940 return TRUE;
5941 }
5942 }
5943
5944 /* Calculate the size */
5945 if (Opcode == 0xAE) DataSize = sizeof(UCHAR);
5946 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
5947
5948 /* Calculate the mask and sign flag */
5949 SignFlag = 1 << ((DataSize * 8) - 1);
5950 DataMask = SignFlag | (SignFlag - 1);
5951
5952 /* Read from the source operand */
5953 if (!Fast486ReadMemory(State,
5954 FAST486_REG_ES,
5955 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
5956 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
5957 FALSE,
5958 &SecondValue,
5959 DataSize))
5960 {
5961 /* Exception occurred */
5962 return FALSE;
5963 }
5964
5965 /* Calculate the result */
5966 FirstValue &= DataMask;
5967 SecondValue &= DataMask;
5968 Result = (FirstValue - SecondValue) & DataMask;
5969
5970 /* Update the flags */
5971 State->Flags.Cf = (FirstValue < SecondValue);
5972 State->Flags.Of = ((FirstValue & SignFlag) != (SecondValue & SignFlag))
5973 && ((FirstValue & SignFlag) != (Result & SignFlag));
5974 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
5975 State->Flags.Zf = (Result == 0);
5976 State->Flags.Sf = ((Result & SignFlag) != 0);
5977 State->Flags.Pf = Fast486CalculateParity(Result);
5978
5979 /* Increment/decrement EDI */
5980 if (AddressSize)
5981 {
5982 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_EDI].Long += DataSize;
5983 else State->GeneralRegs[FAST486_REG_EDI].Long -= DataSize;
5984 }
5985 else
5986 {
5987 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_EDI].LowWord += DataSize;
5988 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= DataSize;
5989 }
5990
5991 // FIXME: This method is slow!
5992 if ((State->PrefixFlags & FAST486_PREFIX_REP)
5993 || (State->PrefixFlags & FAST486_PREFIX_REPNZ))
5994 {
5995 BOOLEAN Repeat = TRUE;
5996
5997 if (AddressSize)
5998 {
5999 if ((--State->GeneralRegs[FAST486_REG_ECX].Long) == 0)
6000 {
6001 /* ECX is 0 */
6002 Repeat = FALSE;
6003 }
6004 }
6005 else
6006 {
6007 if ((--State->GeneralRegs[FAST486_REG_ECX].LowWord) == 0)
6008 {
6009 /* CX is 0 */
6010 Repeat = FALSE;
6011 }
6012 }
6013
6014 if (((State->PrefixFlags & FAST486_PREFIX_REP) && !State->Flags.Zf)
6015 || ((State->PrefixFlags & FAST486_PREFIX_REPNZ) && State->Flags.Zf))
6016 {
6017 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
6018 Repeat = FALSE;
6019 }
6020
6021 if (Repeat)
6022 {
6023 /* Repeat the instruction */
6024 State->InstPtr = State->SavedInstPtr;
6025 }
6026 }
6027
6028 /* Return success */
6029 return TRUE;
6030 }
6031
6032 FAST486_OPCODE_HANDLER(Fast486OpcodeIns)
6033 {
6034 ULONG DataSize;
6035 BOOLEAN OperandSize, AddressSize;
6036
6037 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
6038
6039 /* Make sure this is the right instruction */
6040 ASSERT((Opcode & 0xFE) == 0x6C);
6041
6042 TOGGLE_OPSIZE(OperandSize);
6043 TOGGLE_ADSIZE(AddressSize);
6044
6045 /* Calculate the size */
6046 if (Opcode == 0x6C) DataSize = sizeof(UCHAR);
6047 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
6048
6049 if (State->PrefixFlags & (FAST486_PREFIX_REP | FAST486_PREFIX_REPNZ))
6050 {
6051 UCHAR Block[STRING_BLOCK_SIZE];
6052 ULONG Count = AddressSize ? State->GeneralRegs[FAST486_REG_ECX].Long
6053 : State->GeneralRegs[FAST486_REG_ECX].LowWord;
6054
6055 /* Clear the memory block */
6056 RtlZeroMemory(Block, sizeof(Block));
6057
6058 /* Transfer until finished */
6059 while (Count)
6060 {
6061 ULONG Processed = min(Count, STRING_BLOCK_SIZE / DataSize);
6062
6063 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
6064 if (!AddressSize)
6065 {
6066 ULONG MaxBytes = State->Flags.Df
6067 ? (ULONG)State->GeneralRegs[FAST486_REG_EDI].LowWord
6068 : (0x10000 - (ULONG)State->GeneralRegs[FAST486_REG_EDI].LowWord);
6069
6070 Processed = min(Processed, MaxBytes / DataSize);
6071 if (Processed == 0) Processed = 1;
6072 }
6073
6074 /* Read from the I/O port */
6075 State->IoReadCallback(State,
6076 State->GeneralRegs[FAST486_REG_EDX].LowWord,
6077 Block,
6078 Processed,
6079 DataSize);
6080
6081 if (State->Flags.Df)
6082 {
6083 ULONG i, j;
6084
6085 /* Reduce EDI by the number of bytes to transfer */
6086 if (AddressSize) State->GeneralRegs[FAST486_REG_EDI].Long -= Processed * DataSize;
6087 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= Processed * DataSize;
6088
6089 /* Reverse the block data */
6090 for (i = 0; i < Processed / 2; i++)
6091 {
6092 /* Swap the values */
6093 for (j = 0; j < DataSize; j++)
6094 {
6095 UCHAR Temp = Block[i * DataSize + j];
6096 Block[i * DataSize + j] = Block[(Processed - i - 1) * DataSize + j];
6097 Block[(Processed - i - 1) * DataSize + j] = Temp;
6098 }
6099 }
6100 }
6101
6102 /* Write to memory */
6103 if (!Fast486WriteMemory(State,
6104 FAST486_REG_ES,
6105 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
6106 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
6107 Block,
6108 Processed * DataSize))
6109 {
6110 /* Set ECX */
6111 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = Count;
6112 else State->GeneralRegs[FAST486_REG_ECX].LowWord = LOWORD(Count);
6113
6114 /* Exception occurred */
6115 return FALSE;
6116 }
6117
6118 if (!State->Flags.Df)
6119 {
6120 /* Increase EDI by the number of bytes transfered */
6121 if (AddressSize) State->GeneralRegs[FAST486_REG_EDI].Long += Processed * DataSize;
6122 else State->GeneralRegs[FAST486_REG_EDI].LowWord += Processed * DataSize;
6123 }
6124
6125 /* Reduce the total count by the number processed in this run */
6126 Count -= Processed;
6127 }
6128
6129 /* Clear ECX */
6130 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = 0;
6131 else State->GeneralRegs[FAST486_REG_ECX].LowWord = 0;
6132 }
6133 else
6134 {
6135 ULONG Data = 0;
6136
6137 /* Read from the I/O port */
6138 State->IoReadCallback(State,
6139 State->GeneralRegs[FAST486_REG_EDX].LowWord,
6140 &Data,
6141 1,
6142 DataSize);
6143
6144 /* Write to the destination operand */
6145 if (!Fast486WriteMemory(State,
6146 FAST486_REG_ES,
6147 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
6148 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
6149 &Data,
6150 DataSize))
6151 {
6152 /* Exception occurred */
6153 return FALSE;
6154 }
6155
6156 /* Increment/decrement EDI */
6157 if (AddressSize)
6158 {
6159 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_EDI].Long += DataSize;
6160 else State->GeneralRegs[FAST486_REG_EDI].Long -= DataSize;
6161 }
6162 else
6163 {
6164 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_EDI].LowWord += DataSize;
6165 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= DataSize;
6166 }
6167 }
6168
6169 /* Return success */
6170 return TRUE;
6171 }
6172
6173 FAST486_OPCODE_HANDLER(Fast486OpcodeOuts)
6174 {
6175 ULONG DataSize;
6176 BOOLEAN OperandSize, AddressSize;
6177
6178 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
6179
6180 /* Make sure this is the right instruction */
6181 ASSERT((Opcode & 0xFE) == 0x6E);
6182
6183 TOGGLE_OPSIZE(OperandSize);
6184 TOGGLE_ADSIZE(AddressSize);
6185
6186 /* Calculate the size */
6187 if (Opcode == 0x6E) DataSize = sizeof(UCHAR);
6188 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
6189
6190 if (State->PrefixFlags & (FAST486_PREFIX_REP | FAST486_PREFIX_REPNZ))
6191 {
6192 UCHAR Block[STRING_BLOCK_SIZE];
6193 ULONG Count = AddressSize ? State->GeneralRegs[FAST486_REG_ECX].Long
6194 : State->GeneralRegs[FAST486_REG_ECX].LowWord;
6195
6196 /* Clear the memory block */
6197 RtlZeroMemory(Block, sizeof(Block));
6198
6199 /* Transfer until finished */
6200 while (Count)
6201 {
6202 ULONG Processed = min(Count, STRING_BLOCK_SIZE / DataSize);
6203
6204 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
6205 if (!AddressSize)
6206 {
6207 ULONG MaxBytes = State->Flags.Df
6208 ? (ULONG)State->GeneralRegs[FAST486_REG_ESI].LowWord
6209 : (0x10000 - (ULONG)State->GeneralRegs[FAST486_REG_ESI].LowWord);
6210
6211 Processed = min(Processed, MaxBytes / DataSize);
6212 if (Processed == 0) Processed = 1;
6213 }
6214
6215 /* Read from memory */
6216 if (!Fast486ReadMemory(State,
6217 (State->PrefixFlags & FAST486_PREFIX_SEG)
6218 ? State->SegmentOverride : FAST486_REG_DS,
6219 AddressSize ? State->GeneralRegs[FAST486_REG_ESI].Long
6220 : State->GeneralRegs[FAST486_REG_ESI].LowWord,
6221 FALSE,
6222 Block,
6223 Processed * DataSize))
6224 {
6225 /* Set ECX */
6226 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = Count;
6227 else State->GeneralRegs[FAST486_REG_ECX].LowWord = LOWORD(Count);
6228
6229 /* Exception occurred */
6230 return FALSE;
6231 }
6232
6233 if (State->Flags.Df)
6234 {
6235 ULONG i, j;
6236
6237 /* Reduce ESI by the number of bytes to transfer */
6238 if (AddressSize) State->GeneralRegs[FAST486_REG_ESI].Long -= Processed * DataSize;
6239 else State->GeneralRegs[FAST486_REG_ESI].LowWord -= Processed * DataSize;
6240
6241 /* Reverse the block data */
6242 for (i = 0; i < Processed / 2; i++)
6243 {
6244 /* Swap the values */
6245 for (j = 0; j < DataSize; j++)
6246 {
6247 UCHAR Temp = Block[i * DataSize + j];
6248 Block[i * DataSize + j] = Block[(Processed - i - 1) * DataSize + j];
6249 Block[(Processed - i - 1) * DataSize + j] = Temp;
6250 }
6251 }
6252 }
6253
6254 /* Write to the I/O port */
6255 State->IoWriteCallback(State,
6256 State->GeneralRegs[FAST486_REG_EDX].LowWord,
6257 Block,
6258 Processed,
6259 DataSize);
6260
6261 if (!State->Flags.Df)
6262 {
6263 /* Increase ESI by the number of bytes transfered */
6264 if (AddressSize) State->GeneralRegs[FAST486_REG_ESI].Long += Processed * DataSize;
6265 else State->GeneralRegs[FAST486_REG_ESI].LowWord += Processed * DataSize;
6266 }
6267
6268 /* Reduce the total count by the number processed in this run */
6269 Count -= Processed;
6270 }
6271
6272 /* Clear ECX */
6273 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = 0;
6274 else State->GeneralRegs[FAST486_REG_ECX].LowWord = 0;
6275 }
6276 else
6277 {
6278 ULONG Data = 0;
6279
6280 /* Read from the source operand */
6281 if (!Fast486ReadMemory(State,
6282 (State->PrefixFlags & FAST486_PREFIX_SEG)
6283 ? State->SegmentOverride : FAST486_REG_DS,
6284 AddressSize ? State->GeneralRegs[FAST486_REG_ESI].Long
6285 : State->GeneralRegs[FAST486_REG_ESI].LowWord,
6286 FALSE,
6287 &Data,
6288 DataSize))
6289 {
6290 /* Exception occurred */
6291 return FALSE;
6292 }
6293
6294 /* Write to the I/O port */
6295 State->IoWriteCallback(State,
6296 State->GeneralRegs[FAST486_REG_EDX].LowWord,
6297 &Data,
6298 1,
6299 DataSize);
6300
6301 /* Increment/decrement ESI */
6302 if (AddressSize)
6303 {
6304 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_ESI].Long += DataSize;
6305 else State->GeneralRegs[FAST486_REG_ESI].Long -= DataSize;
6306 }
6307 else
6308 {
6309 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_ESI].LowWord += DataSize;
6310 else State->GeneralRegs[FAST486_REG_ESI].LowWord -= DataSize;
6311 }
6312 }
6313
6314 /* Return success */
6315 return TRUE;
6316 }
6317
6318 /* EOF */