Serenity Operating System
at master 1770 lines 52 kB view raw
1/* 2 * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> 3 * Copyright (c) 2021, Leon Albrecht <leon2002.la@gmail.com> 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#include "SoftFPU.h" 9#include "Emulator.h" 10#include "SoftCPU.h" 11#include "ValueWithShadow.h" 12 13#include <AK/BitCast.h> 14#include <AK/NumericLimits.h> 15#include <AK/UFixedBigInt.h> 16 17#include <unistd.h> 18 19#if defined(AK_COMPILER_GCC) 20# pragma GCC optimize("O3") 21#endif 22 23#define TODO_INSN() \ 24 do { \ 25 reportln("\n=={}== Unimplemented instruction: {}\n"sv, getpid(), __FUNCTION__); \ 26 m_emulator.dump_backtrace(); \ 27 _exit(0); \ 28 } while (0) 29 30template<typename T> 31ALWAYS_INLINE void warn_if_uninitialized(T value_with_shadow, char const* message) 32{ 33 if (value_with_shadow.is_uninitialized()) [[unlikely]] { 34 reportln("\033[31;1mWarning! Use of uninitialized value: {}\033[0m\n"sv, message); 35 UserspaceEmulator::Emulator::the().dump_backtrace(); 36 } 37} 38 39namespace UserspaceEmulator { // NOLINT(readability-implicit-bool-conversion) 0/1 to follow spec closer 40 41ALWAYS_INLINE void SoftFPU::warn_if_mmx_absolute(u8 index) const 42{ 43 if (m_reg_is_mmx[index]) [[unlikely]] { 44 reportln("\033[31;1mWarning! Use of an MMX register as an FPU value ({} abs)\033[0m\n"sv, index); 45 m_emulator.dump_backtrace(); 46 } 47} 48ALWAYS_INLINE void SoftFPU::warn_if_fpu_absolute(u8 index) const 49{ 50 if (!m_reg_is_mmx[index]) [[unlikely]] { 51 reportln("\033[31;1mWarning! Use of an FPU value ({} abs) as an MMX register\033[0m\n"sv, index); 52 m_emulator.dump_backtrace(); 53 } 54} 55 56ALWAYS_INLINE long double SoftFPU::fpu_get(u8 index) 57{ 58 VERIFY(index < 8); 59 if (!fpu_is_set(index)) 60 fpu_set_stack_underflow(); 61 warn_if_mmx_absolute(index); 62 63 u8 effective_index = (m_fpu_stack_top + index) % 8; 64 65 return m_storage[effective_index].fp; 66} 67ALWAYS_INLINE void SoftFPU::fpu_set_absolute(u8 index, long double value) 68{ 69 VERIFY(index < 8); 70 set_tag_from_value_absolute(index, value); 71 m_storage[index].fp = value; 72 m_reg_is_mmx[index] = false; 73} 74ALWAYS_INLINE void SoftFPU::fpu_set(u8 index, long double value) 75{ 76 VERIFY(index < 8); 77 fpu_set_absolute((m_fpu_stack_top + index) % 8, value); 78} 79MMX SoftFPU::mmx_get(u8 index) const 80{ 81 VERIFY(index < 8); 82 warn_if_fpu_absolute(index); 83 return m_storage[index].mmx; 84} 85void SoftFPU::mmx_set(u8 index, MMX value) 86{ 87 m_storage[index].mmx = value; 88 // The high bytes are set to 0b11... to make the floating-point value NaN. 89 // This way we are technically able to find out if we are reading the wrong 90 // type, but this is still difficult, so we use our own lookup for that 91 m_storage[index].__high = 0xFFFFU; 92 m_reg_is_mmx[index] = true; 93} 94 95ALWAYS_INLINE void SoftFPU::fpu_push(long double value) 96{ 97 if (fpu_is_set(7)) 98 fpu_set_stack_overflow(); 99 m_fpu_stack_top = (m_fpu_stack_top - 1u) % 8; 100 101 fpu_set(0, value); 102} 103 104ALWAYS_INLINE long double SoftFPU::fpu_pop() 105{ 106 warn_if_mmx_absolute(m_fpu_stack_top); 107 108 if (!fpu_is_set(0)) 109 fpu_set_stack_underflow(); 110 111 auto ret = fpu_get(0); 112 fpu_set_tag(0, FPU_Tag::Empty); 113 m_fpu_stack_top = (m_fpu_stack_top + 1u) % 8; 114 return ret; 115} 116 117ALWAYS_INLINE void SoftFPU::fpu_set_exception(FPU_Exception ex) 118{ 119 switch (ex) { 120 case FPU_Exception::StackFault: 121 m_fpu_error_stackfault = 1; 122 m_fpu_error_invalid = 1; // Implies InvalidOperation 123 break; 124 case FPU_Exception::InvalidOperation: 125 m_fpu_error_invalid = 1; 126 if (!m_fpu_cw.mask_invalid) 127 break; 128 return; 129 case FPU_Exception::DenormalizedOperand: 130 m_fpu_error_denorm = 1; 131 if (!m_fpu_cw.mask_denorm) 132 break; 133 return; 134 case FPU_Exception::ZeroDivide: 135 m_fpu_error_zero_div = 1; 136 if (!m_fpu_cw.mask_zero_div) 137 break; 138 return; 139 case FPU_Exception::Overflow: 140 m_fpu_error_overflow = 1; 141 if (!m_fpu_cw.mask_overflow) 142 break; 143 return; 144 case FPU_Exception::Underflow: 145 m_fpu_error_underflow = 1; 146 if (!m_fpu_cw.mask_underflow) 147 break; 148 return; 149 case FPU_Exception::Precision: 150 m_fpu_error_precision = 1; 151 if (!m_fpu_cw.mask_precision) 152 break; 153 return; 154 } 155 156 // set exception bit 157 m_fpu_error_summary = 1; 158 159 // FIXME: set traceback 160 // For that we need to get the currently executing instruction and 161 // the previous eip 162 163 // FIXME: Call FPU Exception handler 164 reportln("Trying to call Exception handler from {}"sv, fpu_exception_string(ex)); 165 fpu_dump_env(); 166 m_emulator.dump_backtrace(); 167 TODO(); 168} 169 170template<Arithmetic T> 171ALWAYS_INLINE T SoftFPU::round_checked(long double value) 172{ 173 T result = static_cast<T>(rintl(value)); 174 if (result != value) 175 fpu_set_exception(FPU_Exception::Precision); 176 if (result > value) 177 set_c1(1); 178 else 179 set_c1(0); 180 return result; 181} 182 183template<FloatingPoint T> 184ALWAYS_INLINE T SoftFPU::convert_checked(long double value) 185{ 186 T result = static_cast<T>(value); 187 if (auto rnd = value - result) { 188 if (rnd > 0) 189 set_c1(1); 190 else 191 set_c1(0); 192 fpu_set_exception(FPU_Exception::Precision); 193 } 194 return result; 195} 196 197// Instructions 198 199// DATA TRANSFER 200void SoftFPU::FLD_RM32(const X86::Instruction& insn) 201{ 202 if (insn.modrm().is_register()) { 203 fpu_push(fpu_get(insn.modrm().register_index())); 204 } else { 205 auto new_f32 = insn.modrm().read32(m_cpu, insn); 206 // FIXME: Respect shadow values 207 fpu_push(bit_cast<float>(new_f32.value())); 208 } 209} 210void SoftFPU::FLD_RM64(const X86::Instruction& insn) 211{ 212 VERIFY(!insn.modrm().is_register()); 213 auto new_f64 = insn.modrm().read64(m_cpu, insn); 214 // FIXME: Respect shadow values 215 fpu_push(bit_cast<double>(new_f64.value())); 216} 217void SoftFPU::FLD_RM80(const X86::Instruction& insn) 218{ 219 VERIFY(!insn.modrm().is_register()); 220 221 // long doubles can be up to 128 bits wide in memory for reasons (alignment) and only uses 80 bits of precision 222 // GCC uses 12 bytes in 32 bit and 16 bytes in 64 bit mode 223 // so in the 32 bit case we read a bit to much, but that shouldn't be an issue. 224 // FIXME: Respect shadow values 225 u128 new_f80 = insn.modrm().read128(m_cpu, insn).value(); 226 227 fpu_push(*(long double*)new_f80.bytes().data()); 228} 229 230void SoftFPU::FST_RM32(const X86::Instruction& insn) 231{ 232 VERIFY(!insn.modrm().is_register()); 233 float f32 = convert_checked<float>(fpu_get(0)); 234 235 if (fpu_is_set(0)) 236 insn.modrm().write32(m_cpu, insn, shadow_wrap_as_initialized(bit_cast<u32>(f32))); 237 else 238 insn.modrm().write32(m_cpu, insn, ValueWithShadow<u32>(bit_cast<u32>(f32), 0u)); 239} 240void SoftFPU::FST_RM64(const X86::Instruction& insn) 241{ 242 if (insn.modrm().is_register()) { 243 fpu_set(insn.modrm().register_index(), fpu_get(0)); 244 } else { 245 double f64 = convert_checked<double>(fpu_get(0)); 246 if (fpu_is_set(0)) 247 insn.modrm().write64(m_cpu, insn, shadow_wrap_as_initialized(bit_cast<u64>(f64))); 248 else 249 insn.modrm().write64(m_cpu, insn, ValueWithShadow<u64>(bit_cast<u64>(f64), 0ULL)); 250 } 251} 252 253void SoftFPU::FSTP_RM32(const X86::Instruction& insn) 254{ 255 FST_RM32(insn); 256 fpu_pop(); 257} 258void SoftFPU::FSTP_RM64(const X86::Instruction& insn) 259{ 260 FST_RM64(insn); 261 fpu_pop(); 262} 263void SoftFPU::FSTP_RM80(const X86::Instruction& insn) 264{ 265 if (insn.modrm().is_register()) { 266 fpu_set(insn.modrm().register_index(), fpu_get(0)); 267 fpu_pop(); 268 } else { 269 // FIXME: Respect more shadow values 270 // long doubles can be up to 128 bits wide in memory for reasons (alignment) and only uses 80 bits of precision 271 // gcc uses 12 byte in 32 bit and 16 byte in 64 bit mode 272 // due to only 10 bytes being used, we just write these 10 into memory 273 // We have to do .bytes().data() to get around static type analysis 274 ValueWithShadow<u128> f80 { 0u, 0u }; 275 u128 value {}; 276 f80 = insn.modrm().read128(m_cpu, insn); 277 *(long double*)value.bytes().data() = fpu_pop(); 278 memcpy(f80.value().bytes().data(), &value, 10); // copy 279 f80.set_initialized(); 280 insn.modrm().write128(m_cpu, insn, f80); 281 } 282} 283 284void SoftFPU::FILD_RM16(const X86::Instruction& insn) 285{ 286 VERIFY(!insn.modrm().is_register()); 287 auto m16int = insn.modrm().read16(m_cpu, insn); 288 warn_if_uninitialized(m16int, "int16 loaded as float"); 289 290 fpu_push(static_cast<long double>(static_cast<i16>(m16int.value()))); 291} 292void SoftFPU::FILD_RM32(const X86::Instruction& insn) 293{ 294 VERIFY(!insn.modrm().is_register()); 295 auto m32int = insn.modrm().read32(m_cpu, insn); 296 warn_if_uninitialized(m32int, "int32 loaded as float"); 297 298 fpu_push(static_cast<long double>(static_cast<i32>(m32int.value()))); 299} 300void SoftFPU::FILD_RM64(const X86::Instruction& insn) 301{ 302 VERIFY(!insn.modrm().is_register()); 303 auto m64int = insn.modrm().read64(m_cpu, insn); 304 warn_if_uninitialized(m64int, "int64 loaded as float"); 305 306 fpu_push(static_cast<long double>(static_cast<i64>(m64int.value()))); 307} 308 309void SoftFPU::FIST_RM16(const X86::Instruction& insn) 310{ 311 VERIFY(!insn.modrm().is_register()); 312 auto f = fpu_get(0); 313 set_c1(0); 314 auto int16 = round_checked<i16>(f); 315 316 // FIXME: Respect shadow values 317 insn.modrm().write16(m_cpu, insn, shadow_wrap_as_initialized(bit_cast<u16>(int16))); 318} 319void SoftFPU::FIST_RM32(const X86::Instruction& insn) 320{ 321 VERIFY(!insn.modrm().is_register()); 322 auto f = fpu_get(0); 323 set_c1(0); 324 auto int32 = round_checked<i32>(f); 325 // FIXME: Respect shadow values 326 insn.modrm().write32(m_cpu, insn, shadow_wrap_as_initialized(bit_cast<u32>(int32))); 327} 328 329void SoftFPU::FISTP_RM16(const X86::Instruction& insn) 330{ 331 FIST_RM16(insn); 332 fpu_pop(); 333} 334void SoftFPU::FISTP_RM32(const X86::Instruction& insn) 335{ 336 FIST_RM32(insn); 337 fpu_pop(); 338} 339void SoftFPU::FISTP_RM64(const X86::Instruction& insn) 340{ 341 VERIFY(!insn.modrm().is_register()); 342 auto f = fpu_pop(); 343 set_c1(0); 344 auto i64 = round_checked<int64_t>(f); 345 // FIXME: Respect shadow values 346 insn.modrm().write64(m_cpu, insn, shadow_wrap_as_initialized(bit_cast<u64>(i64))); 347} 348 349void SoftFPU::FISTTP_RM16(const X86::Instruction& insn) 350{ 351 VERIFY(!insn.modrm().is_register()); 352 set_c1(0); 353 i16 value = static_cast<i16>(fpu_pop()); 354 // FIXME: Respect shadow values 355 insn.modrm().write16(m_cpu, insn, shadow_wrap_as_initialized(bit_cast<u16>(value))); 356} 357void SoftFPU::FISTTP_RM32(const X86::Instruction& insn) 358{ 359 VERIFY(!insn.modrm().is_register()); 360 i32 value = static_cast<i32>(fpu_pop()); 361 set_c1(0); 362 // FIXME: Respect shadow values 363 insn.modrm().write32(m_cpu, insn, shadow_wrap_as_initialized(bit_cast<u32>(value))); 364} 365void SoftFPU::FISTTP_RM64(const X86::Instruction& insn) 366{ 367 VERIFY(!insn.modrm().is_register()); 368 set_c1(0); 369 i64 value = static_cast<i64>(fpu_pop()); 370 // FIXME: Respect shadow values 371 insn.modrm().write64(m_cpu, insn, shadow_wrap_as_initialized(bit_cast<u64>(value))); 372} 373 374void SoftFPU::FBLD_M80(const X86::Instruction&) { TODO_INSN(); } 375void SoftFPU::FBSTP_M80(const X86::Instruction&) { TODO_INSN(); } 376 377void SoftFPU::FXCH(const X86::Instruction& insn) 378{ 379 VERIFY(insn.modrm().is_register()); 380 set_c1(0); 381 auto tmp = fpu_get(0); 382 fpu_set(0, fpu_get(insn.modrm().register_index())); 383 fpu_set(insn.modrm().register_index(), tmp); 384} 385 386void SoftFPU::FCMOVE(const X86::Instruction& insn) 387{ 388 VERIFY(insn.modrm().is_register()); 389 if (m_cpu.zf()) 390 fpu_set(0, fpu_get(insn.modrm().rm())); 391} 392void SoftFPU::FCMOVNE(const X86::Instruction& insn) 393{ 394 VERIFY(insn.modrm().is_register()); 395 if (!m_cpu.zf()) 396 fpu_set(0, fpu_get((insn.modrm().reg_fpu()))); 397} 398 399void SoftFPU::FCMOVB(const X86::Instruction& insn) 400{ 401 VERIFY(insn.modrm().is_register()); 402 if (m_cpu.cf()) 403 fpu_set(0, fpu_get(insn.modrm().rm())); 404} 405void SoftFPU::FCMOVNB(const X86::Instruction& insn) 406{ 407 VERIFY(insn.modrm().is_register()); 408 if (!m_cpu.cf()) 409 fpu_set(0, fpu_get(insn.modrm().rm())); 410} 411void SoftFPU::FCMOVBE(const X86::Instruction& insn) 412{ 413 VERIFY(insn.modrm().is_register()); 414 if (m_cpu.cf() || m_cpu.zf()) 415 fpu_set(0, fpu_get(insn.modrm().rm())); 416} 417void SoftFPU::FCMOVNBE(const X86::Instruction& insn) 418{ 419 VERIFY(insn.modrm().is_register()); 420 if (!(m_cpu.cf() || m_cpu.zf())) 421 fpu_set(0, fpu_get(insn.modrm().rm())); 422} 423 424void SoftFPU::FCMOVU(const X86::Instruction& insn) 425{ 426 VERIFY(insn.modrm().is_register()); 427 if (m_cpu.pf()) 428 fpu_set(0, fpu_get((insn.modrm().reg_fpu()))); 429} 430void SoftFPU::FCMOVNU(const X86::Instruction& insn) 431{ 432 VERIFY(insn.modrm().is_register()); 433 if (!m_cpu.pf()) 434 fpu_set(0, fpu_get((insn.modrm().reg_fpu()))); 435} 436 437// BASIC ARITHMETIC 438void SoftFPU::FADD_RM32(const X86::Instruction& insn) 439{ 440 // FIXME look at ::INC_foo for how mem/reg stuff is handled, and use that here too to make sure this is only called for mem32 ops 441 if (insn.modrm().is_register()) { 442 fpu_set(0, fpu_get(insn.modrm().register_index()) + fpu_get(0)); 443 } else { 444 auto new_f32 = insn.modrm().read32(m_cpu, insn); 445 // FIXME: Respect shadow values 446 auto f32 = bit_cast<float>(new_f32.value()); 447 fpu_set(0, fpu_get(0) + f32); 448 } 449} 450void SoftFPU::FADD_RM64(const X86::Instruction& insn) 451{ 452 // FIXME look at ::INC_foo for how mem/reg stuff is handled, and use that here too to make sure this is only called for mem64 ops 453 if (insn.modrm().is_register()) { 454 fpu_set(insn.modrm().register_index(), fpu_get(insn.modrm().register_index()) + fpu_get(0)); 455 } else { 456 auto new_f64 = insn.modrm().read64(m_cpu, insn); 457 // FIXME: Respect shadow values 458 auto f64 = bit_cast<double>(new_f64.value()); 459 fpu_set(0, fpu_get(0) + f64); 460 } 461} 462void SoftFPU::FADDP(const X86::Instruction& insn) 463{ 464 VERIFY(insn.modrm().is_register()); 465 fpu_set(insn.modrm().register_index(), fpu_get(insn.modrm().register_index()) + fpu_get(0)); 466 fpu_pop(); 467} 468 469void SoftFPU::FIADD_RM32(const X86::Instruction& insn) 470{ 471 VERIFY(!insn.modrm().is_register()); 472 auto m32int = (i32)insn.modrm().read32(m_cpu, insn).value(); 473 // FIXME: Respect shadow values 474 fpu_set(0, fpu_get(0) + (long double)m32int); 475} 476void SoftFPU::FIADD_RM16(const X86::Instruction& insn) 477{ 478 VERIFY(!insn.modrm().is_register()); 479 auto m16int = (i16)insn.modrm().read16(m_cpu, insn).value(); 480 // FIXME: Respect shadow values 481 fpu_set(0, fpu_get(0) + (long double)m16int); 482} 483 484void SoftFPU::FSUB_RM32(const X86::Instruction& insn) 485{ 486 if (insn.modrm().is_register()) { 487 fpu_set(0, fpu_get(0) - fpu_get(insn.modrm().register_index())); 488 } else { 489 auto new_f32 = insn.modrm().read32(m_cpu, insn); 490 // FIXME: Respect shadow values 491 auto f32 = bit_cast<float>(new_f32.value()); 492 fpu_set(0, fpu_get(0) - f32); 493 } 494} 495void SoftFPU::FSUB_RM64(const X86::Instruction& insn) 496{ 497 if (insn.modrm().is_register()) { 498 // Note: This is FSUBR (DC E8+i FSUBR st(i) st(0)) in the spec 499 fpu_set(insn.modrm().register_index(), fpu_get(insn.modrm().register_index()) - fpu_get(0)); 500 } else { 501 auto new_f64 = insn.modrm().read64(m_cpu, insn); 502 // FIXME: Respect shadow values 503 auto f64 = bit_cast<double>(new_f64.value()); 504 fpu_set(0, fpu_get(0) - f64); 505 } 506} 507void SoftFPU::FSUBP(const X86::Instruction& insn) 508{ 509 VERIFY(insn.modrm().is_register()); 510 fpu_set(insn.modrm().register_index(), fpu_get(insn.modrm().register_index()) - fpu_get(0)); 511 fpu_pop(); 512} 513 514void SoftFPU::FSUBR_RM32(const X86::Instruction& insn) 515{ 516 if (insn.modrm().is_register()) { 517 fpu_set(0, fpu_get(insn.modrm().register_index()) - fpu_get(0)); 518 } else { 519 auto new_f32 = insn.modrm().read32(m_cpu, insn); 520 // FIXME: Respect shadow values 521 auto f32 = bit_cast<float>(new_f32.value()); 522 fpu_set(0, f32 - fpu_get(0)); 523 } 524} 525void SoftFPU::FSUBR_RM64(const X86::Instruction& insn) 526{ 527 if (insn.modrm().is_register()) { 528 // Note: This is FSUB (DC E0+i FSUB st(i) st(0)) in the spec 529 fpu_set(insn.modrm().register_index(), fpu_get(insn.modrm().register_index()) - fpu_get(0)); 530 } else { 531 auto new_f64 = insn.modrm().read64(m_cpu, insn); 532 // FIXME: Respect shadow values 533 auto f64 = bit_cast<double>(new_f64.value()); 534 fpu_set(0, f64 - fpu_get(0)); 535 } 536} 537void SoftFPU::FSUBRP(const X86::Instruction& insn) 538{ 539 VERIFY(insn.modrm().is_register()); 540 fpu_set(insn.modrm().register_index(), fpu_get(0) - fpu_get(insn.modrm().register_index())); 541 fpu_pop(); 542} 543 544void SoftFPU::FISUB_RM32(const X86::Instruction& insn) 545{ 546 VERIFY(!insn.modrm().is_register()); 547 auto m32int = (i32)insn.modrm().read32(m_cpu, insn).value(); 548 // FIXME: Respect shadow values 549 fpu_set(0, fpu_get(0) - (long double)m32int); 550} 551void SoftFPU::FISUB_RM16(const X86::Instruction& insn) 552{ 553 VERIFY(!insn.modrm().is_register()); 554 auto m16int = (i16)insn.modrm().read16(m_cpu, insn).value(); 555 // FIXME: Respect shadow values 556 fpu_set(0, fpu_get(0) - (long double)m16int); 557} 558 559void SoftFPU::FISUBR_RM16(const X86::Instruction& insn) 560{ 561 VERIFY(!insn.modrm().is_register()); 562 auto m16int = (i16)insn.modrm().read16(m_cpu, insn).value(); 563 // FIXME: Respect shadow values 564 fpu_set(0, (long double)m16int - fpu_get(0)); 565} 566void SoftFPU::FISUBR_RM32(const X86::Instruction& insn) 567{ 568 VERIFY(!insn.modrm().is_register()); 569 auto m32int = (i32)insn.modrm().read32(m_cpu, insn).value(); 570 // FIXME: Respect shadow values 571 fpu_set(0, (long double)m32int - fpu_get(0)); 572} 573 574void SoftFPU::FMUL_RM32(const X86::Instruction& insn) 575{ 576 // FIXME look at ::INC_foo for how mem/reg stuff is handled, and use that here too to make sure this is only called for mem32 ops 577 if (insn.modrm().is_register()) { 578 fpu_set(0, fpu_get(0) * fpu_get(insn.modrm().register_index())); 579 } else { 580 auto new_f32 = insn.modrm().read32(m_cpu, insn); 581 // FIXME: Respect shadow values 582 auto f32 = bit_cast<float>(new_f32.value()); 583 fpu_set(0, fpu_get(0) * f32); 584 } 585} 586void SoftFPU::FMUL_RM64(const X86::Instruction& insn) 587{ 588 // FIXME look at ::INC_foo for how mem/reg stuff is handled, and use that here too to make sure this is only called for mem64 ops 589 if (insn.modrm().is_register()) { 590 fpu_set(insn.modrm().register_index(), fpu_get(insn.modrm().register_index()) * fpu_get(0)); 591 } else { 592 auto new_f64 = insn.modrm().read64(m_cpu, insn); 593 // FIXME: Respect shadow values 594 auto f64 = bit_cast<double>(new_f64.value()); 595 fpu_set(0, fpu_get(0) * f64); 596 } 597} 598void SoftFPU::FMULP(const X86::Instruction& insn) 599{ 600 VERIFY(insn.modrm().is_register()); 601 fpu_set(insn.modrm().register_index(), fpu_get(insn.modrm().register_index()) * fpu_get(0)); 602 fpu_pop(); 603} 604 605void SoftFPU::FIMUL_RM32(const X86::Instruction& insn) 606{ 607 VERIFY(!insn.modrm().is_register()); 608 auto m32int = (i32)insn.modrm().read32(m_cpu, insn).value(); 609 // FIXME: Respect shadow values 610 fpu_set(0, fpu_get(0) * m32int); 611} 612void SoftFPU::FIMUL_RM16(const X86::Instruction& insn) 613{ 614 VERIFY(!insn.modrm().is_register()); 615 auto m16int = (i16)insn.modrm().read16(m_cpu, insn).value(); 616 // FIXME: Respect shadow values 617 fpu_set(0, fpu_get(0) * m16int); 618} 619 620void SoftFPU::FDIV_RM32(const X86::Instruction& insn) 621{ 622 if (insn.modrm().is_register()) { 623 fpu_set(0, fpu_get(0) / fpu_get(insn.modrm().register_index())); 624 } else { 625 auto new_f32 = insn.modrm().read32(m_cpu, insn); 626 // FIXME: Respect shadow values 627 auto f32 = bit_cast<float>(new_f32.value()); 628 // FIXME: Raise IA on + infinity / +-infinity, +-0 / +-0, raise Z on finite / +-0 629 fpu_set(0, fpu_get(0) / f32); 630 } 631} 632void SoftFPU::FDIV_RM64(const X86::Instruction& insn) 633{ 634 if (insn.modrm().is_register()) { 635 // Note: This is FDIVR (DC F0+i FDIVR st(i) st(0)) in the spec 636 fpu_set(insn.modrm().register_index(), fpu_get(insn.modrm().register_index()) / fpu_get(0)); 637 } else { 638 auto new_f64 = insn.modrm().read64(m_cpu, insn); 639 // FIXME: Respect shadow values 640 auto f64 = bit_cast<double>(new_f64.value()); 641 // FIXME: Raise IA on + infinity / +-infinity, +-0 / +-0, raise Z on finite / +-0 642 fpu_set(0, fpu_get(0) / f64); 643 } 644} 645void SoftFPU::FDIVP(const X86::Instruction& insn) 646{ 647 VERIFY(insn.modrm().is_register()); 648 // FIXME: Raise IA on + infinity / +-infinity, +-0 / +-0, raise Z on finite / +-0 649 fpu_set(insn.modrm().register_index(), fpu_get(insn.modrm().register_index()) / fpu_get(0)); 650 fpu_pop(); 651} 652 653void SoftFPU::FDIVR_RM32(const X86::Instruction& insn) 654{ 655 if (insn.modrm().is_register()) { 656 fpu_set(0, fpu_get(insn.modrm().register_index()) / fpu_get(0)); 657 } else { 658 auto new_f32 = insn.modrm().read32(m_cpu, insn); 659 // FIXME: Respect shadow values 660 auto f32 = bit_cast<float>(new_f32.value()); 661 // FIXME: Raise IA on + infinity / +-infinity, +-0 / +-0, raise Z on finite / +-0 662 fpu_set(0, f32 / fpu_get(0)); 663 } 664} 665void SoftFPU::FDIVR_RM64(const X86::Instruction& insn) 666{ 667 if (insn.modrm().is_register()) { 668 // Note: This is FDIV (DC F8+i FDIV st(i) st(0)) in the spec 669 fpu_set(insn.modrm().register_index(), fpu_get(insn.modrm().register_index()) / fpu_get(0)); 670 } else { 671 auto new_f64 = insn.modrm().read64(m_cpu, insn); 672 // FIXME: Respect shadow values 673 auto f64 = bit_cast<double>(new_f64.value()); 674 // FIXME: Raise IA on + infinity / +-infinity, +-0 / +-0, raise Z on finite / +-0 675 fpu_set(0, f64 / fpu_get(0)); 676 } 677} 678void SoftFPU::FDIVRP(const X86::Instruction& insn) 679{ 680 VERIFY(insn.modrm().is_register()); 681 // FIXME: Raise IA on + infinity / +-infinity, +-0 / +-0, raise Z on finite / +-0 682 fpu_set(insn.modrm().register_index(), fpu_get(0) / fpu_get(insn.modrm().register_index())); 683 fpu_pop(); 684} 685 686void SoftFPU::FIDIV_RM16(const X86::Instruction& insn) 687{ 688 VERIFY(!insn.modrm().is_register()); 689 auto m16int = (i16)insn.modrm().read16(m_cpu, insn).value(); 690 // FIXME: Respect shadow values 691 // FIXME: Raise IA on 0 / _=0, raise Z on finite / +-0 692 fpu_set(0, fpu_get(0) / m16int); 693} 694void SoftFPU::FIDIV_RM32(const X86::Instruction& insn) 695{ 696 VERIFY(!insn.modrm().is_register()); 697 auto m32int = (i32)insn.modrm().read32(m_cpu, insn).value(); 698 // FIXME: Respect shadow values 699 // FIXME: Raise IA on 0 / _=0, raise Z on finite / +-0 700 fpu_set(0, fpu_get(0) / m32int); 701} 702 703void SoftFPU::FIDIVR_RM16(const X86::Instruction& insn) 704{ 705 VERIFY(!insn.modrm().is_register()); 706 auto m16int = (i16)insn.modrm().read16(m_cpu, insn).value(); 707 // FIXME: Respect shadow values 708 // FIXME: Raise IA on 0 / _=0, raise Z on finite / +-0 709 fpu_set(0, m16int / fpu_get(0)); 710} 711void SoftFPU::FIDIVR_RM32(const X86::Instruction& insn) 712{ 713 VERIFY(!insn.modrm().is_register()); 714 auto m32int = (i32)insn.modrm().read32(m_cpu, insn).value(); 715 // FIXME: Respect shadow values 716 // FIXME: Raise IA on 0 / _=0, raise Z on finite / +-0 717 fpu_set(0, m32int / fpu_get(0)); 718} 719 720void SoftFPU::FPREM(const X86::Instruction&) 721{ 722 // FIXME: FPREM should only be able to reduce top's exponent by a maximum 723 // amount of 32-63 (impl-specific) 724 long double top = fpu_get(0); 725 long double one = fpu_get(1); 726 727 int Q = static_cast<int>(truncl(top / one)); 728 top = top - (one * Q); 729 set_c2(0); 730 set_c1(Q & 1); 731 set_c3((Q >> 1) & 1); 732 set_c0((Q >> 2) & 1); 733 734 fpu_set(0, top); 735} 736void SoftFPU::FPREM1(const X86::Instruction&) 737{ 738 // FIXME: FPREM1 should only be able to reduce top's exponent by a maximum 739 // amount of 32-63 (impl-specific) 740 long double top = fpu_get(0); 741 long double one = fpu_get(1); 742 743 int Q = static_cast<int>(roundl(top / one)); 744 top = top - (one * Q); 745 set_c2(0); 746 set_c1(Q & 1); 747 set_c3((Q >> 1) & 1); 748 set_c0((Q >> 2) & 1); 749 750 fpu_set(0, top); 751} 752void SoftFPU::FABS(const X86::Instruction&) 753{ 754 set_c1(0); 755 fpu_set(0, __builtin_fabsl(fpu_get(0))); 756} 757void SoftFPU::FCHS(const X86::Instruction&) 758{ 759 set_c1(0); 760 fpu_set(0, -fpu_get(0)); 761} 762 763void SoftFPU::FRNDINT(const X86::Instruction&) 764{ 765 // FIXME: Raise #IA #D 766 auto res = round_checked<long double>(fpu_get(0)); 767 fpu_set(0, res); 768} 769 770void SoftFPU::FSCALE(const X86::Instruction&) 771{ 772 // FIXME: Raise #IA #D #U #O #P 773 fpu_set(0, fpu_get(0) * exp2l(truncl(fpu_get(1)))); 774} 775 776void SoftFPU::FSQRT(const X86::Instruction&) 777{ 778 // FIXME: Raise #IA #D #P 779 if (fpu_get(0) < 0) 780 fpu_set_exception(FPU_Exception::InvalidOperation); 781 fpu_set(0, sqrtl(fpu_get(0))); 782} 783 784void SoftFPU::FXTRACT(const X86::Instruction&) { TODO_INSN(); } 785 786// COMPARISON 787 788// FIXME: there may be an implicit argument, how is this conveyed by the insn 789void SoftFPU::FCOM_RM32(const X86::Instruction&) { TODO_INSN(); } 790void SoftFPU::FCOM_RM64(const X86::Instruction&) { TODO_INSN(); } 791void SoftFPU::FCOMP_RM32(const X86::Instruction&) { TODO_INSN(); } 792void SoftFPU::FCOMP_RM64(const X86::Instruction&) { TODO_INSN(); } 793void SoftFPU::FCOMPP(const X86::Instruction&) 794{ 795 if (fpu_isnan(0) || fpu_isnan(1)) { 796 fpu_set_exception(FPU_Exception::InvalidOperation); 797 if (m_fpu_cw.mask_invalid) 798 fpu_set_unordered(); 799 } else { 800 set_c2(0); 801 set_c0(fpu_get(0) < fpu_get(1)); 802 set_c3(fpu_get(0) == fpu_get(1)); 803 } 804 fpu_pop(); 805 fpu_pop(); 806} 807 808void SoftFPU::FUCOM(const X86::Instruction&) { TODO_INSN(); } // Needs QNaN detection 809void SoftFPU::FUCOMP(const X86::Instruction&) { TODO_INSN(); } 810void SoftFPU::FUCOMPP(const X86::Instruction&) { TODO_INSN(); } 811 812void SoftFPU::FICOM_RM16(const X86::Instruction& insn) 813{ 814 // FIXME: Check for denormals 815 VERIFY(insn.modrm().is_register()); 816 auto val_shd = insn.modrm().read16(m_cpu, insn); 817 warn_if_uninitialized(val_shd, "int16 compare to float"); 818 auto val = static_cast<i16>(val_shd.value()); 819 if (fpu_isnan(0)) { 820 fpu_set_unordered(); 821 } else { 822 set_c0(fpu_get(0) < val); 823 set_c2(0); 824 set_c3(fpu_get(0) == val); 825 } 826 set_c1(0); 827} 828void SoftFPU::FICOM_RM32(const X86::Instruction& insn) 829{ 830 // FIXME: Check for denormals 831 VERIFY(insn.modrm().is_register()); 832 auto val_shd = insn.modrm().read32(m_cpu, insn); 833 warn_if_uninitialized(val_shd, "int32 compare to float"); 834 auto val = static_cast<i32>(val_shd.value()); 835 if (fpu_isnan(0)) { 836 fpu_set_unordered(); 837 } else { 838 set_c0(fpu_get(0) < val); 839 set_c2(0); 840 set_c3(fpu_get(0) == val); 841 } 842 set_c1(0); 843} 844void SoftFPU::FICOMP_RM16(const X86::Instruction& insn) 845{ 846 FICOM_RM16(insn); 847 fpu_pop(); 848} 849void SoftFPU::FICOMP_RM32(const X86::Instruction& insn) 850{ 851 FICOM_RM32(insn); 852 fpu_pop(); 853} 854 855void SoftFPU::FCOMI(const X86::Instruction& insn) 856{ 857 auto i = insn.modrm().rm(); 858 // FIXME: QNaN / exception handling. 859 set_c0(0); 860 if (isnan(fpu_get(0)) || isnan(fpu_get(1))) { 861 fpu_set_exception(FPU_Exception::InvalidOperation); 862 m_cpu.set_zf(1); 863 m_cpu.set_pf(1); 864 m_cpu.set_cf(1); 865 } else { 866 m_cpu.set_zf(fpu_get(0) == fpu_get(i)); 867 m_cpu.set_pf(false); 868 m_cpu.set_cf(fpu_get(0) < fpu_get(i)); 869 } 870 if (!fpu_is_set(1)) 871 fpu_set_exception(FPU_Exception::Underflow); 872 873 m_cpu.set_of(false); 874 m_cpu.set_af(false); 875 m_cpu.set_sf(false); 876 877 // FIXME: Taint should be based on ST(0) and ST(i) 878 m_cpu.m_flags_tainted = false; 879} 880void SoftFPU::FCOMIP(const X86::Instruction& insn) 881{ 882 FCOMI(insn); 883 fpu_pop(); 884} 885 886void SoftFPU::FUCOMI(const X86::Instruction& insn) 887{ 888 auto i = insn.modrm().rm(); 889 // FIXME: Unordered comparison checks. 890 // FIXME: QNaN / exception handling. 891 set_c1(0); 892 if (fpu_isnan(0) || fpu_isnan(i)) { 893 m_cpu.set_zf(true); 894 m_cpu.set_pf(true); 895 m_cpu.set_cf(true); 896 } else { 897 m_cpu.set_zf(fpu_get(0) == fpu_get(i)); 898 m_cpu.set_pf(false); 899 m_cpu.set_cf(fpu_get(0) < fpu_get(i)); 900 } 901 m_cpu.set_of(false); 902 m_cpu.set_af(false); 903 m_cpu.set_sf(false); 904 905 // FIXME: Taint should be based on ST(0) and ST(i) 906 m_cpu.m_flags_tainted = false; 907} 908void SoftFPU::FUCOMIP(const X86::Instruction& insn) 909{ 910 FUCOMI(insn); 911 fpu_pop(); 912} 913 914void SoftFPU::FTST(const X86::Instruction&) 915{ 916 // FIXME: maybe check for denormal 917 set_c1(0); 918 if (fpu_isnan(0)) 919 // raise #IA? 920 fpu_set_unordered(); 921 else { 922 set_c0(fpu_get(0) < 0.); 923 set_c2(0); 924 set_c3(fpu_get(0) == 0.); 925 } 926} 927void SoftFPU::FXAM(const X86::Instruction&) 928{ 929 if (m_reg_is_mmx[m_fpu_stack_top]) { 930 // technically a subset of NaN/INF, with the Tag set to valid, 931 // but we have our own helper for this 932 set_c0(0); 933 set_c2(0); 934 set_c3(0); 935 } else { 936 switch (fpu_get_tag(0)) { 937 case FPU_Tag::Valid: 938 set_c0(0); 939 set_c2(1); 940 set_c3(0); 941 break; 942 case FPU_Tag::Zero: 943 set_c0(1); 944 set_c2(0); 945 set_c3(0); 946 break; 947 case FPU_Tag::Special: 948 if (isinf(fpu_get(0))) { 949 set_c0(1); 950 set_c2(1); 951 set_c3(0); 952 } else if (isnan(fpu_get(0))) { 953 set_c0(1); 954 set_c2(0); 955 set_c3(0); 956 } else { 957 // denormalized 958 set_c0(0); 959 set_c2(1); 960 set_c3(1); 961 } 962 break; 963 case FPU_Tag::Empty: 964 set_c0(1); 965 set_c2(0); 966 set_c3(1); 967 break; 968 default: 969 VERIFY_NOT_REACHED(); 970 } 971 } 972 set_c1(signbit(fpu_get(0))); 973} 974 975// TRANSCENDENTAL 976void SoftFPU::FSIN(const X86::Instruction&) 977{ 978 // FIXME: Raise #IA #D #P 979 // FIXME: Set C1 on when result was rounded up, cleared otherwise 980 // FIXME: Set C2 to 1 if ST(0) is outside range of -2^63 to +2^63; else set to 0 981 // ST(0) shall remain unchanged in this case 982 fpu_set(0, sinl(fpu_get(0))); 983} 984void SoftFPU::FCOS(const X86::Instruction&) 985{ 986 // FIXME: Raise #IA #D #P 987 // FIXME: Set C1 on when result was rounded up, cleared otherwise 988 // FIXME: Set C2 to 1 if ST(0) is outside range of -2^63 to +2^63; else set to 0 989 // ST(0) shall remain unchanged in this case 990 fpu_set(0, cosl(fpu_get(0))); 991} 992void SoftFPU::FSINCOS(const X86::Instruction&) 993{ 994 // FIXME: Raise #IA #D #P 995 // FIXME: Set C1 on when result was rounded up, cleared otherwise 996 // FIXME: Set C2 to 1 if ST(0) is outside range of -2^63 to +2^63; else set to 0 997 // ST(0) shall remain unchanged in this case 998 long double sin = sinl(fpu_get(0)); 999 long double cos = cosl(fpu_get(0)); 1000 fpu_set(0, sin); 1001 fpu_push(cos); 1002} 1003 1004void SoftFPU::FPTAN(const X86::Instruction&) 1005{ 1006 // FIXME: Raise #IA #D #U #P 1007 // FIXME: Set C1 on when result was rounded up, cleared otherwise 1008 // FIXME: Set C2 to 1 if ST(0) is outside range of -2^63 to +2^63; else set to 0 1009 // ST(0) shall remain unchanged in this case 1010 fpu_set(0, tanl(fpu_get(0))); 1011 fpu_push(1.0f); 1012} 1013void SoftFPU::FPATAN(const X86::Instruction&) 1014{ 1015 // FIXME: Raise #IA #D #U #P 1016 // FIXME: Set C1 on when result was rounded up, cleared otherwise 1017 // Note: Not implemented 80287 quirk: 1018 // Restriction to 0 ≤ |ST(1)| < |ST(0)| < +∞ 1019 fpu_set(1, atan2l(fpu_get(1), fpu_get(0))); 1020 fpu_pop(); 1021} 1022 1023void SoftFPU::F2XM1(const X86::Instruction&) 1024{ 1025 // FIXME: Raise #IA #D #U #P 1026 // FIXME: Set C1 on when result was rounded up, cleared otherwise 1027 // FIXME: Validate ST(0) is in range –1.0 to +1.0 1028 auto val = fpu_get(0); 1029 fpu_set(0, exp2(val) - 1.0l); 1030} 1031void SoftFPU::FYL2X(const X86::Instruction&) 1032{ 1033 // FIXME: Set C1 on when result was rounded up, cleared otherwise 1034 // FIXME: Raise #IA #D #U #O #P 1035 auto x = fpu_get(0); 1036 auto y = fpu_get(1); 1037 if (x < 0. && !isinf(x)) { 1038 fpu_set_exception(FPU_Exception::InvalidOperation); 1039 // FIXME: Spec does not say what to do here.... 1040 // So lets just ask libm.... 1041 fpu_set(1, y * log2l(x)); 1042 } else if (x == 0.) { 1043 if (y == 0) 1044 fpu_set_exception(FPU_Exception::InvalidOperation); 1045 fpu_set_exception(FPU_Exception::ZeroDivide); 1046 fpu_set(1, INFINITY * (signbit(y) ? 1 : -1)); 1047 } else { 1048 fpu_set(1, y * log2l(x)); 1049 } 1050 fpu_pop(); 1051} 1052void SoftFPU::FYL2XP1(const X86::Instruction&) 1053{ 1054 // FIXME: Raise #IA #O #U #P #D 1055 auto x = fpu_get(0); 1056 auto y = fpu_get(1); 1057 if (x == 0 && isinf(y)) 1058 fpu_set_exception(FPU_Exception::InvalidOperation); 1059 1060 fpu_set(1, (y * log2l(x + 1.0l))); 1061 fpu_pop(); 1062} 1063 1064// LOAD CONSTANT 1065void SoftFPU::FLD1(const X86::Instruction&) 1066{ 1067 set_c1(0); 1068 fpu_push(1.0l); 1069} 1070void SoftFPU::FLDZ(const X86::Instruction&) 1071{ 1072 set_c1(0); 1073 fpu_push(0.0l); 1074} 1075void SoftFPU::FLDPI(const X86::Instruction&) 1076{ 1077 set_c1(0); 1078 fpu_push(M_PIl); 1079} 1080void SoftFPU::FLDL2E(const X86::Instruction&) 1081{ 1082 set_c1(0); 1083 fpu_push(M_LOG2El); 1084} 1085void SoftFPU::FLDLN2(const X86::Instruction&) 1086{ 1087 set_c1(0); 1088 fpu_push(M_LN2l); 1089} 1090void SoftFPU::FLDL2T(const X86::Instruction&) 1091{ 1092 set_c1(0); 1093 fpu_push(log2l(10.0l)); 1094} 1095void SoftFPU::FLDLG2(const X86::Instruction&) 1096{ 1097 set_c1(0); 1098 fpu_push(log10l(2.0l)); 1099} 1100 1101// CONTROL 1102void SoftFPU::FINCSTP(const X86::Instruction&) 1103{ 1104 m_fpu_stack_top = (m_fpu_stack_top + 1u) % 8u; 1105 set_c1(0); 1106} 1107void SoftFPU::FDECSTP(const X86::Instruction&) 1108{ 1109 m_fpu_stack_top = (m_fpu_stack_top - 1u) % 8u; 1110 set_c1(0); 1111} 1112 1113void SoftFPU::FFREE(const X86::Instruction& insn) 1114{ 1115 fpu_set_tag(insn.modrm().reg_fpu(), FPU_Tag::Empty); 1116} 1117void SoftFPU::FFREEP(const X86::Instruction& insn) 1118{ 1119 FFREE(insn); 1120 fpu_pop(); 1121} 1122 1123void SoftFPU::FNINIT(const X86::Instruction&) 1124{ 1125 m_fpu_cw.cw = 0x037F; 1126 m_fpu_sw = 0; 1127 m_fpu_tw = 0xFFFF; 1128 1129 m_fpu_ip = 0; 1130 m_fpu_cs = 0; 1131 1132 m_fpu_dp = 0; 1133 m_fpu_ds = 0; 1134 1135 m_fpu_iop = 0; 1136}; 1137void SoftFPU::FNCLEX(const X86::Instruction&) 1138{ 1139 m_fpu_error_invalid = 0; 1140 m_fpu_error_denorm = 0; 1141 m_fpu_error_zero_div = 0; 1142 m_fpu_error_overflow = 0; 1143 m_fpu_error_underflow = 0; 1144 m_fpu_error_precision = 0; 1145 m_fpu_error_stackfault = 0; 1146 m_fpu_busy = 0; 1147} 1148 1149void SoftFPU::FNSTCW(const X86::Instruction& insn) 1150{ 1151 insn.modrm().write16(m_cpu, insn, shadow_wrap_as_initialized(m_fpu_cw.cw)); 1152} 1153void SoftFPU::FLDCW(const X86::Instruction& insn) 1154{ 1155 m_fpu_cw.cw = insn.modrm().read16(m_cpu, insn).value(); 1156 1157 // Just let the host's x87 handle the rounding for us 1158 // We do not want to accedentally raise an FP-Exception on the host, so we 1159 // mask all exceptions 1160 AK::X87ControlWord temp = m_fpu_cw; 1161 temp.mask_invalid = 1; 1162 temp.mask_denorm = 1; 1163 temp.mask_zero_div = 1; 1164 temp.mask_overflow = 1; 1165 temp.mask_underflow = 1; 1166 temp.mask_precision = 1; 1167 AK::set_cw_x87(temp); 1168} 1169 1170void SoftFPU::FNSTENV(const X86::Instruction& insn) 1171{ 1172 // Assuming we are always in Protected mode 1173 // FIXME: 16-bit Format 1174 1175 // 32-bit Format 1176 /* 31--------------16---------------0 1177 * | | CW | 0 1178 * +----------------+---------------+ 1179 * | | SW | 4 1180 * +----------------+---------------+ 1181 * | | TW | 8 1182 * +----------------+---------------+ 1183 * | FIP | 12 1184 * +----+-----------+---------------+ 1185 * |0000|fpuOp[10:0]| FIP_sel | 16 1186 * +----+-----------+---------------+ 1187 * | FDP | 20 1188 * +----------------+---------------+ 1189 * | | FDP_ds | 24 1190 * +----------------|---------------+ 1191 * */ 1192 1193 auto address = insn.modrm().resolve(m_cpu, insn); 1194 1195 m_cpu.write_memory16(address, shadow_wrap_as_initialized(m_fpu_cw.cw)); 1196 address.set_offset(address.offset() + 4); 1197 m_cpu.write_memory16(address, shadow_wrap_as_initialized(m_fpu_sw)); 1198 address.set_offset(address.offset() + 4); 1199 m_cpu.write_memory16(address, shadow_wrap_as_initialized(m_fpu_tw)); 1200 address.set_offset(address.offset() + 4); 1201 m_cpu.write_memory32(address, shadow_wrap_as_initialized(m_fpu_ip)); 1202 address.set_offset(address.offset() + 4); 1203 m_cpu.write_memory16(address, shadow_wrap_as_initialized(m_fpu_cs)); 1204 address.set_offset(address.offset() + 2); 1205 m_cpu.write_memory16(address, shadow_wrap_as_initialized<u16>(m_fpu_iop & 0x3FFU)); 1206 address.set_offset(address.offset() + 2); 1207 m_cpu.write_memory32(address, shadow_wrap_as_initialized(m_fpu_dp)); 1208 address.set_offset(address.offset() + 4); 1209 m_cpu.write_memory16(address, shadow_wrap_as_initialized(m_fpu_ds)); 1210} 1211void SoftFPU::FLDENV(const X86::Instruction& insn) 1212{ 1213 // Assuming we are always in Protected mode 1214 // FIXME: 16-bit Format 1215 auto address = insn.modrm().resolve(m_cpu, insn); 1216 1217 // FIXME: Shadow Values 1218 m_fpu_cw.cw = m_cpu.read_memory16(address).value(); 1219 // See note in FLDCW 1220 AK::X87ControlWord temp = m_fpu_cw; 1221 temp.mask_invalid = 1; 1222 temp.mask_denorm = 1; 1223 temp.mask_zero_div = 1; 1224 temp.mask_overflow = 1; 1225 temp.mask_underflow = 1; 1226 temp.mask_precision = 1; 1227 AK::set_cw_x87(temp); 1228 1229 address.set_offset(address.offset() + 4); 1230 m_fpu_sw = m_cpu.read_memory16(address).value(); 1231 address.set_offset(address.offset() + 4); 1232 m_fpu_tw = m_cpu.read_memory16(address).value(); 1233 address.set_offset(address.offset() + 4); 1234 m_fpu_ip = m_cpu.read_memory32(address).value(); 1235 address.set_offset(address.offset() + 4); 1236 m_fpu_cs = m_cpu.read_memory16(address).value(); 1237 address.set_offset(address.offset() + 2); 1238 m_fpu_iop = m_cpu.read_memory16(address).value(); 1239 address.set_offset(address.offset() + 2); 1240 m_fpu_dp = m_cpu.read_memory32(address).value(); 1241 address.set_offset(address.offset() + 4); 1242 m_fpu_ds = m_cpu.read_memory16(address).value(); 1243} 1244 1245void SoftFPU::FNSAVE(const X86::Instruction& insn) 1246{ 1247 FNSTENV(insn); 1248 1249 auto address = insn.modrm().resolve(m_cpu, insn); 1250 address.set_offset(address.offset() + 28); // size of the ENV 1251 1252 // write fpu-stack to memory 1253 u8 raw_data[80]; 1254 for (int i = 0; i < 8; ++i) { 1255 memcpy(raw_data + 10 * i, &m_storage[i], 10); 1256 } 1257 for (int i = 0; i < 5; ++i) { 1258 // FIXME: Shadow Value 1259 m_cpu.write_memory128(address, shadow_wrap_as_initialized(((u128*)raw_data)[i])); 1260 address.set_offset(address.offset() + 16); 1261 } 1262 1263 FNINIT(insn); 1264} 1265void SoftFPU::FRSTOR(const X86::Instruction& insn) 1266{ 1267 FLDENV(insn); 1268 1269 auto address = insn.modrm().resolve(m_cpu, insn); 1270 address.set_offset(address.offset() + 28); // size of the ENV 1271 1272 // read fpu-stack from memory 1273 u8 raw_data[80]; 1274 for (int i = 0; i < 5; ++i) { 1275 // FIXME: Shadow Value 1276 ((u128*)raw_data)[i] = m_cpu.read_memory128(address).value(); 1277 address.set_offset(address.offset() + 16); 1278 } 1279 for (int i = 0; i < 8; ++i) { 1280 memcpy(&m_storage[i], raw_data + 10 * i, 10); 1281 } 1282 1283 memset(m_reg_is_mmx, 0, sizeof(m_reg_is_mmx)); 1284} 1285 1286void SoftFPU::FNSTSW(const X86::Instruction& insn) 1287{ 1288 insn.modrm().write16(m_cpu, insn, shadow_wrap_as_initialized(m_fpu_sw)); 1289} 1290void SoftFPU::FNSTSW_AX(const X86::Instruction&) 1291{ 1292 m_cpu.set_ax(shadow_wrap_as_initialized(m_fpu_sw)); 1293} 1294// FIXME: FWAIT 1295void SoftFPU::FNOP(const X86::Instruction&) { } 1296 1297// DO NOTHING? 1298void SoftFPU::FNENI(const X86::Instruction&) { TODO_INSN(); } 1299void SoftFPU::FNDISI(const X86::Instruction&) { TODO_INSN(); } 1300void SoftFPU::FNSETPM(const X86::Instruction&) { TODO_INSN(); } 1301 1302// MMX 1303// helpers 1304#define LOAD_MM_MM64M() \ 1305 VERIFY(!insn.has_operand_size_override_prefix()); /* SSE2 */ \ 1306 MMX mm; \ 1307 MMX mm64m; \ 1308 if (insn.modrm().mod() == 0b11) { /* 0b11 signals a register */ \ 1309 mm64m = mmx_get(insn.modrm().rm()); \ 1310 } else { \ 1311 auto temp = insn.modrm().read64(m_cpu, insn); \ 1312 warn_if_uninitialized(temp, "Read of uninitialized Memory as Packed integer"); \ 1313 mm64m.raw = temp.value(); \ 1314 } \ 1315 mm = mmx_get(insn.modrm().reg()) 1316 1317#define MMX_intrinsic(intrinsic, res_type, actor_type) \ 1318 LOAD_MM_MM64M(); \ 1319 mm.res_type = __builtin_ia32_##intrinsic(mm.actor_type, mm64m.actor_type); \ 1320 mmx_set(insn.modrm().reg(), mm); \ 1321 mmx_common(); 1322 1323// ARITHMETIC 1324void SoftFPU::PADDB_mm1_mm2m64(const X86::Instruction& insn) 1325{ 1326 LOAD_MM_MM64M(); 1327 mm.v8 += mm64m.v8; 1328 mmx_set(insn.modrm().reg(), mm); 1329 mmx_common(); 1330} 1331void SoftFPU::PADDW_mm1_mm2m64(const X86::Instruction& insn) 1332{ 1333 LOAD_MM_MM64M(); 1334 mm.v16 += mm64m.v16; 1335 mmx_set(insn.modrm().reg(), mm); 1336 mmx_common(); 1337} 1338void SoftFPU::PADDD_mm1_mm2m64(const X86::Instruction& insn) 1339{ 1340 LOAD_MM_MM64M(); 1341 mm.v32 += mm64m.v32; 1342 mmx_set(insn.modrm().reg(), mm); 1343 mmx_common(); 1344} 1345void SoftFPU::PADDSB_mm1_mm2m64(const X86::Instruction& insn) 1346{ 1347 MMX_intrinsic(paddsb, v8, v8); 1348} 1349void SoftFPU::PADDSW_mm1_mm2m64(const X86::Instruction& insn) 1350{ 1351 MMX_intrinsic(paddsw, v16, v16); 1352} 1353void SoftFPU::PADDUSB_mm1_mm2m64(const X86::Instruction& insn) 1354{ 1355 MMX_intrinsic(paddusb, v8, v8); 1356} 1357void SoftFPU::PADDUSW_mm1_mm2m64(const X86::Instruction& insn) 1358{ 1359 MMX_intrinsic(paddusw, v16, v16); 1360} 1361 1362void SoftFPU::PSUBB_mm1_mm2m64(const X86::Instruction& insn) 1363{ 1364 LOAD_MM_MM64M(); 1365 mm.v8 -= mm64m.v8; 1366 mmx_set(insn.modrm().reg(), mm); 1367 mmx_common(); 1368} 1369void SoftFPU::PSUBW_mm1_mm2m64(const X86::Instruction& insn) 1370{ 1371 LOAD_MM_MM64M(); 1372 mm.v16 -= mm64m.v16; 1373 mmx_set(insn.modrm().reg(), mm); 1374 mmx_common(); 1375} 1376void SoftFPU::PSUBD_mm1_mm2m64(const X86::Instruction& insn) 1377{ 1378 LOAD_MM_MM64M(); 1379 mm.v32 -= mm64m.v32; 1380 mmx_set(insn.modrm().reg(), mm); 1381 mmx_common(); 1382} 1383void SoftFPU::PSUBSB_mm1_mm2m64(const X86::Instruction& insn) 1384{ 1385 MMX_intrinsic(psubsb, v8, v8); 1386} 1387void SoftFPU::PSUBSW_mm1_mm2m64(const X86::Instruction& insn) 1388{ 1389 MMX_intrinsic(psubsw, v16, v16); 1390} 1391void SoftFPU::PSUBUSB_mm1_mm2m64(const X86::Instruction& insn) 1392{ 1393 MMX_intrinsic(psubusb, v8, v8); 1394} 1395void SoftFPU::PSUBUSW_mm1_mm2m64(const X86::Instruction& insn) 1396{ 1397 MMX_intrinsic(psubusw, v16, v16); 1398} 1399 1400void SoftFPU::PMULHW_mm1_mm2m64(const X86::Instruction& insn) 1401{ 1402 MMX_intrinsic(pmulhw, v16, v16); 1403} 1404void SoftFPU::PMULLW_mm1_mm2m64(const X86::Instruction& insn) 1405{ 1406 MMX_intrinsic(pmullw, v16, v16); 1407} 1408 1409void SoftFPU::PMADDWD_mm1_mm2m64(const X86::Instruction& insn) 1410{ 1411 MMX_intrinsic(pmaddwd, v32, v16); 1412} 1413 1414// COMPARISON 1415void SoftFPU::PCMPEQB_mm1_mm2m64(const X86::Instruction& insn) 1416{ 1417 LOAD_MM_MM64M(); 1418 1419 mm.v8 = mm.v8 == mm64m.v8; 1420 1421 mmx_set(insn.modrm().reg(), mm); 1422 mmx_common(); 1423} 1424void SoftFPU::PCMPEQW_mm1_mm2m64(const X86::Instruction& insn) 1425{ 1426 LOAD_MM_MM64M(); 1427 1428 mm.v16 = mm.v16 == mm64m.v16; 1429 mmx_set(insn.modrm().reg(), mm); 1430 mmx_common(); 1431} 1432void SoftFPU::PCMPEQD_mm1_mm2m64(const X86::Instruction& insn) 1433{ 1434 LOAD_MM_MM64M(); 1435 1436 mm.v32 = mm.v32 == mm64m.v32; 1437 1438 mmx_set(insn.modrm().reg(), mm); 1439 mmx_common(); 1440} 1441 1442void SoftFPU::PCMPGTB_mm1_mm2m64(const X86::Instruction& insn) 1443{ 1444 LOAD_MM_MM64M(); 1445 1446 mm.v8 = mm.v8 > mm64m.v8; 1447 1448 mmx_set(insn.modrm().reg(), mm); 1449 mmx_common(); 1450} 1451void SoftFPU::PCMPGTW_mm1_mm2m64(const X86::Instruction& insn) 1452{ 1453 LOAD_MM_MM64M(); 1454 1455 mm.v16 = mm.v16 > mm64m.v16; 1456 1457 mmx_set(insn.modrm().reg(), mm); 1458 mmx_common(); 1459} 1460void SoftFPU::PCMPGTD_mm1_mm2m64(const X86::Instruction& insn) 1461{ 1462 LOAD_MM_MM64M(); 1463 1464 mm.v32 = mm.v32 > mm64m.v32; 1465 1466 mmx_set(insn.modrm().reg(), mm); 1467 mmx_common(); 1468} 1469 1470// CONVERSION 1471void SoftFPU::PACKSSDW_mm1_mm2m64(const X86::Instruction& insn) 1472{ 1473 MMX_intrinsic(packssdw, v16, v32); 1474} 1475void SoftFPU::PACKSSWB_mm1_mm2m64(const X86::Instruction& insn) 1476{ 1477 MMX_intrinsic(packsswb, v8, v16); 1478} 1479void SoftFPU::PACKUSWB_mm1_mm2m64(const X86::Instruction& insn) 1480{ 1481 MMX_intrinsic(packuswb, v8, v16); 1482} 1483 1484// UNPACK 1485void SoftFPU::PUNPCKHBW_mm1_mm2m64(const X86::Instruction& insn) 1486{ 1487 MMX_intrinsic(punpckhbw, v8, v8); 1488} 1489 1490void SoftFPU::PUNPCKHWD_mm1_mm2m64(const X86::Instruction& insn) 1491{ 1492 MMX_intrinsic(punpckhwd, v16, v16); 1493} 1494void SoftFPU::PUNPCKHDQ_mm1_mm2m64(const X86::Instruction& insn) 1495{ 1496 MMX_intrinsic(punpckhdq, v32, v32); 1497} 1498 1499void SoftFPU::PUNPCKLBW_mm1_mm2m32(const X86::Instruction& insn) 1500{ 1501 MMX_intrinsic(punpcklbw, v8, v8); 1502} 1503void SoftFPU::PUNPCKLWD_mm1_mm2m32(const X86::Instruction& insn) 1504{ 1505 MMX_intrinsic(punpcklwd, v16, v16); 1506} 1507void SoftFPU::PUNPCKLDQ_mm1_mm2m32(const X86::Instruction& insn) 1508{ 1509 MMX_intrinsic(punpckldq, v32, v32); 1510} 1511 1512// LOGICAL 1513void SoftFPU::PAND_mm1_mm2m64(const X86::Instruction& insn) 1514{ 1515 LOAD_MM_MM64M(); 1516 1517 mm.raw &= mm64m.raw; 1518 1519 mmx_set(insn.modrm().reg(), mm); 1520 mmx_common(); 1521} 1522void SoftFPU::PANDN_mm1_mm2m64(const X86::Instruction& insn) 1523{ 1524 LOAD_MM_MM64M(); 1525 1526 mm.raw &= ~mm64m.raw; 1527 1528 mmx_set(insn.modrm().reg(), mm); 1529 mmx_common(); 1530} 1531void SoftFPU::POR_mm1_mm2m64(const X86::Instruction& insn) 1532{ 1533 LOAD_MM_MM64M(); 1534 1535 mm.raw |= mm64m.raw; 1536 1537 mmx_set(insn.modrm().reg(), mm); 1538 mmx_common(); 1539} 1540void SoftFPU::PXOR_mm1_mm2m64(const X86::Instruction& insn) 1541{ 1542 LOAD_MM_MM64M(); 1543 1544 mm.raw ^= mm64m.raw; 1545 1546 mmx_set(insn.modrm().reg(), mm); 1547 mmx_common(); 1548} 1549 1550// SHIFT 1551void SoftFPU::PSLLW_mm1_mm2m64(const X86::Instruction& insn) 1552{ 1553 LOAD_MM_MM64M(); 1554 1555 mm.v16 <<= mm64m.v16; 1556 1557 mmx_set(insn.modrm().reg(), mm); 1558 mmx_common(); 1559} 1560void SoftFPU::PSLLW_mm1_imm8(const X86::Instruction& insn) 1561{ 1562 VERIFY(!insn.has_operand_size_override_prefix()); // SSE2 1563 u8 imm = insn.imm8(); 1564 MMX mm = mmx_get(insn.modrm().reg()); 1565 1566 mm.v16 <<= imm; 1567 1568 mmx_set(insn.modrm().reg(), mm); 1569 mmx_common(); 1570} 1571void SoftFPU::PSLLD_mm1_mm2m64(const X86::Instruction& insn) 1572{ 1573 LOAD_MM_MM64M(); 1574 1575 mm.v32 <<= mm64m.v32; 1576 1577 mmx_set(insn.modrm().reg(), mm); 1578 mmx_common(); 1579} 1580void SoftFPU::PSLLD_mm1_imm8(const X86::Instruction& insn) 1581{ 1582 VERIFY(!insn.has_operand_size_override_prefix()); /* SSE2 */ 1583 u8 imm = insn.imm8(); 1584 MMX mm = mmx_get(insn.modrm().reg()); 1585 1586 mm.v32 <<= imm; 1587 1588 mmx_set(insn.modrm().reg(), mm); 1589 mmx_common(); 1590} 1591void SoftFPU::PSLLQ_mm1_mm2m64(const X86::Instruction& insn) 1592{ 1593 LOAD_MM_MM64M(); 1594 1595 mm.raw <<= mm64m.raw; 1596 1597 mmx_set(insn.modrm().reg(), mm); 1598 mmx_common(); 1599} 1600void SoftFPU::PSLLQ_mm1_imm8(const X86::Instruction& insn) 1601{ 1602 VERIFY(!insn.has_operand_size_override_prefix()); /* SSE2 */ 1603 u8 imm = insn.imm8(); 1604 MMX mm = mmx_get(insn.modrm().reg()); 1605 1606 mm.raw <<= imm; 1607 1608 mmx_set(insn.modrm().reg(), mm); 1609 mmx_common(); 1610} 1611void SoftFPU::PSRAW_mm1_mm2m64(const X86::Instruction& insn) 1612{ 1613 LOAD_MM_MM64M(); 1614 1615 mm.v16 >>= mm64m.v16; 1616 1617 mmx_set(insn.modrm().reg(), mm); 1618 mmx_common(); 1619} 1620void SoftFPU::PSRAW_mm1_imm8(const X86::Instruction& insn) 1621{ 1622 VERIFY(!insn.has_operand_size_override_prefix()); /* SSE2 */ 1623 u8 imm = insn.imm8(); 1624 MMX mm = mmx_get(insn.modrm().reg()); 1625 1626 mm.v16 >>= imm; 1627 1628 mmx_set(insn.modrm().reg(), mm); 1629 mmx_common(); 1630} 1631void SoftFPU::PSRAD_mm1_mm2m64(const X86::Instruction& insn) 1632{ 1633 LOAD_MM_MM64M(); 1634 1635 mm.v32 >>= mm64m.v32; 1636 1637 mmx_set(insn.modrm().reg(), mm); 1638 mmx_common(); 1639} 1640void SoftFPU::PSRAD_mm1_imm8(const X86::Instruction& insn) 1641{ 1642 VERIFY(!insn.has_operand_size_override_prefix()); /* SSE2 */ 1643 u8 imm = insn.imm8(); 1644 MMX mm = mmx_get(insn.modrm().reg()); 1645 1646 mm.v32 >>= imm; 1647 1648 mmx_set(insn.modrm().reg(), mm); 1649 mmx_common(); 1650} 1651void SoftFPU::PSRLW_mm1_mm2m64(const X86::Instruction& insn) 1652{ 1653 LOAD_MM_MM64M(); 1654 1655 mm.v16u >>= mm64m.v16u; 1656 1657 mmx_set(insn.modrm().reg(), mm); 1658 mmx_common(); 1659} 1660void SoftFPU::PSRLW_mm1_imm8(const X86::Instruction& insn) 1661{ 1662 VERIFY(!insn.has_operand_size_override_prefix()); /* SSE2 */ 1663 u8 imm = insn.imm8(); 1664 MMX mm = mmx_get(insn.modrm().reg()); 1665 1666 mm.v16u >>= imm; 1667 1668 mmx_set(insn.modrm().reg(), mm); 1669 mmx_common(); 1670} 1671void SoftFPU::PSRLD_mm1_mm2m64(const X86::Instruction& insn) 1672{ 1673 LOAD_MM_MM64M(); 1674 1675 mm.v32u >>= mm64m.v32u; 1676 1677 mmx_set(insn.modrm().reg(), mm); 1678 mmx_common(); 1679} 1680void SoftFPU::PSRLD_mm1_imm8(const X86::Instruction& insn) 1681{ 1682 VERIFY(!insn.has_operand_size_override_prefix()); /* SSE2 */ 1683 u8 imm = insn.imm8(); 1684 MMX mm = mmx_get(insn.modrm().reg()); 1685 1686 mm.v32u >>= imm; 1687 1688 mmx_set(insn.modrm().reg(), mm); 1689 mmx_common(); 1690} 1691void SoftFPU::PSRLQ_mm1_mm2m64(const X86::Instruction& insn) 1692{ 1693 LOAD_MM_MM64M(); 1694 1695 mm.raw >>= mm64m.raw; 1696 1697 mmx_set(insn.modrm().reg(), mm); 1698 mmx_common(); 1699} 1700void SoftFPU::PSRLQ_mm1_imm8(const X86::Instruction& insn) 1701{ 1702 VERIFY(!insn.has_operand_size_override_prefix()); /* SSE2 */ 1703 u8 imm = insn.imm8(); 1704 MMX mm = mmx_get(insn.modrm().reg()); 1705 1706 mm.raw >>= imm; 1707 1708 mmx_set(insn.modrm().reg(), mm); 1709 mmx_common(); 1710} 1711 1712// DATA TRANSFER 1713void SoftFPU::MOVD_mm1_rm32(const X86::Instruction& insn) 1714{ 1715 VERIFY(!insn.has_operand_size_override_prefix()); /* SSE2 */ 1716 u8 mmx_index = insn.modrm().reg(); 1717 // FIXME:: Shadow Value 1718 // upper half is zeroed out 1719 mmx_set(mmx_index, { .raw = insn.modrm().read32(m_cpu, insn).value() }); 1720 mmx_common(); 1721}; 1722void SoftFPU::MOVD_rm32_mm2(const X86::Instruction& insn) 1723{ 1724 VERIFY(!insn.has_operand_size_override_prefix()); /* SSE2 */ 1725 u8 mmx_index = insn.modrm().reg(); 1726 // FIXME:: Shadow Value 1727 insn.modrm().write32(m_cpu, insn, 1728 shadow_wrap_as_initialized(static_cast<u32>(mmx_get(mmx_index).raw))); 1729 mmx_common(); 1730}; 1731 1732void SoftFPU::MOVQ_mm1_mm2m64(const X86::Instruction& insn) 1733{ 1734 VERIFY(!insn.has_operand_size_override_prefix()); /* SSE2 */ 1735 // FIXME: Shadow Value 1736 if (insn.modrm().mod() == 0b11) { 1737 // instruction 1738 mmx_set(insn.modrm().reg(), 1739 mmx_get(insn.modrm().rm())); 1740 } else { 1741 mmx_set(insn.modrm().reg(), 1742 { .raw = insn.modrm().read64(m_cpu, insn).value() }); 1743 } 1744 mmx_common(); 1745} 1746void SoftFPU::MOVQ_mm1m64_mm2(const X86::Instruction& insn) 1747{ 1748 VERIFY(!insn.has_operand_size_override_prefix()); /* SSE2 */ 1749 if (insn.modrm().mod() == 0b11) { 1750 // instruction 1751 mmx_set(insn.modrm().rm(), 1752 mmx_get(insn.modrm().reg())); 1753 } else { 1754 // FIXME: Shadow Value 1755 insn.modrm().write64(m_cpu, insn, 1756 shadow_wrap_as_initialized(mmx_get(insn.modrm().reg()).raw)); 1757 } 1758 mmx_common(); 1759} 1760void SoftFPU::MOVQ_mm1_rm64(const X86::Instruction&) { TODO_INSN(); }; // long mode 1761void SoftFPU::MOVQ_rm64_mm2(const X86::Instruction&) { TODO_INSN(); }; // long mode 1762 1763// EMPTY MMX STATE 1764void SoftFPU::EMMS(const X86::Instruction&) 1765{ 1766 // clear tagword 1767 m_fpu_tw = 0xFFFF; 1768} 1769 1770}