summaryrefslogtreecommitdiff
path: root/disasm.cpp
diff options
context:
space:
mode:
authorOxore <oxore@protonmail.com>2023-05-08 14:57:10 +0300
committerOxore <oxore@protonmail.com>2023-05-08 14:57:10 +0300
commit9922aef7a58bb29fcfb90ecb5c718f6465e0d6ab (patch)
tree701714ceaf8f1b8919268c19b2b1a938c7bf977b /disasm.cpp
parent6f08b26adb8337feb27e354d9aa2e2470404b5ca (diff)
Impl ASR, ASL, LSR, LSL, ROXR, ROXL, ROR and ROL
Diffstat (limited to 'disasm.cpp')
-rw-r--r--disasm.cpp94
1 files changed, 89 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<int>(k) < 4;
+}
+
+static void disasm_shift_rotate(
+ DisasmNode &node, uint16_t instr, const DataBuffer &code, const Settings &s)
+{
+ const OpSize opsize = static_cast<OpSize>((instr >> 6) & 3);
+ const unsigned xn = instr & 7;
+ const uint8_t rotation = (instr >> 9) & 7;
+ const ShiftKind kind = (opsize == OpSize::kInvalid)
+ ? static_cast<ShiftKind>(rotation)
+ : static_cast<ShiftKind>((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<ShiftDirection>((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);