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