Serenity Operating System
at master 799 lines 25 kB view raw
1/* 2 * Copyright (c) 2022, Leon Albrecht <leon.a@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include "SoftVPU.h" 8#include "SoftCPU.h" 9#include <AK/SIMDMath.h> 10 11namespace UserspaceEmulator { 12 13void SoftVPU::PREFETCHTNTA(X86::Instruction const&) { TODO(); } 14void SoftVPU::PREFETCHT0(X86::Instruction const&) { TODO(); } 15void SoftVPU::PREFETCHT1(X86::Instruction const&) { TODO(); } 16void SoftVPU::PREFETCHT2(X86::Instruction const&) { TODO(); } 17 18void SoftVPU::LDMXCSR(X86::Instruction const& insn) 19{ 20 // FIXME: Shadows 21 m_mxcsr.mxcsr = insn.modrm().read32(m_cpu, insn).value(); 22 23 // #GP - General Protection Fault 24 VERIFY((m_mxcsr.mxcsr & 0xFFFF'0000) == 0); 25 26 // Just let the host's SSE (or if not available x87) handle the rounding for us 27 // We do not want to accidentally raise an FP-Exception on the host, so we 28 // mask all exceptions 29#ifdef __SSE__ 30 AK::MXCSR temp = m_mxcsr; 31 temp.invalid_operation_mask = 1; 32 temp.denormal_operation_mask = 1; 33 temp.divide_by_zero_mask = 1; 34 temp.overflow_mask = 1; 35 temp.underflow_mask = 1; 36 temp.precision_mask = 1; 37 AK::set_mxcsr(temp); 38#else 39 // FIXME: This will mess with x87-land, because it uses the same trick, and 40 // Does not know of us doing this 41 AK::X87ControlWord cw { 0x037F }; 42 cw.rounding_control = m_mxcsr.rounding_control; 43 AK::set_cw_x87(cw); 44#endif 45} 46void SoftVPU::STMXCSR(X86::Instruction const& insn) 47{ 48 // FIXME: Shadows 49 insn.modrm().write32(m_cpu, insn, ValueWithShadow<u32>::create_initialized(m_mxcsr.mxcsr)); 50} 51 52void SoftVPU::MOVUPS_xmm1_xmm2m128(X86::Instruction const& insn) 53{ 54 u8 xmm1 = insn.modrm().reg(); 55 if (insn.modrm().is_register()) { 56 m_xmm[xmm1] = m_xmm[insn.modrm().rm()]; 57 } else { 58 // FIXME: Shadows 59 m_xmm[xmm1].ps = bit_cast<f32x4>(insn.modrm().read128(m_cpu, insn).value()); 60 } 61} 62void SoftVPU::MOVSS_xmm1_xmm2m32(X86::Instruction const& insn) 63{ 64 u8 xmm1 = insn.modrm().reg(); 65 if (insn.modrm().is_register()) { 66 m_xmm[xmm1].ps[0] = m_xmm[insn.modrm().rm()].ps[0]; 67 } else { 68 // FIXME: Shadows 69 m_xmm[xmm1].ps[0] = bit_cast<float>(insn.modrm().read32(m_cpu, insn).value()); 70 } 71} 72void SoftVPU::MOVUPS_xmm1m128_xmm2(X86::Instruction const& insn) 73{ 74 u8 xmm2 = insn.modrm().reg(); 75 if (insn.modrm().is_register()) { 76 m_xmm[insn.modrm().rm()] = m_xmm[xmm2]; 77 } else { 78 // FIXME: Shadows 79 u128 temp = bit_cast<u128>(m_xmm[xmm2]); 80 insn.modrm().write128(m_cpu, insn, ValueWithShadow<u128>::create_initialized(temp)); 81 } 82} 83void SoftVPU::MOVSS_xmm1m32_xmm2(X86::Instruction const& insn) 84{ 85 u8 xmm2 = insn.modrm().reg(); 86 if (insn.modrm().is_register()) { 87 m_xmm[insn.modrm().rm()].ps[0] = m_xmm[xmm2].ps[0]; 88 } else { 89 // FIXME: Shadows 90 u32 temp = bit_cast<u32>(m_xmm[xmm2].ps[0]); 91 insn.modrm().write32(m_cpu, insn, ValueWithShadow<u32>::create_initialized(temp)); 92 } 93} 94void SoftVPU::MOVLPS_xmm1_xmm2m64(X86::Instruction const& insn) 95{ 96 u8 xmm1 = insn.modrm().reg(); 97 if (insn.modrm().is_register()) { 98 // Note: MOVHLPS 99 m_xmm[xmm1].puqw[0] = m_xmm[insn.modrm().rm()].puqw[1]; 100 } else { 101 // FIXME: Shadows 102 // Note: Technically we are transferring two packed floats not a quad word 103 m_xmm[xmm1].puqw[0] = insn.modrm().read64(m_cpu, insn).value(); 104 } 105} 106void SoftVPU::MOVLPS_m64_xmm2(X86::Instruction const& insn) 107{ 108 u8 xmm2 = insn.modrm().reg(); 109 // FIXME: This might not hold true for SSE2 or later 110 VERIFY(!insn.modrm().is_register()); 111 // Note: Technically we are transferring two packed floats not a quad word 112 insn.modrm().write64(m_cpu, insn, ValueWithShadow<u64>::create_initialized(m_xmm[xmm2].puqw[0])); 113} 114 115void SoftVPU::UNPCKLPS_xmm1_xmm2m128(X86::Instruction const& insn) 116{ 117 f32x4& xmm1 = m_xmm[insn.modrm().reg()].ps; 118 f32x4 xmm2m128; 119 120 if (insn.modrm().is_register()) { 121 xmm2m128 = m_xmm[insn.modrm().rm()].ps; 122 } else { 123 // FIXME: Shadows 124 xmm2m128 = bit_cast<f32x4>(insn.modrm().read128(m_cpu, insn).value()); 125 } 126 f32x4 dest; 127 if (insn.modrm().is_register()) { 128 xmm2m128 = m_xmm[insn.modrm().rm()].ps; 129 } else { 130 // FIXME: Shadows 131 xmm2m128 = bit_cast<f32x4>(insn.modrm().read128(m_cpu, insn).value()); 132 } 133 134 dest[0] = xmm1[0]; 135 dest[1] = xmm2m128[0]; 136 dest[2] = xmm1[1]; 137 dest[3] = xmm2m128[1]; 138 139 m_xmm[insn.modrm().reg()].ps = dest; 140} 141void SoftVPU::UNPCKHPS_xmm1_xmm2m128(X86::Instruction const& insn) 142{ 143 f32x4 xmm1 = m_xmm[insn.modrm().reg()].ps; 144 f32x4 xmm2m128; 145 146 if (insn.modrm().is_register()) { 147 xmm2m128 = m_xmm[insn.modrm().rm()].ps; 148 } else { 149 // FIXME: Shadows 150 xmm2m128 = bit_cast<f32x4>(insn.modrm().read128(m_cpu, insn).value()); 151 } 152 f32x4 dest; 153 dest[0] = xmm1[2]; 154 dest[1] = xmm2m128[2]; 155 dest[2] = xmm1[3]; 156 dest[3] = xmm2m128[3]; 157 158 m_xmm[insn.modrm().reg()].ps = dest; 159} 160 161void SoftVPU::MOVHPS_xmm1_xmm2m64(X86::Instruction const& insn) 162{ 163 u8 xmm1 = insn.modrm().reg(); 164 if (insn.modrm().is_register()) { 165 // Note: MOVLHPS 166 m_xmm[xmm1].puqw[1] = m_xmm[insn.modrm().rm()].puqw[0]; 167 } else { 168 // FIXME: Shadows 169 // Note: Technically we are transferring two packed floats not a quad word 170 m_xmm[xmm1].puqw[1] = insn.modrm().read64(m_cpu, insn).value(); 171 } 172} 173void SoftVPU::MOVHPS_m64_xmm2(X86::Instruction const& insn) 174{ 175 u8 xmm1 = insn.modrm().reg(); 176 VERIFY(!insn.modrm().is_register()); 177 // Note: Technically we are transferring two packed floats not a quad word 178 insn.modrm().write64(m_cpu, insn, ValueWithShadow<u64>::create_initialized(m_xmm[xmm1].puqw[1])); 179} 180void SoftVPU::MOVAPS_xmm1_xmm2m128(X86::Instruction const& insn) 181{ 182 u8 xmm1 = insn.modrm().reg(); 183 if (insn.modrm().is_register()) { 184 m_xmm[xmm1] = m_xmm[insn.modrm().rm()]; 185 } else { 186 // FIXME: Alignment-check 16 187 auto temp = insn.modrm().read128(m_cpu, insn); 188 m_xmm[xmm1].ps = bit_cast<f32x4>(temp.value()); 189 } 190} 191void SoftVPU::MOVAPS_xmm1m128_xmm2(X86::Instruction const& insn) 192{ 193 u8 xmm2 = insn.modrm().reg(); 194 if (insn.modrm().is_register()) { 195 m_xmm[insn.modrm().rm()] = m_xmm[xmm2]; 196 } else { 197 // FIXME: Alignment-check 16 198 u128 temp = bit_cast<u128>(m_xmm[xmm2]); 199 insn.modrm().write128(m_cpu, insn, ValueWithShadow<u128>::create_initialized(temp)); 200 } 201} 202 203void SoftVPU::CVTPI2PS_xmm1_mm2m64(X86::Instruction const& insn) 204{ 205 // FIXME: Raise Precision 206 // FIXME: Honor Rounding control 207 u8 xmm1 = insn.modrm().reg(); 208 if (insn.modrm().is_register()) { 209 i32x2 mm = m_cpu.mmx_get(insn.modrm().rm()).v32; 210 m_xmm[xmm1].ps[0] = mm[0]; 211 m_xmm[xmm1].ps[1] = mm[1]; 212 } else { 213 // FIXME: Shadows 214 i32x2 m64 = bit_cast<i32x2>(insn.modrm().read64(m_cpu, insn).value()); 215 m_xmm[xmm1].ps[0] = m64[0]; 216 m_xmm[xmm1].ps[1] = m64[1]; 217 } 218} 219void SoftVPU::CVTSI2SS_xmm1_rm32(X86::Instruction const& insn) 220{ 221 // FIXME: Raise Precision 222 // FIXME: Shadows 223 // FIXME: Honor Rounding Control 224 m_xmm[insn.modrm().reg()].ps[0] = (i32)insn.modrm().read32(m_cpu, insn).value(); 225} 226 227void SoftVPU::MOVNTPS_xmm1m128_xmm2(X86::Instruction const&) { TODO(); } 228 229void SoftVPU::CVTTPS2PI_mm1_xmm2m64(X86::Instruction const&) { TODO(); } 230void SoftVPU::CVTTSS2SI_r32_xmm2m32(X86::Instruction const& insn) 231{ 232 // FIXME: Raise Invalid, Precision 233 float value; 234 if (insn.modrm().is_register()) 235 value = m_xmm[insn.modrm().rm()].ps[0]; 236 else 237 value = bit_cast<float>(insn.modrm().read32(m_cpu, insn).value()); 238 239 m_cpu.gpr32(insn.reg32()) = ValueWithShadow<u32>::create_initialized((u32)(i32)truncf(value)); 240} 241void SoftVPU::CVTPS2PI_xmm1_mm2m64(X86::Instruction const&) { TODO(); } 242void SoftVPU::CVTSS2SI_r32_xmm2m32(X86::Instruction const& insn) 243{ 244 // FIXME: Raise Invalid, Precision 245 insn.modrm().write32(m_cpu, insn, 246 ValueWithShadow<u32>::create_initialized(static_cast<i32>(m_xmm[insn.modrm().reg()].ps[0]))); 247} 248 249void SoftVPU::UCOMISS_xmm1_xmm2m32(X86::Instruction const& insn) 250{ 251 float xmm1 = m_xmm[insn.modrm().reg()].ps[0]; 252 float xmm2m32; 253 if (insn.modrm().is_register()) 254 xmm2m32 = m_xmm[insn.modrm().rm()].ps[0]; 255 else 256 xmm2m32 = bit_cast<float>(insn.modrm().read32(m_cpu, insn).value()); 257 // FIXME: Raise Invalid on SNaN 258 if (isnan(xmm1) || isnan(xmm2m32)) { 259 m_cpu.set_zf(true); 260 m_cpu.set_pf(true); 261 m_cpu.set_cf(true); 262 } else { 263 m_cpu.set_zf(xmm1 == xmm2m32); 264 m_cpu.set_pf(false); 265 m_cpu.set_cf(xmm1 < xmm2m32); 266 } 267 m_cpu.set_of(false); 268 m_cpu.set_af(false); 269 m_cpu.set_sf(false); 270} 271void SoftVPU::COMISS_xmm1_xmm2m32(X86::Instruction const& insn) 272{ 273 // FIXME: Raise on QNaN 274 UCOMISS_xmm1_xmm2m32(insn); 275} 276 277void SoftVPU::MOVMSKPS_reg_xmm(X86::Instruction const& insn) 278{ 279 VERIFY(insn.modrm().is_register()); 280 u8 mask = 0; 281 f32x4 xmm = m_xmm[insn.modrm().rm()].ps; 282 mask |= signbit(xmm[0]) << 0; 283 mask |= signbit(xmm[1]) << 1; 284 mask |= signbit(xmm[2]) << 2; 285 mask |= signbit(xmm[3]) << 3; 286 287 m_cpu.gpr32(insn.reg32()) = ValueWithShadow<u32>::create_initialized(mask); 288} 289 290void SoftVPU::SQRTPS_xmm1_xmm2m128(X86::Instruction const& insn) 291{ 292 // FIXME: Raise Invalid, Precision, Denormal 293 f32x4 xmm2m128; 294 295 if (insn.modrm().is_register()) { 296 xmm2m128 = m_xmm[insn.modrm().rm()].ps; 297 } else { 298 // FIXME: Shadows 299 xmm2m128 = bit_cast<f32x4>(insn.modrm().read128(m_cpu, insn).value()); 300 } 301 302 m_xmm[insn.modrm().reg()].ps = sqrt(xmm2m128); 303} 304void SoftVPU::SQRTSS_xmm1_xmm2m32(X86::Instruction const& insn) 305{ 306 // FIXME: Raise Invalid, Precision, Denormal 307 float xmm2m32; 308 309 if (insn.modrm().is_register()) { 310 xmm2m32 = m_xmm[insn.modrm().rm()].ps[0]; 311 } else { 312 // FIXME: Shadows 313 xmm2m32 = bit_cast<float>(insn.modrm().read32(m_cpu, insn).value()); 314 } 315 316 m_xmm[insn.modrm().reg()].ps[0] = AK::sqrt(xmm2m32); 317} 318void SoftVPU::RSQRTPS_xmm1_xmm2m128(X86::Instruction const& insn) 319{ 320 f32x4 xmm2m128; 321 if (insn.modrm().is_register()) { 322 xmm2m128 = m_xmm[insn.modrm().rm()].ps; 323 } else { 324 // FIXME: Shadows 325 xmm2m128 = bit_cast<f32x4>(insn.modrm().read128(m_cpu, insn).value()); 326 } 327 328 m_xmm[insn.modrm().reg()].ps = rsqrt(xmm2m128); 329} 330void SoftVPU::RSQRTSS_xmm1_xmm2m32(X86::Instruction const& insn) 331{ 332 float xmm2m32; 333 if (insn.modrm().is_register()) { 334 xmm2m32 = m_xmm[insn.modrm().rm()].ps[0]; 335 } else { 336 // FIXME: Shadows 337 xmm2m32 = bit_cast<float>(insn.modrm().read32(m_cpu, insn).value()); 338 } 339 340 m_xmm[insn.modrm().reg()].ps[0] = AK::rsqrt(xmm2m32); 341} 342 343void SoftVPU::RCPPS_xmm1_xmm2m128(X86::Instruction const& insn) 344{ 345 f32x4 xmm2m128; 346 if (insn.modrm().is_register()) { 347 xmm2m128 = m_xmm[insn.modrm().rm()].ps; 348 } else { 349 // FIXME: Shadows 350 xmm2m128 = bit_cast<f32x4>(insn.modrm().read128(m_cpu, insn).value()); 351 } 352 353 m_xmm[insn.modrm().reg()].ps = 1.f / xmm2m128; 354} 355void SoftVPU::RCPSS_xmm1_xmm2m32(X86::Instruction const& insn) 356{ 357 float xmm2m32; 358 if (insn.modrm().is_register()) { 359 xmm2m32 = m_xmm[insn.modrm().rm()].ps[0]; 360 } else { 361 // FIXME: Shadows 362 xmm2m32 = bit_cast<float>(insn.modrm().read32(m_cpu, insn).value()); 363 } 364 365 m_xmm[insn.modrm().reg()].ps[0] = 1.f / xmm2m32; 366} 367 368void SoftVPU::ANDPS_xmm1_xmm2m128(X86::Instruction const& insn) 369{ 370 u32x4 xmm2m128; 371 if (insn.modrm().is_register()) { 372 xmm2m128 = m_xmm[insn.modrm().rm()].pudw; 373 } else { 374 // FIXME: Shadows 375 xmm2m128 = bit_cast<u32x4>(insn.modrm().read128(m_cpu, insn).value()); 376 } 377 378 m_xmm[insn.modrm().reg()].pudw &= xmm2m128; 379} 380void SoftVPU::ANDNPS_xmm1_xmm2m128(X86::Instruction const& insn) 381{ 382 u32x4 xmm2m128; 383 if (insn.modrm().is_register()) { 384 xmm2m128 = m_xmm[insn.modrm().rm()].pudw; 385 } else { 386 // FIXME: Shadows 387 xmm2m128 = bit_cast<u32x4>(insn.modrm().read128(m_cpu, insn).value()); 388 } 389 390 u32x4& xmm1 = m_xmm[insn.modrm().reg()].pudw; 391 xmm1 = ~xmm1 & xmm2m128; 392} 393void SoftVPU::ORPS_xmm1_xmm2m128(X86::Instruction const& insn) 394{ 395 u32x4 xmm2m128; 396 if (insn.modrm().is_register()) { 397 xmm2m128 = m_xmm[insn.modrm().rm()].pudw; 398 } else { 399 // FIXME: Shadows 400 xmm2m128 = bit_cast<u32x4>(insn.modrm().read128(m_cpu, insn).value()); 401 } 402 403 m_xmm[insn.modrm().reg()].pudw |= xmm2m128; 404} 405void SoftVPU::XORPS_xmm1_xmm2m128(X86::Instruction const& insn) 406{ 407 u32x4 xmm2m128; 408 if (insn.modrm().is_register()) { 409 xmm2m128 = m_xmm[insn.modrm().rm()].pudw; 410 } else { 411 // FIXME: Shadows 412 xmm2m128 = bit_cast<u32x4>(insn.modrm().read128(m_cpu, insn).value()); 413 } 414 415 m_xmm[insn.modrm().reg()].pudw ^= xmm2m128; 416} 417 418void SoftVPU::ADDPS_xmm1_xmm2m128(X86::Instruction const& insn) 419{ 420 // Raise Overflow, Underflow, Invalid, Precision, Denormal 421 f32x4 xmm2m128; 422 if (insn.modrm().is_register()) { 423 xmm2m128 = m_xmm[insn.modrm().rm()].ps; 424 } else { 425 // FIXME: Shadows 426 xmm2m128 = bit_cast<f32x4>(insn.modrm().read128(m_cpu, insn).value()); 427 } 428 429 m_xmm[insn.modrm().reg()].ps += xmm2m128; 430} 431void SoftVPU::ADDSS_xmm1_xmm2m32(X86::Instruction const& insn) 432{ 433 // Raise Overflow, Underflow, Invalid, Precision, Denormal 434 float xmm2m32; 435 if (insn.modrm().is_register()) { 436 xmm2m32 = m_xmm[insn.modrm().rm()].ps[0]; 437 } else { 438 // FIXME: Shadows 439 xmm2m32 = bit_cast<float>(insn.modrm().read32(m_cpu, insn).value()); 440 } 441 442 m_xmm[insn.modrm().reg()].ps[0] += xmm2m32; 443} 444 445void SoftVPU::MULPS_xmm1_xmm2m128(X86::Instruction const& insn) 446{ 447 // Raise Overflow, Underflow, Invalid, Precision, Denormal 448 f32x4 xmm2m128; 449 if (insn.modrm().is_register()) { 450 xmm2m128 = m_xmm[insn.modrm().rm()].ps; 451 } else { 452 // FIXME: Shadows 453 xmm2m128 = bit_cast<f32x4>(insn.modrm().read128(m_cpu, insn).value()); 454 } 455 456 m_xmm[insn.modrm().reg()].ps *= xmm2m128; 457} 458void SoftVPU::MULSS_xmm1_xmm2m32(X86::Instruction const& insn) 459{ 460 // Raise Overflow, Underflow, Invalid, Precision, Denormal 461 float xmm1 = m_xmm[insn.modrm().reg()].ps[0]; 462 float xmm2m32; 463 464 if (insn.modrm().is_register()) { 465 xmm2m32 = m_xmm[insn.modrm().rm()].ps[0]; 466 } else { 467 // FIXME: Shadows 468 xmm2m32 = bit_cast<float>(insn.modrm().read32(m_cpu, insn).value()); 469 } 470 xmm1 *= xmm2m32; 471 472 m_xmm[insn.modrm().reg()].ps[0] *= xmm1; 473} 474 475void SoftVPU::SUBPS_xmm1_xmm2m128(X86::Instruction const& insn) 476{ 477 // Raise Overflow, Underflow, Invalid, Precision, Denormal 478 f32x4 xmm2m128; 479 480 if (insn.modrm().is_register()) { 481 xmm2m128 = m_xmm[insn.modrm().rm()].ps; 482 } else { 483 // FIXME: Shadows 484 xmm2m128 = bit_cast<f32x4>(insn.modrm().read128(m_cpu, insn).value()); 485 } 486 487 m_xmm[insn.modrm().reg()].ps -= xmm2m128; 488} 489void SoftVPU::SUBSS_xmm1_xmm2m32(X86::Instruction const& insn) 490{ 491 // Raise Overflow, Underflow, Invalid, Precision, Denormal 492 float xmm2m32; 493 494 if (insn.modrm().is_register()) { 495 xmm2m32 = m_xmm[insn.modrm().rm()].ps[0]; 496 } else { 497 // FIXME: Shadows 498 xmm2m32 = bit_cast<float>(insn.modrm().read32(m_cpu, insn).value()); 499 } 500 501 m_xmm[insn.modrm().reg()].ps[0] -= xmm2m32; 502} 503 504void SoftVPU::MINPS_xmm1_xmm2m128(X86::Instruction const& insn) 505{ 506 // FIXME: Raise Invalid (including QNaN Source Operand), Denormal 507 f32x4 xmm1 = m_xmm[insn.modrm().reg()].ps; 508 f32x4 xmm2m128; 509 510 if (insn.modrm().is_register()) { 511 xmm2m128 = m_xmm[insn.modrm().rm()].ps; 512 } else { 513 // FIXME: Shadows 514 xmm2m128 = bit_cast<f32x4>(insn.modrm().read128(m_cpu, insn).value()); 515 } 516 517 for (auto i = 0; i < 4; ++i) { 518 // When only one is NaN or both are 0.0s (of either sign), or 519 // FIXME: xmm2m32 is SNaN 520 // xmm2m32 is returned unchanged 521 if (isnan(xmm1[i]) || isnan(xmm2m128[i]) || xmm1[i] == xmm2m128[i]) 522 xmm1[i] = xmm2m128[i]; 523 else 524 xmm1[i] = min(xmm1[i], xmm2m128[i]); 525 } 526 527 m_xmm[insn.modrm().reg()].ps = xmm1; 528} 529void SoftVPU::MINSS_xmm1_xmm2m32(X86::Instruction const& insn) 530{ 531 // FIXME: Raise Invalid (Including QNaN Source Operand), Denormal 532 float xmm1 = m_xmm[insn.modrm().reg()].ps[0]; 533 float xmm2m32; 534 535 if (insn.modrm().is_register()) { 536 xmm2m32 = m_xmm[insn.modrm().rm()].ps[0]; 537 } else { 538 // FIXME: Shadows 539 xmm2m32 = bit_cast<float>(insn.modrm().read32(m_cpu, insn).value()); 540 } 541 // When only one is NaN or both are 0.0s (of either sign), or 542 // FIXME: xmm2m32 is SNaN 543 // xmm2m32 is returned unchanged 544 if (isnan(xmm1) || isnan(xmm2m32) || xmm1 == xmm2m32) 545 xmm1 = xmm2m32; 546 else 547 xmm1 = min(xmm1, xmm2m32); 548 549 m_xmm[insn.modrm().reg()].ps[0] = xmm1; 550} 551 552void SoftVPU::DIVPS_xmm1_xmm2m128(X86::Instruction const& insn) 553{ 554 // Raise Overflow, Underflow, Invalid, Divide-by-Zero, Precision, Denormal 555 f32x4 xmm2m128; 556 if (insn.modrm().is_register()) { 557 xmm2m128 = m_xmm[insn.modrm().rm()].ps; 558 } else { 559 // FIXME: Shadows 560 xmm2m128 = bit_cast<f32x4>(insn.modrm().read128(m_cpu, insn).value()); 561 } 562 563 m_xmm[insn.modrm().reg()].ps /= xmm2m128; 564} 565void SoftVPU::DIVSS_xmm1_xmm2m32(X86::Instruction const& insn) 566{ 567 // Raise Overflow, Underflow, Invalid, Divide-by-Zero, Precision, Denormal 568 float xmm2m32; 569 if (insn.modrm().is_register()) { 570 xmm2m32 = m_xmm[insn.modrm().rm()].ps[0]; 571 } else { 572 // FIXME: Shadows 573 xmm2m32 = bit_cast<float>(insn.modrm().read32(m_cpu, insn).value()); 574 } 575 576 m_xmm[insn.modrm().reg()].ps[0] /= xmm2m32; 577} 578 579void SoftVPU::MAXPS_xmm1_xmm2m128(X86::Instruction const& insn) 580{ 581 // FIXME: Raise Invalid (including QNaN Source Operand), Denormal 582 f32x4 xmm1 = m_xmm[insn.modrm().reg()].ps; 583 f32x4 xmm2m128; 584 585 if (insn.modrm().is_register()) { 586 xmm2m128 = m_xmm[insn.modrm().rm()].ps; 587 } else { 588 // FIXME: Shadows 589 xmm2m128 = bit_cast<f32x4>(insn.modrm().read128(m_cpu, insn).value()); 590 } 591 592 for (auto i = 0; i < 4; ++i) { 593 // When only one is NaN or both are 0.0s (of either sign), or 594 // FIXME: xmm2m32 is SNaN 595 // xmm2m32 is returned unchanged 596 if (isnan(xmm1[i]) || isnan(xmm2m128[i]) || xmm1[i] == xmm2m128[i]) 597 xmm1[i] = xmm2m128[i]; 598 else 599 xmm1[i] = max(xmm1[i], xmm2m128[i]); 600 } 601 602 m_xmm[insn.modrm().reg()].ps = xmm1; 603} 604void SoftVPU::MAXSS_xmm1_xmm2m32(X86::Instruction const& insn) 605{ 606 // FIXME: Raise Invalid (Including QNaN Source Operand), Denormal 607 float xmm1 = m_xmm[insn.modrm().reg()].ps[0]; 608 float xmm2m32; 609 610 if (insn.modrm().is_register()) { 611 xmm2m32 = m_xmm[insn.modrm().rm()].ps[0]; 612 } else { 613 // FIXME: Shadows 614 xmm2m32 = bit_cast<float>(insn.modrm().read32(m_cpu, insn).value()); 615 } 616 // When only one is NaN or both are 0.0s (of either sign), or 617 // FIXME: xmm2m32 is SNaN 618 // xmm2m32 is returned unchanged 619 if (isnan(xmm1) || isnan(xmm2m32) || xmm1 == xmm2m32) 620 xmm1 = xmm2m32; 621 else 622 xmm1 = max(xmm1, xmm2m32); 623 624 m_xmm[insn.modrm().reg()].ps[0] = xmm1; 625} 626 627void SoftVPU::PSHUFW_mm1_mm2m64_imm8(X86::Instruction const& insn) 628{ 629 MMX src; 630 if (insn.modrm().is_register()) { 631 src = m_cpu.mmx_get(insn.modrm().rm()); 632 } else { 633 // FIXME: Shadows 634 src = bit_cast<MMX>(insn.modrm().read64(m_cpu, insn).value()); 635 } 636 637 u8 order = insn.imm8(); 638 MMX dest; 639 640 dest.v16u[0] = src.v16u[(order >> 0) & 0b11]; 641 dest.v16u[1] = src.v16u[(order >> 2) & 0b11]; 642 dest.v16u[2] = src.v16u[(order >> 4) & 0b11]; 643 dest.v16u[3] = src.v16u[(order >> 6) & 0b11]; 644 645 m_cpu.mmx_set(insn.modrm().reg(), dest); 646} 647 648void SoftVPU::CMPPS_xmm1_xmm2m128_imm8(X86::Instruction const& insn) 649{ 650 // FIXME: Raise Denormal, Invalid Operation (QNaN dependent on imm8) 651 XMM& xmm1 = m_xmm[insn.modrm().reg()]; 652 f32x4 xmm2m128; 653 654 if (insn.modrm().is_register()) { 655 xmm2m128 = m_xmm[insn.modrm().rm()].ps; 656 } else { 657 // FIXME: Shadows 658 xmm2m128 = bit_cast<f32x4>(insn.modrm().read128(m_cpu, insn).value()); 659 } 660 using enum ComparePredicate; 661 switch ((ComparePredicate)insn.imm8()) { 662 case EQ: 663 xmm1.ps = xmm1.ps == xmm2m128; 664 break; 665 case LT: 666 xmm1.ps = xmm1.ps < xmm2m128; 667 break; 668 case LE: 669 xmm1.ps = xmm1.ps <= xmm2m128; 670 break; 671 case UNORD: 672 for (auto i = 0; i < 4; ++i) 673 xmm1.pudw[i] = 0xFFFF'FFFF * (isnan(xmm1.ps[i]) || isnan(xmm2m128[i])); 674 break; 675 case NEQ: 676 xmm1.ps = xmm1.ps != xmm2m128; 677 break; 678 case NLT: 679 xmm1.ps = xmm1.ps >= xmm2m128; 680 break; 681 case NLE: 682 xmm1.ps = xmm1.ps > xmm2m128; 683 break; 684 case ORD: 685 for (auto i = 0; i < 4; ++i) 686 xmm1.pudw[i] = 0xFFFF'FFFF * (!isnan(xmm1.ps[i]) && !isnan(xmm2m128[i])); 687 break; 688 } 689} 690void SoftVPU::CMPSS_xmm1_xmm2m32_imm8(X86::Instruction const& insn) 691{ 692 // FIXME: Raise Denormal, Invalid Operation (QNaN dependent on imm8) 693 float xmm1 = m_xmm[insn.modrm().reg()].ps[0]; 694 float xmm2m128; 695 bool res; 696 697 if (insn.modrm().is_register()) { 698 xmm2m128 = m_xmm[insn.modrm().rm()].ps[0]; 699 } else { 700 // FIXME: Shadows 701 xmm2m128 = bit_cast<float>(insn.modrm().read32(m_cpu, insn).value()); 702 } 703 using enum ComparePredicate; 704 switch ((ComparePredicate)insn.imm8()) { 705 case EQ: 706 res = xmm1 == xmm2m128; 707 break; 708 case LT: 709 res = xmm1 < xmm2m128; 710 break; 711 case LE: 712 res = xmm1 <= xmm2m128; 713 break; 714 case UNORD: 715 res = isnan(xmm1) || isnan(xmm2m128); 716 break; 717 case NEQ: 718 res = xmm1 != xmm2m128; 719 break; 720 case NLT: 721 res = xmm1 >= xmm2m128; 722 break; 723 case NLE: 724 res = xmm1 > xmm2m128; 725 break; 726 case ORD: 727 res = !isnan(xmm1) && !isnan(xmm2m128); 728 break; 729 } 730 731 m_xmm[insn.modrm().reg()].pudw[0] = 0xFFFF'FFFF * res; 732} 733 734void SoftVPU::PINSRW_mm1_r32m16_imm8(X86::Instruction const&) { TODO(); } 735void SoftVPU::PINSRW_xmm1_r32m16_imm8(X86::Instruction const&) { TODO(); } 736void SoftVPU::PEXTRW_reg_mm1_imm8(X86::Instruction const&) { TODO(); } 737void SoftVPU::PEXTRW_reg_xmm1_imm8(X86::Instruction const&) { TODO(); } 738 739void SoftVPU::SHUFPS_xmm1_xmm2m128_imm8(X86::Instruction const& insn) 740{ 741 f32x4 src; 742 if (insn.modrm().is_register()) { 743 src = m_xmm[insn.modrm().rm()].ps; 744 } else { 745 // FIXME: Shadows 746 src = bit_cast<f32x4>(insn.modrm().read128(m_cpu, insn).value()); 747 } 748 749 u8 order = insn.imm8(); 750 f32x4 dest; 751 dest[0] = src[(order >> 0) & 0b11]; 752 dest[1] = src[(order >> 2) & 0b11]; 753 dest[2] = src[(order >> 4) & 0b11]; 754 dest[3] = src[(order >> 6) & 0b11]; 755 756 m_xmm[insn.modrm().reg()].ps = dest; 757} 758 759void SoftVPU::PMOVMSKB_reg_mm1(X86::Instruction const&) { TODO(); } 760void SoftVPU::PMOVMSKB_reg_xmm1(X86::Instruction const& insn) 761{ 762 VERIFY(insn.modrm().is_register()); 763 XMM src = m_xmm[insn.modrm().rm()]; 764 765 u32 dest = 0; 766 for (int i = 0; i < 16; ++i) 767 dest |= (src.pub[i] >> 7) << i; 768 769 m_cpu.gpr32(insn.reg32()) = ValueWithShadow<u32>::create_initialized(dest); 770} 771 772void SoftVPU::PMINUB_mm1_mm2m64(X86::Instruction const&) { TODO(); } 773void SoftVPU::PMINUB_xmm1_xmm2m128(X86::Instruction const&) { TODO(); } 774 775void SoftVPU::PMAXUB_mm1_mm2m64(X86::Instruction const&) { TODO(); } 776void SoftVPU::PMAXUB_xmm1_xmm2m128(X86::Instruction const&) { TODO(); } 777 778void SoftVPU::PAVGB_mm1_mm2m64(X86::Instruction const&) { TODO(); } 779void SoftVPU::PAVGB_xmm1_xmm2m128(X86::Instruction const&) { TODO(); } 780 781void SoftVPU::PAVGW_mm1_mm2m64(X86::Instruction const&) { TODO(); } 782void SoftVPU::PAVGW_xmm1_xmm2m128(X86::Instruction const&) { TODO(); } 783 784void SoftVPU::PMULHUW_mm1_mm2m64(X86::Instruction const&) { TODO(); } 785void SoftVPU::PMULHUW_xmm1_xmm2m64(X86::Instruction const&) { TODO(); } 786 787void SoftVPU::MOVNTQ_m64_mm1(X86::Instruction const&) { TODO(); } 788 789void SoftVPU::PMINSB_mm1_mm2m64(X86::Instruction const&) { TODO(); } 790void SoftVPU::PMINSB_xmm1_xmm2m128(X86::Instruction const&) { TODO(); } 791 792void SoftVPU::PMAXSB_mm1_mm2m64(X86::Instruction const&) { TODO(); } 793void SoftVPU::PMAXSB_xmm1_xmm2m128(X86::Instruction const&) { TODO(); } 794 795void SoftVPU::PSADBB_mm1_mm2m64(X86::Instruction const&) { TODO(); } 796void SoftVPU::PSADBB_xmm1_xmm2m128(X86::Instruction const&) { TODO(); } 797 798void SoftVPU::MASKMOVQ_mm1_mm2m64(X86::Instruction const&) { TODO(); } 799}