From 75a7445a985a9d90780566966db4ade4e2229019 Mon Sep 17 00:00:00 2001 From: AJR Date: Sat, 30 Jan 2021 12:30:56 -0500 Subject: [PATCH] unidasm: Add disassemblers for NEC/Renesas V850 family --- scripts/src/cpu.lua | 9 + src/devices/cpu/v850/v850dasm.cpp | 1028 +++++++++++++++++++++++++++++ src/devices/cpu/v850/v850dasm.h | 86 +++ src/tools/unidasm.cpp | 4 + 4 files changed, 1127 insertions(+) create mode 100644 src/devices/cpu/v850/v850dasm.cpp create mode 100644 src/devices/cpu/v850/v850dasm.h diff --git a/scripts/src/cpu.lua b/scripts/src/cpu.lua index f44462b78c3..4860eecbd5e 100644 --- a/scripts/src/cpu.lua +++ b/scripts/src/cpu.lua @@ -2017,6 +2017,15 @@ if (CPUS["V810"]~=null or _OPTIONS["with-tools"]) then table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/v810/v810dasm.h") end +-------------------------------------------------- +-- NEC V850, disassembler only +-------------------------------------------------- + +if (_OPTIONS["with-tools"]) then + table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/v850/v850dasm.cpp") + table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/v850/v850dasm.h") +end + -------------------------------------------------- -- NEC uPD7725 --@src/devices/cpu/upd7725/upd7725.h,CPUS["UPD7725"] = true diff --git a/src/devices/cpu/v850/v850dasm.cpp b/src/devices/cpu/v850/v850dasm.cpp new file mode 100644 index 00000000000..feab6087348 --- /dev/null +++ b/src/devices/cpu/v850/v850dasm.cpp @@ -0,0 +1,1028 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/*************************************************************************** + + NEC/Renesas V850 disassembler + + The "V850E2" disassembler includes some instructions which are actually + available only on V850E2S and V850E2M. More opcodes probably cause + reserved instruction exceptions (RIE) than are decoded for even these + advanced variants. + +***************************************************************************/ + +#include "emu.h" +#include "v850dasm.h" + +v850_disassembler::v850_disassembler() + : util::disasm_interface() +{ +} + +v850es_disassembler::v850es_disassembler() + : v850_disassembler() +{ +} + +v850e2_disassembler::v850e2_disassembler() + : v850es_disassembler() +{ +} + +u32 v850_disassembler::opcode_alignment() const +{ + return 2; +} + +const std::string_view v850_disassembler::s_regs[32] = { + "zero", "r1", "r2", "sp", "gp", "tp", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "ep", "lp" +}; + +const std::string_view v850_disassembler::s_dsp_ops[4] = { + "satsubr", "satsub", "satadd", "mulh" +}; + +const std::string_view v850es_disassembler::s_szx_ops[4] = { + "zxb", "sxb", "zxh", "sxh" +}; + +const std::string_view v850_disassembler::s_rr_ops[8] = { + "or", "xor", "and", "tst", "subr", "sub", "add", "cmp" +}; + +const std::string_view v850_disassembler::s_imm5_ops[8] = { + "mov", "satadd", "add", "cmp", "shr", "sar", "shl", "mulh" +}; + +const std::string_view v850_disassembler::s_bit_ops[4] = { + "set1", "not1", "clr1", "tst1" +}; + +const std::string_view v850_disassembler::s_conds[16] = { + "V", "C/L", "Z", "NH", "S/N", "T", "LT", "LE", + "NV", "NC/NL", "NZ", "H", "NS/P", "SA", "GE", "GT" +}; + +const std::string_view v850_disassembler::s_bconds[16] = { + "bv", "bc", "be", "bnh", "bn", "br", "blt", "ble", + "bnv", "bnc", "bne", "bh", "bp", "bsa", "bge", "bgt" +}; + +void v850_disassembler::format_system_reg(std::ostream &stream, u8 sreg) +{ + switch (sreg) + { + case 0: + stream << "EIPC"; + break; + + case 1: + stream << "EIPSW"; + break; + + case 2: + stream << "FEPC"; + break; + + case 3: + stream << "FEPSW"; + break; + + case 4: + stream << "ECR"; + break; + + case 5: + stream << "PSW"; + break; + + default: + util::stream_format(stream, "sr%d", sreg); + break; + } +} + +void v850es_disassembler::format_system_reg(std::ostream &stream, u8 sreg) +{ + switch (sreg) + { + case 16: + stream << "CTPC"; + break; + + case 17: + stream << "CTPSW"; + break; + + case 20: + stream << "CTBP"; + break; + + case 21: + stream << "DIR"; + break; + + default: + v850_disassembler::format_system_reg(stream, sreg); + break; + } +} + +void v850e2_disassembler::format_system_reg(std::ostream &stream, u8 sreg) +{ + switch (sreg) + { + case 28: + // V850E2S, V850E2M only + stream << "EIWR"; + break; + + case 29: + // V850E2S, V850E2M only + stream << "FEWR"; + break; + + case 30: + // V850E2S, V850E2M only + stream << "DBWR"; + break; + + case 31: + // V850E2S, V850E2M only + stream << "BSEL"; + break; + + default: + // all others are banked on V850E2S/E2M + util::stream_format(stream, "sr%d", sreg); + break; + } +} + +void v850_disassembler::format_imm5_signed(std::ostream &stream, u8 imm5) +{ + if (imm5 >= 0x20) + { + stream << '-'; + imm5 = 0x20 - imm5; + } + if (imm5 > 9) + stream << "0x"; + util::stream_format(stream, "%X", imm5); +} + +void v850_disassembler::format_imm16_signed(std::ostream &stream, u16 imm16) +{ + if (s16(imm16) < 0) + { + stream << '-'; + imm16 = -imm16; + } + if (imm16 > 9) + stream << "0x"; + util::stream_format(stream, "%X", imm16); +} + +void v850_disassembler::format_disp16_reg(std::ostream &stream, u16 disp16, u8 reg) +{ + if (reg == 0 && disp16 >= 0x8000) + stream << "0xFFFF"; + else + { + if (s16(disp16) < 0) + { + stream << '-'; + disp16 = -disp16; + } + if (disp16 > 9) + stream << "0x"; + } + util::stream_format(stream, "%X[%s]", disp16, s_regs[reg]); +} + +void v850_disassembler::format_disp8_ep(std::ostream &stream, u8 disp8) +{ + format_disp16_reg(stream, disp8, 30); +} + +void v850e2_disassembler::format_disp23_reg(std::ostream &stream, u32 disp23, u8 reg) +{ + if (disp23 >= 0x400000) + { + if (reg == 0) + disp23 |= 0xffc00000; + else + { + stream << '-'; + disp23 = 0x800000 - disp23; + } + } + util::stream_format(stream, "0x%X[%s]", disp23, s_regs[reg]); +} + +void v850e2_disassembler::format_disp32_reg(std::ostream &stream, u32 disp32, u8 reg) +{ + util::stream_format(stream, "0x%08X[%s]", disp32, s_regs[reg]); +} + +void v850es_disassembler::format_list12(std::ostream &stream, u16 list12) +{ + stream << '{'; + for (u8 reg = 20; list12 != 0; reg++) + { + if (BIT(list12, 11)) + { + stream << s_regs[reg]; + list12 &= 0x7ff; + if (list12 != 0) + stream << ", "; + } + list12 <<= 1; + } + stream << '}'; +} + +offs_t v850_disassembler::dasm_000000(std::ostream &stream, u16 opcode, offs_t pc, const v850_disassembler::data_buffer &opcodes) +{ + if (opcode == 0) + stream << "nop"; + else + util::stream_format(stream, "%-8s%s, %s", "mov", s_regs[BIT(opcode, 0, 5)], s_regs[BIT(opcode, 11, 5)]); + return 2 | SUPPORTED; +} + +offs_t v850e2_disassembler::dasm_000000(std::ostream &stream, u16 opcode, offs_t pc, const v850e2_disassembler::data_buffer &opcodes) +{ + if ((opcode & 0xf800) != 0) + return v850es_disassembler::dasm_000000(stream, opcode, pc, opcodes); + else switch (BIT(opcode, 0, 5)) + { + case 0b00000: + stream << "nop"; + break; + + case 0b11100: + // V850E2S, V850E2M only + stream << "syncm"; + break; + + case 0b11101: + // V850E2S, V850E2M only + stream << "synce"; + break; + + case 0b11111: + // V850E2S, V850E2M only + stream << "syncp"; + break; + + default: + stream << "rie"; + break; + } + return 2 | SUPPORTED; +} + +offs_t v850_disassembler::dasm_000010(std::ostream &stream, u16 opcode, offs_t pc, const v850_disassembler::data_buffer &opcodes) +{ + util::stream_format(stream, "%-8s%s, %s", "divh", s_regs[BIT(opcode, 0, 5)], s_regs[BIT(opcode, 11, 5)]); + return 2 | SUPPORTED; +} + +offs_t v850es_disassembler::dasm_000010(std::ostream &stream, u16 opcode, offs_t pc, const v850es_disassembler::data_buffer &opcodes) +{ + if (opcode == 0xf840) + { + stream << "dbtrap"; + return 2 | STEP_OVER | SUPPORTED; + } + else if ((opcode & 0xf800) == 0) + { + util::stream_format(stream, "%-8s%s", "switch", s_regs[BIT(opcode, 0, 5)]); + return 2 | SUPPORTED; + } + else + return v850_disassembler::dasm_000010(stream, opcode, pc, opcodes); +} + +offs_t v850e2_disassembler::dasm_000010(std::ostream &stream, u16 opcode, offs_t pc, const v850e2_disassembler::data_buffer &opcodes) +{ + if ((opcode & 0x001f) == 0) + { + if ((opcode & 0xe800) != 0 && !BIT(opcode, 15)) + { + // V850E2S, V850E2M only + util::stream_format(stream, "%-8s0x%X", "fetrap", 0x30 + BIT(opcode, 11, 4)); + return 2 | STEP_OVER | SUPPORTED; + } + else + { + stream << "rie"; + return 2 | SUPPORTED; + } + } + else + return v850es_disassembler::dasm_000010(stream, opcode, pc, opcodes); +} + +offs_t v850_disassembler::dasm_000011(std::ostream &stream, u16 opcode, offs_t pc, const v850_disassembler::data_buffer &opcodes) +{ + util::stream_format(stream, "%-8s[%s]", "jmp", s_regs[BIT(opcode, 0, 5)]); + return 2 | ((opcode & 0x001f) == 0x001f ? STEP_OUT : 0) | SUPPORTED; +} + +offs_t v850es_disassembler::dasm_000011(std::ostream &stream, u16 opcode, offs_t pc, const v850_disassembler::data_buffer &opcodes) +{ + if ((opcode & 0xf800) != 0) + { + u8 disp4 = BIT(opcode, 0, 4); + util::stream_format(stream, "%-8s", BIT(opcode, 4) ? "sld.hu" : "sld.bu"); + format_disp8_ep(stream, disp4); + util::stream_format(stream, ", %s", s_regs[BIT(opcode, 0, 5)]); + return 2 | SUPPORTED; + } + else + return v850_disassembler::dasm_000011(stream, opcode, pc, opcodes); +} + +offs_t v850_disassembler::dasm_0001(std::ostream &stream, u16 opcode, offs_t pc, const v850_disassembler::data_buffer &opcodes) +{ + util::stream_format(stream, "%-8s%s, %s", s_dsp_ops[BIT(opcode, 5, 2)], s_regs[BIT(opcode, 0, 5)], s_regs[BIT(opcode, 11, 5)]); + return 2 | SUPPORTED; +} + +offs_t v850es_disassembler::dasm_0001(std::ostream &stream, u16 opcode, offs_t pc, const v850_disassembler::data_buffer &opcodes) +{ + if ((opcode & 0xf800) == 0) + { + util::stream_format(stream, "%-8s%s", s_szx_ops[BIT(opcode, 5, 2)], s_regs[BIT(opcode, 0, 5)]); + return 2 | SUPPORTED; + } + else + return v850_disassembler::dasm_0001(stream, opcode, pc, opcodes); +} + +offs_t v850_disassembler::dasm_010x(std::ostream &stream, u16 opcode, offs_t pc, const v850_disassembler::data_buffer &opcodes) +{ + u8 imm5 = BIT(opcode, 0, 5); + util::stream_format(stream, "%-8s", s_imm5_ops[BIT(opcode, 5, 3)]); + if (BIT(opcode, 7) && (opcode & 0x00c0) != 0x00c0) + util::stream_format(stream, "%d", imm5); + else + format_imm5_signed(stream, imm5); + util::stream_format(stream, ", %s", s_regs[BIT(opcode, 11, 5)]); + return 2 | SUPPORTED; +} + +offs_t v850es_disassembler::dasm_010x(std::ostream &stream, u16 opcode, offs_t pc, const v850es_disassembler::data_buffer &opcodes) +{ + if ((opcode & 0xf8c0) == 0) + { + util::stream_format(stream, "%-8s0x%02X", "callt", BIT(opcode, 0, 6)); + return 2 | STEP_OVER | SUPPORTED; + } + else + return v850_disassembler::dasm_010x(stream, opcode, pc, opcodes); +} + +offs_t v850e2_disassembler::dasm_010x(std::ostream &stream, u16 opcode, offs_t pc, const v850e2_disassembler::data_buffer &opcodes) +{ + if ((opcode & 0xf8e0) == 0x00e0) + { + s32 disp32 = opcodes.r32(pc + 2); + if ((opcode & 0x001f) == 0) + { + util::stream_format(stream, "%-8s0x%08X", "jr", pc + disp32); + return 6 | SUPPORTED; + } + else + { + util::stream_format(stream, "%-8s0x%08X, %s", "jarl", pc + disp32, s_regs[BIT(opcode, 0, 5)]); + return 6 | STEP_OVER | SUPPORTED; + } + } + else + return v850es_disassembler::dasm_010x(stream, opcode, pc, opcodes); +} + +offs_t v850_disassembler::dasm_1100(std::ostream &stream, u16 opcode, offs_t pc, const v850_disassembler::data_buffer &opcodes) +{ + u16 imm16 = opcodes.r16(pc + 2); + if ((opcode & 0x0060) == 0x0040) + util::stream_format(stream, "%-8s0x%04X", "movhi", imm16); + else + { + util::stream_format(stream, "%-8s", BIT(opcode, 6) ? "satsubi" : BIT(opcode, 5) ? "movea" : "addi"); + format_imm16_signed(stream, imm16); + } + util::stream_format(stream, ", %s, %s", s_regs[BIT(opcode, 0, 5)], s_regs[BIT(opcode, 11, 5)]); + return 4 | SUPPORTED; +} + +offs_t v850es_disassembler::dasm_1100(std::ostream &stream, u16 opcode, offs_t pc, const v850es_disassembler::data_buffer &opcodes) +{ + if ((opcode & 0xf840) == 0x0040) + { + u32 opcode2 = opcodes.r16(pc + 2); + u8 imm5 = BIT(opcode, 1, 5); + util::stream_format(stream, "%-8s%s%X, ", "dispose", imm5 > 9 ? "0x" : "", imm5); + format_list12(stream, (opcode2 & 0x0f00) | (opcode2 & 0xf000) >> 8 | (opcode2 & 0x00c0) >> 4 | (opcode & 0x0001) << 1 | (opcode2 & 0x0020) >> 5); + if ((opcode2 & 0x001f) != 0) + { + util::stream_format(stream, ", [%s]", s_regs[BIT(opcode2, 0, 5)]); + return 4 | STEP_OUT | SUPPORTED; + } + else + return 4 | SUPPORTED; + } + else if ((opcode & 0xf860) == 0x0020) + { + u32 imm32 = opcodes.r32(pc + 2); + util::stream_format(stream, "%-8s0x%08X, %s", "mov", imm32, s_regs[BIT(opcode, 0, 5)]); + return 6 | SUPPORTED; + } + else + return v850_disassembler::dasm_1100(stream, opcode, pc, opcodes); +} + +offs_t v850_disassembler::dasm_1101(std::ostream &stream, u16 opcode, offs_t pc, const v850_disassembler::data_buffer &opcodes) +{ + u16 imm16 = opcodes.r16(pc + 2); + if ((opcode & 0x0060) == 0x0060) + { + util::stream_format(stream, "%-8s", "mulhi"); + format_imm16_signed(stream, imm16); + util::stream_format(stream, ", %s, %s", s_regs[BIT(opcode, 0, 5)], s_regs[BIT(opcode, 11, 5)]); + } + else + util::stream_format(stream, "%-8s0x%04X, %s, %s", BIT(opcode, 6) ? "andi" : BIT(opcode, 5) ? "xori" : "ori", + imm16, s_regs[BIT(opcode, 0, 5)], s_regs[BIT(opcode, 11, 5)]); + return 4 | SUPPORTED; +} + +offs_t v850e2_disassembler::dasm_1101(std::ostream &stream, u16 opcode, offs_t pc, const v850e2_disassembler::data_buffer &opcodes) +{ + if ((opcode & 0xf860) == 0x0060) + { + u32 disp32 = opcodes.r32(pc + 2); + util::stream_format(stream, "%-8s", "jmp"); + format_disp32_reg(stream, disp32, BIT(opcode, 0, 5)); + return 6 | SUPPORTED; + } + else + return v850es_disassembler::dasm_1101(stream, opcode, pc, opcodes); +} + +offs_t v850_disassembler::dasm_11110(std::ostream &stream, u16 opcode1, u16 opcode2, offs_t pc, const v850_disassembler::data_buffer &opcodes) +{ + s32 disp22 = u32(opcode1 & 0x003f) << 16 | opcode2; + if (BIT(opcode1, 5)) + disp22 -= 0x400000; + if ((opcode1 & 0xf800) != 0) + { + util::stream_format(stream, "%-8s0x%08X, %s", "jarl", pc + disp22, s_regs[BIT(opcode1, 11, 5)]); + return 4 | STEP_OVER | SUPPORTED; + } + else + { + util::stream_format(stream, "%-8s0x%08X", "jr", pc + disp22); + return 4 | SUPPORTED; + } +} + +offs_t v850es_disassembler::dasm_11110(std::ostream &stream, u16 opcode1, u16 opcode2, offs_t pc, const v850es_disassembler::data_buffer &opcodes) +{ + if (!BIT(opcode2, 0)) + return v850_disassembler::dasm_11110(stream, opcode1, opcode2, pc, opcodes); + else if ((opcode1 & 0xf800) != 0) + { + util::stream_format(stream, "%-8s", "ld.bu"); + format_disp16_reg(stream, (opcode2 & 0xfffe) | (opcode1 & 0x0020) >> 5, BIT(opcode1, 0, 5)); + util::stream_format(stream, ", %s", s_regs[BIT(opcode1, 11, 5)]); + return 4 | SUPPORTED; + } + else + { + u8 imm5 = BIT(opcode1, 1, 5); + util::stream_format(stream, "%-8s", "prepare"); + format_list12(stream, (opcode2 & 0x0f00) | (opcode2 & 0xf000) >> 8 | (opcode2 & 0x00c0) >> 4 | (opcode1 & 0x0001) << 1 | (opcode2 & 0x0020) >> 5); + util::stream_format(stream, ", %s%X", imm5 > 9 ? "0x" : "", imm5); + switch (opcode2 & 0x001a) + { + case 0b00000: + default: + // EP unchanged + return 4 | SUPPORTED; + + case 0b00010: + // SP to EP + util::stream_format(stream, ", %s", s_regs[3]); + return 4 | SUPPORTED; + + case 0b01010: + // 16-bit immediate data sign-extended into EP + stream << ", "; + format_imm16_signed(stream, opcodes.r16(pc + 4)); + return 6 | SUPPORTED; + + case 0b10010: + // 16-bit immediate data logically shifted left by 16 to EP + util::stream_format(stream, ", 0x%04X0000", opcodes.r16(pc + 4)); + return 6 | SUPPORTED; + + case 0b11010: + // 32-bit immediate data to EP + util::stream_format(stream, "0x%08X", opcodes.r32(pc + 4)); + return 8 | SUPPORTED; + } + } +} + +offs_t v850e2_disassembler::dasm_11110(std::ostream &stream, u16 opcode1, u16 opcode2, offs_t pc, const v850e2_disassembler::data_buffer &opcodes) +{ + if ((opcode1 & 0xf800) == 0) + { + // V850E2S, V850E2M only for these forms + switch (BIT(opcode2, 0, 4)) + { + case 0b0101: + util::stream_format(stream, "%-8s", BIT(opcode1, 5) ? "ld.bu" : "ld.b"); + format_disp23_reg(stream, BIT(opcode2, 4, 7) | u32(opcodes.r16(pc + 4)) << 7, BIT(opcode1, 0, 5)); + util::stream_format(stream, ", %s", s_regs[BIT(opcode2, 11, 5)]); + return 6 | SUPPORTED; + + case 0b0111: + util::stream_format(stream, "%-8s", BIT(opcode1, 5) ? "ld.hu" : "ld.h"); + format_disp23_reg(stream, BIT(opcode2, 4, 7) | u32(opcodes.r16(pc + 4)) << 7, BIT(opcode1, 0, 5)); + util::stream_format(stream, ", %s", s_regs[BIT(opcode2, 11, 5)]); + return 6 | SUPPORTED; + + case 0b1001: + util::stream_format(stream, "%-8s", "ld.w"); + format_disp23_reg(stream, BIT(opcode2, 4, 7) | u32(opcodes.r16(pc + 4)) << 7, BIT(opcode1, 0, 5)); + util::stream_format(stream, ", %s", s_regs[BIT(opcode2, 11, 5)]); + return 6 | SUPPORTED; + + case 0b1101: + util::stream_format(stream, "%-8s%s, ", BIT(opcode1, 5) ? "st.h" : "st.b", s_regs[BIT(opcode2, 11, 5)]); + format_disp23_reg(stream, BIT(opcode2, 4, 7) | u32(opcodes.r16(pc + 4)) << 7, BIT(opcode1, 0, 5)); + return 6 | SUPPORTED; + + case 0b1111: + util::stream_format(stream, "%-8s%s, ", "st.w", s_regs[BIT(opcode2, 11, 5)]); + format_disp23_reg(stream, BIT(opcode2, 4, 7) | u32(opcodes.r16(pc + 4)) << 7, BIT(opcode1, 0, 5)); + return 6 | SUPPORTED; + } + } + return v850es_disassembler::dasm_11110(stream, opcode1, opcode2, pc, opcodes); +} + +offs_t v850_disassembler::dasm_extended(std::ostream &stream, u16 opcode1, u16 opcode2, offs_t pc, const v850_disassembler::data_buffer &opcodes) +{ + switch (BIT(opcode2, 5, 6)) + { + case 0b000000: + util::stream_format(stream, "%-8s%s, %s", "setf", s_conds[BIT(opcode1, 0, 4)], s_regs[BIT(opcode1, 11, 5)]); + return 4 | SUPPORTED; + + case 0b000001: + util::stream_format(stream, "%-8s%s, ", "ldsr", s_regs[BIT(opcode1, 0, 5)]); + format_system_reg(stream, BIT(opcode1, 11, 5)); + return 4 | SUPPORTED; + + case 0b000010: + util::stream_format(stream, "%-8s", "stsr"); + format_system_reg(stream, BIT(opcode1, 0, 5)); + util::stream_format(stream, ", %s", s_regs[BIT(opcode1, 11, 5)]); + return 4 | SUPPORTED; + + case 0b000100: case 0b000101: case 0b000110: + util::stream_format(stream, "%-8s%s, %s", s_imm5_ops[BIT(opcode2, 5, 3)], + s_regs[BIT(opcode1, 0, 5)], s_regs[BIT(opcode1, 11, 5)]); + return 4 | SUPPORTED; + + case 0b001000: + util::stream_format(stream, "%-8s0x%02X", "trap", BIT(opcode1, 0, 5)); + return 4 | STEP_OVER | SUPPORTED; + + case 0b001001: + stream << "halt"; + return 4 | SUPPORTED; + + case 0b001010: + stream << "reti"; + return 4 | STEP_OUT | SUPPORTED; + + case 0b001011: + switch (BIT(opcode1, 13, 3)) + { + case 0b000: + stream << "di"; + return 4 | SUPPORTED; + + case 0b100: + stream << "ei"; + return 4 | SUPPORTED; + } + [[fallthrough]]; + + case 0b000011: case 0b000111: case 0b001100: case 0b001101: case 0b001110: + util::stream_format(stream, "%-8s0x%04X%04X ; undefined", "dw", opcode2, opcode1); + return 4 | SUPPORTED; + + default: + util::stream_format(stream, "%-8s0x%04X%04X ; ILGOP", "dw", opcode2, opcode1); + return 4 | SUPPORTED; + } +} + +offs_t v850es_disassembler::dasm_extended(std::ostream &stream, u16 opcode1, u16 opcode2, offs_t pc, const v850_disassembler::data_buffer &opcodes) +{ + if (BIT(opcode2, 0)) + { + util::stream_format(stream, "%-8s", "ld.hu"); + format_disp16_reg(stream, opcode2 & 0xfffe, BIT(opcode1, 0, 5)); + util::stream_format(stream, ", %s", s_regs[BIT(opcode1, 11, 5)]); + return 4 | SUPPORTED; + } + else switch (BIT(opcode2, 5, 6)) + { + case 0b000111: + util::stream_format(stream, "%-8s%s, [%s]", s_bit_ops[BIT(opcode2, 1, 2)], + s_regs[BIT(opcode1, 11, 5)], s_regs[BIT(opcode1, 0, 5)]); + return 4 | SUPPORTED; + + case 0b001010: + switch (BIT(opcode2, 1, 2)) + { + case 0b00: + stream << "reti"; + return 4 | STEP_OUT | SUPPORTED; + + case 0b10: + stream << "ctret"; + return 4 | STEP_OUT | SUPPORTED; + + case 0b11: + stream << "dbret"; + return 4 | STEP_OUT | SUPPORTED; + + default: + util::stream_format(stream, "%-8s0x%04X%04X ; undefined", "dw", opcode2, opcode1); + return 4 | SUPPORTED; + } + + case 0b001011: + switch (BIT(opcode1, 11, 5)) + { + case 0b00000: + stream << "di"; + return 4 | SUPPORTED; + + case 0b10000: + stream << "ei"; + return 4 | SUPPORTED; + + default: + util::stream_format(stream, "%-8s0x%04X%04X ; undefined", "dw", opcode2, opcode1); + return 4 | SUPPORTED; + } + + case 0b010000: + util::stream_format(stream, "%-8s%s, %s", "sasf", s_conds[BIT(opcode1, 0, 4)], s_regs[BIT(opcode1, 11, 5)]); + return 4 | SUPPORTED; + + case 0b010001: + util::stream_format(stream, "%-8s%s, %s, %s", BIT(opcode2, 1) ? "mulu" : "mul", + s_regs[BIT(opcode1, 0, 5)], s_regs[BIT(opcode1, 11, 5)], s_regs[BIT(opcode2, 11, 5)]); + return 4 | SUPPORTED; + + case 0b010010: case 0b010011: + { + u16 imm9 = (opcode1 & 0x001f) | (opcode2 & 0x003c) << 3; + util::stream_format(stream, "%-8s", BIT(opcode2, 1) ? "mulu" : "mul"); + if (imm9 >= 0x100) + { + stream << '-'; + imm9 = 0x200 - imm9; + } + if (imm9 > 9) + stream << "0x"; + util::stream_format(stream, "%X, %s, %s", imm9, s_regs[BIT(opcode1, 11, 5)], s_regs[BIT(opcode2, 11, 5)]); + return 4 | SUPPORTED; + } + + case 0b010100: case 0b010101: + util::stream_format(stream, "%-8s%s, %s, %s", BIT(opcode2, 1) ? "divhu" : "divh", + s_regs[BIT(opcode1, 0, 5)], s_regs[BIT(opcode1, 11, 5)], s_regs[BIT(opcode2, 11, 5)]); + return 4 | SUPPORTED; + + case 0b010110: case 0b010111: + util::stream_format(stream, "%-8s%s, %s, %s", BIT(opcode2, 1) ? "divu" : "div", + s_regs[BIT(opcode1, 0, 5)], s_regs[BIT(opcode1, 11, 5)], s_regs[BIT(opcode2, 11, 5)]); + return 4 | SUPPORTED; + + case 0b011000: + util::stream_format(stream, "%-8s%s, ", "cmov", s_conds[BIT(opcode2, 1, 4)]); + format_imm5_signed(stream, BIT(opcode1, 0, 5)); + util::stream_format(stream, ", %s, %s", s_regs[BIT(opcode1, 11, 5)], s_regs[BIT(opcode2, 11, 5)]); + return 4 | SUPPORTED; + + case 0b011001: + util::stream_format(stream, "%-8s%s, %s, %s", "cmov", + s_conds[BIT(opcode2, 1, 4)], s_regs[BIT(opcode1, 11, 5)], s_regs[BIT(opcode2, 11, 5)]); + return 4 | SUPPORTED; + + case 0b011010: + switch (BIT(opcode2, 1, 4)) + { + case 0b0000: + util::stream_format(stream, "%-8s%s, %s", "bsw", s_regs[BIT(opcode1, 11, 5)], s_regs[BIT(opcode2, 11, 5)]); + return 4 | SUPPORTED; + + case 0b0001: + util::stream_format(stream, "%-8s%s, %s", "bsh", s_regs[BIT(opcode1, 11, 5)], s_regs[BIT(opcode2, 11, 5)]); + return 4 | SUPPORTED; + + case 0b0010: + util::stream_format(stream, "%-8s%s, %s", "hsw", s_regs[BIT(opcode1, 11, 5)], s_regs[BIT(opcode2, 11, 5)]); + return 4 | SUPPORTED; + } + [[fallthrough]]; + + case 0b000011: case 0b011011: case 0b011100: case 0b011101: case 0b011110: + util::stream_format(stream, "%-8s0x%04X%04X ; undefined", "dw", opcode2, opcode1); + return 4 | SUPPORTED; + + default: + return v850_disassembler::dasm_extended(stream, opcode1, opcode2, pc, opcodes); + } +} + +offs_t v850e2_disassembler::dasm_extended(std::ostream &stream, u16 opcode1, u16 opcode2, offs_t pc, const v850e2_disassembler::data_buffer &opcodes) +{ + if (!BIT(opcode2, 0)) + { + if (opcode2 == 0 && BIT(opcode1, 4)) + { + util::stream_format(stream, "%-8s0x%02X, 0x%X", "rie", BIT(opcode1, 11, 5), BIT(opcode1, 0, 4)); + return 4 | SUPPORTED; + } + else if ((opcode2 & 0x07ff) == 0x0346) + { + util::stream_format(stream, "%-8s%s, %s", "hsh", s_regs[BIT(opcode1, 11, 5)], s_regs[BIT(opcode2, 11, 5)]); + return 4 | SUPPORTED; + } + else switch (BIT(opcode2, 5, 6)) + { + case 0b000100: case 0b000101: case 0b000110: + util::stream_format(stream, "%-8s%s, %s", s_imm5_ops[BIT(opcode2, 5, 3)], + s_regs[BIT(opcode1, 0, 5)], s_regs[BIT(opcode1, 11, 5)]); + if (BIT(opcode2, 1)) + util::stream_format(stream, ", %s", s_regs[BIT(opcode2, 11, 5)]); + return 4 | SUPPORTED; + + case 0b000111: + switch (BIT(opcode2, 1, 4)) + { + case 0b0000: case 0b0001: case 0b0010: case 0b0011: + util::stream_format(stream, "%-8s%s, [%s]", s_bit_ops[BIT(opcode2, 1, 2)], + s_regs[BIT(opcode1, 11, 5)], s_regs[BIT(opcode1, 0, 5)]); + return 4 | SUPPORTED; + + case 0b0111: + // V850E2S, V850E2M only + util::stream_format(stream, "%-8s[%s], %s, %s", "caxi", + s_regs[BIT(opcode1, 0, 5)], s_regs[BIT(opcode1, 11, 5)], s_regs[BIT(opcode2, 11, 5)]); + return 4 | SUPPORTED; + + default: + stream << "rie"; + return 4 | SUPPORTED; + } + + case 0b001010: + switch (BIT(opcode2, 1, 4)) + { + case 0b0000: + stream << "reti"; + return 4 | STEP_OUT | SUPPORTED; + + case 0b0010: + stream << "ctret"; + return 4 | STEP_OUT | SUPPORTED; + + case 0b0100: + // V850E2S, V850E2M only + stream << "eiret"; + return 4 | STEP_OUT | SUPPORTED; + + case 0b0101: + // V850E2S, V850E2M only + stream << "feret"; + return 4 | STEP_OUT | SUPPORTED; + + default: + stream << "rie"; + return 4 | SUPPORTED; + } + + case 0b001011: + switch (BIT(opcode1, 11, 5)) + { + case 0b00000: + stream << "di"; + return 4 | SUPPORTED; + + case 0b10000: + stream << "ei"; + return 4 | SUPPORTED; + + case 0b11010: + // V850E2S, V850E2M only + util::stream_format(stream, "%-8s0x%02X", "syscall", (opcode1 & 0x001f) | (opcode2 & 0x3800) >> 6); + return 4 | STEP_OVER | SUPPORTED; + + default: + stream << "rie"; + return 4 | SUPPORTED; + } + + case 0b010111: + // V850E2S, V850E2M only + util::stream_format(stream, "%-8s%s, %s, %s", BIT(opcode2, 1) ? "divqu" : "divq", + s_regs[BIT(opcode1, 0, 5)], s_regs[BIT(opcode1, 11, 5)], s_regs[BIT(opcode2, 11, 5)]); + return 4 | SUPPORTED; + + case 0b011011: + switch (BIT(opcode2, 1, 4)) + { + case 0b0000: + util::stream_format(stream, "%-8s%s, %s", "sch0r", s_regs[BIT(opcode1, 11, 5)], s_regs[BIT(opcode2, 11, 5)]); + return 4 | SUPPORTED; + + case 0b0001: + util::stream_format(stream, "%-8s%s, %s", "sch1r", s_regs[BIT(opcode1, 11, 5)], s_regs[BIT(opcode2, 11, 5)]); + return 4 | SUPPORTED; + + case 0b0010: + util::stream_format(stream, "%-8s%s, %s", "sch0l", s_regs[BIT(opcode1, 11, 5)], s_regs[BIT(opcode2, 11, 5)]); + return 4 | SUPPORTED; + + case 0b0011: + util::stream_format(stream, "%-8s%s, %s", "sch1l", s_regs[BIT(opcode1, 11, 5)], s_regs[BIT(opcode2, 11, 5)]); + return 4 | SUPPORTED; + + default: + stream << "rie"; + return 4 | SUPPORTED; + } + + case 0b011100: case 0b011101: + if ((opcode2 & 0x001e) != 0x001a) + util::stream_format(stream, "%-8s%s, %s, %s, %s", BIT(opcode2, 5) ? "adf" : "sbf", s_conds[BIT(opcode2, 1, 4)], + s_regs[BIT(opcode1, 0, 5)], s_regs[BIT(opcode1, 11, 5)], s_regs[BIT(opcode2, 11, 5)]); + else + util::stream_format(stream, "%-8s%s, %s, %s", BIT(opcode2, 5) ? "satadd" : "satsub", + s_regs[BIT(opcode1, 0, 5)], s_regs[BIT(opcode1, 11, 5)], s_regs[BIT(opcode2, 11, 5)]); + return 4 | SUPPORTED; + + case 0b011110: case 0b011111: + util::stream_format(stream, "%-8s%s, %s, %s, %s", BIT(opcode2, 5) ? "macu" : "mac", + s_regs[BIT(opcode1, 0, 5)], s_regs[BIT(opcode1, 11, 5)], + s_regs[BIT(opcode2, 11, 5)], s_regs[BIT(opcode2, 0, 5)]); + return 4 | SUPPORTED; + } + } + return v850es_disassembler::dasm_extended(stream, opcode1, opcode2, pc, opcodes); +} + +offs_t v850_disassembler::disassemble(std::ostream &stream, offs_t pc, const v850_disassembler::data_buffer &opcodes, const v850_disassembler::data_buffer ¶ms) +{ + u16 opcode = opcodes.r16(pc); + + switch (BIT(opcode, 7, 4)) + { + default: // compiler warnings can be a nuisance + case 0b0000: + if (BIT(opcode, 6)) + { + if (BIT(opcode, 5)) + return dasm_000011(stream, opcode, pc, opcodes); + else + return dasm_000010(stream, opcode, pc, opcodes); + } + else if (BIT(opcode, 5)) + { + util::stream_format(stream, "%-8s%s, %s", "not", s_regs[BIT(opcode, 0, 5)], s_regs[BIT(opcode, 11, 5)]); + return 2 | SUPPORTED; + } + else + return dasm_000000(stream, opcode, pc, opcodes); + + case 0b0001: + return dasm_0001(stream, opcode, pc, opcodes); + + case 0b0010: case 0b0011: + util::stream_format(stream, "%-8s%s, %s", s_rr_ops[BIT(opcode, 5, 3)], s_regs[BIT(opcode, 0, 5)], s_regs[BIT(opcode, 11, 5)]); + return 2 | SUPPORTED; + + case 0b0100: case 0b0101: + return dasm_010x(stream, opcode, pc, opcodes); + + case 0b0110: + { + u8 disp7 = BIT(opcode, 0, 7); + util::stream_format(stream, "%-8s", "sld.b"); + format_disp8_ep(stream, disp7); + util::stream_format(stream, ", %s", s_regs[BIT(opcode, 11, 5)]); + return 2 | SUPPORTED; + } + + case 0b0111: + { + u8 disp7 = BIT(opcode, 0, 7); + util::stream_format(stream, "%-8s", "sst.b"); + util::stream_format(stream, "%s, ", s_regs[BIT(opcode, 11, 5)]); + format_disp8_ep(stream, disp7); + return 2 | SUPPORTED; + } + + case 0b1000: + { + u8 disp8 = BIT(opcode, 0, 7) << 1; + util::stream_format(stream, "%-8s", "sld.h"); + format_disp8_ep(stream, disp8); + util::stream_format(stream, ", %s", s_regs[BIT(opcode, 11, 5)]); + return 2 | SUPPORTED; + } + + case 0b1001: + { + u8 disp8 = BIT(opcode, 0, 7) << 1; + util::stream_format(stream, "%-8s", "sst.h"); + util::stream_format(stream, "%s, ", s_regs[BIT(opcode, 11, 5)]); + format_disp8_ep(stream, disp8); + return 2 | SUPPORTED; + } + + case 0b1010: + { + u8 disp8 = BIT(opcode, 1, 6) << 2; + if (BIT(opcode, 0)) + { + util::stream_format(stream, "%-8s", "sst.w"); + util::stream_format(stream, "%s, ", s_regs[BIT(opcode, 11, 5)]); + format_disp8_ep(stream, disp8); + } + else + { + util::stream_format(stream, "%-8s", "sld.w"); + format_disp8_ep(stream, disp8); + util::stream_format(stream, ", %s", s_regs[BIT(opcode, 11, 5)]); + } + return 2 | SUPPORTED; + } + + case 0b1011: + { + s16 disp9 = s8((opcode & 0xf800) >> 8 | (opcode & 0x0070) >> 4) * 2; + util::stream_format(stream, "%-8s0x%08X", s_bconds[BIT(opcode, 0, 4)], pc + disp9); + return 2 | SUPPORTED; + } + + case 0b1100: + return dasm_1100(stream, opcode, pc, opcodes); + + case 0b1101: + return dasm_1101(stream, opcode, pc, opcodes); + + case 0b1110: + { + u16 disp16 = opcodes.r16(pc + 2); + if (BIT(opcode, 6)) + util::stream_format(stream, "%-8s%s, ", BIT(opcode, 5) ? (BIT(disp16, 0) ? "st.w" : "st.h") : "st.b", s_regs[BIT(opcode, 11, 5)]); + else + util::stream_format(stream, "%-8s", BIT(opcode, 5) ? (BIT(disp16, 0) ? "ld.w" : "ld.h") : "ld.b"); + format_disp16_reg(stream, BIT(opcode, 5) ? disp16 & 0xfffe : disp16, BIT(opcode, 0, 5)); + if (!BIT(opcode, 6)) + util::stream_format(stream, ", %s", s_regs[BIT(opcode, 11, 5)]); + return 4 | SUPPORTED; + } + + case 0b1111: + if (!BIT(opcode, 6)) + return dasm_11110(stream, opcode, opcodes.r16(pc + 2), pc, opcodes); + else if (BIT(opcode, 5)) + return dasm_extended(stream, opcode, opcodes.r16(pc + 2), pc, opcodes); + else + { + util::stream_format(stream, "%-8s%d, ", s_bit_ops[BIT(opcode, 14, 2)], BIT(opcode, 11, 3)); + format_disp16_reg(stream, opcodes.r16(pc + 2), BIT(opcode, 0, 5)); + return 4 | SUPPORTED; + } + } +} diff --git a/src/devices/cpu/v850/v850dasm.h b/src/devices/cpu/v850/v850dasm.h new file mode 100644 index 00000000000..7b5ff1649e8 --- /dev/null +++ b/src/devices/cpu/v850/v850dasm.h @@ -0,0 +1,86 @@ +// license:BSD-3-Clause +// copyright-holders:AJR + +#ifndef MAME_CPU_V850_V850DASM_H +#define MAME_CPU_V850_V850DASM_H + +#pragma once + +#include + +class v850_disassembler : public util::disasm_interface +{ +public: + // construction/destruction + v850_disassembler(); + + // 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; + +protected: + // internal helpers + virtual void format_system_reg(std::ostream &stream, u8 sreg); + void format_imm5_signed(std::ostream &stream, u8 imm5); + void format_imm16_signed(std::ostream &stream, u16 imm16); + void format_disp16_reg(std::ostream &stream, u16 disp16, u8 reg); + void format_disp8_ep(std::ostream &stream, u8 disp8); + virtual offs_t dasm_000000(std::ostream &stream, u16 opcode, offs_t pc, const data_buffer &opcodes); + virtual offs_t dasm_000010(std::ostream &stream, u16 opcode, offs_t pc, const data_buffer &opcodes); + virtual offs_t dasm_000011(std::ostream &stream, u16 opcode, offs_t pc, const data_buffer &opcodes); + virtual offs_t dasm_0001(std::ostream &stream, u16 opcode, offs_t pc, const data_buffer &opcodes); + virtual offs_t dasm_010x(std::ostream &stream, u16 opcode, offs_t pc, const data_buffer &opcodes); + virtual offs_t dasm_1100(std::ostream &stream, u16 opcode, offs_t pc, const data_buffer &opcodes); + virtual offs_t dasm_1101(std::ostream &stream, u16 opcode, offs_t pc, const data_buffer &opcodes); + virtual offs_t dasm_11110(std::ostream &stream, u16 opcode1, u16 opcode2, offs_t pc, const data_buffer &opcodes); + virtual offs_t dasm_extended(std::ostream &stream, u16 opcode1, u16 opcode2, offs_t pc, const data_buffer &opcodes); + + // static tables + static const std::string_view s_regs[32]; + static const std::string_view s_dsp_ops[4]; + static const std::string_view s_rr_ops[8]; + static const std::string_view s_imm5_ops[8]; + static const std::string_view s_bit_ops[4]; + static const std::string_view s_conds[16]; + static const std::string_view s_bconds[16]; +}; + +class v850es_disassembler : public v850_disassembler +{ +public: + // construction/destruction + v850es_disassembler(); + +protected: + void format_list12(std::ostream &stream, u16 list12); + virtual void format_system_reg(std::ostream &stream, u8 sreg) override; + virtual offs_t dasm_000010(std::ostream &stream, u16 opcode, offs_t pc, const data_buffer &opcodes) override; + virtual offs_t dasm_000011(std::ostream &stream, u16 opcode, offs_t pc, const data_buffer &opcodes) override; + virtual offs_t dasm_0001(std::ostream &stream, u16 opcode, offs_t pc, const data_buffer &opcodes) override; + virtual offs_t dasm_010x(std::ostream &stream, u16 opcode, offs_t pc, const data_buffer &opcodes) override; + virtual offs_t dasm_1100(std::ostream &stream, u16 opcode, offs_t pc, const data_buffer &opcodes) override; + virtual offs_t dasm_11110(std::ostream &stream, u16 opcode1, u16 opcode2, offs_t pc, const data_buffer &opcodes) override; + virtual offs_t dasm_extended(std::ostream &stream, u16 opcode1, u16 opcode2, offs_t pc, const data_buffer &opcodes) override; + + static const std::string_view s_szx_ops[4]; +}; + +class v850e2_disassembler : public v850es_disassembler +{ +public: + // construction/destruction + v850e2_disassembler(); + +protected: + void format_disp23_reg(std::ostream &stream, u32 disp23, u8 reg); + void format_disp32_reg(std::ostream &stream, u32 disp32, u8 reg); + virtual void format_system_reg(std::ostream &stream, u8 sreg) override; + virtual offs_t dasm_000000(std::ostream &stream, u16 opcode, offs_t pc, const data_buffer &opcodes) override; + virtual offs_t dasm_000010(std::ostream &stream, u16 opcode, offs_t pc, const data_buffer &opcodes) override; + virtual offs_t dasm_010x(std::ostream &stream, u16 opcode, offs_t pc, const data_buffer &opcodes) override; + virtual offs_t dasm_1101(std::ostream &stream, u16 opcode, offs_t pc, const data_buffer &opcodes) override; + virtual offs_t dasm_11110(std::ostream &stream, u16 opcode1, u16 opcode2, offs_t pc, const data_buffer &opcodes) override; + virtual offs_t dasm_extended(std::ostream &stream, u16 opcode1, u16 opcode2, offs_t pc, const data_buffer &opcodes) override; +}; + +#endif // MAME_CPU_V850_V850DASM_H diff --git a/src/tools/unidasm.cpp b/src/tools/unidasm.cpp index 81232078454..8566bc221b7 100644 --- a/src/tools/unidasm.cpp +++ b/src/tools/unidasm.cpp @@ -180,6 +180,7 @@ using util::BIT; #include "cpu/upd78k/upd78k3d.h" #include "cpu/v60/v60d.h" #include "cpu/v810/v810dasm.h" +#include "cpu/v850/v850dasm.h" #include "cpu/vt50/vt50dasm.h" #include "cpu/vt61/vt61dasm.h" #include "cpu/we32000/we32100d.h" @@ -616,6 +617,9 @@ static const dasm_table_entry dasm_table[] = { "upi41", le, 0, []() -> util::disasm_interface * { return new mcs48_disassembler(true, false); } }, { "v60", le, 0, []() -> util::disasm_interface * { return new v60_disassembler; } }, { "v810", le, 0, []() -> util::disasm_interface * { return new v810_disassembler; } }, + { "v850", le, 0, []() -> util::disasm_interface * { return new v850_disassembler; } }, + { "v850es", le, 0, []() -> util::disasm_interface * { return new v850es_disassembler; } }, + { "v850e2", le, 0, []() -> util::disasm_interface * { return new v850e2_disassembler; } }, { "vt50", le, 0, []() -> util::disasm_interface * { return new vt50_disassembler; } }, { "vt52", le, 0, []() -> util::disasm_interface * { return new vt52_disassembler; } }, { "vt61", le, -1, []() -> util::disasm_interface * { return new vt61_disassembler; } },