summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOxore <oxore@protonmail.com>2023-04-23 00:27:58 +0300
committerOxore <oxore@protonmail.com>2023-04-23 00:35:30 +0300
commit771b675f2ec83c1b6b2d41d236fc4bd3c368b1cd (patch)
tree14d83b3b84b1edc218018c8eea9a49fefe15282d
parent8b874f105d52a461942bbb8960d0f729c0865507 (diff)
Pass settings everywhere, impl cross references
-rw-r--r--common.h4
-rw-r--r--disasm.cpp89
-rw-r--r--disasm.h41
-rw-r--r--main.cpp69
4 files changed, 149 insertions, 54 deletions
diff --git a/common.h b/common.h
index 315946f..5988a29 100644
--- a/common.h
+++ b/common.h
@@ -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]);
}
-
diff --git a/disasm.cpp b/disasm.cpp
index 0a0130c..ae44972 100644
--- a/disasm.cpp
+++ b/disasm.cpp
@@ -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;
+ }
}
diff --git a/disasm.h b/disasm.h
index a332cd9..f8820ef 100644
--- a/disasm.h
+++ b/disasm.h
@@ -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:
};
diff --git a/main.cpp b/main.cpp
index e8ceca9..f84c55e 100644
--- a/main.cpp
+++ b/main.cpp
@@ -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);
}