diff options
author | Oxore <oxore@protonmail.com> | 2023-05-20 16:41:59 +0300 |
---|---|---|
committer | Oxore <oxore@protonmail.com> | 2023-05-20 16:41:59 +0300 |
commit | 429d978d108dfb77665f0c03a7190e2754c8fa1f (patch) | |
tree | 057c0eb090a7f9592c91ba9778795034e06bcd0f | |
parent | d9136afc4a89ad26663e18afd61683dd9dae523f (diff) |
Impl marks referencing for MOVE and MOVEA
-rw-r--r-- | common.h | 12 | ||||
-rw-r--r-- | disasm.cpp | 46 | ||||
-rw-r--r-- | main.cpp | 96 | ||||
-rw-r--r-- | test.bash | 19 | ||||
-rw-r--r-- | test_marks_referencing.bash | 1 | ||||
-rw-r--r-- | test_random.bash | 2 |
6 files changed, 127 insertions, 49 deletions
@@ -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; @@ -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: @@ -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]{}; @@ -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 |