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