diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/devices/cpu/m16c/m16cdasm.cpp | 1193 | ||||
-rw-r--r-- | src/devices/cpu/m16c/m16cdasm.h | 52 | ||||
-rw-r--r-- | src/tools/unidasm.cpp | 2 |
3 files changed, 1247 insertions, 0 deletions
diff --git a/src/devices/cpu/m16c/m16cdasm.cpp b/src/devices/cpu/m16c/m16cdasm.cpp new file mode 100644 index 00000000000..6421dce9b66 --- /dev/null +++ b/src/devices/cpu/m16c/m16cdasm.cpp @@ -0,0 +1,1193 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/*************************************************************************** + + Mitsubishi/Renesas M16C disassembler + +***************************************************************************/ + +#include "emu.h" +#include "m16cdasm.h" + +m16c_disassembler::m16c_disassembler() + : util::disasm_interface() +{ +} + +const char *const m16c_disassembler::s_regs[2][6] = +{ + { "R0L", "R0H", "R1L", "R1H", "A0", "A1" }, + { "R0", "R1", "R2", "R3", "A0", "A1" } +}; + +const char *const m16c_disassembler::s_cregs[8] = +{ + "", "INTBL", "INTBH", "FLG", "ISP", "SP", "SB", "FB" +}; + +const char *const m16c_disassembler::s_byte_ops[8] = +{ + "mov.b", "mov.b", + "and.b", "or.b", + "add.b", "sub.b", + "mov.b", "cmp.b" +}; + +const char *const m16c_disassembler::s_bit_ops[14] = +{ + "btstc", "btsts", + "bmcnd", "bntst", + "band", "bnand", + "bor", "bnor", + "bclr", "bset", + "bnot", "btst", + "bxor", "bxnor" +}; + +const char *const m16c_disassembler::s_cnds[16] = +{ + "c", "gtu", "z", "n", // GEU = C, EQ = Z + "nc", "leu", "nz", "pz", // LTU = NC, NE = NZ + "le", "o", "ge", "", + "gt", "no", "lt", "" +}; + +const char *const m16c_disassembler::s_imm76_ops[2][9] = +{ + { "tst.b", "xor.b", "and.b", "or.b", "add.b", "sub.b", "adc.b", "sbb.b", "cmp.b" }, + { "tst.w", "xor.w", "and.w", "or.w", "add.w", "sub.w", "adc.w", "sbb.w", "cmp.w" } +}; + +const char *const m16c_disassembler::s_nibmov_ops[4] = +{ + "movll", "movhl", "movlh", "movhh" +}; + +const char *const m16c_disassembler::s_decimal_ops[2][4] = +{ + { "dadd.b", "dsub.b", "dadc.b", "dsbb.b" }, + { "dadd.w", "dsub.w", "dadc.w", "dsbb.w" } +}; + + +u32 m16c_disassembler::opcode_alignment() const +{ + return 1; +} + +void m16c_disassembler::format_imm8(std::ostream &stream, u8 imm) const +{ + stream << '#'; + if (imm >= 0xa0) + stream << '0'; + util::stream_format(stream, "%02Xh", imm); +} + +void m16c_disassembler::format_imm16(std::ostream &stream, u16 imm) const +{ + util::stream_format(stream, "#%0*Xh", imm >= 0xa000 ? 5 : 4, imm); +} + +void m16c_disassembler::format_label(std::ostream &stream, u32 label) const +{ + label &= 0xfffff; + util::stream_format(stream, "%0*Xh", label >= 0xa0000 ? 6 : 5, label); +} + +void m16c_disassembler::format_imm_signed(std::ostream &stream, s16 imm) const +{ + stream << '#'; + if (imm < 0) + { + stream << '-'; + imm = -imm; + } + if (u16(imm) > 9) + { + int places = 1; + for (u16 temp = imm; temp > 9; temp >>= 4) + ++places; + util::stream_format(stream, "%0*Xh", places, u16(imm)); + } + else + util::stream_format(stream, "%d", imm); +} + +void m16c_disassembler::format_relative(std::ostream &stream, const char *reg, s32 disp) const +{ + if (disp < 0) + { + stream << '-'; + disp = -disp; + } + if (disp > 9) + { + int places = 1; + for (u32 temp = disp; temp > 9; temp >>= 4) + ++places; + util::stream_format(stream, "%0*Xh[%s]", places, u32(disp), reg); + } + else + util::stream_format(stream, "%d[%s]", disp, reg); +} + +void m16c_disassembler::dasm_ea(std::ostream &stream, offs_t &pc, const data_buffer &opcodes, u8 mode, bool size) const +{ + if (mode < 6) + stream << s_regs[size][mode]; + else if (mode < 8) + util::stream_format(stream, "[%s]", s_regs[1][mode - 2]); + else if (mode < 0xc) + format_relative(stream, mode < 0xa ? s_regs[1][mode - 4] : s_cregs[mode - 4], s8(opcodes.r8(pc++))); + else + { + if (mode == 0xf) + format_label(stream, opcodes.r16(pc)); + else + format_relative(stream, mode < 0xe ? s_regs[1][mode - 8] : s_cregs[mode - 8], s16(opcodes.r16(pc))); + pc += 2; + } +} + +void m16c_disassembler::dasm_general(std::ostream &stream, offs_t &pc, const data_buffer &opcodes, bool size) const +{ + const u8 op2 = opcodes.r8(pc++); + dasm_ea(stream, pc, opcodes, op2 >> 4, size); + stream << ", "; + dasm_ea(stream, pc, opcodes, op2 & 0x0f, size); +} + +void m16c_disassembler::dasm_quick(std::ostream &stream, offs_t &pc, const data_buffer &opcodes, bool size) const +{ + const u8 op2 = opcodes.r8(pc++); + util::stream_format(stream, "#%d, ", s8(op2) >> 4); + dasm_ea(stream, pc, opcodes, op2 & 0x0f, size); +} + +void m16c_disassembler::dasm_shift(std::ostream &stream, offs_t &pc, const data_buffer &opcodes, bool size) const +{ + const u8 op2 = opcodes.r8(pc++); + util::stream_format(stream, "#%d, ", s8(op2) < 0 ? s8(op2) >> 4 : (op2 >> 4) + 1); + dasm_ea(stream, pc, opcodes, op2 & 0x0f, size); +} + +void m16c_disassembler::dasm_74(std::ostream &stream, offs_t &pc, const data_buffer &opcodes, bool size) const +{ + const u8 op2 = opcodes.r8(pc++); + switch (op2 >> 4) + { + case 0x0: case 0x1: + { + util::stream_format(stream, "%-8s", size ? "ste.w" : "ste.b"); + dasm_ea(stream, pc, opcodes, op2 & 0x0f, size); + stream << ", "; + format_label(stream, u32(opcodes.r8(pc + 2)) << 16 | opcodes.r16(pc)); + if (BIT(op2, 4)) + util::stream_format(stream, "[%s]", s_regs[1][4]); + pc += 3; + break; + } + + case 0x2: + util::stream_format(stream, "%-8s", size ? "ste.w" : "ste.b"); + dasm_ea(stream, pc, opcodes, op2 & 0x0f, size); + util::stream_format(stream, ", [%s%s]", s_regs[1][5], s_regs[1][4]); + break; + + case 0x3: + util::stream_format(stream, "%-8s", size ? "mov.w" : "mov.b"); + dasm_ea(stream, pc, opcodes, op2 & 0x0f, size); + stream << ", "; + format_relative(stream, s_cregs[5], s8(opcodes.r8(pc++))); + break; + + case 0x4: + util::stream_format(stream, "%-8s", size ? "push.w" : "push.b"); + dasm_ea(stream, pc, opcodes, op2 & 0x0f, size); + break; + + case 0x5: + util::stream_format(stream, "%-8s", size ? "neg.w" : "neg.b"); + dasm_ea(stream, pc, opcodes, op2 & 0x0f, size); + break; + + case 0x6: + util::stream_format(stream, "%-8s%s, ", size ? "rot.w" : "rot.b", s_regs[0][3]); + dasm_ea(stream, pc, opcodes, op2 & 0x0f, size); + break; + + case 0x7: + util::stream_format(stream, "%-8s", size ? "not.w" : "not.b"); + dasm_ea(stream, pc, opcodes, op2 & 0x0f, size); + break; + + case 0x8: case 0x9: + { + const int offset = BIT(op2, 3) ? (BIT(op2, 2) ? 2 : 1) : 0; + util::stream_format(stream, "%-8s", size ? "lde.w" : "lde.b"); + format_label(stream, u32(opcodes.r8(pc + offset + 2)) << 16 | opcodes.r16(pc + offset)); + if (BIT(op2, 4)) + util::stream_format(stream, "[%s]", s_regs[1][4]); + stream << ", "; + dasm_ea(stream, pc, opcodes, op2 & 0x0f, size); + pc += 3; + break; + } + + case 0xa: + util::stream_format(stream, "%-8s[%s%s], ", size ? "lde.w" : "lde.b", s_regs[1][5], s_regs[1][4]); + dasm_ea(stream, pc, opcodes, op2 & 0x0f, size); + break; + + case 0xb: + { + const int offset = BIT(op2, 3) ? (BIT(op2, 2) ? 2 : 1) : 0; + util::stream_format(stream, "%-8s", size ? "mov.w" : "mov.b"); + format_relative(stream, s_cregs[5], s8(opcodes.r8(pc + offset))); + stream << ", "; + dasm_ea(stream, pc, opcodes, op2 & 0x0f, size); + ++pc; + break; + } + + case 0xc: + { + const int offset = BIT(op2, 3) ? (BIT(op2, 2) ? 2 : 1) : 0; + util::stream_format(stream, "%-8s", size ? "mov.w" : "mov.b"); + if (size) + format_imm16(stream, opcodes.r16(pc + offset)); + else + format_imm8(stream, opcodes.r8(pc + offset)); + stream << ", "; + dasm_ea(stream, pc, opcodes, op2 & 0x0f, size); + pc += size ? 2 : 1; + break; + } + + case 0xd: + util::stream_format(stream, "%-8s", size ? "pop.w" : "pop.b"); + dasm_ea(stream, pc, opcodes, op2 & 0x0f, size); + break; + + case 0xe: + util::stream_format(stream, "%-8s%s, ", size ? "shl.w" : "shl.b", s_regs[0][3]); + dasm_ea(stream, pc, opcodes, op2 & 0x0f, size); + break; + + case 0xf: + util::stream_format(stream, "%-8s%s, ", size ? "sha.w" : "sha.b", s_regs[0][3]); + dasm_ea(stream, pc, opcodes, op2 & 0x0f, size); + break; + + default: + --pc; + util::stream_format(stream, "%-8s%Xh ; und", ".byte", size ? 0x75 : 0x74); + break; + } +} + +void m16c_disassembler::dasm_76(std::ostream &stream, offs_t &pc, const data_buffer &opcodes, bool size) const +{ + const u8 op2 = opcodes.r8(pc++); + if (op2 < 0x90) + { + const int offset = BIT(op2, 3) ? (BIT(op2, 2) ? 2 : 1) : 0; + util::stream_format(stream, "%-8s", s_imm76_ops[size][op2 >> 4]); + if (size) + { + if (op2 < 0x40) + format_imm16(stream, opcodes.r16(pc + offset)); + else + format_imm_signed(stream, s16(opcodes.r16(pc + offset))); + } + else + { + if (op2 < 0x40) + format_imm8(stream, opcodes.r8(pc + offset)); + else + format_imm_signed(stream, s8(opcodes.r8(pc + offset))); + } + stream << ", "; + dasm_ea(stream, pc, opcodes, op2 & 0x0f, size); + pc += size ? 2 : 1; + } + else switch (op2 >> 4) + { + case 0x9: + util::stream_format(stream, "%-8s", size ? "divx.w" : "divx.b"); + dasm_ea(stream, pc, opcodes, op2 & 0x0f, size); + break; + + case 0xa: + util::stream_format(stream, "%-8s", size ? "rolc.w" : "rolc.b"); + dasm_ea(stream, pc, opcodes, op2 & 0x0f, size); + break; + + case 0xb: + util::stream_format(stream, "%-8s", size ? "rorc.w" : "rorc.b"); + dasm_ea(stream, pc, opcodes, op2 & 0x0f, size); + break; + + case 0xc: + util::stream_format(stream, "%-8s", size ? "divu.w" : "divu.b"); + dasm_ea(stream, pc, opcodes, op2 & 0x0f, size); + break; + + case 0xd: + util::stream_format(stream, "%-8s", size ? "div.w" : "div.b"); + dasm_ea(stream, pc, opcodes, op2 & 0x0f, size); + break; + + case 0xe: + util::stream_format(stream, "%-8s", size ? "adcf.w" : "adcf.b"); + dasm_ea(stream, pc, opcodes, op2 & 0x0f, size); + break; + + case 0xf: + util::stream_format(stream, "%-8s", size ? "abs.w" : "abs.b"); + dasm_ea(stream, pc, opcodes, op2 & 0x0f, size); + break; + + default: + --pc; + util::stream_format(stream, "%-8s%Xh ; und", ".byte", size ? 0x77 : 0x76); + break; + } +} + +void m16c_disassembler::dasm_7a(std::ostream &stream, offs_t &pc, const data_buffer &opcodes, bool size) const +{ + const u8 op2 = opcodes.r8(pc++); + if (op2 < 0x40) + { + util::stream_format(stream, "%-8s%s, ", size ? "xchg.w" : "xchg.b", s_regs[size][op2 >> 4]); + dasm_ea(stream, pc, opcodes, op2 & 0x0f, size); + } + else if (op2 >= 0x90) + { + if (size) + util::stream_format(stream, "%-8s%s, ", "stc", s_cregs[BIT(op2, 4, 3)]); + else + util::stream_format(stream, "%-8s", "ldc"); + dasm_ea(stream, pc, opcodes, op2 & 0x0f, true); + if (!size) + util::stream_format(stream, ", %s", s_cregs[BIT(op2, 4, 3)]); + } + else + { + --pc; + util::stream_format(stream, "%-8s%Xh ; und", ".byte", size ? 0x7b : 0x7a); + } +} + +void m16c_disassembler::dasm_7c(std::ostream &stream, offs_t &pc, const data_buffer &opcodes) const +{ + const u8 op2 = opcodes.r8(pc++); + if (!BIT(op2, 6)) + { + util::stream_format(stream, "%-8s", s_nibmov_ops[BIT(op2, 4, 2)]); + if (BIT(op2, 7)) + util::stream_format(stream, "%s, ", s_regs[0][0]); + dasm_ea(stream, pc, opcodes, op2 & 0x0f, false); + if (!BIT(op2, 7)) + util::stream_format(stream, ", %s", s_regs[0][0]); + } + else if (op2 < 0x60) + { + const int offset = BIT(op2, 3) ? (BIT(op2, 2) ? 2 : 1) : 0; + util::stream_format(stream, "%-8s", BIT(op2, 4) ? "mul.b" : "mulu.b"); + format_imm8(stream, opcodes.r8(pc + offset)); + stream << ", "; + dasm_ea(stream, pc, opcodes, op2 & 0x0f, false); + ++pc; + } + else if (op2 < 0x70) + { + util::stream_format(stream, "%-8s", "exts.b"); + dasm_ea(stream, pc, opcodes, op2 & 0x0f, false); + } + else if ((op2 & 0xf0) == 0xc0) + { + util::stream_format(stream, "%-8sPC, ", "stc"); + dasm_ea(stream, pc, opcodes, op2 & 0x0f, true); + if ((op2 & 0x0e) < 0x06) + stream << s_regs[1][(op2 & 0x0e) | BIT(op2, 2) ? 1 : 2]; + } + else if ((op2 & 0xf4) == 0xe4) + { + util::stream_format(stream, "%-8s", s_decimal_ops[0][op2 & 0x03]); + if (BIT(op2, 3)) + format_imm8(stream, opcodes.r8(pc++)); + else + stream << s_regs[0][1]; + util::stream_format(stream, ", %s", s_regs[0][0]); + } + else switch (op2) + { + case 0xe0: + util::stream_format(stream, "%-8s", "divu.b"); + format_imm8(stream, opcodes.r8(pc++)); + break; + + case 0xe1: + util::stream_format(stream, "%-8s", "div.b"); + format_imm_signed(stream, s8(opcodes.r8(pc++))); + break; + + case 0xe2: + util::stream_format(stream, "%-8s", "push.b"); + format_imm8(stream, opcodes.r8(pc++)); + break; + + case 0xe3: + util::stream_format(stream, "%-8s", "divx.b"); + format_imm_signed(stream, s8(opcodes.r16(pc++))); + break; + + case 0xe8: + stream << "smovf.b"; + break; + + case 0xe9: + stream << "smovb.b"; + break; + + case 0xea: + stream << "sstr.b"; + break; + + case 0xeb: + util::stream_format(stream, "%-8s", "add.b"); + format_imm_signed(stream, s8(opcodes.r8(pc++))); + util::stream_format(stream, ", %s", s_cregs[5]); + break; + + case 0xf0: + util::stream_format(stream, "%-8s", "ldctx"); + format_label(stream, opcodes.r16(pc)); + stream << ", "; + format_label(stream, u32(opcodes.r8(pc + 4)) << 16 | opcodes.r16(pc + 2)); + pc += 5; + break; + + case 0xf1: + stream << "rmpa.b"; + break; + + case 0xf2: + util::stream_format(stream, "%-8s", "enter"); + format_imm_signed(stream, opcodes.r8(pc++)); // probably not signed + break; + + case 0xf3: + util::stream_format(stream, "%-8s%s", "exts.w", s_regs[1][0]); + break; + + default: + --pc; + util::stream_format(stream, "%-8s%Xh ; und", ".byte", 0x7c); + break; + } +} + +void m16c_disassembler::dasm_7d(std::ostream &stream, offs_t &pc, offs_t &flags, const data_buffer &opcodes) const +{ + const u8 op2 = opcodes.r8(pc++); + if (op2 < 0x40) + { + if (BIT(op2, 4)) + { + util::stream_format(stream, "%-8s", BIT(op2, 5) ? "jsri.w" : "jsri.a"); + flags |= STEP_OVER; + } + else + util::stream_format(stream, "%-8s", BIT(op2, 5) ? "jmpi.w" : "jmpi.a"); + if ((op2 & 0x0e) == 0x0c) + { + format_label(stream, u32(opcodes.r8(pc + 2)) << 16 | opcodes.r16(pc)); + util::stream_format(stream, "[%s]", s_regs[1][op2 & 0x07]); + pc += 3; + } + else + { + if (!BIT(op2, 5) && (op2 & 0x0e) < 0x06) + stream << s_regs[1][(op2 & 0x0e) | BIT(op2, 2) ? 1 : 2]; + dasm_ea(stream, pc, opcodes, op2 & 0x0f, true); + } + } + else if (op2 < 0x60) + { + util::stream_format(stream, "%-8s", BIT(op2, 4) ? "mul.w" : "mulu.w"); + const int offset = BIT(op2, 3) ? (BIT(op2, 2) ? 2 : 1) : 0; + if (BIT(op2, 4)) + format_imm_signed(stream, opcodes.r16(pc + offset)); + else + format_imm16(stream, opcodes.r16(pc + offset)); + stream << ", "; + dasm_ea(stream, pc, opcodes, op2 & 0x0f, true); + pc += 2; + } + else if ((op2 & 0xf8) == 0x98) + { + util::stream_format(stream, "%-8s", "pusha"); + dasm_ea(stream, pc, opcodes, op2 & 0x0f, false); + } + else if ((op2 & 0xf8) == 0xa0) + util::stream_format(stream, "%-8s#%d", "ldipl", op2 & 0x07); + else if ((op2 & 0xf0) == 0xb0) + util::stream_format(stream, "%-8s#%d, %s", "add.w", util::sext(op2, 4), s_cregs[5]); + else if ((op2 & 0xf8) == 0xc8 && s_cnds[op2 & 0x0f][0] != '\0') + { + util::stream_format(stream, "j%-7s", s_cnds[op2 & 0x0f]); + format_label(stream, pc + opcodes.r8(pc)); + ++pc; + flags |= STEP_COND; + } + else if ((op2 & 0xf0) == 0xd0 && s_cnds[op2 & 0x0f][0] != '\0') + util::stream_format(stream, "bm%-6sC", s_cnds[op2 & 0x0f]); + else if ((op2 & 0xf4) == 0xe4) + { + util::stream_format(stream, "%-8s", s_decimal_ops[1][op2 & 0x03]); + if (BIT(op2, 3)) + { + format_imm16(stream, opcodes.r16(pc)); + pc += 2; + } + else + stream << s_regs[1][1]; + util::stream_format(stream, ", %s", s_regs[1][0]); + } + else switch (op2) + { + case 0xe0: + util::stream_format(stream, "%-8s", "divu.w"); + format_imm16(stream, opcodes.r16(pc)); + pc += 2; + break; + + case 0xe1: + util::stream_format(stream, "%-8s", "div.w"); + format_imm_signed(stream, s16(opcodes.r16(pc))); + pc += 2; + break; + + case 0xe2: + util::stream_format(stream, "%-8s", "push.w"); + format_imm16(stream, opcodes.r16(pc)); + pc += 2; + break; + + case 0xe3: + util::stream_format(stream, "%-8s", "divx.w"); + format_imm_signed(stream, s16(opcodes.r16(pc))); + pc += 2; + break; + + case 0xe8: + stream << "smovf.w"; + break; + + case 0xe9: + stream << "smovb.w"; + break; + + case 0xea: + stream << "sstr.w"; + break; + + case 0xeb: + util::stream_format(stream, "%-8s", "add.w"); + format_imm_signed(stream, s16(opcodes.r16(pc))); + util::stream_format(stream, ", %s", s_cregs[5]); + pc += 2; + break; + + case 0xf0: + util::stream_format(stream, "%-8s", "stctx"); + format_label(stream, opcodes.r16(pc)); + stream << ", "; + format_label(stream, u32(opcodes.r8(pc + 4)) << 16 | opcodes.r16(pc + 2)); + pc += 5; + break; + + case 0xf1: + stream << "rmpa.w"; + break; + + case 0xf2: + stream << "exitd"; + flags |= STEP_OUT; + break; + + case 0xf3: + stream << "wait"; + break; + + default: + --pc; + util::stream_format(stream, "%-8s%Xh ; und", ".byte", 0x7d); + break; + } +} + +void m16c_disassembler::dasm_7e(std::ostream &stream, offs_t &pc, const data_buffer &opcodes) const +{ + const u8 op2 = opcodes.r8(pc++); + if (op2 < 0xe0) + { + if ((op2 & 0xf0) == 0x20) + { + const int offset = (op2 & 0x0e) == 0x06 ? 0 : (op2 & 0x0c) == 0x0c ? 2 : 1; + const u8 cnd = opcodes.r8(pc + offset); + if (cnd < 0x08 || (cnd >= 0xf8 && s_cnds[cnd & 0x0f][0] != '\0')) + util::stream_format(stream, "bm%-6s", s_cnds[cnd & 0x0f]); + else + { + --pc; + util::stream_format(stream, "%-8s%Xh ; und", ".byte", 0x7e); + return; + } + } + else + util::stream_format(stream, "%-8s", s_bit_ops[op2 >> 4]); + if (!BIT(op2, 3)) + { + if ((op2 & 0x0f) < 6) + { + const u8 pos = opcodes.r8(pc++); + util::stream_format(stream, "%u, %s", pos, s_regs[1][op2 & 0x0f]); + } + else + util::stream_format(stream, "[%s]", s_regs[1][4 + BIT(op2, 0)]); + } + else if (BIT(op2, 2)) + { + if ((op2 & 0x0f) == 0x0f) + { + const u16 abs = opcodes.r16(pc); + util::stream_format(stream, "%d, ", abs & 0x07); + format_label(stream, abs >> 3); + } + else + format_relative(stream, BIT(op2, 1) ? s_cregs[6] : s_regs[1][op2 & 0x07], s16(opcodes.r16(pc))); + pc += 2; + } + else if (BIT(op2, 1)) + { + const s8 dsp8 = s8(opcodes.r8(pc++)); + util::stream_format(stream, "%d, ", dsp8 & 0x07); + format_relative(stream, s_cregs[6 + BIT(op2, 0)], dsp8 >> 3); + } + else + format_relative(stream, s_regs[1][4 + BIT(op2, 0)], s8(opcodes.r8(pc++))); + if ((op2 & 0xf0) == 0x20) + ++pc; + } + else + { + --pc; + util::stream_format(stream, "%-8s%Xh ; und", ".byte", 0x7e); + } +} + +void m16c_disassembler::dasm_eb(std::ostream &stream, offs_t &pc, offs_t &flags, const data_buffer &opcodes) const +{ + const u8 op2 = opcodes.r8(pc++); + if (op2 >= 0xc0) + { + util::stream_format(stream, "%-8s", "int"); + format_imm8(stream, op2 & 0x3f); + flags |= STEP_OVER; + } + else if (op2 >= 0x80) + util::stream_format(stream, "%-8s#%d, %s%s", BIT(op2, 5) ? "sha.l" : "shl.l", + BIT(op2, 3) ? util::sext(op2, 4) : (op2 & 0x0f) + 1, + s_regs[1][2 + BIT(op2, 4)], s_regs[1][BIT(op2, 4)]); + else if ((op2 & 0x4f) == 0x01) + util::stream_format(stream, "%-8s%s, %s%s", BIT(op2, 5) ? "sha.l" : "shl.l", + s_regs[0][3], s_regs[1][2 + BIT(op2, 4)], s_regs[1][BIT(op2, 4)]); + else if ((op2 & 0x0e) == 0x04) + util::stream_format(stream, "%-8s%c", BIT(op2, 0) ? "fclr" : "fset", "CDZSBOIU"[op2 >> 4]); + else if (op2 < 0x60 && BIT(op2, 3)) + { + util::stream_format(stream, "%-8s", "mova"); + dasm_ea(stream, pc, opcodes, op2 & 0x0f, false); + util::stream_format(stream, ", %s", s_regs[1][op2 >> 4]); + } + else if ((op2 & 0x0f) == 0 && op2 >= 0x10) + { + util::stream_format(stream, "%-8s", "ldc"); + format_imm16(stream, opcodes.r16(pc)); + util::stream_format(stream, ", %s", s_cregs[op2 >> 4]); + pc += 2; + } + else if ((op2 & 0x0e) == 0x02 && op2 >= 0x10) + util::stream_format(stream, "%-8s%s", BIT(op2, 0) ? "popc" : "pushc", s_cregs[op2 >> 4]); + else + { + --pc; + util::stream_format(stream, "%-8s0%Xh ; und", ".byte", 0xeb); + } +} + +offs_t m16c_disassembler::disassemble(std::ostream &stream, offs_t pc, const m16c_disassembler::data_buffer &opcodes, const m16c_disassembler::data_buffer ¶ms) +{ + const offs_t pc0 = pc; + offs_t flags = SUPPORTED; + + const u8 op1 = opcodes.r8(pc++); + if (op1 < 0x40) + { + if (op1 == 0x00) + { + stream << "brk"; + flags |= STEP_OVER; + } + else if (op1 == 0x04) + stream << "nop"; + else + { + util::stream_format(stream, "%-8s", s_byte_ops[BIT(op1, 3, 3)]); + if (op1 < 0x08) + util::stream_format(stream, "%s, ", s_regs[0][BIT(op1, 2)]); + switch (op1 & 0x03) + { + case 0: + util::stream_format(stream, "%s", s_regs[0][BIT(~op1, 2)]); + break; + + case 3: + format_label(stream, opcodes.r16(pc)); + pc += 2; + break; + + default: + format_relative(stream, s_cregs[5 + (op1 & 3)], s8(opcodes.r8(pc++))); + break; + } + if (op1 >= 0x08) + util::stream_format(stream, ", %s", s_regs[0][(BIT(op1, 3, 3) == 6 ? 4 : 0) + BIT(op1, 2)]); + } + } + else if (op1 < 0x60) + { + util::stream_format(stream, "%-8s%d, ", s_bit_ops[op1 >> 3], op1 & 0x07); + format_relative(stream, s_cregs[6], s8(opcodes.r8(pc++))); + } + else if (op1 < 0x68) + { + util::stream_format(stream, "%-8s", "jmp.s"); + format_label(stream, pc + 1 + s8(op1 & 0x07)); + } + else if (op1 < 0x70) + { + const s8 disp = s8(opcodes.r8(pc++)); + util::stream_format(stream, "b%-7s", s_cnds[op1 & 0x07]); + format_label(stream, pc + disp - 1); + flags |= STEP_COND; + } + else switch (op1) + { + case 0x70: case 0x71: + util::stream_format(stream, "%-8s", BIT(op1, 0) ? "mulu.w" : "mulu.b"); + dasm_general(stream, pc, opcodes, BIT(op1, 0)); + break; + + case 0x72: case 0x73: + util::stream_format(stream, "%-8s", BIT(op1, 0) ? "mov.w" : "mov.b"); + dasm_general(stream, pc, opcodes, BIT(op1, 0)); + break; + + case 0x74: case 0x75: + dasm_74(stream, pc, opcodes, BIT(op1, 0)); + break; + + case 0x76: case 0x77: + dasm_76(stream, pc, opcodes, BIT(op1, 0)); + break; + + case 0x78: case 0x79: + util::stream_format(stream, "%-8s", BIT(op1, 0) ? "mul.w" : "mul.b"); + dasm_general(stream, pc, opcodes, BIT(op1, 0)); + break; + + case 0x7a: case 0x7b: + dasm_7a(stream, pc, opcodes, BIT(op1, 0)); + break; + + case 0x7c: + dasm_7c(stream, pc, opcodes); + break; + + case 0x7d: + dasm_7d(stream, pc, flags, opcodes); + break; + + case 0x7e: + dasm_7e(stream, pc, opcodes); + break; + + case 0x80: case 0x81: + util::stream_format(stream, "%-8s", BIT(op1, 0) ? "tst.w" : "tst.b"); + dasm_general(stream, pc, opcodes, BIT(op1, 0)); + break; + + case 0x82: case 0x8a: case 0x92: case 0x9a: + util::stream_format(stream, "%-8s%s", BIT(op1, 4) ? "pop.b" : "push.b", s_regs[0][BIT(op1, 3)]); + break; + + case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: + case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f: + util::stream_format(stream, "%-8s", BIT(op1, 3) ? "sub.b" : "add.b"); + format_imm_signed(stream, opcodes.r8(pc++)); + stream << ", "; + switch (op1 & 0x07) + { + case 3: case 4: + stream << s_regs[0][BIT(op1, 0)]; + break; + + case 5: case 6: + format_relative(stream, s_cregs[(op1 & 0x07) + 1], s8(opcodes.r8(pc++))); + break; + + case 7: + format_label(stream, opcodes.r16(pc)); + pc += 2; + break; + } + break; + + case 0x88: case 0x89: + util::stream_format(stream, "%-8s", BIT(op1, 0) ? "xor.w" : "xor.b"); + dasm_general(stream, pc, opcodes, BIT(op1, 0)); + break; + + case 0x90: case 0x91: + util::stream_format(stream, "%-8s", BIT(op1, 0) ? "and.w" : "and.b"); + dasm_general(stream, pc, opcodes, BIT(op1, 0)); + break; + + case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: + case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f: + util::stream_format(stream, "%-8s", BIT(op1, 3) ? "or.b" : "and.b"); + format_imm8(stream, opcodes.r8(pc++)); + stream << ", "; + switch (op1 & 0x07) + { + case 3: case 4: + stream << s_regs[0][BIT(op1, 0)]; + break; + + case 5: case 6: + format_relative(stream, s_cregs[(op1 & 0x07) + 1], s8(opcodes.r8(pc++))); + break; + + case 7: + format_label(stream, opcodes.r16(pc)); + pc += 2; + break; + } + break; + + case 0x98: case 0x99: + util::stream_format(stream, "%-8s", BIT(op1, 0) ? "or.w" : "or.b"); + dasm_general(stream, pc, opcodes, BIT(op1, 0)); + break; + + case 0xa0: case 0xa1: + util::stream_format(stream, "%-8s", BIT(op1, 0) ? "add.w" : "add.b"); + dasm_general(stream, pc, opcodes, BIT(op1, 0)); + break; + + case 0xa2: case 0xaa: + util::stream_format(stream, "%-8s", "mov.w"); + format_imm16(stream, opcodes.r16(pc)); + pc += 2; + util::stream_format(stream, ", %s", s_regs[1][4 + BIT(op1, 3)]); + break; + + case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: + util::stream_format(stream, "%-8s", BIT(op1, 3) ? "dec.b" : "inc.b"); + switch (op1 & 0x07) + { + case 3: case 4: + stream << s_regs[0][BIT(op1, 0)]; + break; + + case 5: case 6: + format_relative(stream, s_cregs[(op1 & 0x07) + 1], s8(opcodes.r8(pc++))); + break; + + case 7: + format_label(stream, opcodes.r16(pc)); + pc += 2; + break; + } + break; + + case 0xa8: case 0xa9: + util::stream_format(stream, "%-8s", BIT(op1, 0) ? "sub.w" : "sub.b"); + dasm_general(stream, pc, opcodes, BIT(op1, 0)); + break; + + case 0xb0: case 0xb1: + util::stream_format(stream, "%-8s", BIT(op1, 0) ? "adc.w" : "adc.b"); + dasm_general(stream, pc, opcodes, BIT(op1, 0)); + break; + + case 0xb2: case 0xba: case 0xf2: case 0xfa: + util::stream_format(stream, "%-8s%s", BIT(op1, 6) ? "dec.w" : "inc.w", s_regs[1][4 + BIT(op1, 3)]); + break; + + case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: + case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: + util::stream_format(stream, "%-8s", op1 < 0xc8 ? "mov.b" : op1 < 0xd0 ? "stz" : "stnz"); + if (BIT(op1, 6)) + format_imm8(stream, opcodes.r8(pc++)); + else + stream << "#0"; + stream << ", "; + switch (op1 & 0x07) + { + case 3: case 4: + stream << s_regs[0][BIT(op1, 0)]; + break; + + case 5: case 6: + format_relative(stream, s_cregs[(op1 & 0x07) + 1], s8(opcodes.r8(pc++))); + break; + + case 7: + format_label(stream, opcodes.r16(pc)); + pc += 2; + break; + } + break; + + case 0xb8: case 0xb9: + util::stream_format(stream, "%-8s", BIT(op1, 0) ? "sbb.w" : "sbb.b"); + dasm_general(stream, pc, opcodes, BIT(op1, 0)); + break; + + case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: + util::stream_format(stream, "%-8s", "not.b"); + switch (op1 & 0x07) + { + case 3: case 4: + stream << s_regs[0][BIT(op1, 0)]; + break; + + case 5: case 6: + format_relative(stream, s_cregs[(op1 & 0x07) + 1], s8(opcodes.r8(pc++))); + break; + + case 7: + format_label(stream, opcodes.r16(pc)); + pc += 2; + break; + } + break; + + case 0xc0: case 0xc1: + util::stream_format(stream, "%-8s", BIT(op1, 0) ? "cmp.w" : "cmp.b"); + dasm_general(stream, pc, opcodes, BIT(op1, 0)); + break; + + case 0xc2: case 0xca: case 0xd2: case 0xda: + util::stream_format(stream, "%-8s%s", BIT(op1, 4) ? "pop.w" : "push.w", s_regs[1][4 + BIT(op1, 3)]); + break; + + case 0xc8: case 0xc9: + util::stream_format(stream, "%-8s", BIT(op1, 0) ? "add.w" : "add.b"); + dasm_quick(stream, pc, opcodes, BIT(op1, 0)); + break; + + case 0xd0: case 0xd1: + util::stream_format(stream, "%-8s", BIT(op1, 0) ? "cmp.w" : "cmp.b"); + dasm_quick(stream, pc, opcodes, BIT(op1, 0)); + break; + + case 0xd8: case 0xd9: + util::stream_format(stream, "%-8s", BIT(op1, 0) ? "mov.w" : "mov.b"); + dasm_quick(stream, pc, opcodes, BIT(op1, 0)); + break; + + case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: + util::stream_format(stream, "%-8s", "stzx"); + format_imm8(stream, opcodes.r8(pc++)); + stream << ", "; + switch (op1 & 0x07) + { + case 3: case 4: + format_imm8(stream, opcodes.r8(pc++)); + util::stream_format(stream, ", %s", s_regs[0][BIT(op1, 0)]); + break; + + case 5: case 6: + format_imm8(stream, opcodes.r8(pc + 1)); + stream << ", "; + format_relative(stream, s_cregs[(op1 & 0x07) + 1], s8(opcodes.r8(pc))); + pc += 2; + break; + + case 7: + format_imm8(stream, opcodes.r8(pc + 2)); + stream << ", "; + format_label(stream, opcodes.r16(pc)); + pc += 3; + break; + } + break; + + case 0xe0: case 0xe1: + util::stream_format(stream, "%-8s", BIT(op1, 0) ? "rot.w" : "rot.b"); + dasm_shift(stream, pc, opcodes, BIT(op1, 0)); + break; + + case 0xe2: case 0xea: + util::stream_format(stream, "%-8s", "mov.b"); + format_imm8(stream, opcodes.r8(pc++)); + util::stream_format(stream, ", %s", s_regs[1][4 + BIT(op1, 3)]); + break; + + case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7: + util::stream_format(stream, "%-8s", "cmp.b"); + format_imm_signed(stream, s8(opcodes.r8(pc++))); + stream << ", "; + switch (op1 & 0x07) + { + case 3: case 4: + stream << s_regs[0][BIT(op1, 0)]; + break; + + case 5: case 6: + format_relative(stream, s_cregs[(op1 & 0x07) + 1], s8(opcodes.r8(pc++))); + break; + + case 7: + format_label(stream, opcodes.r16(pc)); + pc += 2; + break; + } + break; + + case 0xe8: case 0xe9: + util::stream_format(stream, "%-8s", BIT(op1, 0) ? "shl.w" : "shl.b"); + dasm_shift(stream, pc, opcodes, BIT(op1, 0)); + break; + + case 0xeb: + dasm_eb(stream, pc, flags, opcodes); + break; + + case 0xec: + { + const u8 op2 = opcodes.r8(pc++); + util::stream_format(stream, "%-8s", "pushm"); + for (int i = 0; i < 8; i++) + { + if (BIT(op2, i)) + { + stream << (i < 2 ? s_cregs[7 - i] : s_regs[1][7 - i]); + if ((op2 >> i) != 1) + stream << ", "; + } + } + break; + } + + case 0xed: + { + const u8 op2 = opcodes.r8(pc++); + util::stream_format(stream, "%-8s", "popm"); + for (int i = 0; i < 8; i++) + { + if (BIT(op2, i)) + { + stream << (i > 6 ? s_cregs[i] : s_regs[1][i]); + if ((op2 >> i) != 1) + stream << ", "; + } + } + break; + } + + case 0xee: + util::stream_format(stream, "%-8s", "jmps"); + format_imm8(stream, opcodes.r8(pc++)); + break; + + case 0xef: + util::stream_format(stream, "%-8s", "jsrs"); + format_imm8(stream, opcodes.r8(pc++)); + flags |= STEP_OVER; + break; + + case 0xf0: case 0xf1: + util::stream_format(stream, "%-8s", BIT(op1, 0) ? "sha.w" : "sha.b"); + dasm_shift(stream, pc, opcodes, BIT(op1, 0)); + break; + + case 0xf3: + stream << "rts"; + flags |= STEP_OUT; + break; + + case 0xf4: case 0xf5: + util::stream_format(stream, "%-8s", BIT(op1, 0) ? "jsr.w" : "jmp.w"); + format_label(stream, pc + s16(opcodes.r16(pc))); + pc += 2; + if (BIT(op1, 0)) + flags |= STEP_COND; + break; + + case 0xf6: + stream << "into"; + flags |= STEP_OVER | STEP_COND; + break; + + case 0xf8: case 0xf9: + { + const u8 op2 = opcodes.r8(pc++); + if (BIT(op2, 3)) + util::stream_format(stream, "%-8s#%d, ", BIT(op1, 0) ? "adjnz.w" : "adjnz.b", 8 - (op2 & 0x07)); + else + util::stream_format(stream, "%-8s#%d, ", BIT(op1, 0) ? "sbjnz.w" : "sbjnz.b", op2 & 0x07); + dasm_ea(stream, pc, opcodes, op2 & 0x0f, BIT(op1, 0)); + format_label(stream, pc0 + 2 + s8(opcodes.r8(pc))); + ++pc; + flags |= STEP_COND; + break; + } + + case 0xfb: + stream << "reit"; + flags |= STEP_OUT; + break; + + case 0xfc: case 0xfd: + util::stream_format(stream, "%-8s", BIT(op1, 0) ? "jsr.a" : "jmp.a"); + format_label(stream, u32(opcodes.r8(pc + 2)) << 16 | opcodes.r16(pc)); + pc += 3; + if (BIT(op1, 0)) + flags |= STEP_COND; + break; + + case 0xfe: + util::stream_format(stream, "%-8s", "jmp.b"); + format_label(stream, pc + s8(opcodes.r8(pc))); + ++pc; + break; + + case 0xff: + default: + util::stream_format(stream, "%-8s%0*Xh ; und", ".byte", op1 >= 0xa0 ? 3 : 2, op1); + break; + } + + return (pc - pc0) | flags; +} diff --git a/src/devices/cpu/m16c/m16cdasm.h b/src/devices/cpu/m16c/m16cdasm.h new file mode 100644 index 00000000000..f924132c549 --- /dev/null +++ b/src/devices/cpu/m16c/m16cdasm.h @@ -0,0 +1,52 @@ +// license:BSD-3-Clause +// copyright-holders:AJR + +#ifndef MAME_CPU_M16C_M16CDASM_H +#define MAME_CPU_M16C_M16CDASM_H + +#pragma once + +class m16c_disassembler : public util::disasm_interface +{ +public: + // construction/destruction + m16c_disassembler(); + +protected: + // disassembler overrides + virtual u32 opcode_alignment() const override; + virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) override; + +private: + // static tables + static const char *const s_regs[2][6]; + static const char *const s_cregs[8]; + static const char *const s_byte_ops[8]; + static const char *const s_bit_ops[14]; + static const char *const s_cnds[16]; + static const char *const s_imm76_ops[2][9]; + static const char *const s_nibmov_ops[4]; + static const char *const s_decimal_ops[2][4]; + + // formatting helpers + void format_imm8(std::ostream &stream, u8 imm) const; + void format_imm16(std::ostream &stream, u16 imm) const; + void format_label(std::ostream &stream, u32 label) const; + void format_imm_signed(std::ostream &stream, s16 imm) const; + void format_relative(std::ostream &stream, const char *reg, s32 disp) const; + + // internal helpers + void dasm_ea(std::ostream &stream, offs_t &pc, const data_buffer &opcodes, u8 mode, bool size) const; + void dasm_general(std::ostream &stream, offs_t &pc, const data_buffer &opcodes, bool size) const; + void dasm_quick(std::ostream &stream, offs_t &pc, const data_buffer &opcodes, bool size) const; + void dasm_shift(std::ostream &stream, offs_t &pc, const data_buffer &opcodes, bool size) const; + void dasm_74(std::ostream &stream, offs_t &pc, const data_buffer &opcodes, bool size) const; + void dasm_76(std::ostream &stream, offs_t &pc, const data_buffer &opcodes, bool size) const; + void dasm_7a(std::ostream &stream, offs_t &pc, const data_buffer &opcodes, bool size) const; + void dasm_7c(std::ostream &stream, offs_t &pc, const data_buffer &opcodes) const; + void dasm_7d(std::ostream &stream, offs_t &pc, offs_t &flags, const data_buffer &opcodes) const; + void dasm_7e(std::ostream &stream, offs_t &pc, const data_buffer &opcodes) const; + void dasm_eb(std::ostream &stream, offs_t &pc, offs_t &flags, const data_buffer &opcodes) const; +}; + +#endif // MAME_CPU_M16C_M16CDASM_H diff --git a/src/tools/unidasm.cpp b/src/tools/unidasm.cpp index 78bb666ebf2..d3ace561834 100644 --- a/src/tools/unidasm.cpp +++ b/src/tools/unidasm.cpp @@ -84,6 +84,7 @@ using util::BIT; #include "cpu/lc8670/lc8670dsm.h" #include "cpu/lh5801/5801dasm.h" #include "cpu/lr35902/lr35902d.h" +#include "cpu/m16c/m16cdasm.h" #include "cpu/m32c/m32cdasm.h" #include "cpu/m37710/m7700ds.h" #include "cpu/m6502/m4510d.h" @@ -498,6 +499,7 @@ static const dasm_table_entry dasm_table[] = { "lh5801", le, 0, []() -> util::disasm_interface * { return new lh5801_disassembler; } }, { "lr35902", le, 0, []() -> util::disasm_interface * { return new lr35902_disassembler; } }, { "m146805", be, 0, []() -> util::disasm_interface * { return new m146805_disassembler; } }, + { "m16c", le, 0, []() -> util::disasm_interface * { return new m16c_disassembler; } }, { "m32c", le, 0, []() -> util::disasm_interface * { return new m32c_disassembler; } }, { "m37710", le, 0, []() -> util::disasm_interface * { return new m7700_disassembler(&m7700_unidasm); } }, { "m4510", le, 0, []() -> util::disasm_interface * { return new m4510_disassembler; } }, |