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