summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common.h1
-rw-r--r--src/disasm.cpp86
-rw-r--r--src/disasm.h111
-rw-r--r--src/m68k.cpp17
-rw-r--r--src/m68k.h12
-rw-r--r--src/main.cpp15
6 files changed, 182 insertions, 60 deletions
diff --git a/src/common.h b/src/common.h
index 40be645..d2f857d 100644
--- a/src/common.h
+++ b/src/common.h
@@ -84,7 +84,6 @@ constexpr RefKindMask kRefWriteMask = kRef1WriteMask | kRef2WriteMask; // For an
constexpr RefKindMask kRefDataMask = kRefReadMask | kRefWriteMask;
constexpr uint32_t kInstructionSizeStepBytes = 2;
constexpr uint32_t kRomSizeBytes = 4 * 1024 * 1024;
-constexpr uint32_t kDisasmMapSizeElements = kRomSizeBytes / kInstructionSizeStepBytes;
static inline constexpr size_t Min(size_t a, size_t b) { return a < b ? a : b; }
diff --git a/src/disasm.cpp b/src/disasm.cpp
index 35c2351..3d1ac4a 100644
--- a/src/disasm.cpp
+++ b/src/disasm.cpp
@@ -3,6 +3,7 @@
#include "disasm.h"
#include "m68k.h"
+#include "debug.h"
#include <cassert>
#include <cerrno>
@@ -12,11 +13,11 @@
void DisasmNode::AddReferencedBy(const uint32_t address_from, const ReferenceType ref_type)
{
ReferenceRecord *node = new ReferenceRecord{nullptr, ref_type, address_from};
- assert(node);
+ ASSERT(node);
if (this->last_ref_by) {
this->last_ref_by->next = node;
} else {
- assert(nullptr == this->ref_by);
+ ASSERT(nullptr == this->ref_by);
this->ref_by = node;
}
this->last_ref_by = node;
@@ -30,30 +31,45 @@ DisasmNode::~DisasmNode()
ref = ref->next;
delete prev;
}
-}
-
-static constexpr uint32_t AlignInstructionAddress(const uint32_t address)
-{
- return address & ~1UL;
+ ref_by = nullptr;
+ last_ref_by = nullptr;
}
DisasmNode &DisasmMap::insertNode(uint32_t address, NodeType type)
{
+ ASSERT(address < _code_size);
+ if (IsInstruction(type)) {
+ address = AlignInstructionAddress(address);
+ }
auto *node = findNodeByAddress(address);
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.
+ // XXX: Traced data must not be classified as instruction. But the
+ // traced data support is yet to come.
if (IsInstruction(type) && !IsInstruction(node->type)) {
- *const_cast<NodeType*>(&node->type) = type;
- // Make sure it is OpCode::kNone so it will be properly disassembled
- node->op = Op{};
+ if (0 == (node->size & 1) && 0 == (node->address & 1)) {
+ *const_cast<NodeType*>(&node->type) = type;
+ // Make sure it is OpCode::kNone so it will be properly disassembled
+ node->op = Op{};
+ }
}
return *node;
}
- node = new DisasmNode(DisasmNode{type, AlignInstructionAddress(address)});
- assert(node);
- _map[address / kInstructionSizeStepBytes] = node;
+ if (IsInstruction(type) && _map[address + 1]) {
+ // Sorry, can't do instruction here. Only 1 byte of data could fit.
+ node = new DisasmNode(DisasmNode::DataRaw8(address, 0));
+ ASSERT(node->size == 1);
+ } else {
+ node = new DisasmNode(DisasmNode::Simple(type, address));
+ }
+ ASSERT(node);
+ // Spread across the size
+ for (size_t o = 0; o < node->size; o++) {
+ ASSERT(_map[address + o] == nullptr || _map[address + o] == node);
+ _map[address + o] = node;
+ }
return *node;
}
@@ -70,7 +86,7 @@ DisasmNode &DisasmMap::insertReferencedBy(
void DisasmMap::InsertNode(uint32_t address, NodeType type)
{
- assert(_type == DisasmMapType::kTraced);
+ ASSERT(_type == DisasmMapType::kTraced);
insertNode(address, type);
}
@@ -114,8 +130,7 @@ bool DisasmMap::ApplySymbolsFromElf(const ELF::Image &elf)
if (null_symbol.name != nullptr && *null_symbol.name != '\0') {
const size_t ret = fwrite(
&null_symbol, sizeof null_symbol, 1, symtab_stream);
- (void) ret;
- assert(ret == 1);
+ ASSERT(ret == 1), (void)ret;
}
const size_t nentries = symtab.size/symtab.entsize;
for (size_t i = 0; i < nentries; i++) {
@@ -131,8 +146,7 @@ bool DisasmMap::ApplySymbolsFromElf(const ELF::Image &elf)
const auto symbol = Symbol{elfsym.value, type, elfsym.name, elfsym.size};
if (symbol.name != nullptr && *symbol.name != '\0') {
const size_t ret = fwrite(&symbol, sizeof symbol, 1, symtab_stream);
- (void) ret;
- assert(ret == 1);
+ ASSERT(ret == 1), (void) ret;
}
}
}
@@ -173,6 +187,7 @@ static constexpr bool IsNextLikelyAnInstruction(const Op &op)
{
return (op.opcode != OpCode::kNone &&
op.opcode != OpCode::kRaw &&
+ op.opcode != OpCode::kRaw8 &&
!IsBRA(op) &&
op.opcode != OpCode::kJMP &&
op.opcode != OpCode::kRTS &&
@@ -183,13 +198,16 @@ static constexpr bool IsNextLikelyAnInstruction(const Op &op)
void DisasmMap::Disasm(
const DataView &code, const Settings &s, size_t at, bool nested)
{
+ at = AlignInstructionAddress(at);
+ _code_size = code.size;
+ ASSERT(_code_size <= kRomSizeBytes);
// Some of logic of this function is covered by integration tests in
// `test_walk_and_follow_jumps.bash`.
bool inside_code_span = nested;
- while (at < Min(kRomSizeBytes, code.size)) {
+ while (at < code.size) {
DisasmNode *node;
if (_type == DisasmMapType::kTraced) {
- node = _map[at / kInstructionSizeStepBytes];
+ node = _map[at];
if (!node) {
if (inside_code_span) {
node = &insertNode(at, NodeType::kTracedInstruction);
@@ -198,19 +216,19 @@ void DisasmMap::Disasm(
continue;
}
}
+ ASSERT(node->address == at);
} else {
node = &insertNode(at, NodeType::kTracedInstruction);
}
- const bool perform_disasm = node->op.opcode == OpCode::kNone ||
- (_type == DisasmMapType::kRaw && node->op.opcode == OpCode::kRaw) ||
- inside_code_span;
+ const bool perform_disasm = node->IsYetToBeHandled(_type) || inside_code_span;
if (perform_disasm) {
const auto size = node->Disasm(code, s);
- assert(size >= kInstructionSizeStepBytes);
if (canBeAllocated(*node)) {
// Spread across the size
- for (size_t o = kInstructionSizeStepBytes; o < size; o++) {
- _map[(node->address + o) / kInstructionSizeStepBytes] = node;
+ const size_t address = node->address;
+ for (size_t o = 0; o < size; o++) {
+ ASSERT(_map[address + o] == nullptr || _map[address + o] == node);
+ _map[address + o] = node;
}
} else {
node->DisasmAsRaw(code);
@@ -227,11 +245,11 @@ void DisasmMap::Disasm(
const bool has_code_ref1 = node->ref1_addr < code.size && has_ref1;
if (has_code_ref1) {
const NodeType type = (node->ref_kinds & (kRef1ReadMask | kRef1WriteMask))
- ? NodeType::kData : NodeType::kRefInstruction;
+ ? NodeType::kRefData : NodeType::kRefInstruction;
const auto ref_type = ReferenceTypeFromRefKindMask1(node->ref_kinds);
auto &ref_node = insertReferencedBy(
node->address, node->ref1_addr, type, ref_type);
- if (ref_node.op.opcode == OpCode::kNone) {
+ if (ref_node.IsYetToBeHandled(_type)) {
if (s.follow_jumps) {
Disasm(code, s, ref_node.address, true);
} else {
@@ -243,11 +261,11 @@ void DisasmMap::Disasm(
const bool has_code_ref2 = (has_ref2 && node->ref2_addr < code.size);
if (has_code_ref2) {
const NodeType type = (node->ref_kinds & (kRef2ReadMask | kRef2WriteMask))
- ? NodeType::kData : NodeType::kRefInstruction;
+ ? NodeType::kRefData : NodeType::kRefInstruction;
const auto ref_type = ReferenceTypeFromRefKindMask2(node->ref_kinds);
auto &ref_node = insertReferencedBy(
node->address, node->ref2_addr, type, ref_type);
- if (ref_node.op.opcode == OpCode::kNone) {
+ if (ref_node.IsYetToBeHandled(_type)) {
if (s.follow_jumps) {
Disasm(code, s, ref_node.address, true);
} else {
@@ -263,19 +281,21 @@ void DisasmMap::Disasm(
DisasmMap::~DisasmMap()
{
- for (size_t i = 0; i < kDisasmMapSizeElements; i++) {
+ ASSERT(_map != nullptr);
+ for (size_t i = 0; i < kRomSizeBytes; i++) {
auto *const node = _map[i];
if (!node) {
continue;
}
- const auto size = node->size / kInstructionSizeStepBytes;
+ const auto size = node->size;
for (size_t o = 0; o < size; o++) {
- assert(_map[i + o] == node);
+ ASSERT(_map[i + o] == node);
_map[i + o] = nullptr;
}
delete node;
i += size - 1;
}
+ free(_map);
if (_symtab != nullptr) {
free(_symtab);
}
diff --git a/src/disasm.h b/src/disasm.h
index 2a6a1d0..13109a5 100644
--- a/src/disasm.h
+++ b/src/disasm.h
@@ -25,18 +25,28 @@ struct ReferenceRecord {
uint32_t address{};
};
+enum class DisasmMapType {
+ kTraced,
+ kRaw,
+};
+
enum class NodeType {
kTracedInstruction,
kRefInstruction,
- kData,
+ kRefData,
};
+static constexpr uint32_t AlignInstructionAddress(const uint32_t address)
+{
+ return address & ~1UL;
+}
+
struct DisasmNode {
const NodeType type{};
/// Address of the instruction (PC value basically)
const uint32_t address{};
/// Instruction size in bytes
- size_t size{kInstructionSizeStepBytes};
+ size_t size{selectSize(type, kInstructionSizeStepBytes)};
/// Indicates whether `ref_addr` should be interpreted and how
RefKindMask ref_kinds{};
/// Address of first argument reference
@@ -46,6 +56,48 @@ struct DisasmNode {
ReferenceRecord *ref_by{};
ReferenceRecord *last_ref_by{};
Op op{};
+ static DisasmNode Simple(NodeType t, uint32_t address)
+ {
+ return DisasmNode{
+ /* .type = */ t,
+ /* .address = */ alignAddress(NodeType::kTracedInstruction, address),
+ /* .size = */ selectSize(t, (address & 1) ? 1 : 2),
+ /* .ref_kinds = */ 0,
+ /* .ref1_addr = */ 0,
+ /* .ref2_addr = */ 0,
+ /* .ref_by = */ nullptr,
+ /* .last_ref_by = */ nullptr,
+ /* .op = */ selectOp(t, (address & 1) ? 1 : 2),
+ };
+ }
+ static DisasmNode TracedRaw(uint32_t address, uint16_t raw)
+ {
+ return DisasmNode{
+ /* .type = */ NodeType::kTracedInstruction,
+ /* .address = */ alignAddress(NodeType::kTracedInstruction, address),
+ /* .size = */ sizeof(raw),
+ /* .ref_kinds = */ 0,
+ /* .ref1_addr = */ 0,
+ /* .ref2_addr = */ 0,
+ /* .ref_by = */ nullptr,
+ /* .last_ref_by = */ nullptr,
+ /* .op = */ Op::Raw(raw),
+ };
+ }
+ static DisasmNode DataRaw8(uint32_t address, uint8_t raw)
+ {
+ return DisasmNode{
+ /* .type = */ NodeType::kRefData,
+ /* .address = */ address,
+ /* .size = */ sizeof(raw),
+ /* .ref_kinds = */ 0,
+ /* .ref1_addr = */ 0,
+ /* .ref2_addr = */ 0,
+ /* .ref_by = */ nullptr,
+ /* .last_ref_by = */ nullptr,
+ /* .op = */ Op::Raw8(raw),
+ };
+ }
/*! Disassembles instruction with arguments
* returns size of whole instruction with arguments in bytes
@@ -53,7 +105,46 @@ struct DisasmNode {
size_t Disasm(const DataView &code, const Settings &);
size_t DisasmAsRaw(const DataView &code);
void AddReferencedBy(uint32_t address, ReferenceType);
+ bool IsYetToBeHandled(DisasmMapType dmtype)
+ {
+ return op.opcode == OpCode::kNone ||
+ (dmtype == DisasmMapType::kRaw && op.opcode == OpCode::kRaw);
+ }
~DisasmNode();
+private:
+ static constexpr uint32_t alignAddress(NodeType t, uint32_t address)
+ {
+ switch (t) {
+ case NodeType::kTracedInstruction:
+ case NodeType::kRefInstruction:
+ return AlignInstructionAddress(address);
+ case NodeType::kRefData:
+ return address;
+ }
+ return address;
+ }
+ static constexpr uint32_t selectSize(NodeType t, size_t size)
+ {
+ switch (t) {
+ case NodeType::kTracedInstruction:
+ case NodeType::kRefInstruction:
+ return kInstructionSizeStepBytes;
+ case NodeType::kRefData:
+ return size;
+ }
+ return 1;
+ }
+ static constexpr Op selectOp(NodeType t, size_t size)
+ {
+ switch (t) {
+ case NodeType::kTracedInstruction:
+ case NodeType::kRefInstruction:
+ return Op{};
+ case NodeType::kRefData:
+ return (size & 1) ? Op::Raw8(0) : Op::Raw(0);
+ }
+ return Op{};
+ }
};
static constexpr inline bool IsInstruction(NodeType t)
@@ -74,14 +165,10 @@ struct Symbol {
size_t size{};
};
-enum class DisasmMapType {
- kTraced,
- kRaw,
-};
-
class DisasmMap {
const DisasmMapType _type;
- DisasmNode *_map[kDisasmMapSizeElements]{};
+ DisasmNode **_map{static_cast<DisasmNode **>(calloc(kRomSizeBytes, sizeof(*_map)))};
+ size_t _code_size{};
Symbol *_symtab{};
size_t _symtab_size{};
TraceTable _tt{};
@@ -116,7 +203,7 @@ public:
constexpr DisasmNode *DisasmMap::findNodeByAddress(uint32_t address) const
{
if (address < kRomSizeBytes)
- return _map[address / kInstructionSizeStepBytes];
+ return _map[address];
return nullptr;
}
@@ -191,10 +278,10 @@ constexpr bool DisasmMap::HasSymbolsInRange(
constexpr bool DisasmMap::canBeAllocated(const DisasmNode& node) const
{
- const auto size = node.size / kInstructionSizeStepBytes;
+ const auto size = node.size;
const auto *const node_real = findNodeByAddress(node.address);
- for (size_t i = 1; i < size; i++) {
- const auto *const ptr = _map[node.address / kInstructionSizeStepBytes + i];
+ for (size_t i = 0; i < size; i++) {
+ const auto *const ptr = _map[node.address + i];
if (ptr != nullptr && ptr != node_real) {
return false;
}
diff --git a/src/m68k.cpp b/src/m68k.cpp
index fe96ee6..248bfb3 100644
--- a/src/m68k.cpp
+++ b/src/m68k.cpp
@@ -169,7 +169,13 @@ static Arg FetchArg(
static size_t disasm_verbatim(DisasmNode &node, const uint16_t instr)
{
- node.op = Op::Raw(instr);
+ if (node.op.opcode == OpCode::kRaw8) {
+ node.op = Op::Raw8(instr >> 8);
+ node.size = 1;
+ } else {
+ node.op = Op::Raw(instr);
+ node.size = 2;
+ }
return node.size;
}
@@ -856,7 +862,7 @@ static size_t disasm_trivial(
DisasmNode &node, const OpCode opcode)
{
node.op = Op::Typical(opcode, OpSize::kNone);
- return node.size;
+ return node.size = kInstructionSizeStepBytes;
}
static size_t disasm_tas(
@@ -1661,7 +1667,7 @@ size_t DisasmNode::Disasm(const DataView &code, const Settings &s)
{
// We assume that machine have no MMU and ROM data always starts at 0
assert(this->address < code.size);
- size = kInstructionSizeStepBytes;
+ size = 0;
ref_kinds = 0;
ref1_addr = 0;
ref2_addr = 0;
@@ -1693,6 +1699,7 @@ static const char *ToString(const OpCode opcode, const Condition condition)
assert(false);
break;
case OpCode::kRaw: return ".short";
+ case OpCode::kRaw8: return ".byte";
case OpCode::kORI: return "ori";
case OpCode::kANDI: return "andi";
case OpCode::kSUBI: return "subi";
@@ -1954,6 +1961,9 @@ static size_t snprint_reg_mask_sierra(
int SNPrintArgRaw(char *const buf, const size_t bufsz, const Arg &arg)
{
+ if (arg.type == ArgType::kRaw8) {
+ return snprintf(buf, bufsz, "0x%02x", arg.ubyte);
+ }
return snprintf(buf, bufsz, "0x%04x", arg.uword);
}
@@ -1974,6 +1984,7 @@ static int SNPrintArg(
assert(false);
break;
case ArgType::kRaw:
+ case ArgType::kRaw8:
return SNPrintArgRaw(buf, bufsz, arg);
case ArgType::kDn:
if (TargetAssembler::kSierraAsm68 == target_asm) {
diff --git a/src/m68k.h b/src/m68k.h
index 40bdf1f..8fe10ee 100644
--- a/src/m68k.h
+++ b/src/m68k.h
@@ -22,6 +22,7 @@ enum class OpSize: int {
enum class OpCode: uint8_t {
kNone,
kRaw, ///< Emits ".short"
+ kRaw8, ///< Emits ".byte"
kORI,
kANDI,
kSUBI,
@@ -152,6 +153,7 @@ enum class ArgType: uint8_t {
kSR,
kUSP,
kRaw, ///< Emits "0xXXXX" for ".short"
+ kRaw8, ///< Emits "0xXX" for ".byte"
};
struct D8AnPCXiAddr {
@@ -181,6 +183,7 @@ struct Arg {
union {
int32_t lword{}; ///< kLong, kWord, kDisplacement, kImmediate
uint16_t uword; ///< kRegMask, kRaw
+ uint8_t ubyte; ///< kRaw8
uint8_t xn; ///< kDn, kAn, kAnAddr, kAnAddrIncr, kAnAddrDecr
D16AnPCAddr d16_an; ///< kD16AnAddr
D16AnPCAddr d16_pc; ///< kD16PCAddr
@@ -311,6 +314,11 @@ struct Arg {
a.uword = instr;
return a;
}
+ static constexpr auto Raw8(const uint16_t instr) {
+ Arg a{{ArgType::kRaw8}, false, {0}};
+ a.ubyte = instr;
+ return a;
+ }
};
struct Op {
@@ -332,6 +340,10 @@ struct Op {
{
return Op::Typical(OpCode::kRaw, OpSize::kNone, Arg::Raw(instr));
}
+ static constexpr auto Raw8(const uint8_t data)
+ {
+ return Op::Typical(OpCode::kRaw8, OpSize::kNone, Arg::Raw(data));
+ }
};
constexpr size_t kMnemonicBufferSize = 10;
diff --git a/src/main.cpp b/src/main.cpp
index 2a060df..7ce10fa 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -595,17 +595,10 @@ static bool EmitDisassembly(
ctx.output = output;
}
for (size_t address = 0; address < code.size;) {
- const DisasmNode raw = DisasmNode{
- /* .type = */ NodeType::kTracedInstruction,
- /* .address = */ static_cast<uint32_t>(address),
- /* .size = */ 2,
- /* .ref_kinds = */ 0,
- /* .ref1_addr = */ 0,
- /* .ref2_addr = */ 0,
- /* .ref_by = */ nullptr,
- /* .last_ref_by = */ nullptr,
- /* .op = */ Op::Raw(GetU16BE(code.buffer + address)),
- };
+ const DisasmNode raw = (address & 1)
+ ? DisasmNode::DataRaw8(static_cast<uint32_t>(address), GetU8(code.buffer + address))
+ : DisasmNode::TracedRaw(
+ static_cast<uint32_t>(address), GetU16BE(code.buffer + address));
const DisasmNode *node = disasm_map.FindNodeByAddress(address);
const bool traced = node;
if (node == nullptr) {