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