diff options
Diffstat (limited to 'DevTools/UserspaceEmulator/SoftCPU.cpp')
-rw-r--r-- | DevTools/UserspaceEmulator/SoftCPU.cpp | 81 |
1 files changed, 78 insertions, 3 deletions
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<bool check_zf, typename Callback> +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<typename Destination, typename Source> static typename TypeDoubler<Destination>::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<false>(insn, [&] { + write_memory8({ es(), di() }, al()); + set_di(di() + (df() ? -1 : 1)); + }); + } else { + do_once_or_repeat<false>(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<false>(insn, [&] { + write_memory32({ es(), di() }, eax()); + set_di(di() + (df() ? -4 : 4)); + }); + } else { + do_once_or_repeat<false>(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<false>(insn, [&] { + write_memory16({ es(), di() }, ax()); + set_di(di() + (df() ? -2 : 2)); + }); + } else { + do_once_or_repeat<false>(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(); } |