1 /* 2 * Fast486 386/486 CPU Emulation Library 3 * extraops.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 "common.h" 32 #include "opgroups.h" 33 #include "extraops.h" 34 35 /* PUBLIC VARIABLES ***********************************************************/ 36 37 FAST486_OPCODE_HANDLER_PROC 38 Fast486ExtendedHandlers[FAST486_NUM_OPCODE_HANDLERS] = 39 { 40 Fast486ExtOpcodeGroup0F00, /* 0x00 - 0x01 */ 41 Fast486ExtOpcodeGroup0F01, 42 Fast486ExtOpcodeLar, /* 0x02 */ 43 Fast486ExtOpcodeLsl, /* 0x03 */ 44 Fast486ExtOpcodeInvalid, /* 0x04 - 0x05 */ // Invalid 45 Fast486ExtOpcodeInvalid, // Invalid 46 Fast486ExtOpcodeClts, /* 0x06 */ 47 Fast486ExtOpcodeInvalid, /* 0x07 */ // Invalid 48 Fast486ExtOpcodeUnimplemented, // TODO: OPCODE 0x08 NOT IMPLEMENTED 49 Fast486ExtOpcodeUnimplemented, // TODO: OPCODE 0x09 NOT IMPLEMENTED 50 Fast486ExtOpcodeInvalid, /* 0x0A */ // Invalid 51 Fast486ExtOpcode0F0B, /* 0x0B */ // Reserved (UD2) 52 Fast486ExtOpcodeInvalid, /* 0x0C - 0x1F */ // Invalid 53 Fast486ExtOpcodeInvalid, // Invalid 54 Fast486ExtOpcodeInvalid, // Invalid 55 Fast486ExtOpcodeInvalid, // Invalid 56 Fast486ExtOpcodeInvalid, // Invalid 57 Fast486ExtOpcodeInvalid, // Invalid 58 Fast486ExtOpcodeInvalid, // Invalid 59 Fast486ExtOpcodeInvalid, // Invalid 60 Fast486ExtOpcodeInvalid, // Invalid 61 Fast486ExtOpcodeInvalid, // Invalid 62 Fast486ExtOpcodeInvalid, // Invalid 63 Fast486ExtOpcodeInvalid, // Invalid 64 Fast486ExtOpcodeInvalid, // Invalid 65 Fast486ExtOpcodeInvalid, // Invalid 66 Fast486ExtOpcodeInvalid, // Invalid 67 Fast486ExtOpcodeInvalid, // Invalid 68 Fast486ExtOpcodeInvalid, // Invalid 69 Fast486ExtOpcodeInvalid, // Invalid 70 Fast486ExtOpcodeInvalid, // Invalid 71 Fast486ExtOpcodeInvalid, // Invalid 72 Fast486ExtOpcodeStoreControlReg, /* 0x20 */ 73 Fast486ExtOpcodeStoreDebugReg, /* 0x21 */ 74 Fast486ExtOpcodeLoadControlReg, /* 0x22 */ 75 Fast486ExtOpcodeLoadDebugReg, /* 0x23 */ 76 Fast486ExtOpcodeUnimplemented, // TODO: OPCODE 0x24 NOT IMPLEMENTED 77 Fast486ExtOpcodeInvalid, /* 0x25 */ // Invalid 78 Fast486ExtOpcodeUnimplemented, // TODO: OPCODE 0x26 NOT IMPLEMENTED 79 Fast486ExtOpcodeInvalid, /* 0x27 - 0x7F */ // Invalid 80 Fast486ExtOpcodeInvalid, // Invalid 81 Fast486ExtOpcodeInvalid, // Invalid 82 Fast486ExtOpcodeInvalid, // Invalid 83 Fast486ExtOpcodeInvalid, // Invalid 84 Fast486ExtOpcodeInvalid, // Invalid 85 Fast486ExtOpcodeInvalid, // Invalid 86 Fast486ExtOpcodeInvalid, // Invalid 87 Fast486ExtOpcodeInvalid, // Invalid 88 Fast486ExtOpcodeInvalid, // Invalid 89 Fast486ExtOpcodeInvalid, // Invalid 90 Fast486ExtOpcodeInvalid, // Invalid 91 Fast486ExtOpcodeInvalid, // Invalid 92 Fast486ExtOpcodeInvalid, // Invalid 93 Fast486ExtOpcodeInvalid, // Invalid 94 Fast486ExtOpcodeInvalid, // Invalid 95 Fast486ExtOpcodeInvalid, // Invalid 96 Fast486ExtOpcodeInvalid, // Invalid 97 Fast486ExtOpcodeInvalid, // Invalid 98 Fast486ExtOpcodeInvalid, // Invalid 99 Fast486ExtOpcodeInvalid, // Invalid 100 Fast486ExtOpcodeInvalid, // Invalid 101 Fast486ExtOpcodeInvalid, // Invalid 102 Fast486ExtOpcodeInvalid, // Invalid 103 Fast486ExtOpcodeInvalid, // Invalid 104 Fast486ExtOpcodeInvalid, // Invalid 105 Fast486ExtOpcodeInvalid, // Invalid 106 Fast486ExtOpcodeInvalid, // Invalid 107 Fast486ExtOpcodeInvalid, // Invalid 108 Fast486ExtOpcodeInvalid, // Invalid 109 Fast486ExtOpcodeInvalid, // Invalid 110 Fast486ExtOpcodeInvalid, // Invalid 111 Fast486ExtOpcodeInvalid, // Invalid 112 Fast486ExtOpcodeInvalid, // Invalid 113 Fast486ExtOpcodeInvalid, // Invalid 114 Fast486ExtOpcodeInvalid, // Invalid 115 Fast486ExtOpcodeInvalid, // Invalid 116 Fast486ExtOpcodeInvalid, // Invalid 117 Fast486ExtOpcodeInvalid, // Invalid 118 Fast486ExtOpcodeInvalid, // Invalid 119 Fast486ExtOpcodeInvalid, // Invalid 120 Fast486ExtOpcodeInvalid, // Invalid 121 Fast486ExtOpcodeInvalid, // Invalid 122 Fast486ExtOpcodeInvalid, // Invalid 123 Fast486ExtOpcodeInvalid, // Invalid 124 Fast486ExtOpcodeInvalid, // Invalid 125 Fast486ExtOpcodeInvalid, // Invalid 126 Fast486ExtOpcodeInvalid, // Invalid 127 Fast486ExtOpcodeInvalid, // Invalid 128 Fast486ExtOpcodeInvalid, // Invalid 129 Fast486ExtOpcodeInvalid, // Invalid 130 Fast486ExtOpcodeInvalid, // Invalid 131 Fast486ExtOpcodeInvalid, // Invalid 132 Fast486ExtOpcodeInvalid, // Invalid 133 Fast486ExtOpcodeInvalid, // Invalid 134 Fast486ExtOpcodeInvalid, // Invalid 135 Fast486ExtOpcodeInvalid, // Invalid 136 Fast486ExtOpcodeInvalid, // Invalid 137 Fast486ExtOpcodeInvalid, // Invalid 138 Fast486ExtOpcodeInvalid, // Invalid 139 Fast486ExtOpcodeInvalid, // Invalid 140 Fast486ExtOpcodeInvalid, // Invalid 141 Fast486ExtOpcodeInvalid, // Invalid 142 Fast486ExtOpcodeInvalid, // Invalid 143 Fast486ExtOpcodeInvalid, // Invalid 144 Fast486ExtOpcodeInvalid, // Invalid 145 Fast486ExtOpcodeInvalid, // Invalid 146 Fast486ExtOpcodeInvalid, // Invalid 147 Fast486ExtOpcodeInvalid, // Invalid 148 Fast486ExtOpcodeInvalid, // Invalid 149 Fast486ExtOpcodeInvalid, // Invalid 150 Fast486ExtOpcodeInvalid, // Invalid 151 Fast486ExtOpcodeInvalid, // Invalid 152 Fast486ExtOpcodeInvalid, // Invalid 153 Fast486ExtOpcodeInvalid, // Invalid 154 Fast486ExtOpcodeInvalid, // Invalid 155 Fast486ExtOpcodeInvalid, // Invalid 156 Fast486ExtOpcodeInvalid, // Invalid 157 Fast486ExtOpcodeInvalid, // Invalid 158 Fast486ExtOpcodeInvalid, // Invalid 159 Fast486ExtOpcodeInvalid, // Invalid 160 Fast486ExtOpcodeInvalid, // Invalid 161 Fast486ExtOpcodeInvalid, // Invalid 162 Fast486ExtOpcodeInvalid, // Invalid 163 Fast486ExtOpcodeInvalid, // Invalid 164 Fast486ExtOpcodeInvalid, // Invalid 165 Fast486ExtOpcodeInvalid, // Invalid 166 Fast486ExtOpcodeInvalid, // Invalid 167 Fast486ExtOpcodeInvalid, // Invalid 168 Fast486ExtOpcodeConditionalJmp, /* 0x80 - 0x8F */ 169 Fast486ExtOpcodeConditionalJmp, 170 Fast486ExtOpcodeConditionalJmp, 171 Fast486ExtOpcodeConditionalJmp, 172 Fast486ExtOpcodeConditionalJmp, 173 Fast486ExtOpcodeConditionalJmp, 174 Fast486ExtOpcodeConditionalJmp, 175 Fast486ExtOpcodeConditionalJmp, 176 Fast486ExtOpcodeConditionalJmp, 177 Fast486ExtOpcodeConditionalJmp, 178 Fast486ExtOpcodeConditionalJmp, 179 Fast486ExtOpcodeConditionalJmp, 180 Fast486ExtOpcodeConditionalJmp, 181 Fast486ExtOpcodeConditionalJmp, 182 Fast486ExtOpcodeConditionalJmp, 183 Fast486ExtOpcodeConditionalJmp, 184 Fast486ExtOpcodeConditionalSet, /* 0x90 - 0x9F */ 185 Fast486ExtOpcodeConditionalSet, 186 Fast486ExtOpcodeConditionalSet, 187 Fast486ExtOpcodeConditionalSet, 188 Fast486ExtOpcodeConditionalSet, 189 Fast486ExtOpcodeConditionalSet, 190 Fast486ExtOpcodeConditionalSet, 191 Fast486ExtOpcodeConditionalSet, 192 Fast486ExtOpcodeConditionalSet, 193 Fast486ExtOpcodeConditionalSet, 194 Fast486ExtOpcodeConditionalSet, 195 Fast486ExtOpcodeConditionalSet, 196 Fast486ExtOpcodeConditionalSet, 197 Fast486ExtOpcodeConditionalSet, 198 Fast486ExtOpcodeConditionalSet, 199 Fast486ExtOpcodeConditionalSet, 200 Fast486ExtOpcodePushFs, /* 0xA0 */ 201 Fast486ExtOpcodePopFs, /* 0xA1 */ 202 Fast486ExtOpcodeInvalid, /* 0xA2 */ // Invalid 203 Fast486ExtOpcodeBitTest, /* 0xA3 */ 204 Fast486ExtOpcodeShld, /* 0xA4 - 0xA5 */ 205 Fast486ExtOpcodeShld, 206 Fast486ExtOpcodeInvalid, /* 0xA6 - 0xA7 */ // Invalid 207 Fast486ExtOpcodeInvalid, // Invalid 208 Fast486ExtOpcodePushGs, /* 0xA8 - 0xA9 */ 209 Fast486ExtOpcodePopGs, 210 Fast486ExtOpcodeInvalid, /* 0xAA */ // Invalid 211 Fast486ExtOpcodeBts, /* 0xAB */ 212 Fast486ExtOpcodeShrd, /* 0xAC - 0xAD */ 213 Fast486ExtOpcodeShrd, 214 Fast486ExtOpcodeInvalid, /* 0xAE */ // Invalid 215 Fast486ExtOpcodeImul, /* 0xAF */ 216 Fast486ExtOpcodeCmpXchgByte, /* 0xB0 */ 217 Fast486ExtOpcodeCmpXchg, /* 0xB1 */ 218 Fast486ExtOpcodeLss, /* 0xB2 */ 219 Fast486ExtOpcodeBtr, /* 0xB3 */ 220 Fast486ExtOpcodeLfsLgs, /* 0xB4 - 0xB5 */ 221 Fast486ExtOpcodeLfsLgs, 222 Fast486ExtOpcodeMovzxByte, /* 0xB6 - 0xB7 */ 223 Fast486ExtOpcodeMovzxWord, 224 Fast486ExtOpcodeInvalid, /* 0xB8 */ // Invalid 225 Fast486ExtOpcodeGroup0FB9, /* 0xB9 */ 226 Fast486ExtOpcodeGroup0FBA, /* 0xBA */ 227 Fast486ExtOpcodeBtc, /* 0xBB */ 228 Fast486ExtOpcodeBsf, /* 0xBC */ 229 Fast486ExtOpcodeBsr, /* 0xBD */ 230 Fast486ExtOpcodeMovsxByte, /* 0xBE - 0xBF */ 231 Fast486ExtOpcodeMovsxWord, 232 Fast486ExtOpcodeXaddByte, /* 0xC0 - 0xC1 */ 233 Fast486ExtOpcodeXadd, 234 Fast486ExtOpcodeInvalid, /* 0xC2 - 0xC7 */ // Invalid 235 Fast486ExtOpcodeInvalid, // Invalid 236 Fast486ExtOpcodeInvalid, // Invalid 237 Fast486ExtOpcodeInvalid, // Invalid 238 Fast486ExtOpcodeInvalid, // Invalid 239 Fast486ExtOpcodeInvalid, // Invalid 240 Fast486ExtOpcodeBswap, /* 0xC8 - 0xCF */ 241 Fast486ExtOpcodeBswap, 242 Fast486ExtOpcodeBswap, 243 Fast486ExtOpcodeBswap, 244 Fast486ExtOpcodeBswap, 245 Fast486ExtOpcodeBswap, 246 Fast486ExtOpcodeBswap, 247 Fast486ExtOpcodeBswap, 248 Fast486ExtOpcodeInvalid, /* 0xD0 - 0xFF */ // Invalid 249 Fast486ExtOpcodeInvalid, // Invalid 250 Fast486ExtOpcodeInvalid, // Invalid 251 Fast486ExtOpcodeInvalid, // Invalid 252 Fast486ExtOpcodeInvalid, // Invalid 253 Fast486ExtOpcodeInvalid, // Invalid 254 Fast486ExtOpcodeInvalid, // Invalid 255 Fast486ExtOpcodeInvalid, // Invalid 256 Fast486ExtOpcodeInvalid, // Invalid 257 Fast486ExtOpcodeInvalid, // Invalid 258 Fast486ExtOpcodeInvalid, // Invalid 259 Fast486ExtOpcodeInvalid, // Invalid 260 Fast486ExtOpcodeInvalid, // Invalid 261 Fast486ExtOpcodeInvalid, // Invalid 262 Fast486ExtOpcodeInvalid, // Invalid 263 Fast486ExtOpcodeInvalid, // Invalid 264 Fast486ExtOpcodeInvalid, // Invalid 265 Fast486ExtOpcodeInvalid, // Invalid 266 Fast486ExtOpcodeInvalid, // Invalid 267 Fast486ExtOpcodeInvalid, // Invalid 268 Fast486ExtOpcodeInvalid, // Invalid 269 Fast486ExtOpcodeInvalid, // Invalid 270 Fast486ExtOpcodeInvalid, // Invalid 271 Fast486ExtOpcodeInvalid, // Invalid 272 Fast486ExtOpcodeInvalid, // Invalid 273 Fast486ExtOpcodeInvalid, // Invalid 274 Fast486ExtOpcodeInvalid, // Invalid 275 Fast486ExtOpcodeInvalid, // Invalid 276 Fast486ExtOpcodeInvalid, // Invalid 277 Fast486ExtOpcodeInvalid, // Invalid 278 Fast486ExtOpcodeInvalid, // Invalid 279 Fast486ExtOpcodeInvalid, // Invalid 280 Fast486ExtOpcodeInvalid, // Invalid 281 Fast486ExtOpcodeInvalid, // Invalid 282 Fast486ExtOpcodeInvalid, // Invalid 283 Fast486ExtOpcodeInvalid, // Invalid 284 Fast486ExtOpcodeInvalid, // Invalid 285 Fast486ExtOpcodeInvalid, // Invalid 286 Fast486ExtOpcodeInvalid, // Invalid 287 Fast486ExtOpcodeInvalid, // Invalid 288 Fast486ExtOpcodeInvalid, // Invalid 289 Fast486ExtOpcodeInvalid, // Invalid 290 Fast486ExtOpcodeInvalid, // Invalid 291 Fast486ExtOpcodeInvalid, // Invalid 292 Fast486ExtOpcodeInvalid, // Invalid 293 Fast486ExtOpcodeInvalid, // Invalid 294 Fast486ExtOpcodeInvalid, // Invalid 295 Fast486ExtOpcodeInvalid, // Invalid 296 }; 297 298 /* PUBLIC FUNCTIONS ***********************************************************/ 299 300 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeInvalid) 301 { 302 DPRINT1("FAST486 -- Extended opcode 0x%02X is INVALID!\n", Opcode); 303 Fast486Exception(State, FAST486_EXCEPTION_UD); 304 return; 305 } 306 307 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeUnimplemented) 308 { 309 DPRINT1("FAST486 -- Extended opcode 0x%02X is UNIMPLEMENTED\n", Opcode); 310 // Fast486Exception(State, FAST486_EXCEPTION_UD); 311 } 312 313 FAST486_OPCODE_HANDLER(Fast486ExtOpcode0F0B) 314 { 315 /* Reserved opcode (UD2) */ 316 Fast486Exception(State, FAST486_EXCEPTION_UD); 317 } 318 319 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLar) 320 { 321 BOOLEAN OperandSize, AddressSize; 322 FAST486_MOD_REG_RM ModRegRm; 323 BOOLEAN Valid; 324 USHORT Selector; 325 FAST486_GDT_ENTRY GdtEntry; 326 DWORD AccessRights; 327 328 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; 329 330 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) 331 || State->Flags.Vm) 332 { 333 /* Not recognized */ 334 Fast486Exception(State, FAST486_EXCEPTION_UD); 335 return; 336 } 337 338 NO_LOCK_PREFIX(); 339 TOGGLE_OPSIZE(OperandSize); 340 TOGGLE_ADSIZE(AddressSize); 341 342 /* Get the operands */ 343 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) 344 { 345 /* Exception occurred */ 346 return; 347 } 348 349 if (OperandSize) 350 { 351 ULONG Value; 352 353 /* Read the value */ 354 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value)) 355 { 356 /* Exception occurred */ 357 return; 358 } 359 360 Selector = LOWORD(Value); 361 } 362 else 363 { 364 /* Read the value */ 365 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Selector)) 366 { 367 /* Exception occurred */ 368 return; 369 } 370 } 371 372 if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry)) 373 { 374 /* Exception occurred */ 375 return; 376 } 377 378 if (!Valid) 379 { 380 State->Flags.Zf = FALSE; 381 return; 382 } 383 384 /* Privilege check */ 385 if (((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl)) 386 || (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl)) 387 { 388 State->Flags.Zf = FALSE; 389 return; 390 } 391 392 /* Set ZF */ 393 State->Flags.Zf = TRUE; 394 395 /* Get the access rights */ 396 AccessRights = ((PDWORD)&GdtEntry)[1] & 0x00F0FF00; 397 398 /* Return the access rights */ 399 if (OperandSize) Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, AccessRights); 400 else Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(AccessRights)); 401 } 402 403 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLsl) 404 { 405 BOOLEAN OperandSize, AddressSize; 406 FAST486_MOD_REG_RM ModRegRm; 407 BOOLEAN Valid; 408 USHORT Selector; 409 ULONG Limit; 410 FAST486_GDT_ENTRY GdtEntry; 411 412 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; 413 414 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) 415 || State->Flags.Vm) 416 { 417 /* Not recognized */ 418 Fast486Exception(State, FAST486_EXCEPTION_UD); 419 return; 420 } 421 422 NO_LOCK_PREFIX(); 423 TOGGLE_OPSIZE(OperandSize); 424 TOGGLE_ADSIZE(AddressSize); 425 426 /* Get the operands */ 427 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) 428 { 429 /* Exception occurred */ 430 return; 431 } 432 433 if (OperandSize) 434 { 435 ULONG Value; 436 437 /* Read the value */ 438 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value)) 439 { 440 /* Exception occurred */ 441 return; 442 } 443 444 Selector = LOWORD(Value); 445 } 446 else 447 { 448 /* Read the value */ 449 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Selector)) 450 { 451 /* Exception occurred */ 452 return; 453 } 454 } 455 456 if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry)) 457 { 458 /* Exception occurred */ 459 return; 460 } 461 462 if (!Valid) 463 { 464 State->Flags.Zf = FALSE; 465 return; 466 } 467 468 /* Privilege check */ 469 if (((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl)) 470 || (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl)) 471 { 472 State->Flags.Zf = FALSE; 473 return; 474 } 475 476 /* Calculate the limit */ 477 Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16); 478 479 if (GdtEntry.Granularity) 480 { 481 Limit <<= 12; 482 Limit |= 0x00000FFF; 483 } 484 485 /* Set ZF */ 486 State->Flags.Zf = TRUE; 487 488 /* Return the limit */ 489 if (OperandSize) Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, Limit); 490 else Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(Limit)); 491 } 492 493 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeClts) 494 { 495 NO_LOCK_PREFIX(); 496 497 /* The current privilege level must be zero */ 498 if (Fast486GetCurrentPrivLevel(State) != 0) 499 { 500 Fast486Exception(State, FAST486_EXCEPTION_GP); 501 return; 502 } 503 504 /* Clear the task switch bit */ 505 State->ControlRegisters[FAST486_REG_CR0] &= ~FAST486_CR0_TS; 506 } 507 508 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreControlReg) 509 { 510 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; 511 FAST486_MOD_REG_RM ModRegRm; 512 513 NO_LOCK_PREFIX(); 514 TOGGLE_ADSIZE(AddressSize); 515 516 /* Get the operands */ 517 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) 518 { 519 /* Exception occurred */ 520 return; 521 } 522 523 /* The current privilege level must be zero */ 524 if (Fast486GetCurrentPrivLevel(State) != 0) 525 { 526 Fast486Exception(State, FAST486_EXCEPTION_GP); 527 return; 528 } 529 530 if ((ModRegRm.Register == 1) || (ModRegRm.Register > 3)) 531 { 532 /* CR1, CR4, CR5, CR6 and CR7 don't exist */ 533 Fast486Exception(State, FAST486_EXCEPTION_UD); 534 return; 535 } 536 537 if (ModRegRm.Register != 0) 538 { 539 /* CR2 and CR3 and are stored in array indexes 1 and 2 */ 540 ModRegRm.Register--; 541 } 542 543 /* Store the value of the control register */ 544 State->GeneralRegs[ModRegRm.SecondRegister].Long = State->ControlRegisters[ModRegRm.Register]; 545 } 546 547 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreDebugReg) 548 { 549 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; 550 FAST486_MOD_REG_RM ModRegRm; 551 552 NO_LOCK_PREFIX(); 553 TOGGLE_ADSIZE(AddressSize); 554 555 /* Get the operands */ 556 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) 557 { 558 /* Exception occurred */ 559 return; 560 } 561 562 /* The current privilege level must be zero */ 563 if (Fast486GetCurrentPrivLevel(State) != 0) 564 { 565 Fast486Exception(State, FAST486_EXCEPTION_GP); 566 return; 567 } 568 569 if ((ModRegRm.Register == 6) || (ModRegRm.Register == 7)) 570 { 571 /* DR6 and DR7 are aliases to DR4 and DR5 */ 572 ModRegRm.Register -= 2; 573 } 574 575 if (State->DebugRegisters[FAST486_REG_DR5] & FAST486_DR5_GD) 576 { 577 /* Disallow access to debug registers */ 578 Fast486Exception(State, FAST486_EXCEPTION_GP); 579 return; 580 } 581 582 /* Store the value of the debug register */ 583 State->GeneralRegs[ModRegRm.SecondRegister].Long = State->DebugRegisters[ModRegRm.Register]; 584 } 585 586 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadControlReg) 587 { 588 ULONG Value; 589 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; 590 FAST486_MOD_REG_RM ModRegRm; 591 592 NO_LOCK_PREFIX(); 593 TOGGLE_ADSIZE(AddressSize); 594 595 /* Get the operands */ 596 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) 597 { 598 /* Exception occurred */ 599 return; 600 } 601 602 /* The current privilege level must be zero */ 603 if (Fast486GetCurrentPrivLevel(State) != 0) 604 { 605 Fast486Exception(State, FAST486_EXCEPTION_GP); 606 return; 607 } 608 609 if ((ModRegRm.Register == 1) || (ModRegRm.Register > 3)) 610 { 611 /* CR1, CR4, CR5, CR6 and CR7 don't exist */ 612 Fast486Exception(State, FAST486_EXCEPTION_UD); 613 return; 614 } 615 616 if (ModRegRm.Register != 0) 617 { 618 /* CR2 and CR3 and are stored in array indexes 1 and 2 */ 619 ModRegRm.Register--; 620 } 621 622 /* Get the value */ 623 Value = State->GeneralRegs[ModRegRm.SecondRegister].Long; 624 625 if (ModRegRm.Register == (INT)FAST486_REG_CR0) 626 { 627 /* CR0 checks */ 628 629 if (((Value & (FAST486_CR0_PG | FAST486_CR0_PE)) == FAST486_CR0_PG) 630 || ((Value & (FAST486_CR0_CD | FAST486_CR0_NW)) == FAST486_CR0_NW)) 631 { 632 /* Invalid value */ 633 Fast486Exception(State, FAST486_EXCEPTION_GP); 634 return; 635 } 636 } 637 638 #ifndef FAST486_NO_PREFETCH 639 /* Changing CR0 or CR3 can interfere with prefetching (because of paging) */ 640 State->PrefetchValid = FALSE; 641 #endif 642 643 if (ModRegRm.Register == (INT)FAST486_REG_CR3) 644 { 645 /* Flush the TLB */ 646 Fast486FlushTlb(State); 647 } 648 649 /* Load a value to the control register */ 650 State->ControlRegisters[ModRegRm.Register] = Value; 651 } 652 653 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadDebugReg) 654 { 655 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; 656 FAST486_MOD_REG_RM ModRegRm; 657 658 NO_LOCK_PREFIX(); 659 TOGGLE_ADSIZE(AddressSize); 660 661 /* Get the operands */ 662 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) 663 { 664 /* Exception occurred */ 665 return; 666 } 667 668 /* The current privilege level must be zero */ 669 if (Fast486GetCurrentPrivLevel(State) != 0) 670 { 671 Fast486Exception(State, FAST486_EXCEPTION_GP); 672 return; 673 } 674 675 if ((ModRegRm.Register == 6) || (ModRegRm.Register == 7)) 676 { 677 /* DR6 and DR7 are aliases to DR4 and DR5 */ 678 ModRegRm.Register -= 2; 679 } 680 681 if (State->DebugRegisters[FAST486_REG_DR5] & FAST486_DR5_GD) 682 { 683 /* Disallow access to debug registers */ 684 Fast486Exception(State, FAST486_EXCEPTION_GP); 685 return; 686 } 687 688 /* Load a value to the debug register */ 689 State->DebugRegisters[ModRegRm.Register] = State->GeneralRegs[ModRegRm.SecondRegister].Long; 690 691 if (ModRegRm.Register == (INT)FAST486_REG_DR4) 692 { 693 /* The reserved bits are 1 */ 694 State->DebugRegisters[ModRegRm.Register] |= FAST486_DR4_RESERVED; 695 } 696 else if (ModRegRm.Register == (INT)FAST486_REG_DR5) 697 { 698 /* The reserved bits are 0 */ 699 State->DebugRegisters[ModRegRm.Register] &= ~FAST486_DR5_RESERVED; 700 } 701 } 702 703 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushFs) 704 { 705 /* Call the internal API */ 706 Fast486StackPush(State, State->SegmentRegs[FAST486_REG_FS].Selector); 707 } 708 709 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopFs) 710 { 711 ULONG NewSelector; 712 713 if (!Fast486StackPop(State, &NewSelector)) 714 { 715 /* Exception occurred */ 716 return; 717 } 718 719 /* Call the internal API */ 720 Fast486LoadSegment(State, FAST486_REG_FS, LOWORD(NewSelector)); 721 } 722 723 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBitTest) 724 { 725 BOOLEAN OperandSize, AddressSize; 726 FAST486_MOD_REG_RM ModRegRm; 727 UINT DataSize; 728 ULONG BitNumber; 729 730 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; 731 TOGGLE_OPSIZE(OperandSize); 732 TOGGLE_ADSIZE(AddressSize); 733 734 /* Get the number of bits */ 735 if (OperandSize) DataSize = 32; 736 else DataSize = 16; 737 738 /* Get the operands */ 739 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) 740 { 741 /* Exception occurred */ 742 return; 743 } 744 745 /* Get the bit number */ 746 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long 747 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord; 748 749 if (ModRegRm.Memory) 750 { 751 /* 752 * For memory operands, add the bit offset divided by 753 * the data size to the address 754 */ 755 ModRegRm.MemoryAddress += (BitNumber / DataSize) * (DataSize / 8); 756 } 757 758 /* Normalize the bit number */ 759 BitNumber %= DataSize; 760 761 if (OperandSize) 762 { 763 ULONG Value; 764 765 /* Read the value */ 766 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value)) 767 { 768 /* Exception occurred */ 769 return; 770 } 771 772 /* Set CF to the bit value */ 773 State->Flags.Cf = (Value >> BitNumber) & 1; 774 } 775 else 776 { 777 USHORT Value; 778 779 /* Read the value */ 780 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value)) 781 { 782 /* Exception occurred */ 783 return; 784 } 785 786 /* Set CF to the bit value */ 787 State->Flags.Cf = (Value >> BitNumber) & 1; 788 } 789 } 790 791 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShld) 792 { 793 BOOLEAN OperandSize, AddressSize; 794 FAST486_MOD_REG_RM ModRegRm; 795 UCHAR Count; 796 797 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; 798 TOGGLE_OPSIZE(OperandSize); 799 TOGGLE_ADSIZE(AddressSize); 800 801 /* Make sure this is the right instruction */ 802 ASSERT((Opcode & 0xFE) == 0xA4); 803 804 /* Get the operands */ 805 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) 806 { 807 /* Exception occurred */ 808 return; 809 } 810 811 if (Opcode == 0xA4) 812 { 813 /* Fetch the count */ 814 if (!Fast486FetchByte(State, &Count)) 815 { 816 /* Exception occurred */ 817 return; 818 } 819 } 820 else 821 { 822 /* The count is in CL */ 823 Count = State->GeneralRegs[FAST486_REG_ECX].LowByte; 824 } 825 826 /* Normalize the count */ 827 Count &= 0x1F; 828 829 /* Do nothing if the count is zero */ 830 if (Count == 0) return; 831 832 if (OperandSize) 833 { 834 ULONG Source, Destination, Result; 835 836 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Source, &Destination)) 837 { 838 /* Exception occurred */ 839 return; 840 } 841 842 /* Calculate the result */ 843 Result = (Destination << Count) | (Source >> (32 - Count)); 844 845 /* Update flags */ 846 State->Flags.Cf = (Destination >> (32 - Count)) & 1; 847 if (Count == 1) State->Flags.Of = (Result & SIGN_FLAG_LONG) 848 != (Destination & SIGN_FLAG_LONG); 849 State->Flags.Zf = (Result == 0); 850 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0); 851 State->Flags.Pf = Fast486CalculateParity(Result); 852 853 /* Write back the result */ 854 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result); 855 } 856 else 857 { 858 USHORT Source, Destination, Result; 859 ULONG DoubleSource; 860 861 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Source, &Destination)) 862 { 863 /* Exception occurred */ 864 return; 865 } 866 867 DoubleSource = Source | (Source << 16); 868 869 /* Calculate the result */ 870 Result = (Destination << Count) | (DoubleSource >> (32 - Count)); 871 872 /* Update flags */ 873 if (Count <= 16) State->Flags.Cf = (Destination >> (16 - Count)) & 1; 874 else State->Flags.Cf = (Source >> (32 - Count)) & 1; 875 876 if (Count == 1) State->Flags.Of = (Result & SIGN_FLAG_WORD) 877 != (Destination & SIGN_FLAG_WORD); 878 State->Flags.Zf = (Result == 0); 879 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0); 880 State->Flags.Pf = Fast486CalculateParity(Result); 881 882 /* Write back the result */ 883 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Result); 884 } 885 } 886 887 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushGs) 888 { 889 /* Call the internal API */ 890 Fast486StackPush(State, State->SegmentRegs[FAST486_REG_GS].Selector); 891 } 892 893 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopGs) 894 { 895 ULONG NewSelector; 896 897 if (!Fast486StackPop(State, &NewSelector)) 898 { 899 /* Exception occurred */ 900 return; 901 } 902 903 /* Call the internal API */ 904 Fast486LoadSegment(State, FAST486_REG_GS, LOWORD(NewSelector)); 905 } 906 907 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBts) 908 { 909 BOOLEAN OperandSize, AddressSize; 910 FAST486_MOD_REG_RM ModRegRm; 911 UINT DataSize; 912 ULONG BitNumber; 913 914 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; 915 TOGGLE_OPSIZE(OperandSize); 916 TOGGLE_ADSIZE(AddressSize); 917 918 /* Get the number of bits */ 919 if (OperandSize) DataSize = 32; 920 else DataSize = 16; 921 922 /* Get the operands */ 923 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) 924 { 925 /* Exception occurred */ 926 return; 927 } 928 929 /* Get the bit number */ 930 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long 931 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord; 932 933 if (ModRegRm.Memory) 934 { 935 /* 936 * For memory operands, add the bit offset divided by 937 * the data size to the address 938 */ 939 ModRegRm.MemoryAddress += (BitNumber / DataSize) * (DataSize / 8); 940 } 941 942 /* Normalize the bit number */ 943 BitNumber %= DataSize; 944 945 if (OperandSize) 946 { 947 ULONG Value; 948 949 /* Read the value */ 950 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value)) 951 { 952 /* Exception occurred */ 953 return; 954 } 955 956 /* Set CF to the bit value */ 957 State->Flags.Cf = (Value >> BitNumber) & 1; 958 959 /* Set the bit */ 960 Value |= 1 << BitNumber; 961 962 /* Write back the result */ 963 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value); 964 } 965 else 966 { 967 USHORT Value; 968 969 /* Read the value */ 970 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value)) 971 { 972 /* Exception occurred */ 973 return; 974 } 975 976 /* Set CF to the bit value */ 977 State->Flags.Cf = (Value >> BitNumber) & 1; 978 979 /* Set the bit */ 980 Value |= 1 << BitNumber; 981 982 /* Write back the result */ 983 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value); 984 } 985 } 986 987 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShrd) 988 { 989 BOOLEAN OperandSize, AddressSize; 990 FAST486_MOD_REG_RM ModRegRm; 991 UCHAR Count; 992 993 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; 994 TOGGLE_OPSIZE(OperandSize); 995 TOGGLE_ADSIZE(AddressSize); 996 997 /* Make sure this is the right instruction */ 998 ASSERT((Opcode & 0xFE) == 0xAC); 999 1000 /* Get the operands */ 1001 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) 1002 { 1003 /* Exception occurred */ 1004 return; 1005 } 1006 1007 if (Opcode == 0xAC) 1008 { 1009 /* Fetch the count */ 1010 if (!Fast486FetchByte(State, &Count)) 1011 { 1012 /* Exception occurred */ 1013 return; 1014 } 1015 } 1016 else 1017 { 1018 /* The count is in CL */ 1019 Count = State->GeneralRegs[FAST486_REG_ECX].LowByte; 1020 } 1021 1022 /* Normalize the count */ 1023 Count &= 0x1F; 1024 1025 /* Do nothing if the count is zero */ 1026 if (Count == 0) return; 1027 1028 if (OperandSize) 1029 { 1030 ULONG Source, Destination, Result; 1031 1032 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Source, &Destination)) 1033 { 1034 /* Exception occurred */ 1035 return; 1036 } 1037 1038 /* Calculate the result */ 1039 Result = (Destination >> Count) | (Source << (32 - Count)); 1040 1041 /* Update flags */ 1042 State->Flags.Cf = (Destination >> (Count - 1)) & 1; 1043 if (Count == 1) State->Flags.Of = (Result & SIGN_FLAG_LONG) 1044 != (Destination & SIGN_FLAG_LONG); 1045 State->Flags.Zf = (Result == 0); 1046 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0); 1047 State->Flags.Pf = Fast486CalculateParity(Result); 1048 1049 /* Write back the result */ 1050 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result); 1051 } 1052 else 1053 { 1054 USHORT Source, Destination, Result; 1055 1056 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Source, &Destination)) 1057 { 1058 /* Exception occurred */ 1059 return; 1060 } 1061 1062 /* Calculate the result */ 1063 Result = (Destination >> Count) | (Source << (16 - Count)); 1064 1065 if (Count >= 16) Result |= (ULONG)(Source | (Source << 16)) >> (Count - 16); 1066 1067 /* Update flags */ 1068 if (Count <= 16) State->Flags.Cf = (Destination >> (Count - 1)) & 1; 1069 else State->Flags.Cf = (Source >> (Count - 17)) & 1; 1070 1071 if (Count == 1) State->Flags.Of = (Result & SIGN_FLAG_WORD) 1072 != (Destination & SIGN_FLAG_WORD); 1073 State->Flags.Zf = (Result == 0); 1074 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0); 1075 State->Flags.Pf = Fast486CalculateParity(Result); 1076 1077 /* Write back the result */ 1078 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Result); 1079 } 1080 } 1081 1082 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeImul) 1083 { 1084 BOOLEAN OperandSize, AddressSize; 1085 FAST486_MOD_REG_RM ModRegRm; 1086 1087 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; 1088 1089 TOGGLE_OPSIZE(OperandSize); 1090 TOGGLE_ADSIZE(AddressSize); 1091 1092 /* Get the operands */ 1093 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) 1094 { 1095 /* Exception occurred */ 1096 return; 1097 } 1098 1099 if (OperandSize) 1100 { 1101 LONG Source, Destination; 1102 LONGLONG Result; 1103 1104 /* Read the operands */ 1105 if (!Fast486ReadModrmDwordOperands(State, 1106 &ModRegRm, 1107 (PULONG)&Destination, 1108 (PULONG)&Source)) 1109 { 1110 /* Exception occurred */ 1111 return; 1112 } 1113 1114 /* Calculate the result */ 1115 Result = (LONGLONG)Source * (LONGLONG)Destination; 1116 1117 /* Update the flags */ 1118 State->Flags.Cf = State->Flags.Of = ((Result < -2147483648LL) || (Result > 2147483647LL)); 1119 1120 /* Write back the result */ 1121 Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, (ULONG)((LONG)Result)); 1122 } 1123 else 1124 { 1125 SHORT Source, Destination; 1126 LONG Result; 1127 1128 /* Read the operands */ 1129 if (!Fast486ReadModrmWordOperands(State, 1130 &ModRegRm, 1131 (PUSHORT)&Destination, 1132 (PUSHORT)&Source)) 1133 { 1134 /* Exception occurred */ 1135 return; 1136 } 1137 1138 /* Calculate the result */ 1139 Result = (LONG)Source * (LONG)Destination; 1140 1141 /* Update the flags */ 1142 State->Flags.Cf = State->Flags.Of = ((Result < -32768) || (Result > 32767)); 1143 1144 /* Write back the result */ 1145 Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, (USHORT)((SHORT)Result)); 1146 } 1147 } 1148 1149 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchgByte) 1150 { 1151 FAST486_MOD_REG_RM ModRegRm; 1152 UCHAR Accumulator = State->GeneralRegs[FAST486_REG_EAX].LowByte; 1153 UCHAR Source, Destination, Result; 1154 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; 1155 1156 TOGGLE_ADSIZE(AddressSize); 1157 1158 /* Get the operands */ 1159 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) 1160 { 1161 /* Exception occurred */ 1162 return; 1163 } 1164 1165 /* Read the operands */ 1166 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, &Source, &Destination)) 1167 { 1168 /* Exception occurred */ 1169 return; 1170 } 1171 1172 /* Compare AL with the destination */ 1173 Result = Accumulator - Destination; 1174 1175 /* Update the flags */ 1176 State->Flags.Cf = (Accumulator < Destination); 1177 State->Flags.Of = ((Accumulator & SIGN_FLAG_BYTE) != (Destination & SIGN_FLAG_BYTE)) 1178 && ((Accumulator & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE)); 1179 State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F); 1180 State->Flags.Zf = (Result == 0); 1181 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0); 1182 State->Flags.Pf = Fast486CalculateParity(Result); 1183 1184 if (State->Flags.Zf) 1185 { 1186 /* Load the source operand into the destination */ 1187 Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Source); 1188 } 1189 else 1190 { 1191 /* Load the destination into AL */ 1192 State->GeneralRegs[FAST486_REG_EAX].LowByte = Destination; 1193 } 1194 } 1195 1196 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchg) 1197 { 1198 FAST486_MOD_REG_RM ModRegRm; 1199 BOOLEAN OperandSize, AddressSize; 1200 1201 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; 1202 1203 TOGGLE_OPSIZE(OperandSize); 1204 TOGGLE_ADSIZE(AddressSize); 1205 1206 /* Get the operands */ 1207 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) 1208 { 1209 /* Exception occurred */ 1210 return; 1211 } 1212 1213 if (OperandSize) 1214 { 1215 ULONG Source, Destination, Result; 1216 ULONG Accumulator = State->GeneralRegs[FAST486_REG_EAX].Long; 1217 1218 /* Read the operands */ 1219 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Source, &Destination)) 1220 { 1221 /* Exception occurred */ 1222 return; 1223 } 1224 1225 /* Compare EAX with the destination */ 1226 Result = Accumulator - Destination; 1227 1228 /* Update the flags */ 1229 State->Flags.Cf = (Accumulator < Destination); 1230 State->Flags.Of = ((Accumulator & SIGN_FLAG_LONG) != (Destination & SIGN_FLAG_LONG)) 1231 && ((Accumulator & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG)); 1232 State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F); 1233 State->Flags.Zf = (Result == 0); 1234 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0); 1235 State->Flags.Pf = Fast486CalculateParity(Result); 1236 1237 if (State->Flags.Zf) 1238 { 1239 /* Load the source operand into the destination */ 1240 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Source); 1241 } 1242 else 1243 { 1244 /* Load the destination into EAX */ 1245 State->GeneralRegs[FAST486_REG_EAX].Long = Destination; 1246 } 1247 } 1248 else 1249 { 1250 USHORT Source, Destination, Result; 1251 USHORT Accumulator = State->GeneralRegs[FAST486_REG_EAX].LowWord; 1252 1253 /* Read the operands */ 1254 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Source, &Destination)) 1255 { 1256 /* Exception occurred */ 1257 return; 1258 } 1259 1260 /* Compare AX with the destination */ 1261 Result = Accumulator - Destination; 1262 1263 /* Update the flags */ 1264 State->Flags.Cf = (Accumulator < Destination); 1265 State->Flags.Of = ((Accumulator & SIGN_FLAG_WORD) != (Destination & SIGN_FLAG_WORD)) 1266 && ((Accumulator & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD)); 1267 State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F); 1268 State->Flags.Zf = (Result == 0); 1269 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0); 1270 State->Flags.Pf = Fast486CalculateParity(Result); 1271 1272 if (State->Flags.Zf) 1273 { 1274 /* Load the source operand into the destination */ 1275 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Source); 1276 } 1277 else 1278 { 1279 /* Load the destination into AX */ 1280 State->GeneralRegs[FAST486_REG_EAX].LowWord = Destination; 1281 } 1282 } 1283 } 1284 1285 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLss) 1286 { 1287 UCHAR FarPointer[6]; 1288 BOOLEAN OperandSize, AddressSize; 1289 FAST486_MOD_REG_RM ModRegRm; 1290 1291 /* Make sure this is the right instruction */ 1292 ASSERT(Opcode == 0xB2); 1293 1294 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; 1295 1296 TOGGLE_OPSIZE(OperandSize); 1297 TOGGLE_ADSIZE(AddressSize); 1298 1299 /* Get the operands */ 1300 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) 1301 { 1302 /* Exception occurred */ 1303 return; 1304 } 1305 1306 if (!ModRegRm.Memory) 1307 { 1308 /* Invalid */ 1309 Fast486Exception(State, FAST486_EXCEPTION_UD); 1310 return; 1311 } 1312 1313 if (!Fast486ReadMemory(State, 1314 (State->PrefixFlags & FAST486_PREFIX_SEG) 1315 ? State->SegmentOverride : FAST486_REG_DS, 1316 ModRegRm.MemoryAddress, 1317 FALSE, 1318 FarPointer, 1319 OperandSize ? 6 : 4)) 1320 { 1321 /* Exception occurred */ 1322 return; 1323 } 1324 1325 if (OperandSize) 1326 { 1327 ULONG Offset = *((PULONG)FarPointer); 1328 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(ULONG)]); 1329 1330 /* Set the register to the offset */ 1331 State->GeneralRegs[ModRegRm.Register].Long = Offset; 1332 1333 /* Load the segment */ 1334 Fast486LoadSegment(State, FAST486_REG_SS, Segment); 1335 } 1336 else 1337 { 1338 USHORT Offset = *((PUSHORT)FarPointer); 1339 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(USHORT)]); 1340 1341 /* Set the register to the offset */ 1342 State->GeneralRegs[ModRegRm.Register].LowWord = Offset; 1343 1344 /* Load the segment */ 1345 Fast486LoadSegment(State, FAST486_REG_SS, Segment); 1346 } 1347 } 1348 1349 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtr) 1350 { 1351 BOOLEAN OperandSize, AddressSize; 1352 FAST486_MOD_REG_RM ModRegRm; 1353 UINT DataSize; 1354 ULONG BitNumber; 1355 1356 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; 1357 TOGGLE_OPSIZE(OperandSize); 1358 TOGGLE_ADSIZE(AddressSize); 1359 1360 /* Get the number of bits */ 1361 if (OperandSize) DataSize = 32; 1362 else DataSize = 16; 1363 1364 /* Get the operands */ 1365 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) 1366 { 1367 /* Exception occurred */ 1368 return; 1369 } 1370 1371 /* Get the bit number */ 1372 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long 1373 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord; 1374 1375 if (ModRegRm.Memory) 1376 { 1377 /* 1378 * For memory operands, add the bit offset divided by 1379 * the data size to the address 1380 */ 1381 ModRegRm.MemoryAddress += (BitNumber / DataSize) * (DataSize / 8); 1382 } 1383 1384 /* Normalize the bit number */ 1385 BitNumber %= DataSize; 1386 1387 if (OperandSize) 1388 { 1389 ULONG Value; 1390 1391 /* Read the value */ 1392 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value)) 1393 { 1394 /* Exception occurred */ 1395 return; 1396 } 1397 1398 /* Set CF to the bit value */ 1399 State->Flags.Cf = (Value >> BitNumber) & 1; 1400 1401 /* Clear the bit */ 1402 Value &= ~(1 << BitNumber); 1403 1404 /* Write back the result */ 1405 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value); 1406 } 1407 else 1408 { 1409 USHORT Value; 1410 1411 /* Read the value */ 1412 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value)) 1413 { 1414 /* Exception occurred */ 1415 return; 1416 } 1417 1418 /* Set CF to the bit value */ 1419 State->Flags.Cf = (Value >> BitNumber) & 1; 1420 1421 /* Clear the bit */ 1422 Value &= ~(1 << BitNumber); 1423 1424 /* Write back the result */ 1425 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value); 1426 } 1427 } 1428 1429 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLfsLgs) 1430 { 1431 UCHAR FarPointer[6]; 1432 BOOLEAN OperandSize, AddressSize; 1433 FAST486_MOD_REG_RM ModRegRm; 1434 1435 /* Make sure this is the right instruction */ 1436 ASSERT((Opcode & 0xFE) == 0xB4); 1437 1438 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; 1439 1440 TOGGLE_OPSIZE(OperandSize); 1441 TOGGLE_ADSIZE(AddressSize); 1442 1443 /* Get the operands */ 1444 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) 1445 { 1446 /* Exception occurred */ 1447 return; 1448 } 1449 1450 if (!ModRegRm.Memory) 1451 { 1452 /* Invalid */ 1453 Fast486Exception(State, FAST486_EXCEPTION_UD); 1454 return; 1455 } 1456 1457 if (!Fast486ReadMemory(State, 1458 (State->PrefixFlags & FAST486_PREFIX_SEG) 1459 ? State->SegmentOverride : FAST486_REG_DS, 1460 ModRegRm.MemoryAddress, 1461 FALSE, 1462 FarPointer, 1463 OperandSize ? 6 : 4)) 1464 { 1465 /* Exception occurred */ 1466 return; 1467 } 1468 1469 if (OperandSize) 1470 { 1471 ULONG Offset = *((PULONG)FarPointer); 1472 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(ULONG)]); 1473 1474 /* Set the register to the offset */ 1475 State->GeneralRegs[ModRegRm.Register].Long = Offset; 1476 1477 /* Load the segment */ 1478 Fast486LoadSegment(State, 1479 (Opcode == 0xB4) 1480 ? FAST486_REG_FS : FAST486_REG_GS, 1481 Segment); 1482 } 1483 else 1484 { 1485 USHORT Offset = *((PUSHORT)FarPointer); 1486 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(USHORT)]); 1487 1488 /* Set the register to the offset */ 1489 State->GeneralRegs[ModRegRm.Register].LowWord = Offset; 1490 1491 /* Load the segment */ 1492 Fast486LoadSegment(State, 1493 (Opcode == 0xB4) 1494 ? FAST486_REG_FS : FAST486_REG_GS, 1495 Segment); 1496 } 1497 } 1498 1499 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxByte) 1500 { 1501 UCHAR Value; 1502 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; 1503 FAST486_MOD_REG_RM ModRegRm; 1504 1505 TOGGLE_ADSIZE(AddressSize); 1506 1507 /* Make sure this is the right instruction */ 1508 ASSERT(Opcode == 0xB6); 1509 1510 /* Get the operands */ 1511 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) 1512 { 1513 /* Exception occurred */ 1514 return; 1515 } 1516 1517 /* Read the operands */ 1518 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value)) 1519 { 1520 /* Exception occurred */ 1521 return; 1522 } 1523 1524 /* Write back the zero-extended value */ 1525 Fast486WriteModrmDwordOperands(State, 1526 &ModRegRm, 1527 TRUE, 1528 (ULONG)Value); 1529 } 1530 1531 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxWord) 1532 { 1533 USHORT Value; 1534 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; 1535 FAST486_MOD_REG_RM ModRegRm; 1536 1537 TOGGLE_ADSIZE(AddressSize); 1538 1539 /* Make sure this is the right instruction */ 1540 ASSERT(Opcode == 0xB7); 1541 1542 /* Get the operands */ 1543 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) 1544 { 1545 /* Exception occurred */ 1546 return; 1547 } 1548 1549 /* Read the operands */ 1550 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value)) 1551 { 1552 /* Exception occurred */ 1553 return; 1554 } 1555 1556 /* Write back the zero-extended value */ 1557 Fast486WriteModrmDwordOperands(State, 1558 &ModRegRm, 1559 TRUE, 1560 (ULONG)Value); 1561 } 1562 1563 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtc) 1564 { 1565 BOOLEAN OperandSize, AddressSize; 1566 FAST486_MOD_REG_RM ModRegRm; 1567 UINT DataSize; 1568 ULONG BitNumber; 1569 1570 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; 1571 TOGGLE_OPSIZE(OperandSize); 1572 TOGGLE_ADSIZE(AddressSize); 1573 1574 /* Get the number of bits */ 1575 if (OperandSize) DataSize = 32; 1576 else DataSize = 16; 1577 1578 /* Get the operands */ 1579 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) 1580 { 1581 /* Exception occurred */ 1582 return; 1583 } 1584 1585 /* Get the bit number */ 1586 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long 1587 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord; 1588 1589 if (ModRegRm.Memory) 1590 { 1591 /* 1592 * For memory operands, add the bit offset divided by 1593 * the data size to the address 1594 */ 1595 ModRegRm.MemoryAddress += (BitNumber / DataSize) * (DataSize / 8); 1596 } 1597 1598 /* Normalize the bit number */ 1599 BitNumber %= DataSize; 1600 1601 if (OperandSize) 1602 { 1603 ULONG Value; 1604 1605 /* Read the value */ 1606 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value)) 1607 { 1608 /* Exception occurred */ 1609 return; 1610 } 1611 1612 /* Set CF to the bit value */ 1613 State->Flags.Cf = (Value >> BitNumber) & 1; 1614 1615 /* Toggle the bit */ 1616 Value ^= 1 << BitNumber; 1617 1618 /* Write back the result */ 1619 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value); 1620 } 1621 else 1622 { 1623 USHORT Value; 1624 1625 /* Read the value */ 1626 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value)) 1627 { 1628 /* Exception occurred */ 1629 return; 1630 } 1631 1632 /* Set CF to the bit value */ 1633 State->Flags.Cf = (Value >> BitNumber) & 1; 1634 1635 /* Toggle the bit */ 1636 Value ^= 1 << BitNumber; 1637 1638 /* Write back the result */ 1639 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value); 1640 } 1641 } 1642 1643 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsf) 1644 { 1645 UINT i; 1646 ULONG Value = 0; 1647 BOOLEAN OperandSize, AddressSize; 1648 FAST486_MOD_REG_RM ModRegRm; 1649 ULONG BitNumber; 1650 UINT DataSize; 1651 1652 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; 1653 TOGGLE_OPSIZE(OperandSize); 1654 TOGGLE_ADSIZE(AddressSize); 1655 1656 /* Make sure this is the right instruction */ 1657 ASSERT(Opcode == 0xBC); 1658 1659 /* Get the number of bits */ 1660 if (OperandSize) DataSize = 32; 1661 else DataSize = 16; 1662 1663 /* Get the operands */ 1664 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) 1665 { 1666 /* Exception occurred */ 1667 return; 1668 } 1669 1670 /* Read the value */ 1671 if (OperandSize) 1672 { 1673 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value)) 1674 { 1675 /* Exception occurred */ 1676 return; 1677 } 1678 } 1679 else 1680 { 1681 if (!Fast486ReadModrmWordOperands(State, 1682 &ModRegRm, 1683 (PUSHORT)NULL, 1684 (PUSHORT)&Value)) 1685 { 1686 /* Exception occurred */ 1687 return; 1688 } 1689 } 1690 1691 /* Set ZF */ 1692 State->Flags.Zf = (Value == 0); 1693 if (State->Flags.Zf) return; 1694 1695 for (i = 0; i < DataSize; i++) 1696 { 1697 if (Value & (1 << i)) 1698 { 1699 /* Save the bit number */ 1700 BitNumber = i; 1701 1702 /* Exit the loop */ 1703 break; 1704 } 1705 } 1706 1707 /* Write back the result */ 1708 if (OperandSize) Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, BitNumber); 1709 else Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(BitNumber)); 1710 } 1711 1712 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsr) 1713 { 1714 INT i; 1715 ULONG Value = 0; 1716 BOOLEAN OperandSize, AddressSize; 1717 FAST486_MOD_REG_RM ModRegRm; 1718 ULONG BitNumber; 1719 UINT DataSize; 1720 1721 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; 1722 TOGGLE_OPSIZE(OperandSize); 1723 TOGGLE_ADSIZE(AddressSize); 1724 1725 /* Make sure this is the right instruction */ 1726 ASSERT(Opcode == 0xBD); 1727 1728 /* Get the number of bits */ 1729 if (OperandSize) DataSize = 32; 1730 else DataSize = 16; 1731 1732 /* Get the operands */ 1733 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) 1734 { 1735 /* Exception occurred */ 1736 return; 1737 } 1738 1739 /* Read the value */ 1740 if (OperandSize) 1741 { 1742 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value)) 1743 { 1744 /* Exception occurred */ 1745 return; 1746 } 1747 } 1748 else 1749 { 1750 if (!Fast486ReadModrmWordOperands(State, 1751 &ModRegRm, 1752 (PUSHORT)NULL, 1753 (PUSHORT)&Value)) 1754 { 1755 /* Exception occurred */ 1756 return; 1757 } 1758 } 1759 1760 /* Set ZF according to the value */ 1761 State->Flags.Zf = (Value == 0); 1762 if (State->Flags.Zf) return; 1763 1764 for (i = DataSize - 1; i >= 0; i--) 1765 { 1766 if (Value & (1 << i)) 1767 { 1768 /* Save the bit number */ 1769 BitNumber = i; 1770 1771 /* Exit the loop */ 1772 break; 1773 } 1774 } 1775 1776 /* Write back the result */ 1777 if (OperandSize) Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, BitNumber); 1778 else Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(BitNumber)); 1779 } 1780 1781 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxByte) 1782 { 1783 CHAR Value; 1784 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; 1785 FAST486_MOD_REG_RM ModRegRm; 1786 1787 TOGGLE_ADSIZE(AddressSize); 1788 1789 /* Make sure this is the right instruction */ 1790 ASSERT(Opcode == 0xBE); 1791 1792 /* Get the operands */ 1793 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) 1794 { 1795 /* Exception occurred */ 1796 return; 1797 } 1798 1799 /* Read the operands */ 1800 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, (PUCHAR)&Value)) 1801 { 1802 /* Exception occurred */ 1803 return; 1804 } 1805 1806 /* Write back the sign-extended value */ 1807 Fast486WriteModrmDwordOperands(State, 1808 &ModRegRm, 1809 TRUE, 1810 (ULONG)((LONG)Value)); 1811 } 1812 1813 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxWord) 1814 { 1815 SHORT Value; 1816 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; 1817 FAST486_MOD_REG_RM ModRegRm; 1818 1819 TOGGLE_ADSIZE(AddressSize); 1820 1821 /* Make sure this is the right instruction */ 1822 ASSERT(Opcode == 0xBF); 1823 1824 /* Get the operands */ 1825 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) 1826 { 1827 /* Exception occurred */ 1828 return; 1829 } 1830 1831 /* Read the operands */ 1832 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, (PUSHORT)&Value)) 1833 { 1834 /* Exception occurred */ 1835 return; 1836 } 1837 1838 /* Write back the sign-extended value */ 1839 Fast486WriteModrmDwordOperands(State, 1840 &ModRegRm, 1841 TRUE, 1842 (ULONG)((LONG)Value)); 1843 } 1844 1845 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalJmp) 1846 { 1847 BOOLEAN Jump = FALSE; 1848 LONG Offset = 0; 1849 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size; 1850 1851 TOGGLE_OPSIZE(Size); 1852 NO_LOCK_PREFIX(); 1853 1854 /* Make sure this is the right instruction */ 1855 ASSERT((Opcode & 0xF0) == 0x80); 1856 1857 /* Fetch the offset */ 1858 if (Size) 1859 { 1860 if (!Fast486FetchDword(State, (PULONG)&Offset)) 1861 { 1862 /* Exception occurred */ 1863 return; 1864 } 1865 } 1866 else 1867 { 1868 SHORT Value; 1869 1870 if (!Fast486FetchWord(State, (PUSHORT)&Value)) 1871 { 1872 /* Exception occurred */ 1873 return; 1874 } 1875 1876 /* Sign-extend */ 1877 Offset = (LONG)Value; 1878 } 1879 1880 switch ((Opcode & 0x0F) >> 1) 1881 { 1882 /* JO / JNO */ 1883 case 0: 1884 { 1885 Jump = State->Flags.Of; 1886 break; 1887 } 1888 1889 /* JC / JNC */ 1890 case 1: 1891 { 1892 Jump = State->Flags.Cf; 1893 break; 1894 } 1895 1896 /* JZ / JNZ */ 1897 case 2: 1898 { 1899 Jump = State->Flags.Zf; 1900 break; 1901 } 1902 1903 /* JBE / JNBE */ 1904 case 3: 1905 { 1906 Jump = State->Flags.Cf || State->Flags.Zf; 1907 break; 1908 } 1909 1910 /* JS / JNS */ 1911 case 4: 1912 { 1913 Jump = State->Flags.Sf; 1914 break; 1915 } 1916 1917 /* JP / JNP */ 1918 case 5: 1919 { 1920 Jump = State->Flags.Pf; 1921 break; 1922 } 1923 1924 /* JL / JNL */ 1925 case 6: 1926 { 1927 Jump = State->Flags.Sf != State->Flags.Of; 1928 break; 1929 } 1930 1931 /* JLE / JNLE */ 1932 case 7: 1933 { 1934 Jump = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf; 1935 break; 1936 } 1937 } 1938 1939 if (Opcode & 1) 1940 { 1941 /* Invert the result */ 1942 Jump = !Jump; 1943 } 1944 1945 if (Jump) 1946 { 1947 /* Move the instruction pointer */ 1948 State->InstPtr.Long += Offset; 1949 } 1950 } 1951 1952 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalSet) 1953 { 1954 BOOLEAN Value = FALSE; 1955 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; 1956 FAST486_MOD_REG_RM ModRegRm; 1957 1958 TOGGLE_ADSIZE(AddressSize); 1959 1960 /* Get the operands */ 1961 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) 1962 { 1963 /* Exception occurred */ 1964 return; 1965 } 1966 1967 /* Make sure this is the right instruction */ 1968 ASSERT((Opcode & 0xF0) == 0x90); 1969 1970 switch ((Opcode & 0x0F) >> 1) 1971 { 1972 /* SETO / SETNO */ 1973 case 0: 1974 { 1975 Value = State->Flags.Of; 1976 break; 1977 } 1978 1979 /* SETC / SETNC */ 1980 case 1: 1981 { 1982 Value = State->Flags.Cf; 1983 break; 1984 } 1985 1986 /* SETZ / SETNZ */ 1987 case 2: 1988 { 1989 Value = State->Flags.Zf; 1990 break; 1991 } 1992 1993 /* SETBE / SETNBE */ 1994 case 3: 1995 { 1996 Value = State->Flags.Cf || State->Flags.Zf; 1997 break; 1998 } 1999 2000 /* SETS / SETNS */ 2001 case 4: 2002 { 2003 Value = State->Flags.Sf; 2004 break; 2005 } 2006 2007 /* SETP / SETNP */ 2008 case 5: 2009 { 2010 Value = State->Flags.Pf; 2011 break; 2012 } 2013 2014 /* SETL / SETNL */ 2015 case 6: 2016 { 2017 Value = State->Flags.Sf != State->Flags.Of; 2018 break; 2019 } 2020 2021 /* SETLE / SETNLE */ 2022 case 7: 2023 { 2024 Value = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf; 2025 break; 2026 } 2027 } 2028 2029 if (Opcode & 1) 2030 { 2031 /* Invert the result */ 2032 Value = !Value; 2033 } 2034 2035 /* Write back the result */ 2036 Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value); 2037 } 2038 2039 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXaddByte) 2040 { 2041 UCHAR Source, Destination, Result; 2042 FAST486_MOD_REG_RM ModRegRm; 2043 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; 2044 2045 /* Make sure this is the right instruction */ 2046 ASSERT(Opcode == 0xC0); 2047 2048 TOGGLE_ADSIZE(AddressSize); 2049 2050 /* Get the operands */ 2051 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) 2052 { 2053 /* Exception occurred */ 2054 return; 2055 } 2056 2057 if (!Fast486ReadModrmByteOperands(State, 2058 &ModRegRm, 2059 &Source, 2060 &Destination)) 2061 { 2062 /* Exception occurred */ 2063 return; 2064 } 2065 2066 /* Calculate the result */ 2067 Result = Source + Destination; 2068 2069 /* Update the flags */ 2070 State->Flags.Cf = (Result < Source) && (Result < Destination); 2071 State->Flags.Of = ((Source & SIGN_FLAG_BYTE) == (Destination & SIGN_FLAG_BYTE)) 2072 && ((Source & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE)); 2073 State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0); 2074 State->Flags.Zf = (Result == 0); 2075 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0); 2076 State->Flags.Pf = Fast486CalculateParity(Result); 2077 2078 /* Write the sum to the destination */ 2079 if (!Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Result)) 2080 { 2081 /* Exception occurred */ 2082 return; 2083 } 2084 2085 /* Write the old value of the destination to the source */ 2086 Fast486WriteModrmByteOperands(State, &ModRegRm, TRUE, Destination); 2087 } 2088 2089 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXadd) 2090 { 2091 FAST486_MOD_REG_RM ModRegRm; 2092 BOOLEAN OperandSize, AddressSize; 2093 2094 /* Make sure this is the right instruction */ 2095 ASSERT(Opcode == 0xC1); 2096 2097 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; 2098 2099 TOGGLE_ADSIZE(AddressSize); 2100 TOGGLE_OPSIZE(OperandSize); 2101 2102 /* Get the operands */ 2103 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) 2104 { 2105 /* Exception occurred */ 2106 return; 2107 } 2108 2109 /* Check the operand size */ 2110 if (OperandSize) 2111 { 2112 ULONG Source, Destination, Result; 2113 2114 if (!Fast486ReadModrmDwordOperands(State, 2115 &ModRegRm, 2116 &Source, 2117 &Destination)) 2118 { 2119 /* Exception occurred */ 2120 return; 2121 } 2122 2123 /* Calculate the result */ 2124 Result = Source + Destination; 2125 2126 /* Update the flags */ 2127 State->Flags.Cf = (Result < Source) && (Result < Destination); 2128 State->Flags.Of = ((Source & SIGN_FLAG_LONG) == (Destination & SIGN_FLAG_LONG)) 2129 && ((Source & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG)); 2130 State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0); 2131 State->Flags.Zf = (Result == 0); 2132 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0); 2133 State->Flags.Pf = Fast486CalculateParity(Result); 2134 2135 /* Write the old value of the destination to the source */ 2136 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, Destination)) 2137 { 2138 /* Exception occurred */ 2139 return; 2140 } 2141 2142 /* Write the sum to the destination */ 2143 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result); 2144 } 2145 else 2146 { 2147 USHORT Source, Destination, Result; 2148 2149 if (!Fast486ReadModrmWordOperands(State, 2150 &ModRegRm, 2151 &Source, 2152 &Destination)) 2153 { 2154 /* Exception occurred */ 2155 return; 2156 } 2157 2158 /* Calculate the result */ 2159 Result = Source + Destination; 2160 2161 /* Update the flags */ 2162 State->Flags.Cf = (Result < Source) && (Result < Destination); 2163 State->Flags.Of = ((Source & SIGN_FLAG_WORD) == (Destination & SIGN_FLAG_WORD)) 2164 && ((Source & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD)); 2165 State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0); 2166 State->Flags.Zf = (Result == 0); 2167 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0); 2168 State->Flags.Pf = Fast486CalculateParity(Result); 2169 2170 /* Write the old value of the destination to the source */ 2171 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, Destination)) 2172 { 2173 /* Exception occurred */ 2174 return; 2175 } 2176 2177 /* Write the sum to the destination */ 2178 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Result); 2179 } 2180 } 2181 2182 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBswap) 2183 { 2184 PUCHAR Pointer; 2185 2186 NO_LOCK_PREFIX(); 2187 2188 /* Get a pointer to the value */ 2189 Pointer = (PUCHAR)&State->GeneralRegs[Opcode & 0x07].Long; 2190 2191 /* Swap the byte order */ 2192 SWAP(Pointer[0], Pointer[3]); 2193 SWAP(Pointer[1], Pointer[2]); 2194 } 2195 2196 FAST486_OPCODE_HANDLER(Fast486OpcodeExtended) 2197 { 2198 UCHAR SecondOpcode; 2199 2200 /* Fetch the second operation code */ 2201 if (!Fast486FetchByte(State, &SecondOpcode)) 2202 { 2203 /* Exception occurred */ 2204 return; 2205 } 2206 2207 /* Call the extended opcode handler */ 2208 Fast486ExtendedHandlers[SecondOpcode](State, SecondOpcode); 2209 } 2210 2211 /* EOF */ 2212