diff options
author | 2024-01-21 09:47:03 +1100 | |
---|---|---|
committer | 2024-01-21 09:47:03 +1100 | |
commit | 832c8d9e648c6298c267fa50dc59ee3f2461e6ea (patch) | |
tree | e961d9c7c6d480b8f92b311057009fbdce49bf32 /src/devices/cpu/c33 | |
parent | 5a42c9c12bad9c2416c3b334ea99af64dfb80634 (diff) |
cpu/c33, tools/unidasm.cpp: Added disassembler for Epson C33 ADV Core.
Diffstat (limited to 'src/devices/cpu/c33')
-rw-r--r-- | src/devices/cpu/c33/c33dasm.cpp | 600 | ||||
-rw-r--r-- | src/devices/cpu/c33/c33dasm.h | 33 |
2 files changed, 633 insertions, 0 deletions
diff --git a/src/devices/cpu/c33/c33dasm.cpp b/src/devices/cpu/c33/c33dasm.cpp new file mode 100644 index 00000000000..41460879526 --- /dev/null +++ b/src/devices/cpu/c33/c33dasm.cpp @@ -0,0 +1,600 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb +/* + Epson C33 disassembler + + TODO: + * Only C33 ADV Core is currently supported - add support for C33 STD Core + * Reconstruct more assembler synthetics + * Should psrset and psrclr use symbolic names for bits? + * Should loop instructions have friendlier syntax? +*/ + +#include "emu.h" +#include "c33dasm.h" + +#include <tuple> +#include <utility> + + +namespace { + +char const *const special_reg_names[16] = { + "%psr", + "%sp", + "%alr", + "%ahr", + "%lco", + "%lca", + "%lea", + "%sor", + "%ttbr", + "%dp", + "%idir", + "%dbbr", + nullptr, + "%usp", + "%ssp", + "%pc" }; + +std::pair<char const *, unsigned> const class_0_00_ops[32] = { + { "nop", 0 }, // 000 0000 0 00 00 + { "slp", 0 }, // 000 0000 0 01 00 + { "halt", 0 }, // 000 0000 0 10 00 + { nullptr, 0 }, + { nullptr, 0 }, + { nullptr, 0 }, + { nullptr, 0 }, + { nullptr, 0 }, + { "pushn %%r%1$u", 4 }, // 000 0001 0 00 00 + { "popn %%r%1$u", 4 }, // 000 0001 0 01 00 + { nullptr, 0 }, + { "jpr %%r%1$u", 4 }, // 000 0001 0 11 00 + { nullptr, 0 }, + { nullptr, 0 }, + { nullptr, 0 }, + { "jpr.d %%r%1$u", 4 }, // 000 0001 1 11 00 + { "brk", 0 }, // 000 0010 0 00 00 + { "retd", 0 }, // 000 0010 0 01 00 + { "int %1$u", 2 }, // 000 0010 0 10 00 + { "reti", 0 }, // 000 0010 0 11 00 + { nullptr, 0 }, + { nullptr, 0 }, + { nullptr, 0 }, + { nullptr, 0 }, + { "call %%r%1$u", 4 }, // 000 0011 0 00 00 + { "ret", 0 }, // 000 0011 0 01 00 + { "jp %%r%1$u", 4 }, // 000 0011 0 10 00 + { "retm", 0 }, // 000 0011 0 11 00 + { "call.d %%r%1$u", 4 }, // 000 0011 1 00 00 + { "ret.d", 0 }, // 000 0011 1 01 00 + { "jp.d %%r%1$u", 4 }, // 000 0011 1 10 00 + { nullptr, 0 } }; + +std::tuple<char const *, bool, bool> const class_0_01_ops[32] = { + { "push %%r%1$u", false, false }, // 000 0000 000 01 + { "pop %%r%1$u", false, false }, // 000 0000 001 01 + { "pushs %%r%2$u", true, false }, // 000 0000 010 01 + { "pops %%r%2$u", true, false }, // 000 0000 011 01 + { "mac.w %%r%1$u", false, false }, // 000 0000 100 01 + { "mac.hw %%r%1$u", false, false }, // 000 0000 101 01 + { "macclr", false, true }, // 000 0000 110 01 + { "ld.cf", false, true }, // 000 0000 111 01 + { "divu.w %%r%1$u", false, false }, // 000 0001 000 01 + { "div.w %%r%1$u", false, false }, // 000 0001 001 01 + { "repeat %%r%1$u", false, false }, // 000 0001 010 01 + { "repeat %1$u", false, false }, // 000 0001 011 01 + { nullptr, false, false }, + { "add %%r%1$u,%%dp", false, false }, // 000 0001 101 01 + { nullptr, false, false }, + { nullptr, false, false }, + { nullptr, false, false }, + { nullptr, false, false }, + { nullptr, false, false }, + { nullptr, false, false }, + { nullptr, false, false }, + { nullptr, false, false }, + { nullptr, false, false }, + { nullptr, false, false }, + { nullptr, false, false }, + { nullptr, false, false }, + { nullptr, false, false }, + { nullptr, false, false }, + { nullptr, false, false }, + { nullptr, false, false }, + { nullptr, false, false }, + { nullptr, false, false } }; + +char const *const class_0_jumps[16] = { + nullptr, + nullptr, + nullptr, + nullptr, + "jrgt%1$s 0x%2$x", // 000 0100 + "jrge%1$s 0x%2$x", // 000 0101 + "jrlt%1$s 0x%2$x", // 000 0110 + "jrle%1$s 0x%2$x", // 000 0111 + "jrugt%1$s 0x%2$x", // 000 1000 + "jruge%1$s 0x%2$x", // 000 1001 + "jrult%1$s 0x%2$x", // 000 1010 + "jrule%1$s 0x%2$x", // 000 1011 + "jreq%1$s 0x%2$x", // 000 1100 + "jrne%1$s 0x%2$x", // 000 1101 + "call%1$s 0x%2$x", // 000 1110 + "jp%1$s 0x%2$x" }; // 000 1111 + +std::pair<char const *, char const *> const class_1_ops[32] = { + { "ld.b %%r%1$u,[%%r%2$u]", "ld.b %%r%1$u,[%%r%2$u + 0x%4$x]" }, // 001 000 00 + { "ld.b %%r%1$u,[%%r%2$u]+", nullptr }, // 001 000 01 + { "add %%r%1$u,%%r%2$u", nullptr }, // 001 000 10 + { "srl %%r%1$u,%3$u", nullptr }, // 001 000 11 + { "ld.ub %%r%1$u,[%%r%2$u]", "ld.ub %%r%1$u,[%%r%2$u + 0x%4$x]" }, // 001 001 00 + { "ld.ub %%r%1$u,[%%r%2$u]+", nullptr }, // 001 001 01 + { "sub %%r%1$u,%%r%2$u", nullptr }, // 001 001 10 + { "sll %%r%1$u,%3$u", nullptr }, // 001 001 11 + { "ld.h %%r%1$u,[%%r%2$u]", "ld.h %%r%1$u,[%%r%2$u + 0x%4$x]" }, // 001 010 00 + { "ld.h %%r%1$u,[%%r%2$u]+", nullptr }, // 001 010 01 + { "cmp %%r%1$u,%%r%2$u", nullptr }, // 001 010 10 + { "sra %%r%1$u,%3$u", nullptr }, // 001 010 11 + { "ld.uh %%r%1$u,[%%r%2$u]", "ld.uh %%r%1$u,[%%r%2$u + 0x%4$x]" }, // 001 011 00 + { "ld.uh %%r%1$u,[%%r%2$u]+", nullptr }, // 001 011 01 + { "ld.w %%r%1$u,%%r%2$u", nullptr }, // 001 011 10 + { "sla %%r%1$u,%3$u", nullptr }, // 001 011 11 + { "ld.w %%r%1$u,[%%r%2$u]", "ld.w %%r%1$u,[%%r%2$u + 0x%4$x]" }, // 001 100 00 + { "ld.w %%r%1$u,[%%r%2$u]+", nullptr }, // 001 100 01 + { "and %%r%1$u,%%r%2$u", nullptr }, // 001 100 10 + { "rr %%r%1$u,%3$u", nullptr }, // 001 100 11 + { "ld.b [%%r%2$u],%%r%1$u", "ld.b [%%r%2$u + 0x%4$x],%%r%1$u" }, // 001 101 00 + { "ld.b [%%r%2$u]+,%%r%1$u", nullptr }, // 001 101 01 + { "or %%r%1$u,%%r%2$u", nullptr }, // 001 101 10 + { "rl %%r%1$u,%3$u", nullptr }, // 001 101 11 + { "ld.h [%%r%2$u],%%r%1$u", "ld.h [%%r%2$u + 0x%4$x],%%r%1$u" }, // 001 110 00 + { "ld.h [%%r%2$u]+,%%r%1$u", nullptr }, // 001 110 01 + { "xor %%r%1$u,%%r%2$u", nullptr }, // 001 110 10 + { nullptr, nullptr }, + { "ld.w [%%r%2$u],%%r%1$u", "ld.w [%%r%2$u + 0x%4$x],%%r%1$u" }, // 001 111 00 + { "ld.w [%%r%2$u]+,%%r%1$u", nullptr }, // 001 111 01 + { "not %%r%1$u,%%r%2$u", nullptr }, // 001 111 10 + { nullptr, nullptr } }; + +char const *const class_1_ext_shifts[4] = { + nullptr, + "ext sra,%1$u", // 001 110 11 0000 01 + "ext srl,%1$u", // 001 110 11 0000 10 + "ext sll,%1$u" }; // 001 110 11 0000 11 + +char const *const class_1_ext_predicates[16] = { + nullptr, + nullptr, + nullptr, + nullptr, + "ext gt", // 001 110 11 0100 + "ext ge", // 001 110 11 0101 + "ext lt", // 001 110 11 0110 + "ext le", // 001 110 11 0111 + "ext ugt", // 001 110 11 1000 + "ext uge", // 001 110 11 1001 + "ext ult", // 001 110 11 1010 + "ext ule", // 001 110 11 1011 + "ext eq", // 001 110 11 1100 + "ext ne", // 001 110 11 1101 + nullptr, + nullptr }; + +std::pair<char const *, bool> class_1_ext_3[4] = { + { "ext %%r%1$u", true }, + { "ext %%r%1$u,sra,%2$u", false }, + { "ext %%r%1$u,srl,%2$u", false }, + { "ext %%r%1$u,sll,%2$u", false } }; + +std::pair<char const *, unsigned> const class_2_3_ops[16] = { + { "ld.b %%r%1$u,[%%sp + 0x%2$x]", 1 }, // 010 000 + { "ld.ub %%r%1$u,[%%sp + 0x%2$x]", 1 }, // 010 001 + { "ld.h %%r%1$u,[%%sp + 0x%2$x]", 2 }, // 010 010 + { "ld.uh %%r%1$u,[%%sp + 0x%2$x]", 2 }, // 010 011 + { "ld.w %%r%1$u,[%%sp + 0x%2$x]", 4 }, // 010 100 + { "ld.b [%%sp + 0x%2$x],%%r%1$u", 1 }, // 010 101 + { "ld.h [%%sp + 0x%2$x],%%r%1$u", 2 }, // 010 110 + { "ld.w [%%sp + 0x%2$x],%%r%1$u", 4 }, // 010 111 + { "add %%r%1$u,0x%2$x", 1 }, // 011 000 + { "sub %%r%1$u,0x%2$x", 1 }, // 011 001 + { "cmp %%r%1$u,%5$s0x%4$x", 1 }, // 011 010 + { "ld.w %%r%1$u,%5$s0x%4$x", 1 }, // 011 011 + { "and %%r%1$u,0x%3$x", 1 }, // 011 100 + { "or %%r%1$u,0x%3$x", 1 }, // 011 101 + { "xor %%r%1$u,0x%3$x", 1 }, // 011 110 + { "not %%r%1$u,0x%3$x", 1 } }; // 011 111 + +std::pair<char const *, bool> const class_4_ops[32] = { + { nullptr, false }, + { nullptr, false }, + { nullptr, false }, + { nullptr, false }, + { nullptr, false }, + { nullptr, false }, + { nullptr, false }, + { nullptr, false }, + { "srl %%r%1$u,%2$u", false }, // 100 010 00 + { "srl %%r%1$u,%%r%2$u", false }, // 100 010 01 + { "scan0 %%r%1$u,%%r%2$u", false }, // 100 010 10 + { "div0s %%r%2$u", true }, // 100 010 11 + { "sll %%r%1$u,%2$u", false }, // 100 011 00 + { "sll %%r%1$u,%%r%2$u", false }, // 100 011 01 + { "scan1 %%r%1$u,%%r%2$u", false }, // 100 011 10 + { "div0u %%r%2$u", true }, // 100 011 11 + { "sra %%r%1$u,%2$u", false }, // 100 100 00 + { "sra %%r%1$u,%%r%2$u", false }, // 100 100 01 + { "swap %%r%1$u,%%r%2$u", false }, // 100 100 10 + { "div1 %%r%2$u", true }, // 100 100 11 + { "sla %%r%1$u,%2$u", false }, // 100 101 00 + { "sla %%r%1$u,%%r%2$u", false }, // 100 101 01 + { "mirror %%r%1$u,%%r%2$u", false }, // 100 101 10 + { "div2s %%r%2$u", true }, // 100 101 11 + { "rr %%r%1$u,%2$u", false }, // 100 110 00 + { "rr %%r%1$u,%%r%2$u", false }, // 100 110 01 + { "swaph %%r%1$u,%%r%2$u", false }, // 100 110 10 + { "div3s %%r%2$u", true }, // 100 110 11 + { "rl %%r%1$u,%2$u", false }, // 100 111 00 + { "rl %%r%1$u,%%r%2$u", false }, // 100 111 01 + { "sat.b %%r%1$u,%%r%2$u", false }, // 100 111 10 + { "sat.ub %%r%1$u,%%r%2$u", false } }; // 100 111 11 + +std::tuple<char const *, char const *, unsigned, unsigned> const class_5_ops[32] = { + { "ld.w %4$s,%%r%2$d", nullptr, 4, 1 }, // 101 000 00 + { "ld.b %%r%1$u,%%r%2$u", nullptr, 4, 0 }, // 101 000 01 + { "mlt.h %%r%1$u,%%r%2$u", nullptr, 4, 0 }, // 101 000 10 + { "mlt.hw %%r%1$u,%%r%2$u", nullptr, 4, 0 }, // 101 000 11 + { "ld.w %%r%1$d,%4$s", nullptr, 4, 2 }, // 101 001 00 + { "ld.ub %%r%1$u,%%r%2$u", nullptr, 4, 0 }, // 101 001 01 + { "mltu.h %%r%1$u,%%r%2$u", nullptr, 4, 0 }, // 101 001 10 + { "mac1.h %%r%1$u,%%r%2$u", nullptr, 4, 0 }, // 101 001 11 + { "btst [%%r%2$u],%1$u", "btst [%%r%2$u + 0x%3$x],%1$u", 3, 0 }, // 101 010 00 + { "ld.h %%r%1$u,%%r%2$u", nullptr, 4, 0 }, // 101 010 01 + { "mlt.w %%r%1$u,%%r%2$u", nullptr, 4, 0 }, // 101 010 10 + { "mac1.hw %%r%1$u,%%r%2$u", nullptr, 4, 0 }, // 101 010 11 + { "bclr [%%r%2$u],%1$u", "bclr [%%r%2$u + 0x%3$x],%1$u", 3, 0 }, // 101 011 00 + { "ld.uh %%r%1$u,%%r%2$u", nullptr, 4, 0 }, // 101 011 01 + { "mltu.w %%r%1$u,%%r%2$u", nullptr, 4, 0 }, // 101 011 10 + { nullptr, nullptr, 0, 0 }, + { "bset [%%r%2$u],%1$u", "bset [%%r%2$u + 0x%3$x],%1$u", 3, 0 }, // 101 100 00 + { "ld.c %%r%1$u,0x%2$x", nullptr, 4, 0 }, // 101 100 01 + { "mac %%r%2$u", nullptr, 0, 0 }, // 101 100 10 + { "mac1.w %%r%1$u,%%r%2$u", nullptr, 4, 0 }, // 101 100 11 + { "bnot [%%r%2$u],%1$u", "bnot [%%r%2$u + 0x%3$x],%1$u", 3, 0 }, // 101 101 00 + { "ld.c 0x%2$x,%%r%1$u", nullptr, 4, 0 }, // 101 101 01 + { "sat.h %%r%1$u,%%r%2$u", nullptr, 4, 0 }, // 101 101 10 + { "sat.uh %%r%1$u,%%r%2$u", nullptr, 4, 0 }, // 101 101 11 + { "addc %%r%1$u,%%r%2$u", nullptr, 4, 0 }, // 101 110 00 + { "loop %%r%1$u,%%r%2$u", nullptr, 4, 0 }, // 101 110 01 + { "loop %%r%1$u,%2$u", nullptr, 4, 0 }, // 101 110 10 + { "loop %1$u,%2$u", nullptr, 4, 0 }, // 101 110 11 + { "sbc %%r%1$u,%%r%2$u", nullptr, 4, 0 }, // 101 111 00 + { "sat.w %%r%1$u,%%r%2$u", nullptr, 4, 0 }, // 101 111 01 + { "sat.uw %%r%1$u,%%r%2$u", nullptr, 4, 0 }, // 101 111 10 + { nullptr, nullptr, 0, 0 } }; + +std::pair<char const *, unsigned> const class_7_ops[8] = { + { "ld.b %%r%1$u,[%%dp + 0x%2$x]", 1 }, // 111 000 + { "ld.ub %%r%1$u,[%%dp + 0x%2$x]", 1 }, // 111 001 + { "ld.h %%r%1$u,[%%dp + 0x%2$x]", 2 }, // 111 010 + { "ld.uh %%r%1$u,[%%dp + 0x%2$x]", 2 }, // 111 011 + { "ld.w %%r%1$u,[%%dp + 0x%2$x]", 4 }, // 111 100 + { "ld.b [%%dp + 0x%2$x],%%r%1$u", 1 }, // 111 101 + { "ld.h [%%dp + 0x%2$x],%%r%1$u", 1 }, // 111 110 + { "ld.w [%%dp + 0x%2$x],%%r%1$u", 1 } }; // 111 111 + +} // anonymous namespace + +c33_disassembler::c33_disassembler() +{ +} + + +u32 c33_disassembler::opcode_alignment() const +{ + return 2; +} + + +offs_t c33_disassembler::disassemble( + std::ostream &stream, + offs_t pc, + data_buffer const &opcodes, + data_buffer const ¶ms) +{ + u16 op; + + u32 ext_imm = 0; + unsigned ext_count = 0; + op = opcodes.r16(pc); + if (BIT(op, 13, 3) == 6) + { + ext_imm = BIT(op, 0, 13); + ext_count = 1; + op = opcodes.r16(pc + 2); + if (BIT(op, 13, 3) == 6) + { + ext_imm = (ext_imm << 13) | BIT(op, 0, 13); + ext_count = 2; + op = opcodes.r16(pc + 4); + } + } + + switch (BIT(op, 13, 3)) + { + case 0: + if (offs_t const r = dasm_class_0(stream, pc, op, ext_imm, ext_count); r) + return r; + break; + case 1: + if (offs_t const r = dasm_class_1(stream, op, ext_imm, ext_count); r) + return r; + break; + case 2: + case 3: + if (offs_t const r = dasm_class_2_3(stream, op, ext_imm, ext_count); r) + return r; + break; + case 4: + if (offs_t const r = dasm_class_4(stream, op, ext_imm, ext_count); r) + return r; + break; + case 5: + if (offs_t const r = dasm_class_5(stream, op, ext_imm, ext_count); r) + return r; + break; + case 6: + if (offs_t const r = dasm_class_6(stream, op, ext_imm, ext_count); r) + return r; + break; + case 7: + if (offs_t const r = dasm_class_7(stream, op, ext_imm, ext_count); r) + return r; + break; + }; + + if (offs_t const r = max_ext(stream, 0, ext_imm, ext_count); r) + return r; + + stream << "<unknown>"; + return 2; +} + + +offs_t c33_disassembler::dasm_class_0(std::ostream &stream, offs_t pc, u16 op, u32 ext_imm, unsigned ext_count) const +{ + switch (BIT(op, 9, 4)) + { + case 0b0000: + case 0b0001: + case 0b0010: + case 0b0011: + if (BIT(op, 4, 2) == 0) + { + auto const [inst, target_bits] = class_0_00_ops[BIT(op, 6, 5)]; + if (inst && ((4 == target_bits) || !BIT(op, target_bits, 4 - target_bits))) + { + if (offs_t const r = max_ext(stream, 0, ext_imm, ext_count); r) + return r; + + util::stream_format(stream, inst, BIT(op, 0, 4)); + return 2; + } + } + else if (BIT(op, 4, 2) == 1) + { + auto const [inst, use_special_reg, no_arg] = class_0_01_ops[BIT(op, 6, 5)]; + char const *const special_reg = use_special_reg ? special_reg_names[BIT(op, 0, 4)] : nullptr; + if (inst && (!use_special_reg || special_reg) && (!no_arg || !BIT(op, 0, 4))) + { + if (offs_t const r = max_ext(stream, 0, ext_imm, ext_count); r) + return r; + + util::stream_format(stream, inst, BIT(op, 0, 4), special_reg); + return 2; + } + } + break; + + default: + { + s32 imm = (BIT(ext_imm, 16, 10) << 22) | (BIT(ext_imm, 0, 13) << 9) | (BIT(op, 0, 8) << 1); + if (!ext_count) + imm = util::sext(imm, 9); + else if (1 == ext_count) + imm = util::sext(imm, 22); + + util::stream_format(stream, class_0_jumps[BIT(op, 9, 4)], BIT(op, 8) ? ".d" : " ", pc + (ext_count * 2) + imm); + return 2 + (ext_count * 2); + } + } + + return 0; // catch invalid forms +} + +offs_t c33_disassembler::dasm_class_1(std::ostream &stream, u16 op, u32 ext_imm, unsigned ext_count) const +{ + switch (BIT(op, 8, 5)) + { + case 0b110'11: + if (!BIT(op, 4, 4)) + { + char const *const inst = class_1_ext_shifts[BIT(op, 2, 2)]; + if (inst) + { + if (offs_t const r = max_ext(stream, 0, ext_imm, ext_count); r) + return r; + + util::stream_format(stream, inst, BIT(op, 0, 2)); + return 2; + } + } + else + { + char const *const inst = class_1_ext_predicates[BIT(op, 4, 4)]; + if (inst && !BIT(op, 0, 4)) + { + if (offs_t const r = max_ext(stream, 0, ext_imm, ext_count); r) + return r; + + stream << inst; + return 2; + } + } + break; + + case 0b111'11: + { + auto const [inst, no_imm] = class_1_ext_3[BIT(op, 2, 2)]; + if (!no_imm || !BIT(op, 0, 2)) + { + if (offs_t const r = max_ext(stream, 0, ext_imm, ext_count); r) + return r; + + util::stream_format(stream, inst, BIT(op, 4, 4), BIT(op, 0, 2)); + return 2; + } + } + break; + + default: + { + auto const [inst, inst_ext] = class_1_ops[BIT(op, 8, 5)]; + if (offs_t const r = max_ext(stream, inst_ext ? 2 : 0, ext_imm, ext_count); r) + return r; + + util::stream_format(stream, ext_count ? inst_ext : inst, BIT(op, 0, 4), BIT(op, 4, 4), 0x10 | BIT(op, 4, 4), ext_imm); + return 2 + (ext_count * 2); + } + } + + return 0; // catch invalid ext forms +} + + +offs_t c33_disassembler::dasm_class_2_3(std::ostream &stream, u16 op, u32 ext_imm, unsigned ext_count) const +{ + auto const [inst, mul] = class_2_3_ops[BIT(op, 10, 4)]; + + u8 const reg = BIT(op, 0, 4); + u32 imm = (ext_imm << 6) | BIT(op, 4, 6); + s32 simm = util::sext(imm, 6 + (ext_count * 13)); + u32 abs = std::abs(simm); + char const *const sign = (0 > simm) ? "-" : ""; + if (!ext_count) + { + imm *= mul; + simm *= mul; + abs *= mul; + } + util::stream_format(stream, inst, reg, imm, simm, abs, sign); + return 2 + (ext_count * 2); +} + + +offs_t c33_disassembler::dasm_class_4(std::ostream &stream, u16 op, u32 ext_imm, unsigned ext_count) const +{ + if (BIT(op, 11, 2) == 0) + { + if (offs_t const r = max_ext(stream, 0, ext_imm, ext_count); r) + return r; + + util::stream_format(stream, BIT(op, 10) ? "sub %%sp,0x%1$x" : "add %%sp,0x%1$x", BIT(op, 0, 10) * 4); + return 2; + } + else + { + auto const [inst, no_dest] = class_4_ops[BIT(op, 8, 5)]; + if (!no_dest || !BIT(op, 0, 4)) + { + if (offs_t const r = max_ext(stream, 0, ext_imm, ext_count); r) + return r; + + util::stream_format(stream, inst, BIT(op, 0, 4), BIT(op, 4, 4)); + return 2; + } + } + + return 0; // catch invalid forms of division instructions +} + + +offs_t c33_disassembler::dasm_class_5(std::ostream &stream, u16 op, u32 ext_imm, unsigned ext_count) const +{ + if (BIT(op, 6, 7) == 0b111'11'00) + { + if (offs_t const r = max_ext(stream, 0, ext_imm, ext_count); r) + return r; + + util::stream_format(stream, "do.c 0x%1$x", BIT(op, 0, 6)); + return 2; + } + else if (BIT(op, 5, 8) == 0b111'11'01'0) + { + if (offs_t const r = max_ext(stream, 0, ext_imm, ext_count); r) + return r; + + util::stream_format(stream, "psrset %1$u", BIT(op, 0, 5)); + return 2; + } + else if (BIT(op, 5, 8) == 0b111'11'10'0) + { + if (offs_t const r = max_ext(stream, 0, ext_imm, ext_count); r) + return r; + + util::stream_format(stream, "psrclr %1$u", BIT(op, 0, 5)); + return 2; + } + else + { + auto const [inst, inst_ext, target_bits, special_reg_pos] = class_5_ops[BIT(op, 8, 5)]; + char const *const special_reg = special_reg_pos ? special_reg_names[BIT(op, (special_reg_pos - 1) * 4, 4)] : nullptr; + if (inst && (!special_reg_pos || special_reg) && ((4 == target_bits) || !BIT(op, target_bits, 4 - target_bits))) + { + if (offs_t const r = max_ext(stream, inst_ext ? 2 : 0, ext_imm, ext_count); r) + return r; + + util::stream_format(stream, ext_count ? inst_ext : inst, BIT(op, 0, 4), BIT(op, 4, 4), ext_imm, special_reg); + return 2 + (ext_count * 2); + } + } + + return 0; // catch invalid forms +} + + +offs_t c33_disassembler::dasm_class_6(std::ostream &stream, u16 op, u32 ext_imm, unsigned ext_count) const +{ + if (offs_t const r = max_ext(stream, 0, ext_imm, ext_count); r) + return r; + + util::stream_format(stream, "ext 0x%1$x", BIT(op, 0, 13)); + return 2; +} + + +offs_t c33_disassembler::dasm_class_7(std::ostream &stream, u16 op, u32 ext_imm, unsigned ext_count) const +{ + auto const [inst, mul] = class_7_ops[BIT(op, 10, 3)]; + + u8 const reg = BIT(op, 0, 4); + u32 imm = (ext_imm << 6) | BIT(op, 4, 6); + if (!ext_count) + imm *= mul; + util::stream_format(stream, inst, reg, imm); + return 2 + (ext_count * 2); +} + + +offs_t c33_disassembler::max_ext(std::ostream &stream, unsigned max, u32 ext_imm, unsigned ext_count) const +{ + if (max >= ext_count) + { + return 0; + } + else + { + util::stream_format(stream, "ext 0x%1$x", BIT(ext_imm, (ext_count - 1) * 13, 13)); + return 2; + } +} diff --git a/src/devices/cpu/c33/c33dasm.h b/src/devices/cpu/c33/c33dasm.h new file mode 100644 index 00000000000..5f8254ad05d --- /dev/null +++ b/src/devices/cpu/c33/c33dasm.h @@ -0,0 +1,33 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb +/* + Epson C33 disassembler +*/ + +#ifndef MAME_CPU_C33_C33DASM_H +#define MAME_CPU_C33_C33DASM_H + +#pragma once + + +class c33_disassembler : public util::disasm_interface +{ +public: + c33_disassembler(); + + virtual u32 opcode_alignment() const override; + virtual offs_t disassemble(std::ostream &stream, offs_t pc, data_buffer const &opcodes, data_buffer const ¶ms) override; + +private: + offs_t dasm_class_0(std::ostream &stream, offs_t pc, u16 op, u32 ext_imm, unsigned ext_count) const; + offs_t dasm_class_1(std::ostream &stream, u16 op, u32 ext_imm, unsigned ext_count) const; + offs_t dasm_class_2_3(std::ostream &stream, u16 op, u32 ext_imm, unsigned ext_count) const; + offs_t dasm_class_4(std::ostream &stream, u16 op, u32 ext_imm, unsigned ext_count) const; + offs_t dasm_class_6(std::ostream &stream, u16 op, u32 ext_imm, unsigned ext_count) const; + offs_t dasm_class_5(std::ostream &stream, u16 op, u32 ext_imm, unsigned ext_count) const; + offs_t dasm_class_7(std::ostream &stream, u16 op, u32 ext_imm, unsigned ext_count) const; + + offs_t max_ext(std::ostream &stream, unsigned max, u32 ext_imm, unsigned ext_count) const; +}; + +#endif // MAME_CPU_C33_C33DASM_H |