diff options
Diffstat (limited to 'src/devices/cpu/cr16b/cr16bdasm.cpp')
-rw-r--r-- | src/devices/cpu/cr16b/cr16bdasm.cpp | 1051 |
1 files changed, 1051 insertions, 0 deletions
diff --git a/src/devices/cpu/cr16b/cr16bdasm.cpp b/src/devices/cpu/cr16b/cr16bdasm.cpp new file mode 100644 index 00000000000..e52ab7e02f2 --- /dev/null +++ b/src/devices/cpu/cr16b/cr16bdasm.cpp @@ -0,0 +1,1051 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/*************************************************************************** + + National Semiconductor CompactRISC CR16B disassembler + + Core architecture versions supported by this disassembler: + * CR16A: 17-bit PC + * CR16B: 21-bit PC using large memory model, enhanced instruction set + + CR16C has a 24-bit PC and expands the instruction set still further. + Its instruction encoding is entirely different and is therefore not + supported here. + + It should be noted that the PC is guaranteed to be always aligned to + even addresses. To this end, whenever the PC is stored in or loaded + from a register or register pair or a stack, the bits are shifted + right or left by one. + +***************************************************************************/ + +#include "util/disasmintf.h" +#include "cr16bdasm.h" + +#include "util/strformat.h" + +using osd::u32; +using util::BIT; +using offs_t = u32; + +cr16b_disassembler::cr16b_disassembler(cr16_arch arch) + : util::disasm_interface() + , m_arch(arch) +{ +} + +cr16a_disassembler::cr16a_disassembler() + : cr16b_disassembler(cr16_arch::CR16A) +{ +} + +cr16b_disassembler::cr16b_disassembler() + : cr16b_disassembler(cr16_arch::CR16B) +{ +} + +u32 cr16b_disassembler::opcode_alignment() const +{ + return 2; +} + +// Condition codes +const char *const cr16b_disassembler::s_cc[14] = +{ + "eq", "ne", + "cs", "cc", + "hi", "ls", + "gt", "le", + "fs", "fc", + "lo", "hs", + "lt", "ge" +}; + + +void cr16b_disassembler::format_reg(std::ostream &stream, u8 reg) +{ + if (reg == 15) + stream << "sp"; + else if (reg == 14) + stream << "ra"; + else if (reg == 13 && m_arch != cr16_arch::CR16A) + stream << "era"; // R13 in SMM + else + util::stream_format(stream, "r%d", reg); +} + +void cr16b_disassembler::format_rpair(std::ostream &stream, u8 reg) +{ + if (reg == 13 && m_arch != cr16_arch::CR16A) + stream << "(ra,era)"; + else + util::stream_format(stream, "(r%d,r%d)", reg + 1, reg); +} + +void cr16a_disassembler::format_rproc(std::ostream &stream, u8 reg) +{ + switch (reg) + { + case 1: + stream << "psr"; + break; + + case 3: + stream << "intbase"; + break; + + case 11: + stream << "isp"; + break; + + default: + stream << "res"; + break; + } +} + +void cr16b_disassembler::format_rproc(std::ostream &stream, u8 reg) +{ + switch (reg) + { + case 1: + stream << "psr"; + break; + + case 3: + stream << "intbasel"; + break; + + case 4: + stream << "intbaseh"; + break; + + case 5: + stream << "cfg"; + break; + + case 7: + stream << "dsr"; + break; + + case 9: + stream << "dcr"; + break; + + case 11: + stream << "isp"; + break; + + case 13: + stream << "carl"; + break; + + case 14: + stream << "carh"; + break; + + default: + stream << "res"; + break; + } +} + +void cr16b_disassembler::format_short_imm(std::ostream &stream, u8 imm) +{ + // 5-bit short immediate value (0 to 15, -16, -14 to -1) + if (imm == 0) + stream << "$0"; + else if (imm >= 0x10) + util::stream_format(stream, "$-0x%01X", 0x10 - (imm & 0x0f)); + else + util::stream_format(stream, "$0x%01X", imm); +} + +void cr16b_disassembler::format_short_imm_unsigned(std::ostream &stream, u8 imm, bool i) +{ + if (imm == 0) + stream << "$0"; + else if (i) + util::stream_format(stream, "$0x%04X", (imm >= 0x10) ? 0xfff0 | (imm & 0x0f) : imm); + else + util::stream_format(stream, "$0x%02X", (imm >= 0x10) ? 0xf0 | (imm & 0x0f) : imm); +} + +void cr16b_disassembler::format_short_imm_decimal(std::ostream &stream, u8 imm) +{ + if (imm >= 0x10) + util::stream_format(stream, "$-%d", 0x10 - (imm & 0x0f)); + else + util::stream_format(stream, "$%d", imm); +} + +void cr16b_disassembler::format_medium_imm(std::ostream &stream, u16 imm, bool i) +{ + if (i) + util::stream_format(stream, "$0x%04X", imm); + else + util::stream_format(stream, "$0x%02X", imm & 0xff); +} + +void cr16b_disassembler::format_medium_imm_decimal(std::ostream &stream, u16 imm) +{ + util::stream_format(stream, "$%d", s16(imm)); +} + +void cr16b_disassembler::format_imm21(std::ostream &stream, u32 imm) +{ + util::stream_format(stream, "$0x%06X", imm); +} + +void cr16b_disassembler::format_disp5(std::ostream &stream, u8 disp) +{ + // 5-bit short displacement (0 to 15, 16 to 30 even) + if (disp == 0) + stream << "0"; + else + util::stream_format(stream, "0x%X", disp); +} + +void cr16b_disassembler::format_disp16(std::ostream &stream, u16 disp) +{ + // 16-bit displacement (0 to 64K-1) + util::stream_format(stream, "0x%X", disp); +} + +void cr16b_disassembler::format_disp18(std::ostream &stream, u32 disp) +{ + // 18-bit medium displacement (-128K to 128K-1 or 0 to 256K-1, result truncated to 18 bits) + if (disp == 0) + stream << "0"; + else if (disp >= 0x20000) + util::stream_format(stream, "-0x%X", 0x40000 - disp); + else + util::stream_format(stream, "0x%X", disp); +} + +void cr16b_disassembler::format_abs18(std::ostream &stream, u32 addr) +{ + // 18-bit absolute (any memory location within first 256K) + util::stream_format(stream, "0x%05X", addr); +} + +void cr16b_disassembler::format_pc_disp5(std::ostream &stream, offs_t pc, u8 disp) +{ + if (m_arch == cr16_arch::CR16A) + util::stream_format(stream, "0x%05X", (disp >= 0x10 ? pc + 0x20 - disp : pc + disp) & 0x1ffff); // SMM + else + util::stream_format(stream, "0x%06X", (disp >= 0x10 ? pc + 0x20 - disp : pc + disp) & 0x1fffff); // LMM +} + +void cr16b_disassembler::format_pc_disp9(std::ostream &stream, offs_t pc, u16 disp) +{ + if (m_arch == cr16_arch::CR16A) + util::stream_format(stream, "0x%05X", (disp >= 0x100 ? pc + 0x200 - disp : pc + disp) & 0x1ffff); // SMM + else + util::stream_format(stream, "0x%06X", (disp >= 0x100 ? pc + 0x200 - disp : pc + disp) & 0x1fffff); // LMM +} + +void cr16b_disassembler::format_pc_disp17(std::ostream &stream, offs_t pc, u32 disp) +{ + util::stream_format(stream, "0x%05X", (disp >= 0x10000 ? pc + 0x20000 - disp : pc + disp) & 0x1ffff); +} + +void cr16b_disassembler::format_pc_disp21(std::ostream &stream, offs_t pc, u32 disp) +{ + util::stream_format(stream, "0x%06X", (pc + ((disp & 0x0ffffe) | (disp & 0x000001) << 20)) & 0x1fffff); +} + +void cr16b_disassembler::format_excp_vector(std::ostream &stream, u8 vec) +{ + switch (vec) + { + case 0x05: // Supervisor call + stream << "svc"; + break; + + case 0x06: // Division by zero + stream << "dvz"; + break; + + case 0x07: // Flag + stream << "flg"; + break; + + case 0x08: // Breakpoint + stream << "bpt"; + break; + + case 0x0a: // Undefined instruction + stream << "und"; + break; + + case 0x0e: // Debug + stream << (m_arch != cr16_arch::CR16A ? "dbg" : "und ; reserved"); + break; + + default: + stream << "und ; reserved"; + break; + } +} + +offs_t cr16b_disassembler::disassemble(std::ostream &stream, offs_t pc, const cr16b_disassembler::data_buffer &opcodes, const cr16b_disassembler::data_buffer ¶ms) +{ + u16 opcode = opcodes.r16(pc); + + if (BIT(opcode, 15)) + { + // Load and store group (excluding LOADM, STORM) + if (BIT(opcode, 14)) + { + util::stream_format(stream, "stor%c ", BIT(opcode, 13) ? 'w' : 'b'); + format_reg(stream, (opcode & 0x01e0) >> 5); + stream << ", "; + } + else + util::stream_format(stream, "load%c ", BIT(opcode, 13) ? 'w' : 'b'); + + switch (opcode & 0x1801) + { + case 0x1001: + format_disp18(stream, u32(opcode & 0x0600) << 7 | opcodes.r16(pc + 2)); + stream << "("; + format_reg(stream, (opcode & 0x001e) >> 1); + stream << ")"; + if (!BIT(opcode, 14)) + { + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + } + return 4 | SUPPORTED; + + case 0x1801: + if ((opcode & 0x001e) == 0x001e) + format_abs18(stream, u32(opcode & 0x0600) << 7 | opcodes.r16(pc + 2)); + else + { + format_disp18(stream, u32(opcode & 0x0600) << 7 | opcodes.r16(pc + 2)); + format_rpair(stream, (opcode & 0x001e) >> 1); + } + if (!BIT(opcode, 14)) + { + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + } + return 4 | SUPPORTED; + + default: + format_disp5(stream, (opcode & 0x1e00) >> 8 | (opcode & 0x0001)); + stream << "("; + format_reg(stream, (opcode & 0x001e) >> 1); + stream << ")"; + if (!BIT(opcode, 14)) + { + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + } + return 2 | SUPPORTED; + } + } + else switch (opcode & 0x7e01) + { + case 0x0000: case 0x0001: case 0x2000: case 0x2001: + util::stream_format(stream, "add%c ", BIT(opcode, 13) ? 'w' : 'b'); + if ((opcode & 0x001f) == 0x0011) + { + format_medium_imm(stream, opcodes.r16(pc + 2), BIT(opcode, 13)); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 4 | SUPPORTED; + } + else + { + format_short_imm(stream, opcode & 0x001f); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 2 | SUPPORTED; + } + + case 0x0200: case 0x0201: case 0x2200: case 0x2201: + if (opcode == 0x0200) // NOP = ADDU $0, R0 + stream << "nop"; + else + { + util::stream_format(stream, "addu%c ", BIT(opcode, 13) ? 'w' : 'b'); + if ((opcode & 0x001f) == 0x0011) + { + format_medium_imm(stream, opcodes.r16(pc + 2), BIT(opcode, 13)); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 4 | SUPPORTED; + } + else + { + format_short_imm(stream, opcode & 0x001f); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 2 | SUPPORTED; + } + } + return 2 | SUPPORTED; + + case 0x0400: case 0x0401: case 0x2400: case 0x2401: + case 0x4401: case 0x6401: + // Bit manipulation and store immediate (memory operand) + if (m_arch == cr16_arch::CR16A) + { + stream << "res"; + return 2 | SUPPORTED; + } + switch (opcode & 0x00c0) + { + case 0x0000: + util::stream_format(stream, "cbit%c $%d", BIT(opcode, 13) ? 'w' : 'b', (opcode & 0x001e) >> 1); + break; + + case 0x0040: + util::stream_format(stream, "sbit%c $%d", BIT(opcode, 13) ? 'w' : 'b', (opcode & 0x001e) >> 1); + break; + + case 0x0080: + util::stream_format(stream, "tbit%c $%d", BIT(opcode, 13) ? 'w' : 'b', (opcode & 0x001e) >> 1); + break; + + case 0x00c0: + util::stream_format(stream, "stor%c ", BIT(opcode, 13) ? 'w' : 'b'); + format_short_imm(stream, (opcode & 0x001e) >> 1); // unsigned 4-bit value + break; + } + if (BIT(opcode, 14)) + { + stream << ",0("; + format_reg(stream, (opcode & 0x0120) >> 5); + stream << ")"; + return 2 | SUPPORTED; + } + else + { + stream << ", "; + if (BIT(opcode, 0)) + { + format_disp16(stream, opcodes.r16(pc + 2)); + stream << "("; + format_reg(stream, (opcode & 0x0120) >> 5); + stream << ")"; + } + else + format_abs18(stream, u32(opcode & 0x0100) << 9 | u32(opcode & 0x0020) << 11 | opcodes.r16(pc + 2)); + return 4 | SUPPORTED; + } + + case 0x0600: case 0x0601: case 0x2600: case 0x2601: + util::stream_format(stream, "mul%c ", BIT(opcode, 13) ? 'w' : 'b'); + if ((opcode & 0x001f) == 0x0011) + { + format_medium_imm(stream, opcodes.r16(pc + 2), BIT(opcode, 13)); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 4 | SUPPORTED; + } + else + { + format_short_imm(stream, opcode & 0x001f); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 2 | SUPPORTED; + } + + case 0x0800: case 0x0801: case 0x2800: case 0x2801: + util::stream_format(stream, "ashu%c ", BIT(opcode, 13) ? 'w' : 'b'); + if ((opcode & 0x001f) == 0x0011) + { + format_medium_imm_decimal(stream, opcodes.r16(pc + 2)); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 4 | SUPPORTED; + } + else + { + format_short_imm_decimal(stream, opcode & 0x001f); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 2 | SUPPORTED; + } + + case 0x0a00: case 0x0a01: case 0x2a00: case 0x2a01: + util::stream_format(stream, "lsh%c ", BIT(opcode, 13) ? 'w' : 'b'); + if ((opcode & 0x001f) == 0x0011) + { + format_medium_imm_decimal(stream, opcodes.r16(pc + 2)); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 4 | SUPPORTED; + } + else + { + format_short_imm_decimal(stream, opcode & 0x001f); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 2 | SUPPORTED; + } + + case 0x0c00: case 0x0c01: case 0x2c00: case 0x2c01: + util::stream_format(stream, "xor%c ", BIT(opcode, 13) ? 'w' : 'b'); + if ((opcode & 0x001f) == 0x0011) + { + format_medium_imm(stream, opcodes.r16(pc + 2), BIT(opcode, 13)); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 4 | SUPPORTED; + } + else + { + format_short_imm_unsigned(stream, opcode & 0x001f, BIT(opcode, 13)); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 2 | SUPPORTED; + } + + case 0x0e00: case 0x0e01: case 0x2e00: case 0x2e01: + util::stream_format(stream, "cmp%c ", BIT(opcode, 13) ? 'w' : 'b'); + if ((opcode & 0x001f) == 0x0011) + { + format_medium_imm(stream, opcodes.r16(pc + 2), BIT(opcode, 13)); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 4 | SUPPORTED; + } + else + { + format_short_imm(stream, opcode & 0x001f); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 2 | SUPPORTED; + } + + case 0x1000: case 0x1001: case 0x3000: case 0x3001: + util::stream_format(stream, "and%c ", BIT(opcode, 13) ? 'w' : 'b'); + if ((opcode & 0x001f) == 0x0011) + { + format_medium_imm(stream, opcodes.r16(pc + 2), BIT(opcode, 13)); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 4 | SUPPORTED; + } + else + { + format_short_imm_unsigned(stream, opcode & 0x001f, BIT(opcode, 13)); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 2 | SUPPORTED; + } + + case 0x1200: case 0x1201: case 0x3200: case 0x3201: + util::stream_format(stream, "addc%c ", BIT(opcode, 13) ? 'w' : 'b'); + if ((opcode & 0x001f) == 0x0011) + { + format_medium_imm(stream, opcodes.r16(pc + 2), BIT(opcode, 13)); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 4 | SUPPORTED; + } + else + { + format_short_imm(stream, opcode & 0x001f); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 2 | SUPPORTED; + } + + case 0x1400: + // Conditional or unconditional branch to small address + if ((opcode & 0x000e) == 0x000e || (opcode & 0x01e0) != 0x01e0) + { + if ((opcode & 0x01e0) == 0x01c0) + stream << "br "; + else + util::stream_format(stream, "b%s ", s_cc[(opcode & 0x01e0) >> 5]); + format_pc_disp17(stream, pc, u32(opcode & 0x0010) << 12 | opcodes.r16(pc + 2)); + return 4 | SUPPORTED; + } + else + { + stream << "res"; + return 2 | SUPPORTED; + } + + case 0x1401: case 0x3401: + // Compare and branch group + if (m_arch == cr16_arch::CR16A) + stream << "res"; + else + { + util::stream_format(stream, "b%s%c%c ", BIT(opcode, 7) ? "ne" : "eq", BIT(opcode, 6) ? '1' : '0', BIT(opcode, 13) ? 'w' : 'b'); + format_reg(stream, (opcode & 0x0120) >> 5); + stream << ", "; + format_pc_disp5(stream, pc, opcode & 0x001e); + } + return 2 | SUPPORTED; + + case 0x1600: + // Jump and link to large address + if (m_arch == cr16_arch::CR16A) + stream << "res"; + else + { + stream << "jal "; + format_rpair(stream, (opcode & 0x01e0) >> 5); + stream << ", "; + format_rpair(stream, (opcode & 0x001e) >> 1); + } + return 2 | SUPPORTED; + + case 0x1601: + if ((opcode & 0x01e0) != 0x01e0 && m_arch != cr16_arch::CR16A) + { + if ((opcode & 0x01e0) == 0x01c0) + stream << "jump "; + else + util::stream_format(stream, "j%s ", s_cc[(opcode & 0x01e0) >> 5]); + format_rpair(stream, (opcode & 0x001e) >> 1); + return 2 | (opcode == 0x17db ? STEP_OUT : 0) | SUPPORTED; + } + else + { + stream << "res"; + return 2 | SUPPORTED; + } + + case 0x1800: case 0x1801: case 0x3800: case 0x3801: + util::stream_format(stream, "mov%c ", BIT(opcode, 13) ? 'w' : 'b'); + if ((opcode & 0x001f) == 0x0011) + { + format_medium_imm(stream, opcodes.r16(pc + 2), BIT(opcode, 13)); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 4 | SUPPORTED; + } + else + { + format_short_imm_unsigned(stream, opcode & 0x001f, BIT(opcode, 13)); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 2 | SUPPORTED; + } + + case 0x1a00: case 0x1a01: case 0x3a00: case 0x3a01: + util::stream_format(stream, "subc%c ", BIT(opcode, 13) ? 'w' : 'b'); + if ((opcode & 0x001f) == 0x0011) + { + format_medium_imm(stream, opcodes.r16(pc + 2), BIT(opcode, 13)); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 4 | SUPPORTED; + } + else + { + format_short_imm(stream, opcode & 0x001f); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 2 | SUPPORTED; + } + + case 0x1c00: case 0x1c01: case 0x3c00: case 0x3c01: + util::stream_format(stream, "or%c ", BIT(opcode, 13) ? 'w' : 'b'); + if ((opcode & 0x001f) == 0x0011) + { + format_medium_imm(stream, opcodes.r16(pc + 2), BIT(opcode, 13)); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 4 | SUPPORTED; + } + else + { + format_short_imm_unsigned(stream, opcode & 0x001f, BIT(opcode, 13)); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 2 | SUPPORTED; + } + + case 0x1e00: case 0x1e01: case 0x3e00: case 0x3e01: + util::stream_format(stream, "sub%c ", BIT(opcode, 13) ? 'w' : 'b'); + if ((opcode & 0x001f) == 0x0011) + { + format_medium_imm(stream, opcodes.r16(pc + 2), BIT(opcode, 13)); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 4 | SUPPORTED; + } + else + { + format_short_imm(stream, opcode & 0x001f); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 2 | SUPPORTED; + } + + case 0x3400: + // Branch and link to small address + if ((opcode & 0x000e) == 0x000e) + { + stream << "bal "; + format_reg(stream, (opcode & 0x01e0) >> 5); + stream << ", "; + format_pc_disp17(stream, pc, u32(opcode & 0x0010) << 12 | opcodes.r16(pc + 2)); + return 4 | STEP_OVER | SUPPORTED; + } + else + { + stream << "res"; + return 2 | SUPPORTED; + } + + case 0x3600: case 0x3601: + // TBIT imm, reg only exists as a word operation + stream << "tbit "; + if ((opcode & 0x001f) == 0x0011) + { + format_medium_imm_decimal(stream, opcodes.r16(pc + 2)); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 4 | SUPPORTED; + } + else + { + format_short_imm_decimal(stream, opcode & 0x001f); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 2 | SUPPORTED; + } + + case 0x4000: case 0x4200: case 0x4400: case 0x4600: + case 0x4800: case 0x4a00: case 0x4c00: case 0x4e00: + case 0x5000: case 0x5200: case 0x5400: case 0x5600: + case 0x5800: case 0x5a00: case 0x5c00: case 0x5e00: + // Conditional or unconditional branch with 9-bit displacement + if ((opcode & 0x01e0) != 0x01e0) + { + if ((opcode & 0x01e0) == 0x01c0) + stream << "br "; + else + util::stream_format(stream, "b%s ", s_cc[(opcode & 0x01e0) >> 5]); + format_pc_disp9(stream, pc, (opcode & 0x1e00) >> 4 | (opcode & 0x001e)); + } + else + stream << "res"; + return 2 | SUPPORTED; + + case 0x4001: case 0x6001: + util::stream_format(stream, "add%c ", BIT(opcode, 13) ? 'w' : 'b'); + format_reg(stream, (opcode & 0x001e) >> 1); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 2 | SUPPORTED; + + case 0x4201: case 0x6201: + util::stream_format(stream, "addu%c ", BIT(opcode, 13) ? 'w' : 'b'); + format_reg(stream, (opcode & 0x001e) >> 1); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 2 | SUPPORTED; + + case 0x4601: case 0x6601: + util::stream_format(stream, "mul%c ", BIT(opcode, 13) ? 'w' : 'b'); + format_reg(stream, (opcode & 0x001e) >> 1); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 2 | SUPPORTED; + + case 0x4801: case 0x6801: + util::stream_format(stream, "ashu%c ", BIT(opcode, 13) ? 'w' : 'b'); + format_reg(stream, (opcode & 0x001e) >> 1); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 2 | SUPPORTED; + + case 0x4a01: case 0x6a01: + util::stream_format(stream, "lsh%c ", BIT(opcode, 13) ? 'w' : 'b'); + format_reg(stream, (opcode & 0x001e) >> 1); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 2 | SUPPORTED; + + case 0x4c01: case 0x6c01: + util::stream_format(stream, "xor%c ", BIT(opcode, 13) ? 'w' : 'b'); + format_reg(stream, (opcode & 0x001e) >> 1); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 2 | SUPPORTED; + + case 0x4e01: case 0x6e01: + util::stream_format(stream, "cmp%c ", BIT(opcode, 13) ? 'w' : 'b'); + format_reg(stream, (opcode & 0x001e) >> 1); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 2 | SUPPORTED; + + case 0x5001: case 0x7001: + util::stream_format(stream, "and%c ", BIT(opcode, 13) ? 'w' : 'b'); + format_reg(stream, (opcode & 0x001e) >> 1); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 2 | SUPPORTED; + + case 0x5201: case 0x7201: + util::stream_format(stream, "addc%c ", BIT(opcode, 13) ? 'w' : 'b'); + format_reg(stream, (opcode & 0x001e) >> 1); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 2 | SUPPORTED; + + case 0x5401: + if ((opcode & 0x01e0) != 0x01e0) + { + if ((opcode & 0x01e0) == 0x01c0) + stream << "jump "; + else + util::stream_format(stream, "j%s ", s_cc[(opcode & 0x01e0) >> 5]); + format_reg(stream, (opcode & 0x001e) >> 1); + return 2 | (opcode == 0x55dd ? STEP_OUT : 0) | SUPPORTED; + } + else + { + stream << "res"; + return 2 | SUPPORTED; + } + + case 0x5801: case 0x7801: + util::stream_format(stream, "mov%c ", BIT(opcode, 13) ? 'w' : 'b'); + format_reg(stream, (opcode & 0x001e) >> 1); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 2 | SUPPORTED; + + case 0x5a01: case 0x7a01: + util::stream_format(stream, "subc%c ", BIT(opcode, 13) ? 'w' : 'b'); + format_reg(stream, (opcode & 0x001e) >> 1); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 2 | SUPPORTED; + + case 0x5c01: case 0x7c01: + util::stream_format(stream, "or%c ", BIT(opcode, 13) ? 'w' : 'b'); + format_reg(stream, (opcode & 0x001e) >> 1); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 2 | SUPPORTED; + + case 0x5e01: case 0x7e01: + util::stream_format(stream, "sub%c ", BIT(opcode, 13) ? 'w' : 'b'); + format_reg(stream, (opcode & 0x001e) >> 1); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 2 | SUPPORTED; + + case 0x6000: + if (m_arch == cr16_arch::CR16A) + stream << "res"; + else + { + stream << "mulsb "; + format_reg(stream, (opcode & 0x001e) >> 1); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + } + return 2 | SUPPORTED; + + case 0x6200: + if (m_arch == cr16_arch::CR16A) + stream << "res"; + else + { + stream << "mulsw "; + format_reg(stream, (opcode & 0x001e) >> 1); + stream << ", "; + format_rpair(stream, (opcode & 0x01e0) >> 5); + } + return 2 | SUPPORTED; + + case 0x6400: case 0x6600: + if (m_arch == cr16_arch::CR16A) + { + stream << "res"; + return 2 | SUPPORTED; + } + else + { + stream << "movd "; + format_imm21(stream, u32(opcode & 0x0200) << 11 | u32(opcode & 0x000e) << 16 | u32(opcode & 0x0010) << 12 | opcodes.r16(pc + 2)); + stream << ", "; + format_rpair(stream, (opcode & 0x01e0) >> 5); + return 4 | SUPPORTED; + } + + case 0x6800: case 0x6a00: + util::stream_format(stream, "mov%cb ", BIT(opcode, 9) ? 'z' : 'x'); + format_reg(stream, (opcode & 0x001e) >> 1); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 2 | SUPPORTED; + + case 0x6c00: + // Push and pop group + if (m_arch == cr16_arch::CR16A) + stream << "res"; + else + { + if (BIT(opcode, 8)) + stream << "popret "; + else if (BIT(opcode, 7)) + stream << "pop "; + else + stream << "push "; + util::stream_format(stream, "$%d, ", ((opcode & 0x0060) >> 5) + 1); + format_reg(stream, (opcode & 0x001e) >> 1); + if (BIT(opcode, 8)) + { + util::stream_format(stream, " ; %cMM", BIT(opcode, 7) ? 'L' : 'S'); + return 2 | STEP_OUT | SUPPORTED; + } + } + return 2 | SUPPORTED; + + case 0x6e00: + if ((opcode & 0x01c0) != 0x01c0) + { + util::stream_format(stream, "s%s ", s_cc[(opcode & 0x01e0) >> 5]); + format_reg(stream, (opcode & 0x001e) >> 1); + } + else + stream << "res"; + return 2 | SUPPORTED; + + case 0x7000: + stream << "lpr "; + format_reg(stream, (opcode & 0x001e) >> 1); + stream << ", "; + format_rproc(stream, (opcode & 0x01e0) >> 5); + return 2 | SUPPORTED; + + case 0x7200: + stream << "spr "; + format_rproc(stream, (opcode & 0x01e0) >> 5); + stream << ", "; + format_reg(stream, (opcode & 0x001e) >> 1); + return 2 | SUPPORTED; + + case 0x7400: + // Conditional or unconditional branch to large address + if ((opcode & 0x01e0) != 0x01e0 && m_arch != cr16_arch::CR16A) + { + if ((opcode & 0x01e0) == 0x01c0) + stream << "br "; + else + util::stream_format(stream, "b%s ", s_cc[(opcode & 0x01e0) >> 5]); + format_pc_disp21(stream, pc, u32(opcode & 0x000e) << 16 | u32(opcode & 0x0010) << 12 | opcodes.r16(pc + 2)); + return 4 | SUPPORTED; + } + else + { + stream << "res"; + return 2 | SUPPORTED; + } + + case 0x7401: + // Jump and link to small address + stream << "jal "; + format_reg(stream, (opcode & 0x01e0) >> 5); + stream << ", "; + format_reg(stream, (opcode & 0x001e) >> 1); + return 2 | SUPPORTED; + + case 0x7600: + // Branch and link to large address + if (m_arch == cr16_arch::CR16A) + { + stream << "res"; + return 2 | SUPPORTED; + } + else + { + stream << "bal "; + format_rpair(stream, (opcode & 0x01e0) >> 5); + stream << ", "; + format_pc_disp21(stream, pc, u32(opcode & 0x000e) << 16 | u32(opcode & 0x0010) << 12 | opcodes.r16(pc + 2)); + return 4 | STEP_OVER | SUPPORTED; + } + + case 0x7601: + // TBIT reg, reg only exists as a word operation + stream << "tbit "; + format_reg(stream, (opcode & 0x001e) >> 1); + stream << ", "; + format_reg(stream, (opcode & 0x01e0) >> 5); + return 2 | SUPPORTED; + + case 0x7800: + if (opcode == 0x79fe) + { + stream << "retx"; + return 2 | STEP_OUT | SUPPORTED; + } + else + { + stream << "res"; + return 2 | SUPPORTED; + } + + case 0x7a00: + if ((opcode & 0x01e0) == 0x01e0) + { + stream << "excp "; + format_excp_vector(stream, (opcode & 0x001e) >> 1); + return 2 | STEP_OVER | SUPPORTED; + } + else + { + stream << "res"; + return 2 | SUPPORTED; + } + + case 0x7c00: + if (opcode == 0x7dde) + stream << "di"; + else if (opcode == 0x7dfe) + stream << "ei"; + else + stream << "res"; + return 2 | SUPPORTED; + + case 0x7e00: + // Various special operations + if (opcode == 0x7ffe) + stream << "wait"; + else if (m_arch == cr16_arch::CR16A) + stream << "res"; + else if ((opcode & 0x000c) == 0x0000) + { + stream << "muluw "; + format_reg(stream, (opcode & 0x0012) >> 1); + stream << ", "; + format_rpair(stream, (opcode & 0x01e0) >> 5); + } + else if ((opcode & 0x011e) == 0x0004) + { + if (BIT(opcode, 7)) + stream << "storm "; + else + stream << "loadm "; + util::stream_format(stream, "$%d", ((opcode & 0x0060) >> 5) + 1); + } + else if (opcode == 0x7fe6) + stream << "eiwait"; + else + stream << "res"; + return 2 | SUPPORTED; + + default: + stream << "res"; + return 2 | SUPPORTED; + } +} |