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