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