diff options
Diffstat (limited to 'disasm.h')
-rw-r--r-- | disasm.h | 401 |
1 files changed, 0 insertions, 401 deletions
diff --git a/disasm.h b/disasm.h deleted file mode 100644 index 65429dc..0000000 --- a/disasm.h +++ /dev/null @@ -1,401 +0,0 @@ -#pragma once - -/* SPDX-License-Identifier: Unlicense - */ - -#include "data_buffer.h" -#include "common.h" - -#include <cstddef> -#include <cstdint> -#include <cstdio> - -enum class OpSize: int { - kByte = 0, - kWord = 1, - kLong = 2, - kInvalid = 3, - kNone = kInvalid, - kShort, ///< Semantically is the same as kByte, pseudosize, used for Bcc -}; - -enum class OpCode: uint8_t { - kNone, - kRaw, ///< Emits ".short" - kORI, - kANDI, - kSUBI, - kADDI, - kEORI, - kCMPI, - kBTST, - kBCHG, - kBCLR, - kBSET, - kMOVEP, - kMOVEA, - kMOVE, - kNEGX, - kCLR, - kNEG, - kNOT, - kEXT, - kNBCD, - kSWAP, - kPEA, - kILLEGAL, - kTAS, - kTST, - kTRAP, - kLINK, - kUNLK, - kRESET, - kNOP, - kSTOP, - kRTE, - kRTS, - kTRAPV, - kRTR, - kJSR, - kJMP, - kMOVEM, - kLEA, - kCHK, - kADDQ, - kSUBQ, - kScc, - kDBcc, - kBcc, - kMOVEQ, - kDIVU, - kDIVS, - kSBCD, - kOR, - kSUB, - kSUBX, - kSUBA, - kEOR, - kCMPM, - kCMP, - kCMPA, - kMULU, - kMULS, - kABCD, - kEXG, - kAND, - kADD, - kADDX, - kADDA, - kASR, - kASL, - kLSR, - kLSL, - kROXR, - kROXL, - kROR, - kROL, -}; - -enum class Condition: uint8_t { - kT = 0, - kF = 1, - kHI = 2, - kLS = 3, - kCC = 4, - kCS = 5, - kNE = 6, - kEQ = 7, - kVC = 8, - kVS = 9, - kPL = 10, - kMI = 11, - kGE = 12, - kLT = 13, - kGT = 14, - kLE = 15, -}; - -enum class AddrMode: uint8_t { - kInvalid = 0, - kDn = 1, - kAn = 2, - kAnAddr = 3, - kAnAddrIncr = 4, - kAnAddrDecr = 5, - kD16AnAddr = 6, - kD8AnXiAddr = 7, - kWord = 8, - kLong = 9, - kD16PCAddr = 10, - kD8PCXiAddr = 11, - kImmediate = 12, -}; - -enum class ArgType: uint8_t { - kNone = 0, - kDn = 1, ///< Dn - kAn = 2, ///< An - kAnAddr = 3, ///< (An) - kAnAddrIncr = 4, ///< (An)+ - kAnAddrDecr = 5, ///< -(An) - kD16AnAddr = 6, ///< (d16,An) - kD8AnXiAddr = 7, ///< (d8,An,Xi) - kWord = 8, ///< (xxx).W - kLong = 9, ///< (xxx).L - kD16PCAddr = 10, ///< (d16,PC) - kD8PCXiAddr = 11, ///< (d8,PC,Xn) - kImmediate = 12, ///< #imm - kRegMask, - kRegMaskPredecrement, - kDisplacement, ///< For BRA, BSR, Bcc and DBcc - kCCR, - kSR, - kUSP, - kRaw, ///< Emits "0xXXXX" for ".short" -}; - -struct D8AnPCXiAddr { - uint8_t an; ///< ID number of An reg, for kD8AnXiAddr only - /*! ID number of Xi reg (3 lower bits), for kD8AnXiAddr and kD8PCXiAddr. - * Bit 3 (mask 0x8) means 0 == Dn, 1 == An. - * Bit 4 (mask 0x10) means 0 == Word, 1 == Long. - */ - uint8_t xi; - int8_t d8; ///< Displacement, for kD8AnXiAddr and kD8PCXiAddr -}; - -struct D16AnPCAddr { - uint8_t an; ///< ID number of An reg, for kD16AnAddr only - int16_t d16; ///< Displacement, for D16AnAddr and kD16PCAddr -}; - -static_assert(sizeof(D8AnPCXiAddr) <= sizeof(uint32_t), ""); -static_assert(sizeof(D16AnPCAddr) <= sizeof(uint32_t), ""); - -struct Arg { - union { - ArgType type{ArgType::kNone}; - AddrMode mode; - }; - union { - int32_t lword{}; ///< kLong, kWord, kDisplacement, kImmediate - uint16_t uword; ///< kRegMask, kRaw - uint8_t xn; ///< kDn, kAn, kAnAddr, kAnAddrIncr, kAnAddrDecr - D16AnPCAddr d16_an; ///< kD16AnAddr - D16AnPCAddr d16_pc; ///< kD16PCAddr - D8AnPCXiAddr d8_an_xi; ///< kD8AnXiAddr - D8AnPCXiAddr d8_pc_xi; ///< kD8PCXiAddr - }; - /// Size of the instruction extension: 0, 2 or 4 bytes - constexpr size_t Size(const OpSize s) const - { - switch (mode) { - case AddrMode::kInvalid: - case AddrMode::kDn: - case AddrMode::kAn: - case AddrMode::kAnAddr: - case AddrMode::kAnAddrIncr: - case AddrMode::kAnAddrDecr: - return 0; - case AddrMode::kD16AnAddr: - case AddrMode::kD8AnXiAddr: - case AddrMode::kWord: - return 2; - case AddrMode::kLong: - return 4; - case AddrMode::kD16PCAddr: - case AddrMode::kD8PCXiAddr: - return 2; - case AddrMode::kImmediate: - // Byte and Word immediate are of 2 bytes length - return s == OpSize::kLong ? 4 : 2; - } - return 0; - } - static constexpr auto AddrModeXn(const ArgType type, const uint8_t xn) { - Arg a{{type}, {0}}; - a.xn = xn; - return a; - } - static constexpr auto Dn(const uint8_t xn) { return AddrModeXn(ArgType::kDn, xn); } - static constexpr auto An(const uint8_t xn) { return AddrModeXn(ArgType::kAn, xn); } - static constexpr auto AnAddr(const uint8_t xn) { return AddrModeXn(ArgType::kAnAddr, xn); } - static constexpr auto AnAddrIncr(const uint8_t xn) - { - return AddrModeXn(ArgType::kAnAddrIncr, xn); - } - static constexpr auto AnAddrDecr(const uint8_t xn) - { - return AddrModeXn(ArgType::kAnAddrDecr, xn); - } - static constexpr auto D16AnAddr(const uint8_t xn, const int16_t d16) - { - Arg a{{ArgType::kD16AnAddr}, {0}}; - a.d16_an = D16AnPCAddr{xn, d16}; - return a; - } - static constexpr auto D16PCAddr(const int16_t d16) - { - Arg a{{ArgType::kD16PCAddr}, {0}}; - a.d16_pc = D16AnPCAddr{0, d16}; - return a; - } - static constexpr auto Word(const int16_t w) - { - Arg a{{ArgType::kWord}, {0}}; - a.lword = w; - return a; - } - static constexpr auto Long(const int32_t l) - { - Arg a{{ArgType::kLong}, {0}}; - a.lword = l; - return a; - } - static constexpr auto D8AnXiAddr( - const uint8_t xn, const uint8_t xi, const OpSize s, const int8_t d8) - { - Arg a{{ArgType::kD8AnXiAddr}, {0}}; - a.d8_an_xi = D8AnPCXiAddr{xn, uint8_t(xi | (s == OpSize::kLong ? 0x10u : 0u)), d8}; - return a; - } - static constexpr auto D8PCXiAddr( - const uint8_t xn, const uint8_t xi, const OpSize s, const int8_t d8) - { - Arg a{{ArgType::kD8PCXiAddr}, {0}}; - a.d8_pc_xi = D8AnPCXiAddr{xn, uint8_t(xi | (s == OpSize::kLong ? 0x10u : 0u)), d8}; - return a; - } - static constexpr auto Immediate(const int32_t value) { - Arg a{{ArgType::kImmediate}, {0}}; - a.lword = value; - return a; - } - static constexpr auto RegMask(const uint16_t regmask) { - Arg a{{ArgType::kRegMask}, {0}}; - a.uword = regmask; - return a; - } - static constexpr auto RegMaskPredecrement(const uint16_t regmask) { - Arg a{{ArgType::kRegMaskPredecrement}, {0}}; - a.uword = regmask; - return a; - } - static constexpr auto Displacement(const int32_t displacement) { - Arg a{{ArgType::kDisplacement}, {0}}; - a.lword = displacement; - return a; - } - static constexpr auto CCR() { return Arg{{ArgType::kCCR}, {0}}; } - static constexpr auto SR() { return Arg{{ArgType::kSR}, {0}}; } - static constexpr auto USP() { return Arg{{ArgType::kUSP}, {0}}; } - static constexpr auto Raw(const uint16_t instr) { - Arg a{{ArgType::kRaw}, {0}}; - a.uword = instr; - return a; - } - int SNPrint( - char *buf, - size_t bufsz, - bool imm_as_hex = false, - RefKindMask ref_kinds = 0, - const char *label = nullptr, - uint32_t self_addr = 0, - uint32_t ref_addr = 0) const; -}; - -enum class NodeType { - kTracedInstruction, - kRefInstruction, - kData, -}; - -constexpr size_t kRefsCountPerBuffer = 10; - -constexpr size_t kMnemonicBufferSize = 10; -constexpr size_t kArgsBufferSize = 80; - -enum class ReferenceType { - kUnknown = 0, - kCall, - kBranch, - kRead, - kWrite, -}; - -struct ReferenceRecord { - ReferenceType type{}; - uint32_t address{}; -}; - -struct ReferenceNode { - ReferenceNode *next{}; - ReferenceRecord refs[kRefsCountPerBuffer]; - uint32_t refs_count{}; -}; - -struct Op { - OpCode opcode{OpCode::kNone}; ///< Identifies instruction (mnemonic) - /// Size specifier, the suffix `b`, `w` or `l` - OpSize size_spec{OpSize::kNone}; - Condition condition{Condition::kT}; ///< For Scc, Bcc and Dbcc - Arg arg1{}; ///< First argument, optional - Arg arg2{}; ///< Second argument, optional, cannot be set if arg1 is not set - static constexpr auto Typical( - const OpCode opcode = OpCode::kNone, - const OpSize opsize = OpSize::kNone, - const Arg arg1 = Arg{}, - const Arg arg2 = Arg{}) - { - return Op{opcode, opsize, Condition::kT, arg1, arg2}; - } - static constexpr auto Raw(const uint16_t instr) - { - return Op::Typical(OpCode::kRaw, OpSize::kNone, Arg::Raw(instr)); - } - int FPrint( - FILE *, - const char *indent, - bool imm_as_hex, - RefKindMask ref_kinds = 0, - const char *ref1_label = nullptr, - const char *ref2_label = nullptr, - uint32_t self_addr = 0, - uint32_t ref1_addr = 0, - uint32_t ref2_addr = 0) const; -}; - -struct DisasmNode { - const NodeType type{}; - /// Address of the instruction (PC value basically) - const uint32_t address{}; - /// Instruction size in bytes - size_t size{kInstructionSizeStepBytes}; - /// Indicates whether `ref_addr` should be interpreted and how - RefKindMask ref_kinds{}; - /// Address of first argument reference - uint32_t ref1_addr{}; - /// Address of second argument reference - uint32_t ref2_addr{}; - ReferenceNode *ref_by{}; - ReferenceNode *last_ref_by{}; - Op op{}; - - /*! Disassembles instruction with arguments - * returns size of whole instruction with arguments in bytes - */ - size_t Disasm(const DataView &code); - size_t DisasmAsRaw(const DataView &code); - void AddReferencedBy(uint32_t address, ReferenceType); - ~DisasmNode(); -}; - -static constexpr inline bool IsInstruction(NodeType t) -{ - return t == NodeType::kTracedInstruction || t == NodeType::kRefInstruction; -} - -static constexpr inline bool IsBRA(Op op) -{ - return op.opcode == OpCode::kBcc && op.condition == Condition::kT; -} |