summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOxore <oxore@protonmail.com>2023-05-08 21:28:07 +0300
committerOxore <oxore@protonmail.com>2023-05-08 21:28:07 +0300
commit3c0b372d623a52a2e0623f48c4adfb74fb727748 (patch)
treef2d052227914cab332ea565ede4081525cc4d7e1
parent5463fd221e7a1071f351ea12b617c90c4fe98d64 (diff)
Impl EXG
-rw-r--r--disasm.cpp25
-rw-r--r--test.bash7
2 files changed, 26 insertions, 6 deletions
diff --git a/disasm.cpp b/disasm.cpp
index 7b42703..401c869 100644
--- a/disasm.cpp
+++ b/disasm.cpp
@@ -1552,11 +1552,26 @@ static void disasm_mulu_muls(
return disasm_verbatim(node, instr, code, s);
}
-static void disasm_exg(
- DisasmNode &node, uint16_t instr, const DataBuffer &code, const Settings &s)
+static inline void disasm_exg(DisasmNode &node, uint16_t instr)
{
- // TODO Implement
- return disasm_verbatim(node, instr, code, s);
+ assert((instr & 0x130) == 0x100);
+ const int m1 = (instr >> 3) & 1;
+ const int m2 = (instr >> 6) & 3;
+ assert(m2 != 0); // Therefore m == 0 and m == 1 are impossible
+ assert(m2 != 3); // Therefore m == 6 and m == 7 are impossible
+ const int m = (m2 << 1) | m1;
+ assert(m != 4); // Only m == 2, m == 3 and m == 5 values are allowed
+ const int xn = instr & 7;
+ const int xi = (instr >> 9) & 7;
+ const auto src = (m == 3) ? AddrModeArg::An(xi) : AddrModeArg::Dn(xi);
+ const auto dst = (m == 2) ? AddrModeArg::Dn(xn) : AddrModeArg::An(xn);
+ char src_str[32]{};
+ char dst_str[32]{};
+ src.SNPrint(src_str, sizeof(src_str));
+ dst.SNPrint(dst_str, sizeof(dst_str));
+ snprintf(node.mnemonic, kMnemonicBufferSize, "exg");
+ snprintf(node.arguments, kArgsBufferSize, "%s,%s", src_str, dst_str);
+ node.size = kInstructionSizeStepBytes + src.Size() + dst.Size();
}
static void disasm_chunk_c(
@@ -1575,7 +1590,7 @@ static void disasm_chunk_c(
}
const unsigned m_split = instr & 0x1f8;
if (m_split == 0x188 || m_split == 0x148 || m_split == 0x140) {
- return disasm_exg(node, instr, code, s);
+ return disasm_exg(node, instr);
}
return disasm_or_and(node, instr, code, s, opsize, "and");
}
diff --git a/test.bash b/test.bash
index 5ee822d..50ee0e3 100644
--- a/test.bash
+++ b/test.bash
@@ -93,6 +93,12 @@ run_test_iterative() {
done
}
+# cxxx exg
+#
+run_test_simple "exg Dn, Dn" "\xcd\x41"
+run_test_simple "exg Dn, An" "\xcd\x89"
+run_test_simple "exg An, An" "\xcd\x49"
+
# cxxx and
#
run_test_simple "andb Dn, Dn" "\xc4\x01"
@@ -104,7 +110,6 @@ run_test_simple "andw -(An), Dn" "\xc4\x61"
run_test_simple "andl (d8,PC,An), Dn" "\xc0\xbb\xc8\x07"
# GNU AS would emit ANDI for "and #imm,Xn", so we diassemble it as short
run_test_expect_short "andl #imm, D6" "\xc6\xbc\x44\xd1\xe6\xe9"
-run_test_expect_short "andl D2, D0 swapped direction" "\xc1\x42"
# cxxx abcd
#