diff options
author | Oxore <oxore@protonmail.com> | 2025-01-08 00:46:44 +0300 |
---|---|---|
committer | Oxore <oxore@protonmail.com> | 2025-02-01 18:26:18 +0300 |
commit | 6769fca1dd90f4e34e1fd6b2256c3795bbcaf658 (patch) | |
tree | 80899430ea776d80b98be4e198591a61f8384d16 /src | |
parent | 8340b1f42288e0143bca8a254600fb34025ec803 (diff) |
WIP
Diffstat (limited to 'src')
-rw-r--r-- | src/common.h | 1 | ||||
-rw-r--r-- | src/disasm.cpp | 86 | ||||
-rw-r--r-- | src/disasm.h | 111 | ||||
-rw-r--r-- | src/m68k.cpp | 17 | ||||
-rw-r--r-- | src/m68k.h | 12 | ||||
-rw-r--r-- | src/main.cpp | 15 |
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) { @@ -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) { |