summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common.h18
-rw-r--r--disasm.cpp61
-rw-r--r--disasm.h22
-rw-r--r--main.cpp61
4 files changed, 108 insertions, 54 deletions
diff --git a/common.h b/common.h
index aa48b81..65f7648 100644
--- a/common.h
+++ b/common.h
@@ -12,8 +12,22 @@ struct Settings {
bool raw_data_comment{};
};
-constexpr unsigned kRefRelMask = 1;
-constexpr unsigned kRefAbsMask = 2;
+using RefKindMask = unsigned;
+
+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
+/// 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 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 kRefDataMask = kRefReadMask | kRefWriteMask;
constexpr size_t kInstructionSizeStepBytes = 2;
constexpr size_t kRomSizeBytes = 4 * 1024 * 1024;
constexpr size_t kDisasmMapSizeElements = kRomSizeBytes / kInstructionSizeStepBytes;
diff --git a/disasm.cpp b/disasm.cpp
index e5ec421..a5223c7 100644
--- a/disasm.cpp
+++ b/disasm.cpp
@@ -178,23 +178,23 @@ static size_t disasm_jsr_jmp(
case AddrMode::kWord: // 4eb8 / 4ef8
{
const uint32_t ref_addr = static_cast<uint32_t>(a.lword);
- node.ref_addr = ref_addr;
- node.has_ref = true;
+ node.ref1_addr = ref_addr;
+ node.ref_kinds = kRef1AbsMask;
}
break;
case AddrMode::kLong: // 4eb9 / 4ef9
{
const uint32_t ref_addr = static_cast<uint32_t>(a.lword);
- node.ref_addr = ref_addr;
- node.has_ref = true;
+ node.ref1_addr = ref_addr;
+ node.ref_kinds = kRef1AbsMask;
}
break;
case AddrMode::kD16PCAddr: // 4eba / 4efa
{
const uint32_t ref_addr = node.offset + kInstructionSizeStepBytes +
static_cast<uint32_t>(a.d16_pc.d16);
- node.ref_addr = ref_addr;
- node.has_ref = true;
+ node.ref1_addr = ref_addr;
+ node.ref_kinds = kRef1RelMask;
}
break;
case AddrMode::kD8PCXiAddr: // 4ebb / 4efb
@@ -205,7 +205,7 @@ static size_t disasm_jsr_jmp(
return disasm_verbatim(node, instr);
}
const bool is_jmp = instr & 0x40;
- node.is_call = !is_jmp;
+ node.ref_kinds |= is_jmp ? 0 : kRefCallMask;
node.op = Op::Typical(is_jmp ? OpCode::kJMP : OpCode::kJSR, OpSize::kNone, a);
return node.size = kInstructionSizeStepBytes + a.Size(opsize);
}
@@ -299,9 +299,17 @@ static size_t disasm_lea(
return disasm_verbatim(node, instr);
case AddrMode::kD16AnAddr:
case AddrMode::kD8AnXiAddr:
+ break;
case AddrMode::kWord:
case AddrMode::kLong:
+ node.ref1_addr = static_cast<uint32_t>(addr.lword);
+ node.ref_kinds = kRef1AbsMask | kRefReadMask;
+ break;
case AddrMode::kD16PCAddr:
+ node.ref1_addr = node.offset + kInstructionSizeStepBytes +
+ static_cast<uint32_t>(addr.d16_pc.d16);
+ node.ref_kinds = kRef1RelMask | kRefReadMask;
+ break;
case AddrMode::kD8PCXiAddr:
break;
case AddrMode::kImmediate:
@@ -369,9 +377,8 @@ static size_t disasm_bra_bsr_bcc(
const uint32_t ref_addr = static_cast<uint32_t>(node.offset + dispmt);
Condition condition = static_cast<Condition>((instr >> 8) & 0xf);
// False condition Indicates BSR
- node.is_call = (condition == Condition::kF);
- node.ref_addr = ref_addr;
- node.has_ref = true;
+ node.ref1_addr = ref_addr;
+ node.ref_kinds = kRef1RelMask | ((condition == Condition::kF) ? kRefCallMask : 0);
node.op = Op{OpCode::kBcc, opsize, condition, Arg::Displacement(dispmt)};
return node.size;
}
@@ -992,8 +999,8 @@ static size_t disasm_dbcc(DisasmNode &node, const uint16_t instr, const DataBuff
}
const int16_t dispmt_raw = GetI16BE(code.buffer + node.offset + kInstructionSizeStepBytes);
const int32_t dispmt = dispmt_raw + kInstructionSizeStepBytes;
- node.ref_addr = static_cast<uint32_t>(node.offset + dispmt);
- node.has_ref = true;
+ node.ref2_addr = static_cast<uint32_t>(node.offset + dispmt);
+ node.ref_kinds = kRef2RelMask;
node.op = Op{
OpCode::kDBcc,
OpSize::kNone,
@@ -1499,11 +1506,16 @@ size_t DisasmNode::Disasm(const DataBuffer &code)
return this->size;
}
size = kInstructionSizeStepBytes;
- has_ref = 0;
- ref_addr = 0;
- is_call = false;
+ ref_kinds = 0;
+ ref1_addr = 0;
+ ref2_addr = 0;
const uint16_t instr = GetU16BE(code.buffer + this->offset);
- return m68k_disasm(*this, instr, code);
+ if (this->type == TracedNodeType::kInstruction) {
+ return m68k_disasm(*this, instr, code);
+ } else {
+ // Data should not be disassembled
+ return disasm_verbatim(*this, instr);
+ }
}
size_t DisasmNode::DisasmAsRaw(const DataBuffer &code)
@@ -1511,9 +1523,9 @@ size_t DisasmNode::DisasmAsRaw(const DataBuffer &code)
// We assume that machine have no MMU and ROM data always starts with 0
assert(this->offset < code.occupied_size);
size = kInstructionSizeStepBytes;
- has_ref = 0;
- ref_addr = 0;
- is_call = false;
+ ref_kinds = 0;
+ ref1_addr = 0;
+ ref2_addr = 0;
const uint16_t instr = GetU16BE(code.buffer + this->offset);
return disasm_verbatim(*this, instr);
}
@@ -1735,7 +1747,7 @@ static size_t snprint_reg_mask(
int Arg::SNPrint(
char *const buf,
const size_t bufsz,
- const unsigned ref_kinds,
+ const RefKindMask ref_kinds,
const uint32_t self_addr,
const uint32_t ref_addr) const
{
@@ -1828,19 +1840,20 @@ int Arg::SNPrint(
int Op::FPrint(
FILE *const stream,
- const unsigned ref_kinds,
+ const RefKindMask ref_kinds,
const uint32_t self_addr,
- const uint32_t ref_addr) const
+ const uint32_t ref1_addr,
+ const uint32_t ref2_addr) const
{
assert(opcode != OpCode::kNone);
char mnemonic_str[kMnemonicBufferSize]{};
OpcodeSNPrintf(mnemonic_str, kMnemonicBufferSize, opcode, condition, size_spec);
if (arg1.type != ArgType::kNone) {
char arg1_str[kArgsBufferSize]{};
- arg1.SNPrint(arg1_str, kArgsBufferSize, ref_kinds, self_addr, ref_addr);
+ arg1.SNPrint(arg1_str, kArgsBufferSize, ref_kinds & kRef1Mask, self_addr, ref1_addr);
if (arg2.type != ArgType::kNone) {
char arg2_str[kArgsBufferSize]{};
- arg2.SNPrint(arg2_str, kArgsBufferSize, ref_kinds, self_addr, ref_addr);
+ arg2.SNPrint(arg2_str, kArgsBufferSize, ref_kinds & kRef2Mask, self_addr, ref2_addr);
return fprintf(stream, " %s %s,%s", mnemonic_str, arg1_str, arg2_str);
} else {
return fprintf(stream, " %s %s", mnemonic_str, arg1_str);
diff --git a/disasm.h b/disasm.h
index 925925c..1b0dd7a 100644
--- a/disasm.h
+++ b/disasm.h
@@ -297,7 +297,7 @@ struct Arg {
int SNPrint(
char *buf,
size_t bufsz,
- unsigned ref_kinds = 0,
+ RefKindMask ref_kinds = 0,
uint32_t self_addr = 0,
uint32_t ref_addr = 0) const;
};
@@ -314,8 +314,10 @@ constexpr size_t kArgsBufferSize = 80;
enum class ReferenceType {
kUnknown = 0,
- kBranch,
kCall,
+ kBranch,
+ kRead,
+ kWrite,
};
struct ReferenceRecord {
@@ -350,9 +352,10 @@ struct Op {
}
int FPrint(
FILE *,
- unsigned ref_kinds = 0,
+ RefKindMask ref_kinds = 0,
uint32_t self_addr = 0,
- uint32_t ref_addr = 0) const;
+ uint32_t ref1_addr = 0,
+ uint32_t ref2_addr = 0) const;
};
struct DisasmNode {
@@ -362,12 +365,11 @@ struct DisasmNode {
/// Instruction size in bytes
size_t size{kInstructionSizeStepBytes};
/// Indicates whether `ref_addr` should be interpreted and how
- bool has_ref{};
- /// Absolute address of where to branch to
- uint32_t ref_addr{};
- /// Indicates whether instruction is a call (BSR, JSR) or just a branch
- /// (Bcc, JMP) if `has_branch_addr` is set
- bool is_call{};
+ RefKindMask ref_kinds{};
+ /// Absolute address of reference
+ uint32_t ref1_addr{};
+ /// Absolute address of reference
+ uint32_t ref2_addr{};
ReferenceNode *ref_by{};
ReferenceNode *last_ref_by{};
Op op{};
diff --git a/main.cpp b/main.cpp
index 144b22a..1741a34 100644
--- a/main.cpp
+++ b/main.cpp
@@ -58,10 +58,16 @@ static uint32_t AlignInstructionAddress(const uint32_t offset)
return offset & ~1UL;
}
-DisasmNode *DisasmMap::insertTracedNode(uint32_t offset, TracedNodeType type)
+DisasmNode *DisasmMap::insertTracedNode(const uint32_t offset, const TracedNodeType type)
{
auto *node = findNodeByOffset(offset);
if (node) {
+ // Instruction nodes take precedence over data nodes. If a node that
+ // was previously accessed only as data now turns out to be an
+ // instruction, then it must become an instruction node.
+ if (type == TracedNodeType::kInstruction && node->type != TracedNodeType::kInstruction) {
+ *const_cast<TracedNodeType*>(&node->type) = type;
+ }
return node;
}
node = new DisasmNode(DisasmNode{type, AlignInstructionAddress(offset)});
@@ -107,9 +113,14 @@ void DisasmMap::Disasm(const DataBuffer &code, const Settings &)
node->DisasmAsRaw(code);
}
// FIXME implement deep graph walk for DisasmMapType::kTraced case
- if (node->has_ref && node->ref_addr < code.occupied_size) {
- auto *const ref_node = insertTracedNode(
- node->ref_addr, TracedNodeType::kInstruction);
+ const bool has_code_ref =
+ ((node->ref_kinds & kRef1Mask) && node->ref1_addr < code.occupied_size) ||
+ ((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))
+ ? 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)) {
@@ -120,8 +131,14 @@ void DisasmMap::Disasm(const DataBuffer &code, const Settings &)
} else {
ref_node->DisasmAsRaw(code);
}
- ref_node->AddReferencedBy(
- node->offset, node->is_call ? ReferenceType::kCall : ReferenceType::kBranch);
+ 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);
}
i += node->size;
}
@@ -167,9 +184,11 @@ static size_t RenderRawDataComment(
static const char *ReferenceTypeToString(ReferenceType type)
{
switch (type) {
- case ReferenceType::kUnknown: return "UNKN";
- case ReferenceType::kBranch: return "BRANCH";
+ case ReferenceType::kUnknown: return "UNKNOWN";
case ReferenceType::kCall: return "CALL";
+ case ReferenceType::kBranch: return "BRANCH";
+ case ReferenceType::kRead: return "READ";
+ case ReferenceType::kWrite: return "WRITE";
}
return "UNKN";
}
@@ -225,21 +244,27 @@ static void RenderDisassembly(
}
fprintf(output, "\n");
} else {
- const bool with_reference = node->has_ref && s.marks &&
- (s.abs_marks || s.rel_marks);
- const auto *referenced = disasm_map.FindNodeByOffset(node->ref_addr);
- if (with_reference && referenced) {
- const uint32_t ref_addr = referenced->offset;
- const unsigned ref_kinds = ((s.abs_marks ? kRefAbsMask : 0) |
- (s.rel_marks ? kRefRelMask : 0));
- node->op.FPrint(output, ref_kinds, node->offset, ref_addr);
+ const bool with_ref = node->ref_kinds && s.marks && (s.abs_marks || s.rel_marks);
+ const auto *ref1 = (node->ref_kinds & kRef1Mask)
+ ? disasm_map.FindNodeByOffset(node->ref1_addr) : nullptr;
+ const auto *ref2 = (node->ref_kinds & kRef2Mask)
+ ? disasm_map.FindNodeByOffset(node->ref2_addr) : nullptr;
+ const uint32_t ref1_addr = (with_ref && ref1) ? ref1->offset : 0;
+ 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));
+ node->op.FPrint(output, ref_kinds, node->offset, ref1_addr, ref2_addr);
} else {
node->op.FPrint(output);
}
}
- if (node->has_ref && s.xrefs_to) {
+ if (node->ref_kinds && s.xrefs_to) {
char ref_addr_str[12]{};
- snprintf(ref_addr_str, sizeof(ref_addr_str), " .L%08x", node->ref_addr);
+ const uint32_t ref_addr =
+ (node->ref_kinds & kRef1Mask) ? node->ref1_addr : node->ref2_addr;
+ snprintf(ref_addr_str, sizeof(ref_addr_str), " .L%08x", ref_addr);
fprintf(output, " |%s", ref_addr_str);
}
if (s.raw_data_comment) {