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