diff options
author | Oxore <oxore@protonmail.com> | 2023-04-23 00:27:58 +0300 |
---|---|---|
committer | Oxore <oxore@protonmail.com> | 2023-04-23 00:35:30 +0300 |
commit | 771b675f2ec83c1b6b2d41d236fc4bd3c368b1cd (patch) | |
tree | 14d83b3b84b1edc218018c8eea9a49fefe15282d | |
parent | 8b874f105d52a461942bbb8960d0f729c0865507 (diff) |
Pass settings everywhere, impl cross references
-rw-r--r-- | common.h | 4 | ||||
-rw-r--r-- | disasm.cpp | 89 | ||||
-rw-r--r-- | disasm.h | 41 | ||||
-rw-r--r-- | main.cpp | 69 |
4 files changed, 149 insertions, 54 deletions
@@ -1,5 +1,8 @@ #pragma once +struct Settings { +}; + constexpr size_t kInstructionSizeStepBytes = 2; constexpr size_t kRomSizeBytes = 4 * 1024 * 1024; constexpr size_t kDisasmMapSizeElements = kRomSizeBytes / kInstructionSizeStepBytes; @@ -23,4 +26,3 @@ static inline int32_t GetI32BE(uint8_t *buffer) (static_cast<uint32_t>(buffer[2]) << 8) | static_cast<uint32_t>(buffer[3]); } - @@ -7,7 +7,7 @@ #include <cstdlib> static void disasm_verbatim( - DisasmNode& node, uint16_t instr, uint32_t, const DataBuffer &) + DisasmNode& node, uint16_t instr, const DataBuffer &, const Settings &) { node.size = kInstructionSizeStepBytes; snprintf(node.mnemonic, kMnemonicBufferSize, ".short"); @@ -15,7 +15,7 @@ static void disasm_verbatim( } static void disasm_mfff0_v4e70( - DisasmNode& node, uint16_t instr, uint32_t offset, const DataBuffer &code) + DisasmNode& node, uint16_t instr, const DataBuffer &code, const Settings &s) { node.size = kInstructionSizeStepBytes; if (instr == 0x4e70) { @@ -31,7 +31,7 @@ static void disasm_mfff0_v4e70( } else if (instr == 0x4e77) { snprintf(node.mnemonic, kMnemonicBufferSize, "rtr"); } else { - disasm_verbatim(node, instr, offset, code); + disasm_verbatim(node, instr, code, s); } } @@ -41,7 +41,7 @@ enum class JsrJmp { }; static void disasm_jsr_jmp( - DisasmNode& node, uint16_t instr, uint32_t offset, const DataBuffer & code, JsrJmp jsrjmp) + DisasmNode& node, uint16_t instr, const DataBuffer &code, const Settings &s, JsrJmp jsrjmp) { const char *mnemonic = (jsrjmp == JsrJmp::kJsr) ? "jsr" : "jmp"; const int addrmode = instr & 0x3f; @@ -62,7 +62,7 @@ static void disasm_jsr_jmp( case 5: // 4ea8 .. 4eaf, Displacement { node.size = kInstructionSizeStepBytes * 2; - const int16_t dispmt = GetI16BE(code.buffer + offset + kInstructionSizeStepBytes); + const int16_t dispmt = GetI16BE(code.buffer + node.offset + kInstructionSizeStepBytes); snprintf(node.mnemonic, kMnemonicBufferSize, "%s", mnemonic); snprintf(node.arguments, kArgsBufferSize, "%%a%d@(%d:w)", xn, dispmt); return; @@ -70,7 +70,7 @@ static void disasm_jsr_jmp( case 6: // 4eb0 .. 4eb7, Brief Extension Word { node.size = kInstructionSizeStepBytes * 2; - const uint16_t briefext = GetU16BE(code.buffer + offset + kInstructionSizeStepBytes); + const uint16_t briefext = GetU16BE(code.buffer + node.offset + kInstructionSizeStepBytes); const char reg = ((briefext >> 15) & 1) ? 'a' : 'd'; const int xn2 = (briefext >> 12) & 7; const char size_spec = ((briefext >> 11) & 1) ? 'l' : 'w'; @@ -84,8 +84,9 @@ static void disasm_jsr_jmp( switch (xn) { case 0: // 4eb8 (xxx).W { + // TODO set has_branch_addr and branch_addr node.size = kInstructionSizeStepBytes * 2; - const int32_t dispmt = GetI16BE(code.buffer + offset + kInstructionSizeStepBytes); + const int32_t dispmt = GetI16BE(code.buffer + node.offset + kInstructionSizeStepBytes); snprintf(node.mnemonic, kMnemonicBufferSize, "%s", mnemonic); snprintf(node.arguments, kArgsBufferSize, "0x%x:w", dispmt); return; @@ -93,7 +94,7 @@ static void disasm_jsr_jmp( case 1: // 4eb9 (xxx).L { node.size = kInstructionSizeStepBytes * 3; - const int32_t dispmt = GetI32BE(code.buffer + offset + kInstructionSizeStepBytes); + const int32_t dispmt = GetI32BE(code.buffer + node.offset + kInstructionSizeStepBytes); snprintf(node.mnemonic, kMnemonicBufferSize, "%s", mnemonic); snprintf(node.arguments, kArgsBufferSize, "0x%x:l", dispmt); return; @@ -101,7 +102,7 @@ static void disasm_jsr_jmp( case 2: // 4eba, Displacement { node.size = kInstructionSizeStepBytes * 2; - const int16_t dispmt = GetI16BE(code.buffer + offset + kInstructionSizeStepBytes); + const int16_t dispmt = GetI16BE(code.buffer + node.offset + kInstructionSizeStepBytes); snprintf(node.mnemonic, kMnemonicBufferSize, "%s", mnemonic); snprintf(node.arguments, kArgsBufferSize, "%%pc@(%d:w)", dispmt); return; @@ -110,7 +111,7 @@ static void disasm_jsr_jmp( { node.size = kInstructionSizeStepBytes * 2; const uint16_t briefext = GetU16BE( - code.buffer + offset + kInstructionSizeStepBytes); + code.buffer + node.offset + kInstructionSizeStepBytes); const char reg = ((briefext >> 15) & 1) ? 'a' : 'd'; const int xn2 = (briefext >> 12) & 7; const char size_spec = ((briefext >> 11) & 1) ? 'l' : 'w'; @@ -127,19 +128,19 @@ static void disasm_jsr_jmp( } break; } - return disasm_verbatim(node, instr, offset, code); + return disasm_verbatim(node, instr, code, s); } static void disasm_jsr( - DisasmNode& node, uint16_t instr, uint32_t offset, const DataBuffer & code) + DisasmNode& node, uint16_t instr, const DataBuffer &code, const Settings &s) { - return disasm_jsr_jmp(node, instr, offset, code, JsrJmp::kJsr); + return disasm_jsr_jmp(node, instr, code, s, JsrJmp::kJsr); } static void disasm_jmp( - DisasmNode& node, uint16_t instr, uint32_t offset, const DataBuffer & code) + DisasmNode& node, uint16_t instr, const DataBuffer &code, const Settings &s) { - return disasm_jsr_jmp(node, instr, offset, code, JsrJmp::kJmp); + return disasm_jsr_jmp(node, instr, code, s, JsrJmp::kJmp); } enum class Condition { @@ -185,19 +186,21 @@ static inline const char *branch_instr_name_by_cond(Condition condition) } static void disasm_bra_bsr_bcc( - DisasmNode& node, uint16_t instr, uint32_t offset, const DataBuffer & code) + DisasmNode& node, uint16_t instr, const DataBuffer &code, const Settings &) { const char *mnemonic = branch_instr_name_by_cond(static_cast<Condition>((instr >> 8) & 0xf)); int dispmt = static_cast<int8_t>(instr & 0xff); const char *size_spec = "s"; if (dispmt == 0) { - dispmt = GetI16BE(code.buffer + offset + kInstructionSizeStepBytes); + dispmt = GetI16BE(code.buffer + node.offset + kInstructionSizeStepBytes); node.size = kInstructionSizeStepBytes * 2; size_spec = "w"; } else { node.size = kInstructionSizeStepBytes; } dispmt += kInstructionSizeStepBytes; + node.branch_addr = node.offset + dispmt; + node.has_branch_addr = true; const char * const sign = dispmt >= 0 ? "+" : ""; snprintf(node.mnemonic, kMnemonicBufferSize, "%s%s", mnemonic, size_spec); snprintf(node.arguments, kArgsBufferSize, ".%s%d", sign, dispmt); @@ -205,24 +208,60 @@ static void disasm_bra_bsr_bcc( } static void m68k_disasm( - DisasmNode& node, uint16_t instr, uint32_t offset, const DataBuffer &code) + DisasmNode& node, uint16_t instr, const DataBuffer &code, const Settings &s) { if ((instr & 0xfff0) == 0x4e70) { - return disasm_mfff0_v4e70(node, instr, offset, code); + return disasm_mfff0_v4e70(node, instr, code, s); } else if ((instr & 0xffc0) == 0x4e80) { - return disasm_jsr(node, instr, offset, code); + return disasm_jsr(node, instr, code, s); } else if ((instr & 0xffc0) == 0x4ec0) { - return disasm_jmp(node, instr, offset, code); + return disasm_jmp(node, instr, code, s); } else if ((instr & 0xf000) == 0x6000) { - return disasm_bra_bsr_bcc(node, instr, offset, code); + return disasm_bra_bsr_bcc(node, instr, code, s); } - return disasm_verbatim(node, instr, offset, code); + return disasm_verbatim(node, instr, code, s); } -void DisasmNode::Disasm(const DataBuffer &code) +void DisasmNode::Disasm(const DataBuffer &code, const Settings &s) { // We assume that no MMU and ROM is always starts with 0 assert(this->offset < code.occupied_size); + // It is possible to have multiple DisasmNode::Disasm() calls, and there is + // no point to disassemble it again if it already has mnemonic determined + if (this->mnemonic[0] != '\0') { + return; + } const uint16_t instr = GetU16BE(code.buffer + this->offset); - m68k_disasm(*this, instr, this->offset, code); + m68k_disasm(*this, instr, code, s); +} + + +void DisasmNode::AddReferencedBy(uint32_t offset) +{ + ReferenceNode *node{}; + if (this->last_ref_by) { + node = this->last_ref_by; + } else { + node = new ReferenceNode{}; + assert(node); + this->ref_by = this->last_ref_by = node; + } + node->refs[node->refs_count] = offset; + node->refs_count++; + if (node->refs_count >= kRefsCountPerBuffer) { + ReferenceNode *new_node = new ReferenceNode{}; + assert(new_node); + node->next = new_node; + this->last_ref_by = new_node; + } +} + +DisasmNode::~DisasmNode() +{ + ReferenceNode *ref{this->ref_by}; + while (ref) { + ReferenceNode *prev = ref; + ref = ref->next; + delete prev; + } } @@ -11,16 +11,39 @@ enum class TracedNodeType { kData, }; -constexpr size_t kMnemonicBufferSize{10}; -constexpr size_t kArgsBufferSize{50}; +constexpr size_t kRefsCountPerBuffer = 10; + +constexpr size_t kMnemonicBufferSize = 8; +constexpr size_t kArgsBufferSize = 64; +constexpr size_t kMarkBufferSize = 64; + +struct ReferenceNode { + ReferenceNode *next{}; + uint32_t refs[kRefsCountPerBuffer]; + uint32_t refs_count{}; +}; struct DisasmNode { - TracedNodeType type{}; - uint32_t offset{}; - size_t size{kInstructionSizeStepBytes}; // Instruction size in bytes + const TracedNodeType type{}; + /// Absolute offset of the instruction (PC value basically) + const uint32_t offset{}; + /// Instruction size in bytes + size_t size{kInstructionSizeStepBytes}; + /// Indicates whether `branch_addr` should be interpreted bool has_branch_addr{}; - uint32_t branch_addr{}; // Absolute address of where to branch to - char mnemonic[kMnemonicBufferSize]{}; // Mnemonic of the instruction at the current offset - char arguments[kArgsBufferSize]{}; // Formatted arguments of the instruction - void Disasm(const DataBuffer &code); + /// Absolute address of where to branch to + uint32_t branch_addr{}; + /// Mnemonic of the instruction at the current offset + char mnemonic[kMnemonicBufferSize]{}; + /// Formatted arguments of the instruction; + char arguments[kArgsBufferSize]{}; + /// Additional instruction specific info to put in a comment + char additional[kArgsBufferSize]{}; + /// Additional instruction specific info to put in a comment + ReferenceNode *ref_by{}; + ReferenceNode *last_ref_by{}; + void Disasm(const DataBuffer &code, const Settings&); + void AddReferencedBy(uint32_t offset); + ~DisasmNode(); +private: }; @@ -34,6 +34,7 @@ class DisasmMap { DisasmNode *_map[kDisasmMapSizeElements]{}; DisasmNode *findNodeByOffset(uint32_t offset) const; + DisasmNode *insertTracedNode(uint32_t offset, TracedNodeType); public: const DisasmNode *FindNodeByOffset(uint32_t offset) const { @@ -41,9 +42,12 @@ public: }; // Returns true if node inserted, false if node already exist and has not // been changed - bool InsertTracedNode(uint32_t offset, TracedNodeType); + bool InsertTracedNode(uint32_t offset, TracedNodeType type) + { + return nullptr != insertTracedNode(offset, type); + } // This function disassembles everything that has been traced - void DisasmAll(const DataBuffer &code); + void DisasmAll(const DataBuffer &code, const Settings &); ~DisasmMap(); }; @@ -54,22 +58,31 @@ DisasmNode *DisasmMap::findNodeByOffset(uint32_t offset) const return nullptr; } -bool DisasmMap::InsertTracedNode(uint32_t offset, TracedNodeType type) +DisasmNode *DisasmMap::insertTracedNode(uint32_t offset, TracedNodeType type) { - if (findNodeByOffset(offset)) - return false; - auto *node = new DisasmNode(DisasmNode{type, offset}); + auto *node = findNodeByOffset(offset); + if (node) { + return node; + } + node = new DisasmNode(DisasmNode{type, offset}); assert(node); _map[offset / kInstructionSizeStepBytes] = node; - return true; + return node; } -void DisasmMap::DisasmAll(const DataBuffer &code) +void DisasmMap::DisasmAll(const DataBuffer &code, const Settings & s) { for (size_t i = 0; i < kDisasmMapSizeElements; i++) { auto *node = _map[i]; - if (node) { - _map[i]->Disasm(code); + if (!node) { + continue; + } + node->Disasm(code, s); + if (node->has_branch_addr && node->branch_addr < code.occupied_size) { + auto *ref_node = insertTracedNode( + node->branch_addr, TracedNodeType::kInstruction); + ref_node->Disasm(code, s); + ref_node->AddReferencedBy(node->offset); } } } @@ -85,7 +98,7 @@ DisasmMap::~DisasmMap() static size_t RenderRawDataComment( char *out, size_t out_sz, uint32_t offset, size_t instr_sz, const DataBuffer &code) { - size_t overall_sz = Min(out_sz, snprintf(out, out_sz, " |")); + size_t overall_sz{}; for (size_t i = 0; i < instr_sz; i += kInstructionSizeStepBytes) { overall_sz += Min( @@ -102,14 +115,31 @@ static size_t RenderRawDataComment( return overall_sz; } -static void RenderDisassembly(FILE *output, const DisasmMap &disasm_map, const DataBuffer &code) +static void RenderDisassembly( + FILE *output, const DisasmMap &disasm_map, const DataBuffer &code, const Settings &) { for (size_t i = 0; i < code.occupied_size;) { const DisasmNode *node = disasm_map.FindNodeByOffset(i); if (node) { char comment[100]{}; RenderRawDataComment(comment, sizeof(comment) - 1, node->offset, node->size, code); - fprintf(output, " %s %s%s\n", node->mnemonic, node->arguments, comment); + if (node->ref_by) { + fprintf(output, "| Referenced by:\n"); + for (ReferenceNode *ref{node->ref_by}; ref; ref = ref->next) { + fprintf(output, "|"); + for (size_t i = 0; i < ref->refs_count; i++) { + fprintf(output, " @%08x", ref->refs[i]); + } + fprintf(output, "\n"); + } + fprintf(output, ".L%08x:\n", node->offset); + } + char branch_addr[12]{}; + if (node->has_branch_addr) { + snprintf(branch_addr, sizeof(branch_addr), " .L%08x", node->branch_addr); + } + const char *const delimiter = node->arguments[0] != '\0' ? " " : ""; + fprintf(output, " %s%s%s |%s%s\n", node->mnemonic, delimiter, node->arguments, branch_addr, comment); i += node->size; } else { fprintf(output, " .short 0x%02x%02x\n", code.buffer[i], code.buffer[i + 1]); @@ -175,7 +205,7 @@ static size_t ReadFromStream(DataBuffer &db, FILE *stream) return db.occupied_size; } -static int M68kDisasmByTrace(FILE *input_stream, FILE *output_stream, FILE *trace_stream) +static int M68kDisasmByTrace(FILE *input_stream, FILE *output_stream, FILE *trace_stream, const Settings &s) { // Read machine code into buffer DataBuffer code{}; @@ -202,14 +232,14 @@ static int M68kDisasmByTrace(FILE *input_stream, FILE *output_stream, FILE *trac assert(disasm_map); ParseTraceData(*disasm_map, trace_data); // Disasm into output map - disasm_map->DisasmAll(code); + disasm_map->DisasmAll(code, s); // Print output into output_stream - RenderDisassembly(output_stream, *disasm_map, code); + RenderDisassembly(output_stream, *disasm_map, code, s); delete disasm_map; return 0; } -static int M68kDisasmAll(FILE *input_stream, FILE *output_stream) +static int M68kDisasmAll(FILE *input_stream, FILE *output_stream, const Settings &) { uint8_t instruction[kInstructionSizeStepBytes]{}; const size_t read_size = kInstructionSizeStepBytes; @@ -308,10 +338,11 @@ int main(int, char* argv[]) return EXIT_FAILURE; } } + Settings s{}; // Run the program const int ret = trace_stream - ? M68kDisasmByTrace(input_stream, output_stream, trace_stream) - : M68kDisasmAll(input_stream, output_stream); + ? M68kDisasmByTrace(input_stream, output_stream, trace_stream, s) + : M68kDisasmAll(input_stream, output_stream, s); if (trace_stream != nullptr) { fclose(trace_stream); } |