diff --git a/DevTools/UserspaceEmulator/SoftCPU.cpp b/DevTools/UserspaceEmulator/SoftCPU.cpp index 72fd0edff7..f7a7f9fe05 100644 --- a/DevTools/UserspaceEmulator/SoftCPU.cpp +++ b/DevTools/UserspaceEmulator/SoftCPU.cpp @@ -157,6 +157,38 @@ u32 SoftCPU::pop32() return value; } +template +void SoftCPU::do_once_or_repeat(const X86::Instruction& insn, Callback callback) +{ + if (!insn.has_rep_prefix()) + return callback(); + + if (insn.has_address_size_override_prefix()) { + while (cx()) { + callback(); + set_cx(cx() - 1); + if constexpr (check_zf) { + if (insn.rep_prefix() == X86::Prefix::REPZ && !zf()) + break; + if (insn.rep_prefix() == X86::Prefix::REPNZ && zf()) + break; + } + } + return; + } + + while (ecx()) { + callback(); + set_ecx(ecx() - 1); + if constexpr (check_zf) { + if (insn.rep_prefix() == X86::Prefix::REPZ && !zf()) + break; + if (insn.rep_prefix() == X86::Prefix::REPNZ && zf()) + break; + } + } +} + template static typename TypeDoubler::type op_xor(SoftCPU& cpu, const Destination& dest, const Source& src) { @@ -1064,9 +1096,52 @@ void SoftCPU::SMSW_RM16(const X86::Instruction&) { TODO(); } void SoftCPU::STC(const X86::Instruction&) { TODO(); } void SoftCPU::STD(const X86::Instruction&) { TODO(); } void SoftCPU::STI(const X86::Instruction&) { TODO(); } -void SoftCPU::STOSB(const X86::Instruction&) { TODO(); } -void SoftCPU::STOSD(const X86::Instruction&) { TODO(); } -void SoftCPU::STOSW(const X86::Instruction&) { TODO(); } + +void SoftCPU::STOSB(const X86::Instruction& insn) +{ + if (insn.has_address_size_override_prefix()) { + do_once_or_repeat(insn, [&] { + write_memory8({ es(), di() }, al()); + set_di(di() + (df() ? -1 : 1)); + }); + } else { + do_once_or_repeat(insn, [&] { + write_memory8({ es(), edi() }, al()); + set_edi(edi() + (df() ? -1 : 1)); + }); + } +} + +void SoftCPU::STOSD(const X86::Instruction& insn) +{ + if (insn.has_address_size_override_prefix()) { + do_once_or_repeat(insn, [&] { + write_memory32({ es(), di() }, eax()); + set_di(di() + (df() ? -4 : 4)); + }); + } else { + do_once_or_repeat(insn, [&] { + write_memory32({ es(), edi() }, eax()); + set_edi(edi() + (df() ? -4 : 4)); + }); + } +} + +void SoftCPU::STOSW(const X86::Instruction& insn) +{ + if (insn.has_address_size_override_prefix()) { + do_once_or_repeat(insn, [&] { + write_memory16({ es(), di() }, ax()); + set_di(di() + (df() ? -2 : 2)); + }); + } else { + do_once_or_repeat(insn, [&] { + write_memory16({ es(), edi() }, ax()); + set_edi(edi() + (df() ? -2 : 2)); + }); + } +} + void SoftCPU::STR_RM16(const X86::Instruction&) { TODO(); } void SoftCPU::UD0(const X86::Instruction&) { TODO(); } void SoftCPU::UD1(const X86::Instruction&) { TODO(); } diff --git a/DevTools/UserspaceEmulator/SoftCPU.h b/DevTools/UserspaceEmulator/SoftCPU.h index bd95158add..a812395f1b 100644 --- a/DevTools/UserspaceEmulator/SoftCPU.h +++ b/DevTools/UserspaceEmulator/SoftCPU.h @@ -190,6 +190,7 @@ public: bool af() const { return m_eflags & Flags::AF; } bool pf() const { return m_eflags & Flags::PF; } bool cf() const { return m_eflags & Flags::CF; } + bool df() const { return m_eflags & Flags::DF; } void set_flag(Flags::Flag flag, bool value) { @@ -205,6 +206,7 @@ public: void set_af(bool value) { set_flag(Flags::AF, value); } void set_pf(bool value) { set_flag(Flags::PF, value); } void set_cf(bool value) { set_flag(Flags::CF, value); } + void set_df(bool value) { set_flag(Flags::DF, value); } void set_flags_oszapc(u32 new_flags) { @@ -785,6 +787,9 @@ private: template void generic_reg8_RM8(Op, const X86::Instruction&); + template + void do_once_or_repeat(const X86::Instruction& insn, Callback); + private: Emulator& m_emulator;