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