summaryrefslogtreecommitdiff
path: root/DevTools
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2020-07-11 22:12:37 +0200
committerAndreas Kling <kling@serenityos.org>2020-07-11 23:57:14 +0200
commit0af485dfffb6ae96b4440b3f9b01849ae6aabd95 (patch)
tree075ed62cdbffd33a2e58b52d79222e6239953f8e /DevTools
parent6688ce41b21f54d71138a16a949907775397d315 (diff)
downloadserenity-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.cpp81
-rw-r--r--DevTools/UserspaceEmulator/SoftCPU.h5
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;