Browse Source

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.
Andreas Kling 5 years ago
parent
commit
0af485dfff
2 changed files with 83 additions and 3 deletions
  1. 78 3
      DevTools/UserspaceEmulator/SoftCPU.cpp
  2. 5 0
      DevTools/UserspaceEmulator/SoftCPU.h

+ 78 - 3
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(); }

+ 5 - 0
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;