diff options
-rw-r--r-- | disasm.cpp | 131 | ||||
-rw-r--r-- | test.bash | 34 |
2 files changed, 162 insertions, 3 deletions
@@ -534,9 +534,134 @@ static void disasm_bra_bsr_bcc( return; } -static void chunk_mf000_v0000(DisasmNode& n, uint16_t i, const DataBuffer &c, const Settings &s) +const char *mnemonic_for_bitops(OpSize opsize) { - return disasm_verbatim(n, i, c, s); + switch (opsize) { + case OpSize::kByte: return "btst"; + case OpSize::kWord: return "bchg"; + case OpSize::kLong: return "bclr"; + case OpSize::kInvalid: return "bset"; + } + assert(false); + return "?"; +} + +static void disasm_dobule_args_bitops_movep( + DisasmNode& node, uint16_t instr, const DataBuffer &code, const Settings &s) +{ + // TODO + return disasm_verbatim(node, instr, code, s); +} + +static void disasm_bitops( + DisasmNode& node, uint16_t instr, const DataBuffer &code, const Settings &s) +{ + // TODO + return disasm_verbatim(node, instr, code, s); +} + +static inline void disasm_logical_imm_to( + DisasmNode& node, const char* mnemonic, const char suffix, const int16_t imm) +{ + const char *reg = suffix == 'b' ? "ccr" : "sr"; + snprintf(node.mnemonic, kMnemonicBufferSize, "%s%c", mnemonic, suffix); + snprintf(node.arguments, kArgsBufferSize, "#%d,%%%s", imm, reg); + node.size = kInstructionSizeStepBytes * 2; +} + +const char *mnemonic_for_chunk_mf000_v1000(const unsigned opcode) +{ + switch (opcode) { + case 0: return "ori"; + case 1: return "andi"; + case 2: return "subi"; + case 3: return "addi"; + case 4: break; + case 5: return "eori"; + case 6: return "cmpi"; + case 7: break; + } + assert(false); + return "?"; +} + +static void chunk_mf000_v0000( + DisasmNode& node, uint16_t instr, const DataBuffer &code, const Settings &s) +{ + const bool has_source_reg = (instr >> 8) & 1; + if (has_source_reg) { + return disasm_dobule_args_bitops_movep(node, instr, code, s); + } + const unsigned opcode = (instr >> 9) & 7; + if (opcode == 7) { + // Does not exist + return disasm_verbatim(node, instr, code, s); + } + if (opcode == 4) { + return disasm_bitops(node, instr, code, s); + } + const int m = (instr >> 3) & 7; + const int xn = instr & 7; + const auto opsize = static_cast<OpSize>((instr >> 6) & 3); + if (opsize == OpSize::kInvalid) { + // Does not exist + return disasm_verbatim(node, instr, code, s); + } + // Anticipating #imm which means "to CCR"/"to SR", depending on OpSize + if (m == 7 && xn == 4) { + if (opcode == 2 || opcode == 3 || opcode == 6) { + // CMPI, SUBI and ANDI neither have immediate destination arguments + // nor "to CCR"/"to SR" variations + return disasm_verbatim(node, instr, code, s); + } + if (opsize == OpSize::kLong) { + // Does not exist + return disasm_verbatim(node, instr, code, s); + } + } + const char suffix = suffix_from_opsize(opsize); + const auto src = AddrModeArg::Fetch( + node.offset + kInstructionSizeStepBytes, code, 7, 4, suffix); + if (src.mode == AddrMode::kInvalid) { + return disasm_verbatim(node, instr, code, s); + } + assert(src.mode == AddrMode::kImmediate); + const char *mnemonic = mnemonic_for_chunk_mf000_v1000(opcode); + if (m == 7 && xn == 4) { + return disasm_logical_imm_to(node, mnemonic, suffix, src.value); + } + const auto dst = AddrModeArg::Fetch( + node.offset + kInstructionSizeStepBytes + src.Size(), code, m, xn, suffix); + switch (dst.mode) { + case AddrMode::kInvalid: + return disasm_verbatim(node, instr, code, s); + case AddrMode::kDn: + 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: + if (opcode != 6) { + // PC relative destination address argument available for CMPI only + return disasm_verbatim(node, instr, code, s); + } + break; + case AddrMode::kImmediate: + return disasm_verbatim(node, instr, code, s); + } + char dst_str[32]{}; + dst.SNPrint(dst_str, sizeof(dst_str)); + snprintf(node.mnemonic, kMnemonicBufferSize, "%s%c", mnemonic, suffix); + snprintf(node.arguments, kArgsBufferSize, "#%d,%s", src.value, dst_str); + node.size = kInstructionSizeStepBytes + src.Size() + dst.Size(); } static void disasm_move_movea( @@ -760,7 +885,7 @@ static void disasm_tst_tas_illegal( { const auto opsize = static_cast<OpSize>((instr >> 6) & 3); const int m = (instr >> 3) & 7; - const int xn = instr& 7; + const int xn = instr & 7; if (opsize == OpSize::kInvalid) { if (m == 7 && xn == 4){ return disasm_trivial(node, instr, code, s, "illegal"); @@ -93,6 +93,34 @@ run_test_iterative() { done } +# 0xxx +# +run_test_simple "orib zero to CCR" "\x00\x3c\x00\x00" +run_test_simple "orib positive to CCR" "\x00\x3c\x00\x01" +run_test_simple "orib positive to CCR" "\x00\x3c\x00\x7f" +run_test_expect_short "orib #imm (too much for orib) to CCR" "\x00\x3c\x01\x00" +run_test_simple "orib negative to CCR" "\x00\x3c\xff\x80" +run_test_simple "orib negative to CCR" "\x00\x3c\xff\xff" +run_test_simple "oriw zero to SR" "\x00\x7c\x00\x00" +run_test_simple "oriw positive to SR" "\x00\x7c\x00\x0a" +run_test_simple "andiw positive to SR" "\x02\x7c\x00\x0a" +run_test_simple "eoriw positive to SR" "\x0a\x7c\x00\x0a" +run_test_simple "andib positive to CCR" "\x02\x3c\x00\x0a" +run_test_simple "eorib positive to CCR" "\x0a\x3c\x00\x0a" +run_test_simple "orib positive to Dn" "\x00\x07\x00\x0a" +run_test_simple "oriw positive to Dn" "\x00\x45\x00\x0a" +run_test_simple "oril positive to Dn" "\x00\x83\x00\x00\x00\x0a" +run_test_simple "andib negative to Dn" "\x00\x07\xff\x80" +run_test_simple "andiw negative to Dn" "\x00\x45\xff\x80" +run_test_simple "andil negative to Dn" "\x00\x83\xff\x80\x00\x00" +run_test_simple "addiw zero to (An)+" "\x06\x5a\x00\x00" +run_test_simple "subiw zero from -(An)" "\x06\x62\x00\x00" +run_test_simple "cmpib zero to (An)" "\x0c\x12\x00\x20" +run_test_simple "cmpiw zero to (An)" "\x0c\x52\x00\x30" +run_test_simple "cmpil zero to (An)" "\x0c\x92\x00\x00\x00\x40" +# From random tests +run_test_expect_short "cmpil with invalid opsize" "\x0c\xe4\x26\xa3" + # 4axx # run_test_simple "tas Dn" "\x4a\xc2" @@ -356,6 +384,12 @@ run_test_simple "blts" "\x6d\x0a" run_test_simple "bgts" "\x6e\x0a" run_test_simple "bles" "\x6f\x0a" +# 4afc +# +# reset +# +run_test_simple "illegal" "\x4a\xfc" + # 4e70 # # reset |