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