summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common.h12
-rw-r--r--disasm.cpp46
-rw-r--r--main.cpp96
-rw-r--r--test.bash19
-rw-r--r--test_marks_referencing.bash1
-rw-r--r--test_random.bash2
6 files changed, 127 insertions, 49 deletions
diff --git a/common.h b/common.h
index 65f7648..7ee965b 100644
--- a/common.h
+++ b/common.h
@@ -18,15 +18,21 @@ constexpr RefKindMask kRef1RelMask = (1 << 0); // For first argument
constexpr RefKindMask kRef1AbsMask = (1 << 1); // For first argument
constexpr RefKindMask kRef2RelMask = (1 << 2); // For second argument
constexpr RefKindMask kRef2AbsMask = (1 << 3); // For second argument
+constexpr RefKindMask kRef1ReadMask = (1 << 4); // For first argument
+constexpr RefKindMask kRef1WriteMask = (1 << 5); // For first argument
+constexpr RefKindMask kRef2ReadMask = (1 << 6); // For second argument
+constexpr RefKindMask kRef2WriteMask = (1 << 7); // For second argument
/// Indicates whether instruction is a call or just a branch, for any argument.
/// Calls are BSR and JSR, branches are DBcc, Bcc and JMP.
-constexpr RefKindMask kRefCallMask = (1 << 4);
-constexpr RefKindMask kRefReadMask = (1 << 5); // For any argument
-constexpr RefKindMask kRefWriteMask = (1 << 6); // For any argument
+constexpr RefKindMask kRefCallMask = (1 << 8);
constexpr RefKindMask kRefRelMask = kRef1RelMask | kRef2RelMask;
constexpr RefKindMask kRefAbsMask = kRef1AbsMask | kRef2AbsMask;
constexpr RefKindMask kRef1Mask = kRef1RelMask | kRef1AbsMask; // For first argument
constexpr RefKindMask kRef2Mask = kRef2RelMask | kRef2AbsMask; // For second argument
+constexpr RefKindMask kRef1DataMask = kRef1ReadMask | kRef1WriteMask; // For first argument
+constexpr RefKindMask kRef2DataMask = kRef2ReadMask | kRef2WriteMask; // For second argument
+constexpr RefKindMask kRefReadMask = kRef1ReadMask | kRef2ReadMask; // For any argument
+constexpr RefKindMask kRefWriteMask = kRef1WriteMask | kRef2WriteMask; // For any argument
constexpr RefKindMask kRefDataMask = kRefReadMask | kRefWriteMask;
constexpr size_t kInstructionSizeStepBytes = 2;
constexpr size_t kRomSizeBytes = 4 * 1024 * 1024;
diff --git a/disasm.cpp b/disasm.cpp
index 0726f66..a95b0a2 100644
--- a/disasm.cpp
+++ b/disasm.cpp
@@ -262,10 +262,10 @@ static size_t disasm_ext_movem(
case AddrMode::kLong: // 48b9 / 4cb9 / 48f9 / 4cf9
if (dir == MoveDirection::kRegisterToMemory) {
node.ref2_addr = static_cast<uint32_t>(a.lword);
- node.ref_kinds = kRef2AbsMask | kRefWriteMask;
+ node.ref_kinds = kRef2AbsMask | kRef2WriteMask;
} else {
node.ref1_addr = static_cast<uint32_t>(a.lword);
- node.ref_kinds = kRef1AbsMask | kRefReadMask;
+ node.ref_kinds = kRef1AbsMask | kRef1ReadMask;
}
break;
case AddrMode::kD16PCAddr: // 48ba / 4cba / 48fa / 4cfa
@@ -275,7 +275,7 @@ static size_t disasm_ext_movem(
} else if (a.mode == AddrMode::kD16PCAddr) {
node.ref1_addr = node.offset + kInstructionSizeStepBytes +
static_cast<uint32_t>(a.d16_pc.d16);
- node.ref_kinds = kRef1RelMask | kRefReadMask;
+ node.ref_kinds = kRef1RelMask | kRef1ReadMask;
}
break;
case AddrMode::kImmediate: // 4ebc / 4efc
@@ -315,12 +315,12 @@ static size_t disasm_lea(
case AddrMode::kWord:
case AddrMode::kLong:
node.ref1_addr = static_cast<uint32_t>(addr.lword);
- node.ref_kinds = kRef1AbsMask | kRefReadMask;
+ node.ref_kinds = kRef1AbsMask | kRef1ReadMask;
break;
case AddrMode::kD16PCAddr:
node.ref1_addr = node.offset + kInstructionSizeStepBytes +
static_cast<uint32_t>(addr.d16_pc.d16);
- node.ref_kinds = kRef1RelMask | kRefReadMask;
+ node.ref_kinds = kRef1RelMask | kRef1ReadMask;
break;
case AddrMode::kD8PCXiAddr:
break;
@@ -603,12 +603,35 @@ static size_t disasm_move_movea(
? OpSize::kByte : (opsize_raw == 3 ? OpSize::kWord : OpSize::kLong);
const auto src = FetchArg(
node.offset + kInstructionSizeStepBytes, code, instr, opsize);
- if (src.mode == AddrMode::kInvalid) {
- return disasm_verbatim(node, instr);
- }
- if (opsize == OpSize::kByte && src.mode == AddrMode::kAn) {
- // Does not exist
+ switch (src.mode) {
+ case AddrMode::kInvalid:
return disasm_verbatim(node, instr);
+ case AddrMode::kDn:
+ break;
+ case AddrMode::kAn:
+ if (opsize == OpSize::kByte) {
+ // Does not exist
+ return disasm_verbatim(node, instr);
+ }
+ case AddrMode::kAnAddr:
+ case AddrMode::kAnAddrIncr:
+ case AddrMode::kAnAddrDecr:
+ case AddrMode::kD16AnAddr:
+ case AddrMode::kD8AnXiAddr:
+ break;
+ case AddrMode::kWord:
+ case AddrMode::kLong:
+ node.ref1_addr = static_cast<uint32_t>(src.lword);
+ node.ref_kinds |= kRef1AbsMask | kRef1ReadMask;
+ break;
+ case AddrMode::kD16PCAddr:
+ node.ref1_addr = node.offset + kInstructionSizeStepBytes +
+ static_cast<uint32_t>(src.d16_pc.d16);
+ node.ref_kinds |= kRef1RelMask | kRef1ReadMask;
+ break;
+ case AddrMode::kD8PCXiAddr:
+ case AddrMode::kImmediate:
+ break;
}
const int m = (instr >> 6) & 7;
const int xn = (instr >> 9) & 7;
@@ -629,8 +652,11 @@ static size_t disasm_move_movea(
case AddrMode::kAnAddrDecr:
case AddrMode::kD16AnAddr:
case AddrMode::kD8AnXiAddr:
+ break;
case AddrMode::kWord:
case AddrMode::kLong:
+ node.ref2_addr = static_cast<uint32_t>(dst.lword);
+ node.ref_kinds |= kRef2AbsMask | kRef2WriteMask;
break;
case AddrMode::kD16PCAddr:
case AddrMode::kD8PCXiAddr:
diff --git a/main.cpp b/main.cpp
index 3a4e34a..4f10d03 100644
--- a/main.cpp
+++ b/main.cpp
@@ -28,6 +28,12 @@ class DisasmMap {
DisasmNode *_map[kDisasmMapSizeElements]{};
DisasmNode *findNodeByOffset(uint32_t offset) const;
DisasmNode *insertTracedNode(uint32_t offset, TracedNodeType);
+ void insertReferencedBy(
+ const uint32_t by_addr,
+ const uint32_t ref_addr,
+ const TracedNodeType type,
+ const DataBuffer &code,
+ const ReferenceType ref_type);
bool canBeAllocated(const DisasmNode& node) const;
public:
const DisasmNode *FindNodeByOffset(uint32_t offset) const
@@ -78,6 +84,27 @@ DisasmNode *DisasmMap::insertTracedNode(const uint32_t offset, const TracedNodeT
return node;
}
+void DisasmMap::insertReferencedBy(
+ const uint32_t by_addr,
+ const uint32_t ref_addr,
+ const TracedNodeType type,
+ const DataBuffer &code,
+ const ReferenceType ref_type)
+{
+ auto *const ref_node = insertTracedNode(ref_addr, type);
+ const auto size = ref_node->Disasm(code);
+ assert(size >= kInstructionSizeStepBytes);
+ if (canBeAllocated(*ref_node)) {
+ // Spread across the size
+ for (size_t o = kInstructionSizeStepBytes; o < size; o++) {
+ _map[(ref_node->offset + o) / kInstructionSizeStepBytes] = ref_node;
+ }
+ } else {
+ ref_node->DisasmAsRaw(code);
+ }
+ ref_node->AddReferencedBy(by_addr, ref_type);
+}
+
bool DisasmMap::canBeAllocated(const DisasmNode& node) const
{
const auto size = node.size / kInstructionSizeStepBytes;
@@ -91,6 +118,28 @@ bool DisasmMap::canBeAllocated(const DisasmNode& node) const
return true;
}
+static ReferenceType ReferenceTypeFromRefKindMask1(const RefKindMask ref_kinds)
+{
+ return (ref_kinds & kRefCallMask)
+ ? ReferenceType::kCall
+ : (ref_kinds & kRef1ReadMask)
+ ? ReferenceType::kRead
+ : (ref_kinds & kRef1WriteMask)
+ ? ReferenceType::kWrite
+ : ReferenceType::kBranch;
+}
+
+static ReferenceType ReferenceTypeFromRefKindMask2(const RefKindMask ref_kinds)
+{
+ return (ref_kinds & kRefCallMask)
+ ? ReferenceType::kCall
+ : (ref_kinds & kRef2ReadMask)
+ ? ReferenceType::kRead
+ : (ref_kinds & kRef2WriteMask)
+ ? ReferenceType::kWrite
+ : ReferenceType::kBranch;
+}
+
void DisasmMap::Disasm(const DataBuffer &code, const Settings &)
{
DisasmNode *node;
@@ -115,32 +164,21 @@ void DisasmMap::Disasm(const DataBuffer &code, const Settings &)
node->DisasmAsRaw(code);
}
// FIXME implement deep graph walk for DisasmMapType::kTraced case
- const bool has_code_ref =
- ((node->ref_kinds & kRef1Mask) && node->ref1_addr < code.occupied_size) ||
+ const bool has_code_ref1 =
+ ((node->ref_kinds & kRef1Mask) && node->ref1_addr < code.occupied_size);
+ if (has_code_ref1) {
+ const TracedNodeType type = (node->ref_kinds & (kRef1ReadMask | kRef1WriteMask))
+ ? TracedNodeType::kData : TracedNodeType::kInstruction;
+ const auto ref_type = ReferenceTypeFromRefKindMask1(node->ref_kinds);
+ insertReferencedBy(node->offset, node->ref1_addr, type, code, ref_type);
+ }
+ const bool has_code_ref2 =
((node->ref_kinds & kRef2Mask) && node->ref2_addr < code.occupied_size);
- if (has_code_ref) {
- const uint32_t ref_addr = (node->ref_kinds & kRef1Mask) ? node->ref1_addr : node->ref2_addr;
- const TracedNodeType type = (node->ref_kinds & (kRefReadMask | kRefWriteMask))
+ if (has_code_ref2) {
+ const TracedNodeType type = (node->ref_kinds & (kRef2ReadMask | kRef2WriteMask))
? TracedNodeType::kData : TracedNodeType::kInstruction;
- auto *const ref_node = insertTracedNode(ref_addr, type);
- const auto size = ref_node->Disasm(code);
- assert(size >= kInstructionSizeStepBytes);
- if (canBeAllocated(*ref_node)) {
- // Spread across the size
- for (size_t o = kInstructionSizeStepBytes; o < size; o++) {
- _map[(ref_node->offset + o) / kInstructionSizeStepBytes] = ref_node;
- }
- } else {
- ref_node->DisasmAsRaw(code);
- }
- const auto ref_type = (node->ref_kinds & kRefCallMask)
- ? ReferenceType::kCall
- : (node->ref_kinds & kRefReadMask)
- ? ReferenceType::kRead
- : (node->ref_kinds & kRefWriteMask)
- ? ReferenceType::kWrite
- : ReferenceType::kBranch;
- ref_node->AddReferencedBy(node->offset, ref_type);
+ const auto ref_type = ReferenceTypeFromRefKindMask2(node->ref_kinds);
+ insertReferencedBy(node->offset, node->ref2_addr, type, code, ref_type);
}
i += node->size;
}
@@ -255,8 +293,14 @@ static void RenderDisassembly(
const uint32_t ref2_addr = (with_ref && ref2) ? ref2->offset : 0;
if (with_ref && (ref1 || ref2)) {
const RefKindMask ref_kinds =
- ((s.abs_marks ? (node->ref_kinds & kRefAbsMask) : 0) |
- (s.rel_marks ? (node->ref_kinds & kRefRelMask) : 0));
+ (s.abs_marks
+ ? ((ref1 ? (node->ref_kinds & kRef1AbsMask) : 0) |
+ (ref2 ? (node->ref_kinds & kRef2AbsMask) : 0))
+ : 0) |
+ (s.rel_marks
+ ? ((ref1 ? (node->ref_kinds & kRef1RelMask) : 0) |
+ (ref2 ? (node->ref_kinds & kRef2RelMask) : 0))
+ : 0);
node->op.FPrint(output, ref_kinds, node->offset, ref1_addr, ref2_addr);
if (s.xrefs_to && ref1) {
char ref_addr_str[12]{};
diff --git a/test.bash b/test.bash
index 7de13cf..2bbb5dc 100644
--- a/test.bash
+++ b/test.bash
@@ -117,7 +117,7 @@ run_test_simple "cmpb (An)+, Dn" "\xb4\x19"
run_test_simple "cmpb -(An), Dn" "\xb4\x21"
run_test_simple "cmpl (d8,PC,An), Dn" "\xb0\xbb\x88\xff"
run_test_simple "cmpw (xxx).W, Dn" "\xb0\x78\x88\xff"
-# GNU AS would emit CMPI for "cmp #imm,Xn", so we diassemble it as short
+# GNU AS would emit CMPI for "cmp #imm,Xn", so we disassemble it as short
run_test_expect_short "cmpl #imm, D6" "\xb6\xbc\x44\xd1\xe6\xe9"
# bxxx cmpa
@@ -172,7 +172,7 @@ run_test_simple "andb (An), Dn" "\xc4\x11"
run_test_simple "andb (An)+, Dn" "\xc4\x19"
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
+# GNU AS would emit ANDI for "and #imm,Xn", so we disassemble it as short
run_test_expect_short "andl #imm, D6" "\xc6\xbc\x44\xd1\xe6\xe9"
# cxxx abcd
@@ -194,7 +194,7 @@ run_test_simple "orb (An), Dn" "\x84\x11"
run_test_simple "orb (An)+, Dn" "\x84\x19"
run_test_simple "orw -(An), Dn" "\x84\x61"
run_test_simple "orl (d8,PC,An), Dn" "\x80\xbb\x88\x07"
-# GNU AS would emit ORI for "or #imm,Xn", so we diassemble it as short
+# GNU AS would emit ORI for "or #imm,Xn", so we disassemble it as short
run_test_expect_short "orl #imm, D6" "\x86\xbc\x44\xd1\xe6\xe9"
run_test_expect_short "orl D2, D0 swapped direction" "\x81\x42"
@@ -261,7 +261,7 @@ run_test_simple "subw An, Dn" "\x94\x49"
run_test_simple "subb (An), Dn" "\x94\x11"
run_test_simple "subb (An)+, Dn" "\x94\x19"
run_test_simple "subb -(An), Dn" "\x94\x21"
-# GNU AS would emit SUBQ for "sub #imm,Xn", so we diassemble it as short
+# GNU AS would emit SUBQ for "sub #imm,Xn", so we disassemble it as short
run_test_expect_short "subl #imm, D6" "\x96\xbc\x44\xd1\xe6\xe9"
# dxxx addx
@@ -290,7 +290,7 @@ run_test_simple "addb (An), Dn" "\xd4\x11"
run_test_simple "addb (An)+, Dn" "\xd4\x19"
run_test_simple "addb -(An), Dn" "\xd4\x21"
run_test_simple "addl (d8,PC,An), Dn" "\xd0\xbb\x88\xff"
-# GNU AS would emit ADDI for "add #imm,Xn", so we diassemble it as short
+# GNU AS would emit ADDI for "add #imm,Xn", so we disassemble it as short
run_test_expect_short "addl #imm, D6" "\xd6\xbc\x44\xd1\xe6\xe9"
# 4xxx chkw
@@ -412,13 +412,10 @@ run_test_simple "moveq #127 to D7" "\x7e\x7f"
run_test_simple "moveq #-1 to D5" "\x7a\xff"
run_test_simple "moveq #-128 to D1" "\x72\x80"
-# From random tests
-#
-run_test_simple "movel %pc@(-16,%a0:l),%a3@+ with nop" "\x26\xfb\x88\xf0\x4e\x71"
-
# 1xxx [xxxx [xxxx]]
#
run_test_simple "moveb Dn to Dn" "\x10\x01"
+run_test_expect_short "moveb An to Dn" "\x10\x09"
run_test_simple "moveb (An) to Dn" "\x10\x11"
run_test_simple "moveb (An)+ to Dn" "\x10\x19"
run_test_simple "moveb -(An) to Dn" "\x10\x21"
@@ -464,6 +461,10 @@ run_test_simple "movel #imm to Dn" "\x24\x3c\xa8\x90\x00\x00"
run_test_simple "moveal Dn" "\x20\x41"
run_test_simple "moveal #imm" "\x20\x7c\xa8\x90\x00\x00"
+# From random tests
+#
+run_test_simple "movel %pc@(-16,%a0:l),%a3@+ with nop" "\x26\xfb\x88\xf0\x4e\x71"
+
# 4890 xxx
#
run_test_simple "movemw single register to (An)" "\x48\x90\x00\x01"
diff --git a/test_marks_referencing.bash b/test_marks_referencing.bash
index a5aaa67..237db1e 100644
--- a/test_marks_referencing.bash
+++ b/test_marks_referencing.bash
@@ -92,3 +92,4 @@ run_test_rdisp "braw .+2" "\x4e\x71\x60\x00\x00\x00"
run_test_rword "moveml 0x0:w,%d0" "\x4c\xf8\x00\x01\x00\x00"
run_test_rword "moveml 0x6:w,%a0" "\x4c\xf8\x01\x00\x00\x06\x4e\x71\x4e\x71"
run_test_rword "movemw 0x0:l,%a0" "\x4e\x71\x4e\x71\x4c\xb9\x01\x00\x00\x00\x00\x02"
+run_test_rword "movew 0x0:w,0x2:w" "\x4e\x75\x4e\x76\x31\xf8\x00\x00\x00\x02"
diff --git a/test_random.bash b/test_random.bash
index a6e6d9d..094dad1 100644
--- a/test_random.bash
+++ b/test_random.bash
@@ -7,7 +7,7 @@
AS=m68k-none-elf-as
OBJCOPY=m68k-none-elf-objcopy
LD="m68k-none-elf-ld -Ttest.ld"
-DISASM="./cmake-build/m68k-disasm -fabs-marks -frel-marks -fmarks"
+DISASM="./cmake-build/m68k-disasm -fabs-marks -frel-marks -fmarks -frdc"
TEST_DIR=/tmp/m68k-disasm-random-tests
set -e