diff options
author | 2022-08-25 16:07:11 +0700 | |
---|---|---|
committer | 2022-08-25 16:07:11 +0700 | |
commit | 361f9f487cda9175cc7c14fd3e3ffe235bb7bb4f (patch) | |
tree | 580304df5c96f05a5377fe8d48e33fe4b25e891d /src | |
parent | 423a1c96337a1cbbbe2c594d194cb5ec9138ab15 (diff) |
mn1610: new disassembler
Diffstat (limited to 'src')
-rw-r--r-- | src/devices/cpu/mn1610/mn1610d.cpp | 343 | ||||
-rw-r--r-- | src/devices/cpu/mn1610/mn1610d.h | 36 | ||||
-rw-r--r-- | src/tools/unidasm.cpp | 3 |
3 files changed, 382 insertions, 0 deletions
diff --git a/src/devices/cpu/mn1610/mn1610d.cpp b/src/devices/cpu/mn1610/mn1610d.cpp new file mode 100644 index 00000000000..f04b40f1378 --- /dev/null +++ b/src/devices/cpu/mn1610/mn1610d.cpp @@ -0,0 +1,343 @@ +// license:BSD-3-Clause +// copyright-holders:Patrick Mackinlay + +/* + * Disassembler for Panafacom MN1610 and MN1613. + * + * Source: + * - http://www.st.rim.or.jp/~nkomatsu/panafacom/MN1610.html + * + * TODO: + * - mn1617 + */ +#include "emu.h" + +#include "mn1610d.h" + +char const *const reg[] = { "r0", "r1", "r2", "r3", "r4", "sp", "str", "ic" }; + +enum operand_type : unsigned +{ + NONE = 0, + + // mn1610 + EA, // effective address + Rd, // register at bits 8-10 + Rs, // register at bits 0-2 + I2, // 2 bit immediate + I4, // 4 bit immediate + Ib, // 8 bit immediate + EE, // shift carry operation + SK, // skip + + // mn1613 + R0, // register 0 + D0, // double-width register 0 + Ri, // index register at bits 0-1 + Mi, // index register at bits 0-1 with optional pre-decrement/post-increment + Iw, // 16 bit immediate + BB, // segment register + C, // include carry + BR, // base register + SR, // special register + HR, // hardware register +}; + +struct instruction +{ + u16 value; + u16 mask; + + char const *const opcode; + operand_type operands[4]; + + u32 flags; +}; + +static const struct instruction mn1610_table[] = +{ + // memory + { 0xc700, 0xc700, "b", { EA } }, // 11mm m111 nnnn nnnn + { 0x8700, 0xc700, "bal", { EA }, // 10mm m111 nnnn nnnn + util::disasm_interface::STEP_OVER }, + { 0xc600, 0xc700, "ims", { EA }, // 11mm m110 nnnn nnnn + util::disasm_interface::STEP_COND }, + { 0x8600, 0xc700, "dms", { EA }, // 10mm m110 nnnn nnnn + util::disasm_interface::STEP_COND }, + { 0xc000, 0xc000, "l", { Rd, EA } }, // 11mm mrrr nnnn nnnn + { 0x8000, 0xc000, "st", { Rd, EA } }, // 10mm mrrr nnnn nnnn + + // arithmetic + { 0x5000, 0xf808, "cb", { Rd, Rs, SK } }, // 0101 0ddd kkkk 0sss + { 0x5008, 0xf808, "c", { Rd, Rs, SK } }, // 0101 0ddd kkkk 1sss + { 0x5800, 0xf808, "s", { Rd, Rs, SK } }, // 0101 1ddd kkkk 0sss + { 0x5808, 0xf808, "a", { Rd, Rs, SK } }, // 0101 1ddd kkkk 1sss + { 0x6000, 0xf808, "eor", { Rd, Rs, SK } }, // 0110 0ddd kkkk 0sss + { 0x6008, 0xf808, "or", { Rd, Rs, SK } }, // 0110 0ddd kkkk 1sss + { 0x6808, 0xf808, "and", { Rd, Rs, SK } }, // 0110 1ddd kkkk 1sss + { 0x6800, 0xf808, "lad", { Rd, Rs, SK } }, // 0110 1ddd kkkk 0sss + { 0x7000, 0xf808, "dswp", { Rd, Rs, SK } }, // 0111 0ddd kkkk 0sss + { 0x7008, 0xf808, "bswp", { Rd, Rs, SK } }, // 0111 0ddd kkkk 1sss + { 0x7800, 0xf808, "mvb", { Rd, Rs, SK } }, // 0111 1ddd kkkk 0sss + { 0x7808, 0xf808, "mv", { Rd, Rs, SK } }, // 0111 1ddd kkkk 1sss + + // shift + { 0x200c, 0xf80c, "sl", { Rd, EE, SK } }, // 0010 0rrr kkkk 11ee + { 0x2008, 0xf80c, "sr", { Rd, EE, SK } }, // 0010 0rrr kkkk 10ee + + // immediate + { 0x3800, 0xf800, "sbit", { Rd, I4, SK } }, // 0011 1rrr kkkk nnnn + { 0x3000, 0xf800, "rbit", { Rd, I4, SK } }, // 0011 0rrr kkkk nnnn + { 0x2800, 0xf800, "tbit", { Rd, I4, SK } }, // 0010 1rrr kkkk nnnn + { 0x4800, 0xf800, "ai", { Rd, I4, SK } }, // 0100 1rrr kkkk nnnn + { 0x4000, 0xf800, "si", { Rd, I4, SK } }, // 0100 0rrr kkkk nnnn + + // i/o + { 0x1800, 0xf800, "rd", { Rd, Ib } }, // 0001 1rrr nnnn nnnn + { 0x1000, 0xf800, "wt", { Rd, Ib } }, // 0001 0rrr nnnn nnnn + { 0x0800, 0xf800, "mvi", { Rd, Ib } }, // 0000 1rrr nnnn nnnn + + // other + { 0x2000, 0xffff, "h", { }, // 0010 0000 0000 0000 + util::disasm_interface::STEP_OVER }, + { 0x2001, 0xf8ff, "push", { Rd } }, // 0010 0rrr 0000 0001 + { 0x2002, 0xf8ff, "pop", { Rd } }, // 0010 0rrr 0000 0010 + { 0x2003, 0xffff, "ret", { }, // 0010 0000 0000 0011 + util::disasm_interface::STEP_OUT }, + { 0x2004, 0xfffc, "lpsw", { I2 }, // 0010 0000 0000 01nn + util::disasm_interface::STEP_OUT }, +}; + +// opcodes are sorted in descending order of number of bits in mask to ensure correct decoding +static const struct instruction mn1613_table[] = +{ + { 0x1707, 0xffff, "popm", { } }, // 0001 0111 0000 0111 + { 0x170f, 0xffff, "pshm", { } }, // 0001 0111 0000 1111 + { 0x2607, 0xffff, "bd", { Iw } }, // 0010 0110 0000 0111 a16 + { 0x2617, 0xffff, "bald", { Iw }, // 0010 0110 0001 0111 a16 + util::disasm_interface::STEP_OVER }, + { 0x270f, 0xffff, "bl", { Iw } }, // 0010 0111 0000 1111 a16 + { 0x271f, 0xffff, "ball", { Iw }, // 0010 0111 0001 1111 a16 + util::disasm_interface::STEP_OVER }, + { 0x3f07, 0xffff, "retl", { }, // 0011 1111 0000 0111 + util::disasm_interface::STEP_OUT }, + { 0x3f17, 0xffff, "blk", { } }, // 0011 1111 0001 0111 + + { 0x2704, 0xfffc, "br", { Ri } }, // 0010 0111 0000 01ii + { 0x2714, 0xfffc, "balr", { Ri }, // 0010 0111 0001 01ii + util::disasm_interface::STEP_OVER }, + + { 0x0f07, 0xff8f, "lb", { BR, Iw } }, // 0000 1111 0bbb 0111 a16 + { 0x0f0f, 0xff8f, "ls", { SR, Iw } }, // 0000 1111 0ppp 1111 a16 + { 0x0f87, 0xff8f, "stb", { BR, Iw } }, // 0000 1111 1bbb 0111 a16 + { 0x0f8f, 0xff8f, "sts", { SR, Iw } }, // 0000 1111 1ppp 1111 a16 + + { 0x1f0f, 0xff0f, "fix", { R0, D0, SK } }, // 0001 1111 kkkk 1111 + { 0x1f07, 0xff0f, "flt", { D0, R0, SK } }, // 0001 1111 kkkk 0111 + + { 0x2010, 0xf8fc, "wtr", { Rd, Ri } }, // 0010 0rrr 0001 00ii + { 0x2014, 0xf8fc, "rdr", { Rd, Ri } }, // 0010 0rrr 0001 01ii + { 0x2708, 0xffc8, "ld", { Rs, BB, Iw } }, // 0010 0111 00bb 1rrr a16 + { 0x2748, 0xffc8, "std", { Rs, BB, Iw } }, // 0010 0111 01bb 1rrr a16 + + { 0x0f00, 0xff88, "setb", { Rs, BR } }, // 0000 1111 0bbb 0sss + { 0x0f08, 0xff88, "sets", { Rs, SR } }, // 0000 1111 0ppp 1sss + { 0x0f80, 0xff88, "cpyb", { Rs, BR } }, // 0000 1111 1bbb 0ddd + { 0x0f88, 0xff88, "cpys", { Rs, SR } }, // 0000 1111 1ppp 1ddd + { 0x3f00, 0xff88, "seth", { Rs, HR } }, // 0011 1111 0hhh 0sss + { 0x3f70, 0xff88, "srbt", { R0, Rs } }, // 0011 1111 0111 0sss + { 0x3f80, 0xff88, "cpyh", { Rs, HR } }, // 0011 1111 1hhh 0ddd + { 0x3ff0, 0xff88, "debp", { Rs, R0 } }, // 0011 1111 1111 0ddd + { 0x5700, 0xff0c, "cbr", { R0, Ri, SK } }, // 0101 0111 kkkk 00ii + { 0x5708, 0xff0c, "cwr", { R0, Ri, SK } }, // 0101 0111 kkkk 10ii + { 0x5f00, 0xff0c, "swr", { R0, Ri, SK } }, // 0101 1111 kkkk 00ii + { 0x5f08, 0xff0c, "awr", { R0, Ri, SK } }, // 0101 1111 kkkk 10ii + { 0x6700, 0xff0c, "eorr", { R0, Ri, SK } }, // 0110 0111 kkkk 00ii + { 0x6704, 0xff0c, "fd", { D0, Ri, SK } }, // 0110 0111 kkkk 01ii + { 0x6708, 0xff0c, "orr", { R0, Ri, SK } }, // 0110 0111 kkkk 10ii + { 0x670c, 0xff0c, "fm", { D0, Ri, SK } }, // 0110 0111 kkkk 11ii + { 0x6f00, 0xff0c, "ladr", { R0, Ri, SK } }, // 0110 1111 kkkk 00ii + { 0x6f04, 0xff0c, "fs", { D0, Ri, SK } }, // 0110 1111 kkkk 01ii + { 0x6f08, 0xff0c, "andr", { R0, Ri, SK } }, // 0110 1111 kkkk 10ii + { 0x6f0c, 0xff0c, "fa", { D0, Ri, SK } }, // 0110 1111 kkkk 11ii + { 0x7700, 0xff0c, "dswr", { R0, Ri, SK } }, // 0111 0111 kkkk 00ii + { 0x7708, 0xff0c, "bswr", { R0, Ri, SK } }, // 0111 0111 kkkk 10ii + { 0x770c, 0xff0c, "d", { R0, Ri, SK } }, // 0111 0111 kkkk 11ii + { 0x7f00, 0xff0c, "mvbr", { R0, Ri, SK } }, // 0111 1111 kkkk 00ii + { 0x7f08, 0xff0c, "mvwr", { R0, Ri, SK } }, // 0111 1111 kkkk 10ii + { 0x7f0c, 0xff0c, "m", { D0, Ri, SK } }, // 0111 1111 kkkk 11ii + + { 0x1700, 0xff08, "trst", { Rs, Iw, SK } }, // 0001 0111 kkkk 0sss a16 + { 0x1708, 0xff08, "tset", { Rs, Iw, SK } }, // 0001 0111 kkkk 1sss a16 + { 0x4704, 0xff04, "sd", { D0, Ri, C, SK } }, // 0100 0111 kkkk c1ii + { 0x4f04, 0xff04, "ad", { D0, Ri, C, SK } }, // 0100 1111 kkkk c1ii + { 0x5704, 0xff04, "das", { R0, Ri, C, SK } }, // 0101 0111 kkkk c1ii + { 0x5f04, 0xff04, "daa", { R0, Ri, C, SK } }, // 0101 1111 kkkk c1ii + + { 0x5007, 0xf80f, "cbi", { Rd, Iw, SK } }, // 0101 0ddd kkkk 0111 i16 + { 0x500f, 0xf80f, "cwi", { Rd, Iw, SK } }, // 0101 0ddd kkkk 1111 i16 + { 0x5807, 0xf80f, "swi", { Rd, Iw, SK } }, // 0101 1ddd kkkk 0111 i16 + { 0x580f, 0xf80f, "awi", { Rd, Iw, SK } }, // 0101 1ddd kkkk 1111 i16 + { 0x6007, 0xf80f, "eori", { Rd, Iw, SK } }, // 0110 0ddd kkkk 0111 i16 + { 0x600f, 0xf80f, "ori", { Rd, Iw, SK } }, // 0110 0ddd kkkk 1111 i16 + { 0x6807, 0xf80f, "ladi", { Rd, Iw, SK } }, // 0110 1ddd kkkk 0111 i16 + { 0x680f, 0xf80f, "andi", { Rd, Iw, SK } }, // 0110 1ddd kkkk 1111 i16 + { 0x780f, 0xf80f, "mvwi", { Rd, Iw, SK } }, // 0111 1ddd kkkk 1111 i16 + + // these two instructions require mm != 00 + { 0x2040, 0xf8cc, "lr", { Rd, BB, Mi } }, // 0010 0rrr mmbb 00ii + { 0x2080, 0xf8cc, "lr", { Rd, BB, Mi } }, // 0010 0rrr mmbb 00ii + { 0x20c0, 0xf8cc, "lr", { Rd, BB, Mi } }, // 0010 0rrr mmbb 00ii + { 0x2044, 0xf8cc, "str", { Rd, BB, Mi } }, // 0010 0rrr mmbb 01ii + { 0x2084, 0xf8cc, "str", { Rd, BB, Mi } }, // 0010 0rrr mmbb 01ii + { 0x20c4, 0xf8cc, "str", { Rd, BB, Mi } }, // 0010 0rrr mmbb 01ii + + { 0x1f00, 0xff00, "neg", { Rs, C, SK } }, // 0001 1111 kkkk cddd +}; + +std::optional<std::string> mn1610_disassembler::operand(unsigned t, u16 pc, u16 data) +{ + char const *const ee[] = { nullptr, "re", "se", "ce" }; + char const *const sk[] = { nullptr, "skp", "m", "pz", "z", "nz", "mz", "p", "ez", "enz", "oz", "onz", "lmz", "lp", "lpz", "lm" }; + + switch (t) + { + case EA: + switch (BIT(data, 11, 3)) + { + case 0: return util::string_format("0x%02x", BIT(data, 0, 8)); + case 1: return util::string_format("0x%04x", pc + s8(BIT(data, 0, 8))); + case 2: return util::string_format("[0x%02x]", BIT(data, 0, 8)); + case 3: return util::string_format("[0x%04x]", pc + s8(BIT(data, 0, 8))); + case 4: return util::string_format("0x%02x(%s)", BIT(data, 0, 8), reg[3]); + case 5: return util::string_format("0x%02x(%s)", BIT(data, 0, 8), reg[4]); + case 6: return util::string_format("[0x%02x](%s)", BIT(data, 0, 8), reg[3]); + case 7: return util::string_format("[0x%02x](%s)", BIT(data, 0, 8), reg[4]); + } + break; + case Rd: return util::string_format("%s", reg[BIT(data, 8, 3)]); + case Rs: return util::string_format("%s", reg[BIT(data, 0, 3)]); + case I2: return util::string_format("0x%x", BIT(data, 0, 2)); + case I4: return util::string_format("0x%x", BIT(data, 0, 4)); + case Ib: return util::string_format("0x%02x", BIT(data, 0, 8)); + case EE: + if (BIT(data, 0, 2)) + return util::string_format("%s", ee[BIT(data, 0, 2)]); + break; + case SK: + if (BIT(data, 4, 4)) + return util::string_format("%s", sk[BIT(data, 4, 4)]); + break; + } + + return std::nullopt; +} + +offs_t mn1610_disassembler::disassemble(std::ostream &stream, offs_t pc, data_buffer const &opcodes, data_buffer const ¶ms) +{ + u32 flags = SUPPORTED; + u32 words = 1; + + u16 const op = opcodes.r16(pc); + + for (instruction const &i : mn1610_table) + { + if ((op & i.mask) == i.value) + { + util::stream_format(stream, "%-4s", i.opcode); + flags |= i.flags; + + char delimeter = ' '; + for (operand_type const t : i.operands) + { + std::optional<std::string> const o = operand(t, pc, op); + if (o) + { + util::stream_format(stream, "%c%s", delimeter, *o); + + if (t == SK) + flags |= STEP_COND; + + delimeter = ','; + } + } + + return words | flags; + } + } + + return words | flags; +} + +std::optional<std::string> mn1613_disassembler::operand(unsigned t, u16 pc, u16 data) +{ + char const *const br[] = { "csbr", "ssbr", "tsr0", "tsr1", "osr0", "osr1", "osr2", "osr3" }; + char const *const sr[] = { "sbrb", "icb", "npp", "", "", "", "", "" }; + char const *const hr[] = { "tcr", "tir", "tsr", "scr", "ssr", "sor", "iisr", "" }; + + switch (t) + { + case R0: return util::string_format("%s", reg[0]); + case D0: return util::string_format("d%s", reg[0]); + case Ri: return util::string_format("(%s)", reg[BIT(data, 0, 2)]); + case Mi: + switch (BIT(data, 6, 2)) + { + case 1: return util::string_format("(%s)", reg[BIT(data, 0, 2)]); + case 2: return util::string_format("-(%s)", reg[BIT(data, 0, 2)]); + case 3: return util::string_format("(%s)+", reg[BIT(data, 0, 2)]); + } + break; + case Iw: return util::string_format("0x%04x", data); + case BB: + if (BIT(data, 4, 2)) + return util::string_format("%s", br[BIT(data, 4, 2)]); + break; + case C: return util::string_format("c"); + case BR: return util::string_format("%s", br[BIT(data, 4, 3)]); + case SR: return util::string_format("%s", sr[BIT(data, 4, 3)]); + case HR: return util::string_format("%s", hr[BIT(data, 4, 3)]); + + default: + return mn1610_disassembler::operand(t, pc, data); + } + + return std::nullopt; +} + +offs_t mn1613_disassembler::disassemble(std::ostream &stream, offs_t pc, data_buffer const &opcodes, data_buffer const ¶ms) +{ + u32 flags = SUPPORTED; + u32 words = 1; + + u16 const op = opcodes.r16(pc); + + for (instruction const &i : mn1613_table) + { + if ((op & i.mask) == i.value) + { + util::stream_format(stream, "%-4s", i.opcode); + flags |= i.flags; + + char delimeter = ' '; + for (operand_type const t : i.operands) + { + u16 const data = (t == Iw) ? opcodes.r16(pc + words++) : op; + std::optional<std::string> const o = operand(t, pc, data); + if (o) + { + util::stream_format(stream, "%c%s", delimeter, *o); + + if (t == SK) + flags |= STEP_COND; + + delimeter = ','; + } + } + + return words | flags; + } + } + + return mn1610_disassembler::disassemble(stream, pc, opcodes, params); +} diff --git a/src/devices/cpu/mn1610/mn1610d.h b/src/devices/cpu/mn1610/mn1610d.h new file mode 100644 index 00000000000..769dfc51d6b --- /dev/null +++ b/src/devices/cpu/mn1610/mn1610d.h @@ -0,0 +1,36 @@ +// license:BSD-3-Clause +// copyright-holders:Patrick Mackinlay + +#ifndef MAME_CPU_MN1610_MN1610D_H +#define MAME_CPU_MN1610_MN1610D_H + +#pragma once + +#include <optional> + +class mn1610_disassembler : public util::disasm_interface +{ +public: + mn1610_disassembler() = default; + virtual ~mn1610_disassembler() = default; + + virtual u32 opcode_alignment() const override { return 1; } + virtual offs_t disassemble(std::ostream &stream, offs_t pc, data_buffer const &opcodes, data_buffer const ¶ms) override; + +protected: + virtual std::optional<std::string> operand(unsigned t, u16 pc, u16 data); +}; + +class mn1613_disassembler : public mn1610_disassembler +{ +public: + mn1613_disassembler() = default; + virtual ~mn1613_disassembler() = default; + + virtual offs_t disassemble(std::ostream &stream, offs_t pc, data_buffer const &opcodes, data_buffer const ¶ms) override; + +protected: + virtual std::optional<std::string> operand(unsigned t, u16 pc, u16 data) override; +}; + +#endif // MAME_CPU_MN1610_MN1610D_H diff --git a/src/tools/unidasm.cpp b/src/tools/unidasm.cpp index a72b3f0e070..19168392d3d 100644 --- a/src/tools/unidasm.cpp +++ b/src/tools/unidasm.cpp @@ -117,6 +117,7 @@ using util::BIT; #include "cpu/mips/mips3dsm.h" #include "cpu/mips/mips1dsm.h" #include "cpu/mk1/mk1dasm.h" +#include "cpu/mn1610/mn1610d.h" #include "cpu/mn1880/mn1880d.h" #include "cpu/mn10200/mn102dis.h" #include "cpu/msm65x2/msm65x2d.h" @@ -527,6 +528,8 @@ static const dasm_table_entry dasm_table[] = { "mm76", le, 0, []() -> util::disasm_interface * { return new mm76_disassembler; } }, { "mm78", le, 0, []() -> util::disasm_interface * { return new mm78_disassembler; } }, { "mn10200", le, 0, []() -> util::disasm_interface * { return new mn10200_disassembler; } }, + { "mn1610", be, -1, []() -> util::disasm_interface * { return new mn1610_disassembler; } }, + { "mn1613", be, -1, []() -> util::disasm_interface * { return new mn1613_disassembler; } }, { "mn1860", be, 0, []() -> util::disasm_interface * { return new mn1860_disassembler; } }, { "mn1870", be, 0, []() -> util::disasm_interface * { return new mn1870_disassembler; } }, { "mn1880", be, 0, []() -> util::disasm_interface * { return new mn1880_disassembler; } }, |