mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-09-30 00:31:14 +00:00
UserspaceEmulator: Implement the SSE extension
This almost fully implements the SSE extension, similar to the x87 and MMX extensions, using a separate class "SoftVPU". Currently missing are all shadow and exception checks, as well as the denormals-are-zero and flush-to-zero flags. Also missing are some integer-SIMD functions.
This commit is contained in:
parent
1d2ad9cf61
commit
2377344a89
Notes:
sideshowbarker
2024-07-17 17:49:11 +09:00
Author: https://github.com/Hendiadyoin1 Commit: https://github.com/SerenityOS/serenity/commit/2377344a89 Pull-request: https://github.com/SerenityOS/serenity/pull/13405
|
@ -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)
|
||||
|
|
|
@ -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<ValueWithShadow<u8>>, insn); } \
|
||||
void SoftCPU::mnemonic##_RM8_CL(const X86::Instruction& insn) { generic_RM8_CL(op<ValueWithShadow<u8>>, 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(); }
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "Emulator.h"
|
||||
#include "Region.h"
|
||||
#include "SoftFPU.h"
|
||||
#include "SoftVPU.h"
|
||||
#include "ValueWithShadow.h"
|
||||
#include <AK/ByteReader.h>
|
||||
#include <LibX86/Instruction.h>
|
||||
|
@ -1247,6 +1248,7 @@ private:
|
|||
|
||||
Emulator& m_emulator;
|
||||
SoftFPU m_fpu;
|
||||
SoftVPU m_vpu;
|
||||
|
||||
ValueWithShadow<PartAddressableRegister> m_gpr[8];
|
||||
|
||||
|
|
778
Userland/DevTools/UserspaceEmulator/SoftVPU.cpp
Normal file
778
Userland/DevTools/UserspaceEmulator/SoftVPU.cpp
Normal file
|
@ -0,0 +1,778 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Leon Albrecht <leon.a@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include "SoftVPU.h"
|
||||
#include "SoftCPU.h"
|
||||
#include <AK/SIMDMath.h>
|
||||
|
||||
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<u32>::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<f32x4>(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<float>(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<u128>(m_xmm[xmm2]);
|
||||
insn.modrm().write128(m_cpu, insn, ValueWithShadow<u128>::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<u32>(m_xmm[xmm2].ps[0]);
|
||||
insn.modrm().write32(m_cpu, insn, ValueWithShadow<u32>::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<u64>::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<f32x4>(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<f32x4>(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<f32x4>(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<u64>::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<f32x4>(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<u128>(m_xmm[xmm2]);
|
||||
insn.modrm().write128(m_cpu, insn, ValueWithShadow<u128>::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<i32x2>(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<float>(insn.modrm().read32(m_cpu, insn).value());
|
||||
|
||||
m_cpu.gpr32(insn.reg32()) = ValueWithShadow<u32>::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<u32>::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<float>(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<u32>::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<f32x4>(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<float>(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<f32x4>(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<float>(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<f32x4>(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<float>(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<u32x4>(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<u32x4>(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<u32x4>(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<u32x4>(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<f32x4>(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<float>(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<f32x4>(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<float>(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<f32x4>(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<float>(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<f32x4>(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<float>(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<f32x4>(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<float>(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<f32x4>(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<float>(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<MMX>(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<f32x4>(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<float>(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<f32x4>(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<u32>::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(); }
|
||||
}
|
186
Userland/DevTools/UserspaceEmulator/SoftVPU.h
Normal file
186
Userland/DevTools/UserspaceEmulator/SoftVPU.h
Normal file
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Leon Albrecht <leon.a@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/SIMD.h>
|
||||
#include <AK/Types.h>
|
||||
#include <LibX86/Instruction.h>
|
||||
#include <math.h>
|
||||
|
||||
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&);
|
||||
};
|
||||
|
||||
}
|
Loading…
Reference in a new issue