[FAST486]
[reactos.git] / reactos / lib / fast486 / opcodes.c
1 /*
2 * Fast486 386/486 CPU Emulation Library
3 * opcodes.c
4 *
5 * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22 /* INCLUDES *******************************************************************/
23
24 #include <windef.h>
25
26 // #define NDEBUG
27 #include <debug.h>
28
29 #include <fast486.h>
30 #include "opcodes.h"
31 #include "opgroups.h"
32 #include "extraops.h"
33 #include "common.h"
34 #include "fpu.h"
35
36 /* PUBLIC VARIABLES ***********************************************************/
37
38 FAST486_OPCODE_HANDLER_PROC
39 Fast486OpcodeHandlers[FAST486_NUM_OPCODE_HANDLERS] =
40 {
41 Fast486OpcodeAddByteModrm, /* 0x00 - 0x03 */
42 Fast486OpcodeAddModrm,
43 Fast486OpcodeAddByteModrm,
44 Fast486OpcodeAddModrm,
45 Fast486OpcodeAddAl, /* 0x04 */
46 Fast486OpcodeAddEax, /* 0x05 */
47 Fast486OpcodePushEs, /* 0x06 */
48 Fast486OpcodePopEs, /* 0x07 */
49 Fast486OpcodeOrByteModrm, /* 0x08 - 0x0B */
50 Fast486OpcodeOrModrm,
51 Fast486OpcodeOrByteModrm,
52 Fast486OpcodeOrModrm,
53 Fast486OpcodeOrAl, /* 0x0C */
54 Fast486OpcodeOrEax, /* 0x0D */
55 Fast486OpcodePushCs, /* 0x0E */
56 Fast486OpcodeExtended, /* 0x0F */
57 Fast486OpcodeAdcByteModrm, /* 0x10 - 0x13 */
58 Fast486OpcodeAdcModrm,
59 Fast486OpcodeAdcByteModrm,
60 Fast486OpcodeAdcModrm,
61 Fast486OpcodeAdcAl, /* 0x14 */
62 Fast486OpcodeAdcEax, /* 0x15 */
63 Fast486OpcodePushSs, /* 0x16 */
64 Fast486OpcodePopSs, /* 0x17 */
65 Fast486OpcodeSbbByteModrm, /* 0x18 - 0x1B */
66 Fast486OpcodeSbbModrm,
67 Fast486OpcodeSbbByteModrm,
68 Fast486OpcodeSbbModrm,
69 Fast486OpcodeSbbAl, /* 0x1C */
70 Fast486OpcodeSbbEax, /* 0x1D */
71 Fast486OpcodePushDs, /* 0x1E */
72 Fast486OpcodePopDs, /* 0x1F */
73 Fast486OpcodeAndByteModrm, /* 0x20 - 0x23 */
74 Fast486OpcodeAndModrm,
75 Fast486OpcodeAndByteModrm,
76 Fast486OpcodeAndModrm,
77 Fast486OpcodeAndAl, /* 0x24 */
78 Fast486OpcodeAndEax, /* 0x25 */
79 Fast486OpcodePrefix, /* 0x26 */
80 Fast486OpcodeDaa, /* 0x27 */
81 Fast486OpcodeCmpSubByteModrm, /* 0x28 - 0x2B */
82 Fast486OpcodeCmpSubModrm,
83 Fast486OpcodeCmpSubByteModrm,
84 Fast486OpcodeCmpSubModrm,
85 Fast486OpcodeCmpSubAl, /* 0x2C */
86 Fast486OpcodeCmpSubEax, /* 0x2D */
87 Fast486OpcodePrefix, /* 0x2E */
88 Fast486OpcodeDas, /* 0x2F */
89 Fast486OpcodeXorByteModrm, /* 0x30 - 0x33 */
90 Fast486OpcodeXorModrm,
91 Fast486OpcodeXorByteModrm,
92 Fast486OpcodeXorModrm,
93 Fast486OpcodeXorAl, /* 0x34 */
94 Fast486OpcodeXorEax, /* 0x35 */
95 Fast486OpcodePrefix, /* 0x36 */
96 Fast486OpcodeAaa, /* 0x37 */
97 Fast486OpcodeCmpSubByteModrm, /* 0x38 - 0x3B */
98 Fast486OpcodeCmpSubModrm,
99 Fast486OpcodeCmpSubByteModrm,
100 Fast486OpcodeCmpSubModrm,
101 Fast486OpcodeCmpSubAl, /* 0x3C */
102 Fast486OpcodeCmpSubEax, /* 0x3D */
103 Fast486OpcodePrefix, /* 0x3E */
104 Fast486OpcodeAas, /* 0x3F */
105 Fast486OpcodeIncrement, /* 0x40 - 0x47 */
106 Fast486OpcodeIncrement,
107 Fast486OpcodeIncrement,
108 Fast486OpcodeIncrement,
109 Fast486OpcodeIncrement,
110 Fast486OpcodeIncrement,
111 Fast486OpcodeIncrement,
112 Fast486OpcodeIncrement,
113 Fast486OpcodeDecrement, /* 0x48 - 0x4F */
114 Fast486OpcodeDecrement,
115 Fast486OpcodeDecrement,
116 Fast486OpcodeDecrement,
117 Fast486OpcodeDecrement,
118 Fast486OpcodeDecrement,
119 Fast486OpcodeDecrement,
120 Fast486OpcodeDecrement,
121 Fast486OpcodePushReg, /* 0x50 - 0x57 */
122 Fast486OpcodePushReg,
123 Fast486OpcodePushReg,
124 Fast486OpcodePushReg,
125 Fast486OpcodePushReg,
126 Fast486OpcodePushReg,
127 Fast486OpcodePushReg,
128 Fast486OpcodePushReg,
129 Fast486OpcodePopReg, /* 0x58 - 0x5F */
130 Fast486OpcodePopReg,
131 Fast486OpcodePopReg,
132 Fast486OpcodePopReg,
133 Fast486OpcodePopReg,
134 Fast486OpcodePopReg,
135 Fast486OpcodePopReg,
136 Fast486OpcodePopReg,
137 Fast486OpcodePushAll, /* 0x60 */
138 Fast486OpcodePopAll, /* 0x61 */
139 Fast486OpcodeBound, /* 0x62 */
140 Fast486OpcodeArpl, /* 0x63 */
141 Fast486OpcodePrefix, /* 0x64 - 0x67 */
142 Fast486OpcodePrefix,
143 Fast486OpcodePrefix,
144 Fast486OpcodePrefix,
145 Fast486OpcodePushImm, /* 0x68 */
146 Fast486OpcodeImulModrmImm, /* 0x69 */
147 Fast486OpcodePushByteImm, /* 0x6A */
148 Fast486OpcodeImulModrmImm, /* 0x6B */
149 Fast486OpcodeIns, /* 0x6C */
150 Fast486OpcodeIns, /* 0x6D */
151 Fast486OpcodeOuts, /* 0x6E */
152 Fast486OpcodeOuts, /* 0x6F */
153 Fast486OpcodeShortConditionalJmp, /* 0x70 - 0x7F */
154 Fast486OpcodeShortConditionalJmp,
155 Fast486OpcodeShortConditionalJmp,
156 Fast486OpcodeShortConditionalJmp,
157 Fast486OpcodeShortConditionalJmp,
158 Fast486OpcodeShortConditionalJmp,
159 Fast486OpcodeShortConditionalJmp,
160 Fast486OpcodeShortConditionalJmp,
161 Fast486OpcodeShortConditionalJmp,
162 Fast486OpcodeShortConditionalJmp,
163 Fast486OpcodeShortConditionalJmp,
164 Fast486OpcodeShortConditionalJmp,
165 Fast486OpcodeShortConditionalJmp,
166 Fast486OpcodeShortConditionalJmp,
167 Fast486OpcodeShortConditionalJmp,
168 Fast486OpcodeShortConditionalJmp,
169 Fast486OpcodeGroup8082, /* 0x80 */
170 Fast486OpcodeGroup81, /* 0x81 */
171 Fast486OpcodeGroup8082, /* 0x82 */
172 Fast486OpcodeGroup83, /* 0x83 */
173 Fast486OpcodeTestByteModrm, /* 0x84 */
174 Fast486OpcodeTestModrm, /* 0x85 */
175 Fast486OpcodeXchgByteModrm, /* 0x86 */
176 Fast486OpcodeXchgModrm, /* 0x87 */
177 Fast486OpcodeMovByteModrm, /* 0x88 */
178 Fast486OpcodeMovModrm, /* 0x89 */
179 Fast486OpcodeMovByteModrm, /* 0x8A */
180 Fast486OpcodeMovModrm, /* 0x8B */
181 Fast486OpcodeMovStoreSeg, /* 0x8C */
182 Fast486OpcodeLea, /* 0x8D */
183 Fast486OpcodeMovLoadSeg, /* 0x8E */
184 Fast486OpcodeGroup8F, /* 0x8F */
185 Fast486OpcodeNop, /* 0x90 */
186 Fast486OpcodeExchangeEax, /* 0x91 - 0x97 */
187 Fast486OpcodeExchangeEax,
188 Fast486OpcodeExchangeEax,
189 Fast486OpcodeExchangeEax,
190 Fast486OpcodeExchangeEax,
191 Fast486OpcodeExchangeEax,
192 Fast486OpcodeExchangeEax,
193 Fast486OpcodeCwde, /* 0x98 */
194 Fast486OpcodeCdq, /* 0x99 */
195 Fast486OpcodeCallAbs, /* 0x9A */
196 Fast486OpcodeWait, /* 0x9B */
197 Fast486OpcodePushFlags, /* 0x9C */
198 Fast486OpcodePopFlags, /* 0x9D */
199 Fast486OpcodeSahf, /* 0x9E */
200 Fast486OpcodeLahf, /* 0x9F */
201 Fast486OpcodeMovAlOffset, /* 0xA0 */
202 Fast486OpcodeMovEaxOffset, /* 0xA1 */
203 Fast486OpcodeMovOffsetAl, /* 0xA2 */
204 Fast486OpcodeMovOffsetEax, /* 0xA3 */
205 Fast486OpcodeMovs, /* 0xA4 */
206 Fast486OpcodeMovs, /* 0xA5 */
207 Fast486OpcodeCmps, /* 0xA6 */
208 Fast486OpcodeCmps, /* 0xA7 */
209 Fast486OpcodeTestAl, /* 0xA8 */
210 Fast486OpcodeTestEax, /* 0xA9 */
211 Fast486OpcodeStos, /* 0xAA */
212 Fast486OpcodeStos, /* 0xAB */
213 Fast486OpcodeLods, /* 0xAC */
214 Fast486OpcodeLods, /* 0xAD */
215 Fast486OpcodeScas, /* 0xAE */
216 Fast486OpcodeScas, /* 0xAF */
217 Fast486OpcodeMovByteRegImm, /* 0xB0 - 0xB7 */
218 Fast486OpcodeMovByteRegImm,
219 Fast486OpcodeMovByteRegImm,
220 Fast486OpcodeMovByteRegImm,
221 Fast486OpcodeMovByteRegImm,
222 Fast486OpcodeMovByteRegImm,
223 Fast486OpcodeMovByteRegImm,
224 Fast486OpcodeMovByteRegImm,
225 Fast486OpcodeMovRegImm, /* 0xB8 - 0xBF */
226 Fast486OpcodeMovRegImm,
227 Fast486OpcodeMovRegImm,
228 Fast486OpcodeMovRegImm,
229 Fast486OpcodeMovRegImm,
230 Fast486OpcodeMovRegImm,
231 Fast486OpcodeMovRegImm,
232 Fast486OpcodeMovRegImm,
233 Fast486OpcodeGroupC0, /* 0xC0 */
234 Fast486OpcodeGroupC1, /* 0xC1 */
235 Fast486OpcodeRet, /* 0xC2 */
236 Fast486OpcodeRet, /* 0xC3 */
237 Fast486OpcodeLdsLes, /* 0xC4 */
238 Fast486OpcodeLdsLes, /* 0xC5 */
239 Fast486OpcodeGroupC6, /* 0xC6 */
240 Fast486OpcodeGroupC7, /* 0xC7 */
241 Fast486OpcodeEnter, /* 0xC8 */
242 Fast486OpcodeLeave, /* 0xC9 */
243 Fast486OpcodeRetFar, /* 0xCA */
244 Fast486OpcodeRetFar, /* 0xCB */
245 Fast486OpcodeInt, /* 0xCC */
246 Fast486OpcodeInt, /* 0xCD */
247 Fast486OpcodeInt, /* 0xCE */
248 Fast486OpcodeIret, /* 0xCF */
249 Fast486OpcodeGroupD0, /* 0xD0 - 0xD3 */
250 Fast486OpcodeGroupD1,
251 Fast486OpcodeGroupD2,
252 Fast486OpcodeGroupD3,
253 Fast486OpcodeAam, /* 0xD4 */
254 Fast486OpcodeAad, /* 0xD5 */
255 Fast486OpcodeSalc, /* 0xD6 */
256 Fast486OpcodeXlat, /* 0xD7 */
257 Fast486FpuOpcodeD8, /* 0xD8 - 0xDF */
258 Fast486FpuOpcodeD9,
259 Fast486FpuOpcodeDA,
260 Fast486FpuOpcodeDB,
261 Fast486FpuOpcodeDC,
262 Fast486FpuOpcodeDD,
263 Fast486FpuOpcodeDE,
264 Fast486FpuOpcodeDF,
265 Fast486OpcodeLoop, /* 0xE0 - 0xE2 */
266 Fast486OpcodeLoop,
267 Fast486OpcodeLoop,
268 Fast486OpcodeJecxz, /* 0xE3 */
269 Fast486OpcodeInByte, /* 0xE4 */
270 Fast486OpcodeIn, /* 0xE5 */
271 Fast486OpcodeOutByte, /* 0xE6 */
272 Fast486OpcodeOut, /* 0xE7 */
273 Fast486OpcodeCall, /* 0xE8 */
274 Fast486OpcodeJmp, /* 0xE9 */
275 Fast486OpcodeJmpAbs, /* 0xEA */
276 Fast486OpcodeShortJump, /* 0xEB */
277 Fast486OpcodeInByte, /* 0xEC */
278 Fast486OpcodeIn, /* 0xED */
279 Fast486OpcodeOutByte, /* 0xEE */
280 Fast486OpcodeOut, /* 0xEF */
281 Fast486OpcodePrefix, /* 0xF0 */
282 Fast486OpcodeInvalid, /* 0xF1 */ // Invalid opcode -- ICEBP/INT01 opcode
283 Fast486OpcodePrefix, /* 0xF2 */
284 Fast486OpcodePrefix, /* 0xF3 */
285 Fast486OpcodeHalt, /* 0xF4 */
286 Fast486OpcodeComplCarry, /* 0xF5 */
287 Fast486OpcodeGroupF6, /* 0xF6 */
288 Fast486OpcodeGroupF7, /* 0xF7 */
289 Fast486OpcodeClearCarry, /* 0xF8 */
290 Fast486OpcodeSetCarry, /* 0xF9 */
291 Fast486OpcodeClearInt, /* 0xFA */
292 Fast486OpcodeSetInt, /* 0xFB */
293 Fast486OpcodeClearDir, /* 0xFC */
294 Fast486OpcodeSetDir, /* 0xFD */
295 Fast486OpcodeGroupFE, /* 0xFE */
296 Fast486OpcodeGroupFF, /* 0xFF */
297 };
298
299 /* PUBLIC FUNCTIONS ***********************************************************/
300
301 FAST486_OPCODE_HANDLER(Fast486OpcodeInvalid)
302 {
303 /*
304 * This is not a valid opcode.
305 * Well, not totally: see http://www.rcollins.org/secrets/opcodes/ICEBP.html
306 * for more details.
307 */
308 DPRINT1("FAST486 -- Calling ICEBP opcode\n");
309 Fast486Exception(State, FAST486_EXCEPTION_UD);
310 }
311
312 FAST486_OPCODE_HANDLER(Fast486OpcodePrefix)
313 {
314 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 >= Fast486GetCurrentPrivLevel(State))
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 >= Fast486GetCurrentPrivLevel(State))
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 AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3836 FAST486_MOD_REG_RM ModRegRm;
3837
3838 /* Make sure this is the right instruction */
3839 ASSERT(Opcode == 0x8C);
3840
3841 TOGGLE_ADSIZE(AddressSize);
3842
3843 /* Get the operands */
3844 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3845 {
3846 /* Exception occurred */
3847 return;
3848 }
3849
3850 if (ModRegRm.Register >= FAST486_NUM_SEG_REGS)
3851 {
3852 /* Invalid */
3853 Fast486Exception(State, FAST486_EXCEPTION_UD);
3854 return;
3855 }
3856
3857 Fast486WriteModrmWordOperands(State,
3858 &ModRegRm,
3859 FALSE,
3860 State->SegmentRegs[ModRegRm.Register].Selector);
3861 }
3862
3863 FAST486_OPCODE_HANDLER(Fast486OpcodeLea)
3864 {
3865 FAST486_MOD_REG_RM ModRegRm;
3866 BOOLEAN OperandSize, AddressSize;
3867
3868 /* Make sure this is the right instruction */
3869 ASSERT(Opcode == 0x8D);
3870
3871 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3872
3873 TOGGLE_ADSIZE(AddressSize);
3874 TOGGLE_OPSIZE(OperandSize);
3875
3876 /* Get the operands */
3877 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3878 {
3879 /* Exception occurred */
3880 return;
3881 }
3882
3883 /* The second operand must be memory */
3884 if (!ModRegRm.Memory)
3885 {
3886 /* Invalid */
3887 Fast486Exception(State, FAST486_EXCEPTION_UD);
3888 return;
3889 }
3890
3891 /* Write the address to the register */
3892 if (OperandSize)
3893 {
3894 Fast486WriteModrmDwordOperands(State,
3895 &ModRegRm,
3896 TRUE,
3897 ModRegRm.MemoryAddress);
3898 }
3899 else
3900 {
3901 Fast486WriteModrmWordOperands(State,
3902 &ModRegRm,
3903 TRUE,
3904 ModRegRm.MemoryAddress);
3905
3906 }
3907 }
3908
3909 FAST486_OPCODE_HANDLER(Fast486OpcodeMovLoadSeg)
3910 {
3911 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3912 FAST486_MOD_REG_RM ModRegRm;
3913 USHORT Selector;
3914
3915 /* Make sure this is the right instruction */
3916 ASSERT(Opcode == 0x8E);
3917
3918 TOGGLE_ADSIZE(AddressSize);
3919
3920 /* Get the operands */
3921 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3922 {
3923 /* Exception occurred */
3924 return;
3925 }
3926
3927 if ((ModRegRm.Register >= FAST486_NUM_SEG_REGS)
3928 || ((FAST486_SEG_REGS)ModRegRm.Register == FAST486_REG_CS))
3929 {
3930 /* Invalid */
3931 Fast486Exception(State, FAST486_EXCEPTION_UD);
3932 return;
3933 }
3934
3935 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Selector))
3936 {
3937 /* Exception occurred */
3938 return;
3939 }
3940
3941 if (!Fast486LoadSegment(State, ModRegRm.Register, Selector))
3942 {
3943 /* Exception occurred */
3944 return;
3945 }
3946
3947 if ((INT)ModRegRm.Register == FAST486_REG_SS)
3948 {
3949 /* Inhibit all interrupts until the next instruction */
3950 State->DoNotInterrupt = TRUE;
3951 }
3952 }
3953
3954 FAST486_OPCODE_HANDLER(Fast486OpcodeCwde)
3955 {
3956 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
3957
3958 /* Make sure this is the right instruction */
3959 ASSERT(Opcode == 0x98);
3960
3961 TOGGLE_OPSIZE(Size);
3962 NO_LOCK_PREFIX();
3963
3964 if (Size)
3965 {
3966 /* Sign extend AX to EAX */
3967 State->GeneralRegs[FAST486_REG_EAX].Long = MAKELONG
3968 (
3969 State->GeneralRegs[FAST486_REG_EAX].LowWord,
3970 (State->GeneralRegs[FAST486_REG_EAX].LowWord & SIGN_FLAG_WORD)
3971 ? 0xFFFF : 0x0000
3972 );
3973 }
3974 else
3975 {
3976 /* Sign extend AL to AX */
3977 State->GeneralRegs[FAST486_REG_EAX].HighByte =
3978 (State->GeneralRegs[FAST486_REG_EAX].LowByte & SIGN_FLAG_BYTE)
3979 ? 0xFF : 0x00;
3980 }
3981 }
3982
3983 FAST486_OPCODE_HANDLER(Fast486OpcodeCdq)
3984 {
3985 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
3986
3987 /* Make sure this is the right instruction */
3988 ASSERT(Opcode == 0x99);
3989
3990 TOGGLE_OPSIZE(Size);
3991 NO_LOCK_PREFIX();
3992
3993 if (Size)
3994 {
3995 /* Sign extend EAX to EDX:EAX */
3996 State->GeneralRegs[FAST486_REG_EDX].Long =
3997 (State->GeneralRegs[FAST486_REG_EAX].Long & SIGN_FLAG_LONG)
3998 ? 0xFFFFFFFF : 0x00000000;
3999 }
4000 else
4001 {
4002 /* Sign extend AX to DX:AX */
4003 State->GeneralRegs[FAST486_REG_EDX].LowWord =
4004 (State->GeneralRegs[FAST486_REG_EAX].LowWord & SIGN_FLAG_WORD)
4005 ? 0xFFFF : 0x0000;
4006 }
4007 }
4008
4009 FAST486_OPCODE_HANDLER(Fast486OpcodeCallAbs)
4010 {
4011 USHORT Segment = 0;
4012 ULONG Offset = 0;
4013 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4014
4015 /* Make sure this is the right instruction */
4016 ASSERT(Opcode == 0x9A);
4017
4018 TOGGLE_OPSIZE(Size);
4019 NO_LOCK_PREFIX();
4020
4021 /* Fetch the offset */
4022 if (Size)
4023 {
4024 if (!Fast486FetchDword(State, &Offset))
4025 {
4026 /* Exception occurred */
4027 return;
4028 }
4029 }
4030 else
4031 {
4032 if (!Fast486FetchWord(State, (PUSHORT)&Offset))
4033 {
4034 /* Exception occurred */
4035 return;
4036 }
4037 }
4038
4039 /* Fetch the segment */
4040 if (!Fast486FetchWord(State, &Segment))
4041 {
4042 /* Exception occurred */
4043 return;
4044 }
4045
4046 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
4047 {
4048 if (!Fast486ProcessGate(State, Segment, Offset, TRUE))
4049 {
4050 /* Gate processed or exception occurred */
4051 return;
4052 }
4053 }
4054
4055 /* Push the current code segment selector */
4056 if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector))
4057 {
4058 /* Exception occurred */
4059 return;
4060 }
4061
4062 /* Push the current value of the instruction pointer */
4063 if (!Fast486StackPush(State, State->InstPtr.Long))
4064 {
4065 /* Exception occurred */
4066 return;
4067 }
4068
4069 /* Load the new CS */
4070 if (!Fast486LoadSegment(State, FAST486_REG_CS, Segment))
4071 {
4072 /* Exception occurred */
4073 return;
4074 }
4075
4076 /* Load new (E)IP */
4077 if (Size) State->InstPtr.Long = Offset;
4078 else State->InstPtr.LowWord = LOWORD(Offset);
4079 }
4080
4081 FAST486_OPCODE_HANDLER(Fast486OpcodeWait)
4082 {
4083 #ifndef FAST486_NO_FPU
4084
4085 if ((!State->FpuControl.Pm && State->FpuStatus.Pe)
4086 || (!State->FpuControl.Um && State->FpuStatus.Ue)
4087 || (!State->FpuControl.Om && State->FpuStatus.Oe)
4088 || (!State->FpuControl.Zm && State->FpuStatus.Ze)
4089 || (!State->FpuControl.Dm && State->FpuStatus.De)
4090 || (!State->FpuControl.Im && State->FpuStatus.Ie))
4091 {
4092 Fast486FpuException(State);
4093 }
4094
4095 #endif
4096 }
4097
4098 FAST486_OPCODE_HANDLER(Fast486OpcodePushFlags)
4099 {
4100 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4101
4102 NO_LOCK_PREFIX();
4103 TOGGLE_OPSIZE(Size);
4104
4105 /* Check for VM86 mode when IOPL is not 3 */
4106 if (State->Flags.Vm && (State->Flags.Iopl != 3))
4107 {
4108 /* Call the VM86 monitor */
4109 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, 0);
4110 return;
4111 }
4112
4113 /* Push the flags */
4114 if (Size) Fast486StackPush(State, State->Flags.Long);
4115 else Fast486StackPush(State, LOWORD(State->Flags.Long));
4116 }
4117
4118 FAST486_OPCODE_HANDLER(Fast486OpcodePopFlags)
4119 {
4120 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4121 UINT Cpl = Fast486GetCurrentPrivLevel(State);
4122 FAST486_FLAGS_REG NewFlags;
4123
4124 NO_LOCK_PREFIX();
4125 TOGGLE_OPSIZE(Size);
4126
4127 /* Pop the new flags */
4128 if (!Fast486StackPop(State, &NewFlags.Long))
4129 {
4130 /* Exception occurred */
4131 return;
4132 }
4133
4134 /* Check for VM86 mode when IOPL is not 3 */
4135 if (State->Flags.Vm && (State->Flags.Iopl != 3))
4136 {
4137 /* Call the VM86 monitor */
4138 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, 0);
4139 return;
4140 }
4141
4142 State->Flags.Cf = NewFlags.Cf;
4143 State->Flags.Pf = NewFlags.Pf;
4144 State->Flags.Af = NewFlags.Af;
4145 State->Flags.Zf = NewFlags.Zf;
4146 State->Flags.Sf = NewFlags.Sf;
4147 State->Flags.Tf = NewFlags.Tf;
4148 State->Flags.Df = NewFlags.Df;
4149 State->Flags.Of = NewFlags.Of;
4150 State->Flags.Nt = NewFlags.Nt;
4151 State->Flags.Ac = NewFlags.Ac;
4152
4153 if (Cpl == 0) State->Flags.Iopl = NewFlags.Iopl;
4154 if (Cpl <= State->Flags.Iopl) State->Flags.If = NewFlags.If;
4155 }
4156
4157 FAST486_OPCODE_HANDLER(Fast486OpcodeSahf)
4158 {
4159 /* Make sure this is the right instruction */
4160 ASSERT(Opcode == 0x9E);
4161
4162 /* Set the low-order byte of FLAGS to AH */
4163 State->Flags.Long &= 0xFFFFFF00;
4164 State->Flags.Long |= State->GeneralRegs[FAST486_REG_EAX].HighByte;
4165
4166 /* Restore the reserved bits of FLAGS */
4167 State->Flags.AlwaysSet = TRUE;
4168 State->Flags.Reserved0 = State->Flags.Reserved1 = FALSE;
4169 }
4170
4171 FAST486_OPCODE_HANDLER(Fast486OpcodeLahf)
4172 {
4173 /* Make sure this is the right instruction */
4174 ASSERT(Opcode == 0x9F);
4175
4176 /* Set AH to the low-order byte of FLAGS */
4177 State->GeneralRegs[FAST486_REG_EAX].HighByte = LOBYTE(State->Flags.Long);
4178 }
4179
4180 FAST486_OPCODE_HANDLER(Fast486OpcodeRet)
4181 {
4182 ULONG ReturnAddress;
4183 USHORT BytesToPop = 0;
4184 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4185
4186 /* Make sure this is the right instruction */
4187 ASSERT((Opcode & 0xFE) == 0xC2);
4188
4189 NO_LOCK_PREFIX();
4190 TOGGLE_OPSIZE(Size);
4191
4192 if (Opcode == 0xC2)
4193 {
4194 /* Fetch the number of bytes to pop after the return */
4195 if (!Fast486FetchWord(State, &BytesToPop)) return;
4196 }
4197
4198 /* Pop the return address */
4199 if (!Fast486StackPop(State, &ReturnAddress)) return;
4200
4201 /* Return to the calling procedure, and if necessary, pop the parameters */
4202 if (Size)
4203 {
4204 State->InstPtr.Long = ReturnAddress;
4205 State->GeneralRegs[FAST486_REG_ESP].Long += BytesToPop;
4206 }
4207 else
4208 {
4209 State->InstPtr.LowWord = LOWORD(ReturnAddress);
4210 State->GeneralRegs[FAST486_REG_ESP].LowWord += BytesToPop;
4211 }
4212 }
4213
4214 FAST486_OPCODE_HANDLER(Fast486OpcodeLdsLes)
4215 {
4216 UCHAR FarPointer[6];
4217 BOOLEAN OperandSize, AddressSize;
4218 FAST486_MOD_REG_RM ModRegRm;
4219
4220 /* Make sure this is the right instruction */
4221 ASSERT((Opcode & 0xFE) == 0xC4);
4222
4223 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
4224
4225 TOGGLE_OPSIZE(OperandSize);
4226 TOGGLE_ADSIZE(AddressSize);
4227
4228 /* Get the operands */
4229 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
4230 {
4231 /* Exception occurred */
4232 return;
4233 }
4234
4235 if (!ModRegRm.Memory)
4236 {
4237 /* Check if this is a BOP and the host supports BOPs */
4238 if ((Opcode == 0xC4)
4239 && (ModRegRm.Register == FAST486_REG_EAX)
4240 && (ModRegRm.SecondRegister == FAST486_REG_ESP)
4241 && (State->BopCallback != NULL))
4242 {
4243 UCHAR BopCode;
4244
4245 /* Fetch the BOP code */
4246 if (!Fast486FetchByte(State, &BopCode))
4247 {
4248 /* Exception occurred */
4249 return;
4250 }
4251
4252 #ifndef FAST486_NO_PREFETCH
4253 /* Invalidate the prefetch since BOP handlers can alter the memory */
4254 State->PrefetchValid = FALSE;
4255 #endif
4256
4257 /* Call the BOP handler */
4258 State->BopCallback(State, BopCode);
4259
4260 /*
4261 * If an interrupt should occur at this time, delay it.
4262 * We must do this because if an interrupt begins and the BOP callback
4263 * changes the CS:IP, the interrupt handler won't execute and the
4264 * stack pointer will never be restored.
4265 */
4266 State->DoNotInterrupt = TRUE;
4267
4268 return;
4269 }
4270
4271 /* Invalid */
4272 Fast486Exception(State, FAST486_EXCEPTION_UD);
4273 return;
4274 }
4275
4276 if (!Fast486ReadMemory(State,
4277 (State->PrefixFlags & FAST486_PREFIX_SEG)
4278 ? State->SegmentOverride : FAST486_REG_DS,
4279 ModRegRm.MemoryAddress,
4280 FALSE,
4281 FarPointer,
4282 OperandSize ? 6 : 4))
4283 {
4284 /* Exception occurred */
4285 return;
4286 }
4287
4288 if (OperandSize)
4289 {
4290 ULONG Offset = *((PULONG)FarPointer);
4291 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(ULONG)]);
4292
4293 /* Set the register to the offset */
4294 State->GeneralRegs[ModRegRm.Register].Long = Offset;
4295
4296 /* Load the segment */
4297 Fast486LoadSegment(State,
4298 (Opcode == 0xC4)
4299 ? FAST486_REG_ES : FAST486_REG_DS,
4300 Segment);
4301 }
4302 else
4303 {
4304 USHORT Offset = *((PUSHORT)FarPointer);
4305 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(USHORT)]);
4306
4307 /* Set the register to the offset */
4308 State->GeneralRegs[ModRegRm.Register].LowWord = Offset;
4309
4310 /* Load the segment */
4311 Fast486LoadSegment(State,
4312 (Opcode == 0xC4)
4313 ? FAST486_REG_ES : FAST486_REG_DS,
4314 Segment);
4315 }
4316 }
4317
4318 FAST486_OPCODE_HANDLER(Fast486OpcodeEnter)
4319 {
4320 INT i;
4321 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4322 USHORT FrameSize;
4323 UCHAR NestingLevel;
4324 FAST486_REG FramePointer;
4325
4326 /* Make sure this is the right instruction */
4327 ASSERT(Opcode == 0xC8);
4328
4329 NO_LOCK_PREFIX();
4330 TOGGLE_OPSIZE(Size);
4331
4332 if (!Fast486FetchWord(State, &FrameSize))
4333 {
4334 /* Exception occurred */
4335 return;
4336 }
4337
4338 if (!Fast486FetchByte(State, &NestingLevel))
4339 {
4340 /* Exception occurred */
4341 return;
4342 }
4343
4344 /* Push EBP */
4345 if (!Fast486StackPush(State, State->GeneralRegs[FAST486_REG_EBP].Long))
4346 {
4347 /* Exception occurred */
4348 return;
4349 }
4350
4351 /* Save ESP */
4352 FramePointer = State->GeneralRegs[FAST486_REG_ESP];
4353
4354 /* Set up the nested procedure stacks */
4355 for (i = 1; i < NestingLevel; i++)
4356 {
4357 if (Size)
4358 {
4359 State->GeneralRegs[FAST486_REG_EBP].Long -= 4;
4360 Fast486StackPush(State, State->GeneralRegs[FAST486_REG_EBP].Long);
4361 }
4362 else
4363 {
4364 State->GeneralRegs[FAST486_REG_EBP].LowWord -= 2;
4365 Fast486StackPush(State, State->GeneralRegs[FAST486_REG_EBP].LowWord);
4366 }
4367 }
4368
4369 if (NestingLevel > 0) Fast486StackPush(State, FramePointer.Long);
4370
4371 /* Set EBP to the frame pointer */
4372 if (Size) State->GeneralRegs[FAST486_REG_EBP].Long = FramePointer.Long;
4373 else State->GeneralRegs[FAST486_REG_EBP].LowWord = FramePointer.LowWord;
4374
4375 /* Reserve space for the frame */
4376 if (State->SegmentRegs[FAST486_REG_SS].Size)
4377 {
4378 State->GeneralRegs[FAST486_REG_ESP].Long -= (ULONG)FrameSize;
4379 }
4380 else
4381 {
4382 State->GeneralRegs[FAST486_REG_ESP].LowWord -= FrameSize;
4383 }
4384 }
4385
4386 FAST486_OPCODE_HANDLER(Fast486OpcodeLeave)
4387 {
4388 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4389 ULONG Value;
4390
4391 /* Make sure this is the right instruction */
4392 ASSERT(Opcode == 0xC9);
4393
4394 NO_LOCK_PREFIX();
4395 TOGGLE_OPSIZE(Size);
4396
4397 if (State->SegmentRegs[FAST486_REG_SS].Size)
4398 {
4399 /* Set the stack pointer (ESP) to the base pointer (EBP) */
4400 State->GeneralRegs[FAST486_REG_ESP].Long = State->GeneralRegs[FAST486_REG_EBP].Long;
4401 }
4402 else
4403 {
4404 /* Set the stack pointer (SP) to the base pointer (BP) */
4405 State->GeneralRegs[FAST486_REG_ESP].LowWord = State->GeneralRegs[FAST486_REG_EBP].LowWord;
4406 }
4407
4408 /* Pop the saved base pointer from the stack */
4409 if (Fast486StackPop(State, &Value))
4410 {
4411 if (Size) State->GeneralRegs[FAST486_REG_EBP].Long = Value;
4412 else State->GeneralRegs[FAST486_REG_EBP].LowWord = LOWORD(Value);
4413 }
4414 }
4415
4416 FAST486_OPCODE_HANDLER(Fast486OpcodeRetFar)
4417 {
4418 ULONG Segment = 0;
4419 ULONG Offset = 0;
4420 USHORT BytesToPop = 0;
4421 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4422
4423 /* Make sure this is the right instruction */
4424 ASSERT((Opcode & 0xFE) == 0xCA);
4425
4426 TOGGLE_OPSIZE(Size);
4427 NO_LOCK_PREFIX();
4428
4429 if (Opcode == 0xCA)
4430 {
4431 /* Fetch the number of bytes to pop after the return */
4432 if (!Fast486FetchWord(State, &BytesToPop)) return;
4433 }
4434
4435 /* Pop the offset */
4436 if (!Fast486StackPop(State, &Offset))
4437 {
4438 /* Exception occurred */
4439 return;
4440 }
4441
4442 /* Pop the segment */
4443 if (!Fast486StackPop(State, &Segment))
4444 {
4445 /* Exception occurred */
4446 return;
4447 }
4448
4449 /* Load the new CS */
4450 if (!Fast486LoadSegment(State, FAST486_REG_CS, Segment))
4451 {
4452 /* Exception occurred */
4453 return;
4454 }
4455
4456 if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) && !State->Flags.Vm)
4457 {
4458 UINT i;
4459 UINT OldCpl = Fast486GetCurrentPrivLevel(State);
4460 ULONG StackPtr;
4461 ULONG StackSel;
4462
4463 if (GET_SEGMENT_RPL(Segment) > OldCpl)
4464 {
4465 /* Pop ESP */
4466 if (!Fast486StackPop(State, &StackPtr))
4467 {
4468 /* Exception */
4469 return;
4470 }
4471
4472 /* Pop SS */
4473 if (!Fast486StackPop(State, &StackSel))
4474 {
4475 /* Exception */
4476 return;
4477 }
4478 }
4479
4480 /* Update the CPL */
4481 State->Cpl = GET_SEGMENT_RPL(Segment);
4482
4483 if (State->Cpl > OldCpl)
4484 {
4485 /* Load new SS */
4486 if (!Fast486LoadSegment(State, FAST486_REG_SS, StackSel))
4487 {
4488 /* Exception */
4489 return;
4490 }
4491
4492 /* Set ESP */
4493 if (Size) State->GeneralRegs[FAST486_REG_ESP].Long = StackPtr;
4494 else State->GeneralRegs[FAST486_REG_ESP].LowWord = LOWORD(StackPtr);
4495
4496 /* Check segment security */
4497 for (i = 0; i < FAST486_NUM_SEG_REGS; i++)
4498 {
4499 /* Don't check CS or SS */
4500 if ((i == FAST486_REG_CS) || (i == FAST486_REG_SS)) continue;
4501
4502 if ((State->Cpl > State->SegmentRegs[i].Dpl)
4503 && (!State->SegmentRegs[i].Executable
4504 || !State->SegmentRegs[i].DirConf))
4505 {
4506 /* Load the NULL descriptor in the segment */
4507 if (!Fast486LoadSegment(State, i, 0)) return;
4508 }
4509 }
4510 }
4511 }
4512
4513 /* Load new (E)IP, and if necessary, pop the parameters */
4514 if (Size)
4515 {
4516 State->InstPtr.Long = Offset;
4517 State->GeneralRegs[FAST486_REG_ESP].Long += BytesToPop;
4518 }
4519 else
4520 {
4521 State->InstPtr.LowWord = LOWORD(Offset);
4522 State->GeneralRegs[FAST486_REG_ESP].LowWord += BytesToPop;
4523 }
4524 }
4525
4526 FAST486_OPCODE_HANDLER(Fast486OpcodeInt)
4527 {
4528 UCHAR IntNum;
4529
4530 /* Check for V86 mode */
4531 if (State->Flags.Vm && (State->Flags.Iopl != 3))
4532 {
4533 /* Call the V86 monitor */
4534 Fast486Exception(State, FAST486_EXCEPTION_GP);
4535 return;
4536 }
4537
4538 switch (Opcode)
4539 {
4540 case 0xCC: // INT 3
4541 {
4542 /* This is the INT3 instruction */
4543 IntNum = 3;
4544 break;
4545 }
4546
4547 case 0xCD: // INT xx
4548 {
4549 /* Fetch the interrupt number */
4550 if (!Fast486FetchByte(State, &IntNum))
4551 {
4552 /* Exception occurred */
4553 return;
4554 }
4555
4556 break;
4557 }
4558
4559 case 0xCE: // INTO
4560 {
4561 /* Don't do anything if OF is cleared */
4562 if (!State->Flags.Of) return;
4563
4564 /* Exception #OF */
4565 IntNum = FAST486_EXCEPTION_OF;
4566
4567 break;
4568 }
4569
4570 default:
4571 {
4572 /* Should not happen */
4573 ASSERT(FALSE);
4574 }
4575 }
4576
4577 /* Perform the interrupt */
4578 Fast486PerformInterrupt(State, IntNum);
4579 }
4580
4581 FAST486_OPCODE_HANDLER(Fast486OpcodeIret)
4582 {
4583 FAST486_SEG_REGS i;
4584 ULONG InstPtr, CodeSel, StackPtr, StackSel;
4585 FAST486_FLAGS_REG NewFlags;
4586 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4587
4588 /* Make sure this is the right instruction */
4589 ASSERT(Opcode == 0xCF);
4590
4591 NO_LOCK_PREFIX();
4592 TOGGLE_OPSIZE(Size);
4593
4594 /* Check if this is a nested task return */
4595 if (State->Flags.Nt && (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE))
4596 {
4597 /* Clear the NT flag of the current task */
4598 State->Flags.Nt = FALSE;
4599
4600 /* Switch to the old task */
4601 Fast486TaskSwitch(State, FAST486_TASK_RETURN, 0);
4602 return;
4603 }
4604
4605 /* Pop EIP */
4606 if (!Fast486StackPop(State, &InstPtr))
4607 {
4608 /* Exception occurred */
4609 return;
4610 }
4611
4612 /* Pop CS */
4613 if (!Fast486StackPop(State, &CodeSel))
4614 {
4615 /* Exception occurred */
4616 return;
4617 }
4618
4619 /* Pop EFLAGS */
4620 if (!Fast486StackPop(State, &NewFlags.Long))
4621 {
4622 /* Exception occurred */
4623 return;
4624 }
4625
4626 /* Check for protected mode */
4627 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
4628 {
4629 UINT OldCpl = Fast486GetCurrentPrivLevel(State);
4630
4631 if (State->Flags.Vm)
4632 {
4633 /* Return from VM86 mode */
4634
4635 /* Check the IOPL */
4636 if (State->Flags.Iopl == 3)
4637 {
4638 /* Set new EIP */
4639 State->InstPtr.Long = LOWORD(InstPtr);
4640
4641 /* Load new CS */
4642 if (!Fast486LoadSegment(State, FAST486_REG_CS, CodeSel))
4643 {
4644 /* Exception occurred */
4645 return;
4646 }
4647
4648 /* Set the new flags */
4649 if (Size) State->Flags.Long = NewFlags.Long & REAL_MODE_FLAGS_MASK;
4650 else State->Flags.LowWord = NewFlags.LowWord & REAL_MODE_FLAGS_MASK;
4651 State->Flags.AlwaysSet = State->Flags.Vm = TRUE;
4652 State->Flags.Iopl = 3;
4653 }
4654 else
4655 {
4656 /* Call the VM86 monitor */
4657 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, 0);
4658 return;
4659 }
4660
4661 return;
4662 }
4663
4664 if (NewFlags.Vm)
4665 {
4666 /* Return to VM86 mode */
4667 ULONG Es, Ds, Fs, Gs;
4668
4669 /* Pop ESP, SS, ES, DS, FS, GS */
4670 if (!Fast486StackPop(State, &StackPtr)) return;
4671 if (!Fast486StackPop(State, &StackSel)) return;
4672 if (!Fast486StackPop(State, &Es)) return;
4673 if (!Fast486StackPop(State, &Ds)) return;
4674 if (!Fast486StackPop(State, &Fs)) return;
4675 if (!Fast486StackPop(State, &Gs)) return;
4676
4677 /* Set the new IP */
4678 State->InstPtr.Long = LOWORD(InstPtr);
4679
4680 /* Set the new flags */
4681 if (Size) State->Flags.Long = NewFlags.Long & REAL_MODE_FLAGS_MASK;
4682 else State->Flags.LowWord = NewFlags.LowWord & REAL_MODE_FLAGS_MASK;
4683 State->Flags.AlwaysSet = State->Flags.Vm = TRUE;
4684
4685 /* Load the new segments */
4686 if (!Fast486LoadSegment(State, FAST486_REG_CS, CodeSel)) return;
4687 if (!Fast486LoadSegment(State, FAST486_REG_SS, StackSel)) return;
4688 if (!Fast486LoadSegment(State, FAST486_REG_ES, Es)) return;
4689 if (!Fast486LoadSegment(State, FAST486_REG_DS, Ds)) return;
4690 if (!Fast486LoadSegment(State, FAST486_REG_FS, Fs)) return;
4691 if (!Fast486LoadSegment(State, FAST486_REG_GS, Gs)) return;
4692
4693 return;
4694 }
4695
4696 /* Load the new CS */
4697 if (!Fast486LoadSegment(State, FAST486_REG_CS, CodeSel))
4698 {
4699 /* Exception occurred */
4700 return;
4701 }
4702
4703 /* Set EIP */
4704 if (Size) State->InstPtr.Long = InstPtr;
4705 else State->InstPtr.LowWord = LOWORD(InstPtr);
4706
4707 if (GET_SEGMENT_RPL(CodeSel) > OldCpl)
4708 {
4709 /* Pop ESP */
4710 if (!Fast486StackPop(State, &StackPtr))
4711 {
4712 /* Exception */
4713 return;
4714 }
4715
4716 /* Pop SS */
4717 if (!Fast486StackPop(State, &StackSel))
4718 {
4719 /* Exception */
4720 return;
4721 }
4722 }
4723
4724 /* Update the CPL */
4725 State->Cpl = GET_SEGMENT_RPL(CodeSel);
4726
4727 /* Set the new flags */
4728 if (Size) State->Flags.Long = NewFlags.Long & PROT_MODE_FLAGS_MASK;
4729 else State->Flags.LowWord = NewFlags.LowWord & PROT_MODE_FLAGS_MASK;
4730 State->Flags.AlwaysSet = TRUE;
4731
4732 /* Set additional flags */
4733 if (OldCpl <= State->Flags.Iopl) State->Flags.If = NewFlags.If;
4734 if (OldCpl == 0) State->Flags.Iopl = NewFlags.Iopl;
4735
4736 if (State->Cpl > OldCpl)
4737 {
4738 /* Load new SS */
4739 if (!Fast486LoadSegment(State, FAST486_REG_SS, StackSel))
4740 {
4741 /* Exception */
4742 return;
4743 }
4744
4745 /* Set ESP */
4746 if (Size) State->GeneralRegs[FAST486_REG_ESP].Long = StackPtr;
4747 else State->GeneralRegs[FAST486_REG_ESP].LowWord = LOWORD(StackPtr);
4748
4749 /* Check segment security */
4750 for (i = 0; i < FAST486_NUM_SEG_REGS; i++)
4751 {
4752 /* Don't check CS or SS */
4753 if ((i == FAST486_REG_CS) || (i == FAST486_REG_SS)) continue;
4754
4755 if ((State->Cpl > State->SegmentRegs[i].Dpl)
4756 && (!State->SegmentRegs[i].Executable
4757 || !State->SegmentRegs[i].DirConf))
4758 {
4759 /* Load the NULL descriptor in the segment */
4760 if (!Fast486LoadSegment(State, i, 0)) return;
4761 }
4762 }
4763 }
4764 }
4765 else
4766 {
4767 if (Size && (InstPtr & 0xFFFF0000))
4768 {
4769 /* Invalid */
4770 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, 0);
4771 return;
4772 }
4773
4774 /* Set new EIP */
4775 State->InstPtr.Long = InstPtr;
4776
4777 /* Load new CS */
4778 if (!Fast486LoadSegment(State, FAST486_REG_CS, CodeSel))
4779 {
4780 /* Exception occurred */
4781 return;
4782 }
4783
4784 /* Set the new flags */
4785 if (Size) State->Flags.Long = NewFlags.Long & REAL_MODE_FLAGS_MASK;
4786 else State->Flags.LowWord = NewFlags.LowWord & REAL_MODE_FLAGS_MASK;
4787 State->Flags.AlwaysSet = TRUE;
4788 }
4789 }
4790
4791 FAST486_OPCODE_HANDLER(Fast486OpcodeAam)
4792 {
4793 UCHAR Base;
4794 UCHAR Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
4795
4796 NO_LOCK_PREFIX();
4797
4798 /* Fetch the base */
4799 if (!Fast486FetchByte(State, &Base))
4800 {
4801 /* Exception occurred */
4802 return;
4803 }
4804
4805 /* Check if the base is zero */
4806 if (Base == 0)
4807 {
4808 /* Divide error */
4809 Fast486Exception(State, FAST486_EXCEPTION_DE);
4810 return;
4811 }
4812
4813 /* Adjust */
4814 State->GeneralRegs[FAST486_REG_EAX].HighByte = Value / Base;
4815 State->GeneralRegs[FAST486_REG_EAX].LowByte = Value %= Base;
4816
4817 /* Update flags */
4818 State->Flags.Af = FALSE;
4819 State->Flags.Zf = (Value == 0);
4820 State->Flags.Sf = ((Value & SIGN_FLAG_BYTE) != 0);
4821 State->Flags.Pf = Fast486CalculateParity(Value);
4822 }
4823
4824 FAST486_OPCODE_HANDLER(Fast486OpcodeAad)
4825 {
4826 UCHAR Base;
4827 UCHAR Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
4828
4829 NO_LOCK_PREFIX();
4830
4831 /* Fetch the base */
4832 if (!Fast486FetchByte(State, &Base))
4833 {
4834 /* Exception occurred */
4835 return;
4836 }
4837
4838 /* Adjust */
4839 Value += State->GeneralRegs[FAST486_REG_EAX].HighByte * Base;
4840 State->GeneralRegs[FAST486_REG_EAX].LowWord = Value;
4841
4842 /* Update flags */
4843 State->Flags.Af = FALSE;
4844 State->Flags.Zf = (Value == 0);
4845 State->Flags.Sf = ((Value & SIGN_FLAG_BYTE) != 0);
4846 State->Flags.Pf = Fast486CalculateParity(Value);
4847 }
4848
4849 FAST486_OPCODE_HANDLER(Fast486OpcodeXlat)
4850 {
4851 UCHAR Value;
4852 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
4853
4854 TOGGLE_ADSIZE(AddressSize);
4855
4856 /* Read a byte from DS:[(E)BX + AL] */
4857 if (!Fast486ReadMemory(State,
4858 (State->PrefixFlags & FAST486_PREFIX_SEG)
4859 ? State->SegmentOverride : FAST486_REG_DS,
4860 (AddressSize ? State->GeneralRegs[FAST486_REG_EBX].Long
4861 : State->GeneralRegs[FAST486_REG_EBX].LowWord)
4862 + State->GeneralRegs[FAST486_REG_EAX].LowByte,
4863 FALSE,
4864 &Value,
4865 sizeof(UCHAR)))
4866 {
4867 /* Exception occurred */
4868 return;
4869 }
4870
4871 /* Set AL to the result */
4872 State->GeneralRegs[FAST486_REG_EAX].LowByte = Value;
4873 }
4874
4875 FAST486_OPCODE_HANDLER(Fast486OpcodeLoop)
4876 {
4877 BOOLEAN Condition;
4878 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4879 CHAR Offset = 0;
4880
4881 /* Make sure this is the right instruction */
4882 ASSERT((Opcode >= 0xE0) && (Opcode <= 0xE2));
4883
4884 NO_LOCK_PREFIX();
4885 TOGGLE_ADSIZE(Size);
4886
4887 if (Size) Condition = ((--State->GeneralRegs[FAST486_REG_ECX].Long) != 0);
4888 else Condition = ((--State->GeneralRegs[FAST486_REG_ECX].LowWord) != 0);
4889
4890 if (Opcode == 0xE0)
4891 {
4892 /* Additional rule for LOOPNZ */
4893 if (State->Flags.Zf) Condition = FALSE;
4894 }
4895 else if (Opcode == 0xE1)
4896 {
4897 /* Additional rule for LOOPZ */
4898 if (!State->Flags.Zf) Condition = FALSE;
4899 }
4900
4901 /* Fetch the offset */
4902 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
4903 {
4904 /* An exception occurred */
4905 return;
4906 }
4907
4908 if (Condition)
4909 {
4910 /* Move the instruction pointer */
4911 if (Size) State->InstPtr.Long += Offset;
4912 else State->InstPtr.LowWord += Offset;
4913 }
4914 }
4915
4916 FAST486_OPCODE_HANDLER(Fast486OpcodeJecxz)
4917 {
4918 BOOLEAN Condition;
4919 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4920 CHAR Offset = 0;
4921
4922 /* Make sure this is the right instruction */
4923 ASSERT(Opcode == 0xE3);
4924
4925 NO_LOCK_PREFIX();
4926 TOGGLE_ADSIZE(Size);
4927
4928 if (Size) Condition = (State->GeneralRegs[FAST486_REG_ECX].Long == 0);
4929 else Condition = (State->GeneralRegs[FAST486_REG_ECX].LowWord == 0);
4930
4931 /* Fetch the offset */
4932 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
4933 {
4934 /* An exception occurred */
4935 return;
4936 }
4937
4938 if (Condition)
4939 {
4940 /* Move the instruction pointer */
4941 if (Size) State->InstPtr.Long += Offset;
4942 else State->InstPtr.LowWord += Offset;
4943 }
4944 }
4945
4946 FAST486_OPCODE_HANDLER(Fast486OpcodeCall)
4947 {
4948 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4949
4950 /* Make sure this is the right instruction */
4951 ASSERT(Opcode == 0xE8);
4952
4953 TOGGLE_OPSIZE(Size);
4954 NO_LOCK_PREFIX();
4955
4956 if (Size)
4957 {
4958 LONG Offset = 0;
4959
4960 /* Fetch the offset */
4961 if (!Fast486FetchDword(State, (PULONG)&Offset))
4962 {
4963 /* An exception occurred */
4964 return;
4965 }
4966
4967 /* Push the current value of the instruction pointer */
4968 if (!Fast486StackPush(State, State->InstPtr.Long))
4969 {
4970 /* Exception occurred */
4971 return;
4972 }
4973
4974 /* Move the instruction pointer */
4975 State->InstPtr.Long += Offset;
4976 }
4977 else
4978 {
4979 SHORT Offset = 0;
4980
4981 /* Fetch the offset */
4982 if (!Fast486FetchWord(State, (PUSHORT)&Offset))
4983 {
4984 /* An exception occurred */
4985 return;
4986 }
4987
4988 /* Push the current value of the instruction pointer */
4989 if (!Fast486StackPush(State, State->InstPtr.Long))
4990 {
4991 /* Exception occurred */
4992 return;
4993 }
4994
4995 /* Move the instruction pointer */
4996 State->InstPtr.LowWord += Offset;
4997 }
4998 }
4999
5000 FAST486_OPCODE_HANDLER(Fast486OpcodeJmp)
5001 {
5002 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
5003
5004 /* Make sure this is the right instruction */
5005 ASSERT(Opcode == 0xE9);
5006
5007 TOGGLE_OPSIZE(Size);
5008 NO_LOCK_PREFIX();
5009
5010 if (Size)
5011 {
5012 LONG Offset = 0;
5013
5014 /* Fetch the offset */
5015 if (!Fast486FetchDword(State, (PULONG)&Offset))
5016 {
5017 /* An exception occurred */
5018 return;
5019 }
5020
5021 /* Move the instruction pointer */
5022 State->InstPtr.Long += Offset;
5023 }
5024 else
5025 {
5026 SHORT Offset = 0;
5027
5028 /* Fetch the offset */
5029 if (!Fast486FetchWord(State, (PUSHORT)&Offset))
5030 {
5031 /* An exception occurred */
5032 return;
5033 }
5034
5035 /* Move the instruction pointer */
5036 State->InstPtr.Long += Offset;
5037
5038 /* Clear the top half of EIP */
5039 State->InstPtr.Long &= 0xFFFF;
5040 }
5041 }
5042
5043 FAST486_OPCODE_HANDLER(Fast486OpcodeJmpAbs)
5044 {
5045 USHORT Segment = 0;
5046 ULONG Offset = 0;
5047 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
5048
5049 /* Make sure this is the right instruction */
5050 ASSERT(Opcode == 0xEA);
5051
5052 TOGGLE_OPSIZE(Size);
5053 NO_LOCK_PREFIX();
5054
5055 /* Fetch the offset */
5056 if (Size)
5057 {
5058 if (!Fast486FetchDword(State, &Offset))
5059 {
5060 /* Exception occurred */
5061 return;
5062 }
5063 }
5064 else
5065 {
5066 if (!Fast486FetchWord(State, (PUSHORT)&Offset))
5067 {
5068 /* Exception occurred */
5069 return;
5070 }
5071 }
5072
5073 /* Fetch the segment */
5074 if (!Fast486FetchWord(State, &Segment))
5075 {
5076 /* Exception occurred */
5077 return;
5078 }
5079
5080 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
5081 {
5082 if (!Fast486ProcessGate(State, Segment, Offset, FALSE))
5083 {
5084 /* Gate processed or exception occurred */
5085 return;
5086 }
5087 }
5088
5089 /* Load the new CS */
5090 if (!Fast486LoadSegment(State, FAST486_REG_CS, Segment))
5091 {
5092 /* Exception occurred */
5093 return;
5094 }
5095
5096 /* Load new EIP */
5097 State->InstPtr.Long = Offset;
5098 }
5099
5100 FAST486_OPCODE_HANDLER(Fast486OpcodeMovAlOffset)
5101 {
5102 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5103 ULONG Offset;
5104
5105 /* Make sure this is the right instruction */
5106 ASSERT(Opcode == 0xA0);
5107
5108 TOGGLE_ADSIZE(AddressSize);
5109
5110 if (AddressSize)
5111 {
5112 if (!Fast486FetchDword(State, &Offset))
5113 {
5114 /* Exception occurred */
5115 return;
5116 }
5117 }
5118 else
5119 {
5120 USHORT WordOffset;
5121
5122 if (!Fast486FetchWord(State, &WordOffset))
5123 {
5124 /* Exception occurred */
5125 return;
5126 }
5127
5128 Offset = (ULONG)WordOffset;
5129 }
5130
5131 /* Read from memory */
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].LowByte,
5138 sizeof(UCHAR));
5139 }
5140
5141 FAST486_OPCODE_HANDLER(Fast486OpcodeMovEaxOffset)
5142 {
5143 BOOLEAN OperandSize, AddressSize;
5144
5145 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5146
5147 /* Make sure this is the right instruction */
5148 ASSERT(Opcode == 0xA1);
5149
5150 TOGGLE_OPSIZE(OperandSize);
5151 TOGGLE_ADSIZE(AddressSize);
5152
5153 if (AddressSize)
5154 {
5155 ULONG Offset;
5156
5157 if (!Fast486FetchDword(State, &Offset))
5158 {
5159 /* Exception occurred */
5160 return;
5161 }
5162
5163 /* Read from memory */
5164 if (OperandSize)
5165 {
5166 Fast486ReadMemory(State,
5167 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5168 State->SegmentOverride : FAST486_REG_DS,
5169 Offset,
5170 FALSE,
5171 &State->GeneralRegs[FAST486_REG_EAX].Long,
5172 sizeof(ULONG));
5173 }
5174 else
5175 {
5176 Fast486ReadMemory(State,
5177 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5178 State->SegmentOverride : FAST486_REG_DS,
5179 Offset,
5180 FALSE,
5181 &State->GeneralRegs[FAST486_REG_EAX].LowWord,
5182 sizeof(USHORT));
5183 }
5184 }
5185 else
5186 {
5187 USHORT Offset;
5188
5189 if (!Fast486FetchWord(State, &Offset))
5190 {
5191 /* Exception occurred */
5192 return;
5193 }
5194
5195 /* Read from memory */
5196 if (OperandSize)
5197 {
5198 Fast486ReadMemory(State,
5199 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5200 State->SegmentOverride : FAST486_REG_DS,
5201 Offset,
5202 FALSE,
5203 &State->GeneralRegs[FAST486_REG_EAX].Long,
5204 sizeof(ULONG));
5205 }
5206 else
5207 {
5208 Fast486ReadMemory(State,
5209 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5210 State->SegmentOverride : FAST486_REG_DS,
5211 Offset,
5212 FALSE,
5213 &State->GeneralRegs[FAST486_REG_EAX].LowWord,
5214 sizeof(USHORT));
5215 }
5216 }
5217 }
5218
5219 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetAl)
5220 {
5221 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5222 ULONG Offset;
5223
5224 /* Make sure this is the right instruction */
5225 ASSERT(Opcode == 0xA2);
5226
5227 TOGGLE_ADSIZE(AddressSize);
5228
5229 if (AddressSize)
5230 {
5231 if (!Fast486FetchDword(State, &Offset))
5232 {
5233 /* Exception occurred */
5234 return;
5235 }
5236 }
5237 else
5238 {
5239 USHORT WordOffset;
5240
5241 if (!Fast486FetchWord(State, &WordOffset))
5242 {
5243 /* Exception occurred */
5244 return;
5245 }
5246
5247 Offset = (ULONG)WordOffset;
5248 }
5249
5250 /* Write to memory */
5251 Fast486WriteMemory(State,
5252 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5253 State->SegmentOverride : FAST486_REG_DS,
5254 Offset,
5255 &State->GeneralRegs[FAST486_REG_EAX].LowByte,
5256 sizeof(UCHAR));
5257 }
5258
5259 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetEax)
5260 {
5261 BOOLEAN OperandSize, AddressSize;
5262
5263 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5264
5265 /* Make sure this is the right instruction */
5266 ASSERT(Opcode == 0xA3);
5267
5268 TOGGLE_OPSIZE(OperandSize);
5269 TOGGLE_ADSIZE(AddressSize);
5270
5271 if (AddressSize)
5272 {
5273 ULONG Offset;
5274
5275 if (!Fast486FetchDword(State, &Offset))
5276 {
5277 /* Exception occurred */
5278 return;
5279 }
5280
5281 /* Write to memory */
5282 if (OperandSize)
5283 {
5284 Fast486WriteMemory(State,
5285 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5286 State->SegmentOverride : FAST486_REG_DS,
5287 Offset,
5288 &State->GeneralRegs[FAST486_REG_EAX].Long,
5289 sizeof(ULONG));
5290 }
5291 else
5292 {
5293 Fast486WriteMemory(State,
5294 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5295 State->SegmentOverride : FAST486_REG_DS,
5296 Offset,
5297 &State->GeneralRegs[FAST486_REG_EAX].LowWord,
5298 sizeof(USHORT));
5299 }
5300 }
5301 else
5302 {
5303 USHORT Offset;
5304
5305 if (!Fast486FetchWord(State, &Offset))
5306 {
5307 /* Exception occurred */
5308 return;
5309 }
5310
5311 /* Write to memory */
5312 if (OperandSize)
5313 {
5314 Fast486WriteMemory(State,
5315 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5316 State->SegmentOverride : FAST486_REG_DS,
5317 Offset,
5318 &State->GeneralRegs[FAST486_REG_EAX].Long,
5319 sizeof(ULONG));
5320 }
5321 else
5322 {
5323 Fast486WriteMemory(State,
5324 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5325 State->SegmentOverride : FAST486_REG_DS,
5326 Offset,
5327 &State->GeneralRegs[FAST486_REG_EAX].LowWord,
5328 sizeof(USHORT));
5329 }
5330 }
5331 }
5332
5333 FAST486_OPCODE_HANDLER(Fast486OpcodeSalc)
5334 {
5335 /*
5336 * See: http://www.rcollins.org/secrets/opcodes/SALC.html
5337 * for more information.
5338 */
5339
5340 /* Make sure this is the right instruction */
5341 ASSERT(Opcode == 0xD6);
5342
5343 NO_LOCK_PREFIX();
5344
5345 /* Set all the bits of AL to CF */
5346 State->GeneralRegs[FAST486_REG_EAX].LowByte = State->Flags.Cf ? 0xFF : 0x00;
5347 }
5348
5349 FAST486_OPCODE_HANDLER(Fast486OpcodeMovs)
5350 {
5351 ULONG Data, DataSize;
5352 BOOLEAN OperandSize, AddressSize;
5353 FAST486_SEG_REGS Segment = FAST486_REG_DS;
5354
5355 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5356
5357 /* Make sure this is the right instruction */
5358 ASSERT((Opcode & 0xFE) == 0xA4);
5359
5360 TOGGLE_OPSIZE(OperandSize);
5361 TOGGLE_ADSIZE(AddressSize);
5362
5363 if (State->PrefixFlags & FAST486_PREFIX_SEG)
5364 {
5365 /* Use the override segment instead of DS */
5366 Segment = State->SegmentOverride;
5367 }
5368
5369 if (State->PrefixFlags & (FAST486_PREFIX_REP | FAST486_PREFIX_REPNZ))
5370 {
5371 if ((AddressSize && (State->GeneralRegs[FAST486_REG_ECX].Long == 0))
5372 || (!AddressSize && (State->GeneralRegs[FAST486_REG_ECX].LowWord == 0)))
5373 {
5374 /* Do nothing */
5375 return;
5376 }
5377 }
5378
5379 /* Calculate the size */
5380 if (Opcode == 0xA4) DataSize = sizeof(UCHAR);
5381 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
5382
5383 /* Read from the source operand */
5384 if (!Fast486ReadMemory(State,
5385 Segment,
5386 AddressSize ? State->GeneralRegs[FAST486_REG_ESI].Long
5387 : State->GeneralRegs[FAST486_REG_ESI].LowWord,
5388 FALSE,
5389 &Data,
5390 DataSize))
5391 {
5392 /* Exception occurred */
5393 return;
5394 }
5395
5396 /* Write to the destination operand */
5397 if (!Fast486WriteMemory(State,
5398 FAST486_REG_ES,
5399 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
5400 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
5401 &Data,
5402 DataSize))
5403 {
5404 /* Exception occurred */
5405 return;
5406 }
5407
5408 /* Increment/decrement ESI and EDI */
5409 if (AddressSize)
5410 {
5411 if (!State->Flags.Df)
5412 {
5413 State->GeneralRegs[FAST486_REG_ESI].Long += DataSize;
5414 State->GeneralRegs[FAST486_REG_EDI].Long += DataSize;
5415 }
5416 else
5417 {
5418 State->GeneralRegs[FAST486_REG_ESI].Long -= DataSize;
5419 State->GeneralRegs[FAST486_REG_EDI].Long -= DataSize;
5420 }
5421 }
5422 else
5423 {
5424 if (!State->Flags.Df)
5425 {
5426 State->GeneralRegs[FAST486_REG_ESI].LowWord += DataSize;
5427 State->GeneralRegs[FAST486_REG_EDI].LowWord += DataSize;
5428 }
5429 else
5430 {
5431 State->GeneralRegs[FAST486_REG_ESI].LowWord -= DataSize;
5432 State->GeneralRegs[FAST486_REG_EDI].LowWord -= DataSize;
5433 }
5434 }
5435
5436 // FIXME: This method is slow!
5437 if (State->PrefixFlags & (FAST486_PREFIX_REP | FAST486_PREFIX_REPNZ))
5438 {
5439 if (AddressSize)
5440 {
5441 if (--State->GeneralRegs[FAST486_REG_ECX].Long)
5442 {
5443 /* Repeat the instruction */
5444 State->InstPtr = State->SavedInstPtr;
5445 }
5446 }
5447 else
5448 {
5449 if (--State->GeneralRegs[FAST486_REG_ECX].LowWord)
5450 {
5451 /* Repeat the instruction */
5452 State->InstPtr = State->SavedInstPtr;
5453 }
5454 }
5455 }
5456 }
5457
5458 FAST486_OPCODE_HANDLER(Fast486OpcodeCmps)
5459 {
5460 ULONG FirstValue = 0, SecondValue = 0, Result;
5461 ULONG DataSize, DataMask, SignFlag;
5462 BOOLEAN OperandSize, AddressSize;
5463 FAST486_SEG_REGS Segment = FAST486_REG_DS;
5464
5465 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5466
5467 /* Make sure this is the right instruction */
5468 ASSERT((Opcode & 0xFE) == 0xA6);
5469
5470 TOGGLE_OPSIZE(OperandSize);
5471 TOGGLE_ADSIZE(AddressSize);
5472
5473 if (State->PrefixFlags & FAST486_PREFIX_SEG)
5474 {
5475 /* Use the override segment instead of DS */
5476 Segment = State->SegmentOverride;
5477 }
5478
5479 if ((State->PrefixFlags & FAST486_PREFIX_REP)
5480 || (State->PrefixFlags & FAST486_PREFIX_REPNZ))
5481 {
5482 if ((AddressSize && (State->GeneralRegs[FAST486_REG_ECX].Long == 0))
5483 || (!AddressSize && (State->GeneralRegs[FAST486_REG_ECX].LowWord == 0)))
5484 {
5485 /* Do nothing */
5486 return;
5487 }
5488 }
5489
5490 /* Calculate the size */
5491 if (Opcode == 0xA6) DataSize = sizeof(UCHAR);
5492 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
5493
5494 /* Calculate the mask and sign flag */
5495 SignFlag = 1 << ((DataSize * 8) - 1);
5496 DataMask = SignFlag | (SignFlag - 1);
5497
5498 /* Read from the first source operand */
5499 if (!Fast486ReadMemory(State,
5500 Segment,
5501 AddressSize ? State->GeneralRegs[FAST486_REG_ESI].Long
5502 : State->GeneralRegs[FAST486_REG_ESI].LowWord,
5503 FALSE,
5504 &FirstValue,
5505 DataSize))
5506 {
5507 /* Exception occurred */
5508 return;
5509 }
5510
5511 /* Read from the second source operand */
5512 if (!Fast486ReadMemory(State,
5513 FAST486_REG_ES,
5514 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
5515 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
5516 FALSE,
5517 &SecondValue,
5518 DataSize))
5519 {
5520 /* Exception occurred */
5521 return;
5522 }
5523
5524 /* Calculate the result */
5525 FirstValue &= DataMask;
5526 SecondValue &= DataMask;
5527 Result = (FirstValue - SecondValue) & DataMask;
5528
5529 /* Update the flags */
5530 State->Flags.Cf = (FirstValue < SecondValue);
5531 State->Flags.Of = ((FirstValue & SignFlag) != (SecondValue & SignFlag))
5532 && ((FirstValue & SignFlag) != (Result & SignFlag));
5533 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
5534 State->Flags.Zf = (Result == 0);
5535 State->Flags.Sf = ((Result & SignFlag) != 0);
5536 State->Flags.Pf = Fast486CalculateParity(Result);
5537
5538 /* Increment/decrement ESI and EDI */
5539 if (AddressSize)
5540 {
5541 if (!State->Flags.Df)
5542 {
5543 State->GeneralRegs[FAST486_REG_ESI].Long += DataSize;
5544 State->GeneralRegs[FAST486_REG_EDI].Long += DataSize;
5545 }
5546 else
5547 {
5548 State->GeneralRegs[FAST486_REG_ESI].Long -= DataSize;
5549 State->GeneralRegs[FAST486_REG_EDI].Long -= DataSize;
5550 }
5551 }
5552 else
5553 {
5554 if (!State->Flags.Df)
5555 {
5556 State->GeneralRegs[FAST486_REG_ESI].LowWord += DataSize;
5557 State->GeneralRegs[FAST486_REG_EDI].LowWord += DataSize;
5558 }
5559 else
5560 {
5561 State->GeneralRegs[FAST486_REG_ESI].LowWord -= DataSize;
5562 State->GeneralRegs[FAST486_REG_EDI].LowWord -= DataSize;
5563 }
5564 }
5565
5566 // FIXME: This method is slow!
5567 if ((State->PrefixFlags & FAST486_PREFIX_REP)
5568 || (State->PrefixFlags & FAST486_PREFIX_REPNZ))
5569 {
5570 BOOLEAN Repeat = TRUE;
5571
5572 if (AddressSize)
5573 {
5574 if ((--State->GeneralRegs[FAST486_REG_ECX].Long) == 0)
5575 {
5576 /* ECX is 0 */
5577 Repeat = FALSE;
5578 }
5579 }
5580 else
5581 {
5582 if ((--State->GeneralRegs[FAST486_REG_ECX].LowWord) == 0)
5583 {
5584 /* CX is 0 */
5585 Repeat = FALSE;
5586 }
5587 }
5588
5589 if (((State->PrefixFlags & FAST486_PREFIX_REP) && !State->Flags.Zf)
5590 || ((State->PrefixFlags & FAST486_PREFIX_REPNZ) && State->Flags.Zf))
5591 {
5592 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
5593 Repeat = FALSE;
5594 }
5595
5596 if (Repeat)
5597 {
5598 /* Repeat the instruction */
5599 State->InstPtr = State->SavedInstPtr;
5600 }
5601 }
5602 }
5603
5604 FAST486_OPCODE_HANDLER(Fast486OpcodeStos)
5605 {
5606 ULONG DataSize;
5607 BOOLEAN OperandSize, AddressSize;
5608
5609 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5610
5611 /* Make sure this is the right instruction */
5612 ASSERT((Opcode & 0xFE) == 0xAA);
5613
5614 TOGGLE_OPSIZE(OperandSize);
5615 TOGGLE_ADSIZE(AddressSize);
5616
5617 /* Calculate the size */
5618 if (Opcode == 0xAA) DataSize = sizeof(UCHAR);
5619 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
5620
5621 if (State->PrefixFlags & (FAST486_PREFIX_REP | FAST486_PREFIX_REPNZ))
5622 {
5623 UCHAR Block[STRING_BLOCK_SIZE];
5624 ULONG Count = AddressSize ? State->GeneralRegs[FAST486_REG_ECX].Long
5625 : State->GeneralRegs[FAST486_REG_ECX].LowWord;
5626
5627 /* Fill the memory block with the data */
5628 if (DataSize == sizeof(UCHAR))
5629 {
5630 RtlFillMemory(Block, sizeof(Block), State->GeneralRegs[FAST486_REG_EAX].LowByte);
5631 }
5632 else
5633 {
5634 ULONG i;
5635
5636 for (i = 0; i < STRING_BLOCK_SIZE / DataSize; i++)
5637 {
5638 if (DataSize == sizeof(USHORT))
5639 {
5640 ((PUSHORT)Block)[i] = State->GeneralRegs[FAST486_REG_EAX].LowWord;
5641 }
5642 else
5643 {
5644 ((PULONG)Block)[i] = State->GeneralRegs[FAST486_REG_EAX].Long;
5645 }
5646 }
5647 }
5648
5649 /* Transfer until finished */
5650 while (Count)
5651 {
5652 ULONG Processed = min(Count, STRING_BLOCK_SIZE / DataSize);
5653
5654 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
5655 if (!AddressSize)
5656 {
5657 ULONG MaxBytes = State->Flags.Df
5658 ? (ULONG)State->GeneralRegs[FAST486_REG_EDI].LowWord
5659 : (0x10000 - (ULONG)State->GeneralRegs[FAST486_REG_EDI].LowWord);
5660
5661 Processed = min(Processed, MaxBytes / DataSize);
5662 if (Processed == 0) Processed = 1;
5663 }
5664
5665 if (State->Flags.Df)
5666 {
5667 /* Set EDI to the starting location */
5668 if (AddressSize) State->GeneralRegs[FAST486_REG_EDI].Long -= (Processed - 1) * DataSize;
5669 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= (Processed - 1) * DataSize;
5670 }
5671
5672 /* Write to memory */
5673 if (!Fast486WriteMemory(State,
5674 FAST486_REG_ES,
5675 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
5676 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
5677 Block,
5678 Processed * DataSize))
5679 {
5680 /* Set ECX */
5681 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = Count;
5682 else State->GeneralRegs[FAST486_REG_ECX].LowWord = LOWORD(Count);
5683
5684 /* Exception occurred */
5685 return;
5686 }
5687
5688 if (!State->Flags.Df)
5689 {
5690 /* Increase EDI by the number of bytes transfered */
5691 if (AddressSize) State->GeneralRegs[FAST486_REG_EDI].Long += Processed * DataSize;
5692 else State->GeneralRegs[FAST486_REG_EDI].LowWord += Processed * DataSize;
5693 }
5694 else
5695 {
5696 /* Reduce EDI */
5697 if (AddressSize) State->GeneralRegs[FAST486_REG_EDI].Long -= DataSize;
5698 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= DataSize;
5699 }
5700
5701 /* Reduce the total count by the number processed in this run */
5702 Count -= Processed;
5703 }
5704
5705 /* Clear ECX */
5706 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = 0;
5707 else State->GeneralRegs[FAST486_REG_ECX].LowWord = 0;
5708 }
5709 else
5710 {
5711 /* Write to the destination operand */
5712 if (!Fast486WriteMemory(State,
5713 FAST486_REG_ES,
5714 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
5715 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
5716 &State->GeneralRegs[FAST486_REG_EAX].Long,
5717 DataSize))
5718 {
5719 /* Exception occurred */
5720 return;
5721 }
5722
5723 /* Increment/decrement EDI */
5724 if (AddressSize)
5725 {
5726 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_EDI].Long += DataSize;
5727 else State->GeneralRegs[FAST486_REG_EDI].Long -= DataSize;
5728 }
5729 else
5730 {
5731 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_EDI].LowWord += DataSize;
5732 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= DataSize;
5733 }
5734 }
5735 }
5736
5737 FAST486_OPCODE_HANDLER(Fast486OpcodeLods)
5738 {
5739 ULONG DataSize;
5740 BOOLEAN OperandSize, AddressSize;
5741 FAST486_SEG_REGS Segment = FAST486_REG_DS;
5742
5743 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5744
5745 /* Make sure this is the right instruction */
5746 ASSERT((Opcode & 0xFE) == 0xAC);
5747
5748 TOGGLE_OPSIZE(OperandSize);
5749 TOGGLE_ADSIZE(AddressSize);
5750
5751 if (State->PrefixFlags & FAST486_PREFIX_SEG)
5752 {
5753 /* Use the override segment instead of DS */
5754 Segment = State->SegmentOverride;
5755 }
5756
5757 /* Calculate the size */
5758 if (Opcode == 0xAC) DataSize = sizeof(UCHAR);
5759 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
5760
5761 if (State->PrefixFlags & (FAST486_PREFIX_REP | FAST486_PREFIX_REPNZ))
5762 {
5763 ULONG Count = AddressSize ? State->GeneralRegs[FAST486_REG_ECX].Long
5764 : State->GeneralRegs[FAST486_REG_ECX].LowWord;
5765
5766 /* If the count is 0, do nothing */
5767 if (Count == 0) return;
5768
5769 /* Only the last entry will be loaded */
5770 if (!State->Flags.Df)
5771 {
5772 if (AddressSize) State->GeneralRegs[FAST486_REG_ESI].Long += (Count - 1) * DataSize;
5773 else State->GeneralRegs[FAST486_REG_ESI].LowWord += (Count - 1) * DataSize;
5774 }
5775 else
5776 {
5777 if (AddressSize) State->GeneralRegs[FAST486_REG_ESI].Long -= (Count - 1) * DataSize;
5778 else State->GeneralRegs[FAST486_REG_ESI].LowWord -= (Count - 1) * DataSize;
5779 }
5780
5781 /* Clear ECX */
5782 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = 0;
5783 else State->GeneralRegs[FAST486_REG_ECX].LowWord = 0;
5784 }
5785
5786 /* Read from the source operand */
5787 if (!Fast486ReadMemory(State,
5788 Segment,
5789 AddressSize ? State->GeneralRegs[FAST486_REG_ESI].Long
5790 : State->GeneralRegs[FAST486_REG_ESI].LowWord,
5791 FALSE,
5792 &State->GeneralRegs[FAST486_REG_EAX].Long,
5793 DataSize))
5794 {
5795 /* Exception occurred */
5796 return;
5797 }
5798
5799 /* Increment/decrement ESI */
5800 if (AddressSize)
5801 {
5802 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_ESI].Long += DataSize;
5803 else State->GeneralRegs[FAST486_REG_ESI].Long -= DataSize;
5804 }
5805 else
5806 {
5807 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_ESI].LowWord += DataSize;
5808 else State->GeneralRegs[FAST486_REG_ESI].LowWord -= DataSize;
5809 }
5810 }
5811
5812 FAST486_OPCODE_HANDLER(Fast486OpcodeScas)
5813 {
5814 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
5815 ULONG SecondValue = 0;
5816 ULONG Result;
5817 ULONG DataSize, DataMask, SignFlag;
5818 BOOLEAN OperandSize, AddressSize;
5819
5820 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5821
5822 /* Make sure this is the right instruction */
5823 ASSERT((Opcode & 0xFE) == 0xAE);
5824
5825 TOGGLE_OPSIZE(OperandSize);
5826 TOGGLE_ADSIZE(AddressSize);
5827
5828 if ((State->PrefixFlags & FAST486_PREFIX_REP)
5829 || (State->PrefixFlags & FAST486_PREFIX_REPNZ))
5830 {
5831 if ((AddressSize && (State->GeneralRegs[FAST486_REG_ECX].Long == 0))
5832 || (!AddressSize && (State->GeneralRegs[FAST486_REG_ECX].LowWord == 0)))
5833 {
5834 /* Do nothing */
5835 return;
5836 }
5837 }
5838
5839 /* Calculate the size */
5840 if (Opcode == 0xAE) DataSize = sizeof(UCHAR);
5841 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
5842
5843 /* Calculate the mask and sign flag */
5844 SignFlag = 1 << ((DataSize * 8) - 1);
5845 DataMask = SignFlag | (SignFlag - 1);
5846
5847 /* Read from the source operand */
5848 if (!Fast486ReadMemory(State,
5849 FAST486_REG_ES,
5850 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
5851 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
5852 FALSE,
5853 &SecondValue,
5854 DataSize))
5855 {
5856 /* Exception occurred */
5857 return;
5858 }
5859
5860 /* Calculate the result */
5861 FirstValue &= DataMask;
5862 SecondValue &= DataMask;
5863 Result = (FirstValue - SecondValue) & DataMask;
5864
5865 /* Update the flags */
5866 State->Flags.Cf = (FirstValue < SecondValue);
5867 State->Flags.Of = ((FirstValue & SignFlag) != (SecondValue & SignFlag))
5868 && ((FirstValue & SignFlag) != (Result & SignFlag));
5869 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
5870 State->Flags.Zf = (Result == 0);
5871 State->Flags.Sf = ((Result & SignFlag) != 0);
5872 State->Flags.Pf = Fast486CalculateParity(Result);
5873
5874 /* Increment/decrement EDI */
5875 if (AddressSize)
5876 {
5877 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_EDI].Long += DataSize;
5878 else State->GeneralRegs[FAST486_REG_EDI].Long -= DataSize;
5879 }
5880 else
5881 {
5882 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_EDI].LowWord += DataSize;
5883 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= DataSize;
5884 }
5885
5886 // FIXME: This method is slow!
5887 if ((State->PrefixFlags & FAST486_PREFIX_REP)
5888 || (State->PrefixFlags & FAST486_PREFIX_REPNZ))
5889 {
5890 BOOLEAN Repeat = TRUE;
5891
5892 if (AddressSize)
5893 {
5894 if ((--State->GeneralRegs[FAST486_REG_ECX].Long) == 0)
5895 {
5896 /* ECX is 0 */
5897 Repeat = FALSE;
5898 }
5899 }
5900 else
5901 {
5902 if ((--State->GeneralRegs[FAST486_REG_ECX].LowWord) == 0)
5903 {
5904 /* CX is 0 */
5905 Repeat = FALSE;
5906 }
5907 }
5908
5909 if (((State->PrefixFlags & FAST486_PREFIX_REP) && !State->Flags.Zf)
5910 || ((State->PrefixFlags & FAST486_PREFIX_REPNZ) && State->Flags.Zf))
5911 {
5912 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
5913 Repeat = FALSE;
5914 }
5915
5916 if (Repeat)
5917 {
5918 /* Repeat the instruction */
5919 State->InstPtr = State->SavedInstPtr;
5920 }
5921 }
5922 }
5923
5924 FAST486_OPCODE_HANDLER(Fast486OpcodeIns)
5925 {
5926 ULONG DataSize;
5927 BOOLEAN OperandSize, AddressSize;
5928
5929 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5930
5931 /* Make sure this is the right instruction */
5932 ASSERT((Opcode & 0xFE) == 0x6C);
5933
5934 TOGGLE_OPSIZE(OperandSize);
5935 TOGGLE_ADSIZE(AddressSize);
5936
5937 /* Calculate the size */
5938 if (Opcode == 0x6C) DataSize = sizeof(UCHAR);
5939 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
5940
5941 if (State->PrefixFlags & (FAST486_PREFIX_REP | FAST486_PREFIX_REPNZ))
5942 {
5943 UCHAR Block[STRING_BLOCK_SIZE];
5944 ULONG Count = AddressSize ? State->GeneralRegs[FAST486_REG_ECX].Long
5945 : State->GeneralRegs[FAST486_REG_ECX].LowWord;
5946
5947 /* Clear the memory block */
5948 RtlZeroMemory(Block, sizeof(Block));
5949
5950 /* Transfer until finished */
5951 while (Count)
5952 {
5953 ULONG Processed = min(Count, STRING_BLOCK_SIZE / DataSize);
5954
5955 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
5956 if (!AddressSize)
5957 {
5958 ULONG MaxBytes = State->Flags.Df
5959 ? (ULONG)State->GeneralRegs[FAST486_REG_EDI].LowWord
5960 : (0x10000 - (ULONG)State->GeneralRegs[FAST486_REG_EDI].LowWord);
5961
5962 Processed = min(Processed, MaxBytes / DataSize);
5963 if (Processed == 0) Processed = 1;
5964 }
5965
5966 /* Read from the I/O port */
5967 State->IoReadCallback(State,
5968 State->GeneralRegs[FAST486_REG_EDX].LowWord,
5969 Block,
5970 Processed,
5971 DataSize);
5972
5973 if (State->Flags.Df)
5974 {
5975 ULONG i, j;
5976
5977 /* Reduce EDI by the number of bytes to transfer */
5978 if (AddressSize) State->GeneralRegs[FAST486_REG_EDI].Long -= Processed * DataSize;
5979 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= Processed * DataSize;
5980
5981 /* Reverse the block data */
5982 for (i = 0; i < Processed / 2; i++)
5983 {
5984 /* Swap the values */
5985 for (j = 0; j < DataSize; j++)
5986 {
5987 UCHAR Temp = Block[i * DataSize + j];
5988 Block[i * DataSize + j] = Block[(Processed - i - 1) * DataSize + j];
5989 Block[(Processed - i - 1) * DataSize + j] = Temp;
5990 }
5991 }
5992 }
5993
5994 /* Write to memory */
5995 if (!Fast486WriteMemory(State,
5996 FAST486_REG_ES,
5997 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
5998 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
5999 Block,
6000 Processed * DataSize))
6001 {
6002 /* Set ECX */
6003 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = Count;
6004 else State->GeneralRegs[FAST486_REG_ECX].LowWord = LOWORD(Count);
6005
6006 /* Exception occurred */
6007 return;
6008 }
6009
6010 if (!State->Flags.Df)
6011 {
6012 /* Increase EDI by the number of bytes transfered */
6013 if (AddressSize) State->GeneralRegs[FAST486_REG_EDI].Long += Processed * DataSize;
6014 else State->GeneralRegs[FAST486_REG_EDI].LowWord += Processed * DataSize;
6015 }
6016
6017 /* Reduce the total count by the number processed in this run */
6018 Count -= Processed;
6019 }
6020
6021 /* Clear ECX */
6022 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = 0;
6023 else State->GeneralRegs[FAST486_REG_ECX].LowWord = 0;
6024 }
6025 else
6026 {
6027 ULONG Data = 0;
6028
6029 /* Read from the I/O port */
6030 State->IoReadCallback(State,
6031 State->GeneralRegs[FAST486_REG_EDX].LowWord,
6032 &Data,
6033 1,
6034 DataSize);
6035
6036 /* Write to the destination operand */
6037 if (!Fast486WriteMemory(State,
6038 FAST486_REG_ES,
6039 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
6040 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
6041 &Data,
6042 DataSize))
6043 {
6044 /* Exception occurred */
6045 return;
6046 }
6047
6048 /* Increment/decrement EDI */
6049 if (AddressSize)
6050 {
6051 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_EDI].Long += DataSize;
6052 else State->GeneralRegs[FAST486_REG_EDI].Long -= DataSize;
6053 }
6054 else
6055 {
6056 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_EDI].LowWord += DataSize;
6057 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= DataSize;
6058 }
6059 }
6060 }
6061
6062 FAST486_OPCODE_HANDLER(Fast486OpcodeOuts)
6063 {
6064 ULONG DataSize;
6065 BOOLEAN OperandSize, AddressSize;
6066
6067 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
6068
6069 /* Make sure this is the right instruction */
6070 ASSERT((Opcode & 0xFE) == 0x6E);
6071
6072 TOGGLE_OPSIZE(OperandSize);
6073 TOGGLE_ADSIZE(AddressSize);
6074
6075 /* Calculate the size */
6076 if (Opcode == 0x6E) DataSize = sizeof(UCHAR);
6077 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
6078
6079 if (State->PrefixFlags & (FAST486_PREFIX_REP | FAST486_PREFIX_REPNZ))
6080 {
6081 UCHAR Block[STRING_BLOCK_SIZE];
6082 ULONG Count = AddressSize ? State->GeneralRegs[FAST486_REG_ECX].Long
6083 : State->GeneralRegs[FAST486_REG_ECX].LowWord;
6084
6085 /* Clear the memory block */
6086 RtlZeroMemory(Block, sizeof(Block));
6087
6088 /* Transfer until finished */
6089 while (Count)
6090 {
6091 ULONG Processed = min(Count, STRING_BLOCK_SIZE / DataSize);
6092
6093 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
6094 if (!AddressSize)
6095 {
6096 ULONG MaxBytes = State->Flags.Df
6097 ? (ULONG)State->GeneralRegs[FAST486_REG_ESI].LowWord
6098 : (0x10000 - (ULONG)State->GeneralRegs[FAST486_REG_ESI].LowWord);
6099
6100 Processed = min(Processed, MaxBytes / DataSize);
6101 if (Processed == 0) Processed = 1;
6102 }
6103
6104 /* Read from memory */
6105 if (!Fast486ReadMemory(State,
6106 (State->PrefixFlags & FAST486_PREFIX_SEG)
6107 ? State->SegmentOverride : FAST486_REG_DS,
6108 AddressSize ? State->GeneralRegs[FAST486_REG_ESI].Long
6109 : State->GeneralRegs[FAST486_REG_ESI].LowWord,
6110 FALSE,
6111 Block,
6112 Processed * DataSize))
6113 {
6114 /* Set ECX */
6115 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = Count;
6116 else State->GeneralRegs[FAST486_REG_ECX].LowWord = LOWORD(Count);
6117
6118 /* Exception occurred */
6119 return;
6120 }
6121
6122 if (State->Flags.Df)
6123 {
6124 ULONG i, j;
6125
6126 /* Reduce ESI by the number of bytes to transfer */
6127 if (AddressSize) State->GeneralRegs[FAST486_REG_ESI].Long -= Processed * DataSize;
6128 else State->GeneralRegs[FAST486_REG_ESI].LowWord -= Processed * DataSize;
6129
6130 /* Reverse the block data */
6131 for (i = 0; i < Processed / 2; i++)
6132 {
6133 /* Swap the values */
6134 for (j = 0; j < DataSize; j++)
6135 {
6136 UCHAR Temp = Block[i * DataSize + j];
6137 Block[i * DataSize + j] = Block[(Processed - i - 1) * DataSize + j];
6138 Block[(Processed - i - 1) * DataSize + j] = Temp;
6139 }
6140 }
6141 }
6142
6143 /* Write to the I/O port */
6144 State->IoWriteCallback(State,
6145 State->GeneralRegs[FAST486_REG_EDX].LowWord,
6146 Block,
6147 Processed,
6148 DataSize);
6149
6150 if (!State->Flags.Df)
6151 {
6152 /* Increase ESI by the number of bytes transfered */
6153 if (AddressSize) State->GeneralRegs[FAST486_REG_ESI].Long += Processed * DataSize;
6154 else State->GeneralRegs[FAST486_REG_ESI].LowWord += Processed * DataSize;
6155 }
6156
6157 /* Reduce the total count by the number processed in this run */
6158 Count -= Processed;
6159 }
6160
6161 /* Clear ECX */
6162 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = 0;
6163 else State->GeneralRegs[FAST486_REG_ECX].LowWord = 0;
6164 }
6165 else
6166 {
6167 ULONG Data = 0;
6168
6169 /* Read from the source operand */
6170 if (!Fast486ReadMemory(State,
6171 (State->PrefixFlags & FAST486_PREFIX_SEG)
6172 ? State->SegmentOverride : FAST486_REG_DS,
6173 AddressSize ? State->GeneralRegs[FAST486_REG_ESI].Long
6174 : State->GeneralRegs[FAST486_REG_ESI].LowWord,
6175 FALSE,
6176 &Data,
6177 DataSize))
6178 {
6179 /* Exception occurred */
6180 return;
6181 }
6182
6183 /* Write to the I/O port */
6184 State->IoWriteCallback(State,
6185 State->GeneralRegs[FAST486_REG_EDX].LowWord,
6186 &Data,
6187 1,
6188 DataSize);
6189
6190 /* Increment/decrement ESI */
6191 if (AddressSize)
6192 {
6193 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_ESI].Long += DataSize;
6194 else State->GeneralRegs[FAST486_REG_ESI].Long -= DataSize;
6195 }
6196 else
6197 {
6198 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_ESI].LowWord += DataSize;
6199 else State->GeneralRegs[FAST486_REG_ESI].LowWord -= DataSize;
6200 }
6201 }
6202 }
6203
6204 /* EOF */