From 9922aef7a58bb29fcfb90ecb5c718f6465e0d6ab Mon Sep 17 00:00:00 2001 From: Oxore Date: Mon, 8 May 2023 14:57:10 +0300 Subject: Impl ASR, ASL, LSR, LSL, ROXR, ROXL, ROR and ROL --- disasm.cpp | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- test.bash | 17 ++++++++++++ 2 files changed, 106 insertions(+), 5 deletions(-) diff --git a/disasm.cpp b/disasm.cpp index bd2a329..7e4aba3 100644 --- a/disasm.cpp +++ b/disasm.cpp @@ -17,6 +17,18 @@ enum class MoveDirection: bool { kMemoryToRegister = 1, }; +enum class ShiftDirection: bool { + kRight = 0, + kLeft = 1, +}; + +enum class ShiftKind: int { + kArithmeticShift = 0, + kLogicalShift = 1, + kRotateX = 2, + kRotate = 3, +}; + enum class OpSize: int { kByte = 0, kWord = 1, @@ -273,9 +285,9 @@ static char suffix_from_opsize(OpSize opsize) case OpSize::kByte: return 'b'; case OpSize::kWord: return 'w'; case OpSize::kLong: return 'l'; - case OpSize::kInvalid: return 'l'; + case OpSize::kInvalid: return 'w'; } - return 'l'; + return 'w'; } static inline size_t snprint_reg_mask( @@ -1485,9 +1497,81 @@ static void disasm_add_sub_x_a( node.size = kInstructionSizeStepBytes + addr.Size() + reg.Size(); } -static void chunk_mf000_ve000(DisasmNode &n, uint16_t i, const DataBuffer &c, const Settings &s) +static inline const char *ShiftKindToMnemonic(const ShiftKind k) { - return disasm_verbatim(n, i, c, s); + switch (k) { + case ShiftKind::kArithmeticShift: return "as"; + case ShiftKind::kLogicalShift: return "ls"; + case ShiftKind::kRotateX: return "rox"; + case ShiftKind::kRotate: return "ro"; + } + assert(false); + return "?"; +} + +static inline bool IsValidShiftKind(const ShiftKind k) +{ + return static_cast(k) < 4; +} + +static void disasm_shift_rotate( + DisasmNode &node, uint16_t instr, const DataBuffer &code, const Settings &s) +{ + const OpSize opsize = static_cast((instr >> 6) & 3); + const unsigned xn = instr & 7; + const uint8_t rotation = (instr >> 9) & 7; + const ShiftKind kind = (opsize == OpSize::kInvalid) + ? static_cast(rotation) + : static_cast((instr >> 3) & 3); + if (!IsValidShiftKind(kind)) { + return disasm_verbatim(node, instr, code, s); + } + const unsigned m = (instr >> 5) & 1; + const char suffix = suffix_from_opsize(opsize); + const auto dst = (opsize == OpSize::kInvalid) + ? AddrModeArg::Fetch(node.offset + kInstructionSizeStepBytes, code, instr, suffix) + : AddrModeArg::Dn(xn); + if (opsize == OpSize::kInvalid) { + switch (dst.mode) { + case AddrMode::kInvalid: + return disasm_verbatim(node, instr, code, s); + case AddrMode::kDn: + // Intersects with situation when args are "#1,%dx". GNU AS would + // not understand shift instruction with single argument of "%dx". + return disasm_verbatim(node, instr, code, s); + break; + case AddrMode::kAn: + return disasm_verbatim(node, instr, code, s); + case AddrMode::kAnAddr: + case AddrMode::kAnAddrIncr: + case AddrMode::kAnAddrDecr: + case AddrMode::kD16AnAddr: + case AddrMode::kD8AnXiAddr: + case AddrMode::kWord: + case AddrMode::kLong: + break; + case AddrMode::kD16PCAddr: + case AddrMode::kD8PCXiAddr: + case AddrMode::kImmediate: + return disasm_verbatim(node, instr, code, s); + } + } + const unsigned imm = ((rotation - 1) & 7) + 1; + const unsigned src = (opsize == OpSize::kInvalid) ? 1 : rotation; + const auto dir = static_cast((instr >> 8) & 1); + char dst_str[32]{}; + dst.SNPrint(dst_str, sizeof(dst_str)); + const char *mnemonic = ShiftKindToMnemonic(kind); + const char dirchar = (dir == ShiftDirection::kRight) ? 'r' : 'l'; + snprintf(node.mnemonic, kMnemonicBufferSize, "%s%c%c", mnemonic, dirchar, suffix); + if (opsize == OpSize::kInvalid) { + snprintf(node.arguments, kArgsBufferSize, "%s", dst_str); + } else if (m == 1) { + snprintf(node.arguments, kArgsBufferSize, "%%d%u,%s", src, dst_str); + } else { + snprintf(node.arguments, kArgsBufferSize, "#%u,%s", imm, dst_str); + } + node.size = kInstructionSizeStepBytes + dst.Size(); } static void m68k_disasm(DisasmNode &n, uint16_t i, const DataBuffer &c, const Settings &s) @@ -1521,7 +1605,7 @@ static void m68k_disasm(DisasmNode &n, uint16_t i, const DataBuffer &c, const Se case 0xd: return disasm_add_sub_x_a(n, i, c, s, "add"); case 0xe: - return chunk_mf000_ve000(n, i, c, s); + return disasm_shift_rotate(n, i, c, s); case 0xf: // Does not exist return disasm_verbatim(n, i, c, s); diff --git a/test.bash b/test.bash index 854ac56..b4dd6ac 100644 --- a/test.bash +++ b/test.bash @@ -93,6 +93,23 @@ run_test_iterative() { done } +# exxx asl, asr, lsl, lsr, roxl, roxr, rol, ror +# +run_test_simple "asrb Dn, Dn" "\xe2\x22" +run_test_simple "asrb #1, Dn" "\xe2\x02" +run_test_simple "asrb #8, Dn" "\xe0\x02" +run_test_simple "aslb #7, Dn" "\xef\x02" +run_test_simple "asrw Dn, Dn" "\xe2\x62" +run_test_simple "asrl Dn, Dn" "\xe2\xa2" +run_test_simple "aslw #6, Dn" "\xed\x43" +run_test_simple "asll #5, Dn" "\xeb\x83" +run_test_simple "asrw (An)" "\xe0\xd0" +run_test_simple "lsrw (An)+" "\xe2\xd8" +run_test_simple "roxrw -(An)" "\xe4\xe0" +run_test_simple "rorw (d16,An)" "\xe6\xef\x01\x00" +# Found on random tests +run_test_simple "lsrb D1,D4" "\xe2\x2c" + # 9xxx subx # run_test_simple "subxb Dn, Dn" "\x91\x00" -- cgit v1.2.3