diff options
author | Andreas Kling <kling@serenityos.org> | 2020-07-11 22:12:37 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-07-11 23:57:14 +0200 |
commit | 0af485dfffb6ae96b4440b3f9b01849ae6aabd95 (patch) | |
tree | 075ed62cdbffd33a2e58b52d79222e6239953f8e /DevTools | |
parent | 6688ce41b21f54d71138a16a949907775397d315 (diff) | |
download | serenity-0af485dfffb6ae96b4440b3f9b01849ae6aabd95.zip |
UserspaceEmulator: Implement STOSB/STOSW/STOSD
...and add a template to handle REP* instruction prefixes. This can be
further generalized, but let's go one step at a time.
Diffstat (limited to 'DevTools')
-rw-r--r-- | DevTools/UserspaceEmulator/SoftCPU.cpp | 81 | ||||
-rw-r--r-- | DevTools/UserspaceEmulator/SoftCPU.h | 5 |
2 files changed, 83 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(); } 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<bool update_dest, typename Op> void generic_reg8_RM8(Op, const X86::Instruction&); + template<bool check_zf, typename Callback> + void do_once_or_repeat(const X86::Instruction& insn, Callback); + private: Emulator& m_emulator; |