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