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