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