diff options
-rw-r--r-- | disasm.cpp | 381 | ||||
-rw-r--r-- | disasm.h | 356 |
2 files changed, 321 insertions, 416 deletions
@@ -32,46 +32,50 @@ enum class ShiftKind: int { kRotate = 3, }; -constexpr AddrModeArg FetchImmediate(const uint32_t offset, const DataBuffer &code, const OpSize s) +constexpr Arg FetchImmediate(const uint32_t offset, const DataBuffer &code, const OpSize s) { if (s == OpSize::kInvalid) { - return AddrModeArg{}; + return Arg{}; } else if (s == OpSize::kLong) { if (offset + kInstructionSizeStepBytes < code.occupied_size) { const int32_t value = GetI32BE(code.buffer + offset); - return AddrModeArg::Immediate(s, value); + return Arg::Immediate(value); } } else if (offset < code.occupied_size) { const int16_t value = GetI16BE(code.buffer + offset); if (s == OpSize::kByte) { + // Technically it is impossible to have value lower that -128 in 8 + // bits signed integer, but the second byte being 0xff is actually + // a valid thing and it is how values from -255 to -129 are + // represented. if (value > 255 || value < -255) { // Invalid immediate value for instruction with .b suffix - return AddrModeArg{}; + return Arg{}; } } - return AddrModeArg::Immediate(s, value); + return Arg::Immediate(value); } - return AddrModeArg{}; + return Arg{}; } -constexpr AddrModeArg FetchAddrModeArg( +constexpr Arg FetchArg( const uint32_t offset, const DataBuffer &code, const int m, const int xn, const OpSize s) { switch (m) { case 0: // Dn - return AddrModeArg::Dn(xn); + return Arg::Dn(xn); case 1: // An - return AddrModeArg::An(xn); + return Arg::An(xn); case 2: // (An) - return AddrModeArg::AnAddr(xn); + return Arg::AnAddr(xn); case 3: // (An)+ - return AddrModeArg::AnAddrIncr(xn); + return Arg::AnAddrIncr(xn); case 4: // -(An) - return AddrModeArg::AnAddrDecr(xn); + return Arg::AnAddrDecr(xn); case 5: // (d16, An), Additional Word if (offset < code.occupied_size) { const int16_t d16 = GetI16BE(code.buffer + offset); - return AddrModeArg::D16AnAddr(xn, d16); + return Arg::D16AnAddr(xn, d16); } break; case 6: // (d8, An, Xi), Brief Extension Word @@ -82,11 +86,11 @@ constexpr AddrModeArg FetchAddrModeArg( // i.e. xxxx_x000_xxxx_xxxx break; } - const char r = ((briefext >> 15) & 1) ? 'a' : 'd'; - const uint8_t xi = (briefext >> 12) & 7; + // Xi number (lower 3 bits, mask 0x7) with An/Dn bit (mask 0x8) + const uint8_t xi = (briefext >> 12) & 0xf; const OpSize s = ((briefext >> 11) & 1) ? OpSize::kLong : OpSize::kWord; const int8_t d8 = briefext & 0xff; - return AddrModeArg::D8AnXiAddr(xn, r, xi, s, d8); + return Arg::D8AnXiAddr(xn, xi, s, d8); } break; case 7: @@ -94,19 +98,19 @@ constexpr AddrModeArg FetchAddrModeArg( case 0: // (xxx).W, Additional Word if (offset < code.occupied_size) { const int32_t w = GetI16BE(code.buffer + offset); - return AddrModeArg::Word(w); + return Arg::Word(w); } break; case 1: // (xxx).L, Additional Long if (offset + kInstructionSizeStepBytes < code.occupied_size) { const int32_t l = GetI32BE(code.buffer + offset); - return AddrModeArg::Long(l); + return Arg::Long(l); } break; case 2: // (d16, PC), Additional Word if (offset < code.occupied_size) { const int16_t d16 = GetI16BE(code.buffer + offset); - return AddrModeArg::D16PCAddr(xn, d16); + return Arg::D16PCAddr(d16); } break; case 3: // (d8, PC, Xi), Brief Extension Word @@ -117,11 +121,11 @@ constexpr AddrModeArg FetchAddrModeArg( // i.e. xxxx_x000_xxxx_xxxx break; } - const char r = ((briefext >> 15) & 1) ? 'a' : 'd'; - const uint8_t xi = (briefext >> 12) & 7; + // Xi number (lower 3 bits, mask 0x7) with An/Dn bit (mask 0x8) + const uint8_t xi = (briefext >> 12) & 0xf; const OpSize s = ((briefext >> 11) & 1) ? OpSize::kLong : OpSize::kWord; const int8_t d8 = briefext & 0xff; - return AddrModeArg::D8PCXiAddr(xn, r, xi, s, d8); + return Arg::D8PCXiAddr(xn, xi, s, d8); } break; case 4: // #imm @@ -133,16 +137,16 @@ constexpr AddrModeArg FetchAddrModeArg( } break; } - return AddrModeArg{}; + return Arg{}; } -static inline AddrModeArg FetchAddrModeArg( +static inline Arg FetchArg( const uint32_t offset, const DataBuffer &code, const uint16_t instr, const OpSize s) { const int addrmode = instr & 0x3f; const int m = (addrmode >> 3) & 7; const int xn = addrmode & 7; - return FetchAddrModeArg(offset, code, m, xn, s); + return FetchArg(offset, code, m, xn, s); } static size_t disasm_verbatim(DisasmNode &node, const uint16_t instr) @@ -156,7 +160,8 @@ static size_t disasm_verbatim(DisasmNode &node, const uint16_t instr) static size_t disasm_jsr_jmp( DisasmNode &node, const uint16_t instr, const DataBuffer &code, const JKind jtype) { - const auto a = FetchAddrModeArg(node.offset + kInstructionSizeStepBytes, code, instr, OpSize::kWord); + const OpSize opsize = OpSize::kWord; + const auto a = FetchArg(node.offset + kInstructionSizeStepBytes, code, instr, opsize); switch (a.mode) { case AddrMode::kInvalid: case AddrMode::kDn: // 4e80..4e87 / 4ec0..4ec7 @@ -180,7 +185,7 @@ static size_t disasm_jsr_jmp( case AddrMode::kWord: // 4eb8 / 4ef8 { // FIXME support s.abs_marks option for this instruction - const uint32_t branch_addr = static_cast<uint32_t>(a.value); + const uint32_t branch_addr = static_cast<uint32_t>(a.lword); node.branch_addr = branch_addr; node.has_branch_addr = true; } @@ -188,7 +193,7 @@ static size_t disasm_jsr_jmp( case AddrMode::kLong: // 4eb9 / 4ef9 { // FIXME support s.abs_marks option for this instruction - const uint32_t branch_addr = static_cast<uint32_t>(a.value); + const uint32_t branch_addr = static_cast<uint32_t>(a.lword); node.branch_addr = branch_addr; node.has_branch_addr = true; } @@ -196,7 +201,7 @@ static size_t disasm_jsr_jmp( case AddrMode::kD16PCAddr: // 4eba / 4efa { // FIXME support s.abs_marks option for this instruction - const uint32_t branch_addr = static_cast<uint32_t>(a.value) + kInstructionSizeStepBytes; + const uint32_t branch_addr = static_cast<uint32_t>(a.lword) + kInstructionSizeStepBytes; node.branch_addr = branch_addr; node.has_branch_addr = true; } @@ -211,20 +216,20 @@ static size_t disasm_jsr_jmp( node.is_call = (jtype == JKind::kJsr); node.opcode = (jtype == JKind::kJsr) ? OpCode::kJSR : OpCode::kJMP; node.size_spec = OpSize::kNone; - node.arg1 = Arg::FromAddrModeArg(a); - return node.size = kInstructionSizeStepBytes + a.Size(); + node.arg1 = a; + return node.size = kInstructionSizeStepBytes + a.Size(opsize); } static inline size_t disasm_ext( DisasmNode &node, const OpSize opsize, - const AddrModeArg arg) + const Arg arg) { assert(arg.mode == AddrMode::kDn); node.opcode = OpCode::kEXT; node.size_spec = opsize; - node.arg1 = Arg::FromAddrModeArg(arg); - return node.size = kInstructionSizeStepBytes + arg.Size(); + node.arg1 = arg; + return node.size = kInstructionSizeStepBytes + arg.Size(opsize); } static size_t disasm_ext_movem( @@ -235,7 +240,7 @@ static size_t disasm_ext_movem( const unsigned xn = instr & 7; const auto opsize = static_cast<OpSize>(((instr >> 6) & 1) + 1); if (m == 0 && dir == MoveDirection::kRegisterToMemory) { - return disasm_ext(node, opsize, AddrModeArg::Dn(xn)); + return disasm_ext(node, opsize, Arg::Dn(xn)); } if (node.offset + kInstructionSizeStepBytes >= code.occupied_size) { // Not enough space for regmask, but maybe it is just EXT? @@ -246,7 +251,7 @@ static size_t disasm_ext_movem( // This is just not representable: at least one register must be specified return disasm_verbatim(node, instr); } - const auto a = FetchAddrModeArg( + const auto a = FetchArg( node.offset + kInstructionSizeStepBytes * 2, code, m, xn, opsize); switch (a.mode) { case AddrMode::kInvalid: @@ -282,20 +287,21 @@ static size_t disasm_ext_movem( node.opcode = OpCode::kMOVEM; node.size_spec = opsize; if (dir == MoveDirection::kMemoryToRegister) { - node.arg1 = Arg::FromAddrModeArg(a); + node.arg1 = a; node.arg2 = (a.mode == AddrMode::kAnAddrDecr) ? Arg::RegMaskPredecrement(regmask) : Arg::RegMask(regmask); } else { node.arg1 = (a.mode == AddrMode::kAnAddrDecr) ? Arg::RegMaskPredecrement(regmask) : Arg::RegMask(regmask); - node.arg2 = Arg::FromAddrModeArg(a); + node.arg2 = a; } - return node.size = kInstructionSizeStepBytes * 2 + a.Size(); + return node.size = kInstructionSizeStepBytes * 2 + a.Size(opsize); } static size_t disasm_lea( DisasmNode &node, const uint16_t instr, const DataBuffer &code) { - const auto addr = FetchAddrModeArg( - node.offset + kInstructionSizeStepBytes, code, instr, OpSize::kLong); + const OpSize opsize = OpSize::kLong; + const auto addr = FetchArg( + node.offset + kInstructionSizeStepBytes, code, instr, opsize); switch (addr.mode) { case AddrMode::kInvalid: case AddrMode::kDn: @@ -317,19 +323,20 @@ static size_t disasm_lea( return disasm_verbatim(node, instr); } const unsigned an = ((instr >> 9) & 7); - const auto reg = AddrModeArg::An(an); + const auto reg = Arg::An(an); node.opcode = OpCode::kLEA; node.size_spec = OpSize::kLong; - node.arg1 = Arg::FromAddrModeArg(addr); - node.arg2 = Arg::FromAddrModeArg(reg); - return node.size = kInstructionSizeStepBytes + addr.Size() + reg.Size(); + node.arg1 = addr; + node.arg2 = reg; + return node.size = kInstructionSizeStepBytes + addr.Size(opsize) + reg.Size(opsize); } static size_t disasm_chk( DisasmNode &node, const uint16_t instr, const DataBuffer &code) { - const auto src = FetchAddrModeArg( - node.offset + kInstructionSizeStepBytes, code, instr, OpSize::kWord); + const OpSize opsize = OpSize::kWord; + const auto src = FetchArg( + node.offset + kInstructionSizeStepBytes, code, instr, opsize); switch (src.mode) { case AddrMode::kInvalid: return disasm_verbatim(node, instr); @@ -351,12 +358,12 @@ static size_t disasm_chk( return disasm_verbatim(node, instr); } const unsigned dn = ((instr >> 9) & 7); - const auto dst = AddrModeArg::Dn(dn); + const auto dst = Arg::Dn(dn); node.opcode = OpCode::kCHK; node.size_spec = OpSize::kWord; - node.arg1 = Arg::FromAddrModeArg(src); - node.arg2 = Arg::FromAddrModeArg(dst); - return node.size = kInstructionSizeStepBytes + src.Size() + dst.Size(); + node.arg1 = src; + node.arg2 = dst; + return node.size = kInstructionSizeStepBytes + src.Size(opsize) + dst.Size(opsize); } static size_t disasm_bra_bsr_bcc( @@ -413,24 +420,24 @@ static inline size_t disasm_movep( const unsigned an = instr & 7; const OpSize opsize = ((instr >> 6) & 1) ? OpSize::kLong : OpSize::kWord; const auto dir = static_cast<MoveDirection>(!((instr >> 7) & 1)); - const auto addr = FetchAddrModeArg( + const auto addr = FetchArg( node.offset + kInstructionSizeStepBytes, code, 5, an, opsize); if (addr.mode == AddrMode::kInvalid) { // Boundary check failed, most likely return disasm_verbatim(node, instr); } assert(addr.mode == AddrMode::kD16AnAddr); - const auto reg = AddrModeArg::Dn(dn); + const auto reg = Arg::Dn(dn); node.opcode = OpCode::kMOVEP; node.size_spec = opsize; if (dir == MoveDirection::kRegisterToMemory) { - node.arg1 = Arg::FromAddrModeArg(reg); - node.arg2 = Arg::FromAddrModeArg(addr); + node.arg1 = reg; + node.arg2 = addr; } else { - node.arg1 = Arg::FromAddrModeArg(addr); - node.arg2 = Arg::FromAddrModeArg(reg); + node.arg1 = addr; + node.arg2 = reg; } - return node.size = kInstructionSizeStepBytes + addr.Size() + reg.Size(); + return node.size = kInstructionSizeStepBytes + addr.Size(opsize) + reg.Size(opsize); } static size_t disasm_src_arg_bitops_movep( @@ -447,7 +454,7 @@ static size_t disasm_src_arg_bitops_movep( const unsigned xn = instr & 7; // Fetch AddrMode::kDn if has_dn_src, otherwise fetch AddrMode::kImmediate // byte - const auto src = FetchAddrModeArg( + const auto src = FetchArg( node.offset + kInstructionSizeStepBytes, code, (has_dn_src) ? 0 : 7, @@ -462,8 +469,9 @@ static size_t disasm_src_arg_bitops_movep( assert(dn == 4); assert(src.mode == AddrMode::kImmediate); } - const auto dst = FetchAddrModeArg( - node.offset + kInstructionSizeStepBytes + src.Size(), code, m, xn, OpSize::kWord); + const OpSize opsize = OpSize::kWord; + const auto dst = FetchArg( + node.offset + kInstructionSizeStepBytes + src.Size(opsize), code, m, xn, opsize); const unsigned opcode = (instr >> 6) & 3; switch (dst.mode) { case AddrMode::kInvalid: @@ -492,9 +500,9 @@ static size_t disasm_src_arg_bitops_movep( } node.opcode = OpCodeForBitOps(opcode); node.size_spec = dst.mode == AddrMode::kDn ? OpSize::kLong : OpSize::kByte; - node.arg1 = Arg::FromAddrModeArg(src); - node.arg2 = Arg::FromAddrModeArg(dst); - return node.size = kInstructionSizeStepBytes + src.Size() + dst.Size(); + node.arg1 = src; + node.arg2 = dst; + return node.size = kInstructionSizeStepBytes + src.Size(opsize) + dst.Size(opsize); } static size_t disasm_bitops(DisasmNode &n, const uint16_t i, const DataBuffer &c) @@ -503,11 +511,11 @@ static size_t disasm_bitops(DisasmNode &n, const uint16_t i, const DataBuffer &c } static size_t disasm_logical_immediate_to( - DisasmNode &node, OpCode opcode, OpSize opsize, AddrModeArg imm) + DisasmNode &node, OpCode opcode, OpSize opsize, Arg imm) { node.opcode = opcode; node.size_spec = opsize; - node.arg1 = Arg::FromAddrModeArg(imm); + node.arg1 = imm; node.arg2 = (opsize == OpSize::kByte) ? Arg::CCR() : Arg::SR(); return node.size = kInstructionSizeStepBytes * 2; } @@ -571,8 +579,8 @@ static size_t disasm_bitops_movep( if (m == 7 && xn == 4) { return disasm_logical_immediate_to(node, mnemonic, opsize, src); } - const auto dst = FetchAddrModeArg( - node.offset + kInstructionSizeStepBytes + src.Size(), code, m, xn, opsize); + const auto dst = FetchArg( + node.offset + kInstructionSizeStepBytes + src.Size(opsize), code, m, xn, opsize); switch (dst.mode) { case AddrMode::kInvalid: return disasm_verbatim(node, instr); @@ -600,9 +608,9 @@ static size_t disasm_bitops_movep( } node.opcode = mnemonic; node.size_spec = opsize; - node.arg1 = Arg::FromAddrModeArg(src); - node.arg2 = Arg::FromAddrModeArg(dst); - return node.size = kInstructionSizeStepBytes + src.Size() + dst.Size(); + node.arg1 = src; + node.arg2 = dst; + return node.size = kInstructionSizeStepBytes + src.Size(opsize) + dst.Size(opsize); } static size_t disasm_move_movea( @@ -611,7 +619,7 @@ static size_t disasm_move_movea( const int opsize_raw = (instr >> 12) & 3; const OpSize opsize = (opsize_raw == 1) ? OpSize::kByte : (opsize_raw == 3 ? OpSize::kWord : OpSize::kLong); - const auto src = FetchAddrModeArg( + const auto src = FetchArg( node.offset + kInstructionSizeStepBytes, code, instr, opsize); if (src.mode == AddrMode::kInvalid) { return disasm_verbatim(node, instr); @@ -622,8 +630,8 @@ static size_t disasm_move_movea( } const int m = (instr >> 6) & 7; const int xn = (instr >> 9) & 7; - const auto dst = FetchAddrModeArg( - node.offset + kInstructionSizeStepBytes + src.Size(), code, m, xn, opsize); + const auto dst = FetchArg( + node.offset + kInstructionSizeStepBytes + src.Size(opsize), code, m, xn, opsize); switch (dst.mode) { case AddrMode::kInvalid: return disasm_verbatim(node, instr); @@ -649,16 +657,16 @@ static size_t disasm_move_movea( } node.opcode = (dst.mode == AddrMode::kAn) ? OpCode::kMOVEA : OpCode::kMOVE; node.size_spec = opsize; - node.arg1 = Arg::FromAddrModeArg(src); - node.arg2 = Arg::FromAddrModeArg(dst); - return node.size = kInstructionSizeStepBytes + src.Size() + dst.Size(); + node.arg1 = src; + node.arg2 = dst; + return node.size = kInstructionSizeStepBytes + src.Size(opsize) + dst.Size(opsize); } static size_t disasm_move_from_sr( DisasmNode &node, const uint16_t instr, const DataBuffer &code) { const auto opsize = OpSize::kWord; - const auto dst = FetchAddrModeArg( + const auto dst = FetchArg( node.offset + kInstructionSizeStepBytes, code, instr, opsize); switch (dst.mode) { case AddrMode::kInvalid: @@ -683,15 +691,15 @@ static size_t disasm_move_from_sr( node.opcode = OpCode::kMOVE; node.size_spec = opsize; node.arg1 = Arg::SR(); - node.arg2 = Arg::FromAddrModeArg(dst); - return node.size = kInstructionSizeStepBytes + dst.Size(); + node.arg2 = dst; + return node.size = kInstructionSizeStepBytes + dst.Size(opsize); } static size_t disasm_move_to( DisasmNode &node, const uint16_t instr, const DataBuffer &code, const ArgType reg) { const auto opsize = OpSize::kWord; - const auto src = FetchAddrModeArg( + const auto src = FetchArg( node.offset + kInstructionSizeStepBytes, code, instr, opsize); switch (src.mode) { case AddrMode::kInvalid: @@ -714,9 +722,9 @@ static size_t disasm_move_to( } node.opcode = OpCode::kMOVE; node.size_spec = opsize; - node.arg1 = Arg::FromAddrModeArg(src); + node.arg1 = src; node.arg2 = Arg{reg, 0}; - return node.size = kInstructionSizeStepBytes + src.Size(); + return node.size = kInstructionSizeStepBytes + src.Size(opsize); } static OpCode opcode_for_negx_clr_neg_not(const unsigned opcode) @@ -750,7 +758,7 @@ static size_t disasm_move_negx_clr_neg_not( assert(false); return disasm_verbatim(node, instr); } - const auto a = FetchAddrModeArg( + const auto a = FetchArg( node.offset + kInstructionSizeStepBytes, code, instr, opsize); switch (a.mode) { case AddrMode::kInvalid: @@ -774,8 +782,8 @@ static size_t disasm_move_negx_clr_neg_not( } node.opcode = opcode_for_negx_clr_neg_not(opcode); node.size_spec = opsize; - node.arg1 = Arg::FromAddrModeArg(a); - return node.size = kInstructionSizeStepBytes + a.Size(); + node.arg1 = a; + return node.size = kInstructionSizeStepBytes + a.Size(opsize); } static inline size_t disasm_trivial( @@ -790,7 +798,7 @@ static inline size_t disasm_tas( DisasmNode &node, const uint16_t instr, const DataBuffer &code) { const auto opsize = OpSize::kByte; - const auto a = FetchAddrModeArg( + const auto a = FetchArg( node.offset + kInstructionSizeStepBytes, code, instr, opsize); switch (a.mode) { case AddrMode::kInvalid: @@ -814,8 +822,8 @@ static inline size_t disasm_tas( } node.opcode = OpCode::kTAS; node.size_spec = opsize; - node.arg1 = Arg::FromAddrModeArg(a); - return node.size = kInstructionSizeStepBytes + a.Size(); + node.arg1 = a; + return node.size = kInstructionSizeStepBytes + a.Size(opsize); } static size_t disasm_tst_tas_illegal( @@ -830,7 +838,7 @@ static size_t disasm_tst_tas_illegal( } return disasm_tas(node, instr, code); } - const auto a = FetchAddrModeArg(node.offset + kInstructionSizeStepBytes, code, m, xn, opsize); + const auto a = FetchArg(node.offset + kInstructionSizeStepBytes, code, m, xn, opsize); switch (a.mode) { case AddrMode::kInvalid: return disasm_verbatim(node, instr); @@ -853,8 +861,8 @@ static size_t disasm_tst_tas_illegal( } node.opcode = OpCode::kTST; node.size_spec = opsize; - node.arg1 = Arg::FromAddrModeArg(a); - return node.size = kInstructionSizeStepBytes + a.Size(); + node.arg1 = a; + return node.size = kInstructionSizeStepBytes + a.Size(opsize); } static size_t disasm_trap(DisasmNode &node, const uint16_t instr) @@ -884,8 +892,8 @@ static size_t disasm_link_unlink(DisasmNode &node, const uint16_t instr, const D node.opcode = OpCode::kLINK; node.size_spec = opsize; node.arg1 = Arg::AddrModeXn(ArgType::kAn, xn); - node.arg2 = Arg::FromAddrModeArg(src); - return node.size = kInstructionSizeStepBytes + src.Size(); + node.arg2 = src; + return node.size = kInstructionSizeStepBytes + src.Size(opsize); } static size_t disasm_move_usp(DisasmNode &node, const uint16_t instr) @@ -907,8 +915,9 @@ static size_t disasm_move_usp(DisasmNode &node, const uint16_t instr) static size_t disasm_nbcd_swap_pea(DisasmNode &node, const uint16_t instr, const DataBuffer &code) { const bool is_nbcd = !((instr >> 6) & 1); - const auto arg = FetchAddrModeArg( - node.offset + kInstructionSizeStepBytes, code, instr, OpSize::kWord); + const OpSize opsize = OpSize::kWord; + const auto arg = FetchArg( + node.offset + kInstructionSizeStepBytes, code, instr, opsize); bool is_swap{}; switch (arg.mode) { case AddrMode::kInvalid: @@ -944,8 +953,8 @@ static size_t disasm_nbcd_swap_pea(DisasmNode &node, const uint16_t instr, const } node.opcode = is_nbcd ? OpCode::kNBCD : is_swap ? OpCode::kSWAP : OpCode::kPEA; node.size_spec = is_nbcd ? OpSize::kByte : is_swap ? OpSize::kWord : OpSize::kLong; - node.arg1 = Arg::FromAddrModeArg(arg); - return node.size = kInstructionSizeStepBytes + arg.Size(); + node.arg1 = arg; + return node.size = kInstructionSizeStepBytes + arg.Size(opsize); } static size_t disasm_stop(DisasmNode &node, const uint16_t instr, const DataBuffer &code) @@ -956,7 +965,7 @@ static size_t disasm_stop(DisasmNode &node, const uint16_t instr, const DataBuff } node.opcode = OpCode::kSTOP; node.size_spec = OpSize::kNone; - node.arg1 = Arg::FromAddrModeArg(a); + node.arg1 = a; return node.size = kInstructionSizeStepBytes * 2; } @@ -1006,7 +1015,7 @@ static size_t disasm_chunk_4(DisasmNode &node, const uint16_t instr, const DataB static size_t disasm_addq_subq( DisasmNode &node, const uint16_t instr, const DataBuffer &code, const OpSize opsize) { - const auto a = FetchAddrModeArg(node.offset + kInstructionSizeStepBytes, code, instr, opsize); + const auto a = FetchArg(node.offset + kInstructionSizeStepBytes, code, instr, opsize); switch (a.mode) { case AddrMode::kInvalid: return disasm_verbatim(node, instr); @@ -1037,8 +1046,8 @@ static size_t disasm_addq_subq( node.opcode = ((instr >> 8) & 1) ? OpCode::kSUBQ : OpCode::kADDQ; node.size_spec = opsize; node.arg1 = Arg::Immediate(imm); - node.arg2 = Arg::FromAddrModeArg(a); - return node.size = kInstructionSizeStepBytes + a.Size(); + node.arg2 = a; + return node.size = kInstructionSizeStepBytes + a.Size(opsize); } static size_t disasm_dbcc(DisasmNode &node, const uint16_t instr, const DataBuffer &code) @@ -1064,8 +1073,9 @@ static size_t disasm_dbcc(DisasmNode &node, const uint16_t instr, const DataBuff static size_t disasm_scc_dbcc(DisasmNode &node, const uint16_t instr, const DataBuffer &code) { - const auto a = FetchAddrModeArg( - node.offset + kInstructionSizeStepBytes, code, instr, OpSize::kWord); + const OpSize opsize = OpSize::kWord; + const auto a = FetchArg( + node.offset + kInstructionSizeStepBytes, code, instr, opsize); switch (a.mode) { case AddrMode::kInvalid: return disasm_verbatim(node, instr); @@ -1090,8 +1100,8 @@ static size_t disasm_scc_dbcc(DisasmNode &node, const uint16_t instr, const Data node.opcode = OpCode::kScc; node.condition = static_cast<Condition>((instr >> 8) & 0xf); node.size_spec = OpSize::kNone; - node.arg1 = Arg::FromAddrModeArg(a); - return node.size = kInstructionSizeStepBytes + a.Size(); + node.arg1 = a; + return node.size = kInstructionSizeStepBytes + a.Size(opsize); } static size_t disasm_addq_subq_scc_dbcc(DisasmNode &n, const uint16_t instr, const DataBuffer &c) @@ -1110,13 +1120,14 @@ static size_t disasm_moveq(DisasmNode &node, const uint16_t instr) return disasm_verbatim(node, instr); } const int xn = (instr >> 9) & 7; - const auto dst = AddrModeArg::Dn(xn); + const auto dst = Arg::Dn(xn); const int8_t data = instr & 0xff; + const OpSize opsize = OpSize::kLong; node.opcode = OpCode::kMOVEQ; - node.size_spec = OpSize::kLong; + node.size_spec = opsize; node.arg1 = Arg::Immediate(data); - node.arg2 = Arg::FromAddrModeArg(dst); - return node.size = kInstructionSizeStepBytes + dst.Size(); + node.arg2 = dst; + return node.size = kInstructionSizeStepBytes + dst.Size(opsize); } @@ -1127,7 +1138,7 @@ static size_t disasm_divu_divs_mulu_muls( const OpCode opcode) { const auto opsize = OpSize::kWord; - const auto src = FetchAddrModeArg( + const auto src = FetchArg( node.offset + kInstructionSizeStepBytes, code, instr, opsize); switch (src.mode) { case AddrMode::kInvalid: @@ -1150,12 +1161,12 @@ static size_t disasm_divu_divs_mulu_muls( break; } const unsigned dn = (instr >> 9) & 7; - const auto dst = AddrModeArg::Dn(dn); + const auto dst = Arg::Dn(dn); node.opcode = opcode; node.size_spec = opsize; - node.arg1 = Arg::FromAddrModeArg(src); - node.arg2 = Arg::FromAddrModeArg(dst); - return node.size = kInstructionSizeStepBytes + dst.Size() + src.Size(); + node.arg1 = src; + node.arg2 = dst; + return node.size = kInstructionSizeStepBytes + dst.Size(opsize) + src.Size(opsize); } static size_t disasm_addx_subx_abcd_sbcd( @@ -1167,16 +1178,16 @@ static size_t disasm_addx_subx_abcd_sbcd( const int m = (instr >> 3) & 1; const int xn = instr & 7; const int xi = (instr >> 9) & 7; - const auto src = m ? AddrModeArg::AnAddrDecr(xn) : AddrModeArg::Dn(xn); - const auto dst = m ? AddrModeArg::AnAddrDecr(xi) : AddrModeArg::Dn(xi); + const auto src = m ? Arg::AnAddrDecr(xn) : Arg::Dn(xn); + const auto dst = m ? Arg::AnAddrDecr(xi) : Arg::Dn(xi); node.opcode = opcode; // XXX GNU AS does not know ABCD.B, it only knows ABCD, but happily consumes // SBCD.B and others. That's why `skip_suffix` flag is needed, specifically // for ABCD mnemonic. It is probably a bug in GNU AS. node.size_spec = (opcode == OpCode::kABCD) ? OpSize::kNone : opsize; - node.arg1 = Arg::FromAddrModeArg(src); - node.arg2 = Arg::FromAddrModeArg(dst); - return node.size = kInstructionSizeStepBytes + src.Size() + dst.Size(); + node.arg1 = src; + node.arg2 = dst; + return node.size = kInstructionSizeStepBytes + src.Size(opsize) + dst.Size(opsize); } static size_t disasm_or_and( @@ -1187,7 +1198,7 @@ static size_t disasm_or_and( const OpCode opcode) { const bool dir_to_addr = (instr >> 8) & 1; - const auto addr = FetchAddrModeArg( + const auto addr = FetchArg( node.offset + kInstructionSizeStepBytes, code, instr, opsize); switch (addr.mode) { case AddrMode::kInvalid: @@ -1222,17 +1233,17 @@ static size_t disasm_or_and( } break; } - const auto reg = AddrModeArg::Dn((instr >> 9) & 7); + const auto reg = Arg::Dn((instr >> 9) & 7); node.opcode = opcode; node.size_spec = opsize; if (dir_to_addr) { - node.arg1 = Arg::FromAddrModeArg(reg); - node.arg2 = Arg::FromAddrModeArg(addr); + node.arg1 = reg; + node.arg2 = addr; } else { - node.arg1 = Arg::FromAddrModeArg(addr); - node.arg2 = Arg::FromAddrModeArg(reg); + node.arg1 = addr; + node.arg2 = reg; } - return node.size = kInstructionSizeStepBytes + addr.Size() + reg.Size(); + return node.size = kInstructionSizeStepBytes + addr.Size(opsize) + reg.Size(opsize); } static size_t disasm_divu_divs_sbcd_or( @@ -1255,7 +1266,7 @@ static inline size_t disasm_adda_suba_cmpa( DisasmNode &node, const uint16_t instr, const DataBuffer &code, const OpCode opcode) { const OpSize opsize = static_cast<OpSize>(((instr >> 8) & 1) + 1); - const auto src = FetchAddrModeArg( + const auto src = FetchArg( node.offset + kInstructionSizeStepBytes, code, instr, opsize); switch (src.mode) { case AddrMode::kInvalid: @@ -1275,12 +1286,12 @@ static inline size_t disasm_adda_suba_cmpa( break; } const unsigned an = (instr >> 9) & 7; - const auto dst = AddrModeArg::An(an); + const auto dst = Arg::An(an); node.opcode = opcode; node.size_spec = opsize; - node.arg1 = Arg::FromAddrModeArg(src); - node.arg2 = Arg::FromAddrModeArg(dst); - return node.size = kInstructionSizeStepBytes + src.Size() + dst.Size(); + node.arg1 = src; + node.arg2 = dst; + return node.size = kInstructionSizeStepBytes + src.Size(opsize) + dst.Size(opsize); } static size_t disasm_add_sub_cmp( @@ -1291,7 +1302,7 @@ static size_t disasm_add_sub_cmp( const OpSize opsize, const bool dir_to_addr) { - const auto addr = FetchAddrModeArg( + const auto addr = FetchArg( node.offset + kInstructionSizeStepBytes, code, instr, opsize); switch (addr.mode) { case AddrMode::kInvalid: @@ -1327,17 +1338,17 @@ static size_t disasm_add_sub_cmp( break; } const unsigned dn = (instr >> 9) & 7; - const auto reg = AddrModeArg::Dn(dn); + const auto reg = Arg::Dn(dn); node.opcode = opcode; node.size_spec = opsize; if (dir_to_addr) { - node.arg1 = Arg::FromAddrModeArg(reg); - node.arg2 = Arg::FromAddrModeArg(addr); + node.arg1 = reg; + node.arg2 = addr; } else { - node.arg1 = Arg::FromAddrModeArg(addr); - node.arg2 = Arg::FromAddrModeArg(reg); + node.arg1 = addr; + node.arg2 = reg; } - return node.size = kInstructionSizeStepBytes + addr.Size() + reg.Size(); + return node.size = kInstructionSizeStepBytes + addr.Size(opsize) + reg.Size(opsize); } static size_t disasm_cmpm(DisasmNode &node, const uint16_t instr) @@ -1350,19 +1361,19 @@ static size_t disasm_cmpm(DisasmNode &node, const uint16_t instr) (void) m; const int xn = instr & 7; const int xi = (instr >> 9) & 7; - const auto src = AddrModeArg::AnAddrIncr(xn); - const auto dst = AddrModeArg::AnAddrIncr(xi); + const auto src = Arg::AnAddrIncr(xn); + const auto dst = Arg::AnAddrIncr(xi); node.opcode = OpCode::kCMPM; node.size_spec = opsize; - node.arg1 = Arg::FromAddrModeArg(src); - node.arg2 = Arg::FromAddrModeArg(dst); - return node.size = kInstructionSizeStepBytes + src.Size() + dst.Size(); + node.arg1 = src; + node.arg2 = dst; + return node.size = kInstructionSizeStepBytes + src.Size(opsize) + dst.Size(opsize); } static size_t disasm_eor(DisasmNode &node, const uint16_t instr, const DataBuffer &code) { const OpSize opsize = static_cast<OpSize>((instr >> 6) & 3); - const auto addr = FetchAddrModeArg( + const auto addr = FetchArg( node.offset + kInstructionSizeStepBytes, code, instr, opsize); switch (addr.mode) { case AddrMode::kInvalid: @@ -1385,12 +1396,12 @@ static size_t disasm_eor(DisasmNode &node, const uint16_t instr, const DataBuffe // PC relative and immediate cannot be destination return disasm_verbatim(node, instr); } - const auto reg = AddrModeArg::Dn((instr >> 9) & 7); + const auto reg = Arg::Dn((instr >> 9) & 7); node.opcode = OpCode::kEOR; node.size_spec = opsize; - node.arg1 = Arg::FromAddrModeArg(reg); - node.arg2 = Arg::FromAddrModeArg(addr); - return node.size = kInstructionSizeStepBytes + addr.Size() + reg.Size(); + node.arg1 = reg; + node.arg2 = addr; + return node.size = kInstructionSizeStepBytes + addr.Size(opsize) + reg.Size(opsize); } static size_t disasm_eor_cmpm_cmp_cmpa( @@ -1422,13 +1433,14 @@ static inline size_t disasm_exg(DisasmNode &node, const uint16_t instr) assert(m != 4); // Only m == 2, m == 3 and m == 5 values are allowed const int xn = instr & 7; const int xi = (instr >> 9) & 7; - const auto src = (m == 3) ? AddrModeArg::An(xi) : AddrModeArg::Dn(xi); - const auto dst = (m == 2) ? AddrModeArg::Dn(xn) : AddrModeArg::An(xn); + const auto src = (m == 3) ? Arg::An(xi) : Arg::Dn(xi); + const auto dst = (m == 2) ? Arg::Dn(xn) : Arg::An(xn); + const auto opsize = OpSize::kNone; node.opcode = OpCode::kEXG; - node.size_spec = OpSize::kNone; - node.arg1 = Arg::FromAddrModeArg(src); - node.arg2 = Arg::FromAddrModeArg(dst); - return node.size = kInstructionSizeStepBytes + src.Size() + dst.Size(); + node.size_spec = opsize; + node.arg1 = src; + node.arg2 = dst; + return node.size = kInstructionSizeStepBytes + src.Size(opsize) + dst.Size(opsize); } static size_t disasm_chunk_c(DisasmNode &node, const uint16_t instr, const DataBuffer &code) @@ -1497,8 +1509,8 @@ static size_t disasm_shift_rotate(DisasmNode &node, const uint16_t instr, const return disasm_verbatim(node, instr); } const auto dst = (opsize == OpSize::kInvalid) - ? FetchAddrModeArg(node.offset + kInstructionSizeStepBytes, code, instr, opsize) - : AddrModeArg::Dn(xn); + ? FetchArg(node.offset + kInstructionSizeStepBytes, code, instr, opsize) + : Arg::Dn(xn); if (opsize == OpSize::kInvalid) { switch (dst.mode) { case AddrMode::kInvalid: @@ -1530,13 +1542,13 @@ static size_t disasm_shift_rotate(DisasmNode &node, const uint16_t instr, const node.opcode = ShiftKindToOpcode(kind, dir); node.size_spec = opsize; if (opsize == OpSize::kInvalid) { - node.arg1 = Arg::FromAddrModeArg(dst); + node.arg1 = dst; } else { const unsigned m = (instr >> 5) & 1; node.arg1 = m ? Arg::AddrModeXn(ArgType::kDn, src) : Arg::Immediate(imm); - node.arg2 = Arg::FromAddrModeArg(dst); + node.arg2 = dst; } - return node.size = kInstructionSizeStepBytes + dst.Size(); + return node.size = kInstructionSizeStepBytes + dst.Size(opsize); } static size_t m68k_disasm(DisasmNode &n, uint16_t i, const DataBuffer &c) @@ -1759,34 +1771,19 @@ static int OpcodeSNPrintf( return snprintf(buf, bufsz, "%s%s", ToString(opcode, condition), ToString(size_spec)); } -static char RegChar(RegKind k) +static char RegChar(const uint8_t xi) { - switch (k) { - case RegKind::kDnWord: - case RegKind::kDnLong: - return 'd'; - case RegKind::kAnWord: - case RegKind::kAnLong: - return 'a'; - } - assert(false); - return 'd'; + return (xi & 0x08) ? 'a' : 'd'; } -static char SizeSpecChar(RegKind k) +static char SizeSpecChar(const uint8_t xi) { - switch (k) { - case RegKind::kDnWord: - return 'w'; - case RegKind::kDnLong: - return 'l'; - case RegKind::kAnWord: - return 'w'; - case RegKind::kAnLong: - return 'l'; - } - assert(false); - return 'w'; + return (xi & 0x10) ? 'l' : 'w'; +} + +static unsigned RegNum(const uint8_t xi) +{ + return xi & 0x7; } static inline size_t snprint_reg_mask( @@ -1843,12 +1840,12 @@ int Arg::SNPrint(char *const buf, const size_t bufsz, const Settings &) const return snprintf(buf, bufsz, "%%a%u@(%d:w)", d16_an.an, d16_an.d16); case ArgType::kD8AnXiAddr: return snprintf( - buf, bufsz, "%%a%u@(%d,%%%c%d:%c)", + buf, bufsz, "%%a%u@(%d,%%%c%u:%c)", d8_an_xi.an, d8_an_xi.d8, - RegChar(d8_an_xi.kind), - d8_an_xi.xi, - SizeSpecChar(d8_an_xi.kind)); + RegChar(d8_an_xi.xi), + RegNum(d8_an_xi.xi), + SizeSpecChar(d8_an_xi.xi)); case ArgType::kWord: return snprintf(buf, bufsz, "0x%x:w", lword); case ArgType::kLong: @@ -1857,11 +1854,11 @@ int Arg::SNPrint(char *const buf, const size_t bufsz, const Settings &) const return snprintf(buf, bufsz, "%%pc@(%d:w)", d16_pc.d16); case ArgType::kD8PCXiAddr: return snprintf( - buf, bufsz, "%%pc@(%d,%%%c%d:%c)", + buf, bufsz, "%%pc@(%d,%%%c%u:%c)", d8_pc_xi.d8, - RegChar(d8_pc_xi.kind), - d8_pc_xi.xi, - SizeSpecChar(d8_pc_xi.kind)); + RegChar(d8_pc_xi.xi), + RegNum(d8_pc_xi.xi), + SizeSpecChar(d8_pc_xi.xi)); case ArgType::kImmediate: return snprintf(buf, bufsz, "#%d", lword); case ArgType::kRegMask: @@ -10,22 +10,6 @@ #include <cstdint> #include <cstdio> -enum class AddrMode: uint8_t { - kInvalid = 0, - kDn, - kAn, - kAnAddr, - kAnAddrIncr, - kAnAddrDecr, - kD16AnAddr, - kD8AnXiAddr, - kWord, - kLong, - kD16PCAddr, - kD8PCXiAddr, - kImmediate, -}; - enum class OpSize: int { kByte = 0, kWord = 1, @@ -35,90 +19,6 @@ enum class OpSize: int { kShort, ///< Semantically is the same as kByte, pseudosize, used for Bcc }; -struct AddrModeArg { - AddrMode mode{}; - uint8_t xn{}; /// Xn register number: 0..7 - char r{}; /// Xi register type specifier letter: either 'd' or 'a' - uint8_t xi{}; /// Xi register number: 0..7 - OpSize s{}; /// Size specifier of Xi or imm - int32_t value{}; /// Word, Long or Immediate - /// Size of the extension: 0, 2 or 4 bytes - constexpr size_t Size() 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: - return s == OpSize::kLong ? 4 : 2; - } - return 0; - } - static constexpr AddrModeArg Dn(uint8_t xn) - { - return AddrModeArg{AddrMode::kDn, xn}; - } - static constexpr AddrModeArg An(uint8_t xn) - { - return AddrModeArg{AddrMode::kAn, xn}; - } - static constexpr AddrModeArg AnAddr(uint8_t xn) - { - return AddrModeArg{AddrMode::kAnAddr, xn}; - } - static constexpr AddrModeArg AnAddrIncr(uint8_t xn) - { - return AddrModeArg{AddrMode::kAnAddrIncr, xn}; - } - static constexpr AddrModeArg AnAddrDecr(uint8_t xn) - { - return AddrModeArg{AddrMode::kAnAddrDecr, xn}; - } - static constexpr AddrModeArg D16AnAddr(uint8_t xn, int16_t d16) - { - return AddrModeArg{AddrMode::kD16AnAddr, xn, 0, 0, OpSize::kWord, d16}; - } - static constexpr AddrModeArg D8AnXiAddr( - uint8_t xn, char r, uint8_t xi, OpSize s, int8_t d8) - { - return AddrModeArg{AddrMode::kD8AnXiAddr, xn, r, xi, s, d8}; - } - static constexpr AddrModeArg Word(int16_t w) - { - return AddrModeArg{AddrMode::kWord, 0, 0, 0, OpSize::kWord, w}; - } - static constexpr AddrModeArg Long(int32_t l) - { - return AddrModeArg{AddrMode::kLong, 1, 0, 0, OpSize::kWord, l}; - } - static constexpr AddrModeArg D16PCAddr(uint8_t xn, int16_t d16) - { - return AddrModeArg{AddrMode::kD16PCAddr, xn, 0, 0, OpSize::kWord, d16}; - } - static constexpr AddrModeArg D8PCXiAddr( - uint8_t xn, char r, uint8_t xi, OpSize s, int8_t d8) - { - return AddrModeArg{AddrMode::kD8PCXiAddr, xn, r, xi, s, d8}; - } - static constexpr AddrModeArg Immediate(OpSize s, int32_t value) - { - return AddrModeArg{AddrMode::kImmediate, 4, 0, 0, s, value}; - } -}; - enum class OpCode: uint8_t { kNone, kRaw, ///< Emits ".short" @@ -215,40 +115,52 @@ enum class Condition: uint8_t { 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, - kRaw, ///< Emits "0xXXXX" for ".short" - kDn, ///< Dn - kAn, ///< An - kAnAddr, ///< (An) - kAnAddrIncr, ///< (An)+ - kAnAddrDecr, ///< -(An) - kD16AnAddr, ///< (d16,An) - kD8AnXiAddr, ///< (d8,An,Xi) - kWord, ///< (xxx).W - kLong, ///< (xxx).L - kD16PCAddr, ///< (d16,PC) - kD8PCXiAddr, ///< (d8,PC,Xn) - kImmediate, ///< #imm + 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, -}; - -enum class RegKind: uint8_t { - kDnWord, - kDnLong, - kAnWord, - kAnLong, + kRaw, ///< Emits "0xXXXX" for ".short" }; struct D8AnPCXiAddr { - RegKind kind; ///< Kind of Xi reg, for kD8AnXiAddr and kD8PCXiAddr uint8_t an; ///< ID number of An reg, for kD8AnXiAddr only - uint8_t xi; ///< ID number of Xi reg, for kD8AnXiAddr and kD8PCXiAddr + /*! 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 }; @@ -257,12 +169,14 @@ struct D16AnPCAddr { int16_t d16; ///< Displacement, for D16AnAddr and kD16PCAddr }; -static_assert(sizeof(D8AnPCXiAddr) == sizeof(uint32_t), ""); -static_assert(sizeof(D16AnPCAddr) == sizeof(uint32_t), ""); +static_assert(sizeof(D8AnPCXiAddr) <= sizeof(uint32_t), ""); +static_assert(sizeof(D16AnPCAddr) <= sizeof(uint32_t), ""); struct Arg { - using Self = Arg; - ArgType type{ArgType::kNone}; + union { + ArgType type{ArgType::kNone}; + AddrMode mode; + }; union { int32_t lword{}; ///< kLong, kWord, kDisplacement, kImmediate uint16_t uword; ///< kRegMask, kRaw @@ -272,129 +186,113 @@ struct Arg { D8AnPCXiAddr d8_an_xi; ///< kD8AnXiAddr D8AnPCXiAddr d8_pc_xi; ///< kD8PCXiAddr }; - static constexpr Self Raw(const uint16_t instr) { - Arg a{ArgType::kRaw, 0}; - a.uword = instr; - return a; - } - static constexpr Self RegMask(const uint16_t regmask) { - Arg a{ArgType::kRegMask, 0}; - a.uword = regmask; - return a; - } - static constexpr Self RegMaskPredecrement(const uint16_t regmask) { - Arg a{ArgType::kRegMaskPredecrement, 0}; - a.uword = regmask; - return a; - } - static constexpr Self Displacement(const int32_t displacement) { - Arg a{ArgType::kDisplacement, 0}; - a.lword = displacement; - return a; - } - static constexpr Self Immediate(int32_t value) { - Arg a{ArgType::kImmediate, 0}; - a.lword = value; - return a; + /// 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 Self CCR() { return Arg{ArgType::kCCR, 0}; } - static constexpr Self SR() { return Arg{ArgType::kSR, 0}; } - static constexpr Self USP() { return Arg{ArgType::kUSP, 0}; } - static constexpr Self AddrModeXn(const ArgType type, const uint8_t xn) { + static constexpr auto AddrModeXn(const ArgType type, const uint8_t xn) { Arg a{type, 0}; a.xn = xn; return a; } -private: - static constexpr Self addrModeD16AnAddr(const D16AnPCAddr d16_an) { + 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 = d16_an; + a.d16_an = D16AnPCAddr{xn, d16}; return a; } - static constexpr Self addrModeD16PCAddr(const D16AnPCAddr d16_pc) { + static constexpr auto D16PCAddr(const int16_t d16) + { Arg a{ArgType::kD16PCAddr, 0}; - a.d16_pc = d16_pc; + a.d16_pc = D16AnPCAddr{0, d16}; return a; } - static constexpr Self addrModeWord(const int16_t value) { + static constexpr auto Word(const int16_t w) + { Arg a{ArgType::kWord, 0}; - a.lword = value; + a.lword = w; return a; } - static constexpr Self addrModeLong(const int32_t value) { + static constexpr auto Long(const int32_t l) + { Arg a{ArgType::kLong, 0}; - a.lword = value; + a.lword = l; return a; } - static constexpr Self addrModeD8AnAddr(const D8AnPCXiAddr d8_an_xi) { + 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 = d8_an_xi; + a.d8_an_xi = D8AnPCXiAddr{xn, uint8_t(xi | (s == OpSize::kLong ? 0x10u : 0u)), d8}; return a; } - static constexpr Self addrModeD8PCAddr(const D8AnPCXiAddr d8_pc_xi) { + 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 = d8_pc_xi; + a.d8_pc_xi = D8AnPCXiAddr{xn, uint8_t(xi | (s == OpSize::kLong ? 0x10u : 0u)), d8}; return a; } - static constexpr Self addrModeImmediate(const int32_t value) { + static constexpr auto Immediate(const int32_t value) { Arg a{ArgType::kImmediate, 0}; a.lword = value; return a; } - static constexpr RegKind regKindFromRegCharSizeChar(char r, OpSize s) - { - if (r == 'd' && s == OpSize::kWord) { - return RegKind::kDnWord; - } else if (r == 'd' && s == OpSize::kLong) { - return RegKind::kDnLong; - } else if (r == 'a' && s == OpSize::kWord) { - return RegKind::kAnWord; - } else if (r == 'a' && s == OpSize::kLong) { - return RegKind::kAnLong; - } - return RegKind::kDnWord; + static constexpr auto RegMask(const uint16_t regmask) { + Arg a{ArgType::kRegMask, 0}; + a.uword = regmask; + return a; } -public: - static constexpr Self FromAddrModeArg(AddrModeArg arg) { - switch (arg.mode) { - case AddrMode::kInvalid: - return Arg{}; - case AddrMode::kDn: - return AddrModeXn(ArgType::kDn, arg.xn); - case AddrMode::kAn: - return AddrModeXn(ArgType::kAn, arg.xn); - case AddrMode::kAnAddr: - return AddrModeXn(ArgType::kAnAddr, arg.xn); - case AddrMode::kAnAddrIncr: - return AddrModeXn(ArgType::kAnAddrIncr, arg.xn); - case AddrMode::kAnAddrDecr: - return AddrModeXn(ArgType::kAnAddrDecr, arg.xn); - case AddrMode::kD16AnAddr: - return addrModeD16AnAddr(D16AnPCAddr{arg.xn, static_cast<int16_t>(arg.value)}); - case AddrMode::kD8AnXiAddr: - return addrModeD8AnAddr(D8AnPCXiAddr{ - regKindFromRegCharSizeChar(arg.r, arg.s), - arg.xn, - arg.xi, - static_cast<int8_t>(arg.value), - }); - case AddrMode::kWord: - return addrModeWord(arg.value); - case AddrMode::kLong: - return addrModeLong(arg.value); - case AddrMode::kD16PCAddr: - return addrModeD16PCAddr(D16AnPCAddr{0, static_cast<int16_t>(arg.value)}); - case AddrMode::kD8PCXiAddr: - return addrModeD8PCAddr(D8AnPCXiAddr{ - regKindFromRegCharSizeChar(arg.r, arg.s), - 0, - arg.xi, - static_cast<int8_t>(arg.value), - }); - case AddrMode::kImmediate: - return addrModeImmediate(arg.value); - } - return Arg{}; + 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, const Settings&) const; }; @@ -426,6 +324,15 @@ struct ReferenceNode { 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 +}; + struct DisasmNode { const TracedNodeType type{}; /// Absolute offset of the instruction (PC value basically) @@ -441,11 +348,12 @@ struct DisasmNode { bool is_call{}; ReferenceNode *ref_by{}; ReferenceNode *last_ref_by{}; - OpCode opcode{OpCode::kNone}; ///< Should replace `mnemonic` field + 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{}, arg2{}; ///< Should replace `arguments` field + Arg arg1{}, arg2{}; ///< Argument specifiers (in order as in asm listing) + Op op{}; /*! Disassembles instruction with arguments * returns size of whole instruction with arguments in bytes |