diff --git a/Userland/DevTools/UserspaceEmulator/CMakeLists.txt b/Userland/DevTools/UserspaceEmulator/CMakeLists.txt index 224e837f8f..acb608dd32 100644 --- a/Userland/DevTools/UserspaceEmulator/CMakeLists.txt +++ b/Userland/DevTools/UserspaceEmulator/CMakeLists.txt @@ -16,10 +16,11 @@ set(SOURCES SoftCPU.cpp SoftFPU.cpp SoftMMU.cpp + SoftVPU.cpp main.cpp ) -add_compile_options(-mmmx) +add_compile_options(-mmmx -Wno-psabi) serenity_bin(UserspaceEmulator) target_link_libraries(UserspaceEmulator LibX86 LibDebug LibCore LibPthread LibLine) diff --git a/Userland/DevTools/UserspaceEmulator/SoftCPU.cpp b/Userland/DevTools/UserspaceEmulator/SoftCPU.cpp index 07ec12d522..40f897242d 100644 --- a/Userland/DevTools/UserspaceEmulator/SoftCPU.cpp +++ b/Userland/DevTools/UserspaceEmulator/SoftCPU.cpp @@ -32,6 +32,12 @@ m_fpu.name(insn); \ } +#define VPU_INSTRUCTION(name) \ + void SoftCPU::name(const X86::Instruction& insn) \ + { \ + m_vpu.name(insn); \ + } + #define DEFINE_GENERIC_SHIFT_ROTATE_INSN_HANDLERS(mnemonic, op) \ void SoftCPU::mnemonic##_RM8_1(const X86::Instruction& insn) { generic_RM8_1(op>, insn); } \ void SoftCPU::mnemonic##_RM8_CL(const X86::Instruction& insn) { generic_RM8_CL(op>, insn); } \ @@ -73,6 +79,7 @@ constexpr T sign_extended_to(U value) SoftCPU::SoftCPU(Emulator& emulator) : m_emulator(emulator) , m_fpu(emulator, *this) + , m_vpu(emulator, *this) { PartAddressableRegister empty_reg; explicit_bzero(&empty_reg, sizeof(empty_reg)); @@ -2895,84 +2902,84 @@ FPU_INSTRUCTION(MOVD_rm32_mm2); FPU_INSTRUCTION(MOVQ_rm64_mm2); // long mode FPU_INSTRUCTION(EMMS); -void SoftCPU::PREFETCHTNTA(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::PREFETCHT0(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::PREFETCHT1(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::PREFETCHT2(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::LDMXCSR(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::STMXCSR(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::MOVUPS_xmm1_xmm2m128(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::MOVSS_xmm1_xmm2m32(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::MOVUPS_xmm1m128_xmm2(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::MOVSS_xmm1m32_xmm2(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::MOVLPS_xmm1_xmm2m64(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::MOVLPS_m64_xmm2(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::UNPCKLPS_xmm1_xmm2m128(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::UNPCKHPS_xmm1_xmm2m128(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::MOVHPS_xmm1_xmm2m64(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::MOVHPS_m64_xmm2(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::MOVAPS_xmm1_xmm2m128(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::MOVAPS_xmm1m128_xmm2(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::CVTTPS2PI_mm1_xmm2m64(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::CVTTSS2SI_r32_xmm2m32(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::CVTPI2PS_xmm1_mm2m64(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::CVTSI2SS_xmm1_rm32(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::MOVNTPS_xmm1m128_xmm2(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::CVTPS2PI_xmm1_mm2m64(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::CVTSS2SI_xmm1_rm32(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::UCOMISS_xmm1_xmm2m32(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::COMISS_xmm1_xmm2m32(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::MOVMSKPS_reg_xmm(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::SQRTPS_xmm1_xmm2m128(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::SQRTSS_xmm1_xmm2m32(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::RSQRTPS_xmm1_xmm2m128(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::RSQRTSS_xmm1_xmm2m32(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::RCPPS_xmm1_xmm2m128(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::RCPSS_xmm1_xmm2m32(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::ANDPS_xmm1_xmm2m128(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::ANDNPS_xmm1_xmm2m128(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::ORPS_xmm1_xmm2m128(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::XORPS_xmm1_xmm2m128(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::ADDPS_xmm1_xmm2m128(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::ADDSS_xmm1_xmm2m32(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::MULPS_xmm1_xmm2m128(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::MULSS_xmm1_xmm2m32(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::SUBPS_xmm1_xmm2m128(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::SUBSS_xmm1_xmm2m32(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::MINPS_xmm1_xmm2m128(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::MINSS_xmm1_xmm2m32(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::DIVPS_xmm1_xmm2m128(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::DIVSS_xmm1_xmm2m32(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::MAXPS_xmm1_xmm2m128(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::MAXSS_xmm1_xmm2m32(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::PSHUFW_mm1_mm2m64_imm8(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::CMPPS_xmm1_xmm2m128_imm8(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::CMPSS_xmm1_xmm2m32_imm8(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::PINSRW_mm1_r32m16_imm8(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::PINSRW_xmm1_r32m16_imm8(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::PEXTRW_reg_mm1_imm8(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::PEXTRW_reg_xmm1_imm8(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::SHUFPS_xmm1_xmm2m128_imm8(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::PMOVMSKB_reg_mm1(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::PMOVMSKB_reg_xmm1(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::PMINUB_mm1_mm2m64(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::PMINUB_xmm1_xmm2m128(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::PMAXUB_mm1_mm2m64(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::PMAXUB_xmm1_xmm2m128(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::PAVGB_mm1_mm2m64(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::PAVGB_xmm1_xmm2m128(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::PAVGW_mm1_mm2m64(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::PAVGW_xmm1_xmm2m128(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::PMULHUW_mm1_mm2m64(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::PMULHUW_xmm1_xmm2m64(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::MOVNTQ_m64_mm1(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::PMINSB_mm1_mm2m64(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::PMINSB_xmm1_xmm2m128(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::PMAXSB_mm1_mm2m64(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::PMAXSB_xmm1_xmm2m128(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::PSADBB_mm1_mm2m64(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::PSADBB_xmm1_xmm2m128(X86::Instruction const&) { TODO_INSN(); }; -void SoftCPU::MASKMOVQ_mm1_mm2m64(X86::Instruction const&) { TODO_INSN(); }; +VPU_INSTRUCTION(PREFETCHTNTA); +VPU_INSTRUCTION(PREFETCHT0); +VPU_INSTRUCTION(PREFETCHT1); +VPU_INSTRUCTION(PREFETCHT2); +VPU_INSTRUCTION(LDMXCSR); +VPU_INSTRUCTION(STMXCSR); +VPU_INSTRUCTION(MOVUPS_xmm1_xmm2m128); +VPU_INSTRUCTION(MOVSS_xmm1_xmm2m32); +VPU_INSTRUCTION(MOVUPS_xmm1m128_xmm2); +VPU_INSTRUCTION(MOVSS_xmm1m32_xmm2); +VPU_INSTRUCTION(MOVLPS_xmm1_xmm2m64); +VPU_INSTRUCTION(MOVLPS_m64_xmm2); +VPU_INSTRUCTION(UNPCKLPS_xmm1_xmm2m128); +VPU_INSTRUCTION(UNPCKHPS_xmm1_xmm2m128); +VPU_INSTRUCTION(MOVHPS_xmm1_xmm2m64); +VPU_INSTRUCTION(MOVHPS_m64_xmm2); +VPU_INSTRUCTION(MOVAPS_xmm1_xmm2m128); +VPU_INSTRUCTION(MOVAPS_xmm1m128_xmm2); +VPU_INSTRUCTION(CVTTPS2PI_mm1_xmm2m64); +VPU_INSTRUCTION(CVTTSS2SI_r32_xmm2m32); +VPU_INSTRUCTION(CVTPI2PS_xmm1_mm2m64); +VPU_INSTRUCTION(CVTSI2SS_xmm1_rm32); +VPU_INSTRUCTION(MOVNTPS_xmm1m128_xmm2); +VPU_INSTRUCTION(CVTPS2PI_xmm1_mm2m64); +VPU_INSTRUCTION(CVTSS2SI_xmm1_rm32); +VPU_INSTRUCTION(UCOMISS_xmm1_xmm2m32); +VPU_INSTRUCTION(COMISS_xmm1_xmm2m32); +VPU_INSTRUCTION(MOVMSKPS_reg_xmm); +VPU_INSTRUCTION(SQRTPS_xmm1_xmm2m128); +VPU_INSTRUCTION(SQRTSS_xmm1_xmm2m32); +VPU_INSTRUCTION(RSQRTPS_xmm1_xmm2m128); +VPU_INSTRUCTION(RSQRTSS_xmm1_xmm2m32); +VPU_INSTRUCTION(RCPPS_xmm1_xmm2m128); +VPU_INSTRUCTION(RCPSS_xmm1_xmm2m32); +VPU_INSTRUCTION(ANDPS_xmm1_xmm2m128); +VPU_INSTRUCTION(ANDNPS_xmm1_xmm2m128); +VPU_INSTRUCTION(ORPS_xmm1_xmm2m128); +VPU_INSTRUCTION(XORPS_xmm1_xmm2m128); +VPU_INSTRUCTION(ADDPS_xmm1_xmm2m128); +VPU_INSTRUCTION(ADDSS_xmm1_xmm2m32); +VPU_INSTRUCTION(MULPS_xmm1_xmm2m128); +VPU_INSTRUCTION(MULSS_xmm1_xmm2m32); +VPU_INSTRUCTION(SUBPS_xmm1_xmm2m128); +VPU_INSTRUCTION(SUBSS_xmm1_xmm2m32); +VPU_INSTRUCTION(MINPS_xmm1_xmm2m128); +VPU_INSTRUCTION(MINSS_xmm1_xmm2m32); +VPU_INSTRUCTION(DIVPS_xmm1_xmm2m128); +VPU_INSTRUCTION(DIVSS_xmm1_xmm2m32); +VPU_INSTRUCTION(MAXPS_xmm1_xmm2m128); +VPU_INSTRUCTION(MAXSS_xmm1_xmm2m32); +VPU_INSTRUCTION(PSHUFW_mm1_mm2m64_imm8); +VPU_INSTRUCTION(CMPPS_xmm1_xmm2m128_imm8); +VPU_INSTRUCTION(CMPSS_xmm1_xmm2m32_imm8); +VPU_INSTRUCTION(PINSRW_mm1_r32m16_imm8); +VPU_INSTRUCTION(PINSRW_xmm1_r32m16_imm8); +VPU_INSTRUCTION(PEXTRW_reg_mm1_imm8); +VPU_INSTRUCTION(PEXTRW_reg_xmm1_imm8); +VPU_INSTRUCTION(SHUFPS_xmm1_xmm2m128_imm8); +VPU_INSTRUCTION(PMOVMSKB_reg_mm1); +VPU_INSTRUCTION(PMOVMSKB_reg_xmm1); +VPU_INSTRUCTION(PMINUB_mm1_mm2m64); +VPU_INSTRUCTION(PMINUB_xmm1_xmm2m128); +VPU_INSTRUCTION(PMAXUB_mm1_mm2m64); +VPU_INSTRUCTION(PMAXUB_xmm1_xmm2m128); +VPU_INSTRUCTION(PAVGB_mm1_mm2m64); +VPU_INSTRUCTION(PAVGB_xmm1_xmm2m128); +VPU_INSTRUCTION(PAVGW_mm1_mm2m64); +VPU_INSTRUCTION(PAVGW_xmm1_xmm2m128); +VPU_INSTRUCTION(PMULHUW_mm1_mm2m64); +VPU_INSTRUCTION(PMULHUW_xmm1_xmm2m64); +VPU_INSTRUCTION(MOVNTQ_m64_mm1); +VPU_INSTRUCTION(PMINSB_mm1_mm2m64); +VPU_INSTRUCTION(PMINSB_xmm1_xmm2m128); +VPU_INSTRUCTION(PMAXSB_mm1_mm2m64); +VPU_INSTRUCTION(PMAXSB_xmm1_xmm2m128); +VPU_INSTRUCTION(PSADBB_mm1_mm2m64); +VPU_INSTRUCTION(PSADBB_xmm1_xmm2m128); +VPU_INSTRUCTION(MASKMOVQ_mm1_mm2m64); void SoftCPU::wrap_0xC0(const X86::Instruction&) { TODO_INSN(); } void SoftCPU::wrap_0xC1_16(const X86::Instruction&) { TODO_INSN(); } diff --git a/Userland/DevTools/UserspaceEmulator/SoftCPU.h b/Userland/DevTools/UserspaceEmulator/SoftCPU.h index 5ce677d9c6..fec118ca78 100644 --- a/Userland/DevTools/UserspaceEmulator/SoftCPU.h +++ b/Userland/DevTools/UserspaceEmulator/SoftCPU.h @@ -10,6 +10,7 @@ #include "Emulator.h" #include "Region.h" #include "SoftFPU.h" +#include "SoftVPU.h" #include "ValueWithShadow.h" #include #include @@ -1247,6 +1248,7 @@ private: Emulator& m_emulator; SoftFPU m_fpu; + SoftVPU m_vpu; ValueWithShadow m_gpr[8]; diff --git a/Userland/DevTools/UserspaceEmulator/SoftVPU.cpp b/Userland/DevTools/UserspaceEmulator/SoftVPU.cpp new file mode 100644 index 0000000000..02ac73d242 --- /dev/null +++ b/Userland/DevTools/UserspaceEmulator/SoftVPU.cpp @@ -0,0 +1,778 @@ +/* + * Copyright (c) 2022, Leon Albrecht + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "SoftVPU.h" +#include "SoftCPU.h" +#include + +namespace UserspaceEmulator { + +void SoftVPU::PREFETCHTNTA(X86::Instruction const&) { TODO(); } +void SoftVPU::PREFETCHT0(X86::Instruction const&) { TODO(); } +void SoftVPU::PREFETCHT1(X86::Instruction const&) { TODO(); } +void SoftVPU::PREFETCHT2(X86::Instruction const&) { TODO(); } + +void SoftVPU::LDMXCSR(X86::Instruction const& insn) +{ + // FIXME: Shadows + m_mxcsr = insn.modrm().read32(m_cpu, insn).value(); + // #GP - General Protection Fault + VERIFY((m_mxcsr & 0xFFFF'0000) == 0); +} +void SoftVPU::STMXCSR(X86::Instruction const& insn) +{ + // FIXME: Shadows + insn.modrm().write32(m_cpu, insn, ValueWithShadow::create_initialized(m_mxcsr)); +} + +void SoftVPU::MOVUPS_xmm1_xmm2m128(X86::Instruction const& insn) +{ + u8 xmm1 = insn.modrm().reg(); + if (insn.modrm().is_register()) { + m_xmm[xmm1] = m_xmm[insn.modrm().rm()]; + } else { + // FIXME: Shadows + m_xmm[xmm1].ps = bit_cast(insn.modrm().read128(m_cpu, insn).value()); + } +} +void SoftVPU::MOVSS_xmm1_xmm2m32(X86::Instruction const& insn) +{ + u8 xmm1 = insn.modrm().reg(); + if (insn.modrm().is_register()) { + m_xmm[xmm1].ps[0] = m_xmm[insn.modrm().rm()].ps[0]; + } else { + // FIXME: Shadows + m_xmm[xmm1].ps[0] = bit_cast(insn.modrm().read32(m_cpu, insn).value()); + } +} +void SoftVPU::MOVUPS_xmm1m128_xmm2(X86::Instruction const& insn) +{ + u8 xmm2 = insn.modrm().reg(); + if (insn.modrm().is_register()) { + m_xmm[insn.modrm().rm()] = m_xmm[xmm2]; + } else { + // FIXME: Shadows + u128 temp = bit_cast(m_xmm[xmm2]); + insn.modrm().write128(m_cpu, insn, ValueWithShadow::create_initialized(temp)); + } +} +void SoftVPU::MOVSS_xmm1m32_xmm2(X86::Instruction const& insn) +{ + u8 xmm2 = insn.modrm().reg(); + if (insn.modrm().is_register()) { + m_xmm[insn.modrm().rm()].ps[0] = m_xmm[xmm2].ps[0]; + } else { + // FIXME: Shadows + u32 temp = bit_cast(m_xmm[xmm2].ps[0]); + insn.modrm().write32(m_cpu, insn, ValueWithShadow::create_initialized(temp)); + } +} +void SoftVPU::MOVLPS_xmm1_xmm2m64(X86::Instruction const& insn) +{ + u8 xmm1 = insn.modrm().reg(); + if (insn.modrm().is_register()) { + // Note: MOVHLPS + m_xmm[xmm1].puqw[0] = m_xmm[insn.modrm().rm()].puqw[1]; + } else { + // FIXME: Shadows + // Note: Technically we are transfereing two packed floats not a quad word + m_xmm[xmm1].puqw[0] = insn.modrm().read64(m_cpu, insn).value(); + } +} +void SoftVPU::MOVLPS_m64_xmm2(X86::Instruction const& insn) +{ + u8 xmm2 = insn.modrm().reg(); + // FIXME: This might not hold true for SSE2 or later + VERIFY(!insn.modrm().is_register()); + // Note: Technically we are transfereing two packed floats not a quad word + insn.modrm().write64(m_cpu, insn, ValueWithShadow::create_initialized(m_xmm[xmm2].puqw[0])); +} + +void SoftVPU::UNPCKLPS_xmm1_xmm2m128(X86::Instruction const& insn) +{ + f32x4& xmm1 = m_xmm[insn.modrm().reg()].ps; + f32x4 xmm2m128; + + if (insn.modrm().is_register()) { + xmm2m128 = m_xmm[insn.modrm().rm()].ps; + } else { + // FIXME: Shadows + xmm2m128 = bit_cast(insn.modrm().read128(m_cpu, insn).value()); + } + f32x4 dest; + if (insn.modrm().is_register()) { + xmm2m128 = m_xmm[insn.modrm().rm()].ps; + } else { + // FIXME: Shadows + xmm2m128 = bit_cast(insn.modrm().read128(m_cpu, insn).value()); + } + + dest[0] = xmm1[0]; + dest[1] = xmm2m128[0]; + dest[2] = xmm1[1]; + dest[3] = xmm2m128[1]; + + m_xmm[insn.modrm().reg()].ps = dest; +} +void SoftVPU::UNPCKHPS_xmm1_xmm2m128(X86::Instruction const& insn) +{ + f32x4 xmm1 = m_xmm[insn.modrm().reg()].ps; + f32x4 xmm2m128; + + if (insn.modrm().is_register()) { + xmm2m128 = m_xmm[insn.modrm().rm()].ps; + } else { + // FIXME: Shadows + xmm2m128 = bit_cast(insn.modrm().read128(m_cpu, insn).value()); + } + f32x4 dest; + dest[0] = xmm1[2]; + dest[1] = xmm2m128[2]; + dest[2] = xmm1[3]; + dest[3] = xmm2m128[3]; + + m_xmm[insn.modrm().reg()].ps = dest; +} + +void SoftVPU::MOVHPS_xmm1_xmm2m64(X86::Instruction const& insn) +{ + u8 xmm1 = insn.modrm().reg(); + if (insn.modrm().is_register()) { + // Note: MOVLHPS + m_xmm[xmm1].puqw[1] = m_xmm[insn.modrm().rm()].puqw[0]; + } else { + // FIXME: Shadows + // Note: Technically we are transfereing two packed floats not a quad word + m_xmm[xmm1].puqw[1] = insn.modrm().read64(m_cpu, insn).value(); + } +} +void SoftVPU::MOVHPS_m64_xmm2(X86::Instruction const& insn) +{ + u8 xmm1 = insn.modrm().reg(); + VERIFY(!insn.modrm().is_register()); + // Note: Technically we are transfereing two packed floats not a quad word + insn.modrm().write64(m_cpu, insn, ValueWithShadow::create_initialized(m_xmm[xmm1].puqw[1])); +} +void SoftVPU::MOVAPS_xmm1_xmm2m128(X86::Instruction const& insn) +{ + u8 xmm1 = insn.modrm().reg(); + if (insn.modrm().is_register()) { + m_xmm[xmm1] = m_xmm[insn.modrm().rm()]; + } else { + // FIXME: Alignment-check 16 + auto temp = insn.modrm().read128(m_cpu, insn); + m_xmm[xmm1].ps = bit_cast(temp.value()); + } +} +void SoftVPU::MOVAPS_xmm1m128_xmm2(X86::Instruction const& insn) +{ + u8 xmm2 = insn.modrm().reg(); + if (insn.modrm().is_register()) { + m_xmm[insn.modrm().rm()] = m_xmm[xmm2]; + } else { + // FIXME: Alignment-check 16 + u128 temp = bit_cast(m_xmm[xmm2]); + insn.modrm().write128(m_cpu, insn, ValueWithShadow::create_initialized(temp)); + } +} + +void SoftVPU::CVTPI2PS_xmm1_mm2m64(X86::Instruction const& insn) +{ + // FIXME: Raise Precission + // FIXME: Honor Rounding control + u8 xmm1 = insn.modrm().reg(); + if (insn.modrm().is_register()) { + i32x2 mm = m_cpu.mmx_get(insn.modrm().rm()).v32; + m_xmm[xmm1].ps[0] = mm[0]; + m_xmm[xmm1].ps[1] = mm[1]; + } else { + // FIXME: Shadows + i32x2 m64 = bit_cast(insn.modrm().read64(m_cpu, insn).value()); + m_xmm[xmm1].ps[0] = m64[0]; + m_xmm[xmm1].ps[1] = m64[1]; + } +} +void SoftVPU::CVTSI2SS_xmm1_rm32(X86::Instruction const& insn) +{ + // FIXME: Raise Precission + // FIXME: Shadows + // FIXME: Honor Rounding Control + m_xmm[insn.modrm().reg()].ps[0] = (i32)insn.modrm().read32(m_cpu, insn).value(); +} + +void SoftVPU::MOVNTPS_xmm1m128_xmm2(X86::Instruction const&) { TODO(); } + +void SoftVPU::CVTTPS2PI_mm1_xmm2m64(X86::Instruction const&) { TODO(); } +void SoftVPU::CVTTSS2SI_r32_xmm2m32(X86::Instruction const& insn) +{ + // FIXME: Raise Invalid, Precision + float value; + if (insn.modrm().is_register()) + value = m_xmm[insn.modrm().rm()].ps[0]; + else + value = bit_cast(insn.modrm().read32(m_cpu, insn).value()); + + m_cpu.gpr32(insn.reg32()) = ValueWithShadow::create_initialized((u32)lround(value)); +} +void SoftVPU::CVTPS2PI_xmm1_mm2m64(X86::Instruction const&) { TODO(); } +void SoftVPU::CVTSS2SI_xmm1_rm32(X86::Instruction const& insn) +{ + // FIXME: Raise Invalid, Precision + insn.modrm().write32(m_cpu, insn, + ValueWithShadow::create_initialized((u32)lround(m_xmm[insn.modrm().reg()].ps[0]))); +} + +void SoftVPU::UCOMISS_xmm1_xmm2m32(X86::Instruction const& insn) +{ + float xmm1 = m_xmm[insn.modrm().reg()].ps[0]; + float xmm2m32; + if (insn.modrm().is_register()) + xmm2m32 = m_xmm[insn.modrm().rm()].ps[0]; + else + xmm2m32 = bit_cast(insn.modrm().read32(m_cpu, insn).value()); + // FIXME: Raise Invalid on SNaN + if (isnan(xmm1) || isnan(xmm2m32)) { + m_cpu.set_zf(true); + m_cpu.set_pf(true); + m_cpu.set_cf(true); + } else { + m_cpu.set_zf(xmm1 == xmm2m32); + m_cpu.set_pf(false); + m_cpu.set_cf(xmm1 < xmm2m32); + } + m_cpu.set_of(false); + m_cpu.set_af(false); + m_cpu.set_sf(false); +} +void SoftVPU::COMISS_xmm1_xmm2m32(X86::Instruction const& insn) +{ + // FIXME: Raise on QNaN + UCOMISS_xmm1_xmm2m32(insn); +} + +void SoftVPU::MOVMSKPS_reg_xmm(X86::Instruction const& insn) +{ + VERIFY(insn.modrm().is_register()); + u8 mask = 0; + f32x4 xmm = m_xmm[insn.modrm().rm()].ps; + mask |= signbit(xmm[0]) << 0; + mask |= signbit(xmm[1]) << 1; + mask |= signbit(xmm[2]) << 2; + mask |= signbit(xmm[3]) << 3; + + m_cpu.gpr32(insn.reg32()) = ValueWithShadow::create_initialized(mask); +} + +void SoftVPU::SQRTPS_xmm1_xmm2m128(X86::Instruction const& insn) +{ + // FIXME: Raise Invalid, Precision, Denormal + f32x4 xmm2m128; + + if (insn.modrm().is_register()) { + xmm2m128 = m_xmm[insn.modrm().rm()].ps; + } else { + // FIXME: Shadows + xmm2m128 = bit_cast(insn.modrm().read128(m_cpu, insn).value()); + } + + m_xmm[insn.modrm().reg()].ps = sqrt(xmm2m128); +} +void SoftVPU::SQRTSS_xmm1_xmm2m32(X86::Instruction const& insn) +{ + // FIXME: Raise Invalid, Precision, Denormal + float xmm2m32; + + if (insn.modrm().is_register()) { + xmm2m32 = m_xmm[insn.modrm().rm()].ps[0]; + } else { + // FIXME: Shadows + xmm2m32 = bit_cast(insn.modrm().read32(m_cpu, insn).value()); + } + + m_xmm[insn.modrm().reg()].ps[0] = AK::sqrt(xmm2m32); +} +void SoftVPU::RSQRTPS_xmm1_xmm2m128(X86::Instruction const& insn) +{ + f32x4 xmm2m128; + if (insn.modrm().is_register()) { + xmm2m128 = m_xmm[insn.modrm().rm()].ps; + } else { + // FIXME: Shadows + xmm2m128 = bit_cast(insn.modrm().read128(m_cpu, insn).value()); + } + + m_xmm[insn.modrm().reg()].ps = rsqrt(xmm2m128); +} +void SoftVPU::RSQRTSS_xmm1_xmm2m32(X86::Instruction const& insn) +{ + float xmm2m32; + if (insn.modrm().is_register()) { + xmm2m32 = m_xmm[insn.modrm().rm()].ps[0]; + } else { + // FIXME: Shadows + xmm2m32 = bit_cast(insn.modrm().read32(m_cpu, insn).value()); + } + + m_xmm[insn.modrm().reg()].ps[0] = AK::rsqrt(xmm2m32); +} + +void SoftVPU::RCPPS_xmm1_xmm2m128(X86::Instruction const& insn) +{ + f32x4 xmm2m128; + if (insn.modrm().is_register()) { + xmm2m128 = m_xmm[insn.modrm().rm()].ps; + } else { + // FIXME: Shadows + xmm2m128 = bit_cast(insn.modrm().read128(m_cpu, insn).value()); + } + + m_xmm[insn.modrm().reg()].ps = 1.f / xmm2m128; +} +void SoftVPU::RCPSS_xmm1_xmm2m32(X86::Instruction const& insn) +{ + float xmm2m32; + if (insn.modrm().is_register()) { + xmm2m32 = m_xmm[insn.modrm().rm()].ps[0]; + } else { + // FIXME: Shadows + xmm2m32 = bit_cast(insn.modrm().read32(m_cpu, insn).value()); + } + + m_xmm[insn.modrm().reg()].ps[0] = 1.f / xmm2m32; +} + +void SoftVPU::ANDPS_xmm1_xmm2m128(X86::Instruction const& insn) +{ + u32x4 xmm2m128; + if (insn.modrm().is_register()) { + xmm2m128 = m_xmm[insn.modrm().rm()].pudw; + } else { + // FIXME: Shadows + xmm2m128 = bit_cast(insn.modrm().read128(m_cpu, insn).value()); + } + + m_xmm[insn.modrm().reg()].pudw &= xmm2m128; +} +void SoftVPU::ANDNPS_xmm1_xmm2m128(X86::Instruction const& insn) +{ + u32x4 xmm2m128; + if (insn.modrm().is_register()) { + xmm2m128 = m_xmm[insn.modrm().rm()].pudw; + } else { + // FIXME: Shadows + xmm2m128 = bit_cast(insn.modrm().read128(m_cpu, insn).value()); + } + + u32x4& xmm1 = m_xmm[insn.modrm().reg()].pudw; + xmm1 = ~xmm1 & xmm2m128; +} +void SoftVPU::ORPS_xmm1_xmm2m128(X86::Instruction const& insn) +{ + u32x4 xmm2m128; + if (insn.modrm().is_register()) { + xmm2m128 = m_xmm[insn.modrm().rm()].pudw; + } else { + // FIXME: Shadows + xmm2m128 = bit_cast(insn.modrm().read128(m_cpu, insn).value()); + } + + m_xmm[insn.modrm().reg()].pudw |= xmm2m128; +} +void SoftVPU::XORPS_xmm1_xmm2m128(X86::Instruction const& insn) +{ + u32x4 xmm2m128; + if (insn.modrm().is_register()) { + xmm2m128 = m_xmm[insn.modrm().rm()].pudw; + } else { + // FIXME: Shadows + xmm2m128 = bit_cast(insn.modrm().read128(m_cpu, insn).value()); + } + + m_xmm[insn.modrm().reg()].pudw ^= xmm2m128; +} + +void SoftVPU::ADDPS_xmm1_xmm2m128(X86::Instruction const& insn) +{ + // Raise Overflow, Underflow, Invalid, Precision, Denormal + f32x4 xmm2m128; + if (insn.modrm().is_register()) { + xmm2m128 = m_xmm[insn.modrm().rm()].ps; + } else { + // FIXME: Shadows + xmm2m128 = bit_cast(insn.modrm().read128(m_cpu, insn).value()); + } + + m_xmm[insn.modrm().reg()].ps += xmm2m128; +} +void SoftVPU::ADDSS_xmm1_xmm2m32(X86::Instruction const& insn) +{ + // Raise Overflow, Underflow, Invalid, Precision, Denormal + float xmm2m32; + if (insn.modrm().is_register()) { + xmm2m32 = m_xmm[insn.modrm().rm()].ps[0]; + } else { + // FIXME: Shadows + xmm2m32 = bit_cast(insn.modrm().read32(m_cpu, insn).value()); + } + + m_xmm[insn.modrm().reg()].ps[0] += xmm2m32; +} + +void SoftVPU::MULPS_xmm1_xmm2m128(X86::Instruction const& insn) +{ + // Raise Overflow, Underflow, Invalid, Precision, Denormal + f32x4 xmm2m128; + if (insn.modrm().is_register()) { + xmm2m128 = m_xmm[insn.modrm().rm()].ps; + } else { + // FIXME: Shadows + xmm2m128 = bit_cast(insn.modrm().read128(m_cpu, insn).value()); + } + + m_xmm[insn.modrm().reg()].ps *= xmm2m128; +} +void SoftVPU::MULSS_xmm1_xmm2m32(X86::Instruction const& insn) +{ + // Raise Overflow, Underflow, Invalid, Precision, Denormal + float xmm1 = m_xmm[insn.modrm().reg()].ps[0]; + float xmm2m32; + + if (insn.modrm().is_register()) { + xmm2m32 = m_xmm[insn.modrm().rm()].ps[0]; + } else { + // FIXME: Shadows + xmm2m32 = bit_cast(insn.modrm().read32(m_cpu, insn).value()); + } + xmm1 *= xmm2m32; + + m_xmm[insn.modrm().reg()].ps[0] *= xmm1; +} + +void SoftVPU::SUBPS_xmm1_xmm2m128(X86::Instruction const& insn) +{ + // Raise Overflow, Underflow, Invalid, Precision, Denormal + f32x4 xmm2m128; + + if (insn.modrm().is_register()) { + xmm2m128 = m_xmm[insn.modrm().rm()].ps; + } else { + // FIXME: Shadows + xmm2m128 = bit_cast(insn.modrm().read128(m_cpu, insn).value()); + } + + m_xmm[insn.modrm().reg()].ps -= xmm2m128; +} +void SoftVPU::SUBSS_xmm1_xmm2m32(X86::Instruction const& insn) +{ + // Raise Overflow, Underflow, Invalid, Precision, Denormal + float xmm2m32; + + if (insn.modrm().is_register()) { + xmm2m32 = m_xmm[insn.modrm().rm()].ps[0]; + } else { + // FIXME: Shadows + xmm2m32 = bit_cast(insn.modrm().read32(m_cpu, insn).value()); + } + + m_xmm[insn.modrm().reg()].ps[0] -= xmm2m32; +} + +void SoftVPU::MINPS_xmm1_xmm2m128(X86::Instruction const& insn) +{ + // FIXME: Raise Invalid (including QNaN Source Operand), Denormal + f32x4 xmm1 = m_xmm[insn.modrm().reg()].ps; + f32x4 xmm2m128; + + if (insn.modrm().is_register()) { + xmm2m128 = m_xmm[insn.modrm().rm()].ps; + } else { + // FIXME: Shadows + xmm2m128 = bit_cast(insn.modrm().read128(m_cpu, insn).value()); + } + + for (auto i = 0; i < 4; ++i) { + // When only one is NaN or both are 0.0s (of either sign), or + // FIXME: xmm2m32 is SNaN + // xmm2m32 is returned unchanged + if (isnan(xmm1[i]) || isnan(xmm2m128[i]) || xmm1[i] == xmm2m128[i]) + xmm1[i] = xmm2m128[i]; + else + xmm1[i] = min(xmm1[i], xmm2m128[i]); + } + + m_xmm[insn.modrm().reg()].ps = xmm1; +} +void SoftVPU::MINSS_xmm1_xmm2m32(X86::Instruction const& insn) +{ + // FIXME: Raise Invalid (Including QNaN Source Operand), Denormal + float xmm1 = m_xmm[insn.modrm().reg()].ps[0]; + float xmm2m32; + + if (insn.modrm().is_register()) { + xmm2m32 = m_xmm[insn.modrm().rm()].ps[0]; + } else { + // FIXME: Shadows + xmm2m32 = bit_cast(insn.modrm().read32(m_cpu, insn).value()); + } + // When only one is NaN or both are 0.0s (of either sign), or + // FIXME: xmm2m32 is SNaN + // xmm2m32 is returned unchanged + if (isnan(xmm1) || isnan(xmm2m32) || xmm1 == xmm2m32) + xmm1 = xmm2m32; + else + xmm1 = min(xmm1, xmm2m32); + + m_xmm[insn.modrm().reg()].ps[0] = xmm1; +} + +void SoftVPU::DIVPS_xmm1_xmm2m128(X86::Instruction const& insn) +{ + // Raise Overflow, Underflow, Invalid, Divide-by-Zero, Precision, Denormal + f32x4 xmm2m128; + if (insn.modrm().is_register()) { + xmm2m128 = m_xmm[insn.modrm().rm()].ps; + } else { + // FIXME: Shadows + xmm2m128 = bit_cast(insn.modrm().read128(m_cpu, insn).value()); + } + + m_xmm[insn.modrm().reg()].ps /= xmm2m128; +} +void SoftVPU::DIVSS_xmm1_xmm2m32(X86::Instruction const& insn) +{ + // Raise Overflow, Underflow, Invalid, Divide-by-Zero, Precision, Denormal + float xmm2m32; + if (insn.modrm().is_register()) { + xmm2m32 = m_xmm[insn.modrm().rm()].ps[0]; + } else { + // FIXME: Shadows + xmm2m32 = bit_cast(insn.modrm().read32(m_cpu, insn).value()); + } + + m_xmm[insn.modrm().reg()].ps[0] /= xmm2m32; +} + +void SoftVPU::MAXPS_xmm1_xmm2m128(X86::Instruction const& insn) +{ + // FIXME: Raise Invalid (including QNaN Source Operand), Denormal + f32x4 xmm1 = m_xmm[insn.modrm().reg()].ps; + f32x4 xmm2m128; + + if (insn.modrm().is_register()) { + xmm2m128 = m_xmm[insn.modrm().rm()].ps; + } else { + // FIXME: Shadows + xmm2m128 = bit_cast(insn.modrm().read128(m_cpu, insn).value()); + } + + for (auto i = 0; i < 4; ++i) { + // When only one is NaN or both are 0.0s (of either sign), or + // FIXME: xmm2m32 is SNaN + // xmm2m32 is returned unchanged + if (isnan(xmm1[i]) || isnan(xmm2m128[i]) || xmm1[i] == xmm2m128[i]) + xmm1[i] = xmm2m128[i]; + else + xmm1[i] = max(xmm1[i], xmm2m128[i]); + } + + m_xmm[insn.modrm().reg()].ps = xmm1; +} +void SoftVPU::MAXSS_xmm1_xmm2m32(X86::Instruction const& insn) +{ + // FIXME: Raise Invalid (Including QNaN Source Operand), Denormal + float xmm1 = m_xmm[insn.modrm().reg()].ps[0]; + float xmm2m32; + + if (insn.modrm().is_register()) { + xmm2m32 = m_xmm[insn.modrm().rm()].ps[0]; + } else { + // FIXME: Shadows + xmm2m32 = bit_cast(insn.modrm().read32(m_cpu, insn).value()); + } + // When only one is NaN or both are 0.0s (of either sign), or + // FIXME: xmm2m32 is SNaN + // xmm2m32 is returned unchanged + if (isnan(xmm1) || isnan(xmm2m32) || xmm1 == xmm2m32) + xmm1 = xmm2m32; + else + xmm1 = max(xmm1, xmm2m32); + + m_xmm[insn.modrm().reg()].ps[0] = xmm1; +} + +void SoftVPU::PSHUFW_mm1_mm2m64_imm8(X86::Instruction const& insn) +{ + MMX src; + if (insn.modrm().is_register()) { + src = m_cpu.mmx_get(insn.modrm().rm()); + } else { + // FIXME: Shadows + src = bit_cast(insn.modrm().read64(m_cpu, insn).value()); + } + + u8 order = insn.imm8(); + MMX dest; + + dest.v16u[0] = src.v16u[(order >> 0) & 0b11]; + dest.v16u[1] = src.v16u[(order >> 2) & 0b11]; + dest.v16u[2] = src.v16u[(order >> 4) & 0b11]; + dest.v16u[3] = src.v16u[(order >> 6) & 0b11]; + + m_cpu.mmx_set(insn.modrm().reg(), dest); +} + +void SoftVPU::CMPPS_xmm1_xmm2m128_imm8(X86::Instruction const& insn) +{ + // FIXME: Raise Denormal, Invalid Operation (QNaN dependend on imm8) + XMM& xmm1 = m_xmm[insn.modrm().reg()]; + f32x4 xmm2m128; + + if (insn.modrm().is_register()) { + xmm2m128 = m_xmm[insn.modrm().rm()].ps; + } else { + // FIXME: Shadows + xmm2m128 = bit_cast(insn.modrm().read128(m_cpu, insn).value()); + } + using enum ComparePredicate; + switch ((ComparePredicate)insn.imm8()) { + case EQ: + xmm1.ps = xmm1.ps == xmm2m128; + break; + case LT: + xmm1.ps = xmm1.ps < xmm2m128; + break; + case LE: + xmm1.ps = xmm1.ps <= xmm2m128; + break; + case UNORD: + for (auto i = 0; i < 4; ++i) + xmm1.pudw[i] = 0xFFFF'FFFF * (isnan(xmm1.ps[i]) || isnan(xmm2m128[i])); + break; + case NEQ: + xmm1.ps = xmm1.ps != xmm2m128; + break; + case NLT: + xmm1.ps = xmm1.ps >= xmm2m128; + break; + case NLE: + xmm1.ps = xmm1.ps > xmm2m128; + break; + case ORD: + for (auto i = 0; i < 4; ++i) + xmm1.pudw[i] = 0xFFFF'FFFF * (!isnan(xmm1.ps[i]) && !isnan(xmm2m128[i])); + break; + } +} +void SoftVPU::CMPSS_xmm1_xmm2m32_imm8(X86::Instruction const& insn) +{ + // FIXME: Raise Denormal, Invalid Operation (QNaN dependend on imm8) + float xmm1 = m_xmm[insn.modrm().reg()].ps[0]; + float xmm2m128; + bool res; + + if (insn.modrm().is_register()) { + xmm2m128 = m_xmm[insn.modrm().rm()].ps[0]; + } else { + // FIXME: Shadows + xmm2m128 = bit_cast(insn.modrm().read32(m_cpu, insn).value()); + } + using enum ComparePredicate; + switch ((ComparePredicate)insn.imm8()) { + case EQ: + res = xmm1 == xmm2m128; + break; + case LT: + res = xmm1 < xmm2m128; + break; + case LE: + res = xmm1 <= xmm2m128; + break; + case UNORD: + res = isnan(xmm1) || isnan(xmm2m128); + break; + case NEQ: + res = xmm1 != xmm2m128; + break; + case NLT: + res = xmm1 >= xmm2m128; + break; + case NLE: + res = xmm1 > xmm2m128; + break; + case ORD: + res = !isnan(xmm1) && !isnan(xmm2m128); + break; + } + + m_xmm[insn.modrm().reg()].pudw[0] = 0xFFFF'FFFF * res; +} + +void SoftVPU::PINSRW_mm1_r32m16_imm8(X86::Instruction const&) { TODO(); } +void SoftVPU::PINSRW_xmm1_r32m16_imm8(X86::Instruction const&) { TODO(); } +void SoftVPU::PEXTRW_reg_mm1_imm8(X86::Instruction const&) { TODO(); } +void SoftVPU::PEXTRW_reg_xmm1_imm8(X86::Instruction const&) { TODO(); } + +void SoftVPU::SHUFPS_xmm1_xmm2m128_imm8(X86::Instruction const& insn) +{ + f32x4 src; + if (insn.modrm().is_register()) { + src = m_xmm[insn.modrm().rm()].ps; + } else { + // FIXME: Shadows + src = bit_cast(insn.modrm().read128(m_cpu, insn).value()); + } + + u8 order = insn.imm8(); + f32x4 dest; + dest[0] = src[(order >> 0) & 0b11]; + dest[1] = src[(order >> 2) & 0b11]; + dest[2] = src[(order >> 4) & 0b11]; + dest[3] = src[(order >> 6) & 0b11]; + + m_xmm[insn.modrm().reg()].ps = dest; +} + +void SoftVPU::PMOVMSKB_reg_mm1(X86::Instruction const&) { TODO(); } +void SoftVPU::PMOVMSKB_reg_xmm1(X86::Instruction const& insn) +{ + VERIFY(insn.modrm().is_register()); + XMM src = m_xmm[insn.modrm().rm()]; + + u32 dest = 0; + for (int i = 0; i < 16; ++i) + dest |= (src.pub[i] >> 7) << i; + + m_cpu.gpr32(insn.reg32()) = ValueWithShadow::create_initialized(dest); +} + +void SoftVPU::PMINUB_mm1_mm2m64(X86::Instruction const&) { TODO(); } +void SoftVPU::PMINUB_xmm1_xmm2m128(X86::Instruction const&) { TODO(); } + +void SoftVPU::PMAXUB_mm1_mm2m64(X86::Instruction const&) { TODO(); } +void SoftVPU::PMAXUB_xmm1_xmm2m128(X86::Instruction const&) { TODO(); } + +void SoftVPU::PAVGB_mm1_mm2m64(X86::Instruction const&) { TODO(); } +void SoftVPU::PAVGB_xmm1_xmm2m128(X86::Instruction const&) { TODO(); } + +void SoftVPU::PAVGW_mm1_mm2m64(X86::Instruction const&) { TODO(); } +void SoftVPU::PAVGW_xmm1_xmm2m128(X86::Instruction const&) { TODO(); } + +void SoftVPU::PMULHUW_mm1_mm2m64(X86::Instruction const&) { TODO(); } +void SoftVPU::PMULHUW_xmm1_xmm2m64(X86::Instruction const&) { TODO(); } + +void SoftVPU::MOVNTQ_m64_mm1(X86::Instruction const&) { TODO(); } + +void SoftVPU::PMINSB_mm1_mm2m64(X86::Instruction const&) { TODO(); } +void SoftVPU::PMINSB_xmm1_xmm2m128(X86::Instruction const&) { TODO(); } + +void SoftVPU::PMAXSB_mm1_mm2m64(X86::Instruction const&) { TODO(); } +void SoftVPU::PMAXSB_xmm1_xmm2m128(X86::Instruction const&) { TODO(); } + +void SoftVPU::PSADBB_mm1_mm2m64(X86::Instruction const&) { TODO(); } +void SoftVPU::PSADBB_xmm1_xmm2m128(X86::Instruction const&) { TODO(); } + +void SoftVPU::MASKMOVQ_mm1_mm2m64(X86::Instruction const&) { TODO(); } +} diff --git a/Userland/DevTools/UserspaceEmulator/SoftVPU.h b/Userland/DevTools/UserspaceEmulator/SoftVPU.h new file mode 100644 index 0000000000..68bebf8c80 --- /dev/null +++ b/Userland/DevTools/UserspaceEmulator/SoftVPU.h @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2022, Leon Albrecht + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include + +namespace UserspaceEmulator { +using namespace AK::SIMD; +class Emulator; +class SoftCPU; + +union XMM { + f32x4 ps; + f64x2 pd; + i8x16 psb; + u8x16 pub; + i16x8 psw; + u16x8 puw; + u32x4 pudw; + u64x2 puqw; +}; + +class SoftVPU { +public: + SoftVPU(Emulator& emulator, SoftCPU& cpu) + : m_emulator(emulator) + , m_cpu(cpu) + , m_mxcsr { 0x1F80 } + { + } + + XMM& operator[](u8 index) { return m_xmm[index]; } + + enum class RoundingMode : u8 { + NEAREST = 0b00, + DOWN = 0b01, + UP = 0b10, + TRUNC = 0b11 + }; + + enum class ComparePredicate : u8 { + EQ = 0, + LT = 1, + LE = 2, + UNORD = 3, + NEQ = 4, + NLT = 5, + NLE = 6, + ORD = 7 + // FIXME: More with VEX prefix + }; + + i32 lround(float value) const + { + // FIXME: This is not yet 100% correct + using enum RoundingMode; + switch ((RoundingMode)rounding_control) { + case NEAREST: + return ::lroundf(value); + case DOWN: + return floorf(value); + case UP: + return ceilf(value); + case TRUNC: + return truncf(value); + default: + VERIFY_NOT_REACHED(); + } + } + +private: + friend SoftCPU; + Emulator& m_emulator; + SoftCPU& m_cpu; + + XMM m_xmm[8]; + union { + u32 m_mxcsr; + struct { + u32 invalid_operation_flag : 1; // IE + u32 denormal_operation_flag : 1; // DE + u32 divide_by_zero_flag : 1; // ZE + u32 overflow_flag : 1; // OE + u32 underflow_flag : 1; // UE + u32 precision_flag : 1; // PE + u32 denormals_are_zero : 1; // FIXME: DAZ + u32 invalid_operation_mask : 1; // IM + u32 denormal_operation_mask : 1; // DM + u32 devide_by_zero_mask : 1; // ZM + u32 overflow_mask : 1; // OM + u32 underflow_mask : 1; // UM + u32 precision_mask : 1; // PM + u32 rounding_control : 2; // FIXME: RC + u32 flush_to_zero : 1; // FIXME: FTZ + u32 __reserved : 16; + }; + }; + + void PREFETCHTNTA(X86::Instruction const&); + void PREFETCHT0(X86::Instruction const&); + void PREFETCHT1(X86::Instruction const&); + void PREFETCHT2(X86::Instruction const&); + void LDMXCSR(X86::Instruction const&); + void STMXCSR(X86::Instruction const&); + void MOVUPS_xmm1_xmm2m128(X86::Instruction const&); + void MOVSS_xmm1_xmm2m32(X86::Instruction const&); + void MOVUPS_xmm1m128_xmm2(X86::Instruction const&); + void MOVSS_xmm1m32_xmm2(X86::Instruction const&); + void MOVLPS_xmm1_xmm2m64(X86::Instruction const&); + void MOVLPS_m64_xmm2(X86::Instruction const&); + void UNPCKLPS_xmm1_xmm2m128(X86::Instruction const&); + void UNPCKHPS_xmm1_xmm2m128(X86::Instruction const&); + void MOVHPS_xmm1_xmm2m64(X86::Instruction const&); + void MOVHPS_m64_xmm2(X86::Instruction const&); + void MOVAPS_xmm1_xmm2m128(X86::Instruction const&); + void MOVAPS_xmm1m128_xmm2(X86::Instruction const&); + void CVTPI2PS_xmm1_mm2m64(X86::Instruction const&); + void CVTSI2SS_xmm1_rm32(X86::Instruction const&); + void MOVNTPS_xmm1m128_xmm2(X86::Instruction const&); + void CVTTPS2PI_mm1_xmm2m64(X86::Instruction const&); + void CVTTSS2SI_r32_xmm2m32(X86::Instruction const&); + void CVTPS2PI_xmm1_mm2m64(X86::Instruction const&); + void CVTSS2SI_xmm1_rm32(X86::Instruction const&); + void UCOMISS_xmm1_xmm2m32(X86::Instruction const&); + void COMISS_xmm1_xmm2m32(X86::Instruction const&); + void MOVMSKPS_reg_xmm(X86::Instruction const&); + void SQRTPS_xmm1_xmm2m128(X86::Instruction const&); + void SQRTSS_xmm1_xmm2m32(X86::Instruction const&); + void RSQRTPS_xmm1_xmm2m128(X86::Instruction const&); + void RSQRTSS_xmm1_xmm2m32(X86::Instruction const&); + void RCPPS_xmm1_xmm2m128(X86::Instruction const&); + void RCPSS_xmm1_xmm2m32(X86::Instruction const&); + void ANDPS_xmm1_xmm2m128(X86::Instruction const&); + void ANDNPS_xmm1_xmm2m128(X86::Instruction const&); + void ORPS_xmm1_xmm2m128(X86::Instruction const&); + void XORPS_xmm1_xmm2m128(X86::Instruction const&); + void ADDPS_xmm1_xmm2m128(X86::Instruction const&); + void ADDSS_xmm1_xmm2m32(X86::Instruction const&); + void MULPS_xmm1_xmm2m128(X86::Instruction const&); + void MULSS_xmm1_xmm2m32(X86::Instruction const&); + void SUBPS_xmm1_xmm2m128(X86::Instruction const&); + void SUBSS_xmm1_xmm2m32(X86::Instruction const&); + void MINPS_xmm1_xmm2m128(X86::Instruction const&); + void MINSS_xmm1_xmm2m32(X86::Instruction const&); + void DIVPS_xmm1_xmm2m128(X86::Instruction const&); + void DIVSS_xmm1_xmm2m32(X86::Instruction const&); + void MAXPS_xmm1_xmm2m128(X86::Instruction const&); + void MAXSS_xmm1_xmm2m32(X86::Instruction const&); + void PSHUFW_mm1_mm2m64_imm8(X86::Instruction const&); + void CMPPS_xmm1_xmm2m128_imm8(X86::Instruction const&); + void CMPSS_xmm1_xmm2m32_imm8(X86::Instruction const&); + void PINSRW_mm1_r32m16_imm8(X86::Instruction const&); + void PINSRW_xmm1_r32m16_imm8(X86::Instruction const&); + void PEXTRW_reg_mm1_imm8(X86::Instruction const&); + void PEXTRW_reg_xmm1_imm8(X86::Instruction const&); + void SHUFPS_xmm1_xmm2m128_imm8(X86::Instruction const&); + void PMOVMSKB_reg_mm1(X86::Instruction const&); + void PMOVMSKB_reg_xmm1(X86::Instruction const&); + void PMINUB_mm1_mm2m64(X86::Instruction const&); + void PMINUB_xmm1_xmm2m128(X86::Instruction const&); + void PMAXUB_mm1_mm2m64(X86::Instruction const&); + void PMAXUB_xmm1_xmm2m128(X86::Instruction const&); + void PAVGB_mm1_mm2m64(X86::Instruction const&); + void PAVGB_xmm1_xmm2m128(X86::Instruction const&); + void PAVGW_mm1_mm2m64(X86::Instruction const&); + void PAVGW_xmm1_xmm2m128(X86::Instruction const&); + void PMULHUW_mm1_mm2m64(X86::Instruction const&); + void PMULHUW_xmm1_xmm2m64(X86::Instruction const&); + void MOVNTQ_m64_mm1(X86::Instruction const&); + void PMINSB_mm1_mm2m64(X86::Instruction const&); + void PMINSB_xmm1_xmm2m128(X86::Instruction const&); + void PMAXSB_mm1_mm2m64(X86::Instruction const&); + void PMAXSB_xmm1_xmm2m128(X86::Instruction const&); + void PSADBB_mm1_mm2m64(X86::Instruction const&); + void PSADBB_xmm1_xmm2m128(X86::Instruction const&); + void MASKMOVQ_mm1_mm2m64(X86::Instruction const&); +}; + +}