diff --git a/DevTools/UserspaceEmulator/SoftCPU.cpp b/DevTools/UserspaceEmulator/SoftCPU.cpp index 5130e6b80f..6edb92358b 100644 --- a/DevTools/UserspaceEmulator/SoftCPU.cpp +++ b/DevTools/UserspaceEmulator/SoftCPU.cpp @@ -1347,6 +1347,22 @@ void SoftCPU::ESCAPE(const X86::Instruction&) TODO(); } +void SoftCPU::FADD_RM32(const X86::Instruction&) { TODO(); } +void SoftCPU::FMUL_RM32(const X86::Instruction&) { TODO(); } +void SoftCPU::FCOM_RM32(const X86::Instruction&) { TODO(); } +void SoftCPU::FCOMP_RM32(const X86::Instruction&) { TODO(); } +void SoftCPU::FSUB_RM32(const X86::Instruction&) { TODO(); } +void SoftCPU::FSUBR_RM32(const X86::Instruction&) { TODO(); } +void SoftCPU::FDIV_RM32(const X86::Instruction&) { TODO(); } +void SoftCPU::FDIVR_RM32(const X86::Instruction&) { TODO(); } +void SoftCPU::FADD_RM64(const X86::Instruction&) { TODO(); } +void SoftCPU::FMUL_RM64(const X86::Instruction&) { TODO(); } +void SoftCPU::FCOM_RM64(const X86::Instruction&) { TODO(); } +void SoftCPU::FCOMP_RM64(const X86::Instruction&) { TODO(); } +void SoftCPU::FSUB_RM64(const X86::Instruction&) { TODO(); } +void SoftCPU::FSUBR_RM64(const X86::Instruction&) { TODO(); } +void SoftCPU::FDIV_RM64(const X86::Instruction&) { TODO(); } +void SoftCPU::FDIVR_RM64(const X86::Instruction&) { TODO(); } void SoftCPU::HLT(const X86::Instruction&) { TODO(); } void SoftCPU::IDIV_RM16(const X86::Instruction& insn) diff --git a/DevTools/UserspaceEmulator/SoftCPU.h b/DevTools/UserspaceEmulator/SoftCPU.h index e954873edf..2acd0ff65c 100644 --- a/DevTools/UserspaceEmulator/SoftCPU.h +++ b/DevTools/UserspaceEmulator/SoftCPU.h @@ -574,6 +574,22 @@ private: virtual void ENTER16(const X86::Instruction&) override; virtual void ENTER32(const X86::Instruction&) override; virtual void ESCAPE(const X86::Instruction&) override; + virtual void FADD_RM32(const X86::Instruction&) override; + virtual void FMUL_RM32(const X86::Instruction&) override; + virtual void FCOM_RM32(const X86::Instruction&) override; + virtual void FCOMP_RM32(const X86::Instruction&) override; + virtual void FSUB_RM32(const X86::Instruction&) override; + virtual void FSUBR_RM32(const X86::Instruction&) override; + virtual void FDIV_RM32(const X86::Instruction&) override; + virtual void FDIVR_RM32(const X86::Instruction&) override; + virtual void FADD_RM64(const X86::Instruction&) override; + virtual void FMUL_RM64(const X86::Instruction&) override; + virtual void FCOM_RM64(const X86::Instruction&) override; + virtual void FCOMP_RM64(const X86::Instruction&) override; + virtual void FSUB_RM64(const X86::Instruction&) override; + virtual void FSUBR_RM64(const X86::Instruction&) override; + virtual void FDIV_RM64(const X86::Instruction&) override; + virtual void FDIVR_RM64(const X86::Instruction&) override; virtual void HLT(const X86::Instruction&) override; virtual void IDIV_RM16(const X86::Instruction&) override; virtual void IDIV_RM32(const X86::Instruction&) override; diff --git a/Libraries/LibX86/Instruction.cpp b/Libraries/LibX86/Instruction.cpp index adfa3b086d..3641973fda 100644 --- a/Libraries/LibX86/Instruction.cpp +++ b/Libraries/LibX86/Instruction.cpp @@ -135,6 +135,8 @@ static void build(InstructionDescriptor* table, u8 op, const char* mnemonic, Ins case OP_RM8: case OP_RM16: case OP_RM32: + case OP_FPU_RM32: + case OP_FPU_RM64: case OP_RM8_reg8: case OP_RM32_reg32: case OP_reg32_RM32: @@ -434,9 +436,34 @@ static void build_0f_slash(u8 op, u8 slash, const char* mnemonic, InstructionFor build(0xD6, "SALC", OP, &Interpreter::SALC); build(0xD7, "XLAT", OP, &Interpreter::XLAT); - // FIXME: D8-DF == FPU - for (u8 i = 0; i <= 7; ++i) - build(0xD8 + i, "FPU?", OP_RM8, &Interpreter::ESCAPE); + // D8-DF == FPU + build_slash(0xD8, 0, "FADD", OP_FPU_RM32, &Interpreter::FADD_RM32); + build_slash(0xD8, 1, "FMUL", OP_FPU_RM32, &Interpreter::FMUL_RM32); + build_slash(0xD8, 2, "FCOM", OP_FPU_RM32, &Interpreter::FCOM_RM32); + // FIXME: D8/2 D1 (...but isn't this what D8/2 does naturally, with D1 just being normal R/M?) + build_slash(0xD8, 3, "FCOMP", OP_FPU_RM32, &Interpreter::FCOMP_RM32); + // FIXME: D8/3 D9 (...but isn't this what D8/3 does naturally, with D9 just being normal R/M?) + build_slash(0xD8, 4, "FSUB", OP_FPU_RM32, &Interpreter::FSUB_RM32); + build_slash(0xD8, 5, "FSUBR", OP_FPU_RM32, &Interpreter::FSUBR_RM32); + build_slash(0xD8, 6, "FDIV", OP_FPU_RM32, &Interpreter::FDIV_RM32); + build_slash(0xD8, 7, "FDIVR", OP_FPU_RM32, &Interpreter::FDIVR_RM32); + + // FIXME + for (u8 i = 0; i <= 3; ++i) + build(0xD9 + i, "FPU?", OP_RM8, &Interpreter::ESCAPE); + + build_slash(0xDC, 0, "FADD", OP_FPU_RM64, &Interpreter::FADD_RM64); + build_slash(0xDC, 1, "FMUL", OP_FPU_RM64, &Interpreter::FMUL_RM64); + build_slash(0xDC, 2, "FCOM", OP_FPU_RM64, &Interpreter::FCOM_RM64); + build_slash(0xDC, 3, "FCOMP", OP_FPU_RM64, &Interpreter::FCOMP_RM64); + build_slash(0xDC, 4, "FSUB", OP_FPU_RM64, &Interpreter::FSUB_RM64); + build_slash(0xDC, 5, "FSUBR", OP_FPU_RM64, &Interpreter::FSUBR_RM64); + build_slash(0xDC, 6, "FDIV", OP_FPU_RM64, &Interpreter::FDIV_RM64); + build_slash(0xDC, 7, "FDIVR", OP_FPU_RM64, &Interpreter::FDIVR_RM64); + + // FIXME + for (u8 i = 0; i <= 2; ++i) + build(0xDD + i, "FPU?", OP_RM8, &Interpreter::ESCAPE); build(0xE0, "LOOPNZ", OP_imm8, &Interpreter::LOOPNZ_imm8); build(0xE1, "LOOPZ", OP_imm8, &Interpreter::LOOPZ_imm8); @@ -707,6 +734,7 @@ static void build_0f_slash(u8 op, u8 slash, const char* mnemonic, InstructionFor static const char* register_name(RegisterIndex8); static const char* register_name(RegisterIndex16); static const char* register_name(RegisterIndex32); +static const char* register_name(FpuRegisterIndex); static const char* register_name(SegmentRegister); static const char* register_name(MMXRegisterIndex); @@ -728,24 +756,38 @@ const char* Instruction::reg32_name() const String MemoryOrRegisterReference::to_string_o8(const Instruction& insn) const { if (is_register()) - return register_name(static_cast(m_register_index)); + return register_name(reg8()); return String::format("[%s]", to_string(insn).characters()); } String MemoryOrRegisterReference::to_string_o16(const Instruction& insn) const { if (is_register()) - return register_name(static_cast(m_register_index)); + return register_name(reg16()); return String::format("[%s]", to_string(insn).characters()); } String MemoryOrRegisterReference::to_string_o32(const Instruction& insn) const { if (is_register()) - return register_name(static_cast(m_register_index)); + return register_name(reg32()); return String::format("[%s]", to_string(insn).characters()); } +String MemoryOrRegisterReference::to_string_fpu32(const Instruction& insn) const +{ + if (is_register()) + return register_name(reg_fpu()); + return String::format("dword ptr [%s]", to_string(insn).characters()); +} + +String MemoryOrRegisterReference::to_string_fpu64(const Instruction& insn) const +{ + if (is_register()) + return register_name(reg_fpu()); + return String::format("qword ptr [%s]", to_string(insn).characters()); +} + String MemoryOrRegisterReference::to_string_mm(const Instruction& insn) const { if (is_register()) @@ -1035,6 +1077,8 @@ String Instruction::to_string_internal(u32 origin, const SymbolProvider* symbol_ auto append_rm8 = [&] { builder.append(m_modrm.to_string_o8(*this)); }; auto append_rm16 = [&] { builder.append(m_modrm.to_string_o16(*this)); }; auto append_rm32 = [&] { builder.append(m_modrm.to_string_o32(*this)); }; + auto append_fpu_rm32 = [&] { builder.append(m_modrm.to_string_fpu32(*this)); }; + auto append_fpu_rm64 = [&] { builder.append(m_modrm.to_string_fpu64(*this)); }; auto append_imm8 = [&] { builder.appendf("%#02x", imm8()); }; auto append_imm8_2 = [&] { builder.appendf("%#02x", imm8_2()); }; auto append_imm16 = [&] { builder.appendf("%#04x", imm16()); }; @@ -1298,6 +1342,12 @@ String Instruction::to_string_internal(u32 origin, const SymbolProvider* symbol_ case OP_RM32: append_rm32(); break; + case OP_FPU_RM32: + append_fpu_rm32(); + break; + case OP_FPU_RM64: + append_fpu_rm64(); + break; case OP_RM8_reg8: append_rm8(); append(", "); @@ -1505,6 +1555,12 @@ const char* register_name(RegisterIndex32 register_index) return names[register_index & 7]; } +const char* register_name(FpuRegisterIndex register_index) +{ + static constexpr const char* names[] = { "st0", "st1", "st2", "st3", "st4", "st5", "st6", "st7" }; + return names[register_index & 7]; +} + const char* register_name(MMXRegisterIndex register_index) { static constexpr const char* names[] = { "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7" }; diff --git a/Libraries/LibX86/Instruction.h b/Libraries/LibX86/Instruction.h index 6d3fd98093..2a297f2d6e 100644 --- a/Libraries/LibX86/Instruction.h +++ b/Libraries/LibX86/Instruction.h @@ -82,6 +82,8 @@ enum InstructionFormat { OP_RM8, OP_RM16, OP_RM32, + OP_FPU_RM32, + OP_FPU_RM64, OP_RM8_reg8, OP_RM32_reg32, OP_reg32_RM32, @@ -256,6 +258,17 @@ enum RegisterIndex32 { RegisterEDI }; +enum FpuRegisterIndex { + ST0 = 0, + ST1, + ST2, + ST3, + ST4, + ST5, + ST6, + ST7 +}; + enum MMXRegisterIndex { RegisterMM0 = 0, RegisterMM1, @@ -339,6 +352,8 @@ public: String to_string_o8(const Instruction&) const; String to_string_o16(const Instruction&) const; String to_string_o32(const Instruction&) const; + String to_string_fpu32(const Instruction&) const; + String to_string_fpu64(const Instruction&) const; String to_string_mm(const Instruction&) const; bool is_register() const { return m_register_index != 0xffffffff; } @@ -347,6 +362,7 @@ public: RegisterIndex32 reg32() const { return static_cast(register_index()); } RegisterIndex16 reg16() const { return static_cast(register_index()); } RegisterIndex8 reg8() const { return static_cast(register_index()); } + FpuRegisterIndex reg_fpu() const { return static_cast(register_index()); } template void write8(CPU&, const Instruction&, T); diff --git a/Libraries/LibX86/Interpreter.h b/Libraries/LibX86/Interpreter.h index 7952fc685f..a2f6704f31 100644 --- a/Libraries/LibX86/Interpreter.h +++ b/Libraries/LibX86/Interpreter.h @@ -156,6 +156,22 @@ public: virtual void ENTER16(const Instruction&) = 0; virtual void ENTER32(const Instruction&) = 0; virtual void ESCAPE(const Instruction&) = 0; + virtual void FADD_RM32(const Instruction&) = 0; + virtual void FMUL_RM32(const Instruction&) = 0; + virtual void FCOM_RM32(const Instruction&) = 0; + virtual void FCOMP_RM32(const Instruction&) = 0; + virtual void FSUB_RM32(const Instruction&) = 0; + virtual void FSUBR_RM32(const Instruction&) = 0; + virtual void FDIV_RM32(const Instruction&) = 0; + virtual void FDIVR_RM32(const Instruction&) = 0; + virtual void FADD_RM64(const Instruction&) = 0; + virtual void FMUL_RM64(const Instruction&) = 0; + virtual void FCOM_RM64(const Instruction&) = 0; + virtual void FCOMP_RM64(const Instruction&) = 0; + virtual void FSUB_RM64(const Instruction&) = 0; + virtual void FSUBR_RM64(const Instruction&) = 0; + virtual void FDIV_RM64(const Instruction&) = 0; + virtual void FDIVR_RM64(const Instruction&) = 0; virtual void HLT(const Instruction&) = 0; virtual void IDIV_RM16(const Instruction&) = 0; virtual void IDIV_RM32(const Instruction&) = 0;